From 197b444407b86b1990f4051b1cb28181e45eb965 Mon Sep 17 00:00:00 2001 From: Yuri Astrakhan Date: Tue, 16 Jul 2024 17:45:22 -0400 Subject: [PATCH 001/683] Ignore underscore-prefixed args for needless_pass_by_value lint When a user explicitly tags a param as unused (yet?), there is no need to raise another lint on it. --- clippy_lints/src/needless_pass_by_value.rs | 15 ++++++++------- tests/ui/needless_pass_by_value.rs | 12 ++++++++---- tests/ui/needless_pass_by_value.stderr | 10 +++++----- 3 files changed, 21 insertions(+), 16 deletions(-) diff --git a/clippy_lints/src/needless_pass_by_value.rs b/clippy_lints/src/needless_pass_by_value.rs index f2e00cef7e9..4b86db33fde 100644 --- a/clippy_lints/src/needless_pass_by_value.rs +++ b/clippy_lints/src/needless_pass_by_value.rs @@ -129,7 +129,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue { }) .collect::>(); - // Collect moved variables and spans which will need dereferencings from the + // Collect moved variables and spans which will need dereferencing from the // function body. let MovedVariablesCtxt { moved_vars } = { let mut ctx = MovedVariablesCtxt::default(); @@ -148,12 +148,13 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue { return; } - // Ignore `self`s. - if idx == 0 { - if let PatKind::Binding(.., ident, _) = arg.pat.kind { - if ident.name == kw::SelfLower { - continue; - } + // Ignore `self`s and params whose variable name starts with an underscore + if let PatKind::Binding(.., ident, _) = arg.pat.kind { + if idx == 0 && ident.name == kw::SelfLower { + continue; + } + if ident.name.as_str().starts_with('_') { + continue; } } diff --git a/tests/ui/needless_pass_by_value.rs b/tests/ui/needless_pass_by_value.rs index 14cba5a7eb5..9408b8c948f 100644 --- a/tests/ui/needless_pass_by_value.rs +++ b/tests/ui/needless_pass_by_value.rs @@ -84,7 +84,7 @@ trait Serialize {} impl<'a, T> Serialize for &'a T where T: Serialize {} impl Serialize for i32 {} -fn test_blanket_ref(_foo: T, _serializable: S) {} +fn test_blanket_ref(vals: T, serializable: S) {} //~^ ERROR: this argument is passed by value, but not consumed in the function body fn issue_2114(s: String, t: String, u: Vec, v: Vec) { @@ -116,7 +116,7 @@ impl S { ) { } - fn baz(&self, _u: U, _s: Self) {} + fn baz(&self, uu: U, ss: Self) {} //~^ ERROR: this argument is passed by value, but not consumed in the function body //~| ERROR: this argument is passed by value, but not consumed in the function body } @@ -162,13 +162,13 @@ fn test_destructure_copy(x: CopyWrapper, y: CopyWrapper, z: CopyWrapper) { // The following 3 lines should not cause an ICE. See #2831 trait Bar<'a, A> {} impl<'b, T> Bar<'b, T> for T {} -fn some_fun<'b, S: Bar<'b, ()>>(_item: S) {} +fn some_fun<'b, S: Bar<'b, ()>>(items: S) {} //~^ ERROR: this argument is passed by value, but not consumed in the function body // Also this should not cause an ICE. See #2831 trait Club<'a, A> {} impl Club<'static, T> for T {} -fn more_fun(_item: impl Club<'static, i32>) {} +fn more_fun(items: impl Club<'static, i32>) {} //~^ ERROR: this argument is passed by value, but not consumed in the function body fn is_sync(_: T) @@ -177,6 +177,10 @@ where { } +struct Obj(String); + +fn prefix_test(_unused_with_prefix: Obj) {} + fn main() { // This should not cause an ICE either // https://github.com/rust-lang/rust-clippy/issues/3144 diff --git a/tests/ui/needless_pass_by_value.stderr b/tests/ui/needless_pass_by_value.stderr index 827a200ba68..dce28186ff8 100644 --- a/tests/ui/needless_pass_by_value.stderr +++ b/tests/ui/needless_pass_by_value.stderr @@ -46,7 +46,7 @@ LL | fn test_destructure(x: Wrapper, y: Wrapper, z: Wrapper) { error: this argument is passed by value, but not consumed in the function body --> tests/ui/needless_pass_by_value.rs:87:49 | -LL | fn test_blanket_ref(_foo: T, _serializable: S) {} +LL | fn test_blanket_ref(vals: T, serializable: S) {} | ^ help: consider taking a reference instead: `&T` error: this argument is passed by value, but not consumed in the function body @@ -106,13 +106,13 @@ LL | t: String, error: this argument is passed by value, but not consumed in the function body --> tests/ui/needless_pass_by_value.rs:119:23 | -LL | fn baz(&self, _u: U, _s: Self) {} +LL | fn baz(&self, uu: U, ss: Self) {} | ^ help: consider taking a reference instead: `&U` error: this argument is passed by value, but not consumed in the function body --> tests/ui/needless_pass_by_value.rs:119:30 | -LL | fn baz(&self, _u: U, _s: Self) {} +LL | fn baz(&self, uu: U, ss: Self) {} | ^^^^ help: consider taking a reference instead: `&Self` error: this argument is passed by value, but not consumed in the function body @@ -166,13 +166,13 @@ LL | struct CopyWrapper(u32); error: this argument is passed by value, but not consumed in the function body --> tests/ui/needless_pass_by_value.rs:165:40 | -LL | fn some_fun<'b, S: Bar<'b, ()>>(_item: S) {} +LL | fn some_fun<'b, S: Bar<'b, ()>>(items: S) {} | ^ help: consider taking a reference instead: `&S` error: this argument is passed by value, but not consumed in the function body --> tests/ui/needless_pass_by_value.rs:171:20 | -LL | fn more_fun(_item: impl Club<'static, i32>) {} +LL | fn more_fun(items: impl Club<'static, i32>) {} | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider taking a reference instead: `&impl Club<'static, i32>` error: aborting due to 22 previous errors From af35dcd33012c131bf2d3675bb40591b740c7728 Mon Sep 17 00:00:00 2001 From: apoisternex Date: Sat, 3 Aug 2024 21:24:51 -0300 Subject: [PATCH 002/683] Fix [`needless_return`] false negative when returned expression borrows a value Fixes #12907 changelog: Fix [`needless_return`] false negative when returned expression borrows a value --- clippy_lints/src/returns.rs | 22 ++++++++++++++++++---- tests/ui/needless_return.fixed | 4 ++++ tests/ui/needless_return.rs | 4 ++++ tests/ui/needless_return.stderr | 14 +++++++++++++- 4 files changed, 39 insertions(+), 5 deletions(-) diff --git a/clippy_lints/src/returns.rs b/clippy_lints/src/returns.rs index 13016cdadb0..034c44a971d 100644 --- a/clippy_lints/src/returns.rs +++ b/clippy_lints/src/returns.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_hir_and_then}; use clippy_utils::source::{snippet_opt, snippet_with_context}; use clippy_utils::sugg::has_enclosing_paren; -use clippy_utils::visitors::{for_each_expr, Descend}; +use clippy_utils::visitors::{for_each_expr, for_each_unconsumed_temporary, Descend}; use clippy_utils::{ binary_expr_needs_parentheses, fn_def_id, is_from_proc_macro, is_inside_let_else, is_res_lang_ctor, path_res, path_to_local_id, span_contains_cfg, span_find_starting_semi, @@ -384,10 +384,24 @@ fn check_final_expr<'tcx>( } }; - let borrows = inner.map_or(false, |inner| last_statement_borrows(cx, inner)); - if borrows { - return; + if let Some(inner) = inner { + if for_each_unconsumed_temporary(cx, inner, |temporary_ty| { + if temporary_ty.has_significant_drop(cx.tcx, cx.param_env) + && temporary_ty + .walk() + .any(|arg| matches!(arg.unpack(), GenericArgKind::Lifetime(re) if !re.is_static())) + { + ControlFlow::Break(()) + } else { + ControlFlow::Continue(()) + } + }) + .is_break() + { + return; + } } + if ret_span.from_expansion() { return; } diff --git a/tests/ui/needless_return.fixed b/tests/ui/needless_return.fixed index fc4129e1db8..c5c570690b4 100644 --- a/tests/ui/needless_return.fixed +++ b/tests/ui/needless_return.fixed @@ -355,4 +355,8 @@ fn conjunctive_blocks() -> String { ({ "a".to_string() } + "b" + { "c" }) } +fn issue12907() -> String { + "".split("").next().unwrap().to_string() +} + fn main() {} diff --git a/tests/ui/needless_return.rs b/tests/ui/needless_return.rs index 61c7a02008f..738611391df 100644 --- a/tests/ui/needless_return.rs +++ b/tests/ui/needless_return.rs @@ -365,4 +365,8 @@ fn conjunctive_blocks() -> String { return { "a".to_string() } + "b" + { "c" }; } +fn issue12907() -> String { + return "".split("").next().unwrap().to_string(); +} + fn main() {} diff --git a/tests/ui/needless_return.stderr b/tests/ui/needless_return.stderr index ea9c230eafd..da0fa220d8c 100644 --- a/tests/ui/needless_return.stderr +++ b/tests/ui/needless_return.stderr @@ -665,5 +665,17 @@ LL - return { "a".to_string() } + "b" + { "c" }; LL + ({ "a".to_string() } + "b" + { "c" }) | -error: aborting due to 53 previous errors +error: unneeded `return` statement + --> tests/ui/needless_return.rs:369:5 + | +LL | return "".split("").next().unwrap().to_string(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove `return` + | +LL - return "".split("").next().unwrap().to_string(); +LL + "".split("").next().unwrap().to_string() + | + +error: aborting due to 54 previous errors From 66283bff5fde5f310f3dd373d22cd4f892b3d312 Mon Sep 17 00:00:00 2001 From: apoisternex Date: Sun, 4 Aug 2024 10:45:42 -0300 Subject: [PATCH 003/683] apply [`needless_return`] suggestion --- clippy_lints/src/useless_conversion.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/useless_conversion.rs b/clippy_lints/src/useless_conversion.rs index 2f7d54e73ed..1890b3fdd40 100644 --- a/clippy_lints/src/useless_conversion.rs +++ b/clippy_lints/src/useless_conversion.rs @@ -217,12 +217,12 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { }, ExprKind::MethodCall(.., args, _) => { cx.typeck_results().type_dependent_def_id(parent.hir_id).map(|did| { - return ( + ( did, args, cx.typeck_results().node_args(parent.hir_id), MethodOrFunction::Method, - ); + ) }) }, _ => None, From f7f9a3fb28faab90cf59d2e11b30e8ebc19d5845 Mon Sep 17 00:00:00 2001 From: sapir Date: Mon, 5 Aug 2024 00:37:51 +0300 Subject: [PATCH 004/683] Update Cargo.lock --- Cargo.lock | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index cd693835ded..915229f7e7e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -79,16 +79,18 @@ dependencies = [ [[package]] name = "gccjit" -version = "2.0.0" -source = "git+https://github.com/rust-lang/gccjit.rs#328cb1b414f67dfa15162ba7a55ed01931f1b219" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62e0ba949ebee07c5cc21f02cb48f28f2c8db7fcbc15fdc5120476a6c43b4636" dependencies = [ "gccjit_sys", ] [[package]] name = "gccjit_sys" -version = "0.1.0" -source = "git+https://github.com/rust-lang/gccjit.rs#328cb1b414f67dfa15162ba7a55ed01931f1b219" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5bbf85e12c2593772329a9d4e8310271f6706e6045ce4f41b041dd34fba6603" dependencies = [ "libc", ] From f579dee206eec8b914487d52fc65843bbae795db Mon Sep 17 00:00:00 2001 From: sapir Date: Mon, 5 Aug 2024 00:37:59 +0300 Subject: [PATCH 005/683] Implement CodeModel --- src/base.rs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/base.rs b/src/base.rs index be149ffe5a1..e3558b6b875 100644 --- a/src/base.rs +++ b/src/base.rs @@ -129,8 +129,19 @@ pub fn compile_codegen_unit( // NOTE: Rust relies on LLVM doing wrapping on overflow. context.add_command_line_option("-fwrapv"); + if let Some(model) = tcx.sess.code_model() { + use rustc_target::spec::CodeModel; + + context.add_command_line_option(match model { + CodeModel::Tiny => "-mcmodel=tiny", + CodeModel::Small => "-mcmodel=small", + CodeModel::Kernel => "-mcmodel=kernel", + CodeModel::Medium => "-mcmodel=medium", + CodeModel::Large => "-mcmodel=large", + }); + } + if tcx.sess.relocation_model() == rustc_target::spec::RelocModel::Static { - context.add_command_line_option("-mcmodel=kernel"); context.add_command_line_option("-fno-pie"); } From 014a84029c1ea3d66056f0ae920e547f8ba90168 Mon Sep 17 00:00:00 2001 From: sapir Date: Mon, 5 Aug 2024 01:15:57 +0300 Subject: [PATCH 006/683] Replace stack_var_count and RETURN_VALUE_COUNT with a single counter --- src/builder.rs | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/src/builder.rs b/src/builder.rs index 307348f595d..e7f1e7e6b90 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -41,9 +41,6 @@ use crate::type_of::LayoutGccExt; // TODO(antoyo) type Funclet = (); -// TODO(antoyo): remove this variable. -static mut RETURN_VALUE_COUNT: usize = 0; - enum ExtremumOperation { Max, Min, @@ -52,13 +49,18 @@ enum ExtremumOperation { pub struct Builder<'a: 'gcc, 'gcc, 'tcx> { pub cx: &'a CodegenCx<'gcc, 'tcx>, pub block: Block<'gcc>, - stack_var_count: Cell, pub location: Option>, + value_counter: Cell, } impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { fn with_cx(cx: &'a CodegenCx<'gcc, 'tcx>, block: Block<'gcc>) -> Self { - Builder { cx, block, stack_var_count: Cell::new(0), location: None } + Builder { cx, block, location: None, value_counter: Cell::new(0) } + } + + fn next_value_counter(&self) -> u64 { + self.value_counter.set(self.value_counter.get() + 1); + self.value_counter.get() } fn atomic_extremum( @@ -324,11 +326,10 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { let void_type = self.context.new_type::<()>(); let current_func = self.block.get_function(); if return_type != void_type { - unsafe { RETURN_VALUE_COUNT += 1 }; let result = current_func.new_local( self.location, return_type, - &format!("returnValue{}", unsafe { RETURN_VALUE_COUNT }), + &format!("returnValue{}", self.next_value_counter()), ); self.block.add_assignment( self.location, @@ -384,7 +385,6 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { let current_func = self.block.get_function(); if return_type != void_type { - unsafe { RETURN_VALUE_COUNT += 1 }; let return_value = self.cx.context.new_call_through_ptr(self.location, func_ptr, &args); let return_value = llvm::adjust_intrinsic_return_value( self, @@ -397,7 +397,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { let result = current_func.new_local( self.location, return_value.get_type(), - &format!("ptrReturnValue{}", unsafe { RETURN_VALUE_COUNT }), + &format!("ptrReturnValue{}", self.next_value_counter()), ); self.block.add_assignment(self.location, result, return_value); result.to_rvalue() @@ -446,11 +446,10 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { let return_type = self.context.new_type::(); let current_func = self.block.get_function(); // TODO(antoyo): return the new_call() directly? Since the overflow function has no side-effects. - unsafe { RETURN_VALUE_COUNT += 1 }; let result = current_func.new_local( self.location, return_type, - &format!("overflowReturnValue{}", unsafe { RETURN_VALUE_COUNT }), + &format!("overflowReturnValue{}", self.next_value_counter()), ); self.block.add_assignment( self.location, @@ -934,9 +933,8 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { fn alloca(&mut self, size: Size, align: Align) -> RValue<'gcc> { let ty = self.cx.type_array(self.cx.type_i8(), size.bytes()).get_aligned(align.bytes()); // TODO(antoyo): It might be better to return a LValue, but fixing the rustc API is non-trivial. - self.stack_var_count.set(self.stack_var_count.get() + 1); self.current_func() - .new_local(self.location, ty, &format!("stack_var_{}", self.stack_var_count.get())) + .new_local(self.location, ty, &format!("stack_var_{}", self.next_value_counter())) .get_address(self.location) } @@ -959,11 +957,10 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { }; let ptr = self.context.new_cast(self.location, ptr, aligned_type.make_pointer()); let deref = ptr.dereference(self.location).to_rvalue(); - unsafe { RETURN_VALUE_COUNT += 1 }; let loaded_value = function.new_local( self.location, aligned_type, - &format!("loadedValue{}", unsafe { RETURN_VALUE_COUNT }), + &format!("loadedValue{}", self.next_value_counter()), ); block.add_assignment(self.location, loaded_value, deref); loaded_value.to_rvalue() From 4fe1647d21e8533d718ae7026391443a76ce3351 Mon Sep 17 00:00:00 2001 From: sapir Date: Wed, 7 Aug 2024 13:43:27 +0300 Subject: [PATCH 007/683] Remove dummy value locals for function ptr calls --- src/builder.rs | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/src/builder.rs b/src/builder.rs index e7f1e7e6b90..38e147599c9 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -341,7 +341,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { self.block .add_eval(self.location, self.cx.context.new_call(self.location, func, &args)); // Return dummy value when not having return value. - self.context.new_rvalue_from_long(self.isize_type, 0) + self.context.new_rvalue_zero(self.isize_type) } } @@ -421,17 +421,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { self.cx.context.new_call_through_ptr(self.location, func_ptr, &args), ); // Return dummy value when not having return value. - let result = current_func.new_local( - self.location, - self.isize_type, - "dummyValueThatShouldNeverBeUsed", - ); - self.block.add_assignment( - self.location, - result, - self.context.new_rvalue_from_long(self.isize_type, 0), - ); - result.to_rvalue() + self.context.new_rvalue_zero(self.isize_type) } } From c2ed04be16d4e23e4511726c7fb1da87de93fd62 Mon Sep 17 00:00:00 2001 From: kyoto7250 <50972773+kyoto7250@users.noreply.github.com> Date: Fri, 9 Aug 2024 00:22:30 +0900 Subject: [PATCH 008/683] check the def_id with using diagnostic_item in unnecessary_min_or_max lint https://github.com/rust-lang/rust-clippy/issues/13191 --- .../src/methods/unnecessary_min_or_max.rs | 45 ++++++++++--------- tests/ui/unnecessary_min_or_max.fixed | 29 ++++++++++++ tests/ui/unnecessary_min_or_max.rs | 29 ++++++++++++ 3 files changed, 82 insertions(+), 21 deletions(-) diff --git a/clippy_lints/src/methods/unnecessary_min_or_max.rs b/clippy_lints/src/methods/unnecessary_min_or_max.rs index 86c0a6322b6..ff5fa7d33e3 100644 --- a/clippy_lints/src/methods/unnecessary_min_or_max.rs +++ b/clippy_lints/src/methods/unnecessary_min_or_max.rs @@ -1,16 +1,15 @@ use std::cmp::Ordering; use super::UNNECESSARY_MIN_OR_MAX; -use clippy_utils::diagnostics::span_lint_and_sugg; - use clippy_utils::consts::{ConstEvalCtxt, Constant, ConstantSource, FullInt}; +use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet; use rustc_errors::Applicability; use rustc_hir::Expr; use rustc_lint::LateContext; use rustc_middle::ty; -use rustc_span::Span; +use rustc_span::{sym, Span}; pub(super) fn check<'tcx>( cx: &LateContext<'tcx>, @@ -21,26 +20,30 @@ pub(super) fn check<'tcx>( ) { let typeck_results = cx.typeck_results(); let ecx = ConstEvalCtxt::with_env(cx.tcx, cx.param_env, typeck_results); - if let Some((left, ConstantSource::Local | ConstantSource::CoreConstant)) = ecx.eval_with_source(recv) - && let Some((right, ConstantSource::Local | ConstantSource::CoreConstant)) = ecx.eval_with_source(arg) + if let Some(id) = typeck_results.type_dependent_def_id(expr.hir_id) + && (cx.tcx.is_diagnostic_item(sym::cmp_ord_min, id) || cx.tcx.is_diagnostic_item(sym::cmp_ord_max, id)) { - let Some(ord) = Constant::partial_cmp(cx.tcx, typeck_results.expr_ty(recv), &left, &right) else { - return; - }; + if let Some((left, ConstantSource::Local | ConstantSource::CoreConstant)) = ecx.eval_with_source(recv) + && let Some((right, ConstantSource::Local | ConstantSource::CoreConstant)) = ecx.eval_with_source(arg) + { + let Some(ord) = Constant::partial_cmp(cx.tcx, typeck_results.expr_ty(recv), &left, &right) else { + return; + }; - lint(cx, expr, name, recv.span, arg.span, ord); - } else if let Some(extrema) = detect_extrema(cx, recv) { - let ord = match extrema { - Extrema::Minimum => Ordering::Less, - Extrema::Maximum => Ordering::Greater, - }; - lint(cx, expr, name, recv.span, arg.span, ord); - } else if let Some(extrema) = detect_extrema(cx, arg) { - let ord = match extrema { - Extrema::Minimum => Ordering::Greater, - Extrema::Maximum => Ordering::Less, - }; - lint(cx, expr, name, recv.span, arg.span, ord); + lint(cx, expr, name, recv.span, arg.span, ord); + } else if let Some(extrema) = detect_extrema(cx, recv) { + let ord = match extrema { + Extrema::Minimum => Ordering::Less, + Extrema::Maximum => Ordering::Greater, + }; + lint(cx, expr, name, recv.span, arg.span, ord); + } else if let Some(extrema) = detect_extrema(cx, arg) { + let ord = match extrema { + Extrema::Minimum => Ordering::Greater, + Extrema::Maximum => Ordering::Less, + }; + lint(cx, expr, name, recv.span, arg.span, ord); + } } } diff --git a/tests/ui/unnecessary_min_or_max.fixed b/tests/ui/unnecessary_min_or_max.fixed index 392f6dd1fee..1f3e131516c 100644 --- a/tests/ui/unnecessary_min_or_max.fixed +++ b/tests/ui/unnecessary_min_or_max.fixed @@ -65,3 +65,32 @@ fn random_u32() -> u32 { // random number generator 0 } + +struct Issue13191 { + min: u16, + max: u16, +} + +impl Issue13191 { + fn new() -> Self { + Self { min: 0, max: 0 } + } + + fn min(mut self, value: u16) -> Self { + self.min = value; + self + } + + fn max(mut self, value: u16) -> Self { + self.max = value; + self + } +} + +fn issue_13191() { + // should not fixed + Issue13191::new().min(0); + + // should not fixed + Issue13191::new().max(0); +} diff --git a/tests/ui/unnecessary_min_or_max.rs b/tests/ui/unnecessary_min_or_max.rs index b03755e6d23..58356b9d49e 100644 --- a/tests/ui/unnecessary_min_or_max.rs +++ b/tests/ui/unnecessary_min_or_max.rs @@ -65,3 +65,32 @@ fn random_u32() -> u32 { // random number generator 0 } + +struct Issue13191 { + min: u16, + max: u16, +} + +impl Issue13191 { + fn new() -> Self { + Self { min: 0, max: 0 } + } + + fn min(mut self, value: u16) -> Self { + self.min = value; + self + } + + fn max(mut self, value: u16) -> Self { + self.max = value; + self + } +} + +fn issue_13191() { + // should not fixed + Issue13191::new().min(0); + + // should not fixed + Issue13191::new().max(0); +} From 2645ea3a680c6f92dc524a55bafa80fa37ba97d9 Mon Sep 17 00:00:00 2001 From: xFrednet Date: Fri, 9 Aug 2024 20:38:41 +0200 Subject: [PATCH 009/683] Remove `feature=cargo-clippy` argument As announced --- src/driver.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/driver.rs b/src/driver.rs index 3fafe2427a2..2de676aea9e 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -270,8 +270,6 @@ pub fn main() { }, _ => Some(s.to_string()), }) - // FIXME: remove this line in 1.79 to only keep `--cfg clippy`. - .chain(vec!["--cfg".into(), r#"feature="cargo-clippy""#.into()]) .chain(vec!["--cfg".into(), "clippy".into()]) .collect::>(); From 3eb28444b522c01e9461255b38990b55915f3651 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 12 Jun 2024 13:06:23 -0400 Subject: [PATCH 010/683] Give Instance::expect_resolve a span --- src/context.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/context.rs b/src/context.rs index 4458ca84bbb..e258f16bacb 100644 --- a/src/context.rs +++ b/src/context.rs @@ -494,6 +494,7 @@ impl<'gcc, 'tcx> MiscMethods<'tcx> for CodegenCx<'gcc, 'tcx> { ty::ParamEnv::reveal_all(), def_id, ty::List::empty(), + None, ); let symbol_name = tcx.symbol_name(instance).name; From 007fa3b94eed08b51a7d5aea2a79292744f04935 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 1 Jul 2024 16:32:32 -0400 Subject: [PATCH 011/683] Fix spans --- src/context.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/context.rs b/src/context.rs index e258f16bacb..86a5000a723 100644 --- a/src/context.rs +++ b/src/context.rs @@ -17,7 +17,7 @@ use rustc_middle::ty::layout::{ }; use rustc_middle::ty::{self, Instance, ParamEnv, PolyExistentialTraitRef, Ty, TyCtxt}; use rustc_session::Session; -use rustc_span::{source_map::respan, Span}; +use rustc_span::{source_map::respan, Span, DUMMY_SP}; use rustc_target::abi::{ call::FnAbi, HasDataLayout, PointeeInfo, Size, TargetDataLayout, VariantIdx, }; @@ -494,7 +494,7 @@ impl<'gcc, 'tcx> MiscMethods<'tcx> for CodegenCx<'gcc, 'tcx> { ty::ParamEnv::reveal_all(), def_id, ty::List::empty(), - None, + DUMMY_SP, ); let symbol_name = tcx.symbol_name(instance).name; From fb4738571fdecbee2ad0d89f6e181f2feb90e908 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 2 Jul 2024 21:05:22 +0200 Subject: [PATCH 012/683] Miri function identity hack: account for possible inlining --- src/common.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common.rs b/src/common.rs index 35699346b29..19333689aaa 100644 --- a/src/common.rs +++ b/src/common.rs @@ -221,7 +221,7 @@ impl<'gcc, 'tcx> ConstMethods<'tcx> for CodegenCx<'gcc, 'tcx> { } value } - GlobalAlloc::Function(fn_instance) => self.get_fn_addr(fn_instance), + GlobalAlloc::Function { instance, .. } => self.get_fn_addr(instance), GlobalAlloc::VTable(ty, trait_ref) => { let alloc = self .tcx From 24ab684b44fc68d9dde7d1ca285795512d521ef3 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 11 Jul 2024 18:57:56 -0400 Subject: [PATCH 013/683] Remove lang feature for type ascription --- example/mini_core.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/example/mini_core.rs b/example/mini_core.rs index a48c0a4450c..f47bfdad131 100644 --- a/example/mini_core.rs +++ b/example/mini_core.rs @@ -1,5 +1,5 @@ #![feature( - no_core, lang_items, intrinsics, unboxed_closures, type_ascription, extern_types, + no_core, lang_items, intrinsics, unboxed_closures, extern_types, decl_macro, rustc_attrs, transparent_unions, auto_traits, freeze_impls, thread_local )] From 6199de283301147369bf3bfd478ba19fe4cb3c85 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Tue, 16 Apr 2024 18:31:43 +0000 Subject: [PATCH 014/683] Sync ar_archive_writer to LLVM 18.1.3 From LLVM 15.0.0-rc3. This adds support for COFF archives containing Arm64EC object files and has various fixes for AIX big archive files. --- src/archive.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/archive.rs b/src/archive.rs index 73ff0c37b66..21676f5dbb6 100644 --- a/src/archive.rs +++ b/src/archive.rs @@ -1,7 +1,7 @@ use std::path::{Path, PathBuf}; use rustc_codegen_ssa::back::archive::{ - get_native_object_symbols, ArArchiveBuilder, ArchiveBuilder, ArchiveBuilderBuilder, + ArArchiveBuilder, ArchiveBuilder, ArchiveBuilderBuilder, DEFAULT_OBJECT_READER, }; use rustc_session::Session; @@ -11,7 +11,7 @@ pub(crate) struct ArArchiveBuilderBuilder; impl ArchiveBuilderBuilder for ArArchiveBuilderBuilder { fn new_archive_builder<'a>(&self, sess: &'a Session) -> Box { - Box::new(ArArchiveBuilder::new(sess, get_native_object_symbols)) + Box::new(ArArchiveBuilder::new(sess, &DEFAULT_OBJECT_READER)) } fn create_dll_import_lib( From f34f3c7e7fcef1c75fac9d9f8eec21101513466c Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 17 Jul 2024 20:17:44 +0200 Subject: [PATCH 015/683] Align cg_gcc rustfmt.toml with rust's --- .rustfmt.toml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.rustfmt.toml b/.rustfmt.toml index 2a35f0230c6..725aec25a07 100644 --- a/.rustfmt.toml +++ b/.rustfmt.toml @@ -1 +1,3 @@ +version = "Two" use_small_heuristics = "Max" +merge_derives = false From fd56f44836380abc2b99a9ac2776e96ff15b8ad0 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 17 Jul 2024 20:22:07 +0200 Subject: [PATCH 016/683] Format cg_gcc with same formatting parameters --- build_system/src/clone_gcc.rs | 2 +- build_system/src/config.rs | 14 +++++++------- build_system/src/test.rs | 14 +++----------- build_system/src/utils.rs | 6 +----- src/abi.rs | 6 +----- src/asm.rs | 6 +----- src/builder.rs | 18 +++--------------- src/common.rs | 6 +----- 8 files changed, 18 insertions(+), 54 deletions(-) diff --git a/build_system/src/clone_gcc.rs b/build_system/src/clone_gcc.rs index aee46afaeb0..cbf590c0c32 100644 --- a/build_system/src/clone_gcc.rs +++ b/build_system/src/clone_gcc.rs @@ -34,7 +34,7 @@ impl Args { "--out-path" => match args.next() { Some(path) if !path.is_empty() => out_path = Some(path), _ => { - return Err("Expected an argument after `--out-path`, found nothing".into()) + return Err("Expected an argument after `--out-path`, found nothing".into()); } }, "--help" => { diff --git a/build_system/src/config.rs b/build_system/src/config.rs index 965aedd8be8..bbb711c8428 100644 --- a/build_system/src/config.rs +++ b/build_system/src/config.rs @@ -54,7 +54,7 @@ impl ConfigFile { config.gcc_path = Some(value.as_str().to_string()) } ("gcc-path", _) => { - return failed_config_parsing(config_file, "Expected a string for `gcc-path`") + return failed_config_parsing(config_file, "Expected a string for `gcc-path`"); } ("download-gccjit", TomlValue::Boolean(value)) => { config.download_gccjit = Some(*value) @@ -63,7 +63,7 @@ impl ConfigFile { return failed_config_parsing( config_file, "Expected a boolean for `download-gccjit`", - ) + ); } _ => return failed_config_parsing(config_file, &format!("Unknown key `{}`", key)), } @@ -73,7 +73,7 @@ impl ConfigFile { return failed_config_parsing( config_file, "At least one of `gcc-path` or `download-gccjit` value must be set", - ) + ); } (Some(_), Some(true)) => { println!( @@ -144,7 +144,7 @@ impl ConfigInfo { _ => { return Err( "Expected a value after `--target-triple`, found nothing".to_string() - ) + ); } }, "--out-dir" => match args.next() { @@ -158,7 +158,7 @@ impl ConfigInfo { self.config_file = Some(arg.to_string()); } _ => { - return Err("Expected a value after `--config-file`, found nothing".to_string()) + return Err("Expected a value after `--config-file`, found nothing".to_string()); } }, "--release-sysroot" => self.sysroot_release_channel = true, @@ -169,7 +169,7 @@ impl ConfigInfo { self.cg_gcc_path = Some(arg.into()); } _ => { - return Err("Expected a value after `--cg_gcc-path`, found nothing".to_string()) + return Err("Expected a value after `--cg_gcc-path`, found nothing".to_string()); } }, "--use-backend" => match args.next() { @@ -277,7 +277,7 @@ impl ConfigInfo { self.gcc_path = match gcc_path { Some(path) => path, None => { - return Err(format!("missing `gcc-path` value from `{}`", config_file.display(),)) + return Err(format!("missing `gcc-path` value from `{}`", config_file.display(),)); } }; Ok(()) diff --git a/build_system/src/test.rs b/build_system/src/test.rs index 8d088a3aac3..06f28d13fb3 100644 --- a/build_system/src/test.rs +++ b/build_system/src/test.rs @@ -109,7 +109,7 @@ impl TestArg { test_arg.flags.extend_from_slice(&["--features".into(), feature]); } _ => { - return Err("Expected an argument after `--features`, found nothing".into()) + return Err("Expected an argument after `--features`, found nothing".into()); } }, "--use-system-gcc" => { @@ -458,11 +458,7 @@ fn setup_rustc(env: &mut Env, args: &TestArg) -> Result { .map_err(|error| format!("Failed to retrieve cargo path: {:?}", error)) .and_then(|cargo| { let cargo = cargo.trim().to_owned(); - if cargo.is_empty() { - Err(format!("`cargo` path is empty")) - } else { - Ok(cargo) - } + if cargo.is_empty() { Err(format!("`cargo` path is empty")) } else { Ok(cargo) } })?; let rustc = String::from_utf8( run_command_with_env(&[&"rustup", &toolchain, &"which", &"rustc"], rust_dir, Some(env))? @@ -471,11 +467,7 @@ fn setup_rustc(env: &mut Env, args: &TestArg) -> Result { .map_err(|error| format!("Failed to retrieve rustc path: {:?}", error)) .and_then(|rustc| { let rustc = rustc.trim().to_owned(); - if rustc.is_empty() { - Err(format!("`rustc` path is empty")) - } else { - Ok(rustc) - } + if rustc.is_empty() { Err(format!("`rustc` path is empty")) } else { Ok(rustc) } })?; let llvm_filecheck = match run_command_with_env( &[ diff --git a/build_system/src/utils.rs b/build_system/src/utils.rs index 3bba8df6c65..e338d1b4992 100644 --- a/build_system/src/utils.rs +++ b/build_system/src/utils.rs @@ -175,11 +175,7 @@ pub fn cargo_install(to_install: &str) -> Result<(), String> { pub fn get_os_name() -> Result { let output = run_command(&[&"uname"], None)?; let name = std::str::from_utf8(&output.stdout).unwrap_or("").trim().to_string(); - if !name.is_empty() { - Ok(name) - } else { - Err("Failed to retrieve the OS name".to_string()) - } + if !name.is_empty() { Ok(name) } else { Err("Failed to retrieve the OS name".to_string()) } } #[derive(Default, PartialEq)] diff --git a/src/abi.rs b/src/abi.rs index 166dd080cf2..0a99e7213be 100644 --- a/src/abi.rs +++ b/src/abi.rs @@ -26,11 +26,7 @@ impl<'a, 'gcc, 'tcx> AbiBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { } else { false }; - if on_stack { - param.to_lvalue().get_address(None) - } else { - param.to_rvalue() - } + if on_stack { param.to_lvalue().get_address(None) } else { param.to_rvalue() } } } diff --git a/src/asm.rs b/src/asm.rs index aa485846cd4..1da691252ab 100644 --- a/src/asm.rs +++ b/src/asm.rs @@ -858,11 +858,7 @@ fn modifier_to_gcc( InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::reg) => modifier, InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg) | InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg_low16) => { - if modifier == Some('v') { - None - } else { - modifier - } + if modifier == Some('v') { None } else { modifier } } InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::preg) => { unreachable!("clobber-only") diff --git a/src/builder.rs b/src/builder.rs index 38e147599c9..a7c16d971a9 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -1030,11 +1030,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { let llty = place.layout.scalar_pair_element_gcc_type(self, i); let load = self.load(llty, llptr, align); scalar_load_metadata(self, load, scalar); - if scalar.is_bool() { - self.trunc(load, self.type_i1()) - } else { - load - } + if scalar.is_bool() { self.trunc(load, self.type_i1()) } else { load } }; OperandValue::Pair( @@ -1782,18 +1778,10 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { // This already happens today with u128::MAX = 2^128 - 1 > f32::MAX. let int_max = |signed: bool, int_width: u64| -> u128 { let shift_amount = 128 - int_width; - if signed { - i128::MAX as u128 >> shift_amount - } else { - u128::MAX >> shift_amount - } + if signed { i128::MAX as u128 >> shift_amount } else { u128::MAX >> shift_amount } }; let int_min = |signed: bool, int_width: u64| -> i128 { - if signed { - i128::MIN >> (128 - int_width) - } else { - 0 - } + if signed { i128::MIN >> (128 - int_width) } else { 0 } }; let compute_clamp_bounds_single = |signed: bool, int_width: u64| -> (u128, u128) { diff --git a/src/common.rs b/src/common.rs index 19333689aaa..70f0dc37e39 100644 --- a/src/common.rs +++ b/src/common.rs @@ -58,11 +58,7 @@ pub fn type_is_pointer(typ: Type<'_>) -> bool { impl<'gcc, 'tcx> ConstMethods<'tcx> for CodegenCx<'gcc, 'tcx> { fn const_null(&self, typ: Type<'gcc>) -> RValue<'gcc> { - if type_is_pointer(typ) { - self.context.new_null(typ) - } else { - self.const_int(typ, 0) - } + if type_is_pointer(typ) { self.context.new_null(typ) } else { self.const_int(typ, 0) } } fn const_undef(&self, typ: Type<'gcc>) -> RValue<'gcc> { From 88f7508da770c6951f9121c5c7cd7de3951f9dd3 Mon Sep 17 00:00:00 2001 From: Slanterns Date: Sun, 28 Jul 2024 01:28:39 +0800 Subject: [PATCH 017/683] stabilize `is_sorted` --- example/std_example.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/example/std_example.rs b/example/std_example.rs index 8ab8fcc525e..9e43b4635f0 100644 --- a/example/std_example.rs +++ b/example/std_example.rs @@ -1,5 +1,5 @@ #![allow(internal_features)] -#![feature(core_intrinsics, coroutines, coroutine_trait, is_sorted, stmt_expr_attributes)] +#![feature(core_intrinsics, coroutines, coroutine_trait, stmt_expr_attributes)] #[cfg(feature="master")] #[cfg(target_arch="x86_64")] From 1cbbac391100028e2ebb871b81f543ddca243dc9 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 29 Jul 2024 08:13:50 +1000 Subject: [PATCH 018/683] Reformat `use` declarations. The previous commit updated `rustfmt.toml` appropriately. This commit is the outcome of running `x fmt --all` with the new formatting options. --- build_system/src/build.rs | 9 +++++---- build_system/src/clean.rs | 4 ++-- build_system/src/clone_gcc.rs | 4 ++-- build_system/src/config.rs | 15 ++++++++------- build_system/src/fmt.rs | 3 ++- build_system/src/main.rs | 3 +-- build_system/src/prepare.rs | 6 +++--- build_system/src/rust_tools.rs | 8 ++++---- build_system/src/test.rs | 14 +++++++------- src/archive.rs | 3 +-- src/asm.rs | 8 ++++---- src/attributes.rs | 3 ++- src/base.rs | 3 +-- src/builder.rs | 5 ++--- src/common.rs | 3 +-- src/consts.rs | 3 +-- src/context.rs | 11 +++++------ src/debuginfo.rs | 3 ++- src/gcc_util.rs | 3 +-- src/int.rs | 19 ++++++++----------- src/intrinsic/llvm.rs | 3 ++- src/intrinsic/simd.rs | 4 +--- src/lib.rs | 9 +++------ src/mono_item.rs | 3 +-- 24 files changed, 69 insertions(+), 80 deletions(-) diff --git a/build_system/src/build.rs b/build_system/src/build.rs index d465ab7e506..8d23f1fda80 100644 --- a/build_system/src/build.rs +++ b/build_system/src/build.rs @@ -1,12 +1,13 @@ -use crate::config::{Channel, ConfigInfo}; -use crate::utils::{ - copy_file, create_dir, get_sysroot_dir, run_command, run_command_with_output_and_env, walk_dir, -}; use std::collections::HashMap; use std::ffi::OsStr; use std::fs; use std::path::Path; +use crate::config::{Channel, ConfigInfo}; +use crate::utils::{ + copy_file, create_dir, get_sysroot_dir, run_command, run_command_with_output_and_env, walk_dir, +}; + #[derive(Default)] struct BuildArg { flags: Vec, diff --git a/build_system/src/clean.rs b/build_system/src/clean.rs index 55f55acf73e..768a78e789e 100644 --- a/build_system/src/clean.rs +++ b/build_system/src/clean.rs @@ -1,8 +1,8 @@ -use crate::utils::{get_sysroot_dir, remove_file, run_command}; - use std::fs::remove_dir_all; use std::path::Path; +use crate::utils::{get_sysroot_dir, remove_file, run_command}; + #[derive(Default)] enum CleanArg { /// `clean all` diff --git a/build_system/src/clone_gcc.rs b/build_system/src/clone_gcc.rs index cbf590c0c32..e28ee873eb6 100644 --- a/build_system/src/clone_gcc.rs +++ b/build_system/src/clone_gcc.rs @@ -1,8 +1,8 @@ +use std::path::{Path, PathBuf}; + use crate::config::ConfigInfo; use crate::utils::{git_clone, run_command_with_output}; -use std::path::{Path, PathBuf}; - fn show_usage() { println!( r#" diff --git a/build_system/src/config.rs b/build_system/src/config.rs index bbb711c8428..15ba1612167 100644 --- a/build_system/src/config.rs +++ b/build_system/src/config.rs @@ -1,14 +1,15 @@ +use std::collections::HashMap; +use std::ffi::OsStr; +use std::path::{Path, PathBuf}; +use std::{env as std_env, fs}; + +use boml::types::TomlValue; +use boml::Toml; + use crate::utils::{ create_dir, create_symlink, get_os_name, get_sysroot_dir, run_command_with_output, rustc_version_info, split_args, }; -use std::collections::HashMap; -use std::env as std_env; -use std::ffi::OsStr; -use std::fs; -use std::path::{Path, PathBuf}; - -use boml::{types::TomlValue, Toml}; #[derive(Default, PartialEq, Eq, Clone, Copy, Debug)] pub enum Channel { diff --git a/build_system/src/fmt.rs b/build_system/src/fmt.rs index 43644ba19b3..de310a6a30f 100644 --- a/build_system/src/fmt.rs +++ b/build_system/src/fmt.rs @@ -1,7 +1,8 @@ -use crate::utils::run_command_with_output; use std::ffi::OsStr; use std::path::Path; +use crate::utils::run_command_with_output; + fn show_usage() { println!( r#" diff --git a/build_system/src/main.rs b/build_system/src/main.rs index d678fd75344..3a860e2b136 100644 --- a/build_system/src/main.rs +++ b/build_system/src/main.rs @@ -1,5 +1,4 @@ -use std::env; -use std::process; +use std::{env, process}; mod build; mod clean; diff --git a/build_system/src/prepare.rs b/build_system/src/prepare.rs index 00aa632165e..d14639afee5 100644 --- a/build_system/src/prepare.rs +++ b/build_system/src/prepare.rs @@ -1,12 +1,12 @@ +use std::fs; +use std::path::{Path, PathBuf}; + use crate::rustc_info::get_rustc_path; use crate::utils::{ cargo_install, create_dir, get_sysroot_dir, git_clone_root_dir, remove_file, run_command, run_command_with_output, walk_dir, }; -use std::fs; -use std::path::{Path, PathBuf}; - fn prepare_libcore( sysroot_path: &Path, libgccjit12_patches: bool, diff --git a/build_system/src/rust_tools.rs b/build_system/src/rust_tools.rs index 242fa7ef949..105f5eebe24 100644 --- a/build_system/src/rust_tools.rs +++ b/build_system/src/rust_tools.rs @@ -1,13 +1,13 @@ +use std::collections::HashMap; +use std::ffi::OsStr; +use std::path::PathBuf; + use crate::config::ConfigInfo; use crate::utils::{ get_toolchain, run_command_with_output_and_env_no_err, rustc_toolchain_version_info, rustc_version_info, }; -use std::collections::HashMap; -use std::ffi::OsStr; -use std::path::PathBuf; - fn args(command: &str) -> Result>, String> { // We skip the binary and the "cargo"/"rustc" option. if let Some("--help") = std::env::args().skip(2).next().as_deref() { diff --git a/build_system/src/test.rs b/build_system/src/test.rs index 06f28d13fb3..dabf6c5aa3e 100644 --- a/build_system/src/test.rs +++ b/build_system/src/test.rs @@ -1,3 +1,10 @@ +use std::collections::HashMap; +use std::ffi::OsStr; +use std::fs::{remove_dir_all, File}; +use std::io::{BufRead, BufReader}; +use std::path::{Path, PathBuf}; +use std::str::FromStr; + use crate::build; use crate::config::{Channel, ConfigInfo}; use crate::utils::{ @@ -6,13 +13,6 @@ use crate::utils::{ split_args, walk_dir, }; -use std::collections::HashMap; -use std::ffi::OsStr; -use std::fs::{remove_dir_all, File}; -use std::io::{BufRead, BufReader}; -use std::path::{Path, PathBuf}; -use std::str::FromStr; - type Env = HashMap; type Runner = fn(&Env, &TestArg) -> Result<(), String>; type Runners = HashMap<&'static str, (&'static str, Runner)>; diff --git a/src/archive.rs b/src/archive.rs index 21676f5dbb6..36f5e0f8094 100644 --- a/src/archive.rs +++ b/src/archive.rs @@ -3,9 +3,8 @@ use std::path::{Path, PathBuf}; use rustc_codegen_ssa::back::archive::{ ArArchiveBuilder, ArchiveBuilder, ArchiveBuilderBuilder, DEFAULT_OBJECT_READER, }; -use rustc_session::Session; - use rustc_session::cstore::DllImport; +use rustc_session::Session; pub(crate) struct ArArchiveBuilderBuilder; diff --git a/src/asm.rs b/src/asm.rs index 1da691252ab..7c135289958 100644 --- a/src/asm.rs +++ b/src/asm.rs @@ -1,3 +1,5 @@ +use std::borrow::Cow; + use gccjit::{LValue, RValue, ToRValue, Type}; use rustc_ast::ast::{InlineAsmOptions, InlineAsmTemplatePiece}; use rustc_codegen_ssa::mir::operand::OperandValue; @@ -6,13 +8,11 @@ use rustc_codegen_ssa::traits::{ AsmBuilderMethods, AsmMethods, BaseTypeMethods, BuilderMethods, GlobalAsmOperandRef, InlineAsmOperandRef, }; - -use rustc_middle::{bug, ty::Instance}; +use rustc_middle::bug; +use rustc_middle::ty::Instance; use rustc_span::Span; use rustc_target::asm::*; -use std::borrow::Cow; - use crate::builder::Builder; use crate::callee::get_fn; use crate::context::CodegenCx; diff --git a/src/attributes.rs b/src/attributes.rs index 27f21107eda..e521551304e 100644 --- a/src/attributes.rs +++ b/src/attributes.rs @@ -9,8 +9,9 @@ use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::ty; use rustc_span::symbol::sym; +use crate::context::CodegenCx; +use crate::errors::TiedTargetFeatures; use crate::gcc_util::{check_tied_features, to_gcc_features}; -use crate::{context::CodegenCx, errors::TiedTargetFeatures}; /// Get GCC attribute for the provided inline heuristic. #[cfg(feature = "master")] diff --git a/src/base.rs b/src/base.rs index e3558b6b875..2eaab3ed00c 100644 --- a/src/base.rs +++ b/src/base.rs @@ -19,8 +19,7 @@ use rustc_target::spec::PanicStrategy; use crate::builder::Builder; use crate::context::CodegenCx; -use crate::{gcc_util, new_context, LockedTargetInfo}; -use crate::{GccContext, SyncContext}; +use crate::{gcc_util, new_context, GccContext, LockedTargetInfo, SyncContext}; #[cfg(feature = "master")] pub fn visibility_to_gcc(linkage: Visibility) -> gccjit::Visibility { diff --git a/src/builder.rs b/src/builder.rs index a7c16d971a9..eabdf0d8342 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -28,9 +28,8 @@ use rustc_middle::ty::layout::{ use rustc_middle::ty::{Instance, ParamEnv, Ty, TyCtxt}; use rustc_span::def_id::DefId; use rustc_span::Span; -use rustc_target::abi::{ - self, call::FnAbi, Align, HasDataLayout, Size, TargetDataLayout, WrappingRange, -}; +use rustc_target::abi::call::FnAbi; +use rustc_target::abi::{self, Align, HasDataLayout, Size, TargetDataLayout, WrappingRange}; use rustc_target::spec::{HasTargetSpec, HasWasmCAbiOpt, Target, WasmCAbi}; use crate::common::{type_is_pointer, SignType, TypeReflection}; diff --git a/src/common.rs b/src/common.rs index 70f0dc37e39..7a456e1c5d6 100644 --- a/src/common.rs +++ b/src/common.rs @@ -1,5 +1,4 @@ -use gccjit::LValue; -use gccjit::{RValue, ToRValue, Type}; +use gccjit::{LValue, RValue, ToRValue, Type}; use rustc_codegen_ssa::traits::{BaseTypeMethods, ConstMethods, MiscMethods, StaticMethods}; use rustc_middle::mir::interpret::{ConstAllocation, GlobalAlloc, Scalar}; use rustc_middle::mir::Mutability; diff --git a/src/consts.rs b/src/consts.rs index ba7e08e33ef..e5673cddc4a 100644 --- a/src/consts.rs +++ b/src/consts.rs @@ -3,14 +3,13 @@ use gccjit::{FnAttribute, VarAttribute, Visibility}; use gccjit::{Function, GlobalKind, LValue, RValue, ToRValue, Type}; use rustc_codegen_ssa::traits::{BaseTypeMethods, ConstMethods, StaticMethods}; use rustc_hir::def::DefKind; -use rustc_middle::bug; use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs}; use rustc_middle::mir::interpret::{ self, read_target_uint, ConstAllocation, ErrorHandled, Scalar as InterpScalar, }; -use rustc_middle::span_bug; use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::{self, Instance}; +use rustc_middle::{bug, span_bug}; use rustc_span::def_id::DefId; use rustc_target::abi::{self, Align, HasDataLayout, Primitive, Size, WrappingRange}; diff --git a/src/context.rs b/src/context.rs index 86a5000a723..e330102fbd8 100644 --- a/src/context.rs +++ b/src/context.rs @@ -6,8 +6,7 @@ use gccjit::{ use rustc_codegen_ssa::base::wants_msvc_seh; use rustc_codegen_ssa::errors as ssa_errors; use rustc_codegen_ssa::traits::{BackendTypes, BaseTypeMethods, MiscMethods}; -use rustc_data_structures::base_n::ToBaseN; -use rustc_data_structures::base_n::ALPHANUMERIC_ONLY; +use rustc_data_structures::base_n::{ToBaseN, ALPHANUMERIC_ONLY}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_middle::mir::mono::CodegenUnit; use rustc_middle::span_bug; @@ -17,10 +16,10 @@ use rustc_middle::ty::layout::{ }; use rustc_middle::ty::{self, Instance, ParamEnv, PolyExistentialTraitRef, Ty, TyCtxt}; use rustc_session::Session; -use rustc_span::{source_map::respan, Span, DUMMY_SP}; -use rustc_target::abi::{ - call::FnAbi, HasDataLayout, PointeeInfo, Size, TargetDataLayout, VariantIdx, -}; +use rustc_span::source_map::respan; +use rustc_span::{Span, DUMMY_SP}; +use rustc_target::abi::call::FnAbi; +use rustc_target::abi::{HasDataLayout, PointeeInfo, Size, TargetDataLayout, VariantIdx}; use rustc_target::spec::{HasTargetSpec, HasWasmCAbiOpt, Target, TlsModel, WasmCAbi}; use crate::callee::get_fn; diff --git a/src/debuginfo.rs b/src/debuginfo.rs index 3d9ea278a63..d770da5a8c4 100644 --- a/src/debuginfo.rs +++ b/src/debuginfo.rs @@ -1,3 +1,5 @@ +use std::ops::Range; + use gccjit::{Location, RValue}; use rustc_codegen_ssa::mir::debuginfo::{DebugScope, FunctionDebugContext, VariableKind}; use rustc_codegen_ssa::traits::{DebugInfoBuilderMethods, DebugInfoMethods}; @@ -10,7 +12,6 @@ use rustc_session::config::DebugInfo; use rustc_span::{BytePos, Pos, SourceFile, SourceFileAndLine, Span, Symbol}; use rustc_target::abi::call::FnAbi; use rustc_target::abi::Size; -use std::ops::Range; use crate::builder::Builder; use crate::context::CodegenCx; diff --git a/src/gcc_util.rs b/src/gcc_util.rs index 53877e8ff7f..8bb90efe6fb 100644 --- a/src/gcc_util.rs +++ b/src/gcc_util.rs @@ -1,11 +1,10 @@ #[cfg(feature = "master")] use gccjit::Context; -use smallvec::{smallvec, SmallVec}; - use rustc_data_structures::fx::FxHashMap; use rustc_middle::bug; use rustc_session::Session; use rustc_target::target_features::RUSTC_SPECIFIC_FEATURES; +use smallvec::{smallvec, SmallVec}; use crate::errors::{ PossibleFeature, TargetFeatureDisableOrEnable, UnknownCTargetFeature, diff --git a/src/int.rs b/src/int.rs index e4c5eb91373..92d5c1cbbb8 100644 --- a/src/int.rs +++ b/src/int.rs @@ -6,18 +6,13 @@ use gccjit::{BinaryOp, ComparisonOp, FunctionType, Location, RValue, ToRValue, T use rustc_codegen_ssa::common::{IntPredicate, TypeKind}; use rustc_codegen_ssa::traits::{BackendTypes, BaseTypeMethods, BuilderMethods, OverflowOp}; use rustc_middle::ty::{ParamEnv, Ty}; -use rustc_target::abi::{ - call::{ArgAbi, ArgAttributes, Conv, FnAbi, PassMode}, - Endian, -}; +use rustc_target::abi::call::{ArgAbi, ArgAttributes, Conv, FnAbi, PassMode}; +use rustc_target::abi::Endian; use rustc_target::spec; -use crate::builder::ToGccComp; -use crate::{ - builder::Builder, - common::{SignType, TypeReflection}, - context::CodegenCx, -}; +use crate::builder::{Builder, ToGccComp}; +use crate::common::{SignType, TypeReflection}; +use crate::context::CodegenCx; impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { pub fn gcc_urem(&self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { @@ -266,7 +261,9 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { lhs: ::Value, rhs: ::Value, ) -> (::Value, ::Value) { - use rustc_middle::ty::{Int, IntTy::*, Uint, UintTy::*}; + use rustc_middle::ty::IntTy::*; + use rustc_middle::ty::UintTy::*; + use rustc_middle::ty::{Int, Uint}; let new_kind = match *typ.kind() { Int(t @ Isize) => Int(t.normalize(self.tcx.sess.target.pointer_width)), diff --git a/src/intrinsic/llvm.rs b/src/intrinsic/llvm.rs index a1270482219..554e57250e6 100644 --- a/src/intrinsic/llvm.rs +++ b/src/intrinsic/llvm.rs @@ -3,7 +3,8 @@ use std::borrow::Cow; use gccjit::{Function, FunctionPtrType, RValue, ToRValue, UnaryOp}; use rustc_codegen_ssa::traits::BuilderMethods; -use crate::{builder::Builder, context::CodegenCx}; +use crate::builder::Builder; +use crate::context::CodegenCx; pub fn adjust_intrinsic_arguments<'a, 'b, 'gcc, 'tcx>( builder: &Builder<'a, 'gcc, 'tcx>, diff --git a/src/intrinsic/simd.rs b/src/intrinsic/simd.rs index ba214a9c24c..8da1df3be15 100644 --- a/src/intrinsic/simd.rs +++ b/src/intrinsic/simd.rs @@ -1,10 +1,8 @@ use std::iter::FromIterator; -use gccjit::ToRValue; -use gccjit::{BinaryOp, RValue, Type}; +use gccjit::{BinaryOp, RValue, ToRValue, Type}; #[cfg(feature = "master")] use gccjit::{ComparisonOp, UnaryOp}; - use rustc_codegen_ssa::base::compare_simd_types; use rustc_codegen_ssa::common::{IntPredicate, TypeKind}; #[cfg(feature = "master")] diff --git a/src/lib.rs b/src/lib.rs index 1132b0cd2f5..cd63a405b67 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -79,14 +79,11 @@ use std::ops::Deref; use std::sync::atomic::AtomicBool; #[cfg(not(feature = "master"))] use std::sync::atomic::Ordering; -use std::sync::Arc; -use std::sync::Mutex; +use std::sync::{Arc, Mutex}; -use back::lto::ThinBuffer; -use back::lto::ThinData; +use back::lto::{ThinBuffer, ThinData}; use errors::LTONotSupported; -use gccjit::CType; -use gccjit::{Context, OptimizationLevel}; +use gccjit::{CType, Context, OptimizationLevel}; #[cfg(feature = "master")] use gccjit::{TargetInfo, Version}; use rustc_ast::expand::allocator::AllocatorKind; diff --git a/src/mono_item.rs b/src/mono_item.rs index 44657ad4f6e..e6b22d51871 100644 --- a/src/mono_item.rs +++ b/src/mono_item.rs @@ -9,10 +9,9 @@ use rustc_middle::mir::mono::{Linkage, Visibility}; use rustc_middle::ty::layout::{FnAbiOf, LayoutOf}; use rustc_middle::ty::{self, Instance, TypeVisitableExt}; -use crate::attributes; -use crate::base; use crate::context::CodegenCx; use crate::type_of::LayoutGccExt; +use crate::{attributes, base}; impl<'gcc, 'tcx> PreDefineMethods<'tcx> for CodegenCx<'gcc, 'tcx> { #[cfg_attr(not(feature = "master"), allow(unused_variables))] From 78f5ee65183e816d2cb0499c6766591fc234d8f7 Mon Sep 17 00:00:00 2001 From: Nicholas Bishop Date: Sat, 11 May 2024 09:56:59 -0400 Subject: [PATCH 019/683] Update compiler_builtins to 0.1.114 The `weak-intrinsics` feature was removed from compiler_builtins in https://github.com/rust-lang/compiler-builtins/pull/598, so dropped the `compiler-builtins-weak-intrinsics` feature from alloc/std/sysroot. In https://github.com/rust-lang/compiler-builtins/pull/593, some builtins for f16/f128 were added. These don't work for all compiler backends, so add a `compiler-builtins-no-f16-f128` feature and disable it for cranelift and gcc. Also disable it for LLVM targets that don't support it. --- build_system/src/build.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/build_system/src/build.rs b/build_system/src/build.rs index 8d23f1fda80..8d9518653c5 100644 --- a/build_system/src/build.rs +++ b/build_system/src/build.rs @@ -142,7 +142,14 @@ pub fn build_sysroot(env: &HashMap, config: &ConfigInfo) -> Resu rustflags.push_str(" -Csymbol-mangling-version=v0"); } - let mut args: Vec<&dyn AsRef> = vec![&"cargo", &"build", &"--target", &config.target]; + let mut args: Vec<&dyn AsRef> = vec![ + &"cargo", + &"build", + &"--target", + &config.target, + &"--features", + &"compiler-builtins-no-f16-f128", + ]; if config.no_default_features { rustflags.push_str(" -Csymbol-mangling-version=v0"); From c57eb5581fe407f364df5812416190b241e8a8bb Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 25 Jul 2024 19:53:17 +0000 Subject: [PATCH 020/683] Move temp file name generation out of the create_dll_import_lib method --- src/archive.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/archive.rs b/src/archive.rs index 36f5e0f8094..4a54d26daf7 100644 --- a/src/archive.rs +++ b/src/archive.rs @@ -1,4 +1,4 @@ -use std::path::{Path, PathBuf}; +use std::path::Path; use rustc_codegen_ssa::back::archive::{ ArArchiveBuilder, ArchiveBuilder, ArchiveBuilderBuilder, DEFAULT_OBJECT_READER, @@ -18,9 +18,8 @@ impl ArchiveBuilderBuilder for ArArchiveBuilderBuilder { _sess: &Session, _lib_name: &str, _dll_imports: &[DllImport], - _tmpdir: &Path, - _is_direct_dependency: bool, - ) -> PathBuf { + _output_path: &Path, + ) { unimplemented!("creating dll imports is not yet supported"); } } From 50b374627fc319d26ec96d5e477685614f6575a2 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 25 Jul 2024 20:08:40 +0000 Subject: [PATCH 021/683] Move computation of decorated names out of the create_dll_import_lib method --- src/archive.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/archive.rs b/src/archive.rs index 4a54d26daf7..0cee05f1cea 100644 --- a/src/archive.rs +++ b/src/archive.rs @@ -3,7 +3,6 @@ use std::path::Path; use rustc_codegen_ssa::back::archive::{ ArArchiveBuilder, ArchiveBuilder, ArchiveBuilderBuilder, DEFAULT_OBJECT_READER, }; -use rustc_session::cstore::DllImport; use rustc_session::Session; pub(crate) struct ArArchiveBuilderBuilder; @@ -17,7 +16,7 @@ impl ArchiveBuilderBuilder for ArArchiveBuilderBuilder { &self, _sess: &Session, _lib_name: &str, - _dll_imports: &[DllImport], + _import_name_and_ordinal_vector: Vec<(String, Option)>, _output_path: &Path, ) { unimplemented!("creating dll imports is not yet supported"); From e80199cc7955f6eb972371b1651528e3ea76554c Mon Sep 17 00:00:00 2001 From: Caleb Zulawski Date: Fri, 2 Aug 2024 00:20:49 -0400 Subject: [PATCH 022/683] Refactor and fill out target feature lists --- src/gcc_util.rs | 4 ++-- src/lib.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/gcc_util.rs b/src/gcc_util.rs index 8bb90efe6fb..5308ccdb614 100644 --- a/src/gcc_util.rs +++ b/src/gcc_util.rs @@ -65,8 +65,8 @@ pub(crate) fn global_gcc_features(sess: &Session, diagnostics: bool) -> Vec Date: Sun, 4 Aug 2024 23:51:59 -0400 Subject: [PATCH 023/683] Hide implicit target features from diagnostics when possible --- src/attributes.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/attributes.rs b/src/attributes.rs index e521551304e..5fdf2680aac 100644 --- a/src/attributes.rs +++ b/src/attributes.rs @@ -75,7 +75,7 @@ pub fn from_fn_attrs<'gcc, 'tcx>( let function_features = codegen_fn_attrs .target_features .iter() - .map(|features| features.as_str()) + .map(|features| features.name.as_str()) .collect::>(); if let Some(features) = check_tied_features( From f824fb6d9fe1b4c5166d4c46f1ea928d3e771f12 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 8 Aug 2024 14:42:44 +0200 Subject: [PATCH 024/683] Update compiler-builtins version to 0.1.118 --- build_system/build_sysroot/Cargo.lock | 2 +- build_system/build_sysroot/Cargo.toml | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/build_system/build_sysroot/Cargo.lock b/build_system/build_sysroot/Cargo.lock index d6ec1f87d01..771f2f18dce 100644 --- a/build_system/build_sysroot/Cargo.lock +++ b/build_system/build_sysroot/Cargo.lock @@ -50,7 +50,7 @@ dependencies = [ [[package]] name = "compiler_builtins" -version = "0.1.109" +version = "0.1.118" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f11973008a8cf741fe6d22f339eba21fd0ca81e2760a769ba8243ed6c21edd7e" dependencies = [ diff --git a/build_system/build_sysroot/Cargo.toml b/build_system/build_sysroot/Cargo.toml index e4669923623..05503128f2a 100644 --- a/build_system/build_sysroot/Cargo.toml +++ b/build_system/build_sysroot/Cargo.toml @@ -6,9 +6,7 @@ resolver = "2" [dependencies] core = { path = "./sysroot_src/library/core" } -# TODO: after the sync, revert to using version 0.1. -# compiler_builtins = "0.1" -compiler_builtins = "=0.1.109" +compiler_builtins = "0.1" alloc = { path = "./sysroot_src/library/alloc" } std = { path = "./sysroot_src/library/std", features = ["panic_unwind", "backtrace"] } test = { path = "./sysroot_src/library/test" } From b373147918786ea7919ace6b47a9f0ce9b66e0f2 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Wed, 20 Mar 2024 22:51:29 +0100 Subject: [PATCH 025/683] Fixes in various places --- example/mini_core_hello_world.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/example/mini_core_hello_world.rs b/example/mini_core_hello_world.rs index 5a7ddc4cd7f..9f096e90220 100644 --- a/example/mini_core_hello_world.rs +++ b/example/mini_core_hello_world.rs @@ -430,6 +430,7 @@ pub enum E2 { V4, } +#[allow(unreachable_patterns)] fn check_niche_behavior () { if let E1::V2 { .. } = (E1::V1 { f: true }) { intrinsics::abort(); From 8bd9b48e7ecc308ff680414049972180476dca78 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 12 Aug 2024 15:11:51 +0200 Subject: [PATCH 026/683] Update compiler version to nightly-2024-08-11 --- rust-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain b/rust-toolchain index 3c83f4b4608..dca3b0c22e4 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2024-07-02" +channel = "nightly-2024-08-11" components = ["rust-src", "rustc-dev", "llvm-tools-preview"] From dd76ad45b381680f26d327a42fa4cb1d1ccf6842 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 6 Aug 2024 14:35:59 +0200 Subject: [PATCH 027/683] Fix libcore patch --- patches/0022-core-Disable-not-compiling-tests.patch | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/patches/0022-core-Disable-not-compiling-tests.patch b/patches/0022-core-Disable-not-compiling-tests.patch index ea1a5a8d355..08e2f1a7628 100644 --- a/patches/0022-core-Disable-not-compiling-tests.patch +++ b/patches/0022-core-Disable-not-compiling-tests.patch @@ -35,8 +35,9 @@ diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index 42a26ae..5ac1042 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs -@@ -1,3 +1,4 @@ +@@ -2,4 +2,5 @@ + // tidy-alphabetical-start +#![cfg(test)] - #![feature(alloc_layout_extra)] - #![feature(array_chunks)] - #![feature(array_ptr_get)] + #![cfg_attr(bootstrap, feature(offset_of_nested))] + #![cfg_attr(target_has_atomic = "128", feature(integer_atomics))] + #![cfg_attr(test, feature(cfg_match))] From 8643c13e547ebf80d6ac2ea167582235084d926c Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 6 Aug 2024 14:44:49 +0200 Subject: [PATCH 028/683] Fix patch `libgccjit12/0001-core-Disable-portable-simd-test.patch` --- .../0001-core-Disable-portable-simd-test.patch | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/patches/libgccjit12/0001-core-Disable-portable-simd-test.patch b/patches/libgccjit12/0001-core-Disable-portable-simd-test.patch index c060300f44f..da664d51b63 100644 --- a/patches/libgccjit12/0001-core-Disable-portable-simd-test.patch +++ b/patches/libgccjit12/0001-core-Disable-portable-simd-test.patch @@ -11,15 +11,15 @@ diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index b71786c..cf484d5 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs -@@ -95,7 +95,6 @@ - #![feature(never_type)] - #![feature(unwrap_infallible)] +@@ -87,7 +87,6 @@ + #![feature(numfmt)] + #![feature(pattern)] #![feature(pointer_is_aligned_to)] -#![feature(portable_simd)] #![feature(ptr_metadata)] - #![feature(unsized_tuple_coercion)] - #![feature(const_option)] -@@ -157,7 +156,6 @@ mod pin; + #![feature(slice_from_ptr_range)] + #![feature(slice_internals)] +@@ -155,7 +154,6 @@ mod pin; mod pin_macro; mod ptr; mod result; From fb6118b824349fe77870cdad85da32d5c73c623a Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 6 Aug 2024 15:00:15 +0200 Subject: [PATCH 029/683] Rename `compiler-builtins-no-f16-f128` into `std/compiler-builtins-no-f16-f128` --- build_system/src/build.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build_system/src/build.rs b/build_system/src/build.rs index 8d9518653c5..3f88945767d 100644 --- a/build_system/src/build.rs +++ b/build_system/src/build.rs @@ -148,7 +148,7 @@ pub fn build_sysroot(env: &HashMap, config: &ConfigInfo) -> Resu &"--target", &config.target, &"--features", - &"compiler-builtins-no-f16-f128", + &"std/compiler-builtins-no-f16-f128", ]; if config.no_default_features { From 3b45cf476aea28edd0b7aa2cf6ed78eb79abdbf6 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 12 Aug 2024 16:09:54 +0200 Subject: [PATCH 030/683] Update sysroot Cargo.lock --- build_system/build_sysroot/Cargo.lock | 99 +++++++++++++++------------ 1 file changed, 54 insertions(+), 45 deletions(-) diff --git a/build_system/build_sysroot/Cargo.lock b/build_system/build_sysroot/Cargo.lock index 771f2f18dce..51bec5aa9e3 100644 --- a/build_system/build_sysroot/Cargo.lock +++ b/build_system/build_sysroot/Cargo.lock @@ -4,12 +4,12 @@ version = 3 [[package]] name = "addr2line" -version = "0.21.0" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" +checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678" dependencies = [ "compiler_builtins", - "gimli", + "gimli 0.29.0", "rustc-std-workspace-alloc", "rustc-std-workspace-core", ] @@ -52,7 +52,7 @@ dependencies = [ name = "compiler_builtins" version = "0.1.118" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f11973008a8cf741fe6d22f339eba21fd0ca81e2760a769ba8243ed6c21edd7e" +checksum = "92afe7344b64cccf3662ca26d5d1c0828ab826f04206b97d856e3625e390e4b5" dependencies = [ "rustc-std-workspace-core", ] @@ -97,9 +97,20 @@ dependencies = [ [[package]] name = "gimli" -version = "0.28.1" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" +checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" +dependencies = [ + "compiler_builtins", + "rustc-std-workspace-alloc", + "rustc-std-workspace-core", +] + +[[package]] +name = "gimli" +version = "0.30.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2e1d97fbe9722ba9bbd0c97051c2956e726562b61f86a25a4360398a40edfc9" dependencies = [ "compiler_builtins", "rustc-std-workspace-alloc", @@ -120,9 +131,9 @@ dependencies = [ [[package]] name = "hermit-abi" -version = "0.3.9" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" +checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" dependencies = [ "compiler_builtins", "rustc-std-workspace-alloc", @@ -131,18 +142,18 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.153" +version = "0.2.155" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" +checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" dependencies = [ "rustc-std-workspace-core", ] [[package]] name = "memchr" -version = "2.7.2" +version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" dependencies = [ "compiler_builtins", "rustc-std-workspace-core", @@ -150,9 +161,9 @@ dependencies = [ [[package]] name = "miniz_oxide" -version = "0.7.2" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7" +checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" dependencies = [ "adler", "compiler_builtins", @@ -162,9 +173,9 @@ dependencies = [ [[package]] name = "object" -version = "0.32.2" +version = "0.36.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" +checksum = "27b64972346851a39438c60b341ebc01bba47464ae329e55cf343eb93964efd9" dependencies = [ "compiler_builtins", "memchr", @@ -205,9 +216,9 @@ dependencies = [ [[package]] name = "r-efi" -version = "4.4.0" +version = "4.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c47196f636c4cc0634b73b0405323d177753c2e15e866952c64ea22902567a34" +checksum = "e9e935efc5854715dfc0a4c9ef18dc69dee0ec3bf9cc3ab740db831c0fdd86a3" dependencies = [ "compiler_builtins", "rustc-std-workspace-core", @@ -226,9 +237,9 @@ dependencies = [ [[package]] name = "rustc-demangle" -version = "0.1.23" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" dependencies = [ "compiler_builtins", "rustc-std-workspace-core", @@ -310,16 +321,14 @@ dependencies = [ "core", "getopts", "libc", - "panic_abort", - "panic_unwind", "std", ] [[package]] name = "unicode-width" -version = "0.1.12" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68f5e5f3158ecfd4b8ff6fe086db7c8467a2dfdac97fe420f2b7c4aa97af66d6" +checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d" dependencies = [ "compiler_builtins", "rustc-std-workspace-core", @@ -339,12 +348,12 @@ dependencies = [ [[package]] name = "unwinding" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37a19a21a537f635c16c7576f22d0f2f7d63353c1337ad4ce0d8001c7952a25b" +checksum = "dc55842d0db6329a669d55a623c674b02d677b16bfb2d24857d4089d41eba882" dependencies = [ "compiler_builtins", - "gimli", + "gimli 0.30.0", "rustc-std-workspace-core", ] @@ -370,9 +379,9 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ "windows_aarch64_gnullvm", "windows_aarch64_msvc", @@ -386,48 +395,48 @@ dependencies = [ [[package]] name = "windows_aarch64_gnullvm" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_msvc" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_i686_gnu" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" [[package]] name = "windows_i686_gnullvm" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_msvc" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_x86_64_gnu" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_msvc" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" From afb14f75e183b7f746984c1f0a9d55dee0e9e34e Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 12 Aug 2024 16:28:27 +0200 Subject: [PATCH 031/683] Unpin compiler-builtins Co-authored-by: Antoni Boucher --- .github/workflows/m68k.yml | 6 ++--- build_system/build_sysroot/Cargo.toml | 16 +++++++++++++ build_system/src/build.rs | 15 ++++-------- build_system/src/config.rs | 11 ++++++++- build_system/src/test.rs | 13 +++++++++- src/context.rs | 34 --------------------------- src/intrinsic/mod.rs | 21 ++++++----------- src/intrinsic/simd.rs | 7 ++---- 8 files changed, 54 insertions(+), 69 deletions(-) diff --git a/.github/workflows/m68k.yml b/.github/workflows/m68k.yml index 34e4f2b0d41..2c824d1a676 100644 --- a/.github/workflows/m68k.yml +++ b/.github/workflows/m68k.yml @@ -85,14 +85,14 @@ jobs: - name: Build sample project with target defined as JSON spec run: | ./y.sh prepare --only-libcore --cross - ./y.sh build --sysroot --target-triple m68k-unknown-linux-gnu --target ${{ github.workspace }}/target_specs/m68k-unknown-linux-gnu.json + ./y.sh build --sysroot --features compiler_builtins/no-f16-f128 --target-triple m68k-unknown-linux-gnu --target ${{ github.workspace }}/target_specs/m68k-unknown-linux-gnu.json ./y.sh cargo build --manifest-path=./tests/hello-world/Cargo.toml --target ${{ github.workspace }}/target_specs/m68k-unknown-linux-gnu.json ./y.sh clean all - name: Build run: | ./y.sh prepare --only-libcore --cross - ./y.sh build --sysroot --target-triple m68k-unknown-linux-gnu + ./y.sh build --sysroot --features compiler_builtins/no-f16-f128 --target-triple m68k-unknown-linux-gnu CG_GCC_TEST_TARGET=m68k-unknown-linux-gnu cargo test ./y.sh clean all @@ -107,4 +107,4 @@ jobs: - name: Run tests run: | - ./y.sh test --release --clean --build-sysroot ${{ matrix.commands }} + ./y.sh test --release --clean --build-sysroot --sysroot-features compiler_builtins/no-f16-f128 ${{ matrix.commands }} diff --git a/build_system/build_sysroot/Cargo.toml b/build_system/build_sysroot/Cargo.toml index 05503128f2a..24152070e64 100644 --- a/build_system/build_sysroot/Cargo.toml +++ b/build_system/build_sysroot/Cargo.toml @@ -17,6 +17,22 @@ rustc-std-workspace-core = { path = "./sysroot_src/library/rustc-std-workspace-c rustc-std-workspace-alloc = { path = "./sysroot_src/library/rustc-std-workspace-alloc" } rustc-std-workspace-std = { path = "./sysroot_src/library/rustc-std-workspace-std" } +# For compiler-builtins we always use a high number of codegen units. +# The goal here is to place every single intrinsic into its own object +# file to avoid symbol clashes with the system libgcc if possible. Note +# that this number doesn't actually produce this many object files, we +# just don't create more than this number of object files. +# +# It's a bit of a bummer that we have to pass this here, unfortunately. +# Ideally this would be specified through an env var to Cargo so Cargo +# knows how many CGUs are for this specific crate, but for now +# per-crate configuration isn't specifiable in the environment. +[profile.dev.package.compiler_builtins] +codegen-units = 10000 + +[profile.release.package.compiler_builtins] +codegen-units = 10000 + [profile.release] debug = "limited" #lto = "fat" # TODO(antoyo): re-enable when the failing LTO tests regarding proc-macros are fixed. diff --git a/build_system/src/build.rs b/build_system/src/build.rs index 3f88945767d..d96683afa35 100644 --- a/build_system/src/build.rs +++ b/build_system/src/build.rs @@ -24,16 +24,6 @@ impl BuildArg { while let Some(arg) = args.next() { match arg.as_str() { - "--features" => { - if let Some(arg) = args.next() { - build_arg.flags.push("--features".to_string()); - build_arg.flags.push(arg.as_str().into()); - } else { - return Err( - "Expected a value after `--features`, found nothing".to_string() - ); - } - } "--sysroot" => { build_arg.build_sysroot = true; } @@ -56,7 +46,6 @@ impl BuildArg { r#" `build` command help: - --features [arg] : Add a new feature [arg] --sysroot : Build with sysroot"# ); ConfigInfo::show_usage(); @@ -150,6 +139,10 @@ pub fn build_sysroot(env: &HashMap, config: &ConfigInfo) -> Resu &"--features", &"std/compiler-builtins-no-f16-f128", ]; + for feature in &config.features { + args.push(&"--features"); + args.push(feature); + } if config.no_default_features { rustflags.push_str(" -Csymbol-mangling-version=v0"); diff --git a/build_system/src/config.rs b/build_system/src/config.rs index 15ba1612167..e381617be06 100644 --- a/build_system/src/config.rs +++ b/build_system/src/config.rs @@ -98,7 +98,7 @@ impl ConfigFile { } } -#[derive(Default, Debug)] +#[derive(Default, Debug, Clone)] pub struct ConfigInfo { pub target: String, pub target_triple: String, @@ -123,6 +123,7 @@ pub struct ConfigInfo { pub no_download: bool, pub no_default_features: bool, pub backend: Option, + pub features: Vec, } impl ConfigInfo { @@ -133,6 +134,13 @@ impl ConfigInfo { args: &mut impl Iterator, ) -> Result { match arg { + "--features" => { + if let Some(arg) = args.next() { + self.features.push(arg); + } else { + return Err("Expected a value after `--features`, found nothing".to_string()); + } + } "--target" => { if let Some(arg) = args.next() { self.target = arg; @@ -443,6 +451,7 @@ impl ConfigInfo { pub fn show_usage() { println!( "\ + --features [arg] : Add a new feature [arg] --target-triple [arg] : Set the target triple to [arg] --target [arg] : Set the target to [arg] --out-dir : Location where the files will be generated diff --git a/build_system/src/test.rs b/build_system/src/test.rs index dabf6c5aa3e..6454005b139 100644 --- a/build_system/src/test.rs +++ b/build_system/src/test.rs @@ -92,6 +92,7 @@ struct TestArg { current_part: Option, sysroot_panic_abort: bool, config_info: ConfigInfo, + sysroot_features: Vec, } impl TestArg { @@ -127,6 +128,14 @@ impl TestArg { "--sysroot-panic-abort" => { test_arg.sysroot_panic_abort = true; } + "--sysroot-features" => match args.next() { + Some(feature) if !feature.is_empty() => { + test_arg.sysroot_features.push(feature); + } + _ => { + return Err(format!("Expected an argument after `{}`, found nothing", arg)) + } + }, "--help" => { show_usage(); return Ok(None); @@ -250,7 +259,9 @@ fn mini_tests(env: &Env, args: &TestArg) -> Result<(), String> { fn build_sysroot(env: &Env, args: &TestArg) -> Result<(), String> { // FIXME: create a function "display_if_not_quiet" or something along the line. println!("[BUILD] sysroot"); - build::build_sysroot(env, &args.config_info)?; + let mut config = args.config_info.clone(); + config.features.extend(args.sysroot_features.iter().cloned()); + build::build_sysroot(env, &config)?; Ok(()) } diff --git a/src/context.rs b/src/context.rs index e330102fbd8..d4ac4f26b03 100644 --- a/src/context.rs +++ b/src/context.rs @@ -227,48 +227,14 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { "__builtin_umul_overflow", "__builtin_usubll_overflow", "__builtin_usub_overflow", - "sqrtf", - "sqrt", "__builtin_powif", "__builtin_powi", - "sinf", - "sin", - "cosf", - "cos", - "powf", - "pow", - "expf", - "exp", - "exp2f", - "exp2", - "logf", - "log", - "log10f", - "log10", - "log2f", - "log2", - "fmaf", - "fma", "fabsf", "fabs", - "fminf", - "fmin", - "fmaxf", - "fmax", "copysignf", "copysign", - "floorf", - "floor", - "ceilf", - "ceil", - "truncf", - "trunc", - "rintf", - "rint", "nearbyintf", "nearbyint", - "roundf", - "round", ]; for builtin in builtins.iter() { diff --git a/src/intrinsic/mod.rs b/src/intrinsic/mod.rs index 839ebf3f298..252b9b6fad6 100644 --- a/src/intrinsic/mod.rs +++ b/src/intrinsic/mod.rs @@ -127,20 +127,13 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { // https://github.com/rust-lang/rust-clippy/issues/12497 // and leave `else if use_integer_compare` to be placed "as is". #[allow(clippy::suspicious_else_formatting)] - let llval = match name { + let value = match name { _ if simple.is_some() => { - // FIXME(antoyo): remove this cast when the API supports function. - let func = unsafe { - std::mem::transmute::, RValue<'gcc>>(simple.expect("simple")) - }; - self.call( - self.type_void(), - None, - None, + let func = simple.expect("simple function"); + self.cx.context.new_call( + self.location, func, &args.iter().map(|arg| arg.immediate()).collect::>(), - None, - None, ) } sym::likely => self.expect(args[0].immediate(), true), @@ -383,7 +376,7 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { _ if name_str.starts_with("simd_") => { match generic_simd_intrinsic(self, name, callee_ty, args, ret_ty, llret_ty, span) { - Ok(llval) => llval, + Ok(value) => value, Err(()) => return Ok(()), } } @@ -396,9 +389,9 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { if let PassMode::Cast { cast: ref ty, .. } = fn_abi.ret.mode { let ptr_llty = self.type_ptr_to(ty.gcc_type(self)); let ptr = self.pointercast(result.val.llval, ptr_llty); - self.store(llval, ptr, result.val.align); + self.store(value, ptr, result.val.align); } else { - OperandRef::from_immediate_or_packed_pair(self, llval, result.layout) + OperandRef::from_immediate_or_packed_pair(self, value, result.layout) .val .store(self, result); } diff --git a/src/intrinsic/simd.rs b/src/intrinsic/simd.rs index 8da1df3be15..d1b4a9689a9 100644 --- a/src/intrinsic/simd.rs +++ b/src/intrinsic/simd.rs @@ -763,10 +763,7 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( _ => return_error!(InvalidMonomorphization::UnrecognizedIntrinsic { span, name }), }; let builtin_name = format!("{}{}", intr_name, elem_ty_str); - let funcs = bx.cx.functions.borrow(); - let function = funcs - .get(&builtin_name) - .unwrap_or_else(|| panic!("unable to find builtin function {}", builtin_name)); + let function = bx.context.get_builtin_function(builtin_name); // TODO(antoyo): add platform-specific behavior here for architectures that have these // intrinsics as instructions (for instance, gpus) @@ -784,7 +781,7 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( .map(|arg| bx.extract_element(arg.immediate(), index).to_rvalue()) .collect() }; - vector_elements.push(bx.context.new_call(None, *function, &arguments)); + vector_elements.push(bx.context.new_call(None, function, &arguments)); } let c = bx.context.new_rvalue_from_vector(None, vec_ty, &vector_elements); Ok(c) From a5e3a3f9b6bd85611fa098dab8948ecdcac98acc Mon Sep 17 00:00:00 2001 From: y21 <30553356+y21@users.noreply.github.com> Date: Mon, 12 Aug 2024 22:54:20 +0200 Subject: [PATCH 032/683] move `manual_c_str_literals` to complexity --- clippy_lints/src/methods/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index d7126990edb..44ed9016961 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -4025,7 +4025,7 @@ declare_clippy_lint! { /// ``` #[clippy::version = "1.78.0"] pub MANUAL_C_STR_LITERALS, - pedantic, + complexity, r#"creating a `CStr` through functions when `c""` literals can be used"# } From b70a1ec0b17a5f32feca23d6e289e4c8bf534c22 Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Tue, 13 Aug 2024 11:27:39 -0400 Subject: [PATCH 033/683] Add missing impl Copy for *mut T --- tests/run/array.rs | 1 + tests/run/closure.rs | 1 + tests/run/condition.rs | 1 + tests/run/fun_ptr.rs | 1 + tests/run/ptr_cast.rs | 1 + tests/run/slice.rs | 1 + tests/run/static.rs | 1 + 7 files changed, 7 insertions(+) diff --git a/tests/run/array.rs b/tests/run/array.rs index 3fe8917c9a3..432f11ad8d4 100644 --- a/tests/run/array.rs +++ b/tests/run/array.rs @@ -31,6 +31,7 @@ impl Copy for i32 {} impl Copy for u8 {} impl Copy for i8 {} impl Copy for i16 {} +impl Copy for *mut T {} #[lang = "receiver"] trait Receiver { diff --git a/tests/run/closure.rs b/tests/run/closure.rs index 355f0acee74..00e61cc001f 100644 --- a/tests/run/closure.rs +++ b/tests/run/closure.rs @@ -33,6 +33,7 @@ impl Copy for i32 {} impl Copy for u32 {} impl Copy for u8 {} impl Copy for i8 {} +impl Copy for *mut T {} #[lang = "receiver"] trait Receiver { diff --git a/tests/run/condition.rs b/tests/run/condition.rs index 1b3ae6dc004..7b05b7decd3 100644 --- a/tests/run/condition.rs +++ b/tests/run/condition.rs @@ -34,6 +34,7 @@ impl Copy for i16 {} impl Copy for char {} impl Copy for i8 {} impl Copy for u8 {} +impl Copy for *mut T {} #[lang = "receiver"] trait Receiver { diff --git a/tests/run/fun_ptr.rs b/tests/run/fun_ptr.rs index 96030359772..4e96f376555 100644 --- a/tests/run/fun_ptr.rs +++ b/tests/run/fun_ptr.rs @@ -28,6 +28,7 @@ impl Copy for i32 {} impl Copy for u8 {} impl Copy for i8 {} impl Copy for i16 {} +impl Copy for *mut T {} #[lang = "receiver"] trait Receiver { diff --git a/tests/run/ptr_cast.rs b/tests/run/ptr_cast.rs index 09d77abe27c..a94279182d6 100644 --- a/tests/run/ptr_cast.rs +++ b/tests/run/ptr_cast.rs @@ -28,6 +28,7 @@ impl Copy for i32 {} impl Copy for u8 {} impl Copy for i8 {} impl Copy for i16 {} +impl Copy for *mut T {} #[lang = "receiver"] trait Receiver { diff --git a/tests/run/slice.rs b/tests/run/slice.rs index 1262c86c810..e86fc823a1a 100644 --- a/tests/run/slice.rs +++ b/tests/run/slice.rs @@ -26,6 +26,7 @@ impl Copy for isize {} impl Copy for usize {} impl Copy for i32 {} impl Copy for u32 {} +impl Copy for *mut T {} #[lang = "receiver"] trait Receiver { diff --git a/tests/run/static.rs b/tests/run/static.rs index e7c46ae3fcc..6247e08f5e3 100644 --- a/tests/run/static.rs +++ b/tests/run/static.rs @@ -34,6 +34,7 @@ trait Copy { } impl Copy for isize {} +impl Copy for *mut T {} #[lang = "receiver"] trait Receiver { From b4ef8980a30cd44f71b01f1b48946dcec185db38 Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Tue, 13 Aug 2024 13:03:25 -0400 Subject: [PATCH 034/683] Fix formatting --- build_system/src/test.rs | 2 +- src/intrinsic/mod.rs | 6 +----- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/build_system/src/test.rs b/build_system/src/test.rs index 6454005b139..303a2e518cf 100644 --- a/build_system/src/test.rs +++ b/build_system/src/test.rs @@ -133,7 +133,7 @@ impl TestArg { test_arg.sysroot_features.push(feature); } _ => { - return Err(format!("Expected an argument after `{}`, found nothing", arg)) + return Err(format!("Expected an argument after `{}`, found nothing", arg)); } }, "--help" => { diff --git a/src/intrinsic/mod.rs b/src/intrinsic/mod.rs index 252b9b6fad6..d95a7782fa0 100644 --- a/src/intrinsic/mod.rs +++ b/src/intrinsic/mod.rs @@ -670,11 +670,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { let step3 = self.or(left, right); // Fourth step. - if width == 8 { - step3 - } else { - self.gcc_bswap(step3, width) - } + if width == 8 { step3 } else { self.gcc_bswap(step3, width) } } 128 => { // TODO(antoyo): find a more efficient implementation? From d3cfb7274d87c441b47c3d4790246be0a5a54e3f Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Tue, 13 Aug 2024 14:04:38 -0400 Subject: [PATCH 035/683] Fix clippy lint --- src/builder.rs | 16 ++++++++-------- src/int.rs | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/builder.rs b/src/builder.rs index eabdf0d8342..7ab9dfee46a 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -141,7 +141,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { ) -> RValue<'gcc> { let size = get_maybe_pointer_size(src); let compare_exchange = - self.context.get_builtin_function(&format!("__atomic_compare_exchange_{}", size)); + self.context.get_builtin_function(format!("__atomic_compare_exchange_{}", size)); let order = self.context.new_rvalue_from_int(self.i32_type, order.to_gcc()); let failure_order = self.context.new_rvalue_from_int(self.i32_type, failure_order.to_gcc()); let weak = self.context.new_rvalue_from_int(self.bool_type, weak as i32); @@ -328,7 +328,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { let result = current_func.new_local( self.location, return_type, - &format!("returnValue{}", self.next_value_counter()), + format!("returnValue{}", self.next_value_counter()), ); self.block.add_assignment( self.location, @@ -396,7 +396,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { let result = current_func.new_local( self.location, return_value.get_type(), - &format!("ptrReturnValue{}", self.next_value_counter()), + format!("ptrReturnValue{}", self.next_value_counter()), ); self.block.add_assignment(self.location, result, return_value); result.to_rvalue() @@ -438,7 +438,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { let result = current_func.new_local( self.location, return_type, - &format!("overflowReturnValue{}", self.next_value_counter()), + format!("overflowReturnValue{}", self.next_value_counter()), ); self.block.add_assignment( self.location, @@ -923,7 +923,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { let ty = self.cx.type_array(self.cx.type_i8(), size.bytes()).get_aligned(align.bytes()); // TODO(antoyo): It might be better to return a LValue, but fixing the rustc API is non-trivial. self.current_func() - .new_local(self.location, ty, &format!("stack_var_{}", self.next_value_counter())) + .new_local(self.location, ty, format!("stack_var_{}", self.next_value_counter())) .get_address(self.location) } @@ -949,7 +949,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { let loaded_value = function.new_local( self.location, aligned_type, - &format!("loadedValue{}", self.next_value_counter()), + format!("loadedValue{}", self.next_value_counter()), ); block.add_assignment(self.location, loaded_value, deref); loaded_value.to_rvalue() @@ -970,7 +970,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { // TODO(antoyo): use ty. // TODO(antoyo): handle alignment. let atomic_load = - self.context.get_builtin_function(&format!("__atomic_load_{}", size.bytes())); + self.context.get_builtin_function(format!("__atomic_load_{}", size.bytes())); let ordering = self.context.new_rvalue_from_int(self.i32_type, order.to_gcc()); let volatile_const_void_ptr_type = @@ -1126,7 +1126,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { ) { // TODO(antoyo): handle alignment. let atomic_store = - self.context.get_builtin_function(&format!("__atomic_store_{}", size.bytes())); + self.context.get_builtin_function(format!("__atomic_store_{}", size.bytes())); let ordering = self.context.new_rvalue_from_int(self.i32_type, order.to_gcc()); let volatile_const_void_ptr_type = self.context.new_type::<()>().make_volatile().make_pointer(); diff --git a/src/int.rs b/src/int.rs index 92d5c1cbbb8..1893d5a17dc 100644 --- a/src/int.rs +++ b/src/int.rs @@ -735,7 +735,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { // TODO(antoyo): check if it's faster to use string literals and a // match instead of format!. - let bswap = self.cx.context.get_builtin_function(&format!("__builtin_bswap{}", width)); + let bswap = self.cx.context.get_builtin_function(format!("__builtin_bswap{}", width)); // FIXME(antoyo): this cast should not be necessary. Remove // when having proper sized integer types. let param_type = bswap.get_param(0).to_rvalue().get_type(); From aec911675788dff017429f616968bc12b5c88adf Mon Sep 17 00:00:00 2001 From: Slanterns Date: Wed, 14 Aug 2024 18:35:58 +0800 Subject: [PATCH 036/683] stabilize `option_get_or_insert_default` --- compiler/rustc_mir_transform/src/lib.rs | 1 - compiler/rustc_session/src/lib.rs | 1 - library/core/src/option.rs | 4 +--- 3 files changed, 1 insertion(+), 5 deletions(-) diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index 1f214bc42cb..386c9e07efa 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -9,7 +9,6 @@ #![feature(let_chains)] #![feature(map_try_insert)] #![feature(never_type)] -#![feature(option_get_or_insert_default)] #![feature(round_char_boundary)] #![feature(try_blocks)] #![feature(yeet_expr)] diff --git a/compiler/rustc_session/src/lib.rs b/compiler/rustc_session/src/lib.rs index d93b3eac080..c3199043c13 100644 --- a/compiler/rustc_session/src/lib.rs +++ b/compiler/rustc_session/src/lib.rs @@ -3,7 +3,6 @@ #![feature(iter_intersperse)] #![feature(let_chains)] #![feature(map_many_mut)] -#![feature(option_get_or_insert_default)] #![feature(rustc_attrs)] // tidy-alphabetical-end diff --git a/library/core/src/option.rs b/library/core/src/option.rs index 6c89c810180..69f0d716cc7 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -1650,8 +1650,6 @@ impl Option { /// # Examples /// /// ``` - /// #![feature(option_get_or_insert_default)] - /// /// let mut x = None; /// /// { @@ -1664,7 +1662,7 @@ impl Option { /// assert_eq!(x, Some(7)); /// ``` #[inline] - #[unstable(feature = "option_get_or_insert_default", issue = "82901")] + #[stable(feature = "option_get_or_insert_default", since = "CURRENT_RUSTC_VERSION")] pub fn get_or_insert_default(&mut self) -> &mut T where T: Default, From 9732128e831b3870b48d95280317f55b9619feb1 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Sun, 18 Aug 2024 22:05:57 +0500 Subject: [PATCH 037/683] Diverging subexpression lint should not fire on todo!() --- clippy_lints/src/mixed_read_write_in_expression.rs | 6 ++++++ tests/ui/diverging_sub_expression.rs | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/clippy_lints/src/mixed_read_write_in_expression.rs b/clippy_lints/src/mixed_read_write_in_expression.rs index 6964d8c8dbb..091b6403cb4 100644 --- a/clippy_lints/src/mixed_read_write_in_expression.rs +++ b/clippy_lints/src/mixed_read_write_in_expression.rs @@ -1,4 +1,5 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; +use clippy_utils::macros::root_macro_call_first_node; use clippy_utils::{get_parent_expr, path_to_local, path_to_local_id}; use rustc_hir::intravisit::{walk_expr, Visitor}; use rustc_hir::{BinOpKind, Block, Expr, ExprKind, HirId, LetStmt, Node, Stmt, StmtKind}; @@ -134,6 +135,11 @@ impl<'a, 'tcx> DivergenceVisitor<'a, 'tcx> { } fn report_diverging_sub_expr(&mut self, e: &Expr<'_>) { + if let Some(macro_call) = root_macro_call_first_node(self.cx, e) { + if self.cx.tcx.item_name(macro_call.def_id).as_str() == "todo" { + return; + } + } span_lint(self.cx, DIVERGING_SUB_EXPRESSION, e.span, "sub-expression diverges"); } } diff --git a/tests/ui/diverging_sub_expression.rs b/tests/ui/diverging_sub_expression.rs index e0acf050949..1abba60fd34 100644 --- a/tests/ui/diverging_sub_expression.rs +++ b/tests/ui/diverging_sub_expression.rs @@ -67,3 +67,9 @@ fn foobar() { }; } } + +#[allow(unused)] +fn ignore_todo() { + let x: u32 = todo!(); + println!("{x}"); +} From b615c821809ff3092f021fc669eb63cb47de9912 Mon Sep 17 00:00:00 2001 From: WeiTheShinobi Date: Wed, 21 Aug 2024 16:12:48 +0800 Subject: [PATCH 038/683] Add new lint: `used_underscore_items` --- CHANGELOG.md | 1 + clippy_lints/src/declared_lints.rs | 1 + clippy_lints/src/misc.rs | 176 ++++++++++++++++++------ tests/ui/used_underscore_binding.stderr | 24 ++-- tests/ui/used_underscore_items.rs | 51 +++++++ tests/ui/used_underscore_items.stderr | 112 +++++++++++++++ 6 files changed, 309 insertions(+), 56 deletions(-) create mode 100644 tests/ui/used_underscore_items.rs create mode 100644 tests/ui/used_underscore_items.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index fddc2fd994e..2ba323997cf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6012,6 +6012,7 @@ Released 2018-09-13 [`use_debug`]: https://rust-lang.github.io/rust-clippy/master/index.html#use_debug [`use_self`]: https://rust-lang.github.io/rust-clippy/master/index.html#use_self [`used_underscore_binding`]: https://rust-lang.github.io/rust-clippy/master/index.html#used_underscore_binding +[`used_underscore_items`]: https://rust-lang.github.io/rust-clippy/master/index.html#used_underscore_items [`useless_asref`]: https://rust-lang.github.io/rust-clippy/master/index.html#useless_asref [`useless_attribute`]: https://rust-lang.github.io/rust-clippy/master/index.html#useless_attribute [`useless_conversion`]: https://rust-lang.github.io/rust-clippy/master/index.html#useless_conversion diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index 8754a4dff87..8d8b9056404 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -485,6 +485,7 @@ pub static LINTS: &[&crate::LintInfo] = &[ crate::misc::SHORT_CIRCUIT_STATEMENT_INFO, crate::misc::TOPLEVEL_REF_ARG_INFO, crate::misc::USED_UNDERSCORE_BINDING_INFO, + crate::misc::USED_UNDERSCORE_ITEMS_INFO, crate::misc_early::BUILTIN_TYPE_SHADOW_INFO, crate::misc_early::DOUBLE_NEG_INFO, crate::misc_early::DUPLICATE_UNDERSCORE_ARGUMENT_INFO, diff --git a/clippy_lints/src/misc.rs b/clippy_lints/src/misc.rs index a9aafe7ed56..3fc3f2b3b7f 100644 --- a/clippy_lints/src/misc.rs +++ b/clippy_lints/src/misc.rs @@ -80,6 +80,45 @@ declare_clippy_lint! { "using a binding which is prefixed with an underscore" } +declare_clippy_lint! { + /// ### What it does + /// Checks for the use of item with a single leading + /// underscore. + /// + /// ### Why is this bad? + /// A single leading underscore is usually used to indicate + /// that a item will not be used. Using such a item breaks this + /// expectation. + /// + /// ### Example + /// ```no_run + /// fn _foo() {} + /// + /// struct _FooStruct {} + /// + /// fn main() { + /// _foo(); + /// let _ = _FooStruct{}; + /// } + /// ``` + /// + /// Use instead: + /// ```no_run + /// fn foo() {} + /// + /// struct FooStruct {} + /// + /// fn main() { + /// foo(); + /// let _ = FooStruct{}; + /// } + /// ``` + #[clippy::version = "pre 1.29.0"] + pub USED_UNDERSCORE_ITEMS, + pedantic, + "using a item which is prefixed with an underscore" +} + declare_clippy_lint! { /// ### What it does /// Checks for the use of short circuit boolean conditions as @@ -104,6 +143,7 @@ declare_clippy_lint! { declare_lint_pass!(LintPass => [ TOPLEVEL_REF_ARG, USED_UNDERSCORE_BINDING, + USED_UNDERSCORE_ITEMS, SHORT_CIRCUIT_STATEMENT, ]); @@ -205,51 +245,99 @@ impl<'tcx> LateLintPass<'tcx> for LintPass { { return; } - let (definition_hir_id, ident) = match expr.kind { - ExprKind::Path(ref qpath) => { - if let QPath::Resolved(None, path) = qpath - && let Res::Local(id) = path.res - && is_used(cx, expr) - { - (id, last_path_segment(qpath).ident) - } else { - return; - } - }, - ExprKind::Field(recv, ident) => { - if let Some(adt_def) = cx.typeck_results().expr_ty_adjusted(recv).ty_adt_def() - && let Some(field) = adt_def.all_fields().find(|field| field.name == ident.name) - && let Some(local_did) = field.did.as_local() - && !cx.tcx.type_of(field.did).skip_binder().is_phantom_data() - { - (cx.tcx.local_def_id_to_hir_id(local_did), ident) - } else { - return; - } - }, - _ => return, - }; - let name = ident.name.as_str(); - if name.starts_with('_') - && !name.starts_with("__") - && let definition_span = cx.tcx.hir().span(definition_hir_id) - && !definition_span.from_expansion() - && !fulfill_or_allowed(cx, USED_UNDERSCORE_BINDING, [expr.hir_id, definition_hir_id]) - { - span_lint_and_then( - cx, - USED_UNDERSCORE_BINDING, - expr.span, - format!( - "used binding `{name}` which is prefixed with an underscore. A leading \ - underscore signals that a binding will not be used" - ), - |diag| { - diag.span_note(definition_span, format!("`{name}` is defined here")); - }, - ); - } + used_underscore_binding(cx, expr); + used_underscore_items(cx, expr); + } +} + +fn used_underscore_items<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { + let (def_id, ident) = match expr.kind { + ExprKind::Call(func, ..) => { + if let ExprKind::Path(QPath::Resolved(.., path)) = func.kind + && let Some(last_segment) = path.segments.last() + && let Res::Def(_, def_id) = last_segment.res + { + (def_id, last_segment.ident) + } else { + return; + } + }, + ExprKind::MethodCall(path, ..) => { + if let Some(def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) { + (def_id, path.ident) + } else { + return; + } + }, + ExprKind::Struct(QPath::Resolved(_, path), ..) => { + if let Some(last_segment) = path.segments.last() + && let Res::Def(_, def_id) = last_segment.res + { + (def_id, last_segment.ident) + } else { + return; + } + }, + _ => return, + }; + let name = ident.name.as_str(); + let definition_span = cx.tcx.def_span(def_id); + if name.starts_with('_') && !name.starts_with("__") && !definition_span.from_expansion() { + span_lint_and_then( + cx, + USED_UNDERSCORE_ITEMS, + expr.span, + "used underscore-prefixed item".to_string(), + |diag| { + diag.span_note(definition_span, "item is defined here".to_string()); + }, + ); + } +} + +fn used_underscore_binding<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { + let (definition_hir_id, ident) = match expr.kind { + ExprKind::Path(ref qpath) => { + if let QPath::Resolved(None, path) = qpath + && let Res::Local(id) = path.res + && is_used(cx, expr) + { + (id, last_path_segment(qpath).ident) + } else { + return; + } + }, + ExprKind::Field(recv, ident) => { + if let Some(adt_def) = cx.typeck_results().expr_ty_adjusted(recv).ty_adt_def() + && let Some(field) = adt_def.all_fields().find(|field| field.name == ident.name) + && let Some(local_did) = field.did.as_local() + && !cx.tcx.type_of(field.did).skip_binder().is_phantom_data() + { + (cx.tcx.local_def_id_to_hir_id(local_did), ident) + } else { + return; + } + }, + _ => return, + }; + + let name = ident.name.as_str(); + if name.starts_with('_') + && !name.starts_with("__") + && let definition_span = cx.tcx.hir().span(definition_hir_id) + && !definition_span.from_expansion() + && !fulfill_or_allowed(cx, USED_UNDERSCORE_BINDING, [expr.hir_id, definition_hir_id]) + { + span_lint_and_then( + cx, + USED_UNDERSCORE_BINDING, + expr.span, + "used underscore-prefixed binding".to_string(), + |diag| { + diag.span_note(definition_span, "binding is defined here".to_string()); + }, + ); } } diff --git a/tests/ui/used_underscore_binding.stderr b/tests/ui/used_underscore_binding.stderr index 556e1792b3e..f9e8013d3ad 100644 --- a/tests/ui/used_underscore_binding.stderr +++ b/tests/ui/used_underscore_binding.stderr @@ -1,10 +1,10 @@ -error: used binding `_foo` which is prefixed with an underscore. A leading underscore signals that a binding will not be used +error: used underscore-prefixed binding --> tests/ui/used_underscore_binding.rs:23:5 | LL | _foo + 1 | ^^^^ | -note: `_foo` is defined here +note: binding is defined here --> tests/ui/used_underscore_binding.rs:22:22 | LL | fn prefix_underscore(_foo: u32) -> u32 { @@ -12,61 +12,61 @@ LL | fn prefix_underscore(_foo: u32) -> u32 { = note: `-D clippy::used-underscore-binding` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::used_underscore_binding)]` -error: used binding `_foo` which is prefixed with an underscore. A leading underscore signals that a binding will not be used +error: used underscore-prefixed binding --> tests/ui/used_underscore_binding.rs:28:20 | LL | println!("{}", _foo); | ^^^^ | -note: `_foo` is defined here +note: binding is defined here --> tests/ui/used_underscore_binding.rs:27:24 | LL | fn in_macro_or_desugar(_foo: u32) { | ^^^^ -error: used binding `_foo` which is prefixed with an underscore. A leading underscore signals that a binding will not be used +error: used underscore-prefixed binding --> tests/ui/used_underscore_binding.rs:29:16 | LL | assert_eq!(_foo, _foo); | ^^^^ | -note: `_foo` is defined here +note: binding is defined here --> tests/ui/used_underscore_binding.rs:27:24 | LL | fn in_macro_or_desugar(_foo: u32) { | ^^^^ -error: used binding `_foo` which is prefixed with an underscore. A leading underscore signals that a binding will not be used +error: used underscore-prefixed binding --> tests/ui/used_underscore_binding.rs:29:22 | LL | assert_eq!(_foo, _foo); | ^^^^ | -note: `_foo` is defined here +note: binding is defined here --> tests/ui/used_underscore_binding.rs:27:24 | LL | fn in_macro_or_desugar(_foo: u32) { | ^^^^ -error: used binding `_underscore_field` which is prefixed with an underscore. A leading underscore signals that a binding will not be used +error: used underscore-prefixed binding --> tests/ui/used_underscore_binding.rs:42:5 | LL | s._underscore_field += 1; | ^^^^^^^^^^^^^^^^^^^ | -note: `_underscore_field` is defined here +note: binding is defined here --> tests/ui/used_underscore_binding.rs:36:5 | LL | _underscore_field: u32, | ^^^^^^^^^^^^^^^^^^^^^^ -error: used binding `_i` which is prefixed with an underscore. A leading underscore signals that a binding will not be used +error: used underscore-prefixed binding --> tests/ui/used_underscore_binding.rs:103:16 | LL | uses_i(_i); | ^^ | -note: `_i` is defined here +note: binding is defined here --> tests/ui/used_underscore_binding.rs:102:13 | LL | let _i = 5; diff --git a/tests/ui/used_underscore_items.rs b/tests/ui/used_underscore_items.rs new file mode 100644 index 00000000000..6b2ca44e32c --- /dev/null +++ b/tests/ui/used_underscore_items.rs @@ -0,0 +1,51 @@ +#![allow(unused)] +#![warn(clippy::used_underscore_items)] + +// should not lint macro +macro_rules! macro_wrap_func { + () => { + fn _marco_foo() {} + }; +} + +macro_wrap_func!(); + +struct _FooStruct {} + +impl _FooStruct { + fn _method_call(self) {} +} + +fn _foo1() {} + +fn _foo2() -> i32 { + 0 +} + +mod a { + pub mod b { + pub mod c { + pub fn _foo3() {} + + pub struct _FooStruct2 {} + + impl _FooStruct2 { + pub fn _method_call(self) {} + } + } + } +} + +fn main() { + _foo1(); + let _ = _foo2(); + a::b::c::_foo3(); + let _ = &_FooStruct {}; + let _ = _FooStruct {}; + + let foo_struct = _FooStruct {}; + foo_struct._method_call(); + + let foo_struct2 = a::b::c::_FooStruct2 {}; + foo_struct2._method_call(); +} diff --git a/tests/ui/used_underscore_items.stderr b/tests/ui/used_underscore_items.stderr new file mode 100644 index 00000000000..127d8248a94 --- /dev/null +++ b/tests/ui/used_underscore_items.stderr @@ -0,0 +1,112 @@ +error: used underscore-prefixed item + --> tests/ui/used_underscore_items.rs:40:5 + | +LL | _foo1(); + | ^^^^^^^ + | +note: item is defined here + --> tests/ui/used_underscore_items.rs:19:1 + | +LL | fn _foo1() {} + | ^^^^^^^^^^ + = note: `-D clippy::used-underscore-items` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::used_underscore_items)]` + +error: used underscore-prefixed item + --> tests/ui/used_underscore_items.rs:41:13 + | +LL | let _ = _foo2(); + | ^^^^^^^ + | +note: item is defined here + --> tests/ui/used_underscore_items.rs:21:1 + | +LL | fn _foo2() -> i32 { + | ^^^^^^^^^^^^^^^^^ + +error: used underscore-prefixed item + --> tests/ui/used_underscore_items.rs:42:5 + | +LL | a::b::c::_foo3(); + | ^^^^^^^^^^^^^^^^ + | +note: item is defined here + --> tests/ui/used_underscore_items.rs:28:13 + | +LL | pub fn _foo3() {} + | ^^^^^^^^^^^^^^ + +error: used underscore-prefixed item + --> tests/ui/used_underscore_items.rs:43:14 + | +LL | let _ = &_FooStruct {}; + | ^^^^^^^^^^^^^ + | +note: item is defined here + --> tests/ui/used_underscore_items.rs:13:1 + | +LL | struct _FooStruct {} + | ^^^^^^^^^^^^^^^^^ + +error: used underscore-prefixed item + --> tests/ui/used_underscore_items.rs:44:13 + | +LL | let _ = _FooStruct {}; + | ^^^^^^^^^^^^^ + | +note: item is defined here + --> tests/ui/used_underscore_items.rs:13:1 + | +LL | struct _FooStruct {} + | ^^^^^^^^^^^^^^^^^ + +error: used underscore-prefixed item + --> tests/ui/used_underscore_items.rs:46:22 + | +LL | let foo_struct = _FooStruct {}; + | ^^^^^^^^^^^^^ + | +note: item is defined here + --> tests/ui/used_underscore_items.rs:13:1 + | +LL | struct _FooStruct {} + | ^^^^^^^^^^^^^^^^^ + +error: used underscore-prefixed item + --> tests/ui/used_underscore_items.rs:47:5 + | +LL | foo_struct._method_call(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: item is defined here + --> tests/ui/used_underscore_items.rs:16:5 + | +LL | fn _method_call(self) {} + | ^^^^^^^^^^^^^^^^^^^^^ + +error: used underscore-prefixed item + --> tests/ui/used_underscore_items.rs:49:23 + | +LL | let foo_struct2 = a::b::c::_FooStruct2 {}; + | ^^^^^^^^^^^^^^^^^^^^^^^ + | +note: item is defined here + --> tests/ui/used_underscore_items.rs:30:13 + | +LL | pub struct _FooStruct2 {} + | ^^^^^^^^^^^^^^^^^^^^^^ + +error: used underscore-prefixed item + --> tests/ui/used_underscore_items.rs:50:5 + | +LL | foo_struct2._method_call(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: item is defined here + --> tests/ui/used_underscore_items.rs:33:17 + | +LL | pub fn _method_call(self) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 9 previous errors + From 89ad7334e014639621113ad8c38727e493d5e01d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 3 Aug 2024 11:17:43 +0200 Subject: [PATCH 039/683] stabilize const_fn_floating_point_arithmetic --- tests/ui/floating_point_abs.fixed | 1 - tests/ui/floating_point_abs.rs | 1 - tests/ui/floating_point_abs.stderr | 16 ++++++++-------- tests/ui/floating_point_mul_add.fixed | 1 - tests/ui/floating_point_mul_add.rs | 1 - tests/ui/floating_point_mul_add.stderr | 26 +++++++++++++------------- tests/ui/floating_point_rad.fixed | 1 - tests/ui/floating_point_rad.rs | 1 - tests/ui/floating_point_rad.stderr | 16 ++++++++-------- 9 files changed, 29 insertions(+), 35 deletions(-) diff --git a/tests/ui/floating_point_abs.fixed b/tests/ui/floating_point_abs.fixed index 5312a8b29c6..33183c76972 100644 --- a/tests/ui/floating_point_abs.fixed +++ b/tests/ui/floating_point_abs.fixed @@ -1,4 +1,3 @@ -#![feature(const_fn_floating_point_arithmetic)] #![warn(clippy::suboptimal_flops)] /// Allow suboptimal ops in constant context diff --git a/tests/ui/floating_point_abs.rs b/tests/ui/floating_point_abs.rs index 8619177130c..a08d5bbcef5 100644 --- a/tests/ui/floating_point_abs.rs +++ b/tests/ui/floating_point_abs.rs @@ -1,4 +1,3 @@ -#![feature(const_fn_floating_point_arithmetic)] #![warn(clippy::suboptimal_flops)] /// Allow suboptimal ops in constant context diff --git a/tests/ui/floating_point_abs.stderr b/tests/ui/floating_point_abs.stderr index f5a778c5b76..0c1f68f3b7f 100644 --- a/tests/ui/floating_point_abs.stderr +++ b/tests/ui/floating_point_abs.stderr @@ -1,5 +1,5 @@ error: manual implementation of `abs` method - --> tests/ui/floating_point_abs.rs:15:5 + --> tests/ui/floating_point_abs.rs:14:5 | LL | if num >= 0.0 { num } else { -num } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `num.abs()` @@ -8,43 +8,43 @@ LL | if num >= 0.0 { num } else { -num } = help: to override `-D warnings` add `#[allow(clippy::suboptimal_flops)]` error: manual implementation of `abs` method - --> tests/ui/floating_point_abs.rs:19:5 + --> tests/ui/floating_point_abs.rs:18:5 | LL | if 0.0 < num { num } else { -num } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `num.abs()` error: manual implementation of `abs` method - --> tests/ui/floating_point_abs.rs:23:5 + --> tests/ui/floating_point_abs.rs:22:5 | LL | if a.a > 0.0 { a.a } else { -a.a } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `a.a.abs()` error: manual implementation of `abs` method - --> tests/ui/floating_point_abs.rs:27:5 + --> tests/ui/floating_point_abs.rs:26:5 | LL | if 0.0 >= num { -num } else { num } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `num.abs()` error: manual implementation of `abs` method - --> tests/ui/floating_point_abs.rs:31:5 + --> tests/ui/floating_point_abs.rs:30:5 | LL | if a.a < 0.0 { -a.a } else { a.a } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `a.a.abs()` error: manual implementation of negation of `abs` method - --> tests/ui/floating_point_abs.rs:35:5 + --> tests/ui/floating_point_abs.rs:34:5 | LL | if num < 0.0 { num } else { -num } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `-num.abs()` error: manual implementation of negation of `abs` method - --> tests/ui/floating_point_abs.rs:39:5 + --> tests/ui/floating_point_abs.rs:38:5 | LL | if 0.0 >= num { num } else { -num } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `-num.abs()` error: manual implementation of negation of `abs` method - --> tests/ui/floating_point_abs.rs:44:12 + --> tests/ui/floating_point_abs.rs:43:12 | LL | a: if a.a >= 0.0 { -a.a } else { a.a }, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `-a.a.abs()` diff --git a/tests/ui/floating_point_mul_add.fixed b/tests/ui/floating_point_mul_add.fixed index 3ce2edf2c71..164aac2601a 100644 --- a/tests/ui/floating_point_mul_add.fixed +++ b/tests/ui/floating_point_mul_add.fixed @@ -1,4 +1,3 @@ -#![feature(const_fn_floating_point_arithmetic)] #![warn(clippy::suboptimal_flops)] /// Allow suboptimal_ops in constant context diff --git a/tests/ui/floating_point_mul_add.rs b/tests/ui/floating_point_mul_add.rs index b5e4a8db4db..ae024b7f224 100644 --- a/tests/ui/floating_point_mul_add.rs +++ b/tests/ui/floating_point_mul_add.rs @@ -1,4 +1,3 @@ -#![feature(const_fn_floating_point_arithmetic)] #![warn(clippy::suboptimal_flops)] /// Allow suboptimal_ops in constant context diff --git a/tests/ui/floating_point_mul_add.stderr b/tests/ui/floating_point_mul_add.stderr index 3e1a071de73..9c75909f715 100644 --- a/tests/ui/floating_point_mul_add.stderr +++ b/tests/ui/floating_point_mul_add.stderr @@ -1,5 +1,5 @@ error: multiply and add expressions can be calculated more efficiently and accurately - --> tests/ui/floating_point_mul_add.rs:20:13 + --> tests/ui/floating_point_mul_add.rs:19:13 | LL | let _ = a * b + c; | ^^^^^^^^^ help: consider using: `a.mul_add(b, c)` @@ -8,73 +8,73 @@ LL | let _ = a * b + c; = help: to override `-D warnings` add `#[allow(clippy::suboptimal_flops)]` error: multiply and add expressions can be calculated more efficiently and accurately - --> tests/ui/floating_point_mul_add.rs:21:13 + --> tests/ui/floating_point_mul_add.rs:20:13 | LL | let _ = a * b - c; | ^^^^^^^^^ help: consider using: `a.mul_add(b, -c)` error: multiply and add expressions can be calculated more efficiently and accurately - --> tests/ui/floating_point_mul_add.rs:22:13 + --> tests/ui/floating_point_mul_add.rs:21:13 | LL | let _ = c + a * b; | ^^^^^^^^^ help: consider using: `a.mul_add(b, c)` error: multiply and add expressions can be calculated more efficiently and accurately - --> tests/ui/floating_point_mul_add.rs:23:13 + --> tests/ui/floating_point_mul_add.rs:22:13 | LL | let _ = c - a * b; | ^^^^^^^^^ help: consider using: `a.mul_add(-b, c)` error: multiply and add expressions can be calculated more efficiently and accurately - --> tests/ui/floating_point_mul_add.rs:24:13 + --> tests/ui/floating_point_mul_add.rs:23:13 | LL | let _ = a + 2.0 * 4.0; | ^^^^^^^^^^^^^ help: consider using: `2.0f64.mul_add(4.0, a)` error: multiply and add expressions can be calculated more efficiently and accurately - --> tests/ui/floating_point_mul_add.rs:25:13 + --> tests/ui/floating_point_mul_add.rs:24:13 | LL | let _ = a + 2. * 4.; | ^^^^^^^^^^^ help: consider using: `2.0f64.mul_add(4., a)` error: multiply and add expressions can be calculated more efficiently and accurately - --> tests/ui/floating_point_mul_add.rs:27:13 + --> tests/ui/floating_point_mul_add.rs:26:13 | LL | let _ = (a * b) + c; | ^^^^^^^^^^^ help: consider using: `a.mul_add(b, c)` error: multiply and add expressions can be calculated more efficiently and accurately - --> tests/ui/floating_point_mul_add.rs:28:13 + --> tests/ui/floating_point_mul_add.rs:27:13 | LL | let _ = c + (a * b); | ^^^^^^^^^^^ help: consider using: `a.mul_add(b, c)` error: multiply and add expressions can be calculated more efficiently and accurately - --> tests/ui/floating_point_mul_add.rs:29:13 + --> tests/ui/floating_point_mul_add.rs:28:13 | LL | let _ = a * b * c + d; | ^^^^^^^^^^^^^ help: consider using: `(a * b).mul_add(c, d)` error: multiply and add expressions can be calculated more efficiently and accurately - --> tests/ui/floating_point_mul_add.rs:31:13 + --> tests/ui/floating_point_mul_add.rs:30:13 | LL | let _ = a.mul_add(b, c) * a.mul_add(b, c) + a.mul_add(b, c) + c; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `a.mul_add(b, c).mul_add(a.mul_add(b, c), a.mul_add(b, c))` error: multiply and add expressions can be calculated more efficiently and accurately - --> tests/ui/floating_point_mul_add.rs:32:13 + --> tests/ui/floating_point_mul_add.rs:31:13 | LL | let _ = 1234.567_f64 * 45.67834_f64 + 0.0004_f64; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `1234.567_f64.mul_add(45.67834_f64, 0.0004_f64)` error: multiply and add expressions can be calculated more efficiently and accurately - --> tests/ui/floating_point_mul_add.rs:34:13 + --> tests/ui/floating_point_mul_add.rs:33:13 | LL | let _ = (a * a + b).sqrt(); | ^^^^^^^^^^^ help: consider using: `a.mul_add(a, b)` error: multiply and add expressions can be calculated more efficiently and accurately - --> tests/ui/floating_point_mul_add.rs:37:13 + --> tests/ui/floating_point_mul_add.rs:36:13 | LL | let _ = a - (b * u as f64); | ^^^^^^^^^^^^^^^^^^ help: consider using: `b.mul_add(-(u as f64), a)` diff --git a/tests/ui/floating_point_rad.fixed b/tests/ui/floating_point_rad.fixed index a710bd9bd60..2f93d233cb4 100644 --- a/tests/ui/floating_point_rad.fixed +++ b/tests/ui/floating_point_rad.fixed @@ -1,4 +1,3 @@ -#![feature(const_fn_floating_point_arithmetic)] #![warn(clippy::suboptimal_flops)] /// Allow suboptimal_flops in constant context diff --git a/tests/ui/floating_point_rad.rs b/tests/ui/floating_point_rad.rs index 14656f021df..9690effc4e1 100644 --- a/tests/ui/floating_point_rad.rs +++ b/tests/ui/floating_point_rad.rs @@ -1,4 +1,3 @@ -#![feature(const_fn_floating_point_arithmetic)] #![warn(clippy::suboptimal_flops)] /// Allow suboptimal_flops in constant context diff --git a/tests/ui/floating_point_rad.stderr b/tests/ui/floating_point_rad.stderr index 64674342c2b..b834f5374e0 100644 --- a/tests/ui/floating_point_rad.stderr +++ b/tests/ui/floating_point_rad.stderr @@ -1,5 +1,5 @@ error: conversion to radians can be done more accurately - --> tests/ui/floating_point_rad.rs:11:13 + --> tests/ui/floating_point_rad.rs:10:13 | LL | let _ = degrees as f64 * std::f64::consts::PI / 180.0; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(degrees as f64).to_radians()` @@ -8,43 +8,43 @@ LL | let _ = degrees as f64 * std::f64::consts::PI / 180.0; = help: to override `-D warnings` add `#[allow(clippy::suboptimal_flops)]` error: conversion to degrees can be done more accurately - --> tests/ui/floating_point_rad.rs:12:13 + --> tests/ui/floating_point_rad.rs:11:13 | LL | let _ = degrees as f64 * 180.0 / std::f64::consts::PI; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(degrees as f64).to_degrees()` error: conversion to degrees can be done more accurately - --> tests/ui/floating_point_rad.rs:17:13 + --> tests/ui/floating_point_rad.rs:16:13 | LL | let _ = x * 180f32 / std::f32::consts::PI; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.to_degrees()` error: conversion to degrees can be done more accurately - --> tests/ui/floating_point_rad.rs:18:13 + --> tests/ui/floating_point_rad.rs:17:13 | LL | let _ = 90. * 180f64 / std::f64::consts::PI; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `90.0_f64.to_degrees()` error: conversion to degrees can be done more accurately - --> tests/ui/floating_point_rad.rs:19:13 + --> tests/ui/floating_point_rad.rs:18:13 | LL | let _ = 90.5 * 180f64 / std::f64::consts::PI; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `90.5_f64.to_degrees()` error: conversion to radians can be done more accurately - --> tests/ui/floating_point_rad.rs:20:13 + --> tests/ui/floating_point_rad.rs:19:13 | LL | let _ = x * std::f32::consts::PI / 180f32; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.to_radians()` error: conversion to radians can be done more accurately - --> tests/ui/floating_point_rad.rs:21:13 + --> tests/ui/floating_point_rad.rs:20:13 | LL | let _ = 90. * std::f32::consts::PI / 180f32; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `90.0_f64.to_radians()` error: conversion to radians can be done more accurately - --> tests/ui/floating_point_rad.rs:22:13 + --> tests/ui/floating_point_rad.rs:21:13 | LL | let _ = 90.5 * std::f32::consts::PI / 180f32; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `90.5_f64.to_radians()` From b179c3e7f72cb03fe9546a008e054f356854fdca Mon Sep 17 00:00:00 2001 From: kyoto7250 <50972773+kyoto7250@users.noreply.github.com> Date: Sat, 24 Aug 2024 23:29:11 +0900 Subject: [PATCH 040/683] check std::panic::panic_any in panic lint --- clippy_lints/src/panic_unimplemented.rs | 78 +++++++++++++++---------- clippy_utils/src/paths.rs | 1 + tests/ui-toml/panic/panic.rs | 5 ++ tests/ui-toml/panic/panic.stderr | 10 +++- 4 files changed, 62 insertions(+), 32 deletions(-) diff --git a/clippy_lints/src/panic_unimplemented.rs b/clippy_lints/src/panic_unimplemented.rs index 4eefd0065f6..fa5b02a5a41 100644 --- a/clippy_lints/src/panic_unimplemented.rs +++ b/clippy_lints/src/panic_unimplemented.rs @@ -1,8 +1,9 @@ use clippy_config::Conf; use clippy_utils::diagnostics::span_lint; -use clippy_utils::is_in_test; use clippy_utils::macros::{is_panic, root_macro_call_first_node}; -use rustc_hir::Expr; +use clippy_utils::{is_in_test, match_def_path, paths}; +use rustc_hir::def::{DefKind, Res}; +use rustc_hir::{Expr, ExprKind, QPath}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::impl_lint_pass; @@ -95,10 +96,49 @@ impl_lint_pass!(PanicUnimplemented => [UNIMPLEMENTED, UNREACHABLE, TODO, PANIC]) impl<'tcx> LateLintPass<'tcx> for PanicUnimplemented { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - let Some(macro_call) = root_macro_call_first_node(cx, expr) else { - return; - }; - if is_panic(cx, macro_call.def_id) { + if let Some(macro_call) = root_macro_call_first_node(cx, expr) { + if is_panic(cx, macro_call.def_id) { + if cx.tcx.hir().is_inside_const_context(expr.hir_id) + || self.allow_panic_in_tests && is_in_test(cx.tcx, expr.hir_id) + { + return; + } + + span_lint( + cx, + PANIC, + macro_call.span, + "`panic` should not be present in production code", + ); + return; + } + match cx.tcx.item_name(macro_call.def_id).as_str() { + "todo" => { + span_lint( + cx, + TODO, + macro_call.span, + "`todo` should not be present in production code", + ); + }, + "unimplemented" => { + span_lint( + cx, + UNIMPLEMENTED, + macro_call.span, + "`unimplemented` should not be present in production code", + ); + }, + "unreachable" => { + span_lint(cx, UNREACHABLE, macro_call.span, "usage of the `unreachable!` macro"); + }, + _ => {}, + } + } else if let ExprKind::Call(func, [_]) = expr.kind + && let ExprKind::Path(QPath::Resolved(None, expr_path)) = func.kind + && let Res::Def(DefKind::Fn, def_id) = expr_path.res + && match_def_path(cx, def_id, &paths::PANIC_ANY) + { if cx.tcx.hir().is_inside_const_context(expr.hir_id) || self.allow_panic_in_tests && is_in_test(cx.tcx, expr.hir_id) { @@ -108,32 +148,10 @@ impl<'tcx> LateLintPass<'tcx> for PanicUnimplemented { span_lint( cx, PANIC, - macro_call.span, - "`panic` should not be present in production code", + expr.span, + "`panic_any` should not be present in production code", ); return; } - match cx.tcx.item_name(macro_call.def_id).as_str() { - "todo" => { - span_lint( - cx, - TODO, - macro_call.span, - "`todo` should not be present in production code", - ); - }, - "unimplemented" => { - span_lint( - cx, - UNIMPLEMENTED, - macro_call.span, - "`unimplemented` should not be present in production code", - ); - }, - "unreachable" => { - span_lint(cx, UNREACHABLE, macro_call.span, "usage of the `unreachable!` macro"); - }, - _ => {}, - } } } diff --git a/clippy_utils/src/paths.rs b/clippy_utils/src/paths.rs index 684c645c199..a767798a9c3 100644 --- a/clippy_utils/src/paths.rs +++ b/clippy_utils/src/paths.rs @@ -56,6 +56,7 @@ pub const OS_STR_TO_OS_STRING: [&str; 5] = ["std", "ffi", "os_str", "OsStr", "to pub const PARKING_LOT_MUTEX_GUARD: [&str; 3] = ["lock_api", "mutex", "MutexGuard"]; pub const PARKING_LOT_RWLOCK_READ_GUARD: [&str; 3] = ["lock_api", "rwlock", "RwLockReadGuard"]; pub const PARKING_LOT_RWLOCK_WRITE_GUARD: [&str; 3] = ["lock_api", "rwlock", "RwLockWriteGuard"]; +pub const PANIC_ANY: [&str; 3] = ["std", "panic", "panic_any"]; pub const PATH_BUF_AS_PATH: [&str; 4] = ["std", "path", "PathBuf", "as_path"]; pub const PATH_MAIN_SEPARATOR: [&str; 3] = ["std", "path", "MAIN_SEPARATOR"]; pub const PATH_TO_PATH_BUF: [&str; 4] = ["std", "path", "Path", "to_path_buf"]; diff --git a/tests/ui-toml/panic/panic.rs b/tests/ui-toml/panic/panic.rs index 618a37ddfc5..b6264c950e4 100644 --- a/tests/ui-toml/panic/panic.rs +++ b/tests/ui-toml/panic/panic.rs @@ -1,5 +1,6 @@ //@compile-flags: --test #![warn(clippy::panic)] +use std::panic::panic_any; fn main() { enum Enam { @@ -12,6 +13,10 @@ fn main() { } } +fn issue_13292() { + panic_any("should lint") +} + #[test] fn lonely_test() { enum Enam { diff --git a/tests/ui-toml/panic/panic.stderr b/tests/ui-toml/panic/panic.stderr index bf7503e086c..a034207d919 100644 --- a/tests/ui-toml/panic/panic.stderr +++ b/tests/ui-toml/panic/panic.stderr @@ -1,5 +1,5 @@ error: `panic` should not be present in production code - --> tests/ui-toml/panic/panic.rs:11:14 + --> tests/ui-toml/panic/panic.rs:12:14 | LL | _ => panic!(""), | ^^^^^^^^^^ @@ -7,5 +7,11 @@ LL | _ => panic!(""), = note: `-D clippy::panic` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::panic)]` -error: aborting due to 1 previous error +error: `panic_any` should not be present in production code + --> tests/ui-toml/panic/panic.rs:17:5 + | +LL | panic_any("should lint") + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors From 3c4367a80f391b46f47c264ac8ea919c6ceda792 Mon Sep 17 00:00:00 2001 From: Pavel Grigorenko Date: Fri, 23 Aug 2024 01:12:57 +0300 Subject: [PATCH 041/683] Fix `elided_named_lifetimes` in code --- clippy_lints/src/unused_io_amount.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/unused_io_amount.rs b/clippy_lints/src/unused_io_amount.rs index 448946bd66d..c6ca17175e2 100644 --- a/clippy_lints/src/unused_io_amount.rs +++ b/clippy_lints/src/unused_io_amount.rs @@ -235,7 +235,7 @@ fn unpack_match<'a>(mut expr: &'a hir::Expr<'a>) -> &'a hir::Expr<'a> { /// If `expr` is an (e).await, return the inner expression "e" that's being /// waited on. Otherwise return None. -fn unpack_await<'a>(expr: &'a hir::Expr<'a>) -> &hir::Expr<'a> { +fn unpack_await<'a>(expr: &'a hir::Expr<'a>) -> &'a hir::Expr<'a> { if let ExprKind::Match(expr, _, hir::MatchSource::AwaitDesugar) = expr.kind { if let ExprKind::Call(func, [ref arg_0, ..]) = expr.kind { if matches!( From 3474df6a8e211457012132bbbf1add59436f1731 Mon Sep 17 00:00:00 2001 From: Alex Macleod Date: Sat, 24 Aug 2024 17:43:34 +0000 Subject: [PATCH 042/683] Rewrite empty_line_after_doc_comments and empty_line_after_outer_attr --- clippy_lints/src/attrs/empty_line_after.rs | 52 --- clippy_lints/src/attrs/mod.rs | 95 ----- clippy_lints/src/declared_lints.rs | 4 +- clippy_lints/src/doc/empty_line_after.rs | 329 ++++++++++++++++++ clippy_lints/src/doc/lazy_continuation.rs | 24 -- clippy_lints/src/doc/mod.rs | 85 ++++- .../src/doc/suspicious_doc_comments.rs | 6 +- clippy_lints/src/methods/iter_kv_map.rs | 1 - clippy_utils/src/attrs.rs | 8 +- clippy_utils/src/hir_utils.rs | 4 +- clippy_utils/src/lib.rs | 15 +- clippy_utils/src/source.rs | 60 +--- .../disallowed_names.rs | 2 +- .../disallowed_names.rs | 2 +- tests/ui/allow_attributes_without_reason.rs | 1 - .../ui/allow_attributes_without_reason.stderr | 4 +- tests/ui/cast_alignment.rs | 8 +- tests/ui/cmp_owned/without_suggestion.rs | 4 +- tests/ui/collapsible_else_if.fixed | 5 +- tests/ui/collapsible_else_if.rs | 5 +- tests/ui/collapsible_else_if.stderr | 16 +- tests/ui/crashes/associated-constant-ice.rs | 2 +- tests/ui/crashes/cc_seme.rs | 4 +- tests/ui/crashes/ice-11230.rs | 2 +- tests/ui/crashes/ice-1588.rs | 2 +- tests/ui/crashes/ice-1969.rs | 2 +- tests/ui/crashes/ice-2499.rs | 6 +- tests/ui/crashes/ice-2594.rs | 1 - tests/ui/crashes/ice-2727.rs | 2 +- tests/ui/crashes/ice-2760.rs | 8 +- tests/ui/crashes/ice-2862.rs | 2 +- tests/ui/crashes/ice-2865.rs | 2 +- tests/ui/crashes/ice-3151.rs | 2 +- tests/ui/crashes/ice-3462.rs | 2 +- tests/ui/crashes/ice-3747.rs | 2 +- tests/ui/crashes/ice-700.rs | 2 +- tests/ui/crashes/ice_exact_size.rs | 2 +- tests/ui/crashes/if_same_then_else.rs | 2 +- tests/ui/crashes/inherent_impl.rs | 2 +- tests/ui/crashes/issue-825.rs | 2 +- tests/ui/crashes/match_same_arms_const.rs | 2 +- tests/ui/crashes/returns.rs | 2 +- tests/ui/doc/doc_lazy_blank_line.fixed | 47 --- tests/ui/doc/doc_lazy_blank_line.rs | 43 --- tests/ui/doc/doc_lazy_blank_line.stderr | 56 --- tests/ui/doc/doc_lazy_list.fixed | 9 +- tests/ui/doc/doc_lazy_list.stderr | 27 +- tests/ui/duplicate_underscore_argument.rs | 1 - tests/ui/duplicate_underscore_argument.stderr | 2 +- .../ui/empty_line_after/doc_comments.1.fixed | 135 +++++++ .../ui/empty_line_after/doc_comments.2.fixed | 144 ++++++++ tests/ui/empty_line_after/doc_comments.rs | 147 ++++++++ tests/ui/empty_line_after/doc_comments.stderr | 176 ++++++++++ .../empty_line_after/outer_attribute.1.fixed | 103 ++++++ .../empty_line_after/outer_attribute.2.fixed | 106 ++++++ tests/ui/empty_line_after/outer_attribute.rs | 112 ++++++ .../empty_line_after/outer_attribute.stderr | 103 ++++++ tests/ui/empty_line_after_doc_comments.rs | 132 ------- tests/ui/empty_line_after_doc_comments.stderr | 37 -- tests/ui/empty_line_after_outer_attribute.rs | 120 ------- .../empty_line_after_outer_attribute.stderr | 54 --- tests/ui/exit1.rs | 2 +- tests/ui/exit2.rs | 2 +- tests/ui/exit3.rs | 2 +- tests/ui/expect_fun_call.fixed | 2 - tests/ui/expect_fun_call.rs | 2 - tests/ui/expect_fun_call.stderr | 30 +- tests/ui/match_overlapping_arm.rs | 2 - tests/ui/match_overlapping_arm.stderr | 32 +- tests/ui/string_slice.rs | 6 +- tests/ui/tabs_in_doc_comments.fixed | 1 - tests/ui/tabs_in_doc_comments.rs | 1 - tests/ui/tabs_in_doc_comments.stderr | 16 +- 73 files changed, 1563 insertions(+), 872 deletions(-) delete mode 100644 clippy_lints/src/attrs/empty_line_after.rs create mode 100644 clippy_lints/src/doc/empty_line_after.rs delete mode 100644 tests/ui/doc/doc_lazy_blank_line.fixed delete mode 100644 tests/ui/doc/doc_lazy_blank_line.rs delete mode 100644 tests/ui/doc/doc_lazy_blank_line.stderr create mode 100644 tests/ui/empty_line_after/doc_comments.1.fixed create mode 100644 tests/ui/empty_line_after/doc_comments.2.fixed create mode 100644 tests/ui/empty_line_after/doc_comments.rs create mode 100644 tests/ui/empty_line_after/doc_comments.stderr create mode 100644 tests/ui/empty_line_after/outer_attribute.1.fixed create mode 100644 tests/ui/empty_line_after/outer_attribute.2.fixed create mode 100644 tests/ui/empty_line_after/outer_attribute.rs create mode 100644 tests/ui/empty_line_after/outer_attribute.stderr delete mode 100644 tests/ui/empty_line_after_doc_comments.rs delete mode 100644 tests/ui/empty_line_after_doc_comments.stderr delete mode 100644 tests/ui/empty_line_after_outer_attribute.rs delete mode 100644 tests/ui/empty_line_after_outer_attribute.stderr diff --git a/clippy_lints/src/attrs/empty_line_after.rs b/clippy_lints/src/attrs/empty_line_after.rs deleted file mode 100644 index 7ff644b4c44..00000000000 --- a/clippy_lints/src/attrs/empty_line_after.rs +++ /dev/null @@ -1,52 +0,0 @@ -use super::{EMPTY_LINE_AFTER_DOC_COMMENTS, EMPTY_LINE_AFTER_OUTER_ATTR}; -use clippy_utils::diagnostics::span_lint; -use clippy_utils::source::{is_present_in_source, without_block_comments, SpanRangeExt}; -use rustc_ast::{AttrKind, AttrStyle}; -use rustc_lint::EarlyContext; -use rustc_span::Span; - -/// Check for empty lines after outer attributes. -/// -/// Attributes and documentation comments are both considered outer attributes -/// by the AST. However, the average user likely considers them to be different. -/// Checking for empty lines after each of these attributes is split into two different -/// lints but can share the same logic. -pub(super) fn check(cx: &EarlyContext<'_>, item: &rustc_ast::Item) { - let mut iter = item.attrs.iter().peekable(); - while let Some(attr) = iter.next() { - if (matches!(attr.kind, AttrKind::Normal(..)) || matches!(attr.kind, AttrKind::DocComment(..))) - && attr.style == AttrStyle::Outer - && is_present_in_source(cx, attr.span) - { - let begin_of_attr_to_item = Span::new(attr.span.lo(), item.span.lo(), item.span.ctxt(), item.span.parent()); - let end_of_attr_to_next_attr_or_item = Span::new( - attr.span.hi(), - iter.peek().map_or(item.span.lo(), |next_attr| next_attr.span.lo()), - item.span.ctxt(), - item.span.parent(), - ); - - if let Some(snippet) = end_of_attr_to_next_attr_or_item.get_source_text(cx) { - let lines = snippet.split('\n').collect::>(); - let lines = without_block_comments(lines); - - if lines.iter().filter(|l| l.trim().is_empty()).count() > 2 { - let (lint_msg, lint_type) = match attr.kind { - AttrKind::DocComment(..) => ( - "found an empty line after a doc comment. \ - Perhaps you need to use `//!` to make a comment on a module, remove the empty line, or make a regular comment with `//`?", - EMPTY_LINE_AFTER_DOC_COMMENTS, - ), - AttrKind::Normal(..) => ( - "found an empty line after an outer attribute. \ - Perhaps you forgot to add a `!` to make it an inner attribute?", - EMPTY_LINE_AFTER_OUTER_ATTR, - ), - }; - - span_lint(cx, lint_type, begin_of_attr_to_item, lint_msg); - } - } - } - } -} diff --git a/clippy_lints/src/attrs/mod.rs b/clippy_lints/src/attrs/mod.rs index 3b14e9aee7f..c8fea25c9f2 100644 --- a/clippy_lints/src/attrs/mod.rs +++ b/clippy_lints/src/attrs/mod.rs @@ -4,7 +4,6 @@ mod blanket_clippy_restriction_lints; mod deprecated_cfg_attr; mod deprecated_semver; mod duplicated_attributes; -mod empty_line_after; mod inline_always; mod mixed_attributes_style; mod non_minimal_cfg; @@ -126,94 +125,6 @@ declare_clippy_lint! { "use of `#[deprecated(since = \"x\")]` where x is not semver" } -declare_clippy_lint! { - /// ### What it does - /// Checks for empty lines after outer attributes - /// - /// ### Why is this bad? - /// Most likely the attribute was meant to be an inner attribute using a '!'. - /// If it was meant to be an outer attribute, then the following item - /// should not be separated by empty lines. - /// - /// ### Known problems - /// Can cause false positives. - /// - /// From the clippy side it's difficult to detect empty lines between an attributes and the - /// following item because empty lines and comments are not part of the AST. The parsing - /// currently works for basic cases but is not perfect. - /// - /// ### Example - /// ```no_run - /// #[allow(dead_code)] - /// - /// fn not_quite_good_code() { } - /// ``` - /// - /// Use instead: - /// ```no_run - /// // Good (as inner attribute) - /// #![allow(dead_code)] - /// - /// fn this_is_fine() { } - /// - /// // or - /// - /// // Good (as outer attribute) - /// #[allow(dead_code)] - /// fn this_is_fine_too() { } - /// ``` - #[clippy::version = "pre 1.29.0"] - pub EMPTY_LINE_AFTER_OUTER_ATTR, - nursery, - "empty line after outer attribute" -} - -declare_clippy_lint! { - /// ### What it does - /// Checks for empty lines after documentation comments. - /// - /// ### Why is this bad? - /// The documentation comment was most likely meant to be an inner attribute or regular comment. - /// If it was intended to be a documentation comment, then the empty line should be removed to - /// be more idiomatic. - /// - /// ### Known problems - /// Only detects empty lines immediately following the documentation. If the doc comment is followed - /// by an attribute and then an empty line, this lint will not trigger. Use `empty_line_after_outer_attr` - /// in combination with this lint to detect both cases. - /// - /// Does not detect empty lines after doc attributes (e.g. `#[doc = ""]`). - /// - /// ### Example - /// ```no_run - /// /// Some doc comment with a blank line after it. - /// - /// fn not_quite_good_code() { } - /// ``` - /// - /// Use instead: - /// ```no_run - /// /// Good (no blank line) - /// fn this_is_fine() { } - /// ``` - /// - /// ```no_run - /// // Good (convert to a regular comment) - /// - /// fn this_is_fine_too() { } - /// ``` - /// - /// ```no_run - /// //! Good (convert to a comment on an inner attribute) - /// - /// fn this_is_fine_as_well() { } - /// ``` - #[clippy::version = "1.70.0"] - pub EMPTY_LINE_AFTER_DOC_COMMENTS, - nursery, - "empty line after documentation comments" -} - declare_clippy_lint! { /// ### What it does /// Checks for `warn`/`deny`/`forbid` attributes targeting the whole clippy::restriction category. @@ -601,18 +512,12 @@ impl EarlyAttributes { impl_lint_pass!(EarlyAttributes => [ DEPRECATED_CFG_ATTR, - EMPTY_LINE_AFTER_OUTER_ATTR, - EMPTY_LINE_AFTER_DOC_COMMENTS, NON_MINIMAL_CFG, DEPRECATED_CLIPPY_CFG_ATTR, UNNECESSARY_CLIPPY_CFG, ]); impl EarlyLintPass for EarlyAttributes { - fn check_item(&mut self, cx: &EarlyContext<'_>, item: &rustc_ast::Item) { - empty_line_after::check(cx, item); - } - fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &Attribute) { deprecated_cfg_attr::check(cx, attr, &self.msrv); deprecated_cfg_attr::check_clippy(cx, attr); diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index 60e51713173..2c77ebc39e4 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -49,8 +49,6 @@ pub static LINTS: &[&crate::LintInfo] = &[ crate::attrs::DEPRECATED_CLIPPY_CFG_ATTR_INFO, crate::attrs::DEPRECATED_SEMVER_INFO, crate::attrs::DUPLICATED_ATTRIBUTES_INFO, - crate::attrs::EMPTY_LINE_AFTER_DOC_COMMENTS_INFO, - crate::attrs::EMPTY_LINE_AFTER_OUTER_ATTR_INFO, crate::attrs::INLINE_ALWAYS_INFO, crate::attrs::MIXED_ATTRIBUTES_STYLE_INFO, crate::attrs::NON_MINIMAL_CFG_INFO, @@ -138,6 +136,8 @@ pub static LINTS: &[&crate::LintInfo] = &[ crate::doc::DOC_LINK_WITH_QUOTES_INFO, crate::doc::DOC_MARKDOWN_INFO, crate::doc::EMPTY_DOCS_INFO, + crate::doc::EMPTY_LINE_AFTER_DOC_COMMENTS_INFO, + crate::doc::EMPTY_LINE_AFTER_OUTER_ATTR_INFO, crate::doc::MISSING_ERRORS_DOC_INFO, crate::doc::MISSING_PANICS_DOC_INFO, crate::doc::MISSING_SAFETY_DOC_INFO, diff --git a/clippy_lints/src/doc/empty_line_after.rs b/clippy_lints/src/doc/empty_line_after.rs new file mode 100644 index 00000000000..289debe0a6a --- /dev/null +++ b/clippy_lints/src/doc/empty_line_after.rs @@ -0,0 +1,329 @@ +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::source::{snippet_indent, SpanRangeExt}; +use clippy_utils::tokenize_with_text; +use itertools::Itertools; +use rustc_ast::token::CommentKind; +use rustc_ast::{AttrKind, AttrStyle, Attribute}; +use rustc_errors::{Applicability, Diag, SuggestionStyle}; +use rustc_hir::{ItemKind, Node}; +use rustc_lexer::TokenKind; +use rustc_lint::LateContext; +use rustc_span::{ExpnKind, InnerSpan, Span, SpanData}; + +use super::{EMPTY_LINE_AFTER_DOC_COMMENTS, EMPTY_LINE_AFTER_OUTER_ATTR}; + +#[derive(Debug, PartialEq, Clone, Copy)] +enum StopKind { + Attr, + Doc(CommentKind), +} + +impl StopKind { + fn is_doc(self) -> bool { + matches!(self, StopKind::Doc(_)) + } +} + +#[derive(Debug)] +struct Stop { + span: Span, + kind: StopKind, + first: usize, + last: usize, +} + +impl Stop { + fn convert_to_inner(&self) -> (Span, String) { + let inner = match self.kind { + // #|[...] + StopKind::Attr => InnerSpan::new(1, 1), + // /// or /** + // ^ ^ + StopKind::Doc(_) => InnerSpan::new(2, 3), + }; + (self.span.from_inner(inner), "!".into()) + } + + fn comment_out(&self, cx: &LateContext<'_>, suggestions: &mut Vec<(Span, String)>) { + match self.kind { + StopKind::Attr => { + if cx.tcx.sess.source_map().is_multiline(self.span) { + suggestions.extend([ + (self.span.shrink_to_lo(), "/* ".into()), + (self.span.shrink_to_hi(), " */".into()), + ]); + } else { + suggestions.push((self.span.shrink_to_lo(), "// ".into())); + } + }, + StopKind::Doc(CommentKind::Line) => suggestions.push((self.span.shrink_to_lo(), "// ".into())), + StopKind::Doc(CommentKind::Block) => { + // /** outer */ /*! inner */ + // ^ ^ + let asterisk = self.span.from_inner(InnerSpan::new(1, 2)); + suggestions.push((asterisk, String::new())); + }, + } + } + + fn from_attr(cx: &LateContext<'_>, attr: &Attribute) -> Option { + let SpanData { lo, hi, .. } = attr.span.data(); + let file = cx.tcx.sess.source_map().lookup_source_file(lo); + + Some(Self { + span: attr.span, + kind: match attr.kind { + AttrKind::Normal(_) => StopKind::Attr, + AttrKind::DocComment(comment_kind, _) => StopKind::Doc(comment_kind), + }, + first: file.lookup_line(file.relative_position(lo))?, + last: file.lookup_line(file.relative_position(hi))?, + }) + } +} + +/// Represents a set of attrs/doc comments separated by 1 or more empty lines +/// +/// ```ignore +/// /// chunk 1 docs +/// // not an empty line so also part of chunk 1 +/// #[chunk_1_attrs] // <-- prev_stop +/// +/// /* gap */ +/// +/// /// chunk 2 docs // <-- next_stop +/// #[chunk_2_attrs] +/// ``` +struct Gap<'a> { + /// The span of individual empty lines including the newline at the end of the line + empty_lines: Vec, + has_comment: bool, + next_stop: &'a Stop, + prev_stop: &'a Stop, + /// The chunk that includes [`prev_stop`](Self::prev_stop) + prev_chunk: &'a [Stop], +} + +impl<'a> Gap<'a> { + fn new(cx: &LateContext<'_>, prev_chunk: &'a [Stop], next_chunk: &'a [Stop]) -> Option { + let prev_stop = prev_chunk.last()?; + let next_stop = next_chunk.first()?; + let gap_span = prev_stop.span.between(next_stop.span); + let gap_snippet = gap_span.get_source_text(cx)?; + + let mut has_comment = false; + let mut empty_lines = Vec::new(); + + for (token, source, inner_span) in tokenize_with_text(&gap_snippet) { + match token { + TokenKind::BlockComment { + doc_style: None, + terminated: true, + } + | TokenKind::LineComment { doc_style: None } => has_comment = true, + TokenKind::Whitespace => { + let newlines = source.bytes().positions(|b| b == b'\n'); + empty_lines.extend( + newlines + .tuple_windows() + .map(|(a, b)| InnerSpan::new(inner_span.start + a + 1, inner_span.start + b)) + .map(|inner_span| gap_span.from_inner(inner_span)), + ); + }, + // Ignore cfg_attr'd out attributes as they may contain empty lines, could also be from macro + // shenanigans + _ => return None, + } + } + + (!empty_lines.is_empty()).then_some(Self { + empty_lines, + has_comment, + next_stop, + prev_stop, + prev_chunk, + }) + } +} + +/// If the node the attributes/docs apply to is the first in the module/crate suggest converting +/// them to inner attributes/docs +fn suggest_inner(cx: &LateContext<'_>, diag: &mut Diag<'_, ()>, kind: StopKind, gaps: &[Gap<'_>]) { + let Some(owner) = cx.last_node_with_lint_attrs.as_owner() else { + return; + }; + let parent_desc = match cx.tcx.parent_hir_node(owner.into()) { + Node::Item(item) + if let ItemKind::Mod(parent_mod) = item.kind + && let [first, ..] = parent_mod.item_ids + && first.owner_id == owner => + { + "parent module" + }, + Node::Crate(crate_mod) + if let Some(first) = crate_mod + .item_ids + .iter() + .map(|&id| cx.tcx.hir().item(id)) + // skip prelude imports + .find(|item| !matches!(item.span.ctxt().outer_expn_data().kind, ExpnKind::AstPass(_))) + && first.owner_id == owner => + { + "crate" + }, + _ => return, + }; + + diag.multipart_suggestion_verbose( + match kind { + StopKind::Attr => format!("if the attribute should apply to the {parent_desc} use an inner attribute"), + StopKind::Doc(_) => format!("if the comment should document the {parent_desc} use an inner doc comment"), + }, + gaps.iter() + .flat_map(|gap| gap.prev_chunk) + .map(Stop::convert_to_inner) + .collect(), + Applicability::MaybeIncorrect, + ); +} + +fn check_gaps(cx: &LateContext<'_>, gaps: &[Gap<'_>]) -> bool { + let Some(first_gap) = gaps.first() else { + return false; + }; + let empty_lines = || gaps.iter().flat_map(|gap| gap.empty_lines.iter().copied()); + let mut has_comment = false; + let mut has_attr = false; + for gap in gaps { + has_comment |= gap.has_comment; + if !has_attr { + has_attr = gap.prev_chunk.iter().any(|stop| stop.kind == StopKind::Attr); + } + } + let kind = first_gap.prev_stop.kind; + let (lint, kind_desc) = match kind { + StopKind::Attr => (EMPTY_LINE_AFTER_OUTER_ATTR, "outer attribute"), + StopKind::Doc(_) => (EMPTY_LINE_AFTER_DOC_COMMENTS, "doc comment"), + }; + let (lines, are, them) = if empty_lines().nth(1).is_some() { + ("lines", "are", "them") + } else { + ("line", "is", "it") + }; + span_lint_and_then( + cx, + lint, + 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() { + let def_id = owner.to_def_id(); + let def_descr = cx.tcx.def_descr(def_id); + diag.span_label( + cx.tcx.def_span(def_id), + match kind { + StopKind::Attr => format!("the attribute applies to this {def_descr}"), + StopKind::Doc(_) => format!("the comment documents this {def_descr}"), + }, + ); + } + + diag.multipart_suggestion_with_style( + format!("if the empty {lines} {are} unintentional remove {them}"), + empty_lines().map(|empty_line| (empty_line, String::new())).collect(), + Applicability::MaybeIncorrect, + SuggestionStyle::HideCodeAlways, + ); + + if has_comment && kind.is_doc() { + // Likely doc comments that applied to some now commented out code + // + // /// Old docs for Foo + // // struct Foo; + + let mut suggestions = Vec::new(); + for stop in gaps.iter().flat_map(|gap| gap.prev_chunk) { + stop.comment_out(cx, &mut suggestions); + } + let name = match cx.tcx.hir().opt_name(cx.last_node_with_lint_attrs) { + Some(name) => format!("`{name}`"), + None => "this".into(), + }; + diag.multipart_suggestion_verbose( + format!("if the doc comment should not document {name} comment it out"), + suggestions, + Applicability::MaybeIncorrect, + ); + } else { + suggest_inner(cx, diag, kind, gaps); + } + + if kind == StopKind::Doc(CommentKind::Line) + && gaps + .iter() + .all(|gap| !gap.has_comment && gap.next_stop.kind == StopKind::Doc(CommentKind::Line)) + { + // Commentless empty gaps between line doc comments, possibly intended to be part of the markdown + + let indent = snippet_indent(cx, first_gap.prev_stop.span).unwrap_or_default(); + diag.multipart_suggestion_verbose( + format!("if the documentation should include the empty {lines} include {them} in the comment"), + empty_lines() + .map(|empty_line| (empty_line, format!("{indent}///"))) + .collect(), + Applicability::MaybeIncorrect, + ); + } + }, + ); + kind.is_doc() +} + +/// Returns `true` if [`EMPTY_LINE_AFTER_DOC_COMMENTS`] triggered, used to skip other doc comment +/// lints where they would be confusing +/// +/// [`EMPTY_LINE_AFTER_OUTER_ATTR`] is also here to share an implementation but does not return +/// `true` if it triggers +pub(super) fn check(cx: &LateContext<'_>, attrs: &[Attribute]) -> bool { + let mut outer = attrs + .iter() + .filter(|attr| attr.style == AttrStyle::Outer && !attr.span.from_expansion()) + .map(|attr| Stop::from_attr(cx, attr)) + .collect::>>() + .unwrap_or_default(); + + if outer.is_empty() { + return false; + } + + // Push a fake attribute Stop for the item itself so we check for gaps between the last outer + // attr/doc comment and the item they apply to + let span = cx.tcx.hir().span(cx.last_node_with_lint_attrs); + if !span.from_expansion() + && let Ok(line) = cx.tcx.sess.source_map().lookup_line(span.lo()) + { + outer.push(Stop { + span, + kind: StopKind::Attr, + first: line.line, + // last doesn't need to be accurate here, we don't compare it with anything + last: line.line, + }); + } + + let mut gaps = Vec::new(); + let mut last = 0; + for pos in outer + .array_windows() + .positions(|[a, b]| b.first.saturating_sub(a.last) > 1) + { + // we want to be after the first stop in the window + let pos = pos + 1; + if let Some(gap) = Gap::new(cx, &outer[last..pos], &outer[pos..]) { + last = pos; + gaps.push(gap); + } + } + + check_gaps(cx, &gaps) +} diff --git a/clippy_lints/src/doc/lazy_continuation.rs b/clippy_lints/src/doc/lazy_continuation.rs index 771bcac2441..f9e4a43c0e7 100644 --- a/clippy_lints/src/doc/lazy_continuation.rs +++ b/clippy_lints/src/doc/lazy_continuation.rs @@ -22,7 +22,6 @@ pub(super) fn check( range: Range, mut span: Span, containers: &[super::Container], - line_break_span: Span, ) { if doc[range.clone()].contains('\t') { // We don't do tab stops correctly. @@ -52,29 +51,6 @@ pub(super) fn check( "doc list item without indentation" }; span_lint_and_then(cx, DOC_LAZY_CONTINUATION, span, msg, |diag| { - let snippet = clippy_utils::source::snippet(cx, line_break_span, ""); - if snippet.chars().filter(|&c| c == '\n').count() > 1 - && let Some(doc_comment_start) = snippet.rfind('\n') - && let doc_comment = snippet[doc_comment_start..].trim() - && (doc_comment == "///" || doc_comment == "//!") - { - // suggest filling in a blank line - diag.span_suggestion_verbose( - line_break_span.shrink_to_lo(), - "if this should be its own paragraph, add a blank doc comment line", - format!("\n{doc_comment}"), - Applicability::MaybeIncorrect, - ); - if ccount > 0 || blockquote_level > 0 { - diag.help("if this not intended to be a quote at all, escape it with `\\>`"); - } else { - let indent = list_indentation - lcount; - diag.help(format!( - "if this is intended to be part of the list, indent {indent} spaces" - )); - } - return; - } if ccount == 0 && blockquote_level == 0 { // simpler suggestion style for indentation let indent = list_indentation - lcount; diff --git a/clippy_lints/src/doc/mod.rs b/clippy_lints/src/doc/mod.rs index 790579b21c9..6db63b59e02 100644 --- a/clippy_lints/src/doc/mod.rs +++ b/clippy_lints/src/doc/mod.rs @@ -32,6 +32,7 @@ use rustc_span::{sym, Span}; use std::ops::Range; use url::Url; +mod empty_line_after; mod link_with_quotes; mod markdown; mod missing_headers; @@ -455,7 +456,82 @@ declare_clippy_lint! { "ensure that the first line of a documentation paragraph isn't too long" } -#[derive(Clone)] +declare_clippy_lint! { + /// ### What it does + /// Checks for empty lines after outer attributes + /// + /// ### Why is this bad? + /// The attribute may have meant to be an inner attribute (`#![attr]`). If + /// it was meant to be an outer attribute (`#[attr]`) then the empty line + /// should be removed + /// + /// ### Example + /// ```no_run + /// #[allow(dead_code)] + /// + /// fn not_quite_good_code() {} + /// ``` + /// + /// Use instead: + /// ```no_run + /// // Good (as inner attribute) + /// #![allow(dead_code)] + /// + /// fn this_is_fine() {} + /// + /// // or + /// + /// // Good (as outer attribute) + /// #[allow(dead_code)] + /// fn this_is_fine_too() {} + /// ``` + #[clippy::version = "pre 1.29.0"] + pub EMPTY_LINE_AFTER_OUTER_ATTR, + suspicious, + "empty line after outer attribute" +} + +declare_clippy_lint! { + /// ### What it does + /// Checks for empty lines after doc comments. + /// + /// ### Why is this bad? + /// The doc comment may have meant to be an inner doc comment, regular + /// comment or applied to some old code that is now commented out. If it was + /// intended to be a doc comment, then the empty line should be removed. + /// + /// ### Example + /// ```no_run + /// /// Some doc comment with a blank line after it. + /// + /// fn f() {} + /// + /// /// Docs for `old_code` + /// // fn old_code() {} + /// + /// fn new_code() {} + /// ``` + /// + /// Use instead: + /// ```no_run + /// //! Convert it to an inner doc comment + /// + /// // Or a regular comment + /// + /// /// Or remove the empty line + /// fn f() {} + /// + /// // /// Docs for `old_code` + /// // fn old_code() {} + /// + /// fn new_code() {} + /// ``` + #[clippy::version = "1.70.0"] + pub EMPTY_LINE_AFTER_DOC_COMMENTS, + suspicious, + "empty line after doc comments" +} + pub struct Documentation { valid_idents: FxHashSet, check_private_items: bool, @@ -482,6 +558,8 @@ impl_lint_pass!(Documentation => [ SUSPICIOUS_DOC_COMMENTS, EMPTY_DOCS, DOC_LAZY_CONTINUATION, + EMPTY_LINE_AFTER_OUTER_ATTR, + EMPTY_LINE_AFTER_DOC_COMMENTS, TOO_LONG_FIRST_DOC_PARAGRAPH, ]); @@ -612,12 +690,10 @@ fn check_attrs(cx: &LateContext<'_>, valid_idents: &FxHashSet, attrs: &[ Some(("fake".into(), "fake".into())) } - if is_doc_hidden(attrs) { + if suspicious_doc_comments::check(cx, attrs) || empty_line_after::check(cx, attrs) || is_doc_hidden(attrs) { return None; } - suspicious_doc_comments::check(cx, attrs); - let (fragments, _) = attrs_to_doc_fragments( attrs.iter().filter_map(|attr| { if in_external_macro(cx.sess(), attr.span) { @@ -816,7 +892,6 @@ fn check_doc<'a, Events: Iterator, Range, attrs: &[Attribute]) { +pub fn check(cx: &LateContext<'_>, attrs: &[Attribute]) -> bool { let replacements: Vec<_> = collect_doc_replacements(attrs); if let Some((&(lo_span, _), &(hi_span, _))) = replacements.first().zip(replacements.last()) { @@ -24,6 +24,10 @@ pub fn check(cx: &LateContext<'_>, attrs: &[Attribute]) { ); }, ); + + true + } else { + false } } diff --git a/clippy_lints/src/methods/iter_kv_map.rs b/clippy_lints/src/methods/iter_kv_map.rs index 33de3b87abc..390dd24b505 100644 --- a/clippy_lints/src/methods/iter_kv_map.rs +++ b/clippy_lints/src/methods/iter_kv_map.rs @@ -14,7 +14,6 @@ use rustc_span::sym; /// - `hashmap.into_iter().map(|(_, v)| v)` /// /// on `HashMaps` and `BTreeMaps` in std - pub(super) fn check<'tcx>( cx: &LateContext<'tcx>, map_type: &'tcx str, // iter / into_iter diff --git a/clippy_utils/src/attrs.rs b/clippy_utils/src/attrs.rs index 42c8b218d14..935a1686c0a 100644 --- a/clippy_utils/src/attrs.rs +++ b/clippy_utils/src/attrs.rs @@ -183,15 +183,15 @@ pub fn span_contains_cfg(cx: &LateContext<'_>, s: Span) -> bool { let mut iter = tokenize_with_text(src); // Search for the token sequence [`#`, `[`, `cfg`] - while iter.any(|(t, _)| matches!(t, TokenKind::Pound)) { - let mut iter = iter.by_ref().skip_while(|(t, _)| { + while iter.any(|(t, ..)| matches!(t, TokenKind::Pound)) { + let mut iter = iter.by_ref().skip_while(|(t, ..)| { matches!( t, TokenKind::Whitespace | TokenKind::LineComment { .. } | TokenKind::BlockComment { .. } ) }); - if matches!(iter.next(), Some((TokenKind::OpenBracket, _))) - && matches!(iter.next(), Some((TokenKind::Ident, "cfg"))) + if matches!(iter.next(), Some((TokenKind::OpenBracket, ..))) + && matches!(iter.next(), Some((TokenKind::Ident, "cfg", _))) { return true; } diff --git a/clippy_utils/src/hir_utils.rs b/clippy_utils/src/hir_utils.rs index f61ef9ac1b0..c1e21ec4e39 100644 --- a/clippy_utils/src/hir_utils.rs +++ b/clippy_utils/src/hir_utils.rs @@ -1194,8 +1194,8 @@ fn eq_span_tokens( && let Some(rsrc) = right.get_source_range(cx) && let Some(rsrc) = rsrc.as_str() { - let pred = |t: &(_, _)| pred(t.0); - let map = |(_, x)| x; + let pred = |&(token, ..): &(TokenKind, _, _)| pred(token); + let map = |(_, source, _)| source; let ltok = tokenize_with_text(lsrc).filter(pred).map(map); let rtok = tokenize_with_text(rsrc).filter(pred).map(map); diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index aec83e54747..66872840574 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -121,7 +121,7 @@ use rustc_middle::ty::{ use rustc_span::hygiene::{ExpnKind, MacroKind}; use rustc_span::source_map::SourceMap; use rustc_span::symbol::{kw, Ident, Symbol}; -use rustc_span::{sym, Span}; +use rustc_span::{sym, InnerSpan, Span}; use rustc_target::abi::Integer; use visitors::Visitable; @@ -2949,13 +2949,14 @@ pub fn expr_use_ctxt<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'tcx>) -> ExprU } /// Tokenizes the input while keeping the text associated with each token. -pub fn tokenize_with_text(s: &str) -> impl Iterator { +pub fn tokenize_with_text(s: &str) -> impl Iterator { let mut pos = 0; tokenize(s).map(move |t| { let end = pos + t.len; let range = pos as usize..end as usize; + let inner = InnerSpan::new(range.start, range.end); pos = end; - (t.kind, s.get(range).unwrap_or_default()) + (t.kind, s.get(range).unwrap_or_default(), inner) }) } @@ -2979,8 +2980,8 @@ pub fn span_contains_comment(sm: &SourceMap, span: Span) -> bool { pub fn span_extract_comment(sm: &SourceMap, span: Span) -> String { let snippet = sm.span_to_snippet(span).unwrap_or_default(); let res = tokenize_with_text(&snippet) - .filter(|(t, _)| matches!(t, TokenKind::BlockComment { .. } | TokenKind::LineComment { .. })) - .map(|(_, s)| s) + .filter(|(t, ..)| matches!(t, TokenKind::BlockComment { .. } | TokenKind::LineComment { .. })) + .map(|(_, s, _)| s) .join("\n"); res } @@ -3000,7 +3001,7 @@ pub fn span_find_starting_semi(sm: &SourceMap, span: Span) -> Span { /// pat: Some(a) /// else_body: return None /// ``` - +/// /// And for this example: /// ```ignore /// let Some(FooBar { a, b }) = ex else { return None }; @@ -3010,7 +3011,7 @@ pub fn span_find_starting_semi(sm: &SourceMap, span: Span) -> Span { /// pat: Some(FooBar { a, b }) /// else_body: return None /// ``` - +/// /// We output `Some(a)` in the first instance, and `Some(FooBar { a, b })` in the second, because /// the question mark operator is applicable here. Callers have to check whether we are in a /// constant or not. diff --git a/clippy_utils/src/source.rs b/clippy_utils/src/source.rs index 482e1e0147b..f97fb4a6471 100644 --- a/clippy_utils/src/source.rs +++ b/clippy_utils/src/source.rs @@ -666,39 +666,6 @@ pub fn walk_span_to_context(span: Span, outer: SyntaxContext) -> Option { (outer_span.ctxt() == outer).then_some(outer_span) } -/// Removes block comments from the given `Vec` of lines. -/// -/// # Examples -/// -/// ```rust,ignore -/// without_block_comments(vec!["/*", "foo", "*/"]); -/// // => vec![] -/// -/// without_block_comments(vec!["bar", "/*", "foo", "*/"]); -/// // => vec!["bar"] -/// ``` -pub fn without_block_comments(lines: Vec<&str>) -> Vec<&str> { - let mut without = vec![]; - - let mut nest_level = 0; - - for line in lines { - if line.contains("/*") { - nest_level += 1; - continue; - } else if line.contains("*/") { - nest_level -= 1; - continue; - } - - if nest_level == 0 { - without.push(line); - } - } - - without -} - /// Trims the whitespace from the start and the end of the span. pub fn trim_span(sm: &SourceMap, span: Span) -> Span { let data = span.data(); @@ -776,7 +743,7 @@ pub fn str_literal_to_char_literal( #[cfg(test)] mod test { - use super::{reindent_multiline, without_block_comments}; + use super::reindent_multiline; #[test] fn test_reindent_multiline_single_line() { @@ -844,29 +811,4 @@ mod test { z }".into(), true, Some(8))); } - - #[test] - fn test_without_block_comments_lines_without_block_comments() { - let result = without_block_comments(vec!["/*", "", "*/"]); - println!("result: {result:?}"); - assert!(result.is_empty()); - - let result = without_block_comments(vec!["", "/*", "", "*/", "#[crate_type = \"lib\"]", "/*", "", "*/", ""]); - assert_eq!(result, vec!["", "#[crate_type = \"lib\"]", ""]); - - let result = without_block_comments(vec!["/* rust", "", "*/"]); - assert!(result.is_empty()); - - let result = without_block_comments(vec!["/* one-line comment */"]); - assert!(result.is_empty()); - - let result = without_block_comments(vec!["/* nested", "/* multi-line", "comment", "*/", "test", "*/"]); - assert!(result.is_empty()); - - let result = without_block_comments(vec!["/* nested /* inline /* comment */ test */ */"]); - assert!(result.is_empty()); - - let result = without_block_comments(vec!["foo", "bar", "baz"]); - assert_eq!(result, vec!["foo", "bar", "baz"]); - } } diff --git a/tests/ui-toml/disallowed_names_append/disallowed_names.rs b/tests/ui-toml/disallowed_names_append/disallowed_names.rs index a2e2b46c426..61ae8de8e33 100644 --- a/tests/ui-toml/disallowed_names_append/disallowed_names.rs +++ b/tests/ui-toml/disallowed_names_append/disallowed_names.rs @@ -1,4 +1,4 @@ -#[warn(clippy::disallowed_names)] +#![warn(clippy::disallowed_names)] fn main() { // `foo` is part of the default configuration diff --git a/tests/ui-toml/disallowed_names_replace/disallowed_names.rs b/tests/ui-toml/disallowed_names_replace/disallowed_names.rs index a2e2b46c426..61ae8de8e33 100644 --- a/tests/ui-toml/disallowed_names_replace/disallowed_names.rs +++ b/tests/ui-toml/disallowed_names_replace/disallowed_names.rs @@ -1,4 +1,4 @@ -#[warn(clippy::disallowed_names)] +#![warn(clippy::disallowed_names)] fn main() { // `foo` is part of the default configuration diff --git a/tests/ui/allow_attributes_without_reason.rs b/tests/ui/allow_attributes_without_reason.rs index 86f6b2c5742..334e7ddd9d2 100644 --- a/tests/ui/allow_attributes_without_reason.rs +++ b/tests/ui/allow_attributes_without_reason.rs @@ -15,7 +15,6 @@ use proc_macros::{external, with_span}; #[warn(deref_nullptr)] #[deny(deref_nullptr)] #[forbid(deref_nullptr)] - fn main() { external! { #[allow(dead_code)] diff --git a/tests/ui/allow_attributes_without_reason.stderr b/tests/ui/allow_attributes_without_reason.stderr index 9bc3ca0f2af..86d7845df04 100644 --- a/tests/ui/allow_attributes_without_reason.stderr +++ b/tests/ui/allow_attributes_without_reason.stderr @@ -36,7 +36,7 @@ LL | #[expect(dead_code)] = help: try adding a reason at the end with `, reason = ".."` error: `allow` attribute without specifying a reason - --> tests/ui/allow_attributes_without_reason.rs:47:5 + --> tests/ui/allow_attributes_without_reason.rs:46:5 | LL | #[allow(unused)] | ^^^^^^^^^^^^^^^^ @@ -44,7 +44,7 @@ LL | #[allow(unused)] = help: try adding a reason at the end with `, reason = ".."` error: `allow` attribute without specifying a reason - --> tests/ui/allow_attributes_without_reason.rs:47:5 + --> tests/ui/allow_attributes_without_reason.rs:46:5 | LL | #[allow(unused)] | ^^^^^^^^^^^^^^^^ diff --git a/tests/ui/cast_alignment.rs b/tests/ui/cast_alignment.rs index 98ef5e36f94..72f5d4268cc 100644 --- a/tests/ui/cast_alignment.rs +++ b/tests/ui/cast_alignment.rs @@ -2,16 +2,16 @@ #![feature(rustc_private)] #![feature(core_intrinsics)] -extern crate libc; - -#[warn(clippy::cast_ptr_alignment)] -#[allow( +#![warn(clippy::cast_ptr_alignment)] +#![allow( clippy::no_effect, clippy::unnecessary_operation, clippy::cast_lossless, clippy::borrow_as_ptr )] +extern crate libc; + fn main() { /* These should be warned against */ diff --git a/tests/ui/cmp_owned/without_suggestion.rs b/tests/ui/cmp_owned/without_suggestion.rs index ec45d635c17..913aab72747 100644 --- a/tests/ui/cmp_owned/without_suggestion.rs +++ b/tests/ui/cmp_owned/without_suggestion.rs @@ -1,5 +1,5 @@ -#[allow(clippy::unnecessary_operation)] -#[allow(clippy::implicit_clone)] +#![allow(clippy::unnecessary_operation)] +#![allow(clippy::implicit_clone)] fn main() { let x = &Baz; diff --git a/tests/ui/collapsible_else_if.fixed b/tests/ui/collapsible_else_if.fixed index 3b410b2f17b..c2d76146c64 100644 --- a/tests/ui/collapsible_else_if.fixed +++ b/tests/ui/collapsible_else_if.fixed @@ -1,9 +1,7 @@ #![allow(clippy::assertions_on_constants, clippy::equatable_if_let, clippy::needless_if)] +#![warn(clippy::collapsible_if, clippy::collapsible_else_if)] #[rustfmt::skip] -#[warn(clippy::collapsible_if)] -#[warn(clippy::collapsible_else_if)] - fn main() { let x = "hello"; let y = "world"; @@ -76,7 +74,6 @@ fn main() { } #[rustfmt::skip] -#[allow(dead_code)] fn issue_7318() { if true { println!("I've been resolved!") }else if false {} diff --git a/tests/ui/collapsible_else_if.rs b/tests/ui/collapsible_else_if.rs index 772ef6f9fc6..3579e46cd44 100644 --- a/tests/ui/collapsible_else_if.rs +++ b/tests/ui/collapsible_else_if.rs @@ -1,9 +1,7 @@ #![allow(clippy::assertions_on_constants, clippy::equatable_if_let, clippy::needless_if)] +#![warn(clippy::collapsible_if, clippy::collapsible_else_if)] #[rustfmt::skip] -#[warn(clippy::collapsible_if)] -#[warn(clippy::collapsible_else_if)] - fn main() { let x = "hello"; let y = "world"; @@ -90,7 +88,6 @@ fn main() { } #[rustfmt::skip] -#[allow(dead_code)] fn issue_7318() { if true { println!("I've been resolved!") }else{ diff --git a/tests/ui/collapsible_else_if.stderr b/tests/ui/collapsible_else_if.stderr index dc19d90b4d1..395c2dcf68d 100644 --- a/tests/ui/collapsible_else_if.stderr +++ b/tests/ui/collapsible_else_if.stderr @@ -1,5 +1,5 @@ error: this `else { if .. }` block can be collapsed - --> tests/ui/collapsible_else_if.rs:13:12 + --> tests/ui/collapsible_else_if.rs:11:12 | LL | } else { | ____________^ @@ -19,7 +19,7 @@ LL + } | error: this `else { if .. }` block can be collapsed - --> tests/ui/collapsible_else_if.rs:21:12 + --> tests/ui/collapsible_else_if.rs:19:12 | LL | } else { | ____________^ @@ -37,7 +37,7 @@ LL + } | error: this `else { if .. }` block can be collapsed - --> tests/ui/collapsible_else_if.rs:29:12 + --> tests/ui/collapsible_else_if.rs:27:12 | LL | } else { | ____________^ @@ -60,7 +60,7 @@ LL + } | error: this `else { if .. }` block can be collapsed - --> tests/ui/collapsible_else_if.rs:40:12 + --> tests/ui/collapsible_else_if.rs:38:12 | LL | } else { | ____________^ @@ -83,7 +83,7 @@ LL + } | error: this `else { if .. }` block can be collapsed - --> tests/ui/collapsible_else_if.rs:51:12 + --> tests/ui/collapsible_else_if.rs:49:12 | LL | } else { | ____________^ @@ -106,7 +106,7 @@ LL + } | error: this `else { if .. }` block can be collapsed - --> tests/ui/collapsible_else_if.rs:62:12 + --> tests/ui/collapsible_else_if.rs:60:12 | LL | } else { | ____________^ @@ -129,7 +129,7 @@ LL + } | error: this `else { if .. }` block can be collapsed - --> tests/ui/collapsible_else_if.rs:73:12 + --> tests/ui/collapsible_else_if.rs:71:12 | LL | } else { | ____________^ @@ -152,7 +152,7 @@ LL + } | error: this `else { if .. }` block can be collapsed - --> tests/ui/collapsible_else_if.rs:96:10 + --> tests/ui/collapsible_else_if.rs:93:10 | LL | }else{ | __________^ diff --git a/tests/ui/crashes/associated-constant-ice.rs b/tests/ui/crashes/associated-constant-ice.rs index 948deba3ea6..fec16671eeb 100644 --- a/tests/ui/crashes/associated-constant-ice.rs +++ b/tests/ui/crashes/associated-constant-ice.rs @@ -1,4 +1,4 @@ -/// Test for https://github.com/rust-lang/rust-clippy/issues/1698 +// Test for https://github.com/rust-lang/rust-clippy/issues/1698 pub trait Trait { const CONSTANT: u8; diff --git a/tests/ui/crashes/cc_seme.rs b/tests/ui/crashes/cc_seme.rs index 98588be9cf8..98897d6d7aa 100644 --- a/tests/ui/crashes/cc_seme.rs +++ b/tests/ui/crashes/cc_seme.rs @@ -1,6 +1,4 @@ -#[allow(dead_code)] - -/// Test for https://github.com/rust-lang/rust-clippy/issues/478 +// Test for https://github.com/rust-lang/rust-clippy/issues/478 enum Baz { One, diff --git a/tests/ui/crashes/ice-11230.rs b/tests/ui/crashes/ice-11230.rs index 5761882273e..94044e9435e 100644 --- a/tests/ui/crashes/ice-11230.rs +++ b/tests/ui/crashes/ice-11230.rs @@ -1,4 +1,4 @@ -/// Test for https://github.com/rust-lang/rust-clippy/issues/11230 +// Test for https://github.com/rust-lang/rust-clippy/issues/11230 fn main() { const A: &[for<'a> fn(&'a ())] = &[]; diff --git a/tests/ui/crashes/ice-1588.rs b/tests/ui/crashes/ice-1588.rs index b0a3d11bce4..9ec093721c1 100644 --- a/tests/ui/crashes/ice-1588.rs +++ b/tests/ui/crashes/ice-1588.rs @@ -1,6 +1,6 @@ #![allow(clippy::all)] -/// Test for https://github.com/rust-lang/rust-clippy/issues/1588 +// Test for https://github.com/rust-lang/rust-clippy/issues/1588 fn main() { match 1 { diff --git a/tests/ui/crashes/ice-1969.rs b/tests/ui/crashes/ice-1969.rs index 96a8fe6c24d..eb901c76729 100644 --- a/tests/ui/crashes/ice-1969.rs +++ b/tests/ui/crashes/ice-1969.rs @@ -1,6 +1,6 @@ #![allow(clippy::all)] -/// Test for https://github.com/rust-lang/rust-clippy/issues/1969 +// Test for https://github.com/rust-lang/rust-clippy/issues/1969 fn main() {} diff --git a/tests/ui/crashes/ice-2499.rs b/tests/ui/crashes/ice-2499.rs index 45b3b1869dd..732f331ad14 100644 --- a/tests/ui/crashes/ice-2499.rs +++ b/tests/ui/crashes/ice-2499.rs @@ -1,8 +1,8 @@ #![allow(dead_code, clippy::char_lit_as_u8, clippy::needless_bool)] -/// Should not trigger an ICE in `SpanlessHash` / `consts::constant` -/// -/// Issue: https://github.com/rust-lang/rust-clippy/issues/2499 +// Should not trigger an ICE in `SpanlessHash` / `consts::constant` +// +// Issue: https://github.com/rust-lang/rust-clippy/issues/2499 fn f(s: &[u8]) -> bool { let t = s[0] as char; diff --git a/tests/ui/crashes/ice-2594.rs b/tests/ui/crashes/ice-2594.rs index 3f3986b6fc6..dddf860bd17 100644 --- a/tests/ui/crashes/ice-2594.rs +++ b/tests/ui/crashes/ice-2594.rs @@ -3,7 +3,6 @@ /// Should not trigger an ICE in `SpanlessHash` / `consts::constant` /// /// Issue: https://github.com/rust-lang/rust-clippy/issues/2594 - fn spanless_hash_ice() { let txt = "something"; let empty_header: [u8; 1] = [1; 1]; diff --git a/tests/ui/crashes/ice-2727.rs b/tests/ui/crashes/ice-2727.rs index 56024abc8f5..59fb9b04b86 100644 --- a/tests/ui/crashes/ice-2727.rs +++ b/tests/ui/crashes/ice-2727.rs @@ -1,4 +1,4 @@ -/// Test for https://github.com/rust-lang/rust-clippy/issues/2727 +// Test for https://github.com/rust-lang/rust-clippy/issues/2727 pub fn f(new: fn()) { new(); diff --git a/tests/ui/crashes/ice-2760.rs b/tests/ui/crashes/ice-2760.rs index 61ef2480498..5f7d91abf99 100644 --- a/tests/ui/crashes/ice-2760.rs +++ b/tests/ui/crashes/ice-2760.rs @@ -5,10 +5,10 @@ dead_code )] -/// This should not compile-fail with: -/// -/// error[E0277]: the trait bound `T: Foo` is not satisfied -// See rust-lang/rust-clippy#2760. +// This should not compile-fail with: +// +// error[E0277]: the trait bound `T: Foo` is not satisfied +// See https://github.com/rust-lang/rust-clippy/issues/2760 trait Foo { type Bar; diff --git a/tests/ui/crashes/ice-2862.rs b/tests/ui/crashes/ice-2862.rs index 8326e3663b0..2573b571f55 100644 --- a/tests/ui/crashes/ice-2862.rs +++ b/tests/ui/crashes/ice-2862.rs @@ -1,4 +1,4 @@ -/// Test for https://github.com/rust-lang/rust-clippy/issues/2862 +// Test for https://github.com/rust-lang/rust-clippy/issues/2862 pub trait FooMap { fn map B>(&self, f: F) -> B; diff --git a/tests/ui/crashes/ice-2865.rs b/tests/ui/crashes/ice-2865.rs index c6298139601..28363707acc 100644 --- a/tests/ui/crashes/ice-2865.rs +++ b/tests/ui/crashes/ice-2865.rs @@ -1,6 +1,6 @@ #![allow(dead_code, clippy::extra_unused_lifetimes)] -/// Test for https://github.com/rust-lang/rust-clippy/issues/2865 +// Test for https://github.com/rust-lang/rust-clippy/issues/2865 struct Ice { size: String, diff --git a/tests/ui/crashes/ice-3151.rs b/tests/ui/crashes/ice-3151.rs index 268ba86fc7a..f88a26cb485 100644 --- a/tests/ui/crashes/ice-3151.rs +++ b/tests/ui/crashes/ice-3151.rs @@ -1,4 +1,4 @@ -/// Test for https://github.com/rust-lang/rust-clippy/issues/3151 +// Test for https://github.com/rust-lang/rust-clippy/issues/3151 #[derive(Clone)] pub struct HashMap { diff --git a/tests/ui/crashes/ice-3462.rs b/tests/ui/crashes/ice-3462.rs index 21cd9d337cd..ccd617e305d 100644 --- a/tests/ui/crashes/ice-3462.rs +++ b/tests/ui/crashes/ice-3462.rs @@ -2,7 +2,7 @@ #![allow(clippy::disallowed_names, clippy::equatable_if_let, clippy::needless_if)] #![allow(unused)] -/// Test for https://github.com/rust-lang/rust-clippy/issues/3462 +// Test for https://github.com/rust-lang/rust-clippy/issues/3462 enum Foo { Bar, diff --git a/tests/ui/crashes/ice-3747.rs b/tests/ui/crashes/ice-3747.rs index cdf018cbc88..44b1d7ed1b2 100644 --- a/tests/ui/crashes/ice-3747.rs +++ b/tests/ui/crashes/ice-3747.rs @@ -1,4 +1,4 @@ -/// Test for https://github.com/rust-lang/rust-clippy/issues/3747 +// Test for https://github.com/rust-lang/rust-clippy/issues/3747 macro_rules! a { ( $pub:tt $($attr:tt)* ) => { diff --git a/tests/ui/crashes/ice-700.rs b/tests/ui/crashes/ice-700.rs index 0cbceedbd6b..5e004b94330 100644 --- a/tests/ui/crashes/ice-700.rs +++ b/tests/ui/crashes/ice-700.rs @@ -1,6 +1,6 @@ #![deny(clippy::all)] -/// Test for https://github.com/rust-lang/rust-clippy/issues/700 +// Test for https://github.com/rust-lang/rust-clippy/issues/700 fn core() {} diff --git a/tests/ui/crashes/ice_exact_size.rs b/tests/ui/crashes/ice_exact_size.rs index 30e4b11ec0b..c0671eaff14 100644 --- a/tests/ui/crashes/ice_exact_size.rs +++ b/tests/ui/crashes/ice_exact_size.rs @@ -1,6 +1,6 @@ #![deny(clippy::all)] -/// Test for https://github.com/rust-lang/rust-clippy/issues/1336 +// Test for https://github.com/rust-lang/rust-clippy/issues/1336 #[allow(dead_code)] struct Foo; diff --git a/tests/ui/crashes/if_same_then_else.rs b/tests/ui/crashes/if_same_then_else.rs index 2f913292995..a900fe5e6bc 100644 --- a/tests/ui/crashes/if_same_then_else.rs +++ b/tests/ui/crashes/if_same_then_else.rs @@ -1,7 +1,7 @@ #![allow(clippy::comparison_chain)] #![deny(clippy::if_same_then_else)] -/// Test for https://github.com/rust-lang/rust-clippy/issues/2426 +// Test for https://github.com/rust-lang/rust-clippy/issues/2426 fn main() {} diff --git a/tests/ui/crashes/inherent_impl.rs b/tests/ui/crashes/inherent_impl.rs index aeb27b5ba8c..800a5a383f6 100644 --- a/tests/ui/crashes/inherent_impl.rs +++ b/tests/ui/crashes/inherent_impl.rs @@ -1,6 +1,6 @@ #![deny(clippy::multiple_inherent_impl)] -/// Test for https://github.com/rust-lang/rust-clippy/issues/4578 +// Test for https://github.com/rust-lang/rust-clippy/issues/4578 macro_rules! impl_foo { ($struct:ident) => { diff --git a/tests/ui/crashes/issue-825.rs b/tests/ui/crashes/issue-825.rs index 05696e3d7d5..e8b455a0ec6 100644 --- a/tests/ui/crashes/issue-825.rs +++ b/tests/ui/crashes/issue-825.rs @@ -1,6 +1,6 @@ #![allow(warnings)] -/// Test for https://github.com/rust-lang/rust-clippy/issues/825 +// Test for https://github.com/rust-lang/rust-clippy/issues/825 // this should compile in a reasonable amount of time fn rust_type_id(name: &str) { diff --git a/tests/ui/crashes/match_same_arms_const.rs b/tests/ui/crashes/match_same_arms_const.rs index 94c939665e6..626179c0015 100644 --- a/tests/ui/crashes/match_same_arms_const.rs +++ b/tests/ui/crashes/match_same_arms_const.rs @@ -1,6 +1,6 @@ #![deny(clippy::match_same_arms)] -/// Test for https://github.com/rust-lang/rust-clippy/issues/2427 +// Test for https://github.com/rust-lang/rust-clippy/issues/2427 const PRICE_OF_SWEETS: u32 = 5; const PRICE_OF_KINDNESS: u32 = 0; diff --git a/tests/ui/crashes/returns.rs b/tests/ui/crashes/returns.rs index 8021ed4607d..91cdb5306c8 100644 --- a/tests/ui/crashes/returns.rs +++ b/tests/ui/crashes/returns.rs @@ -1,4 +1,4 @@ -/// Test for https://github.com/rust-lang/rust-clippy/issues/1346 +// Test for https://github.com/rust-lang/rust-clippy/issues/1346 #[deny(warnings)] fn cfg_return() -> i32 { diff --git a/tests/ui/doc/doc_lazy_blank_line.fixed b/tests/ui/doc/doc_lazy_blank_line.fixed deleted file mode 100644 index 1aaa26afe7f..00000000000 --- a/tests/ui/doc/doc_lazy_blank_line.fixed +++ /dev/null @@ -1,47 +0,0 @@ -// https://github.com/rust-lang/rust-clippy/issues/12917 -#![warn(clippy::doc_lazy_continuation)] - -/// This is a constant. -/// -/// The meaning of which should not be explained. -pub const A: i32 = 42; - -/// This is another constant, no longer used. -/// -/// This block of documentation has a long -/// explanation and derivation to explain -/// why it is what it is, and how it's used. -/// -/// It is left here for historical reasons, and -/// for reference. -/// -/// Reasons it's great: -/// - First reason -/// - Second reason -/// -//pub const B: i32 = 1337; - -/// This is yet another constant. -/// -/// This has a similar fate as `B`. -/// -/// Reasons it's useful: -/// 1. First reason -/// 2. Second reason -/// -//pub const C: i32 = 8008; - -/// This is still in use. -pub const D: i32 = 20; - -/// > blockquote code path -/// - -/// bottom text -pub const E: i32 = 20; - -/// > blockquote code path -/// -#[repr(C)] -/// bottom text -pub struct Foo(i32); diff --git a/tests/ui/doc/doc_lazy_blank_line.rs b/tests/ui/doc/doc_lazy_blank_line.rs deleted file mode 100644 index e1ab8fc8389..00000000000 --- a/tests/ui/doc/doc_lazy_blank_line.rs +++ /dev/null @@ -1,43 +0,0 @@ -// https://github.com/rust-lang/rust-clippy/issues/12917 -#![warn(clippy::doc_lazy_continuation)] - -/// This is a constant. -/// -/// The meaning of which should not be explained. -pub const A: i32 = 42; - -/// This is another constant, no longer used. -/// -/// This block of documentation has a long -/// explanation and derivation to explain -/// why it is what it is, and how it's used. -/// -/// It is left here for historical reasons, and -/// for reference. -/// -/// Reasons it's great: -/// - First reason -/// - Second reason -//pub const B: i32 = 1337; - -/// This is yet another constant. -/// -/// This has a similar fate as `B`. -/// -/// Reasons it's useful: -/// 1. First reason -/// 2. Second reason -//pub const C: i32 = 8008; - -/// This is still in use. -pub const D: i32 = 20; - -/// > blockquote code path - -/// bottom text -pub const E: i32 = 20; - -/// > blockquote code path -#[repr(C)] -/// bottom text -pub struct Foo(i32); diff --git a/tests/ui/doc/doc_lazy_blank_line.stderr b/tests/ui/doc/doc_lazy_blank_line.stderr deleted file mode 100644 index 854906a7474..00000000000 --- a/tests/ui/doc/doc_lazy_blank_line.stderr +++ /dev/null @@ -1,56 +0,0 @@ -error: doc list item without indentation - --> tests/ui/doc/doc_lazy_blank_line.rs:23:5 - | -LL | /// This is yet another constant. - | ^ - | - = help: if this is intended to be part of the list, indent 3 spaces - = note: `-D clippy::doc-lazy-continuation` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::doc_lazy_continuation)]` -help: if this should be its own paragraph, add a blank doc comment line - | -LL ~ /// - Second reason -LL + /// - | - -error: doc list item without indentation - --> tests/ui/doc/doc_lazy_blank_line.rs:32:5 - | -LL | /// This is still in use. - | ^ - | - = help: if this is intended to be part of the list, indent 4 spaces -help: if this should be its own paragraph, add a blank doc comment line - | -LL ~ /// 2. Second reason -LL + /// - | - -error: doc quote line without `>` marker - --> tests/ui/doc/doc_lazy_blank_line.rs:37:5 - | -LL | /// bottom text - | ^ - | - = help: if this not intended to be a quote at all, escape it with `\>` -help: if this should be its own paragraph, add a blank doc comment line - | -LL ~ /// > blockquote code path -LL + /// - | - -error: doc quote line without `>` marker - --> tests/ui/doc/doc_lazy_blank_line.rs:42:5 - | -LL | /// bottom text - | ^ - | - = help: if this not intended to be a quote at all, escape it with `\>` -help: if this should be its own paragraph, add a blank doc comment line - | -LL ~ /// > blockquote code path -LL + /// - | - -error: aborting due to 4 previous errors - diff --git a/tests/ui/doc/doc_lazy_list.fixed b/tests/ui/doc/doc_lazy_list.fixed index ea59ae4c01c..da537518a2b 100644 --- a/tests/ui/doc/doc_lazy_list.fixed +++ b/tests/ui/doc/doc_lazy_list.fixed @@ -7,9 +7,8 @@ fn one() {} /// 1. first line /// lazy list continuations don't make warnings with this lint -/// //~^ ERROR: doc list item without indentation -/// because they don't have the +/// because they don't have the //~^ ERROR: doc list item without indentation fn two() {} @@ -20,9 +19,8 @@ fn three() {} /// - first line /// lazy list continuations don't make warnings with this lint -/// //~^ ERROR: doc list item without indentation -/// because they don't have the +/// because they don't have the //~^ ERROR: doc list item without indentation fn four() {} @@ -33,9 +31,8 @@ fn five() {} /// - - first line /// this will warn on the lazy continuation -/// //~^ ERROR: doc list item without indentation -/// and so should this +/// and so should this //~^ ERROR: doc list item without indentation fn six() {} diff --git a/tests/ui/doc/doc_lazy_list.stderr b/tests/ui/doc/doc_lazy_list.stderr index 52aa74df894..b38f43b7555 100644 --- a/tests/ui/doc/doc_lazy_list.stderr +++ b/tests/ui/doc/doc_lazy_list.stderr @@ -30,12 +30,11 @@ error: doc list item without indentation LL | /// because they don't have the | ^ | - = help: if this is intended to be part of the list, indent 3 spaces -help: if this should be its own paragraph, add a blank doc comment line - | -LL ~ /// lazy list continuations don't make warnings with this lint -LL + /// + = help: if this is supposed to be its own paragraph, add a blank line +help: indent this line | +LL | /// because they don't have the + | +++ error: doc list item without indentation --> tests/ui/doc/doc_lazy_list.rs:16:5 @@ -67,12 +66,11 @@ error: doc list item without indentation LL | /// because they don't have the | ^ | - = help: if this is intended to be part of the list, indent 4 spaces -help: if this should be its own paragraph, add a blank doc comment line - | -LL ~ /// lazy list continuations don't make warnings with this lint -LL + /// + = help: if this is supposed to be its own paragraph, add a blank line +help: indent this line | +LL | /// because they don't have the + | ++++ error: doc list item without indentation --> tests/ui/doc/doc_lazy_list.rs:28:5 @@ -104,12 +102,11 @@ error: doc list item without indentation LL | /// and so should this | ^^^^ | - = help: if this is intended to be part of the list, indent 2 spaces -help: if this should be its own paragraph, add a blank doc comment line - | -LL ~ /// this will warn on the lazy continuation -LL + /// + = help: if this is supposed to be its own paragraph, add a blank line +help: indent this line | +LL | /// and so should this + | ++ error: doc list item without indentation --> tests/ui/doc/doc_lazy_list.rs:56:5 diff --git a/tests/ui/duplicate_underscore_argument.rs b/tests/ui/duplicate_underscore_argument.rs index 118f6e4a34c..a725538436c 100644 --- a/tests/ui/duplicate_underscore_argument.rs +++ b/tests/ui/duplicate_underscore_argument.rs @@ -1,5 +1,4 @@ #![warn(clippy::duplicate_underscore_argument)] -#[allow(dead_code, unused)] fn join_the_dark_side(darth: i32, _darth: i32) {} //~^ ERROR: `darth` already exists, having another argument having almost the same name ma diff --git a/tests/ui/duplicate_underscore_argument.stderr b/tests/ui/duplicate_underscore_argument.stderr index 40a24b823d1..74979b15788 100644 --- a/tests/ui/duplicate_underscore_argument.stderr +++ b/tests/ui/duplicate_underscore_argument.stderr @@ -1,5 +1,5 @@ error: `darth` already exists, having another argument having almost the same name makes code comprehension and documentation more difficult - --> tests/ui/duplicate_underscore_argument.rs:4:23 + --> tests/ui/duplicate_underscore_argument.rs:3:23 | LL | fn join_the_dark_side(darth: i32, _darth: i32) {} | ^^^^^ diff --git a/tests/ui/empty_line_after/doc_comments.1.fixed b/tests/ui/empty_line_after/doc_comments.1.fixed new file mode 100644 index 00000000000..fd6a94b6a80 --- /dev/null +++ b/tests/ui/empty_line_after/doc_comments.1.fixed @@ -0,0 +1,135 @@ +#![warn(clippy::empty_line_after_outer_attr, clippy::empty_line_after_doc_comments)] + +//~vvv empty_line_after_doc_comments +/// Meant to be an +/// inner doc comment +/// for the crate +fn first_in_crate() {} + +mod m { + //~vvv empty_line_after_doc_comments + /// Meant to be an + /// inner doc comment + /// for the module + fn first_in_module() {} +} + +mod some_mod { + //! This doc comment should *NOT* produce a warning + + mod some_inner_mod { + fn some_noop() {} + } + + //~v empty_line_after_doc_comments + /// # Indented + /// Blank line + fn indented() {} +} + +//~v empty_line_after_doc_comments +/// This should produce a warning +fn with_doc_and_newline() {} + +// This should *NOT* produce a warning +#[crate_type = "lib"] +/// some comment +fn with_no_newline_and_comment() {} + +//~v empty_line_after_doc_comments +/// This doc comment should produce a warning +/** This is also a doc comment and is part of the warning + */ +#[allow(non_camel_case_types)] +#[allow(missing_docs)] +#[allow(dead_code)] +fn three_attributes() {} + +mod misattributed { + //~v empty_line_after_doc_comments + /// docs for `old_code` + // fn old_code() {} + fn new_code() {} + + //~vv empty_line_after_doc_comments + /// Docs + /// for OldA + // struct OldA; + /// Docs + /// for OldB + // struct OldB; + /// Docs + /// for Multiple + #[allow(dead_code)] + struct Multiple; +} + +mod block_comments { + //~v empty_line_after_doc_comments + /** + * Meant to be inner doc comment + */ + fn first_in_module() {} + + //~v empty_line_after_doc_comments + /** + * Docs for `old_code` + */ + /* fn old_code() {} */ + /** + * Docs for `new_code` + */ + fn new_code() {} + + //~v empty_line_after_doc_comments + /// Docs for `old_code2` + /* fn old_code2() {} */ + /// Docs for `new_code2` + fn new_code2() {} +} + +// This should *NOT* produce a warning +#[doc = " +Returns the escaped value of the textual representation of + +"] +pub fn function() -> bool { + true +} + +// This should *NOT* produce a warning +#[derive(Clone, Copy)] +pub enum FooFighter { + Bar1, + + Bar2, + + Bar3, + + Bar4, +} + +/// Should not lint +// some line comment +/// gaps without an empty line +struct LineComment; + +/// This should *NOT* produce a warning because the empty line is inside a block comment +/* + +*/ +pub struct EmptyInBlockComment; + +/// This should *NOT* produce a warning +/* test */ +pub struct BlockComment; + +/// Ignore the empty line inside a cfg_attr'd out attribute +#[cfg_attr(any(), multiline( + foo = 1 + + bar = 2 +))] +fn empty_line_in_cfg_attr() {} + +fn main() {} diff --git a/tests/ui/empty_line_after/doc_comments.2.fixed b/tests/ui/empty_line_after/doc_comments.2.fixed new file mode 100644 index 00000000000..7a57dcd9233 --- /dev/null +++ b/tests/ui/empty_line_after/doc_comments.2.fixed @@ -0,0 +1,144 @@ +#![warn(clippy::empty_line_after_outer_attr, clippy::empty_line_after_doc_comments)] + +//~vvv empty_line_after_doc_comments +//! Meant to be an +//! inner doc comment +//! for the crate + +fn first_in_crate() {} + +mod m { + //~vvv empty_line_after_doc_comments + //! Meant to be an + //! inner doc comment + //! for the module + + fn first_in_module() {} +} + +mod some_mod { + //! This doc comment should *NOT* produce a warning + + mod some_inner_mod { + fn some_noop() {} + } + + //~v empty_line_after_doc_comments + /// # Indented + /// + /// Blank line + fn indented() {} +} + +//~v empty_line_after_doc_comments +/// This should produce a warning +fn with_doc_and_newline() {} + +// This should *NOT* produce a warning +#[crate_type = "lib"] +/// some comment +fn with_no_newline_and_comment() {} + +//~v empty_line_after_doc_comments +/// This doc comment should produce a warning +/** This is also a doc comment and is part of the warning + */ +#[allow(non_camel_case_types)] +#[allow(missing_docs)] +#[allow(dead_code)] +fn three_attributes() {} + +mod misattributed { + //~v empty_line_after_doc_comments + // /// docs for `old_code` + // fn old_code() {} + + fn new_code() {} + + //~vv empty_line_after_doc_comments + // /// Docs + // /// for OldA + // struct OldA; + + // /// Docs + // /// for OldB + // struct OldB; + + /// Docs + /// for Multiple + #[allow(dead_code)] + struct Multiple; +} + +mod block_comments { + //~v empty_line_after_doc_comments + /*! + * Meant to be inner doc comment + */ + + fn first_in_module() {} + + //~v empty_line_after_doc_comments + /* + * Docs for `old_code` + */ + /* fn old_code() {} */ + + /** + * Docs for `new_code` + */ + fn new_code() {} + + //~v empty_line_after_doc_comments + // /// Docs for `old_code2` + /* fn old_code2() {} */ + + /// Docs for `new_code2` + fn new_code2() {} +} + +// This should *NOT* produce a warning +#[doc = " +Returns the escaped value of the textual representation of + +"] +pub fn function() -> bool { + true +} + +// This should *NOT* produce a warning +#[derive(Clone, Copy)] +pub enum FooFighter { + Bar1, + + Bar2, + + Bar3, + + Bar4, +} + +/// Should not lint +// some line comment +/// gaps without an empty line +struct LineComment; + +/// This should *NOT* produce a warning because the empty line is inside a block comment +/* + +*/ +pub struct EmptyInBlockComment; + +/// This should *NOT* produce a warning +/* test */ +pub struct BlockComment; + +/// Ignore the empty line inside a cfg_attr'd out attribute +#[cfg_attr(any(), multiline( + foo = 1 + + bar = 2 +))] +fn empty_line_in_cfg_attr() {} + +fn main() {} diff --git a/tests/ui/empty_line_after/doc_comments.rs b/tests/ui/empty_line_after/doc_comments.rs new file mode 100644 index 00000000000..1da761a5c3d --- /dev/null +++ b/tests/ui/empty_line_after/doc_comments.rs @@ -0,0 +1,147 @@ +#![warn(clippy::empty_line_after_outer_attr, clippy::empty_line_after_doc_comments)] + +//~vvv empty_line_after_doc_comments +/// Meant to be an +/// inner doc comment +/// for the crate + +fn first_in_crate() {} + +mod m { + //~vvv empty_line_after_doc_comments + /// Meant to be an + /// inner doc comment + /// for the module + + fn first_in_module() {} +} + +mod some_mod { + //! This doc comment should *NOT* produce a warning + + mod some_inner_mod { + fn some_noop() {} + } + + //~v empty_line_after_doc_comments + /// # Indented + + /// Blank line + fn indented() {} +} + +//~v empty_line_after_doc_comments +/// This should produce a warning + +fn with_doc_and_newline() {} + +// This should *NOT* produce a warning +#[crate_type = "lib"] +/// some comment +fn with_no_newline_and_comment() {} + +//~v empty_line_after_doc_comments +/// This doc comment should produce a warning + +/** This is also a doc comment and is part of the warning + */ + +#[allow(non_camel_case_types)] +#[allow(missing_docs)] +#[allow(dead_code)] +fn three_attributes() {} + +mod misattributed { + //~v empty_line_after_doc_comments + /// docs for `old_code` + // fn old_code() {} + + fn new_code() {} + + //~vv empty_line_after_doc_comments + /// Docs + /// for OldA + // struct OldA; + + /// Docs + /// for OldB + // struct OldB; + + /// Docs + /// for Multiple + #[allow(dead_code)] + struct Multiple; +} + +mod block_comments { + //~v empty_line_after_doc_comments + /** + * Meant to be inner doc comment + */ + + fn first_in_module() {} + + //~v empty_line_after_doc_comments + /** + * Docs for `old_code` + */ + /* fn old_code() {} */ + + /** + * Docs for `new_code` + */ + fn new_code() {} + + //~v empty_line_after_doc_comments + /// Docs for `old_code2` + /* fn old_code2() {} */ + + /// Docs for `new_code2` + fn new_code2() {} +} + +// This should *NOT* produce a warning +#[doc = " +Returns the escaped value of the textual representation of + +"] +pub fn function() -> bool { + true +} + +// This should *NOT* produce a warning +#[derive(Clone, Copy)] +pub enum FooFighter { + Bar1, + + Bar2, + + Bar3, + + Bar4, +} + +/// Should not lint +// some line comment +/// gaps without an empty line +struct LineComment; + +/// This should *NOT* produce a warning because the empty line is inside a block comment +/* + +*/ +pub struct EmptyInBlockComment; + +/// This should *NOT* produce a warning +/* test */ +pub struct BlockComment; + +/// Ignore the empty line inside a cfg_attr'd out attribute +#[cfg_attr(any(), multiline( + foo = 1 + + bar = 2 +))] +fn empty_line_in_cfg_attr() {} + +fn main() {} diff --git a/tests/ui/empty_line_after/doc_comments.stderr b/tests/ui/empty_line_after/doc_comments.stderr new file mode 100644 index 00000000000..c238b4c9a17 --- /dev/null +++ b/tests/ui/empty_line_after/doc_comments.stderr @@ -0,0 +1,176 @@ +error: empty line after doc comment + --> tests/ui/empty_line_after/doc_comments.rs:6:1 + | +LL | / /// for the crate +LL | | + | |_ +LL | fn first_in_crate() {} + | ------------------- the comment documents this function + | + = note: `-D clippy::empty-line-after-doc-comments` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::empty_line_after_doc_comments)]` + = help: if the empty line is unintentional remove it +help: if the comment should document the crate use an inner doc comment + | +LL ~ //! Meant to be an +LL ~ //! inner doc comment +LL ~ //! for the crate + | + +error: empty line after doc comment + --> tests/ui/empty_line_after/doc_comments.rs:14:5 + | +LL | / /// for the module +LL | | + | |_ +LL | fn first_in_module() {} + | -------------------- the comment documents this function + | + = help: if the empty line is unintentional remove it +help: if the comment should document the parent module use an inner doc comment + | +LL ~ //! Meant to be an +LL ~ //! inner doc comment +LL ~ //! for the module + | + +error: empty line after doc comment + --> tests/ui/empty_line_after/doc_comments.rs:27:5 + | +LL | / /// # Indented +LL | | + | |_ +LL | /// Blank line +LL | fn indented() {} + | ------------- the comment documents this function + | + = help: if the empty line is unintentional remove it +help: if the documentation should include the empty line include it in the comment + | +LL | /// + | + +error: empty line after doc comment + --> tests/ui/empty_line_after/doc_comments.rs:34:1 + | +LL | / /// This should produce a warning +LL | | + | |_ +LL | fn with_doc_and_newline() {} + | ------------------------- the comment documents this function + | + = help: if the empty line is unintentional remove it + +error: empty lines after doc comment + --> tests/ui/empty_line_after/doc_comments.rs:44:1 + | +LL | / /// This doc comment should produce a warning +LL | | +LL | | /** This is also a doc comment and is part of the warning +LL | | */ +LL | | + | |_ +... +LL | fn three_attributes() {} + | --------------------- the comment documents this function + | + = help: if the empty lines are unintentional remove them + +error: empty line after doc comment + --> tests/ui/empty_line_after/doc_comments.rs:56:5 + | +LL | / /// docs for `old_code` +LL | | // fn old_code() {} +LL | | + | |_ +LL | fn new_code() {} + | ------------- the comment documents this function + | + = help: if the empty line is unintentional remove it +help: if the doc comment should not document `new_code` comment it out + | +LL | // /// docs for `old_code` + | ++ + +error: empty lines after doc comment + --> tests/ui/empty_line_after/doc_comments.rs:63:5 + | +LL | / /// for OldA +LL | | // struct OldA; +LL | | +LL | | /// Docs +LL | | /// for OldB +LL | | // struct OldB; +LL | | + | |_ +... +LL | struct Multiple; + | --------------- the comment documents this struct + | + = help: if the empty lines are unintentional remove them +help: if the doc comment should not document `Multiple` comment it out + | +LL ~ // /// Docs +LL ~ // /// for OldA +LL | // struct OldA; +LL | +LL ~ // /// Docs +LL ~ // /// for OldB + | + +error: empty line after doc comment + --> tests/ui/empty_line_after/doc_comments.rs:78:5 + | +LL | / /** +LL | | * Meant to be inner doc comment +LL | | */ +LL | | + | |_ +LL | fn first_in_module() {} + | -------------------- the comment documents this function + | + = help: if the empty line is unintentional remove it +help: if the comment should document the parent module use an inner doc comment + | +LL | /*! + | ~ + +error: empty line after doc comment + --> tests/ui/empty_line_after/doc_comments.rs:85:5 + | +LL | / /** +LL | | * Docs for `old_code` +LL | | */ +LL | | /* fn old_code() {} */ +LL | | + | |_ +... +LL | fn new_code() {} + | ------------- the comment documents this function + | + = help: if the empty line is unintentional remove it +help: if the doc comment should not document `new_code` comment it out + | +LL - /** +LL + /* + | + +error: empty line after doc comment + --> tests/ui/empty_line_after/doc_comments.rs:96:5 + | +LL | / /// Docs for `old_code2` +LL | | /* fn old_code2() {} */ +LL | | + | |_ +LL | /// Docs for `new_code2` +LL | fn new_code2() {} + | -------------- the comment documents this function + | + = help: if the empty line is unintentional remove it +help: if the doc comment should not document `new_code2` comment it out + | +LL | // /// Docs for `old_code2` + | ++ + +error: aborting due to 10 previous errors + diff --git a/tests/ui/empty_line_after/outer_attribute.1.fixed b/tests/ui/empty_line_after/outer_attribute.1.fixed new file mode 100644 index 00000000000..cd7ea24b6be --- /dev/null +++ b/tests/ui/empty_line_after/outer_attribute.1.fixed @@ -0,0 +1,103 @@ +//@aux-build:../auxiliary/proc_macro_attr.rs +#![warn(clippy::empty_line_after_outer_attr, clippy::empty_line_after_doc_comments)] + +//~v empty_line_after_outer_attr +#[crate_type = "lib"] +fn first_in_crate() {} + +#[macro_use] +extern crate proc_macro_attr; + +//~v empty_line_after_outer_attr +#[inline] +/// some comment +fn with_one_newline_and_comment() {} + +#[inline] +/// some comment +fn with_no_newline_and_comment() {} + +//~v empty_line_after_outer_attr +#[inline] +fn with_one_newline() {} + +#[rustfmt::skip] +mod two_lines { + //~v empty_line_after_outer_attr + #[crate_type = "lib"] + fn with_two_newlines() {} +} + +//~v empty_line_after_outer_attr +#[doc = "doc attributes should be considered attributes"] +enum Baz { + One, + Two, +} + +//~v empty_line_after_outer_attr +#[repr(C)] +struct Foo { + one: isize, + two: isize, +} + +//~v empty_line_after_outer_attr +#[allow(dead_code)] +mod foo {} + +//~v empty_line_after_outer_attr +#[inline] +// Still lint cases where the empty line does not immediately follow the attribute +fn comment_before_empty_line() {} + +#[doc = " +Returns the escaped value of the textual representation of + +"] +pub fn function() -> bool { + true +} + +#[derive(Clone, Copy)] +pub enum FooFighter { + Bar1, + + Bar2, + + Bar3, + + Bar4, +} + +#[crate_type = "lib"] +/* + +*/ +pub struct EmptyLineInBlockComment; + +#[crate_type = "lib"] +/* test */ +pub struct BlockComment; + +// See https://github.com/rust-lang/rust-clippy/issues/5567 +#[rustfmt::skip] +#[fake_async_trait] +pub trait Bazz { + fn foo() -> Vec { + let _i = ""; + + + + vec![] + } +} + +#[derive(Clone, Copy)] +#[dummy(string = "first line + +second line +")] +pub struct Args; + +fn main() {} diff --git a/tests/ui/empty_line_after/outer_attribute.2.fixed b/tests/ui/empty_line_after/outer_attribute.2.fixed new file mode 100644 index 00000000000..1b044d2fcde --- /dev/null +++ b/tests/ui/empty_line_after/outer_attribute.2.fixed @@ -0,0 +1,106 @@ +//@aux-build:../auxiliary/proc_macro_attr.rs +#![warn(clippy::empty_line_after_outer_attr, clippy::empty_line_after_doc_comments)] + +//~v empty_line_after_outer_attr +#![crate_type = "lib"] + +fn first_in_crate() {} + +#[macro_use] +extern crate proc_macro_attr; + +//~v empty_line_after_outer_attr +#[inline] +/// some comment +fn with_one_newline_and_comment() {} + +#[inline] +/// some comment +fn with_no_newline_and_comment() {} + +//~v empty_line_after_outer_attr +#[inline] +fn with_one_newline() {} + +#[rustfmt::skip] +mod two_lines { + //~v empty_line_after_outer_attr + #![crate_type = "lib"] + + + fn with_two_newlines() {} +} + +//~v empty_line_after_outer_attr +#[doc = "doc attributes should be considered attributes"] +enum Baz { + One, + Two, +} + +//~v empty_line_after_outer_attr +#[repr(C)] +struct Foo { + one: isize, + two: isize, +} + +//~v empty_line_after_outer_attr +#[allow(dead_code)] +mod foo {} + +//~v empty_line_after_outer_attr +#[inline] +// Still lint cases where the empty line does not immediately follow the attribute +fn comment_before_empty_line() {} + +#[doc = " +Returns the escaped value of the textual representation of + +"] +pub fn function() -> bool { + true +} + +#[derive(Clone, Copy)] +pub enum FooFighter { + Bar1, + + Bar2, + + Bar3, + + Bar4, +} + +#[crate_type = "lib"] +/* + +*/ +pub struct EmptyLineInBlockComment; + +#[crate_type = "lib"] +/* test */ +pub struct BlockComment; + +// See https://github.com/rust-lang/rust-clippy/issues/5567 +#[rustfmt::skip] +#[fake_async_trait] +pub trait Bazz { + fn foo() -> Vec { + let _i = ""; + + + + vec![] + } +} + +#[derive(Clone, Copy)] +#[dummy(string = "first line + +second line +")] +pub struct Args; + +fn main() {} diff --git a/tests/ui/empty_line_after/outer_attribute.rs b/tests/ui/empty_line_after/outer_attribute.rs new file mode 100644 index 00000000000..81e1a7ab8ed --- /dev/null +++ b/tests/ui/empty_line_after/outer_attribute.rs @@ -0,0 +1,112 @@ +//@aux-build:../auxiliary/proc_macro_attr.rs +#![warn(clippy::empty_line_after_outer_attr, clippy::empty_line_after_doc_comments)] + +//~v empty_line_after_outer_attr +#[crate_type = "lib"] + +fn first_in_crate() {} + +#[macro_use] +extern crate proc_macro_attr; + +//~v empty_line_after_outer_attr +#[inline] + +/// some comment +fn with_one_newline_and_comment() {} + +#[inline] +/// some comment +fn with_no_newline_and_comment() {} + +//~v empty_line_after_outer_attr +#[inline] + +fn with_one_newline() {} + +#[rustfmt::skip] +mod two_lines { + //~v empty_line_after_outer_attr + #[crate_type = "lib"] + + + fn with_two_newlines() {} +} + +//~v empty_line_after_outer_attr +#[doc = "doc attributes should be considered attributes"] + +enum Baz { + One, + Two, +} + +//~v empty_line_after_outer_attr +#[repr(C)] + +struct Foo { + one: isize, + two: isize, +} + +//~v empty_line_after_outer_attr +#[allow(dead_code)] + +mod foo {} + +//~v empty_line_after_outer_attr +#[inline] +// Still lint cases where the empty line does not immediately follow the attribute + +fn comment_before_empty_line() {} + +#[doc = " +Returns the escaped value of the textual representation of + +"] +pub fn function() -> bool { + true +} + +#[derive(Clone, Copy)] +pub enum FooFighter { + Bar1, + + Bar2, + + Bar3, + + Bar4, +} + +#[crate_type = "lib"] +/* + +*/ +pub struct EmptyLineInBlockComment; + +#[crate_type = "lib"] +/* test */ +pub struct BlockComment; + +// See https://github.com/rust-lang/rust-clippy/issues/5567 +#[rustfmt::skip] +#[fake_async_trait] +pub trait Bazz { + fn foo() -> Vec { + let _i = ""; + + + + vec![] + } +} + +#[derive(Clone, Copy)] +#[dummy(string = "first line + +second line +")] +pub struct Args; + +fn main() {} diff --git a/tests/ui/empty_line_after/outer_attribute.stderr b/tests/ui/empty_line_after/outer_attribute.stderr new file mode 100644 index 00000000000..b73ebb4f662 --- /dev/null +++ b/tests/ui/empty_line_after/outer_attribute.stderr @@ -0,0 +1,103 @@ +error: empty line after outer attribute + --> tests/ui/empty_line_after/outer_attribute.rs:5:1 + | +LL | / #[crate_type = "lib"] +LL | | + | |_ +LL | fn first_in_crate() {} + | ------------------- the attribute applies to this function + | + = note: `-D clippy::empty-line-after-outer-attr` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::empty_line_after_outer_attr)]` + = help: if the empty line is unintentional remove it +help: if the attribute should apply to the crate use an inner attribute + | +LL | #![crate_type = "lib"] + | + + +error: empty line after outer attribute + --> tests/ui/empty_line_after/outer_attribute.rs:13:1 + | +LL | / #[inline] +LL | | + | |_ +LL | /// some comment +LL | fn with_one_newline_and_comment() {} + | --------------------------------- the attribute applies to this function + | + = help: if the empty line is unintentional remove it + +error: empty line after outer attribute + --> tests/ui/empty_line_after/outer_attribute.rs:23:1 + | +LL | / #[inline] +LL | | + | |_ +LL | fn with_one_newline() {} + | --------------------- the attribute applies to this function + | + = help: if the empty line is unintentional remove it + +error: empty lines after outer attribute + --> tests/ui/empty_line_after/outer_attribute.rs:30:5 + | +LL | / #[crate_type = "lib"] +LL | | +LL | | + | |_ +LL | fn with_two_newlines() {} + | ---------------------- the attribute applies to this function + | + = help: if the empty lines are unintentional remove them +help: if the attribute should apply to the parent module use an inner attribute + | +LL | #![crate_type = "lib"] + | + + +error: empty line after outer attribute + --> tests/ui/empty_line_after/outer_attribute.rs:37:1 + | +LL | / #[doc = "doc attributes should be considered attributes"] +LL | | + | |_ +LL | enum Baz { + | -------- the attribute applies to this enum + | + = help: if the empty line is unintentional remove it + +error: empty line after outer attribute + --> tests/ui/empty_line_after/outer_attribute.rs:45:1 + | +LL | / #[repr(C)] +LL | | + | |_ +LL | struct Foo { + | ---------- the attribute applies to this struct + | + = help: if the empty line is unintentional remove it + +error: empty line after outer attribute + --> tests/ui/empty_line_after/outer_attribute.rs:53:1 + | +LL | / #[allow(dead_code)] +LL | | + | |_ +LL | mod foo {} + | ------- the attribute applies to this module + | + = help: if the empty line is unintentional remove it + +error: empty line after outer attribute + --> tests/ui/empty_line_after/outer_attribute.rs:58:1 + | +LL | / #[inline] +LL | | // Still lint cases where the empty line does not immediately follow the attribute +LL | | + | |_ +LL | fn comment_before_empty_line() {} + | ------------------------------ the attribute applies to this function + | + = help: if the empty line is unintentional remove it + +error: aborting due to 8 previous errors + diff --git a/tests/ui/empty_line_after_doc_comments.rs b/tests/ui/empty_line_after_doc_comments.rs deleted file mode 100644 index dd78491749c..00000000000 --- a/tests/ui/empty_line_after_doc_comments.rs +++ /dev/null @@ -1,132 +0,0 @@ -//@aux-build:proc_macro_attr.rs -#![warn(clippy::empty_line_after_doc_comments)] -#![allow(clippy::assertions_on_constants, clippy::duplicated_attributes)] -#![feature(custom_inner_attributes)] -#![rustfmt::skip] - -#[macro_use] -extern crate proc_macro_attr; - -mod some_mod { - //! This doc comment should *NOT* produce a warning - - mod some_inner_mod { - fn some_noop() {} - } -} - -/// This should produce a warning - -fn with_doc_and_newline() { assert!(true)} - -// This should *NOT* produce a warning -#[crate_type = "lib"] - -/// some comment -fn with_one_newline_and_comment() { assert!(true) } - -// This should *NOT* produce a warning -#[crate_type = "lib"] -/// some comment -fn with_no_newline_and_comment() { assert!(true) } - - -// This should *NOT* produce a warning -#[crate_type = "lib"] - -fn with_one_newline() { assert!(true) } - -// This should *NOT* produce a warning -#[crate_type = "lib"] - - -fn with_two_newlines() { assert!(true) } - - -// This should *NOT* produce a warning -#[crate_type = "lib"] - -enum Baz { - One, - Two -} - -// This should *NOT* produce a warning -#[crate_type = "lib"] - -struct Foo { - one: isize, - two: isize -} - -// This should *NOT* produce a warning -#[crate_type = "lib"] - -mod foo { -} - -/// This doc comment should produce a warning - -/** This is also a doc comment and should produce a warning - */ - -// This should *NOT* produce a warning -#[allow(non_camel_case_types)] -#[allow(missing_docs)] -#[allow(missing_docs)] -fn three_attributes() { assert!(true) } - -// This should *NOT* produce a warning -#[doc = " -Returns the escaped value of the textual representation of - -"] -pub fn function() -> bool { - true -} - -// This should *NOT* produce a warning -#[derive(Clone, Copy)] -pub enum FooFighter { - Bar1, - - Bar2, - - Bar3, - - Bar4 -} - -// This should *NOT* produce a warning because the empty line is inside a block comment -#[crate_type = "lib"] -/* - -*/ -pub struct S; - -// This should *NOT* produce a warning -#[crate_type = "lib"] -/* test */ -pub struct T; - -// This should *NOT* produce a warning -// See https://github.com/rust-lang/rust-clippy/issues/5567 -#[fake_async_trait] -pub trait Bazz { - fn foo() -> Vec { - let _i = ""; - - - - vec![] - } -} - -#[derive(Clone, Copy)] -#[dummy(string = "first line - -second line -")] -pub struct Args; - -fn main() {} diff --git a/tests/ui/empty_line_after_doc_comments.stderr b/tests/ui/empty_line_after_doc_comments.stderr deleted file mode 100644 index 889ccf6ba19..00000000000 --- a/tests/ui/empty_line_after_doc_comments.stderr +++ /dev/null @@ -1,37 +0,0 @@ -error: found an empty line after a doc comment. Perhaps you need to use `//!` to make a comment on a module, remove the empty line, or make a regular comment with `//`? - --> tests/ui/empty_line_after_doc_comments.rs:18:1 - | -LL | / /// This should produce a warning -LL | | -LL | | fn with_doc_and_newline() { assert!(true)} - | |_ - | - = note: `-D clippy::empty-line-after-doc-comments` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::empty_line_after_doc_comments)]` - -error: found an empty line after a doc comment. Perhaps you need to use `//!` to make a comment on a module, remove the empty line, or make a regular comment with `//`? - --> tests/ui/empty_line_after_doc_comments.rs:68:1 - | -LL | / /// This doc comment should produce a warning -LL | | -LL | | /** This is also a doc comment and should produce a warning -LL | | */ -... | -LL | | #[allow(missing_docs)] -LL | | fn three_attributes() { assert!(true) } - | |_ - -error: found an empty line after a doc comment. Perhaps you need to use `//!` to make a comment on a module, remove the empty line, or make a regular comment with `//`? - --> tests/ui/empty_line_after_doc_comments.rs:70:1 - | -LL | / /** This is also a doc comment and should produce a warning -LL | | */ -LL | | -LL | | // This should *NOT* produce a warning -... | -LL | | #[allow(missing_docs)] -LL | | fn three_attributes() { assert!(true) } - | |_ - -error: aborting due to 3 previous errors - diff --git a/tests/ui/empty_line_after_outer_attribute.rs b/tests/ui/empty_line_after_outer_attribute.rs deleted file mode 100644 index f147cf2cd5d..00000000000 --- a/tests/ui/empty_line_after_outer_attribute.rs +++ /dev/null @@ -1,120 +0,0 @@ -//@aux-build:proc_macro_attr.rs -#![warn(clippy::empty_line_after_outer_attr)] -#![allow(clippy::assertions_on_constants, clippy::duplicated_attributes)] -#![feature(custom_inner_attributes)] -#![rustfmt::skip] - -#[macro_use] -extern crate proc_macro_attr; - -// This should produce a warning -#[crate_type = "lib"] - -/// some comment -fn with_one_newline_and_comment() { assert!(true) } - -// This should not produce a warning -#[crate_type = "lib"] -/// some comment -fn with_no_newline_and_comment() { assert!(true) } - - -// This should produce a warning -#[crate_type = "lib"] - -fn with_one_newline() { assert!(true) } - -// This should produce a warning, too -#[crate_type = "lib"] - - -fn with_two_newlines() { assert!(true) } - - -// This should produce a warning -#[crate_type = "lib"] - -enum Baz { - One, - Two -} - -// This should produce a warning -#[crate_type = "lib"] - -struct Foo { - one: isize, - two: isize -} - -// This should produce a warning -#[crate_type = "lib"] - -mod foo { -} - -/// This doc comment should not produce a warning - -/** This is also a doc comment and should not produce a warning - */ - -// This should not produce a warning -#[allow(non_camel_case_types)] -#[allow(missing_docs)] -#[allow(missing_docs)] -fn three_attributes() { assert!(true) } - -// This should not produce a warning -#[doc = " -Returns the escaped value of the textual representation of - -"] -pub fn function() -> bool { - true -} - -// This should not produce a warning -#[derive(Clone, Copy)] -pub enum FooFighter { - Bar1, - - Bar2, - - Bar3, - - Bar4 -} - -// This should not produce a warning because the empty line is inside a block comment -#[crate_type = "lib"] -/* - -*/ -pub struct S; - -// This should not produce a warning -#[crate_type = "lib"] -/* test */ -pub struct T; - -// This should not produce a warning -// See https://github.com/rust-lang/rust-clippy/issues/5567 -#[fake_async_trait] -pub trait Bazz { - fn foo() -> Vec { - let _i = ""; - - - - vec![] - } -} - -#[derive(Clone, Copy)] -#[dummy(string = "first line - -second line -")] -pub struct Args; - -fn main() {} diff --git a/tests/ui/empty_line_after_outer_attribute.stderr b/tests/ui/empty_line_after_outer_attribute.stderr deleted file mode 100644 index b43e6e30da2..00000000000 --- a/tests/ui/empty_line_after_outer_attribute.stderr +++ /dev/null @@ -1,54 +0,0 @@ -error: found an empty line after an outer attribute. Perhaps you forgot to add a `!` to make it an inner attribute? - --> tests/ui/empty_line_after_outer_attribute.rs:11:1 - | -LL | / #[crate_type = "lib"] -LL | | -LL | | /// some comment -LL | | fn with_one_newline_and_comment() { assert!(true) } - | |_ - | - = note: `-D clippy::empty-line-after-outer-attr` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::empty_line_after_outer_attr)]` - -error: found an empty line after an outer attribute. Perhaps you forgot to add a `!` to make it an inner attribute? - --> tests/ui/empty_line_after_outer_attribute.rs:23:1 - | -LL | / #[crate_type = "lib"] -LL | | -LL | | fn with_one_newline() { assert!(true) } - | |_ - -error: found an empty line after an outer attribute. Perhaps you forgot to add a `!` to make it an inner attribute? - --> tests/ui/empty_line_after_outer_attribute.rs:28:1 - | -LL | / #[crate_type = "lib"] -... | -LL | | fn with_two_newlines() { assert!(true) } - | |_ - -error: found an empty line after an outer attribute. Perhaps you forgot to add a `!` to make it an inner attribute? - --> tests/ui/empty_line_after_outer_attribute.rs:35:1 - | -LL | / #[crate_type = "lib"] -LL | | -LL | | enum Baz { - | |_ - -error: found an empty line after an outer attribute. Perhaps you forgot to add a `!` to make it an inner attribute? - --> tests/ui/empty_line_after_outer_attribute.rs:43:1 - | -LL | / #[crate_type = "lib"] -LL | | -LL | | struct Foo { - | |_ - -error: found an empty line after an outer attribute. Perhaps you forgot to add a `!` to make it an inner attribute? - --> tests/ui/empty_line_after_outer_attribute.rs:51:1 - | -LL | / #[crate_type = "lib"] -LL | | -LL | | mod foo { - | |_ - -error: aborting due to 6 previous errors - diff --git a/tests/ui/exit1.rs b/tests/ui/exit1.rs index a89f6dd4ca0..36b3c42fd99 100644 --- a/tests/ui/exit1.rs +++ b/tests/ui/exit1.rs @@ -1,4 +1,4 @@ -#[warn(clippy::exit)] +#![warn(clippy::exit)] fn not_main() { if true { diff --git a/tests/ui/exit2.rs b/tests/ui/exit2.rs index d5ff93fb9cc..9bbb7b073a4 100644 --- a/tests/ui/exit2.rs +++ b/tests/ui/exit2.rs @@ -1,4 +1,4 @@ -#[warn(clippy::exit)] +#![warn(clippy::exit)] fn also_not_main() { std::process::exit(3); diff --git a/tests/ui/exit3.rs b/tests/ui/exit3.rs index 9dc0e1015a4..cab908aafd3 100644 --- a/tests/ui/exit3.rs +++ b/tests/ui/exit3.rs @@ -1,4 +1,4 @@ -#[warn(clippy::exit)] +#![warn(clippy::exit)] fn main() { if true { diff --git a/tests/ui/expect_fun_call.fixed b/tests/ui/expect_fun_call.fixed index 6ac3c43ad29..8f800c71941 100644 --- a/tests/ui/expect_fun_call.fixed +++ b/tests/ui/expect_fun_call.fixed @@ -5,8 +5,6 @@ clippy::unnecessary_literal_unwrap )] -/// Checks implementation of the `EXPECT_FUN_CALL` lint - macro_rules! one { () => { 1 diff --git a/tests/ui/expect_fun_call.rs b/tests/ui/expect_fun_call.rs index 22ea2db504f..b5cfafb2993 100644 --- a/tests/ui/expect_fun_call.rs +++ b/tests/ui/expect_fun_call.rs @@ -5,8 +5,6 @@ clippy::unnecessary_literal_unwrap )] -/// Checks implementation of the `EXPECT_FUN_CALL` lint - macro_rules! one { () => { 1 diff --git a/tests/ui/expect_fun_call.stderr b/tests/ui/expect_fun_call.stderr index b41904d04fa..bae853ac5c1 100644 --- a/tests/ui/expect_fun_call.stderr +++ b/tests/ui/expect_fun_call.stderr @@ -1,5 +1,5 @@ error: use of `expect` followed by a function call - --> tests/ui/expect_fun_call.rs:37:26 + --> tests/ui/expect_fun_call.rs:35:26 | LL | with_none_and_format.expect(&format!("Error {}: fake error", error_code)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| panic!("Error {}: fake error", error_code))` @@ -8,85 +8,85 @@ LL | with_none_and_format.expect(&format!("Error {}: fake error", error_code = help: to override `-D warnings` add `#[allow(clippy::expect_fun_call)]` error: use of `expect` followed by a function call - --> tests/ui/expect_fun_call.rs:40:26 + --> tests/ui/expect_fun_call.rs:38:26 | LL | with_none_and_as_str.expect(format!("Error {}: fake error", error_code).as_str()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| panic!("Error {}: fake error", error_code))` error: use of `expect` followed by a function call - --> tests/ui/expect_fun_call.rs:43:37 + --> tests/ui/expect_fun_call.rs:41:37 | LL | with_none_and_format_with_macro.expect(format!("Error {}: fake error", one!()).as_str()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| panic!("Error {}: fake error", one!()))` error: use of `expect` followed by a function call - --> tests/ui/expect_fun_call.rs:53:25 + --> tests/ui/expect_fun_call.rs:51:25 | LL | with_err_and_format.expect(&format!("Error {}: fake error", error_code)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|_| panic!("Error {}: fake error", error_code))` error: use of `expect` followed by a function call - --> tests/ui/expect_fun_call.rs:56:25 + --> tests/ui/expect_fun_call.rs:54:25 | LL | with_err_and_as_str.expect(format!("Error {}: fake error", error_code).as_str()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|_| panic!("Error {}: fake error", error_code))` error: use of `expect` followed by a function call - --> tests/ui/expect_fun_call.rs:68:17 + --> tests/ui/expect_fun_call.rs:66:17 | LL | Some("foo").expect(format!("{} {}", 1, 2).as_ref()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| panic!("{} {}", 1, 2))` error: use of `expect` followed by a function call - --> tests/ui/expect_fun_call.rs:89:21 + --> tests/ui/expect_fun_call.rs:87:21 | LL | Some("foo").expect(&get_string()); | ^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| { panic!("{}", get_string()) })` error: use of `expect` followed by a function call - --> tests/ui/expect_fun_call.rs:90:21 + --> tests/ui/expect_fun_call.rs:88:21 | LL | Some("foo").expect(get_string().as_ref()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| { panic!("{}", get_string()) })` error: use of `expect` followed by a function call - --> tests/ui/expect_fun_call.rs:91:21 + --> tests/ui/expect_fun_call.rs:89:21 | LL | Some("foo").expect(get_string().as_str()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| { panic!("{}", get_string()) })` error: use of `expect` followed by a function call - --> tests/ui/expect_fun_call.rs:93:21 + --> tests/ui/expect_fun_call.rs:91:21 | LL | Some("foo").expect(get_static_str()); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| { panic!("{}", get_static_str()) })` error: use of `expect` followed by a function call - --> tests/ui/expect_fun_call.rs:94:21 + --> tests/ui/expect_fun_call.rs:92:21 | LL | Some("foo").expect(get_non_static_str(&0)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| { panic!("{}", get_non_static_str(&0).to_string()) })` error: use of `expect` followed by a function call - --> tests/ui/expect_fun_call.rs:98:16 + --> tests/ui/expect_fun_call.rs:96:16 | LL | Some(true).expect(&format!("key {}, {}", 1, 2)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| panic!("key {}, {}", 1, 2))` error: use of `expect` followed by a function call - --> tests/ui/expect_fun_call.rs:104:17 + --> tests/ui/expect_fun_call.rs:102:17 | LL | opt_ref.expect(&format!("{:?}", opt_ref)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| panic!("{:?}", opt_ref))` error: use of `expect` followed by a function call - --> tests/ui/expect_fun_call.rs:108:20 + --> tests/ui/expect_fun_call.rs:106:20 | LL | format_capture.expect(&format!("{error_code}")); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| panic!("{error_code}"))` error: use of `expect` followed by a function call - --> tests/ui/expect_fun_call.rs:111:30 + --> tests/ui/expect_fun_call.rs:109:30 | LL | format_capture_and_value.expect(&format!("{error_code}, {}", 1)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| panic!("{error_code}, {}", 1))` diff --git a/tests/ui/match_overlapping_arm.rs b/tests/ui/match_overlapping_arm.rs index 4457ae73da2..a056fdeaa5d 100644 --- a/tests/ui/match_overlapping_arm.rs +++ b/tests/ui/match_overlapping_arm.rs @@ -2,8 +2,6 @@ #![allow(clippy::redundant_pattern_matching)] #![allow(clippy::if_same_then_else, clippy::equatable_if_let, clippy::needless_if)] -/// Tests for match_overlapping_arm - fn overlapping() { const FOO: u64 = 2; diff --git a/tests/ui/match_overlapping_arm.stderr b/tests/ui/match_overlapping_arm.stderr index 65092ffbb55..a60a09a0799 100644 --- a/tests/ui/match_overlapping_arm.stderr +++ b/tests/ui/match_overlapping_arm.stderr @@ -1,11 +1,11 @@ error: some ranges overlap - --> tests/ui/match_overlapping_arm.rs:11:9 + --> tests/ui/match_overlapping_arm.rs:9:9 | LL | 0..=10 => println!("0..=10"), | ^^^^^^ | note: overlaps with this - --> tests/ui/match_overlapping_arm.rs:13:9 + --> tests/ui/match_overlapping_arm.rs:11:9 | LL | 0..=11 => println!("0..=11"), | ^^^^^^ @@ -13,85 +13,85 @@ LL | 0..=11 => println!("0..=11"), = help: to override `-D warnings` add `#[allow(clippy::match_overlapping_arm)]` error: some ranges overlap - --> tests/ui/match_overlapping_arm.rs:18:9 + --> tests/ui/match_overlapping_arm.rs:16:9 | LL | 0..=5 => println!("0..=5"), | ^^^^^ | note: overlaps with this - --> tests/ui/match_overlapping_arm.rs:21:9 + --> tests/ui/match_overlapping_arm.rs:19:9 | LL | FOO..=11 => println!("FOO..=11"), | ^^^^^^^^ error: some ranges overlap - --> tests/ui/match_overlapping_arm.rs:56:9 + --> tests/ui/match_overlapping_arm.rs:54:9 | LL | 0..11 => println!("0..11"), | ^^^^^ | note: overlaps with this - --> tests/ui/match_overlapping_arm.rs:58:9 + --> tests/ui/match_overlapping_arm.rs:56:9 | LL | 0..=11 => println!("0..=11"), | ^^^^^^ error: some ranges overlap - --> tests/ui/match_overlapping_arm.rs:82:9 + --> tests/ui/match_overlapping_arm.rs:80:9 | LL | 0..=10 => println!("0..=10"), | ^^^^^^ | note: overlaps with this - --> tests/ui/match_overlapping_arm.rs:81:9 + --> tests/ui/match_overlapping_arm.rs:79:9 | LL | 5..14 => println!("5..14"), | ^^^^^ error: some ranges overlap - --> tests/ui/match_overlapping_arm.rs:88:9 + --> tests/ui/match_overlapping_arm.rs:86:9 | LL | 0..7 => println!("0..7"), | ^^^^ | note: overlaps with this - --> tests/ui/match_overlapping_arm.rs:90:9 + --> tests/ui/match_overlapping_arm.rs:88:9 | LL | 0..=10 => println!("0..=10"), | ^^^^^^ error: some ranges overlap - --> tests/ui/match_overlapping_arm.rs:101:9 + --> tests/ui/match_overlapping_arm.rs:99:9 | LL | ..=23 => println!("..=23"), | ^^^^^ | note: overlaps with this - --> tests/ui/match_overlapping_arm.rs:103:9 + --> tests/ui/match_overlapping_arm.rs:101:9 | LL | ..26 => println!("..26"), | ^^^^ error: some ranges overlap - --> tests/ui/match_overlapping_arm.rs:111:9 + --> tests/ui/match_overlapping_arm.rs:109:9 | LL | 21..=30 => (), | ^^^^^^^ | note: overlaps with this - --> tests/ui/match_overlapping_arm.rs:113:9 + --> tests/ui/match_overlapping_arm.rs:111:9 | LL | 21..=40 => (), | ^^^^^^^ error: some ranges overlap - --> tests/ui/match_overlapping_arm.rs:126:9 + --> tests/ui/match_overlapping_arm.rs:124:9 | LL | 0..=0x0000_0000_0000_00ff => (), | ^^^^^^^^^^^^^^^^^^^^^^^^^ | note: overlaps with this - --> tests/ui/match_overlapping_arm.rs:128:9 + --> tests/ui/match_overlapping_arm.rs:126:9 | LL | 0..=0x0000_0000_0000_ffff => (), | ^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/string_slice.rs b/tests/ui/string_slice.rs index 1d1911aaa1d..dc519493a4d 100644 --- a/tests/ui/string_slice.rs +++ b/tests/ui/string_slice.rs @@ -1,7 +1,7 @@ -use std::borrow::Cow; +#![warn(clippy::string_slice)] +#![allow(clippy::no_effect)] -#[warn(clippy::string_slice)] -#[allow(clippy::no_effect)] +use std::borrow::Cow; fn main() { &"Ölkanne"[1..]; diff --git a/tests/ui/tabs_in_doc_comments.fixed b/tests/ui/tabs_in_doc_comments.fixed index 26cc5c27e88..3536c1746df 100644 --- a/tests/ui/tabs_in_doc_comments.fixed +++ b/tests/ui/tabs_in_doc_comments.fixed @@ -1,5 +1,4 @@ #![warn(clippy::tabs_in_doc_comments)] -#[allow(dead_code)] /// /// Struct to hold two strings: diff --git a/tests/ui/tabs_in_doc_comments.rs b/tests/ui/tabs_in_doc_comments.rs index 14b06966ecc..033a685066e 100644 --- a/tests/ui/tabs_in_doc_comments.rs +++ b/tests/ui/tabs_in_doc_comments.rs @@ -1,5 +1,4 @@ #![warn(clippy::tabs_in_doc_comments)] -#[allow(dead_code)] /// /// Struct to hold two strings: diff --git a/tests/ui/tabs_in_doc_comments.stderr b/tests/ui/tabs_in_doc_comments.stderr index aef6c391452..f8d30b728e5 100644 --- a/tests/ui/tabs_in_doc_comments.stderr +++ b/tests/ui/tabs_in_doc_comments.stderr @@ -1,5 +1,5 @@ error: using tabs in doc comments is not recommended - --> tests/ui/tabs_in_doc_comments.rs:6:5 + --> tests/ui/tabs_in_doc_comments.rs:5:5 | LL | /// - first one | ^^^^ help: consider using four spaces per tab @@ -8,43 +8,43 @@ LL | /// - first one = help: to override `-D warnings` add `#[allow(clippy::tabs_in_doc_comments)]` error: using tabs in doc comments is not recommended - --> tests/ui/tabs_in_doc_comments.rs:6:13 + --> tests/ui/tabs_in_doc_comments.rs:5:13 | LL | /// - first one | ^^^^^^^^ help: consider using four spaces per tab error: using tabs in doc comments is not recommended - --> tests/ui/tabs_in_doc_comments.rs:7:5 + --> tests/ui/tabs_in_doc_comments.rs:6:5 | LL | /// - second one | ^^^^ help: consider using four spaces per tab error: using tabs in doc comments is not recommended - --> tests/ui/tabs_in_doc_comments.rs:7:14 + --> tests/ui/tabs_in_doc_comments.rs:6:14 | LL | /// - second one | ^^^^ help: consider using four spaces per tab error: using tabs in doc comments is not recommended - --> tests/ui/tabs_in_doc_comments.rs:10:9 + --> tests/ui/tabs_in_doc_comments.rs:9:9 | LL | /// - First String: | ^^^^ help: consider using four spaces per tab error: using tabs in doc comments is not recommended - --> tests/ui/tabs_in_doc_comments.rs:11:9 + --> tests/ui/tabs_in_doc_comments.rs:10:9 | LL | /// - needs to be inside here | ^^^^^^^^ help: consider using four spaces per tab error: using tabs in doc comments is not recommended - --> tests/ui/tabs_in_doc_comments.rs:14:9 + --> tests/ui/tabs_in_doc_comments.rs:13:9 | LL | /// - Second String: | ^^^^ help: consider using four spaces per tab error: using tabs in doc comments is not recommended - --> tests/ui/tabs_in_doc_comments.rs:15:9 + --> tests/ui/tabs_in_doc_comments.rs:14:9 | LL | /// - needs to be inside here | ^^^^^^^^ help: consider using four spaces per tab From 173d5a6af0f2352b3efa0b3a2faad87207706936 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Sat, 24 Aug 2024 17:34:45 -0400 Subject: [PATCH 043/683] Merge commit '0f8eabd6231366bfc1bb1464601297c2d48f8f68' into clippyup --- .cargo/config.toml | 6 +- .github/deploy.sh | 1 + .github/workflows/clippy_bors.yml | 5 - CHANGELOG.md | 1 + Cargo.toml | 4 +- book/src/development/adding_lints.md | 2 +- book/src/lint_configuration.md | 8 +- clippy_config/Cargo.toml | 1 - clippy_config/src/conf.rs | 23 +- clippy_config/src/lib.rs | 2 +- clippy_config/src/msrvs.rs | 17 +- clippy_dev/src/main.rs | 1 + clippy_dev/src/update_lints.rs | 2 +- clippy_lints/Cargo.toml | 1 - clippy_lints/src/absolute_paths.rs | 95 +- clippy_lints/src/approx_const.rs | 3 +- clippy_lints/src/assigning_clones.rs | 3 +- clippy_lints/src/attrs/empty_line_after.rs | 4 +- clippy_lints/src/attrs/mod.rs | 6 +- clippy_lints/src/attrs/non_minimal_cfg.rs | 11 +- .../src/attrs/unnecessary_clippy_cfg.rs | 11 +- clippy_lints/src/attrs/useless_attribute.rs | 10 +- clippy_lints/src/booleans.rs | 33 +- clippy_lints/src/borrow_deref_ref.rs | 7 +- clippy_lints/src/cargo/common_metadata.rs | 2 - clippy_lints/src/cargo/mod.rs | 6 +- .../src/cargo/multiple_crate_versions.rs | 2 - clippy_lints/src/casts/as_ptr_cast_mut.rs | 4 +- clippy_lints/src/casts/cast_lossless.rs | 4 +- .../src/casts/cast_possible_truncation.rs | 6 +- .../src/casts/fn_to_numeric_cast_any.rs | 5 +- clippy_lints/src/casts/unnecessary_cast.rs | 8 +- clippy_lints/src/casts/zero_ptr.rs | 4 +- clippy_lints/src/cfg_not_test.rs | 2 +- clippy_lints/src/checked_conversions.rs | 2 - clippy_lints/src/cognitive_complexity.rs | 2 - clippy_lints/src/collapsible_if.rs | 14 - clippy_lints/src/collection_is_never_read.rs | 37 +- clippy_lints/src/create_dir.rs | 5 +- clippy_lints/src/declared_lints.rs | 5 +- clippy_lints/src/doc/lazy_continuation.rs | 11 +- clippy_lints/src/doc/markdown.rs | 19 +- clippy_lints/src/doc/mod.rs | 120 +- .../src/doc/too_long_first_doc_paragraph.rs | 91 ++ clippy_lints/src/else_if_without_else.rs | 2 - clippy_lints/src/empty_enum.rs | 2 - clippy_lints/src/enum_clike.rs | 3 - clippy_lints/src/eta_reduction.rs | 4 +- clippy_lints/src/float_literal.rs | 8 +- clippy_lints/src/format.rs | 6 +- clippy_lints/src/format_args.rs | 33 +- clippy_lints/src/format_impl.rs | 2 +- clippy_lints/src/from_over_into.rs | 12 +- clippy_lints/src/from_str_radix_10.rs | 4 +- .../src/functions/impl_trait_in_params.rs | 11 +- clippy_lints/src/functions/must_use.rs | 16 +- clippy_lints/src/functions/too_many_lines.rs | 91 +- clippy_lints/src/if_not_else.rs | 3 - clippy_lints/src/implicit_return.rs | 13 +- clippy_lints/src/incompatible_msrv.rs | 15 +- .../src/inconsistent_struct_constructor.rs | 23 +- clippy_lints/src/indexing_slicing.rs | 2 - clippy_lints/src/infinite_iter.rs | 33 +- clippy_lints/src/inherent_impl.rs | 2 - clippy_lints/src/inline_fn_without_body.rs | 2 - clippy_lints/src/int_plus_one.rs | 8 +- clippy_lints/src/item_name_repetitions.rs | 2 - clippy_lints/src/items_after_statements.rs | 2 - clippy_lints/src/items_after_test_module.rs | 9 +- clippy_lints/src/large_enum_variant.rs | 2 - clippy_lints/src/large_stack_frames.rs | 4 +- clippy_lints/src/legacy_numeric_constants.rs | 5 +- clippy_lints/src/len_zero.rs | 4 +- clippy_lints/src/lib.rs | 48 +- clippy_lints/src/literal_representation.rs | 9 +- clippy_lints/src/loops/explicit_iter_loop.rs | 12 +- clippy_lints/src/macro_metavars_in_unsafe.rs | 21 +- clippy_lints/src/manual_async_fn.rs | 8 +- clippy_lints/src/manual_float_methods.rs | 4 +- clippy_lints/src/manual_hash_one.rs | 6 +- clippy_lints/src/manual_non_exhaustive.rs | 6 +- clippy_lints/src/manual_range_patterns.rs | 6 +- clippy_lints/src/manual_retain.rs | 33 +- clippy_lints/src/matches/collapsible_match.rs | 2 +- clippy_lints/src/matches/manual_unwrap_or.rs | 8 +- clippy_lints/src/matches/single_match.rs | 2 +- ...se_sensitive_file_extension_comparisons.rs | 12 +- .../src/methods/filter_map_bool_then.rs | 8 +- .../methods/from_iter_instead_of_collect.rs | 4 +- clippy_lints/src/methods/get_unwrap.rs | 3 +- .../src/methods/is_digit_ascii_radix.rs | 2 - .../src/methods/join_absolute_paths.rs | 4 +- clippy_lints/src/methods/manual_ok_or.rs | 8 +- clippy_lints/src/methods/manual_try_fold.rs | 10 +- clippy_lints/src/methods/mod.rs | 6 +- .../methods/needless_character_iteration.rs | 6 +- clippy_lints/src/methods/needless_collect.rs | 9 +- .../src/methods/needless_option_as_deref.rs | 4 +- .../src/methods/string_lit_chars_any.rs | 4 +- .../src/methods/unnecessary_get_then_check.rs | 10 +- .../src/methods/unnecessary_iter_cloned.rs | 8 +- .../src/methods/unnecessary_lazy_eval.rs | 4 +- .../src/methods/unnecessary_to_owned.rs | 18 +- .../src/methods/unused_enumerate_index.rs | 12 +- clippy_lints/src/min_ident_chars.rs | 4 +- .../src/misc_early/unneeded_field_pattern.rs | 27 +- .../src/missing_enforced_import_rename.rs | 4 +- clippy_lints/src/mut_key.rs | 14 +- clippy_lints/src/mutex_atomic.rs | 4 - clippy_lints/src/needless_bool.rs | 4 - clippy_lints/src/needless_continue.rs | 35 - clippy_lints/src/needless_if.rs | 4 +- clippy_lints/src/needless_late_init.rs | 11 +- clippy_lints/src/needless_pass_by_value.rs | 10 +- clippy_lints/src/no_effect.rs | 47 +- clippy_lints/src/non_copy_const.rs | 6 +- clippy_lints/src/nonstandard_macro_braces.rs | 6 +- .../src/operators/arithmetic_side_effects.rs | 2 +- .../src/operators/assign_op_pattern.rs | 6 +- .../src/operators/misrefactored_assign_op.rs | 6 +- clippy_lints/src/operators/mod.rs | 2 +- .../src/operators/needless_bitwise_bool.rs | 6 +- clippy_lints/src/operators/ptr_eq.rs | 6 +- clippy_lints/src/pathbuf_init_then_push.rs | 8 +- clippy_lints/src/ptr.rs | 16 +- clippy_lints/src/ptr_offset_with_cast.rs | 6 +- clippy_lints/src/redundant_clone.rs | 4 +- clippy_lints/src/reference.rs | 10 +- clippy_lints/src/regex.rs | 4 +- clippy_lints/src/returns.rs | 27 +- clippy_lints/src/single_range_in_vec_init.rs | 8 +- clippy_lints/src/size_of_in_element_count.rs | 3 - clippy_lints/src/std_instead_of_core.rs | 5 +- clippy_lints/src/strings.rs | 2 +- clippy_lints/src/trait_bounds.rs | 10 +- clippy_lints/src/unit_types/unit_arg.rs | 20 +- clippy_lints/src/unused_io_amount.rs | 9 +- clippy_lints/src/unused_unit.rs | 22 +- clippy_lints/src/unwrap.rs | 6 +- clippy_lints/src/use_self.rs | 2 +- clippy_lints/src/utils/author.rs | 3 - .../src/utils/format_args_collector.rs | 49 +- clippy_lints/src/utils/internal_lints.rs | 1 - .../internal_lints/lint_without_lint_pass.rs | 10 +- .../internal_lints/metadata_collector.rs | 1078 ----------------- clippy_lints/src/vec.rs | 8 +- clippy_lints/src/visibility.rs | 14 +- clippy_lints/src/wildcard_imports.rs | 6 +- clippy_lints/src/write.rs | 8 +- clippy_utils/Cargo.toml | 1 - clippy_utils/src/attrs.rs | 38 +- clippy_utils/src/check_proc_macro.rs | 12 +- clippy_utils/src/consts.rs | 2 +- clippy_utils/src/hir_utils.rs | 22 +- clippy_utils/src/lib.rs | 21 +- clippy_utils/src/macros.rs | 18 +- clippy_utils/src/qualify_min_const_fn.rs | 7 +- clippy_utils/src/source.rs | 107 +- clippy_utils/src/ty.rs | 25 +- declare_clippy_lint/src/lib.rs | 25 +- lintcheck/src/json.rs | 39 +- lintcheck/src/output.rs | 14 +- rust-toolchain | 2 +- tests/compile-test.rs | 391 ++++-- tests/config-metadata.rs | 78 ++ .../absolute_paths.allow_crates.stderr | 45 +- .../absolute_paths.allow_long.stderr | 14 + .../absolute_paths.default.stderr | 80 ++ .../absolute_paths.disallow_crates.stderr | 71 -- .../absolute_paths.no_short.stderr | 98 ++ .../ui-toml/absolute_paths/absolute_paths.rs | 184 +-- .../absolute_paths_2015.default.stderr | 14 + .../absolute_paths/absolute_paths_2015.rs | 16 + .../absolute_paths/allow_crates/clippy.toml | 3 +- .../absolute_paths/allow_long/clippy.toml | 1 + .../absolute_paths/auxiliary/helper.rs | 11 - .../absolute_paths/default/clippy.toml | 0 .../disallow_crates/clippy.toml | 1 - .../absolute_paths/no_short/clippy.toml | 1 + .../macro_metavars_in_unsafe/default/test.rs | 15 +- .../default/test.stderr | 16 +- tests/ui/assigning_clones.fixed | 20 + tests/ui/assigning_clones.rs | 20 + .../complex_conditionals_nested.stderr | 2 +- .../checked_unwrap/simple_conditionals.stderr | 26 +- tests/ui/collapsible_match.stderr | 2 +- tests/ui/crashes/ice-3717.fixed | 11 + tests/ui/crashes/ice-3717.rs | 2 - tests/ui/crashes/ice-3717.stderr | 2 +- .../declare_interior_mutable_const/others.rs | 17 + .../others.stderr | 10 +- tests/ui/doc/doc_markdown-issue_13097.fixed | 13 + tests/ui/doc/doc_markdown-issue_13097.rs | 13 + tests/ui/doc/doc_markdown-issue_13097.stderr | 18 + tests/ui/double_must_use.rs | 8 +- tests/ui/double_must_use.stderr | 16 +- tests/ui/explicit_iter_loop.fixed | 12 + tests/ui/explicit_iter_loop.rs | 12 + .../ui/inconsistent_struct_constructor.fixed | 21 + tests/ui/inconsistent_struct_constructor.rs | 21 + .../ui/inconsistent_struct_constructor.stderr | 4 +- tests/ui/min_rust_version_invalid_attr.rs | 2 +- tests/ui/min_rust_version_invalid_attr.stderr | 4 +- tests/ui/string_slice.rs | 5 + tests/ui/string_slice.stderr | 14 +- .../ui/too_long_first_doc_paragraph-fix.fixed | 9 + tests/ui/too_long_first_doc_paragraph-fix.rs | 8 + .../too_long_first_doc_paragraph-fix.stderr | 20 + tests/ui/too_long_first_doc_paragraph.rs | 53 + tests/ui/too_long_first_doc_paragraph.stderr | 22 + tests/ui/unnecessary_lazy_eval.stderr | 566 ++++++--- .../ui/unnecessary_lazy_eval_unfixable.stderr | 35 +- triagebot.toml | 1 + util/gh-pages/index.html | 393 +----- util/gh-pages/script.js | 100 +- util/gh-pages/style.css | 398 ++++++ 216 files changed, 3052 insertions(+), 2969 deletions(-) create mode 100644 clippy_lints/src/doc/too_long_first_doc_paragraph.rs delete mode 100644 clippy_lints/src/utils/internal_lints/metadata_collector.rs create mode 100644 tests/config-metadata.rs create mode 100644 tests/ui-toml/absolute_paths/absolute_paths.allow_long.stderr create mode 100644 tests/ui-toml/absolute_paths/absolute_paths.default.stderr delete mode 100644 tests/ui-toml/absolute_paths/absolute_paths.disallow_crates.stderr create mode 100644 tests/ui-toml/absolute_paths/absolute_paths.no_short.stderr create mode 100644 tests/ui-toml/absolute_paths/absolute_paths_2015.default.stderr create mode 100644 tests/ui-toml/absolute_paths/absolute_paths_2015.rs create mode 100644 tests/ui-toml/absolute_paths/allow_long/clippy.toml delete mode 100644 tests/ui-toml/absolute_paths/auxiliary/helper.rs create mode 100644 tests/ui-toml/absolute_paths/default/clippy.toml delete mode 100644 tests/ui-toml/absolute_paths/disallow_crates/clippy.toml create mode 100644 tests/ui-toml/absolute_paths/no_short/clippy.toml create mode 100644 tests/ui/crashes/ice-3717.fixed create mode 100644 tests/ui/doc/doc_markdown-issue_13097.fixed create mode 100644 tests/ui/doc/doc_markdown-issue_13097.rs create mode 100644 tests/ui/doc/doc_markdown-issue_13097.stderr create mode 100644 tests/ui/too_long_first_doc_paragraph-fix.fixed create mode 100644 tests/ui/too_long_first_doc_paragraph-fix.rs create mode 100644 tests/ui/too_long_first_doc_paragraph-fix.stderr create mode 100644 tests/ui/too_long_first_doc_paragraph.rs create mode 100644 tests/ui/too_long_first_doc_paragraph.stderr create mode 100644 util/gh-pages/style.css diff --git a/.cargo/config.toml b/.cargo/config.toml index ce07290d1e1..d9c635df5dc 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -1,10 +1,10 @@ [alias] +bless = "test --config env.RUSTC_BLESS='1'" uitest = "test --test compile-test" -uibless = "test --test compile-test -- -- --bless" -bless = "test -- -- --bless" +uibless = "bless --test compile-test" dev = "run --package clippy_dev --bin clippy_dev --manifest-path clippy_dev/Cargo.toml --" lintcheck = "run --package lintcheck --bin lintcheck --manifest-path lintcheck/Cargo.toml -- " -collect-metadata = "test --test dogfood --features internal -- collect_metadata" +collect-metadata = "test --test compile-test --config env.COLLECT_METADATA='1'" [build] # -Zbinary-dep-depinfo allows us to track which rlib files to use for compiling UI tests diff --git a/.github/deploy.sh b/.github/deploy.sh index 5a59f94ec91..d937661c0f8 100644 --- a/.github/deploy.sh +++ b/.github/deploy.sh @@ -10,6 +10,7 @@ mkdir out/master/ cp util/gh-pages/index.html out/master cp util/gh-pages/script.js out/master cp util/gh-pages/lints.json out/master +cp util/gh-pages/style.css out/master if [[ -n $TAG_NAME ]]; then echo "Save the doc for the current tag ($TAG_NAME) and point stable/ to it" diff --git a/.github/workflows/clippy_bors.yml b/.github/workflows/clippy_bors.yml index 10e18e84c89..2aa13313fa5 100644 --- a/.github/workflows/clippy_bors.yml +++ b/.github/workflows/clippy_bors.yml @@ -136,11 +136,6 @@ jobs: - name: Test metadata collection run: cargo collect-metadata - - name: Test lint_configuration.md is up-to-date - run: | - echo "run \`cargo collect-metadata\` if this fails" - git update-index --refresh - integration_build: needs: changelog runs-on: ubuntu-latest diff --git a/CHANGELOG.md b/CHANGELOG.md index fddc2fd994e..9bc4ad9698d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5914,6 +5914,7 @@ Released 2018-09-13 [`to_string_in_format_args`]: https://rust-lang.github.io/rust-clippy/master/index.html#to_string_in_format_args [`to_string_trait_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#to_string_trait_impl [`todo`]: https://rust-lang.github.io/rust-clippy/master/index.html#todo +[`too_long_first_doc_paragraph`]: https://rust-lang.github.io/rust-clippy/master/index.html#too_long_first_doc_paragraph [`too_many_arguments`]: https://rust-lang.github.io/rust-clippy/master/index.html#too_many_arguments [`too_many_lines`]: https://rust-lang.github.io/rust-clippy/master/index.html#too_many_lines [`toplevel_ref_arg`]: https://rust-lang.github.io/rust-clippy/master/index.html#toplevel_ref_arg diff --git a/Cargo.toml b/Cargo.toml index 78409c7a09e..b48b881097f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,8 +30,11 @@ color-print = "0.3.4" anstream = "0.6.0" [dev-dependencies] +cargo_metadata = "0.18.1" ui_test = "0.25" regex = "1.5.5" +serde = { version = "1.0.145", features = ["derive"] } +serde_json = "1.0.122" toml = "0.7.3" walkdir = "2.3" filetime = "0.2.9" @@ -41,7 +44,6 @@ itertools = "0.12" clippy_utils = { path = "clippy_utils" } if_chain = "1.0" quote = "1.0.25" -serde = { version = "1.0.145", features = ["derive"] } syn = { version = "2.0", features = ["full"] } futures = "0.3" parking_lot = "0.12" diff --git a/book/src/development/adding_lints.md b/book/src/development/adding_lints.md index a71d94daca7..963e02e5c16 100644 --- a/book/src/development/adding_lints.md +++ b/book/src/development/adding_lints.md @@ -739,7 +739,7 @@ for some users. Adding a configuration is done in the following steps: 5. Update [Lint Configuration](../lint_configuration.md) - Run `cargo collect-metadata` to generate documentation changes for the book. + Run `cargo bless --test config-metadata` to generate documentation changes for the book. [`clippy_config::conf`]: https://github.com/rust-lang/rust-clippy/blob/master/clippy_config/src/conf.rs [`clippy_lints` lib file]: https://github.com/rust-lang/rust-clippy/blob/master/clippy_lints/src/lib.rs diff --git a/book/src/lint_configuration.md b/book/src/lint_configuration.md index e3d550b1466..78348797588 100644 --- a/book/src/lint_configuration.md +++ b/book/src/lint_configuration.md @@ -1,5 +1,5 @@ @@ -199,7 +199,7 @@ Allowed names below the minimum allowed characters. The value `".."` can be used the list to indicate, that the configured values should be appended to the default configuration of Clippy. By default, any configuration will replace the default value. -**Default Value:** `["j", "z", "i", "y", "n", "x", "w"]` +**Default Value:** `["i", "j", "x", "y", "z", "w", "n"]` --- **Affected lints:** @@ -455,7 +455,7 @@ default configuration of Clippy. By default, any configuration will replace the * `doc-valid-idents = ["ClipPy"]` would replace the default list with `["ClipPy"]`. * `doc-valid-idents = ["ClipPy", ".."]` would append `ClipPy` to the default list. -**Default Value:** `["TiB", "CoreGraphics", "CoffeeScript", "TeX", "Direct2D", "PiB", "DirectX", "NetBSD", "OAuth", "NaN", "OpenType", "WebGL2", "WebTransport", "JavaScript", "OpenSSL", "OpenSSH", "EiB", "PureScript", "OpenAL", "MiB", "WebAssembly", "MinGW", "CoreFoundation", "WebGPU", "ClojureScript", "CamelCase", "OpenDNS", "NaNs", "OpenMP", "GitLab", "KiB", "sRGB", "CoreText", "macOS", "TypeScript", "GiB", "OpenExr", "YCbCr", "OpenTelemetry", "OpenBSD", "FreeBSD", "GPLv2", "PostScript", "WebP", "LaTeX", "TensorFlow", "AccessKit", "TrueType", "OpenStreetMap", "OpenGL", "DevOps", "OCaml", "WebRTC", "WebGL", "BibLaTeX", "GitHub", "GraphQL", "iOS", "Direct3D", "BibTeX", "DirectWrite", "GPLv3", "IPv6", "WebSocket", "IPv4", "ECMAScript"]` +**Default Value:** `["KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "AccessKit", "CoreFoundation", "CoreGraphics", "CoreText", "DevOps", "Direct2D", "Direct3D", "DirectWrite", "DirectX", "ECMAScript", "GPLv2", "GPLv3", "GitHub", "GitLab", "IPv4", "IPv6", "ClojureScript", "CoffeeScript", "JavaScript", "PostScript", "PureScript", "TypeScript", "WebAssembly", "NaN", "NaNs", "OAuth", "GraphQL", "OCaml", "OpenAL", "OpenDNS", "OpenGL", "OpenMP", "OpenSSH", "OpenSSL", "OpenStreetMap", "OpenTelemetry", "OpenType", "WebGL", "WebGL2", "WebGPU", "WebRTC", "WebSocket", "WebTransport", "WebP", "OpenExr", "YCbCr", "sRGB", "TensorFlow", "TrueType", "iOS", "macOS", "FreeBSD", "NetBSD", "OpenBSD", "TeX", "LaTeX", "BibTeX", "BibLaTeX", "MinGW", "CamelCase"]` --- **Affected lints:** @@ -949,5 +949,3 @@ Whether to also emit warnings for unsafe blocks with metavariable expansions in --- **Affected lints:** * [`macro_metavars_in_unsafe`](https://rust-lang.github.io/rust-clippy/master/index.html#macro_metavars_in_unsafe) - - diff --git a/clippy_config/Cargo.toml b/clippy_config/Cargo.toml index d5b28e25323..5c4e0761dbc 100644 --- a/clippy_config/Cargo.toml +++ b/clippy_config/Cargo.toml @@ -7,7 +7,6 @@ edition = "2021" [dependencies] itertools = "0.12" -rustc-semver = "1.1" serde = { version = "1.0", features = ["derive"] } toml = "0.7.3" diff --git a/clippy_config/src/conf.rs b/clippy_config/src/conf.rs index 4c2a8255d6b..a6f1b958bfb 100644 --- a/clippy_config/src/conf.rs +++ b/clippy_config/src/conf.rs @@ -1,7 +1,6 @@ use crate::msrvs::Msrv; use crate::types::{DisallowedPath, MacroMatcher, MatchLintBehaviour, PubUnderscoreFieldsBehaviour, Rename}; use crate::ClippyConfiguration; -use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; use rustc_session::Session; use rustc_span::edit_distance::edit_distance; @@ -218,7 +217,7 @@ macro_rules! define_Conf { define_Conf! { /// Which crates to allow absolute paths from #[lints(absolute_paths)] - absolute_paths_allowed_crates: FxHashSet = FxHashSet::default(), + absolute_paths_allowed_crates: Vec = Vec::new(), /// The maximum number of segments a path can have before being linted, anything above this will /// be linted. #[lints(absolute_paths)] @@ -280,12 +279,12 @@ define_Conf! { allowed_dotfiles: Vec = Vec::default(), /// A list of crate names to allow duplicates of #[lints(multiple_crate_versions)] - allowed_duplicate_crates: FxHashSet = FxHashSet::default(), + allowed_duplicate_crates: Vec = Vec::new(), /// Allowed names below the minimum allowed characters. The value `".."` can be used as part of /// the list to indicate, that the configured values should be appended to the default /// configuration of Clippy. By default, any configuration will replace the default value. #[lints(min_ident_chars)] - allowed_idents_below_min_chars: FxHashSet = + allowed_idents_below_min_chars: Vec = DEFAULT_ALLOWED_IDENTS_BELOW_MIN_CHARS.iter().map(ToString::to_string).collect(), /// List of prefixes to allow when determining whether an item's name ends with the module's name. /// If the rest of an item's name is an allowed prefix (e.g. item `ToFoo` or `to_foo` in module `foo`), @@ -323,7 +322,7 @@ define_Conf! { /// 2. Paths with any segment that containing the word 'prelude' /// are already allowed by default. #[lints(wildcard_imports)] - allowed_wildcard_imports: FxHashSet = FxHashSet::default(), + allowed_wildcard_imports: Vec = Vec::new(), /// Suppress checking of the passed type names in all types of operations. /// /// If a specific operation is desired, consider using `arithmetic_side_effects_allowed_binary` or `arithmetic_side_effects_allowed_unary` instead. @@ -355,7 +354,7 @@ define_Conf! { /// arithmetic-side-effects-allowed-binary = [["SomeType" , "f32"], ["AnotherType", "*"]] /// ``` #[lints(arithmetic_side_effects)] - arithmetic_side_effects_allowed_binary: Vec<[String; 2]> = <_>::default(), + arithmetic_side_effects_allowed_binary: Vec<(String, String)> = <_>::default(), /// Suppress checking of the passed type names in unary operations like "negation" (`-`). /// /// #### Example @@ -431,7 +430,7 @@ define_Conf! { /// * `doc-valid-idents = ["ClipPy"]` would replace the default list with `["ClipPy"]`. /// * `doc-valid-idents = ["ClipPy", ".."]` would append `ClipPy` to the default list. #[lints(doc_markdown)] - doc_valid_idents: FxHashSet = DEFAULT_DOC_VALID_IDENTS.iter().map(ToString::to_string).collect(), + doc_valid_idents: Vec = DEFAULT_DOC_VALID_IDENTS.iter().map(ToString::to_string).collect(), /// Whether to apply the raw pointer heuristic to determine if a type is `Send`. #[lints(non_send_fields_in_send_ty)] enable_raw_pointer_heuristic_for_send: bool = true, @@ -706,12 +705,12 @@ fn deserialize(file: &SourceFile) -> TryConf { DEFAULT_ALLOWED_TRAITS_WITH_RENAMED_PARAMS, ); // TODO: THIS SHOULD BE TESTED, this comment will be gone soon - if conf.conf.allowed_idents_below_min_chars.contains("..") { + if conf.conf.allowed_idents_below_min_chars.iter().any(|e| e == "..") { conf.conf .allowed_idents_below_min_chars .extend(DEFAULT_ALLOWED_IDENTS_BELOW_MIN_CHARS.iter().map(ToString::to_string)); } - if conf.conf.doc_valid_idents.contains("..") { + if conf.conf.doc_valid_idents.iter().any(|e| e == "..") { conf.conf .doc_valid_idents .extend(DEFAULT_DOC_VALID_IDENTS.iter().map(ToString::to_string)); @@ -890,14 +889,14 @@ fn calculate_dimensions(fields: &[&str]) -> (usize, Vec) { #[cfg(test)] mod tests { - use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use serde::de::IgnoredAny; + use std::collections::{HashMap, HashSet}; use std::fs; use walkdir::WalkDir; #[test] fn configs_are_tested() { - let mut names: FxHashSet = crate::get_configuration_metadata() + let mut names: HashSet = crate::get_configuration_metadata() .into_iter() .map(|meta| meta.name.replace('_', "-")) .collect(); @@ -910,7 +909,7 @@ mod tests { for entry in toml_files { let file = fs::read_to_string(entry.path()).unwrap(); #[allow(clippy::zero_sized_map_values)] - if let Ok(map) = toml::from_str::>(&file) { + if let Ok(map) = toml::from_str::>(&file) { for name in map.keys() { names.remove(name.as_str()); } diff --git a/clippy_config/src/lib.rs b/clippy_config/src/lib.rs index d2246f12029..ac838cc81d2 100644 --- a/clippy_config/src/lib.rs +++ b/clippy_config/src/lib.rs @@ -14,7 +14,7 @@ )] extern crate rustc_ast; -extern crate rustc_data_structures; +extern crate rustc_attr; #[allow(unused_extern_crates)] extern crate rustc_driver; extern crate rustc_errors; diff --git a/clippy_config/src/msrvs.rs b/clippy_config/src/msrvs.rs index fc56ac51796..0e8215aa8e3 100644 --- a/clippy_config/src/msrvs.rs +++ b/clippy_config/src/msrvs.rs @@ -1,6 +1,6 @@ use rustc_ast::Attribute; -use rustc_semver::RustcVersion; -use rustc_session::Session; +use rustc_attr::parse_version; +use rustc_session::{RustcVersion, Session}; use rustc_span::{sym, Symbol}; use serde::Deserialize; use std::fmt; @@ -10,7 +10,7 @@ macro_rules! msrv_aliases { $($name:ident),* $(,)? })*) => { $($( - pub const $name: RustcVersion = RustcVersion::new($major, $minor, $patch); + pub const $name: RustcVersion = RustcVersion { major: $major, minor :$minor, patch: $patch }; )*)* }; } @@ -18,6 +18,7 @@ macro_rules! msrv_aliases { // names may refer to stabilized feature flags or library items msrv_aliases! { 1,81,0 { LINT_REASONS_STABILIZATION } + 1,80,0 { BOX_INTO_ITER} 1,77,0 { C_STR_LITERALS } 1,76,0 { PTR_FROM_REF, OPTION_RESULT_INSPECT } 1,71,0 { TUPLE_ARRAY_CONVERSIONS, BUILD_HASHER_HASH_ONE } @@ -81,9 +82,9 @@ impl<'de> Deserialize<'de> for Msrv { D: serde::Deserializer<'de>, { let v = String::deserialize(deserializer)?; - RustcVersion::parse(&v) + parse_version(Symbol::intern(&v)) .map(|v| Msrv { stack: vec![v] }) - .map_err(|_| serde::de::Error::custom("not a valid Rust version")) + .ok_or_else(|| serde::de::Error::custom("not a valid Rust version")) } } @@ -95,7 +96,7 @@ impl Msrv { pub fn read_cargo(&mut self, sess: &Session) { let cargo_msrv = std::env::var("CARGO_PKG_RUST_VERSION") .ok() - .and_then(|v| RustcVersion::parse(&v).ok()); + .and_then(|v| parse_version(Symbol::intern(&v))); match (self.current(), cargo_msrv) { (None, Some(cargo_msrv)) => self.stack = vec![cargo_msrv], @@ -115,7 +116,7 @@ impl Msrv { } pub fn meets(&self, required: RustcVersion) -> bool { - self.current().map_or(true, |version| version.meets(required)) + self.current().map_or(true, |msrv| msrv >= required) } fn parse_attr(sess: &Session, attrs: &[Attribute]) -> Option { @@ -131,7 +132,7 @@ impl Msrv { } if let Some(msrv) = msrv_attr.value_str() { - if let Ok(version) = RustcVersion::parse(msrv.as_str()) { + if let Some(version) = parse_version(msrv) { return Some(version); } diff --git a/clippy_dev/src/main.rs b/clippy_dev/src/main.rs index 755b04b0b23..fc15913354c 100644 --- a/clippy_dev/src/main.rs +++ b/clippy_dev/src/main.rs @@ -1,3 +1,4 @@ +#![feature(rustc_private)] // warn on lints, that are included in `rust-lang/rust`s bootstrap #![warn(rust_2018_idioms, unused_lifetimes)] diff --git a/clippy_dev/src/update_lints.rs b/clippy_dev/src/update_lints.rs index 15578d69c3a..8dbda1c634c 100644 --- a/clippy_dev/src/update_lints.rs +++ b/clippy_dev/src/update_lints.rs @@ -604,7 +604,7 @@ fn gen_declared_lints<'a>( details.sort_unstable(); let mut output = GENERATED_FILE_COMMENT.to_string(); - output.push_str("pub(crate) static LINTS: &[&crate::LintInfo] = &[\n"); + output.push_str("pub static LINTS: &[&crate::LintInfo] = &[\n"); for (is_public, module_name, lint_name) in details { if !is_public { diff --git a/clippy_lints/Cargo.toml b/clippy_lints/Cargo.toml index 99ed93468a0..fbd4566da58 100644 --- a/clippy_lints/Cargo.toml +++ b/clippy_lints/Cargo.toml @@ -25,7 +25,6 @@ regex = { version = "1.5", optional = true } unicode-normalization = "0.1" unicode-script = { version = "0.5", default-features = false } semver = "1.0" -rustc-semver = "1.1" url = "2.2" [dev-dependencies] diff --git a/clippy_lints/src/absolute_paths.rs b/clippy_lints/src/absolute_paths.rs index c0a9d888e0b..c72b3f1318c 100644 --- a/clippy_lints/src/absolute_paths.rs +++ b/clippy_lints/src/absolute_paths.rs @@ -1,6 +1,6 @@ use clippy_config::Conf; use clippy_utils::diagnostics::span_lint; -use clippy_utils::source::snippet_opt; +use clippy_utils::is_from_proc_macro; use rustc_data_structures::fx::FxHashSet; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX}; @@ -8,6 +8,7 @@ use rustc_hir::{HirId, ItemKind, Node, Path}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::impl_lint_pass; use rustc_span::symbol::kw; +use rustc_span::Symbol; declare_clippy_lint! { /// ### What it does @@ -24,6 +25,13 @@ declare_clippy_lint! { /// Note: One exception to this is code from macro expansion - this does not lint such cases, as /// using absolute paths is the proper way of referencing items in one. /// + /// ### Known issues + /// + /// There are currently a few cases which are not caught by this lint: + /// * Macro calls. e.g. `path::to::macro!()` + /// * Derive macros. e.g. `#[derive(path::to::macro)]` + /// * Attribute macros. e.g. `#[path::to::macro]` + /// /// ### Example /// ```no_run /// let x = std::f64::consts::PI; @@ -48,63 +56,66 @@ impl_lint_pass!(AbsolutePaths => [ABSOLUTE_PATHS]); pub struct AbsolutePaths { pub absolute_paths_max_segments: u64, - pub absolute_paths_allowed_crates: &'static FxHashSet, + pub absolute_paths_allowed_crates: FxHashSet, } impl AbsolutePaths { pub fn new(conf: &'static Conf) -> Self { Self { absolute_paths_max_segments: conf.absolute_paths_max_segments, - absolute_paths_allowed_crates: &conf.absolute_paths_allowed_crates, + absolute_paths_allowed_crates: conf + .absolute_paths_allowed_crates + .iter() + .map(|x| Symbol::intern(x)) + .collect(), } } } -impl LateLintPass<'_> for AbsolutePaths { +impl<'tcx> LateLintPass<'tcx> for AbsolutePaths { // We should only lint `QPath::Resolved`s, but since `Path` is only used in `Resolved` and `UsePath` // we don't need to use a visitor or anything as we can just check if the `Node` for `hir_id` isn't // a `Use` - #[expect(clippy::cast_possible_truncation)] - fn check_path(&mut self, cx: &LateContext<'_>, path: &Path<'_>, hir_id: HirId) { - let Self { - absolute_paths_max_segments, - absolute_paths_allowed_crates, - } = self; - - if !path.span.from_expansion() - && let node = cx.tcx.hir_node(hir_id) - && !matches!(node, Node::Item(item) if matches!(item.kind, ItemKind::Use(_, _))) - && let [first, rest @ ..] = path.segments - // Handle `::std` - && let (segment, len) = if first.ident.name == kw::PathRoot { - // Indexing is fine as `PathRoot` must be followed by another segment. `len() - 1` - // is fine here for the same reason - (&rest[0], path.segments.len() - 1) - } else { - (first, path.segments.len()) - } - && len > *absolute_paths_max_segments as usize - && let Some(segment_snippet) = snippet_opt(cx, segment.ident.span) - && segment_snippet == segment.ident.as_str() - { - let is_abs_external = - matches!(segment.res, Res::Def(DefKind::Mod, DefId { index, .. }) if index == CRATE_DEF_INDEX); - let is_abs_crate = segment.ident.name == kw::Crate; - - if is_abs_external && absolute_paths_allowed_crates.contains(segment.ident.name.as_str()) - || is_abs_crate && absolute_paths_allowed_crates.contains("crate") + fn check_path(&mut self, cx: &LateContext<'tcx>, path: &Path<'tcx>, hir_id: HirId) { + let segments = match path.segments { + [] | [_] => return, + // Don't count enum variants and trait items as part of the length. + [rest @ .., _] + if let [.., s] = rest + && matches!(s.res, Res::Def(DefKind::Enum | DefKind::Trait | DefKind::TraitAlias, _)) => { + rest + }, + path => path, + }; + if let [s1, s2, ..] = segments + && let has_root = s1.ident.name == kw::PathRoot + && let first = if has_root { s2 } else { s1 } + && let len = segments.len() - usize::from(has_root) + && len as u64 > self.absolute_paths_max_segments + && let crate_name = if let Res::Def(DefKind::Mod, DefId { index, .. }) = first.res + && index == CRATE_DEF_INDEX + { + // `other_crate::foo` or `::other_crate::foo` + first.ident.name + } else if first.ident.name == kw::Crate || has_root { + // `::foo` or `crate::foo` + kw::Crate + } else { return; } - - if is_abs_external || is_abs_crate { - span_lint( - cx, - ABSOLUTE_PATHS, - path.span, - "consider bringing this path into scope with the `use` keyword", - ); - } + && !path.span.from_expansion() + && let node = cx.tcx.hir_node(hir_id) + && !matches!(node, Node::Item(item) if matches!(item.kind, ItemKind::Use(..))) + && !self.absolute_paths_allowed_crates.contains(&crate_name) + && !is_from_proc_macro(cx, path) + { + span_lint( + cx, + ABSOLUTE_PATHS, + path.span, + "consider bringing this path into scope with the `use` keyword", + ); } } } diff --git a/clippy_lints/src/approx_const.rs b/clippy_lints/src/approx_const.rs index 3b4cc113480..56f5e903dc3 100644 --- a/clippy_lints/src/approx_const.rs +++ b/clippy_lints/src/approx_const.rs @@ -4,8 +4,7 @@ use clippy_utils::diagnostics::span_lint_and_help; use rustc_ast::ast::{FloatTy, LitFloatType, LitKind}; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_semver::RustcVersion; -use rustc_session::impl_lint_pass; +use rustc_session::{impl_lint_pass, RustcVersion}; use rustc_span::symbol; use std::f64::consts as f64; diff --git a/clippy_lints/src/assigning_clones.rs b/clippy_lints/src/assigning_clones.rs index 6e336efbb90..55645d04eef 100644 --- a/clippy_lints/src/assigning_clones.rs +++ b/clippy_lints/src/assigning_clones.rs @@ -3,7 +3,7 @@ use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::mir::{enclosing_mir, PossibleBorrowerMap}; use clippy_utils::sugg::Sugg; -use clippy_utils::{is_diag_trait_item, last_path_segment, local_is_initialized, path_to_local}; +use clippy_utils::{is_diag_trait_item, is_in_test, last_path_segment, local_is_initialized, path_to_local}; use rustc_errors::Applicability; use rustc_hir::{self as hir, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; @@ -118,6 +118,7 @@ impl<'tcx> LateLintPass<'tcx> for AssigningClones { } ) && !clone_source_borrows_from_dest(cx, lhs, rhs.span) + && !is_in_test(cx.tcx, e.hir_id) { span_lint_and_then( cx, diff --git a/clippy_lints/src/attrs/empty_line_after.rs b/clippy_lints/src/attrs/empty_line_after.rs index ca43e76ac57..7ff644b4c44 100644 --- a/clippy_lints/src/attrs/empty_line_after.rs +++ b/clippy_lints/src/attrs/empty_line_after.rs @@ -1,6 +1,6 @@ use super::{EMPTY_LINE_AFTER_DOC_COMMENTS, EMPTY_LINE_AFTER_OUTER_ATTR}; use clippy_utils::diagnostics::span_lint; -use clippy_utils::source::{is_present_in_source, snippet_opt, without_block_comments}; +use clippy_utils::source::{is_present_in_source, without_block_comments, SpanRangeExt}; use rustc_ast::{AttrKind, AttrStyle}; use rustc_lint::EarlyContext; use rustc_span::Span; @@ -26,7 +26,7 @@ pub(super) fn check(cx: &EarlyContext<'_>, item: &rustc_ast::Item) { item.span.parent(), ); - if let Some(snippet) = snippet_opt(cx, end_of_attr_to_next_attr_or_item) { + if let Some(snippet) = end_of_attr_to_next_attr_or_item.get_source_text(cx) { let lines = snippet.split('\n').collect::>(); let lines = without_block_comments(lines); diff --git a/clippy_lints/src/attrs/mod.rs b/clippy_lints/src/attrs/mod.rs index 8f430ae601a..3b14e9aee7f 100644 --- a/clippy_lints/src/attrs/mod.rs +++ b/clippy_lints/src/attrs/mod.rs @@ -1,5 +1,3 @@ -//! checks for attributes - mod allow_attributes; mod allow_attributes_without_reason; mod blanket_clippy_restriction_lints; @@ -310,8 +308,8 @@ declare_clippy_lint! { /// ```rust,ignore /// #[allow(unused_mut)] /// fn foo() -> usize { - /// let mut a = Vec::new(); - /// a.len() + /// let mut a = Vec::new(); + /// a.len() /// } /// ``` /// Use instead: diff --git a/clippy_lints/src/attrs/non_minimal_cfg.rs b/clippy_lints/src/attrs/non_minimal_cfg.rs index 3fde7061585..877025cce4c 100644 --- a/clippy_lints/src/attrs/non_minimal_cfg.rs +++ b/clippy_lints/src/attrs/non_minimal_cfg.rs @@ -1,6 +1,6 @@ use super::{Attribute, NON_MINIMAL_CFG}; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::snippet_opt; +use clippy_utils::source::SpanRangeExt; use rustc_ast::{MetaItemKind, NestedMetaItem}; use rustc_errors::Applicability; use rustc_lint::EarlyContext; @@ -29,8 +29,13 @@ fn check_nested_cfg(cx: &EarlyContext<'_>, items: &[NestedMetaItem]) { meta.span, "unneeded sub `cfg` when there is only one condition", |diag| { - if let Some(snippet) = snippet_opt(cx, list[0].span()) { - diag.span_suggestion(meta.span, "try", snippet, Applicability::MaybeIncorrect); + if let Some(snippet) = list[0].span().get_source_text(cx) { + diag.span_suggestion( + meta.span, + "try", + snippet.to_owned(), + Applicability::MaybeIncorrect, + ); } }, ); diff --git a/clippy_lints/src/attrs/unnecessary_clippy_cfg.rs b/clippy_lints/src/attrs/unnecessary_clippy_cfg.rs index 486e7c6ec4f..478ba7a187b 100644 --- a/clippy_lints/src/attrs/unnecessary_clippy_cfg.rs +++ b/clippy_lints/src/attrs/unnecessary_clippy_cfg.rs @@ -1,6 +1,7 @@ use super::{Attribute, UNNECESSARY_CLIPPY_CFG}; use clippy_utils::diagnostics::{span_lint_and_note, span_lint_and_sugg}; -use clippy_utils::source::snippet_opt; +use clippy_utils::source::SpanRangeExt; +use itertools::Itertools; use rustc_ast::AttrStyle; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, Level}; @@ -31,7 +32,7 @@ pub(super) fn check( return; } if nb_items == clippy_lints.len() { - if let Some(snippet) = snippet_opt(cx, behind_cfg_attr.span) { + if let Some(snippet) = behind_cfg_attr.span.get_source_text(cx) { span_lint_and_sugg( cx, UNNECESSARY_CLIPPY_CFG, @@ -47,11 +48,7 @@ pub(super) fn check( ); } } else { - let snippet = clippy_lints - .iter() - .filter_map(|sp| snippet_opt(cx, *sp)) - .collect::>() - .join(","); + let snippet = clippy_lints.iter().filter_map(|sp| sp.get_source_text(cx)).join(","); span_lint_and_note( cx, UNNECESSARY_CLIPPY_CFG, diff --git a/clippy_lints/src/attrs/useless_attribute.rs b/clippy_lints/src/attrs/useless_attribute.rs index f0868231d01..67ba605a59f 100644 --- a/clippy_lints/src/attrs/useless_attribute.rs +++ b/clippy_lints/src/attrs/useless_attribute.rs @@ -1,7 +1,7 @@ use super::utils::{extract_clippy_lint, is_lint_level, is_word}; use super::{Attribute, USELESS_ATTRIBUTE}; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::{first_line_of_span, snippet_opt}; +use clippy_utils::source::{first_line_of_span, SpanRangeExt}; use rustc_ast::NestedMetaItem; use rustc_errors::Applicability; use rustc_hir::{Item, ItemKind}; @@ -69,14 +69,14 @@ pub(super) fn check(cx: &LateContext<'_>, item: &Item<'_>, attrs: &[Attribute]) } let line_span = first_line_of_span(cx, attr.span); - if let Some(mut sugg) = snippet_opt(cx, line_span) { - if sugg.contains("#[") { + if let Some(src) = line_span.get_source_text(cx) { + if src.contains("#[") { + #[expect(clippy::collapsible_span_lint_calls)] span_lint_and_then(cx, USELESS_ATTRIBUTE, line_span, "useless lint attribute", |diag| { - sugg = sugg.replacen("#[", "#![", 1); diag.span_suggestion( line_span, "if you just forgot a `!`, use", - sugg, + src.replacen("#[", "#![", 1), Applicability::MaybeIncorrect, ); }); diff --git a/clippy_lints/src/booleans.rs b/clippy_lints/src/booleans.rs index a2f48c18170..e933fdf1d6e 100644 --- a/clippy_lints/src/booleans.rs +++ b/clippy_lints/src/booleans.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_hir_and_then}; use clippy_utils::eq_expr_value; -use clippy_utils::source::snippet_opt; +use clippy_utils::source::SpanRangeExt; use clippy_utils::ty::{implements_trait, is_type_diagnostic_item}; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; @@ -134,28 +134,30 @@ fn check_inverted_bool_in_condition( let suggestion = match (left.kind, right.kind) { (ExprKind::Unary(UnOp::Not, left_sub), ExprKind::Unary(UnOp::Not, right_sub)) => { - let Some(left) = snippet_opt(cx, left_sub.span) else { + let Some(left) = left_sub.span.get_source_text(cx) else { return; }; - let Some(right) = snippet_opt(cx, right_sub.span) else { + let Some(right) = right_sub.span.get_source_text(cx) else { return; }; let Some(op) = bin_op_eq_str(op) else { return }; format!("{left} {op} {right}") }, (ExprKind::Unary(UnOp::Not, left_sub), _) => { - let Some(left) = snippet_opt(cx, left_sub.span) else { + let Some(left) = left_sub.span.get_source_text(cx) else { return; }; - let Some(right) = snippet_opt(cx, right.span) else { + let Some(right) = right.span.get_source_text(cx) else { return; }; let Some(op) = inverted_bin_op_eq_str(op) else { return }; format!("{left} {op} {right}") }, (_, ExprKind::Unary(UnOp::Not, right_sub)) => { - let Some(left) = snippet_opt(cx, left.span) else { return }; - let Some(right) = snippet_opt(cx, right_sub.span) else { + let Some(left) = left.span.get_source_text(cx) else { + return; + }; + let Some(right) = right_sub.span.get_source_text(cx) else { return; }; let Some(op) = inverted_bin_op_eq_str(op) else { return }; @@ -313,8 +315,7 @@ impl<'a, 'tcx, 'v> SuggestContext<'a, 'tcx, 'v> { self.output.push_str(&str); } else { self.output.push('!'); - let snip = snippet_opt(self.cx, terminal.span)?; - self.output.push_str(&snip); + self.output.push_str(&terminal.span.get_source_text(self.cx)?); } }, True | False | Not(_) => { @@ -345,8 +346,12 @@ impl<'a, 'tcx, 'v> SuggestContext<'a, 'tcx, 'v> { } }, &Term(n) => { - let snip = snippet_opt(self.cx, self.terminals[n as usize].span.source_callsite())?; - self.output.push_str(&snip); + self.output.push_str( + &self.terminals[n as usize] + .span + .source_callsite() + .get_source_text(self.cx)?, + ); }, } Some(()) @@ -370,8 +375,8 @@ fn simplify_not(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option { _ => None, } .and_then(|op| { - let lhs_snippet = snippet_opt(cx, lhs.span)?; - let rhs_snippet = snippet_opt(cx, rhs.span)?; + let lhs_snippet = lhs.span.get_source_text(cx)?; + let rhs_snippet = rhs.span.get_source_text(cx)?; if !(lhs_snippet.starts_with('(') && lhs_snippet.ends_with(')')) { if let (ExprKind::Cast(..), BinOpKind::Ge) = (&lhs.kind, binop.node) { @@ -399,7 +404,7 @@ fn simplify_not(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option { let path: &str = path.ident.name.as_str(); a == path }) - .and_then(|(_, neg_method)| Some(format!("{}.{neg_method}()", snippet_opt(cx, receiver.span)?))) + .and_then(|(_, neg_method)| Some(format!("{}.{neg_method}()", receiver.span.get_source_text(cx)?))) }, _ => None, } diff --git a/clippy_lints/src/borrow_deref_ref.rs b/clippy_lints/src/borrow_deref_ref.rs index bd123a725a7..cba8224b84c 100644 --- a/clippy_lints/src/borrow_deref_ref.rs +++ b/clippy_lints/src/borrow_deref_ref.rs @@ -1,6 +1,6 @@ use crate::reference::DEREF_ADDROF; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::snippet_opt; +use clippy_utils::source::SpanRangeExt; use clippy_utils::ty::implements_trait; use clippy_utils::{get_parent_expr, is_from_proc_macro, is_lint_allowed}; use rustc_errors::Applicability; @@ -73,6 +73,7 @@ impl<'tcx> LateLintPass<'tcx> for BorrowDerefRef { } }) && !is_from_proc_macro(cx, e) + && let Some(deref_text) = deref_target.span.get_source_text(cx) { span_lint_and_then( cx, @@ -83,7 +84,7 @@ impl<'tcx> LateLintPass<'tcx> for BorrowDerefRef { diag.span_suggestion( e.span, "if you would like to reborrow, try removing `&*`", - snippet_opt(cx, deref_target.span).unwrap(), + deref_text.as_str(), Applicability::MachineApplicable, ); @@ -98,7 +99,7 @@ impl<'tcx> LateLintPass<'tcx> for BorrowDerefRef { diag.span_suggestion( e.span, "if you would like to deref, try using `&**`", - format!("&**{}", &snippet_opt(cx, deref_target.span).unwrap()), + format!("&**{deref_text}"), Applicability::MaybeIncorrect, ); }, diff --git a/clippy_lints/src/cargo/common_metadata.rs b/clippy_lints/src/cargo/common_metadata.rs index 3af2d8c0256..fed0aa8b275 100644 --- a/clippy_lints/src/cargo/common_metadata.rs +++ b/clippy_lints/src/cargo/common_metadata.rs @@ -1,5 +1,3 @@ -//! lint on missing cargo common metadata - use cargo_metadata::Metadata; use clippy_utils::diagnostics::span_lint; use rustc_lint::LateContext; diff --git a/clippy_lints/src/cargo/mod.rs b/clippy_lints/src/cargo/mod.rs index 312ad4c2990..96a2b161464 100644 --- a/clippy_lints/src/cargo/mod.rs +++ b/clippy_lints/src/cargo/mod.rs @@ -205,7 +205,7 @@ declare_clippy_lint! { } pub struct Cargo { - allowed_duplicate_crates: &'static FxHashSet, + allowed_duplicate_crates: FxHashSet, ignore_publish: bool, } @@ -221,7 +221,7 @@ impl_lint_pass!(Cargo => [ impl Cargo { pub fn new(conf: &'static Conf) -> Self { Self { - allowed_duplicate_crates: &conf.allowed_duplicate_crates, + allowed_duplicate_crates: conf.allowed_duplicate_crates.iter().cloned().collect(), ignore_publish: conf.cargo_ignore_publish, } } @@ -263,7 +263,7 @@ impl LateLintPass<'_> for Cargo { { match MetadataCommand::new().exec() { Ok(metadata) => { - multiple_crate_versions::check(cx, &metadata, self.allowed_duplicate_crates); + multiple_crate_versions::check(cx, &metadata, &self.allowed_duplicate_crates); }, Err(e) => { for lint in WITH_DEPS_LINTS { diff --git a/clippy_lints/src/cargo/multiple_crate_versions.rs b/clippy_lints/src/cargo/multiple_crate_versions.rs index 2769463c8a5..44cd1f7192f 100644 --- a/clippy_lints/src/cargo/multiple_crate_versions.rs +++ b/clippy_lints/src/cargo/multiple_crate_versions.rs @@ -1,5 +1,3 @@ -//! lint on multiple versions of a crate being used - use cargo_metadata::{DependencyKind, Metadata, Node, Package, PackageId}; use clippy_utils::diagnostics::span_lint; use itertools::Itertools; diff --git a/clippy_lints/src/casts/as_ptr_cast_mut.rs b/clippy_lints/src/casts/as_ptr_cast_mut.rs index f05fd3fcde5..15ecba20a0b 100644 --- a/clippy_lints/src/casts/as_ptr_cast_mut.rs +++ b/clippy_lints/src/casts/as_ptr_cast_mut.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::snippet_opt; +use clippy_utils::source::SpanRangeExt; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::LateContext; @@ -19,7 +19,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, && let as_ptr_sig = cx.tcx.fn_sig(as_ptr_did).instantiate_identity() && let Some(first_param_ty) = as_ptr_sig.skip_binder().inputs().iter().next() && let ty::Ref(_, _, Mutability::Not) = first_param_ty.kind() - && let Some(recv) = snippet_opt(cx, receiver.span) + && let Some(recv) = receiver.span.get_source_text(cx) { // `as_mut_ptr` might not exist let applicability = Applicability::MaybeIncorrect; diff --git a/clippy_lints/src/casts/cast_lossless.rs b/clippy_lints/src/casts/cast_lossless.rs index bd3acc06f4b..346aed7e9f1 100644 --- a/clippy_lints/src/casts/cast_lossless.rs +++ b/clippy_lints/src/casts/cast_lossless.rs @@ -1,7 +1,7 @@ use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::is_in_const_context; -use clippy_utils::source::snippet_opt; +use clippy_utils::source::SpanRangeExt; use clippy_utils::sugg::Sugg; use clippy_utils::ty::is_isize_or_usize; use rustc_errors::Applicability; @@ -34,7 +34,7 @@ pub(super) fn check( diag.help("an `as` cast can become silently lossy if the types change in the future"); let mut applicability = Applicability::MachineApplicable; let from_sugg = Sugg::hir_with_context(cx, cast_from_expr, expr.span.ctxt(), "", &mut applicability); - let Some(ty) = snippet_opt(cx, hygiene::walk_chain(cast_to_hir.span, expr.span.ctxt())) else { + let Some(ty) = hygiene::walk_chain(cast_to_hir.span, expr.span.ctxt()).get_source_text(cx) else { return; }; match cast_to_hir.kind { diff --git a/clippy_lints/src/casts/cast_possible_truncation.rs b/clippy_lints/src/casts/cast_possible_truncation.rs index 102fe25fc67..5708aae3f3e 100644 --- a/clippy_lints/src/casts/cast_possible_truncation.rs +++ b/clippy_lints/src/casts/cast_possible_truncation.rs @@ -4,7 +4,7 @@ use clippy_utils::expr_or_init; use clippy_utils::source::snippet; use clippy_utils::sugg::Sugg; use clippy_utils::ty::{get_discriminant_value, is_isize_or_usize}; -use rustc_errors::{Applicability, Diag, SuggestionStyle}; +use rustc_errors::{Applicability, Diag}; use rustc_hir::def::{DefKind, Res}; use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::LateContext; @@ -190,12 +190,10 @@ fn offer_suggestion( format!("{cast_to_snip}::try_from({})", Sugg::hir(cx, cast_expr, "..")) }; - diag.span_suggestion_with_style( + diag.span_suggestion_verbose( expr.span, "... or use `try_from` and handle the error accordingly", suggestion, Applicability::Unspecified, - // always show the suggestion in a separate line - SuggestionStyle::ShowAlways, ); } diff --git a/clippy_lints/src/casts/fn_to_numeric_cast_any.rs b/clippy_lints/src/casts/fn_to_numeric_cast_any.rs index 5dc6df1e907..b22e8f4ee89 100644 --- a/clippy_lints/src/casts/fn_to_numeric_cast_any.rs +++ b/clippy_lints/src/casts/fn_to_numeric_cast_any.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet_with_applicability; -use rustc_errors::{Applicability, SuggestionStyle}; +use rustc_errors::Applicability; use rustc_hir::Expr; use rustc_lint::LateContext; use rustc_middle::ty::{self, Ty}; @@ -24,12 +24,11 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, expr.span, format!("casting function pointer `{from_snippet}` to `{cast_to}`"), |diag| { - diag.span_suggestion_with_style( + diag.span_suggestion_verbose( expr.span, "did you mean to invoke the function?", format!("{from_snippet}() as {cast_to}"), applicability, - SuggestionStyle::ShowAlways, ); }, ); diff --git a/clippy_lints/src/casts/unnecessary_cast.rs b/clippy_lints/src/casts/unnecessary_cast.rs index fb0b0cba6a6..566adc83d69 100644 --- a/clippy_lints/src/casts/unnecessary_cast.rs +++ b/clippy_lints/src/casts/unnecessary_cast.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::numeric_literal::NumericLiteral; -use clippy_utils::source::snippet_opt; +use clippy_utils::source::{snippet_opt, SpanRangeExt}; use clippy_utils::visitors::{for_each_expr_without_closures, Visitable}; use clippy_utils::{get_parent_expr, is_hir_ty_cfg_dependant, is_ty_alias, path_to_local}; use rustc_ast::{LitFloatType, LitIntType, LitKind}; @@ -104,7 +104,7 @@ pub(super) fn check<'tcx>( let literal_str = &cast_str; if let LitKind::Int(n, _) = lit.node - && let Some(src) = snippet_opt(cx, cast_expr.span) + && let Some(src) = cast_expr.span.get_source_text(cx) && cast_to.is_floating_point() && let Some(num_lit) = NumericLiteral::from_lit_kind(&src, &lit.node) && let from_nbits = 128 - n.get().leading_zeros() @@ -131,7 +131,7 @@ pub(super) fn check<'tcx>( | LitKind::Float(_, LitFloatType::Suffixed(_)) if cast_from.kind() == cast_to.kind() => { - if let Some(src) = snippet_opt(cx, cast_expr.span) { + if let Some(src) = cast_expr.span.get_source_text(cx) { if let Some(num_lit) = NumericLiteral::from_lit_kind(&src, &lit.node) { lint_unnecessary_cast(cx, expr, num_lit.integer, cast_from, cast_to); return true; @@ -253,7 +253,7 @@ fn is_cast_from_ty_alias<'tcx>(cx: &LateContext<'tcx>, expr: impl Visitable<'tcx let res = cx.qpath_res(&qpath, expr.hir_id); // Function call if let Res::Def(DefKind::Fn, def_id) = res { - let Some(snippet) = snippet_opt(cx, cx.tcx.def_span(def_id)) else { + let Some(snippet) = cx.tcx.def_span(def_id).get_source_text(cx) else { return ControlFlow::Continue(()); }; // This is the worst part of this entire function. This is the only way I know of to diff --git a/clippy_lints/src/casts/zero_ptr.rs b/clippy_lints/src/casts/zero_ptr.rs index 3c1c7d2dc3a..c5c4a28646d 100644 --- a/clippy_lints/src/casts/zero_ptr.rs +++ b/clippy_lints/src/casts/zero_ptr.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::snippet_opt; +use clippy_utils::source::SpanRangeExt; use clippy_utils::{is_in_const_context, is_integer_literal, std_or_core}; use rustc_errors::Applicability; use rustc_hir::{Expr, Mutability, Ty, TyKind}; @@ -20,7 +20,7 @@ pub fn check(cx: &LateContext<'_>, expr: &Expr<'_>, from: &Expr<'_>, to: &Ty<'_> let sugg = if let TyKind::Infer = mut_ty.ty.kind { format!("{std_or_core}::{sugg_fn}()") - } else if let Some(mut_ty_snip) = snippet_opt(cx, mut_ty.ty.span) { + } else if let Some(mut_ty_snip) = mut_ty.ty.span.get_source_text(cx) { format!("{std_or_core}::{sugg_fn}::<{mut_ty_snip}>()") } else { return; diff --git a/clippy_lints/src/cfg_not_test.rs b/clippy_lints/src/cfg_not_test.rs index b54f392bf2f..d820c1e0720 100644 --- a/clippy_lints/src/cfg_not_test.rs +++ b/clippy_lints/src/cfg_not_test.rs @@ -5,7 +5,7 @@ use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does - /// Checks for usage of `cfg` that excludes code from `test` builds. (i.e., `#{cfg(not(test))]`) + /// Checks for usage of `cfg` that excludes code from `test` builds. (i.e., `#[cfg(not(test))]`) /// /// ### Why is this bad? /// This may give the false impression that a codebase has 100% coverage, yet actually has untested code. diff --git a/clippy_lints/src/checked_conversions.rs b/clippy_lints/src/checked_conversions.rs index 1711565fca8..dd7c34d1e46 100644 --- a/clippy_lints/src/checked_conversions.rs +++ b/clippy_lints/src/checked_conversions.rs @@ -1,5 +1,3 @@ -//! lint on manually implemented checked conversions that could be transformed into `try_from` - use clippy_config::msrvs::{self, Msrv}; use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_sugg; diff --git a/clippy_lints/src/cognitive_complexity.rs b/clippy_lints/src/cognitive_complexity.rs index 5fa0522e4e5..0099eefbc8d 100644 --- a/clippy_lints/src/cognitive_complexity.rs +++ b/clippy_lints/src/cognitive_complexity.rs @@ -1,5 +1,3 @@ -//! calculate cognitive complexity and warn about overly complex functions - use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::source::{IntoSpan, SpanRangeExt}; diff --git a/clippy_lints/src/collapsible_if.rs b/clippy_lints/src/collapsible_if.rs index f311c052ad6..e73bfc6ebf7 100644 --- a/clippy_lints/src/collapsible_if.rs +++ b/clippy_lints/src/collapsible_if.rs @@ -1,17 +1,3 @@ -//! Checks for if expressions that contain only an if expression. -//! -//! For example, the lint would catch: -//! -//! ```rust,ignore -//! if x { -//! if y { -//! println!("Hello world"); -//! } -//! } -//! ``` -//! -//! This lint is **warn** by default - use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; use clippy_utils::source::{snippet, snippet_block, snippet_block_with_applicability}; use clippy_utils::sugg::Sugg; diff --git a/clippy_lints/src/collection_is_never_read.rs b/clippy_lints/src/collection_is_never_read.rs index eebda3ff76f..c6847411c75 100644 --- a/clippy_lints/src/collection_is_never_read.rs +++ b/clippy_lints/src/collection_is_never_read.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint; -use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item}; +use clippy_utils::ty::{get_type_diagnostic_name, is_type_lang_item}; use clippy_utils::visitors::{for_each_expr, Visitable}; use clippy_utils::{get_enclosing_block, path_to_local_id}; use core::ops::ControlFlow; @@ -7,7 +7,6 @@ use rustc_hir::{Body, ExprKind, HirId, LangItem, LetStmt, Node, PatKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; use rustc_span::symbol::sym; -use rustc_span::Symbol; declare_clippy_lint! { /// ### What it does @@ -44,24 +43,11 @@ declare_clippy_lint! { } declare_lint_pass!(CollectionIsNeverRead => [COLLECTION_IS_NEVER_READ]); -// Add `String` here when it is added to diagnostic items -static COLLECTIONS: [Symbol; 9] = [ - sym::BTreeMap, - sym::BTreeSet, - sym::BinaryHeap, - sym::HashMap, - sym::HashSet, - sym::LinkedList, - sym::Option, - sym::Vec, - sym::VecDeque, -]; - impl<'tcx> LateLintPass<'tcx> for CollectionIsNeverRead { fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx LetStmt<'tcx>) { // Look for local variables whose type is a container. Search surrounding block for read access. if let PatKind::Binding(_, local_id, _, _) = local.pat.kind - && match_acceptable_type(cx, local, &COLLECTIONS) + && match_acceptable_type(cx, local) && let Some(enclosing_block) = get_enclosing_block(cx, local.hir_id) && has_no_read_access(cx, local_id, enclosing_block) { @@ -70,11 +56,22 @@ impl<'tcx> LateLintPass<'tcx> for CollectionIsNeverRead { } } -fn match_acceptable_type(cx: &LateContext<'_>, local: &LetStmt<'_>, collections: &[Symbol]) -> bool { +fn match_acceptable_type(cx: &LateContext<'_>, local: &LetStmt<'_>) -> bool { let ty = cx.typeck_results().pat_ty(local.pat); - collections.iter().any(|&sym| is_type_diagnostic_item(cx, ty, sym)) - // String type is a lang item but not a diagnostic item for now so we need a separate check - || is_type_lang_item(cx, ty, LangItem::String) + matches!( + get_type_diagnostic_name(cx, ty), + Some( + sym::BTreeMap + | sym::BTreeSet + | sym::BinaryHeap + | sym::HashMap + | sym::HashSet + | sym::LinkedList + | sym::Option + | sym::Vec + | sym::VecDeque + ) + ) || is_type_lang_item(cx, ty, LangItem::String) } fn has_no_read_access<'tcx, T: Visitable<'tcx>>(cx: &LateContext<'tcx>, id: HirId, block: T) -> bool { diff --git a/clippy_lints/src/create_dir.rs b/clippy_lints/src/create_dir.rs index b49a977dbea..24570d8f440 100644 --- a/clippy_lints/src/create_dir.rs +++ b/clippy_lints/src/create_dir.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet_with_applicability; -use rustc_errors::{Applicability, SuggestionStyle}; +use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; @@ -46,7 +46,7 @@ impl LateLintPass<'_> for CreateDir { "calling `std::fs::create_dir` where there may be a better way", |diag| { let mut app = Applicability::MaybeIncorrect; - diag.span_suggestion_with_style( + diag.span_suggestion_verbose( expr.span, "consider calling `std::fs::create_dir_all` instead", format!( @@ -54,7 +54,6 @@ impl LateLintPass<'_> for CreateDir { snippet_with_applicability(cx, arg.span, "..", &mut app) ), app, - SuggestionStyle::ShowAlways, ); }, ); diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index 3fb083dd833..60e51713173 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -2,7 +2,7 @@ // Use that command to update this file and do not edit by hand. // Manual edits will be overwritten. -pub(crate) static LINTS: &[&crate::LintInfo] = &[ +pub static LINTS: &[&crate::LintInfo] = &[ #[cfg(feature = "internal")] crate::utils::internal_lints::almost_standard_lint_formulation::ALMOST_STANDARD_LINT_FORMULATION_INFO, #[cfg(feature = "internal")] @@ -22,8 +22,6 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ #[cfg(feature = "internal")] crate::utils::internal_lints::lint_without_lint_pass::MISSING_CLIPPY_VERSION_ATTRIBUTE_INFO, #[cfg(feature = "internal")] - crate::utils::internal_lints::metadata_collector::METADATA_COLLECTOR_INFO, - #[cfg(feature = "internal")] crate::utils::internal_lints::msrv_attr_impl::MISSING_MSRV_ATTR_IMPL_INFO, #[cfg(feature = "internal")] crate::utils::internal_lints::outer_expn_data_pass::OUTER_EXPN_EXPN_DATA_INFO, @@ -146,6 +144,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::doc::NEEDLESS_DOCTEST_MAIN_INFO, crate::doc::SUSPICIOUS_DOC_COMMENTS_INFO, crate::doc::TEST_ATTR_IN_DOCTEST_INFO, + crate::doc::TOO_LONG_FIRST_DOC_PARAGRAPH_INFO, crate::doc::UNNECESSARY_SAFETY_DOC_INFO, crate::double_parens::DOUBLE_PARENS_INFO, crate::drop_forget_ref::DROP_NON_DROP_INFO, diff --git a/clippy_lints/src/doc/lazy_continuation.rs b/clippy_lints/src/doc/lazy_continuation.rs index bd1cc46e185..771bcac2441 100644 --- a/clippy_lints/src/doc/lazy_continuation.rs +++ b/clippy_lints/src/doc/lazy_continuation.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use itertools::Itertools; -use rustc_errors::{Applicability, SuggestionStyle}; +use rustc_errors::Applicability; use rustc_lint::LateContext; use rustc_span::{BytePos, Span}; use std::ops::Range; @@ -59,12 +59,11 @@ pub(super) fn check( && (doc_comment == "///" || doc_comment == "//!") { // suggest filling in a blank line - diag.span_suggestion_with_style( + diag.span_suggestion_verbose( line_break_span.shrink_to_lo(), "if this should be its own paragraph, add a blank doc comment line", format!("\n{doc_comment}"), Applicability::MaybeIncorrect, - SuggestionStyle::ShowAlways, ); if ccount > 0 || blockquote_level > 0 { diag.help("if this not intended to be a quote at all, escape it with `\\>`"); @@ -79,12 +78,11 @@ pub(super) fn check( if ccount == 0 && blockquote_level == 0 { // simpler suggestion style for indentation let indent = list_indentation - lcount; - diag.span_suggestion_with_style( + diag.span_suggestion_verbose( span.shrink_to_hi(), "indent this line", std::iter::repeat(" ").take(indent).join(""), Applicability::MaybeIncorrect, - SuggestionStyle::ShowAlways, ); diag.help("if this is supposed to be its own paragraph, add a blank line"); return; @@ -107,12 +105,11 @@ pub(super) fn check( suggested.push_str(text); } } - diag.span_suggestion_with_style( + diag.span_suggestion_verbose( span, "add markers to start of line", suggested, Applicability::MachineApplicable, - SuggestionStyle::ShowAlways, ); diag.help("if this not intended to be a quote at all, escape it with `\\>`"); }); diff --git a/clippy_lints/src/doc/markdown.rs b/clippy_lints/src/doc/markdown.rs index 41c0bcd55ad..8cdaba88e50 100644 --- a/clippy_lints/src/doc/markdown.rs +++ b/clippy_lints/src/doc/markdown.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; use clippy_utils::source::snippet_with_applicability; use rustc_data_structures::fx::FxHashSet; -use rustc_errors::{Applicability, SuggestionStyle}; +use rustc_errors::Applicability; use rustc_lint::LateContext; use rustc_span::{BytePos, Pos, Span}; use url::Url; @@ -92,6 +92,10 @@ fn check_word(cx: &LateContext<'_>, word: &str, span: Span, code_level: isize, b && matches!(prefix.chars().last(), Some('S' | 'X')) { prefix + } else if let Some(prefix) = s.strip_suffix("ified") + && prefix.chars().all(|c| c.is_ascii_uppercase()) + { + prefix } else { s.strip_suffix('s').unwrap_or(s) }; @@ -133,24 +137,15 @@ fn check_word(cx: &LateContext<'_>, word: &str, span: Span, code_level: isize, b } if has_underscore(word) || word.contains("::") || is_camel_case(word) || word.ends_with("()") { - let mut applicability = Applicability::MachineApplicable; - span_lint_and_then( cx, DOC_MARKDOWN, span, "item in documentation is missing backticks", |diag| { + let mut applicability = Applicability::MachineApplicable; let snippet = snippet_with_applicability(cx, span, "..", &mut applicability); - diag.span_suggestion_with_style( - span, - "try", - format!("`{snippet}`"), - applicability, - // always show the suggestion in a separate line, since the - // inline presentation adds another pair of backticks - SuggestionStyle::ShowAlways, - ); + diag.span_suggestion_verbose(span, "try", format!("`{snippet}`"), applicability); }, ); } diff --git a/clippy_lints/src/doc/mod.rs b/clippy_lints/src/doc/mod.rs index d7b3a7c74f3..790579b21c9 100644 --- a/clippy_lints/src/doc/mod.rs +++ b/clippy_lints/src/doc/mod.rs @@ -1,4 +1,6 @@ mod lazy_continuation; +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}; @@ -309,7 +311,7 @@ declare_clippy_lint! { /// ### Known problems /// Inner doc comments can only appear before items, so there are certain cases where the suggestion /// made by this lint is not valid code. For example: - /// ```rs + /// ```rust /// fn foo() {} /// ///! /// fn bar() {} @@ -422,15 +424,47 @@ declare_clippy_lint! { "require every line of a paragraph to be indented and marked" } +declare_clippy_lint! { + /// ### What it does + /// Checks if the first line in the documentation of items listed in module page is too long. + /// + /// ### Why is this bad? + /// Documentation will show the first paragraph of the doscstring in the summary page of a + /// module, so having a nice, short summary in the first paragraph is part of writing good docs. + /// + /// ### Example + /// ```no_run + /// /// A very short summary. + /// /// A much longer explanation that goes into a lot more detail about + /// /// how the thing works, possibly with doclinks and so one, + /// /// and probably spanning a many rows. + /// struct Foo {} + /// ``` + /// Use instead: + /// ```no_run + /// /// A very short summary. + /// /// + /// /// A much longer explanation that goes into a lot more detail about + /// /// how the thing works, possibly with doclinks and so one, + /// /// and probably spanning a many rows. + /// struct Foo {} + /// ``` + #[clippy::version = "1.81.0"] + pub TOO_LONG_FIRST_DOC_PARAGRAPH, + style, + "ensure that the first line of a documentation paragraph isn't too long" +} + +#[derive(Clone)] pub struct Documentation { - valid_idents: &'static FxHashSet, + valid_idents: FxHashSet, check_private_items: bool, } impl Documentation { pub fn new(conf: &'static Conf) -> Self { Self { - valid_idents: &conf.doc_valid_idents, + valid_idents: conf.doc_valid_idents.iter().cloned().collect(), check_private_items: conf.check_private_items, } } @@ -448,48 +482,60 @@ impl_lint_pass!(Documentation => [ SUSPICIOUS_DOC_COMMENTS, EMPTY_DOCS, DOC_LAZY_CONTINUATION, + TOO_LONG_FIRST_DOC_PARAGRAPH, ]); impl<'tcx> LateLintPass<'tcx> for Documentation { fn check_attributes(&mut self, cx: &LateContext<'tcx>, attrs: &'tcx [Attribute]) { - let Some(headers) = check_attrs(cx, self.valid_idents, attrs) else { + let Some(headers) = check_attrs(cx, &self.valid_idents, attrs) else { return; }; match cx.tcx.hir_node(cx.last_node_with_lint_attrs) { - Node::Item(item) => match item.kind { - ItemKind::Fn(sig, _, body_id) => { - if !(is_entrypoint_fn(cx, item.owner_id.to_def_id()) || in_external_macro(cx.tcx.sess, item.span)) { - let body = cx.tcx.hir().body(body_id); + Node::Item(item) => { + too_long_first_doc_paragraph::check( + cx, + item, + attrs, + headers.first_paragraph_len, + self.check_private_items, + ); + match item.kind { + ItemKind::Fn(sig, _, body_id) => { + if !(is_entrypoint_fn(cx, item.owner_id.to_def_id()) + || in_external_macro(cx.tcx.sess, item.span)) + { + let body = cx.tcx.hir().body(body_id); - let panic_info = FindPanicUnwrap::find_span(cx, cx.tcx.typeck(item.owner_id), body.value); - missing_headers::check( + let panic_info = FindPanicUnwrap::find_span(cx, cx.tcx.typeck(item.owner_id), body.value); + missing_headers::check( + cx, + item.owner_id, + sig, + headers, + Some(body_id), + panic_info, + self.check_private_items, + ); + } + }, + ItemKind::Trait(_, unsafety, ..) => match (headers.safety, unsafety) { + (false, Safety::Unsafe) => span_lint( cx, - item.owner_id, - sig, - headers, - Some(body_id), - panic_info, - self.check_private_items, - ); - } - }, - ItemKind::Trait(_, unsafety, ..) => match (headers.safety, unsafety) { - (false, Safety::Unsafe) => span_lint( - cx, - MISSING_SAFETY_DOC, - cx.tcx.def_span(item.owner_id), - "docs for unsafe trait missing `# Safety` section", - ), - (true, Safety::Safe) => span_lint( - cx, - UNNECESSARY_SAFETY_DOC, - cx.tcx.def_span(item.owner_id), - "docs for safe trait have unnecessary `# Safety` section", - ), + MISSING_SAFETY_DOC, + cx.tcx.def_span(item.owner_id), + "docs for unsafe trait missing `# Safety` section", + ), + (true, Safety::Safe) => span_lint( + cx, + UNNECESSARY_SAFETY_DOC, + cx.tcx.def_span(item.owner_id), + "docs for safe trait have unnecessary `# Safety` section", + ), + _ => (), + }, _ => (), - }, - _ => (), + } }, Node::TraitItem(trait_item) => { if let TraitItemKind::Fn(sig, ..) = trait_item.kind @@ -547,6 +593,7 @@ struct DocHeaders { safety: bool, errors: bool, panics: bool, + first_paragraph_len: usize, } /// Does some pre-processing on raw, desugared `#[doc]` attributes such as parsing them and @@ -653,6 +700,7 @@ fn check_doc<'a, Events: Iterator, Range, Range { if let End(TagEnd::Heading(_)) = event { diff --git a/clippy_lints/src/doc/too_long_first_doc_paragraph.rs b/clippy_lints/src/doc/too_long_first_doc_paragraph.rs new file mode 100644 index 00000000000..7bb3bb12f2c --- /dev/null +++ b/clippy_lints/src/doc/too_long_first_doc_paragraph.rs @@ -0,0 +1,91 @@ +use rustc_ast::ast::Attribute; +use rustc_errors::Applicability; +use rustc_hir::{Item, ItemKind}; +use rustc_lint::LateContext; + +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::is_from_proc_macro; +use clippy_utils::source::snippet_opt; + +use super::TOO_LONG_FIRST_DOC_PARAGRAPH; + +pub(super) fn check( + cx: &LateContext<'_>, + item: &Item<'_>, + attrs: &[Attribute], + mut first_paragraph_len: usize, + check_private_items: bool, +) { + if !check_private_items && !cx.effective_visibilities.is_exported(item.owner_id.def_id) { + return; + } + if first_paragraph_len <= 200 + || !matches!( + item.kind, + // This is the list of items which can be documented AND are displayed on the module + // page. So associated items or impl blocks are not part of this list. + ItemKind::Static(..) + | ItemKind::Const(..) + | ItemKind::Fn(..) + | ItemKind::Macro(..) + | ItemKind::Mod(..) + | ItemKind::TyAlias(..) + | ItemKind::Enum(..) + | ItemKind::Struct(..) + | ItemKind::Union(..) + | ItemKind::Trait(..) + | ItemKind::TraitAlias(..) + ) + { + return; + } + + let mut spans = Vec::new(); + let mut should_suggest_empty_doc = false; + + for attr in attrs { + if let Some(doc) = attr.doc_str() { + spans.push(attr.span); + let doc = doc.as_str(); + let doc = doc.trim(); + if spans.len() == 1 { + // We make this suggestion only if the first doc line ends with a punctuation + // because it might just need to add an empty line with `///`. + should_suggest_empty_doc = doc.ends_with('.') || doc.ends_with('!') || doc.ends_with('?'); + } + let len = doc.chars().count(); + if len >= first_paragraph_len { + break; + } + first_paragraph_len -= len; + } + } + + let &[first_span, .., last_span] = spans.as_slice() else { + return; + }; + if is_from_proc_macro(cx, item) { + return; + } + + span_lint_and_then( + cx, + TOO_LONG_FIRST_DOC_PARAGRAPH, + first_span.with_hi(last_span.lo()), + "first doc comment paragraph is too long", + |diag| { + if should_suggest_empty_doc + && let Some(second_span) = spans.get(1) + && let new_span = first_span.with_hi(second_span.lo()).with_lo(first_span.hi()) + && let Some(snippet) = snippet_opt(cx, new_span) + { + diag.span_suggestion( + new_span, + "add an empty line", + format!("{snippet}///\n"), + Applicability::MachineApplicable, + ); + } + }, + ); +} diff --git a/clippy_lints/src/else_if_without_else.rs b/clippy_lints/src/else_if_without_else.rs index 02f9c2c3648..5315f55ba38 100644 --- a/clippy_lints/src/else_if_without_else.rs +++ b/clippy_lints/src/else_if_without_else.rs @@ -1,5 +1,3 @@ -//! Lint on if expressions with an else if, but without a final else branch. - use clippy_utils::diagnostics::span_lint_and_then; use rustc_ast::ast::{Expr, ExprKind}; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; diff --git a/clippy_lints/src/empty_enum.rs b/clippy_lints/src/empty_enum.rs index 1869faab1d3..f4c55738cb8 100644 --- a/clippy_lints/src/empty_enum.rs +++ b/clippy_lints/src/empty_enum.rs @@ -1,5 +1,3 @@ -//! lint when there is an enum with no variants - use clippy_utils::diagnostics::span_lint_and_help; use rustc_hir::{Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; diff --git a/clippy_lints/src/enum_clike.rs b/clippy_lints/src/enum_clike.rs index e54cd248ead..4755cefe784 100644 --- a/clippy_lints/src/enum_clike.rs +++ b/clippy_lints/src/enum_clike.rs @@ -1,6 +1,3 @@ -//! lint on C-like enums that are `repr(isize/usize)` and have values that -//! don't fit into an `i32` - use clippy_utils::consts::{mir_to_const, Constant}; use clippy_utils::diagnostics::span_lint; use rustc_hir::{Item, ItemKind}; diff --git a/clippy_lints/src/eta_reduction.rs b/clippy_lints/src/eta_reduction.rs index a7e831fdc42..cabc6592258 100644 --- a/clippy_lints/src/eta_reduction.rs +++ b/clippy_lints/src/eta_reduction.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; use clippy_utils::higher::VecArgs; use clippy_utils::source::snippet_opt; -use clippy_utils::ty::type_diagnostic_name; +use clippy_utils::ty::get_type_diagnostic_name; use clippy_utils::usage::{local_used_after_expr, local_used_in}; use clippy_utils::{get_path_from_caller_to_method_type, is_adjusted, path_to_local, path_to_local_id}; use rustc_errors::Applicability; @@ -139,7 +139,7 @@ fn check_clousure<'tcx>(cx: &LateContext<'tcx>, outer_receiver: Option<&Expr<'tc { let callee_ty_raw = typeck.expr_ty(callee); let callee_ty = callee_ty_raw.peel_refs(); - if matches!(type_diagnostic_name(cx, callee_ty), Some(sym::Arc | sym::Rc)) + if matches!(get_type_diagnostic_name(cx, callee_ty), Some(sym::Arc | sym::Rc)) || !check_inputs(typeck, body.params, None, args) { return; diff --git a/clippy_lints/src/float_literal.rs b/clippy_lints/src/float_literal.rs index f095c1add91..012ad8e1a22 100644 --- a/clippy_lints/src/float_literal.rs +++ b/clippy_lints/src/float_literal.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::numeric_literal; use rustc_ast::ast::{self, LitFloatType, LitKind}; -use rustc_errors::{Applicability, SuggestionStyle}; +use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{self, FloatTy}; @@ -117,12 +117,11 @@ impl<'tcx> LateLintPass<'tcx> for FloatLiteral { if type_suffix.is_none() { float_str.push_str(".0"); } - diag.span_suggestion_with_style( + diag.span_suggestion_verbose( expr.span, "consider changing the type or replacing it with", numeric_literal::format(&float_str, type_suffix, true), Applicability::MachineApplicable, - SuggestionStyle::ShowAlways, ); }, ); @@ -134,12 +133,11 @@ impl<'tcx> LateLintPass<'tcx> for FloatLiteral { expr.span, "float has excessive precision", |diag| { - diag.span_suggestion_with_style( + diag.span_suggestion_verbose( expr.span, "consider changing the type or truncating it to", numeric_literal::format(&float_str, type_suffix, true), Applicability::MachineApplicable, - SuggestionStyle::ShowAlways, ); }, ); diff --git a/clippy_lints/src/format.rs b/clippy_lints/src/format.rs index 0b248f784b7..4dedff69b9a 100644 --- a/clippy_lints/src/format.rs +++ b/clippy_lints/src/format.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::macros::{find_format_arg_expr, root_macro_call_first_node, FormatArgsStorage}; -use clippy_utils::source::{snippet_opt, snippet_with_context}; +use clippy_utils::source::{snippet_with_context, SpanRangeExt}; use clippy_utils::sugg::Sugg; use rustc_ast::{FormatArgsPiece, FormatOptions, FormatTrait}; use rustc_errors::Applicability; @@ -65,7 +65,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessFormat { ([], []) => span_useless_format_empty(cx, call_site, "String::new()".to_owned(), applicability), ([], [_]) => { // Simulate macro expansion, converting {{ and }} to { and }. - let Some(snippet) = snippet_opt(cx, format_args.span) else { + let Some(snippet) = format_args.span.get_source_text(cx) else { return; }; let s_expand = snippet.replace("{{", "{").replace("}}", "}"); @@ -73,7 +73,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessFormat { span_useless_format(cx, call_site, sugg, applicability); }, ([arg], [piece]) => { - if let Ok(value) = find_format_arg_expr(expr, arg) + if let Some(value) = find_format_arg_expr(expr, arg) && let FormatArgsPiece::Placeholder(placeholder) = piece && placeholder.format_trait == FormatTrait::Display && placeholder.format_options == FormatOptions::default() diff --git a/clippy_lints/src/format_args.rs b/clippy_lints/src/format_args.rs index a31d5cb6ec7..020c0c5440d 100644 --- a/clippy_lints/src/format_args.rs +++ b/clippy_lints/src/format_args.rs @@ -7,7 +7,7 @@ use clippy_utils::macros::{ find_format_arg_expr, format_arg_removal_span, format_placeholder_format_span, is_assert_macro, is_format_macro, is_panic, matching_root_macro_call, root_macro_call_first_node, FormatArgsStorage, FormatParamUsage, MacroCall, }; -use clippy_utils::source::snippet_opt; +use clippy_utils::source::SpanRangeExt; use clippy_utils::ty::{implements_trait, is_type_lang_item}; use itertools::Itertools; use rustc_ast::{ @@ -224,13 +224,11 @@ impl<'a, 'tcx> FormatArgsExpr<'a, 'tcx> { if let FormatArgsPiece::Placeholder(placeholder) = piece && let Ok(index) = placeholder.argument.index && let Some(arg) = self.format_args.arguments.all_args().get(index) + && let Some(arg_expr) = find_format_arg_expr(self.expr, arg) { - let arg_expr = find_format_arg_expr(self.expr, arg); - self.check_unused_format_specifier(placeholder, arg_expr); - if let Ok(arg_expr) = arg_expr - && placeholder.format_trait == FormatTrait::Display + if placeholder.format_trait == FormatTrait::Display && placeholder.format_options == FormatOptions::default() && !self.is_aliased(index) { @@ -242,28 +240,13 @@ impl<'a, 'tcx> FormatArgsExpr<'a, 'tcx> { } } - fn check_unused_format_specifier( - &self, - placeholder: &FormatPlaceholder, - arg_expr: Result<&Expr<'_>, &rustc_ast::Expr>, - ) { - let ty_or_ast_expr = arg_expr.map(|expr| self.cx.typeck_results().expr_ty(expr).peel_refs()); - - let is_format_args = match ty_or_ast_expr { - Ok(ty) => is_type_lang_item(self.cx, ty, LangItem::FormatArguments), - Err(expr) => matches!(expr.peel_parens_and_refs().kind, rustc_ast::ExprKind::FormatArgs(_)), - }; - + fn check_unused_format_specifier(&self, placeholder: &FormatPlaceholder, arg: &Expr<'_>) { let options = &placeholder.format_options; - let arg_span = match arg_expr { - Ok(expr) => expr.span, - Err(expr) => expr.span, - }; - if let Some(placeholder_span) = placeholder.span - && is_format_args && *options != FormatOptions::default() + && let ty = self.cx.typeck_results().expr_ty(arg).peel_refs() + && is_type_lang_item(self.cx, ty, LangItem::FormatArguments) { span_lint_and_then( self.cx, @@ -274,7 +257,7 @@ impl<'a, 'tcx> FormatArgsExpr<'a, 'tcx> { let mut suggest_format = |spec| { let message = format!("for the {spec} to apply consider using `format!()`"); - if let Some(mac_call) = matching_root_macro_call(self.cx, arg_span, sym::format_args_macro) { + if let Some(mac_call) = matching_root_macro_call(self.cx, arg.span, sym::format_args_macro) { diag.span_suggestion( self.cx.sess().source_map().span_until_char(mac_call.span, '!'), message, @@ -424,7 +407,7 @@ impl<'a, 'tcx> FormatArgsExpr<'a, 'tcx> { count_needed_derefs(receiver_ty, cx.typeck_results().expr_adjustments(receiver).iter()) && implements_trait(cx, target, display_trait_id, &[]) && let Some(sized_trait_id) = cx.tcx.lang_items().sized_trait() - && let Some(receiver_snippet) = snippet_opt(cx, receiver.span.source_callsite()) + && let Some(receiver_snippet) = receiver.span.source_callsite().get_source_text(cx) { let needs_ref = !implements_trait(cx, receiver_ty, sized_trait_id, &[]); if n_needed_derefs == 0 && !needs_ref { diff --git a/clippy_lints/src/format_impl.rs b/clippy_lints/src/format_impl.rs index e6f27cb82d1..7cd12ac7db8 100644 --- a/clippy_lints/src/format_impl.rs +++ b/clippy_lints/src/format_impl.rs @@ -196,7 +196,7 @@ impl<'a, 'tcx> FormatImplExpr<'a, 'tcx> { && trait_name == self.format_trait_impl.name && let Ok(index) = placeholder.argument.index && let Some(arg) = format_args.arguments.all_args().get(index) - && let Ok(arg_expr) = find_format_arg_expr(self.expr, arg) + && let Some(arg_expr) = find_format_arg_expr(self.expr, arg) { self.check_format_arg_self(arg_expr); } diff --git a/clippy_lints/src/from_over_into.rs b/clippy_lints/src/from_over_into.rs index 1c1d8b57bc4..b84bf7c821c 100644 --- a/clippy_lints/src/from_over_into.rs +++ b/clippy_lints/src/from_over_into.rs @@ -3,7 +3,7 @@ use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::macros::span_is_local; use clippy_utils::path_def_id; -use clippy_utils::source::snippet_opt; +use clippy_utils::source::SpanRangeExt; use rustc_errors::Applicability; use rustc_hir::intravisit::{walk_path, Visitor}; use rustc_hir::{ @@ -178,8 +178,8 @@ fn convert_to_from( return None; }; - let from = snippet_opt(cx, self_ty.span)?; - let into = snippet_opt(cx, target_ty.span)?; + let from = self_ty.span.get_source_text(cx)?; + let into = target_ty.span.get_source_text(cx)?; let mut suggestions = vec![ // impl Into for U -> impl From for U @@ -187,10 +187,10 @@ fn convert_to_from( (into_trait_seg.ident.span, String::from("From")), // impl Into for U -> impl Into for U // ~ ~ - (target_ty.span, from.clone()), + (target_ty.span, from.to_owned()), // impl Into for U -> impl Into for T // ~ ~ - (self_ty.span, into), + (self_ty.span, into.to_owned()), // fn into(self) -> T -> fn from(self) -> T // ~~~~ ~~~~ (impl_item.ident.span, String::from("from")), @@ -223,7 +223,7 @@ fn convert_to_from( } for span in finder.upper { - suggestions.push((span, from.clone())); + suggestions.push((span, from.to_owned())); } for span in finder.lower { suggestions.push((span, String::from("val"))); diff --git a/clippy_lints/src/from_str_radix_10.rs b/clippy_lints/src/from_str_radix_10.rs index 6ab7bbc2dfc..e5fa67d6964 100644 --- a/clippy_lints/src/from_str_radix_10.rs +++ b/clippy_lints/src/from_str_radix_10.rs @@ -22,8 +22,8 @@ declare_clippy_lint! { /// /// ### Known problems /// - /// This lint may suggest using (&).parse() instead of .parse() directly - /// in some cases, which is correct but adds unnecessary complexity to the code. + /// This lint may suggest using `(&).parse()` instead of `.parse()` + /// directly in some cases, which is correct but adds unnecessary complexity to the code. /// /// ### Example /// ```ignore diff --git a/clippy_lints/src/functions/impl_trait_in_params.rs b/clippy_lints/src/functions/impl_trait_in_params.rs index cf85c74e688..05e341e06fd 100644 --- a/clippy_lints/src/functions/impl_trait_in_params.rs +++ b/clippy_lints/src/functions/impl_trait_in_params.rs @@ -1,6 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::is_in_test; +use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::intravisit::FnKind; use rustc_hir::{Body, GenericParam, Generics, HirId, ImplItem, ImplItemKind, TraitItem, TraitItemKind}; @@ -18,20 +19,18 @@ fn report(cx: &LateContext<'_>, param: &GenericParam<'_>, generics: &Generics<'_ |diag| { if let Some(gen_span) = generics.span_for_param_suggestion() { // If there's already a generic param with the same bound, do not lint **this** suggestion. - diag.span_suggestion_with_style( + diag.span_suggestion_verbose( gen_span, "add a type parameter", format!(", {{ /* Generic name */ }}: {}", ¶m.name.ident().as_str()[5..]), - rustc_errors::Applicability::HasPlaceholders, - rustc_errors::SuggestionStyle::ShowAlways, + Applicability::HasPlaceholders, ); } else { - diag.span_suggestion_with_style( + diag.span_suggestion_verbose( generics.span, "add a type parameter", format!("<{{ /* Generic name */ }}: {}>", ¶m.name.ident().as_str()[5..]), - rustc_errors::Applicability::HasPlaceholders, - rustc_errors::SuggestionStyle::ShowAlways, + Applicability::HasPlaceholders, ); } }, diff --git a/clippy_lints/src/functions/must_use.rs b/clippy_lints/src/functions/must_use.rs index b179d7b5249..93828121047 100644 --- a/clippy_lints/src/functions/must_use.rs +++ b/clippy_lints/src/functions/must_use.rs @@ -8,11 +8,11 @@ use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::{LateContext, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::{self, Ty}; -use rustc_span::{sym, Span, Symbol}; +use rustc_span::{sym, Span}; use clippy_utils::attrs::is_proc_macro; use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_then}; -use clippy_utils::source::snippet_opt; +use clippy_utils::source::SpanRangeExt; use clippy_utils::ty::is_must_use_ty; use clippy_utils::visitors::for_each_expr_without_closures; use clippy_utils::{return_ty, trait_ref_of_method}; @@ -129,9 +129,9 @@ fn check_needless_must_use( cx, DOUBLE_MUST_USE, fn_header_span, - "this function has an empty `#[must_use]` attribute, but returns a type already marked as `#[must_use]`", + "this function has a `#[must_use]` attribute with no message, but returns a type already marked as `#[must_use]`", None, - "either add some descriptive text or remove the attribute", + "either add some descriptive message or remove the attribute", ); } } @@ -155,7 +155,7 @@ fn check_must_use_candidate<'tcx>( return; } span_lint_and_then(cx, MUST_USE_CANDIDATE, fn_span, msg, |diag| { - if let Some(snippet) = snippet_opt(cx, fn_span) { + if let Some(snippet) = fn_span.get_source_text(cx) { diag.span_suggestion( fn_span, "add the attribute", @@ -193,17 +193,13 @@ fn is_mutable_pat(cx: &LateContext<'_>, pat: &hir::Pat<'_>, tys: &mut DefIdSet) } } -static KNOWN_WRAPPER_TYS: &[Symbol] = &[sym::Rc, sym::Arc]; - fn is_mutable_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, tys: &mut DefIdSet) -> bool { match *ty.kind() { // primitive types are never mutable ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Str => false, ty::Adt(adt, args) => { tys.insert(adt.did()) && !ty.is_freeze(cx.tcx, cx.param_env) - || KNOWN_WRAPPER_TYS - .iter() - .any(|&sym| cx.tcx.is_diagnostic_item(sym, adt.did())) + || matches!(cx.tcx.get_diagnostic_name(adt.did()), Some(sym::Rc | sym::Arc)) && args.types().any(|ty| is_mutable_ty(cx, ty, tys)) }, ty::Tuple(args) => args.iter().any(|ty| is_mutable_ty(cx, ty, tys)), diff --git a/clippy_lints/src/functions/too_many_lines.rs b/clippy_lints/src/functions/too_many_lines.rs index 586ca58d60d..0f5ce340c44 100644 --- a/clippy_lints/src/functions/too_many_lines.rs +++ b/clippy_lints/src/functions/too_many_lines.rs @@ -1,12 +1,11 @@ +use clippy_utils::diagnostics::span_lint; +use clippy_utils::source::SpanRangeExt; use rustc_hir as hir; use rustc_hir::intravisit::FnKind; use rustc_lint::{LateContext, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_span::Span; -use clippy_utils::diagnostics::span_lint; -use clippy_utils::source::snippet_opt; - use super::TOO_MANY_LINES; pub(super) fn check_fn( @@ -22,57 +21,57 @@ pub(super) fn check_fn( return; } - let Some(code_snippet) = snippet_opt(cx, body.value.span) else { - return; - }; let mut line_count: u64 = 0; - let mut in_comment = false; - let mut code_in_line; + let too_many = body.value.span.check_source_text(cx, |src| { + let mut in_comment = false; + let mut code_in_line; - let function_lines = if matches!(body.value.kind, hir::ExprKind::Block(..)) - && code_snippet.as_bytes().first().copied() == Some(b'{') - && code_snippet.as_bytes().last().copied() == Some(b'}') - { - // Removing the braces from the enclosing block - &code_snippet[1..code_snippet.len() - 1] - } else { - &code_snippet - } - .trim() // Remove leading and trailing blank lines - .lines(); + let function_lines = if matches!(body.value.kind, hir::ExprKind::Block(..)) + && src.as_bytes().first().copied() == Some(b'{') + && src.as_bytes().last().copied() == Some(b'}') + { + // Removing the braces from the enclosing block + &src[1..src.len() - 1] + } else { + src + } + .trim() // Remove leading and trailing blank lines + .lines(); - for mut line in function_lines { - code_in_line = false; - loop { - line = line.trim_start(); - if line.is_empty() { + for mut line in function_lines { + code_in_line = false; + loop { + line = line.trim_start(); + if line.is_empty() { + break; + } + if in_comment { + if let Some(i) = line.find("*/") { + line = &line[i + 2..]; + in_comment = false; + continue; + } + } else { + let multi_idx = line.find("/*").unwrap_or(line.len()); + let single_idx = line.find("//").unwrap_or(line.len()); + code_in_line |= multi_idx > 0 && single_idx > 0; + // Implies multi_idx is below line.len() + if multi_idx < single_idx { + line = &line[multi_idx + 2..]; + in_comment = true; + continue; + } + } break; } - if in_comment { - if let Some(i) = line.find("*/") { - line = &line[i + 2..]; - in_comment = false; - continue; - } - } else { - let multi_idx = line.find("/*").unwrap_or(line.len()); - let single_idx = line.find("//").unwrap_or(line.len()); - code_in_line |= multi_idx > 0 && single_idx > 0; - // Implies multi_idx is below line.len() - if multi_idx < single_idx { - line = &line[multi_idx + 2..]; - in_comment = true; - continue; - } + if code_in_line { + line_count += 1; } - break; } - if code_in_line { - line_count += 1; - } - } + line_count > too_many_lines_threshold + }); - if line_count > too_many_lines_threshold { + if too_many { span_lint( cx, TOO_MANY_LINES, diff --git a/clippy_lints/src/if_not_else.rs b/clippy_lints/src/if_not_else.rs index 0ebd8d0c237..120c5396a1c 100644 --- a/clippy_lints/src/if_not_else.rs +++ b/clippy_lints/src/if_not_else.rs @@ -1,6 +1,3 @@ -//! lint on if branches that could be swapped so no `!` operation is necessary -//! on the condition - use clippy_utils::consts::{ConstEvalCtxt, Constant}; use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::is_else_clause; diff --git a/clippy_lints/src/implicit_return.rs b/clippy_lints/src/implicit_return.rs index b926e1e62ba..ba06567b957 100644 --- a/clippy_lints/src/implicit_return.rs +++ b/clippy_lints/src/implicit_return.rs @@ -3,7 +3,7 @@ use clippy_utils::source::{snippet_with_applicability, snippet_with_context, wal use clippy_utils::visitors::for_each_expr_without_closures; use clippy_utils::{get_async_fn_body, is_async_fn, is_from_proc_macro}; use core::ops::ControlFlow; -use rustc_errors::{Applicability, SuggestionStyle}; +use rustc_errors::Applicability; use rustc_hir::intravisit::FnKind; use rustc_hir::{Block, Body, Expr, ExprKind, FnDecl, FnRetTy, HirId}; use rustc_lint::{LateContext, LateLintPass, LintContext}; @@ -54,13 +54,7 @@ fn lint_return(cx: &LateContext<'_>, emission_place: HirId, span: Span) { |diag| { let mut app = Applicability::MachineApplicable; let snip = snippet_with_applicability(cx, span, "..", &mut app); - diag.span_suggestion_with_style( - span, - "add `return` as shown", - format!("return {snip}"), - app, - SuggestionStyle::ShowAlways, - ); + diag.span_suggestion_verbose(span, "add `return` as shown", format!("return {snip}"), app); }, ); } @@ -75,12 +69,11 @@ fn lint_break(cx: &LateContext<'_>, emission_place: HirId, break_span: Span, exp |diag| { let mut app = Applicability::MachineApplicable; let snip = snippet_with_context(cx, expr_span, break_span.ctxt(), "..", &mut app).0; - diag.span_suggestion_with_style( + diag.span_suggestion_verbose( break_span, "change `break` to `return` as shown", format!("return {snip}"), app, - SuggestionStyle::ShowAlways, ); }, ); diff --git a/clippy_lints/src/incompatible_msrv.rs b/clippy_lints/src/incompatible_msrv.rs index 0ef5b803a89..2ad045e1268 100644 --- a/clippy_lints/src/incompatible_msrv.rs +++ b/clippy_lints/src/incompatible_msrv.rs @@ -7,8 +7,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc_hir::{Expr, ExprKind, HirId}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::TyCtxt; -use rustc_semver::RustcVersion; -use rustc_session::impl_lint_pass; +use rustc_session::{impl_lint_pass, RustcVersion}; use rustc_span::def_id::DefId; use rustc_span::{ExpnKind, Span}; @@ -65,18 +64,18 @@ impl IncompatibleMsrv { StabilityLevel::Stable { since: StableSince::Version(version), .. - } => Some(RustcVersion::new( - version.major.into(), - version.minor.into(), - version.patch.into(), - )), + } => Some(version), _ => None, }) { version } else if let Some(parent_def_id) = tcx.opt_parent(def_id) { self.get_def_id_version(tcx, parent_def_id) } else { - RustcVersion::new(1, 0, 0) + RustcVersion { + major: 1, + minor: 0, + patch: 0, + } }; self.is_above_msrv.insert(def_id, version); version diff --git a/clippy_lints/src/inconsistent_struct_constructor.rs b/clippy_lints/src/inconsistent_struct_constructor.rs index 5b0aadf35c6..d386bfca6ba 100644 --- a/clippy_lints/src/inconsistent_struct_constructor.rs +++ b/clippy_lints/src/inconsistent_struct_constructor.rs @@ -1,4 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::fulfill_or_allowed; use clippy_utils::source::snippet; use rustc_data_structures::fx::FxHashMap; use rustc_errors::Applicability; @@ -71,6 +72,8 @@ impl<'tcx> LateLintPass<'tcx> for InconsistentStructConstructor { && let ty = cx.typeck_results().expr_ty(expr) && let Some(adt_def) = ty.ty_adt_def() && adt_def.is_struct() + && let Some(local_def_id) = adt_def.did().as_local() + && let ty_hir_id = cx.tcx.local_def_id_to_hir_id(local_def_id) && let Some(variant) = adt_def.variants().iter().next() { let mut def_order_map = FxHashMap::default(); @@ -103,15 +106,17 @@ impl<'tcx> LateLintPass<'tcx> for InconsistentStructConstructor { snippet(cx, qpath.span(), ".."), ); - span_lint_and_sugg( - cx, - INCONSISTENT_STRUCT_CONSTRUCTOR, - expr.span, - "struct constructor field order is inconsistent with struct definition field order", - "try", - sugg, - Applicability::MachineApplicable, - ); + if !fulfill_or_allowed(cx, INCONSISTENT_STRUCT_CONSTRUCTOR, Some(ty_hir_id)) { + span_lint_and_sugg( + cx, + INCONSISTENT_STRUCT_CONSTRUCTOR, + expr.span, + "struct constructor field order is inconsistent with struct definition field order", + "try", + sugg, + Applicability::MachineApplicable, + ); + } } } } diff --git a/clippy_lints/src/indexing_slicing.rs b/clippy_lints/src/indexing_slicing.rs index 3ac50b8f1fb..22e9674714f 100644 --- a/clippy_lints/src/indexing_slicing.rs +++ b/clippy_lints/src/indexing_slicing.rs @@ -1,5 +1,3 @@ -//! lint on indexing and slicing operations - use clippy_config::Conf; use clippy_utils::consts::{ConstEvalCtxt, Constant}; use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; diff --git a/clippy_lints/src/infinite_iter.rs b/clippy_lints/src/infinite_iter.rs index 676d50c4951..71c317552ee 100644 --- a/clippy_lints/src/infinite_iter.rs +++ b/clippy_lints/src/infinite_iter.rs @@ -1,10 +1,10 @@ use clippy_utils::diagnostics::span_lint; use clippy_utils::higher; -use clippy_utils::ty::{implements_trait, is_type_diagnostic_item}; +use clippy_utils::ty::{get_type_diagnostic_name, implements_trait}; use rustc_hir::{BorrowKind, Closure, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; -use rustc_span::symbol::{sym, Symbol}; +use rustc_span::symbol::sym; declare_clippy_lint! { /// ### What it does @@ -210,18 +210,6 @@ const COMPLETING_METHODS: [(&str, usize); 12] = [ ("product", 0), ]; -/// the paths of types that are known to be infinitely allocating -const INFINITE_COLLECTORS: &[Symbol] = &[ - sym::BinaryHeap, - sym::BTreeMap, - sym::BTreeSet, - sym::HashMap, - sym::HashSet, - sym::LinkedList, - sym::Vec, - sym::VecDeque, -]; - fn complete_infinite_iter(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness { match expr.kind { ExprKind::MethodCall(method, receiver, args, _) => { @@ -248,10 +236,19 @@ fn complete_infinite_iter(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness { } } else if method.ident.name == sym!(collect) { let ty = cx.typeck_results().expr_ty(expr); - if INFINITE_COLLECTORS - .iter() - .any(|diag_item| is_type_diagnostic_item(cx, ty, *diag_item)) - { + if matches!( + get_type_diagnostic_name(cx, ty), + Some( + sym::BinaryHeap + | sym::BTreeMap + | sym::BTreeSet + | sym::HashMap + | sym::HashSet + | sym::LinkedList + | sym::Vec + | sym::VecDeque, + ) + ) { return is_infinite(cx, receiver); } } diff --git a/clippy_lints/src/inherent_impl.rs b/clippy_lints/src/inherent_impl.rs index 9eed7aa9243..d39f910f993 100644 --- a/clippy_lints/src/inherent_impl.rs +++ b/clippy_lints/src/inherent_impl.rs @@ -1,5 +1,3 @@ -//! lint on inherent implementations - use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::is_lint_allowed; use rustc_data_structures::fx::FxHashMap; diff --git a/clippy_lints/src/inline_fn_without_body.rs b/clippy_lints/src/inline_fn_without_body.rs index 5657c58bb0a..1b900f6be8e 100644 --- a/clippy_lints/src/inline_fn_without_body.rs +++ b/clippy_lints/src/inline_fn_without_body.rs @@ -1,5 +1,3 @@ -//! checks for `#[inline]` on trait methods without bodies - use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::sugg::DiagExt; use rustc_errors::Applicability; diff --git a/clippy_lints/src/int_plus_one.rs b/clippy_lints/src/int_plus_one.rs index b8e0eef7c7e..fc575bff7e6 100644 --- a/clippy_lints/src/int_plus_one.rs +++ b/clippy_lints/src/int_plus_one.rs @@ -1,7 +1,5 @@ -//! lint on blocks unnecessarily using >= with a + 1 or - 1 - use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::snippet_opt; +use clippy_utils::source::SpanRangeExt; use rustc_ast::ast::{BinOpKind, Expr, ExprKind, LitKind}; use rustc_ast::token; use rustc_errors::Applicability; @@ -132,8 +130,8 @@ impl IntPlusOne { BinOpKind::Le => "<", _ => return None, }; - if let Some(snippet) = snippet_opt(cx, node.span) { - if let Some(other_side_snippet) = snippet_opt(cx, other_side.span) { + if let Some(snippet) = node.span.get_source_text(cx) { + if let Some(other_side_snippet) = other_side.span.get_source_text(cx) { let rec = match side { Side::Lhs => Some(format!("{snippet} {binop_string} {other_side_snippet}")), Side::Rhs => Some(format!("{other_side_snippet} {binop_string} {snippet}")), diff --git a/clippy_lints/src/item_name_repetitions.rs b/clippy_lints/src/item_name_repetitions.rs index 4d44bae02b8..74bf82f58bd 100644 --- a/clippy_lints/src/item_name_repetitions.rs +++ b/clippy_lints/src/item_name_repetitions.rs @@ -1,5 +1,3 @@ -//! lint on enum variants that are prefixed or suffixed by the same characters - use clippy_config::Conf; use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_hir}; use clippy_utils::is_bool; diff --git a/clippy_lints/src/items_after_statements.rs b/clippy_lints/src/items_after_statements.rs index a88d8e24fda..4f066113aea 100644 --- a/clippy_lints/src/items_after_statements.rs +++ b/clippy_lints/src/items_after_statements.rs @@ -1,5 +1,3 @@ -//! lint when items are used after statements - use clippy_utils::diagnostics::span_lint_hir; use rustc_hir::{Block, ItemKind, StmtKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; diff --git a/clippy_lints/src/items_after_test_module.rs b/clippy_lints/src/items_after_test_module.rs index 3614fb8cc96..8caa484bb99 100644 --- a/clippy_lints/src/items_after_test_module.rs +++ b/clippy_lints/src/items_after_test_module.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_hir_and_then; -use clippy_utils::source::snippet_opt; +use clippy_utils::source::SpanRangeExt; use clippy_utils::{fulfill_or_allowed, is_cfg_test, is_from_proc_macro}; use rustc_errors::{Applicability, SuggestionStyle}; use rustc_hir::{HirId, Item, ItemKind, Mod}; @@ -93,11 +93,14 @@ impl LateLintPass<'_> for ItemsAfterTestModule { if let Some(prev) = mod_pos.checked_sub(1) && let prev = cx.tcx.hir().item(module.item_ids[prev]) && let items_span = last.span.with_lo(test_mod.span.hi()) - && let Some(items) = snippet_opt(cx, items_span) + && let Some(items) = items_span.get_source_text(cx) { diag.multipart_suggestion_with_style( "move the items to before the test module was defined", - vec![(prev.span.shrink_to_hi(), items), (items_span, String::new())], + vec![ + (prev.span.shrink_to_hi(), items.to_owned()), + (items_span, String::new()), + ], Applicability::MachineApplicable, SuggestionStyle::HideCodeAlways, ); diff --git a/clippy_lints/src/large_enum_variant.rs b/clippy_lints/src/large_enum_variant.rs index 225d79aa71d..2f027c11707 100644 --- a/clippy_lints/src/large_enum_variant.rs +++ b/clippy_lints/src/large_enum_variant.rs @@ -1,5 +1,3 @@ -//! lint when there is a large size difference between variants on an enum - use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet_with_applicability; diff --git a/clippy_lints/src/large_stack_frames.rs b/clippy_lints/src/large_stack_frames.rs index 4abf7edc9b4..d2bdf194ada 100644 --- a/clippy_lints/src/large_stack_frames.rs +++ b/clippy_lints/src/large_stack_frames.rs @@ -3,7 +3,7 @@ use std::{fmt, ops}; use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::fn_has_unsatisfiable_preds; -use clippy_utils::source::snippet_opt; +use clippy_utils::source::SpanRangeExt; use rustc_hir::def_id::LocalDefId; use rustc_hir::intravisit::FnKind; use rustc_hir::{Body, FnDecl}; @@ -186,7 +186,7 @@ impl<'tcx> LateLintPass<'tcx> for LargeStackFrames { // TODO: Is there a cleaner, robust way to ask this question? // The obvious `LocalDecl::is_user_variable()` panics on "unwrapping cross-crate data", // and that doesn't get us the true name in scope rather than the span text either. - if let Some(name) = snippet_opt(cx, local_span) + if let Some(name) = local_span.get_source_text(cx) && is_ident(&name) { // If the local is an ordinary named variable, diff --git a/clippy_lints/src/legacy_numeric_constants.rs b/clippy_lints/src/legacy_numeric_constants.rs index 752e1326e3e..ccab1e27d3b 100644 --- a/clippy_lints/src/legacy_numeric_constants.rs +++ b/clippy_lints/src/legacy_numeric_constants.rs @@ -3,7 +3,7 @@ use clippy_config::Conf; use clippy_utils::diagnostics::{span_lint_and_then, span_lint_hir_and_then}; use clippy_utils::{get_parent_expr, is_from_proc_macro}; use hir::def_id::DefId; -use rustc_errors::{Applicability, SuggestionStyle}; +use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::{ExprKind, Item, ItemKind, QPath, UseKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; @@ -143,12 +143,11 @@ impl<'tcx> LateLintPass<'tcx> for LegacyNumericConstants { && !is_from_proc_macro(cx, expr) { span_lint_hir_and_then(cx, LEGACY_NUMERIC_CONSTANTS, expr.hir_id, span, msg, |diag| { - diag.span_suggestion_with_style( + diag.span_suggestion_verbose( span, "use the associated constant instead", sugg, Applicability::MaybeIncorrect, - SuggestionStyle::ShowAlways, ); }); } diff --git a/clippy_lints/src/len_zero.rs b/clippy_lints/src/len_zero.rs index 4c737371bd2..0bc7fc2dd9d 100644 --- a/clippy_lints/src/len_zero.rs +++ b/clippy_lints/src/len_zero.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then}; -use clippy_utils::source::{snippet_opt, snippet_with_context}; +use clippy_utils::source::{snippet_with_context, SpanRangeExt}; use clippy_utils::sugg::{has_enclosing_paren, Sugg}; use clippy_utils::{get_item_name, get_parent_as_impl, is_lint_allowed, peel_ref_operators}; use rustc_ast::ast::LitKind; @@ -216,7 +216,7 @@ impl<'tcx> LateLintPass<'tcx> for LenZero { } fn span_without_enclosing_paren(cx: &LateContext<'_>, span: Span) -> Span { - let Some(snippet) = snippet_opt(cx, span) else { + let Some(snippet) = span.get_source_text(cx) else { return span; }; if has_enclosing_paren(snippet) { diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index ce13a9afef5..2ac06b360be 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -66,8 +66,8 @@ extern crate declare_clippy_lint; #[cfg_attr(feature = "internal", allow(clippy::missing_clippy_version_attribute))] mod utils; -mod declared_lints; -mod deprecated_lints; +pub mod declared_lints; +pub mod deprecated_lints; // begin lints modules, do not remove this comment, it’s used in `update_lints` mod absolute_paths; @@ -440,7 +440,7 @@ impl RegistrationGroups { } } -#[derive(Copy, Clone)] +#[derive(Copy, Clone, Debug)] pub(crate) enum LintCategory { Cargo, Complexity, @@ -479,11 +479,39 @@ impl LintCategory { } } -pub(crate) struct LintInfo { +pub struct LintInfo { /// Double reference to maintain pointer equality - lint: &'static &'static Lint, + pub lint: &'static &'static Lint, category: LintCategory, - explanation: &'static str, + pub explanation: &'static str, + /// e.g. `clippy_lints/src/absolute_paths.rs#43` + pub location: &'static str, + pub version: Option<&'static str>, +} + +impl LintInfo { + /// Returns the lint name in lowercase without the `clippy::` prefix + #[allow(clippy::missing_panics_doc)] + pub fn name_lower(&self) -> String { + self.lint.name.strip_prefix("clippy::").unwrap().to_ascii_lowercase() + } + + /// Returns the name of the lint's category in lowercase (`style`, `pedantic`) + pub fn category_str(&self) -> &'static str { + match self.category { + Cargo => "cargo", + Complexity => "complexity", + Correctness => "correctness", + Nursery => "nursery", + Pedantic => "pedantic", + Perf => "perf", + Restriction => "restriction", + Style => "style", + Suspicious => "suspicious", + #[cfg(feature = "internal")] + Internal => "internal", + } + } } pub fn explain(name: &str) -> i32 { @@ -538,14 +566,6 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { store.register_removed(name, reason); } - #[cfg(feature = "internal")] - { - if std::env::var("ENABLE_METADATA_COLLECTION").eq(&Ok("1".to_string())) { - store.register_late_pass(|_| Box::new(utils::internal_lints::metadata_collector::MetadataCollector::new())); - return; - } - } - let format_args_storage = FormatArgsStorage::default(); let format_args = format_args_storage.clone(); store.register_early_pass(move || { diff --git a/clippy_lints/src/literal_representation.rs b/clippy_lints/src/literal_representation.rs index 259e4d6c08f..81f2a03fb55 100644 --- a/clippy_lints/src/literal_representation.rs +++ b/clippy_lints/src/literal_representation.rs @@ -1,10 +1,7 @@ -//! Lints concerned with the grouping of digits with underscores in integral or -//! floating-point literal expressions. - use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::numeric_literal::{NumericLiteral, Radix}; -use clippy_utils::source::snippet_opt; +use clippy_utils::source::SpanRangeExt; use rustc_ast::ast::{Expr, ExprKind, LitKind}; use rustc_ast::token; use rustc_errors::Applicability; @@ -228,7 +225,7 @@ impl LiteralDigitGrouping { } fn check_lit(&self, cx: &EarlyContext<'_>, lit: token::Lit, span: Span) { - if let Some(src) = snippet_opt(cx, span) + if let Some(src) = span.get_source_text(cx) && let Ok(lit_kind) = LitKind::from_token_lit(lit) && let Some(mut num_lit) = NumericLiteral::from_lit_kind(&src, &lit_kind) { @@ -442,7 +439,7 @@ impl DecimalLiteralRepresentation { // Lint integral literals. if let Ok(lit_kind) = LitKind::from_token_lit(lit) && let LitKind::Int(val, _) = lit_kind - && let Some(src) = snippet_opt(cx, span) + && let Some(src) = span.get_source_text(cx) && let Some(num_lit) = NumericLiteral::from_lit_kind(&src, &lit_kind) && num_lit.radix == Radix::Decimal && val >= u128::from(self.threshold) diff --git a/clippy_lints/src/loops/explicit_iter_loop.rs b/clippy_lints/src/loops/explicit_iter_loop.rs index eea5f2a94ea..b134af500f5 100644 --- a/clippy_lints/src/loops/explicit_iter_loop.rs +++ b/clippy_lints/src/loops/explicit_iter_loop.rs @@ -3,7 +3,7 @@ use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::{ - implements_trait, implements_trait_with_env, is_copy, make_normalized_projection, + implements_trait, implements_trait_with_env, is_copy, is_type_lang_item, make_normalized_projection, make_normalized_projection_with_regions, normalize_with_regions, }; use rustc_errors::Applicability; @@ -20,9 +20,10 @@ pub(super) fn check( msrv: &Msrv, enforce_iter_loop_reborrow: bool, ) { - let Some((adjust, ty)) = is_ref_iterable(cx, self_arg, call_expr, enforce_iter_loop_reborrow) else { + let Some((adjust, ty)) = is_ref_iterable(cx, self_arg, call_expr, enforce_iter_loop_reborrow, msrv) else { return; }; + if let ty::Array(_, count) = *ty.peel_refs().kind() { if !ty.is_ref() { if !msrv.meets(msrvs::ARRAY_INTO_ITERATOR) { @@ -109,6 +110,7 @@ fn is_ref_iterable<'tcx>( self_arg: &Expr<'_>, call_expr: &Expr<'_>, enforce_iter_loop_reborrow: bool, + msrv: &Msrv, ) -> Option<(AdjustKind, Ty<'tcx>)> { let typeck = cx.typeck_results(); if let Some(trait_id) = cx.tcx.get_diagnostic_item(sym::IntoIterator) @@ -128,6 +130,12 @@ fn is_ref_iterable<'tcx>( let self_ty = typeck.expr_ty(self_arg); let self_is_copy = is_copy(cx, self_ty); + if !msrv.meets(msrvs::BOX_INTO_ITER) + && is_type_lang_item(cx, self_ty.peel_refs(), rustc_hir::LangItem::OwnedBox) + { + return None; + } + if adjustments.is_empty() && self_is_copy { // Exact type match, already checked earlier return Some((AdjustKind::None, self_ty)); diff --git a/clippy_lints/src/macro_metavars_in_unsafe.rs b/clippy_lints/src/macro_metavars_in_unsafe.rs index fed58f7ff14..e215097142b 100644 --- a/clippy_lints/src/macro_metavars_in_unsafe.rs +++ b/clippy_lints/src/macro_metavars_in_unsafe.rs @@ -122,8 +122,23 @@ struct BodyVisitor<'a, 'tcx> { /// within a relevant macro. macro_unsafe_blocks: Vec, /// When this is >0, it means that the node currently being visited is "within" a - /// macro definition. This is not necessary for correctness, it merely helps reduce the number - /// of spans we need to insert into the map, since only spans from macros are relevant. + /// macro definition. + /// This is used to detect if an expression represents a metavariable. + /// + /// For example, the following pre-expansion code that we want to lint + /// ```ignore + /// macro_rules! m { ($e:expr) => { unsafe { $e; } } } + /// m!(1); + /// ``` + /// would look like this post-expansion code: + /// ```ignore + /// unsafe { /* macro */ + /// 1 /* root */; /* macro */ + /// } + /// ``` + /// Visiting the block and the statement will increment the `expn_depth` so that it is >0, + /// and visiting the expression with a root context while `expn_depth > 0` tells us + /// that it must be a metavariable. expn_depth: u32, cx: &'a LateContext<'tcx>, lint: &'a mut ExprMetavarsInUnsafe, @@ -157,7 +172,9 @@ impl<'a, 'tcx> Visitor<'tcx> for BodyVisitor<'a, 'tcx> { && (self.lint.warn_unsafe_macro_metavars_in_private_macros || is_public_macro(self.cx, macro_def_id)) { self.macro_unsafe_blocks.push(block.hir_id); + self.expn_depth += 1; walk_block(self, block); + self.expn_depth -= 1; self.macro_unsafe_blocks.pop(); } else if ctxt.is_root() && self.expn_depth > 0 { let unsafe_block = self.macro_unsafe_blocks.last().copied(); diff --git a/clippy_lints/src/manual_async_fn.rs b/clippy_lints/src/manual_async_fn.rs index 25c7e5d38b3..61723aec590 100644 --- a/clippy_lints/src/manual_async_fn.rs +++ b/clippy_lints/src/manual_async_fn.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::{position_before_rarrow, snippet_block, snippet_opt}; +use clippy_utils::source::{position_before_rarrow, snippet_block, SpanRangeExt}; use rustc_errors::Applicability; use rustc_hir::intravisit::FnKind; use rustc_hir::{ @@ -68,8 +68,8 @@ impl<'tcx> LateLintPass<'tcx> for ManualAsyncFn { header_span, "this function can be simplified using the `async fn` syntax", |diag| { - if let Some(vis_snip) = snippet_opt(cx, *vis_span) - && let Some(header_snip) = snippet_opt(cx, header_span) + 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) { @@ -190,6 +190,6 @@ fn suggested_ret(cx: &LateContext<'_>, output: &Ty<'_>) -> Option<(&'static str, Some((sugg, String::new())) } else { let sugg = "return the output of the future directly"; - snippet_opt(cx, output.span).map(|snip| (sugg, format!(" -> {snip}"))) + output.span.get_source_text(cx).map(|src| (sugg, format!(" -> {src}"))) } } diff --git a/clippy_lints/src/manual_float_methods.rs b/clippy_lints/src/manual_float_methods.rs index 6bdc79129a9..9d3ddab60bb 100644 --- a/clippy_lints/src/manual_float_methods.rs +++ b/clippy_lints/src/manual_float_methods.rs @@ -1,6 +1,6 @@ use clippy_utils::consts::{ConstEvalCtxt, Constant}; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::snippet_opt; +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}; @@ -103,7 +103,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualFloatMethods { // case somebody does that for some reason && (is_infinity(&const_1) && is_neg_infinity(&const_2) || is_neg_infinity(&const_1) && is_infinity(&const_2)) - && let Some(local_snippet) = snippet_opt(cx, first.span) + && let Some(local_snippet) = first.span.get_source_text(cx) { let variant = match (kind.node, lhs_kind.node, rhs_kind.node) { (BinOpKind::Or, BinOpKind::Eq, BinOpKind::Eq) => Variant::ManualIsInfinite, diff --git a/clippy_lints/src/manual_hash_one.rs b/clippy_lints/src/manual_hash_one.rs index 1c568b1b74f..11716a539ab 100644 --- a/clippy_lints/src/manual_hash_one.rs +++ b/clippy_lints/src/manual_hash_one.rs @@ -1,7 +1,7 @@ use clippy_config::msrvs::{self, Msrv}; use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_hir_and_then; -use clippy_utils::source::snippet_opt; +use clippy_utils::source::SpanRangeExt; use clippy_utils::visitors::{is_local_used, local_used_once}; use clippy_utils::{is_trait_method, path_to_local_id}; use rustc_errors::Applicability; @@ -107,8 +107,8 @@ impl LateLintPass<'_> for ManualHashOne { finish_expr.span, "manual implementation of `BuildHasher::hash_one`", |diag| { - if let Some(build_hasher) = snippet_opt(cx, build_hasher.span) - && let Some(hashed_value) = snippet_opt(cx, hashed_value.span) + if let Some(build_hasher) = build_hasher.span.get_source_text(cx) + && let Some(hashed_value) = hashed_value.span.get_source_text(cx) { diag.multipart_suggestion( "try", diff --git a/clippy_lints/src/manual_non_exhaustive.rs b/clippy_lints/src/manual_non_exhaustive.rs index 28cfe22835a..6b1d90483cc 100644 --- a/clippy_lints/src/manual_non_exhaustive.rs +++ b/clippy_lints/src/manual_non_exhaustive.rs @@ -2,7 +2,7 @@ use clippy_config::msrvs::{self, Msrv}; use clippy_config::Conf; use clippy_utils::diagnostics::{span_lint_and_then, span_lint_hir_and_then}; use clippy_utils::is_doc_hidden; -use clippy_utils::source::snippet_opt; +use clippy_utils::source::SpanRangeExt; use rustc_ast::ast::{self, VisibilityKind}; use rustc_ast::attr; use rustc_data_structures::fx::FxHashSet; @@ -124,7 +124,7 @@ impl EarlyLintPass for ManualNonExhaustiveStruct { |diag| { if !item.attrs.iter().any(|attr| attr.has_name(sym::non_exhaustive)) && let header_span = cx.sess().source_map().span_until_char(item.span, delimiter) - && let Some(snippet) = snippet_opt(cx, header_span) + && let Some(snippet) = header_span.get_source_text(cx) { diag.span_suggestion( header_span, @@ -194,7 +194,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualNonExhaustiveEnum { "this seems like a manual implementation of the non-exhaustive pattern", |diag| { let header_span = cx.sess().source_map().span_until_char(enum_span, '{'); - if let Some(snippet) = snippet_opt(cx, header_span) { + if let Some(snippet) = header_span.get_source_text(cx) { diag.span_suggestion( header_span, "add the attribute", diff --git a/clippy_lints/src/manual_range_patterns.rs b/clippy_lints/src/manual_range_patterns.rs index 07d4abbf5cd..9afb2b5bc84 100644 --- a/clippy_lints/src/manual_range_patterns.rs +++ b/clippy_lints/src/manual_range_patterns.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::snippet_opt; +use clippy_utils::source::SpanRangeExt; use rustc_ast::LitKind; use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; @@ -143,8 +143,8 @@ impl LateLintPass<'_> for ManualRangePatterns { pat.span, "this OR pattern can be rewritten using a range", |diag| { - if let Some(min) = snippet_opt(cx, min.span) - && let Some(max) = snippet_opt(cx, max.span) + if let Some(min) = min.span.get_source_text(cx) + && let Some(max) = max.span.get_source_text(cx) { diag.span_suggestion( pat.span, diff --git a/clippy_lints/src/manual_retain.rs b/clippy_lints/src/manual_retain.rs index 09f6362b4dd..d4e53f8f74b 100644 --- a/clippy_lints/src/manual_retain.rs +++ b/clippy_lints/src/manual_retain.rs @@ -2,14 +2,13 @@ use clippy_config::msrvs::{self, Msrv}; use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet; -use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item}; +use clippy_utils::ty::{get_type_diagnostic_name, is_type_lang_item}; use clippy_utils::{match_def_path, paths, SpanlessEq}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_hir::ExprKind::Assign; use rustc_lint::{LateContext, LateLintPass}; -use rustc_semver::RustcVersion; use rustc_session::impl_lint_pass; use rustc_span::symbol::sym; use rustc_span::Span; @@ -21,16 +20,6 @@ const ACCEPTABLE_METHODS: [&[&str]; 5] = [ &paths::SLICE_INTO, &paths::VEC_DEQUE_ITER, ]; -const ACCEPTABLE_TYPES: [(rustc_span::Symbol, Option); 7] = [ - (sym::BinaryHeap, Some(msrvs::BINARY_HEAP_RETAIN)), - (sym::BTreeSet, Some(msrvs::BTREE_SET_RETAIN)), - (sym::BTreeMap, Some(msrvs::BTREE_MAP_RETAIN)), - (sym::HashSet, Some(msrvs::HASH_SET_RETAIN)), - (sym::HashMap, Some(msrvs::HASH_MAP_RETAIN)), - (sym::Vec, None), - (sym::VecDeque, None), -]; -const MAP_TYPES: [rustc_span::Symbol; 2] = [sym::BTreeMap, sym::HashMap]; declare_clippy_lint! { /// ### What it does @@ -265,16 +254,22 @@ fn match_acceptable_def_path(cx: &LateContext<'_>, collect_def_id: DefId) -> boo } fn match_acceptable_type(cx: &LateContext<'_>, expr: &hir::Expr<'_>, msrv: &Msrv) -> bool { - let expr_ty = cx.typeck_results().expr_ty(expr).peel_refs(); - ACCEPTABLE_TYPES.iter().any(|(ty, acceptable_msrv)| { - is_type_diagnostic_item(cx, expr_ty, *ty) - && acceptable_msrv.map_or(true, |acceptable_msrv| msrv.meets(acceptable_msrv)) - }) + let ty = cx.typeck_results().expr_ty(expr).peel_refs(); + let required = match get_type_diagnostic_name(cx, ty) { + Some(sym::BinaryHeap) => msrvs::BINARY_HEAP_RETAIN, + Some(sym::BTreeSet) => msrvs::BTREE_SET_RETAIN, + Some(sym::BTreeMap) => msrvs::BTREE_MAP_RETAIN, + Some(sym::HashSet) => msrvs::HASH_SET_RETAIN, + Some(sym::HashMap) => msrvs::HASH_MAP_RETAIN, + Some(sym::Vec | sym::VecDeque) => return true, + _ => return false, + }; + msrv.meets(required) } fn match_map_type(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool { - let expr_ty = cx.typeck_results().expr_ty(expr).peel_refs(); - MAP_TYPES.iter().any(|ty| is_type_diagnostic_item(cx, expr_ty, *ty)) + let ty = cx.typeck_results().expr_ty(expr).peel_refs(); + matches!(get_type_diagnostic_name(cx, ty), Some(sym::BTreeMap | sym::HashMap)) } fn make_span_lint_and_sugg(cx: &LateContext<'_>, span: Span, sugg: String) { diff --git a/clippy_lints/src/matches/collapsible_match.rs b/clippy_lints/src/matches/collapsible_match.rs index 90cfdecc199..b666e77c09e 100644 --- a/clippy_lints/src/matches/collapsible_match.rs +++ b/clippy_lints/src/matches/collapsible_match.rs @@ -96,7 +96,7 @@ fn check_arm<'tcx>( // collapsing patterns need an explicit field name in struct pattern matching // ex: Struct {x: Some(1)} let replace_msg = if is_innermost_parent_pat_struct { - format!(", prefixed by {}:", snippet(cx, binding_span, "their field name")) + format!(", prefixed by `{}`:", snippet(cx, binding_span, "their field name")) } else { String::new() }; diff --git a/clippy_lints/src/matches/manual_unwrap_or.rs b/clippy_lints/src/matches/manual_unwrap_or.rs index 2d4c8daf5cb..d5d83df9347 100644 --- a/clippy_lints/src/matches/manual_unwrap_or.rs +++ b/clippy_lints/src/matches/manual_unwrap_or.rs @@ -1,6 +1,6 @@ use clippy_utils::consts::ConstEvalCtxt; use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::{indent_of, reindent_multiline, snippet_opt}; +use clippy_utils::source::{indent_of, reindent_multiline, SpanRangeExt}; use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::usage::contains_return_break_continue_macro; use clippy_utils::{is_res_lang_ctor, path_to_local_id, peel_blocks, sugg}; @@ -67,11 +67,11 @@ fn check_and_lint<'tcx>( && path_to_local_id(peel_blocks(then_expr), binding_hir_id) && cx.typeck_results().expr_adjustments(then_expr).is_empty() && let Some(ty_name) = find_type_name(cx, ty) - && let Some(or_body_snippet) = snippet_opt(cx, else_expr.span) + && let Some(or_body_snippet) = else_expr.span.get_source_text(cx) && let Some(indent) = indent_of(cx, expr.span) && ConstEvalCtxt::new(cx).eval_simple(else_expr).is_some() { - lint(cx, expr, let_expr, ty_name, or_body_snippet, indent); + lint(cx, expr, let_expr, ty_name, &or_body_snippet, indent); } } @@ -110,7 +110,7 @@ fn lint<'tcx>( expr: &Expr<'tcx>, scrutinee: &'tcx Expr<'_>, ty_name: &str, - or_body_snippet: String, + or_body_snippet: &str, indent: usize, ) { let reindented_or_body = reindent_multiline(or_body_snippet.into(), true, Some(indent)); diff --git a/clippy_lints/src/matches/single_match.rs b/clippy_lints/src/matches/single_match.rs index 24dea03601c..b6930f7b9d1 100644 --- a/clippy_lints/src/matches/single_match.rs +++ b/clippy_lints/src/matches/single_match.rs @@ -22,7 +22,7 @@ use super::{MATCH_BOOL, SINGLE_MATCH, SINGLE_MATCH_ELSE}; /// span, e.g. a string literal `"//"`, but we know that this isn't the case for empty /// match arms. fn empty_arm_has_comment(cx: &LateContext<'_>, span: Span) -> bool { - if let Some(ff) = span.get_source_text(cx) + if let Some(ff) = span.get_source_range(cx) && let Some(text) = ff.as_str() { text.as_bytes().windows(2).any(|w| w == b"//" || w == b"/*") diff --git a/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs b/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs index a5df863d800..740cce0a6c2 100644 --- a/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs +++ b/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::{indent_of, reindent_multiline, snippet_opt}; +use clippy_utils::source::{indent_of, reindent_multiline, SpanRangeExt}; use clippy_utils::ty::is_type_lang_item; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; @@ -49,10 +49,12 @@ pub(super) fn check<'tcx>( "case-sensitive file extension comparison", |diag| { diag.help("consider using a case-insensitive comparison instead"); - if let Some(mut recv_source) = snippet_opt(cx, recv.span) { - if !cx.typeck_results().expr_ty(recv).is_ref() { - recv_source = format!("&{recv_source}"); - } + if let Some(recv_source) = recv.span.get_source_text(cx) { + let recv_source = if cx.typeck_results().expr_ty(recv).is_ref() { + recv_source.to_owned() + } else { + format!("&{recv_source}") + }; let suggestion_source = reindent_multiline( format!( diff --git a/clippy_lints/src/methods/filter_map_bool_then.rs b/clippy_lints/src/methods/filter_map_bool_then.rs index 2e43d19a699..4fbf661727d 100644 --- a/clippy_lints/src/methods/filter_map_bool_then.rs +++ b/clippy_lints/src/methods/filter_map_bool_then.rs @@ -1,7 +1,7 @@ use super::FILTER_MAP_BOOL_THEN; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::paths::BOOL_THEN; -use clippy_utils::source::snippet_opt; +use clippy_utils::source::SpanRangeExt; use clippy_utils::ty::is_copy; use clippy_utils::{is_from_proc_macro, is_trait_method, match_def_path, peel_blocks}; use rustc_errors::Applicability; @@ -42,9 +42,9 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, arg: & .iter() .filter(|adj| matches!(adj.kind, Adjust::Deref(_))) .count() - && let Some(param_snippet) = snippet_opt(cx, param.span) - && let Some(filter) = snippet_opt(cx, recv.span) - && let Some(map) = snippet_opt(cx, then_body.span) + && let Some(param_snippet) = param.span.get_source_text(cx) + && let Some(filter) = recv.span.get_source_text(cx) + && let Some(map) = then_body.span.get_source_text(cx) { span_lint_and_sugg( cx, diff --git a/clippy_lints/src/methods/from_iter_instead_of_collect.rs b/clippy_lints/src/methods/from_iter_instead_of_collect.rs index 917a8e33eb9..f4840785584 100644 --- a/clippy_lints/src/methods/from_iter_instead_of_collect.rs +++ b/clippy_lints/src/methods/from_iter_instead_of_collect.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::snippet_opt; +use clippy_utils::source::SpanRangeExt; use clippy_utils::ty::implements_trait; use clippy_utils::{is_path_diagnostic_item, sugg}; use rustc_errors::Applicability; @@ -39,7 +39,7 @@ fn extract_turbofish(cx: &LateContext<'_>, expr: &hir::Expr<'_>, ty: Ty<'_>) -> } let call_site = expr.span.source_callsite(); - if let Some(snippet) = snippet_opt(cx, call_site) + if let Some(snippet) = call_site.get_source_text(cx) && let snippet_split = snippet.split("::").collect::>() && let Some((_, elements)) = snippet_split.split_last() { diff --git a/clippy_lints/src/methods/get_unwrap.rs b/clippy_lints/src/methods/get_unwrap.rs index c6285c87a26..9daad1a8a94 100644 --- a/clippy_lints/src/methods/get_unwrap.rs +++ b/clippy_lints/src/methods/get_unwrap.rs @@ -74,7 +74,7 @@ pub(super) fn check<'tcx>( "&" }; - diag.span_suggestion_with_style( + diag.span_suggestion_verbose( span, "using `[]` is clearer and more concise", format!( @@ -82,7 +82,6 @@ pub(super) fn check<'tcx>( snippet_with_applicability(cx, recv.span, "..", &mut applicability) ), applicability, - rustc_errors::SuggestionStyle::ShowAlways, ); }, ); diff --git a/clippy_lints/src/methods/is_digit_ascii_radix.rs b/clippy_lints/src/methods/is_digit_ascii_radix.rs index 22d896433f0..40b48ccca5d 100644 --- a/clippy_lints/src/methods/is_digit_ascii_radix.rs +++ b/clippy_lints/src/methods/is_digit_ascii_radix.rs @@ -1,5 +1,3 @@ -//! Lint for `c.is_digit(10)` - use super::IS_DIGIT_ASCII_RADIX; use clippy_config::msrvs::{self, Msrv}; use clippy_utils::consts::{ConstEvalCtxt, FullInt}; diff --git a/clippy_lints/src/methods/join_absolute_paths.rs b/clippy_lints/src/methods/join_absolute_paths.rs index aa1ec60d434..2dad7fcf3c1 100644 --- a/clippy_lints/src/methods/join_absolute_paths.rs +++ b/clippy_lints/src/methods/join_absolute_paths.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::expr_or_init; -use clippy_utils::source::snippet_opt; +use clippy_utils::source::snippet; use clippy_utils::ty::is_type_diagnostic_item; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; @@ -25,7 +25,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, recv: &'tcx Expr<'tcx>, join_a join_arg.span, "argument to `Path::join` starts with a path separator", |diag| { - let arg_str = snippet_opt(cx, spanned.span).unwrap_or_else(|| "..".to_string()); + let arg_str = snippet(cx, spanned.span, ".."); let no_separator = if sym_str.starts_with('/') { arg_str.replacen('/', "", 1) diff --git a/clippy_lints/src/methods/manual_ok_or.rs b/clippy_lints/src/methods/manual_ok_or.rs index b1af0083e65..b1a8e1e5e47 100644 --- a/clippy_lints/src/methods/manual_ok_or.rs +++ b/clippy_lints/src/methods/manual_ok_or.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::{indent_of, reindent_multiline, snippet_opt}; +use clippy_utils::source::{indent_of, reindent_multiline, SpanRangeExt}; use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::{is_res_lang_ctor, path_res, path_to_local_id}; use rustc_errors::Applicability; @@ -23,11 +23,11 @@ pub(super) fn check<'tcx>( && let ExprKind::Call(err_path, [err_arg]) = or_expr.kind && is_res_lang_ctor(cx, path_res(cx, err_path), ResultErr) && is_ok_wrapping(cx, map_expr) - && let Some(recv_snippet) = snippet_opt(cx, recv.span) - && let Some(err_arg_snippet) = snippet_opt(cx, err_arg.span) + && let Some(recv_snippet) = recv.span.get_source_text(cx) + && let Some(err_arg_snippet) = err_arg.span.get_source_text(cx) && let Some(indent) = indent_of(cx, expr.span) { - let reindented_err_arg_snippet = reindent_multiline(err_arg_snippet.into(), true, Some(indent + 4)); + let reindented_err_arg_snippet = reindent_multiline(err_arg_snippet.as_str().into(), true, Some(indent + 4)); span_lint_and_sugg( cx, MANUAL_OK_OR, diff --git a/clippy_lints/src/methods/manual_try_fold.rs b/clippy_lints/src/methods/manual_try_fold.rs index f93edded729..11fba35c16e 100644 --- a/clippy_lints/src/methods/manual_try_fold.rs +++ b/clippy_lints/src/methods/manual_try_fold.rs @@ -1,6 +1,6 @@ use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::snippet_opt; +use clippy_utils::source::SpanRangeExt; use clippy_utils::ty::implements_trait; use clippy_utils::{is_from_proc_macro, is_trait_method}; use rustc_errors::Applicability; @@ -31,13 +31,15 @@ pub(super) fn check<'tcx>( && let Res::Def(DefKind::Ctor(_, _), _) = cx.qpath_res(&qpath, path.hir_id) && let ExprKind::Closure(closure) = acc.kind && !is_from_proc_macro(cx, expr) - && let Some(args_snip) = closure.fn_arg_span.and_then(|fn_arg_span| snippet_opt(cx, fn_arg_span)) + && let Some(args_snip) = closure + .fn_arg_span + .and_then(|fn_arg_span| fn_arg_span.get_source_text(cx)) { let init_snip = rest .is_empty() .then_some(first.span) - .and_then(|span| snippet_opt(cx, span)) - .unwrap_or("...".to_owned()); + .and_then(|span| span.get_source_text(cx)) + .map_or_else(|| "...".to_owned(), |src| src.to_owned()); span_lint_and_sugg( cx, diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 1d7b10fe8f0..d7126990edb 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -2702,10 +2702,10 @@ declare_clippy_lint! { /// } /// }) /// } - /// ``` + /// ``` /// - /// After: - /// ```rust + /// After: + /// ```rust /// use std::{fmt, num::ParseIntError}; /// /// #[derive(Debug)] diff --git a/clippy_lints/src/methods/needless_character_iteration.rs b/clippy_lints/src/methods/needless_character_iteration.rs index e3d78207715..332da722a37 100644 --- a/clippy_lints/src/methods/needless_character_iteration.rs +++ b/clippy_lints/src/methods/needless_character_iteration.rs @@ -7,7 +7,7 @@ use rustc_span::Span; use super::utils::get_last_chain_binding_hir_id; use super::NEEDLESS_CHARACTER_ITERATION; use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::snippet_opt; +use clippy_utils::source::SpanRangeExt; use clippy_utils::{match_def_path, path_to_local_id, peel_blocks}; fn peels_expr_ref<'a, 'tcx>(mut expr: &'a Expr<'tcx>) -> &'a Expr<'tcx> { @@ -35,7 +35,7 @@ fn handle_expr( && path_to_local_id(receiver, first_param) && let char_arg_ty = cx.typeck_results().expr_ty_adjusted(receiver).peel_refs() && *char_arg_ty.kind() == ty::Char - && let Some(snippet) = snippet_opt(cx, before_chars) + && let Some(snippet) = before_chars.get_source_text(cx) { span_lint_and_sugg( cx, @@ -79,7 +79,7 @@ fn handle_expr( && let Some(fn_def_id) = cx.qpath_res(&path, fn_path.hir_id).opt_def_id() && match_def_path(cx, fn_def_id, &["core", "char", "methods", "", "is_ascii"]) && path_to_local_id(peels_expr_ref(arg), first_param) - && let Some(snippet) = snippet_opt(cx, before_chars) + && let Some(snippet) = before_chars.get_source_text(cx) { span_lint_and_sugg( cx, diff --git a/clippy_lints/src/methods/needless_collect.rs b/clippy_lints/src/methods/needless_collect.rs index 46b457daf70..f61923e5bf5 100644 --- a/clippy_lints/src/methods/needless_collect.rs +++ b/clippy_lints/src/methods/needless_collect.rs @@ -2,7 +2,7 @@ use super::NEEDLESS_COLLECT; use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_hir_and_then}; use clippy_utils::source::{snippet, snippet_with_applicability}; use clippy_utils::sugg::Sugg; -use clippy_utils::ty::{is_type_diagnostic_item, make_normalized_projection, make_projection}; +use clippy_utils::ty::{get_type_diagnostic_name, make_normalized_projection, make_projection}; use clippy_utils::{ can_move_expr_to_closure, fn_def_id, get_enclosing_block, higher, is_trait_method, path_to_local, path_to_local_id, CaptureKind, @@ -88,9 +88,10 @@ pub(super) fn check<'tcx>( Node::LetStmt(l) => { if let PatKind::Binding(BindingMode::NONE | BindingMode::MUT, id, _, None) = l.pat.kind && let ty = cx.typeck_results().expr_ty(collect_expr) - && [sym::Vec, sym::VecDeque, sym::BinaryHeap, sym::LinkedList] - .into_iter() - .any(|item| is_type_diagnostic_item(cx, ty, item)) + && matches!( + get_type_diagnostic_name(cx, ty), + Some(sym::Vec | sym::VecDeque | sym::BinaryHeap | sym::LinkedList) + ) && let iter_ty = cx.typeck_results().expr_ty(iter_expr) && let Some(block) = get_enclosing_block(cx, l.hir_id) && let Some(iter_calls) = detect_iter_and_into_iters(block, id, cx, get_captured_ids(cx, iter_ty)) diff --git a/clippy_lints/src/methods/needless_option_as_deref.rs b/clippy_lints/src/methods/needless_option_as_deref.rs index eaae8613d44..9f714fdd47b 100644 --- a/clippy_lints/src/methods/needless_option_as_deref.rs +++ b/clippy_lints/src/methods/needless_option_as_deref.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::path_res; -use clippy_utils::source::snippet_opt; +use clippy_utils::source::SpanRangeExt; use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::usage::local_used_after_expr; use rustc_errors::Applicability; @@ -32,7 +32,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, name expr.span, "derefed type is same as origin", "try", - snippet_opt(cx, recv.span).unwrap(), + recv.span.get_source_text(cx).unwrap().to_owned(), Applicability::MachineApplicable, ); } diff --git a/clippy_lints/src/methods/string_lit_chars_any.rs b/clippy_lints/src/methods/string_lit_chars_any.rs index 5f6f027a3b5..cc0d432b799 100644 --- a/clippy_lints/src/methods/string_lit_chars_any.rs +++ b/clippy_lints/src/methods/string_lit_chars_any.rs @@ -1,6 +1,6 @@ use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::snippet_opt; +use clippy_utils::source::SpanRangeExt; use clippy_utils::{is_from_proc_macro, is_trait_method, path_to_local}; use itertools::Itertools; use rustc_ast::LitKind; @@ -34,7 +34,7 @@ pub(super) fn check<'tcx>( _ => return, } && !is_from_proc_macro(cx, expr) - && let Some(scrutinee_snip) = snippet_opt(cx, scrutinee.span) + && let Some(scrutinee_snip) = scrutinee.span.get_source_text(cx) { // Normalize the char using `map` so `join` doesn't use `Display`, if we don't then // something like `r"\"` will become `'\'`, which is of course invalid diff --git a/clippy_lints/src/methods/unnecessary_get_then_check.rs b/clippy_lints/src/methods/unnecessary_get_then_check.rs index f6184222d8e..64eb8411795 100644 --- a/clippy_lints/src/methods/unnecessary_get_then_check.rs +++ b/clippy_lints/src/methods/unnecessary_get_then_check.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; -use clippy_utils::source::snippet_opt; +use clippy_utils::source::SpanRangeExt; use clippy_utils::ty::is_type_diagnostic_item; use rustc_errors::Applicability; @@ -38,11 +38,11 @@ pub(super) fn check( return; }; let both_calls_span = get_call_span.with_hi(call_span.hi()); - if let Some(snippet) = snippet_opt(cx, both_calls_span) - && let Some(arg_snippet) = snippet_opt(cx, arg.span) + if let Some(snippet) = both_calls_span.get_source_text(cx) + && let Some(arg_snippet) = arg.span.get_source_text(cx) { let generics_snippet = if let Some(generics) = path.args - && let Some(generics_snippet) = snippet_opt(cx, generics.span_ext) + && let Some(generics_snippet) = generics.span_ext.get_source_text(cx) { format!("::{generics_snippet}") } else { @@ -63,7 +63,7 @@ pub(super) fn check( suggestion, Applicability::MaybeIncorrect, ); - } else if let Some(caller_snippet) = snippet_opt(cx, get_caller.span) { + } else if let Some(caller_snippet) = get_caller.span.get_source_text(cx) { let full_span = get_caller.span.with_hi(call_span.hi()); span_lint_and_then( diff --git a/clippy_lints/src/methods/unnecessary_iter_cloned.rs b/clippy_lints/src/methods/unnecessary_iter_cloned.rs index 70885e46e95..4d18bc7ac77 100644 --- a/clippy_lints/src/methods/unnecessary_iter_cloned.rs +++ b/clippy_lints/src/methods/unnecessary_iter_cloned.rs @@ -1,7 +1,7 @@ use super::utils::clone_or_copy_needed; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::higher::ForLoop; -use clippy_utils::source::snippet_opt; +use clippy_utils::source::SpanRangeExt; 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}; @@ -40,7 +40,7 @@ pub fn check_for_loop_iter( && let Some(ForLoop { pat, body, .. }) = ForLoop::hir(grandparent) && let (clone_or_copy_needed, references_to_binding) = clone_or_copy_needed(cx, pat, body) && !clone_or_copy_needed - && let Some(receiver_snippet) = snippet_opt(cx, receiver.span) + && let Some(receiver_snippet) = receiver.span.get_source_text(cx) { // Issue 12098 // https://github.com/rust-lang/rust-clippy/issues/12098 @@ -100,7 +100,7 @@ pub fn check_for_loop_iter( && implements_trait(cx, collection_ty, into_iterator_trait_id, &[]) && let Some(into_iter_item_ty) = cx.get_associated_type(collection_ty, into_iterator_trait_id, "Item") && iter_item_ty == into_iter_item_ty - && let Some(collection_snippet) = snippet_opt(cx, collection.span) + && let Some(collection_snippet) = collection.span.get_source_text(cx) { collection_snippet } else { @@ -122,7 +122,7 @@ pub fn check_for_loop_iter( } else { Applicability::MachineApplicable }; - diag.span_suggestion(expr.span, "use", snippet, applicability); + 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", diff --git a/clippy_lints/src/methods/unnecessary_lazy_eval.rs b/clippy_lints/src/methods/unnecessary_lazy_eval.rs index 4429f032605..b84594c0da1 100644 --- a/clippy_lints/src/methods/unnecessary_lazy_eval.rs +++ b/clippy_lints/src/methods/unnecessary_lazy_eval.rs @@ -64,9 +64,9 @@ pub(super) fn check<'tcx>( // but prefer to avoid changing the signature of the function itself. if let hir::ExprKind::MethodCall(.., span) = expr.kind { span_lint_and_then(cx, UNNECESSARY_LAZY_EVALUATIONS, expr.span, msg, |diag| { - diag.span_suggestion( + diag.span_suggestion_verbose( span, - format!("use `{simplify_using}(..)` instead"), + format!("use `{simplify_using}` instead"), format!("{simplify_using}({})", snippet(cx, body_expr.span, "..")), applicability, ); diff --git a/clippy_lints/src/methods/unnecessary_to_owned.rs b/clippy_lints/src/methods/unnecessary_to_owned.rs index fed2b128dcf..69c5bc57e29 100644 --- a/clippy_lints/src/methods/unnecessary_to_owned.rs +++ b/clippy_lints/src/methods/unnecessary_to_owned.rs @@ -2,7 +2,7 @@ use super::implicit_clone::is_clone_like; use super::unnecessary_iter_cloned::{self, is_into_iter}; use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; -use clippy_utils::source::{snippet, snippet_opt}; +use clippy_utils::source::{snippet, SpanRangeExt}; use clippy_utils::ty::{get_iterator_item_ty, implements_trait, is_copy, is_type_diagnostic_item, is_type_lang_item}; use clippy_utils::visitors::find_all_ret_expressions; use clippy_utils::{ @@ -133,7 +133,7 @@ fn check_addr_of_expr( && (*referent_ty != receiver_ty || (matches!(referent_ty.kind(), ty::Array(..)) && is_copy(cx, *referent_ty)) || is_cow_into_owned(cx, method_name, method_def_id)) - && let Some(receiver_snippet) = snippet_opt(cx, receiver.span) + && let Some(receiver_snippet) = receiver.span.get_source_text(cx) { if receiver_ty == target_ty && n_target_refs >= n_receiver_refs { span_lint_and_sugg( @@ -167,7 +167,7 @@ fn check_addr_of_expr( parent.span, format!("unnecessary use of `{method_name}`"), "use", - receiver_snippet, + receiver_snippet.to_owned(), Applicability::MachineApplicable, ); } else { @@ -217,7 +217,7 @@ fn check_into_iter_call_arg( && let parent_ty = cx.typeck_results().expr_ty(parent) && implements_trait(cx, parent_ty, iterator_trait_id, &[]) && let Some(item_ty) = get_iterator_item_ty(cx, parent_ty) - && let Some(receiver_snippet) = snippet_opt(cx, receiver.span) + && let Some(receiver_snippet) = receiver.span.get_source_text(cx) { if unnecessary_iter_cloned::check_for_loop_iter(cx, parent, method_name, receiver, true) { return true; @@ -309,8 +309,8 @@ fn check_split_call_arg(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: Symb if let Some(parent) = get_parent_expr(cx, expr) && let Some((fn_name, argument_expr)) = get_fn_name_and_arg(cx, parent) && fn_name.as_str() == "split" - && let Some(receiver_snippet) = snippet_opt(cx, receiver.span) - && let Some(arg_snippet) = snippet_opt(cx, argument_expr.span) + && let Some(receiver_snippet) = receiver.span.get_source_text(cx) + && let Some(arg_snippet) = argument_expr.span.get_source_text(cx) { // We may end-up here because of an expression like `x.to_string().split(…)` where the type of `x` // implements `AsRef` but does not implement `Deref`. In this case, we have to @@ -405,7 +405,7 @@ fn check_other_call_arg<'tcx>( None } && can_change_type(cx, maybe_arg, receiver_ty) - && let Some(receiver_snippet) = snippet_opt(cx, receiver.span) + && let Some(receiver_snippet) = receiver.span.get_source_text(cx) { span_lint_and_sugg( cx, @@ -695,7 +695,7 @@ fn check_if_applicable_to_argument<'tcx>(cx: &LateContext<'tcx>, arg: &Expr<'tcx && let arg_ty = arg_ty.peel_refs() // For now we limit this lint to `String` and `Vec`. && (is_str_and_string(cx, arg_ty, original_arg_ty) || is_slice_and_vec(cx, arg_ty, original_arg_ty)) - && let Some(snippet) = snippet_opt(cx, caller.span) + && let Some(snippet) = caller.span.get_source_text(cx) { span_lint_and_sugg( cx, @@ -706,7 +706,7 @@ fn check_if_applicable_to_argument<'tcx>(cx: &LateContext<'tcx>, arg: &Expr<'tcx if original_arg_ty.is_array() { format!("{snippet}.as_slice()") } else { - snippet + snippet.to_owned() }, Applicability::MaybeIncorrect, ); diff --git a/clippy_lints/src/methods/unused_enumerate_index.rs b/clippy_lints/src/methods/unused_enumerate_index.rs index 3004d9c4233..ee5177d1ffa 100644 --- a/clippy_lints/src/methods/unused_enumerate_index.rs +++ b/clippy_lints/src/methods/unused_enumerate_index.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_hir_and_then; -use clippy_utils::source::{snippet, snippet_opt}; +use clippy_utils::source::{snippet, SpanRangeExt}; use clippy_utils::{expr_or_init, is_trait_method, pat_is_wild}; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, FnDecl, PatKind, TyKind}; @@ -81,8 +81,14 @@ pub(super) fn check(cx: &LateContext<'_>, call_expr: &Expr<'_>, recv: &Expr<'_>, let new_closure_param = match find_elem_explicit_type_span(closure.fn_decl) { // We have an explicit type. Get its snippet, that of the binding name, and do `binding: ty`. // Fallback to `..` if we fail getting either snippet. - Some(ty_span) => snippet_opt(cx, elem.span) - .and_then(|binding_name| snippet_opt(cx, ty_span).map(|ty_name| format!("{binding_name}: {ty_name}"))) + Some(ty_span) => elem + .span + .get_source_text(cx) + .and_then(|binding_name| { + ty_span + .get_source_text(cx) + .map(|ty_name| format!("{binding_name}: {ty_name}")) + }) .unwrap_or_else(|| "..".to_string()), // Otherwise, we have no explicit type. We can replace with the binding name of the element. None => snippet(cx, elem.span, "..").into_owned(), diff --git a/clippy_lints/src/min_ident_chars.rs b/clippy_lints/src/min_ident_chars.rs index 53fa444e93c..c83e5198c27 100644 --- a/clippy_lints/src/min_ident_chars.rs +++ b/clippy_lints/src/min_ident_chars.rs @@ -41,14 +41,14 @@ declare_clippy_lint! { impl_lint_pass!(MinIdentChars => [MIN_IDENT_CHARS]); pub struct MinIdentChars { - allowed_idents_below_min_chars: &'static FxHashSet, + allowed_idents_below_min_chars: FxHashSet, min_ident_chars_threshold: u64, } impl MinIdentChars { pub fn new(conf: &'static Conf) -> Self { Self { - allowed_idents_below_min_chars: &conf.allowed_idents_below_min_chars, + allowed_idents_below_min_chars: conf.allowed_idents_below_min_chars.iter().cloned().collect(), min_ident_chars_threshold: conf.min_ident_chars_threshold, } } diff --git a/clippy_lints/src/misc_early/unneeded_field_pattern.rs b/clippy_lints/src/misc_early/unneeded_field_pattern.rs index 6db03adf44a..33ab94e00a5 100644 --- a/clippy_lints/src/misc_early/unneeded_field_pattern.rs +++ b/clippy_lints/src/misc_early/unneeded_field_pattern.rs @@ -1,5 +1,6 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; -use clippy_utils::source::snippet_opt; +use clippy_utils::source::SpanRangeExt; +use itertools::Itertools; use rustc_ast::ast::{Pat, PatKind}; use rustc_lint::EarlyContext; @@ -45,19 +46,6 @@ pub(super) fn check(cx: &EarlyContext<'_>, pat: &Pat) { "you matched a field with a wildcard pattern, consider using `..` instead", ); } else { - let mut normal = vec![]; - - for field in pfields { - match field.pat.kind { - PatKind::Wild => {}, - _ => { - if let Some(n) = snippet_opt(cx, field.span) { - normal.push(n); - } - }, - } - } - #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")] span_lint_and_then( cx, @@ -65,7 +53,16 @@ pub(super) fn check(cx: &EarlyContext<'_>, pat: &Pat) { field.span, "you matched a field with a wildcard pattern, consider using `..` instead", |diag| { - diag.help(format!("try with `{type_name} {{ {}, .. }}`", normal[..].join(", "))); + diag.help(format!( + "try with `{type_name} {{ {}, .. }}`", + pfields + .iter() + .filter_map(|f| match f.pat.kind { + PatKind::Wild => None, + _ => f.span.get_source_text(cx), + }) + .format(", "), + )); }, ); } diff --git a/clippy_lints/src/missing_enforced_import_rename.rs b/clippy_lints/src/missing_enforced_import_rename.rs index cdf6645b3df..59f29d242ab 100644 --- a/clippy_lints/src/missing_enforced_import_rename.rs +++ b/clippy_lints/src/missing_enforced_import_rename.rs @@ -1,7 +1,7 @@ use clippy_config::Conf; use clippy_utils::def_path_def_ids; use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::snippet_opt; +use clippy_utils::source::SpanRangeExt; use rustc_errors::Applicability; use rustc_hir::def::Res; use rustc_hir::def_id::DefIdMap; @@ -73,7 +73,7 @@ impl LateLintPass<'_> for ImportRename { && let Some(name) = self.renames.get(&id) // Remove semicolon since it is not present for nested imports && let span_without_semi = cx.sess().source_map().span_until_char(item.span, ';') - && let Some(snip) = snippet_opt(cx, span_without_semi) + && let Some(snip) = span_without_semi.get_source_text(cx) && let Some(import) = match snip.split_once(" as ") { None => Some(snip.as_str()), Some((import, rename)) => { diff --git a/clippy_lints/src/mut_key.rs b/clippy_lints/src/mut_key.rs index 83af9979b9e..f52b3a6a5a1 100644 --- a/clippy_lints/src/mut_key.rs +++ b/clippy_lints/src/mut_key.rs @@ -125,14 +125,12 @@ impl<'tcx> MutableKeyType<'tcx> { // generics (because the compiler cannot ensure immutability for unknown types). fn check_ty_(&mut self, cx: &LateContext<'tcx>, span: Span, ty: Ty<'tcx>) { let ty = ty.peel_refs(); - if let ty::Adt(def, args) = ty.kind() { - let is_keyed_type = [sym::HashMap, sym::BTreeMap, sym::HashSet, sym::BTreeSet] - .iter() - .any(|diag_item| cx.tcx.is_diagnostic_item(*diag_item, def.did())); - if !is_keyed_type { - return; - } - + if let ty::Adt(def, args) = ty.kind() + && matches!( + cx.tcx.get_diagnostic_name(def.did()), + Some(sym::HashMap | sym::BTreeMap | sym::HashSet | sym::BTreeSet) + ) + { let subst_ty = args.type_at(0); if self.interior_mut.is_interior_mut_ty(cx, subst_ty) { span_lint(cx, MUTABLE_KEY_TYPE, span, "mutable key type"); diff --git a/clippy_lints/src/mutex_atomic.rs b/clippy_lints/src/mutex_atomic.rs index 853e476a006..38841496458 100644 --- a/clippy_lints/src/mutex_atomic.rs +++ b/clippy_lints/src/mutex_atomic.rs @@ -1,7 +1,3 @@ -//! Checks for usage of mutex where an atomic value could be used -//! -//! This lint is **allow** by default - use clippy_utils::diagnostics::span_lint; use clippy_utils::ty::is_type_diagnostic_item; use rustc_hir::Expr; diff --git a/clippy_lints/src/needless_bool.rs b/clippy_lints/src/needless_bool.rs index 9cb4fa41c73..df155a7a412 100644 --- a/clippy_lints/src/needless_bool.rs +++ b/clippy_lints/src/needless_bool.rs @@ -1,7 +1,3 @@ -//! Checks for needless boolean results of if-else expressions -//! -//! This lint is **warn** by default - use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg}; use clippy_utils::source::snippet_with_applicability; use clippy_utils::sugg::Sugg; diff --git a/clippy_lints/src/needless_continue.rs b/clippy_lints/src/needless_continue.rs index b97cb4579ca..ce97370d4d9 100644 --- a/clippy_lints/src/needless_continue.rs +++ b/clippy_lints/src/needless_continue.rs @@ -1,38 +1,3 @@ -//! Checks for continue statements in loops that are redundant. -//! -//! For example, the lint would catch -//! -//! ```rust -//! let mut a = 1; -//! let x = true; -//! -//! while a < 5 { -//! a = 6; -//! if x { -//! // ... -//! } else { -//! continue; -//! } -//! println!("Hello, world"); -//! } -//! ``` -//! -//! And suggest something like this: -//! -//! ```rust -//! let mut a = 1; -//! let x = true; -//! -//! while a < 5 { -//! a = 6; -//! if x { -//! // ... -//! println!("Hello, world"); -//! } -//! } -//! ``` -//! -//! This lint is **warn** by default. use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::source::{indent_of, snippet, snippet_block}; use rustc_ast::ast; diff --git a/clippy_lints/src/needless_if.rs b/clippy_lints/src/needless_if.rs index 1d6233d432a..8e14fbf2f80 100644 --- a/clippy_lints/src/needless_if.rs +++ b/clippy_lints/src/needless_if.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::higher::If; use clippy_utils::is_from_proc_macro; -use clippy_utils::source::{snippet_opt, SpanRangeExt}; +use clippy_utils::source::SpanRangeExt; use rustc_errors::Applicability; use rustc_hir::{ExprKind, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; @@ -57,7 +57,7 @@ impl LateLintPass<'_> for NeedlessIf { src.bytes() .all(|ch| matches!(ch, b'{' | b'}') || ch.is_ascii_whitespace()) }) - && let Some(cond_snippet) = snippet_opt(cx, cond.span) + && let Some(cond_snippet) = cond.span.get_source_text(cx) && !is_from_proc_macro(cx, expr) { span_lint_and_sugg( diff --git a/clippy_lints/src/needless_late_init.rs b/clippy_lints/src/needless_late_init.rs index 4bfc30fa5cf..46cdb82130f 100644 --- a/clippy_lints/src/needless_late_init.rs +++ b/clippy_lints/src/needless_late_init.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::path_to_local; -use clippy_utils::source::snippet_opt; +use clippy_utils::source::{SourceText, SpanRangeExt}; use clippy_utils::ty::needs_ordered_drop; use clippy_utils::visitors::{for_each_expr, for_each_expr_without_closures, is_local_used}; use core::ops::ControlFlow; @@ -236,7 +236,7 @@ fn first_usage<'tcx>( }) } -fn local_snippet_without_semicolon(cx: &LateContext<'_>, local: &LetStmt<'_>) -> Option { +fn local_snippet_without_semicolon(cx: &LateContext<'_>, local: &LetStmt<'_>) -> Option { let span = local.span.with_hi(match local.ty { // let : ; // ~~~~~~~~~~~~~~~ @@ -246,7 +246,7 @@ fn local_snippet_without_semicolon(cx: &LateContext<'_>, local: &LetStmt<'_>) -> None => local.pat.span.hi(), }); - snippet_opt(cx, span) + span.get_source_text(cx) } fn check<'tcx>( @@ -275,7 +275,10 @@ fn check<'tcx>( |diag| { diag.multipart_suggestion( format!("move the declaration `{binding_name}` here"), - vec![(local_stmt.span, String::new()), (assign.lhs_span, let_snippet)], + vec![ + (local_stmt.span, String::new()), + (assign.lhs_span, let_snippet.to_owned()), + ], Applicability::MachineApplicable, ); }, diff --git a/clippy_lints/src/needless_pass_by_value.rs b/clippy_lints/src/needless_pass_by_value.rs index a0bbf6b14b2..addb4b1aee8 100644 --- a/clippy_lints/src/needless_pass_by_value.rs +++ b/clippy_lints/src/needless_pass_by_value.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::is_self; use clippy_utils::ptr::get_spans; -use clippy_utils::source::{snippet, snippet_opt}; +use clippy_utils::source::{snippet, SpanRangeExt}; use clippy_utils::ty::{ implements_trait, implements_trait_with_env_from_iter, is_copy, is_type_diagnostic_item, is_type_lang_item, }; @@ -242,8 +242,8 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue { for (span, suggestion) in clone_spans { diag.span_suggestion( span, - snippet_opt(cx, span) - .map_or("change the call to".into(), |x| format!("change `{x}` to")), + span.get_source_text(cx) + .map_or("change the call to".to_owned(), |src| format!("change `{src}` to")), suggestion, Applicability::Unspecified, ); @@ -267,8 +267,8 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue { for (span, suggestion) in clone_spans { diag.span_suggestion( span, - snippet_opt(cx, span) - .map_or("change the call to".into(), |x| format!("change `{x}` to")), + span.get_source_text(cx) + .map_or("change the call to".to_owned(), |src| format!("change `{src}` to")), suggestion, Applicability::Unspecified, ); diff --git a/clippy_lints/src/no_effect.rs b/clippy_lints/src/no_effect.rs index 8232e69db39..b181791699a 100644 --- a/clippy_lints/src/no_effect.rs +++ b/clippy_lints/src/no_effect.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::{span_lint_hir, span_lint_hir_and_then}; -use clippy_utils::source::snippet_opt; +use clippy_utils::source::SpanRangeExt; use clippy_utils::ty::has_drop; use clippy_utils::{ in_automatically_derived, is_inside_always_const_context, is_lint_allowed, path_to_local, peel_blocks, @@ -268,34 +268,31 @@ fn check_unnecessary_operation(cx: &LateContext<'_>, stmt: &Stmt<'_>) { && reduced.iter().all(|e| e.span.ctxt() == ctxt) { if let ExprKind::Index(..) = &expr.kind { - if is_inside_always_const_context(cx.tcx, expr.hir_id) { - return; + if !is_inside_always_const_context(cx.tcx, expr.hir_id) + && let [arr, func] = &*reduced + && let Some(arr) = arr.span.get_source_text(cx) + && let Some(func) = func.span.get_source_text(cx) + { + span_lint_hir_and_then( + cx, + UNNECESSARY_OPERATION, + expr.hir_id, + stmt.span, + "unnecessary operation", + |diag| { + diag.span_suggestion( + stmt.span, + "statement can be written as", + format!("assert!({arr}.len() > {func});"), + Applicability::MaybeIncorrect, + ); + }, + ); } - let snippet = - if let (Some(arr), Some(func)) = (snippet_opt(cx, reduced[0].span), snippet_opt(cx, reduced[1].span)) { - format!("assert!({arr}.len() > {func});") - } else { - return; - }; - span_lint_hir_and_then( - cx, - UNNECESSARY_OPERATION, - expr.hir_id, - stmt.span, - "unnecessary operation", - |diag| { - diag.span_suggestion( - stmt.span, - "statement can be written as", - snippet, - Applicability::MaybeIncorrect, - ); - }, - ); } else { let mut snippet = String::new(); for e in reduced { - if let Some(snip) = snippet_opt(cx, e.span) { + if let Some(snip) = e.span.get_source_text(cx) { snippet.push_str(&snip); snippet.push(';'); } else { diff --git a/clippy_lints/src/non_copy_const.rs b/clippy_lints/src/non_copy_const.rs index 6915cd40615..25f547f1a43 100644 --- a/clippy_lints/src/non_copy_const.rs +++ b/clippy_lints/src/non_copy_const.rs @@ -1,7 +1,3 @@ -//! Checks for usage of const which the type is not `Freeze` (`Cell`-free). -//! -//! This lint is **warn** by default. - use std::ptr; use clippy_config::Conf; @@ -188,7 +184,7 @@ impl_lint_pass!(NonCopyConst<'_> => [DECLARE_INTERIOR_MUTABLE_CONST, BORROW_INTE impl<'tcx> NonCopyConst<'tcx> { pub fn new(tcx: TyCtxt<'tcx>, conf: &'static Conf) -> Self { Self { - interior_mut: InteriorMut::new(tcx, &conf.ignore_interior_mutability), + interior_mut: InteriorMut::without_pointers(tcx, &conf.ignore_interior_mutability), } } diff --git a/clippy_lints/src/nonstandard_macro_braces.rs b/clippy_lints/src/nonstandard_macro_braces.rs index 2aaf1e6ff46..51ba29d7389 100644 --- a/clippy_lints/src/nonstandard_macro_braces.rs +++ b/clippy_lints/src/nonstandard_macro_braces.rs @@ -1,7 +1,7 @@ use clippy_config::types::MacroMatcher; use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::snippet_opt; +use clippy_utils::source::{SourceText, SpanRangeExt}; use rustc_ast::ast; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::Applicability; @@ -34,7 +34,7 @@ declare_clippy_lint! { } /// The (callsite span, (open brace, close brace), source snippet) -type MacroInfo = (Span, (char, char), String); +type MacroInfo = (Span, (char, char), SourceText); pub struct MacroBraces { macro_braces: FxHashMap, @@ -94,7 +94,7 @@ fn is_offending_macro(cx: &EarlyContext<'_>, span: Span, mac_braces: &MacroBrace if let ExpnKind::Macro(MacroKind::Bang, mac_name) = span.ctxt().outer_expn_data().kind && let name = mac_name.as_str() && let Some(&braces) = mac_braces.macro_braces.get(name) - && let Some(snip) = snippet_opt(cx, span_call_site) + && let Some(snip) = span_call_site.get_source_text(cx) // we must check only invocation sites // https://github.com/rust-lang/rust-clippy/issues/7422 && snip.starts_with(&format!("{name}!")) diff --git a/clippy_lints/src/operators/arithmetic_side_effects.rs b/clippy_lints/src/operators/arithmetic_side_effects.rs index bc71a4790b9..8b9f899d82d 100644 --- a/clippy_lints/src/operators/arithmetic_side_effects.rs +++ b/clippy_lints/src/operators/arithmetic_side_effects.rs @@ -35,7 +35,7 @@ impl ArithmeticSideEffects { ("f64", FxHashSet::from_iter(["f64"])), ("std::string::String", FxHashSet::from_iter(["str"])), ]); - for [lhs, rhs] in &conf.arithmetic_side_effects_allowed_binary { + for (lhs, rhs) in &conf.arithmetic_side_effects_allowed_binary { allowed_binary.entry(lhs).or_default().insert(rhs); } for s in &conf.arithmetic_side_effects_allowed { diff --git a/clippy_lints/src/operators/assign_op_pattern.rs b/clippy_lints/src/operators/assign_op_pattern.rs index 641d881d974..11c97b4ef00 100644 --- a/clippy_lints/src/operators/assign_op_pattern.rs +++ b/clippy_lints/src/operators/assign_op_pattern.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::snippet_opt; +use clippy_utils::source::SpanRangeExt; use clippy_utils::ty::implements_trait; use clippy_utils::visitors::for_each_expr_without_closures; use clippy_utils::{binop_traits, eq_expr_value, trait_ref_of_method}; @@ -46,8 +46,8 @@ pub(super) fn check<'tcx>( expr.span, "manual implementation of an assign operation", |diag| { - if let (Some(snip_a), Some(snip_r)) = - (snippet_opt(cx, assignee.span), snippet_opt(cx, rhs.span)) + if let Some(snip_a) = assignee.span.get_source_text(cx) + && let Some(snip_r) = rhs.span.get_source_text(cx) { diag.span_suggestion( expr.span, diff --git a/clippy_lints/src/operators/misrefactored_assign_op.rs b/clippy_lints/src/operators/misrefactored_assign_op.rs index 311cbd050a1..8daedd1c901 100644 --- a/clippy_lints/src/operators/misrefactored_assign_op.rs +++ b/clippy_lints/src/operators/misrefactored_assign_op.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::snippet_opt; +use clippy_utils::source::SpanRangeExt; use clippy_utils::{eq_expr_value, sugg}; use rustc_errors::Applicability; use rustc_hir as hir; @@ -42,7 +42,9 @@ fn lint_misrefactored_assign_op( expr.span, "variable appears on both sides of an assignment operation", |diag| { - if let (Some(snip_a), Some(snip_r)) = (snippet_opt(cx, assignee.span), snippet_opt(cx, rhs_other.span)) { + if let Some(snip_a) = assignee.span.get_source_text(cx) + && let Some(snip_r) = rhs_other.span.get_source_text(cx) + { let a = &sugg::Sugg::hir(cx, assignee, ".."); let r = &sugg::Sugg::hir(cx, rhs, ".."); let long = format!("{snip_a} = {}", sugg::make_binop(op, a, r)); diff --git a/clippy_lints/src/operators/mod.rs b/clippy_lints/src/operators/mod.rs index 9baecff801f..9e8a821c3f4 100644 --- a/clippy_lints/src/operators/mod.rs +++ b/clippy_lints/src/operators/mod.rs @@ -80,7 +80,7 @@ declare_clippy_lint! { /// ```no_run /// // `n` can be any number, including `i32::MAX`. /// fn foo(n: i32) -> i32 { - /// n + 1 + /// n + 1 /// } /// ``` /// diff --git a/clippy_lints/src/operators/needless_bitwise_bool.rs b/clippy_lints/src/operators/needless_bitwise_bool.rs index ab5fb178700..9d8e833ef6d 100644 --- a/clippy_lints/src/operators/needless_bitwise_bool.rs +++ b/clippy_lints/src/operators/needless_bitwise_bool.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::snippet_opt; +use clippy_utils::source::SpanRangeExt; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::LateContext; @@ -24,8 +24,8 @@ pub(super) fn check(cx: &LateContext<'_>, e: &Expr<'_>, op: BinOpKind, lhs: &Exp e.span, "use of bitwise operator instead of lazy operator between booleans", |diag| { - if let Some(lhs_snip) = snippet_opt(cx, lhs.span) - && let Some(rhs_snip) = snippet_opt(cx, rhs.span) + if let Some(lhs_snip) = lhs.span.get_source_text(cx) + && let Some(rhs_snip) = rhs.span.get_source_text(cx) { let sugg = format!("{lhs_snip} {op_str} {rhs_snip}"); diag.span_suggestion(e.span, "try", sugg, Applicability::MachineApplicable); diff --git a/clippy_lints/src/operators/ptr_eq.rs b/clippy_lints/src/operators/ptr_eq.rs index 607930561e0..861564d5456 100644 --- a/clippy_lints/src/operators/ptr_eq.rs +++ b/clippy_lints/src/operators/ptr_eq.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::snippet_opt; +use clippy_utils::source::SpanRangeExt; use clippy_utils::std_or_core; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind}; @@ -22,8 +22,8 @@ pub(super) fn check<'tcx>( if let Some(left_var) = expr_as_cast_to_raw_pointer(cx, left) && let Some(right_var) = expr_as_cast_to_raw_pointer(cx, right) - && let Some(left_snip) = snippet_opt(cx, left_var.span) - && let Some(right_snip) = snippet_opt(cx, right_var.span) + && let Some(left_snip) = left_var.span.get_source_text(cx) + && let Some(right_snip) = right_var.span.get_source_text(cx) { let Some(top_crate) = std_or_core(cx) else { return }; span_lint_and_sugg( diff --git a/clippy_lints/src/pathbuf_init_then_push.rs b/clippy_lints/src/pathbuf_init_then_push.rs index 18bfb588a11..d7fa48c1e38 100644 --- a/clippy_lints/src/pathbuf_init_then_push.rs +++ b/clippy_lints/src/pathbuf_init_then_push.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::path_to_local_id; -use clippy_utils::source::{snippet, snippet_opt}; +use clippy_utils::source::{snippet, SpanRangeExt}; use clippy_utils::ty::is_type_diagnostic_item; use rustc_ast::{LitKind, StrStyle}; use rustc_errors::Applicability; @@ -74,7 +74,7 @@ impl<'tcx> PathbufPushSearcher<'tcx> { && let Some(arg) = self.arg && let ExprKind::Lit(x) = arg.kind && let LitKind::Str(_, StrStyle::Cooked) = x.node - && let Some(s) = snippet_opt(cx, arg.span) + && let Some(s) = arg.span.get_source_text(cx) { Some(format!(" = PathBuf::from({s});")) } else { @@ -84,8 +84,8 @@ impl<'tcx> PathbufPushSearcher<'tcx> { fn gen_pathbuf_join(&self, cx: &LateContext<'_>) -> Option { let arg = self.arg?; - let arg_str = snippet_opt(cx, arg.span)?; - let init_val = snippet_opt(cx, self.init_val.span)?; + let arg_str = arg.span.get_source_text(cx)?; + let init_val = self.init_val.span.get_source_text(cx)?; Some(format!(" = {init_val}.join({arg_str});")) } diff --git a/clippy_lints/src/ptr.rs b/clippy_lints/src/ptr.rs index 02c05e0aaf9..125f694996c 100644 --- a/clippy_lints/src/ptr.rs +++ b/clippy_lints/src/ptr.rs @@ -1,7 +1,5 @@ -//! Checks for usage of `&Vec[_]` and `&String`. - use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then, span_lint_hir_and_then}; -use clippy_utils::source::snippet_opt; +use clippy_utils::source::SpanRangeExt; use clippy_utils::ty::expr_sig; use clippy_utils::visitors::contains_unsafe_block; use clippy_utils::{get_expr_use_or_unification_node, is_lint_allowed, path_def_id, path_to_local}; @@ -243,7 +241,7 @@ impl<'tcx> LateLintPass<'tcx> for Ptr { .chain(result.replacements.iter().map(|r| { ( r.expr_span, - format!("{}{}", snippet_opt(cx, r.self_span).unwrap(), r.replacement), + format!("{}{}", r.self_span.get_source_text(cx).unwrap(), r.replacement), ) })) .collect(), @@ -372,7 +370,7 @@ impl fmt::Display for DerefTyDisplay<'_, '_> { DerefTy::Path => f.write_str("Path"), DerefTy::Slice(hir_ty, ty) => { f.write_char('[')?; - match hir_ty.and_then(|s| snippet_opt(self.0, s)) { + match hir_ty.and_then(|s| s.get_source_text(self.0)) { Some(s) => f.write_str(&s)?, None => ty.fmt(f)?, } @@ -413,6 +411,7 @@ impl<'tcx> DerefTy<'tcx> { } } +#[expect(clippy::too_many_lines)] fn check_fn_args<'cx, 'tcx: 'cx>( cx: &'cx LateContext<'tcx>, fn_sig: ty::FnSig<'tcx>, @@ -488,8 +487,6 @@ fn check_fn_args<'cx, 'tcx: 'cx>( return None; } - let ty_name = snippet_opt(cx, ty.span()).unwrap_or_else(|| args.type_at(1).to_string()); - span_lint_hir_and_then( cx, PTR_ARG, @@ -500,7 +497,10 @@ fn check_fn_args<'cx, 'tcx: 'cx>( diag.span_suggestion( hir_ty.span, "change this to", - format!("&{}{ty_name}", mutability.prefix_str()), + match ty.span().get_source_text(cx) { + Some(s) => format!("&{}{s}", mutability.prefix_str()), + None => format!("&{}{}", mutability.prefix_str(), args.type_at(1)), + }, Applicability::Unspecified, ); }, diff --git a/clippy_lints/src/ptr_offset_with_cast.rs b/clippy_lints/src/ptr_offset_with_cast.rs index 7c82895d609..87a52cb2186 100644 --- a/clippy_lints/src/ptr_offset_with_cast.rs +++ b/clippy_lints/src/ptr_offset_with_cast.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg}; -use clippy_utils::source::snippet_opt; +use clippy_utils::source::SpanRangeExt; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; @@ -120,8 +120,8 @@ fn build_suggestion( receiver_expr: &Expr<'_>, cast_lhs_expr: &Expr<'_>, ) -> Option { - let receiver = snippet_opt(cx, receiver_expr.span)?; - let cast_lhs = snippet_opt(cx, cast_lhs_expr.span)?; + let receiver = receiver_expr.span.get_source_text(cx)?; + let cast_lhs = cast_lhs_expr.span.get_source_text(cx)?; Some(format!("{receiver}.{}({cast_lhs})", method.suggestion())) } diff --git a/clippy_lints/src/redundant_clone.rs b/clippy_lints/src/redundant_clone.rs index a1231c082e6..bfdc1cbeed7 100644 --- a/clippy_lints/src/redundant_clone.rs +++ b/clippy_lints/src/redundant_clone.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::{span_lint_hir, span_lint_hir_and_then}; use clippy_utils::mir::{visit_local_usage, LocalUsage, PossibleBorrowerMap}; -use clippy_utils::source::snippet_opt; +use clippy_utils::source::SpanRangeExt; use clippy_utils::ty::{has_drop, is_copy, is_type_diagnostic_item, is_type_lang_item, walk_ptrs_ty_depth}; use clippy_utils::{fn_has_unsatisfiable_preds, match_def_path, paths}; use rustc_errors::Applicability; @@ -208,7 +208,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClone { .assert_crate_local() .lint_root; - if let Some(snip) = snippet_opt(cx, span) + if let Some(snip) = span.get_source_text(cx) && let Some(dot) = snip.rfind('.') { let sugg_span = span.with_lo(span.lo() + BytePos(u32::try_from(dot).unwrap())); diff --git a/clippy_lints/src/reference.rs b/clippy_lints/src/reference.rs index 8f32cf5f2a1..2b4ef21fc48 100644 --- a/clippy_lints/src/reference.rs +++ b/clippy_lints/src/reference.rs @@ -1,10 +1,10 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::{snippet_opt, snippet_with_applicability}; +use clippy_utils::source::{snippet_with_applicability, SpanRangeExt}; use rustc_ast::ast::{Expr, ExprKind, Mutability, UnOp}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_session::declare_lint_pass; -use rustc_span::BytePos; +use rustc_span::{BytePos, Span}; declare_clippy_lint! { /// ### What it does @@ -56,11 +56,11 @@ impl EarlyLintPass for DerefAddrOf { { let mut applicability = Applicability::MachineApplicable; let sugg = if e.span.from_expansion() { - if let Some(macro_source) = snippet_opt(cx, e.span) { + if let Some(macro_source) = e.span.get_source_text(cx) { // Remove leading whitespace from the given span // e.g: ` $visitor` turns into `$visitor` - let trim_leading_whitespaces = |span| { - snippet_opt(cx, span) + let trim_leading_whitespaces = |span: Span| { + span.get_source_text(cx) .and_then(|snip| { #[expect(clippy::cast_possible_truncation)] snip.find(|c: char| !c.is_whitespace()) diff --git a/clippy_lints/src/regex.rs b/clippy_lints/src/regex.rs index 95014b23043..f6ef02b7c23 100644 --- a/clippy_lints/src/regex.rs +++ b/clippy_lints/src/regex.rs @@ -2,7 +2,7 @@ use std::fmt::Display; use clippy_utils::consts::{ConstEvalCtxt, Constant}; use clippy_utils::diagnostics::{span_lint, span_lint_and_help}; -use clippy_utils::source::snippet_opt; +use clippy_utils::source::SpanRangeExt; use clippy_utils::{def_path_def_ids, path_def_id, paths}; use rustc_ast::ast::{LitKind, StrStyle}; use rustc_hir::def_id::DefIdMap; @@ -122,7 +122,7 @@ fn lint_syntax_error(cx: &LateContext<'_>, error: ®ex_syntax::Error, unescape }; if let Some((primary, auxiliary, kind)) = parts - && let Some(literal_snippet) = snippet_opt(cx, base) + && let Some(literal_snippet) = base.get_source_text(cx) && let Some(inner) = literal_snippet.get(offset as usize..) // Only convert to native rustc spans if the parsed regex matches the // source snippet exactly, to ensure the span offsets are correct diff --git a/clippy_lints/src/returns.rs b/clippy_lints/src/returns.rs index 13016cdadb0..5ce091b7a7a 100644 --- a/clippy_lints/src/returns.rs +++ b/clippy_lints/src/returns.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_hir_and_then}; -use clippy_utils::source::{snippet_opt, snippet_with_context}; +use clippy_utils::source::{snippet_with_context, SpanRangeExt}; use clippy_utils::sugg::has_enclosing_paren; use clippy_utils::visitors::{for_each_expr, Descend}; use clippy_utils::{ @@ -250,20 +250,25 @@ impl<'tcx> LateLintPass<'tcx> for Return { |err| { err.span_label(local.span, "unnecessary `let` binding"); - if let Some(mut snippet) = snippet_opt(cx, initexpr.span) { - if binary_expr_needs_parentheses(initexpr) { - if !has_enclosing_paren(&snippet) { - snippet = format!("({snippet})"); + if let Some(src) = initexpr.span.get_source_text(cx) { + let sugg = if binary_expr_needs_parentheses(initexpr) { + if has_enclosing_paren(&src) { + src.to_owned() + } else { + format!("({src})") } } else if !cx.typeck_results().expr_adjustments(retexpr).is_empty() { - if !has_enclosing_paren(&snippet) { - snippet = format!("({snippet})"); + if has_enclosing_paren(&src) { + format!("{src} as _") + } else { + format!("({src}) as _") } - snippet.push_str(" as _"); - } + } else { + src.to_owned() + }; err.multipart_suggestion( "return the expression directly", - vec![(local.span, String::new()), (retexpr.span, snippet)], + vec![(local.span, String::new()), (retexpr.span, sugg)], Applicability::MachineApplicable, ); } else { @@ -394,7 +399,7 @@ fn check_final_expr<'tcx>( // Returns may be used to turn an expression into a statement in rustc's AST. // This allows the addition of attributes, like `#[allow]` (See: clippy#9361) - // `#[expect(clippy::needless_return)]` needs to be handled separatly to + // `#[expect(clippy::needless_return)]` needs to be handled separately to // actually fulfill the expectation (clippy::#12998) match cx.tcx.hir().attrs(expr.hir_id) { [] => {}, diff --git a/clippy_lints/src/single_range_in_vec_init.rs b/clippy_lints/src/single_range_in_vec_init.rs index e0558429638..44e585953bf 100644 --- a/clippy_lints/src/single_range_in_vec_init.rs +++ b/clippy_lints/src/single_range_in_vec_init.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::get_trait_def_id; use clippy_utils::higher::VecArgs; use clippy_utils::macros::root_macro_call_first_node; -use clippy_utils::source::snippet_opt; +use clippy_utils::source::SpanRangeExt; use clippy_utils::ty::implements_trait; use rustc_ast::{LitIntType, LitKind, UintTy}; use rustc_errors::Applicability; @@ -92,12 +92,12 @@ impl LateLintPass<'_> for SingleRangeInVecInit { if matches!(lang_item, LangItem::Range) && let ty = cx.typeck_results().expr_ty(start.expr) - && let Some(snippet) = snippet_opt(cx, span) + && let Some(snippet) = span.get_source_text(cx) // `is_from_proc_macro` will skip any `vec![]`. Let's not! && snippet.starts_with(suggested_type.starts_with()) && snippet.ends_with(suggested_type.ends_with()) - && let Some(start_snippet) = snippet_opt(cx, start.span) - && let Some(end_snippet) = snippet_opt(cx, end.span) + && let Some(start_snippet) = start.span.get_source_text(cx) + && let Some(end_snippet) = end.span.get_source_text(cx) { let should_emit_every_value = if let Some(step_def_id) = get_trait_def_id(cx.tcx, &["core", "iter", "Step"]) && implements_trait(cx, ty, step_def_id, &[]) diff --git a/clippy_lints/src/size_of_in_element_count.rs b/clippy_lints/src/size_of_in_element_count.rs index 01f0e3cfadb..7750d8909d3 100644 --- a/clippy_lints/src/size_of_in_element_count.rs +++ b/clippy_lints/src/size_of_in_element_count.rs @@ -1,6 +1,3 @@ -//! Lint on use of `size_of` or `size_of_val` of T in an expression -//! expecting a count of T - use clippy_utils::diagnostics::span_lint_and_help; use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; diff --git a/clippy_lints/src/std_instead_of_core.rs b/clippy_lints/src/std_instead_of_core.rs index 974e21df817..44283a49e84 100644 --- a/clippy_lints/src/std_instead_of_core.rs +++ b/clippy_lints/src/std_instead_of_core.rs @@ -9,7 +9,6 @@ use rustc_hir::def_id::DefId; use rustc_hir::{HirId, Path, PathSegment}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_semver::RustcVersion; use rustc_session::impl_lint_pass; use rustc_span::symbol::kw; use rustc_span::{sym, Span}; @@ -185,9 +184,7 @@ fn is_stable(cx: &LateContext<'_>, mut def_id: DefId, msrv: &Msrv) -> bool { } = stability.level { let stable = match since { - StableSince::Version(v) => { - msrv.meets(RustcVersion::new(v.major.into(), v.minor.into(), v.patch.into())) - }, + StableSince::Version(v) => msrv.meets(v), StableSince::Current => msrv.current().is_none(), StableSince::Err => false, }; diff --git a/clippy_lints/src/strings.rs b/clippy_lints/src/strings.rs index cfc387886dc..6ca4ca000e9 100644 --- a/clippy_lints/src/strings.rs +++ b/clippy_lints/src/strings.rs @@ -190,7 +190,7 @@ impl<'tcx> LateLintPass<'tcx> for StringAdd { } }, ExprKind::Index(target, _idx, _) => { - let e_ty = cx.typeck_results().expr_ty(target).peel_refs(); + let e_ty = cx.typeck_results().expr_ty_adjusted(target).peel_refs(); if e_ty.is_str() || is_type_lang_item(cx, e_ty, LangItem::String) { span_lint( cx, diff --git a/clippy_lints/src/trait_bounds.rs b/clippy_lints/src/trait_bounds.rs index 59b74122f30..2e87d36df31 100644 --- a/clippy_lints/src/trait_bounds.rs +++ b/clippy_lints/src/trait_bounds.rs @@ -1,7 +1,7 @@ use clippy_config::msrvs::{self, Msrv}; use clippy_config::Conf; use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg}; -use clippy_utils::source::{snippet, snippet_opt, snippet_with_applicability}; +use clippy_utils::source::{snippet, snippet_with_applicability, SpanRangeExt}; use clippy_utils::{is_from_proc_macro, SpanlessEq, SpanlessHash}; use core::hash::{Hash, Hasher}; use itertools::Itertools; @@ -206,8 +206,7 @@ impl<'tcx> LateLintPass<'tcx> for TraitBounds { let fixed_trait_snippet = unique_traits .iter() - .filter_map(|b| snippet_opt(cx, b.span)) - .collect::>() + .filter_map(|b| b.span.get_source_text(cx)) .join(" + "); span_lint_and_sugg( @@ -462,9 +461,8 @@ fn rollup_traits( let traits = comparable_bounds .iter() - .filter_map(|&(_, span)| snippet_opt(cx, span)) - .collect::>(); - let traits = traits.join(" + "); + .filter_map(|&(_, span)| span.get_source_text(cx)) + .join(" + "); span_lint_and_sugg( cx, diff --git a/clippy_lints/src/unit_types/unit_arg.rs b/clippy_lints/src/unit_types/unit_arg.rs index afc53e6f32d..978d49f09c3 100644 --- a/clippy_lints/src/unit_types/unit_arg.rs +++ b/clippy_lints/src/unit_types/unit_arg.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::is_from_proc_macro; -use clippy_utils::source::{indent_of, reindent_multiline, snippet_opt}; +use clippy_utils::source::{indent_of, reindent_multiline, SourceText, SpanRangeExt}; use rustc_errors::Applicability; use rustc_hir::{Block, Expr, ExprKind, MatchSource, Node, StmtKind}; use rustc_lint::LateContext; @@ -79,7 +79,7 @@ fn lint_unit_args(cx: &LateContext<'_>, expr: &Expr<'_>, args_to_recover: &[&Exp && block.expr.is_none() && let Some(last_stmt) = block.stmts.iter().last() && let StmtKind::Semi(last_expr) = last_stmt.kind - && let Some(snip) = snippet_opt(cx, last_expr.span) + && let Some(snip) = last_expr.span.get_source_text(cx) { Some((last_stmt.span, snip)) } else { @@ -90,24 +90,24 @@ fn lint_unit_args(cx: &LateContext<'_>, expr: &Expr<'_>, args_to_recover: &[&Exp db.span_suggestion( span, "remove the semicolon from the last statement in the block", - sugg, + sugg.as_str(), Applicability::MaybeIncorrect, ); or = "or "; applicability = Applicability::MaybeIncorrect; }); - let arg_snippets: Vec = args_to_recover + let arg_snippets: Vec<_> = args_to_recover .iter() - .filter_map(|arg| snippet_opt(cx, arg.span)) + .filter_map(|arg| arg.span.get_source_text(cx)) .collect(); - let arg_snippets_without_empty_blocks: Vec = args_to_recover + let arg_snippets_without_empty_blocks: Vec<_> = args_to_recover .iter() .filter(|arg| !is_empty_block(arg)) - .filter_map(|arg| snippet_opt(cx, arg.span)) + .filter_map(|arg| arg.span.get_source_text(cx)) .collect(); - if let Some(call_snippet) = snippet_opt(cx, expr.span) { + if let Some(call_snippet) = expr.span.get_source_text(cx) { let sugg = fmt_stmts_and_call( cx, expr, @@ -161,8 +161,8 @@ fn fmt_stmts_and_call( cx: &LateContext<'_>, call_expr: &Expr<'_>, call_snippet: &str, - args_snippets: &[impl AsRef], - non_empty_block_args_snippets: &[impl AsRef], + args_snippets: &[SourceText], + non_empty_block_args_snippets: &[SourceText], ) -> String { let call_expr_indent = indent_of(cx, call_expr.span).unwrap_or(0); let call_snippet_with_replacements = args_snippets diff --git a/clippy_lints/src/unused_io_amount.rs b/clippy_lints/src/unused_io_amount.rs index 448946bd66d..cfc4ea46bdb 100644 --- a/clippy_lints/src/unused_io_amount.rs +++ b/clippy_lints/src/unused_io_amount.rs @@ -34,11 +34,18 @@ declare_clippy_lint! { /// ```rust,ignore /// use std::io; /// fn foo(w: &mut W) -> io::Result<()> { - /// // must be `w.write_all(b"foo")?;` /// w.write(b"foo")?; /// Ok(()) /// } /// ``` + /// Use instead: + /// ```rust,ignore + /// use std::io; + /// fn foo(w: &mut W) -> io::Result<()> { + /// w.write_all(b"foo")?; + /// Ok(()) + /// } + /// ``` #[clippy::version = "pre 1.29.0"] pub UNUSED_IO_AMOUNT, correctness, diff --git a/clippy_lints/src/unused_unit.rs b/clippy_lints/src/unused_unit.rs index b70aa768b46..65f431d338b 100644 --- a/clippy_lints/src/unused_unit.rs +++ b/clippy_lints/src/unused_unit.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::{position_before_rarrow, snippet_opt}; +use clippy_utils::source::{position_before_rarrow, SpanRangeExt}; use rustc_ast::visit::FnKind; use rustc_ast::{ast, ClosureBinder}; use rustc_errors::Applicability; @@ -128,15 +128,17 @@ fn is_unit_expr(expr: &ast::Expr) -> bool { fn lint_unneeded_unit_return(cx: &EarlyContext<'_>, ty: &ast::Ty, span: Span) { let (ret_span, appl) = - snippet_opt(cx, span.with_hi(ty.span.hi())).map_or((ty.span, Applicability::MaybeIncorrect), |fn_source| { - position_before_rarrow(&fn_source).map_or((ty.span, Applicability::MaybeIncorrect), |rpos| { - ( - #[expect(clippy::cast_possible_truncation)] - ty.span.with_lo(BytePos(span.lo().0 + rpos as u32)), - Applicability::MachineApplicable, - ) - }) - }); + span.with_hi(ty.span.hi()) + .get_source_text(cx) + .map_or((ty.span, Applicability::MaybeIncorrect), |src| { + position_before_rarrow(&src).map_or((ty.span, Applicability::MaybeIncorrect), |rpos| { + ( + #[expect(clippy::cast_possible_truncation)] + ty.span.with_lo(BytePos(span.lo().0 + rpos as u32)), + Applicability::MachineApplicable, + ) + }) + }); span_lint_and_sugg( cx, UNUSED_UNIT, diff --git a/clippy_lints/src/unwrap.rs b/clippy_lints/src/unwrap.rs index c0d9bcdd259..0b4ea0752b6 100644 --- a/clippy_lints/src/unwrap.rs +++ b/clippy_lints/src/unwrap.rs @@ -89,15 +89,15 @@ enum UnwrappableKind { impl UnwrappableKind { fn success_variant_pattern(self) -> &'static str { match self { - UnwrappableKind::Option => "Some(..)", - UnwrappableKind::Result => "Ok(..)", + UnwrappableKind::Option => "Some()", + UnwrappableKind::Result => "Ok()", } } fn error_variant_pattern(self) -> &'static str { match self { UnwrappableKind::Option => "None", - UnwrappableKind::Result => "Err(..)", + UnwrappableKind::Result => "Err()", } } } diff --git a/clippy_lints/src/use_self.rs b/clippy_lints/src/use_self.rs index 93785b45c27..5da48f4f7fb 100644 --- a/clippy_lints/src/use_self.rs +++ b/clippy_lints/src/use_self.rs @@ -229,7 +229,7 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf { && let impl_ty = cx.tcx.type_of(impl_id).instantiate_identity() && same_type_and_consts(ty, impl_ty) // Ensure the type we encounter and the one from the impl have the same lifetime parameters. It may be that - // the lifetime parameters of `ty` are ellided (`impl<'a> Foo<'a> { fn new() -> Self { Foo{..} } }`, in + // the lifetime parameters of `ty` are elided (`impl<'a> Foo<'a> { fn new() -> Self { Foo{..} } }`, in // which case we must still trigger the lint. && (has_no_lifetime(ty) || same_lifetimes(ty, impl_ty)) { diff --git a/clippy_lints/src/utils/author.rs b/clippy_lints/src/utils/author.rs index 316c1f32d3a..0cce45290cf 100644 --- a/clippy_lints/src/utils/author.rs +++ b/clippy_lints/src/utils/author.rs @@ -1,6 +1,3 @@ -//! A group of attributes that can be attached to Rust code in order -//! to generate a clippy lint detecting said code automatically. - use clippy_utils::{get_attr, higher}; use rustc_ast::ast::{LitFloatType, LitKind}; use rustc_ast::LitIntType; diff --git a/clippy_lints/src/utils/format_args_collector.rs b/clippy_lints/src/utils/format_args_collector.rs index 5acfd35fd6a..f50ce6c99de 100644 --- a/clippy_lints/src/utils/format_args_collector.rs +++ b/clippy_lints/src/utils/format_args_collector.rs @@ -1,5 +1,5 @@ use clippy_utils::macros::FormatArgsStorage; -use clippy_utils::source::snippet_opt; +use clippy_utils::source::SpanRangeExt; use itertools::Itertools; use rustc_ast::{Crate, Expr, ExprKind, FormatArgs}; use rustc_data_structures::fx::FxHashMap; @@ -75,38 +75,21 @@ fn has_span_from_proc_macro(cx: &EarlyContext<'_>, args: &FormatArgs) -> bool { // `format!("{} {} {c}", "one", "two", c = "three")` // ^^ ^^ ^^^^^^ - let between_spans = once(args.span) + !once(args.span) .chain(argument_span) .tuple_windows() - .map(|(start, end)| start.between(end)); - - for between_span in between_spans { - let mut seen_comma = false; - - let Some(snippet) = snippet_opt(cx, between_span) else { - return true; - }; - for token in tokenize(&snippet) { - match token.kind { - TokenKind::LineComment { .. } | TokenKind::BlockComment { .. } | TokenKind::Whitespace => {}, - TokenKind::Comma if !seen_comma => seen_comma = true, - // named arguments, `start_val, name = end_val` - // ^^^^^^^^^ between_span - TokenKind::Ident | TokenKind::Eq if seen_comma => {}, - // An unexpected token usually indicates that we crossed a macro boundary - // - // `println!(some_proc_macro!("input {}"), a)` - // ^^^ between_span - // `println!("{}", val!(x))` - // ^^^^^^^ between_span - _ => return true, - } - } - - if !seen_comma { - return true; - } - } - - false + .map(|(start, end)| start.between(end)) + .all(|sp| { + sp.check_source_text(cx, |src| { + // text should be either `, name` or `, name =` + let mut iter = tokenize(src).filter(|t| { + !matches!( + t.kind, + TokenKind::LineComment { .. } | TokenKind::BlockComment { .. } | TokenKind::Whitespace + ) + }); + iter.next().is_some_and(|t| matches!(t.kind, TokenKind::Comma)) + && iter.all(|t| matches!(t.kind, TokenKind::Ident | TokenKind::Eq)) + }) + }) } diff --git a/clippy_lints/src/utils/internal_lints.rs b/clippy_lints/src/utils/internal_lints.rs index 1d294c2944b..f662c7651f6 100644 --- a/clippy_lints/src/utils/internal_lints.rs +++ b/clippy_lints/src/utils/internal_lints.rs @@ -3,7 +3,6 @@ pub mod collapsible_calls; pub mod interning_defined_symbol; pub mod invalid_paths; pub mod lint_without_lint_pass; -pub mod metadata_collector; pub mod msrv_attr_impl; pub mod outer_expn_data_pass; pub mod produce_ice; 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 df342e48d63..20526113d69 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 @@ -9,7 +9,6 @@ use rustc_hir::intravisit::Visitor; use rustc_hir::{ExprKind, HirId, Item, MutTy, Mutability, Path, TyKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::nested_filter; -use rustc_semver::RustcVersion; use rustc_session::impl_lint_pass; use rustc_span::source_map::Spanned; use rustc_span::symbol::Symbol; @@ -92,7 +91,12 @@ pub struct LintWithoutLintPass { registered_lints: FxHashSet, } -impl_lint_pass!(LintWithoutLintPass => [DEFAULT_LINT, LINT_WITHOUT_LINT_PASS, INVALID_CLIPPY_VERSION_ATTRIBUTE, MISSING_CLIPPY_VERSION_ATTRIBUTE]); +impl_lint_pass!(LintWithoutLintPass => [ + DEFAULT_LINT, + LINT_WITHOUT_LINT_PASS, + INVALID_CLIPPY_VERSION_ATTRIBUTE, + MISSING_CLIPPY_VERSION_ATTRIBUTE, +]); impl<'tcx> LateLintPass<'tcx> for LintWithoutLintPass { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) { @@ -220,7 +224,7 @@ fn check_invalid_clippy_version_attribute(cx: &LateContext<'_>, item: &'_ Item<' return; } - if RustcVersion::parse(value.as_str()).is_err() { + if rustc_attr::parse_version(value).is_none() { span_lint_and_help( cx, INVALID_CLIPPY_VERSION_ATTRIBUTE, diff --git a/clippy_lints/src/utils/internal_lints/metadata_collector.rs b/clippy_lints/src/utils/internal_lints/metadata_collector.rs deleted file mode 100644 index 57f45aa3e48..00000000000 --- a/clippy_lints/src/utils/internal_lints/metadata_collector.rs +++ /dev/null @@ -1,1078 +0,0 @@ -//! This lint is used to collect metadata about clippy lints. This metadata is exported as a json -//! file and then used to generate the [clippy lint list](https://rust-lang.github.io/rust-clippy/master/index.html) -//! -//! This module and therefore the entire lint is guarded by a feature flag called `internal` -//! -//! The module transforms all lint names to ascii lowercase to ensure that we don't have mismatches -//! during any comparison or mapping. (Please take care of this, it's not fun to spend time on such -//! a simple mistake) - -use crate::utils::internal_lints::lint_without_lint_pass::{extract_clippy_version_value, is_lint_ref_type}; -use clippy_config::{get_configuration_metadata, ClippyConfiguration}; - -use clippy_utils::diagnostics::span_lint; -use clippy_utils::ty::{match_type, walk_ptrs_ty_depth}; -use clippy_utils::{last_path_segment, match_function_call, match_path, paths}; -use itertools::Itertools; -use rustc_ast as ast; -use rustc_data_structures::fx::FxHashMap; -use rustc_hir::def::DefKind; -use rustc_hir::intravisit::Visitor; -use rustc_hir::{self as hir, intravisit, Closure, ExprKind, Item, ItemKind, Mutability, QPath}; -use rustc_lint::{unerased_lint_store, CheckLintNameResult, LateContext, LateLintPass, LintContext, LintId}; -use rustc_middle::hir::nested_filter; -use rustc_session::impl_lint_pass; -use rustc_span::symbol::Ident; -use rustc_span::{sym, Loc, Span, Symbol}; -use serde::ser::SerializeStruct; -use serde::{Serialize, Serializer}; -use std::collections::{BTreeSet, BinaryHeap}; -use std::fmt::Write as _; -use std::fs::{self, File}; -use std::io::prelude::*; -use std::path::{Path, PathBuf}; -use std::process::Command; -use std::{env, fmt}; - -/// This is the json output file of the lint collector. -const JSON_OUTPUT_FILE: &str = "../util/gh-pages/lints.json"; -/// This is the markdown output file of the lint collector. -const MARKDOWN_OUTPUT_FILE: &str = "../book/src/lint_configuration.md"; -/// These groups will be ignored by the lint group matcher. This is useful for collections like -/// `clippy::all` -const IGNORED_LINT_GROUPS: [&str; 1] = ["clippy::all"]; -/// Lints within this group will be excluded from the collection. These groups -/// have to be defined without the `clippy::` prefix. -const EXCLUDED_LINT_GROUPS: [&str; 1] = ["internal"]; -/// Collected deprecated lint will be assigned to this group in the JSON output -const DEPRECATED_LINT_GROUP_STR: &str = "deprecated"; -/// This is the lint level for deprecated lints that will be displayed in the lint list -const DEPRECATED_LINT_LEVEL: &str = "none"; -/// This array holds Clippy's lint groups with their corresponding default lint level. The -/// lint level for deprecated lints is set in `DEPRECATED_LINT_LEVEL`. -const DEFAULT_LINT_LEVELS: &[(&str, &str)] = &[ - ("correctness", "deny"), - ("suspicious", "warn"), - ("restriction", "allow"), - ("style", "warn"), - ("pedantic", "allow"), - ("complexity", "warn"), - ("perf", "warn"), - ("cargo", "allow"), - ("nursery", "allow"), -]; -/// This prefix is in front of the lint groups in the lint store. The prefix will be trimmed -/// to only keep the actual lint group in the output. -const CLIPPY_LINT_GROUP_PREFIX: &str = "clippy::"; -const LINT_EMISSION_FUNCTIONS: [&[&str]; 7] = [ - &["clippy_utils", "diagnostics", "span_lint"], - &["clippy_utils", "diagnostics", "span_lint_and_help"], - &["clippy_utils", "diagnostics", "span_lint_and_note"], - &["clippy_utils", "diagnostics", "span_lint_hir"], - &["clippy_utils", "diagnostics", "span_lint_and_sugg"], - &["clippy_utils", "diagnostics", "span_lint_and_then"], - &["clippy_utils", "diagnostics", "span_lint_hir_and_then"], -]; -const SUGGESTION_DIAG_METHODS: [(&str, bool); 9] = [ - ("span_suggestion", false), - ("span_suggestion_short", false), - ("span_suggestion_verbose", false), - ("span_suggestion_hidden", false), - ("tool_only_span_suggestion", false), - ("multipart_suggestion", true), - ("multipart_suggestions", true), - ("tool_only_multipart_suggestion", true), - ("span_suggestions", true), -]; - -/// The index of the applicability name of `paths::APPLICABILITY_VALUES` -const APPLICABILITY_NAME_INDEX: usize = 2; -/// This applicability will be set for unresolved applicability values. -const APPLICABILITY_UNRESOLVED_STR: &str = "Unresolved"; -/// The version that will be displayed if none has been defined -const VERSION_DEFAULT_STR: &str = "Unknown"; - -const CHANGELOG_PATH: &str = "../CHANGELOG.md"; - -declare_clippy_lint! { - /// ### What it does - /// Collects metadata about clippy lints for the website. - /// - /// This lint will be used to report problems of syntax parsing. You should hopefully never - /// see this but never say never I guess ^^ - /// - /// ### Why is this bad? - /// This is not a bad thing but definitely a hacky way to do it. See - /// issue [#4310](https://github.com/rust-lang/rust-clippy/issues/4310) for a discussion - /// about the implementation. - /// - /// ### Known problems - /// Hopefully none. It would be pretty uncool to have a problem here :) - /// - /// ### Example output - /// ```json,ignore - /// { - /// "id": "metadata_collector", - /// "id_span": { - /// "path": "clippy_lints/src/utils/internal_lints/metadata_collector.rs", - /// "line": 1 - /// }, - /// "group": "clippy::internal", - /// "docs": " ### What it does\nCollects metadata about clippy lints for the website. [...] " - /// } - /// ``` - #[clippy::version = "1.56.0"] - pub METADATA_COLLECTOR, - internal, - "A busy bee collection metadata about lints" -} - -impl_lint_pass!(MetadataCollector => [METADATA_COLLECTOR]); - -#[allow(clippy::module_name_repetitions)] -#[derive(Debug, Clone)] -pub struct MetadataCollector { - /// All collected lints - /// - /// We use a Heap here to have the lints added in alphabetic order in the export - lints: BinaryHeap, - applicability_info: FxHashMap, - config: Vec, - clippy_project_root: PathBuf, -} - -impl MetadataCollector { - pub fn new() -> Self { - Self { - lints: BinaryHeap::::default(), - applicability_info: FxHashMap::::default(), - config: get_configuration_metadata(), - clippy_project_root: env::current_dir() - .expect("failed to get current dir") - .ancestors() - .nth(1) - .expect("failed to get project root") - .to_path_buf(), - } - } - - fn get_lint_configs(&self, lint_name: &str) -> Option { - self.config - .iter() - .filter(|config| config.lints.iter().any(|&lint| lint == lint_name)) - .map(ToString::to_string) - .reduce(|acc, x| acc + "\n\n" + &x) - .map(|configurations| { - format!( - r#" -### Configuration -This lint has the following configuration variables: - -{configurations} -"# - ) - }) - } - - fn configs_to_markdown(&self, map_fn: fn(&ClippyConfiguration) -> String) -> String { - self.config - .iter() - .filter(|config| config.deprecation_reason.is_none()) - .filter(|config| !config.lints.is_empty()) - .map(map_fn) - .join("\n") - } - - fn get_markdown_docs(&self) -> String { - format!( - r#"# Lint Configuration Options - -The following list shows each configuration option, along with a description, its default value, an example -and lints affected. - ---- - -{}"#, - self.configs_to_markdown(ClippyConfiguration::to_markdown_paragraph), - ) - } -} - -impl Drop for MetadataCollector { - /// You might ask: How hacky is this? - /// My answer: YES - fn drop(&mut self) { - // The metadata collector gets dropped twice, this makes sure that we only write - // when the list is full - if self.lints.is_empty() { - return; - } - - let mut applicability_info = std::mem::take(&mut self.applicability_info); - - // Add deprecated lints - self.lints.extend( - crate::deprecated_lints::DEPRECATED - .iter() - .zip(crate::deprecated_lints::DEPRECATED_VERSION) - .filter_map(|((lint, reason), version)| LintMetadata::new_deprecated(lint, reason, version)), - ); - // Mapping the final data - let mut lints = std::mem::take(&mut self.lints).into_sorted_vec(); - for x in &mut lints { - x.applicability = Some(applicability_info.remove(&x.id).unwrap_or_default()); - replace_produces(&x.id, &mut x.docs, &self.clippy_project_root); - } - - collect_renames(&mut lints); - - // Outputting json - fs::write(JSON_OUTPUT_FILE, serde_json::to_string_pretty(&lints).unwrap()).unwrap(); - - // Outputting markdown - let mut file = File::create(MARKDOWN_OUTPUT_FILE).unwrap(); - writeln!( - file, - " - -{}", - self.get_markdown_docs(), - ) - .unwrap(); - - // Write configuration links to CHANGELOG.md - let changelog = fs::read_to_string(CHANGELOG_PATH).unwrap(); - let mut changelog_file = File::create(CHANGELOG_PATH).unwrap(); - let position = changelog - .find("") - .unwrap(); - writeln!( - changelog_file, - "{}\n{}\n", - &changelog[..position], - self.configs_to_markdown(ClippyConfiguration::to_markdown_link) - ) - .unwrap(); - } -} - -#[derive(Debug, Clone, Serialize, PartialEq, Eq, PartialOrd, Ord)] -struct LintMetadata { - id: String, - id_span: Option, - group: String, - level: String, - docs: String, - version: String, - /// This field is only used in the output and will only be - /// mapped shortly before the actual output. - applicability: Option, - /// All the past names of lints which have been renamed. - #[serde(skip_serializing_if = "BTreeSet::is_empty")] - former_ids: BTreeSet, -} - -impl LintMetadata { - fn new( - id: String, - id_span: SerializableSpan, - group: String, - level: &'static str, - version: String, - docs: String, - ) -> Self { - Self { - id, - id_span: Some(id_span), - group, - level: level.to_string(), - version, - docs, - applicability: None, - former_ids: BTreeSet::new(), - } - } - - fn new_deprecated(name: &str, reason: &str, version: &str) -> Option { - // The reason starts with a lowercase letter and end without a period. - // This needs to be fixed for the website. - let mut reason = reason.to_owned(); - if let Some(reason) = reason.get_mut(0..1) { - reason.make_ascii_uppercase(); - } - name.strip_prefix("clippy::").map(|name| Self { - id: name.into(), - id_span: None, - group: DEPRECATED_LINT_GROUP_STR.into(), - level: DEPRECATED_LINT_LEVEL.into(), - version: version.into(), - docs: format!( - "### What it does\n\n\ - Nothing. This lint has been deprecated\n\n\ - ### Deprecation reason\n\n{reason}.\n", - ), - applicability: None, - former_ids: BTreeSet::new(), - }) - } -} - -fn replace_produces(lint_name: &str, docs: &mut String, clippy_project_root: &Path) { - let mut doc_lines = docs.lines().map(ToString::to_string).collect::>(); - let mut lines = doc_lines.iter_mut(); - - 'outer: loop { - // Find the start of the example - - // ```rust - loop { - match lines.next() { - Some(line) if line.trim_start().starts_with("```rust") => { - if line.contains("ignore") || line.contains("no_run") { - // A {{produces}} marker may have been put on a ignored code block by mistake, - // just seek to the end of the code block and continue checking. - if lines.any(|line| line.trim_start().starts_with("```")) { - continue; - } - - panic!("lint `{lint_name}` has an unterminated code block") - } - - break; - }, - Some(line) if line.trim_start() == "{{produces}}" => { - panic!("lint `{lint_name}` has marker {{{{produces}}}} with an ignored or missing code block") - }, - Some(line) => { - let line = line.trim(); - // These are the two most common markers of the corrections section - if line.eq_ignore_ascii_case("Use instead:") || line.eq_ignore_ascii_case("Could be written as:") { - break 'outer; - } - }, - None => break 'outer, - } - } - - // Collect the example - let mut example = Vec::new(); - loop { - match lines.next() { - Some(line) if line.trim_start() == "```" => break, - Some(line) => example.push(line), - None => panic!("lint `{lint_name}` has an unterminated code block"), - } - } - - // Find the {{produces}} and attempt to generate the output - loop { - match lines.next() { - Some(line) if line.is_empty() => {}, - Some(line) if line.trim() == "{{produces}}" => { - let output = get_lint_output(lint_name, &example, clippy_project_root); - line.replace_range( - .., - &format!( - "
\ - Produces\n\ - \n\ - ```text\n\ - {output}\n\ - ```\n\ -
" - ), - ); - - break; - }, - // No {{produces}}, we can move on to the next example - Some(_) => break, - None => break 'outer, - } - } - } - - *docs = cleanup_docs(&doc_lines); -} - -fn get_lint_output(lint_name: &str, example: &[&mut String], clippy_project_root: &Path) -> String { - let dir = tempfile::tempdir().unwrap_or_else(|e| panic!("failed to create temp dir: {e}")); - let file = dir.path().join("lint_example.rs"); - - let mut source = String::new(); - let unhidden = example - .iter() - .map(|line| line.trim_start().strip_prefix("# ").unwrap_or(line)); - - // Get any attributes - let mut lines = unhidden.peekable(); - while let Some(line) = lines.peek() { - if line.starts_with("#!") { - source.push_str(line); - source.push('\n'); - lines.next(); - } else { - break; - } - } - - let needs_main = !example.iter().any(|line| line.contains("fn main")); - if needs_main { - source.push_str("fn main() {\n"); - } - - for line in lines { - source.push_str(line); - source.push('\n'); - } - - if needs_main { - source.push_str("}\n"); - } - - if let Err(e) = fs::write(&file, &source) { - panic!("failed to write to `{}`: {e}", file.as_path().to_string_lossy()); - } - - let prefixed_name = format!("{CLIPPY_LINT_GROUP_PREFIX}{lint_name}"); - - let mut cmd = Command::new(env::var("CARGO").unwrap_or("cargo".into())); - - cmd.current_dir(clippy_project_root) - .env("CARGO_INCREMENTAL", "0") - .env("CLIPPY_ARGS", "") - .env("CLIPPY_DISABLE_DOCS_LINKS", "1") - // We need to disable this to enable all lints - .env("ENABLE_METADATA_COLLECTION", "0") - .args(["run", "--bin", "clippy-driver"]) - .args(["--target-dir", "./clippy_lints/target"]) - .args(["--", "--error-format=json"]) - .args(["--edition", "2021"]) - .arg("-Cdebuginfo=0") - .args(["-A", "clippy::all"]) - .args(["-W", &prefixed_name]) - .args(["-L", "./target/debug"]) - .args(["-Z", "no-codegen"]); - - let output = cmd - .arg(file.as_path()) - .output() - .unwrap_or_else(|e| panic!("failed to run `{cmd:?}`: {e}")); - - let tmp_file_path = file.to_string_lossy(); - let stderr = std::str::from_utf8(&output.stderr).unwrap(); - let msgs = stderr - .lines() - .filter(|line| line.starts_with('{')) - .map(|line| serde_json::from_str(line).unwrap()) - .collect::>(); - - let mut rendered = String::new(); - let iter = msgs - .iter() - .filter(|msg| matches!(&msg["code"]["code"], serde_json::Value::String(s) if s == &prefixed_name)); - - for message in iter { - let rendered_part = message["rendered"].as_str().expect("rendered field should exist"); - rendered.push_str(rendered_part); - } - - if rendered.is_empty() { - let rendered: Vec<&str> = msgs.iter().filter_map(|msg| msg["rendered"].as_str()).collect(); - let non_json: Vec<&str> = stderr.lines().filter(|line| !line.starts_with('{')).collect(); - panic!( - "did not find lint `{lint_name}` in output of example, got:\n{}\n{}", - non_json.join("\n"), - rendered.join("\n") - ); - } - - // The reader doesn't need to see `/tmp/.tmpfiy2Qd/lint_example.rs` :) - rendered.trim_end().replace(&*tmp_file_path, "lint_example.rs") -} - -#[derive(Debug, Clone, Serialize, PartialEq, Eq, PartialOrd, Ord)] -struct SerializableSpan { - path: String, - line: usize, -} - -impl fmt::Display for SerializableSpan { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}:{}", self.path.rsplit('/').next().unwrap_or_default(), self.line) - } -} - -impl SerializableSpan { - fn from_item(cx: &LateContext<'_>, item: &Item<'_>) -> Self { - Self::from_span(cx, item.ident.span) - } - - fn from_span(cx: &LateContext<'_>, span: Span) -> Self { - let loc: Loc = cx.sess().source_map().lookup_char_pos(span.lo()); - - Self { - path: format!("{}", loc.file.name.prefer_remapped_unconditionaly()), - line: loc.line, - } - } -} - -#[derive(Debug, Clone, Default, PartialEq, Eq, PartialOrd, Ord)] -struct ApplicabilityInfo { - /// Indicates if any of the lint emissions uses multiple spans. This is related to - /// [rustfix#141](https://github.com/rust-lang/rustfix/issues/141) as such suggestions can - /// currently not be applied automatically. - is_multi_part_suggestion: bool, - applicability: Option, -} - -impl Serialize for ApplicabilityInfo { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - let mut s = serializer.serialize_struct("ApplicabilityInfo", 2)?; - s.serialize_field("is_multi_part_suggestion", &self.is_multi_part_suggestion)?; - if let Some(index) = self.applicability { - s.serialize_field( - "applicability", - &paths::APPLICABILITY_VALUES[index][APPLICABILITY_NAME_INDEX], - )?; - } else { - s.serialize_field("applicability", APPLICABILITY_UNRESOLVED_STR)?; - } - s.end() - } -} - -// ================================================================== -// Lint pass -// ================================================================== -impl<'hir> LateLintPass<'hir> for MetadataCollector { - /// Collecting lint declarations like: - /// ```rust, ignore - /// declare_clippy_lint! { - /// /// ### What it does - /// /// Something IDK. - /// pub SOME_LINT, - /// internal, - /// "Who am I?" - /// } - /// ``` - fn check_item(&mut self, cx: &LateContext<'hir>, item: &'hir Item<'_>) { - if let ItemKind::Static(ty, Mutability::Not, _) = item.kind { - // Normal lint - if is_lint_ref_type(cx, ty) - // item validation - // disallow check - && let lint_name = sym_to_string(item.ident.name).to_ascii_lowercase() - // metadata extraction - && let Some((group, level)) = get_lint_group_and_level_or_lint(cx, &lint_name, item) - && let Some(mut raw_docs) = extract_attr_docs_or_lint(cx, item) - { - if let Some(configuration_section) = self.get_lint_configs(&lint_name) { - raw_docs.push_str(&configuration_section); - } - let version = get_lint_version(cx, item); - - self.lints.push(LintMetadata::new( - lint_name, - SerializableSpan::from_item(cx, item), - group, - level, - version, - raw_docs, - )); - } - } - } - - /// Collecting constant applicability from the actual lint emissions - /// - /// Example: - /// ```rust, ignore - /// span_lint_and_sugg( - /// cx, - /// SOME_LINT, - /// item.span, - /// "Le lint message", - /// "Here comes help:", - /// "#![allow(clippy::all)]", - /// Applicability::MachineApplicable, // <-- Extracts this constant value - /// ); - /// ``` - fn check_expr(&mut self, cx: &LateContext<'hir>, expr: &'hir hir::Expr<'_>) { - if let Some(args) = match_lint_emission(cx, expr) { - let emission_info = extract_emission_info(cx, args); - if emission_info.is_empty() { - // See: - // - src/misc.rs:734:9 - // - src/methods/mod.rs:3545:13 - // - src/methods/mod.rs:3496:13 - // We are basically unable to resolve the lint name itself. - return; - } - - for (lint_name, applicability, is_multi_part) in emission_info { - let app_info = self.applicability_info.entry(lint_name).or_default(); - app_info.applicability = applicability; - app_info.is_multi_part_suggestion = is_multi_part; - } - } - } -} - -// ================================================================== -// Lint definition extraction -// ================================================================== -fn sym_to_string(sym: Symbol) -> String { - sym.as_str().to_string() -} - -fn extract_attr_docs_or_lint(cx: &LateContext<'_>, item: &Item<'_>) -> Option { - extract_attr_docs(cx, item).or_else(|| { - lint_collection_error_item(cx, item, "could not collect the lint documentation"); - None - }) -} - -/// This function collects all documentation that has been added to an item using -/// `#[doc = r""]` attributes. Several attributes are aggravated using line breaks -/// -/// ```ignore -/// #[doc = r"Hello world!"] -/// #[doc = r"=^.^="] -/// struct SomeItem {} -/// ``` -/// -/// Would result in `Hello world!\n=^.^=\n` -fn extract_attr_docs(cx: &LateContext<'_>, item: &Item<'_>) -> Option { - let attrs = cx.tcx.hir().attrs(item.hir_id()); - let mut lines = attrs.iter().filter_map(ast::Attribute::doc_str); - - if let Some(line) = lines.next() { - let raw_docs = lines.fold(String::from(line.as_str()) + "\n", |s, line| s + line.as_str() + "\n"); - return Some(raw_docs); - } - - None -} - -/// This function may modify the doc comment to ensure that the string can be displayed using a -/// markdown viewer in Clippy's lint list. The following modifications could be applied: -/// * Removal of leading space after a new line. (Important to display tables) -/// * Ensures that code blocks only contain language information -fn cleanup_docs(docs_collection: &Vec) -> String { - let mut in_code_block = false; - let mut is_code_block_rust = false; - - let mut docs = String::new(); - for line in docs_collection { - // Rustdoc hides code lines starting with `# ` and this removes them from Clippy's lint list :) - if is_code_block_rust && line.trim_start().starts_with("# ") { - continue; - } - - // The line should be represented in the lint list, even if it's just an empty line - docs.push('\n'); - if let Some(info) = line.trim_start().strip_prefix("```") { - in_code_block = !in_code_block; - is_code_block_rust = false; - if in_code_block { - let lang = info - .trim() - .split(',') - // remove rustdoc directives - .find(|&s| !matches!(s, "" | "ignore" | "no_run" | "should_panic")) - // if no language is present, fill in "rust" - .unwrap_or("rust"); - let len_diff = line.len() - line.trim_start().len(); - if len_diff != 0 { - // We put back the indentation. - docs.push_str(&line[..len_diff]); - } - docs.push_str("```"); - docs.push_str(lang); - - is_code_block_rust = lang == "rust"; - continue; - } - } - // This removes the leading space that the macro translation introduces - if let Some(stripped_doc) = line.strip_prefix(' ') { - docs.push_str(stripped_doc); - } else if !line.is_empty() { - docs.push_str(line); - } - } - - docs -} - -fn get_lint_version(cx: &LateContext<'_>, item: &Item<'_>) -> String { - extract_clippy_version_value(cx, item).map_or_else( - || VERSION_DEFAULT_STR.to_string(), - |version| version.as_str().to_string(), - ) -} - -fn get_lint_group_and_level_or_lint( - cx: &LateContext<'_>, - lint_name: &str, - item: &Item<'_>, -) -> Option<(String, &'static str)> { - let result = unerased_lint_store(cx.tcx.sess).check_lint_name( - lint_name, - Some(sym::clippy), - &std::iter::once(Ident::with_dummy_span(sym::clippy)).collect(), - ); - if let CheckLintNameResult::Tool(lint_lst, None) = result { - if let Some(group) = get_lint_group(cx, lint_lst[0]) { - if EXCLUDED_LINT_GROUPS.contains(&group.as_str()) { - return None; - } - - if let Some(level) = get_lint_level_from_group(&group) { - Some((group, level)) - } else { - lint_collection_error_item( - cx, - item, - &format!("Unable to determine lint level for found group `{group}`"), - ); - None - } - } else { - lint_collection_error_item(cx, item, "Unable to determine lint group"); - None - } - } else { - lint_collection_error_item(cx, item, "Unable to find lint in lint_store"); - None - } -} - -fn get_lint_group(cx: &LateContext<'_>, lint_id: LintId) -> Option { - for (group_name, lints, _) in unerased_lint_store(cx.tcx.sess).get_lint_groups() { - if IGNORED_LINT_GROUPS.contains(&group_name) { - continue; - } - - if lints.iter().any(|group_lint| *group_lint == lint_id) { - let group = group_name.strip_prefix(CLIPPY_LINT_GROUP_PREFIX).unwrap_or(group_name); - return Some((*group).to_string()); - } - } - - None -} - -fn get_lint_level_from_group(lint_group: &str) -> Option<&'static str> { - DEFAULT_LINT_LEVELS - .iter() - .find_map(|(group_name, group_level)| (*group_name == lint_group).then_some(*group_level)) -} - -fn collect_renames(lints: &mut Vec) { - for lint in lints { - let mut collected = String::new(); - let mut names = vec![lint.id.clone()]; - - loop { - if let Some(lint_name) = names.pop() { - for (k, v) in crate::deprecated_lints::RENAMED { - if let Some(name) = v.strip_prefix(CLIPPY_LINT_GROUP_PREFIX) - && name == lint_name - && let Some(past_name) = k.strip_prefix(CLIPPY_LINT_GROUP_PREFIX) - { - lint.former_ids.insert(past_name.to_owned()); - writeln!(collected, "* `{past_name}`").unwrap(); - names.push(past_name.to_string()); - } - } - - continue; - } - - break; - } - - if !collected.is_empty() { - write!( - &mut lint.docs, - r#" -### Past names - -{collected} -"# - ) - .unwrap(); - } - } -} - -// ================================================================== -// Lint emission -// ================================================================== -fn lint_collection_error_item(cx: &LateContext<'_>, item: &Item<'_>, message: &str) { - span_lint( - cx, - METADATA_COLLECTOR, - item.ident.span, - format!("metadata collection error for `{}`: {message}", item.ident.name), - ); -} - -// ================================================================== -// Applicability -// ================================================================== -/// This function checks if a given expression is equal to a simple lint emission function call. -/// It will return the function arguments if the emission matched any function. -fn match_lint_emission<'hir>(cx: &LateContext<'hir>, expr: &'hir hir::Expr<'_>) -> Option<&'hir [hir::Expr<'hir>]> { - LINT_EMISSION_FUNCTIONS - .iter() - .find_map(|emission_fn| match_function_call(cx, expr, emission_fn)) -} - -fn take_higher_applicability(a: Option, b: Option) -> Option { - a.map_or(b, |a| a.max(b.unwrap_or_default()).into()) -} - -fn extract_emission_info<'hir>( - cx: &LateContext<'hir>, - args: &'hir [hir::Expr<'hir>], -) -> Vec<(String, Option, bool)> { - let mut lints = Vec::new(); - let mut applicability = None; - let mut multi_part = false; - - for arg in args { - let (arg_ty, _) = walk_ptrs_ty_depth(cx.typeck_results().expr_ty(arg)); - - if match_type(cx, arg_ty, &paths::LINT) { - // If we found the lint arg, extract the lint name - let mut resolved_lints = resolve_lints(cx, arg); - lints.append(&mut resolved_lints); - } else if match_type(cx, arg_ty, &paths::APPLICABILITY) { - applicability = resolve_applicability(cx, arg); - } else if arg_ty.is_closure() { - multi_part |= check_is_multi_part(cx, arg); - applicability = applicability.or_else(|| resolve_applicability(cx, arg)); - } - } - - lints - .into_iter() - .map(|lint_name| (lint_name, applicability, multi_part)) - .collect() -} - -/// Resolves the possible lints that this expression could reference -fn resolve_lints<'hir>(cx: &LateContext<'hir>, expr: &'hir hir::Expr<'hir>) -> Vec { - let mut resolver = LintResolver::new(cx); - resolver.visit_expr(expr); - resolver.lints -} - -/// This function tries to resolve the linked applicability to the given expression. -fn resolve_applicability<'hir>(cx: &LateContext<'hir>, expr: &'hir hir::Expr<'hir>) -> Option { - let mut resolver = ApplicabilityResolver::new(cx); - resolver.visit_expr(expr); - resolver.complete() -} - -fn check_is_multi_part<'hir>(cx: &LateContext<'hir>, closure_expr: &'hir hir::Expr<'hir>) -> bool { - if let ExprKind::Closure(&Closure { body, .. }) = closure_expr.kind { - let mut scanner = IsMultiSpanScanner::new(cx); - intravisit::walk_body(&mut scanner, cx.tcx.hir().body(body)); - return scanner.is_multi_part(); - } else if let Some(local) = get_parent_local(cx, closure_expr) { - if let Some(local_init) = local.init { - return check_is_multi_part(cx, local_init); - } - } - - false -} - -struct LintResolver<'a, 'hir> { - cx: &'a LateContext<'hir>, - lints: Vec, -} - -impl<'a, 'hir> LintResolver<'a, 'hir> { - fn new(cx: &'a LateContext<'hir>) -> Self { - Self { - cx, - lints: Vec::::default(), - } - } -} - -impl<'a, 'hir> Visitor<'hir> for LintResolver<'a, 'hir> { - type NestedFilter = nested_filter::All; - - fn nested_visit_map(&mut self) -> Self::Map { - self.cx.tcx.hir() - } - - fn visit_expr(&mut self, expr: &'hir hir::Expr<'hir>) { - if let ExprKind::Path(qpath) = &expr.kind - && let QPath::Resolved(_, path) = qpath - && let (expr_ty, _) = walk_ptrs_ty_depth(self.cx.typeck_results().expr_ty(expr)) - && match_type(self.cx, expr_ty, &paths::LINT) - { - if let hir::def::Res::Def(DefKind::Static { .. }, _) = path.res { - let lint_name = last_path_segment(qpath).ident.name; - self.lints.push(sym_to_string(lint_name).to_ascii_lowercase()); - } else if let Some(local) = get_parent_local(self.cx, expr) { - if let Some(local_init) = local.init { - intravisit::walk_expr(self, local_init); - } - } - } - - intravisit::walk_expr(self, expr); - } -} - -/// This visitor finds the highest applicability value in the visited expressions -struct ApplicabilityResolver<'a, 'hir> { - cx: &'a LateContext<'hir>, - /// This is the index of highest `Applicability` for `paths::APPLICABILITY_VALUES` - applicability_index: Option, -} - -impl<'a, 'hir> ApplicabilityResolver<'a, 'hir> { - fn new(cx: &'a LateContext<'hir>) -> Self { - Self { - cx, - applicability_index: None, - } - } - - fn add_new_index(&mut self, new_index: usize) { - self.applicability_index = take_higher_applicability(self.applicability_index, Some(new_index)); - } - - fn complete(self) -> Option { - self.applicability_index - } -} - -impl<'a, 'hir> Visitor<'hir> for ApplicabilityResolver<'a, 'hir> { - type NestedFilter = nested_filter::All; - - fn nested_visit_map(&mut self) -> Self::Map { - self.cx.tcx.hir() - } - - fn visit_path(&mut self, path: &hir::Path<'hir>, _id: hir::HirId) { - for (index, enum_value) in paths::APPLICABILITY_VALUES.iter().enumerate() { - if match_path(path, enum_value) { - self.add_new_index(index); - return; - } - } - } - - fn visit_expr(&mut self, expr: &'hir hir::Expr<'hir>) { - let (expr_ty, _) = walk_ptrs_ty_depth(self.cx.typeck_results().expr_ty(expr)); - - if match_type(self.cx, expr_ty, &paths::APPLICABILITY) - && let Some(local) = get_parent_local(self.cx, expr) - && let Some(local_init) = local.init - { - intravisit::walk_expr(self, local_init); - }; - - intravisit::walk_expr(self, expr); - } -} - -/// This returns the parent local node if the expression is a reference one -fn get_parent_local<'hir>(cx: &LateContext<'hir>, expr: &'hir hir::Expr<'hir>) -> Option<&'hir hir::LetStmt<'hir>> { - if let ExprKind::Path(QPath::Resolved(_, path)) = expr.kind { - if let hir::def::Res::Local(local_hir) = path.res { - return get_parent_local_hir_id(cx, local_hir); - } - } - - None -} - -fn get_parent_local_hir_id<'hir>(cx: &LateContext<'hir>, hir_id: hir::HirId) -> Option<&'hir hir::LetStmt<'hir>> { - match cx.tcx.parent_hir_node(hir_id) { - hir::Node::LetStmt(local) => Some(local), - hir::Node::Pat(pattern) => get_parent_local_hir_id(cx, pattern.hir_id), - _ => None, - } -} - -/// This visitor finds the highest applicability value in the visited expressions -struct IsMultiSpanScanner<'a, 'hir> { - cx: &'a LateContext<'hir>, - suggestion_count: usize, -} - -impl<'a, 'hir> IsMultiSpanScanner<'a, 'hir> { - fn new(cx: &'a LateContext<'hir>) -> Self { - Self { - cx, - suggestion_count: 0, - } - } - - /// Add a new single expression suggestion to the counter - fn add_single_span_suggestion(&mut self) { - self.suggestion_count += 1; - } - - /// Signals that a suggestion with possible multiple spans was found - fn add_multi_part_suggestion(&mut self) { - self.suggestion_count += 2; - } - - /// Checks if the suggestions include multiple spans - fn is_multi_part(&self) -> bool { - self.suggestion_count > 1 - } -} - -impl<'a, 'hir> Visitor<'hir> for IsMultiSpanScanner<'a, 'hir> { - type NestedFilter = nested_filter::All; - - fn nested_visit_map(&mut self) -> Self::Map { - self.cx.tcx.hir() - } - - fn visit_expr(&mut self, expr: &'hir hir::Expr<'hir>) { - // Early return if the lint is already multi span - if self.is_multi_part() { - return; - } - - if let ExprKind::MethodCall(path, recv, _, _arg_span) = &expr.kind { - let (self_ty, _) = walk_ptrs_ty_depth(self.cx.typeck_results().expr_ty(recv)); - if match_type(self.cx, self_ty, &paths::DIAG) { - let called_method = path.ident.name.as_str().to_string(); - for (method_name, is_multi_part) in &SUGGESTION_DIAG_METHODS { - if *method_name == called_method { - if *is_multi_part { - self.add_multi_part_suggestion(); - } else { - self.add_single_span_suggestion(); - } - break; - } - } - } - } - - intravisit::walk_expr(self, expr); - } -} diff --git a/clippy_lints/src/vec.rs b/clippy_lints/src/vec.rs index 228db14d1b7..d3e49bff422 100644 --- a/clippy_lints/src/vec.rs +++ b/clippy_lints/src/vec.rs @@ -5,7 +5,7 @@ use clippy_config::msrvs::{self, Msrv}; use clippy_config::Conf; use clippy_utils::consts::{ConstEvalCtxt, Constant}; use clippy_utils::diagnostics::span_lint_hir_and_then; -use clippy_utils::source::snippet_opt; +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}; @@ -214,9 +214,11 @@ impl SuggestedType { } fn snippet(self, cx: &LateContext<'_>, args_span: Option, len_span: Option) -> String { - let maybe_args = args_span.and_then(|sp| snippet_opt(cx, sp)).unwrap_or_default(); + let maybe_args = args_span + .and_then(|sp| sp.get_source_text(cx)) + .map_or(String::new(), |x| x.to_owned()); let maybe_len = len_span - .and_then(|sp| snippet_opt(cx, sp).map(|s| format!("; {s}"))) + .and_then(|sp| sp.get_source_text(cx).map(|s| format!("; {s}"))) .unwrap_or_default(); match self { diff --git a/clippy_lints/src/visibility.rs b/clippy_lints/src/visibility.rs index 63f3a5d7f83..7a85196ceca 100644 --- a/clippy_lints/src/visibility.rs +++ b/clippy_lints/src/visibility.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::snippet_opt; +use clippy_utils::source::SpanRangeExt; use rustc_ast::ast::{Item, VisibilityKind}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; @@ -82,9 +82,7 @@ impl EarlyLintPass for Visibility { if !in_external_macro(cx.sess(), item.span) && let VisibilityKind::Restricted { path, shorthand, .. } = &item.vis.kind { - if **path == kw::SelfLower - && let Some(false) = is_from_proc_macro(cx, item.vis.span) - { + if **path == kw::SelfLower && !is_from_proc_macro(cx, item.vis.span) { span_lint_and_then( cx, NEEDLESS_PUB_SELF, @@ -104,7 +102,7 @@ impl EarlyLintPass for Visibility { if (**path == kw::Super || **path == kw::SelfLower || **path == kw::Crate) && !*shorthand && let [.., last] = &*path.segments - && let Some(false) = is_from_proc_macro(cx, item.vis.span) + && !is_from_proc_macro(cx, item.vis.span) { #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")] span_lint_and_then( @@ -125,7 +123,7 @@ impl EarlyLintPass for Visibility { if *shorthand && let [.., last] = &*path.segments - && let Some(false) = is_from_proc_macro(cx, item.vis.span) + && !is_from_proc_macro(cx, item.vis.span) { #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")] span_lint_and_then( @@ -147,6 +145,6 @@ impl EarlyLintPass for Visibility { } } -fn is_from_proc_macro(cx: &EarlyContext<'_>, span: Span) -> Option { - snippet_opt(cx, span).map(|s| !s.starts_with("pub")) +fn is_from_proc_macro(cx: &EarlyContext<'_>, span: Span) -> bool { + !span.check_source_text(cx, |src| src.starts_with("pub")) } diff --git a/clippy_lints/src/wildcard_imports.rs b/clippy_lints/src/wildcard_imports.rs index c4d64ee4609..7d9e58ad2f8 100644 --- a/clippy_lints/src/wildcard_imports.rs +++ b/clippy_lints/src/wildcard_imports.rs @@ -100,14 +100,14 @@ declare_clippy_lint! { pub struct WildcardImports { warn_on_all: bool, - allowed_segments: &'static FxHashSet, + allowed_segments: FxHashSet, } impl WildcardImports { pub fn new(conf: &'static Conf) -> Self { Self { warn_on_all: conf.warn_on_all_wildcard_imports, - allowed_segments: &conf.allowed_wildcard_imports, + allowed_segments: conf.allowed_wildcard_imports.iter().cloned().collect(), } } } @@ -181,7 +181,7 @@ impl WildcardImports { fn check_exceptions(&self, cx: &LateContext<'_>, item: &Item<'_>, segments: &[PathSegment<'_>]) -> bool { item.span.from_expansion() || is_prelude_import(segments) - || is_allowed_via_config(segments, self.allowed_segments) + || is_allowed_via_config(segments, &self.allowed_segments) || (is_super_only_import(segments) && is_in_test(cx.tcx, item.hir_id())) } } diff --git a/clippy_lints/src/write.rs b/clippy_lints/src/write.rs index 54e7e92f0c4..ec5a5896fb2 100644 --- a/clippy_lints/src/write.rs +++ b/clippy_lints/src/write.rs @@ -2,7 +2,7 @@ use clippy_config::Conf; use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; use clippy_utils::is_in_test; use clippy_utils::macros::{format_arg_removal_span, root_macro_call_first_node, FormatArgsStorage, MacroCall}; -use clippy_utils::source::{expand_past_previous_comma, snippet_opt}; +use clippy_utils::source::{expand_past_previous_comma, SpanRangeExt}; use rustc_ast::token::LitKind; use rustc_ast::{ FormatArgPosition, FormatArgPositionKind, FormatArgs, FormatArgsPiece, FormatOptions, FormatPlaceholder, @@ -397,7 +397,7 @@ fn check_newline(cx: &LateContext<'_>, format_args: &FormatArgs, macro_call: &Ma format!("using `{name}!()` with a format string that ends in a single newline"), |diag| { let name_span = cx.sess().source_map().span_until_char(macro_call.span, '!'); - let Some(format_snippet) = snippet_opt(cx, format_string_span) else { + let Some(format_snippet) = format_string_span.get_source_text(cx) else { return; }; @@ -492,7 +492,7 @@ fn check_literal(cx: &LateContext<'_>, format_args: &FormatArgs, name: &str) { && let Some(arg) = format_args.arguments.by_index(index) && let rustc_ast::ExprKind::Lit(lit) = &arg.expr.kind && !arg.expr.span.from_expansion() - && let Some(value_string) = snippet_opt(cx, arg.expr.span) + && let Some(value_string) = arg.expr.span.get_source_text(cx) { let (replacement, replace_raw) = match lit.kind { LitKind::Str | LitKind::StrRaw(_) => match extract_str_literal(&value_string) { @@ -515,7 +515,7 @@ fn check_literal(cx: &LateContext<'_>, format_args: &FormatArgs, name: &str) { _ => continue, }; - let Some(format_string_snippet) = snippet_opt(cx, format_args.span) else { + let Some(format_string_snippet) = format_args.span.get_source_text(cx) else { continue; }; let format_string_is_raw = format_string_snippet.starts_with('r'); diff --git a/clippy_utils/Cargo.toml b/clippy_utils/Cargo.toml index 9fefd94d339..629ce9d04d4 100644 --- a/clippy_utils/Cargo.toml +++ b/clippy_utils/Cargo.toml @@ -8,7 +8,6 @@ publish = false clippy_config = { path = "../clippy_config" } arrayvec = { version = "0.7", default-features = false } itertools = "0.12" -rustc-semver = "1.1" # FIXME(f16_f128): remove when no longer needed for parsing rustc_apfloat = "0.2.0" diff --git a/clippy_utils/src/attrs.rs b/clippy_utils/src/attrs.rs index d2200bcf710..42c8b218d14 100644 --- a/clippy_utils/src/attrs.rs +++ b/clippy_utils/src/attrs.rs @@ -7,7 +7,7 @@ use rustc_session::Session; use rustc_span::{sym, Span}; use std::str::FromStr; -use crate::source::snippet_opt; +use crate::source::SpanRangeExt; use crate::tokenize_with_text; /// Deprecation status of attributes known by Clippy. @@ -179,25 +179,23 @@ pub fn has_non_exhaustive_attr(tcx: TyCtxt<'_>, adt: AdtDef<'_>) -> bool { /// Checks if the given span contains a `#[cfg(..)]` attribute pub fn span_contains_cfg(cx: &LateContext<'_>, s: Span) -> bool { - let Some(snip) = snippet_opt(cx, s) else { - // Assume true. This would require either an invalid span, or one which crosses file boundaries. - return true; - }; - let mut iter = tokenize_with_text(&snip); + s.check_source_text(cx, |src| { + let mut iter = tokenize_with_text(src); - // Search for the token sequence [`#`, `[`, `cfg`] - while iter.any(|(t, _)| matches!(t, TokenKind::Pound)) { - let mut iter = iter.by_ref().skip_while(|(t, _)| { - matches!( - t, - TokenKind::Whitespace | TokenKind::LineComment { .. } | TokenKind::BlockComment { .. } - ) - }); - if matches!(iter.next(), Some((TokenKind::OpenBracket, _))) - && matches!(iter.next(), Some((TokenKind::Ident, "cfg"))) - { - return true; + // Search for the token sequence [`#`, `[`, `cfg`] + while iter.any(|(t, _)| matches!(t, TokenKind::Pound)) { + let mut iter = iter.by_ref().skip_while(|(t, _)| { + matches!( + t, + TokenKind::Whitespace | TokenKind::LineComment { .. } | TokenKind::BlockComment { .. } + ) + }); + if matches!(iter.next(), Some((TokenKind::OpenBracket, _))) + && matches!(iter.next(), Some((TokenKind::Ident, "cfg"))) + { + return true; + } } - } - false + false + }) } diff --git a/clippy_utils/src/check_proc_macro.rs b/clippy_utils/src/check_proc_macro.rs index 7f2234b310b..2bd6837d973 100644 --- a/clippy_utils/src/check_proc_macro.rs +++ b/clippy_utils/src/check_proc_macro.rs @@ -123,16 +123,14 @@ fn qpath_search_pat(path: &QPath<'_>) -> (Pat, Pat) { fn path_search_pat(path: &Path<'_>) -> (Pat, Pat) { let (head, tail) = match path.segments { - [head, .., tail] => (head, tail), - [p] => (p, p), [] => return (Pat::Str(""), Pat::Str("")), + [p] => (Pat::Sym(p.ident.name), p), + // QPath::Resolved can have a path that looks like `::baz` where + // the path (`Bar::baz`) has it's span covering the whole QPath. + [.., tail] => (Pat::Str(""), tail), }; ( - if head.ident.name == kw::PathRoot { - Pat::Str("::") - } else { - Pat::Sym(head.ident.name) - }, + head, if tail.args.is_some() { Pat::Str(">") } else { diff --git a/clippy_utils/src/consts.rs b/clippy_utils/src/consts.rs index e907e4058e5..760d5bc95f7 100644 --- a/clippy_utils/src/consts.rs +++ b/clippy_utils/src/consts.rs @@ -687,7 +687,7 @@ impl<'tcx> ConstEvalCtxt<'tcx> { if let Some(expr_span) = walk_span_to_context(expr.span, span.ctxt) && let expr_lo = expr_span.lo() && expr_lo >= span.lo - && let Some(src) = (span.lo..expr_lo).get_source_text(&self.tcx) + && let Some(src) = (span.lo..expr_lo).get_source_range(&self.tcx) && let Some(src) = src.as_str() { use rustc_lexer::TokenKind::{BlockComment, LineComment, OpenBrace, Semi, Whitespace}; diff --git a/clippy_utils/src/hir_utils.rs b/clippy_utils/src/hir_utils.rs index f325e4eaf15..f61ef9ac1b0 100644 --- a/clippy_utils/src/hir_utils.rs +++ b/clippy_utils/src/hir_utils.rs @@ -1,6 +1,6 @@ use crate::consts::ConstEvalCtxt; use crate::macros::macro_backtrace; -use crate::source::{snippet_opt, walk_span_to_context, SpanRange, SpanRangeExt}; +use crate::source::{walk_span_to_context, SpanRange, SpanRangeExt}; use crate::tokenize_with_text; use rustc_ast::ast::InlineAsmTemplatePiece; use rustc_data_structures::fx::FxHasher; @@ -588,10 +588,9 @@ fn reduce_exprkind<'hir>(cx: &LateContext<'_>, kind: &'hir ExprKind<'hir>) -> &' // block with an empty span. ([], None) if block.span.is_empty() => &ExprKind::Tup(&[]), // `{}` => `()` - ([], None) => match snippet_opt(cx, block.span) { - // Don't reduce if there are any tokens contained in the braces - Some(snip) - if tokenize(&snip) + ([], None) + if block.span.check_source_text(cx, |src| { + tokenize(src) .map(|t| t.kind) .filter(|t| { !matches!( @@ -599,11 +598,10 @@ fn reduce_exprkind<'hir>(cx: &LateContext<'_>, kind: &'hir ExprKind<'hir>) -> &' TokenKind::LineComment { .. } | TokenKind::BlockComment { .. } | TokenKind::Whitespace ) }) - .ne([TokenKind::OpenBrace, TokenKind::CloseBrace].iter().copied()) => - { - kind - }, - _ => &ExprKind::Tup(&[]), + .eq([TokenKind::OpenBrace, TokenKind::CloseBrace].iter().copied()) + }) => + { + &ExprKind::Tup(&[]) }, ([], Some(expr)) => match expr.kind { // `{ return .. }` => `return ..` @@ -1191,9 +1189,9 @@ fn eq_span_tokens( pred: impl Fn(TokenKind) -> bool, ) -> bool { fn f(cx: &LateContext<'_>, left: Range, right: Range, pred: impl Fn(TokenKind) -> bool) -> bool { - if let Some(lsrc) = left.get_source_text(cx) + if let Some(lsrc) = left.get_source_range(cx) && let Some(lsrc) = lsrc.as_str() - && let Some(rsrc) = right.get_source_text(cx) + && let Some(rsrc) = right.get_source_range(cx) && let Some(rsrc) = rsrc.as_str() { let pred = |t: &(_, _)| pred(t.0); diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 28755ae0710..5db14872c36 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -149,6 +149,7 @@ macro_rules! extract_msrv_attr { /// If the given expression is a local binding, find the initializer expression. /// If that initializer expression is another local binding, find its initializer again. +/// /// This process repeats as long as possible (but usually no more than once). Initializer /// expressions with adjustments are ignored. If this is not desired, use [`find_binding_init`] /// instead. @@ -179,6 +180,7 @@ pub fn expr_or_init<'a, 'b, 'tcx: 'b>(cx: &LateContext<'tcx>, mut expr: &'a Expr } /// Finds the initializer expression for a local binding. Returns `None` if the binding is mutable. +/// /// By only considering immutable bindings, we guarantee that the returned expression represents the /// value of the binding wherever it is referenced. /// @@ -431,12 +433,12 @@ pub fn qpath_generic_tys<'tcx>(qpath: &QPath<'tcx>) -> impl Iterator( path_def_id(cx, maybe_path).map_or(false, |id| cx.tcx.is_diagnostic_item(diag_item, id)) } -/// THIS METHOD IS DEPRECATED and will eventually be removed since it does not match against the +/// THIS METHOD IS DEPRECATED. Matches a `Path` against a slice of segment string literals. +/// +/// This method is deprecated and will eventually be removed since it does not match against the /// entire path or resolved `DefId`. Prefer using `match_def_path`. Consider getting a `DefId` from /// `QPath::Resolved.1.res.opt_def_id()`. /// -/// Matches a `Path` against a slice of segment string literals. -/// /// There is also `match_qpath` if you are dealing with a `rustc_hir::QPath` instead of a /// `rustc_hir::Path`. /// @@ -905,6 +907,7 @@ pub fn is_default_equivalent_call(cx: &LateContext<'_>, repl_func: &Expr<'_>) -> } /// Returns true if the expr is equal to `Default::default()` of it's type when evaluated. +/// /// It doesn't cover all cases, for example indirect function calls (some of std /// functions are supported) but it is the best we have. pub fn is_default_equivalent(cx: &LateContext<'_>, e: &Expr<'_>) -> bool { @@ -1061,6 +1064,7 @@ impl std::ops::BitOrAssign for CaptureKind { } /// Given an expression referencing a local, determines how it would be captured in a closure. +/// /// Note as this will walk up to parent expressions until the capture can be determined it should /// only be used while making a closure somewhere a value is consumed. e.g. a block, match arm, or /// function argument (other than a receiver). @@ -2365,8 +2369,9 @@ pub fn fn_def_id_with_node_args<'tcx>( } /// Returns `Option` where String is a textual representation of the type encapsulated in -/// the slice iff the given expression is a slice of primitives (as defined in the -/// `is_recursively_primitive_type` function) and `None` otherwise. +/// the slice iff the given expression is a slice of primitives. +/// +/// (As defined in the `is_recursively_primitive_type` function.) Returns `None` otherwise. pub fn is_slice_of_primitives(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option { let expr_type = cx.typeck_results().expr_ty_adjusted(expr); let expr_kind = expr_type.kind(); diff --git a/clippy_utils/src/macros.rs b/clippy_utils/src/macros.rs index 455239cc37f..1d7479bff82 100644 --- a/clippy_utils/src/macros.rs +++ b/clippy_utils/src/macros.rs @@ -150,10 +150,11 @@ pub fn first_node_macro_backtrace(cx: &LateContext<'_>, node: &impl HirNode) -> } /// If `node` is the "first node" in a macro expansion, returns `Some` with the `ExpnId` of the -/// macro call site (i.e. the parent of the macro expansion). This generally means that `node` -/// is the outermost node of an entire macro expansion, but there are some caveats noted below. -/// This is useful for finding macro calls while visiting the HIR without processing the macro call -/// at every node within its expansion. +/// macro call site (i.e. the parent of the macro expansion). +/// +/// This generally means that `node` is the outermost node of an entire macro expansion, but there +/// are some caveats noted below. This is useful for finding macro calls while visiting the HIR +/// without processing the macro call at every node within its expansion. /// /// If you already have immediate access to the parent node, it is simpler to /// just check the context of that span directly (e.g. `parent.span.from_expansion()`). @@ -426,12 +427,8 @@ impl FormatArgsStorage { } } -/// Attempt to find the [`rustc_hir::Expr`] that corresponds to the [`FormatArgument`]'s value, if -/// it cannot be found it will return the [`rustc_ast::Expr`]. -pub fn find_format_arg_expr<'hir, 'ast>( - start: &'hir Expr<'hir>, - target: &'ast FormatArgument, -) -> Result<&'hir Expr<'hir>, &'ast rustc_ast::Expr> { +/// Attempt to find the [`rustc_hir::Expr`] that corresponds to the [`FormatArgument`]'s value +pub fn find_format_arg_expr<'hir>(start: &'hir Expr<'hir>, target: &FormatArgument) -> Option<&'hir Expr<'hir>> { let SpanData { lo, hi, @@ -449,7 +446,6 @@ pub fn find_format_arg_expr<'hir, 'ast>( ControlFlow::Continue(()) } }) - .ok_or(&target.expr) } /// Span of the `:` and format specifiers diff --git a/clippy_utils/src/qualify_min_const_fn.rs b/clippy_utils/src/qualify_min_const_fn.rs index 95fbf0b2ea2..d9befb3c157 100644 --- a/clippy_utils/src/qualify_min_const_fn.rs +++ b/clippy_utils/src/qualify_min_const_fn.rs @@ -18,7 +18,6 @@ use rustc_middle::mir::{ use rustc_middle::traits::{BuiltinImplSource, ImplSource, ObligationCause}; use rustc_middle::ty::adjustment::PointerCoercion; use rustc_middle::ty::{self, GenericArgKind, TraitRef, Ty, TyCtxt}; -use rustc_semver::RustcVersion; use rustc_span::symbol::sym; use rustc_span::Span; use rustc_trait_selection::traits::{ObligationCtxt, SelectionContext}; @@ -391,11 +390,7 @@ fn is_const_fn(tcx: TyCtxt<'_>, def_id: DefId, msrv: &Msrv) -> bool { StableSince::Err => return false, }; - msrv.meets(RustcVersion::new( - u32::from(const_stab_rust_version.major), - u32::from(const_stab_rust_version.minor), - u32::from(const_stab_rust_version.patch), - )) + msrv.meets(const_stab_rust_version) } else { // Unstable const fn with the feature enabled. msrv.current().is_none() diff --git a/clippy_utils/src/source.rs b/clippy_utils/src/source.rs index 96dd3c55d37..482e1e0147b 100644 --- a/clippy_utils/src/source.rs +++ b/clippy_utils/src/source.rs @@ -16,7 +16,7 @@ use rustc_span::{ }; use std::borrow::Cow; use std::fmt; -use std::ops::Range; +use std::ops::{Deref, Index, Range}; pub trait HasSession { fn sess(&self) -> &Session; @@ -94,10 +94,16 @@ impl IntoSpan for Range { } pub trait SpanRangeExt: SpanRange { + /// Attempts to get a handle to the source text. Returns `None` if either the span is malformed, + /// or the source text is not accessible. + fn get_source_text(self, cx: &impl HasSession) -> Option { + get_source_range(cx.sess().source_map(), self.into_range()).and_then(SourceText::new) + } + /// Gets the source file, and range in the file, of the given span. Returns `None` if the span /// extends through multiple files, or is malformed. - fn get_source_text(self, cx: &impl HasSession) -> Option { - get_source_text(cx.sess().source_map(), self.into_range()) + fn get_source_range(self, cx: &impl HasSession) -> Option { + get_source_range(cx.sess().source_map(), self.into_range()) } /// Calls the given function with the source text referenced and returns the value. Returns @@ -144,32 +150,70 @@ pub trait SpanRangeExt: SpanRange { fn trim_start(self, cx: &impl HasSession) -> Range { trim_start(cx.sess().source_map(), self.into_range()) } - - /// Writes the referenced source text to the given writer. Will return `Err` if the source text - /// could not be retrieved. - fn write_source_text_to(self, cx: &impl HasSession, dst: &mut impl fmt::Write) -> fmt::Result { - write_source_text_to(cx.sess().source_map(), self.into_range(), dst) - } - - /// Extracts the referenced source text as an owned string. - fn source_text_to_string(self, cx: &impl HasSession) -> Option { - self.with_source_text(cx, ToOwned::to_owned) - } } impl SpanRangeExt for T {} -fn get_source_text(sm: &SourceMap, sp: Range) -> Option { +/// Handle to a range of text in a source file. +pub struct SourceText(SourceFileRange); +impl SourceText { + /// Takes ownership of the source file handle if the source text is accessible. + pub fn new(text: SourceFileRange) -> Option { + if text.as_str().is_some() { + Some(Self(text)) + } else { + None + } + } + + /// Gets the source text. + pub fn as_str(&self) -> &str { + self.0.as_str().unwrap() + } + + /// Converts this into an owned string. + pub fn to_owned(&self) -> String { + self.as_str().to_owned() + } +} +impl Deref for SourceText { + type Target = str; + fn deref(&self) -> &Self::Target { + self.as_str() + } +} +impl AsRef for SourceText { + fn as_ref(&self) -> &str { + self.as_str() + } +} +impl Index for SourceText +where + str: Index, +{ + type Output = >::Output; + fn index(&self, idx: T) -> &Self::Output { + &self.as_str()[idx] + } +} +impl fmt::Display for SourceText { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.as_str().fmt(f) + } +} + +fn get_source_range(sm: &SourceMap, sp: Range) -> Option { let start = sm.lookup_byte_offset(sp.start); let end = sm.lookup_byte_offset(sp.end); if !Lrc::ptr_eq(&start.sf, &end.sf) || start.pos > end.pos { return None; } + sm.ensure_source_file_source_present(&start.sf); let range = start.pos.to_usize()..end.pos.to_usize(); Some(SourceFileRange { sf: start.sf, range }) } fn with_source_text(sm: &SourceMap, sp: Range, f: impl for<'a> FnOnce(&'a str) -> T) -> Option { - if let Some(src) = get_source_text(sm, sp) + if let Some(src) = get_source_range(sm, sp) && let Some(src) = src.as_str() { Some(f(src)) @@ -183,7 +227,7 @@ fn with_source_text_and_range( sp: Range, f: impl for<'a> FnOnce(&'a str, Range) -> T, ) -> Option { - if let Some(src) = get_source_text(sm, sp) + if let Some(src) = get_source_range(sm, sp) && let Some(text) = &src.sf.src { Some(f(text, src.range)) @@ -198,7 +242,7 @@ fn map_range( sp: Range, f: impl for<'a> FnOnce(&'a str, Range) -> Option>, ) -> Option> { - if let Some(src) = get_source_text(sm, sp.clone()) + if let Some(src) = get_source_range(sm, sp.clone()) && let Some(text) = &src.sf.src && let Some(range) = f(text, src.range.clone()) { @@ -232,13 +276,6 @@ fn trim_start(sm: &SourceMap, sp: Range) -> Range { .unwrap_or(sp) } -fn write_source_text_to(sm: &SourceMap, sp: Range, dst: &mut impl fmt::Write) -> fmt::Result { - match with_source_text(sm, sp, |src| dst.write_str(src)) { - Some(x) => x, - None => Err(fmt::Error), - } -} - pub struct SourceFileRange { pub sf: Lrc, pub range: Range, @@ -247,7 +284,11 @@ impl SourceFileRange { /// Attempts to get the text from the source file. This can fail if the source text isn't /// loaded. pub fn as_str(&self) -> Option<&str> { - self.sf.src.as_ref().and_then(|x| x.get(self.range.clone())) + self.sf + .src + .as_ref() + .or_else(|| self.sf.external_src.get().and_then(|src| src.get_source())) + .and_then(|x| x.get(self.range.clone())) } } @@ -548,9 +589,10 @@ pub fn snippet_block_with_context<'a>( (reindent_multiline(snip, true, indent), from_macro) } -/// Same as `snippet_with_applicability`, but first walks the span up to the given context. This -/// will result in the macro call, rather than the expansion, if the span is from a child context. -/// If the span is not from a child context, it will be used directly instead. +/// Same as `snippet_with_applicability`, but first walks the span up to the given context. +/// +/// This will result in the macro call, rather than the expansion, if the span is from a child +/// context. If the span is not from a child context, it will be used directly instead. /// /// e.g. Given the expression `&vec![]`, getting a snippet from the span for `vec![]` as a HIR node /// would result in `box []`. If given the context of the address of expression, this function will @@ -593,9 +635,10 @@ fn snippet_with_context_sess<'a>( } /// Walks the span up to the target context, thereby returning the macro call site if the span is -/// inside a macro expansion, or the original span if it is not. Note this will return `None` in the -/// case of the span being in a macro expansion, but the target context is from expanding a macro -/// argument. +/// inside a macro expansion, or the original span if it is not. +/// +/// Note this will return `None` in the case of the span being in a macro expansion, but the target +/// context is from expanding a macro argument. /// /// Given the following /// diff --git a/clippy_utils/src/ty.rs b/clippy_utils/src/ty.rs index 2f6faba073e..f80981c11af 100644 --- a/clippy_utils/src/ty.rs +++ b/clippy_utils/src/ty.rs @@ -160,8 +160,10 @@ pub fn get_type_diagnostic_name(cx: &LateContext<'_>, ty: Ty<'_>) -> Option, ty: Ty<'_>) -> bool { matches!( get_type_diagnostic_name(cx, ty), @@ -398,8 +400,10 @@ fn is_normalizable_helper<'tcx>( } /// Returns `true` if the given type is a non aggregate primitive (a `bool` or `char`, any -/// integer or floating-point number type). For checking aggregation of primitive types (e.g. -/// tuples and slices of primitive type) see `is_recursively_primitive_type` +/// integer or floating-point number type). +/// +/// For checking aggregation of primitive types (e.g. tuples and slices of primitive type) see +/// `is_recursively_primitive_type` pub fn is_non_aggregate_primitive_type(ty: Ty<'_>) -> bool { matches!(ty.kind(), ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_)) } @@ -455,11 +459,6 @@ pub fn is_type_lang_item(cx: &LateContext<'_>, ty: Ty<'_>, lang_item: LangItem) } } -/// Gets the diagnostic name of the type, if it has one -pub fn type_diagnostic_name(cx: &LateContext<'_>, ty: Ty<'_>) -> Option { - ty.ty_adt_def().and_then(|adt| cx.tcx.get_diagnostic_name(adt.did())) -} - /// Return `true` if the passed `typ` is `isize` or `usize`. pub fn is_isize_or_usize(typ: Ty<'_>) -> bool { matches!(typ.kind(), ty::Int(IntTy::Isize) | ty::Uint(UintTy::Usize)) @@ -476,9 +475,10 @@ pub fn match_type(cx: &LateContext<'_>, ty: Ty<'_>, path: &[&str]) -> bool { } } -/// Checks if the drop order for a type matters. Some std types implement drop solely to -/// deallocate memory. For these types, and composites containing them, changing the drop order -/// won't result in any observable side effects. +/// Checks if the drop order for a type matters. +/// +/// Some std types implement drop solely to deallocate memory. For these types, and composites +/// containing them, changing the drop order won't result in any observable side effects. pub fn needs_ordered_drop<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { fn needs_ordered_drop_inner<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, seen: &mut FxHashSet>) -> bool { if !seen.insert(ty) { @@ -1311,6 +1311,7 @@ pub fn deref_chain<'cx, 'tcx>(cx: &'cx LateContext<'tcx>, ty: Ty<'tcx>) -> impl } /// Checks if a Ty<'_> has some inherent method Symbol. +/// /// This does not look for impls in the type's `Deref::Target` type. /// If you need this, you should wrap this call in `clippy_utils::ty::deref_chain().any(...)`. pub fn get_adt_inherent_method<'a>(cx: &'a LateContext<'_>, ty: Ty<'_>, method_name: Symbol) -> Option<&'a AssocItem> { diff --git a/declare_clippy_lint/src/lib.rs b/declare_clippy_lint/src/lib.rs index ca070f6c250..6aa24329b06 100644 --- a/declare_clippy_lint/src/lib.rs +++ b/declare_clippy_lint/src/lib.rs @@ -1,4 +1,4 @@ -#![feature(let_chains)] +#![feature(let_chains, proc_macro_span)] // warn on lints, that are included in `rust-lang/rust`s bootstrap #![warn(rust_2018_idioms, unused_lifetimes)] @@ -23,6 +23,7 @@ fn parse_attr(path: [&'static str; LEN], attr: &Attribute) -> struct ClippyLint { attrs: Vec, + version: Option, explanation: String, name: Ident, category: Ident, @@ -41,8 +42,14 @@ impl Parse for ClippyLint { let value = lit.value(); let line = value.strip_prefix(' ').unwrap_or(&value); - if line.starts_with("```") { - explanation += "```\n"; + if let Some(lang) = line.strip_prefix("```") { + let tag = lang.split_once(',').map_or(lang, |(left, _)| left); + if !in_code && matches!(tag, "" | "rust" | "ignore" | "should_panic" | "no_run" | "compile_fail") { + explanation += "```rust\n"; + } else { + explanation += line; + explanation.push('\n'); + } in_code = !in_code; } else if !(in_code && line.starts_with("# ")) { explanation += line; @@ -68,6 +75,7 @@ impl Parse for ClippyLint { Ok(Self { attrs, + version, explanation, name, category, @@ -123,6 +131,7 @@ impl Parse for ClippyLint { pub fn declare_clippy_lint(input: TokenStream) -> TokenStream { let ClippyLint { attrs, + version, explanation, name, category, @@ -146,6 +155,14 @@ pub fn declare_clippy_lint(input: TokenStream) -> TokenStream { (&mut category[0..1]).make_ascii_uppercase(); let category_variant = format_ident!("{category}"); + let name_span = name.span().unwrap(); + let location = format!("{}#L{}", name_span.source_file().path().display(), name_span.line()); + + let version = match version { + Some(version) => quote!(Some(#version)), + None => quote!(None), + }; + let output = quote! { rustc_session::declare_tool_lint! { #(#attrs)* @@ -159,6 +176,8 @@ pub fn declare_clippy_lint(input: TokenStream) -> TokenStream { lint: &#name, category: crate::LintCategory::#category_variant, explanation: #explanation, + location: #location, + version: #version, }; }; diff --git a/lintcheck/src/json.rs b/lintcheck/src/json.rs index 4211bce90b2..ee0c80aea52 100644 --- a/lintcheck/src/json.rs +++ b/lintcheck/src/json.rs @@ -12,21 +12,21 @@ const TRUNCATION_TOTAL_TARGET: usize = 1000; #[derive(Debug, Deserialize, Serialize)] struct LintJson { - lint: String, - krate: String, - file_name: String, - byte_pos: (u32, u32), - file_link: String, + /// The lint name e.g. `clippy::bytes_nth` + name: String, + /// The filename and line number e.g. `anyhow-1.0.86/src/error.rs:42` + file_line: String, + file_url: String, rendered: String, } impl LintJson { fn key(&self) -> impl Ord + '_ { - (self.lint.as_str(), self.file_name.as_str(), self.byte_pos) + (self.name.as_str(), self.file_line.as_str()) } fn info_text(&self, action: &str) -> String { - format!("{action} `{}` in `{}` at {}", self.lint, self.krate, self.file_link) + format!("{action} `{}` at [`{}`]({})", self.name, self.file_line, self.file_url) } } @@ -36,13 +36,16 @@ pub(crate) fn output(clippy_warnings: Vec) -> String { .into_iter() .map(|warning| { let span = warning.span(); + let file_name = span + .file_name + .strip_prefix("target/lintcheck/sources/") + .unwrap_or(&span.file_name); + let file_line = format!("{file_name}:{}", span.line_start); LintJson { - file_name: span.file_name.clone(), - byte_pos: (span.byte_start, span.byte_end), - krate: warning.krate, - file_link: warning.url, - lint: warning.lint, - rendered: warning.diag.rendered.unwrap(), + name: warning.name, + file_line, + file_url: warning.url, + rendered: warning.diag.rendered.unwrap().trim().to_string(), } }) .collect(); @@ -63,7 +66,7 @@ pub(crate) fn diff(old_path: &Path, new_path: &Path, truncate: bool) { let mut lint_warnings = vec![]; for (name, changes) in &itertools::merge_join_by(old_warnings, new_warnings, |old, new| old.key().cmp(&new.key())) - .chunk_by(|change| change.as_ref().into_left().lint.to_string()) + .chunk_by(|change| change.as_ref().into_left().name.clone()) { let mut added = Vec::new(); let mut removed = Vec::new(); @@ -162,7 +165,7 @@ fn print_warnings(title: &str, warnings: &[LintJson], truncate_after: usize) { return; } - print_h3(&warnings[0].lint, title); + print_h3(&warnings[0].name, title); println!(); let warnings = truncate(warnings, truncate_after); @@ -171,7 +174,7 @@ fn print_warnings(title: &str, warnings: &[LintJson], truncate_after: usize) { println!("{}", warning.info_text(title)); println!(); println!("```"); - println!("{}", warning.rendered.trim_end()); + println!("{}", warning.rendered); println!("```"); println!(); } @@ -182,7 +185,7 @@ fn print_changed_diff(changed: &[(LintJson, LintJson)], truncate_after: usize) { return; } - print_h3(&changed[0].0.lint, "Changed"); + print_h3(&changed[0].0.name, "Changed"); println!(); let changed = truncate(changed, truncate_after); @@ -191,7 +194,7 @@ fn print_changed_diff(changed: &[(LintJson, LintJson)], truncate_after: usize) { println!("{}", new.info_text("Changed")); println!(); println!("```diff"); - for change in diff::lines(old.rendered.trim_end(), new.rendered.trim_end()) { + for change in diff::lines(&old.rendered, &new.rendered) { use diff::Result::{Both, Left, Right}; match change { diff --git a/lintcheck/src/output.rs b/lintcheck/src/output.rs index 15378630695..e38036315c2 100644 --- a/lintcheck/src/output.rs +++ b/lintcheck/src/output.rs @@ -51,7 +51,7 @@ impl RustcIce { /// A single warning that clippy issued while checking a `Crate` #[derive(Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] pub struct ClippyWarning { - pub lint: String, + pub name: String, pub diag: Diagnostic, pub krate: String, /// The URL that points to the file and line of the lint emission @@ -60,8 +60,8 @@ pub struct ClippyWarning { impl ClippyWarning { pub fn new(mut diag: Diagnostic, base_url: &str, krate: &str) -> Option { - let lint = diag.code.clone()?.code; - if !(lint.contains("clippy") || diag.message.contains("clippy")) + let name = diag.code.clone()?.code; + if !(name.contains("clippy") || diag.message.contains("clippy")) || diag.message.contains("could not read cargo metadata") { return None; @@ -92,7 +92,7 @@ impl ClippyWarning { }; Some(Self { - lint, + name, diag, url, krate: krate.to_string(), @@ -108,7 +108,7 @@ impl ClippyWarning { let mut file = span.file_name.clone(); let file_with_pos = format!("{file}:{}:{}", span.line_start, span.line_end); match format { - OutputFormat::Text => format!("{file_with_pos} {} \"{}\"\n", self.lint, self.diag.message), + OutputFormat::Text => format!("{file_with_pos} {} \"{}\"\n", self.name, self.diag.message), OutputFormat::Markdown => { if file.starts_with("target") { file.insert_str(0, "../"); @@ -116,7 +116,7 @@ impl ClippyWarning { let mut output = String::from("| "); write!(output, "[`{file_with_pos}`]({file}#L{})", span.line_start).unwrap(); - write!(output, r#" | `{:<50}` | "{}" |"#, self.lint, self.diag.message).unwrap(); + write!(output, r#" | `{:<50}` | "{}" |"#, self.name, self.diag.message).unwrap(); output.push('\n'); output }, @@ -164,7 +164,7 @@ fn gather_stats(warnings: &[ClippyWarning]) -> (String, HashMap<&String, usize>) let mut counter: HashMap<&String, usize> = HashMap::new(); warnings .iter() - .for_each(|wrn| *counter.entry(&wrn.lint).or_insert(0) += 1); + .for_each(|wrn| *counter.entry(&wrn.name).or_insert(0) += 1); // collect into a tupled list for sorting let mut stats: Vec<(&&String, &usize)> = counter.iter().collect(); diff --git a/rust-toolchain b/rust-toolchain index 5fbe4e544a9..0be2e81810e 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,4 +1,4 @@ [toolchain] -channel = "nightly-2024-08-08" +channel = "nightly-2024-08-23" components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"] profile = "minimal" diff --git a/tests/compile-test.rs b/tests/compile-test.rs index 64253514fbe..9754254cdd0 100644 --- a/tests/compile-test.rs +++ b/tests/compile-test.rs @@ -1,25 +1,31 @@ -// We need this feature as it changes `dylib` linking behavior and allows us to link to -// `rustc_driver`. -#![feature(rustc_private)] +#![feature(rustc_private, let_chains)] #![warn(rust_2018_idioms, unused_lifetimes)] #![allow(unused_extern_crates)] +use cargo_metadata::diagnostic::{Applicability, Diagnostic}; +use cargo_metadata::Message; +use clippy_config::ClippyConfiguration; +use clippy_lints::declared_lints::LINTS; +use clippy_lints::deprecated_lints::{DEPRECATED, DEPRECATED_VERSION, RENAMED}; +use clippy_lints::LintInfo; +use serde::{Deserialize, Serialize}; +use test_utils::IS_RUSTC_TEST_SUITE; use ui_test::custom_flags::rustfix::RustfixMode; +use ui_test::custom_flags::Flag; use ui_test::spanned::Spanned; +use ui_test::test_result::TestRun; use ui_test::{status_emitter, Args, CommandBuilder, Config, Match, OutputConflictHandling}; -use std::collections::BTreeMap; +use std::collections::{BTreeMap, HashMap}; use std::env::{self, set_var, var_os}; use std::ffi::{OsStr, OsString}; -use std::fs; +use std::fmt::Write; use std::path::{Path, PathBuf}; -use std::sync::LazyLock; -use test_utils::IS_RUSTC_TEST_SUITE; +use std::sync::mpsc::{channel, Sender}; +use std::{fs, iter, thread}; // Test dependencies may need an `extern crate` here to ensure that they show up // in the depinfo file (otherwise cargo thinks they are unused) -extern crate clippy_lints; -extern crate clippy_utils; extern crate futures; extern crate if_chain; extern crate itertools; @@ -55,7 +61,7 @@ static TEST_DEPENDENCIES: &[&str] = &[ /// dependencies must be added to Cargo.toml at the project root. Test /// dependencies that are not *directly* used by this test module require an /// `extern crate` declaration. -static EXTERN_FLAGS: LazyLock> = LazyLock::new(|| { +fn extern_flags() -> Vec { let current_exe_depinfo = { let mut path = env::current_exe().unwrap(); path.set_extension("d"); @@ -103,70 +109,93 @@ static EXTERN_FLAGS: LazyLock> = LazyLock::new(|| { .into_iter() .map(|(name, path)| format!("--extern={name}={path}")) .collect() -}); +} // whether to run internal tests or not const RUN_INTERNAL_TESTS: bool = cfg!(feature = "internal"); -fn base_config(test_dir: &str) -> (Config, Args) { - let mut args = Args::test().unwrap(); - args.bless |= var_os("RUSTC_BLESS").is_some_and(|v| v != "0"); - - let target_dir = PathBuf::from(var_os("CARGO_TARGET_DIR").unwrap_or_else(|| "target".into())); - let mut config = Config { - output_conflict_handling: OutputConflictHandling::Error, - filter_files: env::var("TESTNAME") - .map(|filters| filters.split(',').map(str::to_string).collect()) - .unwrap_or_default(), - target: None, - bless_command: Some("cargo uibless".into()), - out_dir: target_dir.join("ui_test"), - ..Config::rustc(Path::new("tests").join(test_dir)) - }; - config.comment_defaults.base().exit_status = None.into(); - config.comment_defaults.base().require_annotations = None.into(); - config - .comment_defaults - .base() - .set_custom("rustfix", RustfixMode::Everything); - config.comment_defaults.base().diagnostic_code_prefix = Some(Spanned::dummy("clippy::".into())).into(); - config.with_args(&args); - let current_exe_path = env::current_exe().unwrap(); - let deps_path = current_exe_path.parent().unwrap(); - let profile_path = deps_path.parent().unwrap(); - - config.program.args.extend( - [ - "--emit=metadata", - "-Aunused", - "-Ainternal_features", - "-Zui-testing", - "-Zdeduplicate-diagnostics=no", - "-Dwarnings", - &format!("-Ldependency={}", deps_path.display()), - ] - .map(OsString::from), - ); - - config.program.args.extend(EXTERN_FLAGS.iter().map(OsString::from)); - // Prevent rustc from creating `rustc-ice-*` files the console output is enough. - config.program.envs.push(("RUSTC_ICE".into(), Some("0".into()))); - - if let Some(host_libs) = option_env!("HOST_LIBS") { - let dep = format!("-Ldependency={}", Path::new(host_libs).join("deps").display()); - config.program.args.push(dep.into()); - } - - config.program.program = profile_path.join(if cfg!(windows) { - "clippy-driver.exe" - } else { - "clippy-driver" - }); - (config, args) +struct TestContext { + args: Args, + extern_flags: Vec, + diagnostic_collector: Option, + collector_thread: Option>, } -fn run_ui() { - let (mut config, args) = base_config("ui"); +impl TestContext { + fn new() -> Self { + let mut args = Args::test().unwrap(); + args.bless |= var_os("RUSTC_BLESS").is_some_and(|v| v != "0"); + let (diagnostic_collector, collector_thread) = var_os("COLLECT_METADATA") + .is_some() + .then(DiagnosticCollector::spawn) + .unzip(); + Self { + args, + extern_flags: extern_flags(), + diagnostic_collector, + collector_thread, + } + } + + fn base_config(&self, test_dir: &str) -> Config { + let target_dir = PathBuf::from(var_os("CARGO_TARGET_DIR").unwrap_or_else(|| "target".into())); + let mut config = Config { + output_conflict_handling: OutputConflictHandling::Error, + filter_files: env::var("TESTNAME") + .map(|filters| filters.split(',').map(str::to_string).collect()) + .unwrap_or_default(), + target: None, + bless_command: Some("cargo uibless".into()), + out_dir: target_dir.join("ui_test"), + ..Config::rustc(Path::new("tests").join(test_dir)) + }; + let defaults = config.comment_defaults.base(); + defaults.exit_status = None.into(); + defaults.require_annotations = None.into(); + defaults.diagnostic_code_prefix = Some(Spanned::dummy("clippy::".into())).into(); + defaults.set_custom("rustfix", RustfixMode::Everything); + if let Some(collector) = self.diagnostic_collector.clone() { + defaults.set_custom("diagnostic-collector", collector); + } + config.with_args(&self.args); + let current_exe_path = env::current_exe().unwrap(); + let deps_path = current_exe_path.parent().unwrap(); + let profile_path = deps_path.parent().unwrap(); + + config.program.args.extend( + [ + "--emit=metadata", + "-Aunused", + "-Ainternal_features", + "-Zui-testing", + "-Zdeduplicate-diagnostics=no", + "-Dwarnings", + &format!("-Ldependency={}", deps_path.display()), + ] + .map(OsString::from), + ); + + config.program.args.extend(self.extern_flags.iter().map(OsString::from)); + // Prevent rustc from creating `rustc-ice-*` files the console output is enough. + config.program.envs.push(("RUSTC_ICE".into(), Some("0".into()))); + + if let Some(host_libs) = option_env!("HOST_LIBS") { + let dep = format!("-Ldependency={}", Path::new(host_libs).join("deps").display()); + config.program.args.push(dep.into()); + } + + config.program.program = profile_path.join(if cfg!(windows) { + "clippy-driver.exe" + } else { + "clippy-driver" + }); + + config + } +} + +fn run_ui(cx: &TestContext) { + let mut config = cx.base_config("ui"); config .program .envs @@ -176,30 +205,29 @@ fn run_ui() { vec![config], ui_test::default_file_filter, ui_test::default_per_file_config, - status_emitter::Text::from(args.format), + status_emitter::Text::from(cx.args.format), ) .unwrap(); } -fn run_internal_tests() { - // only run internal tests with the internal-tests feature +fn run_internal_tests(cx: &TestContext) { if !RUN_INTERNAL_TESTS { return; } - let (mut config, args) = base_config("ui-internal"); + let mut config = cx.base_config("ui-internal"); config.bless_command = Some("cargo uitest --features internal -- -- --bless".into()); ui_test::run_tests_generic( vec![config], ui_test::default_file_filter, ui_test::default_per_file_config, - status_emitter::Text::from(args.format), + status_emitter::Text::from(cx.args.format), ) .unwrap(); } -fn run_ui_toml() { - let (mut config, args) = base_config("ui-toml"); +fn run_ui_toml(cx: &TestContext) { + let mut config = cx.base_config("ui-toml"); config .comment_defaults @@ -217,19 +245,19 @@ fn run_ui_toml() { .envs .push(("CLIPPY_CONF_DIR".into(), Some(path.parent().unwrap().into()))); }, - status_emitter::Text::from(args.format), + status_emitter::Text::from(cx.args.format), ) .unwrap(); } // Allow `Default::default` as `OptWithSpan` is not nameable #[allow(clippy::default_trait_access)] -fn run_ui_cargo() { +fn run_ui_cargo(cx: &TestContext) { if IS_RUSTC_TEST_SUITE { return; } - let (mut config, args) = base_config("ui-cargo"); + let mut config = cx.base_config("ui-cargo"); config.program.input_file_flag = CommandBuilder::cargo().input_file_flag; config.program.out_dir_flag = CommandBuilder::cargo().out_dir_flag; config.program.args = vec!["clippy".into(), "--color".into(), "never".into(), "--quiet".into()]; @@ -264,23 +292,25 @@ fn run_ui_cargo() { .then(|| ui_test::default_any_file_filter(path, config) && !ignored_32bit(path)) }, |_config, _file_contents| {}, - status_emitter::Text::from(args.format), + status_emitter::Text::from(cx.args.format), ) .unwrap(); } fn main() { set_var("CLIPPY_DISABLE_DOCS_LINKS", "true"); + + let cx = TestContext::new(); + // The SPEEDTEST_* env variables can be used to check Clippy's performance on your PR. It runs the // affected test 1000 times and gets the average. if let Ok(speedtest) = std::env::var("SPEEDTEST") { println!("----------- STARTING SPEEDTEST -----------"); let f = match speedtest.as_str() { - "ui" => run_ui as fn(), - "cargo" => run_ui_cargo as fn(), - "toml" => run_ui_toml as fn(), - "internal" => run_internal_tests as fn(), - "ui-cargo-toml-metadata" => ui_cargo_toml_metadata as fn(), + "ui" => run_ui, + "cargo" => run_ui_cargo, + "toml" => run_ui_toml, + "internal" => run_internal_tests, _ => panic!("unknown speedtest: {speedtest} || accepted speedtests are: [ui, cargo, toml, internal]"), }; @@ -297,7 +327,7 @@ fn main() { let mut sum = 0; for _ in 0..iterations { let start = std::time::Instant::now(); - f(); + f(&cx); sum += start.elapsed().as_millis(); } println!( @@ -306,11 +336,17 @@ fn main() { sum / u128::from(iterations) ); } else { - run_ui(); - run_ui_toml(); - run_ui_cargo(); - run_internal_tests(); + run_ui(&cx); + run_ui_toml(&cx); + run_ui_cargo(&cx); + run_internal_tests(&cx); + drop(cx.diagnostic_collector); + ui_cargo_toml_metadata(); + + if let Some(thread) = cx.collector_thread { + thread.join().unwrap(); + } } } @@ -349,3 +385,180 @@ fn ui_cargo_toml_metadata() { ); } } + +#[derive(Deserialize)] +#[serde(untagged)] +enum DiagnosticOrMessage { + Diagnostic(Diagnostic), + Message(Message), +} + +/// Collects applicabilities from the diagnostics produced for each UI test, producing the +/// `util/gh-pages/lints.json` file used by +#[derive(Debug, Clone)] +struct DiagnosticCollector { + sender: Sender>, +} + +impl DiagnosticCollector { + #[allow(clippy::assertions_on_constants)] + fn spawn() -> (Self, thread::JoinHandle<()>) { + assert!(!IS_RUSTC_TEST_SUITE && !RUN_INTERNAL_TESTS); + + let (sender, receiver) = channel::>(); + + let handle = thread::spawn(|| { + let mut applicabilities = HashMap::new(); + + for stderr in receiver { + for line in stderr.split(|&byte| byte == b'\n') { + let diag = match serde_json::from_slice(line) { + Ok(DiagnosticOrMessage::Diagnostic(diag)) => diag, + Ok(DiagnosticOrMessage::Message(Message::CompilerMessage(message))) => message.message, + _ => continue, + }; + + if let Some(lint) = diag.code.as_ref().and_then(|code| code.code.strip_prefix("clippy::")) { + let applicability = applicabilities + .entry(lint.to_string()) + .or_insert(Applicability::Unspecified); + let diag_applicability = diag + .children + .iter() + .flat_map(|child| &child.spans) + .filter_map(|span| span.suggestion_applicability.clone()) + .max_by_key(applicability_ord); + if let Some(diag_applicability) = diag_applicability + && applicability_ord(&diag_applicability) > applicability_ord(applicability) + { + *applicability = diag_applicability; + } + } + } + } + + let configs = clippy_config::get_configuration_metadata(); + let mut metadata: Vec = LINTS + .iter() + .map(|lint| LintMetadata::new(lint, &applicabilities, &configs)) + .chain( + iter::zip(DEPRECATED, DEPRECATED_VERSION) + .map(|((lint, reason), version)| LintMetadata::new_deprecated(lint, reason, version)), + ) + .collect(); + metadata.sort_unstable_by(|a, b| a.id.cmp(&b.id)); + + let json = serde_json::to_string_pretty(&metadata).unwrap(); + fs::write("util/gh-pages/lints.json", json).unwrap(); + }); + + (Self { sender }, handle) + } +} + +fn applicability_ord(applicability: &Applicability) -> u8 { + match applicability { + Applicability::MachineApplicable => 4, + Applicability::HasPlaceholders => 3, + Applicability::MaybeIncorrect => 2, + Applicability::Unspecified => 1, + _ => unimplemented!(), + } +} + +impl Flag for DiagnosticCollector { + fn post_test_action( + &self, + _config: &ui_test::per_test_config::TestConfig<'_>, + _cmd: &mut std::process::Command, + output: &std::process::Output, + _build_manager: &ui_test::build_manager::BuildManager<'_>, + ) -> Result, ui_test::Errored> { + if !output.stderr.is_empty() { + self.sender.send(output.stderr.clone()).unwrap(); + } + Ok(Vec::new()) + } + + fn clone_inner(&self) -> Box { + Box::new(self.clone()) + } + + fn must_be_unique(&self) -> bool { + true + } +} + +#[derive(Debug, Serialize)] +struct LintMetadata { + id: String, + id_location: Option<&'static str>, + group: &'static str, + level: &'static str, + docs: String, + version: &'static str, + applicability: Applicability, +} + +impl LintMetadata { + fn new(lint: &LintInfo, applicabilities: &HashMap, configs: &[ClippyConfiguration]) -> Self { + let name = lint.name_lower(); + let applicability = applicabilities + .get(&name) + .cloned() + .unwrap_or(Applicability::Unspecified); + let past_names = RENAMED + .iter() + .filter(|(_, new_name)| new_name.strip_prefix("clippy::") == Some(&name)) + .map(|(old_name, _)| old_name.strip_prefix("clippy::").unwrap()) + .collect::>(); + let mut docs = lint.explanation.to_string(); + if !past_names.is_empty() { + docs.push_str("\n### Past names\n\n"); + for past_name in past_names { + writeln!(&mut docs, " * {past_name}").unwrap(); + } + } + let configs: Vec<_> = configs + .iter() + .filter(|conf| conf.lints.contains(&name.as_str())) + .collect(); + if !configs.is_empty() { + docs.push_str("\n### Configuration\n\n"); + for config in configs { + writeln!(&mut docs, "{config}").unwrap(); + } + } + Self { + id: name, + id_location: Some(lint.location), + group: lint.category_str(), + level: lint.lint.default_level.as_str(), + docs, + version: lint.version.unwrap(), + applicability, + } + } + + fn new_deprecated(name: &str, reason: &str, version: &'static str) -> Self { + // The reason starts with a lowercase letter and ends without a period. + // This needs to be fixed for the website. + let mut reason = reason.to_owned(); + if let Some(reason) = reason.get_mut(0..1) { + reason.make_ascii_uppercase(); + } + Self { + id: name.strip_prefix("clippy::").unwrap().into(), + 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", + ), + applicability: Applicability::Unspecified, + } + } +} diff --git a/tests/config-metadata.rs b/tests/config-metadata.rs new file mode 100644 index 00000000000..3e3711873ba --- /dev/null +++ b/tests/config-metadata.rs @@ -0,0 +1,78 @@ +#![feature(rustc_private)] + +use clippy_config::{get_configuration_metadata, ClippyConfiguration}; +use itertools::Itertools; +use regex::Regex; +use std::borrow::Cow; +use std::{env, fs}; + +fn metadata() -> impl Iterator { + get_configuration_metadata() + .into_iter() + .filter(|config| config.deprecation_reason.is_none()) + .filter(|config| !config.lints.is_empty()) +} + +#[test] +fn book() { + let path = "book/src/lint_configuration.md"; + let current = fs::read_to_string(path).unwrap(); + + let configs = metadata().map(|conf| conf.to_markdown_paragraph()).join("\n"); + let expected = format!( + r#" + +# Lint Configuration Options + +The following list shows each configuration option, along with a description, its default value, an example +and lints affected. + +--- + +{} +"#, + configs.trim(), + ); + + if current != expected { + if env::var_os("RUSTC_BLESS").is_some_and(|v| v != "0") { + fs::write(path, expected).unwrap(); + } else { + panic!("`{path}` is out of date, run `cargo bless --test config-metadata` to update it"); + } + } +} + +#[test] +fn changelog() { + let path = "CHANGELOG.md"; + let current = fs::read_to_string(path).unwrap(); + + let configs = metadata().map(|conf| conf.to_markdown_link()).join("\n"); + + let re = Regex::new( + "(?s)\ + ()\ + .*\ + ()\ + ", + ) + .unwrap(); + let expected = re.replace(¤t, format!("$1\n{configs}\n$2")); + + assert!( + matches!(expected, Cow::Owned(_)), + "failed to find configuration section in `{path}`" + ); + + if current != expected { + if env::var_os("RUSTC_BLESS").is_some_and(|v| v != "0") { + fs::write(path, expected.as_bytes()).unwrap(); + } else { + panic!("`{path}` is out of date, run `cargo bless --test config-metadata` to update it"); + } + } +} diff --git a/tests/ui-toml/absolute_paths/absolute_paths.allow_crates.stderr b/tests/ui-toml/absolute_paths/absolute_paths.allow_crates.stderr index 1cc1034cd89..d24b0cd6162 100644 --- a/tests/ui-toml/absolute_paths/absolute_paths.allow_crates.stderr +++ b/tests/ui-toml/absolute_paths/absolute_paths.allow_crates.stderr @@ -1,29 +1,44 @@ error: consider bringing this path into scope with the `use` keyword - --> tests/ui-toml/absolute_paths/absolute_paths.rs:40:5 + --> tests/ui-toml/absolute_paths/absolute_paths.rs:14:13 | -LL | std::f32::MAX; - | ^^^^^^^^^^^^^ +LL | let _ = std::path::is_separator(' '); + | ^^^^^^^^^^^^^^^^^^^^^^^ | - = note: `-D clippy::absolute-paths` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::absolute_paths)]` +note: the lint level is defined here + --> tests/ui-toml/absolute_paths/absolute_paths.rs:7:9 + | +LL | #![deny(clippy::absolute_paths)] + | ^^^^^^^^^^^^^^^^^^^^^^ error: consider bringing this path into scope with the `use` keyword - --> tests/ui-toml/absolute_paths/absolute_paths.rs:41:5 + --> tests/ui-toml/absolute_paths/absolute_paths.rs:20:13 | -LL | core::f32::MAX; - | ^^^^^^^^^^^^^^ +LL | let _ = ::std::path::MAIN_SEPARATOR; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: consider bringing this path into scope with the `use` keyword - --> tests/ui-toml/absolute_paths/absolute_paths.rs:42:5 + --> tests/ui-toml/absolute_paths/absolute_paths.rs:25:13 | -LL | ::core::f32::MAX; - | ^^^^^^^^^^^^^^^^ +LL | let _ = std::collections::hash_map::HashMap::::new(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: consider bringing this path into scope with the `use` keyword - --> tests/ui-toml/absolute_paths/absolute_paths.rs:58:5 + --> tests/ui-toml/absolute_paths/absolute_paths.rs:28:31 | -LL | ::std::f32::MAX; - | ^^^^^^^^^^^^^^^ +LL | let _: &std::path::Path = std::path::Path::new(""); + | ^^^^^^^^^^^^^^^ -error: aborting due to 4 previous errors +error: consider bringing this path into scope with the `use` keyword + --> tests/ui-toml/absolute_paths/absolute_paths.rs:28:13 + | +LL | let _: &std::path::Path = std::path::Path::new(""); + | ^^^^^^^^^^^^^^^ + +error: consider bringing this path into scope with the `use` keyword + --> tests/ui-toml/absolute_paths/absolute_paths.rs:43:13 + | +LL | let _ = std::option::Option::None::; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 6 previous errors diff --git a/tests/ui-toml/absolute_paths/absolute_paths.allow_long.stderr b/tests/ui-toml/absolute_paths/absolute_paths.allow_long.stderr new file mode 100644 index 00000000000..0cc6566af3a --- /dev/null +++ b/tests/ui-toml/absolute_paths/absolute_paths.allow_long.stderr @@ -0,0 +1,14 @@ +error: consider bringing this path into scope with the `use` keyword + --> tests/ui-toml/absolute_paths/absolute_paths.rs:25:13 + | +LL | let _ = std::collections::hash_map::HashMap::::new(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: the lint level is defined here + --> tests/ui-toml/absolute_paths/absolute_paths.rs:7:9 + | +LL | #![deny(clippy::absolute_paths)] + | ^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui-toml/absolute_paths/absolute_paths.default.stderr b/tests/ui-toml/absolute_paths/absolute_paths.default.stderr new file mode 100644 index 00000000000..53aa9030e0d --- /dev/null +++ b/tests/ui-toml/absolute_paths/absolute_paths.default.stderr @@ -0,0 +1,80 @@ +error: consider bringing this path into scope with the `use` keyword + --> tests/ui-toml/absolute_paths/absolute_paths.rs:14:13 + | +LL | let _ = std::path::is_separator(' '); + | ^^^^^^^^^^^^^^^^^^^^^^^ + | +note: the lint level is defined here + --> tests/ui-toml/absolute_paths/absolute_paths.rs:7:9 + | +LL | #![deny(clippy::absolute_paths)] + | ^^^^^^^^^^^^^^^^^^^^^^ + +error: consider bringing this path into scope with the `use` keyword + --> tests/ui-toml/absolute_paths/absolute_paths.rs:20:13 + | +LL | let _ = ::std::path::MAIN_SEPARATOR; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: consider bringing this path into scope with the `use` keyword + --> tests/ui-toml/absolute_paths/absolute_paths.rs:25:13 + | +LL | let _ = std::collections::hash_map::HashMap::::new(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: consider bringing this path into scope with the `use` keyword + --> tests/ui-toml/absolute_paths/absolute_paths.rs:28:31 + | +LL | let _: &std::path::Path = std::path::Path::new(""); + | ^^^^^^^^^^^^^^^ + +error: consider bringing this path into scope with the `use` keyword + --> tests/ui-toml/absolute_paths/absolute_paths.rs:28:13 + | +LL | let _: &std::path::Path = std::path::Path::new(""); + | ^^^^^^^^^^^^^^^ + +error: consider bringing this path into scope with the `use` keyword + --> tests/ui-toml/absolute_paths/absolute_paths.rs:37:13 + | +LL | let _ = ::core::clone::Clone::clone(&0i32); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: consider bringing this path into scope with the `use` keyword + --> tests/ui-toml/absolute_paths/absolute_paths.rs:40:13 + | +LL | let _ = ::clone(&0i32); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: consider bringing this path into scope with the `use` keyword + --> tests/ui-toml/absolute_paths/absolute_paths.rs:43:13 + | +LL | let _ = std::option::Option::None::; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: consider bringing this path into scope with the `use` keyword + --> tests/ui-toml/absolute_paths/absolute_paths.rs:65:17 + | +LL | impl core::fmt::Display for X + | ^^^^^^^^^^^^^ + +error: consider bringing this path into scope with the `use` keyword + --> tests/ui-toml/absolute_paths/absolute_paths.rs:70:18 + | +LL | where T: core::clone::Clone + | ^^^^^^^^^^^^^^^^^^ + +error: consider bringing this path into scope with the `use` keyword + --> tests/ui-toml/absolute_paths/absolute_paths.rs:65:32 + | +LL | impl core::fmt::Display for X + | ^^^^^^^^^^^^^^^^^^ + +error: consider bringing this path into scope with the `use` keyword + --> tests/ui-toml/absolute_paths/absolute_paths.rs:116:5 + | +LL | crate::m1::S + | ^^^^^^^^^^^^ + +error: aborting due to 12 previous errors + diff --git a/tests/ui-toml/absolute_paths/absolute_paths.disallow_crates.stderr b/tests/ui-toml/absolute_paths/absolute_paths.disallow_crates.stderr deleted file mode 100644 index f342ebf6632..00000000000 --- a/tests/ui-toml/absolute_paths/absolute_paths.disallow_crates.stderr +++ /dev/null @@ -1,71 +0,0 @@ -error: consider bringing this path into scope with the `use` keyword - --> tests/ui-toml/absolute_paths/absolute_paths.rs:40:5 - | -LL | std::f32::MAX; - | ^^^^^^^^^^^^^ - | - = note: `-D clippy::absolute-paths` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::absolute_paths)]` - -error: consider bringing this path into scope with the `use` keyword - --> tests/ui-toml/absolute_paths/absolute_paths.rs:41:5 - | -LL | core::f32::MAX; - | ^^^^^^^^^^^^^^ - -error: consider bringing this path into scope with the `use` keyword - --> tests/ui-toml/absolute_paths/absolute_paths.rs:42:5 - | -LL | ::core::f32::MAX; - | ^^^^^^^^^^^^^^^^ - -error: consider bringing this path into scope with the `use` keyword - --> tests/ui-toml/absolute_paths/absolute_paths.rs:43:5 - | -LL | crate::a::b::c::C; - | ^^^^^^^^^^^^^^^^^ - -error: consider bringing this path into scope with the `use` keyword - --> tests/ui-toml/absolute_paths/absolute_paths.rs:44:5 - | -LL | crate::a::b::c::d::e::f::F; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: consider bringing this path into scope with the `use` keyword - --> tests/ui-toml/absolute_paths/absolute_paths.rs:45:5 - | -LL | crate::a::A; - | ^^^^^^^^^^^ - -error: consider bringing this path into scope with the `use` keyword - --> tests/ui-toml/absolute_paths/absolute_paths.rs:46:5 - | -LL | crate::a::b::B; - | ^^^^^^^^^^^^^^ - -error: consider bringing this path into scope with the `use` keyword - --> tests/ui-toml/absolute_paths/absolute_paths.rs:47:5 - | -LL | crate::a::b::c::C::ZERO; - | ^^^^^^^^^^^^^^^^^ - -error: consider bringing this path into scope with the `use` keyword - --> tests/ui-toml/absolute_paths/absolute_paths.rs:48:5 - | -LL | helper::b::c::d::e::f(); - | ^^^^^^^^^^^^^^^^^^^^^ - -error: consider bringing this path into scope with the `use` keyword - --> tests/ui-toml/absolute_paths/absolute_paths.rs:49:5 - | -LL | ::helper::b::c::d::e::f(); - | ^^^^^^^^^^^^^^^^^^^^^^^ - -error: consider bringing this path into scope with the `use` keyword - --> tests/ui-toml/absolute_paths/absolute_paths.rs:58:5 - | -LL | ::std::f32::MAX; - | ^^^^^^^^^^^^^^^ - -error: aborting due to 11 previous errors - diff --git a/tests/ui-toml/absolute_paths/absolute_paths.no_short.stderr b/tests/ui-toml/absolute_paths/absolute_paths.no_short.stderr new file mode 100644 index 00000000000..70d71f6c4ea --- /dev/null +++ b/tests/ui-toml/absolute_paths/absolute_paths.no_short.stderr @@ -0,0 +1,98 @@ +error: consider bringing this path into scope with the `use` keyword + --> tests/ui-toml/absolute_paths/absolute_paths.rs:14:13 + | +LL | let _ = std::path::is_separator(' '); + | ^^^^^^^^^^^^^^^^^^^^^^^ + | +note: the lint level is defined here + --> tests/ui-toml/absolute_paths/absolute_paths.rs:7:9 + | +LL | #![deny(clippy::absolute_paths)] + | ^^^^^^^^^^^^^^^^^^^^^^ + +error: consider bringing this path into scope with the `use` keyword + --> tests/ui-toml/absolute_paths/absolute_paths.rs:20:13 + | +LL | let _ = ::std::path::MAIN_SEPARATOR; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: consider bringing this path into scope with the `use` keyword + --> tests/ui-toml/absolute_paths/absolute_paths.rs:25:13 + | +LL | let _ = std::collections::hash_map::HashMap::::new(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: consider bringing this path into scope with the `use` keyword + --> tests/ui-toml/absolute_paths/absolute_paths.rs:28:31 + | +LL | let _: &std::path::Path = std::path::Path::new(""); + | ^^^^^^^^^^^^^^^ + +error: consider bringing this path into scope with the `use` keyword + --> tests/ui-toml/absolute_paths/absolute_paths.rs:28:13 + | +LL | let _: &std::path::Path = std::path::Path::new(""); + | ^^^^^^^^^^^^^^^ + +error: consider bringing this path into scope with the `use` keyword + --> tests/ui-toml/absolute_paths/absolute_paths.rs:37:13 + | +LL | let _ = ::core::clone::Clone::clone(&0i32); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: consider bringing this path into scope with the `use` keyword + --> tests/ui-toml/absolute_paths/absolute_paths.rs:40:13 + | +LL | let _ = ::clone(&0i32); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: consider bringing this path into scope with the `use` keyword + --> tests/ui-toml/absolute_paths/absolute_paths.rs:43:13 + | +LL | let _ = std::option::Option::None::; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: consider bringing this path into scope with the `use` keyword + --> tests/ui-toml/absolute_paths/absolute_paths.rs:65:17 + | +LL | impl core::fmt::Display for X + | ^^^^^^^^^^^^^ + +error: consider bringing this path into scope with the `use` keyword + --> tests/ui-toml/absolute_paths/absolute_paths.rs:70:18 + | +LL | where T: core::clone::Clone + | ^^^^^^^^^^^^^^^^^^ + +error: consider bringing this path into scope with the `use` keyword + --> tests/ui-toml/absolute_paths/absolute_paths.rs:65:32 + | +LL | impl core::fmt::Display for X + | ^^^^^^^^^^^^^^^^^^ + +error: consider bringing this path into scope with the `use` keyword + --> tests/ui-toml/absolute_paths/absolute_paths.rs:113:14 + | +LL | pub const _: crate::S = { + | ^^^^^^^^ + +error: consider bringing this path into scope with the `use` keyword + --> tests/ui-toml/absolute_paths/absolute_paths.rs:114:9 + | +LL | let crate::S = m1::S; + | ^^^^^^^^ + +error: consider bringing this path into scope with the `use` keyword + --> tests/ui-toml/absolute_paths/absolute_paths.rs:116:5 + | +LL | crate::m1::S + | ^^^^^^^^^^^^ + +error: consider bringing this path into scope with the `use` keyword + --> tests/ui-toml/absolute_paths/absolute_paths.rs:122:14 + | +LL | let _ = ::clone(&m1::S); + | ^^^^^^^^ + +error: aborting due to 15 previous errors + diff --git a/tests/ui-toml/absolute_paths/absolute_paths.rs b/tests/ui-toml/absolute_paths/absolute_paths.rs index a828701bcee..c024f2f513c 100644 --- a/tests/ui-toml/absolute_paths/absolute_paths.rs +++ b/tests/ui-toml/absolute_paths/absolute_paths.rs @@ -1,97 +1,123 @@ //@aux-build:../../ui/auxiliary/proc_macros.rs -//@aux-build:helper.rs -//@revisions: allow_crates disallow_crates +//@revisions: default allow_crates allow_long no_short +//@[default] rustc-env:CLIPPY_CONF_DIR=tests/ui-toml/absolute_paths/default //@[allow_crates] rustc-env:CLIPPY_CONF_DIR=tests/ui-toml/absolute_paths/allow_crates -//@[disallow_crates] rustc-env:CLIPPY_CONF_DIR=tests/ui-toml/absolute_paths/disallow_crates -#![allow(clippy::no_effect, clippy::legacy_numeric_constants, unused)] -#![warn(clippy::absolute_paths)] -#![feature(decl_macro)] +//@[allow_long] rustc-env:CLIPPY_CONF_DIR=tests/ui-toml/absolute_paths/allow_long +//@[no_short] rustc-env:CLIPPY_CONF_DIR=tests/ui-toml/absolute_paths/no_short +#![deny(clippy::absolute_paths)] -extern crate helper; -#[macro_use] extern crate proc_macros; +use proc_macros::{external, inline_macros, with_span}; -pub mod a { - pub mod b { - pub mod c { - pub struct C; +#[inline_macros] +fn main() { + let _ = std::path::is_separator(' '); + //~[default]^ absolute_paths + //~[allow_crates]| absolute_paths + //~[no_short]| absolute_paths - impl C { - pub const ZERO: u32 = 0; - } + // Make sure this is treated as having three path segments, not four. + let _ = ::std::path::MAIN_SEPARATOR; + //~[default]^ absolute_paths + //~[allow_crates]| absolute_paths + //~[no_short]| absolute_paths - pub mod d { - pub mod e { - pub mod f { - pub struct F; - } - } + let _ = std::collections::hash_map::HashMap::::new(); //~ absolute_paths + + // Note `std::path::Path::new` is treated as having three parts + let _: &std::path::Path = std::path::Path::new(""); + //~[default]^ absolute_paths + //~[default]| absolute_paths + //~[allow_crates]| absolute_paths + //~[allow_crates]| absolute_paths + //~[no_short]| absolute_paths + //~[no_short]| absolute_paths + + // Treated as having three parts. + let _ = ::core::clone::Clone::clone(&0i32); + //~[default]^ absolute_paths + //~[no_short]| absolute_paths + let _ = ::clone(&0i32); + //~[default]^ absolute_paths + //~[no_short]| absolute_paths + let _ = std::option::Option::None::; + //~[default]^ absolute_paths + //~[allow_crates]| absolute_paths + //~[no_short]| absolute_paths + + { + // FIXME: macro calls should be checked. + let x = 1i32; + let _ = core::ptr::addr_of!(x); + } + + { + // FIXME: derive macro paths should be checked. + #[derive(core::clone::Clone)] + struct S; + } + + { + use core::fmt; + use core::marker::PhantomData; + + struct X(PhantomData); + impl core::fmt::Display for X + //~[default]^ absolute_paths + //~[default]| absolute_paths + //~[no_short]| absolute_paths + //~[no_short]| absolute_paths + where T: core::clone::Clone + //~[no_short]^ absolute_paths + //~[default]| absolute_paths + { + fn fmt(&self, _: &mut fmt::Formatter) -> fmt::Result { + Ok(()) } } - - pub struct B; } - pub struct A; -} + { + mod m1 { + pub(crate) mod m2 { + pub(crate) const FOO: i32 = 0; + } + } + let _ = m1::m2::FOO; + } -fn main() { - f32::max(1.0, 2.0); - std::f32::MAX; - core::f32::MAX; - ::core::f32::MAX; - crate::a::b::c::C; - crate::a::b::c::d::e::f::F; - crate::a::A; - crate::a::b::B; - crate::a::b::c::C::ZERO; - helper::b::c::d::e::f(); - ::helper::b::c::d::e::f(); - fn b() -> a::b::B { - todo!() - } - std::println!("a"); - let x = 1; - std::ptr::addr_of!(x); - // Test we handle max segments with `PathRoot` properly; this has 4 segments but we should say it - // has 3 - ::std::f32::MAX; - // Do not lint due to the above - ::helper::a(); - // Do not lint - helper::a(); - use crate::a::b::c::C; - use a::b; - use std::f32::MAX; - a::b::c::d::e::f::F; - b::c::C; - fn a() -> a::A { - todo!() - } - use a::b::c; - - fn c() -> c::C { - todo!() - } - fn d() -> Result<(), ()> { - todo!() - } - external! { - crate::a::b::c::C::ZERO; - } - // For some reason, `path.span.from_expansion()` takes care of this for us with_span! { span - crate::a::b::c::C::ZERO; + let _ = std::path::is_separator(' '); } - macro_rules! local_crate { - () => { - crate::a::b::c::C::ZERO; - }; + + external! { + let _ = std::path::is_separator(' '); } - macro local_crate_2_0() { - crate::a::b::c::C::ZERO; + + inline! { + let _ = std::path::is_separator(' '); } - local_crate!(); - local_crate_2_0!(); +} + +pub use core::cmp::Ordering; +pub use std::fs::File; + +#[derive(Clone)] +pub struct S; +mod m1 { + pub use crate::S; +} + +//~[no_short]v absolute_paths +pub const _: crate::S = { + let crate::S = m1::S; //~[no_short] absolute_paths + + crate::m1::S + //~[default]^ absolute_paths + //~[no_short]| absolute_paths +}; + +pub fn f() { + let _ = ::clone(&m1::S); //~[no_short] absolute_paths } diff --git a/tests/ui-toml/absolute_paths/absolute_paths_2015.default.stderr b/tests/ui-toml/absolute_paths/absolute_paths_2015.default.stderr new file mode 100644 index 00000000000..6fc495f0180 --- /dev/null +++ b/tests/ui-toml/absolute_paths/absolute_paths_2015.default.stderr @@ -0,0 +1,14 @@ +error: consider bringing this path into scope with the `use` keyword + --> tests/ui-toml/absolute_paths/absolute_paths_2015.rs:15:13 + | +LL | let _ = ::m1::m2::X; + | ^^^^^^^^^^^ + | +note: the lint level is defined here + --> tests/ui-toml/absolute_paths/absolute_paths_2015.rs:6:9 + | +LL | #![deny(clippy::absolute_paths)] + | ^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui-toml/absolute_paths/absolute_paths_2015.rs b/tests/ui-toml/absolute_paths/absolute_paths_2015.rs new file mode 100644 index 00000000000..033c4780919 --- /dev/null +++ b/tests/ui-toml/absolute_paths/absolute_paths_2015.rs @@ -0,0 +1,16 @@ +//@revisions: default allow_crates +//@[default]rustc-env:CLIPPY_CONF_DIR=tests/ui-toml/absolute_paths/default +//@[allow_crates]rustc-env:CLIPPY_CONF_DIR=tests/ui-toml/absolute_paths/allow_crates +//@edition:2015 + +#![deny(clippy::absolute_paths)] + +mod m1 { + pub mod m2 { + pub struct X; + } +} + +fn main() { + let _ = ::m1::m2::X; //~[default] absolute_paths +} diff --git a/tests/ui-toml/absolute_paths/allow_crates/clippy.toml b/tests/ui-toml/absolute_paths/allow_crates/clippy.toml index 59a621e9d1d..9da49abcd31 100644 --- a/tests/ui-toml/absolute_paths/allow_crates/clippy.toml +++ b/tests/ui-toml/absolute_paths/allow_crates/clippy.toml @@ -1,2 +1 @@ -absolute-paths-max-segments = 2 -absolute-paths-allowed-crates = ["crate", "helper"] +absolute-paths-allowed-crates = ["core", "crate"] diff --git a/tests/ui-toml/absolute_paths/allow_long/clippy.toml b/tests/ui-toml/absolute_paths/allow_long/clippy.toml new file mode 100644 index 00000000000..5992fd1ed82 --- /dev/null +++ b/tests/ui-toml/absolute_paths/allow_long/clippy.toml @@ -0,0 +1 @@ +absolute-paths-max-segments = 3 diff --git a/tests/ui-toml/absolute_paths/auxiliary/helper.rs b/tests/ui-toml/absolute_paths/auxiliary/helper.rs deleted file mode 100644 index 8e2678f5fe6..00000000000 --- a/tests/ui-toml/absolute_paths/auxiliary/helper.rs +++ /dev/null @@ -1,11 +0,0 @@ -pub fn a() {} - -pub mod b { - pub mod c { - pub mod d { - pub mod e { - pub fn f() {} - } - } - } -} diff --git a/tests/ui-toml/absolute_paths/default/clippy.toml b/tests/ui-toml/absolute_paths/default/clippy.toml new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/ui-toml/absolute_paths/disallow_crates/clippy.toml b/tests/ui-toml/absolute_paths/disallow_crates/clippy.toml deleted file mode 100644 index d44d648c641..00000000000 --- a/tests/ui-toml/absolute_paths/disallow_crates/clippy.toml +++ /dev/null @@ -1 +0,0 @@ -absolute-paths-max-segments = 2 diff --git a/tests/ui-toml/absolute_paths/no_short/clippy.toml b/tests/ui-toml/absolute_paths/no_short/clippy.toml new file mode 100644 index 00000000000..357524420c5 --- /dev/null +++ b/tests/ui-toml/absolute_paths/no_short/clippy.toml @@ -0,0 +1 @@ +absolute-paths-max-segments = 0 diff --git a/tests/ui-toml/macro_metavars_in_unsafe/default/test.rs b/tests/ui-toml/macro_metavars_in_unsafe/default/test.rs index a312df5a43a..3dafea56514 100644 --- a/tests/ui-toml/macro_metavars_in_unsafe/default/test.rs +++ b/tests/ui-toml/macro_metavars_in_unsafe/default/test.rs @@ -1,7 +1,7 @@ //! Tests macro_metavars_in_unsafe with default configuration #![feature(decl_macro)] #![warn(clippy::macro_metavars_in_unsafe)] -#![allow(clippy::no_effect)] +#![allow(clippy::no_effect, clippy::not_unsafe_ptr_arg_deref)] #[macro_export] macro_rules! allow_works { @@ -237,6 +237,19 @@ macro_rules! nested_macros { }}; } +pub mod issue13219 { + #[macro_export] + macro_rules! m { + ($e:expr) => { + // Metavariable in a block tail expression + unsafe { $e } + }; + } + pub fn f(p: *const i32) -> i32 { + m!(*p) + } +} + fn main() { allow_works!(1); simple!(1); diff --git a/tests/ui-toml/macro_metavars_in_unsafe/default/test.stderr b/tests/ui-toml/macro_metavars_in_unsafe/default/test.stderr index d6b97f6fde1..6f0ebcbba02 100644 --- a/tests/ui-toml/macro_metavars_in_unsafe/default/test.stderr +++ b/tests/ui-toml/macro_metavars_in_unsafe/default/test.stderr @@ -1,3 +1,15 @@ +error: this macro expands metavariables in an unsafe block + --> tests/ui-toml/macro_metavars_in_unsafe/default/test.rs:245:13 + | +LL | unsafe { $e } + | ^^^^^^^^^^^^^ + | + = note: this allows the user of the macro to write unsafe code outside of an unsafe block + = help: consider expanding any metavariables outside of this block, e.g. by storing them in a variable + = help: ... or also expand referenced metavariables in a safe context to require an unsafe block at callsite + = note: `-D clippy::macro-metavars-in-unsafe` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::macro_metavars_in_unsafe)]` + error: this macro expands metavariables in an unsafe block --> tests/ui-toml/macro_metavars_in_unsafe/default/test.rs:19:9 | @@ -10,8 +22,6 @@ LL | | } = note: this allows the user of the macro to write unsafe code outside of an unsafe block = help: consider expanding any metavariables outside of this block, e.g. by storing them in a variable = help: ... or also expand referenced metavariables in a safe context to require an unsafe block at callsite - = note: `-D clippy::macro-metavars-in-unsafe` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::macro_metavars_in_unsafe)]` error: this macro expands metavariables in an unsafe block --> tests/ui-toml/macro_metavars_in_unsafe/default/test.rs:30:9 @@ -183,5 +193,5 @@ LL | | } = help: consider expanding any metavariables outside of this block, e.g. by storing them in a variable = help: ... or also expand referenced metavariables in a safe context to require an unsafe block at callsite -error: aborting due to 14 previous errors +error: aborting due to 15 previous errors diff --git a/tests/ui/assigning_clones.fixed b/tests/ui/assigning_clones.fixed index b376d55a402..09732d1a50c 100644 --- a/tests/ui/assigning_clones.fixed +++ b/tests/ui/assigning_clones.fixed @@ -396,3 +396,23 @@ impl Clone for DerefWrapperWithClone { *self = Self(source.0.clone()); } } + +#[cfg(test)] +mod test { + #[derive(Default)] + struct Data { + field: String, + } + + fn test_data() -> Data { + Data { + field: "default_value".to_string(), + } + } + + #[test] + fn test() { + let mut data = test_data(); + data.field = "override_value".to_owned(); + } +} diff --git a/tests/ui/assigning_clones.rs b/tests/ui/assigning_clones.rs index 11a5d4459c3..6be25ae17a5 100644 --- a/tests/ui/assigning_clones.rs +++ b/tests/ui/assigning_clones.rs @@ -396,3 +396,23 @@ impl Clone for DerefWrapperWithClone { *self = Self(source.0.clone()); } } + +#[cfg(test)] +mod test { + #[derive(Default)] + struct Data { + field: String, + } + + fn test_data() -> Data { + Data { + field: "default_value".to_string(), + } + } + + #[test] + fn test() { + let mut data = test_data(); + data.field = "override_value".to_owned(); + } +} diff --git a/tests/ui/checked_unwrap/complex_conditionals_nested.stderr b/tests/ui/checked_unwrap/complex_conditionals_nested.stderr index f7e659b10de..329be4d3662 100644 --- a/tests/ui/checked_unwrap/complex_conditionals_nested.stderr +++ b/tests/ui/checked_unwrap/complex_conditionals_nested.stderr @@ -2,7 +2,7 @@ error: called `unwrap` on `x` after checking its variant with `is_some` --> tests/ui/checked_unwrap/complex_conditionals_nested.rs:13:13 | LL | if x.is_some() { - | -------------- help: try: `if let Some(..) = x` + | -------------- help: try: `if let Some() = x` LL | // unnecessary LL | x.unwrap(); | ^^^^^^^^^^ diff --git a/tests/ui/checked_unwrap/simple_conditionals.stderr b/tests/ui/checked_unwrap/simple_conditionals.stderr index ddd600418af..f7e338935a7 100644 --- a/tests/ui/checked_unwrap/simple_conditionals.stderr +++ b/tests/ui/checked_unwrap/simple_conditionals.stderr @@ -2,7 +2,7 @@ error: called `unwrap` on `x` after checking its variant with `is_some` --> tests/ui/checked_unwrap/simple_conditionals.rs:46:9 | LL | if x.is_some() { - | -------------- help: try: `if let Some(..) = x` + | -------------- help: try: `if let Some() = x` LL | // unnecessary LL | x.unwrap(); | ^^^^^^^^^^ @@ -17,7 +17,7 @@ error: called `expect` on `x` after checking its variant with `is_some` --> tests/ui/checked_unwrap/simple_conditionals.rs:49:9 | LL | if x.is_some() { - | -------------- help: try: `if let Some(..) = x` + | -------------- help: try: `if let Some() = x` ... LL | x.expect("an error message"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -59,7 +59,7 @@ error: called `unwrap` on `x` after checking its variant with `is_none` --> tests/ui/checked_unwrap/simple_conditionals.rs:65:9 | LL | if x.is_none() { - | -------------- help: try: `if let Some(..) = x` + | -------------- help: try: `if let Some() = x` ... LL | x.unwrap(); | ^^^^^^^^^^ @@ -68,7 +68,7 @@ error: called `unwrap` on `x` after checking its variant with `is_some` --> tests/ui/checked_unwrap/simple_conditionals.rs:13:13 | LL | if $a.is_some() { - | --------------- help: try: `if let Some(..) = x` + | --------------- help: try: `if let Some() = x` LL | // unnecessary LL | $a.unwrap(); | ^^^^^^^^^^^ @@ -82,7 +82,7 @@ error: called `unwrap` on `x` after checking its variant with `is_ok` --> tests/ui/checked_unwrap/simple_conditionals.rs:78:9 | LL | if x.is_ok() { - | ------------ help: try: `if let Ok(..) = x` + | ------------ help: try: `if let Ok() = x` LL | // unnecessary LL | x.unwrap(); | ^^^^^^^^^^ @@ -91,7 +91,7 @@ error: called `expect` on `x` after checking its variant with `is_ok` --> tests/ui/checked_unwrap/simple_conditionals.rs:81:9 | LL | if x.is_ok() { - | ------------ help: try: `if let Ok(..) = x` + | ------------ help: try: `if let Ok() = x` ... LL | x.expect("an error message"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -127,7 +127,7 @@ error: called `unwrap_err` on `x` after checking its variant with `is_ok` --> tests/ui/checked_unwrap/simple_conditionals.rs:94:9 | LL | if x.is_ok() { - | ------------ help: try: `if let Err(..) = x` + | ------------ help: try: `if let Err() = x` ... LL | x.unwrap_err(); | ^^^^^^^^^^^^^^ @@ -145,7 +145,7 @@ error: called `unwrap_err` on `x` after checking its variant with `is_err` --> tests/ui/checked_unwrap/simple_conditionals.rs:102:9 | LL | if x.is_err() { - | ------------- help: try: `if let Err(..) = x` + | ------------- help: try: `if let Err() = x` ... LL | x.unwrap_err(); | ^^^^^^^^^^^^^^ @@ -154,7 +154,7 @@ error: called `unwrap` on `x` after checking its variant with `is_err` --> tests/ui/checked_unwrap/simple_conditionals.rs:106:9 | LL | if x.is_err() { - | ------------- help: try: `if let Ok(..) = x` + | ------------- help: try: `if let Ok() = x` ... LL | x.unwrap(); | ^^^^^^^^^^ @@ -172,7 +172,7 @@ error: called `unwrap` on `option` after checking its variant with `is_some` --> tests/ui/checked_unwrap/simple_conditionals.rs:134:9 | LL | if option.is_some() { - | ------------------- help: try: `if let Some(..) = &option` + | ------------------- help: try: `if let Some() = &option` LL | option.as_ref().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -189,7 +189,7 @@ error: called `unwrap` on `result` after checking its variant with `is_ok` --> tests/ui/checked_unwrap/simple_conditionals.rs:144:9 | LL | if result.is_ok() { - | ----------------- help: try: `if let Ok(..) = &result` + | ----------------- help: try: `if let Ok() = &result` LL | result.as_ref().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -206,7 +206,7 @@ error: called `unwrap` on `option` after checking its variant with `is_some` --> tests/ui/checked_unwrap/simple_conditionals.rs:153:9 | LL | if option.is_some() { - | ------------------- help: try: `if let Some(..) = &mut option` + | ------------------- help: try: `if let Some() = &mut option` LL | option.as_mut().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -223,7 +223,7 @@ error: called `unwrap` on `result` after checking its variant with `is_ok` --> tests/ui/checked_unwrap/simple_conditionals.rs:162:9 | LL | if result.is_ok() { - | ----------------- help: try: `if let Ok(..) = &mut result` + | ----------------- help: try: `if let Ok() = &mut result` LL | result.as_mut().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/collapsible_match.stderr b/tests/ui/collapsible_match.stderr index 01944baee79..1da78b56239 100644 --- a/tests/ui/collapsible_match.stderr +++ b/tests/ui/collapsible_match.stderr @@ -223,7 +223,7 @@ help: the outer pattern can be modified to include the inner pattern LL | if let Issue9647::A { a, .. } = x { | ^ replace this binding LL | if let Some(u) = a { - | ^^^^^^^ with this pattern, prefixed by a: + | ^^^^^^^ with this pattern, prefixed by `a`: error: this `if let` can be collapsed into the outer `if let` --> tests/ui/collapsible_match.rs:292:9 diff --git a/tests/ui/crashes/ice-3717.fixed b/tests/ui/crashes/ice-3717.fixed new file mode 100644 index 00000000000..3f54b326979 --- /dev/null +++ b/tests/ui/crashes/ice-3717.fixed @@ -0,0 +1,11 @@ +#![deny(clippy::implicit_hasher)] + +use std::collections::HashSet; + +fn main() {} + +pub fn ice_3717(_: &HashSet) { + //~^ ERROR: parameter of type `HashSet` should be generalized over different hashers + let _ = [0u8; 0]; + let _: HashSet = HashSet::default(); +} diff --git a/tests/ui/crashes/ice-3717.rs b/tests/ui/crashes/ice-3717.rs index 770f6cf448a..2890a9277c7 100644 --- a/tests/ui/crashes/ice-3717.rs +++ b/tests/ui/crashes/ice-3717.rs @@ -1,7 +1,5 @@ #![deny(clippy::implicit_hasher)] -//@no-rustfix: need to change the suggestion to a multipart suggestion - use std::collections::HashSet; fn main() {} diff --git a/tests/ui/crashes/ice-3717.stderr b/tests/ui/crashes/ice-3717.stderr index 4b4618ee1bb..aac72c66965 100644 --- a/tests/ui/crashes/ice-3717.stderr +++ b/tests/ui/crashes/ice-3717.stderr @@ -1,5 +1,5 @@ error: parameter of type `HashSet` should be generalized over different hashers - --> tests/ui/crashes/ice-3717.rs:9:21 + --> tests/ui/crashes/ice-3717.rs:7:21 | LL | pub fn ice_3717(_: &HashSet) { | ^^^^^^^^^^^^^^ diff --git a/tests/ui/declare_interior_mutable_const/others.rs b/tests/ui/declare_interior_mutable_const/others.rs index 56a8d22cb1c..9dafad8b784 100644 --- a/tests/ui/declare_interior_mutable_const/others.rs +++ b/tests/ui/declare_interior_mutable_const/others.rs @@ -3,6 +3,7 @@ use std::borrow::Cow; use std::cell::Cell; use std::fmt::Display; +use std::ptr; use std::sync::atomic::AtomicUsize; use std::sync::Once; @@ -53,4 +54,20 @@ mod issue_8493 { issue_8493!(); } +#[repr(C, align(8))] +struct NoAtomic(usize); +#[repr(C, align(8))] +struct WithAtomic(AtomicUsize); + +const fn with_non_null() -> *const WithAtomic { + const NO_ATOMIC: NoAtomic = NoAtomic(0); + (&NO_ATOMIC as *const NoAtomic).cast() +} +const WITH_ATOMIC: *const WithAtomic = with_non_null(); + +struct Generic(T); +impl Generic { + const RAW_POINTER: *const Cell = ptr::null(); +} + fn main() {} diff --git a/tests/ui/declare_interior_mutable_const/others.stderr b/tests/ui/declare_interior_mutable_const/others.stderr index 1f2b9561ce5..4a725147142 100644 --- a/tests/ui/declare_interior_mutable_const/others.stderr +++ b/tests/ui/declare_interior_mutable_const/others.stderr @@ -1,5 +1,5 @@ error: a `const` item should not be interior mutable - --> tests/ui/declare_interior_mutable_const/others.rs:9:1 + --> tests/ui/declare_interior_mutable_const/others.rs:10:1 | LL | const ATOMIC: AtomicUsize = AtomicUsize::new(5); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -9,7 +9,7 @@ LL | const ATOMIC: AtomicUsize = AtomicUsize::new(5); = help: to override `-D warnings` add `#[allow(clippy::declare_interior_mutable_const)]` error: a `const` item should not be interior mutable - --> tests/ui/declare_interior_mutable_const/others.rs:10:1 + --> tests/ui/declare_interior_mutable_const/others.rs:11:1 | LL | const CELL: Cell = Cell::new(6); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -17,7 +17,7 @@ LL | const CELL: Cell = Cell::new(6); = help: consider making this `Sync` so that it can go in a static item or using a `thread_local` error: a `const` item should not be interior mutable - --> tests/ui/declare_interior_mutable_const/others.rs:11:1 + --> tests/ui/declare_interior_mutable_const/others.rs:12:1 | LL | const ATOMIC_TUPLE: ([AtomicUsize; 1], Vec, u8) = ([ATOMIC], Vec::new(), 7); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -25,7 +25,7 @@ LL | const ATOMIC_TUPLE: ([AtomicUsize; 1], Vec, u8) = ([ATOMIC], V = help: consider making this a static item error: a `const` item should not be interior mutable - --> tests/ui/declare_interior_mutable_const/others.rs:16:9 + --> tests/ui/declare_interior_mutable_const/others.rs:17:9 | LL | const $name: $ty = $e; | ^^^^^^^^^^^^^^^^^^^^^^ @@ -36,7 +36,7 @@ LL | declare_const!(_ONCE: Once = Once::new()); = note: this error originates in the macro `declare_const` (in Nightly builds, run with -Z macro-backtrace for more info) error: a `const` item should not be interior mutable - --> tests/ui/declare_interior_mutable_const/others.rs:44:13 + --> tests/ui/declare_interior_mutable_const/others.rs:45:13 | LL | const _BAZ: Cell = Cell::new(0); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/doc/doc_markdown-issue_13097.fixed b/tests/ui/doc/doc_markdown-issue_13097.fixed new file mode 100644 index 00000000000..fb0f40b34a4 --- /dev/null +++ b/tests/ui/doc/doc_markdown-issue_13097.fixed @@ -0,0 +1,13 @@ +// This test checks that words starting with capital letters and ending with "ified" don't +// trigger the lint. + +#![deny(clippy::doc_markdown)] + +pub enum OutputFormat { + /// `HumaNified` + //~^ ERROR: item in documentation is missing backticks + Plain, + // Should not warn! + /// JSONified console output + Json, +} diff --git a/tests/ui/doc/doc_markdown-issue_13097.rs b/tests/ui/doc/doc_markdown-issue_13097.rs new file mode 100644 index 00000000000..8c1e1a3cd6c --- /dev/null +++ b/tests/ui/doc/doc_markdown-issue_13097.rs @@ -0,0 +1,13 @@ +// This test checks that words starting with capital letters and ending with "ified" don't +// trigger the lint. + +#![deny(clippy::doc_markdown)] + +pub enum OutputFormat { + /// HumaNified + //~^ ERROR: item in documentation is missing backticks + Plain, + // Should not warn! + /// JSONified console output + Json, +} diff --git a/tests/ui/doc/doc_markdown-issue_13097.stderr b/tests/ui/doc/doc_markdown-issue_13097.stderr new file mode 100644 index 00000000000..ae68a767ec9 --- /dev/null +++ b/tests/ui/doc/doc_markdown-issue_13097.stderr @@ -0,0 +1,18 @@ +error: item in documentation is missing backticks + --> tests/ui/doc/doc_markdown-issue_13097.rs:7:9 + | +LL | /// HumaNified + | ^^^^^^^^^^ + | +note: the lint level is defined here + --> tests/ui/doc/doc_markdown-issue_13097.rs:4:9 + | +LL | #![deny(clippy::doc_markdown)] + | ^^^^^^^^^^^^^^^^^^^^ +help: try + | +LL | /// `HumaNified` + | ~~~~~~~~~~~~ + +error: aborting due to 1 previous error + diff --git a/tests/ui/double_must_use.rs b/tests/ui/double_must_use.rs index 615de3e2474..4460aeb075b 100644 --- a/tests/ui/double_must_use.rs +++ b/tests/ui/double_must_use.rs @@ -3,19 +3,19 @@ #[must_use] pub fn must_use_result() -> Result<(), ()> { - //~^ ERROR: this function has an empty `#[must_use]` attribute, but returns a type already + //~^ ERROR: this function has a `#[must_use]` attribute with no message, but returns a type already unimplemented!(); } #[must_use] pub fn must_use_tuple() -> (Result<(), ()>, u8) { - //~^ ERROR: this function has an empty `#[must_use]` attribute, but returns a type already + //~^ ERROR: this function has a `#[must_use]` attribute with no message, but returns a type already unimplemented!(); } #[must_use] pub fn must_use_array() -> [Result<(), ()>; 1] { - //~^ ERROR: this function has an empty `#[must_use]` attribute, but returns a type already + //~^ ERROR: this function has a `#[must_use]` attribute with no message, but returns a type already unimplemented!(); } @@ -32,7 +32,7 @@ async fn async_must_use() -> usize { #[must_use] async fn async_must_use_result() -> Result<(), ()> { - //~^ ERROR: this function has an empty `#[must_use]` attribute, but returns a type already + //~^ ERROR: this function has a `#[must_use]` attribute with no message, but returns a type already Ok(()) } diff --git a/tests/ui/double_must_use.stderr b/tests/ui/double_must_use.stderr index 0f2154ecbcf..b26d1e48a8b 100644 --- a/tests/ui/double_must_use.stderr +++ b/tests/ui/double_must_use.stderr @@ -1,36 +1,36 @@ -error: this function has an empty `#[must_use]` attribute, but returns a type already marked as `#[must_use]` +error: this function has a `#[must_use]` attribute with no message, but returns a type already marked as `#[must_use]` --> tests/ui/double_must_use.rs:5:1 | LL | pub fn must_use_result() -> Result<(), ()> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: either add some descriptive text or remove the attribute + = help: either add some descriptive message or remove the attribute = note: `-D clippy::double-must-use` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::double_must_use)]` -error: this function has an empty `#[must_use]` attribute, but returns a type already marked as `#[must_use]` +error: this function has a `#[must_use]` attribute with no message, but returns a type already marked as `#[must_use]` --> tests/ui/double_must_use.rs:11:1 | LL | pub fn must_use_tuple() -> (Result<(), ()>, u8) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: either add some descriptive text or remove the attribute + = help: either add some descriptive message or remove the attribute -error: this function has an empty `#[must_use]` attribute, but returns a type already marked as `#[must_use]` +error: this function has a `#[must_use]` attribute with no message, but returns a type already marked as `#[must_use]` --> tests/ui/double_must_use.rs:17:1 | LL | pub fn must_use_array() -> [Result<(), ()>; 1] { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: either add some descriptive text or remove the attribute + = help: either add some descriptive message or remove the attribute -error: this function has an empty `#[must_use]` attribute, but returns a type already marked as `#[must_use]` +error: this function has a `#[must_use]` attribute with no message, but returns a type already marked as `#[must_use]` --> tests/ui/double_must_use.rs:34:1 | LL | async fn async_must_use_result() -> Result<(), ()> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: either add some descriptive text or remove the attribute + = help: either add some descriptive message or remove the attribute error: aborting due to 4 previous errors diff --git a/tests/ui/explicit_iter_loop.fixed b/tests/ui/explicit_iter_loop.fixed index f38b34c5a7c..1148f0f6c6a 100644 --- a/tests/ui/explicit_iter_loop.fixed +++ b/tests/ui/explicit_iter_loop.fixed @@ -153,3 +153,15 @@ fn main() { let r = &x; for _ in r {} } + +#[clippy::msrv = "1.79"] +pub fn issue_13184() { + // https://github.com/rust-lang/rust-clippy/issues/13184 + // No need to fix, as IntoIterator for Box is valid starting from 1.80 + let mut values: Box<[u32]> = Box::new([1, 2]); + for _ in values.iter() {} + for _ in values.iter_mut() {} + + let rvalues = &values; + for _ in rvalues.iter() {} +} diff --git a/tests/ui/explicit_iter_loop.rs b/tests/ui/explicit_iter_loop.rs index 2e701ada5ac..4dda2f13e5b 100644 --- a/tests/ui/explicit_iter_loop.rs +++ b/tests/ui/explicit_iter_loop.rs @@ -153,3 +153,15 @@ fn main() { let r = &x; for _ in r.iter() {} } + +#[clippy::msrv = "1.79"] +pub fn issue_13184() { + // https://github.com/rust-lang/rust-clippy/issues/13184 + // No need to fix, as IntoIterator for Box is valid starting from 1.80 + let mut values: Box<[u32]> = Box::new([1, 2]); + for _ in values.iter() {} + for _ in values.iter_mut() {} + + let rvalues = &values; + for _ in rvalues.iter() {} +} diff --git a/tests/ui/inconsistent_struct_constructor.fixed b/tests/ui/inconsistent_struct_constructor.fixed index 5778f8f526f..4c324587c96 100644 --- a/tests/ui/inconsistent_struct_constructor.fixed +++ b/tests/ui/inconsistent_struct_constructor.fixed @@ -15,6 +15,14 @@ struct Foo { z: i32, } +#[derive(Default)] +#[allow(clippy::inconsistent_struct_constructor)] +struct Bar { + x: i32, + y: i32, + z: i32, +} + mod without_base { use super::Foo; @@ -70,4 +78,17 @@ mod with_base { } } +mod with_allow_ty_def { + use super::Bar; + + fn test() { + let x = 1; + let y = 1; + let z = 1; + + // Should NOT lint because `Bar` is defined with `#[allow(clippy::inconsistent_struct_constructor)]` + Bar { y, x, z }; + } +} + fn main() {} diff --git a/tests/ui/inconsistent_struct_constructor.rs b/tests/ui/inconsistent_struct_constructor.rs index 9efaf068934..d49f236b9b0 100644 --- a/tests/ui/inconsistent_struct_constructor.rs +++ b/tests/ui/inconsistent_struct_constructor.rs @@ -15,6 +15,14 @@ struct Foo { z: i32, } +#[derive(Default)] +#[allow(clippy::inconsistent_struct_constructor)] +struct Bar { + x: i32, + y: i32, + z: i32, +} + mod without_base { use super::Foo; @@ -74,4 +82,17 @@ mod with_base { } } +mod with_allow_ty_def { + use super::Bar; + + fn test() { + let x = 1; + let y = 1; + let z = 1; + + // Should NOT lint because `Bar` is defined with `#[allow(clippy::inconsistent_struct_constructor)]` + Bar { y, x, z }; + } +} + fn main() {} diff --git a/tests/ui/inconsistent_struct_constructor.stderr b/tests/ui/inconsistent_struct_constructor.stderr index 1192271f911..97bb7c789a7 100644 --- a/tests/ui/inconsistent_struct_constructor.stderr +++ b/tests/ui/inconsistent_struct_constructor.stderr @@ -1,5 +1,5 @@ error: struct constructor field order is inconsistent with struct definition field order - --> tests/ui/inconsistent_struct_constructor.rs:28:9 + --> tests/ui/inconsistent_struct_constructor.rs:36:9 | LL | Foo { y, x, z }; | ^^^^^^^^^^^^^^^ help: try: `Foo { x, y, z }` @@ -8,7 +8,7 @@ LL | Foo { y, x, z }; = 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:55:9 + --> tests/ui/inconsistent_struct_constructor.rs:63:9 | LL | / Foo { LL | | z, diff --git a/tests/ui/min_rust_version_invalid_attr.rs b/tests/ui/min_rust_version_invalid_attr.rs index 2dccadd9fce..c8409d78ed7 100644 --- a/tests/ui/min_rust_version_invalid_attr.rs +++ b/tests/ui/min_rust_version_invalid_attr.rs @@ -17,7 +17,7 @@ mod multiple { //~^ ERROR: `clippy::msrv` is defined multiple times mod foo { - #![clippy::msrv = "1"] + #![clippy::msrv = "1.0"] #![clippy::msrv = "1.0.0"] //~^ ERROR: `clippy::msrv` is defined multiple times } diff --git a/tests/ui/min_rust_version_invalid_attr.stderr b/tests/ui/min_rust_version_invalid_attr.stderr index b4cb1b5713f..dbc276ed89d 100644 --- a/tests/ui/min_rust_version_invalid_attr.stderr +++ b/tests/ui/min_rust_version_invalid_attr.stderr @@ -31,8 +31,8 @@ LL | #![clippy::msrv = "1.0.0"] note: first definition found here --> tests/ui/min_rust_version_invalid_attr.rs:20:9 | -LL | #![clippy::msrv = "1"] - | ^^^^^^^^^^^^^^^^^^^^^^ +LL | #![clippy::msrv = "1.0"] + | ^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 4 previous errors diff --git a/tests/ui/string_slice.rs b/tests/ui/string_slice.rs index 440a86b104a..1d1911aaa1d 100644 --- a/tests/ui/string_slice.rs +++ b/tests/ui/string_slice.rs @@ -1,3 +1,5 @@ +use std::borrow::Cow; + #[warn(clippy::string_slice)] #[allow(clippy::no_effect)] @@ -11,4 +13,7 @@ fn main() { let s = String::from(m); &s[0..2]; //~^ ERROR: indexing into a string may panic if the index is within a UTF-8 character + let a = Cow::Borrowed("foo"); + &a[0..3]; + //~^ ERROR: indexing into a string may panic if the index is within a UTF-8 character } diff --git a/tests/ui/string_slice.stderr b/tests/ui/string_slice.stderr index 7a4596b5f2d..bc0fcde34b8 100644 --- a/tests/ui/string_slice.stderr +++ b/tests/ui/string_slice.stderr @@ -1,5 +1,5 @@ error: indexing into a string may panic if the index is within a UTF-8 character - --> tests/ui/string_slice.rs:5:6 + --> tests/ui/string_slice.rs:7:6 | LL | &"Ölkanne"[1..]; | ^^^^^^^^^^^^^^ @@ -8,16 +8,22 @@ LL | &"Ölkanne"[1..]; = help: to override `-D warnings` add `#[allow(clippy::string_slice)]` error: indexing into a string may panic if the index is within a UTF-8 character - --> tests/ui/string_slice.rs:9:6 + --> tests/ui/string_slice.rs:11:6 | LL | &m[2..5]; | ^^^^^^^ error: indexing into a string may panic if the index is within a UTF-8 character - --> tests/ui/string_slice.rs:12:6 + --> tests/ui/string_slice.rs:14:6 | LL | &s[0..2]; | ^^^^^^^ -error: aborting due to 3 previous errors +error: indexing into a string may panic if the index is within a UTF-8 character + --> tests/ui/string_slice.rs:17:6 + | +LL | &a[0..3]; + | ^^^^^^^ + +error: aborting due to 4 previous errors diff --git a/tests/ui/too_long_first_doc_paragraph-fix.fixed b/tests/ui/too_long_first_doc_paragraph-fix.fixed new file mode 100644 index 00000000000..d4a0cdf3447 --- /dev/null +++ b/tests/ui/too_long_first_doc_paragraph-fix.fixed @@ -0,0 +1,9 @@ +#![warn(clippy::too_long_first_doc_paragraph)] + +/// A very short summary. +/// +/// A much longer explanation that goes into a lot more detail about +/// how the thing works, possibly with doclinks and so one, +/// and probably spanning a many rows. Blablabla, it needs to be over +/// 200 characters so I needed to write something longeeeeeeer. +pub struct Foo; diff --git a/tests/ui/too_long_first_doc_paragraph-fix.rs b/tests/ui/too_long_first_doc_paragraph-fix.rs new file mode 100644 index 00000000000..5a3b6c42a32 --- /dev/null +++ b/tests/ui/too_long_first_doc_paragraph-fix.rs @@ -0,0 +1,8 @@ +#![warn(clippy::too_long_first_doc_paragraph)] + +/// A very short summary. +/// A much longer explanation that goes into a lot more detail about +/// how the thing works, possibly with doclinks and so one, +/// and probably spanning a many rows. Blablabla, it needs to be over +/// 200 characters so I needed to write something longeeeeeeer. +pub struct Foo; diff --git a/tests/ui/too_long_first_doc_paragraph-fix.stderr b/tests/ui/too_long_first_doc_paragraph-fix.stderr new file mode 100644 index 00000000000..6403265a39c --- /dev/null +++ b/tests/ui/too_long_first_doc_paragraph-fix.stderr @@ -0,0 +1,20 @@ +error: first doc comment paragraph is too long + --> tests/ui/too_long_first_doc_paragraph-fix.rs:3:1 + | +LL | / /// A very short summary. +LL | | /// A much longer explanation that goes into a lot more detail about +LL | | /// how the thing works, possibly with doclinks and so one, +LL | | /// and probably spanning a many rows. Blablabla, it needs to be over +LL | | /// 200 characters so I needed to write something longeeeeeeer. + | |_ + | + = note: `-D clippy::too-long-first-doc-paragraph` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::too_long_first_doc_paragraph)]` +help: add an empty line + | +LL ~ /// A very short summary. +LL + /// + | + +error: aborting due to 1 previous error + diff --git a/tests/ui/too_long_first_doc_paragraph.rs b/tests/ui/too_long_first_doc_paragraph.rs new file mode 100644 index 00000000000..1042249c5b7 --- /dev/null +++ b/tests/ui/too_long_first_doc_paragraph.rs @@ -0,0 +1,53 @@ +//@no-rustfix + +#![warn(clippy::too_long_first_doc_paragraph)] + +/// Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc turpis nunc, lacinia +/// a dolor in, pellentesque aliquet enim. Cras nec maximus sem. Mauris arcu libero, +/// gravida non lacinia at, rhoncus eu lacus. +pub struct Bar; + +// Should not warn! (not an item visible on mod page) +/// Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc turpis nunc, lacinia +/// a dolor in, pellentesque aliquet enim. Cras nec maximus sem. Mauris arcu libero, +/// gravida non lacinia at, rhoncus eu lacus. +impl Bar {} + +// Should not warn! (less than 80 characters) +/// Lorem ipsum dolor sit amet, consectetur adipiscing elit. +/// +/// Nunc turpis nunc, lacinia +/// a dolor in, pellentesque aliquet enim. Cras nec maximus sem. Mauris arcu libero, +/// gravida non lacinia at, rhoncus eu lacus. +pub enum Enum { + A, +} + +/// Lorem +/// ipsum dolor sit amet, consectetur adipiscing elit. Nunc turpis nunc, lacinia +/// a dolor in, pellentesque aliquet enim. Cras nec maximus sem. Mauris arcu libero, +/// gravida non lacinia at, rhoncus eu lacus. +pub union Union { + a: u8, + b: u8, +} + +// Should not warn! (title) +/// # bla +/// Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc turpis nunc, lacinia +/// a dolor in, pellentesque aliquet enim. Cras nec maximus sem. Mauris arcu libero, +/// gravida non lacinia at, rhoncus eu lacus. +pub union Union2 { + a: u8, + b: u8, +} + +// Should not warn! (not public) +/// Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc turpis nunc, lacinia +/// a dolor in, pellentesque aliquet enim. Cras nec maximus sem. Mauris arcu libero, +/// gravida non lacinia at, rhoncus eu lacus. +fn f() {} + +fn main() { + // test code goes here +} diff --git a/tests/ui/too_long_first_doc_paragraph.stderr b/tests/ui/too_long_first_doc_paragraph.stderr new file mode 100644 index 00000000000..7f48e5cf884 --- /dev/null +++ b/tests/ui/too_long_first_doc_paragraph.stderr @@ -0,0 +1,22 @@ +error: first doc comment paragraph is too long + --> tests/ui/too_long_first_doc_paragraph.rs:5:1 + | +LL | / /// Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc turpis nunc, lacinia +LL | | /// a dolor in, pellentesque aliquet enim. Cras nec maximus sem. Mauris arcu libero, +LL | | /// gravida non lacinia at, rhoncus eu lacus. + | |_ + | + = note: `-D clippy::too-long-first-doc-paragraph` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::too_long_first_doc_paragraph)]` + +error: first doc comment paragraph is too long + --> tests/ui/too_long_first_doc_paragraph.rs:26:1 + | +LL | / /// Lorem +LL | | /// ipsum dolor sit amet, consectetur adipiscing elit. Nunc turpis nunc, lacinia +LL | | /// a dolor in, pellentesque aliquet enim. Cras nec maximus sem. Mauris arcu libero, +LL | | /// gravida non lacinia at, rhoncus eu lacus. + | |_ + +error: aborting due to 2 previous errors + diff --git a/tests/ui/unnecessary_lazy_eval.stderr b/tests/ui/unnecessary_lazy_eval.stderr index fcd60f48bcc..bcdf65b217e 100644 --- a/tests/ui/unnecessary_lazy_eval.stderr +++ b/tests/ui/unnecessary_lazy_eval.stderr @@ -2,316 +2,432 @@ error: unnecessary closure used to substitute value for `Option::None` --> tests/ui/unnecessary_lazy_eval.rs:83:13 | LL | let _ = opt.unwrap_or_else(|| 2); - | ^^^^-------------------- - | | - | help: use `unwrap_or(..)` instead: `unwrap_or(2)` + | ^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::unnecessary-lazy-evaluations` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::unnecessary_lazy_evaluations)]` +help: use `unwrap_or` instead + | +LL | let _ = opt.unwrap_or(2); + | ~~~~~~~~~~~~ error: unnecessary closure used to substitute value for `Option::None` --> tests/ui/unnecessary_lazy_eval.rs:84:13 | LL | let _ = opt.unwrap_or_else(|| astronomers_pi); - | ^^^^--------------------------------- - | | - | help: use `unwrap_or(..)` instead: `unwrap_or(astronomers_pi)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `unwrap_or` instead + | +LL | let _ = opt.unwrap_or(astronomers_pi); + | ~~~~~~~~~~~~~~~~~~~~~~~~~ error: unnecessary closure used to substitute value for `Option::None` --> tests/ui/unnecessary_lazy_eval.rs:85:13 | LL | let _ = opt.unwrap_or_else(|| ext_str.some_field); - | ^^^^------------------------------------- - | | - | help: use `unwrap_or(..)` instead: `unwrap_or(ext_str.some_field)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `unwrap_or` instead + | +LL | let _ = opt.unwrap_or(ext_str.some_field); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: unnecessary closure used to substitute value for `Option::None` --> tests/ui/unnecessary_lazy_eval.rs:87:13 | LL | let _ = opt.and_then(|_| ext_opt); - | ^^^^--------------------- - | | - | help: use `and(..)` instead: `and(ext_opt)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `and` instead + | +LL | let _ = opt.and(ext_opt); + | ~~~~~~~~~~~~ error: unnecessary closure used to substitute value for `Option::None` --> tests/ui/unnecessary_lazy_eval.rs:88:13 | LL | let _ = opt.or_else(|| ext_opt); - | ^^^^------------------- - | | - | help: use `or(..)` instead: `or(ext_opt)` + | ^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `or` instead + | +LL | let _ = opt.or(ext_opt); + | ~~~~~~~~~~~ error: unnecessary closure used to substitute value for `Option::None` --> tests/ui/unnecessary_lazy_eval.rs:89:13 | LL | let _ = opt.or_else(|| None); - | ^^^^---------------- - | | - | help: use `or(..)` instead: `or(None)` + | ^^^^^^^^^^^^^^^^^^^^ + | +help: use `or` instead + | +LL | let _ = opt.or(None); + | ~~~~~~~~ error: unnecessary closure used to substitute value for `Option::None` --> tests/ui/unnecessary_lazy_eval.rs:90:13 | LL | let _ = opt.get_or_insert_with(|| 2); - | ^^^^------------------------ - | | - | help: use `get_or_insert(..)` instead: `get_or_insert(2)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `get_or_insert` instead + | +LL | let _ = opt.get_or_insert(2); + | ~~~~~~~~~~~~~~~~ error: unnecessary closure used to substitute value for `Option::None` --> tests/ui/unnecessary_lazy_eval.rs:91:13 | LL | let _ = opt.ok_or_else(|| 2); - | ^^^^---------------- - | | - | help: use `ok_or(..)` instead: `ok_or(2)` + | ^^^^^^^^^^^^^^^^^^^^ + | +help: use `ok_or` instead + | +LL | let _ = opt.ok_or(2); + | ~~~~~~~~ error: unnecessary closure used to substitute value for `Option::None` --> tests/ui/unnecessary_lazy_eval.rs:92:13 | LL | let _ = nested_tuple_opt.unwrap_or_else(|| Some((1, 2))); - | ^^^^^^^^^^^^^^^^^------------------------------- - | | - | help: use `unwrap_or(..)` instead: `unwrap_or(Some((1, 2)))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `unwrap_or` instead + | +LL | let _ = nested_tuple_opt.unwrap_or(Some((1, 2))); + | ~~~~~~~~~~~~~~~~~~~~~~~ error: unnecessary closure used with `bool::then` --> tests/ui/unnecessary_lazy_eval.rs:93:13 | LL | let _ = cond.then(|| astronomers_pi); - | ^^^^^----------------------- - | | - | help: use `then_some(..)` instead: `then_some(astronomers_pi)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `then_some` instead + | +LL | let _ = cond.then_some(astronomers_pi); + | ~~~~~~~~~~~~~~~~~~~~~~~~~ error: unnecessary closure used with `bool::then` --> tests/ui/unnecessary_lazy_eval.rs:94:13 | LL | let _ = true.then(|| -> _ {}); - | ^^^^^---------------- - | | - | help: use `then_some(..)` instead: `then_some({})` + | ^^^^^^^^^^^^^^^^^^^^^ + | +help: use `then_some` instead + | +LL | let _ = true.then_some({}); + | ~~~~~~~~~~~~~ error: unnecessary closure used with `bool::then` --> tests/ui/unnecessary_lazy_eval.rs:95:13 | LL | let _ = true.then(|| {}); - | ^^^^^----------- - | | - | help: use `then_some(..)` instead: `then_some({})` + | ^^^^^^^^^^^^^^^^ + | +help: use `then_some` instead + | +LL | let _ = true.then_some({}); + | ~~~~~~~~~~~~~ error: unnecessary closure used to substitute value for `Option::None` --> tests/ui/unnecessary_lazy_eval.rs:99:13 | LL | let _ = Some(1).unwrap_or_else(|| *r); - | ^^^^^^^^--------------------- - | | - | help: use `unwrap_or(..)` instead: `unwrap_or(*r)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `unwrap_or` instead + | +LL | let _ = Some(1).unwrap_or(*r); + | ~~~~~~~~~~~~~ error: unnecessary closure used to substitute value for `Option::None` --> tests/ui/unnecessary_lazy_eval.rs:101:13 | LL | let _ = Some(1).unwrap_or_else(|| *b); - | ^^^^^^^^--------------------- - | | - | help: use `unwrap_or(..)` instead: `unwrap_or(*b)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `unwrap_or` instead + | +LL | let _ = Some(1).unwrap_or(*b); + | ~~~~~~~~~~~~~ error: unnecessary closure used to substitute value for `Option::None` --> tests/ui/unnecessary_lazy_eval.rs:103:13 | LL | let _ = Some(1).as_ref().unwrap_or_else(|| &r); - | ^^^^^^^^^^^^^^^^^--------------------- - | | - | help: use `unwrap_or(..)` instead: `unwrap_or(&r)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `unwrap_or` instead + | +LL | let _ = Some(1).as_ref().unwrap_or(&r); + | ~~~~~~~~~~~~~ error: unnecessary closure used to substitute value for `Option::None` --> tests/ui/unnecessary_lazy_eval.rs:104:13 | LL | let _ = Some(1).as_ref().unwrap_or_else(|| &b); - | ^^^^^^^^^^^^^^^^^--------------------- - | | - | help: use `unwrap_or(..)` instead: `unwrap_or(&b)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `unwrap_or` instead + | +LL | let _ = Some(1).as_ref().unwrap_or(&b); + | ~~~~~~~~~~~~~ error: unnecessary closure used to substitute value for `Option::None` --> tests/ui/unnecessary_lazy_eval.rs:107:13 | LL | let _ = Some(10).unwrap_or_else(|| 2); - | ^^^^^^^^^-------------------- - | | - | help: use `unwrap_or(..)` instead: `unwrap_or(2)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `unwrap_or` instead + | +LL | let _ = Some(10).unwrap_or(2); + | ~~~~~~~~~~~~ error: unnecessary closure used to substitute value for `Option::None` --> tests/ui/unnecessary_lazy_eval.rs:108:13 | LL | let _ = Some(10).and_then(|_| ext_opt); - | ^^^^^^^^^--------------------- - | | - | help: use `and(..)` instead: `and(ext_opt)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `and` instead + | +LL | let _ = Some(10).and(ext_opt); + | ~~~~~~~~~~~~ error: unnecessary closure used to substitute value for `Option::None` --> tests/ui/unnecessary_lazy_eval.rs:109:28 | LL | let _: Option = None.or_else(|| ext_opt); - | ^^^^^------------------- - | | - | help: use `or(..)` instead: `or(ext_opt)` + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `or` instead + | +LL | let _: Option = None.or(ext_opt); + | ~~~~~~~~~~~ error: unnecessary closure used to substitute value for `Option::None` --> tests/ui/unnecessary_lazy_eval.rs:110:13 | LL | let _ = None.get_or_insert_with(|| 2); - | ^^^^^------------------------ - | | - | help: use `get_or_insert(..)` instead: `get_or_insert(2)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `get_or_insert` instead + | +LL | let _ = None.get_or_insert(2); + | ~~~~~~~~~~~~~~~~ error: unnecessary closure used to substitute value for `Option::None` --> tests/ui/unnecessary_lazy_eval.rs:111:35 | LL | let _: Result = None.ok_or_else(|| 2); - | ^^^^^---------------- - | | - | help: use `ok_or(..)` instead: `ok_or(2)` + | ^^^^^^^^^^^^^^^^^^^^^ + | +help: use `ok_or` instead + | +LL | let _: Result = None.ok_or(2); + | ~~~~~~~~ error: unnecessary closure used to substitute value for `Option::None` --> tests/ui/unnecessary_lazy_eval.rs:112:28 | LL | let _: Option = None.or_else(|| None); - | ^^^^^---------------- - | | - | help: use `or(..)` instead: `or(None)` + | ^^^^^^^^^^^^^^^^^^^^^ + | +help: use `or` instead + | +LL | let _: Option = None.or(None); + | ~~~~~~~~ error: unnecessary closure used to substitute value for `Option::None` --> tests/ui/unnecessary_lazy_eval.rs:115:13 | LL | let _ = deep.0.unwrap_or_else(|| 2); - | ^^^^^^^-------------------- - | | - | help: use `unwrap_or(..)` instead: `unwrap_or(2)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `unwrap_or` instead + | +LL | let _ = deep.0.unwrap_or(2); + | ~~~~~~~~~~~~ error: unnecessary closure used to substitute value for `Option::None` --> tests/ui/unnecessary_lazy_eval.rs:116:13 | LL | let _ = deep.0.and_then(|_| ext_opt); - | ^^^^^^^--------------------- - | | - | help: use `and(..)` instead: `and(ext_opt)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `and` instead + | +LL | let _ = deep.0.and(ext_opt); + | ~~~~~~~~~~~~ error: unnecessary closure used to substitute value for `Option::None` --> tests/ui/unnecessary_lazy_eval.rs:117:13 | LL | let _ = deep.0.or_else(|| None); - | ^^^^^^^---------------- - | | - | help: use `or(..)` instead: `or(None)` + | ^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `or` instead + | +LL | let _ = deep.0.or(None); + | ~~~~~~~~ error: unnecessary closure used to substitute value for `Option::None` --> tests/ui/unnecessary_lazy_eval.rs:118:13 | LL | let _ = deep.0.get_or_insert_with(|| 2); - | ^^^^^^^------------------------ - | | - | help: use `get_or_insert(..)` instead: `get_or_insert(2)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `get_or_insert` instead + | +LL | let _ = deep.0.get_or_insert(2); + | ~~~~~~~~~~~~~~~~ error: unnecessary closure used to substitute value for `Option::None` --> tests/ui/unnecessary_lazy_eval.rs:119:13 | LL | let _ = deep.0.ok_or_else(|| 2); - | ^^^^^^^---------------- - | | - | help: use `ok_or(..)` instead: `ok_or(2)` + | ^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `ok_or` instead + | +LL | let _ = deep.0.ok_or(2); + | ~~~~~~~~ error: unnecessary closure used to substitute value for `Option::None` --> tests/ui/unnecessary_lazy_eval.rs:150:28 | LL | let _: Option = None.or_else(|| Some(3)); - | ^^^^^------------------- - | | - | help: use `or(..)` instead: `or(Some(3))` + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `or` instead + | +LL | let _: Option = None.or(Some(3)); + | ~~~~~~~~~~~ error: unnecessary closure used to substitute value for `Option::None` --> tests/ui/unnecessary_lazy_eval.rs:151:13 | LL | let _ = deep.0.or_else(|| Some(3)); - | ^^^^^^^------------------- - | | - | help: use `or(..)` instead: `or(Some(3))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `or` instead + | +LL | let _ = deep.0.or(Some(3)); + | ~~~~~~~~~~~ error: unnecessary closure used to substitute value for `Option::None` --> tests/ui/unnecessary_lazy_eval.rs:152:13 | LL | let _ = opt.or_else(|| Some(3)); - | ^^^^------------------- - | | - | help: use `or(..)` instead: `or(Some(3))` + | ^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `or` instead + | +LL | let _ = opt.or(Some(3)); + | ~~~~~~~~~~~ error: unnecessary closure used to substitute value for `Result::Err` --> tests/ui/unnecessary_lazy_eval.rs:158:13 | LL | let _ = res2.unwrap_or_else(|_| 2); - | ^^^^^--------------------- - | | - | help: use `unwrap_or(..)` instead: `unwrap_or(2)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `unwrap_or` instead + | +LL | let _ = res2.unwrap_or(2); + | ~~~~~~~~~~~~ error: unnecessary closure used to substitute value for `Result::Err` --> tests/ui/unnecessary_lazy_eval.rs:159:13 | LL | let _ = res2.unwrap_or_else(|_| astronomers_pi); - | ^^^^^---------------------------------- - | | - | help: use `unwrap_or(..)` instead: `unwrap_or(astronomers_pi)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `unwrap_or` instead + | +LL | let _ = res2.unwrap_or(astronomers_pi); + | ~~~~~~~~~~~~~~~~~~~~~~~~~ error: unnecessary closure used to substitute value for `Result::Err` --> tests/ui/unnecessary_lazy_eval.rs:160:13 | LL | let _ = res2.unwrap_or_else(|_| ext_str.some_field); - | ^^^^^-------------------------------------- - | | - | help: use `unwrap_or(..)` instead: `unwrap_or(ext_str.some_field)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `unwrap_or` instead + | +LL | let _ = res2.unwrap_or(ext_str.some_field); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: unnecessary closure used to substitute value for `Result::Err` --> tests/ui/unnecessary_lazy_eval.rs:182:35 | LL | let _: Result = res.and_then(|_| Err(2)); - | ^^^^-------------------- - | | - | help: use `and(..)` instead: `and(Err(2))` + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `and` instead + | +LL | let _: Result = res.and(Err(2)); + | ~~~~~~~~~~~ error: unnecessary closure used to substitute value for `Result::Err` --> tests/ui/unnecessary_lazy_eval.rs:183:35 | LL | let _: Result = res.and_then(|_| Err(astronomers_pi)); - | ^^^^--------------------------------- - | | - | help: use `and(..)` instead: `and(Err(astronomers_pi))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `and` instead + | +LL | let _: Result = res.and(Err(astronomers_pi)); + | ~~~~~~~~~~~~~~~~~~~~~~~~ error: unnecessary closure used to substitute value for `Result::Err` --> tests/ui/unnecessary_lazy_eval.rs:184:35 | LL | let _: Result = res.and_then(|_| Err(ext_str.some_field)); - | ^^^^------------------------------------- - | | - | help: use `and(..)` instead: `and(Err(ext_str.some_field))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `and` instead + | +LL | let _: Result = res.and(Err(ext_str.some_field)); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: unnecessary closure used to substitute value for `Result::Err` --> tests/ui/unnecessary_lazy_eval.rs:186:35 | LL | let _: Result = res.or_else(|_| Ok(2)); - | ^^^^------------------ - | | - | help: use `or(..)` instead: `or(Ok(2))` + | ^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `or` instead + | +LL | let _: Result = res.or(Ok(2)); + | ~~~~~~~~~ error: unnecessary closure used to substitute value for `Result::Err` --> tests/ui/unnecessary_lazy_eval.rs:187:35 | LL | let _: Result = res.or_else(|_| Ok(astronomers_pi)); - | ^^^^------------------------------- - | | - | help: use `or(..)` instead: `or(Ok(astronomers_pi))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `or` instead + | +LL | let _: Result = res.or(Ok(astronomers_pi)); + | ~~~~~~~~~~~~~~~~~~~~~~ error: unnecessary closure used to substitute value for `Result::Err` --> tests/ui/unnecessary_lazy_eval.rs:188:35 | LL | let _: Result = res.or_else(|_| Ok(ext_str.some_field)); - | ^^^^----------------------------------- - | | - | help: use `or(..)` instead: `or(Ok(ext_str.some_field))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `or` instead + | +LL | let _: Result = res.or(Ok(ext_str.some_field)); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~ error: unnecessary closure used to substitute value for `Result::Err` --> tests/ui/unnecessary_lazy_eval.rs:189:35 @@ -324,193 +440,265 @@ LL | | // some lines ... | LL | | // some lines LL | | or_else(|_| Ok(ext_str.some_field)); - | |_____----------------------------------^ - | | - | help: use `or(..)` instead: `or(Ok(ext_str.some_field))` + | |_______________________________________^ + | +help: use `or` instead + | +LL | or(Ok(ext_str.some_field)); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~ error: unnecessary closure used with `bool::then` --> tests/ui/unnecessary_lazy_eval.rs:219:14 | LL | let _x = false.then(|| i32::MAX + 1); - | ^^^^^^--------------------- - | | - | help: use `then_some(..)` instead: `then_some(i32::MAX + 1)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `then_some` instead + | +LL | let _x = false.then_some(i32::MAX + 1); + | ~~~~~~~~~~~~~~~~~~~~~~~ error: unnecessary closure used with `bool::then` --> tests/ui/unnecessary_lazy_eval.rs:221:14 | LL | let _x = false.then(|| i32::MAX * 2); - | ^^^^^^--------------------- - | | - | help: use `then_some(..)` instead: `then_some(i32::MAX * 2)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `then_some` instead + | +LL | let _x = false.then_some(i32::MAX * 2); + | ~~~~~~~~~~~~~~~~~~~~~~~ error: unnecessary closure used with `bool::then` --> tests/ui/unnecessary_lazy_eval.rs:223:14 | LL | let _x = false.then(|| i32::MAX - 1); - | ^^^^^^--------------------- - | | - | help: use `then_some(..)` instead: `then_some(i32::MAX - 1)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `then_some` instead + | +LL | let _x = false.then_some(i32::MAX - 1); + | ~~~~~~~~~~~~~~~~~~~~~~~ error: unnecessary closure used with `bool::then` --> tests/ui/unnecessary_lazy_eval.rs:225:14 | LL | let _x = false.then(|| i32::MIN - 1); - | ^^^^^^--------------------- - | | - | help: use `then_some(..)` instead: `then_some(i32::MIN - 1)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `then_some` instead + | +LL | let _x = false.then_some(i32::MIN - 1); + | ~~~~~~~~~~~~~~~~~~~~~~~ error: unnecessary closure used with `bool::then` --> tests/ui/unnecessary_lazy_eval.rs:227:14 | LL | let _x = false.then(|| (1 + 2 * 3 - 2 / 3 + 9) << 2); - | ^^^^^^------------------------------------- - | | - | help: use `then_some(..)` instead: `then_some((1 + 2 * 3 - 2 / 3 + 9) << 2)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `then_some` instead + | +LL | let _x = false.then_some((1 + 2 * 3 - 2 / 3 + 9) << 2); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: unnecessary closure used with `bool::then` --> tests/ui/unnecessary_lazy_eval.rs:229:14 | LL | let _x = false.then(|| 255u8 << 7); - | ^^^^^^------------------- - | | - | help: use `then_some(..)` instead: `then_some(255u8 << 7)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `then_some` instead + | +LL | let _x = false.then_some(255u8 << 7); + | ~~~~~~~~~~~~~~~~~~~~~ error: unnecessary closure used with `bool::then` --> tests/ui/unnecessary_lazy_eval.rs:231:14 | LL | let _x = false.then(|| 255u8 << 8); - | ^^^^^^------------------- - | | - | help: use `then_some(..)` instead: `then_some(255u8 << 8)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `then_some` instead + | +LL | let _x = false.then_some(255u8 << 8); + | ~~~~~~~~~~~~~~~~~~~~~ error: unnecessary closure used with `bool::then` --> tests/ui/unnecessary_lazy_eval.rs:233:14 | LL | let _x = false.then(|| 255u8 >> 8); - | ^^^^^^------------------- - | | - | help: use `then_some(..)` instead: `then_some(255u8 >> 8)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `then_some` instead + | +LL | let _x = false.then_some(255u8 >> 8); + | ~~~~~~~~~~~~~~~~~~~~~ error: unnecessary closure used with `bool::then` --> tests/ui/unnecessary_lazy_eval.rs:236:14 | LL | let _x = false.then(|| i32::MAX + -1); - | ^^^^^^---------------------- - | | - | help: use `then_some(..)` instead: `then_some(i32::MAX + -1)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `then_some` instead + | +LL | let _x = false.then_some(i32::MAX + -1); + | ~~~~~~~~~~~~~~~~~~~~~~~~ error: unnecessary closure used with `bool::then` --> tests/ui/unnecessary_lazy_eval.rs:238:14 | LL | let _x = false.then(|| -i32::MAX); - | ^^^^^^------------------ - | | - | help: use `then_some(..)` instead: `then_some(-i32::MAX)` + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `then_some` instead + | +LL | let _x = false.then_some(-i32::MAX); + | ~~~~~~~~~~~~~~~~~~~~ error: unnecessary closure used with `bool::then` --> tests/ui/unnecessary_lazy_eval.rs:240:14 | LL | let _x = false.then(|| -i32::MIN); - | ^^^^^^------------------ - | | - | help: use `then_some(..)` instead: `then_some(-i32::MIN)` + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `then_some` instead + | +LL | let _x = false.then_some(-i32::MIN); + | ~~~~~~~~~~~~~~~~~~~~ error: unnecessary closure used with `bool::then` --> tests/ui/unnecessary_lazy_eval.rs:243:14 | LL | let _x = false.then(|| 255 >> -7); - | ^^^^^^------------------ - | | - | help: use `then_some(..)` instead: `then_some(255 >> -7)` + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `then_some` instead + | +LL | let _x = false.then_some(255 >> -7); + | ~~~~~~~~~~~~~~~~~~~~ error: unnecessary closure used with `bool::then` --> tests/ui/unnecessary_lazy_eval.rs:245:14 | LL | let _x = false.then(|| 255 << -1); - | ^^^^^^------------------ - | | - | help: use `then_some(..)` instead: `then_some(255 << -1)` + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `then_some` instead + | +LL | let _x = false.then_some(255 << -1); + | ~~~~~~~~~~~~~~~~~~~~ error: unnecessary closure used with `bool::then` --> tests/ui/unnecessary_lazy_eval.rs:247:14 | LL | let _x = false.then(|| 1 / 0); - | ^^^^^^-------------- - | | - | help: use `then_some(..)` instead: `then_some(1 / 0)` + | ^^^^^^^^^^^^^^^^^^^^ + | +help: use `then_some` instead + | +LL | let _x = false.then_some(1 / 0); + | ~~~~~~~~~~~~~~~~ error: unnecessary closure used with `bool::then` --> tests/ui/unnecessary_lazy_eval.rs:249:14 | LL | let _x = false.then(|| x << -1); - | ^^^^^^---------------- - | | - | help: use `then_some(..)` instead: `then_some(x << -1)` + | ^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `then_some` instead + | +LL | let _x = false.then_some(x << -1); + | ~~~~~~~~~~~~~~~~~~ error: unnecessary closure used with `bool::then` --> tests/ui/unnecessary_lazy_eval.rs:251:14 | LL | let _x = false.then(|| x << 2); - | ^^^^^^--------------- - | | - | help: use `then_some(..)` instead: `then_some(x << 2)` + | ^^^^^^^^^^^^^^^^^^^^^ + | +help: use `then_some` instead + | +LL | let _x = false.then_some(x << 2); + | ~~~~~~~~~~~~~~~~~ error: unnecessary closure used with `bool::then` --> tests/ui/unnecessary_lazy_eval.rs:261:14 | LL | let _x = false.then(|| x / 0); - | ^^^^^^-------------- - | | - | help: use `then_some(..)` instead: `then_some(x / 0)` + | ^^^^^^^^^^^^^^^^^^^^ + | +help: use `then_some` instead + | +LL | let _x = false.then_some(x / 0); + | ~~~~~~~~~~~~~~~~ error: unnecessary closure used with `bool::then` --> tests/ui/unnecessary_lazy_eval.rs:263:14 | LL | let _x = false.then(|| x % 0); - | ^^^^^^-------------- - | | - | help: use `then_some(..)` instead: `then_some(x % 0)` + | ^^^^^^^^^^^^^^^^^^^^ + | +help: use `then_some` instead + | +LL | let _x = false.then_some(x % 0); + | ~~~~~~~~~~~~~~~~ error: unnecessary closure used with `bool::then` --> tests/ui/unnecessary_lazy_eval.rs:266:14 | LL | let _x = false.then(|| 1 / -1); - | ^^^^^^--------------- - | | - | help: use `then_some(..)` instead: `then_some(1 / -1)` + | ^^^^^^^^^^^^^^^^^^^^^ + | +help: use `then_some` instead + | +LL | let _x = false.then_some(1 / -1); + | ~~~~~~~~~~~~~~~~~ error: unnecessary closure used with `bool::then` --> tests/ui/unnecessary_lazy_eval.rs:268:14 | LL | let _x = false.then(|| i32::MIN / -1); - | ^^^^^^---------------------- - | | - | help: use `then_some(..)` instead: `then_some(i32::MIN / -1)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `then_some` instead + | +LL | let _x = false.then_some(i32::MIN / -1); + | ~~~~~~~~~~~~~~~~~~~~~~~~ error: unnecessary closure used with `bool::then` --> tests/ui/unnecessary_lazy_eval.rs:271:14 | LL | let _x = false.then(|| i32::MIN / 0); - | ^^^^^^--------------------- - | | - | help: use `then_some(..)` instead: `then_some(i32::MIN / 0)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `then_some` instead + | +LL | let _x = false.then_some(i32::MIN / 0); + | ~~~~~~~~~~~~~~~~~~~~~~~ error: unnecessary closure used with `bool::then` --> tests/ui/unnecessary_lazy_eval.rs:273:14 | LL | let _x = false.then(|| 4 / 2); - | ^^^^^^-------------- - | | - | help: use `then_some(..)` instead: `then_some(4 / 2)` + | ^^^^^^^^^^^^^^^^^^^^ + | +help: use `then_some` instead + | +LL | let _x = false.then_some(4 / 2); + | ~~~~~~~~~~~~~~~~ error: unnecessary closure used with `bool::then` --> tests/ui/unnecessary_lazy_eval.rs:281:14 | LL | let _x = false.then(|| f1 + f2); - | ^^^^^^---------------- - | | - | help: use `then_some(..)` instead: `then_some(f1 + f2)` + | ^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `then_some` instead + | +LL | let _x = false.then_some(f1 + f2); + | ~~~~~~~~~~~~~~~~~~ error: aborting due to 63 previous errors diff --git a/tests/ui/unnecessary_lazy_eval_unfixable.stderr b/tests/ui/unnecessary_lazy_eval_unfixable.stderr index b566b119571..390235b2124 100644 --- a/tests/ui/unnecessary_lazy_eval_unfixable.stderr +++ b/tests/ui/unnecessary_lazy_eval_unfixable.stderr @@ -2,36 +2,47 @@ error: unnecessary closure used to substitute value for `Result::Err` --> tests/ui/unnecessary_lazy_eval_unfixable.rs:13:13 | LL | let _ = Ok(1).unwrap_or_else(|()| 2); - | ^^^^^^---------------------- - | | - | help: use `unwrap_or(..)` instead: `unwrap_or(2)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::unnecessary-lazy-evaluations` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::unnecessary_lazy_evaluations)]` +help: use `unwrap_or` instead + | +LL | let _ = Ok(1).unwrap_or(2); + | ~~~~~~~~~~~~ error: unnecessary closure used to substitute value for `Result::Err` --> tests/ui/unnecessary_lazy_eval_unfixable.rs:19:13 | LL | let _ = Ok(1).unwrap_or_else(|e::E| 2); - | ^^^^^^------------------------ - | | - | help: use `unwrap_or(..)` instead: `unwrap_or(2)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `unwrap_or` instead + | +LL | let _ = Ok(1).unwrap_or(2); + | ~~~~~~~~~~~~ error: unnecessary closure used to substitute value for `Result::Err` --> tests/ui/unnecessary_lazy_eval_unfixable.rs:21:13 | LL | let _ = Ok(1).unwrap_or_else(|SomeStruct { .. }| 2); - | ^^^^^^------------------------------------- - | | - | help: use `unwrap_or(..)` instead: `unwrap_or(2)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `unwrap_or` instead + | +LL | let _ = Ok(1).unwrap_or(2); + | ~~~~~~~~~~~~ error: unnecessary closure used with `bool::then` --> tests/ui/unnecessary_lazy_eval_unfixable.rs:31:13 | LL | let _ = true.then(|| -> &[u8] { &[] }); - | ^^^^^------------------------- - | | - | help: use `then_some(..)` instead: `then_some({ &[] })` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `then_some` instead + | +LL | let _ = true.then_some({ &[] }); + | ~~~~~~~~~~~~~~~~~~ error: aborting due to 4 previous errors diff --git a/triagebot.toml b/triagebot.toml index dcf00e4e384..99b3560a064 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -20,6 +20,7 @@ new_pr = true [assign] contributing_url = "https://github.com/rust-lang/rust-clippy/blob/master/CONTRIBUTING.md" users_on_vacation = [ + "flip1995", "matthiaskrgr", "giraffate", ] diff --git a/util/gh-pages/index.html b/util/gh-pages/index.html index 300c9de178f..f3d7e504fdf 100644 --- a/util/gh-pages/index.html +++ b/util/gh-pages/index.html @@ -23,378 +23,25 @@ Otherwise, have a great day =^.^= - - + -
-
🖌
-
    -
  • {{name}}
  • -
+
+
+
+
Theme
+ + +
@@ -592,7 +239,7 @@ Otherwise, have a great day =^.^=
Applicability: - {{lint.applicability.applicability}} + {{lint.applicability}} (?)
@@ -605,8 +252,8 @@ Otherwise, have a great day =^.^= Related Issues
-
diff --git a/util/gh-pages/script.js b/util/gh-pages/script.js index ed1e090e1b5..1a5330bc0e5 100644 --- a/util/gh-pages/script.js +++ b/util/gh-pages/script.js @@ -50,24 +50,6 @@ ); }; }) - .directive('themeDropdown', function ($document) { - return { - restrict: 'A', - link: function ($scope, $element, $attr) { - $element.bind('click', function () { - $element.toggleClass('open'); - $element.addClass('open-recent'); - }); - - $document.bind('click', function () { - if (!$element.hasClass('open-recent')) { - $element.removeClass('open'); - } - $element.removeClass('open-recent'); - }) - } - } - }) .directive('filterDropdown', function ($document) { return { restrict: 'A', @@ -114,28 +96,19 @@ cargo: true, complexity: true, correctness: true, - deprecated: false, nursery: true, pedantic: true, perf: true, restriction: true, style: true, suspicious: true, + deprecated: false, } $scope.groups = { ...GROUPS_FILTER_DEFAULT }; - const THEMES_DEFAULT = { - light: "Light", - rust: "Rust", - coal: "Coal", - navy: "Navy", - ayu: "Ayu" - }; - $scope.themes = THEMES_DEFAULT; - $scope.versionFilters = { "≥": {enabled: false, minorVersion: null }, "≤": {enabled: false, minorVersion: null }, @@ -153,11 +126,10 @@ ); const APPLICABILITIES_FILTER_DEFAULT = { - Unspecified: true, - Unresolved: true, MachineApplicable: true, MaybeIncorrect: true, - HasPlaceholders: true + HasPlaceholders: true, + Unspecified: true, }; $scope.applicabilities = { @@ -321,10 +293,6 @@ $location.path($scope.search); } - $scope.selectTheme = function (theme) { - setTheme(theme, true); - } - $scope.toggleLevels = function (value) { const levels = $scope.levels; for (const key in levels) { @@ -456,7 +424,7 @@ } $scope.byApplicabilities = function (lint) { - return $scope.applicabilities[lint.applicability.applicability]; + return $scope.applicabilities[lint.applicability]; }; // Show details for one lint @@ -537,6 +505,16 @@ function getQueryVariable(variable) { } } +function storeValue(settingName, value) { + try { + localStorage.setItem(`clippy-lint-list-${settingName}`, value); + } catch (e) { } +} + +function loadValue(settingName) { + return localStorage.getItem(`clippy-lint-list-${settingName}`); +} + function setTheme(theme, store) { let enableHighlight = false; let enableNight = false; @@ -569,14 +547,14 @@ function setTheme(theme, store) { document.getElementById("styleAyu").disabled = !enableAyu; if (store) { - try { - localStorage.setItem('clippy-lint-list-theme', theme); - } catch (e) { } + storeValue("theme", theme); + } else { + document.getElementById(`theme-choice`).value = theme; } } function handleShortcut(ev) { - if (ev.ctrlKey || ev.altKey || ev.metaKey) { + if (ev.ctrlKey || ev.altKey || ev.metaKey || disableShortcuts) { return; } @@ -601,11 +579,51 @@ function handleShortcut(ev) { document.addEventListener("keypress", handleShortcut); document.addEventListener("keydown", handleShortcut); +function changeSetting(elem) { + if (elem.id === "disable-shortcuts") { + disableShortcuts = elem.checked; + storeValue(elem.id, elem.checked); + } +} + +function onEachLazy(lazyArray, func) { + const arr = Array.prototype.slice.call(lazyArray); + for (const el of arr) { + func(el); + } +} + +function handleBlur(event) { + const parent = document.getElementById("settings-dropdown"); + if (!parent.contains(document.activeElement) && + !parent.contains(event.relatedTarget) + ) { + parent.classList.remove("open"); + } +} + +function generateSettings() { + const settings = document.getElementById("settings-dropdown"); + const settingsButton = settings.querySelector(".settings-icon") + settingsButton.onclick = () => settings.classList.toggle("open"); + settingsButton.onblur = handleBlur; + const settingsMenu = settings.querySelector(".settings-menu"); + settingsMenu.onblur = handleBlur; + onEachLazy( + settingsMenu.querySelectorAll("input"), + el => el.onblur = handleBlur, + ); +} + +generateSettings(); + // loading the theme after the initial load const prefersDark = window.matchMedia("(prefers-color-scheme: dark)"); -const theme = localStorage.getItem('clippy-lint-list-theme'); +const theme = loadValue('theme'); if (prefersDark.matches && !theme) { setTheme("coal", false); } else { setTheme(theme, false); } +let disableShortcuts = loadValue('disable-shortcuts') === "true"; +document.getElementById("disable-shortcuts").checked = disableShortcuts; diff --git a/util/gh-pages/style.css b/util/gh-pages/style.css new file mode 100644 index 00000000000..a9485d51104 --- /dev/null +++ b/util/gh-pages/style.css @@ -0,0 +1,398 @@ +blockquote { font-size: 1em; } + +[ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak { + display: none !important; +} + +.dropdown-menu { + color: var(--fg); + background: var(--theme-popup-bg); + border: 1px solid var(--theme-popup-border); +} + +.dropdown-menu .divider { + background-color: var(--theme-popup-border); +} + +.dropdown-menu .checkbox { + display: block; + white-space: nowrap; + margin: 0; +} +.dropdown-menu .checkbox label { + padding: 3px 20px; + width: 100%; +} + +.dropdown-menu .checkbox input { + position: relative; + margin: 0 0.5rem 0; + padding: 0; +} + +.dropdown-menu .checkbox:hover { + background-color: var(--theme-hover); +} + +div.panel div.panel-body button { + background: var(--searchbar-bg); + color: var(--searchbar-fg); + border-color: var(--theme-popup-border); +} + +div.panel div.panel-body button:hover { + box-shadow: 0 0 3px var(--searchbar-shadow-color); +} + +div.panel div.panel-body button.open { + filter: brightness(90%); +} + +.dropdown-toggle .badge { + background-color: #777; +} + +.panel-heading { cursor: pointer; } + +.panel-title { display: flex; flex-wrap: wrap;} +.panel-title .label { display: inline-block; } + +.panel-title-name { flex: 1; min-width: 400px;} +.panel-title-name span { vertical-align: bottom; } + +.panel .panel-title-name .anchor { display: none; } +.panel:hover .panel-title-name .anchor { display: inline;} + +.search-control { + margin-top: 15px; +} + +@media (min-width: 992px) { + .search-control { + margin-top: 0; + } +} + +@media (min-width: 405px) { + #upper-filters { + display: flex; + flex-wrap: wrap; + } +} + +@media (max-width: 430px) { + /* Turn the version filter list to the left */ + #version-filter-selector { + right: 0; + left: auto; + } +} + +@media (max-width: 412px) { + #upper-filters, + .panel-body .search-control { + padding-right: 8px; + padding-left: 8px; + } +} + +.label { + padding-top: 0.3em; + padding-bottom: 0.3em; +} + +.label-lint-group { + min-width: 8em; +} +.label-lint-level { + min-width: 4em; +} + +.label-lint-level-allow { + background-color: #5cb85c; +} +.label-lint-level-warn { + background-color: #f0ad4e; +} +.label-lint-level-deny { + background-color: #d9534f; +} +.label-lint-level-none { + background-color: #777777; + opacity: 0.5; +} + +.label-group-deprecated { + opacity: 0.5; +} + +.label-doc-folding { + color: #000; + background-color: #fff; + border: 1px solid var(--theme-popup-border); +} +.label-doc-folding:hover { + background-color: #e6e6e6; +} + +.lint-doc-md > h3 { + border-top: 1px solid var(--theme-popup-border); + padding: 10px 15px; + margin: 0 -15px; + font-size: 18px; +} +.lint-doc-md > h3:first-child { + border-top: none; + padding-top: 0px; +} + +@media (max-width:749px) { + .lint-additional-info-container { + display: flex; + flex-flow: column; + } + .lint-additional-info-item + .lint-additional-info-item { + border-top: 1px solid var(--theme-popup-border); + } +} +@media (min-width:750px) { + .lint-additional-info-container { + display: flex; + flex-flow: row; + } + .lint-additional-info-item + .lint-additional-info-item { + border-left: 1px solid var(--theme-popup-border); + } +} + +.lint-additional-info-item { + display: inline-flex; + min-width: 200px; + flex-grow: 1; + padding: 9px 5px 5px 15px; +} + +.label-applicability { + background-color: #777777; + margin: auto 5px; +} + +.label-version { + background-color: #777777; + margin: auto 5px; + font-family: monospace; +} + +details { + border-radius: 4px; + padding: .5em .5em 0; +} + +code { + white-space: pre !important; +} + +summary { + font-weight: bold; + margin: -.5em -.5em 0; + padding: .5em; + display: revert; +} + +details[open] { + padding: .5em; +} + +/* Expanding the mdBook theme*/ +.light { + --inline-code-bg: #f6f7f6; +} +.rust { + --inline-code-bg: #f6f7f6; +} +.coal { + --inline-code-bg: #1d1f21; +} +.navy { + --inline-code-bg: #1d1f21; +} +.ayu { + --inline-code-bg: #191f26; +} + +#settings-dropdown { + position: absolute; + margin: 0.7em; + z-index: 10; + display: flex; +} + +/* Applying the mdBook theme */ +.settings-icon { + text-align: center; + width: 2em; + height: 2em; + line-height: 2em; + border: solid 1px var(--icons); + border-radius: 5px; + user-select: none; + cursor: pointer; + background: var(--theme-hover); +} +.settings-menu { + display: none; + list-style: none; + border: 1px solid var(--theme-popup-border); + border-radius: 5px; + color: var(--fg); + background: var(--theme-popup-bg); + overflow: hidden; + padding: 9px; + width: 207px; + position: absolute; + top: 28px; +} + +.settings-icon::before { + /* Wheel */ + content: url('data:image/svg+xml,\ +'); + width: 18px; + height: 18px; + display: block; + filter: invert(0.7); + padding-left: 4px; + padding-top: 3px; +} + +.settings-menu * { + font-weight: normal; +} + +.settings-menu label { + cursor: pointer; +} + +#settings-dropdown.open .settings-menu { + display: block; +} + +#theme-choice { + margin-bottom: 10px; + background: var(--searchbar-bg); + color: var(--searchbar-fg); + border-color: var(--theme-popup-border); + border-radius: 5px; + cursor: pointer; + width: 100%; + border-width: 1px; + padding: 5px; +} + +.alert { + color: var(--fg); + background: var(--theme-hover); + border: 1px solid var(--theme-popup-border); +} +.page-header { + border-color: var(--theme-popup-border); +} +.panel-default > .panel-heading { + background: var(--theme-hover); + color: var(--fg); + border: 1px solid var(--theme-popup-border); +} +.panel-default > .panel-heading:hover { + filter: brightness(90%); +} +.list-group-item { + background: 0%; + border: 1px solid var(--theme-popup-border); +} +.panel, pre, hr { + background: var(--bg); + border: 1px solid var(--theme-popup-border); +} + +#version-filter-selector .checkbox { + display: flex; +} + +#version-filter { + min-width: available; +} + +#version-filter li label { + padding-right: 0; + width: 35%; +} + +.version-filter-input { + height: 60%; + width: 30%; + text-align: center; + border: none; + border-bottom: 1px solid #000000; +} + +#filter-label, .filter-clear { + background: var(--searchbar-bg); + color: var(--searchbar-fg); + border-color: var(--theme-popup-border); + filter: brightness(95%); +} +#filter-label:hover, .filter-clear:hover { + filter: brightness(90%); +} +.filter-input { + background: var(--searchbar-bg); + color: var(--searchbar-fg); + border-color: var(--theme-popup-border); +} + +.filter-input::-webkit-input-placeholder, +.filter-input::-moz-placeholder { + color: var(--searchbar-fg); + opacity: 30%; +} + +.expansion-group { + margin-top: 15px; + padding: 0px 8px; + display: flex; + flex-wrap: nowrap; +} + +@media (min-width: 992px) { + .expansion-group { + margin-top: 0; + padding: 0px 15px; + } +} + +.expansion-control { + width: 50%; +} + +:not(pre) > code { + color: var(--inline-code-color); + background-color: var(--inline-code-bg); +} +html { + scrollbar-color: var(--scrollbar) var(--bg); +} +body { + background: var(--bg); + color: var(--fg); +} From d40e04a1cb08d00736909bfb81be01e4cca9d6d6 Mon Sep 17 00:00:00 2001 From: WeiTheShinobi Date: Sun, 25 Aug 2024 20:51:26 +0800 Subject: [PATCH 044/683] `used_underscore_items` will not lint exteranl item --- clippy_lints/src/misc.rs | 8 +++++- tests/ui/auxiliary/external_item.rs | 7 ++++++ tests/ui/used_underscore_items.rs | 12 +++++++++ tests/ui/used_underscore_items.stderr | 36 +++++++++++++-------------- 4 files changed, 44 insertions(+), 19 deletions(-) create mode 100644 tests/ui/auxiliary/external_item.rs diff --git a/clippy_lints/src/misc.rs b/clippy_lints/src/misc.rs index 3fc3f2b3b7f..3e80e48a948 100644 --- a/clippy_lints/src/misc.rs +++ b/clippy_lints/src/misc.rs @@ -7,6 +7,7 @@ use clippy_utils::{ }; use rustc_errors::Applicability; use rustc_hir::def::Res; +use rustc_hir::def_id::LOCAL_CRATE; use rustc_hir::intravisit::FnKind; use rustc_hir::{ BinOpKind, BindingMode, Body, ByRef, Expr, ExprKind, FnDecl, Mutability, PatKind, QPath, Stmt, StmtKind, @@ -281,9 +282,14 @@ fn used_underscore_items<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { }, _ => return, }; + let name = ident.name.as_str(); let definition_span = cx.tcx.def_span(def_id); - if name.starts_with('_') && !name.starts_with("__") && !definition_span.from_expansion() { + if name.starts_with('_') + && !name.starts_with("__") + && !definition_span.from_expansion() + && def_id.krate == LOCAL_CRATE + { span_lint_and_then( cx, USED_UNDERSCORE_ITEMS, diff --git a/tests/ui/auxiliary/external_item.rs b/tests/ui/auxiliary/external_item.rs new file mode 100644 index 00000000000..ca4bc369e44 --- /dev/null +++ b/tests/ui/auxiliary/external_item.rs @@ -0,0 +1,7 @@ +pub struct _ExternalStruct {} + +impl _ExternalStruct { + pub fn _foo(self) {} +} + +pub fn _exernal_foo() {} diff --git a/tests/ui/used_underscore_items.rs b/tests/ui/used_underscore_items.rs index 6b2ca44e32c..223016a5c96 100644 --- a/tests/ui/used_underscore_items.rs +++ b/tests/ui/used_underscore_items.rs @@ -1,6 +1,9 @@ +//@aux-build:external_item.rs #![allow(unused)] #![warn(clippy::used_underscore_items)] +extern crate external_item; + // should not lint macro macro_rules! macro_wrap_func { () => { @@ -49,3 +52,12 @@ fn main() { let foo_struct2 = a::b::c::_FooStruct2 {}; foo_struct2._method_call(); } + +// should not lint exteranl crate. +// user cannot control how others name their items +fn external_item_call() { + let foo_struct3 = external_item::_ExternalStruct {}; + foo_struct3._foo(); + + external_item::_exernal_foo(); +} diff --git a/tests/ui/used_underscore_items.stderr b/tests/ui/used_underscore_items.stderr index 127d8248a94..93ac3a6fec6 100644 --- a/tests/ui/used_underscore_items.stderr +++ b/tests/ui/used_underscore_items.stderr @@ -1,11 +1,11 @@ error: used underscore-prefixed item - --> tests/ui/used_underscore_items.rs:40:5 + --> tests/ui/used_underscore_items.rs:43:5 | LL | _foo1(); | ^^^^^^^ | note: item is defined here - --> tests/ui/used_underscore_items.rs:19:1 + --> tests/ui/used_underscore_items.rs:22:1 | LL | fn _foo1() {} | ^^^^^^^^^^ @@ -13,97 +13,97 @@ LL | fn _foo1() {} = help: to override `-D warnings` add `#[allow(clippy::used_underscore_items)]` error: used underscore-prefixed item - --> tests/ui/used_underscore_items.rs:41:13 + --> tests/ui/used_underscore_items.rs:44:13 | LL | let _ = _foo2(); | ^^^^^^^ | note: item is defined here - --> tests/ui/used_underscore_items.rs:21:1 + --> tests/ui/used_underscore_items.rs:24:1 | LL | fn _foo2() -> i32 { | ^^^^^^^^^^^^^^^^^ error: used underscore-prefixed item - --> tests/ui/used_underscore_items.rs:42:5 + --> tests/ui/used_underscore_items.rs:45:5 | LL | a::b::c::_foo3(); | ^^^^^^^^^^^^^^^^ | note: item is defined here - --> tests/ui/used_underscore_items.rs:28:13 + --> tests/ui/used_underscore_items.rs:31:13 | LL | pub fn _foo3() {} | ^^^^^^^^^^^^^^ error: used underscore-prefixed item - --> tests/ui/used_underscore_items.rs:43:14 + --> tests/ui/used_underscore_items.rs:46:14 | LL | let _ = &_FooStruct {}; | ^^^^^^^^^^^^^ | note: item is defined here - --> tests/ui/used_underscore_items.rs:13:1 + --> tests/ui/used_underscore_items.rs:16:1 | LL | struct _FooStruct {} | ^^^^^^^^^^^^^^^^^ error: used underscore-prefixed item - --> tests/ui/used_underscore_items.rs:44:13 + --> tests/ui/used_underscore_items.rs:47:13 | LL | let _ = _FooStruct {}; | ^^^^^^^^^^^^^ | note: item is defined here - --> tests/ui/used_underscore_items.rs:13:1 + --> tests/ui/used_underscore_items.rs:16:1 | LL | struct _FooStruct {} | ^^^^^^^^^^^^^^^^^ error: used underscore-prefixed item - --> tests/ui/used_underscore_items.rs:46:22 + --> tests/ui/used_underscore_items.rs:49:22 | LL | let foo_struct = _FooStruct {}; | ^^^^^^^^^^^^^ | note: item is defined here - --> tests/ui/used_underscore_items.rs:13:1 + --> tests/ui/used_underscore_items.rs:16:1 | LL | struct _FooStruct {} | ^^^^^^^^^^^^^^^^^ error: used underscore-prefixed item - --> tests/ui/used_underscore_items.rs:47:5 + --> tests/ui/used_underscore_items.rs:50:5 | LL | foo_struct._method_call(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ | note: item is defined here - --> tests/ui/used_underscore_items.rs:16:5 + --> tests/ui/used_underscore_items.rs:19:5 | LL | fn _method_call(self) {} | ^^^^^^^^^^^^^^^^^^^^^ error: used underscore-prefixed item - --> tests/ui/used_underscore_items.rs:49:23 + --> tests/ui/used_underscore_items.rs:52:23 | LL | let foo_struct2 = a::b::c::_FooStruct2 {}; | ^^^^^^^^^^^^^^^^^^^^^^^ | note: item is defined here - --> tests/ui/used_underscore_items.rs:30:13 + --> tests/ui/used_underscore_items.rs:33:13 | LL | pub struct _FooStruct2 {} | ^^^^^^^^^^^^^^^^^^^^^^ error: used underscore-prefixed item - --> tests/ui/used_underscore_items.rs:50:5 + --> tests/ui/used_underscore_items.rs:53:5 | LL | foo_struct2._method_call(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: item is defined here - --> tests/ui/used_underscore_items.rs:33:17 + --> tests/ui/used_underscore_items.rs:36:17 | LL | pub fn _method_call(self) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ From 494112e51f7a2b59866c835810c3e87a10912c0a Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Mon, 26 Aug 2024 20:01:29 +0500 Subject: [PATCH 045/683] Fix manual_range_patterns case with one element at OR --- clippy_lints/src/manual_range_patterns.rs | 5 +++-- tests/ui/manual_range_patterns.fixed | 8 ++++++++ tests/ui/manual_range_patterns.rs | 8 ++++++++ 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/manual_range_patterns.rs b/clippy_lints/src/manual_range_patterns.rs index 9afb2b5bc84..66d2ab6b24a 100644 --- a/clippy_lints/src/manual_range_patterns.rs +++ b/clippy_lints/src/manual_range_patterns.rs @@ -77,9 +77,10 @@ impl Num { impl LateLintPass<'_> for ManualRangePatterns { fn check_pat(&mut self, cx: &LateContext<'_>, pat: &'_ rustc_hir::Pat<'_>) { // a pattern like 1 | 2 seems fine, lint if there are at least 3 alternatives - // or at least one range + // or more then one range (exclude triggering on stylistic using OR with one element + // like described https://github.com/rust-lang/rust-clippy/issues/11825) if let PatKind::Or(pats) = pat.kind - && (pats.len() >= 3 || pats.iter().any(|p| matches!(p.kind, PatKind::Range(..)))) + && (pats.len() >= 3 || (pats.len() > 1 && pats.iter().any(|p| matches!(p.kind, PatKind::Range(..))))) && !in_external_macro(cx.sess(), pat.span) { let mut min = Num::dummy(i128::MAX); diff --git a/tests/ui/manual_range_patterns.fixed b/tests/ui/manual_range_patterns.fixed index f1b99637afd..60467bf9e88 100644 --- a/tests/ui/manual_range_patterns.fixed +++ b/tests/ui/manual_range_patterns.fixed @@ -45,4 +45,12 @@ fn main() { }; } mac!(f); + + #[rustfmt::skip] + let _ = match f { + | 2..=15 => 4, + | 241..=254 => 5, + | 255 => 6, + | _ => 7, + }; } diff --git a/tests/ui/manual_range_patterns.rs b/tests/ui/manual_range_patterns.rs index 869ffbe80b9..9cd80333449 100644 --- a/tests/ui/manual_range_patterns.rs +++ b/tests/ui/manual_range_patterns.rs @@ -45,4 +45,12 @@ fn main() { }; } mac!(f); + + #[rustfmt::skip] + let _ = match f { + | 2..=15 => 4, + | 241..=254 => 5, + | 255 => 6, + | _ => 7, + }; } From e8ac4ea4187498052849531b86114a1eec5314a1 Mon Sep 17 00:00:00 2001 From: y21 <30553356+y21@users.noreply.github.com> Date: Sun, 10 Sep 2023 16:14:20 +0200 Subject: [PATCH 046/683] new lint: `zombie_processes` --- CHANGELOG.md | 1 + clippy_dev/src/serve.rs | 3 +- clippy_lints/src/declared_lints.rs | 1 + clippy_lints/src/lib.rs | 2 + clippy_lints/src/zombie_processes.rs | 334 +++++++++++++++++++ clippy_utils/src/paths.rs | 4 + tests/ui/suspicious_command_arg_space.fixed | 1 + tests/ui/suspicious_command_arg_space.rs | 1 + tests/ui/suspicious_command_arg_space.stderr | 4 +- tests/ui/zombie_processes.rs | 138 ++++++++ tests/ui/zombie_processes.stderr | 64 ++++ tests/ui/zombie_processes_fixable.fixed | 26 ++ tests/ui/zombie_processes_fixable.rs | 26 ++ tests/ui/zombie_processes_fixable.stderr | 40 +++ 14 files changed, 642 insertions(+), 3 deletions(-) create mode 100644 clippy_lints/src/zombie_processes.rs create mode 100644 tests/ui/zombie_processes.rs create mode 100644 tests/ui/zombie_processes.stderr create mode 100644 tests/ui/zombie_processes_fixable.fixed create mode 100644 tests/ui/zombie_processes_fixable.rs create mode 100644 tests/ui/zombie_processes_fixable.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index c5d7991e073..21252a3f43a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6048,6 +6048,7 @@ Released 2018-09-13 [`zero_repeat_side_effects`]: https://rust-lang.github.io/rust-clippy/master/index.html#zero_repeat_side_effects [`zero_sized_map_values`]: https://rust-lang.github.io/rust-clippy/master/index.html#zero_sized_map_values [`zero_width_space`]: https://rust-lang.github.io/rust-clippy/master/index.html#zero_width_space +[`zombie_processes`]: https://rust-lang.github.io/rust-clippy/master/index.html#zombie_processes [`zst_offset`]: https://rust-lang.github.io/rust-clippy/master/index.html#zst_offset diff --git a/clippy_dev/src/serve.rs b/clippy_dev/src/serve.rs index 19560b31fd3..cc14cd8dae6 100644 --- a/clippy_dev/src/serve.rs +++ b/clippy_dev/src/serve.rs @@ -29,7 +29,7 @@ pub fn run(port: u16, lint: Option) -> ! { } if let Some(url) = url.take() { thread::spawn(move || { - Command::new(PYTHON) + let mut child = Command::new(PYTHON) .arg("-m") .arg("http.server") .arg(port.to_string()) @@ -40,6 +40,7 @@ pub fn run(port: u16, lint: Option) -> ! { thread::sleep(Duration::from_millis(500)); // Launch browser after first export.py has completed and http.server is up let _result = opener::open(url); + child.wait().unwrap(); }); } thread::sleep(Duration::from_millis(1000)); diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index 94da5752beb..10e041fbc09 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -768,4 +768,5 @@ pub static LINTS: &[&crate::LintInfo] = &[ crate::zero_div_zero::ZERO_DIVIDED_BY_ZERO_INFO, crate::zero_repeat_side_effects::ZERO_REPEAT_SIDE_EFFECTS_INFO, crate::zero_sized_map_values::ZERO_SIZED_MAP_VALUES_INFO, + crate::zombie_processes::ZOMBIE_PROCESSES_INFO, ]; diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 2ac06b360be..f24933683b1 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -386,6 +386,7 @@ mod write; mod zero_div_zero; mod zero_repeat_side_effects; mod zero_sized_map_values; +mod zombie_processes; // end lints modules, do not remove this comment, it’s used in `update_lints` use clippy_config::{get_configuration_metadata, Conf}; @@ -933,5 +934,6 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { store.register_late_pass(|_| Box::new(set_contains_or_insert::SetContainsOrInsert)); store.register_early_pass(|| Box::new(byte_char_slices::ByteCharSlice)); store.register_early_pass(|| Box::new(cfg_not_test::CfgNotTest)); + store.register_late_pass(|_| Box::new(zombie_processes::ZombieProcesses)); // add lints here, do not remove this comment, it's used in `new_lint` } diff --git a/clippy_lints/src/zombie_processes.rs b/clippy_lints/src/zombie_processes.rs new file mode 100644 index 00000000000..eda3d7820c1 --- /dev/null +++ b/clippy_lints/src/zombie_processes.rs @@ -0,0 +1,334 @@ +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_errors::Applicability; +use rustc_hir::intravisit::{walk_block, walk_expr, walk_local, Visitor}; +use rustc_hir::{Expr, ExprKind, HirId, LetStmt, Node, PatKind, Stmt, StmtKind}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_session::declare_lint_pass; +use rustc_span::sym; +use std::ops::ControlFlow; +use ControlFlow::{Break, Continue}; + +declare_clippy_lint! { + /// ### What it does + /// Looks for code that spawns a process but never calls `wait()` on the child. + /// + /// ### Why is this bad? + /// As explained in the [standard library documentation](https://doc.rust-lang.org/stable/std/process/struct.Child.html#warning), + /// calling `wait()` is necessary on Unix platforms to properly release all OS resources associated with the process. + /// Not doing so will effectively leak process IDs and/or other limited global resources, + /// which can eventually lead to resource exhaustion, so it's recommended to call `wait()` in long-running applications. + /// Such processes are called "zombie processes". + /// + /// ### Example + /// ```rust + /// use std::process::Command; + /// + /// let _child = Command::new("ls").spawn().expect("failed to execute child"); + /// ``` + /// Use instead: + /// ```rust + /// use std::process::Command; + /// + /// let mut child = Command::new("ls").spawn().expect("failed to execute child"); + /// child.wait().expect("failed to wait on child"); + /// ``` + #[clippy::version = "1.74.0"] + pub ZOMBIE_PROCESSES, + suspicious, + "not waiting on a spawned child process" +} +declare_lint_pass!(ZombieProcesses => [ZOMBIE_PROCESSES]); + +impl<'tcx> LateLintPass<'tcx> for ZombieProcesses { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { + if let ExprKind::Call(..) | ExprKind::MethodCall(..) = expr.kind + && let Some(child_adt) = cx.typeck_results().expr_ty(expr).ty_adt_def() + && match_def_path(cx, child_adt.did(), &paths::CHILD) + { + match cx.tcx.parent_hir_node(expr.hir_id) { + Node::LetStmt(local) + 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; + } + + // Don't emit a suggestion since the binding is used later + check(cx, expr, false); + }, + Node::LetStmt(&LetStmt { pat, .. }) if let PatKind::Wild = pat.kind => { + // `let _ = child;`, also dropped immediately without `wait()`ing + check(cx, expr, true); + }, + Node::Stmt(&Stmt { + kind: StmtKind::Semi(_), + .. + }) => { + // Immediately dropped. E.g. `std::process::Command::new("echo").spawn().unwrap();` + check(cx, expr, true); + }, + _ => {}, + } + } + } +} + +enum BreakReason { + WaitFound, + EarlyReturn, +} + +/// 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}`) +/// - calling `id` or `kill` +/// - no use at all (e.g. `let _x = child;`) +/// - taking a shared reference (`&`), `wait()` can't go through that +/// +/// 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), +} + +impl<'a, 'tcx> Visitor<'tcx> for WaitFinder<'a, 'tcx> { + type Result = ControlFlow; + + fn visit_local(&mut self, l: &'tcx LetStmt<'tcx>) -> Self::Result { + if let Self::WalkUpTo(cx, local_id) = *self + && let PatKind::Binding(_, pat_id, ..) = l.pat.kind + && local_id == pat_id + { + *self = Self::Found(cx, local_id); + } + + walk_local(self, l) + } + + fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) -> Self::Result { + let Self::Found(cx, local_id) = *self else { + return walk_expr(self, ex); + }; + + if path_to_local_id(ex, local_id) { + match cx.tcx.parent_hir_node(ex.hir_id) { + Node::Stmt(Stmt { + kind: StmtKind::Semi(_), + .. + }) => {}, + 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() => {}, + + // Conservatively assume that all other kinds of nodes call `.wait()` somehow. + _ => return Break(BreakReason::WaitFound), + } + } else { + match ex.kind { + ExprKind::Ret(..) => return Break(BreakReason::EarlyReturn), + 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); + } + + return Continue(()); + }, + + 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(())) + + // `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); + }, + + // Propagate early returns in either branch + (Break(BreakReason::EarlyReturn), _) | (_, Break(BreakReason::EarlyReturn)) => { + return Break(BreakReason::EarlyReturn); + }, + } + + return Continue(()); + }, + _ => {}, + } + } + + walk_expr(self, ex) + } +} + +/// This function has shared logic between the different kinds of nodes that can trigger the lint. +/// +/// In particular, `let = ;` requires some custom additional logic +/// such as checking that the binding is not used in certain ways, which isn't necessary for +/// `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) { + let Some(block) = get_enclosing_block(cx, spawn_expr.hir_id) else { + return; + }; + + let mut vis = ExitPointFinder { + cx, + state: ExitPointState::WalkUpTo(spawn_expr.hir_id), + }; + if let Break(ExitCallFound) = vis.visit_block(block) { + // Visitor found an unconditional `exit()` call, so don't lint. + 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, + ); + } else { + diag.note("consider calling `.wait()`"); + } + + 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. +fn is_exit_expression(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { + fn_def_id(cx, expr).is_some_and(|fn_did| { + cx.tcx.is_diagnostic_item(sym::process_exit, fn_did) || match_def_path(cx, fn_did, &paths::ABORT) + }) +} + +#[derive(Debug)] +enum ExitPointState { + /// Still walking up to the expression that initiated the visitor. + WalkUpTo(HirId), + /// We're inside of a control flow construct (e.g. `if`, `match`, `loop`) + /// Within this, we shouldn't accept any `exit()` calls in here, but we can leave all of these + /// constructs later and still continue looking for an `exit()` call afterwards. Example: + /// ```ignore + /// Command::new("").spawn().unwrap(); + /// + /// if true { // depth=1 + /// if true { // depth=2 + /// match () { // depth=3 + /// () => loop { // depth=4 + /// + /// std::process::exit(); + /// ^^^^^^^^^^^^^^^^^^^^^ conditional exit call, ignored + /// + /// } // depth=3 + /// } // depth=2 + /// } // depth=1 + /// } // depth=0 + /// + /// std::process::exit(); + /// ^^^^^^^^^^^^^^^^^^^^^ this exit call is accepted because we're now unconditionally calling it + /// ``` + /// We can only get into this state from `NoExit`. + InControlFlow { depth: u32 }, + /// No exit call found yet, but looking for one. + NoExit, +} + +fn expr_enters_control_flow(expr: &Expr<'_>) -> bool { + matches!(expr.kind, ExprKind::If(..) | ExprKind::Match(..) | ExprKind::Loop(..)) +} + +struct ExitPointFinder<'a, 'tcx> { + state: ExitPointState, + cx: &'a LateContext<'tcx>, +} + +struct ExitCallFound; + +impl<'a, 'tcx> Visitor<'tcx> for ExitPointFinder<'a, 'tcx> { + type Result = ControlFlow; + + fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) -> Self::Result { + match self.state { + ExitPointState::WalkUpTo(id) if expr.hir_id == id => { + self.state = ExitPointState::NoExit; + walk_expr(self, expr) + }, + ExitPointState::NoExit if expr_enters_control_flow(expr) => { + self.state = ExitPointState::InControlFlow { depth: 1 }; + walk_expr(self, expr)?; + if let ExitPointState::InControlFlow { .. } = self.state { + self.state = ExitPointState::NoExit; + } + Continue(()) + }, + ExitPointState::NoExit if is_exit_expression(self.cx, expr) => Break(ExitCallFound), + ExitPointState::InControlFlow { ref mut depth } if expr_enters_control_flow(expr) => { + *depth += 1; + walk_expr(self, expr)?; + match self.state { + ExitPointState::InControlFlow { depth: 1 } => self.state = ExitPointState::NoExit, + ExitPointState::InControlFlow { ref mut depth } => *depth -= 1, + _ => {}, + } + Continue(()) + }, + _ => Continue(()), + } + } +} diff --git a/clippy_utils/src/paths.rs b/clippy_utils/src/paths.rs index a767798a9c3..930fb9fb6f2 100644 --- a/clippy_utils/src/paths.rs +++ b/clippy_utils/src/paths.rs @@ -4,6 +4,7 @@ //! Whenever possible, please consider diagnostic items over hardcoded paths. //! See for more information. +pub const ABORT: [&str; 3] = ["std", "process", "abort"]; pub const APPLICABILITY: [&str; 2] = ["rustc_lint_defs", "Applicability"]; pub const APPLICABILITY_VALUES: [[&str; 3]; 4] = [ ["rustc_lint_defs", "Applicability", "Unspecified"], @@ -23,6 +24,9 @@ pub const CORE_RESULT_OK_METHOD: [&str; 4] = ["core", "result", "Result", "ok"]; pub const CSTRING_AS_C_STR: [&str; 5] = ["alloc", "ffi", "c_str", "CString", "as_c_str"]; pub const EARLY_CONTEXT: [&str; 2] = ["rustc_lint", "EarlyContext"]; pub const EARLY_LINT_PASS: [&str; 3] = ["rustc_lint", "passes", "EarlyLintPass"]; +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 F32_EPSILON: [&str; 4] = ["core", "f32", "", "EPSILON"]; pub const F64_EPSILON: [&str; 4] = ["core", "f64", "", "EPSILON"]; pub const FILE_OPTIONS: [&str; 4] = ["std", "fs", "File", "options"]; diff --git a/tests/ui/suspicious_command_arg_space.fixed b/tests/ui/suspicious_command_arg_space.fixed index 5d7b1e0c17f..704d6ea1bb8 100644 --- a/tests/ui/suspicious_command_arg_space.fixed +++ b/tests/ui/suspicious_command_arg_space.fixed @@ -1,3 +1,4 @@ +#![allow(clippy::zombie_processes)] fn main() { // Things it should warn about: std::process::Command::new("echo").args(["-n", "hello"]).spawn().unwrap(); diff --git a/tests/ui/suspicious_command_arg_space.rs b/tests/ui/suspicious_command_arg_space.rs index 8abd9803a0c..2a2a7557381 100644 --- a/tests/ui/suspicious_command_arg_space.rs +++ b/tests/ui/suspicious_command_arg_space.rs @@ -1,3 +1,4 @@ +#![allow(clippy::zombie_processes)] fn main() { // Things it should warn about: std::process::Command::new("echo").arg("-n hello").spawn().unwrap(); diff --git a/tests/ui/suspicious_command_arg_space.stderr b/tests/ui/suspicious_command_arg_space.stderr index d2517b66b56..6fd07d07d7b 100644 --- a/tests/ui/suspicious_command_arg_space.stderr +++ b/tests/ui/suspicious_command_arg_space.stderr @@ -1,5 +1,5 @@ error: single argument that looks like it should be multiple arguments - --> tests/ui/suspicious_command_arg_space.rs:3:44 + --> tests/ui/suspicious_command_arg_space.rs:4:44 | LL | std::process::Command::new("echo").arg("-n hello").spawn().unwrap(); | ^^^^^^^^^^ @@ -12,7 +12,7 @@ LL | std::process::Command::new("echo").args(["-n", "hello"]).spawn().unwrap | ~~~~ ~~~~~~~~~~~~~~~ error: single argument that looks like it should be multiple arguments - --> tests/ui/suspicious_command_arg_space.rs:6:43 + --> tests/ui/suspicious_command_arg_space.rs:7:43 | LL | std::process::Command::new("cat").arg("--number file").spawn().unwrap(); | ^^^^^^^^^^^^^^^ diff --git a/tests/ui/zombie_processes.rs b/tests/ui/zombie_processes.rs new file mode 100644 index 00000000000..a2abc7fc3a1 --- /dev/null +++ b/tests/ui/zombie_processes.rs @@ -0,0 +1,138 @@ +#![warn(clippy::zombie_processes)] +#![allow(clippy::if_same_then_else, clippy::ifs_same_cond)] + +use std::process::{Child, Command}; + +fn main() { + { + // Check that #[expect] works + #[expect(clippy::zombie_processes)] + let mut x = Command::new("").spawn().unwrap(); + } + + { + let mut x = Command::new("").spawn().unwrap(); + //~^ ERROR: spawned process is never `wait()`ed on + x.kill(); + x.id(); + } + { + let mut x = Command::new("").spawn().unwrap(); + x.wait().unwrap(); // OK + } + { + let x = Command::new("").spawn().unwrap(); + x.wait_with_output().unwrap(); // OK + } + { + let mut x = Command::new("").spawn().unwrap(); + x.try_wait().unwrap(); // OK + } + { + let mut x = Command::new("").spawn().unwrap(); + let mut r = &mut x; + r.wait().unwrap(); // OK, not calling `.wait()` directly on `x` but through `r` -> `x` + } + { + let mut x = Command::new("").spawn().unwrap(); + process_child(x); // OK, other function might call `.wait()` so assume it does + } + { + let mut x = Command::new("").spawn().unwrap(); + //~^ ERROR: spawned process is never `wait()`ed on + let v = &x; + // (allow shared refs is fine because one cannot call `.wait()` through that) + } + + // https://github.com/rust-lang/rust-clippy/pull/11476#issuecomment-1718456033 + // Unconditionally exiting the process in various ways (should not lint) + { + let mut x = Command::new("").spawn().unwrap(); + std::process::exit(0); + } + { + let mut x = Command::new("").spawn().unwrap(); + std::process::abort(); // same as above, but abort instead of exit + } + { + let mut x = Command::new("").spawn().unwrap(); + if true { /* nothing */ } + std::process::abort(); // still unconditionally exits + } + + // Conditionally exiting + // 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 + if true { + std::process::exit(0); + } + } + { + let mut x = Command::new("").spawn().unwrap(); + //~^ ERROR: spawned process is never `wait()`ed on + if true { + while false {} + // Calling `exit()` after leaving a while loop should still be linted. + std::process::exit(0); + } + } + + { + let mut x = { Command::new("").spawn().unwrap() }; + x.wait().unwrap(); + } + + { + struct S { + c: Child, + } + + let mut s = S { + c: Command::new("").spawn().unwrap(), + }; + s.c.wait().unwrap(); + } + + { + let mut x = Command::new("").spawn().unwrap(); + //~^ ERROR: spawned process is never `wait()`ed on + if true { + return; + } + x.wait().unwrap(); + } + + { + let mut x = Command::new("").spawn().unwrap(); + //~^ ERROR: spawned process is never `wait()`ed on + if true { + x.wait().unwrap(); + } + } + + { + let mut x = Command::new("").spawn().unwrap(); + if true { + x.wait().unwrap(); + } else if true { + x.wait().unwrap(); + } else { + x.wait().unwrap(); + } + } + + { + let mut x = Command::new("").spawn().unwrap(); + if true { + x.wait().unwrap(); + return; + } + x.wait().unwrap(); + } +} + +fn process_child(c: Child) { + todo!() +} diff --git a/tests/ui/zombie_processes.stderr b/tests/ui/zombie_processes.stderr new file mode 100644 index 00000000000..eec821a4c8f --- /dev/null +++ b/tests/ui/zombie_processes.stderr @@ -0,0 +1,64 @@ +error: spawned process is never `wait()`ed on + --> tests/ui/zombie_processes.rs:14:21 + | +LL | let mut x = Command::new("").spawn().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: 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` + = help: to override `-D warnings` add `#[allow(clippy::zombie_processes)]` + +error: spawned process is never `wait()`ed on + --> tests/ui/zombie_processes.rs:41:21 + | +LL | let mut x = Command::new("").spawn().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: 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 + --> tests/ui/zombie_processes.rs:66:21 + | +LL | let mut x = Command::new("").spawn().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: 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 + --> tests/ui/zombie_processes.rs:73:21 + | +LL | let mut x = Command::new("").spawn().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: 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 + --> tests/ui/zombie_processes.rs:99:21 + | +LL | let mut x = Command::new("").spawn().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: 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 + --> tests/ui/zombie_processes.rs:108:21 + | +LL | let mut x = Command::new("").spawn().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: 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: aborting due to 6 previous errors + diff --git a/tests/ui/zombie_processes_fixable.fixed b/tests/ui/zombie_processes_fixable.fixed new file mode 100644 index 00000000000..6045262f519 --- /dev/null +++ b/tests/ui/zombie_processes_fixable.fixed @@ -0,0 +1,26 @@ +#![warn(clippy::zombie_processes)] +#![allow(clippy::needless_return)] + +use std::process::{Child, Command}; + +fn main() { + let _ = Command::new("").spawn().unwrap().wait(); + //~^ ERROR: spawned process is never `wait()`ed on + Command::new("").spawn().unwrap().wait(); + //~^ ERROR: spawned process is never `wait()`ed on + spawn_proc().wait(); + //~^ ERROR: spawned process is never `wait()`ed on + spawn_proc().wait().unwrap(); // OK +} + +fn not_main() { + Command::new("").spawn().unwrap().wait(); +} + +fn spawn_proc() -> Child { + Command::new("").spawn().unwrap() +} + +fn spawn_proc_2() -> Child { + return Command::new("").spawn().unwrap(); +} diff --git a/tests/ui/zombie_processes_fixable.rs b/tests/ui/zombie_processes_fixable.rs new file mode 100644 index 00000000000..e1ecb771641 --- /dev/null +++ b/tests/ui/zombie_processes_fixable.rs @@ -0,0 +1,26 @@ +#![warn(clippy::zombie_processes)] +#![allow(clippy::needless_return)] + +use std::process::{Child, Command}; + +fn main() { + let _ = Command::new("").spawn().unwrap(); + //~^ ERROR: spawned process is never `wait()`ed on + Command::new("").spawn().unwrap(); + //~^ ERROR: spawned process is never `wait()`ed on + spawn_proc(); + //~^ ERROR: spawned process is never `wait()`ed on + spawn_proc().wait().unwrap(); // OK +} + +fn not_main() { + Command::new("").spawn().unwrap(); +} + +fn spawn_proc() -> Child { + Command::new("").spawn().unwrap() +} + +fn spawn_proc_2() -> Child { + return Command::new("").spawn().unwrap(); +} diff --git a/tests/ui/zombie_processes_fixable.stderr b/tests/ui/zombie_processes_fixable.stderr new file mode 100644 index 00000000000..e1c40472c32 --- /dev/null +++ b/tests/ui/zombie_processes_fixable.stderr @@ -0,0 +1,40 @@ +error: spawned process is never `wait()`ed on + --> tests/ui/zombie_processes_fixable.rs:7:13 + | +LL | let _ = Command::new("").spawn().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- help: try: `.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` + = help: to override `-D warnings` add `#[allow(clippy::zombie_processes)]` + +error: spawned process is never `wait()`ed on + --> tests/ui/zombie_processes_fixable.rs:9:5 + | +LL | Command::new("").spawn().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- help: try: `.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 + --> tests/ui/zombie_processes_fixable.rs:11:5 + | +LL | spawn_proc(); + | ^^^^^^^^^^^^- help: try: `.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 + --> tests/ui/zombie_processes_fixable.rs:17:5 + | +LL | Command::new("").spawn().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- help: try: `.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: aborting due to 4 previous errors + From 5bbb0d41f1637d3b6a54ded065e807a48c67aec0 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 29 Aug 2024 00:17:40 -0400 Subject: [PATCH 047/683] Stop using ty::GenericPredicates for non-predicates_of queries --- clippy_lints/src/implied_bounds_in_impls.rs | 2 +- clippy_lints/src/methods/type_id_on_box.rs | 3 +-- clippy_lints/src/needless_maybe_sized.rs | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/clippy_lints/src/implied_bounds_in_impls.rs b/clippy_lints/src/implied_bounds_in_impls.rs index 67b48878ca5..6794c6cabfe 100644 --- a/clippy_lints/src/implied_bounds_in_impls.rs +++ b/clippy_lints/src/implied_bounds_in_impls.rs @@ -246,7 +246,7 @@ fn collect_supertrait_bounds<'tcx>(cx: &LateContext<'tcx>, bounds: GenericBounds && let [.., path] = poly_trait.trait_ref.path.segments && poly_trait.bound_generic_params.is_empty() && let Some(trait_def_id) = path.res.opt_def_id() - && let predicates = cx.tcx.explicit_super_predicates_of(trait_def_id).predicates + && let predicates = cx.tcx.explicit_super_predicates_of(trait_def_id).skip_binder() // If the trait has no supertrait, there is no need to collect anything from that bound && !predicates.is_empty() { diff --git a/clippy_lints/src/methods/type_id_on_box.rs b/clippy_lints/src/methods/type_id_on_box.rs index b62ecef0069..db8cc4595d4 100644 --- a/clippy_lints/src/methods/type_id_on_box.rs +++ b/clippy_lints/src/methods/type_id_on_box.rs @@ -25,8 +25,7 @@ fn is_subtrait_of_any(cx: &LateContext<'_>, ty: Ty<'_>) -> bool { || cx .tcx .explicit_super_predicates_of(tr.def_id) - .predicates - .iter() + .iter_identity_copied() .any(|(clause, _)| { matches!(clause.kind().skip_binder(), ty::ClauseKind::Trait(super_tr) if cx.tcx.is_diagnostic_item(sym::Any, super_tr.def_id())) diff --git a/clippy_lints/src/needless_maybe_sized.rs b/clippy_lints/src/needless_maybe_sized.rs index a1d8ec3b32e..62e41088f37 100644 --- a/clippy_lints/src/needless_maybe_sized.rs +++ b/clippy_lints/src/needless_maybe_sized.rs @@ -91,7 +91,7 @@ fn path_to_sized_bound(cx: &LateContext<'_>, trait_bound: &PolyTraitRef<'_>) -> return true; } - for &(predicate, _) in cx.tcx.explicit_super_predicates_of(trait_def_id).predicates { + for (predicate, _) in cx.tcx.explicit_super_predicates_of(trait_def_id).iter_identity_copied() { if let ClauseKind::Trait(trait_predicate) = predicate.kind().skip_binder() && trait_predicate.polarity == PredicatePolarity::Positive && !path.contains(&trait_predicate.def_id()) From 74a2344dc12b5659357272f4cd8b6e837195ab24 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 19 Mar 2024 16:51:40 +0100 Subject: [PATCH 048/683] Extend `implicit_saturation_sub` lint --- clippy_lints/src/implicit_saturating_sub.rs | 284 +++++++++++++++----- 1 file changed, 221 insertions(+), 63 deletions(-) diff --git a/clippy_lints/src/implicit_saturating_sub.rs b/clippy_lints/src/implicit_saturating_sub.rs index 127c73ed637..453ff09bf4f 100644 --- a/clippy_lints/src/implicit_saturating_sub.rs +++ b/clippy_lints/src/implicit_saturating_sub.rs @@ -1,11 +1,13 @@ -use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::{higher, is_integer_literal, peel_blocks_with_stmt, SpanlessEq}; +use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; +use clippy_utils::source::snippet_opt; +use clippy_utils::{higher, is_integer_literal, path_to_local, peel_blocks, peel_blocks_with_stmt, SpanlessEq}; use rustc_ast::ast::LitKind; use rustc_data_structures::packed::Pu128; use rustc_errors::Applicability; -use rustc_hir::{BinOpKind, Expr, ExprKind, QPath}; +use rustc_hir::{BinOp, BinOpKind, Expr, ExprKind, HirId, QPath}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; +use rustc_span::Span; declare_clippy_lint! { /// ### What it does @@ -50,73 +52,229 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitSaturatingSub { // Check if the conditional expression is a binary operation && let ExprKind::Binary(ref cond_op, cond_left, cond_right) = cond.kind - - // Ensure that the binary operator is >, !=, or < - && (BinOpKind::Ne == cond_op.node || BinOpKind::Gt == cond_op.node || BinOpKind::Lt == cond_op.node) - - // Check if assign operation is done - && let Some(target) = subtracts_one(cx, then) - - // Extracting out the variable name - && let ExprKind::Path(QPath::Resolved(_, ares_path)) = target.kind { - // Handle symmetric conditions in the if statement - let (cond_var, cond_num_val) = if SpanlessEq::new(cx).eq_expr(cond_left, target) { - if BinOpKind::Gt == cond_op.node || BinOpKind::Ne == cond_op.node { - (cond_left, cond_right) - } else { - return; - } - } else if SpanlessEq::new(cx).eq_expr(cond_right, target) { - if BinOpKind::Lt == cond_op.node || BinOpKind::Ne == cond_op.node { - (cond_right, cond_left) - } else { - return; - } + check_with_condition(cx, expr, cond_op.node, cond_left, cond_right, then); + } else if let Some(higher::If { + cond, + then: if_block, + r#else: Some(else_block), + }) = higher::If::hir(expr) + && let ExprKind::Binary(ref cond_op, cond_left, cond_right) = cond.kind + { + check_manual_check(cx, expr, cond_op, cond_left, cond_right, if_block, else_block); + } + } +} + +fn check_manual_check<'tcx>( + cx: &LateContext<'tcx>, + expr: &Expr<'tcx>, + condition: &BinOp, + left_hand: &Expr<'tcx>, + right_hand: &Expr<'tcx>, + if_block: &Expr<'tcx>, + else_block: &Expr<'tcx>, +) { + let ty = cx.typeck_results().expr_ty(left_hand); + if ty.is_numeric() && !ty.is_signed() { + match condition.node { + BinOpKind::Gt | BinOpKind::Ge => check_gt( + cx, + condition.span, + expr.span, + left_hand, + right_hand, + if_block, + else_block, + ), + BinOpKind::Lt | BinOpKind::Le => check_gt( + cx, + condition.span, + expr.span, + right_hand, + left_hand, + if_block, + else_block, + ), + _ => {}, + } + } +} + +fn check_gt( + cx: &LateContext<'_>, + condition_span: Span, + expr_span: Span, + big_var: &Expr<'_>, + little_var: &Expr<'_>, + if_block: &Expr<'_>, + else_block: &Expr<'_>, +) { + if let Some(big_var) = Var::new(big_var) + && let Some(little_var) = Var::new(little_var) + { + check_subtraction(cx, condition_span, expr_span, big_var, little_var, if_block, else_block); + } +} + +struct Var { + span: Span, + hir_id: HirId, +} + +impl Var { + fn new(expr: &Expr<'_>) -> Option { + path_to_local(expr).map(|hir_id| Self { + span: expr.span, + hir_id, + }) + } +} + +fn check_subtraction( + cx: &LateContext<'_>, + condition_span: Span, + expr_span: Span, + big_var: Var, + little_var: Var, + if_block: &Expr<'_>, + else_block: &Expr<'_>, +) { + let if_block = peel_blocks(if_block); + let else_block = peel_blocks(else_block); + if is_integer_literal(if_block, 0) { + // We need to check this case as well to prevent infinite recursion. + if is_integer_literal(else_block, 0) { + // Well, seems weird but who knows? + return; + } + // If the subtraction is done in the `else` block, then we need to also revert the two + // variables as it means that the check was reverted too. + check_subtraction(cx, condition_span, expr_span, little_var, big_var, else_block, if_block); + return; + } + if is_integer_literal(else_block, 0) + && let ExprKind::Binary(op, left, right) = if_block.kind + && let BinOpKind::Sub = op.node + { + let local_left = path_to_local(left); + let local_right = path_to_local(right); + if Some(big_var.hir_id) == local_left && Some(little_var.hir_id) == local_right { + // This part of the condition is voluntarily split from the one before to ensure that + // if `snippet_opt` fails, it won't try the next conditions. + if let Some(big_var_snippet) = snippet_opt(cx, big_var.span) + && let Some(little_var_snippet) = snippet_opt(cx, little_var.span) + { + span_lint_and_sugg( + cx, + IMPLICIT_SATURATING_SUB, + expr_span, + "manual arithmetic check found", + "replace it with", + format!("{big_var_snippet}.saturating_sub({little_var_snippet})"), + Applicability::MachineApplicable, + ); + } + } else if Some(little_var.hir_id) == local_left + && Some(big_var.hir_id) == local_right + && let Some(big_var_snippet) = snippet_opt(cx, big_var.span) + && let Some(little_var_snippet) = snippet_opt(cx, little_var.span) + { + span_lint_and_then( + cx, + IMPLICIT_SATURATING_SUB, + condition_span, + "inverted arithmetic check before subtraction", + |diag| { + diag.span_note( + if_block.span, + format!("this subtraction underflows when `{little_var_snippet} < {big_var_snippet}`"), + ); + diag.span_suggestion( + if_block.span, + "try replacing it with", + format!("{big_var_snippet} - {little_var_snippet}"), + Applicability::MaybeIncorrect, + ); + }, + ); + } + } +} + +fn check_with_condition<'tcx>( + cx: &LateContext<'tcx>, + expr: &Expr<'tcx>, + cond_op: BinOpKind, + cond_left: &Expr<'tcx>, + cond_right: &Expr<'tcx>, + then: &Expr<'tcx>, +) { + // Ensure that the binary operator is >, !=, or < + if (BinOpKind::Ne == cond_op || BinOpKind::Gt == cond_op || BinOpKind::Lt == cond_op) + + // Check if assign operation is done + && let Some(target) = subtracts_one(cx, then) + + // Extracting out the variable name + && let ExprKind::Path(QPath::Resolved(_, ares_path)) = target.kind + { + // Handle symmetric conditions in the if statement + let (cond_var, cond_num_val) = if SpanlessEq::new(cx).eq_expr(cond_left, target) { + if BinOpKind::Gt == cond_op || BinOpKind::Ne == cond_op { + (cond_left, cond_right) } else { return; - }; - - // Check if the variable in the condition statement is an integer - if !cx.typeck_results().expr_ty(cond_var).is_integral() { + } + } else if SpanlessEq::new(cx).eq_expr(cond_right, target) { + if BinOpKind::Lt == cond_op || BinOpKind::Ne == cond_op { + (cond_right, cond_left) + } else { return; } + } else { + return; + }; - // Get the variable name - let var_name = ares_path.segments[0].ident.name.as_str(); - match cond_num_val.kind { - ExprKind::Lit(cond_lit) => { - // Check if the constant is zero - if let LitKind::Int(Pu128(0), _) = cond_lit.node { - if cx.typeck_results().expr_ty(cond_left).is_signed() { - } else { - print_lint_and_sugg(cx, var_name, expr); - }; - } - }, - ExprKind::Path(QPath::TypeRelative(_, name)) => { - if name.ident.as_str() == "MIN" - && let Some(const_id) = cx.typeck_results().type_dependent_def_id(cond_num_val.hir_id) - && let Some(impl_id) = cx.tcx.impl_of_method(const_id) - && let None = cx.tcx.impl_trait_ref(impl_id) // An inherent impl - && cx.tcx.type_of(impl_id).instantiate_identity().is_integral() - { + // Check if the variable in the condition statement is an integer + if !cx.typeck_results().expr_ty(cond_var).is_integral() { + return; + } + + // Get the variable name + let var_name = ares_path.segments[0].ident.name.as_str(); + match cond_num_val.kind { + ExprKind::Lit(cond_lit) => { + // Check if the constant is zero + if let LitKind::Int(Pu128(0), _) = cond_lit.node { + if cx.typeck_results().expr_ty(cond_left).is_signed() { + } else { print_lint_and_sugg(cx, var_name, expr); - } - }, - ExprKind::Call(func, []) => { - if let ExprKind::Path(QPath::TypeRelative(_, name)) = func.kind - && name.ident.as_str() == "min_value" - && let Some(func_id) = cx.typeck_results().type_dependent_def_id(func.hir_id) - && let Some(impl_id) = cx.tcx.impl_of_method(func_id) - && let None = cx.tcx.impl_trait_ref(impl_id) // An inherent impl - && cx.tcx.type_of(impl_id).instantiate_identity().is_integral() - { - print_lint_and_sugg(cx, var_name, expr); - } - }, - _ => (), - } + }; + } + }, + ExprKind::Path(QPath::TypeRelative(_, name)) => { + if name.ident.as_str() == "MIN" + && let Some(const_id) = cx.typeck_results().type_dependent_def_id(cond_num_val.hir_id) + && let Some(impl_id) = cx.tcx.impl_of_method(const_id) + && let None = cx.tcx.impl_trait_ref(impl_id) // An inherent impl + && cx.tcx.type_of(impl_id).instantiate_identity().is_integral() + { + print_lint_and_sugg(cx, var_name, expr); + } + }, + ExprKind::Call(func, []) => { + if let ExprKind::Path(QPath::TypeRelative(_, name)) = func.kind + && name.ident.as_str() == "min_value" + && let Some(func_id) = cx.typeck_results().type_dependent_def_id(func.hir_id) + && let Some(impl_id) = cx.tcx.impl_of_method(func_id) + && let None = cx.tcx.impl_trait_ref(impl_id) // An inherent impl + && cx.tcx.type_of(impl_id).instantiate_identity().is_integral() + { + print_lint_and_sugg(cx, var_name, expr); + } + }, + _ => (), } } } From 2622a87587ada00d6aac1d036da8a2f579a675ba Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 19 Mar 2024 16:59:08 +0100 Subject: [PATCH 049/683] Add ui regression tests for `implicit_saturation_sub` lint extension --- tests/ui/implicit_saturating_sub.rs | 7 +++ tests/ui/manual_arithmetic_check-2.rs | 35 +++++++++++ tests/ui/manual_arithmetic_check-2.stderr | 76 +++++++++++++++++++++++ tests/ui/manual_arithmetic_check.fixed | 16 +++++ tests/ui/manual_arithmetic_check.rs | 20 ++++++ tests/ui/manual_arithmetic_check.stderr | 29 +++++++++ 6 files changed, 183 insertions(+) create mode 100644 tests/ui/manual_arithmetic_check-2.rs create mode 100644 tests/ui/manual_arithmetic_check-2.stderr create mode 100644 tests/ui/manual_arithmetic_check.fixed create mode 100644 tests/ui/manual_arithmetic_check.rs create mode 100644 tests/ui/manual_arithmetic_check.stderr diff --git a/tests/ui/implicit_saturating_sub.rs b/tests/ui/implicit_saturating_sub.rs index 5d7b95d2c65..05f7d852383 100644 --- a/tests/ui/implicit_saturating_sub.rs +++ b/tests/ui/implicit_saturating_sub.rs @@ -260,4 +260,11 @@ fn main() { } else if u_32 > 0 { u_32 -= 1; } + + let result = if a < b { + println!("we shouldn't remove this"); + 0 + } else { + a - b + }; } diff --git a/tests/ui/manual_arithmetic_check-2.rs b/tests/ui/manual_arithmetic_check-2.rs new file mode 100644 index 00000000000..e97e3bdfef7 --- /dev/null +++ b/tests/ui/manual_arithmetic_check-2.rs @@ -0,0 +1,35 @@ +//@no-rustfix +#![warn(clippy::implicit_saturating_sub)] +#![allow(arithmetic_overflow)] + +fn main() { + let a = 12u32; + let b = 13u32; + + let result = if a > b { b - a } else { 0 }; + //~^ ERROR: inverted arithmetic check before subtraction + let result = if b < a { b - a } else { 0 }; + //~^ ERROR: inverted arithmetic check before subtraction + + let result = if a > b { 0 } else { a - b }; + //~^ ERROR: inverted arithmetic check before subtraction + let result = if a >= b { 0 } else { a - b }; + //~^ ERROR: inverted arithmetic check before subtraction + let result = if b < a { 0 } else { a - b }; + //~^ ERROR: inverted arithmetic check before subtraction + let result = if b <= a { 0 } else { a - b }; + //~^ ERROR: inverted arithmetic check before subtraction + + let af = 12f32; + let bf = 13f32; + // Should not lint! + let result = if bf < af { 0. } else { af - bf }; + + // Should not lint! + let result = if a < b { + println!("we shouldn't remove this"); + 0 + } else { + a - b + }; +} diff --git a/tests/ui/manual_arithmetic_check-2.stderr b/tests/ui/manual_arithmetic_check-2.stderr new file mode 100644 index 00000000000..d49e536ce3f --- /dev/null +++ b/tests/ui/manual_arithmetic_check-2.stderr @@ -0,0 +1,76 @@ +error: inverted arithmetic check before subtraction + --> tests/ui/manual_arithmetic_check-2.rs:9:23 + | +LL | let result = if a > b { b - a } else { 0 }; + | ^ ----- help: try replacing it with: `a - b` + | +note: this subtraction underflows when `b < a` + --> tests/ui/manual_arithmetic_check-2.rs:9:29 + | +LL | let result = if a > b { b - a } else { 0 }; + | ^^^^^ + = note: `-D clippy::implicit-saturating-sub` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::implicit_saturating_sub)]` + +error: inverted arithmetic check before subtraction + --> tests/ui/manual_arithmetic_check-2.rs:11:23 + | +LL | let result = if b < a { b - a } else { 0 }; + | ^ ----- help: try replacing it with: `a - b` + | +note: this subtraction underflows when `b < a` + --> tests/ui/manual_arithmetic_check-2.rs:11:29 + | +LL | let result = if b < a { b - a } else { 0 }; + | ^^^^^ + +error: inverted arithmetic check before subtraction + --> tests/ui/manual_arithmetic_check-2.rs:14:23 + | +LL | let result = if a > b { 0 } else { a - b }; + | ^ ----- help: try replacing it with: `b - a` + | +note: this subtraction underflows when `a < b` + --> tests/ui/manual_arithmetic_check-2.rs:14:40 + | +LL | let result = if a > b { 0 } else { a - b }; + | ^^^^^ + +error: inverted arithmetic check before subtraction + --> tests/ui/manual_arithmetic_check-2.rs:16:23 + | +LL | let result = if a >= b { 0 } else { a - b }; + | ^^ ----- help: try replacing it with: `b - a` + | +note: this subtraction underflows when `a < b` + --> tests/ui/manual_arithmetic_check-2.rs:16:41 + | +LL | let result = if a >= b { 0 } else { a - b }; + | ^^^^^ + +error: inverted arithmetic check before subtraction + --> tests/ui/manual_arithmetic_check-2.rs:18:23 + | +LL | let result = if b < a { 0 } else { a - b }; + | ^ ----- help: try replacing it with: `b - a` + | +note: this subtraction underflows when `a < b` + --> tests/ui/manual_arithmetic_check-2.rs:18:40 + | +LL | let result = if b < a { 0 } else { a - b }; + | ^^^^^ + +error: inverted arithmetic check before subtraction + --> tests/ui/manual_arithmetic_check-2.rs:20:23 + | +LL | let result = if b <= a { 0 } else { a - b }; + | ^^ ----- help: try replacing it with: `b - a` + | +note: this subtraction underflows when `a < b` + --> tests/ui/manual_arithmetic_check-2.rs:20:41 + | +LL | let result = if b <= a { 0 } else { a - b }; + | ^^^^^ + +error: aborting due to 6 previous errors + diff --git a/tests/ui/manual_arithmetic_check.fixed b/tests/ui/manual_arithmetic_check.fixed new file mode 100644 index 00000000000..afb2abcbe90 --- /dev/null +++ b/tests/ui/manual_arithmetic_check.fixed @@ -0,0 +1,16 @@ +#![warn(clippy::implicit_saturating_sub)] + +fn main() { + let a = 12u32; + let b = 13u32; + + let result = a.saturating_sub(b); + //~^ ERROR: manual arithmetic check found + let result = a.saturating_sub(b); + //~^ ERROR: manual arithmetic check found + + let result = a.saturating_sub(b); + //~^ ERROR: manual arithmetic check found + let result = a.saturating_sub(b); + //~^ ERROR: manual arithmetic check found +} diff --git a/tests/ui/manual_arithmetic_check.rs b/tests/ui/manual_arithmetic_check.rs new file mode 100644 index 00000000000..c11ac7097fc --- /dev/null +++ b/tests/ui/manual_arithmetic_check.rs @@ -0,0 +1,20 @@ +#![warn(clippy::implicit_saturating_sub)] + +fn main() { + let a = 12u32; + let b = 13u32; + let c = 8u32; + + let result = if a > b { a - b } else { 0 }; + //~^ ERROR: manual arithmetic check found + let result = if b < a { a - b } else { 0 }; + //~^ ERROR: manual arithmetic check found + + let result = if a < b { 0 } else { a - b }; + //~^ ERROR: manual arithmetic check found + let result = if b > a { 0 } else { a - b }; + //~^ ERROR: manual arithmetic check found + + // Should not warn! + let result = if a > b { a - b } else { a - c }; +} diff --git a/tests/ui/manual_arithmetic_check.stderr b/tests/ui/manual_arithmetic_check.stderr new file mode 100644 index 00000000000..153a8bb5734 --- /dev/null +++ b/tests/ui/manual_arithmetic_check.stderr @@ -0,0 +1,29 @@ +error: manual arithmetic check found + --> tests/ui/manual_arithmetic_check.rs:7:18 + | +LL | let result = if a > b { a - b } else { 0 }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `a.saturating_sub(b)` + | + = note: `-D clippy::implicit-saturating-sub` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::implicit_saturating_sub)]` + +error: manual arithmetic check found + --> tests/ui/manual_arithmetic_check.rs:9:18 + | +LL | let result = if b < a { a - b } else { 0 }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `a.saturating_sub(b)` + +error: manual arithmetic check found + --> tests/ui/manual_arithmetic_check.rs:12:18 + | +LL | let result = if a < b { 0 } else { a - b }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `a.saturating_sub(b)` + +error: manual arithmetic check found + --> tests/ui/manual_arithmetic_check.rs:14:18 + | +LL | let result = if b > a { 0 } else { a - b }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `a.saturating_sub(b)` + +error: aborting due to 4 previous errors + From 27c63433659773c70dca86a3d6f3b9bd7654c2c3 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 19 Mar 2024 17:00:31 +0100 Subject: [PATCH 050/683] Add ui test to ensure that if `0` is returned from both `if` and `else`, it will not break clippy --- tests/ui/implicit_saturating_sub.fixed | 13 ++++++++++--- tests/ui/implicit_saturating_sub.rs | 6 +++--- tests/ui/manual_arithmetic_check.fixed | 8 ++++++++ tests/ui/manual_arithmetic_check.rs | 4 ++++ tests/ui/manual_arithmetic_check.stderr | 8 ++++---- 5 files changed, 29 insertions(+), 10 deletions(-) diff --git a/tests/ui/implicit_saturating_sub.fixed b/tests/ui/implicit_saturating_sub.fixed index 27f679797dd..81cc1494914 100644 --- a/tests/ui/implicit_saturating_sub.fixed +++ b/tests/ui/implicit_saturating_sub.fixed @@ -184,18 +184,18 @@ fn main() { let mut m = Mock; let mut u_32 = 3000; let a = 200; - let mut _b = 8; + let mut b = 8; if m != 0 { m -= 1; } if a > 0 { - _b -= 1; + b -= 1; } if 0 > a { - _b -= 1; + b -= 1; } if u_32 > 0 { @@ -214,4 +214,11 @@ fn main() { } else if u_32 > 0 { u_32 -= 1; } + + let result = if a < b { + println!("we shouldn't remove this"); + 0 + } else { + a - b + }; } diff --git a/tests/ui/implicit_saturating_sub.rs b/tests/ui/implicit_saturating_sub.rs index 05f7d852383..f73396ebd27 100644 --- a/tests/ui/implicit_saturating_sub.rs +++ b/tests/ui/implicit_saturating_sub.rs @@ -230,18 +230,18 @@ fn main() { let mut m = Mock; let mut u_32 = 3000; let a = 200; - let mut _b = 8; + let mut b = 8; if m != 0 { m -= 1; } if a > 0 { - _b -= 1; + b -= 1; } if 0 > a { - _b -= 1; + b -= 1; } if u_32 > 0 { diff --git a/tests/ui/manual_arithmetic_check.fixed b/tests/ui/manual_arithmetic_check.fixed index afb2abcbe90..600fcd3765d 100644 --- a/tests/ui/manual_arithmetic_check.fixed +++ b/tests/ui/manual_arithmetic_check.fixed @@ -1,8 +1,10 @@ #![warn(clippy::implicit_saturating_sub)] +#![allow(clippy::if_same_then_else)] fn main() { let a = 12u32; let b = 13u32; + let c = 8u32; let result = a.saturating_sub(b); //~^ ERROR: manual arithmetic check found @@ -13,4 +15,10 @@ fn main() { //~^ ERROR: manual arithmetic check found let result = a.saturating_sub(b); //~^ ERROR: manual arithmetic check found + + // Should not warn! + let result = if a > b { a - b } else { a - c }; + + // Just to check it won't break clippy. + let result = if b > a { 0 } else { 0 }; } diff --git a/tests/ui/manual_arithmetic_check.rs b/tests/ui/manual_arithmetic_check.rs index c11ac7097fc..33f5adafe7e 100644 --- a/tests/ui/manual_arithmetic_check.rs +++ b/tests/ui/manual_arithmetic_check.rs @@ -1,4 +1,5 @@ #![warn(clippy::implicit_saturating_sub)] +#![allow(clippy::if_same_then_else)] fn main() { let a = 12u32; @@ -17,4 +18,7 @@ fn main() { // Should not warn! let result = if a > b { a - b } else { a - c }; + + // Just to check it won't break clippy. + let result = if b > a { 0 } else { 0 }; } diff --git a/tests/ui/manual_arithmetic_check.stderr b/tests/ui/manual_arithmetic_check.stderr index 153a8bb5734..b0cf73cd915 100644 --- a/tests/ui/manual_arithmetic_check.stderr +++ b/tests/ui/manual_arithmetic_check.stderr @@ -1,5 +1,5 @@ error: manual arithmetic check found - --> tests/ui/manual_arithmetic_check.rs:7:18 + --> tests/ui/manual_arithmetic_check.rs:9:18 | LL | let result = if a > b { a - b } else { 0 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `a.saturating_sub(b)` @@ -8,19 +8,19 @@ LL | let result = if a > b { a - b } else { 0 }; = help: to override `-D warnings` add `#[allow(clippy::implicit_saturating_sub)]` error: manual arithmetic check found - --> tests/ui/manual_arithmetic_check.rs:9:18 + --> tests/ui/manual_arithmetic_check.rs:11:18 | LL | let result = if b < a { a - b } else { 0 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `a.saturating_sub(b)` error: manual arithmetic check found - --> tests/ui/manual_arithmetic_check.rs:12:18 + --> tests/ui/manual_arithmetic_check.rs:14:18 | LL | let result = if a < b { 0 } else { a - b }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `a.saturating_sub(b)` error: manual arithmetic check found - --> tests/ui/manual_arithmetic_check.rs:14:18 + --> tests/ui/manual_arithmetic_check.rs:16:18 | LL | let result = if b > a { 0 } else { a - b }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `a.saturating_sub(b)` From d20fc38f0a17561166fb57c83ff5660b3cd41392 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 19 Jul 2024 14:51:56 +0200 Subject: [PATCH 051/683] Create new `inverted_saturating_sub` lint --- CHANGELOG.md | 1 + clippy_lints/src/declared_lints.rs | 1 + clippy_lints/src/implicit_saturating_sub.rs | 34 +++++++++++++++++++-- tests/ui/manual_arithmetic_check-2.stderr | 3 +- tests/ui/manual_arithmetic_check.fixed | 2 +- tests/ui/manual_arithmetic_check.rs | 2 +- 6 files changed, 37 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fddc2fd994e..0bef3552966 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5500,6 +5500,7 @@ Released 2018-09-13 [`invalid_regex`]: https://rust-lang.github.io/rust-clippy/master/index.html#invalid_regex [`invalid_upcast_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#invalid_upcast_comparisons [`invalid_utf8_in_unchecked`]: https://rust-lang.github.io/rust-clippy/master/index.html#invalid_utf8_in_unchecked +[`inverted_saturating_sub`]: https://rust-lang.github.io/rust-clippy/master/index.html#inverted_saturating_sub [`invisible_characters`]: https://rust-lang.github.io/rust-clippy/master/index.html#invisible_characters [`is_digit_ascii_radix`]: https://rust-lang.github.io/rust-clippy/master/index.html#is_digit_ascii_radix [`items_after_statements`]: https://rust-lang.github.io/rust-clippy/master/index.html#items_after_statements diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index 8754a4dff87..a6dd6ae7312 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -216,6 +216,7 @@ pub static LINTS: &[&crate::LintInfo] = &[ crate::implicit_return::IMPLICIT_RETURN_INFO, crate::implicit_saturating_add::IMPLICIT_SATURATING_ADD_INFO, crate::implicit_saturating_sub::IMPLICIT_SATURATING_SUB_INFO, + crate::implicit_saturating_sub::INVERTED_SATURATING_SUB_INFO, crate::implied_bounds_in_impls::IMPLIED_BOUNDS_IN_IMPLS_INFO, crate::incompatible_msrv::INCOMPATIBLE_MSRV_INFO, crate::inconsistent_struct_constructor::INCONSISTENT_STRUCT_CONSTRUCTOR_INFO, diff --git a/clippy_lints/src/implicit_saturating_sub.rs b/clippy_lints/src/implicit_saturating_sub.rs index 453ff09bf4f..04c89062039 100644 --- a/clippy_lints/src/implicit_saturating_sub.rs +++ b/clippy_lints/src/implicit_saturating_sub.rs @@ -41,7 +41,37 @@ declare_clippy_lint! { "Perform saturating subtraction instead of implicitly checking lower bound of data type" } -declare_lint_pass!(ImplicitSaturatingSub => [IMPLICIT_SATURATING_SUB]); +declare_clippy_lint! { + /// ### What it does + /// Checks for comparisons between integers, followed by subtracting the greater value from the + /// lower one. + /// + /// ### Why is this bad? + /// This could result in an underflow and is most likely not what the user wants. If this was + /// intended to be a saturated subtraction, consider using the `saturating_sub` method directly. + /// + /// ### Example + /// ```no_run + /// let a = 12u32; + /// let b = 13u32; + /// + /// let result = if a > b { b - a } else { 0 }; + /// ``` + /// + /// Use instead: + /// ```no_run + /// let a = 12u32; + /// let b = 13u32; + /// + /// let result = a.saturating_sub(b); + /// ``` + #[clippy::version = "1.44.0"] + pub INVERTED_SATURATING_SUB, + correctness, + "Check if a variable is smaller than another one and still subtract from it even if smaller" +} + +declare_lint_pass!(ImplicitSaturatingSub => [IMPLICIT_SATURATING_SUB, INVERTED_SATURATING_SUB]); impl<'tcx> LateLintPass<'tcx> for ImplicitSaturatingSub { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { @@ -182,7 +212,7 @@ fn check_subtraction( { span_lint_and_then( cx, - IMPLICIT_SATURATING_SUB, + INVERTED_SATURATING_SUB, condition_span, "inverted arithmetic check before subtraction", |diag| { diff --git a/tests/ui/manual_arithmetic_check-2.stderr b/tests/ui/manual_arithmetic_check-2.stderr index d49e536ce3f..4121aa7464f 100644 --- a/tests/ui/manual_arithmetic_check-2.stderr +++ b/tests/ui/manual_arithmetic_check-2.stderr @@ -9,8 +9,7 @@ note: this subtraction underflows when `b < a` | LL | let result = if a > b { b - a } else { 0 }; | ^^^^^ - = note: `-D clippy::implicit-saturating-sub` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::implicit_saturating_sub)]` + = note: `#[deny(clippy::inverted_saturating_sub)]` on by default error: inverted arithmetic check before subtraction --> tests/ui/manual_arithmetic_check-2.rs:11:23 diff --git a/tests/ui/manual_arithmetic_check.fixed b/tests/ui/manual_arithmetic_check.fixed index 600fcd3765d..29ecbb9ad2a 100644 --- a/tests/ui/manual_arithmetic_check.fixed +++ b/tests/ui/manual_arithmetic_check.fixed @@ -1,4 +1,4 @@ -#![warn(clippy::implicit_saturating_sub)] +#![warn(clippy::implicit_saturating_sub, clippy::inverted_saturating_sub)] #![allow(clippy::if_same_then_else)] fn main() { diff --git a/tests/ui/manual_arithmetic_check.rs b/tests/ui/manual_arithmetic_check.rs index 33f5adafe7e..69554c6b61c 100644 --- a/tests/ui/manual_arithmetic_check.rs +++ b/tests/ui/manual_arithmetic_check.rs @@ -1,4 +1,4 @@ -#![warn(clippy::implicit_saturating_sub)] +#![warn(clippy::implicit_saturating_sub, clippy::inverted_saturating_sub)] #![allow(clippy::if_same_then_else)] fn main() { From 9e7473f08daf4a8ab1fec5186376ad1299555344 Mon Sep 17 00:00:00 2001 From: xFrednet Date: Thu, 29 Aug 2024 21:31:46 +0200 Subject: [PATCH 052/683] Update version attribute for 1.81 lints --- clippy_lints/src/byte_char_slices.rs | 2 +- clippy_lints/src/cfg_not_test.rs | 2 +- clippy_lints/src/field_scoped_visibility_modifiers.rs | 2 +- clippy_lints/src/methods/mod.rs | 4 ++-- clippy_lints/src/needless_maybe_sized.rs | 2 +- clippy_lints/src/set_contains_or_insert.rs | 2 +- clippy_lints/src/string_patterns.rs | 2 +- 7 files changed, 8 insertions(+), 8 deletions(-) diff --git a/clippy_lints/src/byte_char_slices.rs b/clippy_lints/src/byte_char_slices.rs index a9fe190f177..dd2620b0b9d 100644 --- a/clippy_lints/src/byte_char_slices.rs +++ b/clippy_lints/src/byte_char_slices.rs @@ -22,7 +22,7 @@ declare_clippy_lint! { /// ```ignore /// b"Hello" /// ``` - #[clippy::version = "1.68.0"] + #[clippy::version = "1.81.0"] pub BYTE_CHAR_SLICES, style, "hard to read byte char slice" diff --git a/clippy_lints/src/cfg_not_test.rs b/clippy_lints/src/cfg_not_test.rs index d820c1e0720..884d15cabff 100644 --- a/clippy_lints/src/cfg_not_test.rs +++ b/clippy_lints/src/cfg_not_test.rs @@ -22,7 +22,7 @@ declare_clippy_lint! { /// # fn important_check() {} /// important_check(); /// ``` - #[clippy::version = "1.73.0"] + #[clippy::version = "1.81.0"] pub CFG_NOT_TEST, restriction, "enforce against excluding code from test builds" diff --git a/clippy_lints/src/field_scoped_visibility_modifiers.rs b/clippy_lints/src/field_scoped_visibility_modifiers.rs index 95b8e882da7..ba2b37fbf11 100644 --- a/clippy_lints/src/field_scoped_visibility_modifiers.rs +++ b/clippy_lints/src/field_scoped_visibility_modifiers.rs @@ -41,7 +41,7 @@ declare_clippy_lint! { /// } /// } /// ``` - #[clippy::version = "1.78.0"] + #[clippy::version = "1.81.0"] pub FIELD_SCOPED_VISIBILITY_MODIFIERS, restriction, "checks for usage of a scoped visibility modifier, like `pub(crate)`, on fields" diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index d7126990edb..0420f5c7628 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -3964,7 +3964,7 @@ declare_clippy_lint! { /// ```no_run /// let _ = 0; /// ``` - #[clippy::version = "1.78.0"] + #[clippy::version = "1.81.0"] pub UNNECESSARY_MIN_OR_MAX, complexity, "using 'min()/max()' when there is no need for it" @@ -4099,7 +4099,7 @@ declare_clippy_lint! { /// ```no_run /// "foo".is_ascii(); /// ``` - #[clippy::version = "1.80.0"] + #[clippy::version = "1.81.0"] pub NEEDLESS_CHARACTER_ITERATION, suspicious, "is_ascii() called on a char iterator" diff --git a/clippy_lints/src/needless_maybe_sized.rs b/clippy_lints/src/needless_maybe_sized.rs index a1d8ec3b32e..c0847342caf 100644 --- a/clippy_lints/src/needless_maybe_sized.rs +++ b/clippy_lints/src/needless_maybe_sized.rs @@ -26,7 +26,7 @@ declare_clippy_lint! { /// /// // or choose alternative bounds for `T` so that it can be unsized /// ``` - #[clippy::version = "1.79.0"] + #[clippy::version = "1.81.0"] pub NEEDLESS_MAYBE_SIZED, suspicious, "a `?Sized` bound that is unusable due to a `Sized` requirement" diff --git a/clippy_lints/src/set_contains_or_insert.rs b/clippy_lints/src/set_contains_or_insert.rs index e6fe7649397..bc2a71c42b9 100644 --- a/clippy_lints/src/set_contains_or_insert.rs +++ b/clippy_lints/src/set_contains_or_insert.rs @@ -42,7 +42,7 @@ declare_clippy_lint! { /// println!("inserted {value:?}"); /// } /// ``` - #[clippy::version = "1.80.0"] + #[clippy::version = "1.81.0"] pub SET_CONTAINS_OR_INSERT, nursery, "call to `::contains` followed by `::insert`" diff --git a/clippy_lints/src/string_patterns.rs b/clippy_lints/src/string_patterns.rs index 7e211d64da1..8af50ca87d6 100644 --- a/clippy_lints/src/string_patterns.rs +++ b/clippy_lints/src/string_patterns.rs @@ -33,7 +33,7 @@ declare_clippy_lint! { /// ```no_run /// "Hello World!".trim_end_matches(['.', ',', '!', '?']); /// ``` - #[clippy::version = "1.80.0"] + #[clippy::version = "1.81.0"] pub MANUAL_PATTERN_CHAR_COMPARISON, style, "manual char comparison in string patterns" From 9aa23b8317de0fe68415f120b1cbf589fcf3d052 Mon Sep 17 00:00:00 2001 From: xFrednet Date: Thu, 29 Aug 2024 21:38:41 +0200 Subject: [PATCH 053/683] Changelog for Clippy 1.81 :beginner: --- CHANGELOG.md | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 55 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 21252a3f43a..4364e0f7085 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,61 @@ document. ## Unreleased / Beta / In Rust Nightly -[c9139bd5...master](https://github.com/rust-lang/rust-clippy/compare/c9139bd5...master) +[b794b8e0...master](https://github.com/rust-lang/rust-clippy/compare/b794b8e0...master) + +## Rust 1.81 + +Current stable, released 2024-09-05 + +### New Lints + +* Added [`cfg_not_test`] to `restriction` + [#11293](https://github.com/rust-lang/rust-clippy/pull/11293) +* Added [`byte_char_slices`] to `style` + [#10155](https://github.com/rust-lang/rust-clippy/pull/10155) +* Added [`set_contains_or_insert`] to `nursery` + [#12873](https://github.com/rust-lang/rust-clippy/pull/12873) +* Added [`manual_rotate`] to `style` + [#12983](https://github.com/rust-lang/rust-clippy/pull/12983) +* Added [`unnecessary_min_or_max`] to `complexity` + [#12368](https://github.com/rust-lang/rust-clippy/pull/12368) +* Added [`manual_inspect`] to `complexity` + [#12287](https://github.com/rust-lang/rust-clippy/pull/12287) +* Added [`field_scoped_visibility_modifiers`] to `restriction` + [#12893](https://github.com/rust-lang/rust-clippy/pull/12893) +* Added [`manual_pattern_char_comparison`] to `style` + [#12849](https://github.com/rust-lang/rust-clippy/pull/12849) +* Added [`needless_maybe_sized`] to `suspicious` + [#10632](https://github.com/rust-lang/rust-clippy/pull/10632) +* Added [`needless_character_iteration`] to `suspicious` + [#12815](https://github.com/rust-lang/rust-clippy/pull/12815) + +### Moves and Deprecations + +* [`allow_attributes`], [`allow_attributes_without_reason`]: Now work on stable + [rust#120924](https://github.com/rust-lang/rust/pull/120924) +* Renamed `overflow_check_conditional` to [`panicking_overflow_checks`] + [#12944](https://github.com/rust-lang/rust-clippy/pull/12944) +* Moved [`panicking_overflow_checks`] to `correctness` (From `complexity` now warn-by-default) + [#12944](https://github.com/rust-lang/rust-clippy/pull/12944) +* Renamed `thread_local_initializer_can_be_made_const` to [`missing_const_for_thread_local`] + [#12974](https://github.com/rust-lang/rust-clippy/pull/12974) +* Deprecated [`maybe_misused_cfg`] and [`mismatched_target_os`] as they are now caught by cargo + and rustc + [#12875](https://github.com/rust-lang/rust-clippy/pull/12875) + +### Enhancements + +* [`significant_drop_in_scrutinee`]: Now also checks scrutinies of `while let` and `for let` + expressions + [#12870](https://github.com/rust-lang/rust-clippy/pull/12870) +* [`std_instead_of_core`]: Now respects the `msrv` configuration + [#13168](https://github.com/rust-lang/rust-clippy/pull/13168) + +### ICE Fixes + +* [`suboptimal_flops`]: No longer crashes on custom `.log()` functions + [#12884](https://github.com/rust-lang/rust-clippy/pull/12884) ## Rust 1.80 From cbc6910c35ddb682275c9ea83d94037cacc47a77 Mon Sep 17 00:00:00 2001 From: Fridtjof Stoldt Date: Thu, 29 Aug 2024 22:15:18 +0200 Subject: [PATCH 054/683] Changelog: Correct lint level Co-authored-by: Timo <30553356+y21@users.noreply.github.com> --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4364e0f7085..2488da057b5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -41,7 +41,7 @@ Current stable, released 2024-09-05 [rust#120924](https://github.com/rust-lang/rust/pull/120924) * Renamed `overflow_check_conditional` to [`panicking_overflow_checks`] [#12944](https://github.com/rust-lang/rust-clippy/pull/12944) -* Moved [`panicking_overflow_checks`] to `correctness` (From `complexity` now warn-by-default) +* Moved [`panicking_overflow_checks`] to `correctness` (From `complexity` now deny-by-default) [#12944](https://github.com/rust-lang/rust-clippy/pull/12944) * Renamed `thread_local_initializer_can_be_made_const` to [`missing_const_for_thread_local`] [#12974](https://github.com/rust-lang/rust-clippy/pull/12974) From 04d70d04fcf9412d7006ee4646f56f8bf5f2149f Mon Sep 17 00:00:00 2001 From: WeiTheShinobi Date: Sat, 31 Aug 2024 05:02:07 +0800 Subject: [PATCH 055/683] [`single_match`, `single_match_else`] fix suggestion when `match` irrefutable --- clippy_lints/src/matches/single_match.rs | 7 +++++ tests/ui/single_match.fixed | 18 +++++++++++ tests/ui/single_match.rs | 27 ++++++++++++++++ tests/ui/single_match.stderr | 40 +++++++++++++++++++++++- tests/ui/single_match_else.fixed | 4 +++ tests/ui/single_match_else.rs | 10 ++++++ tests/ui/single_match_else.stderr | 14 ++++++++- 7 files changed, 118 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/matches/single_match.rs b/clippy_lints/src/matches/single_match.rs index b6930f7b9d1..4bd46bced38 100644 --- a/clippy_lints/src/matches/single_match.rs +++ b/clippy_lints/src/matches/single_match.rs @@ -91,6 +91,13 @@ fn report_single_pattern(cx: &LateContext<'_>, ex: &Expr<'_>, arm: &Arm<'_>, exp format!(" else {}", expr_block(cx, els, ctxt, "..", Some(expr.span), &mut app)) }); + if snippet(cx, ex.span, "..") == snippet(cx, arm.pat.span, "..") { + let msg = "this pattern is irrefutable, `match` is useless"; + let sugg = expr_block(cx, arm.body, ctxt, "..", Some(expr.span), &mut app); + span_lint_and_sugg(cx, lint, expr.span, msg, "try", sugg, app); + return; + } + let (pat, pat_ref_count) = peel_hir_pat_refs(arm.pat); let (msg, sugg) = if let PatKind::Path(_) | PatKind::Lit(_) = pat.kind && let (ty, ty_ref_count) = peel_middle_ty_refs(cx.typeck_results().expr_ty(ex)) diff --git a/tests/ui/single_match.fixed b/tests/ui/single_match.fixed index 5249c440889..04129ec0f13 100644 --- a/tests/ui/single_match.fixed +++ b/tests/ui/single_match.fixed @@ -296,3 +296,21 @@ fn issue11365() { if let Some(A | B) = &Some(A) { println!() } } + +#[derive(Eq, PartialEq)] +pub struct Data([u8; 4]); + +const DATA: Data = Data([1, 2, 3, 4]); +const CONST_I32: i32 = 1; + +fn irrefutable_match() { + { println!() } + + { println!() } + + let i = 0; + { + let a = 1; + let b = 2; + } +} diff --git a/tests/ui/single_match.rs b/tests/ui/single_match.rs index 882098a56e7..2d51cee3fd9 100644 --- a/tests/ui/single_match.rs +++ b/tests/ui/single_match.rs @@ -360,3 +360,30 @@ fn issue11365() { None | Some(_) => {}, } } + +#[derive(Eq, PartialEq)] +pub struct Data([u8; 4]); + +const DATA: Data = Data([1, 2, 3, 4]); +const CONST_I32: i32 = 1; + +fn irrefutable_match() { + match DATA { + DATA => println!(), + _ => {}, + } + + match CONST_I32 { + CONST_I32 => println!(), + _ => {}, + } + + let i = 0; + match i { + i => { + let a = 1; + let b = 2; + }, + _ => {}, + } +} diff --git a/tests/ui/single_match.stderr b/tests/ui/single_match.stderr index ceb2a193bf7..9578421d2ce 100644 --- a/tests/ui/single_match.stderr +++ b/tests/ui/single_match.stderr @@ -216,5 +216,43 @@ LL | | None | Some(_) => {}, LL | | } | |_____^ help: try: `if let Some(A | B) = &Some(A) { println!() }` -error: aborting due to 20 previous errors +error: this pattern is irrefutable, `match` is useless + --> tests/ui/single_match.rs:371:5 + | +LL | / match DATA { +LL | | DATA => println!(), +LL | | _ => {}, +LL | | } + | |_____^ help: try: `{ println!() }` + +error: this pattern is irrefutable, `match` is useless + --> tests/ui/single_match.rs:376:5 + | +LL | / match CONST_I32 { +LL | | CONST_I32 => println!(), +LL | | _ => {}, +LL | | } + | |_____^ help: try: `{ println!() }` + +error: this pattern is irrefutable, `match` is useless + --> tests/ui/single_match.rs:382:5 + | +LL | / match i { +LL | | i => { +LL | | let a = 1; +LL | | let b = 2; +LL | | }, +LL | | _ => {}, +LL | | } + | |_____^ + | +help: try + | +LL ~ { +LL + let a = 1; +LL + let b = 2; +LL + } + | + +error: aborting due to 23 previous errors diff --git a/tests/ui/single_match_else.fixed b/tests/ui/single_match_else.fixed index 163be16ad8b..fb57411aaa4 100644 --- a/tests/ui/single_match_else.fixed +++ b/tests/ui/single_match_else.fixed @@ -171,3 +171,7 @@ fn issue_10808(bar: Option) { }, } } + +fn irrefutable_match() -> Option<&'static ExprNode> { + { Some(&NODE) } +} diff --git a/tests/ui/single_match_else.rs b/tests/ui/single_match_else.rs index 3f1fd2b3183..2d9e877ee0f 100644 --- a/tests/ui/single_match_else.rs +++ b/tests/ui/single_match_else.rs @@ -199,3 +199,13 @@ fn issue_10808(bar: Option) { }, } } + +fn irrefutable_match() -> Option<&'static ExprNode> { + match ExprNode::Butterflies { + ExprNode::Butterflies => Some(&NODE), + _ => { + let x = 5; + None + }, + } +} diff --git a/tests/ui/single_match_else.stderr b/tests/ui/single_match_else.stderr index 61c348260d0..61209053fd0 100644 --- a/tests/ui/single_match_else.stderr +++ b/tests/ui/single_match_else.stderr @@ -197,5 +197,17 @@ LL + println!("None"); LL + } | -error: aborting due to 9 previous errors +error: this pattern is irrefutable, `match` is useless + --> tests/ui/single_match_else.rs:204:5 + | +LL | / match ExprNode::Butterflies { +LL | | ExprNode::Butterflies => Some(&NODE), +LL | | _ => { +LL | | let x = 5; +LL | | None +LL | | }, +LL | | } + | |_____^ help: try: `{ Some(&NODE) }` + +error: aborting due to 10 previous errors From 9957101f3afd0d1dedfdc9eab81b9aa95cec7771 Mon Sep 17 00:00:00 2001 From: Pavel Grigorenko Date: Sat, 31 Aug 2024 15:31:31 +0300 Subject: [PATCH 056/683] elided_named_lifetimes: bless & add tests --- tests/ui/needless_lifetimes.stderr | 13 ++++++++++++- tests/ui/ptr_arg.stderr | 11 ++++++++++- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/tests/ui/needless_lifetimes.stderr b/tests/ui/needless_lifetimes.stderr index f325d27b8c7..50f845e2d92 100644 --- a/tests/ui/needless_lifetimes.stderr +++ b/tests/ui/needless_lifetimes.stderr @@ -1,3 +1,14 @@ +error: elided lifetime has a name + --> tests/ui/needless_lifetimes.rs:266:52 + | +LL | fn named_input_elided_output<'a>(_arg: &'a str) -> &str { + | -- ^ this elided lifetime gets resolved as `'a` + | | + | lifetime `'a` declared here + | + = note: `-D elided-named-lifetimes` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(elided_named_lifetimes)]` + error: the following explicit lifetimes could be elided: 'a, 'b --> tests/ui/needless_lifetimes.rs:17:23 | @@ -553,5 +564,5 @@ LL - fn one_input<'a>(x: &'a u8) -> &'a u8 { LL + fn one_input(x: &u8) -> &u8 { | -error: aborting due to 46 previous errors +error: aborting due to 47 previous errors diff --git a/tests/ui/ptr_arg.stderr b/tests/ui/ptr_arg.stderr index 1848ef80fc4..4246453e64c 100644 --- a/tests/ui/ptr_arg.stderr +++ b/tests/ui/ptr_arg.stderr @@ -1,3 +1,12 @@ +error: elided lifetime has a name + --> tests/ui/ptr_arg.rs:295:56 + | +LL | fn cow_good_ret_ty<'a>(input: &'a Cow<'a, str>) -> &str { + | -- lifetime `'a` declared here ^ this elided lifetime gets resolved as `'a` + | + = note: `-D elided-named-lifetimes` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(elided_named_lifetimes)]` + error: writing `&Vec` instead of `&[_]` involves a new object where a slice will do --> tests/ui/ptr_arg.rs:13:14 | @@ -212,5 +221,5 @@ error: using a reference to `Cow` is not recommended LL | fn cow_bad_ret_ty_2<'a, 'b>(input: &'a Cow<'a, str>) -> &'b str { | ^^^^^^^^^^^^^^^^ help: change this to: `&str` -error: aborting due to 24 previous errors +error: aborting due to 25 previous errors From e845366c82ada0466a9801363064357ad22daf12 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 22 Jul 2024 11:44:40 +0200 Subject: [PATCH 057/683] Add MSRV check for `saturating_sub` lints in const contexts --- clippy_config/src/msrvs.rs | 2 +- clippy_lints/src/implicit_saturating_sub.rs | 27 ++++++++++++++++++--- clippy_lints/src/lib.rs | 2 +- 3 files changed, 26 insertions(+), 5 deletions(-) diff --git a/clippy_config/src/msrvs.rs b/clippy_config/src/msrvs.rs index 5b9707efd26..db4c13fe33a 100644 --- a/clippy_config/src/msrvs.rs +++ b/clippy_config/src/msrvs.rs @@ -35,7 +35,7 @@ msrv_aliases! { 1,52,0 { STR_SPLIT_ONCE, REM_EUCLID_CONST } 1,51,0 { BORROW_AS_PTR, SEEK_FROM_CURRENT, UNSIGNED_ABS } 1,50,0 { BOOL_THEN, CLAMP } - 1,47,0 { TAU, IS_ASCII_DIGIT_CONST, ARRAY_IMPL_ANY_LEN } + 1,47,0 { TAU, IS_ASCII_DIGIT_CONST, ARRAY_IMPL_ANY_LEN, SATURATING_SUB_CONST } 1,46,0 { CONST_IF_MATCH } 1,45,0 { STR_STRIP_PREFIX } 1,43,0 { LOG2_10, LOG10_2, NUMERIC_ASSOCIATED_CONSTANTS } diff --git a/clippy_lints/src/implicit_saturating_sub.rs b/clippy_lints/src/implicit_saturating_sub.rs index 04c89062039..5a42802e6bb 100644 --- a/clippy_lints/src/implicit_saturating_sub.rs +++ b/clippy_lints/src/implicit_saturating_sub.rs @@ -1,12 +1,16 @@ +use clippy_config::msrvs::{self, Msrv}; +use clippy_config::Conf; use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; use clippy_utils::source::snippet_opt; -use clippy_utils::{higher, is_integer_literal, path_to_local, peel_blocks, peel_blocks_with_stmt, SpanlessEq}; +use clippy_utils::{ + higher, in_constant, is_integer_literal, path_to_local, peel_blocks, peel_blocks_with_stmt, SpanlessEq, +}; use rustc_ast::ast::LitKind; use rustc_data_structures::packed::Pu128; use rustc_errors::Applicability; use rustc_hir::{BinOp, BinOpKind, Expr, ExprKind, HirId, QPath}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::declare_lint_pass; +use rustc_session::impl_lint_pass; use rustc_span::Span; declare_clippy_lint! { @@ -71,13 +75,28 @@ declare_clippy_lint! { "Check if a variable is smaller than another one and still subtract from it even if smaller" } -declare_lint_pass!(ImplicitSaturatingSub => [IMPLICIT_SATURATING_SUB, INVERTED_SATURATING_SUB]); +pub struct ImplicitSaturatingSub { + msrv: Msrv, +} + +impl_lint_pass!(ImplicitSaturatingSub => [IMPLICIT_SATURATING_SUB, INVERTED_SATURATING_SUB]); + +impl ImplicitSaturatingSub { + pub fn new(conf: &'static Conf) -> Self { + Self { + msrv: conf.msrv.clone(), + } + } +} impl<'tcx> LateLintPass<'tcx> for ImplicitSaturatingSub { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { if expr.span.from_expansion() { return; } + if in_constant(cx, expr.hir_id) && !self.msrv.meets(msrvs::SATURATING_SUB_CONST) { + return; + } if let Some(higher::If { cond, then, r#else: None }) = higher::If::hir(expr) // Check if the conditional expression is a binary operation @@ -94,6 +113,8 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitSaturatingSub { check_manual_check(cx, expr, cond_op, cond_left, cond_right, if_block, else_block); } } + + extract_msrv_attr!(LateContext); } fn check_manual_check<'tcx>( diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 2ac06b360be..80e314dd402 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -623,7 +623,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { store.register_late_pass(|_| Box::new(unit_return_expecting_ord::UnitReturnExpectingOrd)); store.register_late_pass(|_| Box::new(strings::StringAdd)); store.register_late_pass(|_| Box::new(implicit_return::ImplicitReturn)); - store.register_late_pass(|_| Box::new(implicit_saturating_sub::ImplicitSaturatingSub)); + 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(|_| Box::new(non_octal_unix_permissions::NonOctalUnixPermissions)); From 2832faf8959932a25fda883ed3f7dfde8b2d2817 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 2 Aug 2024 11:17:14 +0200 Subject: [PATCH 058/683] Move MSRV check later in `implicit_saturating_sub` --- clippy_lints/src/implicit_saturating_sub.rs | 40 +++++++++++++++++---- 1 file changed, 33 insertions(+), 7 deletions(-) diff --git a/clippy_lints/src/implicit_saturating_sub.rs b/clippy_lints/src/implicit_saturating_sub.rs index 5a42802e6bb..3536309d83c 100644 --- a/clippy_lints/src/implicit_saturating_sub.rs +++ b/clippy_lints/src/implicit_saturating_sub.rs @@ -3,7 +3,7 @@ use clippy_config::Conf; use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; use clippy_utils::source::snippet_opt; use clippy_utils::{ - higher, in_constant, is_integer_literal, path_to_local, peel_blocks, peel_blocks_with_stmt, SpanlessEq, + higher, is_in_const_context, is_integer_literal, path_to_local, peel_blocks, peel_blocks_with_stmt, SpanlessEq, }; use rustc_ast::ast::LitKind; use rustc_data_structures::packed::Pu128; @@ -94,9 +94,6 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitSaturatingSub { if expr.span.from_expansion() { return; } - if in_constant(cx, expr.hir_id) && !self.msrv.meets(msrvs::SATURATING_SUB_CONST) { - return; - } if let Some(higher::If { cond, then, r#else: None }) = higher::If::hir(expr) // Check if the conditional expression is a binary operation @@ -110,13 +107,16 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitSaturatingSub { }) = higher::If::hir(expr) && let ExprKind::Binary(ref cond_op, cond_left, cond_right) = cond.kind { - check_manual_check(cx, expr, cond_op, cond_left, cond_right, if_block, else_block); + check_manual_check( + cx, expr, cond_op, cond_left, cond_right, if_block, else_block, &self.msrv, + ); } } extract_msrv_attr!(LateContext); } +#[allow(clippy::too_many_arguments)] fn check_manual_check<'tcx>( cx: &LateContext<'tcx>, expr: &Expr<'tcx>, @@ -125,6 +125,7 @@ fn check_manual_check<'tcx>( right_hand: &Expr<'tcx>, if_block: &Expr<'tcx>, else_block: &Expr<'tcx>, + msrv: &Msrv, ) { let ty = cx.typeck_results().expr_ty(left_hand); if ty.is_numeric() && !ty.is_signed() { @@ -137,6 +138,7 @@ fn check_manual_check<'tcx>( right_hand, if_block, else_block, + msrv, ), BinOpKind::Lt | BinOpKind::Le => check_gt( cx, @@ -146,12 +148,14 @@ fn check_manual_check<'tcx>( left_hand, if_block, else_block, + msrv, ), _ => {}, } } } +#[allow(clippy::too_many_arguments)] fn check_gt( cx: &LateContext<'_>, condition_span: Span, @@ -160,11 +164,21 @@ fn check_gt( little_var: &Expr<'_>, if_block: &Expr<'_>, else_block: &Expr<'_>, + msrv: &Msrv, ) { if let Some(big_var) = Var::new(big_var) && let Some(little_var) = Var::new(little_var) { - check_subtraction(cx, condition_span, expr_span, big_var, little_var, if_block, else_block); + check_subtraction( + cx, + condition_span, + expr_span, + big_var, + little_var, + if_block, + else_block, + msrv, + ); } } @@ -182,6 +196,7 @@ impl Var { } } +#[allow(clippy::too_many_arguments)] fn check_subtraction( cx: &LateContext<'_>, condition_span: Span, @@ -190,6 +205,7 @@ fn check_subtraction( little_var: Var, if_block: &Expr<'_>, else_block: &Expr<'_>, + msrv: &Msrv, ) { let if_block = peel_blocks(if_block); let else_block = peel_blocks(else_block); @@ -201,7 +217,16 @@ fn check_subtraction( } // If the subtraction is done in the `else` block, then we need to also revert the two // variables as it means that the check was reverted too. - check_subtraction(cx, condition_span, expr_span, little_var, big_var, else_block, if_block); + check_subtraction( + cx, + condition_span, + expr_span, + little_var, + big_var, + else_block, + if_block, + msrv, + ); return; } if is_integer_literal(else_block, 0) @@ -215,6 +240,7 @@ fn check_subtraction( // if `snippet_opt` fails, it won't try the next conditions. if let Some(big_var_snippet) = snippet_opt(cx, big_var.span) && let Some(little_var_snippet) = snippet_opt(cx, little_var.span) + && (!is_in_const_context(cx) || msrv.meets(msrvs::SATURATING_SUB_CONST)) { span_lint_and_sugg( cx, From 989ebae2ba5b79e259ee6267a390acd446cb5bff Mon Sep 17 00:00:00 2001 From: alexey semenyuk Date: Thu, 29 Aug 2024 10:55:42 +0500 Subject: [PATCH 059/683] Provide more clear example for WRONG_SELF_CONVENTION --- clippy_lints/src/methods/mod.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index d7126990edb..e1f1df4eecb 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -441,6 +441,17 @@ declare_clippy_lint! { /// } /// } /// ``` + /// + /// Use instead: + /// ```no_run + /// # struct X; + /// impl X { + /// fn as_str(&self) -> &'static str { + /// // .. + /// # "" + /// } + /// } + /// ``` #[clippy::version = "pre 1.29.0"] pub WRONG_SELF_CONVENTION, style, From ba2577f23c0014c171235692ca4d8b6b71fbce7e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 25 Aug 2024 15:15:15 +0200 Subject: [PATCH 060/683] stabilize const_float_bits_conv --- clippy_lints/src/transmute/mod.rs | 6 +- .../src/transmute/transmute_float_to_int.rs | 3 +- .../src/transmute/transmute_int_to_float.rs | 3 +- .../src/transmute/transmute_num_to_bytes.rs | 6 - tests/ui/transmute.rs | 12 ++ tests/ui/transmute.stderr | 112 ++++++++++++++---- tests/ui/transmute_float_to_int.fixed | 28 +++-- tests/ui/transmute_float_to_int.rs | 12 +- tests/ui/transmute_float_to_int.stderr | 50 +++++++- 9 files changed, 186 insertions(+), 46 deletions(-) diff --git a/clippy_lints/src/transmute/mod.rs b/clippy_lints/src/transmute/mod.rs index 373bf61d8ff..a2ae36cc484 100644 --- a/clippy_lints/src/transmute/mod.rs +++ b/clippy_lints/src/transmute/mod.rs @@ -619,10 +619,10 @@ impl<'tcx> LateLintPass<'tcx> for Transmute { | transmute_ref_to_ref::check(cx, e, from_ty, to_ty, arg, const_context) | transmute_ptr_to_ptr::check(cx, e, from_ty, to_ty, arg, &self.msrv) | transmute_int_to_bool::check(cx, e, from_ty, to_ty, arg) - | transmute_int_to_float::check(cx, e, from_ty, to_ty, arg, const_context) + | transmute_int_to_float::check(cx, e, from_ty, to_ty, arg) | transmute_int_to_non_zero::check(cx, e, from_ty, to_ty, arg) - | transmute_float_to_int::check(cx, e, from_ty, to_ty, arg, const_context) - | transmute_num_to_bytes::check(cx, e, from_ty, to_ty, arg, const_context) + | transmute_float_to_int::check(cx, e, from_ty, to_ty, arg) + | transmute_num_to_bytes::check(cx, e, from_ty, to_ty, arg) | (unsound_collection_transmute::check(cx, e, from_ty, to_ty) || transmute_undefined_repr::check(cx, e, from_ty, to_ty)) | (eager_transmute::check(cx, e, arg, from_ty, to_ty)); diff --git a/clippy_lints/src/transmute/transmute_float_to_int.rs b/clippy_lints/src/transmute/transmute_float_to_int.rs index ab3bb5e1062..cb46109c27e 100644 --- a/clippy_lints/src/transmute/transmute_float_to_int.rs +++ b/clippy_lints/src/transmute/transmute_float_to_int.rs @@ -15,10 +15,9 @@ pub(super) fn check<'tcx>( from_ty: Ty<'tcx>, to_ty: Ty<'tcx>, mut arg: &'tcx Expr<'_>, - const_context: bool, ) -> bool { match (&from_ty.kind(), &to_ty.kind()) { - (ty::Float(float_ty), ty::Int(_) | ty::Uint(_)) if !const_context => { + (ty::Float(float_ty), ty::Int(_) | ty::Uint(_)) => { span_lint_and_then( cx, TRANSMUTE_FLOAT_TO_INT, diff --git a/clippy_lints/src/transmute/transmute_int_to_float.rs b/clippy_lints/src/transmute/transmute_int_to_float.rs index d51888e3097..e00fb90c307 100644 --- a/clippy_lints/src/transmute/transmute_int_to_float.rs +++ b/clippy_lints/src/transmute/transmute_int_to_float.rs @@ -14,10 +14,9 @@ pub(super) fn check<'tcx>( from_ty: Ty<'tcx>, to_ty: Ty<'tcx>, arg: &'tcx Expr<'_>, - const_context: bool, ) -> bool { match (&from_ty.kind(), &to_ty.kind()) { - (ty::Int(_) | ty::Uint(_), ty::Float(_)) if !const_context => { + (ty::Int(_) | ty::Uint(_), ty::Float(_)) => { span_lint_and_then( cx, TRANSMUTE_INT_TO_FLOAT, diff --git a/clippy_lints/src/transmute/transmute_num_to_bytes.rs b/clippy_lints/src/transmute/transmute_num_to_bytes.rs index 88b0ac5a368..362f2bb6960 100644 --- a/clippy_lints/src/transmute/transmute_num_to_bytes.rs +++ b/clippy_lints/src/transmute/transmute_num_to_bytes.rs @@ -14,18 +14,12 @@ pub(super) fn check<'tcx>( from_ty: Ty<'tcx>, to_ty: Ty<'tcx>, arg: &'tcx Expr<'_>, - const_context: bool, ) -> bool { match (&from_ty.kind(), &to_ty.kind()) { (ty::Int(_) | ty::Uint(_) | ty::Float(_), ty::Array(arr_ty, _)) => { if !matches!(arr_ty.kind(), ty::Uint(UintTy::U8)) { return false; } - if matches!(from_ty.kind(), ty::Float(_)) && const_context { - // TODO: Remove when const_float_bits_conv is stabilized - // rust#72447 - return false; - } span_lint_and_then( cx, diff --git a/tests/ui/transmute.rs b/tests/ui/transmute.rs index 46629526367..eeea3f080b1 100644 --- a/tests/ui/transmute.rs +++ b/tests/ui/transmute.rs @@ -140,24 +140,32 @@ mod int_to_float { mod issue_5747 { const VALUE16: f16 = unsafe { std::mem::transmute(0_u16) }; + //~^ ERROR: transmute from a `u16` to a `f16` const VALUE32: f32 = unsafe { std::mem::transmute(0_u32) }; + //~^ ERROR: transmute from a `u32` to a `f32` const VALUE64: f64 = unsafe { std::mem::transmute(0_i64) }; + //~^ ERROR: transmute from a `i64` to a `f64` const VALUE128: f128 = unsafe { std::mem::transmute(0_i128) }; + //~^ ERROR: transmute from a `i128` to a `f128` const fn from_bits_16(v: i16) -> f16 { unsafe { std::mem::transmute(v) } + //~^ ERROR: transmute from a `i16` to a `f16` } const fn from_bits_32(v: i32) -> f32 { unsafe { std::mem::transmute(v) } + //~^ ERROR: transmute from a `i32` to a `f32` } const fn from_bits_64(v: u64) -> f64 { unsafe { std::mem::transmute(v) } + //~^ ERROR: transmute from a `u64` to a `f64` } const fn from_bits_128(v: u128) -> f128 { unsafe { std::mem::transmute(v) } + //~^ ERROR: transmute from a `u128` to a `f128` } } } @@ -205,9 +213,13 @@ mod num_to_bytes { //~^ ERROR: transmute from a `i128` to a `[u8; 16]` let _: [u8; 2] = std::mem::transmute(0.0f16); + //~^ ERROR: transmute from a `f16` to a `[u8; 2]` let _: [u8; 4] = std::mem::transmute(0.0f32); + //~^ ERROR: transmute from a `f32` to a `[u8; 4]` let _: [u8; 8] = std::mem::transmute(0.0f64); + //~^ ERROR: transmute from a `f64` to a `[u8; 8]` let _: [u8; 16] = std::mem::transmute(0.0f128); + //~^ ERROR: transmute from a `f128` to a `[u8; 16]` } } } diff --git a/tests/ui/transmute.stderr b/tests/ui/transmute.stderr index 0072f62962a..41a10f381dc 100644 --- a/tests/ui/transmute.stderr +++ b/tests/ui/transmute.stderr @@ -148,8 +148,56 @@ error: transmute from a `i128` to a `f128` LL | let _: f128 = unsafe { std::mem::transmute(0_i128) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f128::from_bits(0_i128 as u128)` +error: transmute from a `u16` to a `f16` + --> tests/ui/transmute.rs:142:39 + | +LL | const VALUE16: f16 = unsafe { std::mem::transmute(0_u16) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f16::from_bits(0_u16)` + +error: transmute from a `u32` to a `f32` + --> tests/ui/transmute.rs:144:39 + | +LL | const VALUE32: f32 = unsafe { std::mem::transmute(0_u32) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f32::from_bits(0_u32)` + +error: transmute from a `i64` to a `f64` + --> tests/ui/transmute.rs:146:39 + | +LL | const VALUE64: f64 = unsafe { std::mem::transmute(0_i64) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f64::from_bits(0_i64 as u64)` + +error: transmute from a `i128` to a `f128` + --> tests/ui/transmute.rs:148:41 + | +LL | const VALUE128: f128 = unsafe { std::mem::transmute(0_i128) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f128::from_bits(0_i128 as u128)` + +error: transmute from a `i16` to a `f16` + --> tests/ui/transmute.rs:152:22 + | +LL | unsafe { std::mem::transmute(v) } + | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f16::from_bits(v as u16)` + +error: transmute from a `i32` to a `f32` + --> tests/ui/transmute.rs:157:22 + | +LL | unsafe { std::mem::transmute(v) } + | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f32::from_bits(v as u32)` + +error: transmute from a `u64` to a `f64` + --> tests/ui/transmute.rs:162:22 + | +LL | unsafe { std::mem::transmute(v) } + | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f64::from_bits(v)` + +error: transmute from a `u128` to a `f128` + --> tests/ui/transmute.rs:167:22 + | +LL | unsafe { std::mem::transmute(v) } + | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f128::from_bits(v)` + error: transmute from a `u8` to a `[u8; 1]` - --> tests/ui/transmute.rs:168:30 + --> tests/ui/transmute.rs:176:30 | LL | let _: [u8; 1] = std::mem::transmute(0u8); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u8.to_ne_bytes()` @@ -158,97 +206,121 @@ LL | let _: [u8; 1] = std::mem::transmute(0u8); = help: to override `-D warnings` add `#[allow(clippy::transmute_num_to_bytes)]` error: transmute from a `u32` to a `[u8; 4]` - --> tests/ui/transmute.rs:171:30 + --> tests/ui/transmute.rs:179:30 | LL | let _: [u8; 4] = std::mem::transmute(0u32); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u32.to_ne_bytes()` error: transmute from a `u128` to a `[u8; 16]` - --> tests/ui/transmute.rs:173:31 + --> tests/ui/transmute.rs:181:31 | LL | let _: [u8; 16] = std::mem::transmute(0u128); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u128.to_ne_bytes()` error: transmute from a `i8` to a `[u8; 1]` - --> tests/ui/transmute.rs:175:30 + --> tests/ui/transmute.rs:183:30 | LL | let _: [u8; 1] = std::mem::transmute(0i8); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i8.to_ne_bytes()` error: transmute from a `i32` to a `[u8; 4]` - --> tests/ui/transmute.rs:177:30 + --> tests/ui/transmute.rs:185:30 | LL | let _: [u8; 4] = std::mem::transmute(0i32); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i32.to_ne_bytes()` error: transmute from a `i128` to a `[u8; 16]` - --> tests/ui/transmute.rs:179:31 + --> tests/ui/transmute.rs:187:31 | LL | let _: [u8; 16] = std::mem::transmute(0i128); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i128.to_ne_bytes()` error: transmute from a `f16` to a `[u8; 2]` - --> tests/ui/transmute.rs:182:30 + --> tests/ui/transmute.rs:190:30 | LL | let _: [u8; 2] = std::mem::transmute(0.0f16); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0.0f16.to_ne_bytes()` error: transmute from a `f32` to a `[u8; 4]` - --> tests/ui/transmute.rs:184:30 + --> tests/ui/transmute.rs:192:30 | LL | let _: [u8; 4] = std::mem::transmute(0.0f32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0.0f32.to_ne_bytes()` error: transmute from a `f64` to a `[u8; 8]` - --> tests/ui/transmute.rs:186:30 + --> tests/ui/transmute.rs:194:30 | LL | let _: [u8; 8] = std::mem::transmute(0.0f64); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0.0f64.to_ne_bytes()` error: transmute from a `f128` to a `[u8; 16]` - --> tests/ui/transmute.rs:188:31 + --> tests/ui/transmute.rs:196:31 | LL | let _: [u8; 16] = std::mem::transmute(0.0f128); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0.0f128.to_ne_bytes()` error: transmute from a `u8` to a `[u8; 1]` - --> tests/ui/transmute.rs:194:30 + --> tests/ui/transmute.rs:202:30 | LL | let _: [u8; 1] = std::mem::transmute(0u8); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u8.to_ne_bytes()` error: transmute from a `u32` to a `[u8; 4]` - --> tests/ui/transmute.rs:196:30 + --> tests/ui/transmute.rs:204:30 | LL | let _: [u8; 4] = std::mem::transmute(0u32); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u32.to_ne_bytes()` error: transmute from a `u128` to a `[u8; 16]` - --> tests/ui/transmute.rs:198:31 + --> tests/ui/transmute.rs:206:31 | LL | let _: [u8; 16] = std::mem::transmute(0u128); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u128.to_ne_bytes()` error: transmute from a `i8` to a `[u8; 1]` - --> tests/ui/transmute.rs:200:30 + --> tests/ui/transmute.rs:208:30 | LL | let _: [u8; 1] = std::mem::transmute(0i8); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i8.to_ne_bytes()` error: transmute from a `i32` to a `[u8; 4]` - --> tests/ui/transmute.rs:202:30 + --> tests/ui/transmute.rs:210:30 | LL | let _: [u8; 4] = std::mem::transmute(0i32); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i32.to_ne_bytes()` error: transmute from a `i128` to a `[u8; 16]` - --> tests/ui/transmute.rs:204:31 + --> tests/ui/transmute.rs:212:31 | LL | let _: [u8; 16] = std::mem::transmute(0i128); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i128.to_ne_bytes()` +error: transmute from a `f16` to a `[u8; 2]` + --> tests/ui/transmute.rs:215:30 + | +LL | let _: [u8; 2] = std::mem::transmute(0.0f16); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0.0f16.to_ne_bytes()` + +error: transmute from a `f32` to a `[u8; 4]` + --> tests/ui/transmute.rs:217:30 + | +LL | let _: [u8; 4] = std::mem::transmute(0.0f32); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0.0f32.to_ne_bytes()` + +error: transmute from a `f64` to a `[u8; 8]` + --> tests/ui/transmute.rs:219:30 + | +LL | let _: [u8; 8] = std::mem::transmute(0.0f64); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0.0f64.to_ne_bytes()` + +error: transmute from a `f128` to a `[u8; 16]` + --> tests/ui/transmute.rs:221:31 + | +LL | let _: [u8; 16] = std::mem::transmute(0.0f128); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0.0f128.to_ne_bytes()` + error: transmute from a `&[u8]` to a `&str` - --> tests/ui/transmute.rs:218:28 + --> tests/ui/transmute.rs:230:28 | LL | let _: &str = unsafe { std::mem::transmute(B) }; | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::str::from_utf8(B).unwrap()` @@ -257,16 +329,16 @@ LL | let _: &str = unsafe { std::mem::transmute(B) }; = help: to override `-D warnings` add `#[allow(clippy::transmute_bytes_to_str)]` error: transmute from a `&mut [u8]` to a `&mut str` - --> tests/ui/transmute.rs:221:32 + --> tests/ui/transmute.rs:233:32 | LL | let _: &mut str = unsafe { std::mem::transmute(mb) }; | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::str::from_utf8_mut(mb).unwrap()` error: transmute from a `&[u8]` to a `&str` - --> tests/ui/transmute.rs:223:30 + --> tests/ui/transmute.rs:235:30 | LL | const _: &str = unsafe { std::mem::transmute(B) }; | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::str::from_utf8_unchecked(B)` -error: aborting due to 42 previous errors +error: aborting due to 54 previous errors diff --git a/tests/ui/transmute_float_to_int.fixed b/tests/ui/transmute_float_to_int.fixed index 4361a7407d1..83814ca43b9 100644 --- a/tests/ui/transmute_float_to_int.fixed +++ b/tests/ui/transmute_float_to_int.fixed @@ -1,7 +1,7 @@ #![warn(clippy::transmute_float_to_int)] #![allow(clippy::missing_transmute_annotations)] -#![feature(f128)] -#![feature(f16)] +#![feature(f128, f128_const)] +#![feature(f16, f16_const)] fn float_to_int() { let _: u32 = unsafe { 1f32.to_bits() }; @@ -20,25 +20,33 @@ fn float_to_int() { } mod issue_5747 { - const VALUE16: i16 = unsafe { std::mem::transmute(1f16) }; - const VALUE32: i32 = unsafe { std::mem::transmute(1f32) }; - const VALUE64: u64 = unsafe { std::mem::transmute(1f64) }; - const VALUE128: u128 = unsafe { std::mem::transmute(1f128) }; + const VALUE16: i16 = unsafe { 1f16.to_bits() as i16 }; + //~^ ERROR: transmute from a `f16` to a `i16` + const VALUE32: i32 = unsafe { 1f32.to_bits() as i32 }; + //~^ ERROR: transmute from a `f32` to a `i32` + const VALUE64: u64 = unsafe { 1f64.to_bits() }; + //~^ ERROR: transmute from a `f64` to a `u64` + const VALUE128: u128 = unsafe { 1f128.to_bits() }; + //~^ ERROR: transmute from a `f128` to a `u128` const fn to_bits_16(v: f16) -> u16 { - unsafe { std::mem::transmute(v) } + unsafe { v.to_bits() } + //~^ ERROR: transmute from a `f16` to a `u16` } const fn to_bits_32(v: f32) -> u32 { - unsafe { std::mem::transmute(v) } + unsafe { v.to_bits() } + //~^ ERROR: transmute from a `f32` to a `u32` } const fn to_bits_64(v: f64) -> i64 { - unsafe { std::mem::transmute(v) } + unsafe { v.to_bits() as i64 } + //~^ ERROR: transmute from a `f64` to a `i64` } const fn to_bits_128(v: f128) -> i128 { - unsafe { std::mem::transmute(v) } + unsafe { v.to_bits() as i128 } + //~^ ERROR: transmute from a `f128` to a `i128` } } diff --git a/tests/ui/transmute_float_to_int.rs b/tests/ui/transmute_float_to_int.rs index 363ce0bcb16..64d6e917203 100644 --- a/tests/ui/transmute_float_to_int.rs +++ b/tests/ui/transmute_float_to_int.rs @@ -1,7 +1,7 @@ #![warn(clippy::transmute_float_to_int)] #![allow(clippy::missing_transmute_annotations)] -#![feature(f128)] -#![feature(f16)] +#![feature(f128, f128_const)] +#![feature(f16, f16_const)] fn float_to_int() { let _: u32 = unsafe { std::mem::transmute(1f32) }; @@ -21,24 +21,32 @@ fn float_to_int() { mod issue_5747 { const VALUE16: i16 = unsafe { std::mem::transmute(1f16) }; + //~^ ERROR: transmute from a `f16` to a `i16` const VALUE32: i32 = unsafe { std::mem::transmute(1f32) }; + //~^ ERROR: transmute from a `f32` to a `i32` const VALUE64: u64 = unsafe { std::mem::transmute(1f64) }; + //~^ ERROR: transmute from a `f64` to a `u64` const VALUE128: u128 = unsafe { std::mem::transmute(1f128) }; + //~^ ERROR: transmute from a `f128` to a `u128` const fn to_bits_16(v: f16) -> u16 { unsafe { std::mem::transmute(v) } + //~^ ERROR: transmute from a `f16` to a `u16` } const fn to_bits_32(v: f32) -> u32 { unsafe { std::mem::transmute(v) } + //~^ ERROR: transmute from a `f32` to a `u32` } const fn to_bits_64(v: f64) -> i64 { unsafe { std::mem::transmute(v) } + //~^ ERROR: transmute from a `f64` to a `i64` } const fn to_bits_128(v: f128) -> i128 { unsafe { std::mem::transmute(v) } + //~^ ERROR: transmute from a `f128` to a `i128` } } diff --git a/tests/ui/transmute_float_to_int.stderr b/tests/ui/transmute_float_to_int.stderr index 9cac75f72cd..0cabab58ab0 100644 --- a/tests/ui/transmute_float_to_int.stderr +++ b/tests/ui/transmute_float_to_int.stderr @@ -37,5 +37,53 @@ error: transmute from a `f64` to a `u64` LL | let _: u64 = unsafe { std::mem::transmute(-1.0) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(-1.0f64).to_bits()` -error: aborting due to 6 previous errors +error: transmute from a `f16` to a `i16` + --> tests/ui/transmute_float_to_int.rs:23:35 + | +LL | const VALUE16: i16 = unsafe { std::mem::transmute(1f16) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `1f16.to_bits() as i16` + +error: transmute from a `f32` to a `i32` + --> tests/ui/transmute_float_to_int.rs:25:35 + | +LL | const VALUE32: i32 = unsafe { std::mem::transmute(1f32) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `1f32.to_bits() as i32` + +error: transmute from a `f64` to a `u64` + --> tests/ui/transmute_float_to_int.rs:27:35 + | +LL | const VALUE64: u64 = unsafe { std::mem::transmute(1f64) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `1f64.to_bits()` + +error: transmute from a `f128` to a `u128` + --> tests/ui/transmute_float_to_int.rs:29:37 + | +LL | const VALUE128: u128 = unsafe { std::mem::transmute(1f128) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `1f128.to_bits()` + +error: transmute from a `f16` to a `u16` + --> tests/ui/transmute_float_to_int.rs:33:18 + | +LL | unsafe { std::mem::transmute(v) } + | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `v.to_bits()` + +error: transmute from a `f32` to a `u32` + --> tests/ui/transmute_float_to_int.rs:38:18 + | +LL | unsafe { std::mem::transmute(v) } + | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `v.to_bits()` + +error: transmute from a `f64` to a `i64` + --> tests/ui/transmute_float_to_int.rs:43:18 + | +LL | unsafe { std::mem::transmute(v) } + | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `v.to_bits() as i64` + +error: transmute from a `f128` to a `i128` + --> tests/ui/transmute_float_to_int.rs:48:18 + | +LL | unsafe { std::mem::transmute(v) } + | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `v.to_bits() as i128` + +error: aborting due to 14 previous errors From 0bdc5ffd685db3d1506dbf21c8df5daaf68aeaac Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Sun, 1 Sep 2024 11:23:24 -0400 Subject: [PATCH 061/683] Support the weak variable attribute --- Cargo.lock | 6 ++---- Cargo.toml | 3 ++- src/consts.rs | 7 ++++++- src/mono_item.rs | 2 +- 4 files changed, 11 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 915229f7e7e..42528419a25 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -80,8 +80,7 @@ dependencies = [ [[package]] name = "gccjit" version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62e0ba949ebee07c5cc21f02cb48f28f2c8db7fcbc15fdc5120476a6c43b4636" +source = "git+https://github.com/rust-lang/gccjit.rs#4fbe2023250357378fb2faf6f484b34cb8f8ebc3" dependencies = [ "gccjit_sys", ] @@ -89,8 +88,7 @@ dependencies = [ [[package]] name = "gccjit_sys" version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5bbf85e12c2593772329a9d4e8310271f6706e6045ce4f41b041dd34fba6603" +source = "git+https://github.com/rust-lang/gccjit.rs#4fbe2023250357378fb2faf6f484b34cb8f8ebc3" dependencies = [ "libc", ] diff --git a/Cargo.toml b/Cargo.toml index 5caca63f634..67a90cc34ee 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,7 +22,8 @@ master = ["gccjit/master"] default = ["master"] [dependencies] -gccjit = "2.1" +#gccjit = "2.1" +gccjit = { git = "https://github.com/rust-lang/gccjit.rs" } # Local copy. #gccjit = { path = "../gccjit.rs" } diff --git a/src/consts.rs b/src/consts.rs index e5673cddc4a..53dbb35d711 100644 --- a/src/consts.rs +++ b/src/consts.rs @@ -7,6 +7,7 @@ use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs} use rustc_middle::mir::interpret::{ self, read_target_uint, ConstAllocation, ErrorHandled, Scalar as InterpScalar, }; +use rustc_middle::mir::mono::Linkage; use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::{self, Instance}; use rustc_middle::{bug, span_bug}; @@ -256,7 +257,7 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { if !self.tcx.is_reachable_non_generic(def_id) { #[cfg(feature = "master")] - global.add_string_attribute(VarAttribute::Visibility(Visibility::Hidden)); + global.add_attribute(VarAttribute::Visibility(Visibility::Hidden)); } global @@ -384,6 +385,10 @@ fn check_and_apply_linkage<'gcc, 'tcx>( let global1 = cx.declare_global_with_linkage(sym, cx.type_i8(), base::global_linkage_to_gcc(linkage)); + if linkage == Linkage::ExternalWeak { + global1.add_attribute(VarAttribute::Weak); + } + // Declare an internal global `extern_with_linkage_foo` which // is initialized with the address of `foo`. If `foo` is // discarded during linking (for example, if `foo` has weak diff --git a/src/mono_item.rs b/src/mono_item.rs index e6b22d51871..ba81dea49d5 100644 --- a/src/mono_item.rs +++ b/src/mono_item.rs @@ -37,7 +37,7 @@ impl<'gcc, 'tcx> PreDefineMethods<'tcx> for CodegenCx<'gcc, 'tcx> { let is_tls = attrs.flags.contains(CodegenFnAttrFlags::THREAD_LOCAL); let global = self.define_global(symbol_name, gcc_type, is_tls, attrs.link_section); #[cfg(feature = "master")] - global.add_string_attribute(VarAttribute::Visibility(base::visibility_to_gcc(visibility))); + global.add_attribute(VarAttribute::Visibility(base::visibility_to_gcc(visibility))); // TODO(antoyo): set linkage. self.instances.borrow_mut().insert(instance, global); From 4dd288cecf8b8fc24921f45413b7609ab55a066d Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Sun, 1 Sep 2024 11:59:27 -0400 Subject: [PATCH 062/683] Fix tests --- build_system/src/test.rs | 3 +- libgccjit.version | 2 +- ...022-core-Disable-not-compiling-tests.patch | 30 +++++++++---------- src/consts.rs | 1 + src/intrinsic/llvm.rs | 2 ++ tests/failing-ice-tests.txt | 4 +++ tests/failing-ui-tests.txt | 26 ++++++++++++++++ 7 files changed, 51 insertions(+), 17 deletions(-) diff --git a/build_system/src/test.rs b/build_system/src/test.rs index 303a2e518cf..dd09de24aa3 100644 --- a/build_system/src/test.rs +++ b/build_system/src/test.rs @@ -637,7 +637,8 @@ fn test_projects(env: &Env, args: &TestArg) -> Result<(), String> { "https://github.com/BurntSushi/memchr", "https://github.com/dtolnay/itoa", "https://github.com/rust-lang/cfg-if", - "https://github.com/rust-lang-nursery/lazy-static.rs", + //"https://github.com/rust-lang-nursery/lazy-static.rs", // TODO: re-enable when the + //failing test is fixed upstream. //"https://github.com/marshallpierce/rust-base64", // FIXME: one test is OOM-killed. // TODO: ignore the base64 test that is OOM-killed. "https://github.com/time-rs/time", diff --git a/libgccjit.version b/libgccjit.version index 23ca7f02215..fa2bacc2c8e 100644 --- a/libgccjit.version +++ b/libgccjit.version @@ -1 +1 @@ -341be3b7d7ac6976cfed8ed59da3573c040d0776 +bcafd46296f7898dac02d127e441b1d838ef2afc diff --git a/patches/0022-core-Disable-not-compiling-tests.patch b/patches/0022-core-Disable-not-compiling-tests.patch index 08e2f1a7628..b2ab05691ec 100644 --- a/patches/0022-core-Disable-not-compiling-tests.patch +++ b/patches/0022-core-Disable-not-compiling-tests.patch @@ -1,26 +1,24 @@ -From f6befc4bb51d84f5f1cf35938a168c953d421350 Mon Sep 17 00:00:00 2001 -From: bjorn3 -Date: Sun, 24 Nov 2019 15:10:23 +0100 +From 18793c6109890493ceb3ff36549849a36e3d8022 Mon Sep 17 00:00:00 2001 +From: None +Date: Sun, 1 Sep 2024 11:42:17 -0400 Subject: [PATCH] [core] Disable not compiling tests --- - library/core/tests/Cargo.toml | 8 ++++++++ - library/core/tests/num/flt2dec/mod.rs | 1 - - library/core/tests/num/int_macros.rs | 2 ++ - library/core/tests/num/uint_macros.rs | 2 ++ - library/core/tests/ptr.rs | 2 ++ - library/core/tests/slice.rs | 2 ++ - 6 files changed, 16 insertions(+), 1 deletion(-) + library/core/tests/Cargo.toml | 14 ++++++++++++++ + library/core/tests/lib.rs | 1 + + 2 files changed, 15 insertions(+) create mode 100644 library/core/tests/Cargo.toml diff --git a/library/core/tests/Cargo.toml b/library/core/tests/Cargo.toml new file mode 100644 -index 0000000..46fd999 +index 0000000..ca326ac --- /dev/null +++ b/library/core/tests/Cargo.toml -@@ -0,0 +1,12 @@ +@@ -0,0 +1,14 @@ ++[workspace] ++ +[package] -+name = "core" ++name = "coretests" +version = "0.0.0" +edition = "2021" + @@ -32,12 +30,14 @@ index 0000000..46fd999 +rand = { version = "0.8.5", default-features = false } +rand_xorshift = { version = "0.3.0", default-features = false } diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs -index 42a26ae..5ac1042 100644 +index 1e336bf..5800ebb 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs -@@ -2,4 +2,5 @@ +@@ -1,4 +1,5 @@ // tidy-alphabetical-start +#![cfg(test)] #![cfg_attr(bootstrap, feature(offset_of_nested))] #![cfg_attr(target_has_atomic = "128", feature(integer_atomics))] #![cfg_attr(test, feature(cfg_match))] +-- +2.46.0 diff --git a/src/consts.rs b/src/consts.rs index 53dbb35d711..483b2355c52 100644 --- a/src/consts.rs +++ b/src/consts.rs @@ -386,6 +386,7 @@ fn check_and_apply_linkage<'gcc, 'tcx>( cx.declare_global_with_linkage(sym, cx.type_i8(), base::global_linkage_to_gcc(linkage)); if linkage == Linkage::ExternalWeak { + #[cfg(feature = "master")] global1.add_attribute(VarAttribute::Weak); } diff --git a/src/intrinsic/llvm.rs b/src/intrinsic/llvm.rs index 554e57250e6..2287c96b41b 100644 --- a/src/intrinsic/llvm.rs +++ b/src/intrinsic/llvm.rs @@ -985,6 +985,8 @@ pub fn intrinsic<'gcc, 'tcx>(name: &str, cx: &CodegenCx<'gcc, 'tcx>) -> Function "llvm.x86.avx512.vpdpbusds.512" => "__builtin_ia32_vpdpbusds_v16si", "llvm.x86.avx512.vpdpbusds.256" => "__builtin_ia32_vpdpbusds_v8si", "llvm.x86.avx512.vpdpbusds.128" => "__builtin_ia32_vpdpbusds_v4si", + "llvm.x86.xsave" => "__builtin_ia32_xsave", + "llvm.x86.xsaveopt" => "__builtin_ia32_xsaveopt", // NOTE: this file is generated by https://github.com/GuillaumeGomez/llvmint/blob/master/generate_list.py _ => include!("archs.rs"), diff --git a/tests/failing-ice-tests.txt b/tests/failing-ice-tests.txt index 2084f86b62e..ff1b6f14894 100644 --- a/tests/failing-ice-tests.txt +++ b/tests/failing-ice-tests.txt @@ -34,3 +34,7 @@ tests/ui/sepcomp/sepcomp-unwind.rs tests/ui/extern/issue-64655-extern-rust-must-allow-unwind.rs tests/ui/extern/issue-64655-allow-unwind-when-calling-panic-directly.rs tests/ui/unwind-no-uwtable.rs +tests/ui/delegation/fn-header.rs +tests/ui/simd/intrinsic/generic-arithmetic-pass.rs +tests/ui/simd/masked-load-store.rs +tests/ui/rfcs/rfc-2632-const-trait-impl/effects/minicore.rs diff --git a/tests/failing-ui-tests.txt b/tests/failing-ui-tests.txt index 5a55bdb156e..56b51275a53 100644 --- a/tests/failing-ui-tests.txt +++ b/tests/failing-ui-tests.txt @@ -95,3 +95,29 @@ tests/ui/simd/intrinsic/generic-arithmetic-pass.rs tests/ui/backtrace/backtrace.rs tests/ui/lifetimes/tail-expr-lock-poisoning.rs tests/ui/runtime/rt-explody-panic-payloads.rs +tests/ui/codegen/equal-pointers-unequal/as-cast/function.rs +tests/ui/codegen/equal-pointers-unequal/as-cast/basic.rs +tests/ui/codegen/equal-pointers-unequal/as-cast/inline1.rs +tests/ui/codegen/equal-pointers-unequal/as-cast/print.rs +tests/ui/codegen/equal-pointers-unequal/as-cast/inline2.rs +tests/ui/codegen/equal-pointers-unequal/as-cast/print3.rs +tests/ui/codegen/equal-pointers-unequal/as-cast/segfault.rs +tests/ui/codegen/equal-pointers-unequal/exposed-provenance/function.rs +tests/ui/codegen/equal-pointers-unequal/exposed-provenance/basic.rs +tests/ui/codegen/equal-pointers-unequal/as-cast/zero.rs +tests/ui/codegen/equal-pointers-unequal/exposed-provenance/inline1.rs +tests/ui/codegen/equal-pointers-unequal/exposed-provenance/print.rs +tests/ui/codegen/equal-pointers-unequal/exposed-provenance/print3.rs +tests/ui/codegen/equal-pointers-unequal/exposed-provenance/inline2.rs +tests/ui/codegen/equal-pointers-unequal/exposed-provenance/segfault.rs +tests/ui/codegen/equal-pointers-unequal/exposed-provenance/zero.rs +tests/ui/codegen/equal-pointers-unequal/strict-provenance/basic.rs +tests/ui/codegen/equal-pointers-unequal/strict-provenance/function.rs +tests/ui/codegen/equal-pointers-unequal/strict-provenance/print.rs +tests/ui/codegen/equal-pointers-unequal/strict-provenance/inline1.rs +tests/ui/codegen/equal-pointers-unequal/strict-provenance/print3.rs +tests/ui/codegen/equal-pointers-unequal/strict-provenance/inline2.rs +tests/ui/codegen/equal-pointers-unequal/strict-provenance/segfault.rs +tests/ui/codegen/equal-pointers-unequal/strict-provenance/zero.rs +tests/ui/sanitizer/cfi-sized-associated-ty.rs +tests/ui/sanitizer/cfi-can-reveal-opaques.rs From cd28176025ef5f00ed58680ac4c346c3b0c19020 Mon Sep 17 00:00:00 2001 From: Yuri Astrakhan Date: Sun, 1 Sep 2024 20:58:14 -0400 Subject: [PATCH 063/683] Minor code simplification --- .../attrs/allow_attributes_without_reason.rs | 2 +- clippy_utils/src/sugg.rs | 38 ++++++++----------- 2 files changed, 17 insertions(+), 23 deletions(-) diff --git a/clippy_lints/src/attrs/allow_attributes_without_reason.rs b/clippy_lints/src/attrs/allow_attributes_without_reason.rs index 4ab97118df1..4c7e07478c1 100644 --- a/clippy_lints/src/attrs/allow_attributes_without_reason.rs +++ b/clippy_lints/src/attrs/allow_attributes_without_reason.rs @@ -26,7 +26,7 @@ pub(super) fn check<'cx>(cx: &LateContext<'cx>, name: Symbol, items: &[NestedMet cx, ALLOW_ATTRIBUTES_WITHOUT_REASON, attr.span, - format!("`{}` attribute without specifying a reason", name.as_str()), + format!("`{name}` attribute without specifying a reason"), |diag| { diag.help("try adding a reason at the end with `, reason = \"..\"`"); }, diff --git a/clippy_utils/src/sugg.rs b/clippy_utils/src/sugg.rs index 0f86d89c980..3255c51d009 100644 --- a/clippy_utils/src/sugg.rs +++ b/clippy_utils/src/sugg.rs @@ -180,8 +180,10 @@ impl<'a> Sugg<'a> { ) -> Self { use rustc_ast::ast::RangeLimits; + let mut snippet = |span: Span| snippet_with_context(cx, span, ctxt, default, app).0; + match expr.kind { - _ if expr.span.ctxt() != ctxt => Sugg::NonParen(snippet_with_context(cx, expr.span, ctxt, default, app).0), + _ if expr.span.ctxt() != ctxt => Sugg::NonParen(snippet(expr.span)), ast::ExprKind::AddrOf(..) | ast::ExprKind::Closure { .. } | ast::ExprKind::If(..) @@ -224,46 +226,38 @@ impl<'a> Sugg<'a> { | ast::ExprKind::While(..) | ast::ExprKind::Await(..) | ast::ExprKind::Err(_) - | ast::ExprKind::Dummy => Sugg::NonParen(snippet_with_context(cx, expr.span, ctxt, default, app).0), + | ast::ExprKind::Dummy => Sugg::NonParen(snippet(expr.span)), ast::ExprKind::Range(ref lhs, ref rhs, RangeLimits::HalfOpen) => Sugg::BinOp( AssocOp::DotDot, - lhs.as_ref().map_or("".into(), |lhs| { - snippet_with_context(cx, lhs.span, ctxt, default, app).0 - }), - rhs.as_ref().map_or("".into(), |rhs| { - snippet_with_context(cx, rhs.span, ctxt, default, app).0 - }), + lhs.as_ref().map_or("".into(), |lhs| snippet(lhs.span)), + rhs.as_ref().map_or("".into(), |rhs| snippet(rhs.span)), ), ast::ExprKind::Range(ref lhs, ref rhs, RangeLimits::Closed) => Sugg::BinOp( AssocOp::DotDotEq, - lhs.as_ref().map_or("".into(), |lhs| { - snippet_with_context(cx, lhs.span, ctxt, default, app).0 - }), - rhs.as_ref().map_or("".into(), |rhs| { - snippet_with_context(cx, rhs.span, ctxt, default, app).0 - }), + lhs.as_ref().map_or("".into(), |lhs| snippet(lhs.span)), + rhs.as_ref().map_or("".into(), |rhs| snippet(rhs.span)), ), ast::ExprKind::Assign(ref lhs, ref rhs, _) => Sugg::BinOp( AssocOp::Assign, - snippet_with_context(cx, lhs.span, ctxt, default, app).0, - snippet_with_context(cx, rhs.span, ctxt, default, app).0, + snippet(lhs.span), + snippet(rhs.span), ), ast::ExprKind::AssignOp(op, ref lhs, ref rhs) => Sugg::BinOp( astbinop2assignop(op), - snippet_with_context(cx, lhs.span, ctxt, default, app).0, - snippet_with_context(cx, rhs.span, ctxt, default, app).0, + snippet(lhs.span), + snippet(rhs.span), ), ast::ExprKind::Binary(op, ref lhs, ref rhs) => Sugg::BinOp( AssocOp::from_ast_binop(op.node), - snippet_with_context(cx, lhs.span, ctxt, default, app).0, - snippet_with_context(cx, rhs.span, ctxt, default, app).0, + snippet(lhs.span), + snippet(rhs.span), ), ast::ExprKind::Cast(ref lhs, ref ty) | //FIXME(chenyukang), remove this after type ascription is removed from AST ast::ExprKind::Type(ref lhs, ref ty) => Sugg::BinOp( AssocOp::As, - snippet_with_context(cx, lhs.span, ctxt, default, app).0, - snippet_with_context(cx, ty.span, ctxt, default, app).0, + snippet(lhs.span), + snippet(ty.span), ), } } From 59b42b92e7fe506a083e194aee2281525f8199c4 Mon Sep 17 00:00:00 2001 From: Alexander Cyon Date: Mon, 2 Sep 2024 07:54:55 +0200 Subject: [PATCH 064/683] chore: Fix some typos --- src/debuginfo.rs | 4 ++-- src/lib.rs | 2 +- tools/generate_intrinsics.py | 10 +++++----- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/debuginfo.rs b/src/debuginfo.rs index 3d9ea278a63..87638642883 100644 --- a/src/debuginfo.rs +++ b/src/debuginfo.rs @@ -50,7 +50,7 @@ impl<'a, 'gcc, 'tcx> DebugInfoBuilderMethods for Builder<'a, 'gcc, 'tcx> { } /// Generate the `debug_context` in an MIR Body. -/// # Souce of Origin +/// # Source of Origin /// Copied from `create_scope_map.rs` of rustc_codegen_llvm fn compute_mir_scopes<'gcc, 'tcx>( cx: &CodegenCx<'gcc, 'tcx>, @@ -85,7 +85,7 @@ fn compute_mir_scopes<'gcc, 'tcx>( /// Update the `debug_context`, adding new scope to it, /// if it's not added as is denoted in `instantiated`. /// -/// # Souce of Origin +/// # Source of Origin /// Copied from `create_scope_map.rs` of rustc_codegen_llvm /// FIXME(tempdragon/?): Add Scope Support Here. fn make_mir_scope<'gcc, 'tcx>( diff --git a/src/lib.rs b/src/lib.rs index 1132b0cd2f5..c11a183acde 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -360,7 +360,7 @@ impl Deref for SyncContext { unsafe impl Send for SyncContext {} // FIXME(antoyo): that shouldn't be Sync. Parallel compilation is currently disabled with "-Zno-parallel-llvm". -// TODO: disable it here by returing false in CodegenBackend::supports_parallel(). +// TODO: disable it here by returning false in CodegenBackend::supports_parallel(). unsafe impl Sync for SyncContext {} impl WriteBackendMethods for GccCodegenBackend { diff --git a/tools/generate_intrinsics.py b/tools/generate_intrinsics.py index 90fb7bfad27..8efed3e43af 100644 --- a/tools/generate_intrinsics.py +++ b/tools/generate_intrinsics.py @@ -45,7 +45,7 @@ def convert_to_string(content): return content -def extract_instrinsics_from_llvm(llvm_path, intrinsics): +def extract_intrinsics_from_llvm(llvm_path, intrinsics): command = ["llvm-tblgen", "llvm/IR/Intrinsics.td"] cwd = os.path.join(llvm_path, "llvm/include") print("=> Running command `{}` from `{}`".format(command, cwd)) @@ -88,7 +88,7 @@ def append_translation(json_data, p, array): append_intrinsic(array, content[1], content[3]) -def extract_instrinsics_from_llvmint(llvmint, intrinsics): +def extract_intrinsics_from_llvmint(llvmint, intrinsics): archs = [ "AMDGPU", "aarch64", @@ -152,9 +152,9 @@ def update_intrinsics(llvm_path, llvmint, llvmint2): intrinsics_llvmint = {} all_intrinsics = {} - extract_instrinsics_from_llvm(llvm_path, intrinsics_llvm) - extract_instrinsics_from_llvmint(llvmint, intrinsics_llvmint) - extract_instrinsics_from_llvmint(llvmint2, intrinsics_llvmint) + extract_intrinsics_from_llvm(llvm_path, intrinsics_llvm) + extract_intrinsics_from_llvmint(llvmint, intrinsics_llvmint) + extract_intrinsics_from_llvmint(llvmint2, intrinsics_llvmint) intrinsics = {} # We give priority to translations from LLVM over the ones from llvmint. From d3c9cc57d291efa09963add37b11cc52edcae19e Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Tue, 3 Sep 2024 12:03:53 -0400 Subject: [PATCH 065/683] Add support for missing SIMD intrinsics --- src/intrinsic/llvm.rs | 45 ++++++++++++++++++++++++++++++++++++++++++- src/intrinsic/simd.rs | 18 ++++++++++++++++- 2 files changed, 61 insertions(+), 2 deletions(-) diff --git a/src/intrinsic/llvm.rs b/src/intrinsic/llvm.rs index 2287c96b41b..614bdbe26b8 100644 --- a/src/intrinsic/llvm.rs +++ b/src/intrinsic/llvm.rs @@ -182,7 +182,10 @@ pub fn adjust_intrinsic_arguments<'a, 'b, 'gcc, 'tcx>( | "__builtin_ia32_vplzcntd_128_mask" | "__builtin_ia32_vplzcntq_512_mask" | "__builtin_ia32_vplzcntq_256_mask" - | "__builtin_ia32_vplzcntq_128_mask" => { + | "__builtin_ia32_vplzcntq_128_mask" + | "__builtin_ia32_cvtqq2pd128_mask" + | "__builtin_ia32_cvtqq2pd256_mask" + | "__builtin_ia32_cvtqq2ps256_mask" => { let mut new_args = args.to_vec(); // Remove last arg as it doesn't seem to be used in GCC and is always false. new_args.pop(); @@ -378,6 +381,23 @@ pub fn adjust_intrinsic_arguments<'a, 'b, 'gcc, 'tcx>( ); args = vec![arg.get_address(None)].into(); } + "__builtin_ia32_cvtqq2pd512_mask" | "__builtin_ia32_cvtqq2ps512_mask" => { + let mut old_args = args.to_vec(); + let mut new_args = vec![]; + new_args.push(old_args.swap_remove(0)); + let arg2_type = gcc_func.get_param_type(1); + let vector_type = arg2_type.dyncast_vector().expect("vector type"); + let zero = builder.context.new_rvalue_zero(vector_type.get_element_type()); + let num_units = vector_type.get_num_units(); + let first_arg = + builder.context.new_rvalue_from_vector(None, arg2_type, &vec![zero; num_units]); + new_args.push(first_arg); + let arg3_type = gcc_func.get_param_type(2); + let minus_one = builder.context.new_rvalue_from_int(arg3_type, -1); + new_args.push(minus_one); + new_args.push(old_args.swap_remove(0)); + args = new_args.into(); + } _ => (), } } else { @@ -987,6 +1007,29 @@ pub fn intrinsic<'gcc, 'tcx>(name: &str, cx: &CodegenCx<'gcc, 'tcx>) -> Function "llvm.x86.avx512.vpdpbusds.128" => "__builtin_ia32_vpdpbusds_v4si", "llvm.x86.xsave" => "__builtin_ia32_xsave", "llvm.x86.xsaveopt" => "__builtin_ia32_xsaveopt", + "llvm.x86.avx512.mask.loadu.w.512" => "__builtin_ia32_loaddquhi512_mask", + "llvm.x86.avx512.mask.loadu.b.512" => "__builtin_ia32_loaddquqi512_mask", + "llvm.x86.avx512.mask.loadu.w.256" => "__builtin_ia32_loaddquhi256_mask", + "llvm.x86.avx512.mask.loadu.b.256" => "__builtin_ia32_loaddquqi256_mask", + "llvm.x86.avx512.mask.loadu.w.128" => "__builtin_ia32_loaddquhi128_mask", + "llvm.x86.avx512.mask.loadu.b.128" => "__builtin_ia32_loaddquqi128_mask", + "llvm.x86.avx512.mask.storeu.w.512" => "__builtin_ia32_storedquhi512_mask", + "llvm.x86.avx512.mask.storeu.b.512" => "__builtin_ia32_storedquqi512_mask", + "llvm.x86.avx512.mask.storeu.w.256" => "__builtin_ia32_storedquhi256_mask", + "llvm.x86.avx512.mask.storeu.b.256" => "__builtin_ia32_storedquqi256_mask", + "llvm.x86.avx512.mask.storeu.w.128" => "__builtin_ia32_storedquhi128_mask", + "llvm.x86.avx512.mask.storeu.b.128" => "__builtin_ia32_storedquqi128_mask", + "llvm.x86.avx512.mask.expand.load.w.512" => "__builtin_ia32_expandloadhi512_mask", + "llvm.x86.avx512.mask.expand.load.w.256" => "__builtin_ia32_expandloadhi256_mask", + "llvm.x86.avx512.mask.expand.load.w.128" => "__builtin_ia32_expandloadhi128_mask", + "llvm.x86.avx512.mask.expand.load.b.512" => "__builtin_ia32_expandloadqi512_mask", + "llvm.x86.avx512.mask.expand.load.b.256" => "__builtin_ia32_expandloadqi256_mask", + "llvm.x86.avx512.mask.expand.load.b.128" => "__builtin_ia32_expandloadqi128_mask", + "llvm.x86.avx512.sitofp.round.v8f64.v8i64" => "__builtin_ia32_cvtqq2pd512_mask", + "llvm.x86.avx512.sitofp.round.v2f64.v2i64" => "__builtin_ia32_cvtqq2pd128_mask", + "llvm.x86.avx512.sitofp.round.v4f64.v4i64" => "__builtin_ia32_cvtqq2pd256_mask", + "llvm.x86.avx512.sitofp.round.v8f32.v8i64" => "__builtin_ia32_cvtqq2ps512_mask", + "llvm.x86.avx512.sitofp.round.v4f32.v4i64" => "__builtin_ia32_cvtqq2ps256_mask", // NOTE: this file is generated by https://github.com/GuillaumeGomez/llvmint/blob/master/generate_list.py _ => include!("archs.rs"), diff --git a/src/intrinsic/simd.rs b/src/intrinsic/simd.rs index d1b4a9689a9..a0d8ff6346f 100644 --- a/src/intrinsic/simd.rs +++ b/src/intrinsic/simd.rs @@ -201,7 +201,7 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( bx.context.new_bitcast(None, shuffled, v_type) }; - if name == sym::simd_bswap || name == sym::simd_bitreverse { + if matches!(name, sym::simd_bswap | sym::simd_bitreverse | sym::simd_ctpop) { require!( bx.type_kind(bx.element_type(llret_ty)) == TypeKind::Integer, InvalidMonomorphization::UnsupportedOperation { span, name, in_ty, in_elem } @@ -212,6 +212,22 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( return Ok(simd_bswap(bx, args[0].immediate())); } + let simd_ctpop = |bx: &mut Builder<'a, 'gcc, 'tcx>, vector: RValue<'gcc>| -> RValue<'gcc> { + let mut vector_elements = vec![]; + let elem_ty = bx.element_type(llret_ty); + for i in 0..in_len { + let index = bx.context.new_rvalue_from_long(bx.ulong_type, i as i64); + let element = bx.extract_element(vector, index).to_rvalue(); + let result = bx.context.new_cast(None, bx.pop_count(element), elem_ty); + vector_elements.push(result); + } + bx.context.new_rvalue_from_vector(None, llret_ty, &vector_elements) + }; + + if name == sym::simd_ctpop { + return Ok(simd_ctpop(bx, args[0].immediate())); + } + // We use a different algorithm from non-vector bitreverse to take advantage of most // processors' vector shuffle units. It works like this: // 1. Generate pre-reversed low and high nibbles as a vector. From 273b561609de64131af3d59a38e38eceb76e4a29 Mon Sep 17 00:00:00 2001 From: Soveu Date: Fri, 12 Jul 2024 12:12:58 +0200 Subject: [PATCH 066/683] add pointers_in_nomem_asm_block lint --- CHANGELOG.md | 1 + clippy_lints/src/declared_lints.rs | 1 + clippy_lints/src/lib.rs | 2 + .../src/pointers_in_nomem_asm_block.rs | 88 +++++++++++++++++++ tests/ui/pointers_in_nomem_asm_block.rs | 33 +++++++ tests/ui/pointers_in_nomem_asm_block.stderr | 34 +++++++ 6 files changed, 159 insertions(+) create mode 100644 clippy_lints/src/pointers_in_nomem_asm_block.rs create mode 100644 tests/ui/pointers_in_nomem_asm_block.rs create mode 100644 tests/ui/pointers_in_nomem_asm_block.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index 682c3cfe015..fc51694ff57 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5758,6 +5758,7 @@ Released 2018-09-13 [`pathbuf_init_then_push`]: https://rust-lang.github.io/rust-clippy/master/index.html#pathbuf_init_then_push [`pattern_type_mismatch`]: https://rust-lang.github.io/rust-clippy/master/index.html#pattern_type_mismatch [`permissions_set_readonly_false`]: https://rust-lang.github.io/rust-clippy/master/index.html#permissions_set_readonly_false +[`pointers_in_nomem_asm_block`]: https://rust-lang.github.io/rust-clippy/master/index.html#pointers_in_nomem_asm_block [`positional_named_format_parameters`]: https://rust-lang.github.io/rust-clippy/master/index.html#positional_named_format_parameters [`possible_missing_comma`]: https://rust-lang.github.io/rust-clippy/master/index.html#possible_missing_comma [`precedence`]: https://rust-lang.github.io/rust-clippy/master/index.html#precedence diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index aded9e276c4..e478ab330e8 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -600,6 +600,7 @@ pub static LINTS: &[&crate::LintInfo] = &[ crate::pathbuf_init_then_push::PATHBUF_INIT_THEN_PUSH_INFO, crate::pattern_type_mismatch::PATTERN_TYPE_MISMATCH_INFO, crate::permissions_set_readonly_false::PERMISSIONS_SET_READONLY_FALSE_INFO, + crate::pointers_in_nomem_asm_block::POINTERS_IN_NOMEM_ASM_BLOCK_INFO, crate::precedence::PRECEDENCE_INFO, crate::ptr::CMP_NULL_INFO, crate::ptr::INVALID_NULL_PTR_USAGE_INFO, diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 078f38656ec..58ad9f645d6 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -287,6 +287,7 @@ mod pass_by_ref_or_value; mod pathbuf_init_then_push; mod pattern_type_mismatch; mod permissions_set_readonly_false; +mod pointers_in_nomem_asm_block; mod precedence; mod ptr; mod ptr_offset_with_cast; @@ -935,5 +936,6 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { store.register_early_pass(|| Box::new(byte_char_slices::ByteCharSlice)); store.register_early_pass(|| Box::new(cfg_not_test::CfgNotTest)); store.register_late_pass(|_| Box::new(zombie_processes::ZombieProcesses)); + store.register_late_pass(|_| Box::new(pointers_in_nomem_asm_block::PointersInNomemAsmBlock)); // add lints here, do not remove this comment, it's used in `new_lint` } diff --git a/clippy_lints/src/pointers_in_nomem_asm_block.rs b/clippy_lints/src/pointers_in_nomem_asm_block.rs new file mode 100644 index 00000000000..385f634a150 --- /dev/null +++ b/clippy_lints/src/pointers_in_nomem_asm_block.rs @@ -0,0 +1,88 @@ +use clippy_utils::diagnostics::span_lint_and_then; +use rustc_ast::InlineAsmOptions; +use rustc_hir::{Expr, ExprKind, InlineAsm, InlineAsmOperand}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_session::declare_lint_pass; +use rustc_span::Span; + +declare_clippy_lint! { + /// ### What it does + /// Checks if any pointer is being passed to an asm! block with `nomem` option. + /// + /// ### Why is this bad? + /// `nomem` forbids any reads or writes to memory and passing a pointer suggests + /// that either of those will happen. + /// + /// ### Example + /// ```no_run + /// fn f(p: *mut u32) { + /// unsafe { core::arch::asm!("mov [{p}], 42", p = in(reg) p, options(nomem, nostack)); } + /// } + /// ``` + /// Use instead: + /// ```no_run + /// fn f(p: *mut u32) { + /// unsafe { core::arch::asm!("mov [{p}], 42", p = in(reg) p, options(nostack)); } + /// } + /// ``` + #[clippy::version = "1.81.0"] + pub POINTERS_IN_NOMEM_ASM_BLOCK, + suspicious, + "pointers in nomem asm block" +} + +declare_lint_pass!(PointersInNomemAsmBlock => [POINTERS_IN_NOMEM_ASM_BLOCK]); + +impl<'tcx> LateLintPass<'tcx> for PointersInNomemAsmBlock { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) { + if let ExprKind::InlineAsm(asm) = &expr.kind { + check_asm(cx, asm); + } + } +} + +fn check_asm(cx: &LateContext<'_>, asm: &InlineAsm<'_>) { + if !asm.options.contains(InlineAsmOptions::NOMEM) { + return; + } + + let spans = asm + .operands + .iter() + .filter(|(op, _span)| has_in_operand_pointer(cx, op)) + .map(|(_op, span)| *span) + .collect::>(); + + if spans.is_empty() { + return; + } + + span_lint_and_then( + cx, + POINTERS_IN_NOMEM_ASM_BLOCK, + spans, + "passing pointers to nomem asm block", + additional_notes, + ); +} + +fn has_in_operand_pointer(cx: &LateContext<'_>, asm_op: &InlineAsmOperand<'_>) -> bool { + let asm_in_expr = match asm_op { + InlineAsmOperand::SymStatic { .. } + | InlineAsmOperand::Out { .. } + | InlineAsmOperand::Const { .. } + | InlineAsmOperand::SymFn { .. } + | InlineAsmOperand::Label { .. } => return false, + InlineAsmOperand::SplitInOut { in_expr, .. } => in_expr, + InlineAsmOperand::In { expr, .. } | InlineAsmOperand::InOut { expr, .. } => expr, + }; + + // This checks for raw ptrs, refs and function pointers - the last one + // also technically counts as reading memory. + cx.typeck_results().expr_ty(asm_in_expr).is_any_ptr() +} + +fn additional_notes(diag: &mut rustc_errors::Diag<'_, ()>) { + diag.note("`nomem` means that no memory write or read happens inside the asm! block"); + diag.note("if this is intentional and no pointers are read or written to, consider allowing the lint"); +} diff --git a/tests/ui/pointers_in_nomem_asm_block.rs b/tests/ui/pointers_in_nomem_asm_block.rs new file mode 100644 index 00000000000..b5abcbb3474 --- /dev/null +++ b/tests/ui/pointers_in_nomem_asm_block.rs @@ -0,0 +1,33 @@ +//@ needs-asm-support +#![warn(clippy::pointers_in_nomem_asm_block)] +#![crate_type = "lib"] +#![no_std] + +use core::arch::asm; + +unsafe fn nomem_bad(p: &i32) { + asm!( + "asdf {p1}, {p2}, {p3}", + p1 = in(reg) p, + //~^ ERROR: passing pointers to nomem asm block + p2 = in(reg) p as *const _ as usize, + p3 = in(reg) p, + options(nomem, nostack, preserves_flags) + ); +} + +unsafe fn nomem_good(p: &i32) { + asm!("asdf {p}", p = in(reg) p, options(readonly, nostack, preserves_flags)); + let p = p as *const i32 as usize; + asm!("asdf {p}", p = in(reg) p, options(nomem, nostack, preserves_flags)); +} + +unsafe fn nomem_bad2(p: &mut i32) { + asm!("asdf {p}", p = in(reg) p, options(nomem, nostack, preserves_flags)); + //~^ ERROR: passing pointers to nomem asm block +} + +unsafe fn nomem_fn(p: extern "C" fn()) { + asm!("call {p}", p = in(reg) p, options(nomem)); + //~^ ERROR: passing pointers to nomem asm block +} diff --git a/tests/ui/pointers_in_nomem_asm_block.stderr b/tests/ui/pointers_in_nomem_asm_block.stderr new file mode 100644 index 00000000000..cabeb37344f --- /dev/null +++ b/tests/ui/pointers_in_nomem_asm_block.stderr @@ -0,0 +1,34 @@ +error: passing pointers to nomem asm block + --> tests/ui/pointers_in_nomem_asm_block.rs:11:9 + | +LL | p1 = in(reg) p, + | ^^^^^^^^^^^^^^ +... +LL | p3 = in(reg) p, + | ^^^^^^^^^^^^^^ + | + = note: `nomem` means that no memory write or read happens inside the asm! block + = note: if this is intentional and no pointers are read or written to, consider allowing the lint + = note: `-D clippy::pointers-in-nomem-asm-block` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::pointers_in_nomem_asm_block)]` + +error: passing pointers to nomem asm block + --> tests/ui/pointers_in_nomem_asm_block.rs:26:22 + | +LL | asm!("asdf {p}", p = in(reg) p, options(nomem, nostack, preserves_flags)); + | ^^^^^^^^^^^^^ + | + = note: `nomem` means that no memory write or read happens inside the asm! block + = note: if this is intentional and no pointers are read or written to, consider allowing the lint + +error: passing pointers to nomem asm block + --> tests/ui/pointers_in_nomem_asm_block.rs:31:22 + | +LL | asm!("call {p}", p = in(reg) p, options(nomem)); + | ^^^^^^^^^^^^^ + | + = note: `nomem` means that no memory write or read happens inside the asm! block + = note: if this is intentional and no pointers are read or written to, consider allowing the lint + +error: aborting due to 3 previous errors + From e064b729b9cff869e3c03b28cc2fd28f25b928dd Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 3 Sep 2024 21:53:06 +0200 Subject: [PATCH 067/683] Add missing intrinsic translation for `llvm.x86.xsave64` --- src/intrinsic/llvm.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/intrinsic/llvm.rs b/src/intrinsic/llvm.rs index 614bdbe26b8..3b9855ddc18 100644 --- a/src/intrinsic/llvm.rs +++ b/src/intrinsic/llvm.rs @@ -802,6 +802,7 @@ pub fn intrinsic<'gcc, 'tcx>(name: &str, cx: &CodegenCx<'gcc, 'tcx>) -> Function "llvm.x86.avx512.mask.cmp.b.128" => "__builtin_ia32_cmpb128_mask", "llvm.x86.xrstor" => "__builtin_ia32_xrstor", "llvm.x86.xsavec" => "__builtin_ia32_xsavec", + "llvm.x86.xsave64" => "__builtin_ia32_xsave64", "llvm.x86.addcarry.32" => "__builtin_ia32_addcarryx_u32", "llvm.x86.subborrow.32" => "__builtin_ia32_sbb_u32", "llvm.x86.avx512.mask.compress.store.w.512" => "__builtin_ia32_compressstoreuhi512_mask", From 197df44af97026e6c04da77a73c3121387f9816f Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 3 Sep 2024 21:58:18 +0200 Subject: [PATCH 068/683] Regenerate intrinsics --- src/intrinsic/archs.rs | 364 ++++++++++++++++++++++++++--------------- 1 file changed, 234 insertions(+), 130 deletions(-) diff --git a/src/intrinsic/archs.rs b/src/intrinsic/archs.rs index f7500933789..b8d1cde1d5d 100644 --- a/src/intrinsic/archs.rs +++ b/src/intrinsic/archs.rs @@ -31,8 +31,11 @@ match name { "llvm.AMDGPU.trig.preop.v2f64" => "__builtin_amdgpu_trig_preop", "llvm.AMDGPU.trig.preop.v4f32" => "__builtin_amdgpu_trig_preop", // aarch64 + "llvm.aarch64.chkfeat" => "__builtin_arm_chkfeat", "llvm.aarch64.dmb" => "__builtin_arm_dmb", "llvm.aarch64.dsb" => "__builtin_arm_dsb", + "llvm.aarch64.gcspopm" => "__builtin_arm_gcspopm", + "llvm.aarch64.gcsss" => "__builtin_arm_gcsss", "llvm.aarch64.isb" => "__builtin_arm_isb", "llvm.aarch64.prefetch" => "__builtin_arm_prefetch", "llvm.aarch64.sve.aesd" => "__builtin_sve_svaesd_u8", @@ -80,7 +83,6 @@ match name { "llvm.amdgcn.dot4.f32.fp8.fp8" => "__builtin_amdgcn_dot4_f32_fp8_fp8", "llvm.amdgcn.ds.add.gs.reg.rtn" => "__builtin_amdgcn_ds_add_gs_reg_rtn", "llvm.amdgcn.ds.bpermute" => "__builtin_amdgcn_ds_bpermute", - "llvm.amdgcn.ds.fadd.v2bf16" => "__builtin_amdgcn_ds_atomic_fadd_v2bf16", "llvm.amdgcn.ds.gws.barrier" => "__builtin_amdgcn_ds_gws_barrier", "llvm.amdgcn.ds.gws.init" => "__builtin_amdgcn_ds_gws_init", "llvm.amdgcn.ds.gws.sema.br" => "__builtin_amdgcn_ds_gws_sema_br", @@ -96,6 +98,7 @@ match name { "llvm.amdgcn.fdot2.f16.f16" => "__builtin_amdgcn_fdot2_f16_f16", "llvm.amdgcn.fdot2.f32.bf16" => "__builtin_amdgcn_fdot2_f32_bf16", "llvm.amdgcn.fmul.legacy" => "__builtin_amdgcn_fmul_legacy", + "llvm.amdgcn.global.load.lds" => "__builtin_amdgcn_global_load_lds", "llvm.amdgcn.groupstaticsize" => "__builtin_amdgcn_groupstaticsize", "llvm.amdgcn.iglp.opt" => "__builtin_amdgcn_iglp_opt", "llvm.amdgcn.implicit.buffer.ptr" => "__builtin_amdgcn_implicit_buffer_ptr", @@ -154,16 +157,11 @@ match name { "llvm.amdgcn.mqsad.u32.u8" => "__builtin_amdgcn_mqsad_u32_u8", "llvm.amdgcn.msad.u8" => "__builtin_amdgcn_msad_u8", "llvm.amdgcn.perm" => "__builtin_amdgcn_perm", - "llvm.amdgcn.permlane16" => "__builtin_amdgcn_permlane16", "llvm.amdgcn.permlane16.var" => "__builtin_amdgcn_permlane16_var", - "llvm.amdgcn.permlane64" => "__builtin_amdgcn_permlane64", - "llvm.amdgcn.permlanex16" => "__builtin_amdgcn_permlanex16", "llvm.amdgcn.permlanex16.var" => "__builtin_amdgcn_permlanex16_var", "llvm.amdgcn.qsad.pk.u16.u8" => "__builtin_amdgcn_qsad_pk_u16_u8", "llvm.amdgcn.queue.ptr" => "__builtin_amdgcn_queue_ptr", "llvm.amdgcn.rcp.legacy" => "__builtin_amdgcn_rcp_legacy", - "llvm.amdgcn.readfirstlane" => "__builtin_amdgcn_readfirstlane", - "llvm.amdgcn.readlane" => "__builtin_amdgcn_readlane", "llvm.amdgcn.rsq.legacy" => "__builtin_amdgcn_rsq_legacy", "llvm.amdgcn.s.barrier" => "__builtin_amdgcn_s_barrier", "llvm.amdgcn.s.barrier.init" => "__builtin_amdgcn_s_barrier_init", @@ -192,6 +190,8 @@ match name { "llvm.amdgcn.s.setreg" => "__builtin_amdgcn_s_setreg", "llvm.amdgcn.s.sleep" => "__builtin_amdgcn_s_sleep", "llvm.amdgcn.s.sleep.var" => "__builtin_amdgcn_s_sleep_var", + "llvm.amdgcn.s.ttracedata" => "__builtin_amdgcn_s_ttracedata", + "llvm.amdgcn.s.ttracedata.imm" => "__builtin_amdgcn_s_ttracedata_imm", "llvm.amdgcn.s.wait.event.export.ready" => "__builtin_amdgcn_s_wait_event_export_ready", "llvm.amdgcn.s.waitcnt" => "__builtin_amdgcn_s_waitcnt", "llvm.amdgcn.s.wakeup.barrier" => "__builtin_amdgcn_s_wakeup_barrier", @@ -227,7 +227,6 @@ match name { "llvm.amdgcn.workgroup.id.x" => "__builtin_amdgcn_workgroup_id_x", "llvm.amdgcn.workgroup.id.y" => "__builtin_amdgcn_workgroup_id_y", "llvm.amdgcn.workgroup.id.z" => "__builtin_amdgcn_workgroup_id_z", - "llvm.amdgcn.writelane" => "__builtin_amdgcn_writelane", // arm "llvm.arm.cdp" => "__builtin_arm_cdp", "llvm.arm.cdp2" => "__builtin_arm_cdp2", @@ -4536,10 +4535,18 @@ match name { "llvm.nvvm.div.rz.d" => "__nvvm_div_rz_d", "llvm.nvvm.div.rz.f" => "__nvvm_div_rz_f", "llvm.nvvm.div.rz.ftz.f" => "__nvvm_div_rz_ftz_f", + "llvm.nvvm.e4m3x2.to.f16x2.rn" => "__nvvm_e4m3x2_to_f16x2_rn", + "llvm.nvvm.e4m3x2.to.f16x2.rn.relu" => "__nvvm_e4m3x2_to_f16x2_rn_relu", + "llvm.nvvm.e5m2x2.to.f16x2.rn" => "__nvvm_e5m2x2_to_f16x2_rn", + "llvm.nvvm.e5m2x2.to.f16x2.rn.relu" => "__nvvm_e5m2x2_to_f16x2_rn_relu", "llvm.nvvm.ex2.approx.d" => "__nvvm_ex2_approx_d", "llvm.nvvm.ex2.approx.f" => "__nvvm_ex2_approx_f", "llvm.nvvm.ex2.approx.ftz.f" => "__nvvm_ex2_approx_ftz_f", "llvm.nvvm.exit" => "__nvvm_exit", + "llvm.nvvm.f16x2.to.e4m3x2.rn" => "__nvvm_f16x2_to_e4m3x2_rn", + "llvm.nvvm.f16x2.to.e4m3x2.rn.relu" => "__nvvm_f16x2_to_e4m3x2_rn_relu", + "llvm.nvvm.f16x2.to.e5m2x2.rn" => "__nvvm_f16x2_to_e5m2x2_rn", + "llvm.nvvm.f16x2.to.e5m2x2.rn.relu" => "__nvvm_f16x2_to_e5m2x2_rn_relu", "llvm.nvvm.f2bf16.rn" => "__nvvm_f2bf16_rn", "llvm.nvvm.f2bf16.rn.relu" => "__nvvm_f2bf16_rn_relu", "llvm.nvvm.f2bf16.rz" => "__nvvm_f2bf16_rz", @@ -4582,6 +4589,10 @@ match name { "llvm.nvvm.fabs.d" => "__nvvm_fabs_d", "llvm.nvvm.fabs.f" => "__nvvm_fabs_f", "llvm.nvvm.fabs.ftz.f" => "__nvvm_fabs_ftz_f", + "llvm.nvvm.ff.to.e4m3x2.rn" => "__nvvm_ff_to_e4m3x2_rn", + "llvm.nvvm.ff.to.e4m3x2.rn.relu" => "__nvvm_ff_to_e4m3x2_rn_relu", + "llvm.nvvm.ff.to.e5m2x2.rn" => "__nvvm_ff_to_e5m2x2_rn", + "llvm.nvvm.ff.to.e5m2x2.rn.relu" => "__nvvm_ff_to_e5m2x2_rn_relu", "llvm.nvvm.ff2bf16x2.rn" => "__nvvm_ff2bf16x2_rn", "llvm.nvvm.ff2bf16x2.rn.relu" => "__nvvm_ff2bf16x2_rn_relu", "llvm.nvvm.ff2bf16x2.rz" => "__nvvm_ff2bf16x2_rz", @@ -4866,6 +4877,7 @@ match name { "llvm.nvvm.round.ftz.f" => "__nvvm_round_ftz_f", "llvm.nvvm.rsqrt.approx.d" => "__nvvm_rsqrt_approx_d", "llvm.nvvm.rsqrt.approx.f" => "__nvvm_rsqrt_approx_f", + "llvm.nvvm.rsqrt.approx.ftz.d" => "__nvvm_rsqrt_approx_ftz_d", "llvm.nvvm.rsqrt.approx.ftz.f" => "__nvvm_rsqrt_approx_ftz_f", "llvm.nvvm.sad.i" => "__nvvm_sad_i", "llvm.nvvm.sad.ll" => "__nvvm_sad_ll", @@ -5164,6 +5176,8 @@ match name { // ppc "llvm.ppc.addex" => "__builtin_ppc_addex", "llvm.ppc.addf128.round.to.odd" => "__builtin_addf128_round_to_odd", + "llvm.ppc.addg6s" => "__builtin_addg6s", + "llvm.ppc.addg6sd" => "__builtin_ppc_addg6s", "llvm.ppc.altivec.crypto.vcipher" => "__builtin_altivec_crypto_vcipher", "llvm.ppc.altivec.crypto.vcipherlast" => "__builtin_altivec_crypto_vcipherlast", "llvm.ppc.altivec.crypto.vncipher" => "__builtin_altivec_crypto_vncipher", @@ -5461,6 +5475,10 @@ match name { "llvm.ppc.bcdsub" => "__builtin_ppc_bcdsub", "llvm.ppc.bcdsub.p" => "__builtin_ppc_bcdsub_p", "llvm.ppc.bpermd" => "__builtin_bpermd", + "llvm.ppc.cbcdtd" => "__builtin_cbcdtd", + "llvm.ppc.cbcdtdd" => "__builtin_ppc_cbcdtd", + "llvm.ppc.cdtbcd" => "__builtin_cdtbcd", + "llvm.ppc.cdtbcdd" => "__builtin_ppc_cdtbcd", "llvm.ppc.cfuged" => "__builtin_cfuged", "llvm.ppc.cmpeqb" => "__builtin_ppc_cmpeqb", "llvm.ppc.cmprb" => "__builtin_ppc_cmprb", @@ -5627,7 +5645,6 @@ match name { "llvm.ppc.qpx.qvstfs" => "__builtin_qpx_qvstfs", "llvm.ppc.qpx.qvstfsa" => "__builtin_qpx_qvstfsa", "llvm.ppc.readflm" => "__builtin_readflm", - "llvm.ppc.rldimi" => "__builtin_ppc_rldimi", "llvm.ppc.rlwimi" => "__builtin_ppc_rlwimi", "llvm.ppc.rlwnm" => "__builtin_ppc_rlwnm", "llvm.ppc.scalar.extract.expq" => "__builtin_vsx_scalar_extract_expq", @@ -7210,29 +7227,6 @@ match name { "llvm.ve.vl.xorm.MMM" => "__builtin_ve_vl_xorm_MMM", "llvm.ve.vl.xorm.mmm" => "__builtin_ve_vl_xorm_mmm", // x86 - "llvm.x86.3dnow.pavgusb" => "__builtin_ia32_pavgusb", - "llvm.x86.3dnow.pf2id" => "__builtin_ia32_pf2id", - "llvm.x86.3dnow.pfacc" => "__builtin_ia32_pfacc", - "llvm.x86.3dnow.pfadd" => "__builtin_ia32_pfadd", - "llvm.x86.3dnow.pfcmpeq" => "__builtin_ia32_pfcmpeq", - "llvm.x86.3dnow.pfcmpge" => "__builtin_ia32_pfcmpge", - "llvm.x86.3dnow.pfcmpgt" => "__builtin_ia32_pfcmpgt", - "llvm.x86.3dnow.pfmax" => "__builtin_ia32_pfmax", - "llvm.x86.3dnow.pfmin" => "__builtin_ia32_pfmin", - "llvm.x86.3dnow.pfmul" => "__builtin_ia32_pfmul", - "llvm.x86.3dnow.pfrcp" => "__builtin_ia32_pfrcp", - "llvm.x86.3dnow.pfrcpit1" => "__builtin_ia32_pfrcpit1", - "llvm.x86.3dnow.pfrcpit2" => "__builtin_ia32_pfrcpit2", - "llvm.x86.3dnow.pfrsqit1" => "__builtin_ia32_pfrsqit1", - "llvm.x86.3dnow.pfrsqrt" => "__builtin_ia32_pfrsqrt", - "llvm.x86.3dnow.pfsub" => "__builtin_ia32_pfsub", - "llvm.x86.3dnow.pfsubr" => "__builtin_ia32_pfsubr", - "llvm.x86.3dnow.pi2fd" => "__builtin_ia32_pi2fd", - "llvm.x86.3dnow.pmulhrw" => "__builtin_ia32_pmulhrw", - "llvm.x86.3dnowa.pf2iw" => "__builtin_ia32_pf2iw", - "llvm.x86.3dnowa.pfnacc" => "__builtin_ia32_pfnacc", - "llvm.x86.3dnowa.pfpnacc" => "__builtin_ia32_pfpnacc", - "llvm.x86.3dnowa.pi2fw" => "__builtin_ia32_pi2fw", "llvm.x86.aadd32" => "__builtin_ia32_aadd32", "llvm.x86.aadd64" => "__builtin_ia32_aadd64", "llvm.x86.aand32" => "__builtin_ia32_aand32", @@ -7334,6 +7328,207 @@ match name { "llvm.x86.avx.vtestz.ps.256" => "__builtin_ia32_vtestzps256", "llvm.x86.avx.vzeroall" => "__builtin_ia32_vzeroall", "llvm.x86.avx.vzeroupper" => "__builtin_ia32_vzeroupper", + "llvm.x86.avx10.mask.vcvt2ps2phx.128" => "__builtin_ia32_vcvt2ps2phx128_mask", + "llvm.x86.avx10.mask.vcvt2ps2phx.256" => "__builtin_ia32_vcvt2ps2phx256_mask", + "llvm.x86.avx10.mask.vcvt2ps2phx.512" => "__builtin_ia32_vcvt2ps2phx512_mask", + "llvm.x86.avx10.mask.vcvtbiasph2bf8128" => "__builtin_ia32_vcvtbiasph2bf8_128_mask", + "llvm.x86.avx10.mask.vcvtbiasph2bf8256" => "__builtin_ia32_vcvtbiasph2bf8_256_mask", + "llvm.x86.avx10.mask.vcvtbiasph2bf8512" => "__builtin_ia32_vcvtbiasph2bf8_512_mask", + "llvm.x86.avx10.mask.vcvtbiasph2bf8s128" => "__builtin_ia32_vcvtbiasph2bf8s_128_mask", + "llvm.x86.avx10.mask.vcvtbiasph2bf8s256" => "__builtin_ia32_vcvtbiasph2bf8s_256_mask", + "llvm.x86.avx10.mask.vcvtbiasph2bf8s512" => "__builtin_ia32_vcvtbiasph2bf8s_512_mask", + "llvm.x86.avx10.mask.vcvtbiasph2hf8128" => "__builtin_ia32_vcvtbiasph2hf8_128_mask", + "llvm.x86.avx10.mask.vcvtbiasph2hf8256" => "__builtin_ia32_vcvtbiasph2hf8_256_mask", + "llvm.x86.avx10.mask.vcvtbiasph2hf8512" => "__builtin_ia32_vcvtbiasph2hf8_512_mask", + "llvm.x86.avx10.mask.vcvtbiasph2hf8s128" => "__builtin_ia32_vcvtbiasph2hf8s_128_mask", + "llvm.x86.avx10.mask.vcvtbiasph2hf8s256" => "__builtin_ia32_vcvtbiasph2hf8s_256_mask", + "llvm.x86.avx10.mask.vcvtbiasph2hf8s512" => "__builtin_ia32_vcvtbiasph2hf8s_512_mask", + "llvm.x86.avx10.mask.vcvthf82ph128" => "__builtin_ia32_vcvthf8_2ph128_mask", + "llvm.x86.avx10.mask.vcvthf82ph256" => "__builtin_ia32_vcvthf8_2ph256_mask", + "llvm.x86.avx10.mask.vcvthf82ph512" => "__builtin_ia32_vcvthf8_2ph512_mask", + "llvm.x86.avx10.mask.vcvtneph2bf8128" => "__builtin_ia32_vcvtneph2bf8_128_mask", + "llvm.x86.avx10.mask.vcvtneph2bf8256" => "__builtin_ia32_vcvtneph2bf8_256_mask", + "llvm.x86.avx10.mask.vcvtneph2bf8512" => "__builtin_ia32_vcvtneph2bf8_512_mask", + "llvm.x86.avx10.mask.vcvtneph2bf8s128" => "__builtin_ia32_vcvtneph2bf8s_128_mask", + "llvm.x86.avx10.mask.vcvtneph2bf8s256" => "__builtin_ia32_vcvtneph2bf8s_256_mask", + "llvm.x86.avx10.mask.vcvtneph2bf8s512" => "__builtin_ia32_vcvtneph2bf8s_512_mask", + "llvm.x86.avx10.mask.vcvtneph2hf8128" => "__builtin_ia32_vcvtneph2hf8_128_mask", + "llvm.x86.avx10.mask.vcvtneph2hf8256" => "__builtin_ia32_vcvtneph2hf8_256_mask", + "llvm.x86.avx10.mask.vcvtneph2hf8512" => "__builtin_ia32_vcvtneph2hf8_512_mask", + "llvm.x86.avx10.mask.vcvtneph2hf8s128" => "__builtin_ia32_vcvtneph2hf8s_128_mask", + "llvm.x86.avx10.mask.vcvtneph2hf8s256" => "__builtin_ia32_vcvtneph2hf8s_256_mask", + "llvm.x86.avx10.mask.vcvtneph2hf8s512" => "__builtin_ia32_vcvtneph2hf8s_512_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvtpd2dq256" => "__builtin_ia32_vcvtpd2dq256_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvtpd2ph256" => "__builtin_ia32_vcvtpd2ph256_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvtpd2ps256" => "__builtin_ia32_vcvtpd2ps256_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvtpd2qq256" => "__builtin_ia32_vcvtpd2qq256_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvtpd2udq256" => "__builtin_ia32_vcvtpd2udq256_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvtpd2uqq256" => "__builtin_ia32_vcvtpd2uqq256_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvtph2dq256" => "__builtin_ia32_vcvtph2dq256_round_mask", + "llvm.x86.avx10.mask.vcvtph2ibs128" => "__builtin_ia32_vcvtph2ibs128_mask", + "llvm.x86.avx10.mask.vcvtph2ibs256" => "__builtin_ia32_vcvtph2ibs256_mask", + "llvm.x86.avx10.mask.vcvtph2ibs512" => "__builtin_ia32_vcvtph2ibs512_mask", + "llvm.x86.avx10.mask.vcvtph2iubs128" => "__builtin_ia32_vcvtph2iubs128_mask", + "llvm.x86.avx10.mask.vcvtph2iubs256" => "__builtin_ia32_vcvtph2iubs256_mask", + "llvm.x86.avx10.mask.vcvtph2iubs512" => "__builtin_ia32_vcvtph2iubs512_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvtph2pd256" => "__builtin_ia32_vcvtph2pd256_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvtph2psx256" => "__builtin_ia32_vcvtph2psx256_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvtph2qq256" => "__builtin_ia32_vcvtph2qq256_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvtph2udq256" => "__builtin_ia32_vcvtph2udq256_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvtph2uqq256" => "__builtin_ia32_vcvtph2uqq256_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvtph2uw256" => "__builtin_ia32_vcvtph2uw256_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvtph2w256" => "__builtin_ia32_vcvtph2w256_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvtps2dq256" => "__builtin_ia32_vcvtps2dq256_round_mask", + "llvm.x86.avx10.mask.vcvtps2ibs128" => "__builtin_ia32_vcvtps2ibs128_mask", + "llvm.x86.avx10.mask.vcvtps2ibs256" => "__builtin_ia32_vcvtps2ibs256_mask", + "llvm.x86.avx10.mask.vcvtps2ibs512" => "__builtin_ia32_vcvtps2ibs512_mask", + "llvm.x86.avx10.mask.vcvtps2iubs128" => "__builtin_ia32_vcvtps2iubs128_mask", + "llvm.x86.avx10.mask.vcvtps2iubs256" => "__builtin_ia32_vcvtps2iubs256_mask", + "llvm.x86.avx10.mask.vcvtps2iubs512" => "__builtin_ia32_vcvtps2iubs512_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvtps2pd256" => "__builtin_ia32_vcvtps2pd256_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvtps2ph256" => "__builtin_ia32_vcvtps2ph256_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvtps2phx256" => "__builtin_ia32_vcvtps2phx256_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvtps2qq256" => "__builtin_ia32_vcvtps2qq256_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvtps2udq256" => "__builtin_ia32_vcvtps2udq256_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvtps2uqq256" => "__builtin_ia32_vcvtps2uqq256_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvttpd2dq256" => "__builtin_ia32_vcvttpd2dq256_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvttpd2qq256" => "__builtin_ia32_vcvttpd2qq256_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvttpd2udq256" => "__builtin_ia32_vcvttpd2udq256_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvttpd2uqq256" => "__builtin_ia32_vcvttpd2uqq256_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvttph2dq256" => "__builtin_ia32_vcvttph2dq256_round_mask", + "llvm.x86.avx10.mask.vcvttph2ibs128" => "__builtin_ia32_vcvttph2ibs128_mask", + "llvm.x86.avx10.mask.vcvttph2ibs256" => "__builtin_ia32_vcvttph2ibs256_mask", + "llvm.x86.avx10.mask.vcvttph2ibs512" => "__builtin_ia32_vcvttph2ibs512_mask", + "llvm.x86.avx10.mask.vcvttph2iubs128" => "__builtin_ia32_vcvttph2iubs128_mask", + "llvm.x86.avx10.mask.vcvttph2iubs256" => "__builtin_ia32_vcvttph2iubs256_mask", + "llvm.x86.avx10.mask.vcvttph2iubs512" => "__builtin_ia32_vcvttph2iubs512_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvttph2qq256" => "__builtin_ia32_vcvttph2qq256_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvttph2udq256" => "__builtin_ia32_vcvttph2udq256_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvttph2uqq256" => "__builtin_ia32_vcvttph2uqq256_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvttph2uw256" => "__builtin_ia32_vcvttph2uw256_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvttph2w256" => "__builtin_ia32_vcvttph2w256_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvttps2dq256" => "__builtin_ia32_vcvttps2dq256_round_mask", + "llvm.x86.avx10.mask.vcvttps2ibs128" => "__builtin_ia32_vcvttps2ibs128_mask", + "llvm.x86.avx10.mask.vcvttps2ibs256" => "__builtin_ia32_vcvttps2ibs256_mask", + "llvm.x86.avx10.mask.vcvttps2ibs512" => "__builtin_ia32_vcvttps2ibs512_mask", + "llvm.x86.avx10.mask.vcvttps2iubs128" => "__builtin_ia32_vcvttps2iubs128_mask", + "llvm.x86.avx10.mask.vcvttps2iubs256" => "__builtin_ia32_vcvttps2iubs256_mask", + "llvm.x86.avx10.mask.vcvttps2iubs512" => "__builtin_ia32_vcvttps2iubs512_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvttps2qq256" => "__builtin_ia32_vcvttps2qq256_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvttps2udq256" => "__builtin_ia32_vcvttps2udq256_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvttps2uqq256" => "__builtin_ia32_vcvttps2uqq256_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vfcmaddcph256" => "__builtin_ia32_vfcmaddcph256_round_mask3", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vfcmulcph256" => "__builtin_ia32_vfcmulcph256_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vfixupimmpd256" => "__builtin_ia32_vfixupimmpd256_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vfixupimmps256" => "__builtin_ia32_vfixupimmps256_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vfmaddcph256" => "__builtin_ia32_vfmaddcph256_round_mask3", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vfmulcph256" => "__builtin_ia32_vfmulcph256_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vgetexppd256" => "__builtin_ia32_vgetexppd256_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vgetexpph256" => "__builtin_ia32_vgetexpph256_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vgetexpps256" => "__builtin_ia32_vgetexpps256_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vgetmantpd256" => "__builtin_ia32_vgetmantpd256_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vgetmantph256" => "__builtin_ia32_vgetmantph256_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vgetmantps256" => "__builtin_ia32_vgetmantps256_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vminmaxpd.round" => "__builtin_ia32_vminmaxpd512_round_mask", + "llvm.x86.avx10.mask.vminmaxpd128" => "__builtin_ia32_vminmaxpd128_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vminmaxpd256.round" => "__builtin_ia32_vminmaxpd256_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vminmaxph.round" => "__builtin_ia32_vminmaxph512_round_mask", + "llvm.x86.avx10.mask.vminmaxph128" => "__builtin_ia32_vminmaxph128_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vminmaxph256.round" => "__builtin_ia32_vminmaxph256_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vminmaxps.round" => "__builtin_ia32_vminmaxps512_round_mask", + "llvm.x86.avx10.mask.vminmaxps128" => "__builtin_ia32_vminmaxps128_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vminmaxps256.round" => "__builtin_ia32_vminmaxps256_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vminmaxsd.round" => "__builtin_ia32_vminmaxsd_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vminmaxsh.round" => "__builtin_ia32_vminmaxsh_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vminmaxss.round" => "__builtin_ia32_vminmaxss_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vrangepd256" => "__builtin_ia32_vrangepd256_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vrangeps256" => "__builtin_ia32_vrangeps256_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vreducepd256" => "__builtin_ia32_vreducepd256_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vreduceph256" => "__builtin_ia32_vreduceph256_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vreduceps256" => "__builtin_ia32_vreduceps256_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vrndscalepd256" => "__builtin_ia32_vrndscalepd256_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vrndscaleph256" => "__builtin_ia32_vrndscaleph256_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vrndscaleps256" => "__builtin_ia32_vrndscaleps256_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vscalefpd256" => "__builtin_ia32_vscalefpd256_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vscalefph256" => "__builtin_ia32_vscalefph256_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vscalefps256" => "__builtin_ia32_vscalefps256_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.maskz.vfcmaddcph256" => "__builtin_ia32_vfcmaddcph256_round_maskz", + // [INVALID CONVERSION]: "llvm.x86.avx10.maskz.vfixupimmpd256" => "__builtin_ia32_vfixupimmpd256_round_maskz", + // [INVALID CONVERSION]: "llvm.x86.avx10.maskz.vfixupimmps256" => "__builtin_ia32_vfixupimmps256_round_maskz", + // [INVALID CONVERSION]: "llvm.x86.avx10.maskz.vfmaddcph256" => "__builtin_ia32_vfmaddcph256_round_maskz", + "llvm.x86.avx10.vaddpd256" => "__builtin_ia32_vaddpd256_round", + "llvm.x86.avx10.vaddph256" => "__builtin_ia32_vaddph256_round", + "llvm.x86.avx10.vaddps256" => "__builtin_ia32_vaddps256_round", + "llvm.x86.avx10.vcvtne2ph2bf8128" => "__builtin_ia32_vcvtne2ph2bf8_128", + "llvm.x86.avx10.vcvtne2ph2bf8256" => "__builtin_ia32_vcvtne2ph2bf8_256", + "llvm.x86.avx10.vcvtne2ph2bf8512" => "__builtin_ia32_vcvtne2ph2bf8_512", + "llvm.x86.avx10.vcvtne2ph2bf8s128" => "__builtin_ia32_vcvtne2ph2bf8s_128", + "llvm.x86.avx10.vcvtne2ph2bf8s256" => "__builtin_ia32_vcvtne2ph2bf8s_256", + "llvm.x86.avx10.vcvtne2ph2bf8s512" => "__builtin_ia32_vcvtne2ph2bf8s_512", + "llvm.x86.avx10.vcvtne2ph2hf8128" => "__builtin_ia32_vcvtne2ph2hf8_128", + "llvm.x86.avx10.vcvtne2ph2hf8256" => "__builtin_ia32_vcvtne2ph2hf8_256", + "llvm.x86.avx10.vcvtne2ph2hf8512" => "__builtin_ia32_vcvtne2ph2hf8_512", + "llvm.x86.avx10.vcvtne2ph2hf8s128" => "__builtin_ia32_vcvtne2ph2hf8s_128", + "llvm.x86.avx10.vcvtne2ph2hf8s256" => "__builtin_ia32_vcvtne2ph2hf8s_256", + "llvm.x86.avx10.vcvtne2ph2hf8s512" => "__builtin_ia32_vcvtne2ph2hf8s_512", + "llvm.x86.avx10.vcvtnebf162ibs128" => "__builtin_ia32_vcvtnebf162ibs128", + "llvm.x86.avx10.vcvtnebf162ibs256" => "__builtin_ia32_vcvtnebf162ibs256", + "llvm.x86.avx10.vcvtnebf162ibs512" => "__builtin_ia32_vcvtnebf162ibs512", + "llvm.x86.avx10.vcvtnebf162iubs128" => "__builtin_ia32_vcvtnebf162iubs128", + "llvm.x86.avx10.vcvtnebf162iubs256" => "__builtin_ia32_vcvtnebf162iubs256", + "llvm.x86.avx10.vcvtnebf162iubs512" => "__builtin_ia32_vcvtnebf162iubs512", + "llvm.x86.avx10.vcvttnebf162ibs128" => "__builtin_ia32_vcvttnebf162ibs128", + "llvm.x86.avx10.vcvttnebf162ibs256" => "__builtin_ia32_vcvttnebf162ibs256", + "llvm.x86.avx10.vcvttnebf162ibs512" => "__builtin_ia32_vcvttnebf162ibs512", + "llvm.x86.avx10.vcvttnebf162iubs128" => "__builtin_ia32_vcvttnebf162iubs128", + "llvm.x86.avx10.vcvttnebf162iubs256" => "__builtin_ia32_vcvttnebf162iubs256", + "llvm.x86.avx10.vcvttnebf162iubs512" => "__builtin_ia32_vcvttnebf162iubs512", + "llvm.x86.avx10.vdivpd256" => "__builtin_ia32_vdivpd256_round", + "llvm.x86.avx10.vdivph256" => "__builtin_ia32_vdivph256_round", + "llvm.x86.avx10.vdivps256" => "__builtin_ia32_vdivps256_round", + "llvm.x86.avx10.vdpphps.128" => "__builtin_ia32_vdpphps128", + "llvm.x86.avx10.vdpphps.256" => "__builtin_ia32_vdpphps256", + "llvm.x86.avx10.vdpphps.512" => "__builtin_ia32_vdpphps512", + "llvm.x86.avx10.vfmaddsubpd256" => "__builtin_ia32_vfmaddsubpd256_round", + "llvm.x86.avx10.vfmaddsubph256" => "__builtin_ia32_vfmaddsubph256_round", + "llvm.x86.avx10.vfmaddsubps256" => "__builtin_ia32_vfmaddsubps256_round", + "llvm.x86.avx10.vmaxpd256" => "__builtin_ia32_vmaxpd256_round", + "llvm.x86.avx10.vmaxph256" => "__builtin_ia32_vmaxph256_round", + "llvm.x86.avx10.vmaxps256" => "__builtin_ia32_vmaxps256_round", + "llvm.x86.avx10.vminmaxnepbf16128" => "__builtin_ia32_vminmaxnepbf16128", + "llvm.x86.avx10.vminmaxnepbf16256" => "__builtin_ia32_vminmaxnepbf16256", + "llvm.x86.avx10.vminmaxnepbf16512" => "__builtin_ia32_vminmaxnepbf16512", + "llvm.x86.avx10.vminmaxpd128" => "__builtin_ia32_vminmaxpd128", + "llvm.x86.avx10.vminmaxpd256" => "__builtin_ia32_vminmaxpd256", + "llvm.x86.avx10.vminmaxph128" => "__builtin_ia32_vminmaxph128", + "llvm.x86.avx10.vminmaxph256" => "__builtin_ia32_vminmaxph256", + "llvm.x86.avx10.vminmaxps128" => "__builtin_ia32_vminmaxps128", + "llvm.x86.avx10.vminmaxps256" => "__builtin_ia32_vminmaxps256", + "llvm.x86.avx10.vminpd256" => "__builtin_ia32_vminpd256_round", + "llvm.x86.avx10.vminph256" => "__builtin_ia32_vminph256_round", + "llvm.x86.avx10.vminps256" => "__builtin_ia32_vminps256_round", + "llvm.x86.avx10.vmpsadbw.512" => "__builtin_ia32_mpsadbw512", + "llvm.x86.avx10.vmulpd256" => "__builtin_ia32_vmulpd256_round", + "llvm.x86.avx10.vmulph256" => "__builtin_ia32_vmulph256_round", + "llvm.x86.avx10.vmulps256" => "__builtin_ia32_vmulps256_round", + "llvm.x86.avx10.vpdpbssd.512" => "__builtin_ia32_vpdpbssd512", + "llvm.x86.avx10.vpdpbssds.512" => "__builtin_ia32_vpdpbssds512", + "llvm.x86.avx10.vpdpbsud.512" => "__builtin_ia32_vpdpbsud512", + "llvm.x86.avx10.vpdpbsuds.512" => "__builtin_ia32_vpdpbsuds512", + "llvm.x86.avx10.vpdpbuud.512" => "__builtin_ia32_vpdpbuud512", + "llvm.x86.avx10.vpdpbuuds.512" => "__builtin_ia32_vpdpbuuds512", + "llvm.x86.avx10.vpdpwsud.512" => "__builtin_ia32_vpdpwsud512", + "llvm.x86.avx10.vpdpwsuds.512" => "__builtin_ia32_vpdpwsuds512", + "llvm.x86.avx10.vpdpwusd.512" => "__builtin_ia32_vpdpwusd512", + "llvm.x86.avx10.vpdpwusds.512" => "__builtin_ia32_vpdpwusds512", + "llvm.x86.avx10.vpdpwuud.512" => "__builtin_ia32_vpdpwuud512", + "llvm.x86.avx10.vpdpwuuds.512" => "__builtin_ia32_vpdpwuuds512", + "llvm.x86.avx10.vsqrtpd256" => "__builtin_ia32_vsqrtpd256_round", + "llvm.x86.avx10.vsqrtph256" => "__builtin_ia32_vsqrtph256_round", + "llvm.x86.avx10.vsqrtps256" => "__builtin_ia32_vsqrtps256_round", + "llvm.x86.avx10.vsubpd256" => "__builtin_ia32_vsubpd256_round", + "llvm.x86.avx10.vsubph256" => "__builtin_ia32_vsubph256_round", + "llvm.x86.avx10.vsubps256" => "__builtin_ia32_vsubps256_round", "llvm.x86.avx2.gather.d.d" => "__builtin_ia32_gatherd_d", "llvm.x86.avx2.gather.d.d.256" => "__builtin_ia32_gatherd_d256", "llvm.x86.avx2.gather.d.pd" => "__builtin_ia32_gatherd_pd", @@ -8738,10 +8933,10 @@ match name { "llvm.x86.avx512.rcp14.ss" => "__builtin_ia32_rcp14ss_mask", "llvm.x86.avx512.rcp28.pd" => "__builtin_ia32_rcp28pd_mask", "llvm.x86.avx512.rcp28.ps" => "__builtin_ia32_rcp28ps_mask", - // [INVALID CONVERSION]: "llvm.x86.avx512.rcp28.sd" => "__builtin_ia32_rcp28sd_round_mask", - // [DUPLICATE]: "llvm.x86.avx512.rcp28.sd" => "__builtin_ia32_rcp28sd_mask", - // [INVALID CONVERSION]: "llvm.x86.avx512.rcp28.ss" => "__builtin_ia32_rcp28ss_round_mask", - // [DUPLICATE]: "llvm.x86.avx512.rcp28.ss" => "__builtin_ia32_rcp28ss_mask", + "llvm.x86.avx512.rcp28.sd" => "__builtin_ia32_rcp28sd_mask", + // [DUPLICATE]: "llvm.x86.avx512.rcp28.sd" => "__builtin_ia32_rcp28sd_round_mask", + "llvm.x86.avx512.rcp28.ss" => "__builtin_ia32_rcp28ss_mask", + // [DUPLICATE]: "llvm.x86.avx512.rcp28.ss" => "__builtin_ia32_rcp28ss_round_mask", "llvm.x86.avx512.rndscale.sd" => "__builtin_ia32_rndscalesd", "llvm.x86.avx512.rndscale.ss" => "__builtin_ia32_rndscaless", "llvm.x86.avx512.rsqrt14.pd.128" => "__builtin_ia32_rsqrt14pd128_mask", @@ -8754,10 +8949,10 @@ match name { "llvm.x86.avx512.rsqrt14.ss" => "__builtin_ia32_rsqrt14ss_mask", "llvm.x86.avx512.rsqrt28.pd" => "__builtin_ia32_rsqrt28pd_mask", "llvm.x86.avx512.rsqrt28.ps" => "__builtin_ia32_rsqrt28ps_mask", - // [INVALID CONVERSION]: "llvm.x86.avx512.rsqrt28.sd" => "__builtin_ia32_rsqrt28sd_round_mask", - // [DUPLICATE]: "llvm.x86.avx512.rsqrt28.sd" => "__builtin_ia32_rsqrt28sd_mask", - // [INVALID CONVERSION]: "llvm.x86.avx512.rsqrt28.ss" => "__builtin_ia32_rsqrt28ss_round_mask", - // [DUPLICATE]: "llvm.x86.avx512.rsqrt28.ss" => "__builtin_ia32_rsqrt28ss_mask", + "llvm.x86.avx512.rsqrt28.sd" => "__builtin_ia32_rsqrt28sd_mask", + // [DUPLICATE]: "llvm.x86.avx512.rsqrt28.sd" => "__builtin_ia32_rsqrt28sd_round_mask", + "llvm.x86.avx512.rsqrt28.ss" => "__builtin_ia32_rsqrt28ss_mask", + // [DUPLICATE]: "llvm.x86.avx512.rsqrt28.ss" => "__builtin_ia32_rsqrt28ss_round_mask", "llvm.x86.avx512.scatter.dpd.512" => "__builtin_ia32_scattersiv8df", "llvm.x86.avx512.scatter.dpi.512" => "__builtin_ia32_scattersiv16si", "llvm.x86.avx512.scatter.dpq.512" => "__builtin_ia32_scattersiv8di", @@ -9082,75 +9277,6 @@ match name { "llvm.x86.lwpval64" => "__builtin_ia32_lwpval64", "llvm.x86.mmx.emms" => "__builtin_ia32_emms", "llvm.x86.mmx.femms" => "__builtin_ia32_femms", - "llvm.x86.mmx.maskmovq" => "__builtin_ia32_maskmovq", - "llvm.x86.mmx.movnt.dq" => "__builtin_ia32_movntq", - "llvm.x86.mmx.packssdw" => "__builtin_ia32_packssdw", - "llvm.x86.mmx.packsswb" => "__builtin_ia32_packsswb", - "llvm.x86.mmx.packuswb" => "__builtin_ia32_packuswb", - "llvm.x86.mmx.padd.b" => "__builtin_ia32_paddb", - "llvm.x86.mmx.padd.d" => "__builtin_ia32_paddd", - "llvm.x86.mmx.padd.q" => "__builtin_ia32_paddq", - "llvm.x86.mmx.padd.w" => "__builtin_ia32_paddw", - "llvm.x86.mmx.padds.b" => "__builtin_ia32_paddsb", - "llvm.x86.mmx.padds.w" => "__builtin_ia32_paddsw", - "llvm.x86.mmx.paddus.b" => "__builtin_ia32_paddusb", - "llvm.x86.mmx.paddus.w" => "__builtin_ia32_paddusw", - "llvm.x86.mmx.palignr.b" => "__builtin_ia32_palignr", - "llvm.x86.mmx.pand" => "__builtin_ia32_pand", - "llvm.x86.mmx.pandn" => "__builtin_ia32_pandn", - "llvm.x86.mmx.pavg.b" => "__builtin_ia32_pavgb", - "llvm.x86.mmx.pavg.w" => "__builtin_ia32_pavgw", - "llvm.x86.mmx.pcmpeq.b" => "__builtin_ia32_pcmpeqb", - "llvm.x86.mmx.pcmpeq.d" => "__builtin_ia32_pcmpeqd", - "llvm.x86.mmx.pcmpeq.w" => "__builtin_ia32_pcmpeqw", - "llvm.x86.mmx.pcmpgt.b" => "__builtin_ia32_pcmpgtb", - "llvm.x86.mmx.pcmpgt.d" => "__builtin_ia32_pcmpgtd", - "llvm.x86.mmx.pcmpgt.w" => "__builtin_ia32_pcmpgtw", - "llvm.x86.mmx.pextr.w" => "__builtin_ia32_vec_ext_v4hi", - "llvm.x86.mmx.pinsr.w" => "__builtin_ia32_vec_set_v4hi", - "llvm.x86.mmx.pmadd.wd" => "__builtin_ia32_pmaddwd", - "llvm.x86.mmx.pmaxs.w" => "__builtin_ia32_pmaxsw", - "llvm.x86.mmx.pmaxu.b" => "__builtin_ia32_pmaxub", - "llvm.x86.mmx.pmins.w" => "__builtin_ia32_pminsw", - "llvm.x86.mmx.pminu.b" => "__builtin_ia32_pminub", - "llvm.x86.mmx.pmovmskb" => "__builtin_ia32_pmovmskb", - "llvm.x86.mmx.pmulh.w" => "__builtin_ia32_pmulhw", - "llvm.x86.mmx.pmulhu.w" => "__builtin_ia32_pmulhuw", - "llvm.x86.mmx.pmull.w" => "__builtin_ia32_pmullw", - "llvm.x86.mmx.pmulu.dq" => "__builtin_ia32_pmuludq", - "llvm.x86.mmx.por" => "__builtin_ia32_por", - "llvm.x86.mmx.psad.bw" => "__builtin_ia32_psadbw", - "llvm.x86.mmx.psll.d" => "__builtin_ia32_pslld", - "llvm.x86.mmx.psll.q" => "__builtin_ia32_psllq", - "llvm.x86.mmx.psll.w" => "__builtin_ia32_psllw", - "llvm.x86.mmx.pslli.d" => "__builtin_ia32_pslldi", - "llvm.x86.mmx.pslli.q" => "__builtin_ia32_psllqi", - "llvm.x86.mmx.pslli.w" => "__builtin_ia32_psllwi", - "llvm.x86.mmx.psra.d" => "__builtin_ia32_psrad", - "llvm.x86.mmx.psra.w" => "__builtin_ia32_psraw", - "llvm.x86.mmx.psrai.d" => "__builtin_ia32_psradi", - "llvm.x86.mmx.psrai.w" => "__builtin_ia32_psrawi", - "llvm.x86.mmx.psrl.d" => "__builtin_ia32_psrld", - "llvm.x86.mmx.psrl.q" => "__builtin_ia32_psrlq", - "llvm.x86.mmx.psrl.w" => "__builtin_ia32_psrlw", - "llvm.x86.mmx.psrli.d" => "__builtin_ia32_psrldi", - "llvm.x86.mmx.psrli.q" => "__builtin_ia32_psrlqi", - "llvm.x86.mmx.psrli.w" => "__builtin_ia32_psrlwi", - "llvm.x86.mmx.psub.b" => "__builtin_ia32_psubb", - "llvm.x86.mmx.psub.d" => "__builtin_ia32_psubd", - "llvm.x86.mmx.psub.q" => "__builtin_ia32_psubq", - "llvm.x86.mmx.psub.w" => "__builtin_ia32_psubw", - "llvm.x86.mmx.psubs.b" => "__builtin_ia32_psubsb", - "llvm.x86.mmx.psubs.w" => "__builtin_ia32_psubsw", - "llvm.x86.mmx.psubus.b" => "__builtin_ia32_psubusb", - "llvm.x86.mmx.psubus.w" => "__builtin_ia32_psubusw", - "llvm.x86.mmx.punpckhbw" => "__builtin_ia32_punpckhbw", - "llvm.x86.mmx.punpckhdq" => "__builtin_ia32_punpckhdq", - "llvm.x86.mmx.punpckhwd" => "__builtin_ia32_punpckhwd", - "llvm.x86.mmx.punpcklbw" => "__builtin_ia32_punpcklbw", - "llvm.x86.mmx.punpckldq" => "__builtin_ia32_punpckldq", - "llvm.x86.mmx.punpcklwd" => "__builtin_ia32_punpcklwd", - "llvm.x86.mmx.pxor" => "__builtin_ia32_pxor", "llvm.x86.monitorx" => "__builtin_ia32_monitorx", "llvm.x86.movdir64b" => "__builtin_ia32_movdir64b", "llvm.x86.mwaitx" => "__builtin_ia32_mwaitx", @@ -9193,16 +9319,10 @@ match name { "llvm.x86.sse.comile.ss" => "__builtin_ia32_comile", "llvm.x86.sse.comilt.ss" => "__builtin_ia32_comilt", "llvm.x86.sse.comineq.ss" => "__builtin_ia32_comineq", - "llvm.x86.sse.cvtpd2pi" => "__builtin_ia32_cvtpd2pi", - "llvm.x86.sse.cvtpi2pd" => "__builtin_ia32_cvtpi2pd", - "llvm.x86.sse.cvtpi2ps" => "__builtin_ia32_cvtpi2ps", - "llvm.x86.sse.cvtps2pi" => "__builtin_ia32_cvtps2pi", "llvm.x86.sse.cvtsi2ss" => "__builtin_ia32_cvtsi2ss", "llvm.x86.sse.cvtsi642ss" => "__builtin_ia32_cvtsi642ss", "llvm.x86.sse.cvtss2si" => "__builtin_ia32_cvtss2si", "llvm.x86.sse.cvtss2si64" => "__builtin_ia32_cvtss2si64", - "llvm.x86.sse.cvttpd2pi" => "__builtin_ia32_cvttpd2pi", - "llvm.x86.sse.cvttps2pi" => "__builtin_ia32_cvttps2pi", "llvm.x86.sse.cvttss2si" => "__builtin_ia32_cvttss2si", "llvm.x86.sse.cvttss2si64" => "__builtin_ia32_cvttss2si64", "llvm.x86.sse.div.ss" => "__builtin_ia32_divss", @@ -9212,7 +9332,6 @@ match name { "llvm.x86.sse.min.ss" => "__builtin_ia32_minss", "llvm.x86.sse.movmsk.ps" => "__builtin_ia32_movmskps", "llvm.x86.sse.mul.ss" => "__builtin_ia32_mulss", - "llvm.x86.sse.pshuf.w" => "__builtin_ia32_pshufw", "llvm.x86.sse.rcp.ps" => "__builtin_ia32_rcpps", "llvm.x86.sse.rcp.ss" => "__builtin_ia32_rcpss", "llvm.x86.sse.rsqrt.ps" => "__builtin_ia32_rsqrtps", @@ -9398,35 +9517,20 @@ match name { "llvm.x86.sse4a.insertqi" => "__builtin_ia32_insertqi", "llvm.x86.sse4a.movnt.sd" => "__builtin_ia32_movntsd", "llvm.x86.sse4a.movnt.ss" => "__builtin_ia32_movntss", - "llvm.x86.ssse3.pabs.b" => "__builtin_ia32_pabsb", "llvm.x86.ssse3.pabs.b.128" => "__builtin_ia32_pabsb128", - "llvm.x86.ssse3.pabs.d" => "__builtin_ia32_pabsd", "llvm.x86.ssse3.pabs.d.128" => "__builtin_ia32_pabsd128", - "llvm.x86.ssse3.pabs.w" => "__builtin_ia32_pabsw", "llvm.x86.ssse3.pabs.w.128" => "__builtin_ia32_pabsw128", - "llvm.x86.ssse3.phadd.d" => "__builtin_ia32_phaddd", "llvm.x86.ssse3.phadd.d.128" => "__builtin_ia32_phaddd128", - "llvm.x86.ssse3.phadd.sw" => "__builtin_ia32_phaddsw", "llvm.x86.ssse3.phadd.sw.128" => "__builtin_ia32_phaddsw128", - "llvm.x86.ssse3.phadd.w" => "__builtin_ia32_phaddw", "llvm.x86.ssse3.phadd.w.128" => "__builtin_ia32_phaddw128", - "llvm.x86.ssse3.phsub.d" => "__builtin_ia32_phsubd", "llvm.x86.ssse3.phsub.d.128" => "__builtin_ia32_phsubd128", - "llvm.x86.ssse3.phsub.sw" => "__builtin_ia32_phsubsw", "llvm.x86.ssse3.phsub.sw.128" => "__builtin_ia32_phsubsw128", - "llvm.x86.ssse3.phsub.w" => "__builtin_ia32_phsubw", "llvm.x86.ssse3.phsub.w.128" => "__builtin_ia32_phsubw128", - "llvm.x86.ssse3.pmadd.ub.sw" => "__builtin_ia32_pmaddubsw", "llvm.x86.ssse3.pmadd.ub.sw.128" => "__builtin_ia32_pmaddubsw128", - "llvm.x86.ssse3.pmul.hr.sw" => "__builtin_ia32_pmulhrsw", "llvm.x86.ssse3.pmul.hr.sw.128" => "__builtin_ia32_pmulhrsw128", - "llvm.x86.ssse3.pshuf.b" => "__builtin_ia32_pshufb", "llvm.x86.ssse3.pshuf.b.128" => "__builtin_ia32_pshufb128", - "llvm.x86.ssse3.psign.b" => "__builtin_ia32_psignb", "llvm.x86.ssse3.psign.b.128" => "__builtin_ia32_psignb128", - "llvm.x86.ssse3.psign.d" => "__builtin_ia32_psignd", "llvm.x86.ssse3.psign.d.128" => "__builtin_ia32_psignd128", - "llvm.x86.ssse3.psign.w" => "__builtin_ia32_psignw", "llvm.x86.ssse3.psign.w.128" => "__builtin_ia32_psignw128", "llvm.x86.sttilecfg" => "__builtin_ia32_tile_storeconfig", "llvm.x86.stui" => "__builtin_ia32_stui", From 2e7d2562805b79647d192a1511f2d616607c565a Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Tue, 3 Sep 2024 16:25:28 -0400 Subject: [PATCH 069/683] Add more SIMD intrinsics --- src/intrinsic/llvm.rs | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/src/intrinsic/llvm.rs b/src/intrinsic/llvm.rs index 3b9855ddc18..2d7bb8a2d54 100644 --- a/src/intrinsic/llvm.rs +++ b/src/intrinsic/llvm.rs @@ -185,7 +185,10 @@ pub fn adjust_intrinsic_arguments<'a, 'b, 'gcc, 'tcx>( | "__builtin_ia32_vplzcntq_128_mask" | "__builtin_ia32_cvtqq2pd128_mask" | "__builtin_ia32_cvtqq2pd256_mask" - | "__builtin_ia32_cvtqq2ps256_mask" => { + | "__builtin_ia32_cvtqq2ps256_mask" + | "__builtin_ia32_cvtuqq2pd128_mask" + | "__builtin_ia32_cvtuqq2pd256_mask" + | "__builtin_ia32_cvtuqq2ps256_mask" => { let mut new_args = args.to_vec(); // Remove last arg as it doesn't seem to be used in GCC and is always false. new_args.pop(); @@ -381,7 +384,8 @@ pub fn adjust_intrinsic_arguments<'a, 'b, 'gcc, 'tcx>( ); args = vec![arg.get_address(None)].into(); } - "__builtin_ia32_cvtqq2pd512_mask" | "__builtin_ia32_cvtqq2ps512_mask" => { + "__builtin_ia32_cvtqq2pd512_mask" | "__builtin_ia32_cvtqq2ps512_mask" | "__builtin_ia32_cvtuqq2pd512_mask" | + "__builtin_ia32_cvtuqq2ps512_mask" => { let mut old_args = args.to_vec(); let mut new_args = vec![]; new_args.push(old_args.swap_remove(0)); @@ -493,6 +497,11 @@ pub fn adjust_intrinsic_arguments<'a, 'b, 'gcc, 'tcx>( let new_args = args.to_vec(); args = vec![new_args[1], new_args[0], new_args[2]].into(); } + "__builtin_ia32_rangesd128_mask_round" | "__builtin_ia32_rangess128_mask_round" + | "__builtin_ia32_reducesd_mask_round" => { + let new_args = args.to_vec(); + args = vec![new_args[0], new_args[1], new_args[4], new_args[2], new_args[3], new_args[5]].into(); + } _ => (), } } @@ -1031,6 +1040,14 @@ pub fn intrinsic<'gcc, 'tcx>(name: &str, cx: &CodegenCx<'gcc, 'tcx>) -> Function "llvm.x86.avx512.sitofp.round.v4f64.v4i64" => "__builtin_ia32_cvtqq2pd256_mask", "llvm.x86.avx512.sitofp.round.v8f32.v8i64" => "__builtin_ia32_cvtqq2ps512_mask", "llvm.x86.avx512.sitofp.round.v4f32.v4i64" => "__builtin_ia32_cvtqq2ps256_mask", + "llvm.x86.avx512.uitofp.round.v8f64.v8u64" => "__builtin_ia32_cvtuqq2pd512_mask", + "llvm.x86.avx512.uitofp.round.v2f64.v2u64" => "__builtin_ia32_cvtuqq2pd128_mask", + "llvm.x86.avx512.uitofp.round.v4f64.v4u64" => "__builtin_ia32_cvtuqq2pd256_mask", + "llvm.x86.avx512.uitofp.round.v8f32.v8u64" => "__builtin_ia32_cvtuqq2ps512_mask", + "llvm.x86.avx512.uitofp.round.v4f32.v4u64" => "__builtin_ia32_cvtuqq2ps256_mask", + "llvm.x86.avx512.mask.reduce.pd.512" => "__builtin_ia32_reducepd512_mask_round", + "llvm.x86.avx512.mask.reduce.ps.512" => "__builtin_ia32_reduceps512_mask_round", + "llvm.x86.avx512.mask.reduce.sd" => "__builtin_ia32_reducesd_mask_round", // NOTE: this file is generated by https://github.com/GuillaumeGomez/llvmint/blob/master/generate_list.py _ => include!("archs.rs"), From 139eea948d2f4d6f816f1ac548527566814b37de Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 4 Sep 2024 00:34:34 +0200 Subject: [PATCH 070/683] fmt --- src/intrinsic/llvm.rs | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/src/intrinsic/llvm.rs b/src/intrinsic/llvm.rs index 2d7bb8a2d54..981603747c5 100644 --- a/src/intrinsic/llvm.rs +++ b/src/intrinsic/llvm.rs @@ -384,8 +384,10 @@ pub fn adjust_intrinsic_arguments<'a, 'b, 'gcc, 'tcx>( ); args = vec![arg.get_address(None)].into(); } - "__builtin_ia32_cvtqq2pd512_mask" | "__builtin_ia32_cvtqq2ps512_mask" | "__builtin_ia32_cvtuqq2pd512_mask" | - "__builtin_ia32_cvtuqq2ps512_mask" => { + "__builtin_ia32_cvtqq2pd512_mask" + | "__builtin_ia32_cvtqq2ps512_mask" + | "__builtin_ia32_cvtuqq2pd512_mask" + | "__builtin_ia32_cvtuqq2ps512_mask" => { let mut old_args = args.to_vec(); let mut new_args = vec![]; new_args.push(old_args.swap_remove(0)); @@ -497,10 +499,19 @@ pub fn adjust_intrinsic_arguments<'a, 'b, 'gcc, 'tcx>( let new_args = args.to_vec(); args = vec![new_args[1], new_args[0], new_args[2]].into(); } - "__builtin_ia32_rangesd128_mask_round" | "__builtin_ia32_rangess128_mask_round" - | "__builtin_ia32_reducesd_mask_round" => { + "__builtin_ia32_rangesd128_mask_round" + | "__builtin_ia32_rangess128_mask_round" + | "__builtin_ia32_reducesd_mask_round" => { let new_args = args.to_vec(); - args = vec![new_args[0], new_args[1], new_args[4], new_args[2], new_args[3], new_args[5]].into(); + args = vec![ + new_args[0], + new_args[1], + new_args[4], + new_args[2], + new_args[3], + new_args[5], + ] + .into(); } _ => (), } From 244ac087349bd57a626202ce37a82f90a94d4037 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 4 Sep 2024 00:35:04 +0200 Subject: [PATCH 071/683] Add missing intrinsic translation for `llvm.x86.xrstor64` --- src/intrinsic/llvm.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/intrinsic/llvm.rs b/src/intrinsic/llvm.rs index 981603747c5..d3e50afe53b 100644 --- a/src/intrinsic/llvm.rs +++ b/src/intrinsic/llvm.rs @@ -821,6 +821,7 @@ pub fn intrinsic<'gcc, 'tcx>(name: &str, cx: &CodegenCx<'gcc, 'tcx>) -> Function "llvm.x86.avx512.mask.cmp.b.256" => "__builtin_ia32_cmpb256_mask", "llvm.x86.avx512.mask.cmp.b.128" => "__builtin_ia32_cmpb128_mask", "llvm.x86.xrstor" => "__builtin_ia32_xrstor", + "llvm.x86.xrstor64" => "__builtin_ia32_xrstor64", "llvm.x86.xsavec" => "__builtin_ia32_xsavec", "llvm.x86.xsave64" => "__builtin_ia32_xsave64", "llvm.x86.addcarry.32" => "__builtin_ia32_addcarryx_u32", From 39e191077bb075a1b4f6facc9b75e5270cb507e4 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 4 Sep 2024 00:42:12 +0200 Subject: [PATCH 072/683] Add missing intrinsic translation for `llvm.x86.xsaveopt64` --- src/intrinsic/llvm.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/intrinsic/llvm.rs b/src/intrinsic/llvm.rs index d3e50afe53b..286aa6dab75 100644 --- a/src/intrinsic/llvm.rs +++ b/src/intrinsic/llvm.rs @@ -1029,6 +1029,7 @@ pub fn intrinsic<'gcc, 'tcx>(name: &str, cx: &CodegenCx<'gcc, 'tcx>) -> Function "llvm.x86.avx512.vpdpbusds.128" => "__builtin_ia32_vpdpbusds_v4si", "llvm.x86.xsave" => "__builtin_ia32_xsave", "llvm.x86.xsaveopt" => "__builtin_ia32_xsaveopt", + "llvm.x86.xsaveopt64" => "__builtin_ia32_xsaveopt64", "llvm.x86.avx512.mask.loadu.w.512" => "__builtin_ia32_loaddquhi512_mask", "llvm.x86.avx512.mask.loadu.b.512" => "__builtin_ia32_loaddquqi512_mask", "llvm.x86.avx512.mask.loadu.w.256" => "__builtin_ia32_loaddquhi256_mask", From 623dc09fa3a1d12f5a83ed763f4defa1c7e84c67 Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Tue, 3 Sep 2024 21:09:49 -0400 Subject: [PATCH 073/683] Add support for more SIMD intrinsics --- src/intrinsic/llvm.rs | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/intrinsic/llvm.rs b/src/intrinsic/llvm.rs index 286aa6dab75..ba57e425b0f 100644 --- a/src/intrinsic/llvm.rs +++ b/src/intrinsic/llvm.rs @@ -501,7 +501,8 @@ pub fn adjust_intrinsic_arguments<'a, 'b, 'gcc, 'tcx>( } "__builtin_ia32_rangesd128_mask_round" | "__builtin_ia32_rangess128_mask_round" - | "__builtin_ia32_reducesd_mask_round" => { + | "__builtin_ia32_reducesd_mask_round" + | "__builtin_ia32_reducess_mask_round" => { let new_args = args.to_vec(); args = vec![ new_args[0], @@ -1061,6 +1062,21 @@ pub fn intrinsic<'gcc, 'tcx>(name: &str, cx: &CodegenCx<'gcc, 'tcx>) -> Function "llvm.x86.avx512.mask.reduce.pd.512" => "__builtin_ia32_reducepd512_mask_round", "llvm.x86.avx512.mask.reduce.ps.512" => "__builtin_ia32_reduceps512_mask_round", "llvm.x86.avx512.mask.reduce.sd" => "__builtin_ia32_reducesd_mask_round", + "llvm.x86.avx512.mask.reduce.ss" => "__builtin_ia32_reducess_mask_round", + "llvm.x86.avx512.mask.loadu.d.256" => "__builtin_ia32_loaddqusi256_mask", + "llvm.x86.avx512.mask.loadu.q.256" => "__builtin_ia32_loaddqudi256_mask", + "llvm.x86.avx512.mask.loadu.ps.256" => "__builtin_ia32_loadups256_mask", + "llvm.x86.avx512.mask.loadu.pd.256" => "__builtin_ia32_loadupd256_mask", + "llvm.x86.avx512.mask.loadu.d.128" => "__builtin_ia32_loaddqusi128_mask", + "llvm.x86.avx512.mask.loadu.q.128" => "__builtin_ia32_loaddqudi128_mask", + "llvm.x86.avx512.mask.loadu.ps.128" => "__builtin_ia32_loadups128_mask", + "llvm.x86.avx512.mask.loadu.pd.128" => "__builtin_ia32_loadupd128_mask", + "llvm.x86.avx512.mask.load.d.512" => "__builtin_ia32_movdqa32load512_mask", + "llvm.x86.avx512.mask.load.q.512" => "__builtin_ia32_movdqa64load512_mask", + "llvm.x86.avx512.mask.load.ps.512" => "__builtin_ia32_loadaps512_mask", + "llvm.x86.avx512.mask.load.pd.512" => "__builtin_ia32_loadapd512_mask", + "llvm.x86.avx512.mask.load.d.256" => "__builtin_ia32_movdqa32load256_mask", + "llvm.x86.avx512.mask.load.q.256" => "__builtin_ia32_movdqa64load256_mask", // NOTE: this file is generated by https://github.com/GuillaumeGomez/llvmint/blob/master/generate_list.py _ => include!("archs.rs"), From c207badc2dd6abb1f416c4e09968184a69ff0484 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 4 Sep 2024 15:19:29 +0200 Subject: [PATCH 074/683] Add missing intrinsics translation for `llvm.x86.xsavec64` and fix more intrinsic calls --- src/intrinsic/llvm.rs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/intrinsic/llvm.rs b/src/intrinsic/llvm.rs index ba57e425b0f..89d5d582e4c 100644 --- a/src/intrinsic/llvm.rs +++ b/src/intrinsic/llvm.rs @@ -361,7 +361,14 @@ pub fn adjust_intrinsic_arguments<'a, 'b, 'gcc, 'tcx>( let minus_one = builder.context.new_rvalue_from_int(arg4_type, -1); args = vec![new_args[1], new_args[0], new_args[2], minus_one].into(); } - "__builtin_ia32_xrstor" | "__builtin_ia32_xsavec" => { + "__builtin_ia32_xrstor" + | "__builtin_ia32_xrstor64" + | "__builtin_ia32_xsavec" + | "__builtin_ia32_xsavec64" + | "__builtin_ia32_xsave" + | "__builtin_ia32_xsave64" + | "__builtin_ia32_xsaveopt" + | "__builtin_ia32_xsaveopt64" => { let new_args = args.to_vec(); let thirty_two = builder.context.new_rvalue_from_int(new_args[1].get_type(), 32); let arg2 = new_args[1] << thirty_two | new_args[2]; @@ -824,7 +831,7 @@ pub fn intrinsic<'gcc, 'tcx>(name: &str, cx: &CodegenCx<'gcc, 'tcx>) -> Function "llvm.x86.xrstor" => "__builtin_ia32_xrstor", "llvm.x86.xrstor64" => "__builtin_ia32_xrstor64", "llvm.x86.xsavec" => "__builtin_ia32_xsavec", - "llvm.x86.xsave64" => "__builtin_ia32_xsave64", + "llvm.x86.xsavec64" => "__builtin_ia32_xsavec64", "llvm.x86.addcarry.32" => "__builtin_ia32_addcarryx_u32", "llvm.x86.subborrow.32" => "__builtin_ia32_sbb_u32", "llvm.x86.avx512.mask.compress.store.w.512" => "__builtin_ia32_compressstoreuhi512_mask", @@ -1029,6 +1036,7 @@ pub fn intrinsic<'gcc, 'tcx>(name: &str, cx: &CodegenCx<'gcc, 'tcx>) -> Function "llvm.x86.avx512.vpdpbusds.256" => "__builtin_ia32_vpdpbusds_v8si", "llvm.x86.avx512.vpdpbusds.128" => "__builtin_ia32_vpdpbusds_v4si", "llvm.x86.xsave" => "__builtin_ia32_xsave", + "llvm.x86.xsave64" => "__builtin_ia32_xsave64", "llvm.x86.xsaveopt" => "__builtin_ia32_xsaveopt", "llvm.x86.xsaveopt64" => "__builtin_ia32_xsaveopt64", "llvm.x86.avx512.mask.loadu.w.512" => "__builtin_ia32_loaddquhi512_mask", From cdb442362b464472f1ede46f5b2763811978c2bf Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Wed, 4 Sep 2024 18:17:31 +0200 Subject: [PATCH 075/683] Bump actions/download-artifact from 3 to 4 --- .github/workflows/clippy_bors.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/clippy_bors.yml b/.github/workflows/clippy_bors.yml index 2aa13313fa5..026771e6fcf 100644 --- a/.github/workflows/clippy_bors.yml +++ b/.github/workflows/clippy_bors.yml @@ -162,7 +162,7 @@ jobs: find $DIR ! -executable -o -type d ! -path $DIR | xargs rm -rf - name: Upload Binaries - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: binaries path: target/debug @@ -202,7 +202,7 @@ jobs: # Download - name: Download target dir - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: name: binaries path: target/debug From 7d2e6ebcbeb2ca161b4b0f8a88bd41bf4c1381f5 Mon Sep 17 00:00:00 2001 From: Lukas Lueg Date: Wed, 4 Sep 2024 19:37:59 +0200 Subject: [PATCH 076/683] Expand missing_transmute_annotations docs Fixes #13339 --- clippy_lints/src/transmute/mod.rs | 32 +++++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/clippy_lints/src/transmute/mod.rs b/clippy_lints/src/transmute/mod.rs index 373bf61d8ff..6e62668fd52 100644 --- a/clippy_lints/src/transmute/mod.rs +++ b/clippy_lints/src/transmute/mod.rs @@ -527,24 +527,44 @@ declare_clippy_lint! { /// Checks if transmute calls have all generics specified. /// /// ### Why is this bad? - /// If not set, some unexpected output type could be retrieved instead of the expected one, - /// potentially leading to invalid code. + /// If not, one or more unexpected types could be used during `transmute()`, potentially leading + /// to Undefined Behavior or other problems. /// - /// This is particularly dangerous in case a seemingly innocent/unrelated change can cause type - /// inference to start inferring a different type. E.g. the transmute is the tail expression of - /// an `if` branch, and a different branches type changes, causing the transmute to silently - /// have a different type, instead of a proper error. + /// This is particularly dangerous in case a seemingly innocent/unrelated change causes type + /// inference to result in a different type. For example, if `transmute()` is the tail + /// expression of an `if`-branch, and the `else`-branch type changes, the compiler may silently + /// infer a different type to be returned by `transmute()`. That is because the compiler is + /// free to change the inference of a type as long as that inference is technically correct, + /// regardless of the programmer's unknown expectation. + /// + /// Both type-parameters, the input- and the output-type, to any `transmute()` should + /// be given explicitly: Setting the input-type explicitly avoids confusion about what the + /// argument's type actually is. Setting the output-type explicitly avoids type-inference + /// to infer a technically correct yet unexpected type. /// /// ### Example /// ```no_run /// # unsafe { + /// // Avoid "naked" calls to `transmute()`! /// let x: i32 = std::mem::transmute([1u16, 2u16]); + /// + /// // `first_answers` is intended to transmute a slice of bool to a slice of u8. + /// // But the programmer forgot to index the first element of the outer slice, + /// // so we are actually transmuting from "pointers to slices" instead of + /// // transmuting from "a slice of bool", causing a nonsensical result. + /// let the_answers: &[&[bool]] = &[&[true, false, true]]; + /// let first_answers: &[u8] = std::mem::transmute(the_answers); /// # } /// ``` /// Use instead: /// ```no_run /// # unsafe { /// let x = std::mem::transmute::<[u16; 2], i32>([1u16, 2u16]); + /// + /// // The explicit type parameters on `transmute()` makes the intention clear, + /// // and cause a type-error if the actual types don't match our expectation. + /// let the_answers: &[&[bool]] = &[&[true, false, true]]; + /// let first_answers: &[u8] = std::mem::transmute::<&[bool], &[u8]>(the_answers[0]); /// # } /// ``` #[clippy::version = "1.79.0"] From f7f550561e801fa1adb74377fd95a151820d8d0e Mon Sep 17 00:00:00 2001 From: Alex Macleod Date: Wed, 4 Sep 2024 21:22:28 +0000 Subject: [PATCH 077/683] Only lint `manual_non_exhaustive` for exported types --- clippy_lints/src/lib.rs | 3 +- clippy_lints/src/manual_non_exhaustive.rs | 182 ++++++++----------- tests/ui/manual_non_exhaustive_enum.rs | 24 ++- tests/ui/manual_non_exhaustive_enum.stderr | 22 ++- tests/ui/manual_non_exhaustive_struct.rs | 50 ++--- tests/ui/manual_non_exhaustive_struct.stderr | 64 ++++--- 6 files changed, 166 insertions(+), 179 deletions(-) diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 078f38656ec..747119e1147 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -633,8 +633,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { let format_args = format_args_storage.clone(); store.register_late_pass(move |_| Box::new(methods::Methods::new(conf, format_args.clone()))); store.register_late_pass(move |_| Box::new(matches::Matches::new(conf))); - store.register_early_pass(move || Box::new(manual_non_exhaustive::ManualNonExhaustiveStruct::new(conf))); - store.register_late_pass(move |_| Box::new(manual_non_exhaustive::ManualNonExhaustiveEnum::new(conf))); + store.register_late_pass(move |_| Box::new(manual_non_exhaustive::ManualNonExhaustive::new(conf))); store.register_late_pass(move |_| Box::new(manual_strip::ManualStrip::new(conf))); store.register_early_pass(move || Box::new(redundant_static_lifetimes::RedundantStaticLifetimes::new(conf))); store.register_early_pass(move || Box::new(redundant_field_names::RedundantFieldNames::new(conf))); diff --git a/clippy_lints/src/manual_non_exhaustive.rs b/clippy_lints/src/manual_non_exhaustive.rs index 6b1d90483cc..01f1d9c3beb 100644 --- a/clippy_lints/src/manual_non_exhaustive.rs +++ b/clippy_lints/src/manual_non_exhaustive.rs @@ -2,16 +2,16 @@ use clippy_config::msrvs::{self, Msrv}; use clippy_config::Conf; use clippy_utils::diagnostics::{span_lint_and_then, span_lint_hir_and_then}; use clippy_utils::is_doc_hidden; -use clippy_utils::source::SpanRangeExt; -use rustc_ast::ast::{self, VisibilityKind}; +use clippy_utils::source::snippet_indent; +use itertools::Itertools; use rustc_ast::attr; use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res}; -use rustc_hir::{self as hir, Expr, ExprKind, QPath}; -use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext}; +use rustc_hir::{Expr, ExprKind, Item, ItemKind, QPath, TyKind, VariantData}; +use rustc_lint::{LateContext, LateLintPass}; use rustc_session::impl_lint_pass; -use rustc_span::def_id::{DefId, LocalDefId}; +use rustc_span::def_id::LocalDefId; use rustc_span::{sym, Span}; declare_clippy_lint! { @@ -62,29 +62,13 @@ declare_clippy_lint! { "manual implementations of the non-exhaustive pattern can be simplified using #[non_exhaustive]" } -#[expect(clippy::module_name_repetitions)] -pub struct ManualNonExhaustiveStruct { +pub struct ManualNonExhaustive { msrv: Msrv, -} - -impl ManualNonExhaustiveStruct { - pub fn new(conf: &'static Conf) -> Self { - Self { - msrv: conf.msrv.clone(), - } - } -} - -impl_lint_pass!(ManualNonExhaustiveStruct => [MANUAL_NON_EXHAUSTIVE]); - -#[expect(clippy::module_name_repetitions)] -pub struct ManualNonExhaustiveEnum { - msrv: Msrv, - constructed_enum_variants: FxHashSet<(DefId, DefId)>, + constructed_enum_variants: FxHashSet, potential_enums: Vec<(LocalDefId, LocalDefId, Span, Span)>, } -impl ManualNonExhaustiveEnum { +impl ManualNonExhaustive { pub fn new(conf: &'static Conf) -> Self { Self { msrv: conf.msrv.clone(), @@ -94,96 +78,78 @@ impl ManualNonExhaustiveEnum { } } -impl_lint_pass!(ManualNonExhaustiveEnum => [MANUAL_NON_EXHAUSTIVE]); +impl_lint_pass!(ManualNonExhaustive => [MANUAL_NON_EXHAUSTIVE]); -impl EarlyLintPass for ManualNonExhaustiveStruct { - fn check_item(&mut self, cx: &EarlyContext<'_>, item: &ast::Item) { - if let ast::ItemKind::Struct(variant_data, _) = &item.kind - && let (fields, delimiter) = match variant_data { - ast::VariantData::Struct { fields, .. } => (&**fields, '{'), - ast::VariantData::Tuple(fields, _) => (&**fields, '('), - ast::VariantData::Unit(_) => return, - } - && fields.len() > 1 - && self.msrv.meets(msrvs::NON_EXHAUSTIVE) - { - let mut iter = fields.iter().filter_map(|f| match f.vis.kind { - VisibilityKind::Public => None, - VisibilityKind::Inherited => Some(Ok(f)), - VisibilityKind::Restricted { .. } => Some(Err(())), - }); - if let Some(Ok(field)) = iter.next() - && iter.next().is_none() - && field.ty.kind.is_unit() - { - span_lint_and_then( - cx, - MANUAL_NON_EXHAUSTIVE, - item.span, - "this seems like a manual implementation of the non-exhaustive pattern", - |diag| { - if !item.attrs.iter().any(|attr| attr.has_name(sym::non_exhaustive)) - && let header_span = cx.sess().source_map().span_until_char(item.span, delimiter) - && let Some(snippet) = header_span.get_source_text(cx) - { - diag.span_suggestion( - header_span, - "add the attribute", - format!("#[non_exhaustive] {snippet}"), - Applicability::Unspecified, - ); - } - diag.span_help(field.span, "remove this field"); - }, - ); - } - } - } - - extract_msrv_attr!(EarlyContext); -} - -impl<'tcx> LateLintPass<'tcx> for ManualNonExhaustiveEnum { - fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) { - if !self.msrv.meets(msrvs::NON_EXHAUSTIVE) { +impl<'tcx> LateLintPass<'tcx> for ManualNonExhaustive { + fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) { + if !self.msrv.meets(msrvs::NON_EXHAUSTIVE) || !cx.effective_visibilities.is_exported(item.owner_id.def_id) { return; } - if let hir::ItemKind::Enum(def, _) = &item.kind - && def.variants.len() > 1 - { - let mut iter = def.variants.iter().filter_map(|v| { - (matches!(v.data, hir::VariantData::Unit(_, _)) - && is_doc_hidden(cx.tcx.hir().attrs(v.hir_id)) - && !attr::contains_name(cx.tcx.hir().attrs(item.hir_id()), sym::non_exhaustive)) - .then_some((v.def_id, v.span)) - }); - if let Some((id, span)) = iter.next() - && iter.next().is_none() - { - self.potential_enums.push((item.owner_id.def_id, id, item.span, span)); - } + match item.kind { + ItemKind::Enum(def, _) if def.variants.len() > 1 => { + let iter = def.variants.iter().filter_map(|v| { + (matches!(v.data, VariantData::Unit(_, _)) && is_doc_hidden(cx.tcx.hir().attrs(v.hir_id))) + .then_some((v.def_id, v.span)) + }); + if let Ok((id, span)) = iter.exactly_one() + && !attr::contains_name(cx.tcx.hir().attrs(item.hir_id()), sym::non_exhaustive) + { + self.potential_enums.push((item.owner_id.def_id, id, item.span, span)); + } + }, + ItemKind::Struct(variant_data, _) => { + let fields = variant_data.fields(); + let private_fields = fields + .iter() + .filter(|field| !cx.effective_visibilities.is_exported(field.def_id)); + if fields.len() > 1 + && let Ok(field) = private_fields.exactly_one() + && let TyKind::Tup([]) = field.ty.kind + { + span_lint_and_then( + cx, + MANUAL_NON_EXHAUSTIVE, + item.span, + "this seems like a manual implementation of the non-exhaustive pattern", + |diag| { + if let Some(non_exhaustive) = + attr::find_by_name(cx.tcx.hir().attrs(item.hir_id()), sym::non_exhaustive) + { + diag.span_note(non_exhaustive.span, "the struct is already non-exhaustive"); + } else { + let indent = snippet_indent(cx, item.span).unwrap_or_default(); + diag.span_suggestion_verbose( + item.span.shrink_to_lo(), + "use the `#[non_exhaustive]` attribute instead", + format!("#[non_exhaustive]\n{indent}"), + Applicability::MaybeIncorrect, + ); + } + diag.span_help(field.span, "remove this field"); + }, + ); + } + }, + _ => {}, } } fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) { if let ExprKind::Path(QPath::Resolved(None, p)) = &e.kind - && let Res::Def(DefKind::Ctor(CtorOf::Variant, CtorKind::Const), id) = p.res + && let Res::Def(DefKind::Ctor(CtorOf::Variant, CtorKind::Const), ctor_id) = p.res + && let Some(local_ctor) = ctor_id.as_local() { - let variant_id = cx.tcx.parent(id); - let enum_id = cx.tcx.parent(variant_id); - - self.constructed_enum_variants.insert((enum_id, variant_id)); + let variant_id = cx.tcx.local_parent(local_ctor); + self.constructed_enum_variants.insert(variant_id); } } fn check_crate_post(&mut self, cx: &LateContext<'tcx>) { - for &(enum_id, _, enum_span, variant_span) in - self.potential_enums.iter().filter(|&&(enum_id, variant_id, _, _)| { - !self - .constructed_enum_variants - .contains(&(enum_id.to_def_id(), variant_id.to_def_id())) - }) + for &(enum_id, _, enum_span, variant_span) in self + .potential_enums + .iter() + .filter(|(_, variant_id, _, _)| !self.constructed_enum_variants.contains(variant_id)) { let hir_id = cx.tcx.local_def_id_to_hir_id(enum_id); span_lint_hir_and_then( @@ -193,15 +159,13 @@ impl<'tcx> LateLintPass<'tcx> for ManualNonExhaustiveEnum { enum_span, "this seems like a manual implementation of the non-exhaustive pattern", |diag| { - let header_span = cx.sess().source_map().span_until_char(enum_span, '{'); - if let Some(snippet) = header_span.get_source_text(cx) { - diag.span_suggestion( - header_span, - "add the attribute", - format!("#[non_exhaustive] {snippet}"), - Applicability::Unspecified, - ); - } + let indent = snippet_indent(cx, enum_span).unwrap_or_default(); + diag.span_suggestion_verbose( + enum_span.shrink_to_lo(), + "use the `#[non_exhaustive]` attribute instead", + format!("#[non_exhaustive]\n{indent}"), + Applicability::MaybeIncorrect, + ); diag.span_help(variant_span, "remove this variant"); }, ); diff --git a/tests/ui/manual_non_exhaustive_enum.rs b/tests/ui/manual_non_exhaustive_enum.rs index 31c3cc80137..ffe2bb92467 100644 --- a/tests/ui/manual_non_exhaustive_enum.rs +++ b/tests/ui/manual_non_exhaustive_enum.rs @@ -1,8 +1,8 @@ #![warn(clippy::manual_non_exhaustive)] #![allow(unused)] //@no-rustfix -enum E { - //~^ ERROR: this seems like a manual implementation of the non-exhaustive pattern +pub enum E { + //~^ manual_non_exhaustive A, B, #[doc(hidden)] @@ -11,7 +11,7 @@ enum E { // if the user explicitly marks as nonexhaustive we shouldn't warn them #[non_exhaustive] -enum Ep { +pub enum Ep { A, B, #[doc(hidden)] @@ -19,14 +19,14 @@ enum Ep { } // marker variant does not have doc hidden attribute, should be ignored -enum NoDocHidden { +pub enum NoDocHidden { A, B, _C, } // name of variant with doc hidden does not start with underscore -enum NoUnderscore { +pub enum NoUnderscore { A, B, #[doc(hidden)] @@ -34,7 +34,7 @@ enum NoUnderscore { } // variant with doc hidden is not unit, should be ignored -enum NotUnit { +pub enum NotUnit { A, B, #[doc(hidden)] @@ -42,13 +42,13 @@ enum NotUnit { } // variant with doc hidden is the only one, should be ignored -enum OnlyMarker { +pub enum OnlyMarker { #[doc(hidden)] _A, } // variant with multiple markers, should be ignored -enum MultipleMarkers { +pub enum MultipleMarkers { A, #[doc(hidden)] _B, @@ -58,13 +58,13 @@ enum MultipleMarkers { // already non_exhaustive and no markers, should be ignored #[non_exhaustive] -enum NonExhaustive { +pub enum NonExhaustive { A, B, } // marked is used, don't lint -enum UsedHidden { +pub enum UsedHidden { #[doc(hidden)] _A, B, @@ -77,11 +77,9 @@ fn foo(x: &mut UsedHidden) { } #[expect(clippy::manual_non_exhaustive)] -enum ExpectLint { +pub enum ExpectLint { A, B, #[doc(hidden)] _C, } - -fn main() {} diff --git a/tests/ui/manual_non_exhaustive_enum.stderr b/tests/ui/manual_non_exhaustive_enum.stderr index dc669568dd2..0a9ac157f85 100644 --- a/tests/ui/manual_non_exhaustive_enum.stderr +++ b/tests/ui/manual_non_exhaustive_enum.stderr @@ -1,11 +1,7 @@ error: this seems like a manual implementation of the non-exhaustive pattern --> tests/ui/manual_non_exhaustive_enum.rs:4:1 | -LL | enum E { - | ^----- - | | - | _help: add the attribute: `#[non_exhaustive] enum E` - | | +LL | / pub enum E { LL | | LL | | A, LL | | B, @@ -21,15 +17,16 @@ LL | _C, | ^^ = note: `-D clippy::manual-non-exhaustive` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::manual_non_exhaustive)]` +help: use the `#[non_exhaustive]` attribute instead + | +LL + #[non_exhaustive] +LL | pub enum E { + | error: this seems like a manual implementation of the non-exhaustive pattern --> tests/ui/manual_non_exhaustive_enum.rs:29:1 | -LL | enum NoUnderscore { - | ^---------------- - | | - | _help: add the attribute: `#[non_exhaustive] enum NoUnderscore` - | | +LL | / pub enum NoUnderscore { LL | | A, LL | | B, LL | | #[doc(hidden)] @@ -42,6 +39,11 @@ help: remove this variant | LL | C, | ^ +help: use the `#[non_exhaustive]` attribute instead + | +LL + #[non_exhaustive] +LL | pub enum NoUnderscore { + | error: aborting due to 2 previous errors diff --git a/tests/ui/manual_non_exhaustive_struct.rs b/tests/ui/manual_non_exhaustive_struct.rs index 4b2803ccc4a..31dd50281fa 100644 --- a/tests/ui/manual_non_exhaustive_struct.rs +++ b/tests/ui/manual_non_exhaustive_struct.rs @@ -1,9 +1,9 @@ #![warn(clippy::manual_non_exhaustive)] #![allow(unused)] //@no-rustfix -mod structs { - struct S { - //~^ ERROR: this seems like a manual implementation of the non-exhaustive pattern +pub mod structs { + pub struct S { + //~^ manual_non_exhaustive pub a: i32, pub b: i32, _c: (), @@ -11,68 +11,76 @@ mod structs { // user forgot to remove the private field #[non_exhaustive] - struct Sp { - //~^ ERROR: this seems like a manual implementation of the non-exhaustive pattern + pub struct Sp { + //~^ manual_non_exhaustive pub a: i32, pub b: i32, _c: (), } // some other fields are private, should be ignored - struct PrivateFields { + pub struct PrivateFields { a: i32, pub b: i32, _c: (), } - // private field name does not start with underscore, should be ignored - struct NoUnderscore { + pub struct NoUnderscore { + //~^ manual_non_exhaustive pub a: i32, pub b: i32, c: (), } // private field is not unit type, should be ignored - struct NotUnit { + pub struct NotUnit { pub a: i32, pub b: i32, _c: i32, } // private field is the only field, should be ignored - struct OnlyMarker { + pub struct OnlyMarker { _a: (), } // already non exhaustive and no private fields, should be ignored #[non_exhaustive] - struct NonExhaustive { + pub struct NonExhaustive { pub a: i32, pub b: i32, } } -mod tuple_structs { - struct T(pub i32, pub i32, ()); - //~^ ERROR: this seems like a manual implementation of the non-exhaustive pattern +pub mod tuple_structs { + pub struct T(pub i32, pub i32, ()); + //~^ manual_non_exhaustive // user forgot to remove the private field #[non_exhaustive] - struct Tp(pub i32, pub i32, ()); - //~^ ERROR: this seems like a manual implementation of the non-exhaustive pattern + pub struct Tp(pub i32, pub i32, ()); + //~^ manual_non_exhaustive // some other fields are private, should be ignored - struct PrivateFields(pub i32, i32, ()); + pub struct PrivateFields(pub i32, i32, ()); // private field is not unit type, should be ignored - struct NotUnit(pub i32, pub i32, i32); + pub struct NotUnit(pub i32, pub i32, i32); // private field is the only field, should be ignored - struct OnlyMarker(()); + pub struct OnlyMarker(()); // already non exhaustive and no private fields, should be ignored #[non_exhaustive] - struct NonExhaustive(pub i32, pub i32); + pub struct NonExhaustive(pub i32, pub i32); } -fn main() {} +mod private { + // Don't lint structs that are not actually public as `#[non_exhaustive]` only applies to + // external crates. The manual pattern can still be used to get module local non exhaustiveness + pub struct NotPublic { + pub a: i32, + pub b: i32, + _c: (), + } +} diff --git a/tests/ui/manual_non_exhaustive_struct.stderr b/tests/ui/manual_non_exhaustive_struct.stderr index 1cab812988a..81de1e4f271 100644 --- a/tests/ui/manual_non_exhaustive_struct.stderr +++ b/tests/ui/manual_non_exhaustive_struct.stderr @@ -1,11 +1,7 @@ error: this seems like a manual implementation of the non-exhaustive pattern --> tests/ui/manual_non_exhaustive_struct.rs:5:5 | -LL | struct S { - | ^------- - | | - | _____help: add the attribute: `#[non_exhaustive] struct S` - | | +LL | / pub struct S { LL | | LL | | pub a: i32, LL | | pub b: i32, @@ -20,11 +16,16 @@ LL | _c: (), | ^^^^^^ = note: `-D clippy::manual-non-exhaustive` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::manual_non_exhaustive)]` +help: use the `#[non_exhaustive]` attribute instead + | +LL ~ #[non_exhaustive] +LL ~ pub struct S { + | error: this seems like a manual implementation of the non-exhaustive pattern --> tests/ui/manual_non_exhaustive_struct.rs:14:5 | -LL | / struct Sp { +LL | / pub struct Sp { LL | | LL | | pub a: i32, LL | | pub b: i32, @@ -32,6 +33,11 @@ LL | | _c: (), LL | | } | |_____^ | +note: the struct is already non-exhaustive + --> tests/ui/manual_non_exhaustive_struct.rs:13:5 + | +LL | #[non_exhaustive] + | ^^^^^^^^^^^^^^^^^ help: remove this field --> tests/ui/manual_non_exhaustive_struct.rs:18:9 | @@ -39,13 +45,10 @@ LL | _c: (), | ^^^^^^ error: this seems like a manual implementation of the non-exhaustive pattern - --> tests/ui/manual_non_exhaustive_struct.rs:29:5 + --> tests/ui/manual_non_exhaustive_struct.rs:28:5 | -LL | struct NoUnderscore { - | ^------------------ - | | - | _____help: add the attribute: `#[non_exhaustive] struct NoUnderscore` - | | +LL | / pub struct NoUnderscore { +LL | | LL | | pub a: i32, LL | | pub b: i32, LL | | c: (), @@ -57,32 +60,45 @@ help: remove this field | LL | c: (), | ^^^^^ +help: use the `#[non_exhaustive]` attribute instead + | +LL ~ #[non_exhaustive] +LL ~ pub struct NoUnderscore { + | error: this seems like a manual implementation of the non-exhaustive pattern --> tests/ui/manual_non_exhaustive_struct.rs:56:5 | -LL | struct T(pub i32, pub i32, ()); - | --------^^^^^^^^^^^^^^^^^^^^^^^ - | | - | help: add the attribute: `#[non_exhaustive] struct T` +LL | pub struct T(pub i32, pub i32, ()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: remove this field - --> tests/ui/manual_non_exhaustive_struct.rs:56:32 + --> tests/ui/manual_non_exhaustive_struct.rs:56:36 + | +LL | pub struct T(pub i32, pub i32, ()); + | ^^ +help: use the `#[non_exhaustive]` attribute instead + | +LL ~ #[non_exhaustive] +LL ~ pub struct T(pub i32, pub i32, ()); | -LL | struct T(pub i32, pub i32, ()); - | ^^ error: this seems like a manual implementation of the non-exhaustive pattern --> tests/ui/manual_non_exhaustive_struct.rs:61:5 | -LL | struct Tp(pub i32, pub i32, ()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | pub struct Tp(pub i32, pub i32, ()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | +note: the struct is already non-exhaustive + --> tests/ui/manual_non_exhaustive_struct.rs:60:5 + | +LL | #[non_exhaustive] + | ^^^^^^^^^^^^^^^^^ help: remove this field - --> tests/ui/manual_non_exhaustive_struct.rs:61:33 + --> tests/ui/manual_non_exhaustive_struct.rs:61:37 | -LL | struct Tp(pub i32, pub i32, ()); - | ^^ +LL | pub struct Tp(pub i32, pub i32, ()); + | ^^ error: aborting due to 5 previous errors From 40fca8f7a8131129b75694109138891e607baab0 Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Thu, 5 Sep 2024 17:00:55 +0200 Subject: [PATCH 078/683] Bump Clippy version -> 0.1.83 --- Cargo.toml | 2 +- clippy_config/Cargo.toml | 2 +- clippy_lints/Cargo.toml | 2 +- clippy_utils/Cargo.toml | 2 +- declare_clippy_lint/Cargo.toml | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index b48b881097f..5b62e387ac6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clippy" -version = "0.1.82" +version = "0.1.83" description = "A bunch of helpful lints to avoid common pitfalls in Rust" repository = "https://github.com/rust-lang/rust-clippy" readme = "README.md" diff --git a/clippy_config/Cargo.toml b/clippy_config/Cargo.toml index 5c4e0761dbc..9da7112345d 100644 --- a/clippy_config/Cargo.toml +++ b/clippy_config/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clippy_config" -version = "0.1.82" +version = "0.1.83" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/clippy_lints/Cargo.toml b/clippy_lints/Cargo.toml index fbd4566da58..d1188940b46 100644 --- a/clippy_lints/Cargo.toml +++ b/clippy_lints/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clippy_lints" -version = "0.1.82" +version = "0.1.83" description = "A bunch of helpful lints to avoid common pitfalls in Rust" repository = "https://github.com/rust-lang/rust-clippy" readme = "README.md" diff --git a/clippy_utils/Cargo.toml b/clippy_utils/Cargo.toml index 629ce9d04d4..fe30b10c435 100644 --- a/clippy_utils/Cargo.toml +++ b/clippy_utils/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clippy_utils" -version = "0.1.82" +version = "0.1.83" edition = "2021" publish = false diff --git a/declare_clippy_lint/Cargo.toml b/declare_clippy_lint/Cargo.toml index 31270241b0b..67a1f7cc72c 100644 --- a/declare_clippy_lint/Cargo.toml +++ b/declare_clippy_lint/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "declare_clippy_lint" -version = "0.1.82" +version = "0.1.83" edition = "2021" publish = false From 3d027d75aff29983cb95da07352bcb8a55487400 Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Thu, 5 Sep 2024 17:01:08 +0200 Subject: [PATCH 079/683] Bump nightly version -> 2024-09-05 --- rust-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain b/rust-toolchain index 0be2e81810e..854fcda2dab 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,4 +1,4 @@ [toolchain] -channel = "nightly-2024-08-23" +channel = "nightly-2024-09-05" components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"] profile = "minimal" From 79081f1271222d4ea12c923d949fc4f1aece2362 Mon Sep 17 00:00:00 2001 From: Kevin Reid Date: Thu, 5 Sep 2024 14:30:27 -0700 Subject: [PATCH 080/683] Correct version of `too_long_first_doc_paragraph` `too_long_first_doc_paragraph` is, empirically, not in the Rust 1.81.0 release. --- clippy_lints/src/doc/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/doc/mod.rs b/clippy_lints/src/doc/mod.rs index 6db63b59e02..f2c87f0fd70 100644 --- a/clippy_lints/src/doc/mod.rs +++ b/clippy_lints/src/doc/mod.rs @@ -450,7 +450,7 @@ declare_clippy_lint! { /// /// and probably spanning a many rows. /// struct Foo {} /// ``` - #[clippy::version = "1.81.0"] + #[clippy::version = "1.82.0"] pub TOO_LONG_FIRST_DOC_PARAGRAPH, style, "ensure that the first line of a documentation paragraph isn't too long" From 0b8cb4a1ebdf3bb9b03f7befe48b3d5e36ba080b Mon Sep 17 00:00:00 2001 From: Pavel Grigorenko Date: Thu, 5 Sep 2024 00:34:04 +0300 Subject: [PATCH 081/683] Make `Ty::boxed_ty` return an `Option` --- clippy_lints/src/escape.rs | 6 +++--- clippy_lints/src/methods/mod.rs | 4 ++-- clippy_lints/src/methods/utils.rs | 4 ++-- clippy_lints/src/unnecessary_box_returns.rs | 6 ++---- clippy_utils/src/ty.rs | 4 ++-- 5 files changed, 11 insertions(+), 13 deletions(-) diff --git a/clippy_lints/src/escape.rs b/clippy_lints/src/escape.rs index a5da52b0be5..80360697941 100644 --- a/clippy_lints/src/escape.rs +++ b/clippy_lints/src/escape.rs @@ -50,7 +50,7 @@ declare_clippy_lint! { } fn is_non_trait_box(ty: Ty<'_>) -> bool { - ty.is_box() && !ty.boxed_ty().is_trait() + ty.boxed_ty().is_some_and(|boxed| !boxed.is_trait()) } struct EscapeDelegate<'a, 'tcx> { @@ -191,8 +191,8 @@ impl<'a, 'tcx> Delegate<'tcx> for EscapeDelegate<'a, 'tcx> { impl<'a, 'tcx> EscapeDelegate<'a, 'tcx> { fn is_large_box(&self, ty: Ty<'tcx>) -> bool { // Large types need to be boxed to avoid stack overflows. - if ty.is_box() { - self.cx.layout_of(ty.boxed_ty()).map_or(0, |l| l.size.bytes()) > self.too_large_for_stack + if let Some(boxed_ty) = ty.boxed_ty() { + self.cx.layout_of(boxed_ty).map_or(0, |l| l.size.bytes()) > self.too_large_for_stack } else { false } diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index d7126990edb..f61bb3a6bf4 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -5187,8 +5187,8 @@ impl SelfKind { fn matches_value<'a>(cx: &LateContext<'a>, parent_ty: Ty<'a>, ty: Ty<'a>) -> bool { if ty == parent_ty { true - } else if ty.is_box() { - ty.boxed_ty() == parent_ty + } else if let Some(boxed_ty) = ty.boxed_ty() { + boxed_ty == parent_ty } else if is_type_diagnostic_item(cx, ty, sym::Rc) || is_type_diagnostic_item(cx, ty, sym::Arc) { if let ty::Adt(_, args) = ty.kind() { args.types().next().map_or(false, |t| t == parent_ty) diff --git a/clippy_lints/src/methods/utils.rs b/clippy_lints/src/methods/utils.rs index 0d2b0a31317..fe860e5ae26 100644 --- a/clippy_lints/src/methods/utils.rs +++ b/clippy_lints/src/methods/utils.rs @@ -16,7 +16,7 @@ pub(super) fn derefs_to_slice<'tcx>( fn may_slice<'a>(cx: &LateContext<'a>, ty: Ty<'a>) -> bool { match ty.kind() { ty::Slice(_) => true, - ty::Adt(def, _) if def.is_box() => may_slice(cx, ty.boxed_ty()), + ty::Adt(..) if let Some(boxed) = ty.boxed_ty() => may_slice(cx, boxed), ty::Adt(..) => is_type_diagnostic_item(cx, ty, sym::Vec), ty::Array(_, size) => size.try_eval_target_usize(cx.tcx, cx.param_env).is_some(), ty::Ref(_, inner, _) => may_slice(cx, *inner), @@ -33,7 +33,7 @@ pub(super) fn derefs_to_slice<'tcx>( } else { match ty.kind() { ty::Slice(_) => Some(expr), - ty::Adt(def, _) if def.is_box() && may_slice(cx, ty.boxed_ty()) => Some(expr), + _ if ty.boxed_ty().is_some_and(|boxed| may_slice(cx, boxed)) => Some(expr), ty::Ref(_, inner, _) => { if may_slice(cx, *inner) { Some(expr) diff --git a/clippy_lints/src/unnecessary_box_returns.rs b/clippy_lints/src/unnecessary_box_returns.rs index 3f130bf5a67..14f4aa6676b 100644 --- a/clippy_lints/src/unnecessary_box_returns.rs +++ b/clippy_lints/src/unnecessary_box_returns.rs @@ -75,11 +75,9 @@ impl UnnecessaryBoxReturns { .instantiate_bound_regions_with_erased(cx.tcx.fn_sig(def_id).skip_binder()) .output(); - if !return_ty.is_box() { + let Some(boxed_ty) = return_ty.boxed_ty() else { return; - } - - let boxed_ty = return_ty.boxed_ty(); + }; // It's sometimes useful to return Box if T is unsized, so don't lint those. // Also, don't lint if we know that T is very large, in which case returning diff --git a/clippy_utils/src/ty.rs b/clippy_utils/src/ty.rs index f80981c11af..585134209ca 100644 --- a/clippy_utils/src/ty.rs +++ b/clippy_utils/src/ty.rs @@ -704,8 +704,8 @@ pub fn expr_sig<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>) -> Option(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option> { - if ty.is_box() { - return ty_sig(cx, ty.boxed_ty()); + if let Some(boxed_ty) = ty.boxed_ty() { + return ty_sig(cx, boxed_ty); } match *ty.kind() { ty::Closure(id, subs) => { From 9415e6e6eb9a570acecebd3dda0ed2b5db9fb910 Mon Sep 17 00:00:00 2001 From: Artem Belyakov Date: Sat, 27 Jul 2024 13:33:08 +0300 Subject: [PATCH 082/683] Add `manual_div_ceil` --- CHANGELOG.md | 1 + clippy_config/src/conf.rs | 2 +- clippy_config/src/msrvs.rs | 1 + clippy_lints/src/declared_lints.rs | 1 + clippy_lints/src/lib.rs | 2 + clippy_lints/src/manual_div_ceil.rs | 158 +++++++++++++++++++ tests/ui/manual_div_ceil.fixed | 30 ++++ tests/ui/manual_div_ceil.rs | 30 ++++ tests/ui/manual_div_ceil.stderr | 35 ++++ tests/ui/manual_div_ceil_with_feature.fixed | 25 +++ tests/ui/manual_div_ceil_with_feature.rs | 25 +++ tests/ui/manual_div_ceil_with_feature.stderr | 47 ++++++ 12 files changed, 356 insertions(+), 1 deletion(-) create mode 100644 clippy_lints/src/manual_div_ceil.rs create mode 100644 tests/ui/manual_div_ceil.fixed create mode 100644 tests/ui/manual_div_ceil.rs create mode 100644 tests/ui/manual_div_ceil.stderr create mode 100644 tests/ui/manual_div_ceil_with_feature.fixed create mode 100644 tests/ui/manual_div_ceil_with_feature.rs create mode 100644 tests/ui/manual_div_ceil_with_feature.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index 31fc74192ab..44a569d1ab5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5614,6 +5614,7 @@ Released 2018-09-13 [`manual_bits`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_bits [`manual_c_str_literals`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_c_str_literals [`manual_clamp`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_clamp +[`manual_div_ceil`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_div_ceil [`manual_filter`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_filter [`manual_filter_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_filter_map [`manual_find`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_find diff --git a/clippy_config/src/conf.rs b/clippy_config/src/conf.rs index a6f1b958bfb..6c1dd232593 100644 --- a/clippy_config/src/conf.rs +++ b/clippy_config/src/conf.rs @@ -864,7 +864,7 @@ fn calculate_dimensions(fields: &[&str]) -> (usize, Vec) { cmp::max(1, terminal_width / (SEPARATOR_WIDTH + max_field_width)) }); - let rows = (fields.len() + (columns - 1)) / columns; + let rows = fields.len().div_ceil(columns); let column_widths = (0..columns) .map(|column| { diff --git a/clippy_config/src/msrvs.rs b/clippy_config/src/msrvs.rs index 0c673ba8046..a70effd6376 100644 --- a/clippy_config/src/msrvs.rs +++ b/clippy_config/src/msrvs.rs @@ -21,6 +21,7 @@ msrv_aliases! { 1,80,0 { BOX_INTO_ITER} 1,77,0 { C_STR_LITERALS } 1,76,0 { PTR_FROM_REF, OPTION_RESULT_INSPECT } + 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 } 1,68,0 { PATH_MAIN_SEPARATOR_STR } diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index e478ab330e8..4804399ef7d 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -301,6 +301,7 @@ pub static LINTS: &[&crate::LintInfo] = &[ crate::manual_async_fn::MANUAL_ASYNC_FN_INFO, crate::manual_bits::MANUAL_BITS_INFO, crate::manual_clamp::MANUAL_CLAMP_INFO, + crate::manual_div_ceil::MANUAL_DIV_CEIL_INFO, crate::manual_float_methods::MANUAL_IS_FINITE_INFO, crate::manual_float_methods::MANUAL_IS_INFINITE_INFO, crate::manual_hash_one::MANUAL_HASH_ONE_INFO, diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index a9d5f82dfd2..9514ba8c315 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -203,6 +203,7 @@ mod manual_assert; mod manual_async_fn; mod manual_bits; mod manual_clamp; +mod manual_div_ceil; mod manual_float_methods; mod manual_hash_one; mod manual_is_ascii_check; @@ -936,5 +937,6 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { store.register_early_pass(|| Box::new(cfg_not_test::CfgNotTest)); store.register_late_pass(|_| Box::new(zombie_processes::ZombieProcesses)); store.register_late_pass(|_| Box::new(pointers_in_nomem_asm_block::PointersInNomemAsmBlock)); + store.register_late_pass(move |_| Box::new(manual_div_ceil::ManualDivCeil::new(conf))); // add lints here, do not remove this comment, it's used in `new_lint` } diff --git a/clippy_lints/src/manual_div_ceil.rs b/clippy_lints/src/manual_div_ceil.rs new file mode 100644 index 00000000000..024c2547dc6 --- /dev/null +++ b/clippy_lints/src/manual_div_ceil.rs @@ -0,0 +1,158 @@ +use clippy_config::msrvs::{self, Msrv}; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet_with_applicability; +use clippy_utils::sugg::Sugg; +use clippy_utils::SpanlessEq; +use rustc_ast::{BinOpKind, LitKind}; +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::symbol::Symbol; + +use clippy_config::Conf; + +declare_clippy_lint! { + /// ### What it does + /// Checks for an expression like `(x + (y - 1)) / y` which is a common manual reimplementation + /// of `x.div_ceil(y)`. + /// + /// ### Why is this bad? + /// It's simpler, clearer and more readable. + /// + /// ### Example + /// ```no_run + /// let x: i32 = 7; + /// let y: i32 = 4; + /// let div = (x + (y - 1)) / y; + /// ``` + /// Use instead: + /// ```no_run + /// #![feature(int_roundings)] + /// let x: i32 = 7; + /// let y: i32 = 4; + /// let div = x.div_ceil(y); + /// ``` + #[clippy::version = "1.81.0"] + pub MANUAL_DIV_CEIL, + complexity, + "manually reimplementing `div_ceil`" +} + +pub struct ManualDivCeil { + msrv: Msrv, +} + +impl ManualDivCeil { + #[must_use] + pub fn new(conf: &'static Conf) -> Self { + Self { + msrv: conf.msrv.clone(), + } + } +} + +impl_lint_pass!(ManualDivCeil => [MANUAL_DIV_CEIL]); + +impl<'tcx> LateLintPass<'tcx> for ManualDivCeil { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'_>) { + if !self.msrv.meets(msrvs::MANUAL_DIV_CEIL) { + return; + } + + let mut applicability = Applicability::MachineApplicable; + + if let ExprKind::Binary(div_op, div_lhs, div_rhs) = expr.kind + && div_op.node == BinOpKind::Div + && check_int_ty_and_feature(cx, div_lhs) + && check_int_ty_and_feature(cx, div_rhs) + && let ExprKind::Binary(inner_op, inner_lhs, inner_rhs) = div_lhs.kind + { + // (x + (y - 1)) / y + if let ExprKind::Binary(sub_op, sub_lhs, sub_rhs) = inner_rhs.kind + && inner_op.node == BinOpKind::Add + && sub_op.node == BinOpKind::Sub + && check_literal(sub_rhs) + && check_eq_expr(cx, sub_lhs, div_rhs) + { + build_suggestion(cx, expr, inner_lhs, div_rhs, &mut applicability); + return; + } + + // ((y - 1) + x) / y + if let ExprKind::Binary(sub_op, sub_lhs, sub_rhs) = inner_lhs.kind + && inner_op.node == BinOpKind::Add + && sub_op.node == BinOpKind::Sub + && check_literal(sub_rhs) + && check_eq_expr(cx, sub_lhs, div_rhs) + { + build_suggestion(cx, expr, inner_rhs, div_rhs, &mut applicability); + return; + } + + // (x + y - 1) / y + if let ExprKind::Binary(add_op, add_lhs, add_rhs) = inner_lhs.kind + && inner_op.node == BinOpKind::Sub + && add_op.node == BinOpKind::Add + && check_literal(inner_rhs) + && check_eq_expr(cx, add_rhs, div_rhs) + { + build_suggestion(cx, expr, add_lhs, div_rhs, &mut applicability); + } + } + } + + extract_msrv_attr!(LateContext); +} + +fn check_int_ty_and_feature(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { + let expr_ty = cx.typeck_results().expr_ty(expr); + match expr_ty.peel_refs().kind() { + ty::Uint(_) => true, + ty::Int(_) => cx + .tcx + .features() + .declared_features + .contains(&Symbol::intern("int_roundings")), + + _ => false, + } +} + +fn check_literal(expr: &Expr<'_>) -> bool { + if let ExprKind::Lit(lit) = expr.kind + && let LitKind::Int(Pu128(1), _) = lit.node + { + return true; + } + false +} + +fn check_eq_expr(cx: &LateContext<'_>, lhs: &Expr<'_>, rhs: &Expr<'_>) -> bool { + SpanlessEq::new(cx).eq_expr(lhs, rhs) +} + +fn build_suggestion( + cx: &LateContext<'_>, + expr: &Expr<'_>, + lhs: &Expr<'_>, + rhs: &Expr<'_>, + applicability: &mut Applicability, +) { + let dividend_sugg = Sugg::hir_with_applicability(cx, lhs, "..", applicability).maybe_par(); + let divisor_snippet = snippet_with_applicability(cx, rhs.span.source_callsite(), "..", applicability); + + let sugg = format!("{dividend_sugg}.div_ceil({divisor_snippet})"); + + span_lint_and_sugg( + cx, + MANUAL_DIV_CEIL, + expr.span, + "manually reimplementing `div_ceil`", + "consider using `.div_ceil()`", + sugg, + *applicability, + ); +} diff --git a/tests/ui/manual_div_ceil.fixed b/tests/ui/manual_div_ceil.fixed new file mode 100644 index 00000000000..e7801f7376a --- /dev/null +++ b/tests/ui/manual_div_ceil.fixed @@ -0,0 +1,30 @@ +#![warn(clippy::manual_div_ceil)] + +fn main() { + let x = 7_u32; + let y = 4_u32; + let z = 11_u32; + + // Lint + let _ = x.div_ceil(y); //~ ERROR: manually reimplementing `div_ceil` + let _ = x.div_ceil(y); //~ ERROR: manually reimplementing `div_ceil` + let _ = x.div_ceil(y); //~ ERROR: manually reimplementing `div_ceil` + + let _ = 7_u32.div_ceil(4); //~ ERROR: manually reimplementing `div_ceil` + let _ = (7_i32 as u32).div_ceil(4); //~ ERROR: manually reimplementing `div_ceil` + + // No lint + let _ = (x + (y - 2)) / y; + let _ = (x + (y + 1)) / y; + + let _ = (x + (y - 1)) / z; + + let x_i = 7_i32; + let y_i = 4_i32; + let z_i = 11_i32; + + // No lint because `int_roundings` feature is not enabled. + let _ = (z as i32 + (y_i - 1)) / y_i; + let _ = (7_u32 as i32 + (y_i - 1)) / y_i; + let _ = (7_u32 as i32 + (4 - 1)) / 4; +} diff --git a/tests/ui/manual_div_ceil.rs b/tests/ui/manual_div_ceil.rs new file mode 100644 index 00000000000..2de74c7eaa8 --- /dev/null +++ b/tests/ui/manual_div_ceil.rs @@ -0,0 +1,30 @@ +#![warn(clippy::manual_div_ceil)] + +fn main() { + let x = 7_u32; + let y = 4_u32; + let z = 11_u32; + + // Lint + let _ = (x + (y - 1)) / y; //~ ERROR: manually reimplementing `div_ceil` + let _ = ((y - 1) + x) / y; //~ ERROR: manually reimplementing `div_ceil` + let _ = (x + y - 1) / y; //~ ERROR: manually reimplementing `div_ceil` + + let _ = (7_u32 + (4 - 1)) / 4; //~ ERROR: manually reimplementing `div_ceil` + let _ = (7_i32 as u32 + (4 - 1)) / 4; //~ ERROR: manually reimplementing `div_ceil` + + // No lint + let _ = (x + (y - 2)) / y; + let _ = (x + (y + 1)) / y; + + let _ = (x + (y - 1)) / z; + + let x_i = 7_i32; + let y_i = 4_i32; + let z_i = 11_i32; + + // No lint because `int_roundings` feature is not enabled. + let _ = (z as i32 + (y_i - 1)) / y_i; + let _ = (7_u32 as i32 + (y_i - 1)) / y_i; + let _ = (7_u32 as i32 + (4 - 1)) / 4; +} diff --git a/tests/ui/manual_div_ceil.stderr b/tests/ui/manual_div_ceil.stderr new file mode 100644 index 00000000000..dc652dff405 --- /dev/null +++ b/tests/ui/manual_div_ceil.stderr @@ -0,0 +1,35 @@ +error: manually reimplementing `div_ceil` + --> tests/ui/manual_div_ceil.rs:9:13 + | +LL | let _ = (x + (y - 1)) / y; + | ^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `x.div_ceil(y)` + | + = note: `-D clippy::manual-div-ceil` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::manual_div_ceil)]` + +error: manually reimplementing `div_ceil` + --> tests/ui/manual_div_ceil.rs:10:13 + | +LL | let _ = ((y - 1) + x) / y; + | ^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `x.div_ceil(y)` + +error: manually reimplementing `div_ceil` + --> tests/ui/manual_div_ceil.rs:11:13 + | +LL | let _ = (x + y - 1) / y; + | ^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `x.div_ceil(y)` + +error: manually reimplementing `div_ceil` + --> tests/ui/manual_div_ceil.rs:13:13 + | +LL | let _ = (7_u32 + (4 - 1)) / 4; + | ^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `7_u32.div_ceil(4)` + +error: manually reimplementing `div_ceil` + --> tests/ui/manual_div_ceil.rs:14:13 + | +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 + diff --git a/tests/ui/manual_div_ceil_with_feature.fixed b/tests/ui/manual_div_ceil_with_feature.fixed new file mode 100644 index 00000000000..a1d678c6689 --- /dev/null +++ b/tests/ui/manual_div_ceil_with_feature.fixed @@ -0,0 +1,25 @@ +#![warn(clippy::manual_div_ceil)] +#![feature(int_roundings)] + +fn main() { + let x = 7_i32; + let y = 4_i32; + let z = 3_i32; + let z_u: u32 = 11; + + // Lint. + let _ = x.div_ceil(y); + let _ = x.div_ceil(y); + let _ = x.div_ceil(y); + + let _ = 7_i32.div_ceil(4); + let _ = (7_i32 as u32).div_ceil(4); + let _ = (7_u32 as i32).div_ceil(4); + let _ = z_u.div_ceil(4); + + // No lint. + let _ = (x + (y - 2)) / y; + let _ = (x + (y + 1)) / y; + + let _ = (x + (y - 1)) / z; +} diff --git a/tests/ui/manual_div_ceil_with_feature.rs b/tests/ui/manual_div_ceil_with_feature.rs new file mode 100644 index 00000000000..58cb1dbe34d --- /dev/null +++ b/tests/ui/manual_div_ceil_with_feature.rs @@ -0,0 +1,25 @@ +#![warn(clippy::manual_div_ceil)] +#![feature(int_roundings)] + +fn main() { + let x = 7_i32; + let y = 4_i32; + let z = 3_i32; + let z_u: u32 = 11; + + // Lint. + let _ = (x + (y - 1)) / y; + let _ = ((y - 1) + x) / y; + let _ = (x + y - 1) / y; + + let _ = (7_i32 + (4 - 1)) / 4; + let _ = (7_i32 as u32 + (4 - 1)) / 4; + let _ = (7_u32 as i32 + (4 - 1)) / 4; + let _ = (z_u + (4 - 1)) / 4; + + // No lint. + let _ = (x + (y - 2)) / y; + let _ = (x + (y + 1)) / y; + + let _ = (x + (y - 1)) / z; +} diff --git a/tests/ui/manual_div_ceil_with_feature.stderr b/tests/ui/manual_div_ceil_with_feature.stderr new file mode 100644 index 00000000000..361ef9bd9f4 --- /dev/null +++ b/tests/ui/manual_div_ceil_with_feature.stderr @@ -0,0 +1,47 @@ +error: manually reimplementing `div_ceil` + --> tests/ui/manual_div_ceil_with_feature.rs:11:13 + | +LL | let _ = (x + (y - 1)) / y; + | ^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `x.div_ceil(y)` + | + = note: `-D clippy::manual-div-ceil` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::manual_div_ceil)]` + +error: manually reimplementing `div_ceil` + --> tests/ui/manual_div_ceil_with_feature.rs:12:13 + | +LL | let _ = ((y - 1) + x) / y; + | ^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `x.div_ceil(y)` + +error: manually reimplementing `div_ceil` + --> tests/ui/manual_div_ceil_with_feature.rs:13:13 + | +LL | let _ = (x + y - 1) / y; + | ^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `x.div_ceil(y)` + +error: manually reimplementing `div_ceil` + --> tests/ui/manual_div_ceil_with_feature.rs:15:13 + | +LL | let _ = (7_i32 + (4 - 1)) / 4; + | ^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `7_i32.div_ceil(4)` + +error: manually reimplementing `div_ceil` + --> tests/ui/manual_div_ceil_with_feature.rs:16:13 + | +LL | let _ = (7_i32 as u32 + (4 - 1)) / 4; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `(7_i32 as u32).div_ceil(4)` + +error: manually reimplementing `div_ceil` + --> tests/ui/manual_div_ceil_with_feature.rs:17:13 + | +LL | let _ = (7_u32 as i32 + (4 - 1)) / 4; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `(7_u32 as i32).div_ceil(4)` + +error: manually reimplementing `div_ceil` + --> tests/ui/manual_div_ceil_with_feature.rs:18:13 + | +LL | let _ = (z_u + (4 - 1)) / 4; + | ^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `z_u.div_ceil(4)` + +error: aborting due to 7 previous errors + From cb0b5199ffbeec62ff622349c3bc15d9b9772a50 Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Thu, 5 Sep 2024 21:28:04 -0400 Subject: [PATCH 083/683] Add more SIMD intrinsics --- src/intrinsic/llvm.rs | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/intrinsic/llvm.rs b/src/intrinsic/llvm.rs index 89d5d582e4c..e57dc1cc75f 100644 --- a/src/intrinsic/llvm.rs +++ b/src/intrinsic/llvm.rs @@ -13,6 +13,11 @@ pub fn adjust_intrinsic_arguments<'a, 'b, 'gcc, 'tcx>( func_name: &str, original_function_name: Option<&String>, ) -> Cow<'b, [RValue<'gcc>]> { + // TODO: this might not be a good way to workaround the missing tile builtins. + if func_name == "__builtin_trap" { + return vec![].into(); + } + // Some LLVM intrinsics do not map 1-to-1 to GCC intrinsics, so we add the missing // arguments here. if gcc_func.get_param_count() != args.len() { @@ -287,7 +292,9 @@ pub fn adjust_intrinsic_arguments<'a, 'b, 'gcc, 'tcx>( new_args.push(last_arg); args = new_args.into(); } - "__builtin_ia32_vfmaddsubps512_mask" | "__builtin_ia32_vfmaddsubpd512_mask" => { + "__builtin_ia32_vfmaddsubps512_mask" + | "__builtin_ia32_vfmaddsubpd512_mask" + | "__builtin_ia32_cmpsh_mask_round" => { let mut new_args = args.to_vec(); let last_arg = new_args.pop().expect("last arg"); let arg4_type = gcc_func.get_param_type(3); @@ -1085,6 +1092,17 @@ pub fn intrinsic<'gcc, 'tcx>(name: &str, cx: &CodegenCx<'gcc, 'tcx>) -> Function "llvm.x86.avx512.mask.load.pd.512" => "__builtin_ia32_loadapd512_mask", "llvm.x86.avx512.mask.load.d.256" => "__builtin_ia32_movdqa32load256_mask", "llvm.x86.avx512.mask.load.q.256" => "__builtin_ia32_movdqa64load256_mask", + "llvm.x86.avx512fp16.mask.cmp.sh" => "__builtin_ia32_cmpsh_mask_round", + "llvm.x86.avx512fp16.vcomi.sh" => "__builtin_ia32_cmpsh_mask_round", + // TODO: support the tile builtins: + "llvm.x86.ldtilecfg" => "__builtin_trap", + "llvm.x86.sttilecfg" => "__builtin_trap", + "llvm.x86.tileloadd64" => "__builtin_trap", + "llvm.x86.tilerelease" => "__builtin_trap", + "llvm.x86.tilestored64" => "__builtin_trap", + "llvm.x86.tileloaddt164" => "__builtin_trap", + "llvm.x86.tilezero" => "__builtin_trap", + "llvm.x86.tdpbf16ps" => "__builtin_trap", // NOTE: this file is generated by https://github.com/GuillaumeGomez/llvmint/blob/master/generate_list.py _ => include!("archs.rs"), From d7996da9dae165c7d6e700f8b734392db30f9697 Mon Sep 17 00:00:00 2001 From: Sour1emon Date: Sat, 31 Aug 2024 16:30:03 -0700 Subject: [PATCH 084/683] Add `manual_is_power_of_two` --- CHANGELOG.md | 1 + clippy_lints/src/declared_lints.rs | 1 + clippy_lints/src/lib.rs | 2 + clippy_lints/src/manual_is_power_of_two.rs | 88 ++++++++++++++++++++++ tests/ui/manual_is_power_of_two.fixed | 14 ++++ tests/ui/manual_is_power_of_two.rs | 14 ++++ tests/ui/manual_is_power_of_two.stderr | 17 +++++ 7 files changed, 137 insertions(+) create mode 100644 clippy_lints/src/manual_is_power_of_two.rs create mode 100644 tests/ui/manual_is_power_of_two.fixed create mode 100644 tests/ui/manual_is_power_of_two.rs create mode 100644 tests/ui/manual_is_power_of_two.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index 44a569d1ab5..f1de51c936e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5626,6 +5626,7 @@ Released 2018-09-13 [`manual_is_ascii_check`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_is_ascii_check [`manual_is_finite`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_is_finite [`manual_is_infinite`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_is_infinite +[`manual_is_power_of_two`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_is_power_of_two [`manual_is_variant_and`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_is_variant_and [`manual_let_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_let_else [`manual_main_separator_str`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_main_separator_str diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index 4804399ef7d..6f468f01b2f 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -306,6 +306,7 @@ pub static LINTS: &[&crate::LintInfo] = &[ crate::manual_float_methods::MANUAL_IS_INFINITE_INFO, crate::manual_hash_one::MANUAL_HASH_ONE_INFO, crate::manual_is_ascii_check::MANUAL_IS_ASCII_CHECK_INFO, + crate::manual_is_power_of_two::MANUAL_IS_POWER_OF_TWO_INFO, crate::manual_let_else::MANUAL_LET_ELSE_INFO, crate::manual_main_separator_str::MANUAL_MAIN_SEPARATOR_STR_INFO, crate::manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE_INFO, diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 9514ba8c315..bc16a3b0c01 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -207,6 +207,7 @@ mod manual_div_ceil; mod manual_float_methods; mod manual_hash_one; mod manual_is_ascii_check; +mod manual_is_power_of_two; mod manual_let_else; mod manual_main_separator_str; mod manual_non_exhaustive; @@ -938,5 +939,6 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { store.register_late_pass(|_| Box::new(zombie_processes::ZombieProcesses)); store.register_late_pass(|_| Box::new(pointers_in_nomem_asm_block::PointersInNomemAsmBlock)); store.register_late_pass(move |_| Box::new(manual_div_ceil::ManualDivCeil::new(conf))); + store.register_late_pass(|_| Box::new(manual_is_power_of_two::ManualIsPowerOfTwo)); // add lints here, do not remove this comment, it's used in `new_lint` } diff --git a/clippy_lints/src/manual_is_power_of_two.rs b/clippy_lints/src/manual_is_power_of_two.rs new file mode 100644 index 00000000000..a65401fc571 --- /dev/null +++ b/clippy_lints/src/manual_is_power_of_two.rs @@ -0,0 +1,88 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet_with_applicability; +use rustc_ast::LitKind; +use rustc_data_structures::packed::Pu128; +use rustc_errors::Applicability; +use rustc_hir::{BinOpKind, Expr, ExprKind}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty::Uint; +use rustc_session::declare_lint_pass; + +declare_clippy_lint! { + /// ### What it does + /// Checks for expressions like `x.count_ones() == 1` or `x & (x - 1) == 0` which are manual + /// reimplementations of `x.is_power_of_two()`` + /// ### Why is this bad? + /// It's simpler and clearer + /// ### Example + /// ```no_run + /// let x: u32 = 1; + /// let result = x.count_ones() == 1; + /// ``` + /// Use instead: + /// ```no_run + /// let x: u32 = 1; + /// let result = x.is_power_of_two(); + /// ``` + #[clippy::version = "1.82.0"] + pub MANUAL_IS_POWER_OF_TWO, + complexity, + "manually reimplementing `is_power_of_two`" +} + +declare_lint_pass!(ManualIsPowerOfTwo => [MANUAL_IS_POWER_OF_TWO]); + +impl LateLintPass<'_> for ManualIsPowerOfTwo { + fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { + let mut applicability = Applicability::MachineApplicable; + + // x.count_ones() == 1 + if let ExprKind::Binary(op, left, right) = expr.kind + && BinOpKind::Eq == op.node + && let ExprKind::MethodCall(method_name, reciever, _, _) = left.kind + && method_name.ident.as_str() == "count_ones" + && let ExprKind::Lit(lit) = right.kind + && let LitKind::Int(Pu128(1), _) = lit.node + && let &Uint(_) = cx.typeck_results().expr_ty(reciever).kind() + { + let snippet = snippet_with_applicability(cx, reciever.span, "..", &mut applicability); + let sugg = format!("{snippet}.is_power_of_two()"); + span_lint_and_sugg( + cx, + MANUAL_IS_POWER_OF_TWO, + expr.span, + "manually reimplementing `is_power_of_two`", + "consider using `.is_power_of_two()`", + sugg, + applicability, + ); + } + + // x & (x - 1) == 0 + if let ExprKind::Binary(op, left, right) = expr.kind + && BinOpKind::Eq == op.node + && let ExprKind::Binary(op1, left1, right1) = left.kind + && BinOpKind::BitAnd == op1.node + && let ExprKind::Binary(op2, left2, right2) = right1.kind + && BinOpKind::Sub == op2.node + && left1.span.eq_ctxt(left2.span) + && let &Uint(_) = cx.typeck_results().expr_ty(left1).kind() + && let ExprKind::Lit(lit) = right2.kind + && let LitKind::Int(Pu128(1), _) = lit.node + && let ExprKind::Lit(lit1) = right.kind + && let LitKind::Int(Pu128(0), _) = lit1.node + { + let snippet = snippet_with_applicability(cx, left1.span, "..", &mut applicability); + let sugg = format!("{snippet}.is_power_of_two()"); + span_lint_and_sugg( + cx, + MANUAL_IS_POWER_OF_TWO, + expr.span, + "manually reimplementing `is_power_of_two`", + "consider using `.is_power_of_two()`", + sugg, + applicability, + ); + } + } +} diff --git a/tests/ui/manual_is_power_of_two.fixed b/tests/ui/manual_is_power_of_two.fixed new file mode 100644 index 00000000000..beee2eaf665 --- /dev/null +++ b/tests/ui/manual_is_power_of_two.fixed @@ -0,0 +1,14 @@ +#![warn(clippy::manual_is_power_of_two)] + +fn main() { + let a = 16_u64; + + let _ = a.is_power_of_two(); + let _ = a.is_power_of_two(); + + let b = 4_i64; + + // is_power_of_two only works for unsigned integers + let _ = b.count_ones() == 1; + let _ = b & (b - 1) == 0; +} diff --git a/tests/ui/manual_is_power_of_two.rs b/tests/ui/manual_is_power_of_two.rs new file mode 100644 index 00000000000..0810b4c28da --- /dev/null +++ b/tests/ui/manual_is_power_of_two.rs @@ -0,0 +1,14 @@ +#![warn(clippy::manual_is_power_of_two)] + +fn main() { + let a = 16_u64; + + let _ = a.count_ones() == 1; + let _ = a & (a - 1) == 0; + + let b = 4_i64; + + // is_power_of_two only works for unsigned integers + let _ = b.count_ones() == 1; + let _ = b & (b - 1) == 0; +} diff --git a/tests/ui/manual_is_power_of_two.stderr b/tests/ui/manual_is_power_of_two.stderr new file mode 100644 index 00000000000..c7dfe6b11b9 --- /dev/null +++ b/tests/ui/manual_is_power_of_two.stderr @@ -0,0 +1,17 @@ +error: manually reimplementing `is_power_of_two` + --> tests/ui/manual_is_power_of_two.rs:6:13 + | +LL | let _ = a.count_ones() == 1; + | ^^^^^^^^^^^^^^^^^^^ help: consider using `.is_power_of_two()`: `a.is_power_of_two()` + | + = note: `-D clippy::manual-is-power-of-two` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::manual_is_power_of_two)]` + +error: manually reimplementing `is_power_of_two` + --> tests/ui/manual_is_power_of_two.rs:7:13 + | +LL | let _ = a & (a - 1) == 0; + | ^^^^^^^^^^^^^^^^ help: consider using `.is_power_of_two()`: `a.is_power_of_two()` + +error: aborting due to 2 previous errors + From 5515566829f3b7ba3c302c5058e986657c01cc7e Mon Sep 17 00:00:00 2001 From: Isaac Bess Date: Mon, 2 Sep 2024 17:00:32 -0700 Subject: [PATCH 085/683] Improve "Why this is bad" section Co-authored-by: Ruby Lazuli --- clippy_lints/src/manual_is_power_of_two.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/manual_is_power_of_two.rs b/clippy_lints/src/manual_is_power_of_two.rs index a65401fc571..daa1abf61f1 100644 --- a/clippy_lints/src/manual_is_power_of_two.rs +++ b/clippy_lints/src/manual_is_power_of_two.rs @@ -13,7 +13,7 @@ declare_clippy_lint! { /// Checks for expressions like `x.count_ones() == 1` or `x & (x - 1) == 0` which are manual /// reimplementations of `x.is_power_of_two()`` /// ### Why is this bad? - /// It's simpler and clearer + /// Manual reimplementations of `is_power_of_two` increase code complexity for little benefit. /// ### Example /// ```no_run /// let x: u32 = 1; From 6ecb48f6d0becb8ff365b787106a8be429b4637a Mon Sep 17 00:00:00 2001 From: Isaac Bess Date: Mon, 2 Sep 2024 17:01:20 -0700 Subject: [PATCH 086/683] Fixed extra backtick Co-authored-by: Ruby Lazuli --- clippy_lints/src/manual_is_power_of_two.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/manual_is_power_of_two.rs b/clippy_lints/src/manual_is_power_of_two.rs index daa1abf61f1..c7ac668267a 100644 --- a/clippy_lints/src/manual_is_power_of_two.rs +++ b/clippy_lints/src/manual_is_power_of_two.rs @@ -10,8 +10,8 @@ use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does - /// Checks for expressions like `x.count_ones() == 1` or `x & (x - 1) == 0` which are manual - /// reimplementations of `x.is_power_of_two()`` + /// Checks for expressions like `x.count_ones() == 1` or `x & (x - 1) == 0`, which are manual + /// reimplementations of `x.is_power_of_two()`. /// ### Why is this bad? /// Manual reimplementations of `is_power_of_two` increase code complexity for little benefit. /// ### Example From f994797e4612f97a0f489e794f30c2113ce8d61e Mon Sep 17 00:00:00 2001 From: Sour1emon Date: Thu, 5 Sep 2024 18:23:00 -0700 Subject: [PATCH 087/683] Add support for different orders of expression --- clippy_lints/src/manual_is_power_of_two.rs | 154 ++++++++++++++------- tests/ui/manual_is_power_of_two.fixed | 6 + tests/ui/manual_is_power_of_two.rs | 6 + tests/ui/manual_is_power_of_two.stderr | 26 +++- 4 files changed, 141 insertions(+), 51 deletions(-) diff --git a/clippy_lints/src/manual_is_power_of_two.rs b/clippy_lints/src/manual_is_power_of_two.rs index c7ac668267a..d7879403ebb 100644 --- a/clippy_lints/src/manual_is_power_of_two.rs +++ b/clippy_lints/src/manual_is_power_of_two.rs @@ -1,5 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; +use clippy_utils::SpanlessEq; use rustc_ast::LitKind; use rustc_data_structures::packed::Pu128; use rustc_errors::Applicability; @@ -10,19 +11,19 @@ use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does - /// Checks for expressions like `x.count_ones() == 1` or `x & (x - 1) == 0`, which are manual + /// Checks for expressions like `x.count_ones() == 1` or `x & (x - 1) == 0`, with x and unsigned integer, which are manual /// reimplementations of `x.is_power_of_two()`. /// ### Why is this bad? /// Manual reimplementations of `is_power_of_two` increase code complexity for little benefit. /// ### Example /// ```no_run - /// let x: u32 = 1; - /// let result = x.count_ones() == 1; + /// let a: u32 = 4; + /// let result = a.count_ones() == 1; /// ``` /// Use instead: /// ```no_run - /// let x: u32 = 1; - /// let result = x.is_power_of_two(); + /// let a: u32 = 4; + /// let result = a.is_power_of_two(); /// ``` #[clippy::version = "1.82.0"] pub MANUAL_IS_POWER_OF_TWO, @@ -36,53 +37,106 @@ impl LateLintPass<'_> for ManualIsPowerOfTwo { fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { let mut applicability = Applicability::MachineApplicable; - // x.count_ones() == 1 - if let ExprKind::Binary(op, left, right) = expr.kind - && BinOpKind::Eq == op.node - && let ExprKind::MethodCall(method_name, reciever, _, _) = left.kind - && method_name.ident.as_str() == "count_ones" - && let ExprKind::Lit(lit) = right.kind - && let LitKind::Int(Pu128(1), _) = lit.node - && let &Uint(_) = cx.typeck_results().expr_ty(reciever).kind() + if let ExprKind::Binary(bin_op, left, right) = expr.kind + && bin_op.node == BinOpKind::Eq { - let snippet = snippet_with_applicability(cx, reciever.span, "..", &mut applicability); - let sugg = format!("{snippet}.is_power_of_two()"); - span_lint_and_sugg( - cx, - MANUAL_IS_POWER_OF_TWO, - expr.span, - "manually reimplementing `is_power_of_two`", - "consider using `.is_power_of_two()`", - sugg, - applicability, - ); - } + // a.count_ones() == 1 + if let ExprKind::MethodCall(method_name, reciever, _, _) = left.kind + && method_name.ident.as_str() == "count_ones" + && let &Uint(_) = cx.typeck_results().expr_ty(reciever).kind() + && check_lit(right, 1) + { + build_sugg(cx, expr, reciever, &mut applicability); + } - // x & (x - 1) == 0 - if let ExprKind::Binary(op, left, right) = expr.kind - && BinOpKind::Eq == op.node - && let ExprKind::Binary(op1, left1, right1) = left.kind - && BinOpKind::BitAnd == op1.node - && let ExprKind::Binary(op2, left2, right2) = right1.kind - && BinOpKind::Sub == op2.node - && left1.span.eq_ctxt(left2.span) - && let &Uint(_) = cx.typeck_results().expr_ty(left1).kind() - && let ExprKind::Lit(lit) = right2.kind - && let LitKind::Int(Pu128(1), _) = lit.node - && let ExprKind::Lit(lit1) = right.kind - && let LitKind::Int(Pu128(0), _) = lit1.node - { - let snippet = snippet_with_applicability(cx, left1.span, "..", &mut applicability); - let sugg = format!("{snippet}.is_power_of_two()"); - span_lint_and_sugg( - cx, - MANUAL_IS_POWER_OF_TWO, - expr.span, - "manually reimplementing `is_power_of_two`", - "consider using `.is_power_of_two()`", - sugg, - applicability, - ); + // 1 == a.count_ones() + if let ExprKind::MethodCall(method_name, reciever, _, _) = right.kind + && method_name.ident.as_str() == "count_ones" + && let &Uint(_) = cx.typeck_results().expr_ty(reciever).kind() + && check_lit(left, 1) + { + build_sugg(cx, expr, reciever, &mut applicability); + } + + // a & (a - 1) == 0 + if let ExprKind::Binary(op1, left1, right1) = left.kind + && op1.node == BinOpKind::BitAnd + && let ExprKind::Binary(op2, left2, right2) = right1.kind + && op2.node == BinOpKind::Sub + && check_eq_expr(cx, left1, left2) + && let &Uint(_) = cx.typeck_results().expr_ty(left1).kind() + && check_lit(right2, 1) + && check_lit(right, 0) + { + build_sugg(cx, expr, left1, &mut applicability); + } + + // (a - 1) & a == 0; + if let ExprKind::Binary(op1, left1, right1) = left.kind + && op1.node == BinOpKind::BitAnd + && let ExprKind::Binary(op2, left2, right2) = left1.kind + && op2.node == BinOpKind::Sub + && check_eq_expr(cx, right1, left2) + && let &Uint(_) = cx.typeck_results().expr_ty(right1).kind() + && check_lit(right2, 1) + && check_lit(right, 0) + { + build_sugg(cx, expr, right1, &mut applicability); + } + + // 0 == a & (a - 1); + if let ExprKind::Binary(op1, left1, right1) = right.kind + && op1.node == BinOpKind::BitAnd + && let ExprKind::Binary(op2, left2, right2) = right1.kind + && op2.node == BinOpKind::Sub + && check_eq_expr(cx, left1, left2) + && let &Uint(_) = cx.typeck_results().expr_ty(left1).kind() + && check_lit(right2, 1) + && check_lit(left, 0) + { + build_sugg(cx, expr, left1, &mut applicability); + } + + // 0 == (a - 1) & a + if let ExprKind::Binary(op1, left1, right1) = right.kind + && op1.node == BinOpKind::BitAnd + && let ExprKind::Binary(op2, left2, right2) = left1.kind + && op2.node == BinOpKind::Sub + && check_eq_expr(cx, right1, left2) + && let &Uint(_) = cx.typeck_results().expr_ty(right1).kind() + && check_lit(right2, 1) + && check_lit(left, 0) + { + build_sugg(cx, expr, right1, &mut applicability); + } } } } + +fn build_sugg(cx: &LateContext<'_>, expr: &Expr<'_>, reciever: &Expr<'_>, applicability: &mut Applicability) { + let snippet = snippet_with_applicability(cx, reciever.span, "..", applicability); + + span_lint_and_sugg( + cx, + MANUAL_IS_POWER_OF_TWO, + expr.span, + "manually reimplementing `is_power_of_two`", + "consider using `.is_power_of_two()`", + format!("{snippet}.is_power_of_two()"), + *applicability, + ); +} + +fn check_lit(expr: &Expr<'_>, expected_num: u128) -> bool { + if let ExprKind::Lit(lit) = expr.kind + && let LitKind::Int(Pu128(num), _) = lit.node + && num == expected_num + { + return true; + } + false +} + +fn check_eq_expr(cx: &LateContext<'_>, lhs: &Expr<'_>, rhs: &Expr<'_>) -> bool { + SpanlessEq::new(cx).eq_expr(lhs, rhs) +} diff --git a/tests/ui/manual_is_power_of_two.fixed b/tests/ui/manual_is_power_of_two.fixed index beee2eaf665..dda5fe0ec3e 100644 --- a/tests/ui/manual_is_power_of_two.fixed +++ b/tests/ui/manual_is_power_of_two.fixed @@ -6,6 +6,12 @@ fn main() { let _ = a.is_power_of_two(); let _ = a.is_power_of_two(); + // Test different orders of expression + let _ = a.is_power_of_two(); + let _ = a.is_power_of_two(); + let _ = a.is_power_of_two(); + let _ = a.is_power_of_two(); + let b = 4_i64; // is_power_of_two only works for unsigned integers diff --git a/tests/ui/manual_is_power_of_two.rs b/tests/ui/manual_is_power_of_two.rs index 0810b4c28da..a1d3a95c410 100644 --- a/tests/ui/manual_is_power_of_two.rs +++ b/tests/ui/manual_is_power_of_two.rs @@ -6,6 +6,12 @@ fn main() { let _ = a.count_ones() == 1; let _ = a & (a - 1) == 0; + // Test different orders of expression + let _ = 1 == a.count_ones(); + let _ = (a - 1) & a == 0; + let _ = 0 == a & (a - 1); + let _ = 0 == (a - 1) & a; + let b = 4_i64; // is_power_of_two only works for unsigned integers diff --git a/tests/ui/manual_is_power_of_two.stderr b/tests/ui/manual_is_power_of_two.stderr index c7dfe6b11b9..3cfc6297abf 100644 --- a/tests/ui/manual_is_power_of_two.stderr +++ b/tests/ui/manual_is_power_of_two.stderr @@ -13,5 +13,29 @@ error: manually reimplementing `is_power_of_two` LL | let _ = a & (a - 1) == 0; | ^^^^^^^^^^^^^^^^ help: consider using `.is_power_of_two()`: `a.is_power_of_two()` -error: aborting due to 2 previous errors +error: manually reimplementing `is_power_of_two` + --> tests/ui/manual_is_power_of_two.rs:10:13 + | +LL | let _ = 1 == a.count_ones(); + | ^^^^^^^^^^^^^^^^^^^ help: consider using `.is_power_of_two()`: `a.is_power_of_two()` + +error: manually reimplementing `is_power_of_two` + --> tests/ui/manual_is_power_of_two.rs:11:13 + | +LL | let _ = (a - 1) & a == 0; + | ^^^^^^^^^^^^^^^^ help: consider using `.is_power_of_two()`: `a.is_power_of_two()` + +error: manually reimplementing `is_power_of_two` + --> tests/ui/manual_is_power_of_two.rs:12:13 + | +LL | let _ = 0 == a & (a - 1); + | ^^^^^^^^^^^^^^^^ help: consider using `.is_power_of_two()`: `a.is_power_of_two()` + +error: manually reimplementing `is_power_of_two` + --> tests/ui/manual_is_power_of_two.rs:13:13 + | +LL | let _ = 0 == (a - 1) & a; + | ^^^^^^^^^^^^^^^^ help: consider using `.is_power_of_two()`: `a.is_power_of_two()` + +error: aborting due to 6 previous errors From e3ca249e9647396b9a3849e147aa53e168cf4c73 Mon Sep 17 00:00:00 2001 From: WeiTheShinobi Date: Fri, 6 Sep 2024 23:10:42 +0800 Subject: [PATCH 088/683] fix `single_match` suggestion --- clippy_lints/src/matches/single_match.rs | 24 ++++++++++++++--- tests/ui/single_match.fixed | 10 +++++-- tests/ui/single_match.rs | 15 +++++++++++ tests/ui/single_match.stderr | 33 +++++++++++++++++++++--- tests/ui/single_match_else.fixed | 2 +- tests/ui/single_match_else.stderr | 2 +- 6 files changed, 75 insertions(+), 11 deletions(-) diff --git a/clippy_lints/src/matches/single_match.rs b/clippy_lints/src/matches/single_match.rs index 4bd46bced38..e7cef5bdbd7 100644 --- a/clippy_lints/src/matches/single_match.rs +++ b/clippy_lints/src/matches/single_match.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::{expr_block, snippet, SpanRangeExt}; +use clippy_utils::source::{expr_block, snippet, snippet_block_with_context, SpanRangeExt}; use clippy_utils::ty::implements_trait; use clippy_utils::{ is_lint_allowed, is_unit_expr, peel_blocks, peel_hir_pat_refs, peel_middle_ty_refs, peel_n_hir_expr_refs, @@ -9,7 +9,7 @@ use rustc_arena::DroplessArena; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; use rustc_hir::intravisit::{walk_pat, Visitor}; -use rustc_hir::{Arm, Expr, ExprKind, HirId, Pat, PatKind, QPath}; +use rustc_hir::{Arm, Expr, ExprKind, HirId, Node, Pat, PatKind, QPath, StmtKind}; use rustc_lint::LateContext; use rustc_middle::ty::{self, AdtDef, ParamEnv, TyCtxt, TypeckResults, VariantDef}; use rustc_span::{sym, Span}; @@ -93,8 +93,24 @@ fn report_single_pattern(cx: &LateContext<'_>, ex: &Expr<'_>, arm: &Arm<'_>, exp if snippet(cx, ex.span, "..") == snippet(cx, arm.pat.span, "..") { let msg = "this pattern is irrefutable, `match` is useless"; - let sugg = expr_block(cx, arm.body, ctxt, "..", Some(expr.span), &mut app); - span_lint_and_sugg(cx, lint, expr.span, msg, "try", sugg, app); + let (sugg, help) = if is_unit_expr(arm.body) { + (String::new(), "`match` expression can be removed") + } else { + let mut sugg = snippet_block_with_context(cx, arm.body.span, ctxt, "..", Some(expr.span), &mut app) + .0 + .to_string(); + if let Node::Stmt(stmt) = cx.tcx.parent_hir_node(expr.hir_id) + && let StmtKind::Expr(_) = stmt.kind + && match arm.body.kind { + ExprKind::Block(block, _) => block.span.from_expansion(), + _ => true, + } + { + sugg.push(';'); + } + (sugg, "try") + }; + span_lint_and_sugg(cx, lint, expr.span, msg, help, sugg.to_string(), app); return; } diff --git a/tests/ui/single_match.fixed b/tests/ui/single_match.fixed index 04129ec0f13..dcf5a1d33c2 100644 --- a/tests/ui/single_match.fixed +++ b/tests/ui/single_match.fixed @@ -304,13 +304,19 @@ const DATA: Data = Data([1, 2, 3, 4]); const CONST_I32: i32 = 1; fn irrefutable_match() { - { println!() } + println!(); - { println!() } + println!(); let i = 0; { let a = 1; let b = 2; } + + + + + + println!() } diff --git a/tests/ui/single_match.rs b/tests/ui/single_match.rs index 2d51cee3fd9..3ba5eebd01b 100644 --- a/tests/ui/single_match.rs +++ b/tests/ui/single_match.rs @@ -386,4 +386,19 @@ fn irrefutable_match() { }, _ => {}, } + + match i { + i => {}, + _ => {}, + } + + match i { + i => (), + _ => (), + } + + match CONST_I32 { + CONST_I32 => println!(), + _ => {}, + } } diff --git a/tests/ui/single_match.stderr b/tests/ui/single_match.stderr index 9578421d2ce..9240b09c50a 100644 --- a/tests/ui/single_match.stderr +++ b/tests/ui/single_match.stderr @@ -223,7 +223,7 @@ LL | / match DATA { LL | | DATA => println!(), LL | | _ => {}, LL | | } - | |_____^ help: try: `{ println!() }` + | |_____^ help: try: `println!();` error: this pattern is irrefutable, `match` is useless --> tests/ui/single_match.rs:376:5 @@ -232,7 +232,7 @@ LL | / match CONST_I32 { LL | | CONST_I32 => println!(), LL | | _ => {}, LL | | } - | |_____^ help: try: `{ println!() }` + | |_____^ help: try: `println!();` error: this pattern is irrefutable, `match` is useless --> tests/ui/single_match.rs:382:5 @@ -254,5 +254,32 @@ LL + let b = 2; LL + } | -error: aborting due to 23 previous errors +error: this pattern is irrefutable, `match` is useless + --> tests/ui/single_match.rs:390:5 + | +LL | / match i { +LL | | i => {}, +LL | | _ => {}, +LL | | } + | |_____^ help: `match` expression can be removed + +error: this pattern is irrefutable, `match` is useless + --> tests/ui/single_match.rs:395:5 + | +LL | / match i { +LL | | i => (), +LL | | _ => (), +LL | | } + | |_____^ help: `match` expression can be removed + +error: this pattern is irrefutable, `match` is useless + --> tests/ui/single_match.rs:400:5 + | +LL | / match CONST_I32 { +LL | | CONST_I32 => println!(), +LL | | _ => {}, +LL | | } + | |_____^ help: try: `println!()` + +error: aborting due to 26 previous errors diff --git a/tests/ui/single_match_else.fixed b/tests/ui/single_match_else.fixed index fb57411aaa4..c2ca746976b 100644 --- a/tests/ui/single_match_else.fixed +++ b/tests/ui/single_match_else.fixed @@ -173,5 +173,5 @@ fn issue_10808(bar: Option) { } fn irrefutable_match() -> Option<&'static ExprNode> { - { Some(&NODE) } + Some(&NODE) } diff --git a/tests/ui/single_match_else.stderr b/tests/ui/single_match_else.stderr index 61209053fd0..a2801751a43 100644 --- a/tests/ui/single_match_else.stderr +++ b/tests/ui/single_match_else.stderr @@ -207,7 +207,7 @@ LL | | let x = 5; LL | | None LL | | }, LL | | } - | |_____^ help: try: `{ Some(&NODE) }` + | |_____^ help: try: `Some(&NODE)` error: aborting due to 10 previous errors From 62f44d7f20cf939ae0bd487d2e70ac1411e9db88 Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Fri, 6 Sep 2024 12:27:20 -0400 Subject: [PATCH 089/683] Add more SIMD intrinsics --- src/intrinsic/llvm.rs | 45 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/src/intrinsic/llvm.rs b/src/intrinsic/llvm.rs index e57dc1cc75f..1a3385a97be 100644 --- a/src/intrinsic/llvm.rs +++ b/src/intrinsic/llvm.rs @@ -418,6 +418,27 @@ pub fn adjust_intrinsic_arguments<'a, 'b, 'gcc, 'tcx>( new_args.push(old_args.swap_remove(0)); args = new_args.into(); } + "__builtin_ia32_addph512_mask_round" + | "__builtin_ia32_subph512_mask_round" + | "__builtin_ia32_mulph512_mask_round" + | "__builtin_ia32_divph512_mask_round" => { + let mut new_args = args.to_vec(); + let last_arg = new_args.pop().expect("last arg"); + + let arg3_type = gcc_func.get_param_type(2); + let vector_type = arg3_type.dyncast_vector().expect("vector type"); + let zero = builder.context.new_rvalue_zero(vector_type.get_element_type()); + let num_units = vector_type.get_num_units(); + let first_arg = + builder.context.new_rvalue_from_vector(None, arg3_type, &vec![zero; num_units]); + new_args.push(first_arg); + + let arg4_type = gcc_func.get_param_type(3); + let minus_one = builder.context.new_rvalue_from_int(arg4_type, -1); + new_args.push(minus_one); + new_args.push(last_arg); + args = new_args.into(); + } _ => (), } } else { @@ -1094,6 +1115,23 @@ pub fn intrinsic<'gcc, 'tcx>(name: &str, cx: &CodegenCx<'gcc, 'tcx>) -> Function "llvm.x86.avx512.mask.load.q.256" => "__builtin_ia32_movdqa64load256_mask", "llvm.x86.avx512fp16.mask.cmp.sh" => "__builtin_ia32_cmpsh_mask_round", "llvm.x86.avx512fp16.vcomi.sh" => "__builtin_ia32_cmpsh_mask_round", + "llvm.x86.avx512fp16.add.ph.512" => "__builtin_ia32_addph512_mask_round", + "llvm.x86.avx512fp16.sub.ph.512" => "__builtin_ia32_subph512_mask_round", + "llvm.x86.avx512fp16.mul.ph.512" => "__builtin_ia32_mulph512_mask_round", + "llvm.x86.avx512fp16.div.ph.512" => "__builtin_ia32_divph512_mask_round", + "llvm.x86.avx512fp16.mask.vfmul.cph.512" => "__builtin_ia32_vfmulcph512_mask_round", + "llvm.x86.avx512fp16.mask.vfmul.csh" => "__builtin_ia32_vfmulcsh_mask_round", + "llvm.x86.avx512fp16.mask.vfcmul.cph.512" => "__builtin_ia32_vfcmulcph512_mask_round", + "llvm.x86.avx512fp16.mask.vfcmul.csh" => "__builtin_ia32_vfcmulcsh_mask_round", + "llvm.x86.avx512fp16.mask.vfmadd.cph.512" => "__builtin_ia32_vfmaddcph512_mask3_round", + "llvm.x86.avx512fp16.maskz.vfmadd.cph.512" => "__builtin_ia32_vfmaddcph512_maskz_round", + "llvm.x86.avx512fp16.mask.vfmadd.csh" => "__builtin_ia32_vfmaddcsh_mask3_round", + "llvm.x86.avx512fp16.maskz.vfmadd.csh" => "__builtin_ia32_vfmaddcsh_maskz_round", + "llvm.x86.avx512fp16.mask.vfcmadd.cph.512" => "__builtin_ia32_vfcmaddcph512_mask3_round", + "llvm.x86.avx512fp16.maskz.vfcmadd.cph.512" => "__builtin_ia32_vfcmaddcph512_maskz_round", + "llvm.x86.avx512fp16.mask.vfcmadd.csh" => "__builtin_ia32_vfcmaddcsh_mask_round", + "llvm.x86.avx512fp16.maskz.vfcmadd.csh" => "__builtin_ia32_vfcmaddcsh_maskz_round", + // TODO: support the tile builtins: "llvm.x86.ldtilecfg" => "__builtin_trap", "llvm.x86.sttilecfg" => "__builtin_trap", @@ -1103,6 +1141,13 @@ pub fn intrinsic<'gcc, 'tcx>(name: &str, cx: &CodegenCx<'gcc, 'tcx>) -> Function "llvm.x86.tileloaddt164" => "__builtin_trap", "llvm.x86.tilezero" => "__builtin_trap", "llvm.x86.tdpbf16ps" => "__builtin_trap", + "llvm.x86.tdpbssd" => "__builtin_trap", + "llvm.x86.tdpbsud" => "__builtin_trap", + "llvm.x86.tdpbusd" => "__builtin_trap", + "llvm.x86.tdpbuud" => "__builtin_trap", + "llvm.x86.tdpfp16ps" => "__builtin_trap", + "llvm.x86.tcmmimfp16ps" => "__builtin_trap", + "llvm.x86.tcmmrlfp16ps" => "__builtin_trap", // NOTE: this file is generated by https://github.com/GuillaumeGomez/llvmint/blob/master/generate_list.py _ => include!("archs.rs"), From bcc5a1c77e7453445040184b8879e9fb49f9adb0 Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Fri, 6 Sep 2024 13:16:57 -0400 Subject: [PATCH 090/683] Update libgccjit version --- libgccjit.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libgccjit.version b/libgccjit.version index fa2bacc2c8e..e5f51a197a4 100644 --- a/libgccjit.version +++ b/libgccjit.version @@ -1 +1 @@ -bcafd46296f7898dac02d127e441b1d838ef2afc +a0cb76246d8d00ed9847d9874e5d5658049c332d From 46f8d360de99afe38dacc1dd6e29133d856e9fd3 Mon Sep 17 00:00:00 2001 From: Samarth1696 Date: Fri, 26 Jul 2024 00:51:30 +0530 Subject: [PATCH 091/683] Lint ready --- CHANGELOG.md | 1 + clippy_lints/src/declared_lints.rs | 1 + clippy_lints/src/lib.rs | 2 + clippy_lints/src/non_zero_suggestions.rs | 107 +++++++++++++++++++++++ tests/ui/non_zero_suggestions.rs | 52 +++++++++++ 5 files changed, 163 insertions(+) create mode 100644 clippy_lints/src/non_zero_suggestions.rs create mode 100644 tests/ui/non_zero_suggestions.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index f1de51c936e..0e5d1688e4a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5773,6 +5773,7 @@ Released 2018-09-13 [`non_minimal_cfg`]: https://rust-lang.github.io/rust-clippy/master/index.html#non_minimal_cfg [`non_octal_unix_permissions`]: https://rust-lang.github.io/rust-clippy/master/index.html#non_octal_unix_permissions [`non_send_fields_in_send_ty`]: https://rust-lang.github.io/rust-clippy/master/index.html#non_send_fields_in_send_ty +[`non_zero_suggestions`]: https://rust-lang.github.io/rust-clippy/master/index.html#non_zero_suggestions [`nonminimal_bool`]: https://rust-lang.github.io/rust-clippy/master/index.html#nonminimal_bool [`nonsensical_open_options`]: https://rust-lang.github.io/rust-clippy/master/index.html#nonsensical_open_options [`nonstandard_macro_braces`]: https://rust-lang.github.io/rust-clippy/master/index.html#nonstandard_macro_braces diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index 6f468f01b2f..16c64830e70 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -557,6 +557,7 @@ pub static LINTS: &[&crate::LintInfo] = &[ crate::non_expressive_names::SIMILAR_NAMES_INFO, crate::non_octal_unix_permissions::NON_OCTAL_UNIX_PERMISSIONS_INFO, crate::non_send_fields_in_send_ty::NON_SEND_FIELDS_IN_SEND_TY_INFO, + crate::non_zero_suggestions::NON_ZERO_SUGGESTIONS_INFO, crate::nonstandard_macro_braces::NONSTANDARD_MACRO_BRACES_INFO, crate::octal_escapes::OCTAL_ESCAPES_INFO, crate::only_used_in_recursion::ONLY_USED_IN_RECURSION_INFO, diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index bc16a3b0c01..3604090b68c 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -273,6 +273,7 @@ mod non_copy_const; mod non_expressive_names; mod non_octal_unix_permissions; mod non_send_fields_in_send_ty; +mod non_zero_suggestions; mod nonstandard_macro_braces; mod octal_escapes; mod only_used_in_recursion; @@ -940,5 +941,6 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { store.register_late_pass(|_| Box::new(pointers_in_nomem_asm_block::PointersInNomemAsmBlock)); store.register_late_pass(move |_| Box::new(manual_div_ceil::ManualDivCeil::new(conf))); store.register_late_pass(|_| Box::new(manual_is_power_of_two::ManualIsPowerOfTwo)); + store.register_late_pass(|_| Box::new(non_zero_suggestions::NonZeroSuggestions)); // add lints here, do not remove this comment, it's used in `new_lint` } diff --git a/clippy_lints/src/non_zero_suggestions.rs b/clippy_lints/src/non_zero_suggestions.rs new file mode 100644 index 00000000000..b9e7053db90 --- /dev/null +++ b/clippy_lints/src/non_zero_suggestions.rs @@ -0,0 +1,107 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet; +use rustc_errors::Applicability; +use rustc_hir::{Expr, ExprKind}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty::{self, Ty}; +use rustc_session::declare_lint_pass; +use rustc_span::symbol::sym; + +declare_clippy_lint! { + /// ### What it does + /// + /// ### Why is this bad? + /// + /// ### Example + /// ```no_run + /// // example code where clippy issues a warning + /// ``` + /// Use instead: + /// ```no_run + /// // example code which does not raise clippy warning + /// ``` + #[clippy::version = "1.81.0"] + pub NON_ZERO_SUGGESTIONS, + restriction, + "suggests using `NonZero#` from `u#` or `i#` for more efficient and type-safe conversions" +} + +declare_lint_pass!(NonZeroSuggestions => [NON_ZERO_SUGGESTIONS]); + +impl<'tcx> LateLintPass<'tcx> for NonZeroSuggestions { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { + if let ExprKind::Call(func, [arg]) = expr.kind { + if let ExprKind::Path(qpath) = &func.kind { + if let Some(def_id) = cx.qpath_res(qpath, func.hir_id).opt_def_id() { + let fn_name = cx.tcx.item_name(def_id); + let target_ty = cx.typeck_results().expr_ty(expr); + + if let ExprKind::MethodCall(rcv_path, receiver, _, _) = &arg.kind { + let receiver_ty = cx.typeck_results().expr_ty(receiver); + if let ty::Adt(adt_def, _) = receiver_ty.kind() { + if adt_def.is_struct() && cx.tcx.get_diagnostic_name(adt_def.did()) == Some(sym::NonZero) { + if let Some(target_non_zero_type) = get_target_non_zero_type(target_ty) { + let arg_snippet = get_arg_snippet(cx, arg, rcv_path); + suggest_non_zero_conversion(cx, expr, fn_name, target_non_zero_type, &arg_snippet); + } + } + } + } + } + } + } + } +} + +fn get_arg_snippet(cx: &LateContext<'_>, arg: &Expr<'_>, rcv_path: &rustc_hir::PathSegment<'_>) -> String { + let arg_snippet = snippet(cx, arg.span, ".."); + if let Some(index) = arg_snippet.rfind(&format!(".{}", rcv_path.ident.name)) { + arg_snippet[..index].trim().to_string() + } else { + arg_snippet.to_string() + } +} + +fn suggest_non_zero_conversion( + cx: &LateContext<'_>, + expr: &Expr<'_>, + fn_name: rustc_span::Symbol, + target_non_zero_type: &str, + arg_snippet: &str, +) { + let suggestion = format!("{}::{}({})", target_non_zero_type, fn_name, arg_snippet); + span_lint_and_sugg( + cx, + NON_ZERO_SUGGESTIONS, + expr.span, + format!( + "Consider using `{}::{}()` for more efficient and type-safe conversion", + target_non_zero_type, fn_name + ), + "Replace with", + suggestion, + Applicability::MachineApplicable, + ); +} + +fn get_target_non_zero_type(ty: Ty<'_>) -> Option<&'static str> { + match ty.kind() { + ty::Uint(uint_ty) => Some(match uint_ty { + ty::UintTy::U8 => "NonZeroU8", + ty::UintTy::U16 => "NonZeroU16", + ty::UintTy::U32 => "NonZeroU32", + ty::UintTy::U64 => "NonZeroU64", + ty::UintTy::U128 => "NonZeroU128", + ty::UintTy::Usize => "NonZeroUsize", + }), + ty::Int(int_ty) => Some(match int_ty { + ty::IntTy::I8 => "NonZeroI8", + ty::IntTy::I16 => "NonZeroI16", + ty::IntTy::I32 => "NonZeroI32", + ty::IntTy::I64 => "NonZeroI64", + ty::IntTy::I128 => "NonZeroI128", + ty::IntTy::Isize => "NonZeroIsize", + }), + _ => None, + } +} diff --git a/tests/ui/non_zero_suggestions.rs b/tests/ui/non_zero_suggestions.rs new file mode 100644 index 00000000000..1a5ee40dc3d --- /dev/null +++ b/tests/ui/non_zero_suggestions.rs @@ -0,0 +1,52 @@ +#![warn(clippy::non_zero_suggestions)] + +use std::num::{ + NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroIsize, NonZeroU128, NonZeroU16, NonZeroU32, + NonZeroU64, NonZeroU8, NonZeroUsize, +}; + +fn main() { + // Basic cases + let _ = u8::try_from(NonZeroU8::new(5).unwrap().get()); + + let _ = u16::from(NonZeroU16::new(10).unwrap().get()); + + // Different integer types + let _ = u32::from(NonZeroU32::new(15).unwrap().get()); + + let _ = u64::from(NonZeroU64::new(20).unwrap().get()); + + let _ = u128::from(NonZeroU128::new(25).unwrap().get()); + + let _ = usize::from(NonZeroUsize::new(30).unwrap().get()); + + // Signed integer types + let _ = i8::try_from(NonZeroI8::new(-5).unwrap().get()); + + let _ = i16::from(NonZeroI16::new(-10).unwrap().get()); + + let _ = i32::from(NonZeroI32::new(-15).unwrap().get()); + + // Edge cases + + // Complex expression + let _ = u8::from(NonZeroU8::new(5).unwrap().get() + 1); + + // Function call + fn get_non_zero() -> NonZeroU8 { + NonZeroU8::new(42).unwrap() + } + let _ = u8::from(get_non_zero().get()); + + // Method chaining + let _ = u16::from(NonZeroU16::new(100).unwrap().get().checked_add(1).unwrap()); + // This should not trigger the lint + + // Different conversion methods + let _ = u32::try_from(NonZeroU32::new(200).unwrap().get()).unwrap(); + + // Cases that should not trigger the lint + let _ = u8::from(5); + let _ = u16::from(10u8); + let _ = i32::try_from(40u32).unwrap(); +} From 73039f654e2efc3a7384462dcd46289851b80e62 Mon Sep 17 00:00:00 2001 From: Samarth1696 Date: Fri, 26 Jul 2024 17:11:51 +0530 Subject: [PATCH 092/683] test cases added including some edge cases --- clippy_lints/src/non_zero_suggestions.rs | 22 +++++- tests/ui/non_zero_suggestions.fixed | 69 ++++++++++++++++++ tests/ui/non_zero_suggestions.rs | 89 ++++++++++++++---------- tests/ui/non_zero_suggestions.stderr | 59 ++++++++++++++++ 4 files changed, 201 insertions(+), 38 deletions(-) create mode 100644 tests/ui/non_zero_suggestions.fixed create mode 100644 tests/ui/non_zero_suggestions.stderr diff --git a/clippy_lints/src/non_zero_suggestions.rs b/clippy_lints/src/non_zero_suggestions.rs index b9e7053db90..715d9eda6ee 100644 --- a/clippy_lints/src/non_zero_suggestions.rs +++ b/clippy_lints/src/non_zero_suggestions.rs @@ -9,16 +9,34 @@ use rustc_span::symbol::sym; declare_clippy_lint! { /// ### What it does + /// Checks for conversions from `NonZero` types to regular integer types, + /// and suggests using `NonZero` types for the target as well. /// /// ### Why is this bad? + /// Converting from `NonZero` types to regular integer types and then back to `NonZero` + /// types is less efficient and loses the type-safety guarantees provided by `NonZero` types. + /// Using `NonZero` types consistently can lead to more optimized code and prevent + /// certain classes of errors related to zero values. /// /// ### Example /// ```no_run - /// // example code where clippy issues a warning + /// use std::num::{NonZeroU32, NonZeroU64}; + /// + /// fn example(x: u64, y: NonZeroU32) { + /// // Bad: Converting NonZeroU32 to u64 unnecessarily + /// let r1 = x / u64::from(y.get()); + /// let r2 = x % u64::from(y.get()); + /// } /// ``` /// Use instead: /// ```no_run - /// // example code which does not raise clippy warning + /// use std::num::{NonZeroU32, NonZeroU64}; + /// + /// fn example(x: u64, y: NonZeroU32) { + /// // Good: Preserving the NonZero property + /// let r1 = x / NonZeroU64::from(y); + /// let r2 = x % NonZeroU64::from(y); + /// } /// ``` #[clippy::version = "1.81.0"] pub NON_ZERO_SUGGESTIONS, diff --git a/tests/ui/non_zero_suggestions.fixed b/tests/ui/non_zero_suggestions.fixed new file mode 100644 index 00000000000..b33de1ef03f --- /dev/null +++ b/tests/ui/non_zero_suggestions.fixed @@ -0,0 +1,69 @@ +#![warn(clippy::non_zero_suggestions)] + +use std::num::{NonZeroI16, NonZeroI8, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize}; + +fn main() { + // Positive test cases (lint should trigger) + + // U32 -> U64 + let x: u64 = 100; + let y = NonZeroU32::new(10).unwrap(); + let r1 = x / NonZeroU64::from(y); + let r2 = x % NonZeroU64::from(y); + + // U16 -> U32 + let a: u32 = 50; + let b = NonZeroU16::new(5).unwrap(); + let r3 = a / NonZeroU32::from(b); + + // I8 -> I16 + let c: i16 = 25; + let d = NonZeroI8::new(3).unwrap(); + let r4 = NonZeroI16::from(d); + + // Different operations + let m: u64 = 400; + let n = NonZeroU32::new(20).unwrap(); + let r5 = m / NonZeroU64::from(n); + + // Edge cases + + // Using the max value of a type + let max_u32 = NonZeroU32::new(u32::MAX).unwrap(); + let r6 = NonZeroU64::from(max_u32); + + // Chained method calls + let _ = NonZeroU64::from(NonZeroU32::new(10).unwrap()); + + // Negative test cases (lint should not trigger) + + // Same size types + let e: u32 = 200; + let f = NonZeroU32::new(20).unwrap(); + let r10 = e / f.get(); + + // Smaller to larger, but not NonZero + let g: u64 = 1000; + let h: u32 = 50; + let r11 = g / u64::from(h); + + // Using From correctly + let k: u64 = 300; + let l = NonZeroU32::new(15).unwrap(); + let r12 = k / NonZeroU64::from(l); +} + +// Additional function to test the lint in a different context +fn divide_numbers(x: u64, y: NonZeroU32) -> u64 { + x / NonZeroU64::from(y) +} + +struct Calculator { + value: u64, +} + +impl Calculator { + fn divide(&self, divisor: NonZeroU32) -> u64 { + self.value / NonZeroU64::from(divisor) + } +} diff --git a/tests/ui/non_zero_suggestions.rs b/tests/ui/non_zero_suggestions.rs index 1a5ee40dc3d..27089eaf86e 100644 --- a/tests/ui/non_zero_suggestions.rs +++ b/tests/ui/non_zero_suggestions.rs @@ -1,52 +1,69 @@ #![warn(clippy::non_zero_suggestions)] -use std::num::{ - NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroIsize, NonZeroU128, NonZeroU16, NonZeroU32, - NonZeroU64, NonZeroU8, NonZeroUsize, -}; +use std::num::{NonZeroI16, NonZeroI8, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize}; fn main() { - // Basic cases - let _ = u8::try_from(NonZeroU8::new(5).unwrap().get()); + // Positive test cases (lint should trigger) - let _ = u16::from(NonZeroU16::new(10).unwrap().get()); + // U32 -> U64 + let x: u64 = 100; + let y = NonZeroU32::new(10).unwrap(); + let r1 = x / u64::from(y.get()); + let r2 = x % u64::from(y.get()); - // Different integer types - let _ = u32::from(NonZeroU32::new(15).unwrap().get()); + // U16 -> U32 + let a: u32 = 50; + let b = NonZeroU16::new(5).unwrap(); + let r3 = a / u32::from(b.get()); - let _ = u64::from(NonZeroU64::new(20).unwrap().get()); + // I8 -> I16 + let c: i16 = 25; + let d = NonZeroI8::new(3).unwrap(); + let r4 = i16::from(d.get()); - let _ = u128::from(NonZeroU128::new(25).unwrap().get()); - - let _ = usize::from(NonZeroUsize::new(30).unwrap().get()); - - // Signed integer types - let _ = i8::try_from(NonZeroI8::new(-5).unwrap().get()); - - let _ = i16::from(NonZeroI16::new(-10).unwrap().get()); - - let _ = i32::from(NonZeroI32::new(-15).unwrap().get()); + // Different operations + let m: u64 = 400; + let n = NonZeroU32::new(20).unwrap(); + let r5 = m / u64::from(n.get()); // Edge cases - // Complex expression - let _ = u8::from(NonZeroU8::new(5).unwrap().get() + 1); + // Using the max value of a type + let max_u32 = NonZeroU32::new(u32::MAX).unwrap(); + let r6 = u64::from(max_u32.get()); - // Function call - fn get_non_zero() -> NonZeroU8 { - NonZeroU8::new(42).unwrap() - } - let _ = u8::from(get_non_zero().get()); + // Chained method calls + let _ = u64::from(NonZeroU32::new(10).unwrap().get()); - // Method chaining - let _ = u16::from(NonZeroU16::new(100).unwrap().get().checked_add(1).unwrap()); - // This should not trigger the lint + // Negative test cases (lint should not trigger) - // Different conversion methods - let _ = u32::try_from(NonZeroU32::new(200).unwrap().get()).unwrap(); + // Same size types + let e: u32 = 200; + let f = NonZeroU32::new(20).unwrap(); + let r10 = e / f.get(); - // Cases that should not trigger the lint - let _ = u8::from(5); - let _ = u16::from(10u8); - let _ = i32::try_from(40u32).unwrap(); + // Smaller to larger, but not NonZero + let g: u64 = 1000; + let h: u32 = 50; + let r11 = g / u64::from(h); + + // Using From correctly + let k: u64 = 300; + let l = NonZeroU32::new(15).unwrap(); + let r12 = k / NonZeroU64::from(l); +} + +// Additional function to test the lint in a different context +fn divide_numbers(x: u64, y: NonZeroU32) -> u64 { + x / u64::from(y.get()) +} + +struct Calculator { + value: u64, +} + +impl Calculator { + fn divide(&self, divisor: NonZeroU32) -> u64 { + self.value / u64::from(divisor.get()) + } } diff --git a/tests/ui/non_zero_suggestions.stderr b/tests/ui/non_zero_suggestions.stderr new file mode 100644 index 00000000000..b30f9dd1e5c --- /dev/null +++ b/tests/ui/non_zero_suggestions.stderr @@ -0,0 +1,59 @@ +error: Consider using `NonZeroU64::from()` for more efficient and type-safe conversion + --> tests/ui/non_zero_suggestions.rs:11:18 + | +LL | let r1 = x / u64::from(y.get()); + | ^^^^^^^^^^^^^^^^^^ help: Replace with: `NonZeroU64::from(y)` + | + = note: `-D clippy::non-zero-suggestions` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::non_zero_suggestions)]` + +error: Consider using `NonZeroU64::from()` for more efficient and type-safe conversion + --> tests/ui/non_zero_suggestions.rs:12:18 + | +LL | let r2 = x % u64::from(y.get()); + | ^^^^^^^^^^^^^^^^^^ help: Replace with: `NonZeroU64::from(y)` + +error: Consider using `NonZeroU32::from()` for more efficient and type-safe conversion + --> tests/ui/non_zero_suggestions.rs:17:18 + | +LL | let r3 = a / u32::from(b.get()); + | ^^^^^^^^^^^^^^^^^^ help: Replace with: `NonZeroU32::from(b)` + +error: Consider using `NonZeroI16::from()` for more efficient and type-safe conversion + --> tests/ui/non_zero_suggestions.rs:22:14 + | +LL | let r4 = i16::from(d.get()); + | ^^^^^^^^^^^^^^^^^^ help: Replace with: `NonZeroI16::from(d)` + +error: Consider using `NonZeroU64::from()` for more efficient and type-safe conversion + --> tests/ui/non_zero_suggestions.rs:27:18 + | +LL | let r5 = m / u64::from(n.get()); + | ^^^^^^^^^^^^^^^^^^ help: Replace with: `NonZeroU64::from(n)` + +error: Consider using `NonZeroU64::from()` for more efficient and type-safe conversion + --> tests/ui/non_zero_suggestions.rs:33:14 + | +LL | let r6 = u64::from(max_u32.get()); + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: Replace with: `NonZeroU64::from(max_u32)` + +error: Consider using `NonZeroU64::from()` for more efficient and type-safe conversion + --> tests/ui/non_zero_suggestions.rs:36:13 + | +LL | let _ = u64::from(NonZeroU32::new(10).unwrap().get()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Replace with: `NonZeroU64::from(NonZeroU32::new(10).unwrap())` + +error: Consider using `NonZeroU64::from()` for more efficient and type-safe conversion + --> tests/ui/non_zero_suggestions.rs:58:9 + | +LL | x / u64::from(y.get()) + | ^^^^^^^^^^^^^^^^^^ help: Replace with: `NonZeroU64::from(y)` + +error: Consider using `NonZeroU64::from()` for more efficient and type-safe conversion + --> tests/ui/non_zero_suggestions.rs:67:22 + | +LL | self.value / u64::from(divisor.get()) + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: Replace with: `NonZeroU64::from(divisor)` + +error: aborting due to 9 previous errors + From 6f01273d5d2acec2a726f2115fbf557967c2336a Mon Sep 17 00:00:00 2001 From: Samarth1696 Date: Fri, 26 Jul 2024 17:46:41 +0530 Subject: [PATCH 093/683] dogfood test passed --- clippy_lints/src/non_zero_suggestions.rs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/clippy_lints/src/non_zero_suggestions.rs b/clippy_lints/src/non_zero_suggestions.rs index 715d9eda6ee..e652f6f5108 100644 --- a/clippy_lints/src/non_zero_suggestions.rs +++ b/clippy_lints/src/non_zero_suggestions.rs @@ -87,15 +87,12 @@ fn suggest_non_zero_conversion( target_non_zero_type: &str, arg_snippet: &str, ) { - let suggestion = format!("{}::{}({})", target_non_zero_type, fn_name, arg_snippet); + let suggestion = format!("{target_non_zero_type}::{fn_name}({arg_snippet})"); span_lint_and_sugg( cx, NON_ZERO_SUGGESTIONS, expr.span, - format!( - "Consider using `{}::{}()` for more efficient and type-safe conversion", - target_non_zero_type, fn_name - ), + format!("Consider using `{target_non_zero_type}::{fn_name}()` for more efficient and type-safe conversion"), "Replace with", suggestion, Applicability::MachineApplicable, From 0f99aa992ea19b0148767c137ff1a936d58b65e0 Mon Sep 17 00:00:00 2001 From: Samarth1696 Date: Fri, 26 Jul 2024 18:16:08 +0530 Subject: [PATCH 094/683] all tests passed --- clippy_lints/src/non_zero_suggestions.rs | 4 +-- tests/ui/non_zero_suggestions.stderr | 36 ++++++++++++------------ 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/clippy_lints/src/non_zero_suggestions.rs b/clippy_lints/src/non_zero_suggestions.rs index e652f6f5108..fc2920868d4 100644 --- a/clippy_lints/src/non_zero_suggestions.rs +++ b/clippy_lints/src/non_zero_suggestions.rs @@ -92,8 +92,8 @@ fn suggest_non_zero_conversion( cx, NON_ZERO_SUGGESTIONS, expr.span, - format!("Consider using `{target_non_zero_type}::{fn_name}()` for more efficient and type-safe conversion"), - "Replace with", + format!("consider using `{target_non_zero_type}::{fn_name}()` for more efficient and type-safe conversion"), + "replace with", suggestion, Applicability::MachineApplicable, ); diff --git a/tests/ui/non_zero_suggestions.stderr b/tests/ui/non_zero_suggestions.stderr index b30f9dd1e5c..4c86720c308 100644 --- a/tests/ui/non_zero_suggestions.stderr +++ b/tests/ui/non_zero_suggestions.stderr @@ -1,59 +1,59 @@ -error: Consider using `NonZeroU64::from()` for more efficient and type-safe conversion +error: consider using `NonZeroU64::from()` for more efficient and type-safe conversion --> tests/ui/non_zero_suggestions.rs:11:18 | LL | let r1 = x / u64::from(y.get()); - | ^^^^^^^^^^^^^^^^^^ help: Replace with: `NonZeroU64::from(y)` + | ^^^^^^^^^^^^^^^^^^ help: replace with: `NonZeroU64::from(y)` | = note: `-D clippy::non-zero-suggestions` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::non_zero_suggestions)]` -error: Consider using `NonZeroU64::from()` for more efficient and type-safe conversion +error: consider using `NonZeroU64::from()` for more efficient and type-safe conversion --> tests/ui/non_zero_suggestions.rs:12:18 | LL | let r2 = x % u64::from(y.get()); - | ^^^^^^^^^^^^^^^^^^ help: Replace with: `NonZeroU64::from(y)` + | ^^^^^^^^^^^^^^^^^^ help: replace with: `NonZeroU64::from(y)` -error: Consider using `NonZeroU32::from()` for more efficient and type-safe conversion +error: consider using `NonZeroU32::from()` for more efficient and type-safe conversion --> tests/ui/non_zero_suggestions.rs:17:18 | LL | let r3 = a / u32::from(b.get()); - | ^^^^^^^^^^^^^^^^^^ help: Replace with: `NonZeroU32::from(b)` + | ^^^^^^^^^^^^^^^^^^ help: replace with: `NonZeroU32::from(b)` -error: Consider using `NonZeroI16::from()` for more efficient and type-safe conversion +error: consider using `NonZeroI16::from()` for more efficient and type-safe conversion --> tests/ui/non_zero_suggestions.rs:22:14 | LL | let r4 = i16::from(d.get()); - | ^^^^^^^^^^^^^^^^^^ help: Replace with: `NonZeroI16::from(d)` + | ^^^^^^^^^^^^^^^^^^ help: replace with: `NonZeroI16::from(d)` -error: Consider using `NonZeroU64::from()` for more efficient and type-safe conversion +error: consider using `NonZeroU64::from()` for more efficient and type-safe conversion --> tests/ui/non_zero_suggestions.rs:27:18 | LL | let r5 = m / u64::from(n.get()); - | ^^^^^^^^^^^^^^^^^^ help: Replace with: `NonZeroU64::from(n)` + | ^^^^^^^^^^^^^^^^^^ help: replace with: `NonZeroU64::from(n)` -error: Consider using `NonZeroU64::from()` for more efficient and type-safe conversion +error: consider using `NonZeroU64::from()` for more efficient and type-safe conversion --> tests/ui/non_zero_suggestions.rs:33:14 | LL | let r6 = u64::from(max_u32.get()); - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: Replace with: `NonZeroU64::from(max_u32)` + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `NonZeroU64::from(max_u32)` -error: Consider using `NonZeroU64::from()` for more efficient and type-safe conversion +error: consider using `NonZeroU64::from()` for more efficient and type-safe conversion --> tests/ui/non_zero_suggestions.rs:36:13 | LL | let _ = u64::from(NonZeroU32::new(10).unwrap().get()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Replace with: `NonZeroU64::from(NonZeroU32::new(10).unwrap())` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `NonZeroU64::from(NonZeroU32::new(10).unwrap())` -error: Consider using `NonZeroU64::from()` for more efficient and type-safe conversion +error: consider using `NonZeroU64::from()` for more efficient and type-safe conversion --> tests/ui/non_zero_suggestions.rs:58:9 | LL | x / u64::from(y.get()) - | ^^^^^^^^^^^^^^^^^^ help: Replace with: `NonZeroU64::from(y)` + | ^^^^^^^^^^^^^^^^^^ help: replace with: `NonZeroU64::from(y)` -error: Consider using `NonZeroU64::from()` for more efficient and type-safe conversion +error: consider using `NonZeroU64::from()` for more efficient and type-safe conversion --> tests/ui/non_zero_suggestions.rs:67:22 | LL | self.value / u64::from(divisor.get()) - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: Replace with: `NonZeroU64::from(divisor)` + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `NonZeroU64::from(divisor)` error: aborting due to 9 previous errors From bed44418eca84e81c7efa7a3ee45f450b8a834f4 Mon Sep 17 00:00:00 2001 From: Samarth1696 Date: Sat, 27 Jul 2024 02:35:16 +0530 Subject: [PATCH 095/683] refactored the code --- clippy_lints/src/non_zero_suggestions.rs | 31 ++++++++++++------------ 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/clippy_lints/src/non_zero_suggestions.rs b/clippy_lints/src/non_zero_suggestions.rs index fc2920868d4..1624c365ee9 100644 --- a/clippy_lints/src/non_zero_suggestions.rs +++ b/clippy_lints/src/non_zero_suggestions.rs @@ -48,23 +48,22 @@ declare_lint_pass!(NonZeroSuggestions => [NON_ZERO_SUGGESTIONS]); impl<'tcx> LateLintPass<'tcx> for NonZeroSuggestions { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { - if let ExprKind::Call(func, [arg]) = expr.kind { - if let ExprKind::Path(qpath) = &func.kind { - if let Some(def_id) = cx.qpath_res(qpath, func.hir_id).opt_def_id() { - let fn_name = cx.tcx.item_name(def_id); - let target_ty = cx.typeck_results().expr_ty(expr); + if let ExprKind::Call(func, [arg]) = expr.kind + && let ExprKind::Path(qpath) = &func.kind + && let Some(def_id) = cx.qpath_res(qpath, func.hir_id).opt_def_id() + && let ExprKind::MethodCall(rcv_path, receiver, _, _) = &arg.kind + { + let fn_name = cx.tcx.item_name(def_id); + let target_ty = cx.typeck_results().expr_ty(expr); + let receiver_ty = cx.typeck_results().expr_ty(receiver); - if let ExprKind::MethodCall(rcv_path, receiver, _, _) = &arg.kind { - let receiver_ty = cx.typeck_results().expr_ty(receiver); - if let ty::Adt(adt_def, _) = receiver_ty.kind() { - if adt_def.is_struct() && cx.tcx.get_diagnostic_name(adt_def.did()) == Some(sym::NonZero) { - if let Some(target_non_zero_type) = get_target_non_zero_type(target_ty) { - let arg_snippet = get_arg_snippet(cx, arg, rcv_path); - suggest_non_zero_conversion(cx, expr, fn_name, target_non_zero_type, &arg_snippet); - } - } - } - } + if let ty::Adt(adt_def, _) = receiver_ty.kind() + && adt_def.is_struct() + && cx.tcx.get_diagnostic_name(adt_def.did()) == Some(sym::NonZero) + { + if let Some(target_non_zero_type) = get_target_non_zero_type(target_ty) { + let arg_snippet = get_arg_snippet(cx, arg, rcv_path); + suggest_non_zero_conversion(cx, expr, fn_name, target_non_zero_type, &arg_snippet); } } } From c6c74083a803f32ffe2447fdcd0afaafaa03179c Mon Sep 17 00:00:00 2001 From: Samarth1696 Date: Sat, 27 Jul 2024 03:15:40 +0530 Subject: [PATCH 096/683] error notations added --- tests/ui/non_zero_suggestions.fixed | 25 +++++++++++++++++++------ tests/ui/non_zero_suggestions.rs | 25 +++++++++++++++++++------ tests/ui/non_zero_suggestions.stderr | 26 ++++++++++++++++---------- 3 files changed, 54 insertions(+), 22 deletions(-) diff --git a/tests/ui/non_zero_suggestions.fixed b/tests/ui/non_zero_suggestions.fixed index b33de1ef03f..d7e6b19edc1 100644 --- a/tests/ui/non_zero_suggestions.fixed +++ b/tests/ui/non_zero_suggestions.fixed @@ -3,40 +3,45 @@ use std::num::{NonZeroI16, NonZeroI8, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize}; fn main() { - // Positive test cases (lint should trigger) - + /// Positive test cases (lint should trigger) // U32 -> U64 let x: u64 = 100; let y = NonZeroU32::new(10).unwrap(); let r1 = x / NonZeroU64::from(y); + //~^ ERROR: consider using `NonZeroU64::from()` for more efficient and type-safe conversion + let r2 = x % NonZeroU64::from(y); + //~^ ERROR: consider using `NonZeroU64::from()` for more efficient and type-safe conversion // U16 -> U32 let a: u32 = 50; let b = NonZeroU16::new(5).unwrap(); let r3 = a / NonZeroU32::from(b); + //~^ ERROR: consider using `NonZeroU32::from()` for more efficient and type-safe conversion // I8 -> I16 let c: i16 = 25; let d = NonZeroI8::new(3).unwrap(); let r4 = NonZeroI16::from(d); + //~^ ERROR: consider using `NonZeroI16::from()` for more efficient and type-safe conversion // Different operations let m: u64 = 400; let n = NonZeroU32::new(20).unwrap(); let r5 = m / NonZeroU64::from(n); + //~^ ERROR: consider using `NonZeroU64::from()` for more efficient and type-safe conversion - // Edge cases - + /// Edge cases // Using the max value of a type let max_u32 = NonZeroU32::new(u32::MAX).unwrap(); let r6 = NonZeroU64::from(max_u32); + //~^ ERROR: consider using `NonZeroU64::from()` for more efficient and type-safe conversion // Chained method calls let _ = NonZeroU64::from(NonZeroU32::new(10).unwrap()); + //~^ ERROR: consider using `NonZeroU64::from()` for more efficient and type-safe conversion - // Negative test cases (lint should not trigger) - + /// Negative test cases (lint should not trigger) // Same size types let e: u32 = 200; let f = NonZeroU32::new(20).unwrap(); @@ -56,8 +61,16 @@ fn main() { // Additional function to test the lint in a different context fn divide_numbers(x: u64, y: NonZeroU32) -> u64 { x / NonZeroU64::from(y) + //~^ ERROR: consider using `NonZeroU64::from()` for more efficient and type-safe conversion } +fn no_bin_exp(x: u64, y: NonZeroU32) -> u64 { + NonZeroU64::from(y) + //~^ ERROR: consider using `NonZeroU64::from()` for more efficient and type-safe conversion +} + +fn some_fn_that_only_takes_u64(_: u64) {} + struct Calculator { value: u64, } diff --git a/tests/ui/non_zero_suggestions.rs b/tests/ui/non_zero_suggestions.rs index 27089eaf86e..8f256dabcb8 100644 --- a/tests/ui/non_zero_suggestions.rs +++ b/tests/ui/non_zero_suggestions.rs @@ -3,40 +3,45 @@ use std::num::{NonZeroI16, NonZeroI8, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize}; fn main() { - // Positive test cases (lint should trigger) - + /// Positive test cases (lint should trigger) // U32 -> U64 let x: u64 = 100; let y = NonZeroU32::new(10).unwrap(); let r1 = x / u64::from(y.get()); + //~^ ERROR: consider using `NonZeroU64::from()` for more efficient and type-safe conversion + let r2 = x % u64::from(y.get()); + //~^ ERROR: consider using `NonZeroU64::from()` for more efficient and type-safe conversion // U16 -> U32 let a: u32 = 50; let b = NonZeroU16::new(5).unwrap(); let r3 = a / u32::from(b.get()); + //~^ ERROR: consider using `NonZeroU32::from()` for more efficient and type-safe conversion // I8 -> I16 let c: i16 = 25; let d = NonZeroI8::new(3).unwrap(); let r4 = i16::from(d.get()); + //~^ ERROR: consider using `NonZeroI16::from()` for more efficient and type-safe conversion // Different operations let m: u64 = 400; let n = NonZeroU32::new(20).unwrap(); let r5 = m / u64::from(n.get()); + //~^ ERROR: consider using `NonZeroU64::from()` for more efficient and type-safe conversion - // Edge cases - + /// Edge cases // Using the max value of a type let max_u32 = NonZeroU32::new(u32::MAX).unwrap(); let r6 = u64::from(max_u32.get()); + //~^ ERROR: consider using `NonZeroU64::from()` for more efficient and type-safe conversion // Chained method calls let _ = u64::from(NonZeroU32::new(10).unwrap().get()); + //~^ ERROR: consider using `NonZeroU64::from()` for more efficient and type-safe conversion - // Negative test cases (lint should not trigger) - + /// Negative test cases (lint should not trigger) // Same size types let e: u32 = 200; let f = NonZeroU32::new(20).unwrap(); @@ -56,8 +61,16 @@ fn main() { // Additional function to test the lint in a different context fn divide_numbers(x: u64, y: NonZeroU32) -> u64 { x / u64::from(y.get()) + //~^ ERROR: consider using `NonZeroU64::from()` for more efficient and type-safe conversion } +fn no_bin_exp(x: u64, y: NonZeroU32) -> u64 { + u64::from(y.get()) + //~^ ERROR: consider using `NonZeroU64::from()` for more efficient and type-safe conversion +} + +fn some_fn_that_only_takes_u64(_: u64) {} + struct Calculator { value: u64, } diff --git a/tests/ui/non_zero_suggestions.stderr b/tests/ui/non_zero_suggestions.stderr index 4c86720c308..b231c8d216e 100644 --- a/tests/ui/non_zero_suggestions.stderr +++ b/tests/ui/non_zero_suggestions.stderr @@ -1,5 +1,5 @@ error: consider using `NonZeroU64::from()` for more efficient and type-safe conversion - --> tests/ui/non_zero_suggestions.rs:11:18 + --> tests/ui/non_zero_suggestions.rs:10:18 | LL | let r1 = x / u64::from(y.get()); | ^^^^^^^^^^^^^^^^^^ help: replace with: `NonZeroU64::from(y)` @@ -8,52 +8,58 @@ LL | let r1 = x / u64::from(y.get()); = help: to override `-D warnings` add `#[allow(clippy::non_zero_suggestions)]` error: consider using `NonZeroU64::from()` for more efficient and type-safe conversion - --> tests/ui/non_zero_suggestions.rs:12:18 + --> tests/ui/non_zero_suggestions.rs:13:18 | LL | let r2 = x % u64::from(y.get()); | ^^^^^^^^^^^^^^^^^^ help: replace with: `NonZeroU64::from(y)` error: consider using `NonZeroU32::from()` for more efficient and type-safe conversion - --> tests/ui/non_zero_suggestions.rs:17:18 + --> tests/ui/non_zero_suggestions.rs:19:18 | LL | let r3 = a / u32::from(b.get()); | ^^^^^^^^^^^^^^^^^^ help: replace with: `NonZeroU32::from(b)` error: consider using `NonZeroI16::from()` for more efficient and type-safe conversion - --> tests/ui/non_zero_suggestions.rs:22:14 + --> tests/ui/non_zero_suggestions.rs:25:14 | LL | let r4 = i16::from(d.get()); | ^^^^^^^^^^^^^^^^^^ help: replace with: `NonZeroI16::from(d)` error: consider using `NonZeroU64::from()` for more efficient and type-safe conversion - --> tests/ui/non_zero_suggestions.rs:27:18 + --> tests/ui/non_zero_suggestions.rs:31:18 | LL | let r5 = m / u64::from(n.get()); | ^^^^^^^^^^^^^^^^^^ help: replace with: `NonZeroU64::from(n)` error: consider using `NonZeroU64::from()` for more efficient and type-safe conversion - --> tests/ui/non_zero_suggestions.rs:33:14 + --> tests/ui/non_zero_suggestions.rs:37:14 | LL | let r6 = u64::from(max_u32.get()); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `NonZeroU64::from(max_u32)` error: consider using `NonZeroU64::from()` for more efficient and type-safe conversion - --> tests/ui/non_zero_suggestions.rs:36:13 + --> tests/ui/non_zero_suggestions.rs:41:13 | LL | let _ = u64::from(NonZeroU32::new(10).unwrap().get()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `NonZeroU64::from(NonZeroU32::new(10).unwrap())` error: consider using `NonZeroU64::from()` for more efficient and type-safe conversion - --> tests/ui/non_zero_suggestions.rs:58:9 + --> tests/ui/non_zero_suggestions.rs:63:9 | LL | x / u64::from(y.get()) | ^^^^^^^^^^^^^^^^^^ help: replace with: `NonZeroU64::from(y)` error: consider using `NonZeroU64::from()` for more efficient and type-safe conversion - --> tests/ui/non_zero_suggestions.rs:67:22 + --> tests/ui/non_zero_suggestions.rs:68:5 + | +LL | u64::from(y.get()) + | ^^^^^^^^^^^^^^^^^^ help: replace with: `NonZeroU64::from(y)` + +error: consider using `NonZeroU64::from()` for more efficient and type-safe conversion + --> tests/ui/non_zero_suggestions.rs:80:22 | LL | self.value / u64::from(divisor.get()) | ^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `NonZeroU64::from(divisor)` -error: aborting due to 9 previous errors +error: aborting due to 10 previous errors From d43acb803f1bdabfd3761e54bd9509f8b19fb16a Mon Sep 17 00:00:00 2001 From: Samarth1696 Date: Thu, 1 Aug 2024 17:29:07 +0530 Subject: [PATCH 097/683] Added checks for binary expr and added different test cases for unfixable cases --- clippy_lints/src/non_zero_suggestions.rs | 53 +++++++++++++------ tests/ui/non_zero_suggestions.fixed | 45 +++++----------- tests/ui/non_zero_suggestions.rs | 45 +++++----------- tests/ui/non_zero_suggestions.stderr | 44 ++++----------- tests/ui/non_zero_suggestions_unfixable.rs | 20 +++++++ .../ui/non_zero_suggestions_unfixable.stderr | 23 ++++++++ 6 files changed, 118 insertions(+), 112 deletions(-) create mode 100644 tests/ui/non_zero_suggestions_unfixable.rs create mode 100644 tests/ui/non_zero_suggestions_unfixable.stderr diff --git a/clippy_lints/src/non_zero_suggestions.rs b/clippy_lints/src/non_zero_suggestions.rs index 1624c365ee9..808de147d72 100644 --- a/clippy_lints/src/non_zero_suggestions.rs +++ b/clippy_lints/src/non_zero_suggestions.rs @@ -1,5 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet; +use rustc_ast::ast::BinOpKind; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; @@ -48,23 +49,42 @@ declare_lint_pass!(NonZeroSuggestions => [NON_ZERO_SUGGESTIONS]); impl<'tcx> LateLintPass<'tcx> for NonZeroSuggestions { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { - if let ExprKind::Call(func, [arg]) = expr.kind - && let ExprKind::Path(qpath) = &func.kind - && let Some(def_id) = cx.qpath_res(qpath, func.hir_id).opt_def_id() - && let ExprKind::MethodCall(rcv_path, receiver, _, _) = &arg.kind + if let ExprKind::Binary(op, _, rhs) = expr.kind + && matches!(op.node, BinOpKind::Div | BinOpKind::Rem) { - let fn_name = cx.tcx.item_name(def_id); - let target_ty = cx.typeck_results().expr_ty(expr); - let receiver_ty = cx.typeck_results().expr_ty(receiver); + check_non_zero_conversion(cx, rhs, Applicability::MachineApplicable); + } else { + // Check if the parent expression is a binary operation + let parent_is_binary = cx.tcx.hir().parent_iter(expr.hir_id).any(|(_, node)| { + matches!(node, rustc_hir::Node::Expr(parent_expr) if matches!(parent_expr.kind, ExprKind::Binary(..))) + }); - if let ty::Adt(adt_def, _) = receiver_ty.kind() - && adt_def.is_struct() - && cx.tcx.get_diagnostic_name(adt_def.did()) == Some(sym::NonZero) - { - if let Some(target_non_zero_type) = get_target_non_zero_type(target_ty) { - let arg_snippet = get_arg_snippet(cx, arg, rcv_path); - suggest_non_zero_conversion(cx, expr, fn_name, target_non_zero_type, &arg_snippet); - } + if !parent_is_binary { + check_non_zero_conversion(cx, expr, Applicability::MaybeIncorrect); + } + } + } +} + +fn check_non_zero_conversion(cx: &LateContext<'_>, expr: &Expr<'_>, applicability: Applicability) { + // Check if the expression is a function call with one argument + if let ExprKind::Call(func, [arg]) = expr.kind + && let ExprKind::Path(qpath) = &func.kind + && let Some(def_id) = cx.qpath_res(qpath, func.hir_id).opt_def_id() + && let ExprKind::MethodCall(rcv_path, receiver, _, _) = &arg.kind + { + let fn_name = cx.tcx.item_name(def_id); + let target_ty = cx.typeck_results().expr_ty(expr); + let receiver_ty = cx.typeck_results().expr_ty(receiver); + + // Check if the receiver type is a NonZero type + if let ty::Adt(adt_def, _) = receiver_ty.kind() + && adt_def.is_struct() + && cx.tcx.get_diagnostic_name(adt_def.did()) == Some(sym::NonZero) + { + if let Some(target_non_zero_type) = get_target_non_zero_type(target_ty) { + let arg_snippet = get_arg_snippet(cx, arg, rcv_path); + suggest_non_zero_conversion(cx, expr, fn_name, target_non_zero_type, &arg_snippet, applicability); } } } @@ -85,6 +105,7 @@ fn suggest_non_zero_conversion( fn_name: rustc_span::Symbol, target_non_zero_type: &str, arg_snippet: &str, + applicability: Applicability, ) { let suggestion = format!("{target_non_zero_type}::{fn_name}({arg_snippet})"); span_lint_and_sugg( @@ -94,7 +115,7 @@ fn suggest_non_zero_conversion( format!("consider using `{target_non_zero_type}::{fn_name}()` for more efficient and type-safe conversion"), "replace with", suggestion, - Applicability::MachineApplicable, + applicability, ); } diff --git a/tests/ui/non_zero_suggestions.fixed b/tests/ui/non_zero_suggestions.fixed index d7e6b19edc1..9851063782e 100644 --- a/tests/ui/non_zero_suggestions.fixed +++ b/tests/ui/non_zero_suggestions.fixed @@ -1,5 +1,4 @@ #![warn(clippy::non_zero_suggestions)] - use std::num::{NonZeroI16, NonZeroI8, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize}; fn main() { @@ -19,43 +18,33 @@ fn main() { let r3 = a / NonZeroU32::from(b); //~^ ERROR: consider using `NonZeroU32::from()` for more efficient and type-safe conversion - // I8 -> I16 - let c: i16 = 25; - let d = NonZeroI8::new(3).unwrap(); - let r4 = NonZeroI16::from(d); - //~^ ERROR: consider using `NonZeroI16::from()` for more efficient and type-safe conversion - - // Different operations - let m: u64 = 400; - let n = NonZeroU32::new(20).unwrap(); - let r5 = m / NonZeroU64::from(n); - //~^ ERROR: consider using `NonZeroU64::from()` for more efficient and type-safe conversion - - /// Edge cases - // Using the max value of a type - let max_u32 = NonZeroU32::new(u32::MAX).unwrap(); - let r6 = NonZeroU64::from(max_u32); - //~^ ERROR: consider using `NonZeroU64::from()` for more efficient and type-safe conversion - - // Chained method calls - let _ = NonZeroU64::from(NonZeroU32::new(10).unwrap()); + let x = NonZeroU64::from(NonZeroU32::new(5).unwrap()); //~^ ERROR: consider using `NonZeroU64::from()` for more efficient and type-safe conversion /// Negative test cases (lint should not trigger) + // Left hand side expressions should not be triggered + let c: u32 = 50; + let d = NonZeroU16::new(5).unwrap(); + let r4 = u32::from(b.get()) / a; + + // Should not trigger for any other operand other than `/` and `%` + let r5 = a + u32::from(b.get()); + let r6 = a - u32::from(b.get()); + // Same size types let e: u32 = 200; let f = NonZeroU32::new(20).unwrap(); - let r10 = e / f.get(); + let r7 = e / f.get(); // Smaller to larger, but not NonZero let g: u64 = 1000; let h: u32 = 50; - let r11 = g / u64::from(h); + let r8 = g / u64::from(h); // Using From correctly let k: u64 = 300; let l = NonZeroU32::new(15).unwrap(); - let r12 = k / NonZeroU64::from(l); + let r9 = k / NonZeroU64::from(l); } // Additional function to test the lint in a different context @@ -64,13 +53,6 @@ fn divide_numbers(x: u64, y: NonZeroU32) -> u64 { //~^ ERROR: consider using `NonZeroU64::from()` for more efficient and type-safe conversion } -fn no_bin_exp(x: u64, y: NonZeroU32) -> u64 { - NonZeroU64::from(y) - //~^ ERROR: consider using `NonZeroU64::from()` for more efficient and type-safe conversion -} - -fn some_fn_that_only_takes_u64(_: u64) {} - struct Calculator { value: u64, } @@ -78,5 +60,6 @@ struct Calculator { impl Calculator { fn divide(&self, divisor: NonZeroU32) -> u64 { self.value / NonZeroU64::from(divisor) + //~^ ERROR: consider using `NonZeroU64::from()` for more efficient and type-safe conversion } } diff --git a/tests/ui/non_zero_suggestions.rs b/tests/ui/non_zero_suggestions.rs index 8f256dabcb8..1605c459248 100644 --- a/tests/ui/non_zero_suggestions.rs +++ b/tests/ui/non_zero_suggestions.rs @@ -1,5 +1,4 @@ #![warn(clippy::non_zero_suggestions)] - use std::num::{NonZeroI16, NonZeroI8, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize}; fn main() { @@ -19,43 +18,33 @@ fn main() { let r3 = a / u32::from(b.get()); //~^ ERROR: consider using `NonZeroU32::from()` for more efficient and type-safe conversion - // I8 -> I16 - let c: i16 = 25; - let d = NonZeroI8::new(3).unwrap(); - let r4 = i16::from(d.get()); - //~^ ERROR: consider using `NonZeroI16::from()` for more efficient and type-safe conversion - - // Different operations - let m: u64 = 400; - let n = NonZeroU32::new(20).unwrap(); - let r5 = m / u64::from(n.get()); - //~^ ERROR: consider using `NonZeroU64::from()` for more efficient and type-safe conversion - - /// Edge cases - // Using the max value of a type - let max_u32 = NonZeroU32::new(u32::MAX).unwrap(); - let r6 = u64::from(max_u32.get()); - //~^ ERROR: consider using `NonZeroU64::from()` for more efficient and type-safe conversion - - // Chained method calls - let _ = u64::from(NonZeroU32::new(10).unwrap().get()); + let x = u64::from(NonZeroU32::new(5).unwrap().get()); //~^ ERROR: consider using `NonZeroU64::from()` for more efficient and type-safe conversion /// Negative test cases (lint should not trigger) + // Left hand side expressions should not be triggered + let c: u32 = 50; + let d = NonZeroU16::new(5).unwrap(); + let r4 = u32::from(b.get()) / a; + + // Should not trigger for any other operand other than `/` and `%` + let r5 = a + u32::from(b.get()); + let r6 = a - u32::from(b.get()); + // Same size types let e: u32 = 200; let f = NonZeroU32::new(20).unwrap(); - let r10 = e / f.get(); + let r7 = e / f.get(); // Smaller to larger, but not NonZero let g: u64 = 1000; let h: u32 = 50; - let r11 = g / u64::from(h); + let r8 = g / u64::from(h); // Using From correctly let k: u64 = 300; let l = NonZeroU32::new(15).unwrap(); - let r12 = k / NonZeroU64::from(l); + let r9 = k / NonZeroU64::from(l); } // Additional function to test the lint in a different context @@ -64,13 +53,6 @@ fn divide_numbers(x: u64, y: NonZeroU32) -> u64 { //~^ ERROR: consider using `NonZeroU64::from()` for more efficient and type-safe conversion } -fn no_bin_exp(x: u64, y: NonZeroU32) -> u64 { - u64::from(y.get()) - //~^ ERROR: consider using `NonZeroU64::from()` for more efficient and type-safe conversion -} - -fn some_fn_that_only_takes_u64(_: u64) {} - struct Calculator { value: u64, } @@ -78,5 +60,6 @@ struct Calculator { impl Calculator { fn divide(&self, divisor: NonZeroU32) -> u64 { self.value / u64::from(divisor.get()) + //~^ ERROR: consider using `NonZeroU64::from()` for more efficient and type-safe conversion } } diff --git a/tests/ui/non_zero_suggestions.stderr b/tests/ui/non_zero_suggestions.stderr index b231c8d216e..7a57f7983be 100644 --- a/tests/ui/non_zero_suggestions.stderr +++ b/tests/ui/non_zero_suggestions.stderr @@ -1,5 +1,5 @@ error: consider using `NonZeroU64::from()` for more efficient and type-safe conversion - --> tests/ui/non_zero_suggestions.rs:10:18 + --> tests/ui/non_zero_suggestions.rs:9:18 | LL | let r1 = x / u64::from(y.get()); | ^^^^^^^^^^^^^^^^^^ help: replace with: `NonZeroU64::from(y)` @@ -8,58 +8,34 @@ LL | let r1 = x / u64::from(y.get()); = help: to override `-D warnings` add `#[allow(clippy::non_zero_suggestions)]` error: consider using `NonZeroU64::from()` for more efficient and type-safe conversion - --> tests/ui/non_zero_suggestions.rs:13:18 + --> tests/ui/non_zero_suggestions.rs:12:18 | LL | let r2 = x % u64::from(y.get()); | ^^^^^^^^^^^^^^^^^^ help: replace with: `NonZeroU64::from(y)` error: consider using `NonZeroU32::from()` for more efficient and type-safe conversion - --> tests/ui/non_zero_suggestions.rs:19:18 + --> tests/ui/non_zero_suggestions.rs:18:18 | LL | let r3 = a / u32::from(b.get()); | ^^^^^^^^^^^^^^^^^^ help: replace with: `NonZeroU32::from(b)` -error: consider using `NonZeroI16::from()` for more efficient and type-safe conversion - --> tests/ui/non_zero_suggestions.rs:25:14 +error: consider using `NonZeroU64::from()` for more efficient and type-safe conversion + --> tests/ui/non_zero_suggestions.rs:21:13 | -LL | let r4 = i16::from(d.get()); - | ^^^^^^^^^^^^^^^^^^ help: replace with: `NonZeroI16::from(d)` +LL | let x = u64::from(NonZeroU32::new(5).unwrap().get()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `NonZeroU64::from(NonZeroU32::new(5).unwrap())` error: consider using `NonZeroU64::from()` for more efficient and type-safe conversion - --> tests/ui/non_zero_suggestions.rs:31:18 - | -LL | let r5 = m / u64::from(n.get()); - | ^^^^^^^^^^^^^^^^^^ help: replace with: `NonZeroU64::from(n)` - -error: consider using `NonZeroU64::from()` for more efficient and type-safe conversion - --> tests/ui/non_zero_suggestions.rs:37:14 - | -LL | let r6 = u64::from(max_u32.get()); - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `NonZeroU64::from(max_u32)` - -error: consider using `NonZeroU64::from()` for more efficient and type-safe conversion - --> tests/ui/non_zero_suggestions.rs:41:13 - | -LL | let _ = u64::from(NonZeroU32::new(10).unwrap().get()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `NonZeroU64::from(NonZeroU32::new(10).unwrap())` - -error: consider using `NonZeroU64::from()` for more efficient and type-safe conversion - --> tests/ui/non_zero_suggestions.rs:63:9 + --> tests/ui/non_zero_suggestions.rs:52:9 | LL | x / u64::from(y.get()) | ^^^^^^^^^^^^^^^^^^ help: replace with: `NonZeroU64::from(y)` error: consider using `NonZeroU64::from()` for more efficient and type-safe conversion - --> tests/ui/non_zero_suggestions.rs:68:5 - | -LL | u64::from(y.get()) - | ^^^^^^^^^^^^^^^^^^ help: replace with: `NonZeroU64::from(y)` - -error: consider using `NonZeroU64::from()` for more efficient and type-safe conversion - --> tests/ui/non_zero_suggestions.rs:80:22 + --> tests/ui/non_zero_suggestions.rs:62:22 | LL | self.value / u64::from(divisor.get()) | ^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `NonZeroU64::from(divisor)` -error: aborting due to 10 previous errors +error: aborting due to 6 previous errors diff --git a/tests/ui/non_zero_suggestions_unfixable.rs b/tests/ui/non_zero_suggestions_unfixable.rs new file mode 100644 index 00000000000..71f5f94dcc7 --- /dev/null +++ b/tests/ui/non_zero_suggestions_unfixable.rs @@ -0,0 +1,20 @@ +#![warn(clippy::non_zero_suggestions)] +//@no-rustfix +use std::num::{NonZeroI16, NonZeroI8, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize}; + +fn main() { + let x: u64 = u64::from(NonZeroU32::new(5).unwrap().get()); + //~^ ERROR: consider using `NonZeroU64::from()` for more efficient and type-safe conversion + + let n = NonZeroU32::new(20).unwrap(); + let y = u64::from(n.get()); + //~^ ERROR: consider using `NonZeroU64::from()` for more efficient and type-safe conversion + some_fn_that_only_takes_u64(y); +} + +fn return_non_zero(x: u64, y: NonZeroU32) -> u64 { + u64::from(y.get()) + //~^ ERROR: consider using `NonZeroU64::from()` for more efficient and type-safe conversion +} + +fn some_fn_that_only_takes_u64(_: u64) {} diff --git a/tests/ui/non_zero_suggestions_unfixable.stderr b/tests/ui/non_zero_suggestions_unfixable.stderr new file mode 100644 index 00000000000..5e22fddbb1a --- /dev/null +++ b/tests/ui/non_zero_suggestions_unfixable.stderr @@ -0,0 +1,23 @@ +error: consider using `NonZeroU64::from()` for more efficient and type-safe conversion + --> tests/ui/non_zero_suggestions_unfixable.rs:6:18 + | +LL | let x: u64 = u64::from(NonZeroU32::new(5).unwrap().get()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `NonZeroU64::from(NonZeroU32::new(5).unwrap())` + | + = note: `-D clippy::non-zero-suggestions` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::non_zero_suggestions)]` + +error: consider using `NonZeroU64::from()` for more efficient and type-safe conversion + --> tests/ui/non_zero_suggestions_unfixable.rs:10:13 + | +LL | let y = u64::from(n.get()); + | ^^^^^^^^^^^^^^^^^^ help: replace with: `NonZeroU64::from(n)` + +error: consider using `NonZeroU64::from()` for more efficient and type-safe conversion + --> tests/ui/non_zero_suggestions_unfixable.rs:16:5 + | +LL | u64::from(y.get()) + | ^^^^^^^^^^^^^^^^^^ help: replace with: `NonZeroU64::from(y)` + +error: aborting due to 3 previous errors + From af3346a85ffd0952f11581d83c6d6d3d57ae205b Mon Sep 17 00:00:00 2001 From: Samarth1696 Date: Sat, 31 Aug 2024 11:53:16 +0530 Subject: [PATCH 098/683] Check for get method and new test case in unfixable --- clippy_lints/src/non_zero_suggestions.rs | 1 + tests/ui/non_zero_suggestions_unfixable.rs | 3 +++ tests/ui/non_zero_suggestions_unfixable.stderr | 2 +- 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/clippy_lints/src/non_zero_suggestions.rs b/clippy_lints/src/non_zero_suggestions.rs index 808de147d72..90a9f2e994b 100644 --- a/clippy_lints/src/non_zero_suggestions.rs +++ b/clippy_lints/src/non_zero_suggestions.rs @@ -72,6 +72,7 @@ fn check_non_zero_conversion(cx: &LateContext<'_>, expr: &Expr<'_>, applicabilit && let ExprKind::Path(qpath) = &func.kind && let Some(def_id) = cx.qpath_res(qpath, func.hir_id).opt_def_id() && let ExprKind::MethodCall(rcv_path, receiver, _, _) = &arg.kind + && rcv_path.ident.name.as_str() == "get" { let fn_name = cx.tcx.item_name(def_id); let target_ty = cx.typeck_results().expr_ty(expr); diff --git a/tests/ui/non_zero_suggestions_unfixable.rs b/tests/ui/non_zero_suggestions_unfixable.rs index 71f5f94dcc7..4eb22a8d4c7 100644 --- a/tests/ui/non_zero_suggestions_unfixable.rs +++ b/tests/ui/non_zero_suggestions_unfixable.rs @@ -10,6 +10,9 @@ fn main() { let y = u64::from(n.get()); //~^ ERROR: consider using `NonZeroU64::from()` for more efficient and type-safe conversion some_fn_that_only_takes_u64(y); + + let m = NonZeroU32::try_from(1).unwrap(); + let _z: NonZeroU64 = m.into(); } fn return_non_zero(x: u64, y: NonZeroU32) -> u64 { diff --git a/tests/ui/non_zero_suggestions_unfixable.stderr b/tests/ui/non_zero_suggestions_unfixable.stderr index 5e22fddbb1a..787179f2a2d 100644 --- a/tests/ui/non_zero_suggestions_unfixable.stderr +++ b/tests/ui/non_zero_suggestions_unfixable.stderr @@ -14,7 +14,7 @@ LL | let y = u64::from(n.get()); | ^^^^^^^^^^^^^^^^^^ help: replace with: `NonZeroU64::from(n)` error: consider using `NonZeroU64::from()` for more efficient and type-safe conversion - --> tests/ui/non_zero_suggestions_unfixable.rs:16:5 + --> tests/ui/non_zero_suggestions_unfixable.rs:19:5 | LL | u64::from(y.get()) | ^^^^^^^^^^^^^^^^^^ help: replace with: `NonZeroU64::from(y)` From 896ccaa8acddcca4f44b7627210533d0f77459df Mon Sep 17 00:00:00 2001 From: Adam Sandberg Ericsson Date: Sun, 14 Apr 2024 16:47:44 +0100 Subject: [PATCH 099/683] restate GlobalAlloc method safety preconditions in terms of what the caller has to do for greater clarity --- library/core/src/alloc/global.rs | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/library/core/src/alloc/global.rs b/library/core/src/alloc/global.rs index a6f799c4a7d..68f00d07529 100644 --- a/library/core/src/alloc/global.rs +++ b/library/core/src/alloc/global.rs @@ -124,8 +124,8 @@ pub unsafe trait GlobalAlloc { /// /// # Safety /// - /// This function is unsafe because undefined behavior can result - /// if the caller does not ensure that `layout` has non-zero size. + /// `layout` must have non-zero size. Attempting to allocate for a zero-sized `layout` may + /// result in undefined behavior. /// /// (Extension subtraits might provide more specific bounds on /// behavior, e.g., guarantee a sentinel address or a null pointer @@ -156,14 +156,14 @@ pub unsafe trait GlobalAlloc { /// /// # Safety /// - /// This function is unsafe because undefined behavior can result - /// if the caller does not ensure all of the following: + /// The caller must ensure: /// - /// * `ptr` must denote a block of memory currently allocated via - /// this allocator, + /// * `ptr` is a block of memory currently allocated via this allocator and, /// - /// * `layout` must be the same layout that was used - /// to allocate that block of memory. + /// * `layout` is the same layout that was used to allocate that block of + /// memory. + /// + /// Otherwise undefined behavior can result. #[stable(feature = "global_alloc", since = "1.28.0")] unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout); @@ -172,7 +172,8 @@ pub unsafe trait GlobalAlloc { /// /// # Safety /// - /// This function is unsafe for the same reasons that `alloc` is. + /// The caller has to ensure that `layout` has non-zero size. Like `alloc` + /// zero sized `layout` can result in undefined behaviour. /// However the allocated block of memory is guaranteed to be initialized. /// /// # Errors @@ -220,20 +221,21 @@ pub unsafe trait GlobalAlloc { /// /// # Safety /// - /// This function is unsafe because undefined behavior can result - /// if the caller does not ensure all of the following: + /// The caller must ensure that: /// - /// * `ptr` must be currently allocated via this allocator, + /// * `ptr` is allocated via this allocator, /// - /// * `layout` must be the same layout that was used + /// * `layout` is the same layout that was used /// to allocate that block of memory, /// - /// * `new_size` must be greater than zero. + /// * `new_size` is greater than zero. /// /// * `new_size`, when rounded up to the nearest multiple of `layout.align()`, - /// must not overflow `isize` (i.e., the rounded value must be less than or + /// does not overflow `isize` (i.e., the rounded value must be less than or /// equal to `isize::MAX`). /// + /// If these are not followed, undefined behaviour can result. + /// /// (Extension subtraits might provide more specific bounds on /// behavior, e.g., guarantee a sentinel address or a null pointer /// in response to a zero-size allocation request.) From ae5326b967d5a3d34d3c562882feeacd9839950c Mon Sep 17 00:00:00 2001 From: y21 <30553356+y21@users.noreply.github.com> Date: Sat, 7 Sep 2024 17:06:32 +0200 Subject: [PATCH 100/683] visit struct fields in uninit fallback check --- clippy_utils/src/ty.rs | 11 +++++++---- tests/ui/uninit_vec.rs | 32 ++++++++++++++++++++++++++++++++ tests/ui/uninit_vec.stderr | 24 +++++++++++++++++++++++- 3 files changed, 62 insertions(+), 5 deletions(-) diff --git a/clippy_utils/src/ty.rs b/clippy_utils/src/ty.rs index f80981c11af..5756e56c262 100644 --- a/clippy_utils/src/ty.rs +++ b/clippy_utils/src/ty.rs @@ -606,10 +606,13 @@ fn is_uninit_value_valid_for_ty_fallback<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'t ty::Tuple(types) => types.iter().all(|ty| is_uninit_value_valid_for_ty(cx, ty)), // Unions are always fine right now. // This includes MaybeUninit, the main way people use uninitialized memory. - // For ADTs, we could look at all fields just like for tuples, but that's potentially - // exponential, so let's avoid doing that for now. Code doing that is sketchy enough to - // just use an `#[allow()]`. - ty::Adt(adt, _) => adt.is_union(), + ty::Adt(adt, _) if adt.is_union() => true, + // Types (e.g. `UnsafeCell>`) that recursively contain only types that can be uninit + // can themselves be uninit too. + // This purposefully ignores enums as they may have a discriminant that can't be uninit. + ty::Adt(adt, args) if adt.is_struct() => adt + .all_fields() + .all(|field| is_uninit_value_valid_for_ty(cx, field.ty(cx.tcx, args))), // For the rest, conservatively assume that they cannot be uninit. _ => false, } diff --git a/tests/ui/uninit_vec.rs b/tests/ui/uninit_vec.rs index 0cc77a8775d..464f88140bd 100644 --- a/tests/ui/uninit_vec.rs +++ b/tests/ui/uninit_vec.rs @@ -150,4 +150,36 @@ fn main() { vec.set_len(10); } } + + fn nested_union() { + let mut vec: Vec>> = Vec::with_capacity(1); + unsafe { + vec.set_len(1); + } + } + + struct Recursive(*const Recursive, MaybeUninit); + fn recursive_union() { + // Make sure we don't stack overflow on recursive types. + // The pointer acts as the base case because it can't be uninit regardless of its pointee. + + let mut vec: Vec> = Vec::with_capacity(1); + //~^ uninit_vec + unsafe { + vec.set_len(1); + } + } + + #[repr(u8)] + enum Enum { + Variant(T), + } + fn union_in_enum() { + // Enums can have a discriminant that can't be uninit, so this should still warn + let mut vec: Vec> = Vec::with_capacity(1); + //~^ uninit_vec + unsafe { + vec.set_len(1); + } + } } diff --git a/tests/ui/uninit_vec.stderr b/tests/ui/uninit_vec.stderr index e8b77d653f0..e7c81cf792f 100644 --- a/tests/ui/uninit_vec.stderr +++ b/tests/ui/uninit_vec.stderr @@ -125,5 +125,27 @@ LL | vec.set_len(10); | = help: initialize the buffer or wrap the content in `MaybeUninit` -error: aborting due to 12 previous errors +error: calling `set_len()` immediately after reserving a buffer creates uninitialized values + --> tests/ui/uninit_vec.rs:166:9 + | +LL | let mut vec: Vec> = Vec::with_capacity(1); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | vec.set_len(1); + | ^^^^^^^^^^^^^^ + | + = help: initialize the buffer or wrap the content in `MaybeUninit` + +error: calling `set_len()` immediately after reserving a buffer creates uninitialized values + --> tests/ui/uninit_vec.rs:179:9 + | +LL | let mut vec: Vec> = Vec::with_capacity(1); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | vec.set_len(1); + | ^^^^^^^^^^^^^^ + | + = help: initialize the buffer or wrap the content in `MaybeUninit` + +error: aborting due to 14 previous errors From 25efc04ea554301374ac8e6270dbc7f65fead347 Mon Sep 17 00:00:00 2001 From: Jake Herrmann Date: Sat, 7 Sep 2024 12:00:34 -0800 Subject: [PATCH 101/683] Fix typo --- clippy_lints/src/ptr.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/ptr.rs b/clippy_lints/src/ptr.rs index 125f694996c..7d24d25dc2f 100644 --- a/clippy_lints/src/ptr.rs +++ b/clippy_lints/src/ptr.rs @@ -34,7 +34,7 @@ declare_clippy_lint! { /// with the appropriate `.to_owned()`/`to_string()` calls. /// /// ### Why is this bad? - /// Requiring the argument to be of the specific size + /// Requiring the argument to be of the specific type /// makes the function less useful for no benefit; slices in the form of `&[T]` /// or `&str` usually suffice and can be obtained from other types, too. /// From 42d03f6633e3ebc939d3d04d7605301f99d22a54 Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Sat, 7 Sep 2024 20:02:24 -0400 Subject: [PATCH 102/683] Add support for more SIMD intrinsics --- build_system/src/build.rs | 1 + src/intrinsic/simd.rs | 32 ++++++++++++++++++++++---------- 2 files changed, 23 insertions(+), 10 deletions(-) diff --git a/build_system/src/build.rs b/build_system/src/build.rs index d96683afa35..d5d099fb14c 100644 --- a/build_system/src/build.rs +++ b/build_system/src/build.rs @@ -136,6 +136,7 @@ pub fn build_sysroot(env: &HashMap, config: &ConfigInfo) -> Resu &"build", &"--target", &config.target, + // TODO: remove this feature? &"--features", &"std/compiler-builtins-no-f16-f128", ]; diff --git a/src/intrinsic/simd.rs b/src/intrinsic/simd.rs index a0d8ff6346f..79b345982c6 100644 --- a/src/intrinsic/simd.rs +++ b/src/intrinsic/simd.rs @@ -739,11 +739,12 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( return Err(()); }}; } - let (elem_ty_str, elem_ty) = if let ty::Float(ref f) = *in_elem.kind() { + let (elem_ty_str, elem_ty, cast_type) = if let ty::Float(ref f) = *in_elem.kind() { let elem_ty = bx.cx.type_float_from_ty(*f); match f.bit_width() { - 32 => ("f", elem_ty), - 64 => ("", elem_ty), + 16 => ("", elem_ty, Some(bx.cx.double_type)), + 32 => ("f", elem_ty, None), + 64 => ("", elem_ty, None), _ => { return_error!(InvalidMonomorphization::FloatingPointVector { span, @@ -787,17 +788,28 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( for i in 0..in_len { let index = bx.context.new_rvalue_from_long(bx.ulong_type, i as i64); // we have to treat fpowi specially, since fpowi's second argument is always an i32 - let arguments = if name == sym::simd_fpowi { - vec![ + let mut arguments = vec![]; + if name == sym::simd_fpowi { + arguments = vec![ bx.extract_element(args[0].immediate(), index).to_rvalue(), args[1].immediate(), - ] + ]; } else { - args.iter() - .map(|arg| bx.extract_element(arg.immediate(), index).to_rvalue()) - .collect() + for arg in args { + let mut element = bx.extract_element(arg.immediate(), index).to_rvalue(); + // FIXME: it would probably be better to not have casts here and use the proper + // instructions. + if let Some(typ) = cast_type { + element = bx.context.new_cast(None, element, typ); + } + arguments.push(element); + } }; - vector_elements.push(bx.context.new_call(None, function, &arguments)); + let mut result = bx.context.new_call(None, function, &arguments); + if cast_type.is_some() { + result = bx.context.new_cast(None, result, elem_ty); + } + vector_elements.push(result); } let c = bx.context.new_rvalue_from_vector(None, vec_ty, &vector_elements); Ok(c) From 93b94c240ee7ed3d597e237c30ffc54a784752c0 Mon Sep 17 00:00:00 2001 From: Trivikram Kamat <16024985+trivikr@users.noreply.github.com> Date: Sun, 8 Sep 2024 17:05:42 -0700 Subject: [PATCH 103/683] ci: bump actions/checkout to v4 --- .github/workflows/ci.yml | 6 +++--- .github/workflows/failures.yml | 2 +- .github/workflows/gcc12.yml | 2 +- .github/workflows/m68k.yml | 2 +- .github/workflows/release.yml | 2 +- .github/workflows/stdarch.yml | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index cd366dbae16..704d7b9c2fd 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -36,7 +36,7 @@ jobs: ] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 # `rustup show` installs from rust-toolchain.toml - name: Setup rust toolchain @@ -113,13 +113,13 @@ jobs: duplicates: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - run: python tools/check_intrinsics_duplicates.py build_system: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Test build system run: | cd build_system diff --git a/.github/workflows/failures.yml b/.github/workflows/failures.yml index e5d94767fe7..2c1ed9ad429 100644 --- a/.github/workflows/failures.yml +++ b/.github/workflows/failures.yml @@ -31,7 +31,7 @@ jobs: env_extra: "TEST_FLAGS='-Cpanic=abort -Zpanic-abort-tests' GCC_EXEC_PREFIX=/usr/lib/gcc/" steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 # `rustup show` installs from rust-toolchain.toml - name: Setup rust toolchain diff --git a/.github/workflows/gcc12.yml b/.github/workflows/gcc12.yml index 5977ed33c56..7dcad21a02e 100644 --- a/.github/workflows/gcc12.yml +++ b/.github/workflows/gcc12.yml @@ -33,7 +33,7 @@ jobs: ] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 # `rustup show` installs from rust-toolchain.toml - name: Setup rust toolchain diff --git a/.github/workflows/m68k.yml b/.github/workflows/m68k.yml index 34e4f2b0d41..400eb757405 100644 --- a/.github/workflows/m68k.yml +++ b/.github/workflows/m68k.yml @@ -36,7 +36,7 @@ jobs: ] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 # `rustup show` installs from rust-toolchain.toml - name: Setup rust toolchain diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index d5242926eb4..d5c06a836db 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -24,7 +24,7 @@ jobs: ] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 # `rustup show` installs from rust-toolchain.toml - name: Setup rust toolchain diff --git a/.github/workflows/stdarch.yml b/.github/workflows/stdarch.yml index e24b25b7369..33095bdb5f7 100644 --- a/.github/workflows/stdarch.yml +++ b/.github/workflows/stdarch.yml @@ -24,7 +24,7 @@ jobs: ] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 # `rustup show` installs from rust-toolchain.toml - name: Setup rust toolchain From 9e9526c6ab12fce8113d6c18d348572f4f98492b Mon Sep 17 00:00:00 2001 From: Samuel Tardieu Date: Sat, 7 Sep 2024 16:18:45 +0200 Subject: [PATCH 104/683] Special-case suggestions for null pointers constness cast --- clippy_lints/src/casts/mod.rs | 6 +- clippy_lints/src/casts/ptr_cast_constness.rs | 62 ++++++++++++++------ tests/ui/ptr_cast_constness.fixed | 13 ++++ tests/ui/ptr_cast_constness.rs | 13 ++++ tests/ui/ptr_cast_constness.stderr | 22 ++++++- 5 files changed, 97 insertions(+), 19 deletions(-) diff --git a/clippy_lints/src/casts/mod.rs b/clippy_lints/src/casts/mod.rs index c31716fbcee..fccddf558ed 100644 --- a/clippy_lints/src/casts/mod.rs +++ b/clippy_lints/src/casts/mod.rs @@ -410,19 +410,23 @@ declare_clippy_lint! { /// ### Why is this bad? /// Though `as` casts between raw pointers are not terrible, `pointer::cast_mut` and /// `pointer::cast_const` are safer because they cannot accidentally cast the pointer to another - /// type. + /// type. Or, when null pointers are involved, `null()` and `null_mut()` can be used directly. /// /// ### Example /// ```no_run /// let ptr: *const u32 = &42_u32; /// let mut_ptr = ptr as *mut u32; /// let ptr = mut_ptr as *const u32; + /// let ptr1 = std::ptr::null::() as *mut u32; + /// let ptr2 = std::ptr::null_mut::() as *const u32; /// ``` /// Use instead: /// ```no_run /// let ptr: *const u32 = &42_u32; /// let mut_ptr = ptr.cast_mut(); /// let ptr = mut_ptr.cast_const(); + /// let ptr1 = std::ptr::null_mut::(); + /// let ptr2 = std::ptr::null::(); /// ``` #[clippy::version = "1.72.0"] pub PTR_CAST_CONSTNESS, diff --git a/clippy_lints/src/casts/ptr_cast_constness.rs b/clippy_lints/src/casts/ptr_cast_constness.rs index 7513e18d408..98bc38ed134 100644 --- a/clippy_lints/src/casts/ptr_cast_constness.rs +++ b/clippy_lints/src/casts/ptr_cast_constness.rs @@ -1,10 +1,12 @@ use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::std_or_core; use clippy_utils::sugg::Sugg; use rustc_errors::Applicability; -use rustc_hir::{Expr, Mutability}; +use rustc_hir::{Expr, ExprKind, Mutability, QPath}; use rustc_lint::LateContext; use rustc_middle::ty::{self, Ty, TypeVisitableExt}; +use rustc_span::sym; use super::PTR_CAST_CONSTNESS; @@ -16,8 +18,7 @@ pub(super) fn check<'tcx>( cast_to: Ty<'tcx>, msrv: &Msrv, ) { - if msrv.meets(msrvs::POINTER_CAST_CONSTNESS) - && let ty::RawPtr(from_ty, from_mutbl) = cast_from.kind() + if let ty::RawPtr(from_ty, from_mutbl) = cast_from.kind() && let ty::RawPtr(to_ty, to_mutbl) = cast_to.kind() && matches!( (from_mutbl, to_mutbl), @@ -26,20 +27,47 @@ pub(super) fn check<'tcx>( && from_ty == to_ty && !from_ty.has_erased_regions() { - let sugg = Sugg::hir(cx, cast_expr, "_"); - let constness = match *to_mutbl { - Mutability::Not => "const", - Mutability::Mut => "mut", - }; + if let ExprKind::Call(func, []) = cast_expr.kind + && let ExprKind::Path(QPath::Resolved(None, path)) = func.kind + && let Some(defid) = path.res.opt_def_id() + && let Some(prefix) = std_or_core(cx) + && let mut app = Applicability::MachineApplicable + && let sugg = format!("{}", Sugg::hir_with_applicability(cx, cast_expr, "_", &mut app)) + && let Some((_, after_lt)) = sugg.split_once("::<") + && let Some((source, target, target_func)) = match cx.tcx.get_diagnostic_name(defid) { + Some(sym::ptr_null) => Some(("const", "mutable", "null_mut")), + Some(sym::ptr_null_mut) => Some(("mutable", "const", "null")), + _ => None, + } + { + span_lint_and_sugg( + cx, + PTR_CAST_CONSTNESS, + expr.span, + format!("`as` casting to make a {source} null pointer into a {target} null pointer"), + format!("use `{target_func}()` directly instead"), + format!("{prefix}::ptr::{target_func}::<{after_lt}"), + app, + ); + return; + } - span_lint_and_sugg( - cx, - PTR_CAST_CONSTNESS, - expr.span, - "`as` casting between raw pointers while changing only its constness", - format!("try `pointer::cast_{constness}`, a safer alternative"), - format!("{}.cast_{constness}()", sugg.maybe_par()), - Applicability::MachineApplicable, - ); + if msrv.meets(msrvs::POINTER_CAST_CONSTNESS) { + let sugg = Sugg::hir(cx, cast_expr, "_"); + let constness = match *to_mutbl { + Mutability::Not => "const", + Mutability::Mut => "mut", + }; + + span_lint_and_sugg( + cx, + PTR_CAST_CONSTNESS, + expr.span, + "`as` casting between raw pointers while changing only its constness", + format!("try `pointer::cast_{constness}`, a safer alternative"), + format!("{}.cast_{constness}()", sugg.maybe_par()), + Applicability::MachineApplicable, + ); + } } } diff --git a/tests/ui/ptr_cast_constness.fixed b/tests/ui/ptr_cast_constness.fixed index 21ac42196e1..5bf9a30b016 100644 --- a/tests/ui/ptr_cast_constness.fixed +++ b/tests/ui/ptr_cast_constness.fixed @@ -68,3 +68,16 @@ fn _msrv_1_65() { let _ = ptr.cast_mut(); let _ = mut_ptr.cast_const(); } + +#[inline_macros] +fn null_pointers() { + use std::ptr; + let _ = std::ptr::null_mut::(); + let _ = std::ptr::null::(); + + // Make sure the lint is triggered inside a macro + let _ = inline!(std::ptr::null_mut::()); + + // Do not lint inside macros from external crates + let _ = external!(ptr::null::() as *mut u32); +} diff --git a/tests/ui/ptr_cast_constness.rs b/tests/ui/ptr_cast_constness.rs index 5ce590b2b7e..2575a5923e1 100644 --- a/tests/ui/ptr_cast_constness.rs +++ b/tests/ui/ptr_cast_constness.rs @@ -68,3 +68,16 @@ fn _msrv_1_65() { let _ = ptr as *mut u32; let _ = mut_ptr as *const u32; } + +#[inline_macros] +fn null_pointers() { + use std::ptr; + let _ = ptr::null::() as *mut String; + let _ = ptr::null_mut::() as *const u32; + + // Make sure the lint is triggered inside a macro + let _ = inline!(ptr::null::() as *mut u32); + + // Do not lint inside macros from external crates + let _ = external!(ptr::null::() as *mut u32); +} diff --git a/tests/ui/ptr_cast_constness.stderr b/tests/ui/ptr_cast_constness.stderr index 2c52ebd3464..0806ca62806 100644 --- a/tests/ui/ptr_cast_constness.stderr +++ b/tests/ui/ptr_cast_constness.stderr @@ -43,5 +43,25 @@ error: `as` casting between raw pointers while changing only its constness LL | let _ = mut_ptr as *const u32; | ^^^^^^^^^^^^^^^^^^^^^ help: try `pointer::cast_const`, a safer alternative: `mut_ptr.cast_const()` -error: aborting due to 7 previous errors +error: `as` casting to make a const null pointer into a mutable null pointer + --> tests/ui/ptr_cast_constness.rs:75:13 + | +LL | let _ = ptr::null::() as *mut String; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `null_mut()` directly instead: `std::ptr::null_mut::()` + +error: `as` casting to make a mutable null pointer into a const null pointer + --> tests/ui/ptr_cast_constness.rs:76:13 + | +LL | let _ = ptr::null_mut::() as *const u32; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `null()` directly instead: `std::ptr::null::()` + +error: `as` casting to make a const null pointer into a mutable null pointer + --> tests/ui/ptr_cast_constness.rs:79:21 + | +LL | let _ = inline!(ptr::null::() as *mut u32); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `null_mut()` directly instead: `std::ptr::null_mut::()` + | + = note: this error originates in the macro `__inline_mac_fn_null_pointers` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 10 previous errors From 30608732c2f68c423e4a62e6c20cdf28f6d38559 Mon Sep 17 00:00:00 2001 From: Samuel Tardieu Date: Sat, 7 Sep 2024 21:57:29 +0200 Subject: [PATCH 105/683] Handle null pointer constness cast through methods This covers two cases: - `core::ptr::null::().cast_mut()` -> `core::ptr::null_mut::()` - `core::ptr::null_mut::().cast_const()` -> `core::ptr::null::()` --- clippy_lints/src/casts/mod.rs | 5 ++++ clippy_lints/src/casts/ptr_cast_constness.rs | 27 ++++++++++++++++++++ tests/ui/ptr_cast_constness.fixed | 4 +++ tests/ui/ptr_cast_constness.rs | 4 +++ tests/ui/ptr_cast_constness.stderr | 24 +++++++++++++++-- 5 files changed, 62 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/casts/mod.rs b/clippy_lints/src/casts/mod.rs index fccddf558ed..39f50a347c0 100644 --- a/clippy_lints/src/casts/mod.rs +++ b/clippy_lints/src/casts/mod.rs @@ -419,6 +419,8 @@ declare_clippy_lint! { /// let ptr = mut_ptr as *const u32; /// let ptr1 = std::ptr::null::() as *mut u32; /// let ptr2 = std::ptr::null_mut::() as *const u32; + /// let ptr3 = std::ptr::null::().cast_mut(); + /// let ptr4 = std::ptr::null_mut::().cast_const(); /// ``` /// Use instead: /// ```no_run @@ -427,6 +429,8 @@ declare_clippy_lint! { /// let ptr = mut_ptr.cast_const(); /// let ptr1 = std::ptr::null_mut::(); /// let ptr2 = std::ptr::null::(); + /// let ptr3 = std::ptr::null_mut::(); + /// let ptr4 = std::ptr::null::(); /// ``` #[clippy::version = "1.72.0"] pub PTR_CAST_CONSTNESS, @@ -813,6 +817,7 @@ impl<'tcx> LateLintPass<'tcx> for Casts { char_lit_as_u8::check(cx, expr); ptr_as_ptr::check(cx, expr, &self.msrv); cast_slice_different_sizes::check(cx, expr, &self.msrv); + ptr_cast_constness::check_null_ptr_cast_method(cx, expr); } extract_msrv_attr!(LateContext); diff --git a/clippy_lints/src/casts/ptr_cast_constness.rs b/clippy_lints/src/casts/ptr_cast_constness.rs index 98bc38ed134..7518dd2435a 100644 --- a/clippy_lints/src/casts/ptr_cast_constness.rs +++ b/clippy_lints/src/casts/ptr_cast_constness.rs @@ -71,3 +71,30 @@ pub(super) fn check<'tcx>( } } } + +pub(super) fn check_null_ptr_cast_method(cx: &LateContext<'_>, expr: &Expr<'_>) { + if let ExprKind::MethodCall(method, cast_expr, [], _) = expr.kind + && let ExprKind::Call(func, []) = cast_expr.kind + && let ExprKind::Path(QPath::Resolved(None, path)) = func.kind + && let Some(defid) = path.res.opt_def_id() + && let method = match (cx.tcx.get_diagnostic_name(defid), method.ident.as_str()) { + (Some(sym::ptr_null), "cast_mut") => "null_mut", + (Some(sym::ptr_null_mut), "cast_const") => "null", + _ => return, + } + && let Some(prefix) = std_or_core(cx) + && let mut app = Applicability::MachineApplicable + && let sugg = format!("{}", Sugg::hir_with_applicability(cx, cast_expr, "_", &mut app)) + && let Some((_, after_lt)) = sugg.split_once("::<") + { + span_lint_and_sugg( + cx, + PTR_CAST_CONSTNESS, + expr.span, + "changing constness of a null pointer", + format!("use `{method}()` directly instead"), + format!("{prefix}::ptr::{method}::<{after_lt}"), + app, + ); + } +} diff --git a/tests/ui/ptr_cast_constness.fixed b/tests/ui/ptr_cast_constness.fixed index 5bf9a30b016..9a5272c7adc 100644 --- a/tests/ui/ptr_cast_constness.fixed +++ b/tests/ui/ptr_cast_constness.fixed @@ -74,10 +74,14 @@ fn null_pointers() { use std::ptr; let _ = std::ptr::null_mut::(); let _ = std::ptr::null::(); + let _ = std::ptr::null_mut::(); + let _ = std::ptr::null::(); // Make sure the lint is triggered inside a macro let _ = inline!(std::ptr::null_mut::()); + let _ = inline!(std::ptr::null_mut::()); // Do not lint inside macros from external crates let _ = external!(ptr::null::() as *mut u32); + let _ = external!(ptr::null::().cast_mut()); } diff --git a/tests/ui/ptr_cast_constness.rs b/tests/ui/ptr_cast_constness.rs index 2575a5923e1..43ab5f5ba7c 100644 --- a/tests/ui/ptr_cast_constness.rs +++ b/tests/ui/ptr_cast_constness.rs @@ -74,10 +74,14 @@ fn null_pointers() { use std::ptr; let _ = ptr::null::() as *mut String; let _ = ptr::null_mut::() as *const u32; + let _ = ptr::null::().cast_mut(); + let _ = ptr::null_mut::().cast_const(); // Make sure the lint is triggered inside a macro let _ = inline!(ptr::null::() as *mut u32); + let _ = inline!(ptr::null::().cast_mut()); // Do not lint inside macros from external crates let _ = external!(ptr::null::() as *mut u32); + let _ = external!(ptr::null::().cast_mut()); } diff --git a/tests/ui/ptr_cast_constness.stderr b/tests/ui/ptr_cast_constness.stderr index 0806ca62806..a693793a4ae 100644 --- a/tests/ui/ptr_cast_constness.stderr +++ b/tests/ui/ptr_cast_constness.stderr @@ -55,13 +55,33 @@ error: `as` casting to make a mutable null pointer into a const null pointer LL | let _ = ptr::null_mut::() as *const u32; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `null()` directly instead: `std::ptr::null::()` +error: changing constness of a null pointer + --> tests/ui/ptr_cast_constness.rs:77:13 + | +LL | let _ = ptr::null::().cast_mut(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `null_mut()` directly instead: `std::ptr::null_mut::()` + +error: changing constness of a null pointer + --> tests/ui/ptr_cast_constness.rs:78:13 + | +LL | let _ = ptr::null_mut::().cast_const(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `null()` directly instead: `std::ptr::null::()` + error: `as` casting to make a const null pointer into a mutable null pointer - --> tests/ui/ptr_cast_constness.rs:79:21 + --> tests/ui/ptr_cast_constness.rs:81:21 | LL | let _ = inline!(ptr::null::() as *mut u32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `null_mut()` directly instead: `std::ptr::null_mut::()` | = note: this error originates in the macro `__inline_mac_fn_null_pointers` (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 10 previous errors +error: changing constness of a null pointer + --> tests/ui/ptr_cast_constness.rs:82:21 + | +LL | let _ = inline!(ptr::null::().cast_mut()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `null_mut()` directly instead: `std::ptr::null_mut::()` + | + = note: this error originates in the macro `__inline_mac_fn_null_pointers` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 13 previous errors From b0db9c285dae65fc30a72d6862264df23feae430 Mon Sep 17 00:00:00 2001 From: cuishuang Date: Mon, 9 Sep 2024 16:43:46 +0800 Subject: [PATCH 106/683] Remove unnecessary symbols and add missing symbols Signed-off-by: cuishuang --- clippy_lints/src/methods/unnecessary_to_owned.rs | 2 +- tests/ui/crashes/ice-3969.rs | 4 ++-- tests/ui/crashes/ice-6251.rs | 2 +- tests/ui/floating_point_arithmetic_nostd.rs | 2 +- tests/ui/unsafe_removed_from_name.rs | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/clippy_lints/src/methods/unnecessary_to_owned.rs b/clippy_lints/src/methods/unnecessary_to_owned.rs index 69c5bc57e29..9e198c7e55c 100644 --- a/clippy_lints/src/methods/unnecessary_to_owned.rs +++ b/clippy_lints/src/methods/unnecessary_to_owned.rs @@ -717,7 +717,7 @@ fn check_if_applicable_to_argument<'tcx>(cx: &LateContext<'tcx>, arg: &Expr<'tcx // check that: // 1. This is a method with only one argument that doesn't come from a trait. // 2. That it has `Borrow` in its generic predicates. -// 3. `Self` is a std "map type" (ie `HashSet`, `HashMap`, BTreeSet`, `BTreeMap`). +// 3. `Self` is a std "map type" (ie `HashSet`, `HashMap`, `BTreeSet`, `BTreeMap`). fn check_borrow_predicate<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) { if let ExprKind::MethodCall(_, caller, &[arg], _) = expr.kind && let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) diff --git a/tests/ui/crashes/ice-3969.rs b/tests/ui/crashes/ice-3969.rs index d5676cbd91d..ac09ce08753 100644 --- a/tests/ui/crashes/ice-3969.rs +++ b/tests/ui/crashes/ice-3969.rs @@ -1,7 +1,7 @@ // https://github.com/rust-lang/rust-clippy/issues/3969 // used to crash: error: internal compiler error: // src/librustc_traits/normalize_erasing_regions.rs:43: could not fully normalize `::Item test from rustc ./ui/trivial-bounds/trivial-bounds-inconsistent.rs +// std::iter::Iterator>::Item` test from rustc ./ui/trivial-bounds/trivial-bounds-inconsistent.rs // Check that tautalogically false bounds are accepted, and are used // in type inference. @@ -18,7 +18,7 @@ struct Dst { struct TwoStrs(str, str) where str: Sized; -//~^ ERROR: trait bound str: std::marker::Sized does not depend on any type or lifetim +//~^ ERROR: trait bound str: std::marker::Sized does not depend on any type or lifetime //~| NOTE: `-D trivial-bounds` implied by `-D warnings` fn unsized_local() diff --git a/tests/ui/crashes/ice-6251.rs b/tests/ui/crashes/ice-6251.rs index a81137a6465..73e919b6dd2 100644 --- a/tests/ui/crashes/ice-6251.rs +++ b/tests/ui/crashes/ice-6251.rs @@ -1,5 +1,5 @@ // originally from glacier/fixed/77329.rs -// assertion failed: `(left == right) ; different DefIds +// assertion failed: `(left == right)` ; different DefIds //@no-rustfix fn bug() -> impl Iterator { std::iter::empty() diff --git a/tests/ui/floating_point_arithmetic_nostd.rs b/tests/ui/floating_point_arithmetic_nostd.rs index 47c113d61c0..8ea75fae89b 100644 --- a/tests/ui/floating_point_arithmetic_nostd.rs +++ b/tests/ui/floating_point_arithmetic_nostd.rs @@ -4,7 +4,7 @@ #![no_std] // The following should not lint, as the suggested methods `{f16,f32,f64,f128}.mul_add()` -// and ``{f16,f32,f64,f128}::abs()` are not available in no_std +// and `{f16,f32,f64,f128}::abs()` are not available in no_std pub fn mul_add() { let a: f64 = 1234.567; diff --git a/tests/ui/unsafe_removed_from_name.rs b/tests/ui/unsafe_removed_from_name.rs index e0e0ded140f..e9e6c8312f5 100644 --- a/tests/ui/unsafe_removed_from_name.rs +++ b/tests/ui/unsafe_removed_from_name.rs @@ -7,7 +7,7 @@ use std::cell::UnsafeCell as TotallySafeCell; //~| NOTE: `-D clippy::unsafe-removed-from-name` implied by `-D warnings` use std::cell::UnsafeCell as TotallySafeCellAgain; -//~^ ERROR: removed `unsafe` from the name of `UnsafeCell` in use as `TotallySafeCellAgain +//~^ ERROR: removed `unsafe` from the name of `UnsafeCell` in use as `TotallySafeCellAgain` // Shouldn't error use std::cell::RefCell as ProbablyNotUnsafe; From 1f1363335922b76e6940cf632a391f3315f564cf Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Sat, 17 Aug 2024 21:38:10 +0200 Subject: [PATCH 107/683] Bump ui_test --- Cargo.toml | 2 +- tests/compile-test.rs | 10 ++- tests/ui/asm_syntax_not_x86.rs | 3 +- tests/ui/asm_syntax_x86.rs | 4 +- tests/ui/asm_syntax_x86.stderr | 70 +++++++++++++++++++ tests/ui/crashes/ice-7410.rs | 3 +- .../entrypoint_recursion.rs | 2 +- .../no_std_main_recursion.rs | 2 +- tests/ui/def_id_nocore.rs | 2 +- tests/ui/empty_loop_no_std.rs | 2 +- tests/ui/enum_clike_unportable_variant.rs | 2 +- tests/ui/macro_use_imports.fixed | 2 +- tests/ui/macro_use_imports.rs | 2 +- tests/ui/macro_use_imports_expect.rs | 2 +- tests/ui/mixed_attributes_style.rs | 3 +- tests/ui/mixed_attributes_style.stderr | 3 +- tests/ui/non_octal_unix_permissions.fixed | 2 +- tests/ui/non_octal_unix_permissions.rs | 2 +- tests/ui/result_large_err.rs | 2 +- tests/ui/single_call_fn.rs | 2 +- tests/ui/transmute_32bit.rs | 2 +- tests/ui/transmute_64bit.rs | 2 +- 22 files changed, 96 insertions(+), 30 deletions(-) create mode 100644 tests/ui/asm_syntax_x86.stderr diff --git a/Cargo.toml b/Cargo.toml index 5b62e387ac6..cf810798d8c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,7 +31,7 @@ anstream = "0.6.0" [dev-dependencies] cargo_metadata = "0.18.1" -ui_test = "0.25" +ui_test = "0.26.4" regex = "1.5.5" serde = { version = "1.0.145", features = ["derive"] } serde_json = "1.0.122" diff --git a/tests/compile-test.rs b/tests/compile-test.rs index 9754254cdd0..c7243348ce4 100644 --- a/tests/compile-test.rs +++ b/tests/compile-test.rs @@ -13,7 +13,6 @@ use test_utils::IS_RUSTC_TEST_SUITE; use ui_test::custom_flags::rustfix::RustfixMode; use ui_test::custom_flags::Flag; use ui_test::spanned::Spanned; -use ui_test::test_result::TestRun; use ui_test::{status_emitter, Args, CommandBuilder, Config, Match, OutputConflictHandling}; use std::collections::{BTreeMap, HashMap}; @@ -469,15 +468,14 @@ fn applicability_ord(applicability: &Applicability) -> u8 { impl Flag for DiagnosticCollector { fn post_test_action( &self, - _config: &ui_test::per_test_config::TestConfig<'_>, - _cmd: &mut std::process::Command, + _config: &ui_test::per_test_config::TestConfig, output: &std::process::Output, - _build_manager: &ui_test::build_manager::BuildManager<'_>, - ) -> Result, ui_test::Errored> { + _build_manager: &ui_test::build_manager::BuildManager, + ) -> Result<(), ui_test::Errored> { if !output.stderr.is_empty() { self.sender.send(output.stderr.clone()).unwrap(); } - Ok(Vec::new()) + Ok(()) } fn clone_inner(&self) -> Box { diff --git a/tests/ui/asm_syntax_not_x86.rs b/tests/ui/asm_syntax_not_x86.rs index 33cea480681..a7d29cc239e 100644 --- a/tests/ui/asm_syntax_not_x86.rs +++ b/tests/ui/asm_syntax_not_x86.rs @@ -1,5 +1,4 @@ -//@ignore-target-i686 -//@ignore-target-x86 +//@ignore-target: i686 x86 //@needs-asm-support #[warn(clippy::inline_asm_x86_intel_syntax)] diff --git a/tests/ui/asm_syntax_x86.rs b/tests/ui/asm_syntax_x86.rs index 835943b4389..5ceaceb7527 100644 --- a/tests/ui/asm_syntax_x86.rs +++ b/tests/ui/asm_syntax_x86.rs @@ -1,6 +1,4 @@ -//@revisions: i686 x86_64 -//@[i686] only-target-i686 -//@[x86_64] only-target-x86_64 +//@only-target: i686 x86_64 #[warn(clippy::inline_asm_x86_intel_syntax)] mod warn_intel { diff --git a/tests/ui/asm_syntax_x86.stderr b/tests/ui/asm_syntax_x86.stderr new file mode 100644 index 00000000000..1911ef66e23 --- /dev/null +++ b/tests/ui/asm_syntax_x86.stderr @@ -0,0 +1,70 @@ +error: Intel x86 assembly syntax used + --> tests/ui/asm_syntax_x86.rs:8:9 + | +LL | asm!(""); + | ^^^^^^^^ + | + = help: use AT&T x86 assembly syntax + = note: `-D clippy::inline-asm-x86-intel-syntax` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::inline_asm_x86_intel_syntax)]` + +error: Intel x86 assembly syntax used + --> tests/ui/asm_syntax_x86.rs:10:9 + | +LL | asm!("", options()); + | ^^^^^^^^^^^^^^^^^^^ + | + = help: use AT&T x86 assembly syntax + +error: Intel x86 assembly syntax used + --> tests/ui/asm_syntax_x86.rs:12:9 + | +LL | asm!("", options(nostack)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use AT&T x86 assembly syntax + +error: Intel x86 assembly syntax used + --> tests/ui/asm_syntax_x86.rs:18:5 + | +LL | global_asm!(""); + | ^^^^^^^^^^^^^^^ + | + = help: use AT&T x86 assembly syntax + +error: Intel x86 assembly syntax used + --> tests/ui/asm_syntax_x86.rs:20:5 + | +LL | global_asm!("", options()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use AT&T x86 assembly syntax + +error: AT&T x86 assembly syntax used + --> tests/ui/asm_syntax_x86.rs:33:9 + | +LL | asm!("", options(att_syntax)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use Intel x86 assembly syntax + = note: `-D clippy::inline-asm-x86-att-syntax` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::inline_asm_x86_att_syntax)]` + +error: AT&T x86 assembly syntax used + --> tests/ui/asm_syntax_x86.rs:35:9 + | +LL | asm!("", options(nostack, att_syntax)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use Intel x86 assembly syntax + +error: AT&T x86 assembly syntax used + --> tests/ui/asm_syntax_x86.rs:41:5 + | +LL | global_asm!("", options(att_syntax)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use Intel x86 assembly syntax + +error: aborting due to 8 previous errors + diff --git a/tests/ui/crashes/ice-7410.rs b/tests/ui/crashes/ice-7410.rs index a2683b3ce34..ccf6d7ff94f 100644 --- a/tests/ui/crashes/ice-7410.rs +++ b/tests/ui/crashes/ice-7410.rs @@ -1,6 +1,5 @@ //@compile-flags: -Clink-arg=-nostartfiles -//@ignore-target-apple -//@ignore-target-windows +//@ignore-target: apple windows #![feature(lang_items, start, libc)] #![no_std] diff --git a/tests/ui/crate_level_checks/entrypoint_recursion.rs b/tests/ui/crate_level_checks/entrypoint_recursion.rs index aa76688d801..5d853d97bc3 100644 --- a/tests/ui/crate_level_checks/entrypoint_recursion.rs +++ b/tests/ui/crate_level_checks/entrypoint_recursion.rs @@ -1,4 +1,4 @@ -//@ignore-target-apple +//@ignore-target: apple #![feature(rustc_attrs)] diff --git a/tests/ui/crate_level_checks/no_std_main_recursion.rs b/tests/ui/crate_level_checks/no_std_main_recursion.rs index 32eba969592..9e5b2a48903 100644 --- a/tests/ui/crate_level_checks/no_std_main_recursion.rs +++ b/tests/ui/crate_level_checks/no_std_main_recursion.rs @@ -1,5 +1,5 @@ //@compile-flags: -Clink-arg=-nostartfiles -//@ignore-target-apple +//@ignore-target: apple #![feature(lang_items, start, libc)] #![no_std] diff --git a/tests/ui/def_id_nocore.rs b/tests/ui/def_id_nocore.rs index 190d636ebf3..c9650312db8 100644 --- a/tests/ui/def_id_nocore.rs +++ b/tests/ui/def_id_nocore.rs @@ -1,4 +1,4 @@ -//@ignore-target-apple +//@ignore-target: apple #![feature(no_core, lang_items, start)] #![no_core] diff --git a/tests/ui/empty_loop_no_std.rs b/tests/ui/empty_loop_no_std.rs index 5fe32351ed4..1bb895bda75 100644 --- a/tests/ui/empty_loop_no_std.rs +++ b/tests/ui/empty_loop_no_std.rs @@ -1,5 +1,5 @@ //@compile-flags: -Clink-arg=-nostartfiles -//@ignore-target-apple +//@ignore-target: apple #![warn(clippy::empty_loop)] #![feature(lang_items, start, libc)] diff --git a/tests/ui/enum_clike_unportable_variant.rs b/tests/ui/enum_clike_unportable_variant.rs index c50404c5047..37849179d6a 100644 --- a/tests/ui/enum_clike_unportable_variant.rs +++ b/tests/ui/enum_clike_unportable_variant.rs @@ -1,4 +1,4 @@ -//@ignore-32bit +//@ignore-bitwidth: 32 #![warn(clippy::enum_clike_unportable_variant)] #![allow(unused, non_upper_case_globals)] diff --git a/tests/ui/macro_use_imports.fixed b/tests/ui/macro_use_imports.fixed index 38ed5a957e7..28844fab747 100644 --- a/tests/ui/macro_use_imports.fixed +++ b/tests/ui/macro_use_imports.fixed @@ -2,7 +2,7 @@ //@aux-build:macro_use_helper.rs //@aux-build:proc_macro_derive.rs -//@ignore-32bit +//@ignore-bitwidth: 32 #![allow(unused_imports, unreachable_code, unused_variables, dead_code, unused_attributes)] #![allow(clippy::single_component_path_imports)] diff --git a/tests/ui/macro_use_imports.rs b/tests/ui/macro_use_imports.rs index ae6cc16ed27..5381f295989 100644 --- a/tests/ui/macro_use_imports.rs +++ b/tests/ui/macro_use_imports.rs @@ -2,7 +2,7 @@ //@aux-build:macro_use_helper.rs //@aux-build:proc_macro_derive.rs -//@ignore-32bit +//@ignore-bitwidth: 32 #![allow(unused_imports, unreachable_code, unused_variables, dead_code, unused_attributes)] #![allow(clippy::single_component_path_imports)] diff --git a/tests/ui/macro_use_imports_expect.rs b/tests/ui/macro_use_imports_expect.rs index df6d5b9fbab..60cce1d24a2 100644 --- a/tests/ui/macro_use_imports_expect.rs +++ b/tests/ui/macro_use_imports_expect.rs @@ -1,7 +1,7 @@ //@aux-build:macro_rules.rs //@aux-build:macro_use_helper.rs //@aux-build:proc_macro_derive.rs -//@ignore-32bit +//@ignore-bitwidth: 32 #![allow(unused_imports, unreachable_code, unused_variables, dead_code, unused_attributes)] #![allow(clippy::single_component_path_imports)] diff --git a/tests/ui/mixed_attributes_style.rs b/tests/ui/mixed_attributes_style.rs index 1a646c26522..93ab9392cf8 100644 --- a/tests/ui/mixed_attributes_style.rs +++ b/tests/ui/mixed_attributes_style.rs @@ -82,7 +82,8 @@ mod issue_12530 { #![allow(dead_code)] } } - /// Nested mod //~ ERROR: item has both inner and outer attributes + /// Nested mod + //~^ ERROR: item has both inner and outer attributes #[allow(unused)] mod nest_mod_2 { #![allow(unused)] diff --git a/tests/ui/mixed_attributes_style.stderr b/tests/ui/mixed_attributes_style.stderr index a1d3fc430f6..abdc2df23cf 100644 --- a/tests/ui/mixed_attributes_style.stderr +++ b/tests/ui/mixed_attributes_style.stderr @@ -46,13 +46,14 @@ error: item has both inner and outer attributes --> tests/ui/mixed_attributes_style.rs:85:5 | LL | / /// Nested mod +LL | | LL | | #[allow(unused)] LL | | mod nest_mod_2 { LL | | #![allow(unused)] | |_________________________^ error: item has both inner and outer attributes - --> tests/ui/mixed_attributes_style.rs:90:9 + --> tests/ui/mixed_attributes_style.rs:91:9 | LL | / #[allow(dead_code)] LL | | mod inner_mod { diff --git a/tests/ui/non_octal_unix_permissions.fixed b/tests/ui/non_octal_unix_permissions.fixed index 237f5f5b97a..f68d5e30d27 100644 --- a/tests/ui/non_octal_unix_permissions.fixed +++ b/tests/ui/non_octal_unix_permissions.fixed @@ -1,4 +1,4 @@ -//@ignore-target-windows +//@ignore-target: windows #![warn(clippy::non_octal_unix_permissions)] use std::fs::{DirBuilder, File, OpenOptions, Permissions}; diff --git a/tests/ui/non_octal_unix_permissions.rs b/tests/ui/non_octal_unix_permissions.rs index c8da5dbcec2..647c3769d2c 100644 --- a/tests/ui/non_octal_unix_permissions.rs +++ b/tests/ui/non_octal_unix_permissions.rs @@ -1,4 +1,4 @@ -//@ignore-target-windows +//@ignore-target: windows #![warn(clippy::non_octal_unix_permissions)] use std::fs::{DirBuilder, File, OpenOptions, Permissions}; diff --git a/tests/ui/result_large_err.rs b/tests/ui/result_large_err.rs index b25348bf996..9c39f023da2 100644 --- a/tests/ui/result_large_err.rs +++ b/tests/ui/result_large_err.rs @@ -1,4 +1,4 @@ -//@ignore-32bit +//@ignore-bitwidth: 32 #![warn(clippy::result_large_err)] #![allow(clippy::large_enum_variant)] diff --git a/tests/ui/single_call_fn.rs b/tests/ui/single_call_fn.rs index 55e7508a957..a0597664da5 100644 --- a/tests/ui/single_call_fn.rs +++ b/tests/ui/single_call_fn.rs @@ -1,4 +1,4 @@ -//@ignore-32bit +//@ignore-bitwidth: 32 //@aux-build:proc_macros.rs #![allow(clippy::redundant_closure_call, unused)] #![warn(clippy::single_call_fn)] diff --git a/tests/ui/transmute_32bit.rs b/tests/ui/transmute_32bit.rs index 8e1316ca39d..e162bbb2d92 100644 --- a/tests/ui/transmute_32bit.rs +++ b/tests/ui/transmute_32bit.rs @@ -1,4 +1,4 @@ -//@ignore-64bit +//@ignore-bitwidth: 64 #[warn(clippy::wrong_transmute)] fn main() { diff --git a/tests/ui/transmute_64bit.rs b/tests/ui/transmute_64bit.rs index 767cc503a39..fd0ad74bcfa 100644 --- a/tests/ui/transmute_64bit.rs +++ b/tests/ui/transmute_64bit.rs @@ -1,4 +1,4 @@ -//@ignore-32bit +//@ignore-bitwidth: 32 #[warn(clippy::wrong_transmute)] fn main() { From 49a501856dd3dc390de7a7ef01ac9c48c13f209c Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Wed, 11 Sep 2024 12:40:20 +0500 Subject: [PATCH 108/683] Fix WHILE_LET_LOOP doc --- clippy_lints/src/loops/mod.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/clippy_lints/src/loops/mod.rs b/clippy_lints/src/loops/mod.rs index 92ccc0cc0a1..5155fd76b25 100644 --- a/clippy_lints/src/loops/mod.rs +++ b/clippy_lints/src/loops/mod.rs @@ -188,22 +188,22 @@ declare_clippy_lint! { /// The `while let` loop is usually shorter and more /// readable. /// - /// ### Known problems - /// Sometimes the wrong binding is displayed ([#383](https://github.com/rust-lang/rust-clippy/issues/383)). - /// /// ### Example /// ```rust,no_run - /// # let y = Some(1); + /// let y = Some(1); /// loop { /// let x = match y { /// Some(x) => x, /// None => break, /// }; - /// // .. do something with x + /// // .. /// } - /// // is easier written as + /// ``` + /// Use instead: + /// ```rust,no_run + /// let y = Some(1); /// while let Some(x) = y { - /// // .. do something with x + /// // .. /// }; /// ``` #[clippy::version = "pre 1.29.0"] From 2775dcdd24c2fa6a3596a071450f8863d0746d78 Mon Sep 17 00:00:00 2001 From: Alex Macleod Date: Wed, 11 Sep 2024 13:45:03 +0000 Subject: [PATCH 109/683] Remove unused collect_metadata function --- tests/dogfood.rs | 49 +----------------------------------------------- 1 file changed, 1 insertion(+), 48 deletions(-) diff --git a/tests/dogfood.rs b/tests/dogfood.rs index 8d10d5e7161..858be389a9e 100644 --- a/tests/dogfood.rs +++ b/tests/dogfood.rs @@ -6,11 +6,9 @@ #![warn(rust_2018_idioms, unused_lifetimes)] use itertools::Itertools; -use std::fs::File; use std::io::{self, IsTerminal}; use std::path::PathBuf; use std::process::Command; -use std::time::SystemTime; use test_utils::IS_RUSTC_TEST_SUITE; use ui_test::Args; @@ -28,11 +26,7 @@ fn main() { println!("dogfood: test"); } } else if !args.skip.iter().any(|arg| arg == "dogfood") { - if args.filters.iter().any(|arg| arg == "collect_metadata") { - collect_metadata(); - } else { - dogfood(); - } + dogfood(); } } @@ -61,47 +55,6 @@ fn dogfood() { ); } -fn collect_metadata() { - assert!(cfg!(feature = "internal")); - - // Setup for validation - let metadata_output_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("util/gh-pages/lints.json"); - let start_time = SystemTime::now(); - - // Run collection as is - std::env::set_var("ENABLE_METADATA_COLLECTION", "1"); - assert!(run_clippy_for_package( - "clippy_lints", - &["-A", "unfulfilled_lint_expectations"] - )); - - // Check if cargo caching got in the way - if let Ok(file) = File::open(metadata_output_path) { - if let Ok(metadata) = file.metadata() { - if let Ok(last_modification) = metadata.modified() { - if last_modification > start_time { - // The output file has been modified. Most likely by a hungry - // metadata collection monster. So We'll return. - return; - } - } - } - } - - // Force cargo to invalidate the caches - filetime::set_file_mtime( - PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("clippy_lints/src/lib.rs"), - filetime::FileTime::now(), - ) - .unwrap(); - - // Running the collection again - assert!(run_clippy_for_package( - "clippy_lints", - &["-A", "unfulfilled_lint_expectations"] - )); -} - #[must_use] fn run_clippy_for_package(project: &str, args: &[&str]) -> bool { let root_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")); From 58350799a184663845772417c07262dcbd52dfb5 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 11 Sep 2024 15:15:44 +0200 Subject: [PATCH 110/683] ptr::add/sub: these are *not* equivalent to offset(count as isize) --- library/core/src/intrinsics.rs | 3 +-- library/core/src/ptr/const_ptr.rs | 16 +++++++++------- library/core/src/ptr/mut_ptr.rs | 16 +++++++++------- 3 files changed, 19 insertions(+), 16 deletions(-) diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index 7870a62ea81..22fc9f72ec4 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -1425,8 +1425,7 @@ extern "rust-intrinsic" { /// /// If the computed offset is non-zero, then both the starting and resulting pointer must be /// either in bounds or at the end of an allocated object. If either pointer is out - /// of bounds or arithmetic overflow occurs then any further use of the returned value will - /// result in undefined behavior. + /// of bounds or arithmetic overflow occurs then this operation is undefined behavior. /// /// The stabilized version of this intrinsic is [`pointer::offset`]. #[must_use = "returns a new pointer rather than modifying its argument"] diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs index 3b45d46b31d..3df24e0d512 100644 --- a/library/core/src/ptr/const_ptr.rs +++ b/library/core/src/ptr/const_ptr.rs @@ -346,7 +346,7 @@ impl *const T { if self.is_null() { None } else { Some(unsafe { &*(self as *const MaybeUninit) }) } } - /// Adds an offset to a pointer. + /// Adds a signed offset to a pointer. /// /// `count` is in units of T; e.g., a `count` of 3 represents a pointer /// offset of `3 * size_of::()` bytes. @@ -355,7 +355,8 @@ impl *const T { /// /// If any of the following conditions are violated, the result is Undefined Behavior: /// - /// * The computed offset, `count * size_of::()` bytes, must not overflow `isize`. + /// * The computed offset, `count * size_of::()` bytes (using unbounded arithmetic), + /// must fit in an `isize`. /// /// * If the computed offset is non-zero, then `self` must be derived from a pointer to some /// [allocated object], and the entire memory range between `self` and the result must be in @@ -807,7 +808,7 @@ impl *const T { } } - /// Adds an offset to a pointer (convenience for `.offset(count as isize)`). + /// Adds an offset to a pointer. /// /// `count` is in units of T; e.g., a `count` of 3 represents a pointer /// offset of `3 * size_of::()` bytes. @@ -816,7 +817,8 @@ impl *const T { /// /// If any of the following conditions are violated, the result is Undefined Behavior: /// - /// * The computed offset, `count * size_of::()` bytes, must not overflow `isize`. + /// * The computed offset, `count * size_of::()` bytes (using unbounded arithmetic), + /// must fit in an `isize`. /// /// * If the computed offset is non-zero, then `self` must be derived from a pointer to some /// [allocated object], and the entire memory range between `self` and the result must be in @@ -880,8 +882,7 @@ impl *const T { unsafe { self.cast::().add(count).with_metadata_of(self) } } - /// Subtracts an offset from a pointer (convenience for - /// `.offset((count as isize).wrapping_neg())`). + /// Subtracts an offset from a pointer. /// /// `count` is in units of T; e.g., a `count` of 3 represents a pointer /// offset of `3 * size_of::()` bytes. @@ -890,7 +891,8 @@ impl *const T { /// /// If any of the following conditions are violated, the result is Undefined Behavior: /// - /// * The computed offset, `count * size_of::()` bytes, must not overflow `isize`. + /// * The computed offset, `count * size_of::()` bytes (using unbounded arithmetic), + /// must fit in an `isize`. /// /// * If the computed offset is non-zero, then `self` must be derived from a pointer to some /// [allocated object], and the entire memory range between `self` and the result must be in diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index ddb9195d2e7..630983c8355 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -344,7 +344,7 @@ impl *mut T { if self.is_null() { None } else { Some(unsafe { &*(self as *const MaybeUninit) }) } } - /// Adds an offset to a pointer. + /// Adds a signed offset to a pointer. /// /// `count` is in units of T; e.g., a `count` of 3 represents a pointer /// offset of `3 * size_of::()` bytes. @@ -353,7 +353,8 @@ impl *mut T { /// /// If any of the following conditions are violated, the result is Undefined Behavior: /// - /// * The computed offset, `count * size_of::()` bytes, must not overflow `isize`. + /// * The computed offset, `count * size_of::()` bytes (using unbounded arithmetic), + /// must fit in an `isize`. /// /// * If the computed offset is non-zero, then `self` must be derived from a pointer to some /// [allocated object], and the entire memory range between `self` and the result must be in @@ -888,7 +889,7 @@ impl *mut T { unsafe { (self as *const T).sub_ptr(origin) } } - /// Adds an offset to a pointer (convenience for `.offset(count as isize)`). + /// Adds an offset to a pointer. /// /// `count` is in units of T; e.g., a `count` of 3 represents a pointer /// offset of `3 * size_of::()` bytes. @@ -897,7 +898,8 @@ impl *mut T { /// /// If any of the following conditions are violated, the result is Undefined Behavior: /// - /// * The computed offset, `count * size_of::()` bytes, must not overflow `isize`. + /// * The computed offset, `count * size_of::()` bytes (using unbounded arithmetic), + /// must fit in an `isize`. /// /// * If the computed offset is non-zero, then `self` must be derived from a pointer to some /// [allocated object], and the entire memory range between `self` and the result must be in @@ -961,8 +963,7 @@ impl *mut T { unsafe { self.cast::().add(count).with_metadata_of(self) } } - /// Subtracts an offset from a pointer (convenience for - /// `.offset((count as isize).wrapping_neg())`). + /// Subtracts an offset from a pointer. /// /// `count` is in units of T; e.g., a `count` of 3 represents a pointer /// offset of `3 * size_of::()` bytes. @@ -971,7 +972,8 @@ impl *mut T { /// /// If any of the following conditions are violated, the result is Undefined Behavior: /// - /// * The computed offset, `count * size_of::()` bytes, must not overflow `isize`. + /// * The computed offset, `count * size_of::()` bytes (using unbounded arithmetic), + /// must fit in an `isize`. /// /// * If the computed offset is non-zero, then `self` must be derived from a pointer to some /// [allocated object], and the entire memory range between `self` and the result must be in From 0905a7786e44727b265cb11486d742f1c6681e7d Mon Sep 17 00:00:00 2001 From: Caio Date: Wed, 11 Sep 2024 13:58:05 -0300 Subject: [PATCH 111/683] Fix #13381 --- clippy_lints/src/panic_in_result_fn.rs | 12 +++++++----- tests/ui/panic_in_result_fn.rs | 9 +++++++++ 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/clippy_lints/src/panic_in_result_fn.rs b/clippy_lints/src/panic_in_result_fn.rs index 381975199d2..fa15d5e4f9f 100644 --- a/clippy_lints/src/panic_in_result_fn.rs +++ b/clippy_lints/src/panic_in_result_fn.rs @@ -1,8 +1,8 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::macros::root_macro_call_first_node; -use clippy_utils::return_ty; use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::visitors::{for_each_expr, Descend}; +use clippy_utils::{is_inside_always_const_context, return_ty}; use core::ops::ControlFlow; use rustc_hir as hir; use rustc_hir::intravisit::FnKind; @@ -68,10 +68,12 @@ fn lint_impl_body<'tcx>(cx: &LateContext<'tcx>, impl_span: Span, body: &'tcx hir let Some(macro_call) = root_macro_call_first_node(cx, e) else { return ControlFlow::Continue(Descend::Yes); }; - if matches!( - cx.tcx.item_name(macro_call.def_id).as_str(), - "panic" | "assert" | "assert_eq" | "assert_ne" - ) { + if !is_inside_always_const_context(cx.tcx, e.hir_id) + && matches!( + cx.tcx.item_name(macro_call.def_id).as_str(), + "panic" | "assert" | "assert_eq" | "assert_ne" + ) + { panics.push(macro_call.span); ControlFlow::Continue(Descend::No) } else { diff --git a/tests/ui/panic_in_result_fn.rs b/tests/ui/panic_in_result_fn.rs index aaaf9a109ac..e2375aa996f 100644 --- a/tests/ui/panic_in_result_fn.rs +++ b/tests/ui/panic_in_result_fn.rs @@ -71,6 +71,15 @@ fn function_result_with_custom_todo() -> Result // should not emit Ok(true) } +fn issue_13381() -> Result<(), String> { + const { + if N == 0 { + panic!(); + } + } + Ok(()) +} + fn main() -> Result<(), String> { todo!("finish main method"); Ok(()) From 2c93ffb30f9e4804cefa79993875cb0656fb1150 Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Wed, 11 Sep 2024 13:47:41 -0400 Subject: [PATCH 112/683] Add SIMD intrinsic --- src/intrinsic/llvm.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/intrinsic/llvm.rs b/src/intrinsic/llvm.rs index 1a3385a97be..e0abf0ec021 100644 --- a/src/intrinsic/llvm.rs +++ b/src/intrinsic/llvm.rs @@ -294,7 +294,8 @@ pub fn adjust_intrinsic_arguments<'a, 'b, 'gcc, 'tcx>( } "__builtin_ia32_vfmaddsubps512_mask" | "__builtin_ia32_vfmaddsubpd512_mask" - | "__builtin_ia32_cmpsh_mask_round" => { + | "__builtin_ia32_cmpsh_mask_round" + | "__builtin_ia32_vfmaddph512_mask" => { let mut new_args = args.to_vec(); let last_arg = new_args.pop().expect("last arg"); let arg4_type = gcc_func.get_param_type(3); @@ -1131,6 +1132,7 @@ pub fn intrinsic<'gcc, 'tcx>(name: &str, cx: &CodegenCx<'gcc, 'tcx>) -> Function "llvm.x86.avx512fp16.maskz.vfcmadd.cph.512" => "__builtin_ia32_vfcmaddcph512_maskz_round", "llvm.x86.avx512fp16.mask.vfcmadd.csh" => "__builtin_ia32_vfcmaddcsh_mask_round", "llvm.x86.avx512fp16.maskz.vfcmadd.csh" => "__builtin_ia32_vfcmaddcsh_maskz_round", + "llvm.x86.avx512fp16.vfmadd.ph.512" => "__builtin_ia32_vfmaddph512_mask", // TODO: support the tile builtins: "llvm.x86.ldtilecfg" => "__builtin_trap", From 17f3dbf656660497e3c7705596342b087156c0a2 Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Wed, 11 Sep 2024 15:59:02 -0400 Subject: [PATCH 113/683] Add more SIMD intrinsics --- src/intrinsic/llvm.rs | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/src/intrinsic/llvm.rs b/src/intrinsic/llvm.rs index e0abf0ec021..52e5efd6d16 100644 --- a/src/intrinsic/llvm.rs +++ b/src/intrinsic/llvm.rs @@ -1133,6 +1133,38 @@ pub fn intrinsic<'gcc, 'tcx>(name: &str, cx: &CodegenCx<'gcc, 'tcx>) -> Function "llvm.x86.avx512fp16.mask.vfcmadd.csh" => "__builtin_ia32_vfcmaddcsh_mask_round", "llvm.x86.avx512fp16.maskz.vfcmadd.csh" => "__builtin_ia32_vfcmaddcsh_maskz_round", "llvm.x86.avx512fp16.vfmadd.ph.512" => "__builtin_ia32_vfmaddph512_mask", + "llvm.x86.avx512fp16.vcvtsi642sh" => "__builtin_ia32_vcvtsi2sh64_round", + "llvm.x86.avx512fp16.vcvtusi642sh" => "__builtin_ia32_vcvtusi2sh64_round", + "llvm.x86.avx512fp16.vcvtsh2si64" => "__builtin_ia32_vcvtsh2si64_round", + "llvm.x86.avx512fp16.vcvtsh2usi64" => "__builtin_ia32_vcvtsh2usi64_round", + "llvm.x86.avx512fp16.vcvttsh2si64" => "__builtin_ia32_vcvttsh2si64_round", + "llvm.x86.avx512fp16.vcvttsh2usi64" => "__builtin_ia32_vcvttsh2usi64_round", + "llvm.x86.avx512.mask.load.ps.256" => "__builtin_ia32_loadaps256_mask", + "llvm.x86.avx512.mask.load.pd.256" => "__builtin_ia32_loadapd256_mask", + "llvm.x86.avx512.mask.load.d.128" => "__builtin_ia32_movdqa32load128_mask", + "llvm.x86.avx512.mask.load.q.128" => "__builtin_ia32_movdqa64load128_mask", + "llvm.x86.avx512.mask.load.ps.128" => "__builtin_ia32_movdqa64load128_mask", + "llvm.x86.avx512.mask.load.pd.128" => "__builtin_ia32_loadapd128_mask", + "llvm.x86.avx512.mask.storeu.d.256" => "__builtin_ia32_storedqusi256_mask", + "llvm.x86.avx512.mask.storeu.q.256" => "__builtin_ia32_storedqudi256_mask", + "llvm.x86.avx512.mask.storeu.ps.256" => "__builtin_ia32_storeups256_mask", + "llvm.x86.avx512.mask.storeu.pd.256" => "__builtin_ia32_storeupd256_mask", + "llvm.x86.avx512.mask.storeu.d.128" => "__builtin_ia32_storedqusi128_mask", + "llvm.x86.avx512.mask.storeu.q.128" => "__builtin_ia32_storedqudi128_mask", + "llvm.x86.avx512.mask.storeu.ps.128" => "__builtin_ia32_storeups128_mask", + "llvm.x86.avx512.mask.storeu.pd.128" => "__builtin_ia32_storeupd128_mask", + "llvm.x86.avx512.mask.store.d.512" => "__builtin_ia32_movdqa32store512_mask", + "llvm.x86.avx512.mask.store.q.512" => "__builtin_ia32_movdqa64store512_mask", + "llvm.x86.avx512.mask.store.ps.512" => "__builtin_ia32_storeaps512_mask", + "llvm.x86.avx512.mask.store.pd.512" => "__builtin_ia32_storeapd512_mask", + "llvm.x86.avx512.mask.store.d.256" => "__builtin_ia32_movdqa32store256_mask", + "llvm.x86.avx512.mask.store.q.256" => "__builtin_ia32_movdqa64store256_mask", + "llvm.x86.avx512.mask.store.ps.256" => "__builtin_ia32_storeaps256_mask", + "llvm.x86.avx512.mask.store.pd.256" => "__builtin_ia32_storeapd256_mask", + "llvm.x86.avx512.mask.store.d.128" => "__builtin_ia32_movdqa32store128_mask", + "llvm.x86.avx512.mask.store.q.128" => "__builtin_ia32_movdqa64store128_mask", + "llvm.x86.avx512.mask.store.ps.128" => "__builtin_ia32_storeaps128_mask", + "llvm.x86.avx512.mask.store.pd.128" => "__builtin_ia32_storeapd128_mask", // TODO: support the tile builtins: "llvm.x86.ldtilecfg" => "__builtin_trap", From 916eb130be623d7d50f9855baa441935e51067f2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 11 Sep 2024 20:57:05 +0200 Subject: [PATCH 114/683] various updates based on review --- library/core/src/ptr/const_ptr.rs | 31 +++++++++++++++++++------------ library/core/src/ptr/mut_ptr.rs | 31 +++++++++++++++++++------------ 2 files changed, 38 insertions(+), 24 deletions(-) diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs index 3df24e0d512..afec6f87956 100644 --- a/library/core/src/ptr/const_ptr.rs +++ b/library/core/src/ptr/const_ptr.rs @@ -355,8 +355,8 @@ impl *const T { /// /// If any of the following conditions are violated, the result is Undefined Behavior: /// - /// * The computed offset, `count * size_of::()` bytes (using unbounded arithmetic), - /// must fit in an `isize`. + /// * The offset in bytes, `count * size_of::()`, computed on mathematical integers (without + /// "wrapping around"), must fit in an `isize`. /// /// * If the computed offset is non-zero, then `self` must be derived from a pointer to some /// [allocated object], and the entire memory range between `self` and the result must be in @@ -399,7 +399,7 @@ impl *const T { unsafe { intrinsics::offset(self, count) } } - /// Calculates the offset from a pointer in bytes. + /// Adds a signed offset in bytes to a pointer. /// /// `count` is in units of **bytes**. /// @@ -808,7 +808,11 @@ impl *const T { } } - /// Adds an offset to a pointer. + /// Adds an unsigned offset to a pointer. + /// + /// This can only move the pointer forward (or not move it). If you need to move forward or + /// backward depending on the value, then you might want [`offset`](#method.offset) instead + /// which takes a signed offset. /// /// `count` is in units of T; e.g., a `count` of 3 represents a pointer /// offset of `3 * size_of::()` bytes. @@ -817,8 +821,8 @@ impl *const T { /// /// If any of the following conditions are violated, the result is Undefined Behavior: /// - /// * The computed offset, `count * size_of::()` bytes (using unbounded arithmetic), - /// must fit in an `isize`. + /// * The offset in bytes, `count * size_of::()`, computed on mathematical integers (without + /// "wrapping around"), must fit in an `isize`. /// /// * If the computed offset is non-zero, then `self` must be derived from a pointer to some /// [allocated object], and the entire memory range between `self` and the result must be in @@ -861,7 +865,7 @@ impl *const T { unsafe { intrinsics::offset(self, count) } } - /// Calculates the offset from a pointer in bytes (convenience for `.byte_offset(count as isize)`). + /// Adds an unsigned offset in bytes to a pointer. /// /// `count` is in units of bytes. /// @@ -882,7 +886,11 @@ impl *const T { unsafe { self.cast::().add(count).with_metadata_of(self) } } - /// Subtracts an offset from a pointer. + /// Subtracts an unsigned offset from a pointer. + /// + /// This can only move the pointer backward (or not move it). If you need to move forward or + /// backward depending on the value, then you might want [`offset`](#method.offset) instead + /// which takes a signed offset. /// /// `count` is in units of T; e.g., a `count` of 3 represents a pointer /// offset of `3 * size_of::()` bytes. @@ -891,8 +899,8 @@ impl *const T { /// /// If any of the following conditions are violated, the result is Undefined Behavior: /// - /// * The computed offset, `count * size_of::()` bytes (using unbounded arithmetic), - /// must fit in an `isize`. + /// * The offset in bytes, `count * size_of::()`, computed on mathematical integers (without + /// "wrapping around"), must fit in an `isize`. /// /// * If the computed offset is non-zero, then `self` must be derived from a pointer to some /// [allocated object], and the entire memory range between `self` and the result must be in @@ -943,8 +951,7 @@ impl *const T { } } - /// Calculates the offset from a pointer in bytes (convenience for - /// `.byte_offset((count as isize).wrapping_neg())`). + /// Subtracts an unsigned offset in bytes from a pointer. /// /// `count` is in units of bytes. /// diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index 630983c8355..11fb45b1e09 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -353,8 +353,8 @@ impl *mut T { /// /// If any of the following conditions are violated, the result is Undefined Behavior: /// - /// * The computed offset, `count * size_of::()` bytes (using unbounded arithmetic), - /// must fit in an `isize`. + /// * The offset in bytes, `count * size_of::()`, computed on mathematical integers (without + /// "wrapping around"), must fit in an `isize`. /// /// * If the computed offset is non-zero, then `self` must be derived from a pointer to some /// [allocated object], and the entire memory range between `self` and the result must be in @@ -399,7 +399,7 @@ impl *mut T { unsafe { intrinsics::offset(self, count) } } - /// Calculates the offset from a pointer in bytes. + /// Adds a signed offset in bytes to a pointer. /// /// `count` is in units of **bytes**. /// @@ -889,7 +889,11 @@ impl *mut T { unsafe { (self as *const T).sub_ptr(origin) } } - /// Adds an offset to a pointer. + /// Adds an unsigned offset to a pointer. + /// + /// This can only move the pointer forward (or not move it). If you need to move forward or + /// backward depending on the value, then you might want [`offset`](#method.offset) instead + /// which takes a signed offset. /// /// `count` is in units of T; e.g., a `count` of 3 represents a pointer /// offset of `3 * size_of::()` bytes. @@ -898,8 +902,8 @@ impl *mut T { /// /// If any of the following conditions are violated, the result is Undefined Behavior: /// - /// * The computed offset, `count * size_of::()` bytes (using unbounded arithmetic), - /// must fit in an `isize`. + /// * The offset in bytes, `count * size_of::()`, computed on mathematical integers (without + /// "wrapping around"), must fit in an `isize`. /// /// * If the computed offset is non-zero, then `self` must be derived from a pointer to some /// [allocated object], and the entire memory range between `self` and the result must be in @@ -942,7 +946,7 @@ impl *mut T { unsafe { intrinsics::offset(self, count) } } - /// Calculates the offset from a pointer in bytes (convenience for `.byte_offset(count as isize)`). + /// Adds an unsigned offset in bytes to a pointer. /// /// `count` is in units of bytes. /// @@ -963,7 +967,11 @@ impl *mut T { unsafe { self.cast::().add(count).with_metadata_of(self) } } - /// Subtracts an offset from a pointer. + /// Subtracts an unsigned offset from a pointer. + /// + /// This can only move the pointer backward (or not move it). If you need to move forward or + /// backward depending on the value, then you might want [`offset`](#method.offset) instead + /// which takes a signed offset. /// /// `count` is in units of T; e.g., a `count` of 3 represents a pointer /// offset of `3 * size_of::()` bytes. @@ -972,8 +980,8 @@ impl *mut T { /// /// If any of the following conditions are violated, the result is Undefined Behavior: /// - /// * The computed offset, `count * size_of::()` bytes (using unbounded arithmetic), - /// must fit in an `isize`. + /// * The offset in bytes, `count * size_of::()`, computed on mathematical integers (without + /// "wrapping around"), must fit in an `isize`. /// /// * If the computed offset is non-zero, then `self` must be derived from a pointer to some /// [allocated object], and the entire memory range between `self` and the result must be in @@ -1024,8 +1032,7 @@ impl *mut T { } } - /// Calculates the offset from a pointer in bytes (convenience for - /// `.byte_offset((count as isize).wrapping_neg())`). + /// Subtracts an unsigned offset in bytes from a pointer. /// /// `count` is in units of bytes. /// From 1c2e9f8775f9911cb81ddf1b20a59ed2137b004a Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 11 Sep 2024 18:52:36 -0400 Subject: [PATCH 115/683] Remove unused functions from ast CoroutineKind --- clippy_utils/src/ast_utils.rs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/clippy_utils/src/ast_utils.rs b/clippy_utils/src/ast_utils.rs index 181bbdde8e5..de8bbb619f8 100644 --- a/clippy_utils/src/ast_utils.rs +++ b/clippy_utils/src/ast_utils.rs @@ -221,7 +221,7 @@ pub fn eq_expr(l: &Expr, r: &Expr) -> bool { ) => { eq_closure_binder(lb, rb) && lc == rc - && la.map_or(false, CoroutineKind::is_async) == ra.map_or(false, CoroutineKind::is_async) + && eq_coroutine_kind(*la, *ra) && lm == rm && eq_fn_decl(lf, rf) && eq_expr(le, re) @@ -241,6 +241,16 @@ pub fn eq_expr(l: &Expr, r: &Expr) -> bool { } } +fn eq_coroutine_kind(a: Option, b: Option) -> bool { + match (a, b) { + (Some(CoroutineKind::Async { .. }), Some(CoroutineKind::Async { .. })) + | (Some(CoroutineKind::Gen { .. }), Some(CoroutineKind::Gen { .. })) + | (Some(CoroutineKind::AsyncGen { .. }), Some(CoroutineKind::AsyncGen { .. })) + | (None, None) => true, + _ => false, + } +} + pub fn eq_field(l: &ExprField, r: &ExprField) -> bool { l.is_placeholder == r.is_placeholder && eq_id(l.ident, r.ident) From 7097830a9b6c2d9c56d0b8cea7b0612dc8a53b50 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Thu, 12 Sep 2024 11:49:16 +0500 Subject: [PATCH 116/683] Not trigger duplicated_attributes on duplicate reasons --- clippy_lints/src/attrs/duplicated_attributes.rs | 2 +- tests/ui/duplicated_attributes.rs | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/clippy_lints/src/attrs/duplicated_attributes.rs b/clippy_lints/src/attrs/duplicated_attributes.rs index 40a1c4e2884..199e07565b0 100644 --- a/clippy_lints/src/attrs/duplicated_attributes.rs +++ b/clippy_lints/src/attrs/duplicated_attributes.rs @@ -36,7 +36,7 @@ fn check_duplicated_attr( } let Some(ident) = attr.ident() else { return }; let name = ident.name; - if name == sym::doc || name == sym::cfg_attr || name == sym::rustc_on_unimplemented { + if name == sym::doc || name == sym::cfg_attr || name == sym::rustc_on_unimplemented || name == sym::reason { // FIXME: Would be nice to handle `cfg_attr` as well. Only problem is to check that cfg // conditions are the same. // `#[rustc_on_unimplemented]` contains duplicated subattributes, that's expected. diff --git a/tests/ui/duplicated_attributes.rs b/tests/ui/duplicated_attributes.rs index 97cf4a69682..874f5d22075 100644 --- a/tests/ui/duplicated_attributes.rs +++ b/tests/ui/duplicated_attributes.rs @@ -27,4 +27,8 @@ trait Abc {} #[proc_macro_attr::duplicated_attr()] // Should not warn! fn babar() {} +#[allow(missing_docs, reason = "library for internal use only")] +#[allow(exported_private_dependencies, reason = "library for internal use only")] +fn duplicate_reason() {} + fn main() {} From bc3d0722062b8e208ba9096b8445ef69a896ed7d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 12 Sep 2024 16:25:09 +0200 Subject: [PATCH 117/683] also update the wrapping_ docs to use similar wording --- library/core/src/ptr/const_ptr.rs | 16 ++++++---------- library/core/src/ptr/mut_ptr.rs | 17 +++++++---------- 2 files changed, 13 insertions(+), 20 deletions(-) diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs index afec6f87956..57307c149a4 100644 --- a/library/core/src/ptr/const_ptr.rs +++ b/library/core/src/ptr/const_ptr.rs @@ -420,7 +420,7 @@ impl *const T { unsafe { self.cast::().offset(count).with_metadata_of(self) } } - /// Calculates the offset from a pointer using wrapping arithmetic. + /// Adds a signed offset to a pointer using wrapping arithmetic. /// /// `count` is in units of T; e.g., a `count` of 3 represents a pointer /// offset of `3 * size_of::()` bytes. @@ -482,7 +482,7 @@ impl *const T { unsafe { intrinsics::arith_offset(self, count) } } - /// Calculates the offset from a pointer in bytes using wrapping arithmetic. + /// Adds a signed offset in bytes to a pointer using wrapping arithmetic. /// /// `count` is in units of **bytes**. /// @@ -972,8 +972,7 @@ impl *const T { unsafe { self.cast::().sub(count).with_metadata_of(self) } } - /// Calculates the offset from a pointer using wrapping arithmetic. - /// (convenience for `.wrapping_offset(count as isize)`) + /// Adds an unsigned offset to a pointer using wrapping arithmetic. /// /// `count` is in units of T; e.g., a `count` of 3 represents a pointer /// offset of `3 * size_of::()` bytes. @@ -1034,8 +1033,7 @@ impl *const T { self.wrapping_offset(count as isize) } - /// Calculates the offset from a pointer in bytes using wrapping arithmetic. - /// (convenience for `.wrapping_byte_offset(count as isize)`) + /// Adds an unsigned offset in bytes to a pointer using wrapping arithmetic. /// /// `count` is in units of bytes. /// @@ -1053,8 +1051,7 @@ impl *const T { self.cast::().wrapping_add(count).with_metadata_of(self) } - /// Calculates the offset from a pointer using wrapping arithmetic. - /// (convenience for `.wrapping_offset((count as isize).wrapping_neg())`) + /// Subtracts an unsigned offset from a pointer using wrapping arithmetic. /// /// `count` is in units of T; e.g., a `count` of 3 represents a pointer /// offset of `3 * size_of::()` bytes. @@ -1115,8 +1112,7 @@ impl *const T { self.wrapping_offset((count as isize).wrapping_neg()) } - /// Calculates the offset from a pointer in bytes using wrapping arithmetic. - /// (convenience for `.wrapping_offset((count as isize).wrapping_neg())`) + /// Subtracts an unsigned offset in bytes from a pointer using wrapping arithmetic. /// /// `count` is in units of bytes. /// diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index 11fb45b1e09..e09419ff1a7 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -420,7 +420,8 @@ impl *mut T { unsafe { self.cast::().offset(count).with_metadata_of(self) } } - /// Calculates the offset from a pointer using wrapping arithmetic. + /// Adds a signed offset to a pointer using wrapping arithmetic. + /// /// `count` is in units of T; e.g., a `count` of 3 represents a pointer /// offset of `3 * size_of::()` bytes. /// @@ -479,7 +480,7 @@ impl *mut T { unsafe { intrinsics::arith_offset(self, count) as *mut T } } - /// Calculates the offset from a pointer in bytes using wrapping arithmetic. + /// Adds a signed offset in bytes to a pointer using wrapping arithmetic. /// /// `count` is in units of **bytes**. /// @@ -1053,8 +1054,7 @@ impl *mut T { unsafe { self.cast::().sub(count).with_metadata_of(self) } } - /// Calculates the offset from a pointer using wrapping arithmetic. - /// (convenience for `.wrapping_offset(count as isize)`) + /// Adds an unsigned offset to a pointer using wrapping arithmetic. /// /// `count` is in units of T; e.g., a `count` of 3 represents a pointer /// offset of `3 * size_of::()` bytes. @@ -1113,8 +1113,7 @@ impl *mut T { self.wrapping_offset(count as isize) } - /// Calculates the offset from a pointer in bytes using wrapping arithmetic. - /// (convenience for `.wrapping_byte_offset(count as isize)`) + /// Adds an unsigned offset in bytes to a pointer using wrapping arithmetic. /// /// `count` is in units of bytes. /// @@ -1132,8 +1131,7 @@ impl *mut T { self.cast::().wrapping_add(count).with_metadata_of(self) } - /// Calculates the offset from a pointer using wrapping arithmetic. - /// (convenience for `.wrapping_offset((count as isize).wrapping_neg())`) + /// Subtracts an unsigned offset from a pointer using wrapping arithmetic. /// /// `count` is in units of T; e.g., a `count` of 3 represents a pointer /// offset of `3 * size_of::()` bytes. @@ -1192,8 +1190,7 @@ impl *mut T { self.wrapping_offset((count as isize).wrapping_neg()) } - /// Calculates the offset from a pointer in bytes using wrapping arithmetic. - /// (convenience for `.wrapping_offset((count as isize).wrapping_neg())`) + /// Subtracts an unsigned offset in bytes from a pointer using wrapping arithmetic. /// /// `count` is in units of bytes. /// From 6371b308d86757a6328ad4b6ecb3bcdd2a1c6d7a Mon Sep 17 00:00:00 2001 From: Samuel Tardieu Date: Thu, 12 Sep 2024 16:31:05 +0200 Subject: [PATCH 118/683] Make it clearer that the suggestion is an alternative one `needless_pass_by_value` sometimes suggest marking the concerned type as `Copy`. Adding a `or` before this suggestion makes it clearer that this is not the second part of the original suggestion, but an alternative one. --- clippy_lints/src/needless_pass_by_value.rs | 2 +- .../ui/crashes/needless_pass_by_value-w-late-bound.stderr | 2 +- tests/ui/needless_pass_by_value.stderr | 8 ++++---- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/clippy_lints/src/needless_pass_by_value.rs b/clippy_lints/src/needless_pass_by_value.rs index 5bf390056f6..887070bcf9a 100644 --- a/clippy_lints/src/needless_pass_by_value.rs +++ b/clippy_lints/src/needless_pass_by_value.rs @@ -208,7 +208,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue { ) .is_ok() { - diag.span_help(span, "consider marking this type as `Copy`"); + diag.span_help(span, "or consider marking this type as `Copy`"); } } } diff --git a/tests/ui/crashes/needless_pass_by_value-w-late-bound.stderr b/tests/ui/crashes/needless_pass_by_value-w-late-bound.stderr index 90076d4338a..28479570006 100644 --- a/tests/ui/crashes/needless_pass_by_value-w-late-bound.stderr +++ b/tests/ui/crashes/needless_pass_by_value-w-late-bound.stderr @@ -4,7 +4,7 @@ error: this argument is passed by value, but not consumed in the function body LL | fn test(x: Foo<'_>) {} | ^^^^^^^ help: consider taking a reference instead: `&Foo<'_>` | -help: consider marking this type as `Copy` +help: or consider marking this type as `Copy` --> tests/ui/crashes/needless_pass_by_value-w-late-bound.rs:5:1 | LL | struct Foo<'a>(&'a [(); 100]); diff --git a/tests/ui/needless_pass_by_value.stderr b/tests/ui/needless_pass_by_value.stderr index dce28186ff8..46ef8f3e8da 100644 --- a/tests/ui/needless_pass_by_value.stderr +++ b/tests/ui/needless_pass_by_value.stderr @@ -121,7 +121,7 @@ error: this argument is passed by value, but not consumed in the function body LL | fn bar_copy(x: u32, y: CopyWrapper) { | ^^^^^^^^^^^ help: consider taking a reference instead: `&CopyWrapper` | -help: consider marking this type as `Copy` +help: or consider marking this type as `Copy` --> tests/ui/needless_pass_by_value.rs:141:1 | LL | struct CopyWrapper(u32); @@ -133,7 +133,7 @@ error: this argument is passed by value, but not consumed in the function body LL | fn test_destructure_copy(x: CopyWrapper, y: CopyWrapper, z: CopyWrapper) { | ^^^^^^^^^^^ help: consider taking a reference instead: `&CopyWrapper` | -help: consider marking this type as `Copy` +help: or consider marking this type as `Copy` --> tests/ui/needless_pass_by_value.rs:141:1 | LL | struct CopyWrapper(u32); @@ -145,7 +145,7 @@ error: this argument is passed by value, but not consumed in the function body LL | fn test_destructure_copy(x: CopyWrapper, y: CopyWrapper, z: CopyWrapper) { | ^^^^^^^^^^^ help: consider taking a reference instead: `&CopyWrapper` | -help: consider marking this type as `Copy` +help: or consider marking this type as `Copy` --> tests/ui/needless_pass_by_value.rs:141:1 | LL | struct CopyWrapper(u32); @@ -157,7 +157,7 @@ error: this argument is passed by value, but not consumed in the function body LL | fn test_destructure_copy(x: CopyWrapper, y: CopyWrapper, z: CopyWrapper) { | ^^^^^^^^^^^ help: consider taking a reference instead: `&CopyWrapper` | -help: consider marking this type as `Copy` +help: or consider marking this type as `Copy` --> tests/ui/needless_pass_by_value.rs:141:1 | LL | struct CopyWrapper(u32); From e3c822df4e2f61de314a2c1b17705a2b02d84b66 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eduardo=20S=C3=A1nchez=20Mu=C3=B1oz?= Date: Mon, 9 Sep 2024 18:16:23 +0200 Subject: [PATCH 119/683] Stabilize `const_float_classify` --- library/core/src/lib.rs | 1 - library/core/src/num/f128.rs | 12 ++++++------ library/core/src/num/f16.rs | 12 ++++++------ library/core/src/num/f32.rs | 17 ++++++++--------- library/core/src/num/f64.rs | 17 ++++++++--------- 5 files changed, 28 insertions(+), 31 deletions(-) diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index bda38254362..3f2245dac5b 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -121,7 +121,6 @@ #![feature(const_cell_into_inner)] #![feature(const_eval_select)] #![feature(const_exact_div)] -#![feature(const_float_classify)] #![feature(const_fmt_arguments_new)] #![feature(const_hash)] #![feature(const_heap)] diff --git a/library/core/src/num/f128.rs b/library/core/src/num/f128.rs index 1959628bd8f..5506c2dbc09 100644 --- a/library/core/src/num/f128.rs +++ b/library/core/src/num/f128.rs @@ -288,7 +288,7 @@ impl f128 { // concerns about portability, so this implementation is for // private use internally. #[inline] - #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")] + #[rustc_const_unstable(feature = "f128", issue = "116909")] pub(crate) const fn abs_private(self) -> f128 { // SAFETY: This transmutation is fine just like in `to_bits`/`from_bits`. unsafe { @@ -319,7 +319,7 @@ impl f128 { #[inline] #[must_use] #[unstable(feature = "f128", issue = "116909")] - #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")] + #[rustc_const_unstable(feature = "f128", issue = "116909")] pub const fn is_infinite(self) -> bool { (self == f128::INFINITY) | (self == f128::NEG_INFINITY) } @@ -346,7 +346,7 @@ impl f128 { #[inline] #[must_use] #[unstable(feature = "f128", issue = "116909")] - #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")] + #[rustc_const_unstable(feature = "f128", issue = "116909")] pub const fn is_finite(self) -> bool { // There's no need to handle NaN separately: if self is NaN, // the comparison is not true, exactly as desired. @@ -380,7 +380,7 @@ impl f128 { #[inline] #[must_use] #[unstable(feature = "f128", issue = "116909")] - #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")] + #[rustc_const_unstable(feature = "f128", issue = "116909")] pub const fn is_subnormal(self) -> bool { matches!(self.classify(), FpCategory::Subnormal) } @@ -412,7 +412,7 @@ impl f128 { #[inline] #[must_use] #[unstable(feature = "f128", issue = "116909")] - #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")] + #[rustc_const_unstable(feature = "f128", issue = "116909")] pub const fn is_normal(self) -> bool { matches!(self.classify(), FpCategory::Normal) } @@ -437,7 +437,7 @@ impl f128 { /// ``` #[inline] #[unstable(feature = "f128", issue = "116909")] - #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")] + #[rustc_const_unstable(feature = "f128", issue = "116909")] pub const fn classify(self) -> FpCategory { // Other float types suffer from various platform bugs that violate the usual IEEE semantics // and also make bitwise classification not always work reliably. However, `f128` cannot fit diff --git a/library/core/src/num/f16.rs b/library/core/src/num/f16.rs index da92da1086d..ecfae7b6a89 100644 --- a/library/core/src/num/f16.rs +++ b/library/core/src/num/f16.rs @@ -282,7 +282,7 @@ impl f16 { // concerns about portability, so this implementation is for // private use internally. #[inline] - #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")] + #[rustc_const_unstable(feature = "f16", issue = "116909")] pub(crate) const fn abs_private(self) -> f16 { // SAFETY: This transmutation is fine just like in `to_bits`/`from_bits`. unsafe { mem::transmute::(mem::transmute::(self) & !Self::SIGN_MASK) } @@ -310,7 +310,7 @@ impl f16 { #[inline] #[must_use] #[unstable(feature = "f16", issue = "116909")] - #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")] + #[rustc_const_unstable(feature = "f16", issue = "116909")] pub const fn is_infinite(self) -> bool { (self == f16::INFINITY) | (self == f16::NEG_INFINITY) } @@ -336,7 +336,7 @@ impl f16 { #[inline] #[must_use] #[unstable(feature = "f16", issue = "116909")] - #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")] + #[rustc_const_unstable(feature = "f16", issue = "116909")] pub const fn is_finite(self) -> bool { // There's no need to handle NaN separately: if self is NaN, // the comparison is not true, exactly as desired. @@ -368,7 +368,7 @@ impl f16 { #[inline] #[must_use] #[unstable(feature = "f16", issue = "116909")] - #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")] + #[rustc_const_unstable(feature = "f16", issue = "116909")] pub const fn is_subnormal(self) -> bool { matches!(self.classify(), FpCategory::Subnormal) } @@ -398,7 +398,7 @@ impl f16 { #[inline] #[must_use] #[unstable(feature = "f16", issue = "116909")] - #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")] + #[rustc_const_unstable(feature = "f16", issue = "116909")] pub const fn is_normal(self) -> bool { matches!(self.classify(), FpCategory::Normal) } @@ -422,7 +422,7 @@ impl f16 { /// ``` #[inline] #[unstable(feature = "f16", issue = "116909")] - #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")] + #[rustc_const_unstable(feature = "f16", issue = "116909")] pub const fn classify(self) -> FpCategory { // A previous implementation for f32/f64 tried to only use bitmask-based checks, // using `to_bits` to transmute the float to its bit repr and match on that. diff --git a/library/core/src/num/f32.rs b/library/core/src/num/f32.rs index 885f7608a33..9d872b3b676 100644 --- a/library/core/src/num/f32.rs +++ b/library/core/src/num/f32.rs @@ -516,7 +516,7 @@ impl f32 { /// ``` #[must_use] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")] + #[rustc_const_stable(feature = "const_float_classify", since = "CURRENT_RUSTC_VERSION")] #[inline] #[allow(clippy::eq_op)] // > if you intended to check if the operand is NaN, use `.is_nan()` instead :) pub const fn is_nan(self) -> bool { @@ -527,7 +527,6 @@ impl f32 { // concerns about portability, so this implementation is for // private use internally. #[inline] - #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")] pub(crate) const fn abs_private(self) -> f32 { // SAFETY: This transmutation is fine just like in `to_bits`/`from_bits`. unsafe { mem::transmute::(mem::transmute::(self) & !Self::SIGN_MASK) } @@ -550,7 +549,7 @@ impl f32 { /// ``` #[must_use] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")] + #[rustc_const_stable(feature = "const_float_classify", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const fn is_infinite(self) -> bool { // Getting clever with transmutation can result in incorrect answers on some FPUs @@ -575,7 +574,7 @@ impl f32 { /// ``` #[must_use] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")] + #[rustc_const_stable(feature = "const_float_classify", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const fn is_finite(self) -> bool { // There's no need to handle NaN separately: if self is NaN, @@ -603,7 +602,7 @@ impl f32 { /// [subnormal]: https://en.wikipedia.org/wiki/Denormal_number #[must_use] #[stable(feature = "is_subnormal", since = "1.53.0")] - #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")] + #[rustc_const_stable(feature = "const_float_classify", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const fn is_subnormal(self) -> bool { matches!(self.classify(), FpCategory::Subnormal) @@ -630,7 +629,7 @@ impl f32 { /// [subnormal]: https://en.wikipedia.org/wiki/Denormal_number #[must_use] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")] + #[rustc_const_stable(feature = "const_float_classify", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const fn is_normal(self) -> bool { matches!(self.classify(), FpCategory::Normal) @@ -650,7 +649,7 @@ impl f32 { /// assert_eq!(inf.classify(), FpCategory::Infinite); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")] + #[rustc_const_stable(feature = "const_float_classify", since = "CURRENT_RUSTC_VERSION")] pub const fn classify(self) -> FpCategory { // A previous implementation tried to only use bitmask-based checks, // using f32::to_bits to transmute the float to its bit repr and match on that. @@ -710,7 +709,7 @@ impl f32 { /// ``` #[must_use] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")] + #[rustc_const_stable(feature = "const_float_classify", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const fn is_sign_positive(self) -> bool { !self.is_sign_negative() @@ -735,7 +734,7 @@ impl f32 { /// ``` #[must_use] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")] + #[rustc_const_stable(feature = "const_float_classify", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const fn is_sign_negative(self) -> bool { // IEEE754 says: isSignMinus(x) is true if and only if x has negative sign. isSignMinus diff --git a/library/core/src/num/f64.rs b/library/core/src/num/f64.rs index 28cc231ccc7..a026d551a51 100644 --- a/library/core/src/num/f64.rs +++ b/library/core/src/num/f64.rs @@ -515,7 +515,7 @@ impl f64 { /// ``` #[must_use] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")] + #[rustc_const_stable(feature = "const_float_classify", since = "CURRENT_RUSTC_VERSION")] #[inline] #[allow(clippy::eq_op)] // > if you intended to check if the operand is NaN, use `.is_nan()` instead :) pub const fn is_nan(self) -> bool { @@ -526,7 +526,6 @@ impl f64 { // concerns about portability, so this implementation is for // private use internally. #[inline] - #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")] pub(crate) const fn abs_private(self) -> f64 { // SAFETY: This transmutation is fine just like in `to_bits`/`from_bits`. unsafe { mem::transmute::(mem::transmute::(self) & !Self::SIGN_MASK) } @@ -549,7 +548,7 @@ impl f64 { /// ``` #[must_use] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")] + #[rustc_const_stable(feature = "const_float_classify", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const fn is_infinite(self) -> bool { // Getting clever with transmutation can result in incorrect answers on some FPUs @@ -574,7 +573,7 @@ impl f64 { /// ``` #[must_use] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")] + #[rustc_const_stable(feature = "const_float_classify", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const fn is_finite(self) -> bool { // There's no need to handle NaN separately: if self is NaN, @@ -602,7 +601,7 @@ impl f64 { /// [subnormal]: https://en.wikipedia.org/wiki/Denormal_number #[must_use] #[stable(feature = "is_subnormal", since = "1.53.0")] - #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")] + #[rustc_const_stable(feature = "const_float_classify", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const fn is_subnormal(self) -> bool { matches!(self.classify(), FpCategory::Subnormal) @@ -629,7 +628,7 @@ impl f64 { /// [subnormal]: https://en.wikipedia.org/wiki/Denormal_number #[must_use] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")] + #[rustc_const_stable(feature = "const_float_classify", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const fn is_normal(self) -> bool { matches!(self.classify(), FpCategory::Normal) @@ -649,7 +648,7 @@ impl f64 { /// assert_eq!(inf.classify(), FpCategory::Infinite); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")] + #[rustc_const_stable(feature = "const_float_classify", since = "CURRENT_RUSTC_VERSION")] pub const fn classify(self) -> FpCategory { // A previous implementation tried to only use bitmask-based checks, // using f64::to_bits to transmute the float to its bit repr and match on that. @@ -705,7 +704,7 @@ impl f64 { /// ``` #[must_use] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")] + #[rustc_const_stable(feature = "const_float_classify", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const fn is_sign_positive(self) -> bool { !self.is_sign_negative() @@ -739,7 +738,7 @@ impl f64 { /// ``` #[must_use] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")] + #[rustc_const_stable(feature = "const_float_classify", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const fn is_sign_negative(self) -> bool { // IEEE754 says: isSignMinus(x) is true if and only if x has negative sign. isSignMinus From e2c983138876cc29d89c9320b05a6614607d11c7 Mon Sep 17 00:00:00 2001 From: "Tim (Theemathas) Chirananthavat" Date: Thu, 12 Sep 2024 23:39:45 +0700 Subject: [PATCH 120/683] Document subtleties of `ManuallyDrop` --- library/core/src/mem/manually_drop.rs | 126 +++++++++++++++++++++++--- 1 file changed, 115 insertions(+), 11 deletions(-) diff --git a/library/core/src/mem/manually_drop.rs b/library/core/src/mem/manually_drop.rs index be5cee2e852..f4b56c9f13e 100644 --- a/library/core/src/mem/manually_drop.rs +++ b/library/core/src/mem/manually_drop.rs @@ -1,20 +1,19 @@ use crate::ops::{Deref, DerefMut, DerefPure}; use crate::ptr; -/// A wrapper to inhibit the compiler from automatically calling `T`’s destructor. -/// This wrapper is 0-cost. +/// A wrapper to inhibit the compiler from automatically calling `T`’s +/// destructor. This wrapper is 0-cost. /// /// `ManuallyDrop` is guaranteed to have the same layout and bit validity as -/// `T`, and is subject to the same layout optimizations as `T`. As a consequence, -/// it has *no effect* on the assumptions that the compiler makes about its -/// contents. For example, initializing a `ManuallyDrop<&mut T>` with [`mem::zeroed`] -/// is undefined behavior. If you need to handle uninitialized data, use -/// [`MaybeUninit`] instead. +/// `T`, and is subject to the same layout optimizations as `T`. As a +/// consequence, it has *no effect* on the assumptions that the compiler makes +/// about its contents. For example, initializing a `ManuallyDrop<&mut T>` with +/// [`mem::zeroed`] is undefined behavior. If you need to handle uninitialized +/// data, use [`MaybeUninit`] instead. /// -/// Note that accessing the value inside a `ManuallyDrop` is safe. -/// This means that a `ManuallyDrop` whose content has been dropped must not -/// be exposed through a public safe API. -/// Correspondingly, `ManuallyDrop::drop` is unsafe. +/// Note that accessing the value inside a `ManuallyDrop` is safe. This means +/// that a `ManuallyDrop` whose content has been dropped must not be exposed +/// through a public safe API. Correspondingly, `ManuallyDrop::drop` is unsafe. /// /// # `ManuallyDrop` and drop order. /// @@ -40,9 +39,114 @@ use crate::ptr; /// } /// ``` /// +/// # Interaction with `Box`. +/// +/// Currently, once the `Box` inside a `ManuallyDrop>` is dropped, +/// moving the `ManuallyDrop>` is [considered to be undefined +/// behavior](https://github.com/rust-lang/unsafe-code-guidelines/issues/245). +/// That is, the following code causes undefined behavior: +/// +/// ```no_run +/// use std::mem::ManuallyDrop; +/// +/// let mut x = ManuallyDrop::new(Box::new(42)); +/// unsafe { +/// ManuallyDrop::drop(&mut x); +/// } +/// let y = x; // Undefined behavior! +/// ``` +/// +/// This may change in the future. In the meantime, consider using +/// [`MaybeUninit`] instead. +/// +/// # Safety hazards when storing `ManuallyDrop` in a struct / enum. +/// +/// Special care is needed when all of the conditions below are met: +/// * A field of a struct or enum is a `ManuallyDrop` or contains a +/// `ManuallyDrop`, without the `ManuallyDrop` being inside a `union`. +/// * The struct or enum is part of public API, or is stored in a struct or enum +/// that is part of public API. +/// * There is code outside of a `Drop` implementation that calls +/// [`ManuallyDrop::drop`] or [`ManuallyDrop::take`] on the `ManuallyDrop` +/// field. +/// +/// In particular, the following hazards can occur: +/// +/// #### Storing generic types +/// +/// If the `ManuallyDrop` contains a client-supplied generic type, the client +/// might provide a `Box`, causing undefined behavior when the struct / enum is +/// later moved, as mentioned above. For example, the following code causes +/// undefined behavior: +/// +/// ```no_run +/// use std::mem::ManuallyDrop; +/// +/// pub struct BadOption { +/// // Invariant: Has been dropped iff `is_some` is false. +/// value: ManuallyDrop, +/// is_some: bool, +/// } +/// impl BadOption { +/// pub fn new(value: T) -> Self { +/// Self { value: ManuallyDrop::new(value), is_some: true } +/// } +/// pub fn change_to_none(&mut self) { +/// if self.is_some { +/// self.is_some = false; +/// unsafe { +/// // SAFETY: `value` hasn't been dropped yet, as per the invariant +/// // (This is actually unsound!) +/// ManuallyDrop::drop(&mut self.value); +/// } +/// } +/// } +/// } +/// +/// // In another crate: +/// +/// let mut option = BadOption::new(Box::new(42)); +/// option.change_to_none(); +/// let option2 = option; // Undefined behavior! +/// ``` +/// +/// #### Deriving traits +/// +/// Deriving `Debug`, `Clone`, `PartialEq`, `PartialOrd`, `Ord`, or `Hash` on +/// the struct / enum could be unsound, since the derived implementations of +/// these traits would access the `ManuallyDrop` field. For example, the +/// following code causes undefined behavior: +/// +/// ```no_run +/// use std::mem::ManuallyDrop; +/// +/// #[derive(Debug)] // This is unsound! +/// pub struct Foo { +/// value: ManuallyDrop, +/// } +/// impl Foo { +/// pub fn new() -> Self { +/// let mut temp = Self { +/// value: ManuallyDrop::new(String::from("Unsafe rust is hard")) +/// }; +/// unsafe { +/// // SAFETY: `value` hasn't been dropped yet. +/// ManuallyDrop::drop(&mut temp.value); +/// } +/// temp +/// } +/// } +/// +/// // In another crate: +/// +/// let foo = Foo::new(); +/// println!("{:?}", foo); // Undefined behavior! +/// ``` +/// /// [drop order]: https://doc.rust-lang.org/reference/destructors.html /// [`mem::zeroed`]: crate::mem::zeroed /// [`MaybeUninit`]: crate::mem::MaybeUninit +/// [`MaybeUninit`]: crate::mem::MaybeUninit #[stable(feature = "manually_drop", since = "1.20.0")] #[lang = "manually_drop"] #[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] From d66e9addd685c8fc2264e68590d745e869311242 Mon Sep 17 00:00:00 2001 From: VictorHugoPilled Date: Tue, 10 Sep 2024 21:38:59 +0000 Subject: [PATCH 121/683] fix: Fixed incorrect comment form suggestion chore: Ran cargo dev fmt chore: Fixed spacing fix: Fixed spacing for comment suggestion fix: Added new module level test to too_long_first_doc_paragraph chore: Ran cargo uibless --- .../src/doc/too_long_first_doc_paragraph.rs | 9 +++++- tests/ui/too_long_first_doc_paragraph.rs | 10 +++++++ tests/ui/too_long_first_doc_paragraph.stderr | 28 +++++++++++++++---- 3 files changed, 40 insertions(+), 7 deletions(-) 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 7bb3bb12f2c..0165d24c7df 100644 --- a/clippy_lints/src/doc/too_long_first_doc_paragraph.rs +++ b/clippy_lints/src/doc/too_long_first_doc_paragraph.rs @@ -79,10 +79,17 @@ pub(super) fn check( && let new_span = first_span.with_hi(second_span.lo()).with_lo(first_span.hi()) && let Some(snippet) = snippet_opt(cx, new_span) { + let Some(first) = snippet_opt(cx, first_span) else { + return; + }; + let Some(comment_form) = first.get(..3) else { + return; + }; + diag.span_suggestion( new_span, "add an empty line", - format!("{snippet}///\n"), + format!("{snippet}{comment_form}{snippet}"), Applicability::MachineApplicable, ); } diff --git a/tests/ui/too_long_first_doc_paragraph.rs b/tests/ui/too_long_first_doc_paragraph.rs index 1042249c5b7..7d0a37cde46 100644 --- a/tests/ui/too_long_first_doc_paragraph.rs +++ b/tests/ui/too_long_first_doc_paragraph.rs @@ -2,6 +2,16 @@ #![warn(clippy::too_long_first_doc_paragraph)] +pub mod foo { + + // in foo.rs + //! A very short summary. + //! A much longer explanation that goes into a lot more detail about + //! how the thing works, possibly with doclinks and so one, + //! and probably spanning a many rows. Blablabla, it needs to be over + //! 200 characters so I needed to write something longeeeeeeer. +} + /// Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc turpis nunc, lacinia /// a dolor in, pellentesque aliquet enim. Cras nec maximus sem. Mauris arcu libero, /// gravida non lacinia at, rhoncus eu lacus. diff --git a/tests/ui/too_long_first_doc_paragraph.stderr b/tests/ui/too_long_first_doc_paragraph.stderr index 7f48e5cf884..39926647f54 100644 --- a/tests/ui/too_long_first_doc_paragraph.stderr +++ b/tests/ui/too_long_first_doc_paragraph.stderr @@ -1,16 +1,32 @@ error: first doc comment paragraph is too long - --> tests/ui/too_long_first_doc_paragraph.rs:5:1 + --> tests/ui/too_long_first_doc_paragraph.rs:8:5 + | +LL | / //! A very short summary. +LL | | //! A much longer explanation that goes into a lot more detail about +LL | | //! how the thing works, possibly with doclinks and so one, +LL | | //! and probably spanning a many rows. Blablabla, it needs to be over +LL | | //! 200 characters so I needed to write something longeeeeeeer. + | |____^ + | + = note: `-D clippy::too-long-first-doc-paragraph` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::too_long_first_doc_paragraph)]` +help: add an empty line + | +LL ~ //! A very short summary. +LL + //! +LL ~ //! A much longer explanation that goes into a lot more detail about + | + +error: first doc comment paragraph is too long + --> tests/ui/too_long_first_doc_paragraph.rs:15:1 | LL | / /// Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc turpis nunc, lacinia LL | | /// a dolor in, pellentesque aliquet enim. Cras nec maximus sem. Mauris arcu libero, LL | | /// gravida non lacinia at, rhoncus eu lacus. | |_ - | - = note: `-D clippy::too-long-first-doc-paragraph` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::too_long_first_doc_paragraph)]` error: first doc comment paragraph is too long - --> tests/ui/too_long_first_doc_paragraph.rs:26:1 + --> tests/ui/too_long_first_doc_paragraph.rs:36:1 | LL | / /// Lorem LL | | /// ipsum dolor sit amet, consectetur adipiscing elit. Nunc turpis nunc, lacinia @@ -18,5 +34,5 @@ LL | | /// a dolor in, pellentesque aliquet enim. Cras nec maximus sem. Mauris a LL | | /// gravida non lacinia at, rhoncus eu lacus. | |_ -error: aborting due to 2 previous errors +error: aborting due to 3 previous errors From bc7d323bdff24e50acf3129a25c51bf77ab60ed0 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Thu, 12 Sep 2024 20:42:19 +0500 Subject: [PATCH 122/683] Clarify type_complexity --- clippy_lints/src/types/mod.rs | 55 +++++++++++++++++++++++++++++++++-- 1 file changed, 53 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/types/mod.rs b/clippy_lints/src/types/mod.rs index 3a14927802b..120d5ffbbd3 100644 --- a/clippy_lints/src/types/mod.rs +++ b/clippy_lints/src/types/mod.rs @@ -261,8 +261,59 @@ declare_clippy_lint! { /// ### Example /// ```no_run /// # use std::rc::Rc; - /// struct Foo { - /// inner: Rc>>>, + /// struct PointMatrixContainer { + /// matrix: Rc>>>, + /// } + /// + /// fn main() { + /// let point_matrix: Vec>> = vec![ + /// vec![ + /// Box::new((1, 2, 3, 4)), + /// Box::new((5, 6, 7, 8)), + /// ], + /// vec![ + /// Box::new((9, 10, 11, 12)), + /// ], + /// ]; + /// + /// let shared_point_matrix: Rc>>> = Rc::new(point_matrix); + /// + /// let container = PointMatrixContainer { + /// matrix: shared_point_matrix, + /// }; + /// + /// // ... + /// } + /// ``` + /// Use instead: + /// ### Example + /// ```no_run + /// # use std::rc::Rc; + /// type PointMatrix = Vec>>; + /// type SharedPointMatrix = Rc; + /// + /// struct PointMatrixContainer { + /// matrix: SharedPointMatrix, + /// } + /// + /// fn main() { + /// let point_matrix: PointMatrix = vec![ + /// vec![ + /// Box::new((1, 2, 3, 4)), + /// Box::new((5, 6, 7, 8)), + /// ], + /// vec![ + /// Box::new((9, 10, 11, 12)), + /// ], + /// ]; + /// + /// let shared_point_matrix: SharedPointMatrix = Rc::new(point_matrix); + /// + /// let container = PointMatrixContainer { + /// matrix: shared_point_matrix, + /// }; + /// + /// // ... /// } /// ``` #[clippy::version = "pre 1.29.0"] From cd99729478c0b50f11f2ae6badb2cf57e103cd92 Mon Sep 17 00:00:00 2001 From: Obei Sideg Date: Sat, 24 Aug 2024 06:49:09 +0300 Subject: [PATCH 123/683] Update tests for hidden references to mutable static --- .../checked_unwrap/simple_conditionals.stderr | 13 +++- tests/ui/multiple_unsafe_ops_per_block.rs | 1 + tests/ui/multiple_unsafe_ops_per_block.stderr | 58 +++++++-------- tests/ui/must_use_candidates.fixed | 7 +- tests/ui/must_use_candidates.rs | 7 +- tests/ui/must_use_candidates.stderr | 10 +-- tests/ui/redundant_static_lifetimes.fixed | 2 + tests/ui/redundant_static_lifetimes.rs | 2 + tests/ui/redundant_static_lifetimes.stderr | 36 ++++----- tests/ui/useless_conversion.fixed | 2 + tests/ui/useless_conversion.rs | 2 + tests/ui/useless_conversion.stderr | 74 +++++++++---------- 12 files changed, 122 insertions(+), 92 deletions(-) diff --git a/tests/ui/checked_unwrap/simple_conditionals.stderr b/tests/ui/checked_unwrap/simple_conditionals.stderr index f7e338935a7..d92c03f4888 100644 --- a/tests/ui/checked_unwrap/simple_conditionals.stderr +++ b/tests/ui/checked_unwrap/simple_conditionals.stderr @@ -236,5 +236,16 @@ LL | if result.is_ok() { LL | result.as_mut().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 25 previous errors +error: creating a shared reference to mutable static is discouraged + --> tests/ui/checked_unwrap/simple_conditionals.rs:174:12 + | +LL | if X.is_some() { + | ^^^^^^^^^^^ shared reference to mutable static + | + = note: for more information, see + = note: shared references to mutable statics are dangerous; it's undefined behavior if the static is mutated or if a mutable reference is created for it while the shared reference lives + = note: `-D static-mut-refs` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(static_mut_refs)]` + +error: aborting due to 26 previous errors diff --git a/tests/ui/multiple_unsafe_ops_per_block.rs b/tests/ui/multiple_unsafe_ops_per_block.rs index 6b8a103d4a9..87d3517cd5f 100644 --- a/tests/ui/multiple_unsafe_ops_per_block.rs +++ b/tests/ui/multiple_unsafe_ops_per_block.rs @@ -4,6 +4,7 @@ #![allow(deref_nullptr)] #![allow(clippy::unnecessary_operation)] #![allow(dropping_copy_types)] +#![allow(clippy::assign_op_pattern)] #![warn(clippy::multiple_unsafe_ops_per_block)] extern crate proc_macros; diff --git a/tests/ui/multiple_unsafe_ops_per_block.stderr b/tests/ui/multiple_unsafe_ops_per_block.stderr index e732bde0707..a9417a9ef91 100644 --- a/tests/ui/multiple_unsafe_ops_per_block.stderr +++ b/tests/ui/multiple_unsafe_ops_per_block.stderr @@ -1,5 +1,5 @@ error: this `unsafe` block contains 2 unsafe operations, expected only one - --> tests/ui/multiple_unsafe_ops_per_block.rs:37:5 + --> tests/ui/multiple_unsafe_ops_per_block.rs:38:5 | LL | / unsafe { LL | | STATIC += 1; @@ -8,12 +8,12 @@ LL | | } | |_____^ | note: modification of a mutable static occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:38:9 + --> tests/ui/multiple_unsafe_ops_per_block.rs:39:9 | LL | STATIC += 1; | ^^^^^^^^^^^ note: unsafe function call occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:39:9 + --> tests/ui/multiple_unsafe_ops_per_block.rs:40:9 | LL | not_very_safe(); | ^^^^^^^^^^^^^^^ @@ -21,7 +21,7 @@ LL | not_very_safe(); = help: to override `-D warnings` add `#[allow(clippy::multiple_unsafe_ops_per_block)]` error: this `unsafe` block contains 2 unsafe operations, expected only one - --> tests/ui/multiple_unsafe_ops_per_block.rs:46:5 + --> tests/ui/multiple_unsafe_ops_per_block.rs:47:5 | LL | / unsafe { LL | | drop(u.u); @@ -30,18 +30,18 @@ LL | | } | |_____^ | note: union field access occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:47:14 + --> tests/ui/multiple_unsafe_ops_per_block.rs:48:14 | LL | drop(u.u); | ^^^ note: raw pointer dereference occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:48:9 + --> tests/ui/multiple_unsafe_ops_per_block.rs:49:9 | LL | *raw_ptr(); | ^^^^^^^^^^ error: this `unsafe` block contains 3 unsafe operations, expected only one - --> tests/ui/multiple_unsafe_ops_per_block.rs:53:5 + --> tests/ui/multiple_unsafe_ops_per_block.rs:54:5 | LL | / unsafe { LL | | asm!("nop"); @@ -51,23 +51,23 @@ LL | | } | |_____^ | note: inline assembly used here - --> tests/ui/multiple_unsafe_ops_per_block.rs:54:9 + --> tests/ui/multiple_unsafe_ops_per_block.rs:55:9 | LL | asm!("nop"); | ^^^^^^^^^^^ note: unsafe method call occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:55:9 + --> tests/ui/multiple_unsafe_ops_per_block.rs:56:9 | LL | sample.not_very_safe(); | ^^^^^^^^^^^^^^^^^^^^^^ note: modification of a mutable static occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:56:9 + --> tests/ui/multiple_unsafe_ops_per_block.rs:57:9 | LL | STATIC = 0; | ^^^^^^^^^^ error: this `unsafe` block contains 6 unsafe operations, expected only one - --> tests/ui/multiple_unsafe_ops_per_block.rs:62:5 + --> tests/ui/multiple_unsafe_ops_per_block.rs:63:5 | LL | / unsafe { LL | | drop(u.u); @@ -79,55 +79,55 @@ LL | | } | |_____^ | note: union field access occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:63:14 + --> tests/ui/multiple_unsafe_ops_per_block.rs:64:14 | LL | drop(u.u); | ^^^ note: access of a mutable static occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:64:14 + --> tests/ui/multiple_unsafe_ops_per_block.rs:65:14 | LL | drop(STATIC); | ^^^^^^ note: unsafe method call occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:65:9 + --> tests/ui/multiple_unsafe_ops_per_block.rs:66:9 | LL | sample.not_very_safe(); | ^^^^^^^^^^^^^^^^^^^^^^ note: unsafe function call occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:66:9 + --> tests/ui/multiple_unsafe_ops_per_block.rs:67:9 | LL | not_very_safe(); | ^^^^^^^^^^^^^^^ note: raw pointer dereference occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:67:9 + --> tests/ui/multiple_unsafe_ops_per_block.rs:68:9 | LL | *raw_ptr(); | ^^^^^^^^^^ note: inline assembly used here - --> tests/ui/multiple_unsafe_ops_per_block.rs:68:9 + --> tests/ui/multiple_unsafe_ops_per_block.rs:69:9 | LL | asm!("nop"); | ^^^^^^^^^^^ error: this `unsafe` block contains 2 unsafe operations, expected only one - --> tests/ui/multiple_unsafe_ops_per_block.rs:106:5 + --> tests/ui/multiple_unsafe_ops_per_block.rs:107:5 | LL | unsafe { char::from_u32_unchecked(*ptr.cast::()) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: unsafe function call occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:106:14 + --> tests/ui/multiple_unsafe_ops_per_block.rs:107:14 | LL | unsafe { char::from_u32_unchecked(*ptr.cast::()) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: raw pointer dereference occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:106:39 + --> tests/ui/multiple_unsafe_ops_per_block.rs:107:39 | LL | unsafe { char::from_u32_unchecked(*ptr.cast::()) } | ^^^^^^^^^^^^^^^^^^ error: this `unsafe` block contains 2 unsafe operations, expected only one - --> tests/ui/multiple_unsafe_ops_per_block.rs:124:5 + --> tests/ui/multiple_unsafe_ops_per_block.rs:125:5 | LL | / unsafe { LL | | x(); @@ -136,18 +136,18 @@ LL | | } | |_____^ | note: unsafe function call occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:125:9 + --> tests/ui/multiple_unsafe_ops_per_block.rs:126:9 | LL | x(); | ^^^ note: unsafe function call occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:126:9 + --> tests/ui/multiple_unsafe_ops_per_block.rs:127:9 | LL | x(); | ^^^ error: this `unsafe` block contains 2 unsafe operations, expected only one - --> tests/ui/multiple_unsafe_ops_per_block.rs:135:9 + --> tests/ui/multiple_unsafe_ops_per_block.rs:136:9 | LL | / unsafe { LL | | T::X(); @@ -156,18 +156,18 @@ LL | | } | |_________^ | note: unsafe function call occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:136:13 + --> tests/ui/multiple_unsafe_ops_per_block.rs:137:13 | LL | T::X(); | ^^^^^^ note: unsafe function call occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:137:13 + --> tests/ui/multiple_unsafe_ops_per_block.rs:138:13 | LL | T::X(); | ^^^^^^ error: this `unsafe` block contains 2 unsafe operations, expected only one - --> tests/ui/multiple_unsafe_ops_per_block.rs:145:5 + --> tests/ui/multiple_unsafe_ops_per_block.rs:146:5 | LL | / unsafe { LL | | x.0(); @@ -176,12 +176,12 @@ LL | | } | |_____^ | note: unsafe function call occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:146:9 + --> tests/ui/multiple_unsafe_ops_per_block.rs:147:9 | LL | x.0(); | ^^^^^ note: unsafe function call occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:147:9 + --> tests/ui/multiple_unsafe_ops_per_block.rs:148:9 | LL | x.0(); | ^^^^^ diff --git a/tests/ui/must_use_candidates.fixed b/tests/ui/must_use_candidates.fixed index c057eba4aca..adb266ffbc8 100644 --- a/tests/ui/must_use_candidates.fixed +++ b/tests/ui/must_use_candidates.fixed @@ -1,5 +1,10 @@ #![feature(never_type)] -#![allow(unused_mut, clippy::redundant_allocation, clippy::needless_pass_by_ref_mut)] +#![allow( + unused_mut, + clippy::redundant_allocation, + clippy::needless_pass_by_ref_mut, + static_mut_refs +)] #![warn(clippy::must_use_candidate)] use std::rc::Rc; use std::sync::atomic::{AtomicBool, Ordering}; diff --git a/tests/ui/must_use_candidates.rs b/tests/ui/must_use_candidates.rs index 36019652006..49bb16af788 100644 --- a/tests/ui/must_use_candidates.rs +++ b/tests/ui/must_use_candidates.rs @@ -1,5 +1,10 @@ #![feature(never_type)] -#![allow(unused_mut, clippy::redundant_allocation, clippy::needless_pass_by_ref_mut)] +#![allow( + unused_mut, + clippy::redundant_allocation, + clippy::needless_pass_by_ref_mut, + static_mut_refs +)] #![warn(clippy::must_use_candidate)] use std::rc::Rc; use std::sync::atomic::{AtomicBool, Ordering}; diff --git a/tests/ui/must_use_candidates.stderr b/tests/ui/must_use_candidates.stderr index c64636ba442..2117e37866e 100644 --- a/tests/ui/must_use_candidates.stderr +++ b/tests/ui/must_use_candidates.stderr @@ -1,5 +1,5 @@ error: this function could have a `#[must_use]` attribute - --> tests/ui/must_use_candidates.rs:11:1 + --> tests/ui/must_use_candidates.rs:16:1 | LL | pub fn pure(i: u8) -> u8 { | ^^^^^^^^^^^^^^^^^^^^^^^^ help: add the attribute: `#[must_use] pub fn pure(i: u8) -> u8` @@ -8,25 +8,25 @@ LL | pub fn pure(i: u8) -> u8 { = help: to override `-D warnings` add `#[allow(clippy::must_use_candidate)]` error: this method could have a `#[must_use]` attribute - --> tests/ui/must_use_candidates.rs:16:5 + --> tests/ui/must_use_candidates.rs:21:5 | LL | pub fn inherent_pure(&self) -> u8 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: add the attribute: `#[must_use] pub fn inherent_pure(&self) -> u8` error: this function could have a `#[must_use]` attribute - --> tests/ui/must_use_candidates.rs:47:1 + --> tests/ui/must_use_candidates.rs:52:1 | LL | pub fn with_marker(_d: std::marker::PhantomData<&mut u32>) -> bool { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: add the attribute: `#[must_use] pub fn with_marker(_d: std::marker::PhantomData<&mut u32>) -> bool` error: this function could have a `#[must_use]` attribute - --> tests/ui/must_use_candidates.rs:59:1 + --> tests/ui/must_use_candidates.rs:64:1 | LL | pub fn rcd(_x: Rc) -> bool { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: add the attribute: `#[must_use] pub fn rcd(_x: Rc) -> bool` error: this function could have a `#[must_use]` attribute - --> tests/ui/must_use_candidates.rs:67:1 + --> tests/ui/must_use_candidates.rs:72:1 | LL | pub fn arcd(_x: Arc) -> bool { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: add the attribute: `#[must_use] pub fn arcd(_x: Arc) -> bool` diff --git a/tests/ui/redundant_static_lifetimes.fixed b/tests/ui/redundant_static_lifetimes.fixed index 9787bb635e7..3d1c78bd12d 100644 --- a/tests/ui/redundant_static_lifetimes.fixed +++ b/tests/ui/redundant_static_lifetimes.fixed @@ -1,4 +1,6 @@ #![allow(unused)] +// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint +#![allow(static_mut_refs)] #[derive(Debug)] struct Foo; diff --git a/tests/ui/redundant_static_lifetimes.rs b/tests/ui/redundant_static_lifetimes.rs index b5a4827fa94..5932f14b8d9 100644 --- a/tests/ui/redundant_static_lifetimes.rs +++ b/tests/ui/redundant_static_lifetimes.rs @@ -1,4 +1,6 @@ #![allow(unused)] +// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint +#![allow(static_mut_refs)] #[derive(Debug)] struct Foo; diff --git a/tests/ui/redundant_static_lifetimes.stderr b/tests/ui/redundant_static_lifetimes.stderr index 5c5e2f2a573..48871eba2dc 100644 --- a/tests/ui/redundant_static_lifetimes.stderr +++ b/tests/ui/redundant_static_lifetimes.stderr @@ -1,5 +1,5 @@ error: constants have by default a `'static` lifetime - --> tests/ui/redundant_static_lifetimes.rs:6:17 + --> tests/ui/redundant_static_lifetimes.rs:8:17 | LL | const VAR_ONE: &'static str = "Test constant #1"; // ERROR: Consider removing 'static. | -^^^^^^^---- help: consider removing `'static`: `&str` @@ -8,103 +8,103 @@ LL | const VAR_ONE: &'static str = "Test constant #1"; // ERROR: Consider removi = help: to override `-D warnings` add `#[allow(clippy::redundant_static_lifetimes)]` error: constants have by default a `'static` lifetime - --> tests/ui/redundant_static_lifetimes.rs:10:21 + --> tests/ui/redundant_static_lifetimes.rs:12:21 | LL | const VAR_THREE: &[&'static str] = &["one", "two"]; // ERROR: Consider removing 'static | -^^^^^^^---- help: consider removing `'static`: `&str` error: constants have by default a `'static` lifetime - --> tests/ui/redundant_static_lifetimes.rs:12:32 + --> tests/ui/redundant_static_lifetimes.rs:14:32 | LL | const VAR_FOUR: (&str, (&str, &'static str), &'static str) = ("on", ("th", "th"), "on"); // ERROR: Consider removing 'static | -^^^^^^^---- help: consider removing `'static`: `&str` error: constants have by default a `'static` lifetime - --> tests/ui/redundant_static_lifetimes.rs:12:47 + --> tests/ui/redundant_static_lifetimes.rs:14:47 | LL | const VAR_FOUR: (&str, (&str, &'static str), &'static str) = ("on", ("th", "th"), "on"); // ERROR: Consider removing 'static | -^^^^^^^---- help: consider removing `'static`: `&str` error: constants have by default a `'static` lifetime - --> tests/ui/redundant_static_lifetimes.rs:14:17 + --> tests/ui/redundant_static_lifetimes.rs:16:17 | LL | const VAR_SIX: &'static u8 = &5; | -^^^^^^^--- help: consider removing `'static`: `&u8` error: constants have by default a `'static` lifetime - --> tests/ui/redundant_static_lifetimes.rs:16:20 + --> tests/ui/redundant_static_lifetimes.rs:18:20 | LL | const VAR_HEIGHT: &'static Foo = &Foo {}; | -^^^^^^^---- help: consider removing `'static`: `&Foo` error: constants have by default a `'static` lifetime - --> tests/ui/redundant_static_lifetimes.rs:18:19 + --> tests/ui/redundant_static_lifetimes.rs:20:19 | LL | const VAR_SLICE: &'static [u8] = b"Test constant #1"; // ERROR: Consider removing 'static. | -^^^^^^^----- help: consider removing `'static`: `&[u8]` error: constants have by default a `'static` lifetime - --> tests/ui/redundant_static_lifetimes.rs:20:19 + --> tests/ui/redundant_static_lifetimes.rs:22:19 | LL | const VAR_TUPLE: &'static (u8, u8) = &(1, 2); // ERROR: Consider removing 'static. | -^^^^^^^--------- help: consider removing `'static`: `&(u8, u8)` error: constants have by default a `'static` lifetime - --> tests/ui/redundant_static_lifetimes.rs:22:19 + --> tests/ui/redundant_static_lifetimes.rs:24:19 | LL | const VAR_ARRAY: &'static [u8; 1] = b"T"; // ERROR: Consider removing 'static. | -^^^^^^^-------- help: consider removing `'static`: `&[u8; 1]` error: statics have by default a `'static` lifetime - --> tests/ui/redundant_static_lifetimes.rs:24:25 + --> tests/ui/redundant_static_lifetimes.rs:26:25 | LL | static STATIC_VAR_ONE: &'static str = "Test static #1"; // ERROR: Consider removing 'static. | -^^^^^^^---- help: consider removing `'static`: `&str` error: statics have by default a `'static` lifetime - --> tests/ui/redundant_static_lifetimes.rs:28:29 + --> tests/ui/redundant_static_lifetimes.rs:30:29 | LL | static STATIC_VAR_THREE: &[&'static str] = &["one", "two"]; // ERROR: Consider removing 'static | -^^^^^^^---- help: consider removing `'static`: `&str` error: statics have by default a `'static` lifetime - --> tests/ui/redundant_static_lifetimes.rs:30:25 + --> tests/ui/redundant_static_lifetimes.rs:32:25 | LL | static STATIC_VAR_SIX: &'static u8 = &5; | -^^^^^^^--- help: consider removing `'static`: `&u8` error: statics have by default a `'static` lifetime - --> tests/ui/redundant_static_lifetimes.rs:32:28 + --> tests/ui/redundant_static_lifetimes.rs:34:28 | LL | static STATIC_VAR_HEIGHT: &'static Foo = &Foo {}; | -^^^^^^^---- help: consider removing `'static`: `&Foo` error: statics have by default a `'static` lifetime - --> tests/ui/redundant_static_lifetimes.rs:34:27 + --> tests/ui/redundant_static_lifetimes.rs:36:27 | LL | static STATIC_VAR_SLICE: &'static [u8] = b"Test static #3"; // ERROR: Consider removing 'static. | -^^^^^^^----- help: consider removing `'static`: `&[u8]` error: statics have by default a `'static` lifetime - --> tests/ui/redundant_static_lifetimes.rs:36:27 + --> tests/ui/redundant_static_lifetimes.rs:38:27 | LL | static STATIC_VAR_TUPLE: &'static (u8, u8) = &(1, 2); // ERROR: Consider removing 'static. | -^^^^^^^--------- help: consider removing `'static`: `&(u8, u8)` error: statics have by default a `'static` lifetime - --> tests/ui/redundant_static_lifetimes.rs:38:27 + --> tests/ui/redundant_static_lifetimes.rs:40:27 | LL | static STATIC_VAR_ARRAY: &'static [u8; 1] = b"T"; // ERROR: Consider removing 'static. | -^^^^^^^-------- help: consider removing `'static`: `&[u8; 1]` error: statics have by default a `'static` lifetime - --> tests/ui/redundant_static_lifetimes.rs:40:31 + --> tests/ui/redundant_static_lifetimes.rs:42:31 | LL | static mut STATIC_MUT_SLICE: &'static mut [u32] = &mut [0]; | -^^^^^^^---------- help: consider removing `'static`: `&mut [u32]` error: statics have by default a `'static` lifetime - --> tests/ui/redundant_static_lifetimes.rs:69:16 + --> tests/ui/redundant_static_lifetimes.rs:71:16 | LL | static V: &'static u8 = &17; | -^^^^^^^--- help: consider removing `'static`: `&u8` diff --git a/tests/ui/useless_conversion.fixed b/tests/ui/useless_conversion.fixed index ce00fde2f99..eff617a8016 100644 --- a/tests/ui/useless_conversion.fixed +++ b/tests/ui/useless_conversion.fixed @@ -1,5 +1,7 @@ #![deny(clippy::useless_conversion)] #![allow(clippy::needless_if, clippy::unnecessary_wraps)] +// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint +#![allow(static_mut_refs)] fn test_generic(val: T) -> T { let _ = val; diff --git a/tests/ui/useless_conversion.rs b/tests/ui/useless_conversion.rs index 39979619586..64b06620789 100644 --- a/tests/ui/useless_conversion.rs +++ b/tests/ui/useless_conversion.rs @@ -1,5 +1,7 @@ #![deny(clippy::useless_conversion)] #![allow(clippy::needless_if, clippy::unnecessary_wraps)] +// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint +#![allow(static_mut_refs)] fn test_generic(val: T) -> T { let _ = T::from(val); diff --git a/tests/ui/useless_conversion.stderr b/tests/ui/useless_conversion.stderr index 82f945c5e89..b149357bcf4 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:5:13 + --> tests/ui/useless_conversion.rs:7:13 | LL | let _ = T::from(val); | ^^^^^^^^^^^^ help: consider removing `T::from()`: `val` @@ -11,217 +11,217 @@ LL | #![deny(clippy::useless_conversion)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: useless conversion to the same type: `T` - --> tests/ui/useless_conversion.rs:6:5 + --> tests/ui/useless_conversion.rs:8:5 | LL | val.into() | ^^^^^^^^^^ help: consider removing `.into()`: `val` error: useless conversion to the same type: `i32` - --> tests/ui/useless_conversion.rs:18:22 + --> tests/ui/useless_conversion.rs:20: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:48:22 + --> tests/ui/useless_conversion.rs:50: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:53:21 + --> tests/ui/useless_conversion.rs:55: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:59:22 + --> tests/ui/useless_conversion.rs:61: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:65:13 + --> tests/ui/useless_conversion.rs:67: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:70:17 + --> tests/ui/useless_conversion.rs:72: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:132:21 + --> tests/ui/useless_conversion.rs:134: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:133:21 + --> tests/ui/useless_conversion.rs:135: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:134:13 + --> tests/ui/useless_conversion.rs:136: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:135:13 + --> tests/ui/useless_conversion.rs:137: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:136:13 + --> tests/ui/useless_conversion.rs:138: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:137:13 + --> tests/ui/useless_conversion.rs:139: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:138:21 + --> tests/ui/useless_conversion.rs:140: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:143:13 + --> tests/ui/useless_conversion.rs:145: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:149:23 + --> tests/ui/useless_conversion.rs:151: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:151:13 + --> tests/ui/useless_conversion.rs:153: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:153:13 + --> tests/ui/useless_conversion.rs:155: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:185:7 + --> tests/ui/useless_conversion.rs:187: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:175:13 + --> tests/ui/useless_conversion.rs:177:13 | LL | fn b>(_: T) {} | ^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit call to `.into_iter()` in function argument accepting `IntoIterator` - --> tests/ui/useless_conversion.rs:186:7 + --> tests/ui/useless_conversion.rs:188: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:176:18 + --> tests/ui/useless_conversion.rs:178:18 | LL | fn c(_: impl IntoIterator) {} | ^^^^^^^^^^^^^^^^^^^^^^^^ 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 | 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:179:12 + --> tests/ui/useless_conversion.rs:181:12 | LL | T: IntoIterator, | ^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit call to `.into_iter()` in function argument accepting `IntoIterator` - --> tests/ui/useless_conversion.rs:190:7 + --> tests/ui/useless_conversion.rs:192: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:175:13 + --> tests/ui/useless_conversion.rs:177:13 | LL | fn b>(_: T) {} | ^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit call to `.into_iter()` in function argument accepting `IntoIterator` - --> tests/ui/useless_conversion.rs:191:7 + --> tests/ui/useless_conversion.rs:193: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:175:13 + --> tests/ui/useless_conversion.rs:177:13 | LL | fn b>(_: T) {} | ^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit call to `.into_iter()` in function argument accepting `IntoIterator` - --> tests/ui/useless_conversion.rs:237:24 + --> tests/ui/useless_conversion.rs:239: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:216:12 + --> tests/ui/useless_conversion.rs:218:12 | LL | I: IntoIterator + Helper, | ^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit call to `.into_iter()` in function argument accepting `IntoIterator` - --> tests/ui/useless_conversion.rs:245:14 + --> tests/ui/useless_conversion.rs:247: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:225:12 + --> tests/ui/useless_conversion.rs:227:12 | LL | I: IntoIterator, | ^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit call to `.into_iter()` in function argument accepting `IntoIterator` - --> tests/ui/useless_conversion.rs:254:16 + --> tests/ui/useless_conversion.rs:256: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:251:27 + --> tests/ui/useless_conversion.rs:253:27 | LL | pub fn foo(&self, _: I) {} | ^^^^^^^^^^^^ error: explicit call to `.into_iter()` in function argument accepting `IntoIterator` - --> tests/ui/useless_conversion.rs:273:44 + --> tests/ui/useless_conversion.rs:275: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:260:20 + --> tests/ui/useless_conversion.rs:262:20 | LL | J: IntoIterator, | ^^^^^^^^^^^^ From 7fcdebf65860268b482edb38f76dc06e283504fb Mon Sep 17 00:00:00 2001 From: Trevor Spiteri Date: Fri, 13 Sep 2024 13:28:22 +0200 Subject: [PATCH 124/683] Revert "stabilize const_float_bits_conv" for src/tools/clippy/clippy_lints This reverts the part of commit 19908ff7a37a9a431399bb6f2868efc22820f2b6 in subdirectory src/tools/clippy/clippy_lints. --- clippy_lints/src/transmute/mod.rs | 6 +++--- clippy_lints/src/transmute/transmute_float_to_int.rs | 3 ++- clippy_lints/src/transmute/transmute_int_to_float.rs | 3 ++- clippy_lints/src/transmute/transmute_num_to_bytes.rs | 6 ++++++ 4 files changed, 13 insertions(+), 5 deletions(-) diff --git a/clippy_lints/src/transmute/mod.rs b/clippy_lints/src/transmute/mod.rs index a2ae36cc484..373bf61d8ff 100644 --- a/clippy_lints/src/transmute/mod.rs +++ b/clippy_lints/src/transmute/mod.rs @@ -619,10 +619,10 @@ impl<'tcx> LateLintPass<'tcx> for Transmute { | transmute_ref_to_ref::check(cx, e, from_ty, to_ty, arg, const_context) | transmute_ptr_to_ptr::check(cx, e, from_ty, to_ty, arg, &self.msrv) | transmute_int_to_bool::check(cx, e, from_ty, to_ty, arg) - | transmute_int_to_float::check(cx, e, from_ty, to_ty, arg) + | transmute_int_to_float::check(cx, e, from_ty, to_ty, arg, const_context) | transmute_int_to_non_zero::check(cx, e, from_ty, to_ty, arg) - | transmute_float_to_int::check(cx, e, from_ty, to_ty, arg) - | transmute_num_to_bytes::check(cx, e, from_ty, to_ty, arg) + | transmute_float_to_int::check(cx, e, from_ty, to_ty, arg, const_context) + | transmute_num_to_bytes::check(cx, e, from_ty, to_ty, arg, const_context) | (unsound_collection_transmute::check(cx, e, from_ty, to_ty) || transmute_undefined_repr::check(cx, e, from_ty, to_ty)) | (eager_transmute::check(cx, e, arg, from_ty, to_ty)); diff --git a/clippy_lints/src/transmute/transmute_float_to_int.rs b/clippy_lints/src/transmute/transmute_float_to_int.rs index cb46109c27e..ab3bb5e1062 100644 --- a/clippy_lints/src/transmute/transmute_float_to_int.rs +++ b/clippy_lints/src/transmute/transmute_float_to_int.rs @@ -15,9 +15,10 @@ pub(super) fn check<'tcx>( from_ty: Ty<'tcx>, to_ty: Ty<'tcx>, mut arg: &'tcx Expr<'_>, + const_context: bool, ) -> bool { match (&from_ty.kind(), &to_ty.kind()) { - (ty::Float(float_ty), ty::Int(_) | ty::Uint(_)) => { + (ty::Float(float_ty), ty::Int(_) | ty::Uint(_)) if !const_context => { span_lint_and_then( cx, TRANSMUTE_FLOAT_TO_INT, diff --git a/clippy_lints/src/transmute/transmute_int_to_float.rs b/clippy_lints/src/transmute/transmute_int_to_float.rs index e00fb90c307..d51888e3097 100644 --- a/clippy_lints/src/transmute/transmute_int_to_float.rs +++ b/clippy_lints/src/transmute/transmute_int_to_float.rs @@ -14,9 +14,10 @@ pub(super) fn check<'tcx>( from_ty: Ty<'tcx>, to_ty: Ty<'tcx>, arg: &'tcx Expr<'_>, + const_context: bool, ) -> bool { match (&from_ty.kind(), &to_ty.kind()) { - (ty::Int(_) | ty::Uint(_), ty::Float(_)) => { + (ty::Int(_) | ty::Uint(_), ty::Float(_)) if !const_context => { span_lint_and_then( cx, TRANSMUTE_INT_TO_FLOAT, diff --git a/clippy_lints/src/transmute/transmute_num_to_bytes.rs b/clippy_lints/src/transmute/transmute_num_to_bytes.rs index 362f2bb6960..88b0ac5a368 100644 --- a/clippy_lints/src/transmute/transmute_num_to_bytes.rs +++ b/clippy_lints/src/transmute/transmute_num_to_bytes.rs @@ -14,12 +14,18 @@ pub(super) fn check<'tcx>( from_ty: Ty<'tcx>, to_ty: Ty<'tcx>, arg: &'tcx Expr<'_>, + const_context: bool, ) -> bool { match (&from_ty.kind(), &to_ty.kind()) { (ty::Int(_) | ty::Uint(_) | ty::Float(_), ty::Array(arr_ty, _)) => { if !matches!(arr_ty.kind(), ty::Uint(UintTy::U8)) { return false; } + if matches!(from_ty.kind(), ty::Float(_)) && const_context { + // TODO: Remove when const_float_bits_conv is stabilized + // rust#72447 + return false; + } span_lint_and_then( cx, From 7cccef84cf2f5f9f94f77a09a193d414b3cff03d Mon Sep 17 00:00:00 2001 From: Trevor Spiteri Date: Fri, 13 Sep 2024 13:43:41 +0200 Subject: [PATCH 125/683] handle transmutes in const context if msrvs::CONST_FLOAT_BITS_CONV --- clippy_config/src/msrvs.rs | 3 ++- clippy_lints/src/transmute/mod.rs | 6 +++--- clippy_lints/src/transmute/transmute_float_to_int.rs | 6 +++++- clippy_lints/src/transmute/transmute_int_to_float.rs | 4 +++- clippy_lints/src/transmute/transmute_num_to_bytes.rs | 6 +++--- 5 files changed, 16 insertions(+), 9 deletions(-) diff --git a/clippy_config/src/msrvs.rs b/clippy_config/src/msrvs.rs index 0e8215aa8e3..e17458b3310 100644 --- a/clippy_config/src/msrvs.rs +++ b/clippy_config/src/msrvs.rs @@ -17,7 +17,8 @@ macro_rules! msrv_aliases { // names may refer to stabilized feature flags or library items msrv_aliases! { - 1,81,0 { LINT_REASONS_STABILIZATION } + 1,83,0 { CONST_FLOAT_BITS_CONV } + 1,81,0 { LINT_REASONS_STABILIZATION } 1,80,0 { BOX_INTO_ITER} 1,77,0 { C_STR_LITERALS } 1,76,0 { PTR_FROM_REF, OPTION_RESULT_INSPECT } diff --git a/clippy_lints/src/transmute/mod.rs b/clippy_lints/src/transmute/mod.rs index 373bf61d8ff..da7906b1183 100644 --- a/clippy_lints/src/transmute/mod.rs +++ b/clippy_lints/src/transmute/mod.rs @@ -619,10 +619,10 @@ impl<'tcx> LateLintPass<'tcx> for Transmute { | transmute_ref_to_ref::check(cx, e, from_ty, to_ty, arg, const_context) | transmute_ptr_to_ptr::check(cx, e, from_ty, to_ty, arg, &self.msrv) | transmute_int_to_bool::check(cx, e, from_ty, to_ty, arg) - | transmute_int_to_float::check(cx, e, from_ty, to_ty, arg, const_context) + | transmute_int_to_float::check(cx, e, from_ty, to_ty, arg, const_context, &self.msrv) | transmute_int_to_non_zero::check(cx, e, from_ty, to_ty, arg) - | transmute_float_to_int::check(cx, e, from_ty, to_ty, arg, const_context) - | transmute_num_to_bytes::check(cx, e, from_ty, to_ty, arg, const_context) + | transmute_float_to_int::check(cx, e, from_ty, to_ty, arg, const_context, &self.msrv) + | transmute_num_to_bytes::check(cx, e, from_ty, to_ty, arg, const_context, &self.msrv) | (unsound_collection_transmute::check(cx, e, from_ty, to_ty) || transmute_undefined_repr::check(cx, e, from_ty, to_ty)) | (eager_transmute::check(cx, e, arg, from_ty, to_ty)); diff --git a/clippy_lints/src/transmute/transmute_float_to_int.rs b/clippy_lints/src/transmute/transmute_float_to_int.rs index ab3bb5e1062..3507eb9a124 100644 --- a/clippy_lints/src/transmute/transmute_float_to_int.rs +++ b/clippy_lints/src/transmute/transmute_float_to_int.rs @@ -1,4 +1,5 @@ use super::TRANSMUTE_FLOAT_TO_INT; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::sugg; use rustc_ast as ast; @@ -16,9 +17,12 @@ pub(super) fn check<'tcx>( to_ty: Ty<'tcx>, mut arg: &'tcx Expr<'_>, const_context: bool, + msrv: &Msrv, ) -> bool { match (&from_ty.kind(), &to_ty.kind()) { - (ty::Float(float_ty), ty::Int(_) | ty::Uint(_)) if !const_context => { + (ty::Float(float_ty), ty::Int(_) | ty::Uint(_)) + if !const_context || msrv.meets(msrvs::CONST_FLOAT_BITS_CONV) => + { span_lint_and_then( cx, TRANSMUTE_FLOAT_TO_INT, diff --git a/clippy_lints/src/transmute/transmute_int_to_float.rs b/clippy_lints/src/transmute/transmute_int_to_float.rs index d51888e3097..c5c7ed6d398 100644 --- a/clippy_lints/src/transmute/transmute_int_to_float.rs +++ b/clippy_lints/src/transmute/transmute_int_to_float.rs @@ -1,4 +1,5 @@ use super::TRANSMUTE_INT_TO_FLOAT; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::sugg; use rustc_errors::Applicability; @@ -15,9 +16,10 @@ pub(super) fn check<'tcx>( to_ty: Ty<'tcx>, arg: &'tcx Expr<'_>, const_context: bool, + msrv: &Msrv, ) -> bool { match (&from_ty.kind(), &to_ty.kind()) { - (ty::Int(_) | ty::Uint(_), ty::Float(_)) if !const_context => { + (ty::Int(_) | ty::Uint(_), ty::Float(_)) if !const_context || msrv.meets(msrvs::CONST_FLOAT_BITS_CONV) => { span_lint_and_then( cx, TRANSMUTE_INT_TO_FLOAT, diff --git a/clippy_lints/src/transmute/transmute_num_to_bytes.rs b/clippy_lints/src/transmute/transmute_num_to_bytes.rs index 88b0ac5a368..a94cd27c7fd 100644 --- a/clippy_lints/src/transmute/transmute_num_to_bytes.rs +++ b/clippy_lints/src/transmute/transmute_num_to_bytes.rs @@ -1,4 +1,5 @@ use super::TRANSMUTE_NUM_TO_BYTES; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::sugg; use rustc_errors::Applicability; @@ -15,15 +16,14 @@ pub(super) fn check<'tcx>( to_ty: Ty<'tcx>, arg: &'tcx Expr<'_>, const_context: bool, + msrv: &Msrv, ) -> bool { match (&from_ty.kind(), &to_ty.kind()) { (ty::Int(_) | ty::Uint(_) | ty::Float(_), ty::Array(arr_ty, _)) => { if !matches!(arr_ty.kind(), ty::Uint(UintTy::U8)) { return false; } - if matches!(from_ty.kind(), ty::Float(_)) && const_context { - // TODO: Remove when const_float_bits_conv is stabilized - // rust#72447 + if matches!(from_ty.kind(), ty::Float(_)) && const_context && !msrv.meets(msrvs::CONST_FLOAT_BITS_CONV) { return false; } From 6fa092a1024d6fc47926bb8eed9e2df075c2ff2f Mon Sep 17 00:00:00 2001 From: "Tim (Theemathas) Chirananthavat" Date: Fri, 13 Sep 2024 21:26:39 +0700 Subject: [PATCH 126/683] Address WaffleLapkin's comments --- library/core/src/mem/manually_drop.rs | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/library/core/src/mem/manually_drop.rs b/library/core/src/mem/manually_drop.rs index f4b56c9f13e..24d95f93900 100644 --- a/library/core/src/mem/manually_drop.rs +++ b/library/core/src/mem/manually_drop.rs @@ -15,7 +15,7 @@ use crate::ptr; /// that a `ManuallyDrop` whose content has been dropped must not be exposed /// through a public safe API. Correspondingly, `ManuallyDrop::drop` is unsafe. /// -/// # `ManuallyDrop` and drop order. +/// # `ManuallyDrop` and drop order /// /// Rust has a well-defined [drop order] of values. To make sure that fields or /// locals are dropped in a specific order, reorder the declarations such that @@ -39,7 +39,7 @@ use crate::ptr; /// } /// ``` /// -/// # Interaction with `Box`. +/// # Interaction with `Box` /// /// Currently, once the `Box` inside a `ManuallyDrop>` is dropped, /// moving the `ManuallyDrop>` is [considered to be undefined @@ -56,16 +56,17 @@ use crate::ptr; /// let y = x; // Undefined behavior! /// ``` /// -/// This may change in the future. In the meantime, consider using -/// [`MaybeUninit`] instead. +/// This is [likely to change in the +/// future](https://rust-lang.github.io/rfcs/3336-maybe-dangling.html). In the +/// meantime, consider using [`MaybeUninit`] instead. /// -/// # Safety hazards when storing `ManuallyDrop` in a struct / enum. +/// # Safety hazards when storing `ManuallyDrop` in a struct or an enum. /// /// Special care is needed when all of the conditions below are met: /// * A field of a struct or enum is a `ManuallyDrop` or contains a /// `ManuallyDrop`, without the `ManuallyDrop` being inside a `union`. -/// * The struct or enum is part of public API, or is stored in a struct or enum -/// that is part of public API. +/// * The struct or enum is part of public API, or is stored in a struct or an +/// enum that is part of public API. /// * There is code outside of a `Drop` implementation that calls /// [`ManuallyDrop::drop`] or [`ManuallyDrop::take`] on the `ManuallyDrop` /// field. @@ -120,14 +121,15 @@ use crate::ptr; /// ```no_run /// use std::mem::ManuallyDrop; /// -/// #[derive(Debug)] // This is unsound! +/// // This derive is unsound in combination with the `ManuallyDrop::drop` call. +/// #[derive(Debug)] /// pub struct Foo { /// value: ManuallyDrop, /// } /// impl Foo { /// pub fn new() -> Self { /// let mut temp = Self { -/// value: ManuallyDrop::new(String::from("Unsafe rust is hard")) +/// value: ManuallyDrop::new(String::from("Unsafe rust is hard.")) /// }; /// unsafe { /// // SAFETY: `value` hasn't been dropped yet. From f604ed631baa3428fcc8370402985a56fc0fc459 Mon Sep 17 00:00:00 2001 From: "Tim (Theemathas) Chirananthavat" Date: Fri, 13 Sep 2024 22:02:07 +0700 Subject: [PATCH 127/683] Fix awkward wording. --- library/core/src/mem/manually_drop.rs | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/library/core/src/mem/manually_drop.rs b/library/core/src/mem/manually_drop.rs index 24d95f93900..8dea3539e46 100644 --- a/library/core/src/mem/manually_drop.rs +++ b/library/core/src/mem/manually_drop.rs @@ -63,22 +63,21 @@ use crate::ptr; /// # Safety hazards when storing `ManuallyDrop` in a struct or an enum. /// /// Special care is needed when all of the conditions below are met: -/// * A field of a struct or enum is a `ManuallyDrop` or contains a -/// `ManuallyDrop`, without the `ManuallyDrop` being inside a `union`. +/// * A struct or enum contains a `ManuallyDrop`. +/// * The `ManuallyDrop` is not inside a `union`. /// * The struct or enum is part of public API, or is stored in a struct or an /// enum that is part of public API. -/// * There is code outside of a `Drop` implementation that calls -/// [`ManuallyDrop::drop`] or [`ManuallyDrop::take`] on the `ManuallyDrop` -/// field. +/// * There is code that drops the contents of the `ManuallyDrop` field, and +/// this code is outside the struct or enum's `Drop` implementation. /// -/// In particular, the following hazards can occur: +/// In particular, the following hazards may occur: /// /// #### Storing generic types /// /// If the `ManuallyDrop` contains a client-supplied generic type, the client -/// might provide a `Box`, causing undefined behavior when the struct / enum is -/// later moved, as mentioned above. For example, the following code causes -/// undefined behavior: +/// might provide a `Box` as that type. This would cause undefined behavior when +/// the struct or enum is later moved, as mentioned in the previous section. For +/// example, the following code causes undefined behavior: /// /// ```no_run /// use std::mem::ManuallyDrop; @@ -114,7 +113,7 @@ use crate::ptr; /// #### Deriving traits /// /// Deriving `Debug`, `Clone`, `PartialEq`, `PartialOrd`, `Ord`, or `Hash` on -/// the struct / enum could be unsound, since the derived implementations of +/// the struct or enum could be unsound, since the derived implementations of /// these traits would access the `ManuallyDrop` field. For example, the /// following code causes undefined behavior: /// From 15495ebf42a2d9748ae25774a73f28c43e47fd0b Mon Sep 17 00:00:00 2001 From: y21 <30553356+y21@users.noreply.github.com> Date: Mon, 26 Aug 2024 19:24:13 +0200 Subject: [PATCH 128/683] Look at adjusted types instead of fn signature types in `ptr_arg` --- clippy_lints/src/ptr.rs | 102 ++++++++++++++++------------------------ tests/ui/ptr_arg.rs | 22 +++++++++ tests/ui/ptr_arg.stderr | 14 +++++- 3 files changed, 76 insertions(+), 62 deletions(-) diff --git a/clippy_lints/src/ptr.rs b/clippy_lints/src/ptr.rs index 7d24d25dc2f..cd8e921347c 100644 --- a/clippy_lints/src/ptr.rs +++ b/clippy_lints/src/ptr.rs @@ -1,11 +1,9 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then, span_lint_hir_and_then}; use clippy_utils::source::SpanRangeExt; -use clippy_utils::ty::expr_sig; use clippy_utils::visitors::contains_unsafe_block; use clippy_utils::{get_expr_use_or_unification_node, is_lint_allowed, path_def_id, path_to_local}; use hir::LifetimeName; use rustc_errors::{Applicability, MultiSpan}; -use rustc_hir::def_id::DefId; use rustc_hir::hir_id::{HirId, HirIdMap}; use rustc_hir::intravisit::{walk_expr, Visitor}; use rustc_hir::{ @@ -323,7 +321,6 @@ struct PtrArg<'tcx> { idx: usize, emission_id: HirId, span: Span, - ty_did: DefId, ty_name: Symbol, method_renames: &'static [(&'static str, &'static str)], ref_prefix: RefPrefix, @@ -411,7 +408,6 @@ impl<'tcx> DerefTy<'tcx> { } } -#[expect(clippy::too_many_lines)] fn check_fn_args<'cx, 'tcx: 'cx>( cx: &'cx LateContext<'tcx>, fn_sig: ty::FnSig<'tcx>, @@ -514,7 +510,6 @@ fn check_fn_args<'cx, 'tcx: 'cx>( idx: i, emission_id, span: hir_ty.span, - ty_did: adt.did(), ty_name: name.ident.name, method_renames, ref_prefix: RefPrefix { lt: *lt, mutability }, @@ -610,65 +605,50 @@ fn check_ptr_arg_usage<'tcx>(cx: &LateContext<'tcx>, body: &Body<'tcx>, args: &[ set_skip_flag(); } }, - Some((Node::Expr(e), child_id)) => match e.kind { - ExprKind::Call(f, expr_args) => { - let i = expr_args.iter().position(|arg| arg.hir_id == child_id).unwrap_or(0); - if expr_sig(self.cx, f).and_then(|sig| sig.input(i)).map_or(true, |ty| { - match *ty.skip_binder().peel_refs().kind() { - ty::Dynamic(preds, _, _) => !matches_preds(self.cx, args.deref_ty.ty(self.cx), preds), - ty::Param(_) => true, - ty::Adt(def, _) => def.did() == args.ty_did, - _ => false, - } - }) { - // Passed to a function taking the non-dereferenced type. - set_skip_flag(); - } - }, - ExprKind::MethodCall(name, self_arg, expr_args, _) => { - let i = iter::once(self_arg) - .chain(expr_args.iter()) - .position(|arg| arg.hir_id == child_id) - .unwrap_or(0); - if i == 0 { - // Check if the method can be renamed. - let name = name.ident.as_str(); - if let Some((_, replacement)) = args.method_renames.iter().find(|&&(x, _)| x == name) { - result.replacements.push(PtrArgReplacement { - expr_span: e.span, - self_span: self_arg.span, - replacement, - }); - return; - } - } + Some((Node::Expr(use_expr), child_id)) => { + if let ExprKind::Index(e, ..) = use_expr.kind + && e.hir_id == child_id + { + // Indexing works with both owned and its dereferenced type + return; + } - let Some(id) = self.cx.typeck_results().type_dependent_def_id(e.hir_id) else { - set_skip_flag(); + if let ExprKind::MethodCall(name, receiver, ..) = use_expr.kind + && receiver.hir_id == child_id + { + let name = name.ident.as_str(); + + // Check if the method can be renamed. + if let Some((_, replacement)) = args.method_renames.iter().find(|&&(x, _)| x == name) { + result.replacements.push(PtrArgReplacement { + expr_span: use_expr.span, + self_span: receiver.span, + replacement, + }); return; - }; - - match *self.cx.tcx.fn_sig(id).instantiate_identity().skip_binder().inputs()[i] - .peel_refs() - .kind() - { - ty::Dynamic(preds, _, _) if !matches_preds(self.cx, args.deref_ty.ty(self.cx), preds) => { - set_skip_flag(); - }, - ty::Param(_) => { - set_skip_flag(); - }, - // If the types match check for methods which exist on both types. e.g. `Vec::len` and - // `slice::len` - ty::Adt(def, _) if def.did() == args.ty_did && !is_allowed_vec_method(self.cx, e) => { - set_skip_flag(); - }, - _ => (), } - }, - // Indexing is fine for currently supported types. - ExprKind::Index(e, _, _) if e.hir_id == child_id => (), - _ => set_skip_flag(), + + // Some methods exist on both `[T]` and `Vec`, such as `len`, where the receiver type + // doesn't coerce to a slice and our adjusted type check below isn't enough, + // but it would still be valid to call with a slice + if is_allowed_vec_method(self.cx, use_expr) { + return; + } + } + + let deref_ty = args.deref_ty.ty(self.cx); + let adjusted_ty = self.cx.typeck_results().expr_ty_adjusted(e).peel_refs(); + if adjusted_ty == deref_ty { + return; + } + + if let ty::Dynamic(preds, ..) = adjusted_ty.kind() + && matches_preds(self.cx, deref_ty, preds) + { + return; + } + + set_skip_flag(); }, _ => set_skip_flag(), } diff --git a/tests/ui/ptr_arg.rs b/tests/ui/ptr_arg.rs index e6ef6268121..e8b42d3b913 100644 --- a/tests/ui/ptr_arg.rs +++ b/tests/ui/ptr_arg.rs @@ -309,3 +309,25 @@ mod issue_11181 { extern "C" fn allowed(_v: &Vec) {} } } + +mod issue_13308 { + use std::ops::Deref; + + fn repro(source: &str, destination: &mut String) { + source.clone_into(destination); + } + fn repro2(source: &str, destination: &mut String) { + ToOwned::clone_into(source, destination); + } + + fn h1(_: &::Target) {} + fn h2(_: T, _: &T::Target) {} + + // Other cases that are still ok to lint and ideally shouldn't regress + fn good(v1: &String, v2: &String) { + //~^ ERROR: writing `&String` instead of `&str` + //~^^ ERROR: writing `&String` instead of `&str` + h1(v1); + h2(String::new(), v2); + } +} diff --git a/tests/ui/ptr_arg.stderr b/tests/ui/ptr_arg.stderr index 4246453e64c..1a6b3aa1f8d 100644 --- a/tests/ui/ptr_arg.stderr +++ b/tests/ui/ptr_arg.stderr @@ -221,5 +221,17 @@ error: using a reference to `Cow` is not recommended LL | fn cow_bad_ret_ty_2<'a, 'b>(input: &'a Cow<'a, str>) -> &'b str { | ^^^^^^^^^^^^^^^^ help: change this to: `&str` -error: aborting due to 25 previous errors +error: writing `&String` instead of `&str` involves a new object where a slice will do + --> tests/ui/ptr_arg.rs:327:17 + | +LL | fn good(v1: &String, v2: &String) { + | ^^^^^^^ help: change this to: `&str` + +error: writing `&String` instead of `&str` involves a new object where a slice will do + --> tests/ui/ptr_arg.rs:327:30 + | +LL | fn good(v1: &String, v2: &String) { + | ^^^^^^^ help: change this to: `&str` + +error: aborting due to 27 previous errors From 561a6c5f117535b9aec84ca2341fdc8f0cdb0dd5 Mon Sep 17 00:00:00 2001 From: Caio Date: Fri, 13 Sep 2024 15:00:33 -0300 Subject: [PATCH 129/683] [`cfg_match`] Generalize inputs --- library/core/src/macros/mod.rs | 10 +++++----- library/core/tests/macros.rs | 20 ++++++++++++++++++++ 2 files changed, 25 insertions(+), 5 deletions(-) diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs index 888832251f6..aa0646846e4 100644 --- a/library/core/src/macros/mod.rs +++ b/library/core/src/macros/mod.rs @@ -229,8 +229,8 @@ pub macro assert_matches { pub macro cfg_match { // with a final wildcard ( - $(cfg($initial_meta:meta) => { $($initial_tokens:item)* })+ - _ => { $($extra_tokens:item)* } + $(cfg($initial_meta:meta) => { $($initial_tokens:tt)* })+ + _ => { $($extra_tokens:tt)* } ) => { cfg_match! { @__items (); @@ -241,7 +241,7 @@ pub macro cfg_match { // without a final wildcard ( - $(cfg($extra_meta:meta) => { $($extra_tokens:item)* })* + $(cfg($extra_meta:meta) => { $($extra_tokens:tt)* })* ) => { cfg_match! { @__items (); @@ -256,7 +256,7 @@ pub macro cfg_match { (@__items ($($_:meta,)*);) => {}, ( @__items ($($no:meta,)*); - (($($yes:meta)?) ($($tokens:item)*)), + (($($yes:meta)?) ($($tokens:tt)*)), $($rest:tt,)* ) => { // Emit all items within one block, applying an appropriate #[cfg]. The @@ -279,7 +279,7 @@ pub macro cfg_match { // Internal macro to make __apply work out right for different match types, // because of how macros match/expand stuff. - (@__identity $($tokens:item)*) => { + (@__identity $($tokens:tt)*) => { $($tokens)* } } diff --git a/library/core/tests/macros.rs b/library/core/tests/macros.rs index 09994fbcbdb..416d8fba391 100644 --- a/library/core/tests/macros.rs +++ b/library/core/tests/macros.rs @@ -1,3 +1,5 @@ +#![allow(unused_must_use)] + #[allow(dead_code)] trait Trait { fn blah(&self); @@ -173,3 +175,21 @@ fn cfg_match_two_functions() { bar2(); } } + +fn _accepts_expressions() -> i32 { + cfg_match! { + cfg(unix) => { 1 } + _ => { 2 } + } +} + +// The current implementation expands to a macro call, which allows the use of expression +// statements. +fn _allows_stmt_expr_attributes() { + let one = 1; + let two = 2; + cfg_match! { + cfg(unix) => { one * two; } + _ => { one + two; } + } +} \ No newline at end of file From ae15032069f9b6794b8d30fc8bc72f05633d5e0e Mon Sep 17 00:00:00 2001 From: Caio Date: Fri, 13 Sep 2024 15:18:30 -0300 Subject: [PATCH 130/683] Rustfmt --- library/core/tests/macros.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/tests/macros.rs b/library/core/tests/macros.rs index 416d8fba391..fdb4ea29412 100644 --- a/library/core/tests/macros.rs +++ b/library/core/tests/macros.rs @@ -192,4 +192,4 @@ fn _allows_stmt_expr_attributes() { cfg(unix) => { one * two; } _ => { one + two; } } -} \ No newline at end of file +} From 9e697964dc82522ed56b5d2f73f54a8e88638e9a Mon Sep 17 00:00:00 2001 From: Gurinder Singh Date: Sat, 14 Sep 2024 16:12:00 +0530 Subject: [PATCH 131/683] Fix lint levels not getting overridden by attrs on `Stmt` nodes --- tests/ui/expect_tool_lint_rfc_2383.stderr | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/tests/ui/expect_tool_lint_rfc_2383.stderr b/tests/ui/expect_tool_lint_rfc_2383.stderr index f70d3408aa4..028e22ca724 100644 --- a/tests/ui/expect_tool_lint_rfc_2383.stderr +++ b/tests/ui/expect_tool_lint_rfc_2383.stderr @@ -13,6 +13,14 @@ error: this lint expectation is unfulfilled LL | #[expect(invalid_nan_comparisons)] | ^^^^^^^^^^^^^^^^^^^^^^^ +error: this lint expectation is unfulfilled + --> tests/ui/expect_tool_lint_rfc_2383.rs:36:18 + | +LL | #[expect(invalid_nan_comparisons)] + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + error: this lint expectation is unfulfilled --> tests/ui/expect_tool_lint_rfc_2383.rs:107:14 | @@ -37,5 +45,5 @@ error: this lint expectation is unfulfilled LL | #[expect(clippy::overly_complex_bool_expr)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 6 previous errors +error: aborting due to 7 previous errors From b5ea5c23b34129f5af82ccf5b9e5babd9bbc9285 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Thu, 29 Aug 2024 15:33:34 +0200 Subject: [PATCH 132/683] stabilize `const_extern_fn` --- clippy_config/src/msrvs.rs | 3 +- clippy_lints/src/missing_const_for_fn.rs | 10 +- .../ui/missing_const_for_fn/cant_be_const.rs | 6 -- .../missing_const_for_fn/could_be_const.fixed | 14 +++ .../ui/missing_const_for_fn/could_be_const.rs | 14 +++ .../could_be_const.stderr | 99 ++++++++++++++----- .../could_be_const_with_const_extern_fn.fixed | 14 --- .../could_be_const_with_const_extern_fn.rs | 14 --- ...could_be_const_with_const_extern_fn.stderr | 59 ----------- 9 files changed, 111 insertions(+), 122 deletions(-) delete mode 100644 tests/ui/missing_const_for_fn/could_be_const_with_const_extern_fn.fixed delete mode 100644 tests/ui/missing_const_for_fn/could_be_const_with_const_extern_fn.rs delete mode 100644 tests/ui/missing_const_for_fn/could_be_const_with_const_extern_fn.stderr diff --git a/clippy_config/src/msrvs.rs b/clippy_config/src/msrvs.rs index e17458b3310..a2b4b6e256f 100644 --- a/clippy_config/src/msrvs.rs +++ b/clippy_config/src/msrvs.rs @@ -17,6 +17,7 @@ macro_rules! msrv_aliases { // names may refer to stabilized feature flags or library items msrv_aliases! { + 1,83,0 { CONST_EXTERN_FN } 1,83,0 { CONST_FLOAT_BITS_CONV } 1,81,0 { LINT_REASONS_STABILIZATION } 1,80,0 { BOX_INTO_ITER} @@ -27,7 +28,7 @@ msrv_aliases! { 1,68,0 { PATH_MAIN_SEPARATOR_STR } 1,65,0 { LET_ELSE, POINTER_CAST_CONSTNESS } 1,63,0 { CLONE_INTO } - 1,62,0 { BOOL_THEN_SOME, DEFAULT_ENUM_ATTRIBUTE, CONST_EXTERN_FN } + 1,62,0 { BOOL_THEN_SOME, DEFAULT_ENUM_ATTRIBUTE, CONST_EXTERN_C_FN } 1,59,0 { THREAD_LOCAL_CONST_INIT } 1,58,0 { FORMAT_ARGS_CAPTURE, PATTERN_TRAIT_CHAR_ARRAY, CONST_RAW_PTR_DEREF } 1,56,0 { CONST_FN_UNION } diff --git a/clippy_lints/src/missing_const_for_fn.rs b/clippy_lints/src/missing_const_for_fn.rs index 052d738b2e7..859afe1b963 100644 --- a/clippy_lints/src/missing_const_for_fn.rs +++ b/clippy_lints/src/missing_const_for_fn.rs @@ -119,9 +119,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingConstForFn { .iter() .any(|param| matches!(param.kind, GenericParamKind::Const { .. })); - if already_const(header) - || has_const_generic_params - || !could_be_const_with_abi(cx, &self.msrv, header.abi) + if already_const(header) || has_const_generic_params || !could_be_const_with_abi(&self.msrv, header.abi) { return; } @@ -183,13 +181,13 @@ fn already_const(header: hir::FnHeader) -> bool { header.constness == Constness::Const } -fn could_be_const_with_abi(cx: &LateContext<'_>, msrv: &Msrv, abi: Abi) -> bool { +fn could_be_const_with_abi(msrv: &Msrv, abi: Abi) -> bool { match abi { Abi::Rust => true, // `const extern "C"` was stabilized after 1.62.0 - Abi::C { unwind: false } => msrv.meets(msrvs::CONST_EXTERN_FN), + Abi::C { unwind: false } => msrv.meets(msrvs::CONST_EXTERN_C_FN), // Rest ABIs are still unstable and need the `const_extern_fn` feature enabled. - _ => cx.tcx.features().const_extern_fn, + _ => msrv.meets(msrvs::CONST_EXTERN_FN), } } 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 2c6e1e92da0..ca323dcf173 100644 --- a/tests/ui/missing_const_for_fn/cant_be_const.rs +++ b/tests/ui/missing_const_for_fn/cant_be_const.rs @@ -186,12 +186,6 @@ mod msrv { extern "C" fn c() {} } -mod with_extern { - extern "C-unwind" fn c_unwind() {} - extern "system" fn system() {} - extern "system-unwind" fn system_unwind() {} -} - mod with_ty_alias { type Foo = impl std::fmt::Debug; diff --git a/tests/ui/missing_const_for_fn/could_be_const.fixed b/tests/ui/missing_const_for_fn/could_be_const.fixed index f54503ada97..0aef4d31fd9 100644 --- a/tests/ui/missing_const_for_fn/could_be_const.fixed +++ b/tests/ui/missing_const_for_fn/could_be_const.fixed @@ -1,5 +1,6 @@ #![warn(clippy::missing_const_for_fn)] #![allow(incomplete_features, clippy::let_and_return, clippy::missing_transmute_annotations)] +#![allow(unsupported_calling_conventions)] #![feature(const_mut_refs)] #![feature(const_trait_impl)] @@ -204,3 +205,16 @@ mod with_ty_alias { // in this test. const fn alias_ty_is_projection(bar: <() as FooTrait>::Foo) {} } + +mod extern_fn { + const extern "C-unwind" fn c_unwind() {} + //~^ ERROR: this could be a `const fn` + const extern "system" fn system() {} + //~^ ERROR: this could be a `const fn` + const extern "system-unwind" fn system_unwind() {} + //~^ ERROR: this could be a `const fn` + pub const extern "stdcall" fn std_call() {} + //~^ ERROR: this could be a `const fn` + pub const extern "stdcall-unwind" fn std_call_unwind() {} + //~^ ERROR: this could be a `const fn` +} diff --git a/tests/ui/missing_const_for_fn/could_be_const.rs b/tests/ui/missing_const_for_fn/could_be_const.rs index 2c229068e4d..4246494fe72 100644 --- a/tests/ui/missing_const_for_fn/could_be_const.rs +++ b/tests/ui/missing_const_for_fn/could_be_const.rs @@ -1,5 +1,6 @@ #![warn(clippy::missing_const_for_fn)] #![allow(incomplete_features, clippy::let_and_return, clippy::missing_transmute_annotations)] +#![allow(unsupported_calling_conventions)] #![feature(const_mut_refs)] #![feature(const_trait_impl)] @@ -204,3 +205,16 @@ mod with_ty_alias { // in this test. fn alias_ty_is_projection(bar: <() as FooTrait>::Foo) {} } + +mod extern_fn { + extern "C-unwind" fn c_unwind() {} + //~^ ERROR: this could be a `const fn` + extern "system" fn system() {} + //~^ ERROR: this could be a `const fn` + extern "system-unwind" fn system_unwind() {} + //~^ ERROR: this could be a `const fn` + pub extern "stdcall" fn std_call() {} + //~^ ERROR: this could be a `const fn` + pub extern "stdcall-unwind" fn std_call_unwind() {} + //~^ ERROR: this could be a `const fn` +} diff --git a/tests/ui/missing_const_for_fn/could_be_const.stderr b/tests/ui/missing_const_for_fn/could_be_const.stderr index fb4db703103..6bc71e29840 100644 --- a/tests/ui/missing_const_for_fn/could_be_const.stderr +++ b/tests/ui/missing_const_for_fn/could_be_const.stderr @@ -1,5 +1,5 @@ error: this could be a `const fn` - --> tests/ui/missing_const_for_fn/could_be_const.rs:14:5 + --> tests/ui/missing_const_for_fn/could_be_const.rs:15:5 | LL | / pub fn new() -> Self { LL | | @@ -16,7 +16,7 @@ LL | pub const fn new() -> Self { | +++++ error: this could be a `const fn` - --> tests/ui/missing_const_for_fn/could_be_const.rs:20:5 + --> tests/ui/missing_const_for_fn/could_be_const.rs:21:5 | LL | / fn const_generic_params<'a, T, const N: usize>(&self, b: &'a [T; N]) -> &'a [T; N] { LL | | @@ -30,7 +30,7 @@ LL | const fn const_generic_params<'a, T, const N: usize>(&self, b: &'a [T; | +++++ error: this could be a `const fn` - --> tests/ui/missing_const_for_fn/could_be_const.rs:27:1 + --> tests/ui/missing_const_for_fn/could_be_const.rs:28:1 | LL | / fn one() -> i32 { LL | | @@ -44,7 +44,7 @@ LL | const fn one() -> i32 { | +++++ error: this could be a `const fn` - --> tests/ui/missing_const_for_fn/could_be_const.rs:33:1 + --> tests/ui/missing_const_for_fn/could_be_const.rs:34:1 | LL | / fn two() -> i32 { LL | | @@ -59,7 +59,7 @@ LL | const fn two() -> i32 { | +++++ error: this could be a `const fn` - --> tests/ui/missing_const_for_fn/could_be_const.rs:40:1 + --> tests/ui/missing_const_for_fn/could_be_const.rs:41:1 | LL | / fn string() -> String { LL | | @@ -73,7 +73,7 @@ LL | const fn string() -> String { | +++++ error: this could be a `const fn` - --> tests/ui/missing_const_for_fn/could_be_const.rs:46:1 + --> tests/ui/missing_const_for_fn/could_be_const.rs:47:1 | LL | / unsafe fn four() -> i32 { LL | | @@ -87,7 +87,7 @@ LL | const unsafe fn four() -> i32 { | +++++ error: this could be a `const fn` - --> tests/ui/missing_const_for_fn/could_be_const.rs:52:1 + --> tests/ui/missing_const_for_fn/could_be_const.rs:53:1 | LL | / fn generic(t: T) -> T { LL | | @@ -101,7 +101,7 @@ LL | const fn generic(t: T) -> T { | +++++ error: this could be a `const fn` - --> tests/ui/missing_const_for_fn/could_be_const.rs:61:1 + --> tests/ui/missing_const_for_fn/could_be_const.rs:62:1 | LL | / fn generic_arr(t: [T; 1]) -> T { LL | | @@ -115,7 +115,7 @@ LL | const fn generic_arr(t: [T; 1]) -> T { | +++++ error: this could be a `const fn` - --> tests/ui/missing_const_for_fn/could_be_const.rs:75:9 + --> tests/ui/missing_const_for_fn/could_be_const.rs:76:9 | LL | / pub fn b(self, a: &A) -> B { LL | | @@ -129,7 +129,7 @@ LL | pub const fn b(self, a: &A) -> B { | +++++ error: this could be a `const fn` - --> tests/ui/missing_const_for_fn/could_be_const.rs:85:5 + --> tests/ui/missing_const_for_fn/could_be_const.rs:86:5 | LL | / fn const_fn_stabilized_before_msrv(byte: u8) { LL | | @@ -143,7 +143,7 @@ LL | const fn const_fn_stabilized_before_msrv(byte: u8) { | +++++ error: this could be a `const fn` - --> tests/ui/missing_const_for_fn/could_be_const.rs:97:1 + --> tests/ui/missing_const_for_fn/could_be_const.rs:98:1 | LL | / fn msrv_1_46() -> i32 { LL | | @@ -157,7 +157,7 @@ LL | const fn msrv_1_46() -> i32 { | +++++ error: this could be a `const fn` - --> tests/ui/missing_const_for_fn/could_be_const.rs:117:1 + --> tests/ui/missing_const_for_fn/could_be_const.rs:118:1 | LL | fn d(this: D) {} | ^^^^^^^^^^^^^^^^ @@ -168,7 +168,7 @@ LL | const fn d(this: D) {} | +++++ error: this could be a `const fn` - --> tests/ui/missing_const_for_fn/could_be_const.rs:125:9 + --> tests/ui/missing_const_for_fn/could_be_const.rs:126:9 | LL | / fn deref_ptr_can_be_const(self) -> usize { LL | | @@ -182,7 +182,7 @@ LL | const fn deref_ptr_can_be_const(self) -> usize { | +++++ error: this could be a `const fn` - --> tests/ui/missing_const_for_fn/could_be_const.rs:130:9 + --> tests/ui/missing_const_for_fn/could_be_const.rs:131:9 | LL | / fn deref_copied_val(self) -> usize { LL | | @@ -196,7 +196,7 @@ LL | const fn deref_copied_val(self) -> usize { | +++++ error: this could be a `const fn` - --> tests/ui/missing_const_for_fn/could_be_const.rs:141:5 + --> tests/ui/missing_const_for_fn/could_be_const.rs:142:5 | LL | / fn union_access_can_be_const() { LL | | @@ -211,7 +211,7 @@ LL | const fn union_access_can_be_const() { | +++++ error: this could be a `const fn` - --> tests/ui/missing_const_for_fn/could_be_const.rs:149:9 + --> tests/ui/missing_const_for_fn/could_be_const.rs:150:9 | LL | extern "C" fn c() {} | ^^^^^^^^^^^^^^^^^^^^ @@ -222,7 +222,7 @@ LL | const extern "C" fn c() {} | +++++ error: this could be a `const fn` - --> tests/ui/missing_const_for_fn/could_be_const.rs:153:9 + --> tests/ui/missing_const_for_fn/could_be_const.rs:154:9 | LL | extern fn implicit_c() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -233,7 +233,7 @@ LL | const extern fn implicit_c() {} | +++++ error: this could be a `const fn` - --> tests/ui/missing_const_for_fn/could_be_const.rs:170:9 + --> tests/ui/missing_const_for_fn/could_be_const.rs:171:9 | LL | / pub fn new(strings: Vec) -> Self { LL | | Self { strings } @@ -246,7 +246,7 @@ LL | pub const fn new(strings: Vec) -> Self { | +++++ error: this could be a `const fn` - --> tests/ui/missing_const_for_fn/could_be_const.rs:175:9 + --> tests/ui/missing_const_for_fn/could_be_const.rs:176:9 | LL | / pub fn empty() -> Self { LL | | Self { strings: Vec::new() } @@ -259,7 +259,7 @@ LL | pub const fn empty() -> Self { | +++++ error: this could be a `const fn` - --> tests/ui/missing_const_for_fn/could_be_const.rs:186:9 + --> tests/ui/missing_const_for_fn/could_be_const.rs:187:9 | LL | / pub fn new(text: String) -> Self { LL | | let vec = Vec::new(); @@ -273,7 +273,7 @@ LL | pub const fn new(text: String) -> Self { | +++++ error: this could be a `const fn` - --> tests/ui/missing_const_for_fn/could_be_const.rs:205:5 + --> tests/ui/missing_const_for_fn/could_be_const.rs:206:5 | LL | fn alias_ty_is_projection(bar: <() as FooTrait>::Foo) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -283,5 +283,60 @@ help: make the function `const` LL | const fn alias_ty_is_projection(bar: <() as FooTrait>::Foo) {} | +++++ -error: aborting due to 21 previous errors +error: this could be a `const fn` + --> tests/ui/missing_const_for_fn/could_be_const.rs:210:5 + | +LL | extern "C-unwind" fn c_unwind() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: make the function `const` + | +LL | const extern "C-unwind" fn c_unwind() {} + | +++++ + +error: this could be a `const fn` + --> tests/ui/missing_const_for_fn/could_be_const.rs:212:5 + | +LL | extern "system" fn system() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: make the function `const` + | +LL | const extern "system" fn system() {} + | +++++ + +error: this could be a `const fn` + --> tests/ui/missing_const_for_fn/could_be_const.rs:214:5 + | +LL | extern "system-unwind" fn system_unwind() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: make the function `const` + | +LL | const extern "system-unwind" fn system_unwind() {} + | +++++ + +error: this could be a `const fn` + --> tests/ui/missing_const_for_fn/could_be_const.rs:216:5 + | +LL | pub extern "stdcall" fn std_call() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: make the function `const` + | +LL | pub const extern "stdcall" fn std_call() {} + | +++++ + +error: this could be a `const fn` + --> tests/ui/missing_const_for_fn/could_be_const.rs:218:5 + | +LL | pub extern "stdcall-unwind" fn std_call_unwind() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: make the function `const` + | +LL | pub const extern "stdcall-unwind" fn std_call_unwind() {} + | +++++ + +error: aborting due to 26 previous errors diff --git a/tests/ui/missing_const_for_fn/could_be_const_with_const_extern_fn.fixed b/tests/ui/missing_const_for_fn/could_be_const_with_const_extern_fn.fixed deleted file mode 100644 index c103db536ab..00000000000 --- a/tests/ui/missing_const_for_fn/could_be_const_with_const_extern_fn.fixed +++ /dev/null @@ -1,14 +0,0 @@ -#![warn(clippy::missing_const_for_fn)] -#![allow(unsupported_calling_conventions)] -#![feature(const_extern_fn)] - -const extern "C-unwind" fn c_unwind() {} -//~^ ERROR: this could be a `const fn` -const extern "system" fn system() {} -//~^ ERROR: this could be a `const fn` -const extern "system-unwind" fn system_unwind() {} -//~^ ERROR: this could be a `const fn` -pub const extern "stdcall" fn std_call() {} -//~^ ERROR: this could be a `const fn` -pub const extern "stdcall-unwind" fn std_call_unwind() {} -//~^ ERROR: this could be a `const fn` diff --git a/tests/ui/missing_const_for_fn/could_be_const_with_const_extern_fn.rs b/tests/ui/missing_const_for_fn/could_be_const_with_const_extern_fn.rs deleted file mode 100644 index 0f7020ae559..00000000000 --- a/tests/ui/missing_const_for_fn/could_be_const_with_const_extern_fn.rs +++ /dev/null @@ -1,14 +0,0 @@ -#![warn(clippy::missing_const_for_fn)] -#![allow(unsupported_calling_conventions)] -#![feature(const_extern_fn)] - -extern "C-unwind" fn c_unwind() {} -//~^ ERROR: this could be a `const fn` -extern "system" fn system() {} -//~^ ERROR: this could be a `const fn` -extern "system-unwind" fn system_unwind() {} -//~^ ERROR: this could be a `const fn` -pub extern "stdcall" fn std_call() {} -//~^ ERROR: this could be a `const fn` -pub extern "stdcall-unwind" fn std_call_unwind() {} -//~^ ERROR: this could be a `const fn` diff --git a/tests/ui/missing_const_for_fn/could_be_const_with_const_extern_fn.stderr b/tests/ui/missing_const_for_fn/could_be_const_with_const_extern_fn.stderr deleted file mode 100644 index 036094a367b..00000000000 --- a/tests/ui/missing_const_for_fn/could_be_const_with_const_extern_fn.stderr +++ /dev/null @@ -1,59 +0,0 @@ -error: this could be a `const fn` - --> tests/ui/missing_const_for_fn/could_be_const_with_const_extern_fn.rs:5:1 - | -LL | extern "C-unwind" fn c_unwind() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: `-D clippy::missing-const-for-fn` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::missing_const_for_fn)]` -help: make the function `const` - | -LL | const extern "C-unwind" fn c_unwind() {} - | +++++ - -error: this could be a `const fn` - --> tests/ui/missing_const_for_fn/could_be_const_with_const_extern_fn.rs:7:1 - | -LL | extern "system" fn system() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -help: make the function `const` - | -LL | const extern "system" fn system() {} - | +++++ - -error: this could be a `const fn` - --> tests/ui/missing_const_for_fn/could_be_const_with_const_extern_fn.rs:9:1 - | -LL | extern "system-unwind" fn system_unwind() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -help: make the function `const` - | -LL | const extern "system-unwind" fn system_unwind() {} - | +++++ - -error: this could be a `const fn` - --> tests/ui/missing_const_for_fn/could_be_const_with_const_extern_fn.rs:11:1 - | -LL | pub extern "stdcall" fn std_call() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -help: make the function `const` - | -LL | pub const extern "stdcall" fn std_call() {} - | +++++ - -error: this could be a `const fn` - --> tests/ui/missing_const_for_fn/could_be_const_with_const_extern_fn.rs:13:1 - | -LL | pub extern "stdcall-unwind" fn std_call_unwind() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -help: make the function `const` - | -LL | pub const extern "stdcall-unwind" fn std_call_unwind() {} - | +++++ - -error: aborting due to 5 previous errors - From 90745bd1ededab96175485b098f58ae6d26e24f8 Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Sun, 15 Sep 2024 07:41:24 +0300 Subject: [PATCH 133/683] Feed `GitInfo`s from `Config` to `Build` Signed-off-by: onur-ozkan --- src/bootstrap/src/core/config/config.rs | 22 ++++++++++++++++++++++ src/bootstrap/src/lib.rs | 19 +++++++++---------- 2 files changed, 31 insertions(+), 10 deletions(-) diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index 79c2f73161e..928366e64d0 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -342,6 +342,15 @@ pub struct Config { pub out: PathBuf, pub rust_info: channel::GitInfo, + pub cargo_info: channel::GitInfo, + pub rust_analyzer_info: channel::GitInfo, + pub clippy_info: channel::GitInfo, + pub miri_info: channel::GitInfo, + pub rustfmt_info: channel::GitInfo, + pub enzyme_info: channel::GitInfo, + pub in_tree_llvm_info: channel::GitInfo, + pub in_tree_gcc_info: channel::GitInfo, + // These are either the stage0 downloaded binaries or the locally installed ones. pub initial_cargo: PathBuf, pub initial_rustc: PathBuf, @@ -1797,6 +1806,19 @@ impl Config { config.omit_git_hash = omit_git_hash.unwrap_or(default); config.rust_info = GitInfo::new(config.omit_git_hash, &config.src); + config.cargo_info = GitInfo::new(config.omit_git_hash, &config.src.join("src/tools/cargo")); + config.rust_analyzer_info = + GitInfo::new(config.omit_git_hash, &config.src.join("src/tools/rust-analyzer")); + config.clippy_info = + GitInfo::new(config.omit_git_hash, &config.src.join("src/tools/clippy")); + config.miri_info = GitInfo::new(config.omit_git_hash, &config.src.join("src/tools/miri")); + config.rustfmt_info = + GitInfo::new(config.omit_git_hash, &config.src.join("src/tools/rustfmt")); + config.enzyme_info = + GitInfo::new(config.omit_git_hash, &config.src.join("src/tools/enzyme")); + config.in_tree_llvm_info = GitInfo::new(false, &config.src.join("src/llvm-project")); + config.in_tree_gcc_info = GitInfo::new(false, &config.src.join("src/gcc")); + // We need to override `rust.channel` if it's manually specified when using the CI rustc. // This is because if the compiler uses a different channel than the one specified in config.toml, // tests may fail due to using a different channel than the one used by the compiler during tests. diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs index df2acd8b76b..6467f4e3591 100644 --- a/src/bootstrap/src/lib.rs +++ b/src/bootstrap/src/lib.rs @@ -305,18 +305,17 @@ impl Build { #[cfg(not(unix))] let is_sudo = false; - let omit_git_hash = config.omit_git_hash; - let rust_info = GitInfo::new(omit_git_hash, &src); - let cargo_info = GitInfo::new(omit_git_hash, &src.join("src/tools/cargo")); - let rust_analyzer_info = GitInfo::new(omit_git_hash, &src.join("src/tools/rust-analyzer")); - let clippy_info = GitInfo::new(omit_git_hash, &src.join("src/tools/clippy")); - let miri_info = GitInfo::new(omit_git_hash, &src.join("src/tools/miri")); - let rustfmt_info = GitInfo::new(omit_git_hash, &src.join("src/tools/rustfmt")); - let enzyme_info = GitInfo::new(omit_git_hash, &src.join("src/tools/enzyme")); + let rust_info = config.rust_info.clone(); + let cargo_info = config.cargo_info.clone(); + let rust_analyzer_info = config.rust_analyzer_info.clone(); + let clippy_info = config.clippy_info.clone(); + let miri_info = config.miri_info.clone(); + let rustfmt_info = config.rustfmt_info.clone(); + let enzyme_info = config.enzyme_info.clone(); // we always try to use git for LLVM builds - let in_tree_llvm_info = GitInfo::new(false, &src.join("src/llvm-project")); - let in_tree_gcc_info = GitInfo::new(false, &src.join("src/gcc")); + let in_tree_llvm_info = config.in_tree_llvm_info.clone(); + let in_tree_gcc_info = config.in_tree_gcc_info.clone(); let initial_target_libdir_str = if config.dry_run() { "/dummy/lib/path/to/lib/".to_string() From 976131f89663f565da9ab2b26bb8c33674d70460 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 17 Aug 2024 14:19:34 +0200 Subject: [PATCH 134/683] stabilize const_mut_refs --- tests/ui/arithmetic_side_effects.rs | 6 +-- .../missing_const_for_fn/could_be_const.fixed | 1 - .../ui/missing_const_for_fn/could_be_const.rs | 1 - .../could_be_const.stderr | 52 +++++++++---------- 4 files changed, 29 insertions(+), 31 deletions(-) diff --git a/tests/ui/arithmetic_side_effects.rs b/tests/ui/arithmetic_side_effects.rs index 9d06e14e88c..0838d064a5f 100644 --- a/tests/ui/arithmetic_side_effects.rs +++ b/tests/ui/arithmetic_side_effects.rs @@ -1,5 +1,8 @@ //@aux-build:proc_macro_derive.rs +#![feature(f128)] +#![feature(f16)] + #![allow( clippy::assign_op_pattern, clippy::erasing_op, @@ -10,9 +13,6 @@ arithmetic_overflow, unconditional_panic )] -#![feature(const_mut_refs)] -#![feature(f128)] -#![feature(f16)] #![warn(clippy::arithmetic_side_effects)] extern crate proc_macro_derive; diff --git a/tests/ui/missing_const_for_fn/could_be_const.fixed b/tests/ui/missing_const_for_fn/could_be_const.fixed index 0aef4d31fd9..41b424a8e5d 100644 --- a/tests/ui/missing_const_for_fn/could_be_const.fixed +++ b/tests/ui/missing_const_for_fn/could_be_const.fixed @@ -1,7 +1,6 @@ #![warn(clippy::missing_const_for_fn)] #![allow(incomplete_features, clippy::let_and_return, clippy::missing_transmute_annotations)] #![allow(unsupported_calling_conventions)] -#![feature(const_mut_refs)] #![feature(const_trait_impl)] use std::mem::transmute; diff --git a/tests/ui/missing_const_for_fn/could_be_const.rs b/tests/ui/missing_const_for_fn/could_be_const.rs index 4246494fe72..27593575a01 100644 --- a/tests/ui/missing_const_for_fn/could_be_const.rs +++ b/tests/ui/missing_const_for_fn/could_be_const.rs @@ -1,7 +1,6 @@ #![warn(clippy::missing_const_for_fn)] #![allow(incomplete_features, clippy::let_and_return, clippy::missing_transmute_annotations)] #![allow(unsupported_calling_conventions)] -#![feature(const_mut_refs)] #![feature(const_trait_impl)] use std::mem::transmute; diff --git a/tests/ui/missing_const_for_fn/could_be_const.stderr b/tests/ui/missing_const_for_fn/could_be_const.stderr index 6bc71e29840..12d97b17119 100644 --- a/tests/ui/missing_const_for_fn/could_be_const.stderr +++ b/tests/ui/missing_const_for_fn/could_be_const.stderr @@ -1,5 +1,5 @@ error: this could be a `const fn` - --> tests/ui/missing_const_for_fn/could_be_const.rs:15:5 + --> tests/ui/missing_const_for_fn/could_be_const.rs:14:5 | LL | / pub fn new() -> Self { LL | | @@ -16,7 +16,7 @@ LL | pub const fn new() -> Self { | +++++ error: this could be a `const fn` - --> tests/ui/missing_const_for_fn/could_be_const.rs:21:5 + --> tests/ui/missing_const_for_fn/could_be_const.rs:20:5 | LL | / fn const_generic_params<'a, T, const N: usize>(&self, b: &'a [T; N]) -> &'a [T; N] { LL | | @@ -30,7 +30,7 @@ LL | const fn const_generic_params<'a, T, const N: usize>(&self, b: &'a [T; | +++++ error: this could be a `const fn` - --> tests/ui/missing_const_for_fn/could_be_const.rs:28:1 + --> tests/ui/missing_const_for_fn/could_be_const.rs:27:1 | LL | / fn one() -> i32 { LL | | @@ -44,7 +44,7 @@ LL | const fn one() -> i32 { | +++++ error: this could be a `const fn` - --> tests/ui/missing_const_for_fn/could_be_const.rs:34:1 + --> tests/ui/missing_const_for_fn/could_be_const.rs:33:1 | LL | / fn two() -> i32 { LL | | @@ -59,7 +59,7 @@ LL | const fn two() -> i32 { | +++++ error: this could be a `const fn` - --> tests/ui/missing_const_for_fn/could_be_const.rs:41:1 + --> tests/ui/missing_const_for_fn/could_be_const.rs:40:1 | LL | / fn string() -> String { LL | | @@ -73,7 +73,7 @@ LL | const fn string() -> String { | +++++ error: this could be a `const fn` - --> tests/ui/missing_const_for_fn/could_be_const.rs:47:1 + --> tests/ui/missing_const_for_fn/could_be_const.rs:46:1 | LL | / unsafe fn four() -> i32 { LL | | @@ -87,7 +87,7 @@ LL | const unsafe fn four() -> i32 { | +++++ error: this could be a `const fn` - --> tests/ui/missing_const_for_fn/could_be_const.rs:53:1 + --> tests/ui/missing_const_for_fn/could_be_const.rs:52:1 | LL | / fn generic(t: T) -> T { LL | | @@ -101,7 +101,7 @@ LL | const fn generic(t: T) -> T { | +++++ error: this could be a `const fn` - --> tests/ui/missing_const_for_fn/could_be_const.rs:62:1 + --> tests/ui/missing_const_for_fn/could_be_const.rs:61:1 | LL | / fn generic_arr(t: [T; 1]) -> T { LL | | @@ -115,7 +115,7 @@ LL | const fn generic_arr(t: [T; 1]) -> T { | +++++ error: this could be a `const fn` - --> tests/ui/missing_const_for_fn/could_be_const.rs:76:9 + --> tests/ui/missing_const_for_fn/could_be_const.rs:75:9 | LL | / pub fn b(self, a: &A) -> B { LL | | @@ -129,7 +129,7 @@ LL | pub const fn b(self, a: &A) -> B { | +++++ error: this could be a `const fn` - --> tests/ui/missing_const_for_fn/could_be_const.rs:86:5 + --> tests/ui/missing_const_for_fn/could_be_const.rs:85:5 | LL | / fn const_fn_stabilized_before_msrv(byte: u8) { LL | | @@ -143,7 +143,7 @@ LL | const fn const_fn_stabilized_before_msrv(byte: u8) { | +++++ error: this could be a `const fn` - --> tests/ui/missing_const_for_fn/could_be_const.rs:98:1 + --> tests/ui/missing_const_for_fn/could_be_const.rs:97:1 | LL | / fn msrv_1_46() -> i32 { LL | | @@ -157,7 +157,7 @@ LL | const fn msrv_1_46() -> i32 { | +++++ error: this could be a `const fn` - --> tests/ui/missing_const_for_fn/could_be_const.rs:118:1 + --> tests/ui/missing_const_for_fn/could_be_const.rs:117:1 | LL | fn d(this: D) {} | ^^^^^^^^^^^^^^^^ @@ -168,7 +168,7 @@ LL | const fn d(this: D) {} | +++++ error: this could be a `const fn` - --> tests/ui/missing_const_for_fn/could_be_const.rs:126:9 + --> tests/ui/missing_const_for_fn/could_be_const.rs:125:9 | LL | / fn deref_ptr_can_be_const(self) -> usize { LL | | @@ -182,7 +182,7 @@ LL | const fn deref_ptr_can_be_const(self) -> usize { | +++++ error: this could be a `const fn` - --> tests/ui/missing_const_for_fn/could_be_const.rs:131:9 + --> tests/ui/missing_const_for_fn/could_be_const.rs:130:9 | LL | / fn deref_copied_val(self) -> usize { LL | | @@ -196,7 +196,7 @@ LL | const fn deref_copied_val(self) -> usize { | +++++ error: this could be a `const fn` - --> tests/ui/missing_const_for_fn/could_be_const.rs:142:5 + --> tests/ui/missing_const_for_fn/could_be_const.rs:141:5 | LL | / fn union_access_can_be_const() { LL | | @@ -211,7 +211,7 @@ LL | const fn union_access_can_be_const() { | +++++ error: this could be a `const fn` - --> tests/ui/missing_const_for_fn/could_be_const.rs:150:9 + --> tests/ui/missing_const_for_fn/could_be_const.rs:149:9 | LL | extern "C" fn c() {} | ^^^^^^^^^^^^^^^^^^^^ @@ -222,7 +222,7 @@ LL | const extern "C" fn c() {} | +++++ error: this could be a `const fn` - --> tests/ui/missing_const_for_fn/could_be_const.rs:154:9 + --> tests/ui/missing_const_for_fn/could_be_const.rs:153:9 | LL | extern fn implicit_c() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -233,7 +233,7 @@ LL | const extern fn implicit_c() {} | +++++ error: this could be a `const fn` - --> tests/ui/missing_const_for_fn/could_be_const.rs:171:9 + --> tests/ui/missing_const_for_fn/could_be_const.rs:170:9 | LL | / pub fn new(strings: Vec) -> Self { LL | | Self { strings } @@ -246,7 +246,7 @@ LL | pub const fn new(strings: Vec) -> Self { | +++++ error: this could be a `const fn` - --> tests/ui/missing_const_for_fn/could_be_const.rs:176:9 + --> tests/ui/missing_const_for_fn/could_be_const.rs:175:9 | LL | / pub fn empty() -> Self { LL | | Self { strings: Vec::new() } @@ -259,7 +259,7 @@ LL | pub const fn empty() -> Self { | +++++ error: this could be a `const fn` - --> tests/ui/missing_const_for_fn/could_be_const.rs:187:9 + --> tests/ui/missing_const_for_fn/could_be_const.rs:186:9 | LL | / pub fn new(text: String) -> Self { LL | | let vec = Vec::new(); @@ -273,7 +273,7 @@ LL | pub const fn new(text: String) -> Self { | +++++ error: this could be a `const fn` - --> tests/ui/missing_const_for_fn/could_be_const.rs:206:5 + --> tests/ui/missing_const_for_fn/could_be_const.rs:205:5 | LL | fn alias_ty_is_projection(bar: <() as FooTrait>::Foo) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -284,7 +284,7 @@ LL | const fn alias_ty_is_projection(bar: <() as FooTrait>::Foo) {} | +++++ error: this could be a `const fn` - --> tests/ui/missing_const_for_fn/could_be_const.rs:210:5 + --> tests/ui/missing_const_for_fn/could_be_const.rs:209:5 | LL | extern "C-unwind" fn c_unwind() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -295,7 +295,7 @@ LL | const extern "C-unwind" fn c_unwind() {} | +++++ error: this could be a `const fn` - --> tests/ui/missing_const_for_fn/could_be_const.rs:212:5 + --> tests/ui/missing_const_for_fn/could_be_const.rs:211:5 | LL | extern "system" fn system() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -306,7 +306,7 @@ LL | const extern "system" fn system() {} | +++++ error: this could be a `const fn` - --> tests/ui/missing_const_for_fn/could_be_const.rs:214:5 + --> tests/ui/missing_const_for_fn/could_be_const.rs:213:5 | LL | extern "system-unwind" fn system_unwind() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -317,7 +317,7 @@ LL | const extern "system-unwind" fn system_unwind() {} | +++++ error: this could be a `const fn` - --> tests/ui/missing_const_for_fn/could_be_const.rs:216:5 + --> tests/ui/missing_const_for_fn/could_be_const.rs:215:5 | LL | pub extern "stdcall" fn std_call() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -328,7 +328,7 @@ LL | pub const extern "stdcall" fn std_call() {} | +++++ error: this could be a `const fn` - --> tests/ui/missing_const_for_fn/could_be_const.rs:218:5 + --> tests/ui/missing_const_for_fn/could_be_const.rs:217:5 | LL | pub extern "stdcall-unwind" fn std_call_unwind() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ From cb36d78d7ba5ddd1b148db955121f43aad9f5db4 Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Sun, 15 Sep 2024 17:24:37 -0400 Subject: [PATCH 135/683] Add more SIMD intrinsics --- src/base.rs | 5 +++++ src/builder.rs | 3 +++ src/declare.rs | 18 +++++++++++++++- src/intrinsic/llvm.rs | 50 ++++++++++++++++++++++++++++++++++++++++--- 4 files changed, 72 insertions(+), 4 deletions(-) diff --git a/src/base.rs b/src/base.rs index 2eaab3ed00c..d76011da980 100644 --- a/src/base.rs +++ b/src/base.rs @@ -116,6 +116,10 @@ pub fn compile_codegen_unit( context.add_command_line_option("-mavx"); } + /*for feature in tcx.sess.opts.cg.target_feature.split(',') { + println!("Feature: {}", feature); + }*/ + for arg in &tcx.sess.opts.cg.llvm_args { context.add_command_line_option(arg); } @@ -218,6 +222,7 @@ pub fn compile_codegen_unit( // ... and now that we have everything pre-defined, fill out those definitions. for &(mono_item, _) in &mono_items { + //println!("{:?}", mono_item); mono_item.define::>(&cx); } diff --git a/src/builder.rs b/src/builder.rs index 7ab9dfee46a..f07c5a53f68 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -270,6 +270,8 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { actual_val.dereference(self.location).to_rvalue() } } else { + // FIXME: this condition seems wrong: it will pass when both types are not + // a vector. assert!( (!expected_ty.is_vector() || actual_ty.is_vector()) && (expected_ty.is_vector() || !actual_ty.is_vector()), @@ -283,6 +285,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { ); // TODO(antoyo): perhaps use __builtin_convertvector for vector casting. // TODO: remove bitcast now that vector types can be compared? + println!("Name: {}", func_name); self.bitcast(actual_val, expected_ty) } } else { diff --git a/src/declare.rs b/src/declare.rs index a2b158ee0a7..cbf82918a9c 100644 --- a/src/declare.rs +++ b/src/declare.rs @@ -168,7 +168,23 @@ fn declare_raw_fn<'gcc>( variadic: bool, ) -> Function<'gcc> { if name.starts_with("llvm.") { - let intrinsic = llvm::intrinsic(name, cx); + let intrinsic = match name { + "llvm.fma.f16" => { + let param1 = cx.context.new_parameter(None, cx.double_type, "x"); + let param2 = cx.context.new_parameter(None, cx.double_type, "y"); + let param3 = cx.context.new_parameter(None, cx.double_type, "z"); + cx.context.new_function( + None, + FunctionType::Extern, + cx.double_type, + &[param1, param2, param3], + "fma", + false, + ) + } + _ => llvm::intrinsic(name, cx), + }; + cx.intrinsics.borrow_mut().insert(name.to_string(), intrinsic); return intrinsic; } diff --git a/src/intrinsic/llvm.rs b/src/intrinsic/llvm.rs index 52e5efd6d16..098c7fbb485 100644 --- a/src/intrinsic/llvm.rs +++ b/src/intrinsic/llvm.rs @@ -1,5 +1,6 @@ use std::borrow::Cow; +use gccjit::CType; use gccjit::{Function, FunctionPtrType, RValue, ToRValue, UnaryOp}; use rustc_codegen_ssa::traits::BuilderMethods; @@ -320,7 +321,9 @@ pub fn adjust_intrinsic_arguments<'a, 'b, 'gcc, 'tcx>( | "__builtin_ia32_vpmadd52luq512_mask" | "__builtin_ia32_vpmadd52huq256_mask" | "__builtin_ia32_vpmadd52luq256_mask" - | "__builtin_ia32_vpmadd52huq128_mask" => { + | "__builtin_ia32_vpmadd52huq128_mask" + | "__builtin_ia32_vfmaddsubph128_mask" + | "__builtin_ia32_vfmaddsubph256_mask" => { let mut new_args = args.to_vec(); let arg4_type = gcc_func.get_param_type(3); let minus_one = builder.context.new_rvalue_from_int(arg4_type, -1); @@ -440,6 +443,19 @@ pub fn adjust_intrinsic_arguments<'a, 'b, 'gcc, 'tcx>( new_args.push(last_arg); args = new_args.into(); } + // NOTE: the LLVM intrinsics receive 3 floats, but the GCC builtin requires 3 vectors. + "__builtin_ia32_vfmaddsh3_mask" => { + let new_args = args.to_vec(); + let arg1_type = gcc_func.get_param_type(0); + let arg2_type = gcc_func.get_param_type(1); + let arg3_type = gcc_func.get_param_type(2); + let arg5_type = gcc_func.get_param_type(4); + let a = builder.context.new_rvalue_from_vector(None, arg1_type, &[new_args[0]; 8]); + let b = builder.context.new_rvalue_from_vector(None, arg2_type, &[new_args[1]; 8]); + let c = builder.context.new_rvalue_from_vector(None, arg3_type, &[new_args[2]; 8]); + let arg5 = builder.context.new_rvalue_from_int(arg5_type, 4); + args = vec![a, b, c, new_args[3], arg5].into(); + } _ => (), } } else { @@ -452,7 +468,7 @@ pub fn adjust_intrinsic_arguments<'a, 'b, 'gcc, 'tcx>( let arg4 = builder.context.new_bitcast(None, new_args[2], arg4_type); args = vec![new_args[0], new_args[1], arg3, arg4, new_args[3], new_args[5]].into(); } - // NOTE: the LLVM intrinsic receives 3 floats, but the GCC builtin requires 3 vectors. + // NOTE: the LLVM intrinsics receive 3 floats, but the GCC builtin requires 3 vectors. // FIXME: the intrinsics like _mm_mask_fmadd_sd should probably directly call the GCC // intrinsic to avoid this. "__builtin_ia32_vfmaddss3_round" => { @@ -550,6 +566,25 @@ pub fn adjust_intrinsic_arguments<'a, 'b, 'gcc, 'tcx>( ] .into(); } + "__builtin_ia32_rndscalesh_mask_round" => { + let new_args = args.to_vec(); + args = vec![ + new_args[0], + new_args[1], + new_args[4], + new_args[2], + new_args[3], + new_args[5], + ] + .into(); + } + "fma" => { + let mut new_args = args.to_vec(); + new_args[0] = builder.context.new_cast(None, new_args[0], builder.double_type); + new_args[1] = builder.context.new_cast(None, new_args[1], builder.double_type); + new_args[2] = builder.context.new_cast(None, new_args[2], builder.double_type); + args = new_args.into(); + } _ => (), } } @@ -566,7 +601,9 @@ pub fn adjust_intrinsic_return_value<'a, 'gcc, 'tcx>( orig_args: &[RValue<'gcc>], ) -> RValue<'gcc> { match func_name { - "__builtin_ia32_vfmaddss3_round" | "__builtin_ia32_vfmaddsd3_round" => { + "__builtin_ia32_vfmaddss3_round" + | "__builtin_ia32_vfmaddsd3_round" + | "__builtin_ia32_vfmaddsh3_mask" => { #[cfg(feature = "master")] { let zero = builder.context.new_rvalue_zero(builder.int_type); @@ -625,6 +662,10 @@ pub fn adjust_intrinsic_return_value<'a, 'gcc, 'tcx>( &[random_number, success_variable.to_rvalue()], ); } + "fma" => { + let f16_type = builder.context.new_c_type(CType::Float16); + return_value = builder.context.new_cast(None, return_value, f16_type); + } _ => (), } @@ -1165,6 +1206,9 @@ pub fn intrinsic<'gcc, 'tcx>(name: &str, cx: &CodegenCx<'gcc, 'tcx>) -> Function "llvm.x86.avx512.mask.store.q.128" => "__builtin_ia32_movdqa64store128_mask", "llvm.x86.avx512.mask.store.ps.128" => "__builtin_ia32_storeaps128_mask", "llvm.x86.avx512.mask.store.pd.128" => "__builtin_ia32_storeapd128_mask", + "llvm.x86.avx512fp16.vfmadd.f16" => "__builtin_ia32_vfmaddsh3_mask", + "llvm.x86.avx512fp16.vfmaddsub.ph.128" => "__builtin_ia32_vfmaddsubph128_mask", + "llvm.x86.avx512fp16.vfmaddsub.ph.256" => "__builtin_ia32_vfmaddsubph256_mask", // TODO: support the tile builtins: "llvm.x86.ldtilecfg" => "__builtin_trap", From 249d3d2644aa88332b429b8cfecdcf31bbc1bd34 Mon Sep 17 00:00:00 2001 From: Kyle J Strand Date: Sun, 28 Jul 2024 16:48:14 -0600 Subject: [PATCH 136/683] update docs for `catch_unwind` & related funcs Documentation comments for `catch_unwind` and `thread::join` to indicate new behavioral guarantee when catching a foreign exception. --- library/core/src/intrinsics.rs | 15 ++++++--- library/std/src/panic.rs | 58 ++++++++++++++++++++-------------- library/std/src/thread/mod.rs | 27 +++++++++++++++- 3 files changed, 70 insertions(+), 30 deletions(-) diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index 8cb9accd59d..252648214f1 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -2666,12 +2666,17 @@ extern "rust-intrinsic" { /// /// `catch_fn` must not unwind. /// - /// The third argument is a function called if an unwind occurs (both Rust unwinds and foreign - /// unwinds). This function takes the data pointer and a pointer to the target-specific - /// exception object that was caught. For more information, see the compiler's source as well as - /// std's `catch_unwind` implementation. + /// The third argument is a function called if an unwind occurs (both Rust `panic` and foreign + /// unwinds). This function takes the data pointer and a pointer to the target- and + /// runtime-specific exception object that was caught. /// - /// The stable version of this intrinsic is `std::panic::catch_unwind`. + /// Note that in the case of a foreign unwinding operation, the exception object data may not be + /// safely usable from Rust, and should not be directly exposed via the standard library. To + /// prevent unsafe access, the library implementation may either abort the process or present an + /// opaque error type to the user. + /// + /// For more information, see the compiler's source, as well as the documentation for the stable + /// version of this intrinsic, `std::panic::catch_unwind`. #[rustc_nounwind] pub fn catch_unwind(try_fn: fn(*mut u8), data: *mut u8, catch_fn: fn(*mut u8, *mut u8)) -> i32; diff --git a/library/std/src/panic.rs b/library/std/src/panic.rs index 6f0952c41ed..65639112798 100644 --- a/library/std/src/panic.rs +++ b/library/std/src/panic.rs @@ -285,45 +285,55 @@ where /// Invokes a closure, capturing the cause of an unwinding panic if one occurs. /// -/// This function will return `Ok` with the closure's result if the closure -/// does not panic, and will return `Err(cause)` if the closure panics. The -/// `cause` returned is the object with which panic was originally invoked. +/// This function will return `Ok` with the closure's result if the closure does +/// not panic, and will return `Err(cause)` if the closure panics. The `cause` +/// returned is the object with which panic was originally invoked. /// -/// It is currently undefined behavior to unwind from Rust code into foreign -/// code, so this function is particularly useful when Rust is called from -/// another language (normally C). This can run arbitrary Rust code, capturing a -/// panic and allowing a graceful handling of the error. +/// Rust functions that are expected to be called from foreign code that does +/// not support unwinding (such as C compiled with `-fno-exceptions`) should be +/// defined using `extern "C"`, which ensures that if the Rust code panics, it +/// is automatically caught and the process is aborted. If this is the desired +/// behavior, it is not necessary to use `catch_unwind` explicitly. This +/// function should instead be used when more graceful error-handling is needed. /// /// It is **not** recommended to use this function for a general try/catch /// mechanism. The [`Result`] type is more appropriate to use for functions that /// can fail on a regular basis. Additionally, this function is not guaranteed /// to catch all panics, see the "Notes" section below. /// -/// The closure provided is required to adhere to the [`UnwindSafe`] trait to ensure -/// that all captured variables are safe to cross this boundary. The purpose of -/// this bound is to encode the concept of [exception safety][rfc] in the type -/// system. Most usage of this function should not need to worry about this -/// bound as programs are naturally unwind safe without `unsafe` code. If it -/// becomes a problem the [`AssertUnwindSafe`] wrapper struct can be used to quickly -/// assert that the usage here is indeed unwind safe. +/// The closure provided is required to adhere to the [`UnwindSafe`] trait to +/// ensure that all captured variables are safe to cross this boundary. The +/// purpose of this bound is to encode the concept of [exception safety][rfc] in +/// the type system. Most usage of this function should not need to worry about +/// this bound as programs are naturally unwind safe without `unsafe` code. If +/// it becomes a problem the [`AssertUnwindSafe`] wrapper struct can be used to +/// quickly assert that the usage here is indeed unwind safe. /// /// [rfc]: https://github.com/rust-lang/rfcs/blob/master/text/1236-stabilize-catch-panic.md /// /// # Notes /// -/// Note that this function **might not catch all panics** in Rust. A panic in -/// Rust is not always implemented via unwinding, but can be implemented by -/// aborting the process as well. This function *only* catches unwinding panics, -/// not those that abort the process. +/// This function **might not catch all Rust panics**. A Rust panic is not +/// always implemented via unwinding, but can be implemented by aborting the +/// process as well. This function *only* catches unwinding panics, not those +/// that abort the process. /// -/// Note that if a custom panic hook has been set, it will be invoked before -/// the panic is caught, before unwinding. +/// If a custom panic hook has been set, it will be invoked before the panic is +/// caught, before unwinding. /// -/// Also note that unwinding into Rust code with a foreign exception (e.g. -/// an exception thrown from C++ code) is undefined behavior. +/// Although unwinding into Rust code with a foreign exception (e.g. an +/// exception thrown from C++ code, or a `panic!` in Rust code compiled or +/// linked with a different runtime) via an appropriate ABI (e.g. `"C-unwind"`) +/// is permitted, catching such an exception using this function will have one +/// of two behaviors, and it is unspecified which will occur: /// -/// Finally, be **careful in how you drop the result of this function**. -/// If it is `Err`, it contains the panic payload, and dropping that may in turn panic! +/// * The process aborts, after executing all destructors of `f` and the +/// functions it called. +/// * The function returns a `Result::Err` containing an opaque type. +/// +/// Finally, be **careful in how you drop the result of this function**. If it +/// is `Err`, it contains the panic payload, and dropping that may in turn +/// panic! /// /// # Examples /// diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs index e29c28f3c7e..53fcf514bae 100644 --- a/library/std/src/thread/mod.rs +++ b/library/std/src/thread/mod.rs @@ -665,6 +665,19 @@ impl Builder { /// println!("{result}"); /// ``` /// +/// # Notes +/// +/// This function has the same minimal guarantee regarding "foreign" unwinding operations (e.g. +/// an exception thrown from C++ code, or a `panic!` in Rust code compiled or linked with a +/// different runtime) as [`catch_unwind`]; namely, if the thread created with `thread::spawn` +/// unwinds all the way to the root with such an exception, one of two behaviors are possible, +/// and it is unspecified which will occur: +/// +/// * The process aborts. +/// * The process does not abort, and [`join`] will return a `Result::Err` +/// containing an opaque type. +/// +/// [`catch_unwind`]: ../../std/panic/fn.catch_unwind.html /// [`channels`]: crate::sync::mpsc /// [`join`]: JoinHandle::join /// [`Err`]: crate::result::Result::Err @@ -1737,7 +1750,7 @@ impl JoinHandle { /// operations that happen after `join` returns. /// /// If the associated thread panics, [`Err`] is returned with the parameter given - /// to [`panic!`]. + /// to [`panic!`] (though see the Notes below). /// /// [`Err`]: crate::result::Result::Err /// [atomic memory orderings]: crate::sync::atomic @@ -1759,6 +1772,18 @@ impl JoinHandle { /// }).unwrap(); /// join_handle.join().expect("Couldn't join on the associated thread"); /// ``` + /// + /// # Notes + /// + /// If a "foreign" unwinding operation (e.g. an exception thrown from C++ + /// code, or a `panic!` in Rust code compiled or linked with a different + /// runtime) unwinds all the way to the thread root, the process may be + /// aborted; see the Notes on [`thread::spawn`]. If the process is not + /// aborted, this function will return a `Result::Err` containing an opaque + /// type. + /// + /// [`catch_unwind`]: ../../std/panic/fn.catch_unwind.html + /// [`thread::spawn`]: spawn #[stable(feature = "rust1", since = "1.0.0")] pub fn join(self) -> Result { self.0.join() From ae5d448a261baf28f0c22d076d316704e3305c38 Mon Sep 17 00:00:00 2001 From: Nicole LeGare Date: Mon, 16 Sep 2024 15:47:02 -0700 Subject: [PATCH 137/683] Add x86_64-unknown-trusty as tier 3 --- compiler/rustc_target/src/spec/mod.rs | 1 + .../src/spec/targets/x86_64_unknown_trusty.rs | 38 +++++++++++++++++++ src/doc/rustc/src/platform-support.md | 1 + tests/assembly/targets/targets-elf.rs | 3 ++ 4 files changed, 43 insertions(+) create mode 100644 compiler/rustc_target/src/spec/targets/x86_64_unknown_trusty.rs diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index f12e3e595ad..15d08e87f89 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -1792,6 +1792,7 @@ supported_targets! { ("armv7-unknown-trusty", armv7_unknown_trusty), ("aarch64-unknown-trusty", aarch64_unknown_trusty), + ("x86_64-unknown-trusty", x86_64_unknown_trusty), ("riscv32i-unknown-none-elf", riscv32i_unknown_none_elf), ("riscv32im-risc0-zkvm-elf", riscv32im_risc0_zkvm_elf), diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unknown_trusty.rs b/compiler/rustc_target/src/spec/targets/x86_64_unknown_trusty.rs new file mode 100644 index 00000000000..a6af06b03db --- /dev/null +++ b/compiler/rustc_target/src/spec/targets/x86_64_unknown_trusty.rs @@ -0,0 +1,38 @@ +// Trusty OS target for X86_64. + +use crate::spec::{ + LinkSelfContainedDefault, PanicStrategy, RelroLevel, StackProbeType, Target, TargetOptions, +}; + +pub(crate) fn target() -> Target { + Target { + llvm_target: "x86_64-unknown-unknown-musl".into(), + metadata: crate::spec::TargetMetadata { + description: Some("x86_64 Trusty".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(false), + }, + pointer_width: 64, + data_layout: + "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128".into(), + arch: "x86_64".into(), + options: TargetOptions { + executables: true, + max_atomic_width: Some(64), + panic_strategy: PanicStrategy::Abort, + os: "trusty".into(), + link_self_contained: LinkSelfContainedDefault::InferredForMusl, + position_independent_executables: true, + static_position_independent_executables: true, + crt_static_default: true, + crt_static_respected: true, + dynamic_linking: false, + plt_by_default: false, + relro_level: RelroLevel::Full, + stack_probes: StackProbeType::Inline, + mcount: "\u{1}_mcount".into(), + ..Default::default() + }, + } +} diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index 9a35b35af71..5fd79b747f6 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -386,6 +386,7 @@ target | std | host | notes [`x86_64-unknown-hermit`](platform-support/hermit.md) | ✓ | | x86_64 Hermit `x86_64-unknown-l4re-uclibc` | ? | | [`x86_64-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | 64-bit OpenBSD +[`x86_64-unknown-trusty`](platform-support/trusty.md) | ? | | `x86_64-uwp-windows-gnu` | ✓ | | `x86_64-uwp-windows-msvc` | ✓ | | [`x86_64-win7-windows-msvc`](platform-support/win7-windows-msvc.md) | ✓ | | 64-bit Windows 7 support diff --git a/tests/assembly/targets/targets-elf.rs b/tests/assembly/targets/targets-elf.rs index 4e1c5e6806e..6f6f62d3951 100644 --- a/tests/assembly/targets/targets-elf.rs +++ b/tests/assembly/targets/targets-elf.rs @@ -591,6 +591,9 @@ //@ revisions: x86_64_unknown_redox //@ [x86_64_unknown_redox] compile-flags: --target x86_64-unknown-redox //@ [x86_64_unknown_redox] needs-llvm-components: x86 +//@ revisions: x86_64_unknown_trusty +//@ [x86_64_unknown_trusty] compile-flags: --target x86_64-unknown-trusty +//@ [x86_64_unknown_trusty] needs-llvm-components: x86 //@ revisions: x86_64_wrs_vxworks //@ [x86_64_wrs_vxworks] compile-flags: --target x86_64-wrs-vxworks //@ [x86_64_wrs_vxworks] needs-llvm-components: x86 From d2c58ec6c4b23cbaa3b68ff3fb10853e6a59a45c Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Tue, 17 Sep 2024 07:53:19 +0300 Subject: [PATCH 138/683] delete sub directory "debug" to not delete the change-id file Signed-off-by: onur-ozkan --- src/bootstrap/bootstrap.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index 666df49012c..04909cd7921 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -625,9 +625,9 @@ class RustBuild(object): try: # FIXME: A cheap workaround for https://github.com/rust-lang/rust/issues/125578, # remove this once the issue is closed. - bootstrap_out = self.bootstrap_out() - if os.path.exists(bootstrap_out): - shutil.rmtree(bootstrap_out) + bootstrap_build_artifacts = os.path.join(self.bootstrap_out(), "debug") + if os.path.exists(bootstrap_build_artifacts): + shutil.rmtree(bootstrap_build_artifacts) p.map(unpack_component, tarballs_download_info) finally: From c3d58cd5fabf6f09aefed4a8971ca0b65ad47e23 Mon Sep 17 00:00:00 2001 From: Lukas Lueg Date: Tue, 17 Sep 2024 23:19:29 +0200 Subject: [PATCH 139/683] Fix `if_then_some_else_none` sugg missing closure intro Fixes #13407 --- clippy_lints/src/if_then_some_else_none.rs | 2 ++ tests/ui/if_then_some_else_none.fixed | 4 ++++ tests/ui/if_then_some_else_none.rs | 4 ++++ tests/ui/if_then_some_else_none.stderr | 8 +++++++- 4 files changed, 17 insertions(+), 1 deletion(-) diff --git a/clippy_lints/src/if_then_some_else_none.rs b/clippy_lints/src/if_then_some_else_none.rs index 0bca53c1536..55f9625709b 100644 --- a/clippy_lints/src/if_then_some_else_none.rs +++ b/clippy_lints/src/if_then_some_else_none.rs @@ -105,6 +105,8 @@ impl<'tcx> LateLintPass<'tcx> for IfThenSomeElseNone { snippet_with_context(cx, first_stmt.span.until(then_arg.span), ctxt, "..", &mut app); let closure = if method_name == "then" { "|| " } else { "" }; format!("{closure} {{ {block_snippet}; {arg_snip} }}") + } else if method_name == "then" { + (std::borrow::Cow::Borrowed("|| ") + arg_snip).into_owned() } else { arg_snip.into_owned() }; diff --git a/tests/ui/if_then_some_else_none.fixed b/tests/ui/if_then_some_else_none.fixed index ad13372a68b..1f47dddcbc4 100644 --- a/tests/ui/if_then_some_else_none.fixed +++ b/tests/ui/if_then_some_else_none.fixed @@ -113,6 +113,10 @@ fn issue11394(b: bool, v: Result<(), ()>) -> Result<(), ()> { Ok(()) } +fn issue13407(s: &str) -> Option { + (s == "1").then(|| true) +} + const fn issue12103(x: u32) -> Option { // Should not issue an error in `const` context if x > 42 { Some(150) } else { None } diff --git a/tests/ui/if_then_some_else_none.rs b/tests/ui/if_then_some_else_none.rs index 73edbb7da2a..499f008fb87 100644 --- a/tests/ui/if_then_some_else_none.rs +++ b/tests/ui/if_then_some_else_none.rs @@ -131,6 +131,10 @@ fn issue11394(b: bool, v: Result<(), ()>) -> Result<(), ()> { Ok(()) } +fn issue13407(s: &str) -> Option { + if s == "1" { Some(true) } else { None } +} + const fn issue12103(x: u32) -> Option { // Should not issue an error in `const` context if x > 42 { Some(150) } else { None } diff --git a/tests/ui/if_then_some_else_none.stderr b/tests/ui/if_then_some_else_none.stderr index aed01e026cb..e7bc66b3ee8 100644 --- a/tests/ui/if_then_some_else_none.stderr +++ b/tests/ui/if_then_some_else_none.stderr @@ -52,5 +52,11 @@ LL | | None LL | | }; | |_____^ help: try: `foo().then(|| { println!("true!"); 150 })` -error: aborting due to 5 previous errors +error: this could be simplified with `bool::then` + --> tests/ui/if_then_some_else_none.rs:135:5 + | +LL | if s == "1" { Some(true) } else { None } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(s == "1").then(|| true)` + +error: aborting due to 6 previous errors From 652b502d9c2e9495d2e7436a18a0b4bcaedacc0a Mon Sep 17 00:00:00 2001 From: Kyle Huey Date: Fri, 13 Sep 2024 12:41:07 -0700 Subject: [PATCH 140/683] Reorder stack spills so that constants come later. Currently constants are "pulled forward" and have their stack spills emitted first. This confuses LLVM as to where to place breakpoints at function entry, and results in argument values being wrong in the debugger. It's straightforward to avoid emitting the stack spills for constants until arguments/etc have been introduced in debug_introduce_locals, so do that. Example LLVM IR (irrelevant IR elided): Before: define internal void @_ZN11rust_1289457binding17h2c78f956ba4bd2c3E(i64 %a, i64 %b, double %c) unnamed_addr #0 !dbg !178 { start: %c.dbg.spill = alloca [8 x i8], align 8 %b.dbg.spill = alloca [8 x i8], align 8 %a.dbg.spill = alloca [8 x i8], align 8 %x.dbg.spill = alloca [4 x i8], align 4 store i32 0, ptr %x.dbg.spill, align 4, !dbg !192 ; LLVM places breakpoint here. #dbg_declare(ptr %x.dbg.spill, !190, !DIExpression(), !192) store i64 %a, ptr %a.dbg.spill, align 8 #dbg_declare(ptr %a.dbg.spill, !187, !DIExpression(), !193) store i64 %b, ptr %b.dbg.spill, align 8 #dbg_declare(ptr %b.dbg.spill, !188, !DIExpression(), !194) store double %c, ptr %c.dbg.spill, align 8 #dbg_declare(ptr %c.dbg.spill, !189, !DIExpression(), !195) ret void, !dbg !196 } After: define internal void @_ZN11rust_1289457binding17h2c78f956ba4bd2c3E(i64 %a, i64 %b, double %c) unnamed_addr #0 !dbg !178 { start: %x.dbg.spill = alloca [4 x i8], align 4 %c.dbg.spill = alloca [8 x i8], align 8 %b.dbg.spill = alloca [8 x i8], align 8 %a.dbg.spill = alloca [8 x i8], align 8 store i64 %a, ptr %a.dbg.spill, align 8 #dbg_declare(ptr %a.dbg.spill, !187, !DIExpression(), !192) store i64 %b, ptr %b.dbg.spill, align 8 #dbg_declare(ptr %b.dbg.spill, !188, !DIExpression(), !193) store double %c, ptr %c.dbg.spill, align 8 #dbg_declare(ptr %c.dbg.spill, !189, !DIExpression(), !194) store i32 0, ptr %x.dbg.spill, align 4, !dbg !195 ; LLVM places breakpoint here. #dbg_declare(ptr %x.dbg.spill, !190, !DIExpression(), !195) ret void, !dbg !196 } Note in particular the position of the "LLVM places breakpoint here" comment relative to the stack spills for the function arguments. LLVM assumes that the first instruction with with a debug location is the end of the prologue. As LLVM does not currently offer front ends any direct control over the placement of the prologue end reordering the IR is the only mechanism available to fix argument values at function entry in the presence of MIR optimizations like SingleUseConsts. Fixes #128945 --- .../rustc_codegen_ssa/src/mir/debuginfo.rs | 54 ++++++++++++++----- compiler/rustc_codegen_ssa/src/mir/mod.rs | 12 +++-- tests/debuginfo/constant-ordering-prologue.rs | 35 ++++++++++++ 3 files changed, 83 insertions(+), 18 deletions(-) create mode 100644 tests/debuginfo/constant-ordering-prologue.rs diff --git a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs index 5b36a11aa25..0cf19eff1b0 100644 --- a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs +++ b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs @@ -1,4 +1,5 @@ use std::collections::hash_map::Entry; +use std::marker::PhantomData; use std::ops::Range; use rustc_data_structures::fx::FxHashMap; @@ -14,7 +15,7 @@ use rustc_target::abi::{Abi, FieldIdx, FieldsShape, Size, VariantIdx}; use super::operand::{OperandRef, OperandValue}; use super::place::{PlaceRef, PlaceValue}; -use super::{FunctionCx, LocalRef}; +use super::{FunctionCx, LocalRef, PerLocalVarDebugInfoIndexVec}; use crate::traits::*; pub struct FunctionDebugContext<'tcx, S, L> { @@ -48,6 +49,17 @@ pub struct PerLocalVarDebugInfo<'tcx, D> { pub projection: &'tcx ty::List>, } +/// Information needed to emit a constant. +pub struct ConstDebugInfo<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> { + pub name: String, + pub source_info: mir::SourceInfo, + pub operand: OperandRef<'tcx, Bx::Value>, + pub dbg_var: Bx::DIVariable, + pub dbg_loc: Bx::DILocation, + pub fragment: Option>, + pub _phantom: PhantomData<&'a ()>, +} + #[derive(Clone, Copy, Debug)] pub struct DebugScope { pub dbg_scope: S, @@ -427,11 +439,25 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } } - pub(crate) fn debug_introduce_locals(&self, bx: &mut Bx) { + pub(crate) fn debug_introduce_locals( + &self, + bx: &mut Bx, + consts: Vec>, + ) { if bx.sess().opts.debuginfo == DebugInfo::Full || !bx.sess().fewer_names() { for local in self.locals.indices() { self.debug_introduce_local(bx, local); } + + for ConstDebugInfo { name, source_info, operand, dbg_var, dbg_loc, fragment, .. } in + consts.into_iter() + { + self.set_debug_loc(bx, source_info); + let base = FunctionCx::spill_operand_to_stack(operand, Some(name), bx); + bx.clear_dbg_loc(); + + bx.dbg_var_addr(dbg_var, dbg_loc, base.val.llval, Size::ZERO, &[], fragment); + } } } @@ -439,7 +465,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { pub(crate) fn compute_per_local_var_debug_info( &self, bx: &mut Bx, - ) -> Option>>> { + ) -> Option<( + PerLocalVarDebugInfoIndexVec<'tcx, Bx::DIVariable>, + Vec>, + )> { let full_debug_info = self.cx.sess().opts.debuginfo == DebugInfo::Full; let target_is_msvc = self.cx.sess().target.is_like_msvc; @@ -449,6 +478,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } let mut per_local = IndexVec::from_elem(vec![], &self.mir.local_decls); + let mut constants = vec![]; let mut params_seen: FxHashMap<_, Bx::DIVariable> = Default::default(); for var in &self.mir.var_debug_info { let dbg_scope_and_span = if full_debug_info { @@ -545,23 +575,19 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let Some(dbg_loc) = self.dbg_loc(var.source_info) else { continue }; let operand = self.eval_mir_constant_to_operand(bx, &c); - self.set_debug_loc(bx, var.source_info); - let base = - Self::spill_operand_to_stack(operand, Some(var.name.to_string()), bx); - bx.clear_dbg_loc(); - - bx.dbg_var_addr( + constants.push(ConstDebugInfo { + name: var.name.to_string(), + source_info: var.source_info, + operand, dbg_var, dbg_loc, - base.val.llval, - Size::ZERO, - &[], fragment, - ); + _phantom: PhantomData, + }); } } } } - Some(per_local) + Some((per_local, constants)) } } diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs index 61e9b9bd774..7e9cca4f366 100644 --- a/compiler/rustc_codegen_ssa/src/mir/mod.rs +++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs @@ -41,6 +41,9 @@ enum CachedLlbb { Skip, } +type PerLocalVarDebugInfoIndexVec<'tcx, V> = + IndexVec>>; + /// Master context for codegenning from MIR. pub struct FunctionCx<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> { instance: Instance<'tcx>, @@ -107,8 +110,7 @@ pub struct FunctionCx<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> { /// All `VarDebugInfo` from the MIR body, partitioned by `Local`. /// This is `None` if no variable debuginfo/names are needed. - per_local_var_debug_info: - Option>>>, + per_local_var_debug_info: Option>, /// Caller location propagated if this function has `#[track_caller]`. caller_location: Option>, @@ -216,7 +218,9 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( // monomorphization, and if there is an error during collection then codegen never starts -- so // we don't have to do it again. - fx.per_local_var_debug_info = fx.compute_per_local_var_debug_info(&mut start_bx); + let (per_local_var_debug_info, consts_debug_info) = + fx.compute_per_local_var_debug_info(&mut start_bx).unzip(); + fx.per_local_var_debug_info = per_local_var_debug_info; let memory_locals = analyze::non_ssa_locals(&fx); @@ -267,7 +271,7 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( fx.initialize_locals(local_values); // Apply debuginfo to the newly allocated locals. - fx.debug_introduce_locals(&mut start_bx); + fx.debug_introduce_locals(&mut start_bx, consts_debug_info.unwrap_or_default()); // If the backend supports coverage, and coverage is enabled for this function, // do any necessary start-of-function codegen (e.g. locals for MC/DC bitmaps). diff --git a/tests/debuginfo/constant-ordering-prologue.rs b/tests/debuginfo/constant-ordering-prologue.rs new file mode 100644 index 00000000000..f2d4fd37ce3 --- /dev/null +++ b/tests/debuginfo/constant-ordering-prologue.rs @@ -0,0 +1,35 @@ +//@ min-lldb-version: 310 + +//@ compile-flags:-g + +// === GDB TESTS =================================================================================== + +// gdb-command:break constant_ordering_prologue::binding +// gdb-command:run + +// gdb-command:print a +// gdb-check: = 19 +// gdb-command:print b +// gdb-check: = 20 +// gdb-command:print c +// gdb-check: = 21.5 + +// === LLDB TESTS ================================================================================== + +// lldb-command:b "constant_ordering_prologue::binding" +// lldb-command:run + +// lldb-command:print a +// lldb-check: = 19 +// lldb-command:print b +// lldb-check: = 20 +// lldb-command:print c +// lldb-check: = 21.5 + +fn binding(a: i64, b: u64, c: f64) { + let x = 0; +} + +fn main() { + binding(19, 20, 21.5); +} From c592eacc63220df01fb08228fc5bc78b75dc1dd1 Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Tue, 17 Sep 2024 20:42:21 +0300 Subject: [PATCH 141/683] skip in-tree compiler build for llvm-bitcode-linker if ci-rustc is on Signed-off-by: onur-ozkan --- src/bootstrap/src/core/build_steps/tool.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs index a437f829ba5..6c3bb694f92 100644 --- a/src/bootstrap/src/core/build_steps/tool.rs +++ b/src/bootstrap/src/core/build_steps/tool.rs @@ -872,8 +872,11 @@ impl Step for LlvmBitcodeLinker { fn run(self, builder: &Builder<'_>) -> PathBuf { let bin_name = "llvm-bitcode-linker"; - builder.ensure(compile::Std::new(self.compiler, self.compiler.host)); - builder.ensure(compile::Rustc::new(self.compiler, self.target)); + // If enabled, use ci-rustc and skip building the in-tree compiler. + if !builder.download_rustc() { + builder.ensure(compile::Std::new(self.compiler, self.compiler.host)); + builder.ensure(compile::Rustc::new(self.compiler, self.target)); + } let cargo = prepare_tool_cargo( builder, From ae5f8570967d71ab56068372f4d08859a3c13d9f Mon Sep 17 00:00:00 2001 From: VictorHugoPilled Date: Wed, 11 Sep 2024 20:37:08 +0000 Subject: [PATCH 142/683] fix: Specifying reason in expect(clippy::needless_return) no longer triggers false positive chore: Moved new tests into needless_return.rs chore: Ran cargo uibless Initial commit --- clippy_lints/src/returns.rs | 2 +- tests/ui/needless_return.fixed | 20 ++++++++++++++++++++ tests/ui/needless_return.rs | 20 ++++++++++++++++++++ 3 files changed, 41 insertions(+), 1 deletion(-) diff --git a/clippy_lints/src/returns.rs b/clippy_lints/src/returns.rs index 1e709649695..423b9b397f1 100644 --- a/clippy_lints/src/returns.rs +++ b/clippy_lints/src/returns.rs @@ -421,7 +421,7 @@ fn check_final_expr<'tcx>( if matches!(Level::from_attr(attr), Some(Level::Expect(_))) && let metas = attr.meta_item_list() && let Some(lst) = metas - && let [NestedMetaItem::MetaItem(meta_item)] = lst.as_slice() + && let [NestedMetaItem::MetaItem(meta_item), ..] = lst.as_slice() && let [tool, lint_name] = meta_item.path.segments.as_slice() && tool.ident.name == sym::clippy && matches!( diff --git a/tests/ui/needless_return.fixed b/tests/ui/needless_return.fixed index c5c570690b4..ca422e605d6 100644 --- a/tests/ui/needless_return.fixed +++ b/tests/ui/needless_return.fixed @@ -360,3 +360,23 @@ fn issue12907() -> String { } fn main() {} + +fn a(x: Option) -> Option { + match x { + Some(_) => None, + None => { + #[expect(clippy::needless_return, reason = "Use early return for errors.")] + return None; + }, + } +} + +fn b(x: Option) -> Option { + match x { + Some(_) => None, + None => { + #[expect(clippy::needless_return)] + return None; + }, + } +} diff --git a/tests/ui/needless_return.rs b/tests/ui/needless_return.rs index 738611391df..aad6e13136f 100644 --- a/tests/ui/needless_return.rs +++ b/tests/ui/needless_return.rs @@ -370,3 +370,23 @@ fn issue12907() -> String { } fn main() {} + +fn a(x: Option) -> Option { + match x { + Some(_) => None, + None => { + #[expect(clippy::needless_return, reason = "Use early return for errors.")] + return None; + }, + } +} + +fn b(x: Option) -> Option { + match x { + Some(_) => None, + None => { + #[expect(clippy::needless_return)] + return None; + }, + } +} From 431f7d6709908618b3c9291b7ef5317660bb9919 Mon Sep 17 00:00:00 2001 From: y21 <30553356+y21@users.noreply.github.com> Date: Tue, 17 Sep 2024 21:38:37 +0200 Subject: [PATCH 143/683] build quine-mc_cluskey with O3 in dev builds --- Cargo.toml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index cf810798d8c..ddc27179ef2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -67,3 +67,10 @@ harness = false [[test]] name = "dogfood" harness = false + +# quine-mc_cluskey makes up a significant part of the runtime in dogfood +# due to the number of conditions in the clippy_lints crate +# and enabling optimizations for that specific dependency helps a bit +# without increasing total build times. +[profile.dev.package.quine-mc_cluskey] +opt-level = 3 From 4788e8c34ac900f3595e7fe6070f0cf210851cf7 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Wed, 18 Sep 2024 14:48:30 +0000 Subject: [PATCH 144/683] Add the library workspace to the suggested rust-analyzer config --- src/bootstrap/src/core/build_steps/setup.rs | 1 + src/etc/rust_analyzer_settings.json | 1 + 2 files changed, 2 insertions(+) diff --git a/src/bootstrap/src/core/build_steps/setup.rs b/src/bootstrap/src/core/build_steps/setup.rs index f7b26712cab..eb7f29ee23d 100644 --- a/src/bootstrap/src/core/build_steps/setup.rs +++ b/src/bootstrap/src/core/build_steps/setup.rs @@ -46,6 +46,7 @@ static SETTINGS_HASHES: &[&str] = &[ "47d227f424bf889b0d899b9cc992d5695e1b78c406e183cd78eafefbe5488923", "b526bd58d0262dd4dda2bff5bc5515b705fb668a46235ace3e057f807963a11a", "828666b021d837a33e78d870b56d34c88a5e2c85de58b693607ec574f0c27000", + "811fb3b063c739d261fd8590dd30242e117908f5a095d594fa04585daa18ec4d", ]; static RUST_ANALYZER_SETTINGS: &str = include_str!("../../../../etc/rust_analyzer_settings.json"); diff --git a/src/etc/rust_analyzer_settings.json b/src/etc/rust_analyzer_settings.json index d329fe997cd..a20105f0ef3 100644 --- a/src/etc/rust_analyzer_settings.json +++ b/src/etc/rust_analyzer_settings.json @@ -10,6 +10,7 @@ ], "rust-analyzer.linkedProjects": [ "Cargo.toml", + "library/Cargo.toml", "src/tools/x/Cargo.toml", "src/bootstrap/Cargo.toml", "src/tools/rust-analyzer/Cargo.toml", From 978582be7421b3e5f447181c8b20f6d4ded13a52 Mon Sep 17 00:00:00 2001 From: GnomedDev Date: Wed, 18 Sep 2024 16:59:57 +0100 Subject: [PATCH 145/683] [Clippy] Swap `manual_retain` to use diagnostic items instead of paths --- clippy_lints/src/manual_retain.rs | 34 +++++++++++++++---------------- clippy_utils/src/paths.rs | 9 -------- 2 files changed, 17 insertions(+), 26 deletions(-) diff --git a/clippy_lints/src/manual_retain.rs b/clippy_lints/src/manual_retain.rs index d4e53f8f74b..a35b0f914e0 100644 --- a/clippy_lints/src/manual_retain.rs +++ b/clippy_lints/src/manual_retain.rs @@ -3,22 +3,22 @@ use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet; use clippy_utils::ty::{get_type_diagnostic_name, is_type_lang_item}; -use clippy_utils::{match_def_path, paths, SpanlessEq}; +use clippy_utils::SpanlessEq; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_hir::ExprKind::Assign; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::impl_lint_pass; -use rustc_span::symbol::sym; +use rustc_span::symbol::{sym, Symbol}; use rustc_span::Span; -const ACCEPTABLE_METHODS: [&[&str]; 5] = [ - &paths::BINARYHEAP_ITER, - &paths::HASHSET_ITER, - &paths::BTREESET_ITER, - &paths::SLICE_INTO, - &paths::VEC_DEQUE_ITER, +const ACCEPTABLE_METHODS: [Symbol; 5] = [ + sym::binaryheap_iter, + sym::hashset_iter, + sym::btreeset_iter, + sym::slice_iter, + sym::vecdeque_iter, ]; declare_clippy_lint! { @@ -84,7 +84,7 @@ fn check_into_iter( ) { if let hir::ExprKind::MethodCall(_, into_iter_expr, [_], _) = &target_expr.kind && let Some(filter_def_id) = cx.typeck_results().type_dependent_def_id(target_expr.hir_id) - && match_def_path(cx, filter_def_id, &paths::CORE_ITER_FILTER) + && cx.tcx.is_diagnostic_item(sym::iter_filter, filter_def_id) && let hir::ExprKind::MethodCall(_, struct_expr, [], _) = &into_iter_expr.kind && let Some(into_iter_def_id) = cx.typeck_results().type_dependent_def_id(into_iter_expr.hir_id) && Some(into_iter_def_id) == cx.tcx.lang_items().into_iter_fn() @@ -127,14 +127,14 @@ fn check_iter( ) { if let hir::ExprKind::MethodCall(_, filter_expr, [], _) = &target_expr.kind && let Some(copied_def_id) = cx.typeck_results().type_dependent_def_id(target_expr.hir_id) - && (match_def_path(cx, copied_def_id, &paths::CORE_ITER_COPIED) - || match_def_path(cx, copied_def_id, &paths::CORE_ITER_CLONED)) + && (cx.tcx.is_diagnostic_item(sym::iter_copied, copied_def_id) + || cx.tcx.is_diagnostic_item(sym::iter_cloned, copied_def_id)) && let hir::ExprKind::MethodCall(_, iter_expr, [_], _) = &filter_expr.kind && let Some(filter_def_id) = cx.typeck_results().type_dependent_def_id(filter_expr.hir_id) - && match_def_path(cx, filter_def_id, &paths::CORE_ITER_FILTER) + && cx.tcx.is_diagnostic_item(sym::iter_filter, filter_def_id) && let hir::ExprKind::MethodCall(_, struct_expr, [], _) = &iter_expr.kind && let Some(iter_expr_def_id) = cx.typeck_results().type_dependent_def_id(iter_expr.hir_id) - && match_acceptable_def_path(cx, iter_expr_def_id) + && match_acceptable_sym(cx, iter_expr_def_id) && match_acceptable_type(cx, left_expr, msrv) && SpanlessEq::new(cx).eq_expr(left_expr, struct_expr) && let hir::ExprKind::MethodCall(_, _, [closure_expr], _) = filter_expr.kind @@ -189,10 +189,10 @@ fn check_to_owned( && cx.tcx.is_diagnostic_item(sym::to_owned_method, to_owned_def_id) && let hir::ExprKind::MethodCall(_, chars_expr, [_], _) = &filter_expr.kind && let Some(filter_def_id) = cx.typeck_results().type_dependent_def_id(filter_expr.hir_id) - && match_def_path(cx, filter_def_id, &paths::CORE_ITER_FILTER) + && cx.tcx.is_diagnostic_item(sym::iter_filter, filter_def_id) && let hir::ExprKind::MethodCall(_, str_expr, [], _) = &chars_expr.kind && let Some(chars_expr_def_id) = cx.typeck_results().type_dependent_def_id(chars_expr.hir_id) - && match_def_path(cx, chars_expr_def_id, &paths::STR_CHARS) + && cx.tcx.is_diagnostic_item(sym::str_chars, chars_expr_def_id) && let ty = cx.typeck_results().expr_ty(str_expr).peel_refs() && is_type_lang_item(cx, ty, hir::LangItem::String) && SpanlessEq::new(cx).eq_expr(left_expr, str_expr) @@ -247,10 +247,10 @@ fn make_sugg( } } -fn match_acceptable_def_path(cx: &LateContext<'_>, collect_def_id: DefId) -> bool { +fn match_acceptable_sym(cx: &LateContext<'_>, collect_def_id: DefId) -> bool { ACCEPTABLE_METHODS .iter() - .any(|&method| match_def_path(cx, collect_def_id, method)) + .any(|&method| cx.tcx.is_diagnostic_item(method, collect_def_id)) } fn match_acceptable_type(cx: &LateContext<'_>, expr: &hir::Expr<'_>, msrv: &Msrv) -> bool { diff --git a/clippy_utils/src/paths.rs b/clippy_utils/src/paths.rs index 684c645c199..fd28ca12d50 100644 --- a/clippy_utils/src/paths.rs +++ b/clippy_utils/src/paths.rs @@ -12,13 +12,8 @@ pub const APPLICABILITY_VALUES: [[&str; 3]; 4] = [ ["rustc_lint_defs", "Applicability", "MachineApplicable"], ]; pub const DIAG: [&str; 2] = ["rustc_errors", "Diag"]; -pub const BINARYHEAP_ITER: [&str; 5] = ["alloc", "collections", "binary_heap", "BinaryHeap", "iter"]; pub const BTREEMAP_CONTAINS_KEY: [&str; 6] = ["alloc", "collections", "btree", "map", "BTreeMap", "contains_key"]; pub const BTREEMAP_INSERT: [&str; 6] = ["alloc", "collections", "btree", "map", "BTreeMap", "insert"]; -pub const BTREESET_ITER: [&str; 6] = ["alloc", "collections", "btree", "set", "BTreeSet", "iter"]; -pub const CORE_ITER_CLONED: [&str; 6] = ["core", "iter", "traits", "iterator", "Iterator", "cloned"]; -pub const CORE_ITER_COPIED: [&str; 6] = ["core", "iter", "traits", "iterator", "Iterator", "copied"]; -pub const CORE_ITER_FILTER: [&str; 6] = ["core", "iter", "traits", "iterator", "Iterator", "filter"]; pub const CORE_RESULT_OK_METHOD: [&str; 4] = ["core", "result", "Result", "ok"]; pub const CSTRING_AS_C_STR: [&str; 5] = ["alloc", "ffi", "c_str", "CString", "as_c_str"]; pub const EARLY_CONTEXT: [&str; 2] = ["rustc_lint", "EarlyContext"]; @@ -39,7 +34,6 @@ pub const HASHMAP_VALUES: [&str; 5] = ["std", "collections", "hash", "map", "Val pub const HASHMAP_DRAIN: [&str; 5] = ["std", "collections", "hash", "map", "Drain"]; pub const HASHMAP_VALUES_MUT: [&str; 5] = ["std", "collections", "hash", "map", "ValuesMut"]; pub const HASHSET_ITER_TY: [&str; 5] = ["std", "collections", "hash", "set", "Iter"]; -pub const HASHSET_ITER: [&str; 6] = ["std", "collections", "hash", "set", "HashSet", "iter"]; pub const HASHSET_DRAIN: [&str; 5] = ["std", "collections", "hash", "set", "Drain"]; pub const IDENT: [&str; 3] = ["rustc_span", "symbol", "Ident"]; pub const IDENT_AS_STR: [&str; 4] = ["rustc_span", "symbol", "Ident", "as_str"]; @@ -71,13 +65,11 @@ pub const REGEX_SET_NEW: [&str; 3] = ["regex", "RegexSet", "new"]; pub const SERDE_DESERIALIZE: [&str; 3] = ["serde", "de", "Deserialize"]; pub const SERDE_DE_VISITOR: [&str; 3] = ["serde", "de", "Visitor"]; pub const SLICE_INTO_VEC: [&str; 4] = ["alloc", "slice", "", "into_vec"]; -pub const SLICE_INTO: [&str; 4] = ["core", "slice", "", "iter"]; pub const STD_IO_SEEK_FROM_CURRENT: [&str; 4] = ["std", "io", "SeekFrom", "Current"]; pub const STD_IO_SEEKFROM_START: [&str; 4] = ["std", "io", "SeekFrom", "Start"]; pub const STRING_AS_MUT_STR: [&str; 4] = ["alloc", "string", "String", "as_mut_str"]; pub const STRING_AS_STR: [&str; 4] = ["alloc", "string", "String", "as_str"]; pub const STRING_NEW: [&str; 4] = ["alloc", "string", "String", "new"]; -pub const STR_CHARS: [&str; 4] = ["core", "str", "", "chars"]; pub const STR_ENDS_WITH: [&str; 4] = ["core", "str", "", "ends_with"]; pub const STR_LEN: [&str; 4] = ["core", "str", "", "len"]; pub const STR_STARTS_WITH: [&str; 4] = ["core", "str", "", "starts_with"]; @@ -100,7 +92,6 @@ pub const TOKIO_IO_OPEN_OPTIONS: [&str; 4] = ["tokio", "fs", "open_options", "Op pub const TOKIO_IO_OPEN_OPTIONS_NEW: [&str; 5] = ["tokio", "fs", "open_options", "OpenOptions", "new"]; pub const VEC_AS_MUT_SLICE: [&str; 4] = ["alloc", "vec", "Vec", "as_mut_slice"]; pub const VEC_AS_SLICE: [&str; 4] = ["alloc", "vec", "Vec", "as_slice"]; -pub const VEC_DEQUE_ITER: [&str; 5] = ["alloc", "collections", "vec_deque", "VecDeque", "iter"]; pub const VEC_FROM_ELEM: [&str; 3] = ["alloc", "vec", "from_elem"]; pub const VEC_NEW: [&str; 4] = ["alloc", "vec", "Vec", "new"]; pub const VEC_WITH_CAPACITY: [&str; 4] = ["alloc", "vec", "Vec", "with_capacity"]; From 106a9af4cead1956bd27c8643672c891bcb38904 Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Wed, 18 Sep 2024 19:29:05 +0200 Subject: [PATCH 146/683] End my vacation --- triagebot.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/triagebot.toml b/triagebot.toml index 99b3560a064..dcf00e4e384 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -20,7 +20,6 @@ new_pr = true [assign] contributing_url = "https://github.com/rust-lang/rust-clippy/blob/master/CONTRIBUTING.md" users_on_vacation = [ - "flip1995", "matthiaskrgr", "giraffate", ] From d2305ff634ddad950ef3a54103bc59e0309e9a17 Mon Sep 17 00:00:00 2001 From: Alex Macleod Date: Wed, 18 Sep 2024 17:17:16 +0000 Subject: [PATCH 147/683] Generate versions HTML directly --- .github/deploy.sh | 9 +-- util/gh-pages/versions.html | 121 +++++++++++++++++++----------------- util/versions.py | 41 ++++++------ 3 files changed, 87 insertions(+), 84 deletions(-) diff --git a/.github/deploy.sh b/.github/deploy.sh index d937661c0f8..5b4b4be4e36 100644 --- a/.github/deploy.sh +++ b/.github/deploy.sh @@ -25,16 +25,15 @@ if [[ $BETA = "true" ]]; then fi # Generate version index that is shown as root index page -cp util/gh-pages/versions.html out/index.html - -echo "Making the versions.json file" -python3 ./util/versions.py out +python3 ./util/versions.py ./util/gh-pages/versions.html out # Now let's go have some fun with the cloned repo cd out git config user.name "GHA CI" git config user.email "gha@ci.invalid" +git status + if [[ -n $TAG_NAME ]]; then # track files, so that the following check works git add --intent-to-add "$TAG_NAME" @@ -46,8 +45,6 @@ if [[ -n $TAG_NAME ]]; then git add "$TAG_NAME" # Update the symlink git add stable - # Update versions file - git add versions.json git commit -m "Add documentation for ${TAG_NAME} release: ${SHA}" elif [[ $BETA = "true" ]]; then if git diff --exit-code --quiet -- beta/; then diff --git a/util/gh-pages/versions.html b/util/gh-pages/versions.html index 31ce8819329..d38fe39a464 100644 --- a/util/gh-pages/versions.html +++ b/util/gh-pages/versions.html @@ -1,4 +1,5 @@ + @@ -7,26 +8,15 @@ Clippy lints documentation - -
+
-
- - - -
- - - - - - - + .github-corner:hover .octo-arm { + animation: octocat-wave 560ms ease-in-out; + } + @keyframes octocat-wave { + 0%, + 100% { + transform: rotate(0); + } + 20%, + 60% { + transform: rotate(-25deg); + } + 40%, + 80% { + transform: rotate(10deg); + } + } + @media (max-width: 500px) { + .github-corner:hover .octo-arm { + animation: none; + } + .github-corner .octo-arm { + animation: octocat-wave 560ms ease-in-out; + } + } + + diff --git a/util/versions.py b/util/versions.py index c041fc606a8..7a21a840a6d 100755 --- a/util/versions.py +++ b/util/versions.py @@ -1,22 +1,22 @@ #!/usr/bin/env python +from string import Template +import argparse import json -import logging as log import os import sys -log.basicConfig(level=log.INFO, format="%(levelname)s: %(message)s") - - def key(v): if v == "master": - return float("inf") - if v == "stable": return sys.maxsize - if v == "beta": + if v == "stable": return sys.maxsize - 1 + if v == "beta": + return sys.maxsize - 2 if v == "pre-1.29.0": return -1 + if not v.startswith("rust-"): + return None v = v.replace("rust-", "") @@ -26,26 +26,27 @@ def key(v): return s - def main(): - if len(sys.argv) < 2: - log.error("specify output directory") - return + parser = argparse.ArgumentParser() + parser.add_argument("input", help="path to the versions.html template", type=argparse.FileType("r")) + parser.add_argument("outdir", help="path to write the output HTML") + args = parser.parse_args() - outdir = sys.argv[1] versions = [ dir - for dir in os.listdir(outdir) - if not dir.startswith(".") - and not dir.startswith("v") - and os.path.isdir(os.path.join(outdir, dir)) + for dir in os.listdir(args.outdir) + if key(dir) is not None ] - versions.sort(key=key) + versions.sort(key=key, reverse=True) + links = [f'{version}' for version in versions] - with open(os.path.join(outdir, "versions.json"), "w") as fp: - json.dump(versions, fp, indent=2) - log.info("wrote JSON for great justice") + template = Template(args.input.read()) + html = template.substitute(list="\n".join(links)) + path = os.path.join(args.outdir, "index.html") + with open(path, "w") as out: + out.write(html) + print(f"wrote HTML to {path}") if __name__ == "__main__": main() From 5d9b908571ed61679f2a12eaae7e032cdabbb8be Mon Sep 17 00:00:00 2001 From: Veera Date: Wed, 18 Sep 2024 21:29:31 -0400 Subject: [PATCH 148/683] Add Tests --- ...-to-int-transmute-in-consts-issue-87525.rs | 70 +++++++++++++++++++ ...int-transmute-in-consts-issue-87525.stderr | 12 ++++ 2 files changed, 82 insertions(+) create mode 100644 tests/ui/consts/const-eval/ptr-to-int-transmute-in-consts-issue-87525.rs create mode 100644 tests/ui/consts/const-eval/ptr-to-int-transmute-in-consts-issue-87525.stderr diff --git a/tests/ui/consts/const-eval/ptr-to-int-transmute-in-consts-issue-87525.rs b/tests/ui/consts/const-eval/ptr-to-int-transmute-in-consts-issue-87525.rs new file mode 100644 index 00000000000..f8e97904e9e --- /dev/null +++ b/tests/ui/consts/const-eval/ptr-to-int-transmute-in-consts-issue-87525.rs @@ -0,0 +1,70 @@ +const fn foo(ptr: *const u8) -> usize { + unsafe { + std::mem::transmute(ptr) + //~^ ERROR pointers cannot be transmuted to integers + } +} + +trait Human { + const ID: u64 = { + let value = 10; + let ptr: *const i32 = &value; + unsafe { + std::mem::transmute(ptr) + //~^ ERROR pointers cannot be transmuted to integers + } + }; + + fn id_plus_one() -> u64 { + Self::ID + 1 + } +} + +struct Type(T); + +impl Type { + const ID: u64 = { + let value = 10; + let ptr: *const i32 = &value; + unsafe { + std::mem::transmute(ptr) + //~^ ERROR pointers cannot be transmuted to integers + } + }; + + fn id_plus_one() -> u64 { + Self::ID + 1 + } +} + +fn control(ptr: *const u8) -> usize { + unsafe { + std::mem::transmute(ptr) + } +} + +struct ControlStruct; + +impl ControlStruct { + fn new() -> usize { + let value = 10; + let ptr: *const i32 = &value; + unsafe { + std::mem::transmute(ptr) + } + } +} + + +const fn zoom(ptr: *const u8) -> usize { + unsafe { + std::mem::transmute(ptr) + //~^ ERROR pointers cannot be transmuted to integers + } +} + +fn main() { + const a: u8 = 10; + const value: usize = zoom(&a); + //~^ ERROR evaluation of constant value failed +} diff --git a/tests/ui/consts/const-eval/ptr-to-int-transmute-in-consts-issue-87525.stderr b/tests/ui/consts/const-eval/ptr-to-int-transmute-in-consts-issue-87525.stderr new file mode 100644 index 00000000000..a57bc8e1e70 --- /dev/null +++ b/tests/ui/consts/const-eval/ptr-to-int-transmute-in-consts-issue-87525.stderr @@ -0,0 +1,12 @@ +error[E0080]: evaluation of constant value failed + --> $DIR/ptr-to-int-transmute-in-consts-issue-87525.rs:68:26 + | +LL | const value: usize = zoom(&a); + | ^^^^^^^^ unable to turn pointer into integer + | + = help: this code performed an operation that depends on the underlying bytes representing a pointer + = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0080`. From 5a13a93d41b34b869e3813c1dff4d8b81ed4b777 Mon Sep 17 00:00:00 2001 From: GnomedDev Date: Wed, 18 Sep 2024 17:58:18 +0100 Subject: [PATCH 149/683] [Clippy] Swap `map_entry` to use diagnostic items instead of paths --- clippy_lints/src/entry.rs | 12 ++++++------ clippy_utils/src/paths.rs | 4 ---- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/clippy_lints/src/entry.rs b/clippy_lints/src/entry.rs index b7c9d3d0385..9c5100a8c1a 100644 --- a/clippy_lints/src/entry.rs +++ b/clippy_lints/src/entry.rs @@ -1,8 +1,8 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::{reindent_multiline, snippet_indent, snippet_with_applicability, snippet_with_context}; use clippy_utils::{ - can_move_expr_to_closure_no_visit, higher, is_expr_final_block_expr, is_expr_used_or_unified, match_def_path, - paths, peel_hir_expr_while, SpanlessEq, + can_move_expr_to_closure_no_visit, higher, is_expr_final_block_expr, is_expr_used_or_unified, + peel_hir_expr_while, SpanlessEq, }; use core::fmt::{self, Write}; use rustc_errors::Applicability; @@ -11,7 +11,7 @@ use rustc_hir::intravisit::{walk_expr, Visitor}; use rustc_hir::{Block, Expr, ExprKind, HirId, Pat, Stmt, StmtKind, UnOp}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; -use rustc_span::{Span, SyntaxContext, DUMMY_SP}; +use rustc_span::{sym, Span, SyntaxContext, DUMMY_SP}; declare_clippy_lint! { /// ### What it does @@ -269,9 +269,9 @@ fn try_parse_contains<'tcx>(cx: &LateContext<'_>, expr: &'tcx Expr<'_>) -> Optio key, call_ctxt: expr.span.ctxt(), }; - if match_def_path(cx, id, &paths::BTREEMAP_CONTAINS_KEY) { + if cx.tcx.is_diagnostic_item(sym::btreemap_contains_key, id) { Some((MapType::BTree, expr)) - } else if match_def_path(cx, id, &paths::HASHMAP_CONTAINS_KEY) { + } else if cx.tcx.is_diagnostic_item(sym::hashmap_contains_key, id) { Some((MapType::Hash, expr)) } else { None @@ -306,7 +306,7 @@ struct InsertExpr<'tcx> { fn try_parse_insert<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option> { if let ExprKind::MethodCall(_, map, [key, value], _) = expr.kind { let id = cx.typeck_results().type_dependent_def_id(expr.hir_id)?; - if match_def_path(cx, id, &paths::BTREEMAP_INSERT) || match_def_path(cx, id, &paths::HASHMAP_INSERT) { + if cx.tcx.is_diagnostic_item(sym::btreemap_insert, id) || cx.tcx.is_diagnostic_item(sym::hashmap_insert, id) { Some(InsertExpr { map, key, value }) } else { None diff --git a/clippy_utils/src/paths.rs b/clippy_utils/src/paths.rs index fd28ca12d50..59105383093 100644 --- a/clippy_utils/src/paths.rs +++ b/clippy_utils/src/paths.rs @@ -12,8 +12,6 @@ pub const APPLICABILITY_VALUES: [[&str; 3]; 4] = [ ["rustc_lint_defs", "Applicability", "MachineApplicable"], ]; pub const DIAG: [&str; 2] = ["rustc_errors", "Diag"]; -pub const BTREEMAP_CONTAINS_KEY: [&str; 6] = ["alloc", "collections", "btree", "map", "BTreeMap", "contains_key"]; -pub const BTREEMAP_INSERT: [&str; 6] = ["alloc", "collections", "btree", "map", "BTreeMap", "insert"]; pub const CORE_RESULT_OK_METHOD: [&str; 4] = ["core", "result", "Result", "ok"]; pub const CSTRING_AS_C_STR: [&str; 5] = ["alloc", "ffi", "c_str", "CString", "as_c_str"]; pub const EARLY_CONTEXT: [&str; 2] = ["rustc_lint", "EarlyContext"]; @@ -25,8 +23,6 @@ pub const FILE_OPTIONS: [&str; 4] = ["std", "fs", "File", "options"]; pub const FUTURES_IO_ASYNCREADEXT: [&str; 3] = ["futures_util", "io", "AsyncReadExt"]; #[expect(clippy::invalid_paths)] // internal lints do not know about all external crates pub const FUTURES_IO_ASYNCWRITEEXT: [&str; 3] = ["futures_util", "io", "AsyncWriteExt"]; -pub const HASHMAP_CONTAINS_KEY: [&str; 6] = ["std", "collections", "hash", "map", "HashMap", "contains_key"]; -pub const HASHMAP_INSERT: [&str; 6] = ["std", "collections", "hash", "map", "HashMap", "insert"]; pub const HASHMAP_ITER: [&str; 5] = ["std", "collections", "hash", "map", "Iter"]; pub const HASHMAP_ITER_MUT: [&str; 5] = ["std", "collections", "hash", "map", "IterMut"]; pub const HASHMAP_KEYS: [&str; 5] = ["std", "collections", "hash", "map", "Keys"]; From 71dbfd55a110cbd1673346db768fb6a06016abdd Mon Sep 17 00:00:00 2001 From: GnomedDev Date: Wed, 18 Sep 2024 19:36:12 +0100 Subject: [PATCH 150/683] [Clippy] Swap `lines_filter_map_ok` to use a diagnostic item instead of path --- clippy_lints/src/lines_filter_map_ok.rs | 4 ++-- clippy_utils/src/paths.rs | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/clippy_lints/src/lines_filter_map_ok.rs b/clippy_lints/src/lines_filter_map_ok.rs index 3d1c666dfea..8206c75927b 100644 --- a/clippy_lints/src/lines_filter_map_ok.rs +++ b/clippy_lints/src/lines_filter_map_ok.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::ty::is_type_diagnostic_item; -use clippy_utils::{is_diag_item_method, is_trait_method, match_def_path, path_to_local_id, paths}; +use clippy_utils::{is_diag_item_method, is_trait_method, path_to_local_id}; use rustc_errors::Applicability; use rustc_hir::{Body, Closure, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; @@ -96,7 +96,7 @@ fn should_lint(cx: &LateContext<'_>, args: &[Expr<'_>], method_str: &str) -> boo ExprKind::Path(qpath) => cx .qpath_res(qpath, fm_arg.hir_id) .opt_def_id() - .is_some_and(|did| match_def_path(cx, did, &paths::CORE_RESULT_OK_METHOD)), + .is_some_and(|did| cx.tcx.is_diagnostic_item(sym::result_ok_method, did)), // Detect `|x| x.ok()` ExprKind::Closure(Closure { body, .. }) => { if let Body { diff --git a/clippy_utils/src/paths.rs b/clippy_utils/src/paths.rs index 59105383093..0d1d4382875 100644 --- a/clippy_utils/src/paths.rs +++ b/clippy_utils/src/paths.rs @@ -12,7 +12,6 @@ pub const APPLICABILITY_VALUES: [[&str; 3]; 4] = [ ["rustc_lint_defs", "Applicability", "MachineApplicable"], ]; pub const DIAG: [&str; 2] = ["rustc_errors", "Diag"]; -pub const CORE_RESULT_OK_METHOD: [&str; 4] = ["core", "result", "Result", "ok"]; pub const CSTRING_AS_C_STR: [&str; 5] = ["alloc", "ffi", "c_str", "CString", "as_c_str"]; pub const EARLY_CONTEXT: [&str; 2] = ["rustc_lint", "EarlyContext"]; pub const EARLY_LINT_PASS: [&str; 3] = ["rustc_lint", "passes", "EarlyLintPass"]; From 7ffd485be0fb0dc0a96ec0f1a56d108cc70e5584 Mon Sep 17 00:00:00 2001 From: GnomedDev Date: Wed, 18 Sep 2024 21:09:06 +0100 Subject: [PATCH 151/683] [Clippy] Swap `option_as_ref_deref` to use diagnostic items instead of paths --- .../src/methods/option_as_ref_deref.rs | 24 +++++++++---------- clippy_utils/src/paths.rs | 7 ------ 2 files changed, 12 insertions(+), 19 deletions(-) diff --git a/clippy_lints/src/methods/option_as_ref_deref.rs b/clippy_lints/src/methods/option_as_ref_deref.rs index cb57689b0c4..9a18d8a1421 100644 --- a/clippy_lints/src/methods/option_as_ref_deref.rs +++ b/clippy_lints/src/methods/option_as_ref_deref.rs @@ -2,12 +2,12 @@ use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet; use clippy_utils::ty::is_type_diagnostic_item; -use clippy_utils::{match_def_path, path_to_local_id, paths, peel_blocks}; +use clippy_utils::{path_to_local_id, peel_blocks}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; use rustc_middle::ty; -use rustc_span::sym; +use rustc_span::{sym, Symbol}; use super::OPTION_AS_REF_DEREF; @@ -31,14 +31,14 @@ pub(super) fn check( return; } - let deref_aliases: [&[&str]; 7] = [ - &paths::CSTRING_AS_C_STR, - &paths::OS_STRING_AS_OS_STR, - &paths::PATH_BUF_AS_PATH, - &paths::STRING_AS_STR, - &paths::STRING_AS_MUT_STR, - &paths::VEC_AS_SLICE, - &paths::VEC_AS_MUT_SLICE, + let deref_aliases: [Symbol; 7] = [ + sym::cstring_as_c_str, + sym::os_string_as_os_str, + sym::pathbuf_as_path, + sym::string_as_str, + sym::string_as_mut_str, + sym::vec_as_slice, + sym::vec_as_mut_slice, ]; let is_deref = match map_arg.kind { @@ -48,7 +48,7 @@ pub(super) fn check( .map_or(false, |fun_def_id| { cx.tcx.is_diagnostic_item(sym::deref_method, fun_def_id) || cx.tcx.is_diagnostic_item(sym::deref_mut_method, fun_def_id) - || deref_aliases.iter().any(|path| match_def_path(cx, fun_def_id, path)) + || deref_aliases.iter().any(|&sym| cx.tcx.is_diagnostic_item(sym, fun_def_id)) }) }, hir::ExprKind::Closure(&hir::Closure { body, .. }) => { @@ -69,7 +69,7 @@ pub(super) fn check( let method_did = cx.typeck_results().type_dependent_def_id(closure_expr.hir_id).unwrap(); cx.tcx.is_diagnostic_item(sym::deref_method, method_did) || cx.tcx.is_diagnostic_item(sym::deref_mut_method, method_did) - || deref_aliases.iter().any(|path| match_def_path(cx, method_did, path)) + || deref_aliases.iter().any(|&sym| cx.tcx.is_diagnostic_item(sym, method_did)) } else { false } diff --git a/clippy_utils/src/paths.rs b/clippy_utils/src/paths.rs index 0d1d4382875..e0fa814d30b 100644 --- a/clippy_utils/src/paths.rs +++ b/clippy_utils/src/paths.rs @@ -12,7 +12,6 @@ pub const APPLICABILITY_VALUES: [[&str; 3]; 4] = [ ["rustc_lint_defs", "Applicability", "MachineApplicable"], ]; pub const DIAG: [&str; 2] = ["rustc_errors", "Diag"]; -pub const CSTRING_AS_C_STR: [&str; 5] = ["alloc", "ffi", "c_str", "CString", "as_c_str"]; pub const EARLY_CONTEXT: [&str; 2] = ["rustc_lint", "EarlyContext"]; pub const EARLY_LINT_PASS: [&str; 3] = ["rustc_lint", "passes", "EarlyLintPass"]; pub const F32_EPSILON: [&str; 4] = ["core", "f32", "", "EPSILON"]; @@ -40,12 +39,10 @@ pub const LATE_LINT_PASS: [&str; 3] = ["rustc_lint", "passes", "LateLintPass"]; pub const LINT: [&str; 2] = ["rustc_lint_defs", "Lint"]; pub const MSRV: [&str; 3] = ["clippy_config", "msrvs", "Msrv"]; pub const OPEN_OPTIONS_NEW: [&str; 4] = ["std", "fs", "OpenOptions", "new"]; -pub const OS_STRING_AS_OS_STR: [&str; 5] = ["std", "ffi", "os_str", "OsString", "as_os_str"]; pub const OS_STR_TO_OS_STRING: [&str; 5] = ["std", "ffi", "os_str", "OsStr", "to_os_string"]; pub const PARKING_LOT_MUTEX_GUARD: [&str; 3] = ["lock_api", "mutex", "MutexGuard"]; pub const PARKING_LOT_RWLOCK_READ_GUARD: [&str; 3] = ["lock_api", "rwlock", "RwLockReadGuard"]; pub const PARKING_LOT_RWLOCK_WRITE_GUARD: [&str; 3] = ["lock_api", "rwlock", "RwLockWriteGuard"]; -pub const PATH_BUF_AS_PATH: [&str; 4] = ["std", "path", "PathBuf", "as_path"]; pub const PATH_MAIN_SEPARATOR: [&str; 3] = ["std", "path", "MAIN_SEPARATOR"]; pub const PATH_TO_PATH_BUF: [&str; 4] = ["std", "path", "Path", "to_path_buf"]; #[cfg_attr(not(unix), allow(clippy::invalid_paths))] @@ -62,8 +59,6 @@ pub const SERDE_DE_VISITOR: [&str; 3] = ["serde", "de", "Visitor"]; pub const SLICE_INTO_VEC: [&str; 4] = ["alloc", "slice", "", "into_vec"]; pub const STD_IO_SEEK_FROM_CURRENT: [&str; 4] = ["std", "io", "SeekFrom", "Current"]; pub const STD_IO_SEEKFROM_START: [&str; 4] = ["std", "io", "SeekFrom", "Start"]; -pub const STRING_AS_MUT_STR: [&str; 4] = ["alloc", "string", "String", "as_mut_str"]; -pub const STRING_AS_STR: [&str; 4] = ["alloc", "string", "String", "as_str"]; pub const STRING_NEW: [&str; 4] = ["alloc", "string", "String", "new"]; pub const STR_ENDS_WITH: [&str; 4] = ["core", "str", "", "ends_with"]; pub const STR_LEN: [&str; 4] = ["core", "str", "", "len"]; @@ -85,8 +80,6 @@ pub const TOKIO_IO_ASYNCWRITEEXT: [&str; 5] = ["tokio", "io", "util", "async_wri pub const TOKIO_IO_OPEN_OPTIONS: [&str; 4] = ["tokio", "fs", "open_options", "OpenOptions"]; #[expect(clippy::invalid_paths)] // internal lints do not know about all external crates pub const TOKIO_IO_OPEN_OPTIONS_NEW: [&str; 5] = ["tokio", "fs", "open_options", "OpenOptions", "new"]; -pub const VEC_AS_MUT_SLICE: [&str; 4] = ["alloc", "vec", "Vec", "as_mut_slice"]; -pub const VEC_AS_SLICE: [&str; 4] = ["alloc", "vec", "Vec", "as_slice"]; pub const VEC_FROM_ELEM: [&str; 3] = ["alloc", "vec", "from_elem"]; pub const VEC_NEW: [&str; 4] = ["alloc", "vec", "Vec", "new"]; pub const VEC_WITH_CAPACITY: [&str; 4] = ["alloc", "vec", "Vec", "with_capacity"]; From 8fc9e67cf516fe3fe48ea6ddb85d95c76062f98c Mon Sep 17 00:00:00 2001 From: GnomedDev Date: Wed, 18 Sep 2024 21:15:03 +0100 Subject: [PATCH 152/683] [Clippy] Swap `float_equality_without_abs` to use diagnostic items instead of paths --- clippy_lints/src/operators/float_equality_without_abs.rs | 6 +++--- clippy_utils/src/paths.rs | 2 -- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/clippy_lints/src/operators/float_equality_without_abs.rs b/clippy_lints/src/operators/float_equality_without_abs.rs index cace85a2451..be97ad389bf 100644 --- a/clippy_lints/src/operators/float_equality_without_abs.rs +++ b/clippy_lints/src/operators/float_equality_without_abs.rs @@ -1,12 +1,12 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::{match_def_path, paths, sugg}; +use clippy_utils::sugg; use rustc_ast::util::parser::AssocOp; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::LateContext; use rustc_middle::ty; -use rustc_span::source_map::Spanned; +use rustc_span::{sym, source_map::Spanned}; use super::FLOAT_EQUALITY_WITHOUT_ABS; @@ -36,7 +36,7 @@ pub(crate) fn check<'tcx>( // right hand side matches either f32::EPSILON or f64::EPSILON && let ExprKind::Path(ref epsilon_path) = rhs.kind && let Res::Def(DefKind::AssocConst, def_id) = cx.qpath_res(epsilon_path, rhs.hir_id) - && (match_def_path(cx, def_id, &paths::F32_EPSILON) || match_def_path(cx, def_id, &paths::F64_EPSILON)) + && ([sym::f32_epsilon, sym::f64_epsilon].into_iter().any(|sym| cx.tcx.is_diagnostic_item(sym, def_id))) // values of the subtractions on the left hand side are of the type float && let t_val_l = cx.typeck_results().expr_ty(val_l) diff --git a/clippy_utils/src/paths.rs b/clippy_utils/src/paths.rs index e0fa814d30b..ea7c19dec6d 100644 --- a/clippy_utils/src/paths.rs +++ b/clippy_utils/src/paths.rs @@ -14,8 +14,6 @@ pub const APPLICABILITY_VALUES: [[&str; 3]; 4] = [ pub const DIAG: [&str; 2] = ["rustc_errors", "Diag"]; pub const EARLY_CONTEXT: [&str; 2] = ["rustc_lint", "EarlyContext"]; pub const EARLY_LINT_PASS: [&str; 3] = ["rustc_lint", "passes", "EarlyLintPass"]; -pub const F32_EPSILON: [&str; 4] = ["core", "f32", "", "EPSILON"]; -pub const F64_EPSILON: [&str; 4] = ["core", "f64", "", "EPSILON"]; pub const FILE_OPTIONS: [&str; 4] = ["std", "fs", "File", "options"]; #[expect(clippy::invalid_paths)] // internal lints do not know about all external crates pub const FUTURES_IO_ASYNCREADEXT: [&str; 3] = ["futures_util", "io", "AsyncReadExt"]; From 1922a99bc677da7c758ee20dfb02929fe7008095 Mon Sep 17 00:00:00 2001 From: GnomedDev Date: Wed, 18 Sep 2024 21:21:17 +0100 Subject: [PATCH 153/683] [Clippy] Swap `redundant_clone` to use diagnostic items instead of paths --- clippy_lints/src/redundant_clone.rs | 6 +++--- clippy_utils/src/paths.rs | 2 -- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/clippy_lints/src/redundant_clone.rs b/clippy_lints/src/redundant_clone.rs index bfdc1cbeed7..4e24ddad83a 100644 --- a/clippy_lints/src/redundant_clone.rs +++ b/clippy_lints/src/redundant_clone.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::{span_lint_hir, span_lint_hir_and_then}; use clippy_utils::mir::{visit_local_usage, LocalUsage, PossibleBorrowerMap}; use clippy_utils::source::SpanRangeExt; use clippy_utils::ty::{has_drop, is_copy, is_type_diagnostic_item, is_type_lang_item, walk_ptrs_ty_depth}; -use clippy_utils::{fn_has_unsatisfiable_preds, match_def_path, paths}; +use clippy_utils::fn_has_unsatisfiable_preds; use rustc_errors::Applicability; use rustc_hir::intravisit::FnKind; use rustc_hir::{def_id, Body, FnDecl, LangItem}; @@ -102,8 +102,8 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClone { && is_type_lang_item(cx, arg_ty, LangItem::String)); let from_deref = !from_borrow - && (match_def_path(cx, fn_def_id, &paths::PATH_TO_PATH_BUF) - || match_def_path(cx, fn_def_id, &paths::OS_STR_TO_OS_STRING)); + && (cx.tcx.is_diagnostic_item(sym::path_to_pathbuf, fn_def_id) + || cx.tcx.is_diagnostic_item(sym::os_str_to_os_string, fn_def_id)); if !from_borrow && !from_deref { continue; diff --git a/clippy_utils/src/paths.rs b/clippy_utils/src/paths.rs index ea7c19dec6d..0a36d9a6664 100644 --- a/clippy_utils/src/paths.rs +++ b/clippy_utils/src/paths.rs @@ -37,12 +37,10 @@ pub const LATE_LINT_PASS: [&str; 3] = ["rustc_lint", "passes", "LateLintPass"]; pub const LINT: [&str; 2] = ["rustc_lint_defs", "Lint"]; pub const MSRV: [&str; 3] = ["clippy_config", "msrvs", "Msrv"]; pub const OPEN_OPTIONS_NEW: [&str; 4] = ["std", "fs", "OpenOptions", "new"]; -pub const OS_STR_TO_OS_STRING: [&str; 5] = ["std", "ffi", "os_str", "OsStr", "to_os_string"]; pub const PARKING_LOT_MUTEX_GUARD: [&str; 3] = ["lock_api", "mutex", "MutexGuard"]; pub const PARKING_LOT_RWLOCK_READ_GUARD: [&str; 3] = ["lock_api", "rwlock", "RwLockReadGuard"]; pub const PARKING_LOT_RWLOCK_WRITE_GUARD: [&str; 3] = ["lock_api", "rwlock", "RwLockWriteGuard"]; pub const PATH_MAIN_SEPARATOR: [&str; 3] = ["std", "path", "MAIN_SEPARATOR"]; -pub const PATH_TO_PATH_BUF: [&str; 4] = ["std", "path", "Path", "to_path_buf"]; #[cfg_attr(not(unix), allow(clippy::invalid_paths))] pub const PERMISSIONS_FROM_MODE: [&str; 6] = ["std", "os", "unix", "fs", "PermissionsExt", "from_mode"]; pub const PUSH_STR: [&str; 4] = ["alloc", "string", "String", "push_str"]; From 959f7a2bbb481a5f8c7fb410f4017debea27e798 Mon Sep 17 00:00:00 2001 From: GnomedDev Date: Wed, 18 Sep 2024 21:24:42 +0100 Subject: [PATCH 154/683] [Clippy] Swap `manual_main_separator_str` to use diagnostic item instead of path --- clippy_lints/src/manual_main_separator_str.rs | 4 ++-- clippy_utils/src/paths.rs | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/clippy_lints/src/manual_main_separator_str.rs b/clippy_lints/src/manual_main_separator_str.rs index db491a8c8f6..5198d7838a2 100644 --- a/clippy_lints/src/manual_main_separator_str.rs +++ b/clippy_lints/src/manual_main_separator_str.rs @@ -1,7 +1,7 @@ use clippy_config::msrvs::{self, Msrv}; use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::{is_trait_method, match_def_path, paths, peel_hir_expr_refs}; +use clippy_utils::{is_trait_method, peel_hir_expr_refs}; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; use rustc_hir::{Expr, ExprKind, Mutability, QPath}; @@ -56,7 +56,7 @@ impl LateLintPass<'_> for ManualMainSeparatorStr { && let Res::Def(DefKind::Const, receiver_def_id) = path.res && is_trait_method(cx, target, sym::ToString) && self.msrv.meets(msrvs::PATH_MAIN_SEPARATOR_STR) - && match_def_path(cx, receiver_def_id, &paths::PATH_MAIN_SEPARATOR) + && cx.tcx.is_diagnostic_item(sym::path_main_separator, receiver_def_id) && let ty::Ref(_, ty, Mutability::Not) = cx.typeck_results().expr_ty_adjusted(expr).kind() && ty.is_str() { diff --git a/clippy_utils/src/paths.rs b/clippy_utils/src/paths.rs index 0a36d9a6664..5e8157ac0c3 100644 --- a/clippy_utils/src/paths.rs +++ b/clippy_utils/src/paths.rs @@ -40,7 +40,6 @@ pub const OPEN_OPTIONS_NEW: [&str; 4] = ["std", "fs", "OpenOptions", "new"]; pub const PARKING_LOT_MUTEX_GUARD: [&str; 3] = ["lock_api", "mutex", "MutexGuard"]; pub const PARKING_LOT_RWLOCK_READ_GUARD: [&str; 3] = ["lock_api", "rwlock", "RwLockReadGuard"]; pub const PARKING_LOT_RWLOCK_WRITE_GUARD: [&str; 3] = ["lock_api", "rwlock", "RwLockWriteGuard"]; -pub const PATH_MAIN_SEPARATOR: [&str; 3] = ["std", "path", "MAIN_SEPARATOR"]; #[cfg_attr(not(unix), allow(clippy::invalid_paths))] pub const PERMISSIONS_FROM_MODE: [&str; 6] = ["std", "os", "unix", "fs", "PermissionsExt", "from_mode"]; pub const PUSH_STR: [&str; 4] = ["alloc", "string", "String", "push_str"]; From f66915e8f82fd273ee9601c17b3eb2470774801a Mon Sep 17 00:00:00 2001 From: GnomedDev Date: Wed, 18 Sep 2024 21:37:12 +0100 Subject: [PATCH 155/683] [Clippy] Swap `single_char_add_str`/`format_push_string` to use diagnostic items instead of paths --- clippy_lints/src/format_push_string.rs | 4 ++-- clippy_lints/src/methods/single_char_add_str.rs | 6 +++--- clippy_utils/src/paths.rs | 2 -- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/clippy_lints/src/format_push_string.rs b/clippy_lints/src/format_push_string.rs index d05c5a01f41..c6f03c3a7cf 100644 --- a/clippy_lints/src/format_push_string.rs +++ b/clippy_lints/src/format_push_string.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::ty::is_type_lang_item; -use clippy_utils::{higher, match_def_path, paths}; +use clippy_utils::higher; use rustc_hir::{BinOpKind, Expr, ExprKind, LangItem, MatchSource}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; @@ -70,7 +70,7 @@ impl<'tcx> LateLintPass<'tcx> for FormatPushString { let arg = match expr.kind { ExprKind::MethodCall(_, _, [arg], _) => { if let Some(fn_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) - && match_def_path(cx, fn_def_id, &paths::PUSH_STR) + && cx.tcx.is_diagnostic_item(sym::string_push_str, fn_def_id) { arg } else { diff --git a/clippy_lints/src/methods/single_char_add_str.rs b/clippy_lints/src/methods/single_char_add_str.rs index 81450fd8c6c..ccdf5529d53 100644 --- a/clippy_lints/src/methods/single_char_add_str.rs +++ b/clippy_lints/src/methods/single_char_add_str.rs @@ -1,13 +1,13 @@ use crate::methods::{single_char_insert_string, single_char_push_string}; -use clippy_utils::{match_def_path, paths}; use rustc_hir as hir; use rustc_lint::LateContext; +use rustc_span::sym; pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, receiver: &hir::Expr<'_>, args: &[hir::Expr<'_>]) { if let Some(fn_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) { - if match_def_path(cx, fn_def_id, &paths::PUSH_STR) { + if cx.tcx.is_diagnostic_item(sym::string_push_str, fn_def_id) { single_char_push_string::check(cx, expr, receiver, args); - } else if match_def_path(cx, fn_def_id, &paths::INSERT_STR) { + } else if cx.tcx.is_diagnostic_item(sym::string_insert_str, fn_def_id) { single_char_insert_string::check(cx, expr, receiver, args); } } diff --git a/clippy_utils/src/paths.rs b/clippy_utils/src/paths.rs index 5e8157ac0c3..64540637cdb 100644 --- a/clippy_utils/src/paths.rs +++ b/clippy_utils/src/paths.rs @@ -29,7 +29,6 @@ pub const HASHSET_ITER_TY: [&str; 5] = ["std", "collections", "hash", "set", "It pub const HASHSET_DRAIN: [&str; 5] = ["std", "collections", "hash", "set", "Drain"]; pub const IDENT: [&str; 3] = ["rustc_span", "symbol", "Ident"]; pub const IDENT_AS_STR: [&str; 4] = ["rustc_span", "symbol", "Ident", "as_str"]; -pub const INSERT_STR: [&str; 4] = ["alloc", "string", "String", "insert_str"]; pub const ITERTOOLS_NEXT_TUPLE: [&str; 3] = ["itertools", "Itertools", "next_tuple"]; pub const KW_MODULE: [&str; 3] = ["rustc_span", "symbol", "kw"]; pub const LATE_CONTEXT: [&str; 2] = ["rustc_lint", "LateContext"]; @@ -42,7 +41,6 @@ pub const PARKING_LOT_RWLOCK_READ_GUARD: [&str; 3] = ["lock_api", "rwlock", "RwL pub const PARKING_LOT_RWLOCK_WRITE_GUARD: [&str; 3] = ["lock_api", "rwlock", "RwLockWriteGuard"]; #[cfg_attr(not(unix), allow(clippy::invalid_paths))] pub const PERMISSIONS_FROM_MODE: [&str; 6] = ["std", "os", "unix", "fs", "PermissionsExt", "from_mode"]; -pub const PUSH_STR: [&str; 4] = ["alloc", "string", "String", "push_str"]; pub const REGEX_BUILDER_NEW: [&str; 3] = ["regex", "RegexBuilder", "new"]; pub const REGEX_BYTES_BUILDER_NEW: [&str; 4] = ["regex", "bytes", "RegexBuilder", "new"]; pub const REGEX_BYTES_NEW: [&str; 4] = ["regex", "bytes", "Regex", "new"]; From 545967955a52e2a2790def258a9c8a57dea3d379 Mon Sep 17 00:00:00 2001 From: GnomedDev Date: Wed, 18 Sep 2024 21:42:38 +0100 Subject: [PATCH 156/683] [Clippy] Swap `VecArgs::hir` to use diagnostic items instead of paths --- clippy_lints/src/slow_vector_initialization.rs | 2 +- clippy_utils/src/higher.rs | 8 ++++---- clippy_utils/src/paths.rs | 3 --- 3 files changed, 5 insertions(+), 8 deletions(-) diff --git a/clippy_lints/src/slow_vector_initialization.rs b/clippy_lints/src/slow_vector_initialization.rs index b0e25c02265..6c0b0e11c9e 100644 --- a/clippy_lints/src/slow_vector_initialization.rs +++ b/clippy_lints/src/slow_vector_initialization.rs @@ -153,7 +153,7 @@ impl SlowVectorInit { && is_expr_path_def_path(cx, func, &paths::VEC_WITH_CAPACITY) { Some(InitializedSize::Initialized(len_expr)) - } else if matches!(expr.kind, ExprKind::Call(func, _) if is_expr_path_def_path(cx, func, &paths::VEC_NEW)) { + } else if matches!(expr.kind, ExprKind::Call(func, _) if is_path_diagnostic_item(cx, func, sym::vec_new)) { Some(InitializedSize::Uninitialized) } else { None diff --git a/clippy_utils/src/higher.rs b/clippy_utils/src/higher.rs index 8970b4d1229..e09cc9edf3a 100644 --- a/clippy_utils/src/higher.rs +++ b/clippy_utils/src/higher.rs @@ -4,7 +4,7 @@ use crate::consts::{ConstEvalCtxt, Constant}; use crate::ty::is_type_diagnostic_item; -use crate::{is_expn_of, match_def_path, paths}; +use crate::is_expn_of; use rustc_ast::ast; use rustc_hir as hir; @@ -297,10 +297,10 @@ impl<'a> VecArgs<'a> { && is_expn_of(fun.span, "vec").is_some() && let Some(fun_def_id) = cx.qpath_res(qpath, fun.hir_id).opt_def_id() { - return if match_def_path(cx, fun_def_id, &paths::VEC_FROM_ELEM) && args.len() == 2 { + return if cx.tcx.is_diagnostic_item(sym::vec_from_elem, fun_def_id) && args.len() == 2 { // `vec![elem; size]` case Some(VecArgs::Repeat(&args[0], &args[1])) - } else if match_def_path(cx, fun_def_id, &paths::SLICE_INTO_VEC) && args.len() == 1 { + } else if cx.tcx.is_diagnostic_item(sym::slice_into_vec, fun_def_id) && args.len() == 1 { // `vec![a, b, c]` case if let ExprKind::Call(_, [arg]) = &args[0].kind && let ExprKind::Array(args) = arg.kind @@ -309,7 +309,7 @@ impl<'a> VecArgs<'a> { } else { None } - } else if match_def_path(cx, fun_def_id, &paths::VEC_NEW) && args.is_empty() { + } else if cx.tcx.is_diagnostic_item(sym::vec_new, fun_def_id) && args.is_empty() { Some(VecArgs::Vec(&[])) } else { None diff --git a/clippy_utils/src/paths.rs b/clippy_utils/src/paths.rs index 64540637cdb..1d5a2294978 100644 --- a/clippy_utils/src/paths.rs +++ b/clippy_utils/src/paths.rs @@ -49,7 +49,6 @@ pub const REGEX_NEW: [&str; 3] = ["regex", "Regex", "new"]; pub const REGEX_SET_NEW: [&str; 3] = ["regex", "RegexSet", "new"]; pub const SERDE_DESERIALIZE: [&str; 3] = ["serde", "de", "Deserialize"]; pub const SERDE_DE_VISITOR: [&str; 3] = ["serde", "de", "Visitor"]; -pub const SLICE_INTO_VEC: [&str; 4] = ["alloc", "slice", "", "into_vec"]; pub const STD_IO_SEEK_FROM_CURRENT: [&str; 4] = ["std", "io", "SeekFrom", "Current"]; pub const STD_IO_SEEKFROM_START: [&str; 4] = ["std", "io", "SeekFrom", "Start"]; pub const STRING_NEW: [&str; 4] = ["alloc", "string", "String", "new"]; @@ -73,8 +72,6 @@ pub const TOKIO_IO_ASYNCWRITEEXT: [&str; 5] = ["tokio", "io", "util", "async_wri pub const TOKIO_IO_OPEN_OPTIONS: [&str; 4] = ["tokio", "fs", "open_options", "OpenOptions"]; #[expect(clippy::invalid_paths)] // internal lints do not know about all external crates pub const TOKIO_IO_OPEN_OPTIONS_NEW: [&str; 5] = ["tokio", "fs", "open_options", "OpenOptions", "new"]; -pub const VEC_FROM_ELEM: [&str; 3] = ["alloc", "vec", "from_elem"]; -pub const VEC_NEW: [&str; 4] = ["alloc", "vec", "Vec", "new"]; pub const VEC_WITH_CAPACITY: [&str; 4] = ["alloc", "vec", "Vec", "with_capacity"]; pub const INSTANT_NOW: [&str; 4] = ["std", "time", "Instant", "now"]; pub const VEC_IS_EMPTY: [&str; 4] = ["alloc", "vec", "Vec", "is_empty"]; From 984bd6fed6fafb1b6e33c7419ae4485402d76c62 Mon Sep 17 00:00:00 2001 From: GnomedDev Date: Wed, 18 Sep 2024 21:53:28 +0100 Subject: [PATCH 157/683] [Clippy] Swap `repeat_vec_with_capacity` to use diagnostic item instead of path --- clippy_lints/src/repeat_vec_with_capacity.rs | 6 +++--- clippy_lints/src/slow_vector_initialization.rs | 6 +++--- clippy_utils/src/paths.rs | 1 - 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/clippy_lints/src/repeat_vec_with_capacity.rs b/clippy_lints/src/repeat_vec_with_capacity.rs index 678681ea425..08de10f69b0 100644 --- a/clippy_lints/src/repeat_vec_with_capacity.rs +++ b/clippy_lints/src/repeat_vec_with_capacity.rs @@ -3,7 +3,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::higher::VecArgs; use clippy_utils::macros::matching_root_macro_call; use clippy_utils::source::snippet; -use clippy_utils::{expr_or_init, fn_def_id, match_def_path, paths}; +use clippy_utils::{expr_or_init, fn_def_id}; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; @@ -67,7 +67,7 @@ fn emit_lint(cx: &LateContext<'_>, span: Span, kind: &str, note: &'static str, s fn check_vec_macro(cx: &LateContext<'_>, expr: &Expr<'_>) { if matching_root_macro_call(cx, expr.span, sym::vec_macro).is_some() && let Some(VecArgs::Repeat(repeat_expr, len_expr)) = VecArgs::hir(cx, expr) - && fn_def_id(cx, repeat_expr).is_some_and(|did| match_def_path(cx, did, &paths::VEC_WITH_CAPACITY)) + && fn_def_id(cx, repeat_expr).is_some_and(|did| cx.tcx.is_diagnostic_item(sym::vec_with_capacity, did)) && !len_expr.span.from_expansion() && let Some(Constant::Int(2..)) = ConstEvalCtxt::new(cx).eval(expr_or_init(cx, len_expr)) { @@ -91,7 +91,7 @@ fn check_repeat_fn(cx: &LateContext<'_>, expr: &Expr<'_>) { if !expr.span.from_expansion() && fn_def_id(cx, expr).is_some_and(|did| cx.tcx.is_diagnostic_item(sym::iter_repeat, did)) && let ExprKind::Call(_, [repeat_expr]) = expr.kind - && fn_def_id(cx, repeat_expr).is_some_and(|did| match_def_path(cx, did, &paths::VEC_WITH_CAPACITY)) + && fn_def_id(cx, repeat_expr).is_some_and(|did| cx.tcx.is_diagnostic_item(sym::vec_with_capacity, did)) && !repeat_expr.span.from_expansion() { emit_lint( diff --git a/clippy_lints/src/slow_vector_initialization.rs b/clippy_lints/src/slow_vector_initialization.rs index 6c0b0e11c9e..04c16281ec4 100644 --- a/clippy_lints/src/slow_vector_initialization.rs +++ b/clippy_lints/src/slow_vector_initialization.rs @@ -2,8 +2,8 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::macros::matching_root_macro_call; use clippy_utils::sugg::Sugg; use clippy_utils::{ - get_enclosing_block, is_expr_path_def_path, is_integer_literal, is_path_diagnostic_item, path_to_local, - path_to_local_id, paths, SpanlessEq, + get_enclosing_block, is_integer_literal, is_path_diagnostic_item, path_to_local, + path_to_local_id, SpanlessEq, }; use rustc_errors::Applicability; use rustc_hir::intravisit::{walk_block, walk_expr, walk_stmt, Visitor}; @@ -150,7 +150,7 @@ impl SlowVectorInit { } if let ExprKind::Call(func, [len_expr]) = expr.kind - && is_expr_path_def_path(cx, func, &paths::VEC_WITH_CAPACITY) + && is_path_diagnostic_item(cx, func, sym::vec_with_capacity) { Some(InitializedSize::Initialized(len_expr)) } else if matches!(expr.kind, ExprKind::Call(func, _) if is_path_diagnostic_item(cx, func, sym::vec_new)) { diff --git a/clippy_utils/src/paths.rs b/clippy_utils/src/paths.rs index 1d5a2294978..0a0749aa005 100644 --- a/clippy_utils/src/paths.rs +++ b/clippy_utils/src/paths.rs @@ -72,7 +72,6 @@ pub const TOKIO_IO_ASYNCWRITEEXT: [&str; 5] = ["tokio", "io", "util", "async_wri pub const TOKIO_IO_OPEN_OPTIONS: [&str; 4] = ["tokio", "fs", "open_options", "OpenOptions"]; #[expect(clippy::invalid_paths)] // internal lints do not know about all external crates pub const TOKIO_IO_OPEN_OPTIONS_NEW: [&str; 5] = ["tokio", "fs", "open_options", "OpenOptions", "new"]; -pub const VEC_WITH_CAPACITY: [&str; 4] = ["alloc", "vec", "Vec", "with_capacity"]; pub const INSTANT_NOW: [&str; 4] = ["std", "time", "Instant", "now"]; pub const VEC_IS_EMPTY: [&str; 4] = ["alloc", "vec", "Vec", "is_empty"]; pub const VEC_POP: [&str; 4] = ["alloc", "vec", "Vec", "pop"]; From b0152909d659b30879965b84bcf4a69ec4e82746 Mon Sep 17 00:00:00 2001 From: GnomedDev Date: Wed, 18 Sep 2024 21:59:31 +0100 Subject: [PATCH 158/683] [Clippy] Swap `manual_while_let_some` to use diagnostic items instead of paths --- clippy_lints/src/loops/manual_while_let_some.rs | 14 +++++++------- clippy_utils/src/paths.rs | 4 ---- 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/clippy_lints/src/loops/manual_while_let_some.rs b/clippy_lints/src/loops/manual_while_let_some.rs index 57434f35544..55d1b9ee676 100644 --- a/clippy_lints/src/loops/manual_while_let_some.rs +++ b/clippy_lints/src/loops/manual_while_let_some.rs @@ -1,10 +1,10 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet; -use clippy_utils::{match_def_path, paths, SpanlessEq}; +use clippy_utils::SpanlessEq; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, Pat, Stmt, StmtKind, UnOp}; use rustc_lint::LateContext; -use rustc_span::Span; +use rustc_span::{sym, Symbol, Span}; use std::borrow::Cow; use super::MANUAL_WHILE_LET_SOME; @@ -47,20 +47,20 @@ fn report_lint(cx: &LateContext<'_>, pop_span: Span, pop_stmt_kind: PopStmt<'_>, ); } -fn match_method_call(cx: &LateContext<'_>, expr: &Expr<'_>, method: &[&str]) -> bool { +fn match_method_call(cx: &LateContext<'_>, expr: &Expr<'_>, method: Symbol) -> bool { if let ExprKind::MethodCall(..) = expr.kind && let Some(id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) { - match_def_path(cx, id, method) + cx.tcx.is_diagnostic_item(method, id) } else { false } } fn is_vec_pop_unwrap(cx: &LateContext<'_>, expr: &Expr<'_>, is_empty_recv: &Expr<'_>) -> bool { - if (match_method_call(cx, expr, &paths::OPTION_UNWRAP) || match_method_call(cx, expr, &paths::OPTION_EXPECT)) + if (match_method_call(cx, expr, sym::option_unwrap) || match_method_call(cx, expr, sym::option_expect)) && let ExprKind::MethodCall(_, unwrap_recv, ..) = expr.kind - && match_method_call(cx, unwrap_recv, &paths::VEC_POP) + && match_method_call(cx, unwrap_recv, sym::vec_pop) && let ExprKind::MethodCall(_, pop_recv, ..) = unwrap_recv.kind { // make sure they're the same `Vec` @@ -96,7 +96,7 @@ fn check_call_arguments(cx: &LateContext<'_>, stmt: &Stmt<'_>, is_empty_recv: &E pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, full_cond: &'tcx Expr<'_>, body: &'tcx Expr<'_>, loop_span: Span) { if let ExprKind::Unary(UnOp::Not, cond) = full_cond.kind && let ExprKind::MethodCall(_, is_empty_recv, _, _) = cond.kind - && match_method_call(cx, cond, &paths::VEC_IS_EMPTY) + && match_method_call(cx, cond, sym::vec_is_empty) && let ExprKind::Block(body, _) = body.kind && let Some(stmt) = body.stmts.first() { diff --git a/clippy_utils/src/paths.rs b/clippy_utils/src/paths.rs index 0a0749aa005..4a93939d0cc 100644 --- a/clippy_utils/src/paths.rs +++ b/clippy_utils/src/paths.rs @@ -73,9 +73,5 @@ pub const TOKIO_IO_OPEN_OPTIONS: [&str; 4] = ["tokio", "fs", "open_options", "Op #[expect(clippy::invalid_paths)] // internal lints do not know about all external crates pub const TOKIO_IO_OPEN_OPTIONS_NEW: [&str; 5] = ["tokio", "fs", "open_options", "OpenOptions", "new"]; pub const INSTANT_NOW: [&str; 4] = ["std", "time", "Instant", "now"]; -pub const VEC_IS_EMPTY: [&str; 4] = ["alloc", "vec", "Vec", "is_empty"]; -pub const VEC_POP: [&str; 4] = ["alloc", "vec", "Vec", "pop"]; pub const WAKER: [&str; 4] = ["core", "task", "wake", "Waker"]; -pub const OPTION_UNWRAP: [&str; 4] = ["core", "option", "Option", "unwrap"]; -pub const OPTION_EXPECT: [&str; 4] = ["core", "option", "Option", "expect"]; pub const BOOL_THEN: [&str; 4] = ["core", "bool", "", "then"]; From 45c1700e13f5226a6a61d8f1136a319d6a4868bc Mon Sep 17 00:00:00 2001 From: GnomedDev Date: Wed, 18 Sep 2024 22:01:52 +0100 Subject: [PATCH 159/683] [Clippy] Swap `filter_map_bool_then` to use diagnostic item instead of path --- clippy_lints/src/methods/filter_map_bool_then.rs | 5 ++--- clippy_utils/src/paths.rs | 1 - 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/clippy_lints/src/methods/filter_map_bool_then.rs b/clippy_lints/src/methods/filter_map_bool_then.rs index 4fbf661727d..77a62fbb4fb 100644 --- a/clippy_lints/src/methods/filter_map_bool_then.rs +++ b/clippy_lints/src/methods/filter_map_bool_then.rs @@ -1,9 +1,8 @@ use super::FILTER_MAP_BOOL_THEN; use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::paths::BOOL_THEN; use clippy_utils::source::SpanRangeExt; use clippy_utils::ty::is_copy; -use clippy_utils::{is_from_proc_macro, is_trait_method, match_def_path, peel_blocks}; +use clippy_utils::{is_from_proc_macro, is_trait_method, peel_blocks}; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LintContext}; @@ -35,7 +34,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, arg: & && let ExprKind::Closure(then_closure) = then_arg.kind && let then_body = peel_blocks(cx.tcx.hir().body(then_closure.body).value) && let Some(def_id) = cx.typeck_results().type_dependent_def_id(value.hir_id) - && match_def_path(cx, def_id, &BOOL_THEN) + && cx.tcx.is_diagnostic_item(sym::bool_then, def_id) && !is_from_proc_macro(cx, expr) // Count the number of derefs needed to get to the bool because we need those in the suggestion && let needed_derefs = cx.typeck_results().expr_adjustments(recv) diff --git a/clippy_utils/src/paths.rs b/clippy_utils/src/paths.rs index 4a93939d0cc..cb0330d0046 100644 --- a/clippy_utils/src/paths.rs +++ b/clippy_utils/src/paths.rs @@ -74,4 +74,3 @@ pub const TOKIO_IO_OPEN_OPTIONS: [&str; 4] = ["tokio", "fs", "open_options", "Op pub const TOKIO_IO_OPEN_OPTIONS_NEW: [&str; 5] = ["tokio", "fs", "open_options", "OpenOptions", "new"]; pub const INSTANT_NOW: [&str; 4] = ["std", "time", "Instant", "now"]; pub const WAKER: [&str; 4] = ["core", "task", "wake", "Waker"]; -pub const BOOL_THEN: [&str; 4] = ["core", "bool", "", "then"]; From d63e35ba22ae0122e570fdabdb9e8875ef2bbef3 Mon Sep 17 00:00:00 2001 From: GnomedDev Date: Wed, 18 Sep 2024 22:05:02 +0100 Subject: [PATCH 160/683] [Clippy] Swap `waker_clone_wake` to use diagnostic item instead of path --- clippy_lints/src/methods/waker_clone_wake.rs | 4 ++-- clippy_utils/src/paths.rs | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/clippy_lints/src/methods/waker_clone_wake.rs b/clippy_lints/src/methods/waker_clone_wake.rs index da66632d55f..9b64cc7589c 100644 --- a/clippy_lints/src/methods/waker_clone_wake.rs +++ b/clippy_lints/src/methods/waker_clone_wake.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; -use clippy_utils::{is_trait_method, match_def_path, paths}; +use clippy_utils::is_trait_method; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::LateContext; @@ -12,7 +12,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, recv: &' let ty = cx.typeck_results().expr_ty(recv); if let Some(did) = ty.ty_adt_def() - && match_def_path(cx, did.did(), &paths::WAKER) + && cx.tcx.is_diagnostic_item(sym::Waker, did.did()) && let ExprKind::MethodCall(_, waker_ref, &[], _) = recv.kind && is_trait_method(cx, recv, sym::Clone) { diff --git a/clippy_utils/src/paths.rs b/clippy_utils/src/paths.rs index cb0330d0046..89c1bd8a8a0 100644 --- a/clippy_utils/src/paths.rs +++ b/clippy_utils/src/paths.rs @@ -73,4 +73,3 @@ pub const TOKIO_IO_OPEN_OPTIONS: [&str; 4] = ["tokio", "fs", "open_options", "Op #[expect(clippy::invalid_paths)] // internal lints do not know about all external crates pub const TOKIO_IO_OPEN_OPTIONS_NEW: [&str; 5] = ["tokio", "fs", "open_options", "OpenOptions", "new"]; pub const INSTANT_NOW: [&str; 4] = ["std", "time", "Instant", "now"]; -pub const WAKER: [&str; 4] = ["core", "task", "wake", "Waker"]; From 98dc68e85e350a00dd65b76251b598f276d5a7c5 Mon Sep 17 00:00:00 2001 From: GnomedDev Date: Wed, 18 Sep 2024 22:08:04 +0100 Subject: [PATCH 161/683] [Clippy] Swap `instant_subtraction` to use diagnostic item instead of path --- clippy_lints/src/instant_subtraction.rs | 2 +- clippy_utils/src/paths.rs | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/clippy_lints/src/instant_subtraction.rs b/clippy_lints/src/instant_subtraction.rs index f41fdf3203c..6d6820311b6 100644 --- a/clippy_lints/src/instant_subtraction.rs +++ b/clippy_lints/src/instant_subtraction.rs @@ -112,7 +112,7 @@ impl LateLintPass<'_> for InstantSubtraction { fn is_instant_now_call(cx: &LateContext<'_>, expr_block: &'_ Expr<'_>) -> bool { if let ExprKind::Call(fn_expr, []) = expr_block.kind && let Some(fn_id) = clippy_utils::path_def_id(cx, fn_expr) - && clippy_utils::match_def_path(cx, fn_id, &clippy_utils::paths::INSTANT_NOW) + && cx.tcx.is_diagnostic_item(sym::instant_now, fn_id) { true } else { diff --git a/clippy_utils/src/paths.rs b/clippy_utils/src/paths.rs index 89c1bd8a8a0..26f680e2666 100644 --- a/clippy_utils/src/paths.rs +++ b/clippy_utils/src/paths.rs @@ -72,4 +72,3 @@ pub const TOKIO_IO_ASYNCWRITEEXT: [&str; 5] = ["tokio", "io", "util", "async_wri pub const TOKIO_IO_OPEN_OPTIONS: [&str; 4] = ["tokio", "fs", "open_options", "OpenOptions"]; #[expect(clippy::invalid_paths)] // internal lints do not know about all external crates pub const TOKIO_IO_OPEN_OPTIONS_NEW: [&str; 5] = ["tokio", "fs", "open_options", "OpenOptions", "new"]; -pub const INSTANT_NOW: [&str; 4] = ["std", "time", "Instant", "now"]; From acb6748f800f2581834bf7abc744d71e9bfc73d9 Mon Sep 17 00:00:00 2001 From: GnomedDev Date: Wed, 18 Sep 2024 22:10:05 +0100 Subject: [PATCH 162/683] [Clippy] Swap `unnecessary_to_owned` to use diagnostic item instead of path --- clippy_lints/src/methods/unnecessary_to_owned.rs | 4 ++-- clippy_utils/src/paths.rs | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/clippy_lints/src/methods/unnecessary_to_owned.rs b/clippy_lints/src/methods/unnecessary_to_owned.rs index 69c5bc57e29..bf7555a29e2 100644 --- a/clippy_lints/src/methods/unnecessary_to_owned.rs +++ b/clippy_lints/src/methods/unnecessary_to_owned.rs @@ -6,7 +6,7 @@ use clippy_utils::source::{snippet, SpanRangeExt}; use clippy_utils::ty::{get_iterator_item_ty, implements_trait, is_copy, is_type_diagnostic_item, is_type_lang_item}; use clippy_utils::visitors::find_all_ret_expressions; use clippy_utils::{ - fn_def_id, get_parent_expr, is_diag_item_method, is_diag_trait_item, match_def_path, paths, peel_middle_ty_refs, + fn_def_id, get_parent_expr, is_diag_item_method, is_diag_trait_item, peel_middle_ty_refs, return_ty, }; use rustc_errors::Applicability; @@ -250,7 +250,7 @@ fn check_string_from_utf8<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, if let Some((call, arg)) = skip_addr_of_ancestors(cx, expr) && !arg.span.from_expansion() && let ExprKind::Call(callee, _) = call.kind - && fn_def_id(cx, call).is_some_and(|did| match_def_path(cx, did, &paths::STRING_FROM_UTF8)) + && fn_def_id(cx, call).is_some_and(|did| cx.tcx.is_diagnostic_item(sym::string_from_utf8, did)) && let Some(unwrap_call) = get_parent_expr(cx, call) && let ExprKind::MethodCall(unwrap_method_name, ..) = unwrap_call.kind && matches!(unwrap_method_name.ident.name, sym::unwrap | sym::expect) diff --git a/clippy_utils/src/paths.rs b/clippy_utils/src/paths.rs index 26f680e2666..646c7bc5df8 100644 --- a/clippy_utils/src/paths.rs +++ b/clippy_utils/src/paths.rs @@ -61,7 +61,6 @@ 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"]; -pub const STRING_FROM_UTF8: [&str; 4] = ["alloc", "string", "String", "from_utf8"]; #[expect(clippy::invalid_paths)] // internal lints do not know about all external crates pub const TOKIO_FILE_OPTIONS: [&str; 5] = ["tokio", "fs", "file", "File", "options"]; #[expect(clippy::invalid_paths)] // internal lints do not know about all external crates From 1b76ae683c2283c73ed2e84a29c2d023bb0f3974 Mon Sep 17 00:00:00 2001 From: GnomedDev Date: Wed, 18 Sep 2024 22:13:50 +0100 Subject: [PATCH 163/683] [Clippy] Swap `manual_strip` to use diagnostic items instead of paths --- clippy_lints/src/manual_strip.rs | 10 +++++----- clippy_utils/src/paths.rs | 3 --- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/clippy_lints/src/manual_strip.rs b/clippy_lints/src/manual_strip.rs index 85cabd2800a..02d433ecc5a 100644 --- a/clippy_lints/src/manual_strip.rs +++ b/clippy_lints/src/manual_strip.rs @@ -4,7 +4,7 @@ use clippy_utils::consts::{ConstEvalCtxt, Constant}; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet; use clippy_utils::usage::mutated_variables; -use clippy_utils::{eq_expr_value, higher, match_def_path, paths}; +use clippy_utils::{eq_expr_value, higher}; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; use rustc_hir::def::Res; @@ -14,7 +14,7 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_session::impl_lint_pass; use rustc_span::source_map::Spanned; -use rustc_span::Span; +use rustc_span::{sym, Span}; use std::iter; declare_clippy_lint! { @@ -76,9 +76,9 @@ impl<'tcx> LateLintPass<'tcx> for ManualStrip { && self.msrv.meets(msrvs::STR_STRIP_PREFIX) && let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(cond.hir_id) { - let strip_kind = if match_def_path(cx, method_def_id, &paths::STR_STARTS_WITH) { + let strip_kind = if cx.tcx.is_diagnostic_item(sym::str_starts_with, method_def_id) { StripKind::Prefix - } else if match_def_path(cx, method_def_id, &paths::STR_ENDS_WITH) { + } else if cx.tcx.is_diagnostic_item(sym::str_ends_with, method_def_id) { StripKind::Suffix } else { return; @@ -137,7 +137,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualStrip { fn len_arg<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> { if let ExprKind::MethodCall(_, arg, [], _) = expr.kind && let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) - && match_def_path(cx, method_def_id, &paths::STR_LEN) + && cx.tcx.is_diagnostic_item(sym::str_len, method_def_id) { Some(arg) } else { diff --git a/clippy_utils/src/paths.rs b/clippy_utils/src/paths.rs index 646c7bc5df8..986adddc6ae 100644 --- a/clippy_utils/src/paths.rs +++ b/clippy_utils/src/paths.rs @@ -52,9 +52,6 @@ pub const SERDE_DE_VISITOR: [&str; 3] = ["serde", "de", "Visitor"]; pub const STD_IO_SEEK_FROM_CURRENT: [&str; 4] = ["std", "io", "SeekFrom", "Current"]; pub const STD_IO_SEEKFROM_START: [&str; 4] = ["std", "io", "SeekFrom", "Start"]; pub const STRING_NEW: [&str; 4] = ["alloc", "string", "String", "new"]; -pub const STR_ENDS_WITH: [&str; 4] = ["core", "str", "", "ends_with"]; -pub const STR_LEN: [&str; 4] = ["core", "str", "", "len"]; -pub const STR_STARTS_WITH: [&str; 4] = ["core", "str", "", "starts_with"]; 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"]; From f1fc9c07c4db8e1327558ad1088f074434213f42 Mon Sep 17 00:00:00 2001 From: GnomedDev Date: Wed, 18 Sep 2024 22:38:27 +0100 Subject: [PATCH 164/683] [Clippy] Swap `unnecessary_owned_empty_strings` to use diagnostic item instead of path --- clippy_lints/src/unnecessary_owned_empty_strings.rs | 3 +-- clippy_utils/src/paths.rs | 1 - 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/clippy_lints/src/unnecessary_owned_empty_strings.rs b/clippy_lints/src/unnecessary_owned_empty_strings.rs index 6b5e6c6ab20..f01cb457af8 100644 --- a/clippy_lints/src/unnecessary_owned_empty_strings.rs +++ b/clippy_lints/src/unnecessary_owned_empty_strings.rs @@ -1,6 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::ty::is_type_lang_item; -use clippy_utils::{match_def_path, paths}; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; use rustc_hir::{BorrowKind, Expr, ExprKind, LangItem, Mutability}; @@ -42,7 +41,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryOwnedEmptyStrings { && let ty::Ref(_, inner_str, _) = cx.typeck_results().expr_ty_adjusted(expr).kind() && inner_str.is_str() { - if match_def_path(cx, fun_def_id, &paths::STRING_NEW) { + if cx.tcx.is_diagnostic_item(sym::string_new, fun_def_id) { span_lint_and_sugg( cx, UNNECESSARY_OWNED_EMPTY_STRINGS, diff --git a/clippy_utils/src/paths.rs b/clippy_utils/src/paths.rs index 986adddc6ae..dd304e7aae8 100644 --- a/clippy_utils/src/paths.rs +++ b/clippy_utils/src/paths.rs @@ -51,7 +51,6 @@ pub const SERDE_DESERIALIZE: [&str; 3] = ["serde", "de", "Deserialize"]; pub const SERDE_DE_VISITOR: [&str; 3] = ["serde", "de", "Visitor"]; pub const STD_IO_SEEK_FROM_CURRENT: [&str; 4] = ["std", "io", "SeekFrom", "Current"]; pub const STD_IO_SEEKFROM_START: [&str; 4] = ["std", "io", "SeekFrom", "Start"]; -pub const STRING_NEW: [&str; 4] = ["alloc", "string", "String", "new"]; 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"]; From 37e38320b449dcb8bc11a537fd7914c8759c2e0c Mon Sep 17 00:00:00 2001 From: GnomedDev Date: Wed, 18 Sep 2024 23:01:37 +0100 Subject: [PATCH 165/683] [Clippy] Swap `non_octal_unix_permissions` to use diagnostic item instead of path --- clippy_lints/src/non_octal_unix_permissions.rs | 3 +-- clippy_utils/src/paths.rs | 2 -- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/clippy_lints/src/non_octal_unix_permissions.rs b/clippy_lints/src/non_octal_unix_permissions.rs index b915df52762..cfc15d92715 100644 --- a/clippy_lints/src/non_octal_unix_permissions.rs +++ b/clippy_lints/src/non_octal_unix_permissions.rs @@ -1,6 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::{snippet_with_applicability, SpanRangeExt}; -use clippy_utils::{match_def_path, paths}; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; @@ -63,7 +62,7 @@ impl<'tcx> LateLintPass<'tcx> for NonOctalUnixPermissions { ExprKind::Call(func, [param]) => { if let ExprKind::Path(ref path) = func.kind && let Some(def_id) = cx.qpath_res(path, func.hir_id).opt_def_id() - && match_def_path(cx, def_id, &paths::PERMISSIONS_FROM_MODE) + && cx.tcx.is_diagnostic_item(sym::permissions_from_mode, def_id) && let ExprKind::Lit(_) = param.kind && param.span.eq_ctxt(expr.span) && param diff --git a/clippy_utils/src/paths.rs b/clippy_utils/src/paths.rs index dd304e7aae8..c7b1c01de1d 100644 --- a/clippy_utils/src/paths.rs +++ b/clippy_utils/src/paths.rs @@ -39,8 +39,6 @@ pub const OPEN_OPTIONS_NEW: [&str; 4] = ["std", "fs", "OpenOptions", "new"]; pub const PARKING_LOT_MUTEX_GUARD: [&str; 3] = ["lock_api", "mutex", "MutexGuard"]; pub const PARKING_LOT_RWLOCK_READ_GUARD: [&str; 3] = ["lock_api", "rwlock", "RwLockReadGuard"]; pub const PARKING_LOT_RWLOCK_WRITE_GUARD: [&str; 3] = ["lock_api", "rwlock", "RwLockWriteGuard"]; -#[cfg_attr(not(unix), allow(clippy::invalid_paths))] -pub const PERMISSIONS_FROM_MODE: [&str; 6] = ["std", "os", "unix", "fs", "PermissionsExt", "from_mode"]; pub const REGEX_BUILDER_NEW: [&str; 3] = ["regex", "RegexBuilder", "new"]; pub const REGEX_BYTES_BUILDER_NEW: [&str; 4] = ["regex", "bytes", "RegexBuilder", "new"]; pub const REGEX_BYTES_NEW: [&str; 4] = ["regex", "bytes", "Regex", "new"]; From 917775fff17fba253a93d05b39b3c151deb6e106 Mon Sep 17 00:00:00 2001 From: GnomedDev Date: Wed, 18 Sep 2024 23:21:35 +0100 Subject: [PATCH 166/683] [Clippy] Swap `iter_over_hash_type` to use diagnostic items instead of paths --- clippy_lints/src/iter_over_hash_type.rs | 38 +++++++++---------------- clippy_utils/src/paths.rs | 8 ------ 2 files changed, 14 insertions(+), 32 deletions(-) diff --git a/clippy_lints/src/iter_over_hash_type.rs b/clippy_lints/src/iter_over_hash_type.rs index fb29d982417..f162948bb44 100644 --- a/clippy_lints/src/iter_over_hash_type.rs +++ b/clippy_lints/src/iter_over_hash_type.rs @@ -1,10 +1,5 @@ use clippy_utils::diagnostics::span_lint; use clippy_utils::higher::ForLoop; -use clippy_utils::match_any_def_paths; -use clippy_utils::paths::{ - HASHMAP_DRAIN, HASHMAP_ITER, HASHMAP_ITER_MUT, HASHMAP_KEYS, HASHMAP_VALUES, HASHMAP_VALUES_MUT, HASHSET_DRAIN, - HASHSET_ITER_TY, -}; use clippy_utils::ty::is_type_diagnostic_item; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; @@ -44,28 +39,23 @@ declare_lint_pass!(IterOverHashType => [ITER_OVER_HASH_TYPE]); impl LateLintPass<'_> for IterOverHashType { fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'_ rustc_hir::Expr<'_>) { + let hash_iter_tys = [ + sym::HashMap, + sym::HashSet, + sym::hashmap_keys_ty, + sym::hashmap_values_ty, + sym::hashmap_values_mut_ty, + sym::hashmap_iter_ty, + sym::hashmap_iter_mut_ty, + sym::hashmap_drain_ty, + sym::hashset_iter_ty, + sym::hashset_drain_ty, + ]; + if let Some(for_loop) = ForLoop::hir(expr) && !for_loop.body.span.from_expansion() && let ty = cx.typeck_results().expr_ty(for_loop.arg).peel_refs() - && let Some(adt) = ty.ty_adt_def() - && let did = adt.did() - && (match_any_def_paths( - cx, - did, - &[ - &HASHMAP_KEYS, - &HASHMAP_VALUES, - &HASHMAP_VALUES_MUT, - &HASHMAP_ITER, - &HASHMAP_ITER_MUT, - &HASHMAP_DRAIN, - &HASHSET_ITER_TY, - &HASHSET_DRAIN, - ], - ) - .is_some() - || is_type_diagnostic_item(cx, ty, sym::HashMap) - || is_type_diagnostic_item(cx, ty, sym::HashSet)) + && hash_iter_tys.into_iter().any(|sym| is_type_diagnostic_item(cx, ty, sym)) { span_lint( cx, diff --git a/clippy_utils/src/paths.rs b/clippy_utils/src/paths.rs index c7b1c01de1d..ccaed3057f4 100644 --- a/clippy_utils/src/paths.rs +++ b/clippy_utils/src/paths.rs @@ -19,14 +19,6 @@ pub const FILE_OPTIONS: [&str; 4] = ["std", "fs", "File", "options"]; pub const FUTURES_IO_ASYNCREADEXT: [&str; 3] = ["futures_util", "io", "AsyncReadExt"]; #[expect(clippy::invalid_paths)] // internal lints do not know about all external crates pub const FUTURES_IO_ASYNCWRITEEXT: [&str; 3] = ["futures_util", "io", "AsyncWriteExt"]; -pub const HASHMAP_ITER: [&str; 5] = ["std", "collections", "hash", "map", "Iter"]; -pub const HASHMAP_ITER_MUT: [&str; 5] = ["std", "collections", "hash", "map", "IterMut"]; -pub const HASHMAP_KEYS: [&str; 5] = ["std", "collections", "hash", "map", "Keys"]; -pub const HASHMAP_VALUES: [&str; 5] = ["std", "collections", "hash", "map", "Values"]; -pub const HASHMAP_DRAIN: [&str; 5] = ["std", "collections", "hash", "map", "Drain"]; -pub const HASHMAP_VALUES_MUT: [&str; 5] = ["std", "collections", "hash", "map", "ValuesMut"]; -pub const HASHSET_ITER_TY: [&str; 5] = ["std", "collections", "hash", "set", "Iter"]; -pub const HASHSET_DRAIN: [&str; 5] = ["std", "collections", "hash", "set", "Drain"]; pub const IDENT: [&str; 3] = ["rustc_span", "symbol", "Ident"]; pub const IDENT_AS_STR: [&str; 4] = ["rustc_span", "symbol", "Ident", "as_str"]; pub const ITERTOOLS_NEXT_TUPLE: [&str; 3] = ["itertools", "Itertools", "next_tuple"]; From c7453b42801cc4cd9d7b7abaef6456bbb8d0de0b Mon Sep 17 00:00:00 2001 From: GnomedDev Date: Thu, 19 Sep 2024 12:19:48 +0100 Subject: [PATCH 167/683] [Clippy] Swap `open_options` to use diagnostic items instead of paths --- clippy_lints/src/methods/open_options.rs | 23 ++++++++++++----------- clippy_utils/src/paths.rs | 2 -- 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/clippy_lints/src/methods/open_options.rs b/clippy_lints/src/methods/open_options.rs index cbeb48b6cc3..f1a3c81cebb 100644 --- a/clippy_lints/src/methods/open_options.rs +++ b/clippy_lints/src/methods/open_options.rs @@ -126,17 +126,18 @@ fn get_open_options( && let ExprKind::Path(path) = callee.kind && let Some(did) = cx.qpath_res(&path, callee.hir_id).opt_def_id() { - match_any_def_paths( - cx, - did, - &[ - &paths::TOKIO_IO_OPEN_OPTIONS_NEW, - &paths::OPEN_OPTIONS_NEW, - &paths::FILE_OPTIONS, - &paths::TOKIO_FILE_OPTIONS, - ], - ) - .is_some() + let std_file_options = [ + sym::file_options, + sym::open_options_new, + ]; + + let tokio_file_options: &[&[&str]] = &[ + &paths::TOKIO_IO_OPEN_OPTIONS_NEW, + &paths::TOKIO_FILE_OPTIONS, + ]; + + let is_std_options = std_file_options.into_iter().any(|sym| cx.tcx.is_diagnostic_item(sym, did)); + is_std_options || match_any_def_paths(cx, did, tokio_file_options).is_some() } else { false } diff --git a/clippy_utils/src/paths.rs b/clippy_utils/src/paths.rs index ccaed3057f4..103a331a0a7 100644 --- a/clippy_utils/src/paths.rs +++ b/clippy_utils/src/paths.rs @@ -14,7 +14,6 @@ pub const APPLICABILITY_VALUES: [[&str; 3]; 4] = [ pub const DIAG: [&str; 2] = ["rustc_errors", "Diag"]; pub const EARLY_CONTEXT: [&str; 2] = ["rustc_lint", "EarlyContext"]; pub const EARLY_LINT_PASS: [&str; 3] = ["rustc_lint", "passes", "EarlyLintPass"]; -pub const FILE_OPTIONS: [&str; 4] = ["std", "fs", "File", "options"]; #[expect(clippy::invalid_paths)] // internal lints do not know about all external crates pub const FUTURES_IO_ASYNCREADEXT: [&str; 3] = ["futures_util", "io", "AsyncReadExt"]; #[expect(clippy::invalid_paths)] // internal lints do not know about all external crates @@ -27,7 +26,6 @@ pub const LATE_CONTEXT: [&str; 2] = ["rustc_lint", "LateContext"]; pub const LATE_LINT_PASS: [&str; 3] = ["rustc_lint", "passes", "LateLintPass"]; pub const LINT: [&str; 2] = ["rustc_lint_defs", "Lint"]; pub const MSRV: [&str; 3] = ["clippy_config", "msrvs", "Msrv"]; -pub const OPEN_OPTIONS_NEW: [&str; 4] = ["std", "fs", "OpenOptions", "new"]; pub const PARKING_LOT_MUTEX_GUARD: [&str; 3] = ["lock_api", "mutex", "MutexGuard"]; pub const PARKING_LOT_RWLOCK_READ_GUARD: [&str; 3] = ["lock_api", "rwlock", "RwLockReadGuard"]; pub const PARKING_LOT_RWLOCK_WRITE_GUARD: [&str; 3] = ["lock_api", "rwlock", "RwLockWriteGuard"]; From 07b6e0713e37242037136b169d440d58c4500a3c Mon Sep 17 00:00:00 2001 From: GnomedDev Date: Thu, 19 Sep 2024 13:09:25 +0100 Subject: [PATCH 168/683] Categorise paths in `clippy_utils::paths` --- clippy_utils/src/paths.rs | 33 ++++++++++++++++++++------------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/clippy_utils/src/paths.rs b/clippy_utils/src/paths.rs index 103a331a0a7..c8b59fca524 100644 --- a/clippy_utils/src/paths.rs +++ b/clippy_utils/src/paths.rs @@ -4,6 +4,7 @@ //! Whenever possible, please consider diagnostic items over hardcoded paths. //! See for more information. +// Paths inside rustc pub const APPLICABILITY: [&str; 2] = ["rustc_lint_defs", "Applicability"]; pub const APPLICABILITY_VALUES: [[&str; 3]; 4] = [ ["rustc_lint_defs", "Applicability", "Unspecified"], @@ -14,18 +15,32 @@ pub const APPLICABILITY_VALUES: [[&str; 3]; 4] = [ pub const DIAG: [&str; 2] = ["rustc_errors", "Diag"]; pub const EARLY_CONTEXT: [&str; 2] = ["rustc_lint", "EarlyContext"]; pub const EARLY_LINT_PASS: [&str; 3] = ["rustc_lint", "passes", "EarlyLintPass"]; -#[expect(clippy::invalid_paths)] // internal lints do not know about all external crates -pub const FUTURES_IO_ASYNCREADEXT: [&str; 3] = ["futures_util", "io", "AsyncReadExt"]; -#[expect(clippy::invalid_paths)] // internal lints do not know about all external crates -pub const FUTURES_IO_ASYNCWRITEEXT: [&str; 3] = ["futures_util", "io", "AsyncWriteExt"]; pub const IDENT: [&str; 3] = ["rustc_span", "symbol", "Ident"]; pub const IDENT_AS_STR: [&str; 4] = ["rustc_span", "symbol", "Ident", "as_str"]; -pub const ITERTOOLS_NEXT_TUPLE: [&str; 3] = ["itertools", "Itertools", "next_tuple"]; pub const KW_MODULE: [&str; 3] = ["rustc_span", "symbol", "kw"]; pub const LATE_CONTEXT: [&str; 2] = ["rustc_lint", "LateContext"]; 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"]; + +// Paths in `core`/`alloc`/`std`. This should be avoided and cleaned up by adding diagnostic items. +pub const STD_IO_SEEK_FROM_CURRENT: [&str; 4] = ["std", "io", "SeekFrom", "Current"]; +pub const STD_IO_SEEKFROM_START: [&str; 4] = ["std", "io", "SeekFrom", "Start"]; + +// Paths in clippy itself pub const MSRV: [&str; 3] = ["clippy_config", "msrvs", "Msrv"]; + +// Paths in external crates +#[expect(clippy::invalid_paths)] // internal lints do not know about all external crates +pub const FUTURES_IO_ASYNCREADEXT: [&str; 3] = ["futures_util", "io", "AsyncReadExt"]; +#[expect(clippy::invalid_paths)] // internal lints do not know about all external crates +pub const FUTURES_IO_ASYNCWRITEEXT: [&str; 3] = ["futures_util", "io", "AsyncWriteExt"]; +pub const ITERTOOLS_NEXT_TUPLE: [&str; 3] = ["itertools", "Itertools", "next_tuple"]; pub const PARKING_LOT_MUTEX_GUARD: [&str; 3] = ["lock_api", "mutex", "MutexGuard"]; pub const PARKING_LOT_RWLOCK_READ_GUARD: [&str; 3] = ["lock_api", "rwlock", "RwLockReadGuard"]; pub const PARKING_LOT_RWLOCK_WRITE_GUARD: [&str; 3] = ["lock_api", "rwlock", "RwLockWriteGuard"]; @@ -37,14 +52,6 @@ pub const REGEX_NEW: [&str; 3] = ["regex", "Regex", "new"]; pub const REGEX_SET_NEW: [&str; 3] = ["regex", "RegexSet", "new"]; pub const SERDE_DESERIALIZE: [&str; 3] = ["serde", "de", "Deserialize"]; pub const SERDE_DE_VISITOR: [&str; 3] = ["serde", "de", "Visitor"]; -pub const STD_IO_SEEK_FROM_CURRENT: [&str; 4] = ["std", "io", "SeekFrom", "Current"]; -pub const STD_IO_SEEKFROM_START: [&str; 4] = ["std", "io", "SeekFrom", "Start"]; -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"]; #[expect(clippy::invalid_paths)] // internal lints do not know about all external crates pub const TOKIO_FILE_OPTIONS: [&str; 5] = ["tokio", "fs", "file", "File", "options"]; #[expect(clippy::invalid_paths)] // internal lints do not know about all external crates From 290a01e448e9e17710e03fc28c73de19f5889e5a Mon Sep 17 00:00:00 2001 From: Lukas Lueg Date: Thu, 19 Sep 2024 21:27:39 +0200 Subject: [PATCH 169/683] Initial impl of `unnecessary_first_then_check` Fixes #11212 --- CHANGELOG.md | 1 + clippy_lints/src/declared_lints.rs | 1 + clippy_lints/src/methods/mod.rs | 33 +++++++++++ .../methods/unnecessary_first_then_check.rs | 56 +++++++++++++++++++ tests/ui/unnecessary_first_then_check.fixed | 22 ++++++++ tests/ui/unnecessary_first_then_check.rs | 22 ++++++++ tests/ui/unnecessary_first_then_check.stderr | 47 ++++++++++++++++ 7 files changed, 182 insertions(+) create mode 100644 clippy_lints/src/methods/unnecessary_first_then_check.rs create mode 100644 tests/ui/unnecessary_first_then_check.fixed create mode 100644 tests/ui/unnecessary_first_then_check.rs create mode 100644 tests/ui/unnecessary_first_then_check.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index 0e5d1688e4a..6e0aaa25a7c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6021,6 +6021,7 @@ Released 2018-09-13 [`unnecessary_fallible_conversions`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_fallible_conversions [`unnecessary_filter_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_filter_map [`unnecessary_find_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_find_map +[`unnecessary_first_then_check`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_first_then_check [`unnecessary_fold`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_fold [`unnecessary_get_then_check`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_get_then_check [`unnecessary_join`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_join diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index 16c64830e70..824f57cece9 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -467,6 +467,7 @@ pub static LINTS: &[&crate::LintInfo] = &[ crate::methods::UNNECESSARY_FALLIBLE_CONVERSIONS_INFO, crate::methods::UNNECESSARY_FILTER_MAP_INFO, crate::methods::UNNECESSARY_FIND_MAP_INFO, + crate::methods::UNNECESSARY_FIRST_THEN_CHECK_INFO, crate::methods::UNNECESSARY_FOLD_INFO, crate::methods::UNNECESSARY_GET_THEN_CHECK_INFO, crate::methods::UNNECESSARY_JOIN_INFO, diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 9b7cba9dafb..d8812dfd90c 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -111,6 +111,7 @@ mod uninit_assumed_init; mod unit_hash; mod unnecessary_fallible_conversions; mod unnecessary_filter_map; +mod unnecessary_first_then_check; mod unnecessary_fold; mod unnecessary_get_then_check; mod unnecessary_iter_cloned; @@ -4137,6 +4138,34 @@ declare_clippy_lint! { "use of `map` returning the original item" } +declare_clippy_lint! { + /// ### What it does + /// Checks the usage of `.first().is_some()` or `.first().is_none()` to check if a slice is + /// empty. + /// + /// ### Why is this bad? + /// Using `.is_empty()` is shorter and better communicates the intention. + /// + /// ### Example + /// ```no_run + /// let v = vec![1, 2, 3]; + /// if v.first().is_none() { + /// // The vector is empty... + /// } + /// ``` + /// Use instead: + /// ```no_run + /// let v = vec![1, 2, 3]; + /// if v.is_empty() { + /// // The vector is empty... + /// } + /// ``` + #[clippy::version = "1.83.0"] + pub UNNECESSARY_FIRST_THEN_CHECK, + complexity, + "calling `.first().is_some()` or `.first().is_none()` instead of `.is_empty()`" +} + pub struct Methods { avoid_breaking_exported_api: bool, msrv: Msrv, @@ -4294,6 +4323,7 @@ impl_lint_pass!(Methods => [ UNNECESSARY_RESULT_MAP_OR_ELSE, MANUAL_C_STR_LITERALS, UNNECESSARY_GET_THEN_CHECK, + UNNECESSARY_FIRST_THEN_CHECK, NEEDLESS_CHARACTER_ITERATION, MANUAL_INSPECT, UNNECESSARY_MIN_OR_MAX, @@ -5066,6 +5096,9 @@ fn check_is_some_is_none(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, Some(("get", f_recv, [arg], _, _)) => { unnecessary_get_then_check::check(cx, call_span, recv, f_recv, arg, is_some); }, + Some(("first", f_recv, [], _, _)) => { + unnecessary_first_then_check::check(cx, call_span, recv, f_recv, is_some); + }, _ => {}, } } diff --git a/clippy_lints/src/methods/unnecessary_first_then_check.rs b/clippy_lints/src/methods/unnecessary_first_then_check.rs new file mode 100644 index 00000000000..7ae1bb54e60 --- /dev/null +++ b/clippy_lints/src/methods/unnecessary_first_then_check.rs @@ -0,0 +1,56 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::SpanRangeExt; + +use rustc_errors::Applicability; +use rustc_hir::{Expr, ExprKind}; +use rustc_lint::LateContext; +use rustc_span::Span; + +use super::UNNECESSARY_FIRST_THEN_CHECK; + +pub(super) fn check( + cx: &LateContext<'_>, + call_span: Span, + first_call: &Expr<'_>, + first_caller: &Expr<'_>, + is_some: bool, +) { + if !cx + .typeck_results() + .expr_ty_adjusted(first_caller) + .peel_refs() + .is_slice() + { + return; + } + + let ExprKind::MethodCall(_, _, _, first_call_span) = first_call.kind else { + return; + }; + + let both_calls_span = first_call_span.with_hi(call_span.hi()); + if let Some(both_calls_snippet) = both_calls_span.get_source_text(cx) + && let Some(first_caller_snippet) = first_caller.span.get_source_text(cx) + { + let (sugg_span, suggestion) = if is_some { + ( + first_caller.span.with_hi(call_span.hi()), + format!("!{first_caller_snippet}.is_empty()"), + ) + } else { + (both_calls_span, "is_empty()".to_owned()) + }; + span_lint_and_sugg( + cx, + UNNECESSARY_FIRST_THEN_CHECK, + sugg_span, + format!( + "unnecessary use of `{both_calls_snippet}` to check if slice {}", + if is_some { "is not empty" } else { "is empty" } + ), + "replace this with", + suggestion, + Applicability::MaybeIncorrect, + ); + } +} diff --git a/tests/ui/unnecessary_first_then_check.fixed b/tests/ui/unnecessary_first_then_check.fixed new file mode 100644 index 00000000000..7202e1bbd17 --- /dev/null +++ b/tests/ui/unnecessary_first_then_check.fixed @@ -0,0 +1,22 @@ +#![warn(clippy::unnecessary_first_then_check)] +#![allow(clippy::useless_vec, clippy::const_is_empty)] + +fn main() { + let s = [1, 2, 3]; + let _: bool = !s.is_empty(); + let _: bool = s.is_empty(); + + let v = vec![1, 2, 3]; + let _: bool = !v.is_empty(); + + let n = [[1, 2, 3], [4, 5, 6]]; + let _: bool = !n[0].is_empty(); + let _: bool = n[0].is_empty(); + + struct Foo { + bar: &'static [i32], + } + let f = [Foo { bar: &[] }]; + let _: bool = !f[0].bar.is_empty(); + let _: bool = f[0].bar.is_empty(); +} diff --git a/tests/ui/unnecessary_first_then_check.rs b/tests/ui/unnecessary_first_then_check.rs new file mode 100644 index 00000000000..762b9599928 --- /dev/null +++ b/tests/ui/unnecessary_first_then_check.rs @@ -0,0 +1,22 @@ +#![warn(clippy::unnecessary_first_then_check)] +#![allow(clippy::useless_vec, clippy::const_is_empty)] + +fn main() { + let s = [1, 2, 3]; + let _: bool = s.first().is_some(); + let _: bool = s.first().is_none(); + + let v = vec![1, 2, 3]; + let _: bool = v.first().is_some(); + + let n = [[1, 2, 3], [4, 5, 6]]; + let _: bool = n[0].first().is_some(); + let _: bool = n[0].first().is_none(); + + struct Foo { + bar: &'static [i32], + } + let f = [Foo { bar: &[] }]; + let _: bool = f[0].bar.first().is_some(); + let _: bool = f[0].bar.first().is_none(); +} diff --git a/tests/ui/unnecessary_first_then_check.stderr b/tests/ui/unnecessary_first_then_check.stderr new file mode 100644 index 00000000000..bbaf7e68eda --- /dev/null +++ b/tests/ui/unnecessary_first_then_check.stderr @@ -0,0 +1,47 @@ +error: unnecessary use of `first().is_some()` to check if slice is not empty + --> tests/ui/unnecessary_first_then_check.rs:6:19 + | +LL | let _: bool = s.first().is_some(); + | ^^^^^^^^^^^^^^^^^^^ help: replace this with: `!s.is_empty()` + | + = note: `-D clippy::unnecessary-first-then-check` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::unnecessary_first_then_check)]` + +error: unnecessary use of `first().is_none()` to check if slice is empty + --> tests/ui/unnecessary_first_then_check.rs:7:21 + | +LL | let _: bool = s.first().is_none(); + | ^^^^^^^^^^^^^^^^^ help: replace this with: `is_empty()` + +error: unnecessary use of `first().is_some()` to check if slice is not empty + --> tests/ui/unnecessary_first_then_check.rs:10:19 + | +LL | let _: bool = v.first().is_some(); + | ^^^^^^^^^^^^^^^^^^^ help: replace this with: `!v.is_empty()` + +error: unnecessary use of `first().is_some()` to check if slice is not empty + --> tests/ui/unnecessary_first_then_check.rs:13:19 + | +LL | let _: bool = n[0].first().is_some(); + | ^^^^^^^^^^^^^^^^^^^^^^ help: replace this with: `!n[0].is_empty()` + +error: unnecessary use of `first().is_none()` to check if slice is empty + --> tests/ui/unnecessary_first_then_check.rs:14:24 + | +LL | let _: bool = n[0].first().is_none(); + | ^^^^^^^^^^^^^^^^^ help: replace this with: `is_empty()` + +error: unnecessary use of `first().is_some()` to check if slice is not empty + --> tests/ui/unnecessary_first_then_check.rs:20:19 + | +LL | let _: bool = f[0].bar.first().is_some(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace this with: `!f[0].bar.is_empty()` + +error: unnecessary use of `first().is_none()` to check if slice is empty + --> tests/ui/unnecessary_first_then_check.rs:21:28 + | +LL | let _: bool = f[0].bar.first().is_none(); + | ^^^^^^^^^^^^^^^^^ help: replace this with: `is_empty()` + +error: aborting due to 7 previous errors + From e91e01509e1e034a71c545d42410d2ea4f7db89e Mon Sep 17 00:00:00 2001 From: Noa Date: Thu, 19 Sep 2024 16:42:55 -0500 Subject: [PATCH 170/683] Add `field@` and `variant@` doc-link disambiguators --- .../linking-to-items-by-name.md | 4 +- .../passes/collect_intra_doc_links.rs | 95 +++++++++++-------- .../intra-doc/disambiguator-mismatch.rs | 18 +++- .../intra-doc/disambiguator-mismatch.stderr | 50 +++++++--- tests/rustdoc-ui/intra-doc/field-ice.rs | 4 +- tests/rustdoc-ui/intra-doc/field-ice.stderr | 7 +- .../issue-108653-associated-items.stderr | 6 +- tests/rustdoc/intra-doc/field.rs | 20 ++++ 8 files changed, 138 insertions(+), 66 deletions(-) diff --git a/src/doc/rustdoc/src/write-documentation/linking-to-items-by-name.md b/src/doc/rustdoc/src/write-documentation/linking-to-items-by-name.md index 1a367b8274b..5e785483402 100644 --- a/src/doc/rustdoc/src/write-documentation/linking-to-items-by-name.md +++ b/src/doc/rustdoc/src/write-documentation/linking-to-items-by-name.md @@ -89,8 +89,8 @@ fn Foo() {} These prefixes will be stripped when displayed in the documentation, so `[struct@Foo]` will be rendered as `Foo`. The following prefixes are available: `struct`, `enum`, `trait`, `union`, -`mod`, `module`, `const`, `constant`, `fn`, `function`, `method`, `derive`, `type`, `value`, -`macro`, `prim` or `primitive`. +`mod`, `module`, `const`, `constant`, `fn`, `function`, `field`, `variant`, `method`, `derive`, +`type`, `value`, `macro`, `prim` or `primitive`. You can also disambiguate for functions by adding `()` after the function name, or for macros by adding `!` after the macro name. The macro `!` can be followed by `()`, `{}`, diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 676c972529b..871f78dac5f 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -110,7 +110,6 @@ impl Res { let prefix = match kind { DefKind::Fn | DefKind::AssocFn => return Suggestion::Function, - DefKind::Field => return Suggestion::RemoveDisambiguator, DefKind::Macro(MacroKind::Bang) => return Suggestion::Macro, DefKind::Macro(MacroKind::Derive) => "derive", @@ -123,6 +122,8 @@ impl Res { "const" } DefKind::Static { .. } => "static", + DefKind::Field => "field", + DefKind::Variant | DefKind::Ctor(..) => "variant", // Now handle things that don't have a specific disambiguator _ => match kind .ns() @@ -415,6 +416,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { &mut self, path_str: &'path str, ns: Namespace, + disambiguator: Option, item_id: DefId, module_id: DefId, ) -> Result)>, UnresolvedPath<'path>> { @@ -454,7 +456,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { match resolve_primitive(path_root, TypeNS) .or_else(|| self.resolve_path(path_root, TypeNS, item_id, module_id)) .map(|ty_res| { - self.resolve_associated_item(ty_res, item_name, ns, module_id) + self.resolve_associated_item(ty_res, item_name, ns, disambiguator, module_id) .into_iter() .map(|(res, def_id)| (res, Some(def_id))) .collect::>() @@ -557,6 +559,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { root_res: Res, item_name: Symbol, ns: Namespace, + disambiguator: Option, module_id: DefId, ) -> Vec<(Res, DefId)> { let tcx = self.cx.tcx; @@ -583,7 +586,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { // FIXME: if the associated item is defined directly on the type alias, // it will show up on its documentation page, we should link there instead. let Some(res) = self.def_id_to_res(did) else { return Vec::new() }; - self.resolve_associated_item(res, item_name, ns, module_id) + self.resolve_associated_item(res, item_name, ns, disambiguator, module_id) } Res::Def( def_kind @ (DefKind::Struct | DefKind::Union | DefKind::Enum | DefKind::ForeignTy), @@ -604,6 +607,39 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { } } + let search_for_field = || { + let (DefKind::Struct | DefKind::Union) = def_kind else { return vec![] }; + debug!("looking for fields named {item_name} for {did:?}"); + // FIXME: this doesn't really belong in `associated_item` (maybe `variant_field` is better?) + // NOTE: it's different from variant_field because it only resolves struct fields, + // not variant fields (2 path segments, not 3). + // + // We need to handle struct (and union) fields in this code because + // syntactically their paths are identical to associated item paths: + // `module::Type::field` and `module::Type::Assoc`. + // + // On the other hand, variant fields can't be mistaken for associated + // items because they look like this: `module::Type::Variant::field`. + // + // Variants themselves don't need to be handled here, even though + // they also look like associated items (`module::Type::Variant`), + // because they are real Rust syntax (unlike the intra-doc links + // field syntax) and are handled by the compiler's resolver. + let ty::Adt(def, _) = tcx.type_of(did).instantiate_identity().kind() else { + unreachable!() + }; + def.non_enum_variant() + .fields + .iter() + .filter(|field| field.name == item_name) + .map(|field| (root_res, field.did)) + .collect::>() + }; + + if let Some(Disambiguator::Kind(DefKind::Field)) = disambiguator { + return search_for_field(); + } + // Checks if item_name belongs to `impl SomeItem` let mut assoc_items: Vec<_> = tcx .inherent_impls(did) @@ -647,32 +683,8 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { if ns != Namespace::ValueNS { return Vec::new(); } - debug!("looking for fields named {item_name} for {did:?}"); - // FIXME: this doesn't really belong in `associated_item` (maybe `variant_field` is better?) - // NOTE: it's different from variant_field because it only resolves struct fields, - // not variant fields (2 path segments, not 3). - // - // We need to handle struct (and union) fields in this code because - // syntactically their paths are identical to associated item paths: - // `module::Type::field` and `module::Type::Assoc`. - // - // On the other hand, variant fields can't be mistaken for associated - // items because they look like this: `module::Type::Variant::field`. - // - // Variants themselves don't need to be handled here, even though - // they also look like associated items (`module::Type::Variant`), - // because they are real Rust syntax (unlike the intra-doc links - // field syntax) and are handled by the compiler's resolver. - let def = match tcx.type_of(did).instantiate_identity().kind() { - ty::Adt(def, _) if !def.is_enum() => def, - _ => return Vec::new(), - }; - def.non_enum_variant() - .fields - .iter() - .filter(|field| field.name == item_name) - .map(|field| (root_res, field.did)) - .collect::>() + + search_for_field() } Res::Def(DefKind::Trait, did) => filter_assoc_items_by_name_and_namespace( tcx, @@ -1298,7 +1310,7 @@ impl LinkCollector<'_, '_> { match disambiguator.map(Disambiguator::ns) { Some(expected_ns) => { - match self.resolve(path_str, expected_ns, item_id, module_id) { + match self.resolve(path_str, expected_ns, disambiguator, item_id, module_id) { Ok(candidates) => candidates, Err(err) => { // We only looked in one namespace. Try to give a better error if possible. @@ -1307,8 +1319,9 @@ impl LinkCollector<'_, '_> { let mut err = ResolutionFailure::NotResolved(err); for other_ns in [TypeNS, ValueNS, MacroNS] { if other_ns != expected_ns { - if let Ok(&[res, ..]) = - self.resolve(path_str, other_ns, item_id, module_id).as_deref() + if let Ok(&[res, ..]) = self + .resolve(path_str, other_ns, None, item_id, module_id) + .as_deref() { err = ResolutionFailure::WrongNamespace { res: full_res(self.cx.tcx, res), @@ -1328,7 +1341,7 @@ impl LinkCollector<'_, '_> { None => { // Try everything! let mut candidate = |ns| { - self.resolve(path_str, ns, item_id, module_id) + self.resolve(path_str, ns, None, item_id, module_id) .map_err(ResolutionFailure::NotResolved) }; @@ -1532,6 +1545,8 @@ impl Disambiguator { }), "function" | "fn" | "method" => Kind(DefKind::Fn), "derive" => Kind(DefKind::Macro(MacroKind::Derive)), + "field" => Kind(DefKind::Field), + "variant" => Kind(DefKind::Variant), "type" => NS(Namespace::TypeNS), "value" => NS(Namespace::ValueNS), "macro" => NS(Namespace::MacroNS), @@ -1570,6 +1585,8 @@ impl Disambiguator { fn ns(self) -> Namespace { match self { Self::Namespace(n) => n, + // for purposes of link resolution, fields are in the value namespace. + Self::Kind(DefKind::Field) => ValueNS, Self::Kind(k) => { k.ns().expect("only DefKinds with a valid namespace can be disambiguators") } @@ -1604,8 +1621,6 @@ enum Suggestion { Function, /// `m!` Macro, - /// `foo` without any disambiguator - RemoveDisambiguator, } impl Suggestion { @@ -1614,7 +1629,6 @@ impl Suggestion { Self::Prefix(x) => format!("prefix with `{x}@`").into(), Self::Function => "add parentheses".into(), Self::Macro => "add an exclamation mark".into(), - Self::RemoveDisambiguator => "remove the disambiguator".into(), } } @@ -1624,13 +1638,11 @@ impl Suggestion { Self::Prefix(prefix) => format!("{prefix}@{path_str}"), Self::Function => format!("{path_str}()"), Self::Macro => format!("{path_str}!"), - Self::RemoveDisambiguator => path_str.into(), } } fn as_help_span( &self, - path_str: &str, ori_link: &str, sp: rustc_span::Span, ) -> Vec<(rustc_span::Span, String)> { @@ -1678,7 +1690,6 @@ impl Suggestion { } sugg } - Self::RemoveDisambiguator => vec![(sp, path_str.into())], } } } @@ -1827,7 +1838,9 @@ fn resolution_failure( }; name = start; for ns in [TypeNS, ValueNS, MacroNS] { - if let Ok(v_res) = collector.resolve(start, ns, item_id, module_id) { + if let Ok(v_res) = + collector.resolve(start, ns, None, item_id, module_id) + { debug!("found partial_res={v_res:?}"); if let Some(&res) = v_res.first() { *partial_res = Some(full_res(tcx, res)); @@ -2165,7 +2178,7 @@ fn suggest_disambiguator( }; if let (Some(sp), Some(ori_link)) = (sp, ori_link) { - let mut spans = suggestion.as_help_span(path_str, ori_link, sp); + let mut spans = suggestion.as_help_span(ori_link, sp); if spans.len() > 1 { diag.multipart_suggestion(help, spans, Applicability::MaybeIncorrect); } else { diff --git a/tests/rustdoc-ui/intra-doc/disambiguator-mismatch.rs b/tests/rustdoc-ui/intra-doc/disambiguator-mismatch.rs index 2d66566119b..8142bd83877 100644 --- a/tests/rustdoc-ui/intra-doc/disambiguator-mismatch.rs +++ b/tests/rustdoc-ui/intra-doc/disambiguator-mismatch.rs @@ -1,6 +1,8 @@ #![deny(rustdoc::broken_intra_doc_links)] //~^ NOTE lint level is defined -pub enum S {} +pub enum S { + A, +} fn S() {} #[macro_export] @@ -13,6 +15,10 @@ const c: usize = 0; trait T {} +struct X { + y: usize, +} + /// Link to [struct@S] //~^ ERROR incompatible link kind for `S` //~| NOTE this link resolved @@ -78,4 +84,14 @@ trait T {} //~^ ERROR unresolved link to `std` //~| NOTE this link resolves to the crate `std` //~| HELP to link to the crate, prefix with `mod@` + +/// Link to [method@X::y] +//~^ ERROR incompatible link kind for `X::y` +//~| NOTE this link resolved +//~| HELP prefix with `field@` + +/// Link to [field@S::A] +//~^ ERROR incompatible link kind for `S::A` +//~| NOTE this link resolved +//~| HELP prefix with `variant@` pub fn f() {} diff --git a/tests/rustdoc-ui/intra-doc/disambiguator-mismatch.stderr b/tests/rustdoc-ui/intra-doc/disambiguator-mismatch.stderr index ee35749ce7f..488120304fd 100644 --- a/tests/rustdoc-ui/intra-doc/disambiguator-mismatch.stderr +++ b/tests/rustdoc-ui/intra-doc/disambiguator-mismatch.stderr @@ -1,5 +1,5 @@ error: incompatible link kind for `S` - --> $DIR/disambiguator-mismatch.rs:16:14 + --> $DIR/disambiguator-mismatch.rs:22:14 | LL | /// Link to [struct@S] | ^^^^^^^^ this link resolved to an enum, which is not a struct @@ -15,7 +15,7 @@ LL | /// Link to [enum@S] | ~~~~~ error: incompatible link kind for `S` - --> $DIR/disambiguator-mismatch.rs:21:14 + --> $DIR/disambiguator-mismatch.rs:27:14 | LL | /// Link to [mod@S] | ^^^^^ this link resolved to an enum, which is not a module @@ -26,7 +26,7 @@ LL | /// Link to [enum@S] | ~~~~~ error: incompatible link kind for `S` - --> $DIR/disambiguator-mismatch.rs:26:14 + --> $DIR/disambiguator-mismatch.rs:32:14 | LL | /// Link to [union@S] | ^^^^^^^ this link resolved to an enum, which is not a union @@ -37,7 +37,7 @@ LL | /// Link to [enum@S] | ~~~~~ error: incompatible link kind for `S` - --> $DIR/disambiguator-mismatch.rs:31:14 + --> $DIR/disambiguator-mismatch.rs:37:14 | LL | /// Link to [trait@S] | ^^^^^^^ this link resolved to an enum, which is not a trait @@ -48,7 +48,7 @@ LL | /// Link to [enum@S] | ~~~~~ error: incompatible link kind for `T` - --> $DIR/disambiguator-mismatch.rs:36:14 + --> $DIR/disambiguator-mismatch.rs:42:14 | LL | /// Link to [struct@T] | ^^^^^^^^ this link resolved to a trait, which is not a struct @@ -59,7 +59,7 @@ LL | /// Link to [trait@T] | ~~~~~~ error: incompatible link kind for `m` - --> $DIR/disambiguator-mismatch.rs:41:14 + --> $DIR/disambiguator-mismatch.rs:47:14 | LL | /// Link to [derive@m] | ^^^^^^^^ this link resolved to a macro, which is not a derive macro @@ -71,7 +71,7 @@ LL + /// Link to [m!] | error: unresolved link to `m` - --> $DIR/disambiguator-mismatch.rs:46:14 + --> $DIR/disambiguator-mismatch.rs:52:14 | LL | /// Link to [m()] | ^^^ this link resolves to the macro `m`, which is not in the value namespace @@ -82,7 +82,7 @@ LL | /// Link to [m!()] | + error: incompatible link kind for `s` - --> $DIR/disambiguator-mismatch.rs:52:14 + --> $DIR/disambiguator-mismatch.rs:58:14 | LL | /// Link to [const@s] | ^^^^^^^ this link resolved to a static, which is not a constant @@ -93,7 +93,7 @@ LL | /// Link to [static@s] | ~~~~~~~ error: incompatible link kind for `c` - --> $DIR/disambiguator-mismatch.rs:57:14 + --> $DIR/disambiguator-mismatch.rs:63:14 | LL | /// Link to [static@c] | ^^^^^^^^ this link resolved to a constant, which is not a static @@ -104,7 +104,7 @@ LL | /// Link to [const@c] | ~~~~~~ error: incompatible link kind for `c` - --> $DIR/disambiguator-mismatch.rs:62:14 + --> $DIR/disambiguator-mismatch.rs:68:14 | LL | /// Link to [fn@c] | ^^^^ this link resolved to a constant, which is not a function @@ -115,7 +115,7 @@ LL | /// Link to [const@c] | ~~~~~~ error: incompatible link kind for `c` - --> $DIR/disambiguator-mismatch.rs:67:14 + --> $DIR/disambiguator-mismatch.rs:73:14 | LL | /// Link to [c()] | ^^^ this link resolved to a constant, which is not a function @@ -127,7 +127,7 @@ LL + /// Link to [const@c] | error: incompatible link kind for `f` - --> $DIR/disambiguator-mismatch.rs:72:14 + --> $DIR/disambiguator-mismatch.rs:78:14 | LL | /// Link to [const@f] | ^^^^^^^ this link resolved to a function, which is not a constant @@ -139,7 +139,7 @@ LL + /// Link to [f()] | error: unresolved link to `std` - --> $DIR/disambiguator-mismatch.rs:77:14 + --> $DIR/disambiguator-mismatch.rs:83:14 | LL | /// Link to [fn@std] | ^^^^^^ this link resolves to the crate `std`, which is not in the value namespace @@ -149,5 +149,27 @@ help: to link to the crate, prefix with `mod@` LL | /// Link to [mod@std] | ~~~~ -error: aborting due to 13 previous errors +error: incompatible link kind for `X::y` + --> $DIR/disambiguator-mismatch.rs:88:14 + | +LL | /// Link to [method@X::y] + | ^^^^^^^^^^^ this link resolved to a field, which is not a function + | +help: to link to the field, prefix with `field@` + | +LL | /// Link to [field@X::y] + | ~~~~~~ + +error: incompatible link kind for `S::A` + --> $DIR/disambiguator-mismatch.rs:93:14 + | +LL | /// Link to [field@S::A] + | ^^^^^^^^^^ this link resolved to a unit variant, which is not a field + | +help: to link to the unit variant, prefix with `variant@` + | +LL | /// Link to [variant@S::A] + | ~~~~~~~~ + +error: aborting due to 15 previous errors diff --git a/tests/rustdoc-ui/intra-doc/field-ice.rs b/tests/rustdoc-ui/intra-doc/field-ice.rs index c5d501e38da..1ba865b53c2 100644 --- a/tests/rustdoc-ui/intra-doc/field-ice.rs +++ b/tests/rustdoc-ui/intra-doc/field-ice.rs @@ -4,8 +4,8 @@ /// [`Foo::bar`] /// [`Foo::bar()`] //~^ERROR incompatible link kind for `Foo::bar` -//~|HELP to link to the field, remove the disambiguator +//~|HELP to link to the field, prefix with `field@` //~|NOTE this link resolved to a field, which is not a function pub struct Foo { - pub bar: u8 + pub bar: u8, } diff --git a/tests/rustdoc-ui/intra-doc/field-ice.stderr b/tests/rustdoc-ui/intra-doc/field-ice.stderr index cc0ada873af..7321c87b790 100644 --- a/tests/rustdoc-ui/intra-doc/field-ice.stderr +++ b/tests/rustdoc-ui/intra-doc/field-ice.stderr @@ -9,10 +9,11 @@ note: the lint level is defined here | LL | #![deny(rustdoc::broken_intra_doc_links)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -help: to link to the field, remove the disambiguator +help: to link to the field, prefix with `field@` + | +LL - /// [`Foo::bar()`] +LL + /// [`field@Foo::bar`] | -LL | /// [`Foo::bar`] - | ~~~~~~~~ error: aborting due to 1 previous error diff --git a/tests/rustdoc-ui/intra-doc/issue-108653-associated-items.stderr b/tests/rustdoc-ui/intra-doc/issue-108653-associated-items.stderr index ed89fa8391d..9cd855b69ff 100644 --- a/tests/rustdoc-ui/intra-doc/issue-108653-associated-items.stderr +++ b/tests/rustdoc-ui/intra-doc/issue-108653-associated-items.stderr @@ -43,10 +43,10 @@ help: to link to the associated function, add parentheses | LL | /// [`Self::IDENT()`] | ++ -help: to link to the variant, prefix with `type@` +help: to link to the variant, prefix with `variant@` | -LL | /// [`type@Self::IDENT`] - | +++++ +LL | /// [`variant@Self::IDENT`] + | ++++++++ error: `Self::IDENT2` is both an associated constant and an associated type --> $DIR/issue-108653-associated-items.rs:30:7 diff --git a/tests/rustdoc/intra-doc/field.rs b/tests/rustdoc/intra-doc/field.rs index ba6b320e560..e98419618e2 100644 --- a/tests/rustdoc/intra-doc/field.rs +++ b/tests/rustdoc/intra-doc/field.rs @@ -1,4 +1,24 @@ //@ has field/index.html '//a[@href="{{channel}}/core/ops/range/struct.Range.html#structfield.start"]' 'start' //@ has field/index.html '//a[@href="{{channel}}/std/io/error/enum.ErrorKind.html#variant.NotFound"]' 'not_found' +//@ has field/index.html '//a[@href="struct.FieldAndMethod.html#structfield.x"]' 'x' +//@ has field/index.html '//a[@href="enum.VariantAndMethod.html#variant.X"]' 'X' //! [start][std::ops::Range::start] //! [not_found][std::io::ErrorKind::NotFound] +//! [x][field@crate::FieldAndMethod::x] +//! [X][variant@crate::VariantAndMethod::X] + +pub struct FieldAndMethod { + pub x: i32, +} + +impl FieldAndMethod { + pub fn x(&self) {} +} + +pub enum VariantAndMethod { + X {}, +} + +impl VariantAndMethod { + fn X() {} +} From 4f319002cd961ce417820b7f7159b28c840a6ef0 Mon Sep 17 00:00:00 2001 From: GnomedDev Date: Thu, 19 Sep 2024 14:30:22 +0100 Subject: [PATCH 171/683] [Clippy] Remove final std paths for diagnostic item --- clippy_lints/src/methods/seek_from_current.rs | 6 ++-- .../seek_to_start_instead_of_rewind.rs | 6 ++-- clippy_utils/src/lib.rs | 28 ++++++++----------- clippy_utils/src/paths.rs | 3 +- 4 files changed, 18 insertions(+), 25 deletions(-) diff --git a/clippy_lints/src/methods/seek_from_current.rs b/clippy_lints/src/methods/seek_from_current.rs index e45c7962f13..8bc535ac47a 100644 --- a/clippy_lints/src/methods/seek_from_current.rs +++ b/clippy_lints/src/methods/seek_from_current.rs @@ -8,7 +8,7 @@ use rustc_span::sym; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::implements_trait; -use clippy_utils::{match_def_path, paths}; +use clippy_utils::is_enum_variant_ctor; use super::SEEK_FROM_CURRENT; @@ -36,8 +36,8 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, recv: &' fn arg_is_seek_from_current<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> bool { if let ExprKind::Call(f, args) = expr.kind && let ExprKind::Path(ref path) = f.kind - && let Some(def_id) = cx.qpath_res(path, f.hir_id).opt_def_id() - && match_def_path(cx, def_id, &paths::STD_IO_SEEK_FROM_CURRENT) + && let Some(ctor_call_id) = cx.qpath_res(path, f.hir_id).opt_def_id() + && is_enum_variant_ctor(cx, sym::SeekFrom, sym!(Current), ctor_call_id) { // check if argument of `SeekFrom::Current` is `0` if args.len() == 1 diff --git a/clippy_lints/src/methods/seek_to_start_instead_of_rewind.rs b/clippy_lints/src/methods/seek_to_start_instead_of_rewind.rs index cc4cb47e35c..7c09cc252e1 100644 --- a/clippy_lints/src/methods/seek_to_start_instead_of_rewind.rs +++ b/clippy_lints/src/methods/seek_to_start_instead_of_rewind.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::ty::implements_trait; -use clippy_utils::{is_expr_used_or_unified, match_def_path, paths}; +use clippy_utils::{is_expr_used_or_unified, is_enum_variant_ctor}; use rustc_ast::ast::{LitIntType, LitKind}; use rustc_data_structures::packed::Pu128; use rustc_errors::Applicability; @@ -28,8 +28,8 @@ pub(super) fn check<'tcx>( && implements_trait(cx, ty, seek_trait_id, &[]) && let ExprKind::Call(func, args1) = arg.kind && let ExprKind::Path(ref path) = func.kind - && let Some(def_id) = cx.qpath_res(path, func.hir_id).opt_def_id() - && match_def_path(cx, def_id, &paths::STD_IO_SEEKFROM_START) + && let Some(ctor_call_id) = cx.qpath_res(path, func.hir_id).opt_def_id() + && is_enum_variant_ctor(cx, sym::SeekFrom, sym!(Start), ctor_call_id) && args1.len() == 1 && let ExprKind::Lit(lit) = args1[0].kind && let LitKind::Int(Pu128(0), LitIntType::Unsuffixed) = lit.node diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 5db14872c36..0d0d6219c5e 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -263,24 +263,18 @@ pub fn is_res_lang_ctor(cx: &LateContext<'_>, res: Res, lang_item: LangItem) -> } } -pub fn is_res_diagnostic_ctor(cx: &LateContext<'_>, res: Res, diag_item: Symbol) -> bool { - if let Res::Def(DefKind::Ctor(..), id) = res - && let Some(id) = cx.tcx.opt_parent(id) - { - cx.tcx.is_diagnostic_item(diag_item, id) - } else { - false - } -} -/// Checks if a `QPath` resolves to a constructor of a diagnostic item. -pub fn is_diagnostic_ctor(cx: &LateContext<'_>, qpath: &QPath<'_>, diagnostic_item: Symbol) -> bool { - if let QPath::Resolved(_, path) = qpath { - if let Res::Def(DefKind::Ctor(..), ctor_id) = path.res { - return cx.tcx.is_diagnostic_item(diagnostic_item, cx.tcx.parent(ctor_id)); - } - } - false +/// Checks if `{ctor_call_id}(...)` is `{enum_item}::{variant_name}(...)`. +pub fn is_enum_variant_ctor(cx: &LateContext<'_>, enum_item: Symbol, variant_name: Symbol, ctor_call_id: DefId) -> bool { + let Some(enum_def_id) = cx.tcx.get_diagnostic_item(enum_item) else { + return false; + }; + + let variants = cx.tcx.adt_def(enum_def_id).variants().iter(); + variants + .filter(|variant| variant.name == variant_name) + .filter_map(|variant| variant.ctor.as_ref()) + .any(|(_, ctor_def_id)| *ctor_def_id == ctor_call_id) } /// Checks if the `DefId` matches the given diagnostic item or it's constructor. diff --git a/clippy_utils/src/paths.rs b/clippy_utils/src/paths.rs index c8b59fca524..a30edc48fff 100644 --- a/clippy_utils/src/paths.rs +++ b/clippy_utils/src/paths.rs @@ -29,8 +29,7 @@ pub const SYM_MODULE: [&str; 3] = ["rustc_span", "symbol", "sym"]; pub const SYNTAX_CONTEXT: [&str; 3] = ["rustc_span", "hygiene", "SyntaxContext"]; // Paths in `core`/`alloc`/`std`. This should be avoided and cleaned up by adding diagnostic items. -pub const STD_IO_SEEK_FROM_CURRENT: [&str; 4] = ["std", "io", "SeekFrom", "Current"]; -pub const STD_IO_SEEKFROM_START: [&str; 4] = ["std", "io", "SeekFrom", "Start"]; +// ... none currently! // Paths in clippy itself pub const MSRV: [&str; 3] = ["clippy_config", "msrvs", "Msrv"]; From 485e90f1a73bd2024a4a280708ec5b3b8ca8dbe7 Mon Sep 17 00:00:00 2001 From: B I Mohammed Abbas Date: Fri, 20 Sep 2024 16:15:49 +0530 Subject: [PATCH 172/683] Add Vxworks RISC-V targets --- compiler/rustc_target/src/spec/mod.rs | 2 ++ .../src/spec/targets/riscv32_wrs_vxworks.rs | 24 +++++++++++++++++++ .../src/spec/targets/riscv64_wrs_vxworks.rs | 24 +++++++++++++++++++ src/doc/rustc/src/platform-support.md | 2 ++ src/doc/rustc/src/platform-support/vxworks.md | 2 ++ tests/assembly/targets/targets-elf.rs | 6 +++++ 6 files changed, 60 insertions(+) create mode 100644 compiler/rustc_target/src/spec/targets/riscv32_wrs_vxworks.rs create mode 100644 compiler/rustc_target/src/spec/targets/riscv64_wrs_vxworks.rs diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index f12e3e595ad..5a7d86991a2 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -1842,6 +1842,8 @@ supported_targets! { ("powerpc-wrs-vxworks", powerpc_wrs_vxworks), ("powerpc-wrs-vxworks-spe", powerpc_wrs_vxworks_spe), ("powerpc64-wrs-vxworks", powerpc64_wrs_vxworks), + ("riscv32-wrs-vxworks", riscv32_wrs_vxworks), + ("riscv64-wrs-vxworks", riscv64_wrs_vxworks), ("aarch64-kmc-solid_asp3", aarch64_kmc_solid_asp3), ("armv7a-kmc-solid_asp3-eabi", armv7a_kmc_solid_asp3_eabi), diff --git a/compiler/rustc_target/src/spec/targets/riscv32_wrs_vxworks.rs b/compiler/rustc_target/src/spec/targets/riscv32_wrs_vxworks.rs new file mode 100644 index 00000000000..4a6f7950b87 --- /dev/null +++ b/compiler/rustc_target/src/spec/targets/riscv32_wrs_vxworks.rs @@ -0,0 +1,24 @@ +use crate::spec::{base, StackProbeType, Target, TargetOptions}; + +pub(crate) fn target() -> Target { + Target { + llvm_target: "riscv32".into(), + metadata: crate::spec::TargetMetadata { + description: None, + tier: Some(3), + host_tools: Some(false), + std: None, // STD is a work in progress for this target arch + }, + pointer_width: 32, + data_layout: "e-m:e-p:32:32-i64:64-n32-S128".into(), + arch: "riscv32".into(), + options: TargetOptions { + cpu: "generic-rv32".into(), + llvm_abiname: "ilp32d".into(), + max_atomic_width: Some(32), + features: "+m,+a,+f,+d,+c,+zicsr".into(), + stack_probes: StackProbeType::Inline, + ..base::vxworks::opts() + }, + } +} diff --git a/compiler/rustc_target/src/spec/targets/riscv64_wrs_vxworks.rs b/compiler/rustc_target/src/spec/targets/riscv64_wrs_vxworks.rs new file mode 100644 index 00000000000..b0914871a64 --- /dev/null +++ b/compiler/rustc_target/src/spec/targets/riscv64_wrs_vxworks.rs @@ -0,0 +1,24 @@ +use crate::spec::{base, StackProbeType, Target, TargetOptions}; + +pub(crate) fn target() -> Target { + Target { + llvm_target: "riscv64".into(), + metadata: crate::spec::TargetMetadata { + description: None, + tier: Some(3), + host_tools: Some(false), + std: None, // STD is a work in progress for this target arch + }, + pointer_width: 64, + data_layout: "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128".into(), + arch: "riscv64".into(), + options: TargetOptions { + cpu: "generic-rv64".into(), + llvm_abiname: "lp64d".into(), + max_atomic_width: Some(64), + features: "+m,+a,+f,+d,+c,+zicsr".into(), + stack_probes: StackProbeType::Inline, + ..base::vxworks::opts() + }, + } +} diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index 9a35b35af71..76b7dad8f18 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -358,12 +358,14 @@ target | std | host | notes [`riscv32imc-esp-espidf`](platform-support/esp-idf.md) | ✓ | | RISC-V ESP-IDF [`riscv32imac-esp-espidf`](platform-support/esp-idf.md) | ✓ | | RISC-V ESP-IDF [`riscv32imafc-esp-espidf`](platform-support/esp-idf.md) | ✓ | | RISC-V ESP-IDF +[`riscv32-wrs-vxworks`](platform-support/vxworks.md) | ? | | [`riscv64gc-unknown-hermit`](platform-support/hermit.md) | ✓ | | RISC-V Hermit `riscv64gc-unknown-freebsd` | | | RISC-V FreeBSD `riscv64gc-unknown-fuchsia` | | | RISC-V Fuchsia [`riscv64gc-unknown-netbsd`](platform-support/netbsd.md) | ✓ | ✓ | RISC-V NetBSD [`riscv64gc-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | OpenBSD/riscv64 [`riscv64-linux-android`](platform-support/android.md) | | | RISC-V 64-bit Android +[`riscv64-wrs-vxworks`](platform-support/vxworks.md) | ? | | `s390x-unknown-linux-musl` | | | S390x Linux (kernel 3.2, musl 1.2.3) `sparc-unknown-linux-gnu` | ✓ | | 32-bit SPARC Linux [`sparc-unknown-none-elf`](./platform-support/sparc-unknown-none-elf.md) | * | | Bare 32-bit SPARC V7+ diff --git a/src/doc/rustc/src/platform-support/vxworks.md b/src/doc/rustc/src/platform-support/vxworks.md index f1860346c8f..6aa3d8b7361 100644 --- a/src/doc/rustc/src/platform-support/vxworks.md +++ b/src/doc/rustc/src/platform-support/vxworks.md @@ -14,6 +14,8 @@ Target triplets available: - `powerpc-wrs-vxworks` - `powerpc64-wrs-vxworks` - `powerpc-wrs-vxworks-spe` +- `riscv32-wrs-vxworks` +- `riscv64-wrs-vxworks` ## Target maintainers diff --git a/tests/assembly/targets/targets-elf.rs b/tests/assembly/targets/targets-elf.rs index 4e1c5e6806e..70747484603 100644 --- a/tests/assembly/targets/targets-elf.rs +++ b/tests/assembly/targets/targets-elf.rs @@ -372,6 +372,9 @@ //@ revisions: powerpc_wrs_vxworks_spe //@ [powerpc_wrs_vxworks_spe] compile-flags: --target powerpc-wrs-vxworks-spe //@ [powerpc_wrs_vxworks_spe] needs-llvm-components: powerpc +//@ revisions: riscv32_wrs_vxworks +//@ [riscv32_wrs_vxworks] compile-flags: --target riscv32-wrs-vxworks +//@ [riscv32_wrs_vxworks] needs-llvm-components: riscv //@ revisions: riscv32gc_unknown_linux_gnu //@ [riscv32gc_unknown_linux_gnu] compile-flags: --target riscv32gc-unknown-linux-gnu //@ [riscv32gc_unknown_linux_gnu] needs-llvm-components: riscv @@ -414,6 +417,9 @@ //@ revisions: riscv64_linux_android //@ [riscv64_linux_android] compile-flags: --target riscv64-linux-android //@ [riscv64_linux_android] needs-llvm-components: riscv +//@ revisions: riscv64_wrs_vxworks +//@ [riscv64_wrs_vxworks] compile-flags: --target riscv64-wrs-vxworks +//@ [riscv64_wrs_vxworks] needs-llvm-components: riscv //@ revisions: riscv64gc_unknown_freebsd //@ [riscv64gc_unknown_freebsd] compile-flags: --target riscv64gc-unknown-freebsd //@ [riscv64gc_unknown_freebsd] needs-llvm-components: riscv From eb6a52c2f6add6b8afa0736f914e6d212d5af95d Mon Sep 17 00:00:00 2001 From: B I Mohammed Abbas Date: Fri, 20 Sep 2024 17:23:49 +0530 Subject: [PATCH 173/683] Update std support for all vxworks target archs --- compiler/rustc_target/src/spec/targets/aarch64_wrs_vxworks.rs | 2 +- compiler/rustc_target/src/spec/targets/i686_wrs_vxworks.rs | 2 +- .../rustc_target/src/spec/targets/powerpc64_wrs_vxworks.rs | 2 +- compiler/rustc_target/src/spec/targets/powerpc_wrs_vxworks.rs | 2 +- compiler/rustc_target/src/spec/targets/riscv32_wrs_vxworks.rs | 2 +- compiler/rustc_target/src/spec/targets/riscv64_wrs_vxworks.rs | 2 +- compiler/rustc_target/src/spec/targets/x86_64_wrs_vxworks.rs | 2 +- src/doc/rustc/src/platform-support.md | 4 ++-- 8 files changed, 9 insertions(+), 9 deletions(-) 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 3c0f92fa31f..f3d7a96e82f 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_wrs_vxworks.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_wrs_vxworks.rs @@ -7,7 +7,7 @@ pub(crate) fn target() -> Target { description: None, tier: Some(3), host_tools: Some(false), - std: None, // ? + std: Some(true), }, pointer_width: 64, data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(), diff --git a/compiler/rustc_target/src/spec/targets/i686_wrs_vxworks.rs b/compiler/rustc_target/src/spec/targets/i686_wrs_vxworks.rs index ba669334e7f..c91136c3415 100644 --- a/compiler/rustc_target/src/spec/targets/i686_wrs_vxworks.rs +++ b/compiler/rustc_target/src/spec/targets/i686_wrs_vxworks.rs @@ -13,7 +13,7 @@ pub(crate) fn target() -> Target { description: None, tier: Some(3), host_tools: Some(false), - std: None, // ? + std: Some(true), }, pointer_width: 32, data_layout: "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-\ diff --git a/compiler/rustc_target/src/spec/targets/powerpc64_wrs_vxworks.rs b/compiler/rustc_target/src/spec/targets/powerpc64_wrs_vxworks.rs index 1029a135e4a..6544d32a552 100644 --- a/compiler/rustc_target/src/spec/targets/powerpc64_wrs_vxworks.rs +++ b/compiler/rustc_target/src/spec/targets/powerpc64_wrs_vxworks.rs @@ -14,7 +14,7 @@ pub(crate) fn target() -> Target { description: None, tier: Some(3), host_tools: Some(false), - std: None, // ? + std: Some(true), }, pointer_width: 64, data_layout: "E-m:e-Fi64-i64:64-n32:64-S128-v256:256:256-v512:512:512".into(), diff --git a/compiler/rustc_target/src/spec/targets/powerpc_wrs_vxworks.rs b/compiler/rustc_target/src/spec/targets/powerpc_wrs_vxworks.rs index b19513bf1d7..4900d5fef7b 100644 --- a/compiler/rustc_target/src/spec/targets/powerpc_wrs_vxworks.rs +++ b/compiler/rustc_target/src/spec/targets/powerpc_wrs_vxworks.rs @@ -13,7 +13,7 @@ pub(crate) fn target() -> Target { description: None, tier: Some(3), host_tools: Some(false), - std: None, // ? + std: Some(true), }, pointer_width: 32, data_layout: "E-m:e-p:32:32-Fn32-i64:64-n32".into(), diff --git a/compiler/rustc_target/src/spec/targets/riscv32_wrs_vxworks.rs b/compiler/rustc_target/src/spec/targets/riscv32_wrs_vxworks.rs index 4a6f7950b87..5d4b7a3e946 100644 --- a/compiler/rustc_target/src/spec/targets/riscv32_wrs_vxworks.rs +++ b/compiler/rustc_target/src/spec/targets/riscv32_wrs_vxworks.rs @@ -7,7 +7,7 @@ pub(crate) fn target() -> Target { description: None, tier: Some(3), host_tools: Some(false), - std: None, // STD is a work in progress for this target arch + std: Some(true), }, pointer_width: 32, data_layout: "e-m:e-p:32:32-i64:64-n32-S128".into(), diff --git a/compiler/rustc_target/src/spec/targets/riscv64_wrs_vxworks.rs b/compiler/rustc_target/src/spec/targets/riscv64_wrs_vxworks.rs index b0914871a64..5cddce29aa0 100644 --- a/compiler/rustc_target/src/spec/targets/riscv64_wrs_vxworks.rs +++ b/compiler/rustc_target/src/spec/targets/riscv64_wrs_vxworks.rs @@ -7,7 +7,7 @@ pub(crate) fn target() -> Target { description: None, tier: Some(3), host_tools: Some(false), - std: None, // STD is a work in progress for this target arch + std: Some(true), }, pointer_width: 64, data_layout: "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128".into(), diff --git a/compiler/rustc_target/src/spec/targets/x86_64_wrs_vxworks.rs b/compiler/rustc_target/src/spec/targets/x86_64_wrs_vxworks.rs index 604f71ffaa6..45571540268 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_wrs_vxworks.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_wrs_vxworks.rs @@ -15,7 +15,7 @@ pub(crate) fn target() -> Target { description: None, tier: Some(3), host_tools: Some(false), - std: None, // ? + std: Some(true), }, pointer_width: 64, data_layout: diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index 76b7dad8f18..1bed02ad48b 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -358,14 +358,14 @@ target | std | host | notes [`riscv32imc-esp-espidf`](platform-support/esp-idf.md) | ✓ | | RISC-V ESP-IDF [`riscv32imac-esp-espidf`](platform-support/esp-idf.md) | ✓ | | RISC-V ESP-IDF [`riscv32imafc-esp-espidf`](platform-support/esp-idf.md) | ✓ | | RISC-V ESP-IDF -[`riscv32-wrs-vxworks`](platform-support/vxworks.md) | ? | | +[`riscv32-wrs-vxworks`](platform-support/vxworks.md) | ✓ | | [`riscv64gc-unknown-hermit`](platform-support/hermit.md) | ✓ | | RISC-V Hermit `riscv64gc-unknown-freebsd` | | | RISC-V FreeBSD `riscv64gc-unknown-fuchsia` | | | RISC-V Fuchsia [`riscv64gc-unknown-netbsd`](platform-support/netbsd.md) | ✓ | ✓ | RISC-V NetBSD [`riscv64gc-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | OpenBSD/riscv64 [`riscv64-linux-android`](platform-support/android.md) | | | RISC-V 64-bit Android -[`riscv64-wrs-vxworks`](platform-support/vxworks.md) | ? | | +[`riscv64-wrs-vxworks`](platform-support/vxworks.md) | ✓ | | `s390x-unknown-linux-musl` | | | S390x Linux (kernel 3.2, musl 1.2.3) `sparc-unknown-linux-gnu` | ✓ | | 32-bit SPARC Linux [`sparc-unknown-none-elf`](./platform-support/sparc-unknown-none-elf.md) | * | | Bare 32-bit SPARC V7+ From 4957eda2c17ff43d52ece67b118ec304e5c41f11 Mon Sep 17 00:00:00 2001 From: B I Mohammed Abbas Date: Fri, 20 Sep 2024 17:26:42 +0530 Subject: [PATCH 174/683] Allow unused unsafe for vxworks in alligned_malloc to resolve build errors --- library/std/src/sys/alloc/unix.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/std/src/sys/alloc/unix.rs b/library/std/src/sys/alloc/unix.rs index 46ed7de7162..dfce50aec13 100644 --- a/library/std/src/sys/alloc/unix.rs +++ b/library/std/src/sys/alloc/unix.rs @@ -71,6 +71,7 @@ cfg_if::cfg_if! { } } else { #[inline] + #[cfg_attr(target_os = "vxworks", allow(unused_unsafe))] unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 { let mut out = ptr::null_mut(); // We prefer posix_memalign over aligned_alloc since it is more widely available, and From fa125e2be682e22cf0c2a005a08d7fef2520cefa Mon Sep 17 00:00:00 2001 From: Taiki Endo Date: Sat, 21 Sep 2024 01:51:26 +0900 Subject: [PATCH 175/683] Support clobber_abi and vector/access registers (clobber-only) in s390x inline assembly --- compiler/rustc_codegen_gcc/src/asm.rs | 8 ++ compiler/rustc_codegen_llvm/src/asm.rs | 6 + compiler/rustc_span/src/symbol.rs | 1 + compiler/rustc_target/src/asm/mod.rs | 29 ++++- compiler/rustc_target/src/asm/s390x.rs | 111 ++++++++++++++++-- .../asm-experimental-arch.md | 7 ++ tests/codegen/asm-s390x-clobbers.rs | 50 ++++++++ 7 files changed, 200 insertions(+), 12 deletions(-) create mode 100644 tests/codegen/asm-s390x-clobbers.rs diff --git a/compiler/rustc_codegen_gcc/src/asm.rs b/compiler/rustc_codegen_gcc/src/asm.rs index 13a00f7e08d..a04cd4735f4 100644 --- a/compiler/rustc_codegen_gcc/src/asm.rs +++ b/compiler/rustc_codegen_gcc/src/asm.rs @@ -682,6 +682,11 @@ fn reg_to_gcc(reg: InlineAsmRegOrRegClass) -> ConstraintOrRegister { InlineAsmRegClass::S390x(S390xInlineAsmRegClass::reg) => "r", InlineAsmRegClass::S390x(S390xInlineAsmRegClass::reg_addr) => "a", InlineAsmRegClass::S390x(S390xInlineAsmRegClass::freg) => "f", + InlineAsmRegClass::S390x( + S390xInlineAsmRegClass::vreg | S390xInlineAsmRegClass::areg, + ) => { + unreachable!("clobber-only") + } InlineAsmRegClass::Err => unreachable!(), }, }; @@ -757,6 +762,9 @@ fn dummy_output_type<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, reg: InlineAsmRegCl S390xInlineAsmRegClass::reg | S390xInlineAsmRegClass::reg_addr, ) => cx.type_i32(), InlineAsmRegClass::S390x(S390xInlineAsmRegClass::freg) => cx.type_f64(), + InlineAsmRegClass::S390x(S390xInlineAsmRegClass::vreg | S390xInlineAsmRegClass::areg) => { + unreachable!("clobber-only") + } InlineAsmRegClass::Msp430(Msp430InlineAsmRegClass::reg) => cx.type_i16(), InlineAsmRegClass::M68k(M68kInlineAsmRegClass::reg) => cx.type_i32(), InlineAsmRegClass::M68k(M68kInlineAsmRegClass::reg_addr) => cx.type_i32(), diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs index 430ba735243..27f6481c536 100644 --- a/compiler/rustc_codegen_llvm/src/asm.rs +++ b/compiler/rustc_codegen_llvm/src/asm.rs @@ -703,6 +703,9 @@ fn reg_to_llvm(reg: InlineAsmRegOrRegClass, layout: Option<&TyAndLayout<'_>>) -> S390x(S390xInlineAsmRegClass::reg) => "r", S390x(S390xInlineAsmRegClass::reg_addr) => "a", S390x(S390xInlineAsmRegClass::freg) => "f", + S390x(S390xInlineAsmRegClass::vreg | S390xInlineAsmRegClass::areg) => { + unreachable!("clobber-only") + } Msp430(Msp430InlineAsmRegClass::reg) => "r", M68k(M68kInlineAsmRegClass::reg) => "r", M68k(M68kInlineAsmRegClass::reg_addr) => "a", @@ -861,6 +864,9 @@ fn dummy_output_type<'ll>(cx: &CodegenCx<'ll, '_>, reg: InlineAsmRegClass) -> &' Avr(AvrInlineAsmRegClass::reg_ptr) => cx.type_i16(), S390x(S390xInlineAsmRegClass::reg | S390xInlineAsmRegClass::reg_addr) => cx.type_i32(), S390x(S390xInlineAsmRegClass::freg) => cx.type_f64(), + S390x(S390xInlineAsmRegClass::vreg | S390xInlineAsmRegClass::areg) => { + unreachable!("clobber-only") + } Msp430(Msp430InlineAsmRegClass::reg) => cx.type_i16(), M68k(M68kInlineAsmRegClass::reg) => cx.type_i32(), M68k(M68kInlineAsmRegClass::reg_addr) => cx.type_i32(), diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 402232a1720..e2d965ff91b 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -410,6 +410,7 @@ symbols! { arbitrary_enum_discriminant, arbitrary_self_types, arbitrary_self_types_pointers, + areg, args, arith_offset, arm, diff --git a/compiler/rustc_target/src/asm/mod.rs b/compiler/rustc_target/src/asm/mod.rs index 4d8c5cea8a8..df13d24cb9e 100644 --- a/compiler/rustc_target/src/asm/mod.rs +++ b/compiler/rustc_target/src/asm/mod.rs @@ -439,7 +439,7 @@ impl InlineAsmReg { Self::Hexagon(r) => r.overlapping_regs(|r| cb(Self::Hexagon(r))), Self::LoongArch(_) => cb(self), Self::Mips(_) => cb(self), - Self::S390x(_) => cb(self), + Self::S390x(r) => r.overlapping_regs(|r| cb(Self::S390x(r))), Self::Bpf(r) => r.overlapping_regs(|r| cb(Self::Bpf(r))), Self::Avr(r) => r.overlapping_regs(|r| cb(Self::Avr(r))), Self::Msp430(_) => cb(self), @@ -892,6 +892,7 @@ pub enum InlineAsmClobberAbi { AArch64NoX18, RiscV, LoongArch, + S390x, } impl InlineAsmClobberAbi { @@ -941,6 +942,10 @@ impl InlineAsmClobberAbi { "C" | "system" => Ok(InlineAsmClobberAbi::LoongArch), _ => Err(&["C", "system"]), }, + InlineAsmArch::S390x => match name { + "C" | "system" => Ok(InlineAsmClobberAbi::S390x), + _ => Err(&["C", "system"]), + }, _ => Err(&[]), } } @@ -1098,6 +1103,28 @@ impl InlineAsmClobberAbi { f16, f17, f18, f19, f20, f21, f22, f23, } }, + InlineAsmClobberAbi::S390x => clobbered_regs! { + S390x S390xInlineAsmReg { + r0, r1, r2, r3, r4, r5, + r14, + + // f0-f7, v0-v7 + f0, f1, f2, f3, f4, f5, f6, f7, + v0, v1, v2, v3, v4, v5, v6, v7, + + // Technically the left halves of v8-v15 (i.e., f8-f15) are saved, but + // we have no way of expressing this using clobbers. + v8, v9, v10, v11, v12, v13, v14, v15, + + // Other vector registers are volatile + v16, v17, v18, v19, v20, v21, v22, v23, + v24, v25, v26, v27, v28, v29, v30, v31, + + // a0-a1 are reserved, other access registers are volatile + a2, a3, a4, a5, a6, a7, + a8, a9, a10, a11, a12, a13, a14, a15, + } + }, } } } diff --git a/compiler/rustc_target/src/asm/s390x.rs b/compiler/rustc_target/src/asm/s390x.rs index 4258b23ac57..9b31190a72b 100644 --- a/compiler/rustc_target/src/asm/s390x.rs +++ b/compiler/rustc_target/src/asm/s390x.rs @@ -9,6 +9,8 @@ def_reg_class! { reg, reg_addr, freg, + vreg, + areg, } } @@ -35,11 +37,13 @@ impl S390xInlineAsmRegClass { pub fn supported_types( self, - arch: InlineAsmArch, + _arch: InlineAsmArch, ) -> &'static [(InlineAsmType, Option)] { - match (self, arch) { - (Self::reg | Self::reg_addr, _) => types! { _: I8, I16, I32, I64; }, - (Self::freg, _) => types! { _: F32, F64; }, + match self { + Self::reg | Self::reg_addr => types! { _: I8, I16, I32, I64; }, + Self::freg => types! { _: F32, F64; }, + Self::vreg => &[], + Self::areg => &[], } } } @@ -76,6 +80,52 @@ def_regs! { f13: freg = ["f13"], f14: freg = ["f14"], f15: freg = ["f15"], + v0: vreg = ["v0"], + v1: vreg = ["v1"], + v2: vreg = ["v2"], + v3: vreg = ["v3"], + v4: vreg = ["v4"], + v5: vreg = ["v5"], + v6: vreg = ["v6"], + v7: vreg = ["v7"], + v8: vreg = ["v8"], + v9: vreg = ["v9"], + v10: vreg = ["v10"], + v11: vreg = ["v11"], + v12: vreg = ["v12"], + v13: vreg = ["v13"], + v14: vreg = ["v14"], + v15: vreg = ["v15"], + v16: vreg = ["v16"], + v17: vreg = ["v17"], + v18: vreg = ["v18"], + v19: vreg = ["v19"], + v20: vreg = ["v20"], + v21: vreg = ["v21"], + v22: vreg = ["v22"], + v23: vreg = ["v23"], + v24: vreg = ["v24"], + v25: vreg = ["v25"], + v26: vreg = ["v26"], + v27: vreg = ["v27"], + v28: vreg = ["v28"], + v29: vreg = ["v29"], + v30: vreg = ["v30"], + v31: vreg = ["v31"], + a2: areg = ["a2"], + a3: areg = ["a3"], + a4: areg = ["a4"], + a5: areg = ["a5"], + a6: areg = ["a6"], + a7: areg = ["a7"], + a8: areg = ["a8"], + a9: areg = ["a9"], + a10: areg = ["a10"], + a11: areg = ["a11"], + a12: areg = ["a12"], + a13: areg = ["a13"], + a14: areg = ["a14"], + a15: areg = ["a15"], #error = ["r11"] => "The frame pointer cannot be used as an operand for inline asm", #error = ["r15"] => @@ -87,13 +137,8 @@ def_regs! { "c12", "c13", "c14", "c15" ] => "control registers are reserved by the kernel and cannot be used as operands for inline asm", - #error = [ - "a0", "a1", "a2", "a3", - "a4", "a5", "a6", "a7", - "a8", "a9", "a10", "a11", - "a12", "a13", "a14", "a15" - ] => - "access registers are not supported and cannot be used as operands for inline asm", + #error = ["a0", "a1"] => + "a0 and a1 are reserved for system use and cannot be used as operands for inline asm", } } @@ -106,4 +151,48 @@ impl S390xInlineAsmReg { ) -> fmt::Result { write!(out, "%{}", self.name()) } + + pub fn overlapping_regs(self, mut cb: impl FnMut(S390xInlineAsmReg)) { + macro_rules! reg_conflicts { + ( + $( + $full:ident : $($field:ident)* + ),*; + ) => { + match self { + $( + Self::$full => { + cb(Self::$full); + $(cb(Self::$field);)* + } + $(Self::$field)|* => { + cb(Self::$full); + cb(self); + } + )* + r => cb(r), + } + }; + } + + // The left halves of v0-v15 are aliased to f0-f15. + reg_conflicts! { + v0 : f0, + v1 : f1, + v2 : f2, + v3 : f3, + v4 : f4, + v5 : f5, + v6 : f6, + v7 : f7, + v8 : f8, + v9 : f9, + v10 : f10, + v11 : f11, + v12 : f12, + v13 : f13, + v14 : f14, + v15 : f15; + } + } } diff --git a/src/doc/unstable-book/src/language-features/asm-experimental-arch.md b/src/doc/unstable-book/src/language-features/asm-experimental-arch.md index 43e11b6d57d..b1c429c7676 100644 --- a/src/doc/unstable-book/src/language-features/asm-experimental-arch.md +++ b/src/doc/unstable-book/src/language-features/asm-experimental-arch.md @@ -51,7 +51,10 @@ This feature tracks `asm!` and `global_asm!` support for the following architect | CSKY | `reg` | `r[0-31]` | `r` | | CSKY | `freg` | `f[0-31]` | `f` | | s390x | `reg` | `r[0-10]`, `r[12-14]` | `r` | +| s390x | `reg_addr` | `r[1-10]`, `r[12-14]` | `a` | | s390x | `freg` | `f[0-15]` | `f` | +| s390x | `vreg` | `v[0-31]` | Only clobbers | +| s390x | `areg` | `a[2-15]` | Only clobbers | | Arm64EC | `reg` | `x[0-12]`, `x[15-22]`, `x[25-27]`, `x30` | `r` | | Arm64EC | `vreg` | `v[0-15]` | `w` | | Arm64EC | `vreg_low16` | `v[0-15]` | `x` | @@ -90,6 +93,8 @@ This feature tracks `asm!` and `global_asm!` support for the following architect | CSKY | `freg` | None | `f32`, | | s390x | `reg`, `reg_addr` | None | `i8`, `i16`, `i32`, `i64` | | s390x | `freg` | None | `f32`, `f64` | +| s390x | `vreg` | N/A | Only clobbers | +| s390x | `areg` | N/A | Only clobbers | | Arm64EC | `reg` | None | `i8`, `i16`, `i32`, `f32`, `i64`, `f64` | | Arm64EC | `vreg` | None | `i8`, `i16`, `i32`, `f32`, `i64`, `f64`,
`i8x8`, `i16x4`, `i32x2`, `i64x1`, `f32x2`, `f64x1`,
`i8x16`, `i16x8`, `i32x4`, `i64x2`, `f32x4`, `f64x2` | @@ -157,6 +162,8 @@ This feature tracks `asm!` and `global_asm!` support for the following architect | CSKY | `r15` | This is the link register. | | CSKY | `r[26-30]` | Reserved by its ABI. | | CSKY | `r31` | This is the TLS register. | +| s390x | `c[0-15]` | Reserved by the kernel. | +| s390x | `a[0-1]` | Reserved for system use. | | Arm64EC | `xzr` | This is a constant zero register which can't be modified. | | Arm64EC | `x18` | This is an OS-reserved register. | | Arm64EC | `x13`, `x14`, `x23`, `x24`, `x28`, `v[16-31]` | These are AArch64 registers that are not supported for Arm64EC. | diff --git a/tests/codegen/asm-s390x-clobbers.rs b/tests/codegen/asm-s390x-clobbers.rs new file mode 100644 index 00000000000..45f72206bdf --- /dev/null +++ b/tests/codegen/asm-s390x-clobbers.rs @@ -0,0 +1,50 @@ +//@ revisions: s390x +//@[s390x] compile-flags: --target s390x-unknown-linux-gnu +//@[s390x] needs-llvm-components: systemz + +#![crate_type = "rlib"] +#![feature(no_core, rustc_attrs, lang_items, asm_experimental_arch)] +#![no_core] + +#[lang = "sized"] +trait Sized {} + +#[rustc_builtin_macro] +macro_rules! asm { + () => {}; +} + +// CHECK-LABEL: @cc_clobber +// CHECK: call void asm sideeffect "", "~{cc}"() +#[no_mangle] +pub unsafe fn cc_clobber() { + asm!("", options(nostack, nomem)); +} + +// CHECK-LABEL: @no_clobber +// CHECK: call void asm sideeffect "", ""() +#[no_mangle] +pub unsafe fn no_clobber() { + asm!("", options(nostack, nomem, preserves_flags)); +} + +// CHECK-LABEL: @a2_clobber +// CHECK: call void asm sideeffect "", "~{a2}"() +#[no_mangle] +pub unsafe fn a2_clobber() { + asm!("", out("a2") _, options(nostack, nomem, preserves_flags)); +} + +// CHECK-LABEL: @v0_clobber +// CHECK: call void asm sideeffect "", "~{v0}"() +#[no_mangle] +pub unsafe fn v0_clobber() { + asm!("", out("v0") _, options(nostack, nomem, preserves_flags)); +} + +// CHECK-LABEL: @clobber_abi +// CHECK: asm sideeffect "", "={r0},={r1},={r2},={r3},={r4},={r5},={r14},={f0},={f1},={f2},={f3},={f4},={f5},={f6},={f7},~{v0},~{v1},~{v2},~{v3},~{v4},~{v5},~{v6},~{v7},~{v8},~{v9},~{v10},~{v11},~{v12},~{v13},~{v14},~{v15},~{v16},~{v17},~{v18},~{v19},~{v20},~{v21},~{v22},~{v23},~{v24},~{v25},~{v26},~{v27},~{v28},~{v29},~{v30},~{v31},~{a2},~{a3},~{a4},~{a5},~{a6},~{a7},~{a8},~{a9},~{a10},~{a11},~{a12},~{a13},~{a14},~{a15}"() +#[no_mangle] +pub unsafe fn clobber_abi() { + asm!("", clobber_abi("C"), options(nostack, nomem, preserves_flags)); +} From 05ebce8e1a973907db7d3e89e4738a095c250371 Mon Sep 17 00:00:00 2001 From: Ruairidh Williamson Date: Sat, 21 Sep 2024 00:54:20 +0100 Subject: [PATCH 176/683] Add lint unused_trait_names --- CHANGELOG.md | 1 + book/src/lint_configuration.md | 1 + clippy_config/src/conf.rs | 1 + clippy_config/src/msrvs.rs | 1 + clippy_lints/src/declared_lints.rs | 1 + clippy_lints/src/lib.rs | 2 + clippy_lints/src/unused_trait_names.rs | 94 ++++++++++++++++++++++++++ 7 files changed, 101 insertions(+) create mode 100644 clippy_lints/src/unused_trait_names.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index 6e0aaa25a7c..41a86e8ce51 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6063,6 +6063,7 @@ Released 2018-09-13 [`unused_result_ok`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_result_ok [`unused_rounding`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_rounding [`unused_self`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_self +[`unused_trait_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_trait_names [`unused_unit`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_unit [`unusual_byte_groupings`]: https://rust-lang.github.io/rust-clippy/master/index.html#unusual_byte_groupings [`unwrap_in_result`]: https://rust-lang.github.io/rust-clippy/master/index.html#unwrap_in_result diff --git a/book/src/lint_configuration.md b/book/src/lint_configuration.md index 78348797588..91159bc79c5 100644 --- a/book/src/lint_configuration.md +++ b/book/src/lint_configuration.md @@ -727,6 +727,7 @@ The minimum rust version that the project supports. Defaults to the `rust-versio * [`uninlined_format_args`](https://rust-lang.github.io/rust-clippy/master/index.html#uninlined_format_args) * [`unnecessary_lazy_evaluations`](https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_lazy_evaluations) * [`unnested_or_patterns`](https://rust-lang.github.io/rust-clippy/master/index.html#unnested_or_patterns) +* [`unused_trait_names`](https://rust-lang.github.io/rust-clippy/master/index.html#unused_trait_names) * [`use_self`](https://rust-lang.github.io/rust-clippy/master/index.html#use_self) diff --git a/clippy_config/src/conf.rs b/clippy_config/src/conf.rs index 6c1dd232593..1765cf87d48 100644 --- a/clippy_config/src/conf.rs +++ b/clippy_config/src/conf.rs @@ -563,6 +563,7 @@ define_Conf! { uninlined_format_args, unnecessary_lazy_evaluations, unnested_or_patterns, + unused_trait_names, use_self, )] msrv: Msrv = Msrv::empty(), diff --git a/clippy_config/src/msrvs.rs b/clippy_config/src/msrvs.rs index a70effd6376..a6cba849922 100644 --- a/clippy_config/src/msrvs.rs +++ b/clippy_config/src/msrvs.rs @@ -49,6 +49,7 @@ msrv_aliases! { 1,36,0 { ITERATOR_COPIED } 1,35,0 { OPTION_COPIED, RANGE_CONTAINS } 1,34,0 { TRY_FROM } + 1,33,0 { UNDERSCORE_IMPORTS } 1,30,0 { ITERATOR_FIND_MAP, TOOL_ATTRIBUTES } 1,29,0 { ITER_FLATTEN } 1,28,0 { FROM_BOOL } diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index 824f57cece9..2b229d2fe6a 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -748,6 +748,7 @@ pub static LINTS: &[&crate::LintInfo] = &[ crate::unused_result_ok::UNUSED_RESULT_OK_INFO, crate::unused_rounding::UNUSED_ROUNDING_INFO, crate::unused_self::UNUSED_SELF_INFO, + crate::unused_trait_names::UNUSED_TRAIT_NAMES_INFO, crate::unused_unit::UNUSED_UNIT_INFO, crate::unwrap::PANICKING_UNWRAP_INFO, crate::unwrap::UNNECESSARY_UNWRAP_INFO, diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 3604090b68c..b21d3f8d09e 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -376,6 +376,7 @@ mod unused_peekable; mod unused_result_ok; mod unused_rounding; mod unused_self; +mod unused_trait_names; mod unused_unit; mod unwrap; mod unwrap_in_result; @@ -942,5 +943,6 @@ 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(move |_| Box::new(unused_trait_names::UnusedTraitNames::new(conf))); // add lints here, do not remove this comment, it's used in `new_lint` } diff --git a/clippy_lints/src/unused_trait_names.rs b/clippy_lints/src/unused_trait_names.rs new file mode 100644 index 00000000000..c1cf58dcfce --- /dev/null +++ b/clippy_lints/src/unused_trait_names.rs @@ -0,0 +1,94 @@ +use clippy_config::msrvs::{self, Msrv}; +use clippy_config::Conf; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::is_from_proc_macro; +use clippy_utils::source::snippet_opt; +use rustc_errors::Applicability; +use rustc_hir::def::{DefKind, Res}; +use rustc_hir::{Item, ItemKind, UseKind}; +use rustc_lint::{LateContext, LateLintPass, LintContext as _}; +use rustc_middle::lint::in_external_macro; +use rustc_middle::ty::Visibility; +use rustc_session::impl_lint_pass; +use rustc_span::symbol::kw; + +declare_clippy_lint! { + /// ### What it does + /// Checks for `use Trait` where the Trait is only used for its methods and not referenced by a path directly. + /// + /// ### Why is this bad? + /// Traits imported that aren't used directly can be imported anonymously with `use Trait as _`. + /// It is more explicit, avoids polluting the current scope with unused names and can be useful to show which imports are required for traits. + /// + /// ### Example + /// ```no_run + /// use std::fmt::Write; + /// + /// fn main() { + /// let mut s = String::new(); + /// let _ = write!(s, "hello, world!"); + /// println!("{s}"); + /// } + /// ``` + /// Use instead: + /// ```no_run + /// use std::fmt::Write as _; + /// + /// fn main() { + /// let mut s = String::new(); + /// let _ = write!(s, "hello, world!"); + /// println!("{s}"); + /// } + /// ``` + #[clippy::version = "1.83.0"] + pub UNUSED_TRAIT_NAMES, + restriction, + "use items that import a trait but only use it anonymously" +} + +pub struct UnusedTraitNames { + msrv: Msrv, +} + +impl UnusedTraitNames { + pub fn new(conf: &'static Conf) -> Self { + Self { + msrv: conf.msrv.clone(), + } + } +} + +impl_lint_pass!(UnusedTraitNames => [UNUSED_TRAIT_NAMES]); + +impl<'tcx> LateLintPass<'tcx> for UnusedTraitNames { + fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) { + if self.msrv.meets(msrvs::UNDERSCORE_IMPORTS) + && !in_external_macro(cx.sess(), item.span) + && let ItemKind::Use(path, UseKind::Single) = item.kind + // Ignore imports that already use Underscore + && item.ident.name != kw::Underscore + // Only check traits + && let Some(Res::Def(DefKind::Trait, _)) = path.res.first() + && cx.tcx.maybe_unused_trait_imports(()).contains(&item.owner_id.def_id) + // Only check this import if it is visible to its module only (no pub, pub(crate), ...) + && let module = cx.tcx.parent_module_from_def_id(item.owner_id.def_id) + && cx.tcx.visibility(item.owner_id.def_id) == Visibility::Restricted(module.to_def_id()) + && let Some(last_segment) = path.segments.last() + && let Some(snip) = snippet_opt(cx, last_segment.ident.span) + && !is_from_proc_macro(cx, &last_segment.ident) + { + let complete_span = last_segment.ident.span.to(item.ident.span); + span_lint_and_sugg( + cx, + UNUSED_TRAIT_NAMES, + complete_span, + "importing trait that is only used anonymously", + "use", + format!("{snip} as _"), + Applicability::MachineApplicable, + ); + } + } + + extract_msrv_attr!(LateContext); +} From 739ef7bf0d5686ef10e7700f34e34995936e00ff Mon Sep 17 00:00:00 2001 From: Ruairidh Williamson Date: Sat, 21 Sep 2024 00:54:56 +0100 Subject: [PATCH 177/683] Add unused_trait_names tests --- clippy_lints/src/attrs/useless_attribute.rs | 1 + tests/ui/unused_trait_names.fixed | 286 ++++++++++++++++++++ tests/ui/unused_trait_names.rs | 286 ++++++++++++++++++++ tests/ui/unused_trait_names.stderr | 73 +++++ 4 files changed, 646 insertions(+) create mode 100644 tests/ui/unused_trait_names.fixed create mode 100644 tests/ui/unused_trait_names.rs create mode 100644 tests/ui/unused_trait_names.stderr diff --git a/clippy_lints/src/attrs/useless_attribute.rs b/clippy_lints/src/attrs/useless_attribute.rs index 67ba605a59f..1296b59f2e1 100644 --- a/clippy_lints/src/attrs/useless_attribute.rs +++ b/clippy_lints/src/attrs/useless_attribute.rs @@ -51,6 +51,7 @@ pub(super) fn check(cx: &LateContext<'_>, item: &Item<'_>, attrs: &[Attribute]) | "module_name_repetitions" | "single_component_path_imports" | "disallowed_types" + | "unused_trait_names" ) }) { return; diff --git a/tests/ui/unused_trait_names.fixed b/tests/ui/unused_trait_names.fixed new file mode 100644 index 00000000000..7dfd0db65aa --- /dev/null +++ b/tests/ui/unused_trait_names.fixed @@ -0,0 +1,286 @@ +//@aux-build:proc_macros.rs + +#![allow(unused)] +#![warn(clippy::unused_trait_names)] +#![feature(decl_macro)] + +extern crate proc_macros; + +fn main() {} + +fn bad() { + use std::any::Any as _; + + println!("{:?}", "foo".type_id()); +} + +fn good() { + use std::any::Any as _; + + println!("{:?}", "foo".type_id()); +} + +fn used_good() { + use std::any::Any; + + println!("{:?}", Any::type_id("foo")); + println!("{:?}", "foo".type_id()); +} + +fn multi_bad() { + use std::any::{self, Any as _, TypeId}; + + println!("{:?}", "foo".type_id()); +} + +fn multi_good() { + use std::any::{self, Any as _, TypeId}; + + println!("{:?}", "foo".type_id()); +} + +fn renamed_bad() { + use std::any::Any as _; + + println!("{:?}", "foo".type_id()); +} + +fn multi_renamed_bad() { + use std::any::{Any as _, TypeId as MyTypeId}; + + println!("{:?}", "foo".type_id()); +} + +mod pub_good { + pub use std::any::Any; + + fn foo() { + println!("{:?}", "foo".type_id()); + } +} + +mod used_mod_good { + use std::any::Any; + + fn foo() { + println!("{:?}", Any::type_id("foo")); + } +} + +mod mod_import_bad { + fn mod_import_bad() { + use std::any::Any as _; + + println!("{:?}", "foo".type_id()); + } +} + +mod nested_mod_used_good1 { + use std::any::Any; + + mod foo { + fn foo() { + super::Any::type_id("foo"); + } + } +} + +mod nested_mod_used_good2 { + use std::any::Any; + + mod foo { + use super::Any; + + fn foo() { + Any::type_id("foo"); + } + } +} + +mod nested_mod_used_good3 { + use std::any::Any; + + mod foo { + use crate::nested_mod_used_good3::Any; + + fn foo() { + println!("{:?}", Any::type_id("foo")); + } + } +} + +mod nested_mod_used_bad { + use std::any::Any as _; + + fn bar() { + println!("{:?}", "foo".type_id()); + } + + mod foo { + use std::any::Any; + + fn foo() { + println!("{:?}", Any::type_id("foo")); + } + } +} + +// More complex example where `use std::any::Any;` should be anonymised but `use std::any::Any as +// MyAny;` should not as it is used by a sub module. Even though if you removed `use std::any::Any;` +// the code would still compile. +mod nested_mod_used_bad1 { + use std::any::Any as _; + + use std::any::Any as MyAny; + + fn baz() { + println!("{:?}", "baz".type_id()); + } + + mod foo { + use crate::nested_mod_used_bad1::MyAny; + + fn foo() { + println!("{:?}", MyAny::type_id("foo")); + } + } +} + +// Example of nested import with an unused import to try and trick it +mod nested_mod_used_good5 { + use std::any::Any; + + mod foo { + use std::any::Any; + + fn baz() { + println!("{:?}", "baz".type_id()); + } + + mod bar { + use crate::nested_mod_used_good5::foo::Any; + + fn foo() { + println!("{:?}", Any::type_id("foo")); + } + } + } +} + +mod simple_trait { + pub trait MyTrait { + fn do_things(&self); + } + + pub struct MyStruct; + + impl MyTrait for MyStruct { + fn do_things(&self) {} + } +} + +// Underscore imports were stabilized in 1.33 +#[clippy::msrv = "1.32"] +fn msrv_1_32() { + use simple_trait::{MyStruct, MyTrait}; + MyStruct.do_things(); +} + +#[clippy::msrv = "1.33"] +fn msrv_1_33() { + use simple_trait::{MyStruct, MyTrait as _}; + MyStruct.do_things(); +} + +mod lint_inside_macro_expansion_bad { + macro_rules! foo { + () => { + use std::any::Any as _; + fn bar() { + "bar".type_id(); + } + }; + } + + foo!(); +} + +mod macro_and_trait_same_name { + pub macro Foo() {} + pub trait Foo { + fn bar(&self); + } + impl Foo for () { + fn bar(&self) {} + } +} + +fn call_macro_and_trait_good() { + // importing trait and macro but only using macro by path won't allow us to change this to + // `use macro_and_trait_same_name::Foo as _;` + use macro_and_trait_same_name::Foo; + Foo!(); + ().bar(); +} + +proc_macros::external!( + fn ignore_inside_external_proc_macro() { + use std::any::Any; + "foo".type_id(); + } +); + +proc_macros::with_span!( + span + + fn ignore_inside_with_span_proc_macro() { + use std::any::Any; + "foo".type_id(); + } +); + +// This should warn the import is unused but should not trigger unused_trait_names +#[warn(unused)] +mod unused_import { + +} + +#[allow(clippy::unused_trait_names)] +fn allow_lint_fn() { + use std::any::Any; + + "foo".type_id(); +} + +#[allow(clippy::unused_trait_names)] +mod allow_lint_mod { + use std::any::Any; + + fn foo() { + "foo".type_id(); + } +} + +mod allow_lint_import { + #[allow(clippy::unused_trait_names)] + use std::any::Any; + + fn foo() { + "foo".type_id(); + } +} + +// Limitation: Suggests `use std::any::Any as _::{self};` which looks weird +// fn use_trait_self_good() { +// use std::any::Any::{self}; +// "foo".type_id(); +// } + +// Limitation: Suggests `use std::any::{Any as _, Any as _};` +// mod repeated_renamed { +// use std::any::{Any, Any as MyAny}; + +// fn foo() { +// "foo".type_id(); +// } +// } diff --git a/tests/ui/unused_trait_names.rs b/tests/ui/unused_trait_names.rs new file mode 100644 index 00000000000..ce44eedbc79 --- /dev/null +++ b/tests/ui/unused_trait_names.rs @@ -0,0 +1,286 @@ +//@aux-build:proc_macros.rs + +#![allow(unused)] +#![warn(clippy::unused_trait_names)] +#![feature(decl_macro)] + +extern crate proc_macros; + +fn main() {} + +fn bad() { + use std::any::Any; + + println!("{:?}", "foo".type_id()); +} + +fn good() { + use std::any::Any as _; + + println!("{:?}", "foo".type_id()); +} + +fn used_good() { + use std::any::Any; + + println!("{:?}", Any::type_id("foo")); + println!("{:?}", "foo".type_id()); +} + +fn multi_bad() { + use std::any::{self, Any, TypeId}; + + println!("{:?}", "foo".type_id()); +} + +fn multi_good() { + use std::any::{self, Any as _, TypeId}; + + println!("{:?}", "foo".type_id()); +} + +fn renamed_bad() { + use std::any::Any as MyAny; + + println!("{:?}", "foo".type_id()); +} + +fn multi_renamed_bad() { + use std::any::{Any as MyAny, TypeId as MyTypeId}; + + println!("{:?}", "foo".type_id()); +} + +mod pub_good { + pub use std::any::Any; + + fn foo() { + println!("{:?}", "foo".type_id()); + } +} + +mod used_mod_good { + use std::any::Any; + + fn foo() { + println!("{:?}", Any::type_id("foo")); + } +} + +mod mod_import_bad { + fn mod_import_bad() { + use std::any::Any; + + println!("{:?}", "foo".type_id()); + } +} + +mod nested_mod_used_good1 { + use std::any::Any; + + mod foo { + fn foo() { + super::Any::type_id("foo"); + } + } +} + +mod nested_mod_used_good2 { + use std::any::Any; + + mod foo { + use super::Any; + + fn foo() { + Any::type_id("foo"); + } + } +} + +mod nested_mod_used_good3 { + use std::any::Any; + + mod foo { + use crate::nested_mod_used_good3::Any; + + fn foo() { + println!("{:?}", Any::type_id("foo")); + } + } +} + +mod nested_mod_used_bad { + use std::any::Any; + + fn bar() { + println!("{:?}", "foo".type_id()); + } + + mod foo { + use std::any::Any; + + fn foo() { + println!("{:?}", Any::type_id("foo")); + } + } +} + +// More complex example where `use std::any::Any;` should be anonymised but `use std::any::Any as +// MyAny;` should not as it is used by a sub module. Even though if you removed `use std::any::Any;` +// the code would still compile. +mod nested_mod_used_bad1 { + use std::any::Any; + + use std::any::Any as MyAny; + + fn baz() { + println!("{:?}", "baz".type_id()); + } + + mod foo { + use crate::nested_mod_used_bad1::MyAny; + + fn foo() { + println!("{:?}", MyAny::type_id("foo")); + } + } +} + +// Example of nested import with an unused import to try and trick it +mod nested_mod_used_good5 { + use std::any::Any; + + mod foo { + use std::any::Any; + + fn baz() { + println!("{:?}", "baz".type_id()); + } + + mod bar { + use crate::nested_mod_used_good5::foo::Any; + + fn foo() { + println!("{:?}", Any::type_id("foo")); + } + } + } +} + +mod simple_trait { + pub trait MyTrait { + fn do_things(&self); + } + + pub struct MyStruct; + + impl MyTrait for MyStruct { + fn do_things(&self) {} + } +} + +// Underscore imports were stabilized in 1.33 +#[clippy::msrv = "1.32"] +fn msrv_1_32() { + use simple_trait::{MyStruct, MyTrait}; + MyStruct.do_things(); +} + +#[clippy::msrv = "1.33"] +fn msrv_1_33() { + use simple_trait::{MyStruct, MyTrait}; + MyStruct.do_things(); +} + +mod lint_inside_macro_expansion_bad { + macro_rules! foo { + () => { + use std::any::Any; + fn bar() { + "bar".type_id(); + } + }; + } + + foo!(); +} + +mod macro_and_trait_same_name { + pub macro Foo() {} + pub trait Foo { + fn bar(&self); + } + impl Foo for () { + fn bar(&self) {} + } +} + +fn call_macro_and_trait_good() { + // importing trait and macro but only using macro by path won't allow us to change this to + // `use macro_and_trait_same_name::Foo as _;` + use macro_and_trait_same_name::Foo; + Foo!(); + ().bar(); +} + +proc_macros::external!( + fn ignore_inside_external_proc_macro() { + use std::any::Any; + "foo".type_id(); + } +); + +proc_macros::with_span!( + span + + fn ignore_inside_with_span_proc_macro() { + use std::any::Any; + "foo".type_id(); + } +); + +// This should warn the import is unused but should not trigger unused_trait_names +#[warn(unused)] +mod unused_import { + use std::any::Any; +} + +#[allow(clippy::unused_trait_names)] +fn allow_lint_fn() { + use std::any::Any; + + "foo".type_id(); +} + +#[allow(clippy::unused_trait_names)] +mod allow_lint_mod { + use std::any::Any; + + fn foo() { + "foo".type_id(); + } +} + +mod allow_lint_import { + #[allow(clippy::unused_trait_names)] + use std::any::Any; + + fn foo() { + "foo".type_id(); + } +} + +// Limitation: Suggests `use std::any::Any as _::{self};` which looks weird +// fn use_trait_self_good() { +// use std::any::Any::{self}; +// "foo".type_id(); +// } + +// Limitation: Suggests `use std::any::{Any as _, Any as _};` +// mod repeated_renamed { +// use std::any::{Any, Any as MyAny}; + +// fn foo() { +// "foo".type_id(); +// } +// } diff --git a/tests/ui/unused_trait_names.stderr b/tests/ui/unused_trait_names.stderr new file mode 100644 index 00000000000..f59d8f58a17 --- /dev/null +++ b/tests/ui/unused_trait_names.stderr @@ -0,0 +1,73 @@ +error: unused import: `std::any::Any` + --> tests/ui/unused_trait_names.rs:245:9 + | +LL | use std::any::Any; + | ^^^^^^^^^^^^^ + | + = note: `-D unused-imports` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(unused_imports)]` + +error: importing trait that is only used anonymously + --> tests/ui/unused_trait_names.rs:12:19 + | +LL | use std::any::Any; + | ^^^ help: use: `Any as _` + | + = note: `-D clippy::unused-trait-names` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::unused_trait_names)]` + +error: importing trait that is only used anonymously + --> tests/ui/unused_trait_names.rs:31:26 + | +LL | use std::any::{self, Any, TypeId}; + | ^^^ help: use: `Any as _` + +error: importing trait that is only used anonymously + --> tests/ui/unused_trait_names.rs:43:19 + | +LL | use std::any::Any as MyAny; + | ^^^^^^^^^^^^ help: use: `Any as _` + +error: importing trait that is only used anonymously + --> tests/ui/unused_trait_names.rs:49:20 + | +LL | use std::any::{Any as MyAny, TypeId as MyTypeId}; + | ^^^^^^^^^^^^ help: use: `Any as _` + +error: importing trait that is only used anonymously + --> tests/ui/unused_trait_names.rs:72:23 + | +LL | use std::any::Any; + | ^^^ help: use: `Any as _` + +error: importing trait that is only used anonymously + --> tests/ui/unused_trait_names.rs:113:19 + | +LL | use std::any::Any; + | ^^^ help: use: `Any as _` + +error: importing trait that is only used anonymously + --> tests/ui/unused_trait_names.rs:132:19 + | +LL | use std::any::Any; + | ^^^ help: use: `Any as _` + +error: importing trait that is only used anonymously + --> tests/ui/unused_trait_names.rs:191:34 + | +LL | use simple_trait::{MyStruct, MyTrait}; + | ^^^^^^^ help: use: `MyTrait as _` + +error: importing trait that is only used anonymously + --> tests/ui/unused_trait_names.rs:198:27 + | +LL | use std::any::Any; + | ^^^ help: use: `Any as _` +... +LL | foo!(); + | ------ in this macro invocation + | + = note: this error originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 10 previous errors + From 249210e8d86a4de347def1be559dfa79d346cb9f Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Thu, 19 Sep 2024 22:56:04 -0400 Subject: [PATCH 178/683] Fix clippy --- clippy_utils/src/mir/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_utils/src/mir/mod.rs b/clippy_utils/src/mir/mod.rs index e4966690d8c..654fb564848 100644 --- a/clippy_utils/src/mir/mod.rs +++ b/clippy_utils/src/mir/mod.rs @@ -30,7 +30,7 @@ pub fn visit_local_usage(locals: &[Local], mir: &Body<'_>, location: Location) - locals.len() ]; - traversal::Postorder::new(&mir.basic_blocks, location.block) + traversal::Postorder::new(&mir.basic_blocks, location.block, ()) .collect::>() .into_iter() .rev() From de2eba18263855871522cb967bfa82ac1ef22d5e Mon Sep 17 00:00:00 2001 From: "Tim (Theemathas) Chirananthavat" Date: Sat, 21 Sep 2024 12:38:38 +0700 Subject: [PATCH 179/683] Reword ManuallyDrop+Box interaction --- library/core/src/mem/manually_drop.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/library/core/src/mem/manually_drop.rs b/library/core/src/mem/manually_drop.rs index 8dea3539e46..86eac7724cf 100644 --- a/library/core/src/mem/manually_drop.rs +++ b/library/core/src/mem/manually_drop.rs @@ -41,8 +41,9 @@ use crate::ptr; /// /// # Interaction with `Box` /// -/// Currently, once the `Box` inside a `ManuallyDrop>` is dropped, -/// moving the `ManuallyDrop>` is [considered to be undefined +/// Currently, if you have a `ManuallyDrop`, where the type `T` is a `Box` or +/// contains a `Box` inside, then dropping the `T` followed by moving the +/// `ManuallyDrop` is [considered to be undefined /// behavior](https://github.com/rust-lang/unsafe-code-guidelines/issues/245). /// That is, the following code causes undefined behavior: /// From 3ab1da8bab0779888975b62c934160da6b8aa6e7 Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Sun, 22 Sep 2024 20:42:10 +0200 Subject: [PATCH 180/683] Formatting --- clippy_config/src/conf.rs | 2 +- clippy_config/src/lib.rs | 2 +- clippy_config/src/msrvs.rs | 2 +- clippy_config/src/types.rs | 2 +- clippy_dev/src/fmt.rs | 2 +- clippy_dev/src/new_lint.rs | 2 +- clippy_dev/src/update_lints.rs | 30 +-- clippy_lints/src/absolute_paths.rs | 4 +- clippy_lints/src/almost_complete_range.rs | 2 +- clippy_lints/src/approx_const.rs | 4 +- clippy_lints/src/arc_with_non_send_sync.rs | 2 +- clippy_lints/src/assertions_on_constants.rs | 2 +- .../src/assertions_on_result_states.rs | 2 +- clippy_lints/src/assigning_clones.rs | 4 +- .../attrs/allow_attributes_without_reason.rs | 2 +- .../attrs/blanket_clippy_restriction_lints.rs | 4 +- clippy_lints/src/attrs/deprecated_cfg_attr.rs | 2 +- .../src/attrs/duplicated_attributes.rs | 2 +- clippy_lints/src/attrs/inline_always.rs | 4 +- clippy_lints/src/attrs/mod.rs | 2 +- clippy_lints/src/attrs/useless_attribute.rs | 2 +- clippy_lints/src/await_holding_invalid.rs | 2 +- clippy_lints/src/booleans.rs | 4 +- clippy_lints/src/box_default.rs | 2 +- .../src/cargo/lint_groups_priority.rs | 2 +- clippy_lints/src/casts/cast_lossless.rs | 2 +- .../src/casts/cast_possible_truncation.rs | 2 +- clippy_lints/src/casts/cast_possible_wrap.rs | 2 +- clippy_lints/src/casts/cast_precision_loss.rs | 2 +- clippy_lints/src/casts/cast_sign_loss.rs | 2 +- clippy_lints/src/casts/fn_to_numeric_cast.rs | 2 +- .../fn_to_numeric_cast_with_truncation.rs | 2 +- clippy_lints/src/casts/mod.rs | 2 +- clippy_lints/src/casts/ref_as_ptr.rs | 2 +- clippy_lints/src/casts/unnecessary_cast.rs | 4 +- clippy_lints/src/casts/utils.rs | 2 +- clippy_lints/src/checked_conversions.rs | 4 +- clippy_lints/src/cognitive_complexity.rs | 4 +- clippy_lints/src/collection_is_never_read.rs | 2 +- clippy_lints/src/comparison_chain.rs | 2 +- clippy_lints/src/copies.rs | 11 +- clippy_lints/src/crate_in_macro_def.rs | 2 +- clippy_lints/src/dbg_macro.rs | 4 +- clippy_lints/src/default.rs | 2 +- .../src/default_constructed_unit_structs.rs | 2 +- .../src/default_instead_of_iter_empty.rs | 4 +- clippy_lints/src/default_numeric_fallback.rs | 2 +- clippy_lints/src/dereference.rs | 73 +++--- clippy_lints/src/derivable_impls.rs | 2 +- clippy_lints/src/derive.rs | 4 +- clippy_lints/src/doc/empty_line_after.rs | 13 +- clippy_lints/src/doc/link_with_quotes.rs | 2 +- clippy_lints/src/doc/missing_headers.rs | 2 +- clippy_lints/src/doc/mod.rs | 6 +- clippy_lints/src/doc/needless_doctest_main.rs | 2 +- clippy_lints/src/entry.rs | 8 +- clippy_lints/src/enum_clike.rs | 2 +- clippy_lints/src/escape.rs | 4 +- clippy_lints/src/excessive_bools.rs | 2 +- clippy_lints/src/excessive_nesting.rs | 2 +- clippy_lints/src/explicit_write.rs | 4 +- .../src/extra_unused_type_parameters.rs | 4 +- clippy_lints/src/fallible_impl_from.rs | 2 +- clippy_lints/src/floating_point_arithmetic.rs | 2 +- clippy_lints/src/format.rs | 6 +- clippy_lints/src/format_args.rs | 11 +- clippy_lints/src/format_impl.rs | 4 +- clippy_lints/src/format_push_string.rs | 2 +- clippy_lints/src/from_over_into.rs | 4 +- clippy_lints/src/from_str_radix_10.rs | 2 +- clippy_lints/src/functions/mod.rs | 2 +- clippy_lints/src/functions/must_use.rs | 2 +- .../src/functions/not_unsafe_ptr_arg_deref.rs | 2 +- .../src/functions/renamed_function_params.rs | 2 +- clippy_lints/src/functions/result.rs | 4 +- clippy_lints/src/future_not_send.rs | 2 +- clippy_lints/src/if_then_some_else_none.rs | 2 +- clippy_lints/src/implicit_hasher.rs | 6 +- clippy_lints/src/implicit_saturating_sub.rs | 4 +- clippy_lints/src/incompatible_msrv.rs | 4 +- clippy_lints/src/index_refutable_slice.rs | 6 +- clippy_lints/src/ineffective_open_options.rs | 2 +- clippy_lints/src/instant_subtraction.rs | 2 +- clippy_lints/src/item_name_repetitions.rs | 2 +- clippy_lints/src/items_after_test_module.rs | 2 +- .../src/iter_not_returning_iterator.rs | 2 +- clippy_lints/src/iter_over_hash_type.rs | 4 +- clippy_lints/src/large_enum_variant.rs | 2 +- clippy_lints/src/large_stack_arrays.rs | 2 +- clippy_lints/src/legacy_numeric_constants.rs | 4 +- clippy_lints/src/len_zero.rs | 4 +- clippy_lints/src/lib.rs | 2 +- clippy_lints/src/lifetimes.rs | 16 +- .../src/loops/explicit_counter_loop.rs | 2 +- clippy_lints/src/loops/infinite_loop.rs | 2 +- clippy_lints/src/loops/manual_find.rs | 2 +- clippy_lints/src/loops/manual_flatten.rs | 2 +- .../src/loops/manual_while_let_some.rs | 4 +- clippy_lints/src/loops/mod.rs | 4 +- clippy_lints/src/loops/needless_range_loop.rs | 6 +- clippy_lints/src/loops/never_loop.rs | 4 +- clippy_lints/src/loops/same_item_push.rs | 4 +- clippy_lints/src/loops/single_element_loop.rs | 4 +- clippy_lints/src/loops/utils.rs | 4 +- .../src/loops/while_immutable_condition.rs | 2 +- .../src/loops/while_let_on_iterator.rs | 4 +- clippy_lints/src/macro_metavars_in_unsafe.rs | 6 +- clippy_lints/src/macro_use.rs | 2 +- clippy_lints/src/manual_async_fn.rs | 4 +- clippy_lints/src/manual_bits.rs | 2 +- clippy_lints/src/manual_clamp.rs | 8 +- clippy_lints/src/manual_div_ceil.rs | 2 +- clippy_lints/src/manual_hash_one.rs | 2 +- clippy_lints/src/manual_is_ascii_check.rs | 6 +- clippy_lints/src/manual_is_power_of_two.rs | 2 +- clippy_lints/src/manual_let_else.rs | 4 +- clippy_lints/src/manual_main_separator_str.rs | 2 +- clippy_lints/src/manual_non_exhaustive.rs | 4 +- clippy_lints/src/manual_range_patterns.rs | 2 +- clippy_lints/src/manual_rem_euclid.rs | 2 +- clippy_lints/src/manual_retain.rs | 8 +- clippy_lints/src/manual_string_new.rs | 2 +- clippy_lints/src/manual_strip.rs | 6 +- clippy_lints/src/map_unit_fn.rs | 2 +- clippy_lints/src/matches/collapsible_match.rs | 4 +- clippy_lints/src/matches/manual_filter.rs | 4 +- clippy_lints/src/matches/manual_map.rs | 2 +- clippy_lints/src/matches/manual_unwrap_or.rs | 4 +- clippy_lints/src/matches/manual_utils.rs | 8 +- clippy_lints/src/matches/match_same_arms.rs | 2 +- .../src/matches/match_str_case_mismatch.rs | 4 +- clippy_lints/src/matches/mod.rs | 2 +- clippy_lints/src/matches/overlapping_arms.rs | 2 +- clippy_lints/src/matches/redundant_guards.rs | 4 +- .../src/matches/redundant_pattern_match.rs | 6 +- .../matches/significant_drop_in_scrutinee.rs | 2 +- clippy_lints/src/matches/single_match.rs | 6 +- clippy_lints/src/mem_replace.rs | 4 +- .../src/methods/bind_instead_of_map.rs | 2 +- ...se_sensitive_file_extension_comparisons.rs | 4 +- clippy_lints/src/methods/clear_with_drain.rs | 2 +- clippy_lints/src/methods/clone_on_copy.rs | 2 +- clippy_lints/src/methods/clone_on_ref_ptr.rs | 2 +- .../src/methods/cloned_instead_of_copied.rs | 2 +- .../src/methods/collapsible_str_replace.rs | 2 +- clippy_lints/src/methods/drain_collect.rs | 2 +- clippy_lints/src/methods/err_expect.rs | 2 +- clippy_lints/src/methods/expect_fun_call.rs | 4 +- clippy_lints/src/methods/filetype_is_file.rs | 2 +- clippy_lints/src/methods/filter_map.rs | 4 +- .../src/methods/filter_map_bool_then.rs | 4 +- .../src/methods/filter_map_identity.rs | 2 +- clippy_lints/src/methods/flat_map_identity.rs | 2 +- clippy_lints/src/methods/flat_map_option.rs | 2 +- clippy_lints/src/methods/get_last_with_len.rs | 2 +- .../src/methods/inefficient_to_string.rs | 2 +- clippy_lints/src/methods/inspect_for_each.rs | 2 +- clippy_lints/src/methods/into_iter_on_ref.rs | 2 +- clippy_lints/src/methods/iter_filter.rs | 2 +- clippy_lints/src/methods/iter_nth.rs | 2 +- .../iter_on_single_or_empty_collections.rs | 2 +- clippy_lints/src/methods/iter_with_drain.rs | 2 +- .../src/methods/join_absolute_paths.rs | 2 +- .../src/methods/manual_c_str_literals.rs | 2 +- clippy_lints/src/methods/manual_inspect.rs | 4 +- .../src/methods/manual_is_variant_and.rs | 2 +- clippy_lints/src/methods/manual_ok_or.rs | 2 +- clippy_lints/src/methods/manual_try_fold.rs | 2 +- clippy_lints/src/methods/map_clone.rs | 2 +- clippy_lints/src/methods/map_flatten.rs | 2 +- clippy_lints/src/methods/map_identity.rs | 2 +- clippy_lints/src/methods/mod.rs | 13 +- clippy_lints/src/methods/mut_mutex_lock.rs | 2 +- .../methods/needless_character_iteration.rs | 2 +- clippy_lints/src/methods/needless_collect.rs | 8 +- .../src/methods/needless_option_as_deref.rs | 2 +- clippy_lints/src/methods/no_effect_replace.rs | 2 +- clippy_lints/src/methods/open_options.rs | 16 +- .../src/methods/option_as_ref_cloned.rs | 4 +- .../src/methods/option_as_ref_deref.rs | 10 +- .../src/methods/option_map_unwrap_or.rs | 4 +- clippy_lints/src/methods/or_fun_call.rs | 2 +- clippy_lints/src/methods/or_then_unwrap.rs | 2 +- .../src/methods/range_zip_with_len.rs | 2 +- clippy_lints/src/methods/search_is_some.rs | 2 +- clippy_lints/src/methods/seek_from_current.rs | 2 +- .../seek_to_start_instead_of_rewind.rs | 4 +- clippy_lints/src/methods/str_splitn.rs | 4 +- .../methods/suspicious_command_arg_space.rs | 2 +- clippy_lints/src/methods/type_id_on_box.rs | 2 +- .../unnecessary_fallible_conversions.rs | 2 +- .../src/methods/unnecessary_filter_map.rs | 2 +- clippy_lints/src/methods/unnecessary_fold.rs | 70 ++--- .../src/methods/unnecessary_get_then_check.rs | 2 +- .../src/methods/unnecessary_iter_cloned.rs | 2 +- .../src/methods/unnecessary_literal_unwrap.rs | 2 +- .../src/methods/unnecessary_min_or_max.rs | 2 +- .../methods/unnecessary_result_map_or_else.rs | 2 +- .../src/methods/unnecessary_to_owned.rs | 7 +- .../src/methods/unused_enumerate_index.rs | 4 +- clippy_lints/src/methods/useless_asref.rs | 2 +- clippy_lints/src/methods/utils.rs | 4 +- .../src/methods/vec_resize_to_zero.rs | 2 +- clippy_lints/src/methods/waker_clone_wake.rs | 2 +- clippy_lints/src/min_ident_chars.rs | 2 +- clippy_lints/src/misc.rs | 6 +- clippy_lints/src/missing_assert_message.rs | 2 +- .../src/missing_asserts_for_indexing.rs | 4 +- clippy_lints/src/missing_const_for_fn.rs | 4 +- .../src/missing_const_for_thread_local.rs | 4 +- clippy_lints/src/missing_doc.rs | 2 +- clippy_lints/src/missing_fields_in_debug.rs | 4 +- clippy_lints/src/missing_inline.rs | 2 +- .../src/mixed_read_write_in_expression.rs | 2 +- .../src/multiple_unsafe_ops_per_block.rs | 25 +- clippy_lints/src/mut_key.rs | 2 +- clippy_lints/src/mutable_debug_assertion.rs | 2 +- .../src/needless_arbitrary_self_type.rs | 2 +- clippy_lints/src/needless_bool.rs | 6 +- .../src/needless_borrows_for_generic_args.rs | 6 +- clippy_lints/src/needless_for_each.rs | 4 +- clippy_lints/src/needless_pass_by_ref_mut.rs | 2 +- clippy_lints/src/needless_pass_by_value.rs | 15 +- clippy_lints/src/no_effect.rs | 4 +- clippy_lints/src/non_copy_const.rs | 4 +- clippy_lints/src/non_expressive_names.rs | 4 +- .../src/non_octal_unix_permissions.rs | 2 +- clippy_lints/src/nonstandard_macro_braces.rs | 4 +- clippy_lints/src/only_used_in_recursion.rs | 2 +- .../operators/absurd_extreme_comparisons.rs | 2 +- .../src/operators/const_comparisons.rs | 4 +- .../operators/float_equality_without_abs.rs | 3 +- clippy_lints/src/option_if_let_else.rs | 6 +- clippy_lints/src/panic_in_result_fn.rs | 4 +- clippy_lints/src/pass_by_ref_or_value.rs | 2 +- clippy_lints/src/pathbuf_init_then_push.rs | 4 +- clippy_lints/src/pattern_type_mismatch.rs | 4 +- clippy_lints/src/ptr.rs | 4 +- clippy_lints/src/pub_underscore_fields.rs | 2 +- clippy_lints/src/question_mark.rs | 4 +- clippy_lints/src/ranges.rs | 6 +- clippy_lints/src/rc_clone_in_vec_init.rs | 2 +- clippy_lints/src/read_zero_byte_vec.rs | 4 +- clippy_lints/src/redundant_clone.rs | 20 +- clippy_lints/src/redundant_closure_call.rs | 2 +- clippy_lints/src/redundant_else.rs | 2 +- clippy_lints/src/redundant_field_names.rs | 2 +- clippy_lints/src/redundant_locals.rs | 2 +- .../src/redundant_static_lifetimes.rs | 2 +- clippy_lints/src/reference.rs | 2 +- clippy_lints/src/repeat_vec_with_capacity.rs | 2 +- .../src/reserve_after_initialization.rs | 2 +- clippy_lints/src/return_self_not_must_use.rs | 2 +- clippy_lints/src/returns.rs | 8 +- clippy_lints/src/same_name_method.rs | 13 +- clippy_lints/src/set_contains_or_insert.rs | 4 +- .../src/significant_drop_tightening.rs | 4 +- .../src/single_component_path_imports.rs | 2 +- .../src/slow_vector_initialization.rs | 5 +- clippy_lints/src/std_instead_of_core.rs | 4 +- clippy_lints/src/string_patterns.rs | 6 +- clippy_lints/src/strings.rs | 4 +- .../src/suspicious_operation_groupings.rs | 4 +- clippy_lints/src/suspicious_trait_impl.rs | 2 +- clippy_lints/src/swap.rs | 4 +- clippy_lints/src/swap_ptr_to_ref.rs | 2 +- clippy_lints/src/tests_outside_test_module.rs | 2 +- clippy_lints/src/to_digit_is_some.rs | 12 +- clippy_lints/src/trait_bounds.rs | 6 +- clippy_lints/src/transmute/mod.rs | 2 +- .../transmutes_expressible_as_ptr_casts.rs | 2 +- .../transmute/unsound_collection_transmute.rs | 2 +- clippy_lints/src/tuple_array_conversions.rs | 2 +- clippy_lints/src/types/box_collection.rs | 2 +- clippy_lints/src/types/mod.rs | 66 ++--- .../src/types/redundant_allocation.rs | 2 +- clippy_lints/src/types/type_complexity.rs | 2 +- clippy_lints/src/types/vec_box.rs | 2 +- clippy_lints/src/unconditional_recursion.rs | 17 +- .../src/undocumented_unsafe_blocks.rs | 4 +- clippy_lints/src/uninhabited_references.rs | 2 +- clippy_lints/src/uninit_vec.rs | 6 +- clippy_lints/src/unit_return_expecting_ord.rs | 2 +- clippy_lints/src/unit_types/let_unit_value.rs | 2 +- clippy_lints/src/unit_types/unit_arg.rs | 4 +- clippy_lints/src/unnecessary_wraps.rs | 4 +- clippy_lints/src/unnested_or_patterns.rs | 8 +- clippy_lints/src/unsafe_removed_from_name.rs | 2 +- clippy_lints/src/unused_async.rs | 4 +- clippy_lints/src/unused_io_amount.rs | 2 +- clippy_lints/src/unused_peekable.rs | 2 +- clippy_lints/src/unused_trait_names.rs | 2 +- clippy_lints/src/unused_unit.rs | 4 +- clippy_lints/src/unwrap.rs | 4 +- clippy_lints/src/unwrap_in_result.rs | 2 +- clippy_lints/src/use_self.rs | 4 +- clippy_lints/src/useless_conversion.rs | 2 +- clippy_lints/src/utils/author.rs | 2 +- .../src/utils/format_args_collector.rs | 4 +- .../utils/internal_lints/collapsible_calls.rs | 2 +- .../src/utils/internal_lints/invalid_paths.rs | 4 +- .../internal_lints/lint_without_lint_pass.rs | 2 +- .../internal_lints/unnecessary_def_path.rs | 4 +- clippy_lints/src/vec.rs | 4 +- clippy_lints/src/vec_init_then_push.rs | 2 +- clippy_lints/src/visibility.rs | 2 +- clippy_lints/src/wildcard_imports.rs | 2 +- clippy_lints/src/write.rs | 6 +- clippy_lints/src/zombie_processes.rs | 4 +- clippy_utils/src/ast_utils/ident_iter.rs | 2 +- clippy_utils/src/attrs.rs | 2 +- clippy_utils/src/check_proc_macro.rs | 4 +- clippy_utils/src/consts.rs | 10 +- clippy_utils/src/eager_or_lazy.rs | 4 +- clippy_utils/src/higher.rs | 4 +- clippy_utils/src/hir_utils.rs | 8 +- clippy_utils/src/lib.rs | 34 +-- clippy_utils/src/macros.rs | 4 +- clippy_utils/src/mir/mod.rs | 14 +- clippy_utils/src/ptr.rs | 2 +- clippy_utils/src/qualify_min_const_fn.rs | 2 +- clippy_utils/src/source.rs | 21 +- clippy_utils/src/str_utils.rs | 10 +- clippy_utils/src/ty.rs | 4 +- clippy_utils/src/ty/type_certainty/mod.rs | 4 +- clippy_utils/src/usage.rs | 2 +- clippy_utils/src/visitors.rs | 4 +- declare_clippy_lint/src/lib.rs | 17 +- lintcheck/src/driver.rs | 2 +- lintcheck/src/recursive.rs | 2 +- src/driver.rs | 2 +- tests/compile-test.rs | 10 +- tests/config-metadata.rs | 2 +- tests/ui-internal/unnecessary_def_path.fixed | 2 +- tests/ui-internal/unnecessary_def_path.rs | 2 +- .../conf_missing_enforced_import_rename.fixed | 2 +- .../conf_missing_enforced_import_rename.rs | 2 +- ...conf_missing_enforced_import_rename.stderr | 6 +- tests/ui/arithmetic_side_effects.rs | 1 - tests/ui/arithmetic_side_effects.stderr | 246 +++++++++--------- tests/ui/auxiliary/proc_macro_attr.rs | 4 +- tests/ui/auxiliary/proc_macro_derive.rs | 2 +- .../proc_macro_suspicious_else_formatting.rs | 2 +- tests/ui/auxiliary/proc_macros.rs | 2 +- .../borrow_interior_mutable_const/others.rs | 2 +- .../declare_interior_mutable_const/others.rs | 2 +- tests/ui/field_reassign_with_default.rs | 2 +- tests/ui/format_args.fixed | 2 +- tests/ui/format_args.rs | 2 +- tests/ui/format_args_unfixable.rs | 2 +- tests/ui/ignored_unit_patterns.fixed | 15 +- tests/ui/ignored_unit_patterns.rs | 15 +- tests/ui/ignored_unit_patterns.stderr | 18 +- tests/ui/incompatible_msrv.rs | 2 +- tests/ui/legacy_numeric_constants.fixed | 4 +- tests/ui/legacy_numeric_constants.rs | 4 +- tests/ui/manual_saturating_arithmetic.fixed | 2 +- tests/ui/manual_saturating_arithmetic.rs | 2 +- tests/ui/must_use_candidates.fixed | 2 +- tests/ui/must_use_candidates.rs | 2 +- tests/ui/mut_key.rs | 2 +- tests/ui/non_zero_suggestions.fixed | 2 +- tests/ui/non_zero_suggestions.rs | 2 +- tests/ui/non_zero_suggestions_unfixable.rs | 2 +- tests/ui/single_match.fixed | 2 +- tests/ui/single_match.rs | 2 +- tests/ui/suspicious_to_owned.rs | 2 +- tests/ui/transmute_collection.rs | 2 +- tests/ui/transmute_undefined_repr.rs | 2 +- 369 files changed, 874 insertions(+), 973 deletions(-) diff --git a/clippy_config/src/conf.rs b/clippy_config/src/conf.rs index 1765cf87d48..757620341cc 100644 --- a/clippy_config/src/conf.rs +++ b/clippy_config/src/conf.rs @@ -1,6 +1,6 @@ +use crate::ClippyConfiguration; use crate::msrvs::Msrv; use crate::types::{DisallowedPath, MacroMatcher, MatchLintBehaviour, PubUnderscoreFieldsBehaviour, Rename}; -use crate::ClippyConfiguration; use rustc_errors::Applicability; use rustc_session::Session; use rustc_span::edit_distance::edit_distance; diff --git a/clippy_config/src/lib.rs b/clippy_config/src/lib.rs index ac838cc81d2..c63d98a0a13 100644 --- a/clippy_config/src/lib.rs +++ b/clippy_config/src/lib.rs @@ -26,5 +26,5 @@ mod metadata; pub mod msrvs; pub mod types; -pub use conf::{get_configuration_metadata, lookup_conf_file, Conf}; +pub use conf::{Conf, get_configuration_metadata, lookup_conf_file}; pub use metadata::ClippyConfiguration; diff --git a/clippy_config/src/msrvs.rs b/clippy_config/src/msrvs.rs index 5f163cbe8e1..e30df3d3234 100644 --- a/clippy_config/src/msrvs.rs +++ b/clippy_config/src/msrvs.rs @@ -1,7 +1,7 @@ use rustc_ast::Attribute; use rustc_attr::parse_version; use rustc_session::{RustcVersion, Session}; -use rustc_span::{sym, Symbol}; +use rustc_span::{Symbol, sym}; use serde::Deserialize; use std::fmt; diff --git a/clippy_config/src/types.rs b/clippy_config/src/types.rs index d47e34bb5bc..bab63911182 100644 --- a/clippy_config/src/types.rs +++ b/clippy_config/src/types.rs @@ -1,5 +1,5 @@ use serde::de::{self, Deserializer, Visitor}; -use serde::{ser, Deserialize, Serialize}; +use serde::{Deserialize, Serialize, ser}; use std::fmt; #[derive(Debug, Deserialize)] diff --git a/clippy_dev/src/fmt.rs b/clippy_dev/src/fmt.rs index 5fc4365c6e7..8c61c35533c 100644 --- a/clippy_dev/src/fmt.rs +++ b/clippy_dev/src/fmt.rs @@ -1,6 +1,6 @@ use crate::clippy_project_root; use itertools::Itertools; -use rustc_lexer::{tokenize, TokenKind}; +use rustc_lexer::{TokenKind, tokenize}; use shell_escape::escape; use std::ffi::{OsStr, OsString}; use std::ops::ControlFlow; diff --git a/clippy_dev/src/new_lint.rs b/clippy_dev/src/new_lint.rs index de91233d196..c4d9c52a1cc 100644 --- a/clippy_dev/src/new_lint.rs +++ b/clippy_dev/src/new_lint.rs @@ -441,7 +441,7 @@ fn create_lint_for_ty(lint: &LintData<'_>, enable_msrv: bool, ty: &str) -> io::R #[allow(clippy::too_many_lines)] fn setup_mod_file(path: &Path, lint: &LintData<'_>) -> io::Result<&'static str> { - use super::update_lints::{match_tokens, LintDeclSearchResult}; + use super::update_lints::{LintDeclSearchResult, match_tokens}; use rustc_lexer::TokenKind; let lint_name_upper = lint.name.to_uppercase(); diff --git a/clippy_dev/src/update_lints.rs b/clippy_dev/src/update_lints.rs index 8dbda1c634c..d6ed36d52f4 100644 --- a/clippy_dev/src/update_lints.rs +++ b/clippy_dev/src/update_lints.rs @@ -1,7 +1,7 @@ use crate::clippy_project_root; use aho_corasick::AhoCorasickBuilder; use itertools::Itertools; -use rustc_lexer::{tokenize, unescape, LiteralKind, TokenKind}; +use rustc_lexer::{LiteralKind, TokenKind, tokenize, unescape}; use std::collections::{HashMap, HashSet}; use std::ffi::OsStr; use std::fmt::{self, Write}; @@ -1048,23 +1048,17 @@ mod tests { Lint::new("incorrect_match", "group1", "\"abc\"", "module_name", Range::default()), ]; let mut expected: HashMap> = HashMap::new(); - expected.insert( - "group1".to_string(), - vec![ - Lint::new("should_assert_eq", "group1", "\"abc\"", "module_name", Range::default()), - Lint::new("incorrect_match", "group1", "\"abc\"", "module_name", Range::default()), - ], - ); - expected.insert( - "group2".to_string(), - vec![Lint::new( - "should_assert_eq2", - "group2", - "\"abc\"", - "module_name", - Range::default(), - )], - ); + expected.insert("group1".to_string(), vec![ + Lint::new("should_assert_eq", "group1", "\"abc\"", "module_name", Range::default()), + Lint::new("incorrect_match", "group1", "\"abc\"", "module_name", Range::default()), + ]); + expected.insert("group2".to_string(), vec![Lint::new( + "should_assert_eq2", + "group2", + "\"abc\"", + "module_name", + Range::default(), + )]); assert_eq!(expected, Lint::by_lint_group(lints.into_iter())); } } diff --git a/clippy_lints/src/absolute_paths.rs b/clippy_lints/src/absolute_paths.rs index c72b3f1318c..1af6d448a93 100644 --- a/clippy_lints/src/absolute_paths.rs +++ b/clippy_lints/src/absolute_paths.rs @@ -3,12 +3,12 @@ use clippy_utils::diagnostics::span_lint; use clippy_utils::is_from_proc_macro; use rustc_data_structures::fx::FxHashSet; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX}; +use rustc_hir::def_id::{CRATE_DEF_INDEX, DefId}; use rustc_hir::{HirId, ItemKind, Node, Path}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::impl_lint_pass; -use rustc_span::symbol::kw; use rustc_span::Symbol; +use rustc_span::symbol::kw; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/almost_complete_range.rs b/clippy_lints/src/almost_complete_range.rs index 451bae95987..370f0c482fd 100644 --- a/clippy_lints/src/almost_complete_range.rs +++ b/clippy_lints/src/almost_complete_range.rs @@ -1,5 +1,5 @@ -use clippy_config::msrvs::{self, Msrv}; use clippy_config::Conf; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::{trim_span, walk_span_to_context}; use rustc_ast::ast::{Expr, ExprKind, LitKind, Pat, PatKind, RangeEnd, RangeLimits}; diff --git a/clippy_lints/src/approx_const.rs b/clippy_lints/src/approx_const.rs index 56f5e903dc3..4f8f091a095 100644 --- a/clippy_lints/src/approx_const.rs +++ b/clippy_lints/src/approx_const.rs @@ -1,10 +1,10 @@ -use clippy_config::msrvs::{self, Msrv}; use clippy_config::Conf; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_help; use rustc_ast::ast::{FloatTy, LitFloatType, LitKind}; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{impl_lint_pass, RustcVersion}; +use rustc_session::{RustcVersion, impl_lint_pass}; use rustc_span::symbol; use std::f64::consts as f64; diff --git a/clippy_lints/src/arc_with_non_send_sync.rs b/clippy_lints/src/arc_with_non_send_sync.rs index 4eafa330faf..2643f850879 100644 --- a/clippy_lints/src/arc_with_non_send_sync.rs +++ b/clippy_lints/src/arc_with_non_send_sync.rs @@ -4,8 +4,8 @@ use clippy_utils::ty::{implements_trait, is_type_diagnostic_item}; use rustc_hir::{Expr, ExprKind, QPath}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; -use rustc_middle::ty::print::with_forced_trimmed_paths; use rustc_middle::ty::GenericArgKind; +use rustc_middle::ty::print::with_forced_trimmed_paths; use rustc_session::declare_lint_pass; use rustc_span::symbol::sym; diff --git a/clippy_lints/src/assertions_on_constants.rs b/clippy_lints/src/assertions_on_constants.rs index 7eaac80f969..b6684825835 100644 --- a/clippy_lints/src/assertions_on_constants.rs +++ b/clippy_lints/src/assertions_on_constants.rs @@ -1,7 +1,7 @@ use clippy_utils::consts::{ConstEvalCtxt, Constant}; use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::is_inside_always_const_context; -use clippy_utils::macros::{find_assert_args, root_macro_call_first_node, PanicExpn}; +use clippy_utils::macros::{PanicExpn, find_assert_args, root_macro_call_first_node}; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; diff --git a/clippy_lints/src/assertions_on_result_states.rs b/clippy_lints/src/assertions_on_result_states.rs index f1cb4a05af8..c073dee855e 100644 --- a/clippy_lints/src/assertions_on_result_states.rs +++ b/clippy_lints/src/assertions_on_result_states.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::macros::{find_assert_args, root_macro_call_first_node, PanicExpn}; +use clippy_utils::macros::{PanicExpn, find_assert_args, root_macro_call_first_node}; use clippy_utils::source::snippet_with_context; use clippy_utils::ty::{has_debug_impl, is_copy, is_type_diagnostic_item}; use clippy_utils::usage::local_used_after_expr; diff --git a/clippy_lints/src/assigning_clones.rs b/clippy_lints/src/assigning_clones.rs index 55645d04eef..0b82c0cd04c 100644 --- a/clippy_lints/src/assigning_clones.rs +++ b/clippy_lints/src/assigning_clones.rs @@ -1,7 +1,7 @@ -use clippy_config::msrvs::{self, Msrv}; use clippy_config::Conf; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::mir::{enclosing_mir, PossibleBorrowerMap}; +use clippy_utils::mir::{PossibleBorrowerMap, enclosing_mir}; use clippy_utils::sugg::Sugg; use clippy_utils::{is_diag_trait_item, is_in_test, last_path_segment, local_is_initialized, path_to_local}; use rustc_errors::Applicability; diff --git a/clippy_lints/src/attrs/allow_attributes_without_reason.rs b/clippy_lints/src/attrs/allow_attributes_without_reason.rs index 4c7e07478c1..40959eccd3a 100644 --- a/clippy_lints/src/attrs/allow_attributes_without_reason.rs +++ b/clippy_lints/src/attrs/allow_attributes_without_reason.rs @@ -1,4 +1,4 @@ -use super::{Attribute, ALLOW_ATTRIBUTES_WITHOUT_REASON}; +use super::{ALLOW_ATTRIBUTES_WITHOUT_REASON, Attribute}; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::is_from_proc_macro; use rustc_ast::{MetaItemKind, NestedMetaItem}; diff --git a/clippy_lints/src/attrs/blanket_clippy_restriction_lints.rs b/clippy_lints/src/attrs/blanket_clippy_restriction_lints.rs index 9b08fd6d654..508963a20ea 100644 --- a/clippy_lints/src/attrs/blanket_clippy_restriction_lints.rs +++ b/clippy_lints/src/attrs/blanket_clippy_restriction_lints.rs @@ -1,10 +1,10 @@ -use super::utils::extract_clippy_lint; use super::BLANKET_CLIPPY_RESTRICTION_LINTS; +use super::utils::extract_clippy_lint; use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_then}; use rustc_ast::NestedMetaItem; use rustc_lint::{LateContext, Level, LintContext}; use rustc_span::symbol::Symbol; -use rustc_span::{sym, DUMMY_SP}; +use rustc_span::{DUMMY_SP, sym}; pub(super) fn check(cx: &LateContext<'_>, name: Symbol, items: &[NestedMetaItem]) { for lint in items { diff --git a/clippy_lints/src/attrs/deprecated_cfg_attr.rs b/clippy_lints/src/attrs/deprecated_cfg_attr.rs index e872ab6b4b5..abf924f7542 100644 --- a/clippy_lints/src/attrs/deprecated_cfg_attr.rs +++ b/clippy_lints/src/attrs/deprecated_cfg_attr.rs @@ -1,4 +1,4 @@ -use super::{unnecessary_clippy_cfg, Attribute, DEPRECATED_CFG_ATTR, DEPRECATED_CLIPPY_CFG_ATTR}; +use super::{Attribute, DEPRECATED_CFG_ATTR, DEPRECATED_CLIPPY_CFG_ATTR, unnecessary_clippy_cfg}; use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_sugg; use rustc_ast::AttrStyle; diff --git a/clippy_lints/src/attrs/duplicated_attributes.rs b/clippy_lints/src/attrs/duplicated_attributes.rs index 199e07565b0..55f8e1072db 100644 --- a/clippy_lints/src/attrs/duplicated_attributes.rs +++ b/clippy_lints/src/attrs/duplicated_attributes.rs @@ -3,7 +3,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use rustc_ast::{Attribute, MetaItem}; use rustc_data_structures::fx::FxHashMap; use rustc_lint::LateContext; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; use std::collections::hash_map::Entry; fn emit_if_duplicated( diff --git a/clippy_lints/src/attrs/inline_always.rs b/clippy_lints/src/attrs/inline_always.rs index 3b5b80ffefa..d41bb580c6c 100644 --- a/clippy_lints/src/attrs/inline_always.rs +++ b/clippy_lints/src/attrs/inline_always.rs @@ -1,10 +1,10 @@ -use super::utils::is_word; use super::INLINE_ALWAYS; +use super::utils::is_word; use clippy_utils::diagnostics::span_lint; use rustc_ast::Attribute; use rustc_lint::LateContext; use rustc_span::symbol::Symbol; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; pub(super) fn check(cx: &LateContext<'_>, span: Span, name: Symbol, attrs: &[Attribute]) { if span.from_expansion() { diff --git a/clippy_lints/src/attrs/mod.rs b/clippy_lints/src/attrs/mod.rs index c8fea25c9f2..888f28fa225 100644 --- a/clippy_lints/src/attrs/mod.rs +++ b/clippy_lints/src/attrs/mod.rs @@ -12,8 +12,8 @@ mod unnecessary_clippy_cfg; mod useless_attribute; mod utils; -use clippy_config::msrvs::{self, Msrv}; use clippy_config::Conf; +use clippy_config::msrvs::{self, Msrv}; use rustc_ast::{Attribute, MetaItemKind, NestedMetaItem}; use rustc_hir::{ImplItem, Item, ItemKind, TraitItem}; use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass}; diff --git a/clippy_lints/src/attrs/useless_attribute.rs b/clippy_lints/src/attrs/useless_attribute.rs index 1296b59f2e1..12668c616c1 100644 --- a/clippy_lints/src/attrs/useless_attribute.rs +++ b/clippy_lints/src/attrs/useless_attribute.rs @@ -1,7 +1,7 @@ use super::utils::{extract_clippy_lint, is_lint_level, is_word}; use super::{Attribute, USELESS_ATTRIBUTE}; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::{first_line_of_span, SpanRangeExt}; +use clippy_utils::source::{SpanRangeExt, first_line_of_span}; use rustc_ast::NestedMetaItem; use rustc_errors::Applicability; use rustc_hir::{Item, ItemKind}; diff --git a/clippy_lints/src/await_holding_invalid.rs b/clippy_lints/src/await_holding_invalid.rs index d5f017b2650..9952d0af99e 100644 --- a/clippy_lints/src/await_holding_invalid.rs +++ b/clippy_lints/src/await_holding_invalid.rs @@ -7,7 +7,7 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::mir::CoroutineLayout; use rustc_middle::ty::TyCtxt; use rustc_session::impl_lint_pass; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/booleans.rs b/clippy_lints/src/booleans.rs index e933fdf1d6e..3c2af72624f 100644 --- a/clippy_lints/src/booleans.rs +++ b/clippy_lints/src/booleans.rs @@ -4,12 +4,12 @@ use clippy_utils::source::SpanRangeExt; use clippy_utils::ty::{implements_trait, is_type_diagnostic_item}; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; -use rustc_hir::intravisit::{walk_expr, FnKind, Visitor}; +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_session::declare_lint_pass; use rustc_span::def_id::LocalDefId; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/box_default.rs b/clippy_lints/src/box_default.rs index 8459f051d3d..8261c65354f 100644 --- a/clippy_lints/src/box_default.rs +++ b/clippy_lints/src/box_default.rs @@ -4,7 +4,7 @@ use clippy_utils::ty::expr_sig; use clippy_utils::{is_default_equivalent, path_def_id}; use rustc_errors::Applicability; use rustc_hir::def::Res; -use rustc_hir::intravisit::{walk_ty, Visitor}; +use rustc_hir::intravisit::{Visitor, walk_ty}; use rustc_hir::{Block, Expr, ExprKind, LetStmt, Node, QPath, Ty, TyKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; diff --git a/clippy_lints/src/cargo/lint_groups_priority.rs b/clippy_lints/src/cargo/lint_groups_priority.rs index e924542fea2..ffd6c520c9a 100644 --- a/clippy_lints/src/cargo/lint_groups_priority.rs +++ b/clippy_lints/src/cargo/lint_groups_priority.rs @@ -2,7 +2,7 @@ use super::LINT_GROUPS_PRIORITY; use clippy_utils::diagnostics::span_lint_and_then; use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; -use rustc_lint::{unerased_lint_store, LateContext}; +use rustc_lint::{LateContext, unerased_lint_store}; use rustc_span::{BytePos, Pos, SourceFile, Span, SyntaxContext}; use serde::{Deserialize, Serialize}; use std::collections::BTreeMap; diff --git a/clippy_lints/src/casts/cast_lossless.rs b/clippy_lints/src/casts/cast_lossless.rs index 346aed7e9f1..84a44b14dde 100644 --- a/clippy_lints/src/casts/cast_lossless.rs +++ b/clippy_lints/src/casts/cast_lossless.rs @@ -10,7 +10,7 @@ use rustc_lint::LateContext; use rustc_middle::ty::{self, FloatTy, Ty}; use rustc_span::hygiene; -use super::{utils, CAST_LOSSLESS}; +use super::{CAST_LOSSLESS, utils}; pub(super) fn check( cx: &LateContext<'_>, diff --git a/clippy_lints/src/casts/cast_possible_truncation.rs b/clippy_lints/src/casts/cast_possible_truncation.rs index 5708aae3f3e..40a1a9d1ce8 100644 --- a/clippy_lints/src/casts/cast_possible_truncation.rs +++ b/clippy_lints/src/casts/cast_possible_truncation.rs @@ -12,7 +12,7 @@ use rustc_middle::ty::{self, FloatTy, Ty}; use rustc_span::Span; use rustc_target::abi::IntegerType; -use super::{utils, CAST_ENUM_TRUNCATION, CAST_POSSIBLE_TRUNCATION}; +use super::{CAST_ENUM_TRUNCATION, CAST_POSSIBLE_TRUNCATION, utils}; fn constant_int(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option { if let Some(Constant::Int(c)) = ConstEvalCtxt::new(cx).eval(expr) { diff --git a/clippy_lints/src/casts/cast_possible_wrap.rs b/clippy_lints/src/casts/cast_possible_wrap.rs index 11274383595..3cf4a43b0d4 100644 --- a/clippy_lints/src/casts/cast_possible_wrap.rs +++ b/clippy_lints/src/casts/cast_possible_wrap.rs @@ -3,7 +3,7 @@ use rustc_hir::Expr; use rustc_lint::LateContext; use rustc_middle::ty::Ty; -use super::{utils, CAST_POSSIBLE_WRAP}; +use super::{CAST_POSSIBLE_WRAP, utils}; // this should be kept in sync with the allowed bit widths of `usize` and `isize` const ALLOWED_POINTER_SIZES: [u64; 3] = [16, 32, 64]; diff --git a/clippy_lints/src/casts/cast_precision_loss.rs b/clippy_lints/src/casts/cast_precision_loss.rs index 035666e4d4c..1eb115ce6bd 100644 --- a/clippy_lints/src/casts/cast_precision_loss.rs +++ b/clippy_lints/src/casts/cast_precision_loss.rs @@ -4,7 +4,7 @@ use rustc_hir::Expr; use rustc_lint::LateContext; use rustc_middle::ty::{self, FloatTy, Ty}; -use super::{utils, CAST_PRECISION_LOSS}; +use super::{CAST_PRECISION_LOSS, utils}; pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>) { if !cast_from.is_integral() || cast_to.is_integral() { diff --git a/clippy_lints/src/casts/cast_sign_loss.rs b/clippy_lints/src/casts/cast_sign_loss.rs index 9daf237344a..4be53ace687 100644 --- a/clippy_lints/src/casts/cast_sign_loss.rs +++ b/clippy_lints/src/casts/cast_sign_loss.rs @@ -3,7 +3,7 @@ use std::ops::ControlFlow; use clippy_utils::consts::{ConstEvalCtxt, Constant}; use clippy_utils::diagnostics::span_lint; -use clippy_utils::visitors::{for_each_expr_without_closures, Descend}; +use clippy_utils::visitors::{Descend, for_each_expr_without_closures}; use clippy_utils::{method_chain_args, sext}; use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::LateContext; diff --git a/clippy_lints/src/casts/fn_to_numeric_cast.rs b/clippy_lints/src/casts/fn_to_numeric_cast.rs index dbe03e4ae80..ac1a355c8d9 100644 --- a/clippy_lints/src/casts/fn_to_numeric_cast.rs +++ b/clippy_lints/src/casts/fn_to_numeric_cast.rs @@ -5,7 +5,7 @@ use rustc_hir::Expr; use rustc_lint::LateContext; use rustc_middle::ty::{self, Ty, UintTy}; -use super::{utils, FN_TO_NUMERIC_CAST}; +use super::{FN_TO_NUMERIC_CAST, utils}; pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>) { // We only want to check casts to `ty::Uint` or `ty::Int` diff --git a/clippy_lints/src/casts/fn_to_numeric_cast_with_truncation.rs b/clippy_lints/src/casts/fn_to_numeric_cast_with_truncation.rs index dfbae1618ac..18e7798452e 100644 --- a/clippy_lints/src/casts/fn_to_numeric_cast_with_truncation.rs +++ b/clippy_lints/src/casts/fn_to_numeric_cast_with_truncation.rs @@ -5,7 +5,7 @@ use rustc_hir::Expr; use rustc_lint::LateContext; use rustc_middle::ty::{self, Ty}; -use super::{utils, FN_TO_NUMERIC_CAST_WITH_TRUNCATION}; +use super::{FN_TO_NUMERIC_CAST_WITH_TRUNCATION, utils}; pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>) { // We only want to check casts to `ty::Uint` or `ty::Int` diff --git a/clippy_lints/src/casts/mod.rs b/clippy_lints/src/casts/mod.rs index 39f50a347c0..3acd4eca420 100644 --- a/clippy_lints/src/casts/mod.rs +++ b/clippy_lints/src/casts/mod.rs @@ -23,8 +23,8 @@ mod unnecessary_cast; mod utils; mod zero_ptr; -use clippy_config::msrvs::{self, Msrv}; use clippy_config::Conf; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::is_hir_ty_cfg_dependant; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; diff --git a/clippy_lints/src/casts/ref_as_ptr.rs b/clippy_lints/src/casts/ref_as_ptr.rs index 5f48b8bd206..dfa240ccec6 100644 --- a/clippy_lints/src/casts/ref_as_ptr.rs +++ b/clippy_lints/src/casts/ref_as_ptr.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; use clippy_utils::sugg::Sugg; -use clippy_utils::{expr_use_ctxt, is_no_std_crate, ExprUseNode}; +use clippy_utils::{ExprUseNode, expr_use_ctxt, is_no_std_crate}; use rustc_errors::Applicability; use rustc_hir::{Expr, Mutability, Ty, TyKind}; use rustc_lint::LateContext; diff --git a/clippy_lints/src/casts/unnecessary_cast.rs b/clippy_lints/src/casts/unnecessary_cast.rs index 566adc83d69..811d33c8bde 100644 --- a/clippy_lints/src/casts/unnecessary_cast.rs +++ b/clippy_lints/src/casts/unnecessary_cast.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::numeric_literal::NumericLiteral; -use clippy_utils::source::{snippet_opt, SpanRangeExt}; -use clippy_utils::visitors::{for_each_expr_without_closures, Visitable}; +use clippy_utils::source::{SpanRangeExt, snippet_opt}; +use clippy_utils::visitors::{Visitable, for_each_expr_without_closures}; use clippy_utils::{get_parent_expr, is_hir_ty_cfg_dependant, is_ty_alias, path_to_local}; use rustc_ast::{LitFloatType, LitIntType, LitKind}; use rustc_errors::Applicability; diff --git a/clippy_lints/src/casts/utils.rs b/clippy_lints/src/casts/utils.rs index 5a4f20f0990..5ccba92a0af 100644 --- a/clippy_lints/src/casts/utils.rs +++ b/clippy_lints/src/casts/utils.rs @@ -1,4 +1,4 @@ -use clippy_utils::ty::{read_explicit_enum_value, EnumValue}; +use clippy_utils::ty::{EnumValue, read_explicit_enum_value}; use rustc_middle::ty::{self, AdtDef, IntTy, Ty, TyCtxt, UintTy, VariantDiscr}; /// Returns the size in bits of an integral type. diff --git a/clippy_lints/src/checked_conversions.rs b/clippy_lints/src/checked_conversions.rs index dd7c34d1e46..d3aa2fd1ea1 100644 --- a/clippy_lints/src/checked_conversions.rs +++ b/clippy_lints/src/checked_conversions.rs @@ -1,8 +1,8 @@ -use clippy_config::msrvs::{self, Msrv}; use clippy_config::Conf; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; -use clippy_utils::{is_in_const_context, is_integer_literal, SpanlessEq}; +use clippy_utils::{SpanlessEq, is_in_const_context, is_integer_literal}; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind, QPath, TyKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; diff --git a/clippy_lints/src/cognitive_complexity.rs b/clippy_lints/src/cognitive_complexity.rs index 0099eefbc8d..495d8ce3fa7 100644 --- a/clippy_lints/src/cognitive_complexity.rs +++ b/clippy_lints/src/cognitive_complexity.rs @@ -3,7 +3,7 @@ use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::source::{IntoSpan, SpanRangeExt}; use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::visitors::for_each_expr_without_closures; -use clippy_utils::{get_async_fn_body, is_async_fn, LimitStack}; +use clippy_utils::{LimitStack, get_async_fn_body, is_async_fn}; use core::ops::ControlFlow; use rustc_ast::ast::Attribute; use rustc_hir::intravisit::FnKind; @@ -11,7 +11,7 @@ use rustc_hir::{Body, Expr, ExprKind, FnDecl}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_session::impl_lint_pass; use rustc_span::def_id::LocalDefId; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/collection_is_never_read.rs b/clippy_lints/src/collection_is_never_read.rs index c6847411c75..8276e53648c 100644 --- a/clippy_lints/src/collection_is_never_read.rs +++ b/clippy_lints/src/collection_is_never_read.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint; use clippy_utils::ty::{get_type_diagnostic_name, is_type_lang_item}; -use clippy_utils::visitors::{for_each_expr, Visitable}; +use clippy_utils::visitors::{Visitable, for_each_expr}; use clippy_utils::{get_enclosing_block, path_to_local_id}; use core::ops::ControlFlow; use rustc_hir::{Body, ExprKind, HirId, LangItem, LetStmt, Node, PatKind}; diff --git a/clippy_lints/src/comparison_chain.rs b/clippy_lints/src/comparison_chain.rs index 5d78744e9b5..b9baf9af248 100644 --- a/clippy_lints/src/comparison_chain.rs +++ b/clippy_lints/src/comparison_chain.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::ty::implements_trait; -use clippy_utils::{if_sequence, is_else_clause, is_in_const_context, SpanlessEq}; +use clippy_utils::{SpanlessEq, if_sequence, is_else_clause, is_in_const_context}; use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; diff --git a/clippy_lints/src/copies.rs b/clippy_lints/src/copies.rs index 86e0368c4e4..d90a22bb62a 100644 --- a/clippy_lints/src/copies.rs +++ b/clippy_lints/src/copies.rs @@ -1,16 +1,17 @@ use clippy_config::Conf; use clippy_utils::diagnostics::{span_lint_and_note, span_lint_and_then}; -use clippy_utils::source::{first_line_of_span, indent_of, reindent_multiline, snippet, IntoSpan, SpanRangeExt}; -use clippy_utils::ty::{needs_ordered_drop, InteriorMut}; +use clippy_utils::source::{IntoSpan, SpanRangeExt, first_line_of_span, indent_of, reindent_multiline, snippet}; +use clippy_utils::ty::{InteriorMut, needs_ordered_drop}; use clippy_utils::visitors::for_each_expr_without_closures; use clippy_utils::{ - capture_local_usage, eq_expr_value, find_binding_init, get_enclosing_block, hash_expr, hash_stmt, if_sequence, - is_else_clause, is_lint_allowed, path_to_local, search_same, ContainsName, HirEqInterExpr, SpanlessEq, + ContainsName, HirEqInterExpr, SpanlessEq, capture_local_usage, eq_expr_value, find_binding_init, + get_enclosing_block, hash_expr, hash_stmt, if_sequence, is_else_clause, is_lint_allowed, path_to_local, + search_same, }; use core::iter; use core::ops::ControlFlow; use rustc_errors::Applicability; -use rustc_hir::{intravisit, BinOpKind, Block, Expr, ExprKind, HirId, HirIdSet, Stmt, StmtKind}; +use rustc_hir::{BinOpKind, Block, Expr, ExprKind, HirId, HirIdSet, Stmt, StmtKind, intravisit}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::TyCtxt; use rustc_session::impl_lint_pass; diff --git a/clippy_lints/src/crate_in_macro_def.rs b/clippy_lints/src/crate_in_macro_def.rs index 678bdbc0ffb..c8f81413728 100644 --- a/clippy_lints/src/crate_in_macro_def.rs +++ b/clippy_lints/src/crate_in_macro_def.rs @@ -5,8 +5,8 @@ use rustc_ast::tokenstream::{TokenStream, TokenTree}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_session::declare_lint_pass; -use rustc_span::symbol::sym; use rustc_span::Span; +use rustc_span::symbol::sym; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/dbg_macro.rs b/clippy_lints/src/dbg_macro.rs index 93c8fff05e9..a96c86f0765 100644 --- a/clippy_lints/src/dbg_macro.rs +++ b/clippy_lints/src/dbg_macro.rs @@ -1,7 +1,7 @@ use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::is_in_test; -use clippy_utils::macros::{macro_backtrace, MacroCall}; +use clippy_utils::macros::{MacroCall, macro_backtrace}; use clippy_utils::source::snippet_with_applicability; use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; @@ -9,7 +9,7 @@ use rustc_hir::{Expr, ExprKind, Node}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_session::impl_lint_pass; -use rustc_span::{sym, Span, SyntaxContext}; +use rustc_span::{Span, SyntaxContext, sym}; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/default.rs b/clippy_lints/src/default.rs index 0b7279f2b36..dc10b64698b 100644 --- a/clippy_lints/src/default.rs +++ b/clippy_lints/src/default.rs @@ -11,7 +11,7 @@ use rustc_middle::ty; use rustc_middle::ty::print::with_forced_trimmed_paths; use rustc_session::impl_lint_pass; use rustc_span::symbol::{Ident, Symbol}; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/default_constructed_unit_structs.rs b/clippy_lints/src/default_constructed_unit_structs.rs index 13778175496..33a97222b8f 100644 --- a/clippy_lints/src/default_constructed_unit_structs.rs +++ b/clippy_lints/src/default_constructed_unit_structs.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::is_ty_alias; -use hir::def::Res; use hir::ExprKind; +use hir::def::Res; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; diff --git a/clippy_lints/src/default_instead_of_iter_empty.rs b/clippy_lints/src/default_instead_of_iter_empty.rs index ac49e6f1a48..056e39c02af 100644 --- a/clippy_lints/src/default_instead_of_iter_empty.rs +++ b/clippy_lints/src/default_instead_of_iter_empty.rs @@ -2,10 +2,10 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_context; use clippy_utils::{last_path_segment, std_or_core}; use rustc_errors::Applicability; -use rustc_hir::{def, Expr, ExprKind, GenericArg, QPath, TyKind}; +use rustc_hir::{Expr, ExprKind, GenericArg, QPath, TyKind, def}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; -use rustc_span::{sym, SyntaxContext}; +use rustc_span::{SyntaxContext, sym}; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/default_numeric_fallback.rs b/clippy_lints/src/default_numeric_fallback.rs index 05c3cd3c814..a065dc2cf7e 100644 --- a/clippy_lints/src/default_numeric_fallback.rs +++ b/clippy_lints/src/default_numeric_fallback.rs @@ -3,7 +3,7 @@ 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::{walk_expr, walk_stmt, Visitor}; +use rustc_hir::intravisit::{Visitor, walk_expr, walk_stmt}; use rustc_hir::{Block, Body, ConstContext, Expr, ExprKind, FnRetTy, HirId, Lit, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; diff --git a/clippy_lints/src/dereference.rs b/clippy_lints/src/dereference.rs index 0e55d3db469..f34f5e05606 100644 --- a/clippy_lints/src/dereference.rs +++ b/clippy_lints/src/dereference.rs @@ -3,14 +3,14 @@ use clippy_utils::source::{snippet_with_applicability, snippet_with_context}; use clippy_utils::sugg::has_enclosing_paren; use clippy_utils::ty::{implements_trait, is_manually_drop}; use clippy_utils::{ - expr_use_ctxt, get_parent_expr, is_block_like, is_lint_allowed, path_to_local, peel_middle_ty_refs, DefinedTy, - ExprUseNode, + DefinedTy, ExprUseNode, expr_use_ctxt, get_parent_expr, is_block_like, is_lint_allowed, path_to_local, + peel_middle_ty_refs, }; use core::mem; use rustc_ast::util::parser::{PREC_PREFIX, PREC_UNAMBIGUOUS}; use rustc_data_structures::fx::FxIndexMap; use rustc_errors::Applicability; -use rustc_hir::intravisit::{walk_ty, Visitor}; +use rustc_hir::intravisit::{Visitor, walk_ty}; use rustc_hir::{ self as hir, BindingMode, Body, BodyId, BorrowKind, Expr, ExprKind, HirId, MatchSource, Mutability, Node, Pat, PatKind, Path, QPath, TyKind, UnOp, @@ -290,13 +290,10 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> { && let Some(ty) = use_node.defined_ty(cx) && TyCoercionStability::for_defined_ty(cx, ty, use_node.is_return()).is_deref_stable() { - self.state = Some(( - State::ExplicitDeref { mutability: None }, - StateData { - first_expr: expr, - adjusted_ty, - }, - )); + self.state = Some((State::ExplicitDeref { mutability: None }, StateData { + first_expr: expr, + adjusted_ty, + })); } }, RefOp::Method { mutbl, is_ufcs } @@ -458,13 +455,10 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> { && next_adjust.map_or(true, |a| matches!(a.kind, Adjust::Deref(_) | Adjust::Borrow(_))) && iter.all(|a| matches!(a.kind, Adjust::Deref(_) | Adjust::Borrow(_))) { - self.state = Some(( - State::Borrow { mutability }, - StateData { - first_expr: expr, - adjusted_ty, - }, - )); + self.state = Some((State::Borrow { mutability }, StateData { + first_expr: expr, + adjusted_ty, + })); } }, _ => {}, @@ -508,13 +502,10 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> { let stability = state.stability; report(cx, expr, State::DerefedBorrow(state), data, typeck); if stability.is_deref_stable() { - self.state = Some(( - State::Borrow { mutability }, - StateData { - first_expr: expr, - adjusted_ty, - }, - )); + self.state = Some((State::Borrow { mutability }, StateData { + first_expr: expr, + adjusted_ty, + })); } }, (Some((State::DerefedBorrow(state), data)), RefOp::Deref) => { @@ -539,13 +530,10 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> { } else if stability.is_deref_stable() && let Some(parent) = get_parent_expr(cx, expr) { - self.state = Some(( - State::ExplicitDeref { mutability: None }, - StateData { - first_expr: parent, - adjusted_ty, - }, - )); + self.state = Some((State::ExplicitDeref { mutability: None }, StateData { + first_expr: parent, + adjusted_ty, + })); } }, @@ -1138,20 +1126,17 @@ impl<'tcx> Dereferencing<'tcx> { if let Some(outer_pat) = self.ref_locals.get_mut(&local) { if let Some(pat) = outer_pat { // Check for auto-deref - if !matches!( - cx.typeck_results().expr_adjustments(e), - [ - Adjustment { - kind: Adjust::Deref(_), - .. - }, - Adjustment { - kind: Adjust::Deref(_), - .. - }, + if !matches!(cx.typeck_results().expr_adjustments(e), [ + Adjustment { + kind: Adjust::Deref(_), .. - ] - ) { + }, + Adjustment { + kind: Adjust::Deref(_), + .. + }, + .. + ]) { match get_parent_expr(cx, e) { // Field accesses are the same no matter the number of references. Some(Expr { diff --git a/clippy_lints/src/derivable_impls.rs b/clippy_lints/src/derivable_impls.rs index f27f68e2cbc..2920bbb4c81 100644 --- a/clippy_lints/src/derivable_impls.rs +++ b/clippy_lints/src/derivable_impls.rs @@ -1,5 +1,5 @@ -use clippy_config::msrvs::{self, Msrv}; use clippy_config::Conf; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::indent_of; use clippy_utils::{is_default_equivalent, peel_blocks}; diff --git a/clippy_lints/src/derive.rs b/clippy_lints/src/derive.rs index 636698e96f6..61c151d4f9d 100644 --- a/clippy_lints/src/derive.rs +++ b/clippy_lints/src/derive.rs @@ -3,7 +3,7 @@ use clippy_utils::ty::{implements_trait, implements_trait_with_env, is_copy}; use clippy_utils::{has_non_exhaustive_attr, is_lint_allowed, match_def_path, paths}; use rustc_errors::Applicability; use rustc_hir::def_id::DefId; -use rustc_hir::intravisit::{walk_expr, walk_fn, walk_item, FnKind, Visitor}; +use rustc_hir::intravisit::{FnKind, Visitor, walk_expr, walk_fn, walk_item}; use rustc_hir::{ self as hir, BlockCheckMode, BodyId, Expr, ExprKind, FnDecl, Impl, Item, ItemKind, Safety, UnsafeSource, }; @@ -15,7 +15,7 @@ use rustc_middle::ty::{ }; use rustc_session::declare_lint_pass; use rustc_span::def_id::LocalDefId; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/doc/empty_line_after.rs b/clippy_lints/src/doc/empty_line_after.rs index 289debe0a6a..125b9077061 100644 --- a/clippy_lints/src/doc/empty_line_after.rs +++ b/clippy_lints/src/doc/empty_line_after.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::{snippet_indent, SpanRangeExt}; +use clippy_utils::source::{SpanRangeExt, snippet_indent}; use clippy_utils::tokenize_with_text; use itertools::Itertools; use rustc_ast::token::CommentKind; @@ -219,13 +219,10 @@ fn check_gaps(cx: &LateContext<'_>, gaps: &[Gap<'_>]) -> bool { if let Some(owner) = cx.last_node_with_lint_attrs.as_owner() { let def_id = owner.to_def_id(); let def_descr = cx.tcx.def_descr(def_id); - diag.span_label( - cx.tcx.def_span(def_id), - match kind { - StopKind::Attr => format!("the attribute applies to this {def_descr}"), - StopKind::Doc(_) => format!("the comment documents this {def_descr}"), - }, - ); + diag.span_label(cx.tcx.def_span(def_id), match kind { + StopKind::Attr => format!("the attribute applies to this {def_descr}"), + StopKind::Doc(_) => format!("the comment documents this {def_descr}"), + }); } diag.multipart_suggestion_with_style( diff --git a/clippy_lints/src/doc/link_with_quotes.rs b/clippy_lints/src/doc/link_with_quotes.rs index 01191e811b0..1d4345e4541 100644 --- a/clippy_lints/src/doc/link_with_quotes.rs +++ b/clippy_lints/src/doc/link_with_quotes.rs @@ -3,7 +3,7 @@ use std::ops::Range; use clippy_utils::diagnostics::span_lint; use rustc_lint::LateContext; -use super::{Fragments, DOC_LINK_WITH_QUOTES}; +use super::{DOC_LINK_WITH_QUOTES, Fragments}; pub fn check(cx: &LateContext<'_>, trimmed_text: &str, range: Range, fragments: Fragments<'_>) { if ((trimmed_text.starts_with('\'') && trimmed_text.ends_with('\'')) diff --git a/clippy_lints/src/doc/missing_headers.rs b/clippy_lints/src/doc/missing_headers.rs index e3d74840726..c9173030a55 100644 --- a/clippy_lints/src/doc/missing_headers.rs +++ b/clippy_lints/src/doc/missing_headers.rs @@ -5,7 +5,7 @@ use clippy_utils::{is_doc_hidden, return_ty}; use rustc_hir::{BodyId, FnSig, OwnerId, Safety}; use rustc_lint::LateContext; use rustc_middle::ty; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; pub fn check( cx: &LateContext<'_>, diff --git a/clippy_lints/src/doc/mod.rs b/clippy_lints/src/doc/mod.rs index f2c87f0fd70..0ae1fad5692 100644 --- a/clippy_lints/src/doc/mod.rs +++ b/clippy_lints/src/doc/mod.rs @@ -23,12 +23,12 @@ use rustc_middle::hir::nested_filter; use rustc_middle::lint::in_external_macro; use rustc_middle::ty; use rustc_resolve::rustdoc::{ - add_doc_fragment, attrs_to_doc_fragments, main_body_opts, source_span_for_markdown_range, span_of_fragments, - DocFragment, + DocFragment, add_doc_fragment, attrs_to_doc_fragments, main_body_opts, source_span_for_markdown_range, + span_of_fragments, }; use rustc_session::impl_lint_pass; use rustc_span::edition::Edition; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; use std::ops::Range; use url::Url; diff --git a/clippy_lints/src/doc/needless_doctest_main.rs b/clippy_lints/src/doc/needless_doctest_main.rs index c3e3c0431e6..9ba2723157a 100644 --- a/clippy_lints/src/doc/needless_doctest_main.rs +++ b/clippy_lints/src/doc/needless_doctest_main.rs @@ -13,7 +13,7 @@ use rustc_parse::parser::ForceCollect; use rustc_session::parse::ParseSess; use rustc_span::edition::Edition; use rustc_span::source_map::{FilePathMapping, SourceMap}; -use rustc_span::{sym, FileName, Pos}; +use rustc_span::{FileName, Pos, sym}; use super::Fragments; diff --git a/clippy_lints/src/entry.rs b/clippy_lints/src/entry.rs index 9c5100a8c1a..70524e458c7 100644 --- a/clippy_lints/src/entry.rs +++ b/clippy_lints/src/entry.rs @@ -1,17 +1,17 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::{reindent_multiline, snippet_indent, snippet_with_applicability, snippet_with_context}; use clippy_utils::{ - can_move_expr_to_closure_no_visit, higher, is_expr_final_block_expr, is_expr_used_or_unified, - peel_hir_expr_while, SpanlessEq, + SpanlessEq, can_move_expr_to_closure_no_visit, higher, is_expr_final_block_expr, is_expr_used_or_unified, + peel_hir_expr_while, }; use core::fmt::{self, Write}; use rustc_errors::Applicability; use rustc_hir::hir_id::HirIdSet; -use rustc_hir::intravisit::{walk_expr, Visitor}; +use rustc_hir::intravisit::{Visitor, walk_expr}; use rustc_hir::{Block, Expr, ExprKind, HirId, Pat, Stmt, StmtKind, UnOp}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; -use rustc_span::{sym, Span, SyntaxContext, DUMMY_SP}; +use rustc_span::{DUMMY_SP, Span, SyntaxContext, sym}; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/enum_clike.rs b/clippy_lints/src/enum_clike.rs index 4755cefe784..e9e9d00907e 100644 --- a/clippy_lints/src/enum_clike.rs +++ b/clippy_lints/src/enum_clike.rs @@ -1,4 +1,4 @@ -use clippy_utils::consts::{mir_to_const, Constant}; +use clippy_utils::consts::{Constant, mir_to_const}; use clippy_utils::diagnostics::span_lint; use rustc_hir::{Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; diff --git a/clippy_lints/src/escape.rs b/clippy_lints/src/escape.rs index 80360697941..5588124e791 100644 --- a/clippy_lints/src/escape.rs +++ b/clippy_lints/src/escape.rs @@ -1,15 +1,15 @@ use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_hir; -use rustc_hir::{intravisit, AssocItemKind, Body, FnDecl, HirId, HirIdSet, Impl, ItemKind, Node, Pat, PatKind}; +use rustc_hir::{AssocItemKind, Body, FnDecl, HirId, HirIdSet, Impl, ItemKind, Node, Pat, PatKind, intravisit}; use rustc_hir_typeck::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::mir::FakeReadCause; use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::{self, TraitRef, Ty, TyCtxt}; use rustc_session::impl_lint_pass; +use rustc_span::Span; use rustc_span::def_id::LocalDefId; use rustc_span::symbol::kw; -use rustc_span::Span; use rustc_target::spec::abi::Abi; pub struct BoxedLocal { diff --git a/clippy_lints/src/excessive_bools.rs b/clippy_lints/src/excessive_bools.rs index 8f469efb1b5..c88fb50b5af 100644 --- a/clippy_lints/src/excessive_bools.rs +++ b/clippy_lints/src/excessive_bools.rs @@ -5,8 +5,8 @@ use rustc_hir::intravisit::FnKind; use rustc_hir::{Body, FnDecl, Item, ItemKind, TraitFn, TraitItem, TraitItemKind, Ty}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::impl_lint_pass; -use rustc_span::def_id::LocalDefId; use rustc_span::Span; +use rustc_span::def_id::LocalDefId; use rustc_target::spec::abi::Abi; declare_clippy_lint! { diff --git a/clippy_lints/src/excessive_nesting.rs b/clippy_lints/src/excessive_nesting.rs index 5154edd4399..ce0e0faa014 100644 --- a/clippy_lints/src/excessive_nesting.rs +++ b/clippy_lints/src/excessive_nesting.rs @@ -2,7 +2,7 @@ use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::source::snippet; use rustc_ast::node_id::NodeSet; -use rustc_ast::visit::{walk_block, walk_item, Visitor}; +use rustc_ast::visit::{Visitor, walk_block, walk_item}; use rustc_ast::{Block, Crate, Inline, Item, ItemKind, ModKind, NodeId}; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; use rustc_middle::lint::in_external_macro; diff --git a/clippy_lints/src/explicit_write.rs b/clippy_lints/src/explicit_write.rs index 3c4a043a732..5b423a96918 100644 --- a/clippy_lints/src/explicit_write.rs +++ b/clippy_lints/src/explicit_write.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::macros::{format_args_inputs_span, FormatArgsStorage}; +use clippy_utils::macros::{FormatArgsStorage, format_args_inputs_span}; use clippy_utils::source::snippet_with_applicability; use clippy_utils::{is_expn_of, path_def_id}; use rustc_errors::Applicability; @@ -7,7 +7,7 @@ use rustc_hir::def::Res; use rustc_hir::{BindingMode, Block, BlockCheckMode, Expr, ExprKind, Node, PatKind, QPath, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::impl_lint_pass; -use rustc_span::{sym, ExpnId}; +use rustc_span::{ExpnId, sym}; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/extra_unused_type_parameters.rs b/clippy_lints/src/extra_unused_type_parameters.rs index bfe4e253ae4..bf9388b4a70 100644 --- a/clippy_lints/src/extra_unused_type_parameters.rs +++ b/clippy_lints/src/extra_unused_type_parameters.rs @@ -3,7 +3,7 @@ use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_then}; use clippy_utils::{is_from_proc_macro, trait_ref_of_method}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::Applicability; -use rustc_hir::intravisit::{walk_impl_item, walk_item, walk_param_bound, walk_ty, Visitor}; +use rustc_hir::intravisit::{Visitor, walk_impl_item, walk_item, walk_param_bound, walk_ty}; use rustc_hir::{ BodyId, ExprKind, GenericBound, GenericParam, GenericParamKind, Generics, ImplItem, ImplItemKind, Item, ItemKind, PredicateOrigin, Ty, TyKind, WherePredicate, @@ -12,8 +12,8 @@ use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::hir::nested_filter; use rustc_middle::lint::in_external_macro; use rustc_session::impl_lint_pass; -use rustc_span::def_id::{DefId, LocalDefId}; use rustc_span::Span; +use rustc_span::def_id::{DefId, LocalDefId}; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/fallible_impl_from.rs b/clippy_lints/src/fallible_impl_from.rs index 0446943321a..747ea9a4344 100644 --- a/clippy_lints/src/fallible_impl_from.rs +++ b/clippy_lints/src/fallible_impl_from.rs @@ -6,7 +6,7 @@ use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_session::declare_lint_pass; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/floating_point_arithmetic.rs b/clippy_lints/src/floating_point_arithmetic.rs index bf4bcabfe89..8da6623f34d 100644 --- a/clippy_lints/src/floating_point_arithmetic.rs +++ b/clippy_lints/src/floating_point_arithmetic.rs @@ -1,4 +1,4 @@ -use clippy_utils::consts::Constant::{Int, F32, F64}; +use clippy_utils::consts::Constant::{F32, F64, Int}; use clippy_utils::consts::{ConstEvalCtxt, Constant}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::{ diff --git a/clippy_lints/src/format.rs b/clippy_lints/src/format.rs index 4dedff69b9a..5e3f6b6a137 100644 --- a/clippy_lints/src/format.rs +++ b/clippy_lints/src/format.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::macros::{find_format_arg_expr, root_macro_call_first_node, FormatArgsStorage}; -use clippy_utils::source::{snippet_with_context, SpanRangeExt}; +use clippy_utils::macros::{FormatArgsStorage, find_format_arg_expr, root_macro_call_first_node}; +use clippy_utils::source::{SpanRangeExt, snippet_with_context}; use clippy_utils::sugg::Sugg; use rustc_ast::{FormatArgsPiece, FormatOptions, FormatTrait}; use rustc_errors::Applicability; @@ -8,7 +8,7 @@ use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_session::impl_lint_pass; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/format_args.rs b/clippy_lints/src/format_args.rs index 020c0c5440d..83ab9f6557b 100644 --- a/clippy_lints/src/format_args.rs +++ b/clippy_lints/src/format_args.rs @@ -1,11 +1,12 @@ use arrayvec::ArrayVec; -use clippy_config::msrvs::{self, Msrv}; use clippy_config::Conf; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; use clippy_utils::is_diag_trait_item; use clippy_utils::macros::{ - find_format_arg_expr, format_arg_removal_span, format_placeholder_format_span, is_assert_macro, is_format_macro, - is_panic, matching_root_macro_call, root_macro_call_first_node, FormatArgsStorage, FormatParamUsage, MacroCall, + FormatArgsStorage, FormatParamUsage, MacroCall, find_format_arg_expr, format_arg_removal_span, + format_placeholder_format_span, is_assert_macro, is_format_macro, is_panic, matching_root_macro_call, + root_macro_call_first_node, }; use clippy_utils::source::SpanRangeExt; use clippy_utils::ty::{implements_trait, is_type_lang_item}; @@ -18,11 +19,11 @@ use rustc_errors::Applicability; use rustc_errors::SuggestionStyle::{CompletelyHidden, ShowCode}; use rustc_hir::{Expr, ExprKind, LangItem}; use rustc_lint::{LateContext, LateLintPass, LintContext}; -use rustc_middle::ty::adjustment::{Adjust, Adjustment}; use rustc_middle::ty::Ty; +use rustc_middle::ty::adjustment::{Adjust, Adjustment}; use rustc_session::impl_lint_pass; use rustc_span::edition::Edition::Edition2021; -use rustc_span::{sym, Span, Symbol}; +use rustc_span::{Span, Symbol, sym}; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/format_impl.rs b/clippy_lints/src/format_impl.rs index 7cd12ac7db8..c196f404ce6 100644 --- a/clippy_lints/src/format_impl.rs +++ b/clippy_lints/src/format_impl.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg}; -use clippy_utils::macros::{find_format_arg_expr, is_format_macro, root_macro_call_first_node, FormatArgsStorage}; +use clippy_utils::macros::{FormatArgsStorage, find_format_arg_expr, is_format_macro, root_macro_call_first_node}; use clippy_utils::{get_parent_as_impl, is_diag_trait_item, path_to_local, peel_ref_operators}; use rustc_ast::{FormatArgsPiece, FormatTrait}; use rustc_errors::Applicability; @@ -7,7 +7,7 @@ use rustc_hir::{Expr, ExprKind, Impl, ImplItem, ImplItemKind, QPath}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::impl_lint_pass; use rustc_span::symbol::kw; -use rustc_span::{sym, Symbol}; +use rustc_span::{Symbol, sym}; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/format_push_string.rs b/clippy_lints/src/format_push_string.rs index c6f03c3a7cf..8b1f86cbb91 100644 --- a/clippy_lints/src/format_push_string.rs +++ b/clippy_lints/src/format_push_string.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::ty::is_type_lang_item; use clippy_utils::higher; +use clippy_utils::ty::is_type_lang_item; use rustc_hir::{BinOpKind, Expr, ExprKind, LangItem, MatchSource}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; diff --git a/clippy_lints/src/from_over_into.rs b/clippy_lints/src/from_over_into.rs index 5e9098474dc..d716a624cc6 100644 --- a/clippy_lints/src/from_over_into.rs +++ b/clippy_lints/src/from_over_into.rs @@ -1,11 +1,11 @@ -use clippy_config::msrvs::{self, Msrv}; use clippy_config::Conf; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::macros::span_is_local; use clippy_utils::path_def_id; use clippy_utils::source::SpanRangeExt; use rustc_errors::Applicability; -use rustc_hir::intravisit::{walk_path, Visitor}; +use rustc_hir::intravisit::{Visitor, walk_path}; use rustc_hir::{ FnRetTy, GenericArg, GenericArgs, HirId, Impl, ImplItemKind, ImplItemRef, Item, ItemKind, PatKind, Path, PathSegment, Ty, TyKind, diff --git a/clippy_lints/src/from_str_radix_10.rs b/clippy_lints/src/from_str_radix_10.rs index e5fa67d6964..7361546153c 100644 --- a/clippy_lints/src/from_str_radix_10.rs +++ b/clippy_lints/src/from_str_radix_10.rs @@ -3,7 +3,7 @@ use clippy_utils::sugg::Sugg; use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item}; use clippy_utils::{is_in_const_context, is_integer_literal}; use rustc_errors::Applicability; -use rustc_hir::{def, Expr, ExprKind, LangItem, PrimTy, QPath, TyKind}; +use rustc_hir::{Expr, ExprKind, LangItem, PrimTy, QPath, TyKind, def}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::Ty; use rustc_session::declare_lint_pass; diff --git a/clippy_lints/src/functions/mod.rs b/clippy_lints/src/functions/mod.rs index 0f48941783b..ba8a459c917 100644 --- a/clippy_lints/src/functions/mod.rs +++ b/clippy_lints/src/functions/mod.rs @@ -14,8 +14,8 @@ use rustc_hir::intravisit; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::TyCtxt; use rustc_session::impl_lint_pass; -use rustc_span::def_id::{DefIdSet, LocalDefId}; use rustc_span::Span; +use rustc_span::def_id::{DefIdSet, LocalDefId}; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/functions/must_use.rs b/clippy_lints/src/functions/must_use.rs index 93828121047..cfd11e9339f 100644 --- a/clippy_lints/src/functions/must_use.rs +++ b/clippy_lints/src/functions/must_use.rs @@ -8,7 +8,7 @@ use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::{LateContext, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::{self, Ty}; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; use clippy_utils::attrs::is_proc_macro; use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_then}; diff --git a/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs b/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs index 1aeefe73cf6..c2b40ae01d4 100644 --- a/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs +++ b/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs @@ -1,4 +1,4 @@ -use rustc_hir::{self as hir, intravisit, HirId, HirIdSet}; +use rustc_hir::{self as hir, HirId, HirIdSet, intravisit}; use rustc_lint::LateContext; use rustc_middle::ty; use rustc_span::def_id::LocalDefId; diff --git a/clippy_lints/src/functions/renamed_function_params.rs b/clippy_lints/src/functions/renamed_function_params.rs index c7de0385c02..ac2e866e4ff 100644 --- a/clippy_lints/src/functions/renamed_function_params.rs +++ b/clippy_lints/src/functions/renamed_function_params.rs @@ -4,8 +4,8 @@ use rustc_hir::def_id::{DefId, DefIdSet}; use rustc_hir::hir_id::OwnerId; use rustc_hir::{Impl, ImplItem, ImplItemKind, ImplItemRef, ItemKind, Node, TraitRef}; use rustc_lint::LateContext; -use rustc_span::symbol::{kw, Ident, Symbol}; use rustc_span::Span; +use rustc_span::symbol::{Ident, Symbol, kw}; use super::RENAMED_FUNCTION_PARAMS; diff --git a/clippy_lints/src/functions/result.rs b/clippy_lints/src/functions/result.rs index c3a0b40a677..d4eaa166320 100644 --- a/clippy_lints/src/functions/result.rs +++ b/clippy_lints/src/functions/result.rs @@ -3,11 +3,11 @@ use rustc_hir as hir; use rustc_lint::{LateContext, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::{self, Ty}; -use rustc_span::{sym, Span}; +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::{approx_ty_size, is_type_diagnostic_item, AdtVariantInfo}; +use clippy_utils::ty::{AdtVariantInfo, approx_ty_size, is_type_diagnostic_item}; use super::{RESULT_LARGE_ERR, RESULT_UNIT_ERR}; diff --git a/clippy_lints/src/future_not_send.rs b/clippy_lints/src/future_not_send.rs index 9488ba75686..a4dbe134f36 100644 --- a/clippy_lints/src/future_not_send.rs +++ b/clippy_lints/src/future_not_send.rs @@ -8,7 +8,7 @@ use rustc_middle::ty::print::PrintTraitRefExt; use rustc_middle::ty::{self, AliasTy, ClauseKind, PredicateKind}; use rustc_session::declare_lint_pass; use rustc_span::def_id::LocalDefId; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::traits::{self, FulfillmentError, ObligationCtxt}; diff --git a/clippy_lints/src/if_then_some_else_none.rs b/clippy_lints/src/if_then_some_else_none.rs index 55f9625709b..d63c18c0eda 100644 --- a/clippy_lints/src/if_then_some_else_none.rs +++ b/clippy_lints/src/if_then_some_else_none.rs @@ -1,5 +1,5 @@ -use clippy_config::msrvs::{self, Msrv}; use clippy_config::Conf; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::eager_or_lazy::switch_to_eager_eval; use clippy_utils::source::snippet_with_context; diff --git a/clippy_lints/src/implicit_hasher.rs b/clippy_lints/src/implicit_hasher.rs index e56f33f8dcf..f683925145a 100644 --- a/clippy_lints/src/implicit_hasher.rs +++ b/clippy_lints/src/implicit_hasher.rs @@ -3,18 +3,18 @@ use std::collections::BTreeMap; use rustc_errors::{Applicability, Diag}; use rustc_hir as hir; -use rustc_hir::intravisit::{walk_body, walk_expr, walk_inf, walk_ty, Visitor}; +use rustc_hir::intravisit::{Visitor, walk_body, walk_expr, walk_inf, walk_ty}; use rustc_hir::{Body, Expr, ExprKind, GenericArg, Item, ItemKind, QPath, TyKind}; use rustc_hir_analysis::lower_ty; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::nested_filter; use rustc_middle::ty::{Ty, TypeckResults}; use rustc_session::declare_lint_pass; -use rustc_span::symbol::sym; use rustc_span::Span; +use rustc_span::symbol::sym; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::{snippet, IntoSpan, SpanRangeExt}; +use clippy_utils::source::{IntoSpan, SpanRangeExt, snippet}; use clippy_utils::ty::is_type_diagnostic_item; declare_clippy_lint! { diff --git a/clippy_lints/src/implicit_saturating_sub.rs b/clippy_lints/src/implicit_saturating_sub.rs index 3536309d83c..f4a64f5c20b 100644 --- a/clippy_lints/src/implicit_saturating_sub.rs +++ b/clippy_lints/src/implicit_saturating_sub.rs @@ -1,9 +1,9 @@ -use clippy_config::msrvs::{self, Msrv}; use clippy_config::Conf; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; use clippy_utils::source::snippet_opt; use clippy_utils::{ - higher, is_in_const_context, is_integer_literal, path_to_local, peel_blocks, peel_blocks_with_stmt, SpanlessEq, + SpanlessEq, higher, is_in_const_context, is_integer_literal, path_to_local, peel_blocks, peel_blocks_with_stmt, }; use rustc_ast::ast::LitKind; use rustc_data_structures::packed::Pu128; diff --git a/clippy_lints/src/incompatible_msrv.rs b/clippy_lints/src/incompatible_msrv.rs index 2ad045e1268..0b3a6ee1bea 100644 --- a/clippy_lints/src/incompatible_msrv.rs +++ b/clippy_lints/src/incompatible_msrv.rs @@ -1,5 +1,5 @@ -use clippy_config::msrvs::Msrv; use clippy_config::Conf; +use clippy_config::msrvs::Msrv; use clippy_utils::diagnostics::span_lint; use clippy_utils::is_in_test; use rustc_attr::{StabilityLevel, StableSince}; @@ -7,7 +7,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc_hir::{Expr, ExprKind, HirId}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::TyCtxt; -use rustc_session::{impl_lint_pass, RustcVersion}; +use rustc_session::{RustcVersion, impl_lint_pass}; use rustc_span::def_id::DefId; use rustc_span::{ExpnKind, Span}; diff --git a/clippy_lints/src/index_refutable_slice.rs b/clippy_lints/src/index_refutable_slice.rs index 2f9661c9ea3..39afb6810b8 100644 --- a/clippy_lints/src/index_refutable_slice.rs +++ b/clippy_lints/src/index_refutable_slice.rs @@ -1,5 +1,5 @@ -use clippy_config::msrvs::{self, Msrv}; use clippy_config::Conf; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::consts::{ConstEvalCtxt, Constant}; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::higher::IfLet; @@ -8,14 +8,14 @@ use clippy_utils::{is_expn_of, is_lint_allowed, path_to_local}; use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; use rustc_errors::Applicability; use rustc_hir as hir; -use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::HirId; +use rustc_hir::intravisit::{self, Visitor}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::nested_filter; use rustc_middle::ty; use rustc_session::impl_lint_pass; -use rustc_span::symbol::Ident; use rustc_span::Span; +use rustc_span::symbol::Ident; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/ineffective_open_options.rs b/clippy_lints/src/ineffective_open_options.rs index af5b1f95739..3a28553b55e 100644 --- a/clippy_lints/src/ineffective_open_options.rs +++ b/clippy_lints/src/ineffective_open_options.rs @@ -7,7 +7,7 @@ use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_session::declare_lint_pass; -use rustc_span::{sym, BytePos, Span}; +use rustc_span::{BytePos, Span, sym}; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/instant_subtraction.rs b/clippy_lints/src/instant_subtraction.rs index 6d6820311b6..66931a7f98c 100644 --- a/clippy_lints/src/instant_subtraction.rs +++ b/clippy_lints/src/instant_subtraction.rs @@ -1,5 +1,5 @@ -use clippy_config::msrvs::{self, Msrv}; use clippy_config::Conf; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_context; use clippy_utils::sugg::Sugg; diff --git a/clippy_lints/src/item_name_repetitions.rs b/clippy_lints/src/item_name_repetitions.rs index 74bf82f58bd..66a8a3167a4 100644 --- a/clippy_lints/src/item_name_repetitions.rs +++ b/clippy_lints/src/item_name_repetitions.rs @@ -8,8 +8,8 @@ use rustc_data_structures::fx::FxHashSet; use rustc_hir::{EnumDef, FieldDef, Item, ItemKind, OwnerId, Variant, VariantData}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::impl_lint_pass; -use rustc_span::symbol::Symbol; use rustc_span::Span; +use rustc_span::symbol::Symbol; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/items_after_test_module.rs b/clippy_lints/src/items_after_test_module.rs index 8caa484bb99..1ac549b74ac 100644 --- a/clippy_lints/src/items_after_test_module.rs +++ b/clippy_lints/src/items_after_test_module.rs @@ -6,7 +6,7 @@ use rustc_hir::{HirId, Item, ItemKind, Mod}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; use rustc_span::hygiene::AstPass; -use rustc_span::{sym, ExpnKind}; +use rustc_span::{ExpnKind, sym}; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/iter_not_returning_iterator.rs b/clippy_lints/src/iter_not_returning_iterator.rs index ba0cd5d6eb3..b19b348c743 100644 --- a/clippy_lints/src/iter_not_returning_iterator.rs +++ b/clippy_lints/src/iter_not_returning_iterator.rs @@ -4,7 +4,7 @@ use rustc_hir::def_id::LocalDefId; use rustc_hir::{FnSig, ImplItem, ImplItemKind, Item, ItemKind, Node, TraitItem, TraitItemKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; -use rustc_span::{sym, Symbol}; +use rustc_span::{Symbol, sym}; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/iter_over_hash_type.rs b/clippy_lints/src/iter_over_hash_type.rs index f162948bb44..5131f5b7269 100644 --- a/clippy_lints/src/iter_over_hash_type.rs +++ b/clippy_lints/src/iter_over_hash_type.rs @@ -55,7 +55,9 @@ impl LateLintPass<'_> for IterOverHashType { if let Some(for_loop) = ForLoop::hir(expr) && !for_loop.body.span.from_expansion() && let ty = cx.typeck_results().expr_ty(for_loop.arg).peel_refs() - && hash_iter_tys.into_iter().any(|sym| is_type_diagnostic_item(cx, ty, sym)) + && hash_iter_tys + .into_iter() + .any(|sym| is_type_diagnostic_item(cx, ty, sym)) { span_lint( cx, diff --git a/clippy_lints/src/large_enum_variant.rs b/clippy_lints/src/large_enum_variant.rs index 2f027c11707..923089c7223 100644 --- a/clippy_lints/src/large_enum_variant.rs +++ b/clippy_lints/src/large_enum_variant.rs @@ -1,7 +1,7 @@ use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet_with_applicability; -use clippy_utils::ty::{approx_ty_size, is_copy, AdtVariantInfo}; +use clippy_utils::ty::{AdtVariantInfo, approx_ty_size, is_copy}; use rustc_errors::Applicability; use rustc_hir::{Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; diff --git a/clippy_lints/src/large_stack_arrays.rs b/clippy_lints/src/large_stack_arrays.rs index 15a75b06089..0f061d6de50 100644 --- a/clippy_lints/src/large_stack_arrays.rs +++ b/clippy_lints/src/large_stack_arrays.rs @@ -8,7 +8,7 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::{self, ConstKind}; use rustc_session::impl_lint_pass; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/legacy_numeric_constants.rs b/clippy_lints/src/legacy_numeric_constants.rs index ccab1e27d3b..e17d6213679 100644 --- a/clippy_lints/src/legacy_numeric_constants.rs +++ b/clippy_lints/src/legacy_numeric_constants.rs @@ -1,5 +1,5 @@ -use clippy_config::msrvs::{Msrv, NUMERIC_ASSOCIATED_CONSTANTS}; use clippy_config::Conf; +use clippy_config::msrvs::{Msrv, NUMERIC_ASSOCIATED_CONSTANTS}; use clippy_utils::diagnostics::{span_lint_and_then, span_lint_hir_and_then}; use clippy_utils::{get_parent_expr, is_from_proc_macro}; use hir::def_id::DefId; @@ -10,7 +10,7 @@ use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_session::impl_lint_pass; use rustc_span::symbol::kw; -use rustc_span::{sym, Symbol}; +use rustc_span::{Symbol, sym}; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/len_zero.rs b/clippy_lints/src/len_zero.rs index 0bc7fc2dd9d..c1ba66de57e 100644 --- a/clippy_lints/src/len_zero.rs +++ b/clippy_lints/src/len_zero.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then}; -use clippy_utils::source::{snippet_with_context, SpanRangeExt}; -use clippy_utils::sugg::{has_enclosing_paren, Sugg}; +use clippy_utils::source::{SpanRangeExt, snippet_with_context}; +use clippy_utils::sugg::{Sugg, has_enclosing_paren}; use clippy_utils::{get_item_name, get_parent_as_impl, is_lint_allowed, peel_ref_operators}; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index b21d3f8d09e..1d41f568f37 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -394,7 +394,7 @@ mod zero_sized_map_values; mod zombie_processes; // end lints modules, do not remove this comment, it’s used in `update_lints` -use clippy_config::{get_configuration_metadata, Conf}; +use clippy_config::{Conf, get_configuration_metadata}; use clippy_utils::macros::FormatArgsStorage; use rustc_data_structures::fx::FxHashSet; use rustc_lint::{Lint, LintId}; diff --git a/clippy_lints/src/lifetimes.rs b/clippy_lints/src/lifetimes.rs index ba34af9c100..755afe959b3 100644 --- a/clippy_lints/src/lifetimes.rs +++ b/clippy_lints/src/lifetimes.rs @@ -3,25 +3,25 @@ use clippy_utils::trait_ref_of_method; use itertools::Itertools; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::Applicability; +use rustc_hir::FnRetTy::Return; use rustc_hir::intravisit::nested_filter::{self as hir_nested_filter, NestedFilter}; use rustc_hir::intravisit::{ - walk_fn_decl, walk_generic_param, walk_generics, walk_impl_item_ref, walk_item, walk_param_bound, - walk_poly_trait_ref, walk_trait_ref, walk_ty, Visitor, + Visitor, walk_fn_decl, walk_generic_param, walk_generics, walk_impl_item_ref, walk_item, walk_param_bound, + walk_poly_trait_ref, walk_trait_ref, walk_ty, }; -use rustc_hir::FnRetTy::Return; use rustc_hir::{ - lang_items, BareFnTy, BodyId, FnDecl, FnSig, GenericArg, GenericBound, GenericParam, GenericParamKind, Generics, - Impl, ImplItem, ImplItemKind, Item, ItemKind, Lifetime, LifetimeName, LifetimeParamKind, Node, PolyTraitRef, - PredicateOrigin, TraitFn, TraitItem, TraitItemKind, Ty, TyKind, WherePredicate, + BareFnTy, BodyId, FnDecl, FnSig, GenericArg, GenericBound, GenericParam, GenericParamKind, Generics, Impl, + ImplItem, ImplItemKind, Item, ItemKind, Lifetime, LifetimeName, LifetimeParamKind, Node, PolyTraitRef, + PredicateOrigin, TraitFn, TraitItem, TraitItemKind, Ty, TyKind, WherePredicate, lang_items, }; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::hir::map::Map; use rustc_middle::hir::nested_filter as middle_nested_filter; use rustc_middle::lint::in_external_macro; use rustc_session::declare_lint_pass; -use rustc_span::def_id::LocalDefId; -use rustc_span::symbol::{kw, Ident, Symbol}; use rustc_span::Span; +use rustc_span::def_id::LocalDefId; +use rustc_span::symbol::{Ident, Symbol, kw}; use std::ops::ControlFlow; declare_clippy_lint! { diff --git a/clippy_lints/src/loops/explicit_counter_loop.rs b/clippy_lints/src/loops/explicit_counter_loop.rs index 73a23615c2d..9aa4d2f0adc 100644 --- a/clippy_lints/src/loops/explicit_counter_loop.rs +++ b/clippy_lints/src/loops/explicit_counter_loop.rs @@ -1,4 +1,4 @@ -use super::{make_iterator_snippet, IncrementVisitor, InitializeVisitor, EXPLICIT_COUNTER_LOOP}; +use super::{EXPLICIT_COUNTER_LOOP, IncrementVisitor, InitializeVisitor, make_iterator_snippet}; use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; use clippy_utils::source::snippet_with_applicability; use clippy_utils::{get_enclosing_block, is_integer_const}; diff --git a/clippy_lints/src/loops/infinite_loop.rs b/clippy_lints/src/loops/infinite_loop.rs index 5b5bb88c179..858e3be5093 100644 --- a/clippy_lints/src/loops/infinite_loop.rs +++ b/clippy_lints/src/loops/infinite_loop.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::{fn_def_id, is_from_proc_macro, is_lint_allowed}; -use hir::intravisit::{walk_expr, Visitor}; +use hir::intravisit::{Visitor, walk_expr}; use hir::{Expr, ExprKind, FnRetTy, FnSig, Node}; use rustc_ast::Label; use rustc_errors::Applicability; diff --git a/clippy_lints/src/loops/manual_find.rs b/clippy_lints/src/loops/manual_find.rs index b27528c11d4..bfe2e68b5d1 100644 --- a/clippy_lints/src/loops/manual_find.rs +++ b/clippy_lints/src/loops/manual_find.rs @@ -1,5 +1,5 @@ -use super::utils::make_iterator_snippet; use super::MANUAL_FIND; +use super::utils::make_iterator_snippet; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::implements_trait; diff --git a/clippy_lints/src/loops/manual_flatten.rs b/clippy_lints/src/loops/manual_flatten.rs index dbc094a6d73..366c310592f 100644 --- a/clippy_lints/src/loops/manual_flatten.rs +++ b/clippy_lints/src/loops/manual_flatten.rs @@ -1,5 +1,5 @@ -use super::utils::make_iterator_snippet; use super::MANUAL_FLATTEN; +use super::utils::make_iterator_snippet; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::visitors::is_local_used; use clippy_utils::{higher, path_to_local_id, peel_blocks_with_stmt}; diff --git a/clippy_lints/src/loops/manual_while_let_some.rs b/clippy_lints/src/loops/manual_while_let_some.rs index 55d1b9ee676..7476a87267f 100644 --- a/clippy_lints/src/loops/manual_while_let_some.rs +++ b/clippy_lints/src/loops/manual_while_let_some.rs @@ -1,10 +1,10 @@ +use clippy_utils::SpanlessEq; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet; -use clippy_utils::SpanlessEq; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, Pat, Stmt, StmtKind, UnOp}; use rustc_lint::LateContext; -use rustc_span::{sym, Symbol, Span}; +use rustc_span::{Span, Symbol, sym}; use std::borrow::Cow; use super::MANUAL_WHILE_LET_SOME; diff --git a/clippy_lints/src/loops/mod.rs b/clippy_lints/src/loops/mod.rs index 5155fd76b25..17215621d2a 100644 --- a/clippy_lints/src/loops/mod.rs +++ b/clippy_lints/src/loops/mod.rs @@ -22,15 +22,15 @@ mod while_immutable_condition; mod while_let_loop; mod while_let_on_iterator; -use clippy_config::msrvs::Msrv; use clippy_config::Conf; +use clippy_config::msrvs::Msrv; use clippy_utils::higher; use rustc_ast::Label; use rustc_hir::{Expr, ExprKind, LoopSource, Pat}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::impl_lint_pass; use rustc_span::Span; -use utils::{make_iterator_snippet, IncrementVisitor, InitializeVisitor}; +use utils::{IncrementVisitor, InitializeVisitor, make_iterator_snippet}; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/loops/needless_range_loop.rs b/clippy_lints/src/loops/needless_range_loop.rs index e18e4374667..20dd5a311dc 100644 --- a/clippy_lints/src/loops/needless_range_loop.rs +++ b/clippy_lints/src/loops/needless_range_loop.rs @@ -3,17 +3,17 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet; use clippy_utils::ty::has_iter_method; use clippy_utils::visitors::is_local_used; -use clippy_utils::{contains_name, higher, is_integer_const, sugg, SpanlessEq}; +use clippy_utils::{SpanlessEq, contains_name, higher, is_integer_const, sugg}; use rustc_ast::ast; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::intravisit::{walk_expr, Visitor}; +use rustc_hir::intravisit::{Visitor, walk_expr}; use rustc_hir::{BinOpKind, BorrowKind, Closure, Expr, ExprKind, HirId, Mutability, Pat, PatKind, QPath}; use rustc_lint::LateContext; use rustc_middle::middle::region; use rustc_middle::ty::{self, Ty}; -use rustc_span::symbol::{sym, Symbol}; +use rustc_span::symbol::{Symbol, sym}; use std::{iter, mem}; /// Checks for looping over a range and then indexing a sequence with it. diff --git a/clippy_lints/src/loops/never_loop.rs b/clippy_lints/src/loops/never_loop.rs index 313a5bfefbc..1c55e3e22e8 100644 --- a/clippy_lints/src/loops/never_loop.rs +++ b/clippy_lints/src/loops/never_loop.rs @@ -1,5 +1,5 @@ -use super::utils::make_iterator_snippet; use super::NEVER_LOOP; +use super::utils::make_iterator_snippet; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::higher::ForLoop; use clippy_utils::macros::root_macro_call_first_node; @@ -7,7 +7,7 @@ use clippy_utils::source::snippet; use rustc_errors::Applicability; use rustc_hir::{Block, Destination, Expr, ExprKind, HirId, InlineAsmOperand, Pat, Stmt, StmtKind}; use rustc_lint::LateContext; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; use std::iter::once; pub(super) fn check<'tcx>( diff --git a/clippy_lints/src/loops/same_item_push.rs b/clippy_lints/src/loops/same_item_push.rs index 9185cf1f8b2..5662d3013e1 100644 --- a/clippy_lints/src/loops/same_item_push.rs +++ b/clippy_lints/src/loops/same_item_push.rs @@ -6,11 +6,11 @@ use clippy_utils::ty::{implements_trait, is_type_diagnostic_item}; use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::intravisit::{walk_expr, Visitor}; +use rustc_hir::intravisit::{Visitor, walk_expr}; use rustc_hir::{BindingMode, Block, Expr, ExprKind, HirId, Mutability, Node, Pat, PatKind, Stmt, StmtKind}; use rustc_lint::LateContext; -use rustc_span::symbol::sym; use rustc_span::SyntaxContext; +use rustc_span::symbol::sym; /// Detects for loop pushing the same item into a Vec pub(super) fn check<'tcx>( diff --git a/clippy_lints/src/loops/single_element_loop.rs b/clippy_lints/src/loops/single_element_loop.rs index 2b41911e8ec..70f76ced09a 100644 --- a/clippy_lints/src/loops/single_element_loop.rs +++ b/clippy_lints/src/loops/single_element_loop.rs @@ -2,10 +2,10 @@ use super::SINGLE_ELEMENT_LOOP; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::{indent_of, snippet, snippet_with_applicability}; use clippy_utils::visitors::contains_break_or_continue; -use rustc_ast::util::parser::PREC_PREFIX; use rustc_ast::Mutability; +use rustc_ast::util::parser::PREC_PREFIX; use rustc_errors::Applicability; -use rustc_hir::{is_range_literal, BorrowKind, Expr, ExprKind, Pat, PatKind}; +use rustc_hir::{BorrowKind, Expr, ExprKind, Pat, PatKind, is_range_literal}; use rustc_lint::LateContext; use rustc_span::edition::Edition; use rustc_span::sym; diff --git a/clippy_lints/src/loops/utils.rs b/clippy_lints/src/loops/utils.rs index 7b45cc95431..9a89a41d2b3 100644 --- a/clippy_lints/src/loops/utils.rs +++ b/clippy_lints/src/loops/utils.rs @@ -2,13 +2,13 @@ use clippy_utils::ty::{has_iter_method, implements_trait}; use clippy_utils::{get_parent_expr, is_integer_const, path_to_local, path_to_local_id, sugg}; use rustc_ast::ast::{LitIntType, LitKind}; use rustc_errors::Applicability; -use rustc_hir::intravisit::{walk_expr, walk_local, Visitor}; +use rustc_hir::intravisit::{Visitor, walk_expr, walk_local}; use rustc_hir::{BinOpKind, BorrowKind, Expr, ExprKind, HirId, HirIdMap, LetStmt, Mutability, PatKind}; use rustc_lint::LateContext; use rustc_middle::hir::nested_filter; use rustc_middle::ty::{self, Ty}; use rustc_span::source_map::Spanned; -use rustc_span::symbol::{sym, Symbol}; +use rustc_span::symbol::{Symbol, sym}; #[derive(Debug, PartialEq, Eq)] enum IncrementVisitorVarState { diff --git a/clippy_lints/src/loops/while_immutable_condition.rs b/clippy_lints/src/loops/while_immutable_condition.rs index cc1bd5929d0..eab096e9a22 100644 --- a/clippy_lints/src/loops/while_immutable_condition.rs +++ b/clippy_lints/src/loops/while_immutable_condition.rs @@ -4,7 +4,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::usage::mutated_variables; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefIdMap; -use rustc_hir::intravisit::{walk_expr, Visitor}; +use rustc_hir::intravisit::{Visitor, walk_expr}; use rustc_hir::{Expr, ExprKind, HirIdSet, QPath}; use rustc_lint::LateContext; use std::ops::ControlFlow; diff --git a/clippy_lints/src/loops/while_let_on_iterator.rs b/clippy_lints/src/loops/while_let_on_iterator.rs index c171fa1c622..7d9fbaf3cea 100644 --- a/clippy_lints/src/loops/while_let_on_iterator.rs +++ b/clippy_lints/src/loops/while_let_on_iterator.rs @@ -5,13 +5,13 @@ use clippy_utils::visitors::is_res_used; use clippy_utils::{get_enclosing_loop_or_multi_call_closure, higher, is_refutable, is_res_lang_ctor, is_trait_method}; use rustc_errors::Applicability; use rustc_hir::def::Res; -use rustc_hir::intravisit::{walk_expr, Visitor}; +use rustc_hir::intravisit::{Visitor, walk_expr}; use rustc_hir::{Closure, Expr, ExprKind, HirId, LangItem, LetStmt, Mutability, PatKind, UnOp}; use rustc_lint::LateContext; use rustc_middle::hir::nested_filter::OnlyBodies; use rustc_middle::ty::adjustment::Adjust; -use rustc_span::symbol::sym; use rustc_span::Symbol; +use rustc_span::symbol::sym; pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { if let Some(higher::WhileLet { if_then, let_pat, let_expr, label, .. }) = higher::WhileLet::hir(expr) diff --git a/clippy_lints/src/macro_metavars_in_unsafe.rs b/clippy_lints/src/macro_metavars_in_unsafe.rs index e215097142b..ccc554042d6 100644 --- a/clippy_lints/src/macro_metavars_in_unsafe.rs +++ b/clippy_lints/src/macro_metavars_in_unsafe.rs @@ -3,13 +3,13 @@ use clippy_utils::diagnostics::span_lint_hir_and_then; use clippy_utils::is_lint_allowed; use itertools::Itertools; use rustc_hir::def_id::LocalDefId; -use rustc_hir::intravisit::{walk_block, walk_expr, walk_stmt, Visitor}; +use rustc_hir::intravisit::{Visitor, walk_block, walk_expr, walk_stmt}; use rustc_hir::{BlockCheckMode, Expr, ExprKind, HirId, Stmt, UnsafeSource}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::impl_lint_pass; -use rustc_span::{sym, Span, SyntaxContext}; -use std::collections::btree_map::Entry; +use rustc_span::{Span, SyntaxContext, sym}; use std::collections::BTreeMap; +use std::collections::btree_map::Entry; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/macro_use.rs b/clippy_lints/src/macro_use.rs index 067384b0901..bd6b3f1a47b 100644 --- a/clippy_lints/src/macro_use.rs +++ b/clippy_lints/src/macro_use.rs @@ -8,7 +8,7 @@ use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_session::impl_lint_pass; use rustc_span::edition::Edition; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; use std::collections::BTreeMap; declare_clippy_lint! { diff --git a/clippy_lints/src/manual_async_fn.rs b/clippy_lints/src/manual_async_fn.rs index 61723aec590..fc3bba9e512 100644 --- a/clippy_lints/src/manual_async_fn.rs +++ b/clippy_lints/src/manual_async_fn.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::{position_before_rarrow, snippet_block, SpanRangeExt}; +use clippy_utils::source::{SpanRangeExt, position_before_rarrow, snippet_block}; use rustc_errors::Applicability; use rustc_hir::intravisit::FnKind; use rustc_hir::{ @@ -9,7 +9,7 @@ use rustc_hir::{ use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; use rustc_span::def_id::LocalDefId; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/manual_bits.rs b/clippy_lints/src/manual_bits.rs index 5cbdc7f864a..c0e87e8a1fa 100644 --- a/clippy_lints/src/manual_bits.rs +++ b/clippy_lints/src/manual_bits.rs @@ -1,5 +1,5 @@ -use clippy_config::msrvs::{self, Msrv}; use clippy_config::Conf; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::get_parent_expr; use clippy_utils::source::snippet_with_context; diff --git a/clippy_lints/src/manual_clamp.rs b/clippy_lints/src/manual_clamp.rs index 4123c933660..788649fd4f9 100644 --- a/clippy_lints/src/manual_clamp.rs +++ b/clippy_lints/src/manual_clamp.rs @@ -1,5 +1,5 @@ -use clippy_config::msrvs::{self, Msrv}; use clippy_config::Conf; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::consts::{ConstEvalCtxt, Constant}; use clippy_utils::diagnostics::{span_lint_and_then, span_lint_hir_and_then}; use clippy_utils::higher::If; @@ -7,8 +7,8 @@ use clippy_utils::sugg::Sugg; use clippy_utils::ty::implements_trait; use clippy_utils::visitors::is_const_evaluatable; use clippy_utils::{ - eq_expr_value, is_diag_trait_item, is_in_const_context, is_trait_method, path_res, path_to_local_id, peel_blocks, - peel_blocks_with_stmt, MaybePath, + MaybePath, eq_expr_value, is_diag_trait_item, is_in_const_context, is_trait_method, path_res, path_to_local_id, + peel_blocks, peel_blocks_with_stmt, }; use itertools::Itertools; use rustc_errors::{Applicability, Diag}; @@ -17,8 +17,8 @@ use rustc_hir::{Arm, BinOpKind, Block, Expr, ExprKind, HirId, PatKind, PathSegme use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::Ty; use rustc_session::impl_lint_pass; -use rustc_span::symbol::sym; use rustc_span::Span; +use rustc_span::symbol::sym; use std::cmp::Ordering; use std::ops::Deref; diff --git a/clippy_lints/src/manual_div_ceil.rs b/clippy_lints/src/manual_div_ceil.rs index 024c2547dc6..00e02e2a336 100644 --- a/clippy_lints/src/manual_div_ceil.rs +++ b/clippy_lints/src/manual_div_ceil.rs @@ -1,8 +1,8 @@ use clippy_config::msrvs::{self, Msrv}; +use clippy_utils::SpanlessEq; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; use clippy_utils::sugg::Sugg; -use clippy_utils::SpanlessEq; use rustc_ast::{BinOpKind, LitKind}; use rustc_data_structures::packed::Pu128; use rustc_errors::Applicability; diff --git a/clippy_lints/src/manual_hash_one.rs b/clippy_lints/src/manual_hash_one.rs index 11716a539ab..c62bd65bea6 100644 --- a/clippy_lints/src/manual_hash_one.rs +++ b/clippy_lints/src/manual_hash_one.rs @@ -1,5 +1,5 @@ -use clippy_config::msrvs::{self, Msrv}; use clippy_config::Conf; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_hir_and_then; use clippy_utils::source::SpanRangeExt; use clippy_utils::visitors::{is_local_used, local_used_once}; diff --git a/clippy_lints/src/manual_is_ascii_check.rs b/clippy_lints/src/manual_is_ascii_check.rs index 31c37c3bc3b..24207705743 100644 --- a/clippy_lints/src/manual_is_ascii_check.rs +++ b/clippy_lints/src/manual_is_ascii_check.rs @@ -1,17 +1,17 @@ -use clippy_config::msrvs::{self, Msrv}; use clippy_config::Conf; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::macros::matching_root_macro_call; use clippy_utils::sugg::Sugg; use clippy_utils::{higher, is_in_const_context, path_to_local, peel_ref_operators}; -use rustc_ast::ast::RangeLimits; 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_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_session::impl_lint_pass; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/manual_is_power_of_two.rs b/clippy_lints/src/manual_is_power_of_two.rs index d7879403ebb..da2a982ee17 100644 --- a/clippy_lints/src/manual_is_power_of_two.rs +++ b/clippy_lints/src/manual_is_power_of_two.rs @@ -1,6 +1,6 @@ +use clippy_utils::SpanlessEq; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; -use clippy_utils::SpanlessEq; use rustc_ast::LitKind; use rustc_data_structures::packed::Pu128; use rustc_errors::Applicability; diff --git a/clippy_lints/src/manual_let_else.rs b/clippy_lints/src/manual_let_else.rs index ebebdf679a8..17185df5d76 100644 --- a/clippy_lints/src/manual_let_else.rs +++ b/clippy_lints/src/manual_let_else.rs @@ -1,4 +1,4 @@ -use crate::question_mark::{QuestionMark, QUESTION_MARK}; +use crate::question_mark::{QUESTION_MARK, QuestionMark}; use clippy_config::msrvs; use clippy_config::types::MatchLintBehaviour; use clippy_utils::diagnostics::span_lint_and_then; @@ -12,8 +12,8 @@ use rustc_hir::{Expr, ExprKind, MatchSource, Pat, PatKind, QPath, Stmt, StmtKind use rustc_lint::{LateContext, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_span::symbol::{sym, Symbol}; use rustc_span::Span; +use rustc_span::symbol::{Symbol, sym}; use std::slice; declare_clippy_lint! { diff --git a/clippy_lints/src/manual_main_separator_str.rs b/clippy_lints/src/manual_main_separator_str.rs index 5198d7838a2..85e99a92cf5 100644 --- a/clippy_lints/src/manual_main_separator_str.rs +++ b/clippy_lints/src/manual_main_separator_str.rs @@ -1,5 +1,5 @@ -use clippy_config::msrvs::{self, Msrv}; use clippy_config::Conf; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::{is_trait_method, peel_hir_expr_refs}; use rustc_errors::Applicability; diff --git a/clippy_lints/src/manual_non_exhaustive.rs b/clippy_lints/src/manual_non_exhaustive.rs index 01f1d9c3beb..25868ccae40 100644 --- a/clippy_lints/src/manual_non_exhaustive.rs +++ b/clippy_lints/src/manual_non_exhaustive.rs @@ -1,5 +1,5 @@ -use clippy_config::msrvs::{self, Msrv}; use clippy_config::Conf; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::{span_lint_and_then, span_lint_hir_and_then}; use clippy_utils::is_doc_hidden; use clippy_utils::source::snippet_indent; @@ -12,7 +12,7 @@ use rustc_hir::{Expr, ExprKind, Item, ItemKind, QPath, TyKind, VariantData}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::impl_lint_pass; use rustc_span::def_id::LocalDefId; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/manual_range_patterns.rs b/clippy_lints/src/manual_range_patterns.rs index 66d2ab6b24a..ffa3eacf354 100644 --- a/clippy_lints/src/manual_range_patterns.rs +++ b/clippy_lints/src/manual_range_patterns.rs @@ -7,7 +7,7 @@ use rustc_hir::{Expr, ExprKind, PatKind, RangeEnd, UnOp}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_session::declare_lint_pass; -use rustc_span::{Span, DUMMY_SP}; +use rustc_span::{DUMMY_SP, Span}; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/manual_rem_euclid.rs b/clippy_lints/src/manual_rem_euclid.rs index 6cf5d272d7d..86293169ea2 100644 --- a/clippy_lints/src/manual_rem_euclid.rs +++ b/clippy_lints/src/manual_rem_euclid.rs @@ -1,5 +1,5 @@ -use clippy_config::msrvs::{self, Msrv}; use clippy_config::Conf; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::consts::{ConstEvalCtxt, FullInt}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_context; diff --git a/clippy_lints/src/manual_retain.rs b/clippy_lints/src/manual_retain.rs index a35b0f914e0..a60163be770 100644 --- a/clippy_lints/src/manual_retain.rs +++ b/clippy_lints/src/manual_retain.rs @@ -1,17 +1,17 @@ -use clippy_config::msrvs::{self, Msrv}; use clippy_config::Conf; +use clippy_config::msrvs::{self, Msrv}; +use clippy_utils::SpanlessEq; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet; use clippy_utils::ty::{get_type_diagnostic_name, is_type_lang_item}; -use clippy_utils::SpanlessEq; use rustc_errors::Applicability; use rustc_hir as hir; -use rustc_hir::def_id::DefId; use rustc_hir::ExprKind::Assign; +use rustc_hir::def_id::DefId; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::impl_lint_pass; -use rustc_span::symbol::{sym, Symbol}; use rustc_span::Span; +use rustc_span::symbol::{Symbol, sym}; const ACCEPTABLE_METHODS: [Symbol; 5] = [ sym::binaryheap_iter, diff --git a/clippy_lints/src/manual_string_new.rs b/clippy_lints/src/manual_string_new.rs index 781db4b97f0..198f7aaddc7 100644 --- a/clippy_lints/src/manual_string_new.rs +++ b/clippy_lints/src/manual_string_new.rs @@ -5,7 +5,7 @@ use rustc_hir::{Expr, ExprKind, PathSegment, QPath, TyKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_session::declare_lint_pass; -use rustc_span::{sym, symbol, Span}; +use rustc_span::{Span, sym, symbol}; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/manual_strip.rs b/clippy_lints/src/manual_strip.rs index 02d433ecc5a..9aceca66bf7 100644 --- a/clippy_lints/src/manual_strip.rs +++ b/clippy_lints/src/manual_strip.rs @@ -1,5 +1,5 @@ -use clippy_config::msrvs::{self, Msrv}; use clippy_config::Conf; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::consts::{ConstEvalCtxt, Constant}; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet; @@ -8,13 +8,13 @@ use clippy_utils::{eq_expr_value, higher}; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; use rustc_hir::def::Res; -use rustc_hir::intravisit::{walk_expr, Visitor}; +use rustc_hir::intravisit::{Visitor, walk_expr}; use rustc_hir::{BinOpKind, BorrowKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_session::impl_lint_pass; use rustc_span::source_map::Spanned; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; use std::iter; declare_clippy_lint! { diff --git a/clippy_lints/src/map_unit_fn.rs b/clippy_lints/src/map_unit_fn.rs index 2db71b1f7a3..a97dbbbc33f 100644 --- a/clippy_lints/src/map_unit_fn.rs +++ b/clippy_lints/src/map_unit_fn.rs @@ -7,7 +7,7 @@ use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{self, Ty}; use rustc_session::declare_lint_pass; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/matches/collapsible_match.rs b/clippy_lints/src/matches/collapsible_match.rs index b666e77c09e..50e6dfc6298 100644 --- a/clippy_lints/src/matches/collapsible_match.rs +++ b/clippy_lints/src/matches/collapsible_match.rs @@ -4,7 +4,7 @@ use clippy_utils::higher::IfLetOrMatch; use clippy_utils::source::snippet; use clippy_utils::visitors::is_local_used; use clippy_utils::{ - is_res_lang_ctor, is_unit_expr, path_to_local, peel_blocks_with_stmt, peel_ref_operators, SpanlessEq, + SpanlessEq, is_res_lang_ctor, is_unit_expr, path_to_local, peel_blocks_with_stmt, peel_ref_operators, }; use rustc_errors::MultiSpan; use rustc_hir::LangItem::OptionNone; @@ -12,7 +12,7 @@ use rustc_hir::{Arm, Expr, HirId, Pat, PatKind}; use rustc_lint::LateContext; use rustc_span::Span; -use super::{pat_contains_disallowed_or, COLLAPSIBLE_MATCH}; +use super::{COLLAPSIBLE_MATCH, pat_contains_disallowed_or}; pub(super) fn check_match<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>], msrv: &Msrv) { if let Some(els_arm) = arms.iter().rfind(|arm| arm_is_wild_like(cx, arm)) { diff --git a/clippy_lints/src/matches/manual_filter.rs b/clippy_lints/src/matches/manual_filter.rs index 619ec83127a..cfa054706d6 100644 --- a/clippy_lints/src/matches/manual_filter.rs +++ b/clippy_lints/src/matches/manual_filter.rs @@ -6,10 +6,10 @@ use clippy_utils::{is_res_lang_ctor, path_res, path_to_local_id}; use rustc_hir::LangItem::{OptionNone, OptionSome}; use rustc_hir::{Arm, Expr, ExprKind, HirId, Pat, PatKind}; use rustc_lint::LateContext; -use rustc_span::{sym, SyntaxContext}; +use rustc_span::{SyntaxContext, sym}; -use super::manual_utils::{check_with, SomeExpr}; use super::MANUAL_FILTER; +use super::manual_utils::{SomeExpr, check_with}; // Function called on the of `[&+]Some((ref | ref mut) x) => ` // Need to check if it's of the form `=if {} else {}` diff --git a/clippy_lints/src/matches/manual_map.rs b/clippy_lints/src/matches/manual_map.rs index ed3d8b09fdc..de57d1eee92 100644 --- a/clippy_lints/src/matches/manual_map.rs +++ b/clippy_lints/src/matches/manual_map.rs @@ -1,5 +1,5 @@ -use super::manual_utils::{check_with, SomeExpr}; use super::MANUAL_MAP; +use super::manual_utils::{SomeExpr, check_with}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::{is_res_lang_ctor, path_res}; diff --git a/clippy_lints/src/matches/manual_unwrap_or.rs b/clippy_lints/src/matches/manual_unwrap_or.rs index d5d83df9347..59d37520011 100644 --- a/clippy_lints/src/matches/manual_unwrap_or.rs +++ b/clippy_lints/src/matches/manual_unwrap_or.rs @@ -1,12 +1,12 @@ use clippy_utils::consts::ConstEvalCtxt; use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::{indent_of, reindent_multiline, SpanRangeExt}; +use clippy_utils::source::{SpanRangeExt, indent_of, reindent_multiline}; use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::usage::contains_return_break_continue_macro; use clippy_utils::{is_res_lang_ctor, path_to_local_id, peel_blocks, sugg}; use rustc_errors::Applicability; -use rustc_hir::def::{DefKind, Res}; use rustc_hir::LangItem::{OptionNone, ResultErr}; +use rustc_hir::def::{DefKind, Res}; use rustc_hir::{Arm, Expr, Pat, PatKind}; use rustc_lint::LateContext; use rustc_middle::ty::Ty; diff --git a/clippy_lints/src/matches/manual_utils.rs b/clippy_lints/src/matches/manual_utils.rs index be80aebed6d..d38560998a5 100644 --- a/clippy_lints/src/matches/manual_utils.rs +++ b/clippy_lints/src/matches/manual_utils.rs @@ -4,16 +4,16 @@ use clippy_utils::source::{snippet_with_applicability, snippet_with_context}; use clippy_utils::sugg::Sugg; use clippy_utils::ty::{is_copy, is_type_diagnostic_item, peel_mid_ty_refs_is_mutable, type_is_unsafe_function}; use clippy_utils::{ - can_move_expr_to_closure, is_else_clause, is_lint_allowed, is_res_lang_ctor, path_res, path_to_local_id, - peel_blocks, peel_hir_expr_refs, peel_hir_expr_while, CaptureKind, + CaptureKind, can_move_expr_to_closure, is_else_clause, is_lint_allowed, is_res_lang_ctor, path_res, + path_to_local_id, peel_blocks, peel_hir_expr_refs, peel_hir_expr_while, }; use rustc_ast::util::parser::PREC_UNAMBIGUOUS; use rustc_errors::Applicability; -use rustc_hir::def::Res; use rustc_hir::LangItem::{OptionNone, OptionSome}; +use rustc_hir::def::Res; use rustc_hir::{BindingMode, Expr, ExprKind, HirId, Mutability, Pat, PatKind, Path, QPath}; use rustc_lint::LateContext; -use rustc_span::{sym, SyntaxContext}; +use rustc_span::{SyntaxContext, sym}; #[expect(clippy::too_many_arguments)] #[expect(clippy::too_many_lines)] diff --git a/clippy_lints/src/matches/match_same_arms.rs b/clippy_lints/src/matches/match_same_arms.rs index da8c918a62b..f9ffbc5dc0b 100644 --- a/clippy_lints/src/matches/match_same_arms.rs +++ b/clippy_lints/src/matches/match_same_arms.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_hir_and_then; use clippy_utils::source::snippet_with_applicability; -use clippy_utils::{is_lint_allowed, path_to_local, search_same, SpanlessEq, SpanlessHash}; +use clippy_utils::{SpanlessEq, SpanlessHash, is_lint_allowed, path_to_local, search_same}; use core::cmp::Ordering; use core::{iter, slice}; use rustc_arena::DroplessArena; diff --git a/clippy_lints/src/matches/match_str_case_mismatch.rs b/clippy_lints/src/matches/match_str_case_mismatch.rs index 322e9c3ebe5..40518ce2ca7 100644 --- a/clippy_lints/src/matches/match_str_case_mismatch.rs +++ b/clippy_lints/src/matches/match_str_case_mismatch.rs @@ -2,12 +2,12 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::ty::is_type_lang_item; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; -use rustc_hir::intravisit::{walk_expr, Visitor}; +use rustc_hir::intravisit::{Visitor, walk_expr}; use rustc_hir::{Arm, Expr, ExprKind, LangItem, PatKind}; use rustc_lint::LateContext; use rustc_middle::ty; -use rustc_span::symbol::Symbol; use rustc_span::Span; +use rustc_span::symbol::Symbol; use super::MATCH_STR_CASE_MISMATCH; diff --git a/clippy_lints/src/matches/mod.rs b/clippy_lints/src/matches/mod.rs index cf5377e0725..686fc4a0fa0 100644 --- a/clippy_lints/src/matches/mod.rs +++ b/clippy_lints/src/matches/mod.rs @@ -24,8 +24,8 @@ mod single_match; mod try_err; mod wild_in_or_pats; -use clippy_config::msrvs::{self, Msrv}; use clippy_config::Conf; +use clippy_config::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 rustc_hir::{Arm, Expr, ExprKind, LetStmt, MatchSource, Pat, PatKind}; diff --git a/clippy_lints/src/matches/overlapping_arms.rs b/clippy_lints/src/matches/overlapping_arms.rs index 71f211be925..6a4c553cee0 100644 --- a/clippy_lints/src/matches/overlapping_arms.rs +++ b/clippy_lints/src/matches/overlapping_arms.rs @@ -1,4 +1,4 @@ -use clippy_utils::consts::{mir_to_const, ConstEvalCtxt, FullInt}; +use clippy_utils::consts::{ConstEvalCtxt, FullInt, mir_to_const}; use clippy_utils::diagnostics::span_lint_and_note; use core::cmp::Ordering; use rustc_hir::{Arm, Expr, PatKind, RangeEnd}; diff --git a/clippy_lints/src/matches/redundant_guards.rs b/clippy_lints/src/matches/redundant_guards.rs index 8222c3057f7..564c598a334 100644 --- a/clippy_lints/src/matches/redundant_guards.rs +++ b/clippy_lints/src/matches/redundant_guards.rs @@ -10,11 +10,11 @@ use rustc_hir::def::{DefKind, Res}; use rustc_hir::{Arm, BinOpKind, Expr, ExprKind, MatchSource, Node, PatKind, UnOp}; use rustc_lint::LateContext; use rustc_span::symbol::Ident; -use rustc_span::{sym, Span, Symbol}; +use rustc_span::{Span, Symbol, sym}; use std::borrow::Cow; use std::ops::ControlFlow; -use super::{pat_contains_disallowed_or, REDUNDANT_GUARDS}; +use super::{REDUNDANT_GUARDS, pat_contains_disallowed_or}; pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'tcx>], msrv: &Msrv) { for outer_arm in arms { diff --git a/clippy_lints/src/matches/redundant_pattern_match.rs b/clippy_lints/src/matches/redundant_pattern_match.rs index 0e4b2d9d34a..b646e87a439 100644 --- a/clippy_lints/src/matches/redundant_pattern_match.rs +++ b/clippy_lints/src/matches/redundant_pattern_match.rs @@ -1,18 +1,18 @@ 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::sugg::{make_unop, Sugg}; +use clippy_utils::sugg::{Sugg, make_unop}; use clippy_utils::ty::{is_type_diagnostic_item, needs_ordered_drop}; use clippy_utils::visitors::{any_temporaries_need_ordered_drop, for_each_expr_without_closures}; use clippy_utils::{higher, is_expn_of, is_trait_method}; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; -use rustc_hir::def::{DefKind, Res}; 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_lint::LateContext; use rustc_middle::ty::{self, GenericArgKind, Ty}; -use rustc_span::{sym, Span, Symbol}; +use rustc_span::{Span, Symbol, sym}; use std::fmt::Write; use std::ops::ControlFlow; diff --git a/clippy_lints/src/matches/significant_drop_in_scrutinee.rs b/clippy_lints/src/matches/significant_drop_in_scrutinee.rs index 9c2f42d2187..537f7272f7f 100644 --- a/clippy_lints/src/matches/significant_drop_in_scrutinee.rs +++ b/clippy_lints/src/matches/significant_drop_in_scrutinee.rs @@ -8,7 +8,7 @@ use clippy_utils::{get_attr, is_lint_allowed}; use itertools::Itertools; use rustc_ast::Mutability; use rustc_errors::{Applicability, Diag}; -use rustc_hir::intravisit::{walk_expr, Visitor}; +use rustc_hir::intravisit::{Visitor, walk_expr}; use rustc_hir::{Arm, Expr, ExprKind, MatchSource}; use rustc_lint::{LateContext, LintContext}; use rustc_middle::ty::{GenericArgKind, Region, RegionKind, Ty, TyCtxt, TypeVisitable, TypeVisitor}; diff --git a/clippy_lints/src/matches/single_match.rs b/clippy_lints/src/matches/single_match.rs index e7cef5bdbd7..2eda238ae8c 100644 --- a/clippy_lints/src/matches/single_match.rs +++ b/clippy_lints/src/matches/single_match.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::{expr_block, snippet, snippet_block_with_context, SpanRangeExt}; +use clippy_utils::source::{SpanRangeExt, expr_block, snippet, snippet_block_with_context}; use clippy_utils::ty::implements_trait; use clippy_utils::{ is_lint_allowed, is_unit_expr, peel_blocks, peel_hir_pat_refs, peel_middle_ty_refs, peel_n_hir_expr_refs, @@ -8,11 +8,11 @@ use core::ops::ControlFlow; use rustc_arena::DroplessArena; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::intravisit::{walk_pat, Visitor}; +use rustc_hir::intravisit::{Visitor, walk_pat}; use rustc_hir::{Arm, Expr, ExprKind, HirId, Node, Pat, PatKind, QPath, StmtKind}; use rustc_lint::LateContext; use rustc_middle::ty::{self, AdtDef, ParamEnv, TyCtxt, TypeckResults, VariantDef}; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; use super::{MATCH_BOOL, SINGLE_MATCH, SINGLE_MATCH_ELSE}; diff --git a/clippy_lints/src/mem_replace.rs b/clippy_lints/src/mem_replace.rs index 72a5945ad9b..146748734cf 100644 --- a/clippy_lints/src/mem_replace.rs +++ b/clippy_lints/src/mem_replace.rs @@ -1,5 +1,5 @@ -use clippy_config::msrvs::{self, Msrv}; use clippy_config::Conf; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg, span_lint_and_then}; use clippy_utils::source::{snippet, snippet_with_applicability}; use clippy_utils::sugg::Sugg; @@ -13,8 +13,8 @@ use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::lint::in_external_macro; use rustc_session::impl_lint_pass; -use rustc_span::symbol::sym; use rustc_span::Span; +use rustc_span::symbol::sym; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/methods/bind_instead_of_map.rs b/clippy_lints/src/methods/bind_instead_of_map.rs index 2a8a5fcc3b6..91a5de16e96 100644 --- a/clippy_lints/src/methods/bind_instead_of_map.rs +++ b/clippy_lints/src/methods/bind_instead_of_map.rs @@ -1,4 +1,4 @@ -use super::{contains_return, BIND_INSTEAD_OF_MAP}; +use super::{BIND_INSTEAD_OF_MAP, contains_return}; use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; use clippy_utils::peel_blocks; use clippy_utils::source::{snippet, snippet_with_context}; diff --git a/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs b/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs index 740cce0a6c2..76bdbe55e2f 100644 --- a/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs +++ b/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs @@ -1,12 +1,12 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::{indent_of, reindent_multiline, SpanRangeExt}; +use clippy_utils::source::{SpanRangeExt, indent_of, reindent_multiline}; use clippy_utils::ty::is_type_lang_item; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, LangItem}; use rustc_lint::LateContext; -use rustc_span::source_map::Spanned; use rustc_span::Span; +use rustc_span::source_map::Spanned; use super::CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS; diff --git a/clippy_lints/src/methods/clear_with_drain.rs b/clippy_lints/src/methods/clear_with_drain.rs index 5389861245a..6e24cabca8b 100644 --- a/clippy_lints/src/methods/clear_with_drain.rs +++ b/clippy_lints/src/methods/clear_with_drain.rs @@ -4,8 +4,8 @@ use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item}; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, LangItem, QPath}; use rustc_lint::LateContext; -use rustc_span::symbol::sym; use rustc_span::Span; +use rustc_span::symbol::sym; use super::CLEAR_WITH_DRAIN; diff --git a/clippy_lints/src/methods/clone_on_copy.rs b/clippy_lints/src/methods/clone_on_copy.rs index e7a2060be04..79a473e0e6f 100644 --- a/clippy_lints/src/methods/clone_on_copy.rs +++ b/clippy_lints/src/methods/clone_on_copy.rs @@ -7,7 +7,7 @@ use rustc_lint::LateContext; use rustc_middle::ty::adjustment::Adjust; use rustc_middle::ty::print::with_forced_trimmed_paths; use rustc_middle::ty::{self}; -use rustc_span::symbol::{sym, Symbol}; +use rustc_span::symbol::{Symbol, sym}; use super::CLONE_ON_COPY; diff --git a/clippy_lints/src/methods/clone_on_ref_ptr.rs b/clippy_lints/src/methods/clone_on_ref_ptr.rs index e0826b53004..96e2de0dc1c 100644 --- a/clippy_lints/src/methods/clone_on_ref_ptr.rs +++ b/clippy_lints/src/methods/clone_on_ref_ptr.rs @@ -4,7 +4,7 @@ use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; use rustc_middle::ty; -use rustc_span::symbol::{sym, Symbol}; +use rustc_span::symbol::{Symbol, sym}; use super::CLONE_ON_REF_PTR; diff --git a/clippy_lints/src/methods/cloned_instead_of_copied.rs b/clippy_lints/src/methods/cloned_instead_of_copied.rs index fcafa162236..fa04f74eec1 100644 --- a/clippy_lints/src/methods/cloned_instead_of_copied.rs +++ b/clippy_lints/src/methods/cloned_instead_of_copied.rs @@ -6,7 +6,7 @@ use rustc_errors::Applicability; use rustc_hir::Expr; use rustc_lint::LateContext; use rustc_middle::ty; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; use super::CLONED_INSTEAD_OF_COPIED; diff --git a/clippy_lints/src/methods/collapsible_str_replace.rs b/clippy_lints/src/methods/collapsible_str_replace.rs index 1fab6c0e499..f7bf8764bde 100644 --- a/clippy_lints/src/methods/collapsible_str_replace.rs +++ b/clippy_lints/src/methods/collapsible_str_replace.rs @@ -8,7 +8,7 @@ use rustc_hir as hir; use rustc_lint::LateContext; use std::collections::VecDeque; -use super::{method_call, COLLAPSIBLE_STR_REPLACE}; +use super::{COLLAPSIBLE_STR_REPLACE, method_call}; pub(super) fn check<'tcx>( cx: &LateContext<'tcx>, diff --git a/clippy_lints/src/methods/drain_collect.rs b/clippy_lints/src/methods/drain_collect.rs index 56171a13452..10360b4817b 100644 --- a/clippy_lints/src/methods/drain_collect.rs +++ b/clippy_lints/src/methods/drain_collect.rs @@ -8,7 +8,7 @@ use rustc_hir::{Expr, ExprKind, LangItem, Path, QPath}; use rustc_lint::LateContext; use rustc_middle::ty; use rustc_middle::ty::Ty; -use rustc_span::{sym, Symbol}; +use rustc_span::{Symbol, sym}; /// Checks if both types match the given diagnostic item, e.g.: /// diff --git a/clippy_lints/src/methods/err_expect.rs b/clippy_lints/src/methods/err_expect.rs index dc978c8a584..3b1adb16b80 100644 --- a/clippy_lints/src/methods/err_expect.rs +++ b/clippy_lints/src/methods/err_expect.rs @@ -6,7 +6,7 @@ use rustc_errors::Applicability; use rustc_lint::LateContext; use rustc_middle::ty; use rustc_middle::ty::Ty; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; pub(super) fn check( cx: &LateContext<'_>, diff --git a/clippy_lints/src/methods/expect_fun_call.rs b/clippy_lints/src/methods/expect_fun_call.rs index c9f56e1d980..2922086522c 100644 --- a/clippy_lints/src/methods/expect_fun_call.rs +++ b/clippy_lints/src/methods/expect_fun_call.rs @@ -1,13 +1,13 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::macros::{format_args_inputs_span, root_macro_call_first_node, FormatArgsStorage}; +use clippy_utils::macros::{FormatArgsStorage, format_args_inputs_span, root_macro_call_first_node}; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; use rustc_middle::ty; -use rustc_span::symbol::sym; use rustc_span::Span; +use rustc_span::symbol::sym; use std::borrow::Cow; use super::EXPECT_FUN_CALL; diff --git a/clippy_lints/src/methods/filetype_is_file.rs b/clippy_lints/src/methods/filetype_is_file.rs index 2ab0401947c..35008c39c08 100644 --- a/clippy_lints/src/methods/filetype_is_file.rs +++ b/clippy_lints/src/methods/filetype_is_file.rs @@ -3,7 +3,7 @@ use clippy_utils::get_parent_expr; use clippy_utils::ty::is_type_diagnostic_item; use rustc_hir as hir; use rustc_lint::LateContext; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; use super::FILETYPE_IS_FILE; diff --git a/clippy_lints/src/methods/filter_map.rs b/clippy_lints/src/methods/filter_map.rs index 02a11257007..06482a743dd 100644 --- a/clippy_lints/src/methods/filter_map.rs +++ b/clippy_lints/src/methods/filter_map.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; use clippy_utils::macros::{is_panic, matching_root_macro_call, root_macro_call}; use clippy_utils::source::{indent_of, reindent_multiline, snippet}; use clippy_utils::ty::is_type_diagnostic_item; -use clippy_utils::{higher, is_trait_method, path_to_local_id, peel_blocks, SpanlessEq}; +use clippy_utils::{SpanlessEq, higher, is_trait_method, path_to_local_id, peel_blocks}; use hir::{Body, HirId, MatchSource, Pat}; use rustc_errors::Applicability; use rustc_hir as hir; @@ -10,8 +10,8 @@ use rustc_hir::def::Res; use rustc_hir::{Closure, Expr, ExprKind, PatKind, PathSegment, QPath, UnOp}; use rustc_lint::LateContext; use rustc_middle::ty::adjustment::Adjust; -use rustc_span::symbol::{sym, Ident, Symbol}; use rustc_span::Span; +use rustc_span::symbol::{Ident, Symbol, sym}; use std::borrow::Cow; use super::{MANUAL_FILTER_MAP, MANUAL_FIND_MAP, OPTION_FILTER_MAP, RESULT_FILTER_MAP}; diff --git a/clippy_lints/src/methods/filter_map_bool_then.rs b/clippy_lints/src/methods/filter_map_bool_then.rs index 77a62fbb4fb..129e6925428 100644 --- a/clippy_lints/src/methods/filter_map_bool_then.rs +++ b/clippy_lints/src/methods/filter_map_bool_then.rs @@ -7,9 +7,9 @@ use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_middle::ty::adjustment::Adjust; use rustc_middle::ty::Binder; -use rustc_span::{sym, Span}; +use rustc_middle::ty::adjustment::Adjust; +use rustc_span::{Span, sym}; pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, arg: &Expr<'_>, call_span: Span) { if !in_external_macro(cx.sess(), expr.span) diff --git a/clippy_lints/src/methods/filter_map_identity.rs b/clippy_lints/src/methods/filter_map_identity.rs index 999df875c75..cf7f276dabb 100644 --- a/clippy_lints/src/methods/filter_map_identity.rs +++ b/clippy_lints/src/methods/filter_map_identity.rs @@ -3,7 +3,7 @@ use clippy_utils::{is_expr_identity_function, is_expr_untyped_identity_function, use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; use super::FILTER_MAP_IDENTITY; diff --git a/clippy_lints/src/methods/flat_map_identity.rs b/clippy_lints/src/methods/flat_map_identity.rs index 651ea34f9d0..0c2ecfbc8ff 100644 --- a/clippy_lints/src/methods/flat_map_identity.rs +++ b/clippy_lints/src/methods/flat_map_identity.rs @@ -3,7 +3,7 @@ use clippy_utils::{is_expr_untyped_identity_function, is_trait_method}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; use super::FLAT_MAP_IDENTITY; diff --git a/clippy_lints/src/methods/flat_map_option.rs b/clippy_lints/src/methods/flat_map_option.rs index 0a4a381b861..3242dcadb70 100644 --- a/clippy_lints/src/methods/flat_map_option.rs +++ b/clippy_lints/src/methods/flat_map_option.rs @@ -4,7 +4,7 @@ use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; use rustc_middle::ty; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; use super::FLAT_MAP_OPTION; use clippy_utils::ty::is_type_diagnostic_item; diff --git a/clippy_lints/src/methods/get_last_with_len.rs b/clippy_lints/src/methods/get_last_with_len.rs index 62037651134..5f6fb4c821d 100644 --- a/clippy_lints/src/methods/get_last_with_len.rs +++ b/clippy_lints/src/methods/get_last_with_len.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; -use clippy_utils::{is_integer_literal, SpanlessEq}; +use clippy_utils::{SpanlessEq, is_integer_literal}; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::LateContext; diff --git a/clippy_lints/src/methods/inefficient_to_string.rs b/clippy_lints/src/methods/inefficient_to_string.rs index 230a8eb2ec4..4ed7de81ea3 100644 --- a/clippy_lints/src/methods/inefficient_to_string.rs +++ b/clippy_lints/src/methods/inefficient_to_string.rs @@ -5,7 +5,7 @@ use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; use rustc_middle::ty::{self, Ty}; -use rustc_span::symbol::{sym, Symbol}; +use rustc_span::symbol::{Symbol, sym}; use super::INEFFICIENT_TO_STRING; diff --git a/clippy_lints/src/methods/inspect_for_each.rs b/clippy_lints/src/methods/inspect_for_each.rs index ad4b6fa130e..3706f3b670b 100644 --- a/clippy_lints/src/methods/inspect_for_each.rs +++ b/clippy_lints/src/methods/inspect_for_each.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::is_trait_method; use rustc_hir as hir; use rustc_lint::LateContext; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; use super::INSPECT_FOR_EACH; diff --git a/clippy_lints/src/methods/into_iter_on_ref.rs b/clippy_lints/src/methods/into_iter_on_ref.rs index bbc7ce8d78a..bedeb63367d 100644 --- a/clippy_lints/src/methods/into_iter_on_ref.rs +++ b/clippy_lints/src/methods/into_iter_on_ref.rs @@ -5,8 +5,8 @@ use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; use rustc_middle::ty::{self, Ty}; -use rustc_span::symbol::{sym, Symbol}; use rustc_span::Span; +use rustc_span::symbol::{Symbol, sym}; use super::INTO_ITER_ON_REF; diff --git a/clippy_lints/src/methods/iter_filter.rs b/clippy_lints/src/methods/iter_filter.rs index b93d51eac64..f6612c984a7 100644 --- a/clippy_lints/src/methods/iter_filter.rs +++ b/clippy_lints/src/methods/iter_filter.rs @@ -10,8 +10,8 @@ use clippy_utils::{get_parent_expr, is_trait_method, peel_blocks, span_contains_ use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::QPath; -use rustc_span::symbol::{sym, Ident, Symbol}; use rustc_span::Span; +use rustc_span::symbol::{Ident, Symbol, sym}; use std::borrow::Cow; /// diff --git a/clippy_lints/src/methods/iter_nth.rs b/clippy_lints/src/methods/iter_nth.rs index e31fa2f777d..82bda5d9512 100644 --- a/clippy_lints/src/methods/iter_nth.rs +++ b/clippy_lints/src/methods/iter_nth.rs @@ -3,8 +3,8 @@ use clippy_utils::ty::get_type_diagnostic_name; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; -use rustc_span::symbol::sym; use rustc_span::Span; +use rustc_span::symbol::sym; use super::ITER_NTH; diff --git a/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs b/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs index 7f6b666e434..9d562f5e51d 100644 --- a/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs +++ b/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs @@ -5,9 +5,9 @@ use clippy_utils::source::snippet; use clippy_utils::{get_expr_use_or_unification_node, is_res_lang_ctor, path_res, std_or_core}; use rustc_errors::Applicability; +use rustc_hir::LangItem::{OptionNone, OptionSome}; use rustc_hir::def_id::DefId; use rustc_hir::hir_id::HirId; -use rustc_hir::LangItem::{OptionNone, OptionSome}; use rustc_hir::{Expr, ExprKind, Node}; use rustc_lint::LateContext; diff --git a/clippy_lints/src/methods/iter_with_drain.rs b/clippy_lints/src/methods/iter_with_drain.rs index 1378a07cbc4..16305871337 100644 --- a/clippy_lints/src/methods/iter_with_drain.rs +++ b/clippy_lints/src/methods/iter_with_drain.rs @@ -3,8 +3,8 @@ use clippy_utils::is_range_full; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, QPath}; use rustc_lint::LateContext; -use rustc_span::symbol::sym; use rustc_span::Span; +use rustc_span::symbol::sym; use super::ITER_WITH_DRAIN; diff --git a/clippy_lints/src/methods/join_absolute_paths.rs b/clippy_lints/src/methods/join_absolute_paths.rs index 2dad7fcf3c1..2ad070793cb 100644 --- a/clippy_lints/src/methods/join_absolute_paths.rs +++ b/clippy_lints/src/methods/join_absolute_paths.rs @@ -6,8 +6,8 @@ use rustc_ast::ast::LitKind; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::LateContext; -use rustc_span::symbol::sym; use rustc_span::Span; +use rustc_span::symbol::sym; use super::JOIN_ABSOLUTE_PATHS; diff --git a/clippy_lints/src/methods/manual_c_str_literals.rs b/clippy_lints/src/methods/manual_c_str_literals.rs index cb9fb373c10..96af9db1af7 100644 --- a/clippy_lints/src/methods/manual_c_str_literals.rs +++ b/clippy_lints/src/methods/manual_c_str_literals.rs @@ -6,7 +6,7 @@ use rustc_ast::{LitKind, StrStyle}; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, Node, QPath, TyKind}; use rustc_lint::LateContext; -use rustc_span::{sym, Span, Symbol}; +use rustc_span::{Span, Symbol, sym}; use super::MANUAL_C_STR_LITERALS; diff --git a/clippy_lints/src/methods/manual_inspect.rs b/clippy_lints/src/methods/manual_inspect.rs index cac2e11f591..64c19c327b2 100644 --- a/clippy_lints/src/methods/manual_inspect.rs +++ b/clippy_lints/src/methods/manual_inspect.rs @@ -3,13 +3,13 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::{IntoSpan, SpanRangeExt}; use clippy_utils::ty::get_field_by_name; use clippy_utils::visitors::{for_each_expr, for_each_expr_without_closures}; -use clippy_utils::{expr_use_ctxt, is_diag_item_method, is_diag_trait_item, path_to_local_id, ExprUseNode}; +use clippy_utils::{ExprUseNode, expr_use_ctxt, is_diag_item_method, is_diag_trait_item, path_to_local_id}; use core::ops::ControlFlow; use rustc_errors::Applicability; use rustc_hir::{BindingMode, BorrowKind, ByRef, ClosureKind, Expr, ExprKind, Mutability, Node, PatKind}; use rustc_lint::LateContext; use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability}; -use rustc_span::{sym, Span, Symbol, DUMMY_SP}; +use rustc_span::{DUMMY_SP, Span, Symbol, sym}; use super::MANUAL_INSPECT; diff --git a/clippy_lints/src/methods/manual_is_variant_and.rs b/clippy_lints/src/methods/manual_is_variant_and.rs index d29acd4622a..c377abd6237 100644 --- a/clippy_lints/src/methods/manual_is_variant_and.rs +++ b/clippy_lints/src/methods/manual_is_variant_and.rs @@ -4,7 +4,7 @@ use clippy_utils::source::snippet; use clippy_utils::ty::is_type_diagnostic_item; use rustc_errors::Applicability; use rustc_lint::LateContext; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; use super::MANUAL_IS_VARIANT_AND; diff --git a/clippy_lints/src/methods/manual_ok_or.rs b/clippy_lints/src/methods/manual_ok_or.rs index b1a8e1e5e47..4321dd6b0e0 100644 --- a/clippy_lints/src/methods/manual_ok_or.rs +++ b/clippy_lints/src/methods/manual_ok_or.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::{indent_of, reindent_multiline, SpanRangeExt}; +use clippy_utils::source::{SpanRangeExt, indent_of, reindent_multiline}; use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::{is_res_lang_ctor, path_res, path_to_local_id}; use rustc_errors::Applicability; diff --git a/clippy_lints/src/methods/manual_try_fold.rs b/clippy_lints/src/methods/manual_try_fold.rs index 11fba35c16e..31449d41770 100644 --- a/clippy_lints/src/methods/manual_try_fold.rs +++ b/clippy_lints/src/methods/manual_try_fold.rs @@ -8,7 +8,7 @@ use rustc_hir::def::{DefKind, Res}; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; use super::MANUAL_TRY_FOLD; diff --git a/clippy_lints/src/methods/map_clone.rs b/clippy_lints/src/methods/map_clone.rs index 08ce7e204dd..ac378ff3702 100644 --- a/clippy_lints/src/methods/map_clone.rs +++ b/clippy_lints/src/methods/map_clone.rs @@ -11,7 +11,7 @@ use rustc_middle::mir::Mutability; use rustc_middle::ty; use rustc_middle::ty::adjustment::Adjust; use rustc_span::symbol::Ident; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; use super::MAP_CLONE; diff --git a/clippy_lints/src/methods/map_flatten.rs b/clippy_lints/src/methods/map_flatten.rs index 22a03825194..07a7a12b162 100644 --- a/clippy_lints/src/methods/map_flatten.rs +++ b/clippy_lints/src/methods/map_flatten.rs @@ -6,8 +6,8 @@ use rustc_errors::Applicability; use rustc_hir::Expr; use rustc_lint::LateContext; use rustc_middle::ty; -use rustc_span::symbol::sym; use rustc_span::Span; +use rustc_span::symbol::sym; use super::MAP_FLATTEN; diff --git a/clippy_lints/src/methods/map_identity.rs b/clippy_lints/src/methods/map_identity.rs index 5dd7b1b02ad..1f204de01da 100644 --- a/clippy_lints/src/methods/map_identity.rs +++ b/clippy_lints/src/methods/map_identity.rs @@ -4,7 +4,7 @@ use clippy_utils::{is_expr_untyped_identity_function, is_trait_method}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; use super::MAP_IDENTITY; diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 098d3fca9b2..7696dd16b25 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -132,8 +132,8 @@ mod waker_clone_wake; mod wrong_self_convention; mod zst_offset; -use clippy_config::msrvs::{self, Msrv}; use clippy_config::Conf; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::consts::{ConstEvalCtxt, Constant}; use clippy_utils::diagnostics::{span_lint, span_lint_and_help}; use clippy_utils::macros::FormatArgsStorage; @@ -147,7 +147,7 @@ use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::{self, TraitRef, Ty}; use rustc_session::impl_lint_pass; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; declare_clippy_lint! { /// ### What it does @@ -5174,12 +5174,9 @@ impl ShouldImplTraitCase { fn lifetime_param_cond(&self, impl_item: &hir::ImplItem<'_>) -> bool { self.lint_explicit_lifetime || !impl_item.generics.params.iter().any(|p| { - matches!( - p.kind, - hir::GenericParamKind::Lifetime { - kind: hir::LifetimeParamKind::Explicit - } - ) + matches!(p.kind, hir::GenericParamKind::Lifetime { + kind: hir::LifetimeParamKind::Explicit + }) }) } } diff --git a/clippy_lints/src/methods/mut_mutex_lock.rs b/clippy_lints/src/methods/mut_mutex_lock.rs index 1a0fce2876d..83e8370f939 100644 --- a/clippy_lints/src/methods/mut_mutex_lock.rs +++ b/clippy_lints/src/methods/mut_mutex_lock.rs @@ -5,7 +5,7 @@ use rustc_errors::Applicability; use rustc_hir::{Expr, Mutability}; use rustc_lint::LateContext; use rustc_middle::ty; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; use super::MUT_MUTEX_LOCK; diff --git a/clippy_lints/src/methods/needless_character_iteration.rs b/clippy_lints/src/methods/needless_character_iteration.rs index 332da722a37..348f740e7dd 100644 --- a/clippy_lints/src/methods/needless_character_iteration.rs +++ b/clippy_lints/src/methods/needless_character_iteration.rs @@ -4,8 +4,8 @@ use rustc_lint::LateContext; use rustc_middle::ty; use rustc_span::Span; -use super::utils::get_last_chain_binding_hir_id; use super::NEEDLESS_CHARACTER_ITERATION; +use super::utils::get_last_chain_binding_hir_id; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::SpanRangeExt; use clippy_utils::{match_def_path, path_to_local_id, peel_blocks}; diff --git a/clippy_lints/src/methods/needless_collect.rs b/clippy_lints/src/methods/needless_collect.rs index f61923e5bf5..421c7a5e070 100644 --- a/clippy_lints/src/methods/needless_collect.rs +++ b/clippy_lints/src/methods/needless_collect.rs @@ -4,12 +4,12 @@ use clippy_utils::source::{snippet, snippet_with_applicability}; use clippy_utils::sugg::Sugg; use clippy_utils::ty::{get_type_diagnostic_name, make_normalized_projection, make_projection}; use clippy_utils::{ - can_move_expr_to_closure, fn_def_id, get_enclosing_block, higher, is_trait_method, path_to_local, path_to_local_id, - CaptureKind, + CaptureKind, can_move_expr_to_closure, fn_def_id, get_enclosing_block, higher, is_trait_method, path_to_local, + path_to_local_id, }; use rustc_data_structures::fx::FxHashMap; use rustc_errors::{Applicability, MultiSpan}; -use rustc_hir::intravisit::{walk_block, walk_expr, Visitor}; +use rustc_hir::intravisit::{Visitor, walk_block, walk_expr}; use rustc_hir::{ BindingMode, Block, Expr, ExprKind, HirId, HirIdSet, LetStmt, Mutability, Node, PatKind, Stmt, StmtKind, }; @@ -17,7 +17,7 @@ use rustc_lint::LateContext; use rustc_middle::hir::nested_filter; use rustc_middle::ty::{self, AssocKind, ClauseKind, EarlyBinder, GenericArg, GenericArgKind, Ty}; use rustc_span::symbol::Ident; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; const NEEDLESS_COLLECT_MSG: &str = "avoid using `collect()` when not needed"; diff --git a/clippy_lints/src/methods/needless_option_as_deref.rs b/clippy_lints/src/methods/needless_option_as_deref.rs index 9f714fdd47b..538aa9097a4 100644 --- a/clippy_lints/src/methods/needless_option_as_deref.rs +++ b/clippy_lints/src/methods/needless_option_as_deref.rs @@ -4,8 +4,8 @@ use clippy_utils::source::SpanRangeExt; use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::usage::local_used_after_expr; use rustc_errors::Applicability; -use rustc_hir::def::Res; use rustc_hir::Expr; +use rustc_hir::def::Res; use rustc_lint::LateContext; use rustc_span::sym; diff --git a/clippy_lints/src/methods/no_effect_replace.rs b/clippy_lints/src/methods/no_effect_replace.rs index a301a5f7d65..32f32f1b216 100644 --- a/clippy_lints/src/methods/no_effect_replace.rs +++ b/clippy_lints/src/methods/no_effect_replace.rs @@ -1,6 +1,6 @@ +use clippy_utils::SpanlessEq; use clippy_utils::diagnostics::span_lint; use clippy_utils::ty::is_type_lang_item; -use clippy_utils::SpanlessEq; use rustc_ast::LitKind; use rustc_hir::{ExprKind, LangItem}; use rustc_lint::LateContext; diff --git a/clippy_lints/src/methods/open_options.rs b/clippy_lints/src/methods/open_options.rs index f1a3c81cebb..da084871402 100644 --- a/clippy_lints/src/methods/open_options.rs +++ b/clippy_lints/src/methods/open_options.rs @@ -8,7 +8,7 @@ use rustc_hir::{Expr, ExprKind}; use rustc_lint::LateContext; use rustc_middle::ty::Ty; use rustc_span::source_map::Spanned; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; use super::{NONSENSICAL_OPEN_OPTIONS, SUSPICIOUS_OPEN_OPTIONS}; @@ -126,17 +126,13 @@ fn get_open_options( && let ExprKind::Path(path) = callee.kind && let Some(did) = cx.qpath_res(&path, callee.hir_id).opt_def_id() { - let std_file_options = [ - sym::file_options, - sym::open_options_new, - ]; + let std_file_options = [sym::file_options, sym::open_options_new]; - let tokio_file_options: &[&[&str]] = &[ - &paths::TOKIO_IO_OPEN_OPTIONS_NEW, - &paths::TOKIO_FILE_OPTIONS, - ]; + let tokio_file_options: &[&[&str]] = &[&paths::TOKIO_IO_OPEN_OPTIONS_NEW, &paths::TOKIO_FILE_OPTIONS]; - let is_std_options = std_file_options.into_iter().any(|sym| cx.tcx.is_diagnostic_item(sym, did)); + let is_std_options = std_file_options + .into_iter() + .any(|sym| cx.tcx.is_diagnostic_item(sym, did)); is_std_options || match_any_def_paths(cx, did, tokio_file_options).is_some() } else { false diff --git a/clippy_lints/src/methods/option_as_ref_cloned.rs b/clippy_lints/src/methods/option_as_ref_cloned.rs index ba167f9d9c2..9b22494888f 100644 --- a/clippy_lints/src/methods/option_as_ref_cloned.rs +++ b/clippy_lints/src/methods/option_as_ref_cloned.rs @@ -3,9 +3,9 @@ use clippy_utils::ty::is_type_diagnostic_item; use rustc_errors::Applicability; use rustc_hir::Expr; use rustc_lint::LateContext; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; -use super::{method_call, OPTION_AS_REF_CLONED}; +use super::{OPTION_AS_REF_CLONED, method_call}; pub(super) fn check(cx: &LateContext<'_>, cloned_recv: &Expr<'_>, cloned_ident_span: Span) { if let Some((method @ ("as_ref" | "as_mut"), as_ref_recv, [], as_ref_ident_span, _)) = method_call(cloned_recv) diff --git a/clippy_lints/src/methods/option_as_ref_deref.rs b/clippy_lints/src/methods/option_as_ref_deref.rs index 9a18d8a1421..389e02056b2 100644 --- a/clippy_lints/src/methods/option_as_ref_deref.rs +++ b/clippy_lints/src/methods/option_as_ref_deref.rs @@ -7,7 +7,7 @@ use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; use rustc_middle::ty; -use rustc_span::{sym, Symbol}; +use rustc_span::{Symbol, sym}; use super::OPTION_AS_REF_DEREF; @@ -48,7 +48,9 @@ pub(super) fn check( .map_or(false, |fun_def_id| { cx.tcx.is_diagnostic_item(sym::deref_method, fun_def_id) || cx.tcx.is_diagnostic_item(sym::deref_mut_method, fun_def_id) - || deref_aliases.iter().any(|&sym| cx.tcx.is_diagnostic_item(sym, fun_def_id)) + || deref_aliases + .iter() + .any(|&sym| cx.tcx.is_diagnostic_item(sym, fun_def_id)) }) }, hir::ExprKind::Closure(&hir::Closure { body, .. }) => { @@ -69,7 +71,9 @@ pub(super) fn check( let method_did = cx.typeck_results().type_dependent_def_id(closure_expr.hir_id).unwrap(); cx.tcx.is_diagnostic_item(sym::deref_method, method_did) || cx.tcx.is_diagnostic_item(sym::deref_mut_method, method_did) - || deref_aliases.iter().any(|&sym| cx.tcx.is_diagnostic_item(sym, method_did)) + || deref_aliases + .iter() + .any(|&sym| cx.tcx.is_diagnostic_item(sym, method_did)) } else { false } diff --git a/clippy_lints/src/methods/option_map_unwrap_or.rs b/clippy_lints/src/methods/option_map_unwrap_or.rs index ed3bed42eb3..b160ab6de8e 100644 --- a/clippy_lints/src/methods/option_map_unwrap_or.rs +++ b/clippy_lints/src/methods/option_map_unwrap_or.rs @@ -5,11 +5,11 @@ use clippy_utils::ty::{is_copy, is_type_diagnostic_item}; use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; use rustc_hir::def::Res; -use rustc_hir::intravisit::{walk_path, Visitor}; +use rustc_hir::intravisit::{Visitor, walk_path}; use rustc_hir::{ExprKind, HirId, Node, PatKind, Path, QPath}; use rustc_lint::LateContext; use rustc_middle::hir::nested_filter; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; use std::ops::ControlFlow; use super::MAP_UNWRAP_OR; diff --git a/clippy_lints/src/methods/or_fun_call.rs b/clippy_lints/src/methods/or_fun_call.rs index e4326cb958e..8a7e72b63bb 100644 --- a/clippy_lints/src/methods/or_fun_call.rs +++ b/clippy_lints/src/methods/or_fun_call.rs @@ -11,8 +11,8 @@ use clippy_utils::{ use rustc_errors::Applicability; use rustc_lint::LateContext; use rustc_middle::ty; -use rustc_span::symbol::{self, sym, Symbol}; use rustc_span::Span; +use rustc_span::symbol::{self, Symbol, sym}; use {rustc_ast as ast, rustc_hir as hir}; use super::{OR_FUN_CALL, UNWRAP_OR_DEFAULT}; diff --git a/clippy_lints/src/methods/or_then_unwrap.rs b/clippy_lints/src/methods/or_then_unwrap.rs index 7b0bdcf99e7..3e64e15dc86 100644 --- a/clippy_lints/src/methods/or_then_unwrap.rs +++ b/clippy_lints/src/methods/or_then_unwrap.rs @@ -6,7 +6,7 @@ use rustc_errors::Applicability; use rustc_hir::lang_items::LangItem; use rustc_hir::{Expr, ExprKind}; use rustc_lint::LateContext; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; use super::OR_THEN_UNWRAP; diff --git a/clippy_lints/src/methods/range_zip_with_len.rs b/clippy_lints/src/methods/range_zip_with_len.rs index 28ca76832eb..f4d206c5307 100644 --- a/clippy_lints/src/methods/range_zip_with_len.rs +++ b/clippy_lints/src/methods/range_zip_with_len.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint; use clippy_utils::source::snippet; -use clippy_utils::{higher, is_integer_const, is_trait_method, SpanlessEq}; +use clippy_utils::{SpanlessEq, higher, is_integer_const, is_trait_method}; use rustc_hir::{Expr, ExprKind, QPath}; use rustc_lint::LateContext; use rustc_span::sym; diff --git a/clippy_lints/src/methods/search_is_some.rs b/clippy_lints/src/methods/search_is_some.rs index 3b2dd285b8c..4ab165a5528 100644 --- a/clippy_lints/src/methods/search_is_some.rs +++ b/clippy_lints/src/methods/search_is_some.rs @@ -8,8 +8,8 @@ use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::PatKind; use rustc_lint::LateContext; -use rustc_span::symbol::sym; use rustc_span::Span; +use rustc_span::symbol::sym; use super::SEARCH_IS_SOME; diff --git a/clippy_lints/src/methods/seek_from_current.rs b/clippy_lints/src/methods/seek_from_current.rs index 8bc535ac47a..7ef07fe899c 100644 --- a/clippy_lints/src/methods/seek_from_current.rs +++ b/clippy_lints/src/methods/seek_from_current.rs @@ -6,9 +6,9 @@ use rustc_lint::LateContext; use rustc_span::sym; use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::is_enum_variant_ctor; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::implements_trait; -use clippy_utils::is_enum_variant_ctor; use super::SEEK_FROM_CURRENT; diff --git a/clippy_lints/src/methods/seek_to_start_instead_of_rewind.rs b/clippy_lints/src/methods/seek_to_start_instead_of_rewind.rs index 7c09cc252e1..9c966f010f1 100644 --- a/clippy_lints/src/methods/seek_to_start_instead_of_rewind.rs +++ b/clippy_lints/src/methods/seek_to_start_instead_of_rewind.rs @@ -1,12 +1,12 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::ty::implements_trait; -use clippy_utils::{is_expr_used_or_unified, is_enum_variant_ctor}; +use clippy_utils::{is_enum_variant_ctor, is_expr_used_or_unified}; use rustc_ast::ast::{LitIntType, LitKind}; use rustc_data_structures::packed::Pu128; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::LateContext; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; use super::SEEK_TO_START_INSTEAD_OF_REWIND; diff --git a/clippy_lints/src/methods/str_splitn.rs b/clippy_lints/src/methods/str_splitn.rs index 12cabd43cb1..69032776b2b 100644 --- a/clippy_lints/src/methods/str_splitn.rs +++ b/clippy_lints/src/methods/str_splitn.rs @@ -3,7 +3,7 @@ use clippy_utils::consts::{ConstEvalCtxt, Constant}; use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; use clippy_utils::source::snippet_with_context; use clippy_utils::usage::local_used_after_expr; -use clippy_utils::visitors::{for_each_expr, Descend}; +use clippy_utils::visitors::{Descend, for_each_expr}; use clippy_utils::{is_diag_item_method, match_def_path, path_to_local_id, paths}; use core::ops::ControlFlow; use rustc_errors::Applicability; @@ -12,7 +12,7 @@ use rustc_hir::{ }; use rustc_lint::LateContext; use rustc_middle::ty; -use rustc_span::{sym, Span, Symbol, SyntaxContext}; +use rustc_span::{Span, Symbol, SyntaxContext, sym}; use super::{MANUAL_SPLIT_ONCE, NEEDLESS_SPLITN}; diff --git a/clippy_lints/src/methods/suspicious_command_arg_space.rs b/clippy_lints/src/methods/suspicious_command_arg_space.rs index 38f2c916912..c60a49067ec 100644 --- a/clippy_lints/src/methods/suspicious_command_arg_space.rs +++ b/clippy_lints/src/methods/suspicious_command_arg_space.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::ty::is_type_diagnostic_item; use rustc_errors::{Applicability, Diag}; use rustc_lint::LateContext; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; use {rustc_ast as ast, rustc_hir as hir}; use super::SUSPICIOUS_COMMAND_ARG_SPACE; diff --git a/clippy_lints/src/methods/type_id_on_box.rs b/clippy_lints/src/methods/type_id_on_box.rs index db8cc4595d4..e67ba5c4d31 100644 --- a/clippy_lints/src/methods/type_id_on_box.rs +++ b/clippy_lints/src/methods/type_id_on_box.rs @@ -7,7 +7,7 @@ use rustc_lint::LateContext; use rustc_middle::ty::adjustment::{Adjust, Adjustment}; use rustc_middle::ty::print::with_forced_trimmed_paths; use rustc_middle::ty::{self, ExistentialPredicate, Ty}; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; /// Checks if the given type is `dyn Any`, or a trait object that has `Any` as a supertrait. /// Only in those cases will its vtable have a `type_id` method that returns the implementor's diff --git a/clippy_lints/src/methods/unnecessary_fallible_conversions.rs b/clippy_lints/src/methods/unnecessary_fallible_conversions.rs index d46b584f8f4..ce81282ddfe 100644 --- a/clippy_lints/src/methods/unnecessary_fallible_conversions.rs +++ b/clippy_lints/src/methods/unnecessary_fallible_conversions.rs @@ -6,7 +6,7 @@ use rustc_hir::{Expr, ExprKind, QPath}; use rustc_lint::LateContext; use rustc_middle::ty; use rustc_middle::ty::print::with_forced_trimmed_paths; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; use super::UNNECESSARY_FALLIBLE_CONVERSIONS; diff --git a/clippy_lints/src/methods/unnecessary_filter_map.rs b/clippy_lints/src/methods/unnecessary_filter_map.rs index c9b9d98dbe6..ca46da81fa0 100644 --- a/clippy_lints/src/methods/unnecessary_filter_map.rs +++ b/clippy_lints/src/methods/unnecessary_filter_map.rs @@ -2,7 +2,7 @@ use super::utils::clone_or_copy_needed; use clippy_utils::diagnostics::span_lint; use clippy_utils::ty::is_copy; use clippy_utils::usage::mutated_variables; -use clippy_utils::visitors::{for_each_expr_without_closures, Descend}; +use clippy_utils::visitors::{Descend, for_each_expr_without_closures}; use clippy_utils::{is_res_lang_ctor, is_trait_method, path_res, path_to_local_id}; use core::ops::ControlFlow; use rustc_hir as hir; diff --git a/clippy_lints/src/methods/unnecessary_fold.rs b/clippy_lints/src/methods/unnecessary_fold.rs index 380ea317b94..b5d8972d7aa 100644 --- a/clippy_lints/src/methods/unnecessary_fold.rs +++ b/clippy_lints/src/methods/unnecessary_fold.rs @@ -8,7 +8,7 @@ use rustc_hir as hir; use rustc_hir::PatKind; use rustc_lint::LateContext; use rustc_middle::ty; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; use super::UNNECESSARY_FOLD; @@ -123,60 +123,32 @@ pub(super) fn check( if let hir::ExprKind::Lit(lit) = init.kind { match lit.node { ast::LitKind::Bool(false) => { - check_fold_with_op( - cx, - expr, - acc, - fold_span, - hir::BinOpKind::Or, - Replacement { - has_args: true, - has_generic_return: false, - method_name: "any", - }, - ); + check_fold_with_op(cx, expr, acc, fold_span, hir::BinOpKind::Or, Replacement { + 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 { - has_args: true, - has_generic_return: false, - method_name: "all", - }, - ); + check_fold_with_op(cx, expr, acc, fold_span, hir::BinOpKind::And, Replacement { + 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 { - has_args: false, - has_generic_return: needs_turbofish(cx, expr), - method_name: "sum", - }, - ); + check_fold_with_op(cx, expr, acc, fold_span, hir::BinOpKind::Add, Replacement { + 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 { - has_args: false, - has_generic_return: needs_turbofish(cx, expr), - method_name: "product", - }, - ); + check_fold_with_op(cx, expr, acc, fold_span, hir::BinOpKind::Mul, Replacement { + has_args: false, + has_generic_return: needs_turbofish(cx, expr), + method_name: "product", + }); }, _ => (), } diff --git a/clippy_lints/src/methods/unnecessary_get_then_check.rs b/clippy_lints/src/methods/unnecessary_get_then_check.rs index 64eb8411795..39fce2c40c9 100644 --- a/clippy_lints/src/methods/unnecessary_get_then_check.rs +++ b/clippy_lints/src/methods/unnecessary_get_then_check.rs @@ -6,7 +6,7 @@ use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::LateContext; use rustc_middle::ty::Ty; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; use super::UNNECESSARY_GET_THEN_CHECK; diff --git a/clippy_lints/src/methods/unnecessary_iter_cloned.rs b/clippy_lints/src/methods/unnecessary_iter_cloned.rs index 4d18bc7ac77..029704882dd 100644 --- a/clippy_lints/src/methods/unnecessary_iter_cloned.rs +++ b/clippy_lints/src/methods/unnecessary_iter_cloned.rs @@ -10,7 +10,7 @@ use rustc_errors::Applicability; use rustc_hir::def_id::DefId; use rustc_hir::{BindingMode, Expr, ExprKind, Node, PatKind}; use rustc_lint::LateContext; -use rustc_span::{sym, Symbol}; +use rustc_span::{Symbol, sym}; use super::UNNECESSARY_TO_OWNED; diff --git a/clippy_lints/src/methods/unnecessary_literal_unwrap.rs b/clippy_lints/src/methods/unnecessary_literal_unwrap.rs index 494d71fc053..6dc8adb42df 100644 --- a/clippy_lints/src/methods/unnecessary_literal_unwrap.rs +++ b/clippy_lints/src/methods/unnecessary_literal_unwrap.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::{is_res_lang_ctor, last_path_segment, path_res, MaybePath}; +use clippy_utils::{MaybePath, is_res_lang_ctor, last_path_segment, path_res}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; diff --git a/clippy_lints/src/methods/unnecessary_min_or_max.rs b/clippy_lints/src/methods/unnecessary_min_or_max.rs index ff5fa7d33e3..062d1348555 100644 --- a/clippy_lints/src/methods/unnecessary_min_or_max.rs +++ b/clippy_lints/src/methods/unnecessary_min_or_max.rs @@ -9,7 +9,7 @@ use rustc_errors::Applicability; use rustc_hir::Expr; use rustc_lint::LateContext; use rustc_middle::ty; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; pub(super) fn check<'tcx>( cx: &LateContext<'tcx>, diff --git a/clippy_lints/src/methods/unnecessary_result_map_or_else.rs b/clippy_lints/src/methods/unnecessary_result_map_or_else.rs index c14a87c1534..dc50717112d 100644 --- a/clippy_lints/src/methods/unnecessary_result_map_or_else.rs +++ b/clippy_lints/src/methods/unnecessary_result_map_or_else.rs @@ -8,8 +8,8 @@ use rustc_hir::{Closure, Expr, ExprKind, HirId, QPath}; use rustc_lint::LateContext; use rustc_span::symbol::sym; -use super::utils::get_last_chain_binding_hir_id; use super::UNNECESSARY_RESULT_MAP_OR_ELSE; +use super::utils::get_last_chain_binding_hir_id; fn emit_lint(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, def_arg: &Expr<'_>) { let msg = "unused \"map closure\" when calling `Result::map_or_else` value"; diff --git a/clippy_lints/src/methods/unnecessary_to_owned.rs b/clippy_lints/src/methods/unnecessary_to_owned.rs index f62cf55e72a..cfa1fdb8137 100644 --- a/clippy_lints/src/methods/unnecessary_to_owned.rs +++ b/clippy_lints/src/methods/unnecessary_to_owned.rs @@ -2,12 +2,11 @@ use super::implicit_clone::is_clone_like; use super::unnecessary_iter_cloned::{self, is_into_iter}; use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; -use clippy_utils::source::{snippet, SpanRangeExt}; +use clippy_utils::source::{SpanRangeExt, snippet}; use clippy_utils::ty::{get_iterator_item_ty, implements_trait, is_copy, is_type_diagnostic_item, is_type_lang_item}; use clippy_utils::visitors::find_all_ret_expressions; use clippy_utils::{ - fn_def_id, get_parent_expr, is_diag_item_method, is_diag_trait_item, peel_middle_ty_refs, - return_ty, + fn_def_id, get_parent_expr, is_diag_item_method, is_diag_trait_item, peel_middle_ty_refs, return_ty, }; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; @@ -20,7 +19,7 @@ use rustc_middle::ty::adjustment::{Adjust, Adjustment, OverloadedDeref}; use rustc_middle::ty::{ self, ClauseKind, GenericArg, GenericArgKind, GenericArgsRef, ParamTy, ProjectionPredicate, TraitPredicate, Ty, }; -use rustc_span::{sym, Symbol}; +use rustc_span::{Symbol, sym}; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _; use rustc_trait_selection::traits::{Obligation, ObligationCause}; diff --git a/clippy_lints/src/methods/unused_enumerate_index.rs b/clippy_lints/src/methods/unused_enumerate_index.rs index ee5177d1ffa..6c2ae9cc6bf 100644 --- a/clippy_lints/src/methods/unused_enumerate_index.rs +++ b/clippy_lints/src/methods/unused_enumerate_index.rs @@ -1,11 +1,11 @@ use clippy_utils::diagnostics::span_lint_hir_and_then; -use clippy_utils::source::{snippet, SpanRangeExt}; +use clippy_utils::source::{SpanRangeExt, snippet}; use clippy_utils::{expr_or_init, is_trait_method, pat_is_wild}; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, FnDecl, PatKind, TyKind}; use rustc_lint::LateContext; use rustc_middle::ty::AdtDef; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; use crate::loops::UNUSED_ENUMERATE_INDEX; diff --git a/clippy_lints/src/methods/useless_asref.rs b/clippy_lints/src/methods/useless_asref.rs index ebad4ae6ee9..eafe7486bb0 100644 --- a/clippy_lints/src/methods/useless_asref.rs +++ b/clippy_lints/src/methods/useless_asref.rs @@ -9,7 +9,7 @@ use rustc_hir::{self as hir, LangItem}; use rustc_lint::LateContext; use rustc_middle::ty::adjustment::Adjust; use rustc_middle::ty::{Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor}; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; use core::ops::ControlFlow; diff --git a/clippy_lints/src/methods/utils.rs b/clippy_lints/src/methods/utils.rs index fe860e5ae26..4e33dc1df54 100644 --- a/clippy_lints/src/methods/utils.rs +++ b/clippy_lints/src/methods/utils.rs @@ -1,12 +1,12 @@ use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::{get_parent_expr, path_to_local_id, usage}; -use rustc_hir::intravisit::{walk_expr, Visitor}; +use rustc_hir::intravisit::{Visitor, walk_expr}; use rustc_hir::{BorrowKind, Expr, ExprKind, HirId, Mutability, Pat, QPath, Stmt, StmtKind}; use rustc_lint::LateContext; use rustc_middle::hir::nested_filter; use rustc_middle::ty::{self, Ty}; -use rustc_span::symbol::sym; use rustc_span::Span; +use rustc_span::symbol::sym; pub(super) fn derefs_to_slice<'tcx>( cx: &LateContext<'tcx>, diff --git a/clippy_lints/src/methods/vec_resize_to_zero.rs b/clippy_lints/src/methods/vec_resize_to_zero.rs index 3e271a60611..5ea4ada128a 100644 --- a/clippy_lints/src/methods/vec_resize_to_zero.rs +++ b/clippy_lints/src/methods/vec_resize_to_zero.rs @@ -6,7 +6,7 @@ use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::LateContext; use rustc_span::source_map::Spanned; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; use super::VEC_RESIZE_TO_ZERO; diff --git a/clippy_lints/src/methods/waker_clone_wake.rs b/clippy_lints/src/methods/waker_clone_wake.rs index 9b64cc7589c..b5f34a9be2e 100644 --- a/clippy_lints/src/methods/waker_clone_wake.rs +++ b/clippy_lints/src/methods/waker_clone_wake.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::snippet_with_applicability; use clippy_utils::is_trait_method; +use clippy_utils::source::snippet_with_applicability; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::LateContext; diff --git a/clippy_lints/src/min_ident_chars.rs b/clippy_lints/src/min_ident_chars.rs index c83e5198c27..a99e21d938c 100644 --- a/clippy_lints/src/min_ident_chars.rs +++ b/clippy_lints/src/min_ident_chars.rs @@ -3,7 +3,7 @@ use clippy_utils::diagnostics::span_lint; use clippy_utils::is_from_proc_macro; use rustc_data_structures::fx::FxHashSet; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::intravisit::{walk_item, walk_trait_item, Visitor}; +use rustc_hir::intravisit::{Visitor, walk_item, walk_trait_item}; use rustc_hir::{GenericParamKind, HirId, Item, ItemKind, ItemLocalId, Node, Pat, PatKind, TraitItem, UsePath}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; diff --git a/clippy_lints/src/misc.rs b/clippy_lints/src/misc.rs index 3e80e48a948..408dbef9cb1 100644 --- a/clippy_lints/src/misc.rs +++ b/clippy_lints/src/misc.rs @@ -2,8 +2,8 @@ use clippy_utils::diagnostics::{span_lint_and_then, span_lint_hir, span_lint_hir use clippy_utils::source::{snippet, snippet_with_context}; use clippy_utils::sugg::Sugg; use clippy_utils::{ - fulfill_or_allowed, get_parent_expr, in_automatically_derived, is_lint_allowed, iter_input_pats, last_path_segment, - SpanlessEq, + SpanlessEq, fulfill_or_allowed, get_parent_expr, in_automatically_derived, is_lint_allowed, iter_input_pats, + last_path_segment, }; use rustc_errors::Applicability; use rustc_hir::def::Res; @@ -15,8 +15,8 @@ use rustc_hir::{ use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_session::declare_lint_pass; -use rustc_span::def_id::LocalDefId; use rustc_span::Span; +use rustc_span::def_id::LocalDefId; use crate::ref_patterns::REF_PATTERNS; diff --git a/clippy_lints/src/missing_assert_message.rs b/clippy_lints/src/missing_assert_message.rs index a9ea11f4c2b..86348f04600 100644 --- a/clippy_lints/src/missing_assert_message.rs +++ b/clippy_lints/src/missing_assert_message.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::is_in_test; -use clippy_utils::macros::{find_assert_args, find_assert_eq_args, root_macro_call_first_node, PanicExpn}; +use clippy_utils::macros::{PanicExpn, find_assert_args, find_assert_eq_args, root_macro_call_first_node}; use rustc_hir::Expr; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; diff --git a/clippy_lints/src/missing_asserts_for_indexing.rs b/clippy_lints/src/missing_asserts_for_indexing.rs index 94c91b09517..b40d7eba15e 100644 --- a/clippy_lints/src/missing_asserts_for_indexing.rs +++ b/clippy_lints/src/missing_asserts_for_indexing.rs @@ -1,7 +1,7 @@ use std::mem; use std::ops::ControlFlow; -use clippy_utils::comparisons::{normalize_comparison, Rel}; +use clippy_utils::comparisons::{Rel, normalize_comparison}; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet; use clippy_utils::visitors::for_each_expr_without_closures; @@ -14,7 +14,7 @@ use rustc_hir::{BinOp, Block, Body, Expr, ExprKind, UnOp}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; use rustc_span::source_map::Spanned; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/missing_const_for_fn.rs b/clippy_lints/src/missing_const_for_fn.rs index 859afe1b963..eea0459e026 100644 --- a/clippy_lints/src/missing_const_for_fn.rs +++ b/clippy_lints/src/missing_const_for_fn.rs @@ -1,5 +1,5 @@ -use clippy_config::msrvs::{self, Msrv}; use clippy_config::Conf; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_then; 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}; @@ -11,8 +11,8 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty; use rustc_session::impl_lint_pass; -use rustc_span::def_id::LocalDefId; use rustc_span::Span; +use rustc_span::def_id::LocalDefId; use rustc_target::spec::abi::Abi; declare_clippy_lint! { diff --git a/clippy_lints/src/missing_const_for_thread_local.rs b/clippy_lints/src/missing_const_for_thread_local.rs index 954216038fb..c2f524a6353 100644 --- a/clippy_lints/src/missing_const_for_thread_local.rs +++ b/clippy_lints/src/missing_const_for_thread_local.rs @@ -1,12 +1,12 @@ -use clippy_config::msrvs::{self, Msrv}; use clippy_config::Conf; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::macros::macro_backtrace; use clippy_utils::qualify_min_const_fn::is_min_const_fn; use clippy_utils::source::snippet; use clippy_utils::{fn_has_unsatisfiable_preds, peel_blocks}; use rustc_errors::Applicability; -use rustc_hir::{intravisit, Expr, ExprKind}; +use rustc_hir::{Expr, ExprKind, intravisit}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::impl_lint_pass; use rustc_span::sym::{self, thread_local_macro}; diff --git a/clippy_lints/src/missing_doc.rs b/clippy_lints/src/missing_doc.rs index 2166b0fe5a0..64fc1a8a1a5 100644 --- a/clippy_lints/src/missing_doc.rs +++ b/clippy_lints/src/missing_doc.rs @@ -17,7 +17,7 @@ use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::ty::Visibility; use rustc_session::impl_lint_pass; use rustc_span::def_id::CRATE_DEF_ID; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/missing_fields_in_debug.rs b/clippy_lints/src/missing_fields_in_debug.rs index 77595b121aa..fc01b6753f1 100644 --- a/clippy_lints/src/missing_fields_in_debug.rs +++ b/clippy_lints/src/missing_fields_in_debug.rs @@ -3,7 +3,7 @@ use std::ops::ControlFlow; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::is_path_lang_item; use clippy_utils::ty::is_type_diagnostic_item; -use clippy_utils::visitors::{for_each_expr, Visitable}; +use clippy_utils::visitors::{Visitable, for_each_expr}; use rustc_ast::LitKind; use rustc_data_structures::fx::FxHashSet; use rustc_hir::def::{DefKind, Res}; @@ -13,7 +13,7 @@ use rustc_hir::{ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{Ty, TypeckResults}; use rustc_session::declare_lint_pass; -use rustc_span::{sym, Span, Symbol}; +use rustc_span::{Span, Symbol, sym}; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/missing_inline.rs b/clippy_lints/src/missing_inline.rs index 33a14d8b7fe..d342be4545c 100644 --- a/clippy_lints/src/missing_inline.rs +++ b/clippy_lints/src/missing_inline.rs @@ -3,7 +3,7 @@ use rustc_ast::ast; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_session::declare_lint_pass; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/mixed_read_write_in_expression.rs b/clippy_lints/src/mixed_read_write_in_expression.rs index 0b7d97c32c5..d333b71edb1 100644 --- a/clippy_lints/src/mixed_read_write_in_expression.rs +++ b/clippy_lints/src/mixed_read_write_in_expression.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; use clippy_utils::macros::root_macro_call_first_node; use clippy_utils::{get_parent_expr, path_to_local, path_to_local_id}; -use rustc_hir::intravisit::{walk_expr, Visitor}; +use rustc_hir::intravisit::{Visitor, walk_expr}; use rustc_hir::{BinOpKind, Block, Expr, ExprKind, HirId, LetStmt, Node, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; diff --git a/clippy_lints/src/multiple_unsafe_ops_per_block.rs b/clippy_lints/src/multiple_unsafe_ops_per_block.rs index 0bde0da3cd8..12bcc608174 100644 --- a/clippy_lints/src/multiple_unsafe_ops_per_block.rs +++ b/clippy_lints/src/multiple_unsafe_ops_per_block.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::visitors::{for_each_expr, Descend, Visitable}; +use clippy_utils::visitors::{Descend, Visitable, for_each_expr}; use core::ops::ControlFlow::Continue; use hir::def::{DefKind, Res}; use hir::{BlockCheckMode, ExprKind, QPath, Safety, UnOp}; @@ -153,19 +153,16 @@ fn collect_unsafe_exprs<'tcx>( ExprKind::AssignOp(_, lhs, rhs) | ExprKind::Assign(lhs, rhs, _) => { if matches!( lhs.kind, - ExprKind::Path(QPath::Resolved( - _, - hir::Path { - res: Res::Def( - DefKind::Static { - mutability: Mutability::Mut, - .. - }, - _ - ), - .. - } - )) + ExprKind::Path(QPath::Resolved(_, hir::Path { + res: Res::Def( + DefKind::Static { + mutability: Mutability::Mut, + .. + }, + _ + ), + .. + })) ) { unsafe_ops.push(("modification of a mutable static occurs here", expr.span)); collect_unsafe_exprs(cx, rhs, unsafe_ops); diff --git a/clippy_lints/src/mut_key.rs b/clippy_lints/src/mut_key.rs index f52b3a6a5a1..8118c14bd4a 100644 --- a/clippy_lints/src/mut_key.rs +++ b/clippy_lints/src/mut_key.rs @@ -6,9 +6,9 @@ use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_session::impl_lint_pass; +use rustc_span::Span; use rustc_span::def_id::LocalDefId; use rustc_span::symbol::sym; -use rustc_span::Span; use std::iter; declare_clippy_lint! { diff --git a/clippy_lints/src/mutable_debug_assertion.rs b/clippy_lints/src/mutable_debug_assertion.rs index 563ce2d82ea..6ab811b4f2f 100644 --- a/clippy_lints/src/mutable_debug_assertion.rs +++ b/clippy_lints/src/mutable_debug_assertion.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint; use clippy_utils::macros::{find_assert_eq_args, root_macro_call_first_node}; -use rustc_hir::intravisit::{walk_expr, Visitor}; +use rustc_hir::intravisit::{Visitor, walk_expr}; use rustc_hir::{BorrowKind, Expr, ExprKind, MatchSource, Mutability}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::nested_filter; diff --git a/clippy_lints/src/needless_arbitrary_self_type.rs b/clippy_lints/src/needless_arbitrary_self_type.rs index 60c44382059..3c47d0edfdc 100644 --- a/clippy_lints/src/needless_arbitrary_self_type.rs +++ b/clippy_lints/src/needless_arbitrary_self_type.rs @@ -3,8 +3,8 @@ use rustc_ast::ast::{BindingMode, ByRef, Lifetime, Mutability, Param, PatKind, P use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_session::declare_lint_pass; -use rustc_span::symbol::kw; use rustc_span::Span; +use rustc_span::symbol::kw; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/needless_bool.rs b/clippy_lints/src/needless_bool.rs index df155a7a412..2eacd6875d6 100644 --- a/clippy_lints/src/needless_bool.rs +++ b/clippy_lints/src/needless_bool.rs @@ -2,16 +2,16 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg}; use clippy_utils::source::snippet_with_applicability; use clippy_utils::sugg::Sugg; use clippy_utils::{ - get_parent_expr, higher, is_block_like, is_else_clause, is_expn_of, is_parent_stmt, is_receiver_of_method_call, - peel_blocks, peel_blocks_with_stmt, span_extract_comment, SpanlessEq, + SpanlessEq, get_parent_expr, higher, is_block_like, is_else_clause, is_expn_of, is_parent_stmt, + is_receiver_of_method_call, peel_blocks, peel_blocks_with_stmt, span_extract_comment, }; use rustc_ast::ast::LitKind; 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::source_map::Spanned; use rustc_span::Span; +use rustc_span::source_map::Spanned; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/needless_borrows_for_generic_args.rs b/clippy_lints/src/needless_borrows_for_generic_args.rs index 32e7fde03b2..f6db12ed84e 100644 --- a/clippy_lints/src/needless_borrows_for_generic_args.rs +++ b/clippy_lints/src/needless_borrows_for_generic_args.rs @@ -1,10 +1,10 @@ -use clippy_config::msrvs::{self, Msrv}; use clippy_config::Conf; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::mir::{enclosing_mir, expr_local, local_assignments, used_exactly_once, PossibleBorrowerMap}; +use clippy_utils::mir::{PossibleBorrowerMap, enclosing_mir, expr_local, local_assignments, used_exactly_once}; use clippy_utils::source::snippet_with_context; use clippy_utils::ty::{implements_trait, is_copy}; -use clippy_utils::{expr_use_ctxt, peel_n_hir_expr_refs, DefinedTy, ExprUseNode}; +use clippy_utils::{DefinedTy, ExprUseNode, expr_use_ctxt, peel_n_hir_expr_refs}; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, LocalDefId}; diff --git a/clippy_lints/src/needless_for_each.rs b/clippy_lints/src/needless_for_each.rs index 6390e51f916..b54eb164e81 100644 --- a/clippy_lints/src/needless_for_each.rs +++ b/clippy_lints/src/needless_for_each.rs @@ -1,9 +1,9 @@ use rustc_errors::Applicability; -use rustc_hir::intravisit::{walk_expr, Visitor}; +use rustc_hir::intravisit::{Visitor, walk_expr}; use rustc_hir::{Block, BlockCheckMode, Closure, Expr, ExprKind, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::is_trait_method; diff --git a/clippy_lints/src/needless_pass_by_ref_mut.rs b/clippy_lints/src/needless_pass_by_ref_mut.rs index d543fd467ab..19cbf595908 100644 --- a/clippy_lints/src/needless_pass_by_ref_mut.rs +++ b/clippy_lints/src/needless_pass_by_ref_mut.rs @@ -17,9 +17,9 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::mir::FakeReadCause; use rustc_middle::ty::{self, Ty, TyCtxt, UpvarId, UpvarPath}; use rustc_session::impl_lint_pass; +use rustc_span::Span; use rustc_span::def_id::LocalDefId; use rustc_span::symbol::kw; -use rustc_span::Span; use rustc_target::spec::abi::Abi; declare_clippy_lint! { diff --git a/clippy_lints/src/needless_pass_by_value.rs b/clippy_lints/src/needless_pass_by_value.rs index 887070bcf9a..0775d7abdbb 100644 --- a/clippy_lints/src/needless_pass_by_value.rs +++ b/clippy_lints/src/needless_pass_by_value.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::is_self; use clippy_utils::ptr::get_spans; -use clippy_utils::source::{snippet, SpanRangeExt}; +use clippy_utils::source::{SpanRangeExt, snippet}; use clippy_utils::ty::{ implements_trait, implements_trait_with_env_from_iter, is_copy, is_type_diagnostic_item, is_type_lang_item, }; @@ -19,7 +19,7 @@ use rustc_middle::ty::{self, Ty, TypeVisitableExt}; use rustc_session::declare_lint_pass; use rustc_span::def_id::LocalDefId; use rustc_span::symbol::kw; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; use rustc_target::spec::abi::Abi; use rustc_trait_selection::traits; use rustc_trait_selection::traits::misc::type_allowed_to_implement_copy; @@ -182,14 +182,9 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue { && !is_copy(cx, ty) && ty.is_sized(cx.tcx, cx.param_env) && !allowed_traits.iter().any(|&t| { - implements_trait_with_env_from_iter( - cx.tcx, - cx.param_env, - ty, - t, - None, - [Option::>::None], - ) + implements_trait_with_env_from_iter(cx.tcx, cx.param_env, ty, t, None, [Option::< + ty::GenericArg<'tcx>, + >::None]) }) && !implements_borrow_trait && !all_borrowable_trait diff --git a/clippy_lints/src/no_effect.rs b/clippy_lints/src/no_effect.rs index b181791699a..392cfcb813e 100644 --- a/clippy_lints/src/no_effect.rs +++ b/clippy_lints/src/no_effect.rs @@ -7,8 +7,8 @@ use clippy_utils::{ use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; use rustc_hir::{ - is_range_literal, BinOpKind, BlockCheckMode, Expr, ExprKind, HirId, HirIdMap, ItemKind, LocalSource, Node, PatKind, - Stmt, StmtKind, UnsafeSource, + BinOpKind, BlockCheckMode, Expr, ExprKind, HirId, HirIdMap, ItemKind, LocalSource, Node, PatKind, Stmt, StmtKind, + UnsafeSource, is_range_literal, }; use rustc_infer::infer::TyCtxtInferExt as _; use rustc_lint::{LateContext, LateLintPass, LintContext}; diff --git a/clippy_lints/src/non_copy_const.rs b/clippy_lints/src/non_copy_const.rs index 25f547f1a43..5e20b406426 100644 --- a/clippy_lints/src/non_copy_const.rs +++ b/clippy_lints/src/non_copy_const.rs @@ -4,7 +4,7 @@ use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::is_in_const_context; use clippy_utils::macros::macro_backtrace; -use clippy_utils::ty::{implements_trait, InteriorMut}; +use clippy_utils::ty::{InteriorMut, implements_trait}; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; use rustc_hir::{ @@ -15,7 +15,7 @@ use rustc_middle::mir::interpret::{ErrorHandled, EvalToValTreeResult, GlobalId}; use rustc_middle::ty::adjustment::Adjust; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_session::impl_lint_pass; -use rustc_span::{sym, Span, DUMMY_SP}; +use rustc_span::{DUMMY_SP, Span, sym}; use rustc_target::abi::VariantIdx; // FIXME: this is a correctness problem but there's no suitable diff --git a/clippy_lints/src/non_expressive_names.rs b/clippy_lints/src/non_expressive_names.rs index 832518d2d35..d85032e9eee 100644 --- a/clippy_lints/src/non_expressive_names.rs +++ b/clippy_lints/src/non_expressive_names.rs @@ -3,12 +3,12 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; use rustc_ast::ast::{ self, Arm, AssocItem, AssocItemKind, Attribute, Block, FnDecl, Item, ItemKind, Local, Pat, PatKind, }; -use rustc_ast::visit::{walk_block, walk_expr, walk_pat, Visitor}; +use rustc_ast::visit::{Visitor, walk_block, walk_expr, walk_pat}; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_session::impl_lint_pass; use rustc_span::symbol::{Ident, Symbol}; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; use std::cmp::Ordering; declare_clippy_lint! { diff --git a/clippy_lints/src/non_octal_unix_permissions.rs b/clippy_lints/src/non_octal_unix_permissions.rs index cfc15d92715..3f156aa5510 100644 --- a/clippy_lints/src/non_octal_unix_permissions.rs +++ b/clippy_lints/src/non_octal_unix_permissions.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::{snippet_with_applicability, SpanRangeExt}; +use clippy_utils::source::{SpanRangeExt, snippet_with_applicability}; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; diff --git a/clippy_lints/src/nonstandard_macro_braces.rs b/clippy_lints/src/nonstandard_macro_braces.rs index 51ba29d7389..a13391a5945 100644 --- a/clippy_lints/src/nonstandard_macro_braces.rs +++ b/clippy_lints/src/nonstandard_macro_braces.rs @@ -1,5 +1,5 @@ -use clippy_config::types::MacroMatcher; use clippy_config::Conf; +use clippy_config::types::MacroMatcher; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::{SourceText, SpanRangeExt}; use rustc_ast::ast; @@ -8,8 +8,8 @@ use rustc_errors::Applicability; use rustc_hir::def_id::DefId; use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_session::impl_lint_pass; -use rustc_span::hygiene::{ExpnKind, MacroKind}; use rustc_span::Span; +use rustc_span::hygiene::{ExpnKind, MacroKind}; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/only_used_in_recursion.rs b/clippy_lints/src/only_used_in_recursion.rs index aadd729f32a..372128ac16f 100644 --- a/clippy_lints/src/only_used_in_recursion.rs +++ b/clippy_lints/src/only_used_in_recursion.rs @@ -9,8 +9,8 @@ use rustc_hir::{Body, Expr, ExprKind, HirId, ImplItem, ImplItemKind, Node, PatKi use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{self, ConstKind, EarlyBinder, GenericArgKind, GenericArgsRef}; use rustc_session::impl_lint_pass; -use rustc_span::symbol::{kw, Ident}; use rustc_span::Span; +use rustc_span::symbol::{Ident, kw}; use std::iter; declare_clippy_lint! { diff --git a/clippy_lints/src/operators/absurd_extreme_comparisons.rs b/clippy_lints/src/operators/absurd_extreme_comparisons.rs index a0de5ea711c..dbc9948eeed 100644 --- a/clippy_lints/src/operators/absurd_extreme_comparisons.rs +++ b/clippy_lints/src/operators/absurd_extreme_comparisons.rs @@ -2,7 +2,7 @@ use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::LateContext; use rustc_middle::ty; -use clippy_utils::comparisons::{normalize_comparison, Rel}; +use clippy_utils::comparisons::{Rel, normalize_comparison}; use clippy_utils::consts::{ConstEvalCtxt, Constant}; use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::source::snippet; diff --git a/clippy_lints/src/operators/const_comparisons.rs b/clippy_lints/src/operators/const_comparisons.rs index c1317524396..5d94cfab3b0 100644 --- a/clippy_lints/src/operators/const_comparisons.rs +++ b/clippy_lints/src/operators/const_comparisons.rs @@ -7,12 +7,12 @@ use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::LateContext; use rustc_middle::ty::layout::HasTyCtxt; use rustc_middle::ty::{Ty, TypeckResults}; -use rustc_span::source_map::Spanned; use rustc_span::Span; +use rustc_span::source_map::Spanned; +use clippy_utils::SpanlessEq; use clippy_utils::diagnostics::span_lint_and_note; use clippy_utils::source::snippet; -use clippy_utils::SpanlessEq; use super::{IMPOSSIBLE_COMPARISONS, REDUNDANT_COMPARISONS}; diff --git a/clippy_lints/src/operators/float_equality_without_abs.rs b/clippy_lints/src/operators/float_equality_without_abs.rs index be97ad389bf..34f7dbea84e 100644 --- a/clippy_lints/src/operators/float_equality_without_abs.rs +++ b/clippy_lints/src/operators/float_equality_without_abs.rs @@ -6,7 +6,8 @@ use rustc_hir::def::{DefKind, Res}; use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::LateContext; use rustc_middle::ty; -use rustc_span::{sym, source_map::Spanned}; +use rustc_span::source_map::Spanned; +use rustc_span::sym; use super::FLOAT_EQUALITY_WITHOUT_ABS; diff --git a/clippy_lints/src/option_if_let_else.rs b/clippy_lints/src/option_if_let_else.rs index ae02d22512e..6d9e75f51d6 100644 --- a/clippy_lints/src/option_if_let_else.rs +++ b/clippy_lints/src/option_if_let_else.rs @@ -1,12 +1,12 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::sugg::Sugg; use clippy_utils::{ - can_move_expr_to_closure, eager_or_lazy, higher, is_else_clause, is_in_const_context, is_res_lang_ctor, - peel_blocks, peel_hir_expr_while, CaptureKind, + CaptureKind, can_move_expr_to_closure, eager_or_lazy, higher, is_else_clause, is_in_const_context, + is_res_lang_ctor, peel_blocks, peel_hir_expr_while, }; use rustc_errors::Applicability; -use rustc_hir::def::Res; use rustc_hir::LangItem::{OptionNone, OptionSome, ResultErr, ResultOk}; +use rustc_hir::def::Res; use rustc_hir::{Arm, BindingMode, Expr, ExprKind, MatchSource, Mutability, Pat, PatKind, Path, QPath, UnOp}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; diff --git a/clippy_lints/src/panic_in_result_fn.rs b/clippy_lints/src/panic_in_result_fn.rs index fa15d5e4f9f..eebc62e2a5a 100644 --- a/clippy_lints/src/panic_in_result_fn.rs +++ b/clippy_lints/src/panic_in_result_fn.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::macros::root_macro_call_first_node; use clippy_utils::ty::is_type_diagnostic_item; -use clippy_utils::visitors::{for_each_expr, Descend}; +use clippy_utils::visitors::{Descend, for_each_expr}; use clippy_utils::{is_inside_always_const_context, return_ty}; use core::ops::ControlFlow; use rustc_hir as hir; @@ -9,7 +9,7 @@ use rustc_hir::intravisit::FnKind; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; use rustc_span::def_id::LocalDefId; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/pass_by_ref_or_value.rs b/clippy_lints/src/pass_by_ref_or_value.rs index 5ca244f0141..75d8c09f2b0 100644 --- a/clippy_lints/src/pass_by_ref_or_value.rs +++ b/clippy_lints/src/pass_by_ref_or_value.rs @@ -18,7 +18,7 @@ use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::{self, RegionKind, TyCtxt}; use rustc_session::impl_lint_pass; use rustc_span::def_id::LocalDefId; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; use rustc_target::spec::abi::Abi; declare_clippy_lint! { diff --git a/clippy_lints/src/pathbuf_init_then_push.rs b/clippy_lints/src/pathbuf_init_then_push.rs index d7fa48c1e38..1b9a5a44382 100644 --- a/clippy_lints/src/pathbuf_init_then_push.rs +++ b/clippy_lints/src/pathbuf_init_then_push.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::path_to_local_id; -use clippy_utils::source::{snippet, SpanRangeExt}; +use clippy_utils::source::{SpanRangeExt, snippet}; use clippy_utils::ty::is_type_diagnostic_item; use rustc_ast::{LitKind, StrStyle}; use rustc_errors::Applicability; @@ -9,7 +9,7 @@ use rustc_hir::{BindingMode, Block, Expr, ExprKind, HirId, LetStmt, PatKind, QPa use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_session::impl_lint_pass; -use rustc_span::{sym, Span, Symbol}; +use rustc_span::{Span, Symbol, sym}; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/pattern_type_mismatch.rs b/clippy_lints/src/pattern_type_mismatch.rs index c1296b04387..42fbba8ef6d 100644 --- a/clippy_lints/src/pattern_type_mismatch.rs +++ b/clippy_lints/src/pattern_type_mismatch.rs @@ -1,13 +1,13 @@ use clippy_utils::diagnostics::span_lint_and_then; use rustc_hir::{ - intravisit, Body, Expr, ExprKind, FnDecl, LetExpr, LocalSource, Mutability, Pat, PatKind, Stmt, StmtKind, + Body, Expr, ExprKind, FnDecl, LetExpr, LocalSource, Mutability, Pat, PatKind, Stmt, StmtKind, intravisit, }; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty; use rustc_session::declare_lint_pass; -use rustc_span::def_id::LocalDefId; use rustc_span::Span; +use rustc_span::def_id::LocalDefId; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/ptr.rs b/clippy_lints/src/ptr.rs index cd8e921347c..807636bb642 100644 --- a/clippy_lints/src/ptr.rs +++ b/clippy_lints/src/ptr.rs @@ -5,7 +5,7 @@ use clippy_utils::{get_expr_use_or_unification_node, is_lint_allowed, path_def_i use hir::LifetimeName; use rustc_errors::{Applicability, MultiSpan}; use rustc_hir::hir_id::{HirId, HirIdMap}; -use rustc_hir::intravisit::{walk_expr, Visitor}; +use rustc_hir::intravisit::{Visitor, walk_expr}; use rustc_hir::{ self as hir, AnonConst, BinOpKind, BindingMode, Body, Expr, ExprKind, FnRetTy, FnSig, GenericArg, ImplItemKind, ItemKind, Lifetime, Mutability, Node, Param, PatKind, QPath, Safety, TraitFn, TraitItem, TraitItemKind, TyKind, @@ -17,7 +17,7 @@ use rustc_middle::hir::nested_filter; use rustc_middle::ty::{self, Binder, ClauseKind, ExistentialPredicate, List, PredicateKind, Ty}; use rustc_session::declare_lint_pass; use rustc_span::symbol::Symbol; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; use rustc_target::spec::abi::Abi; use rustc_trait_selection::infer::InferCtxtExt as _; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _; diff --git a/clippy_lints/src/pub_underscore_fields.rs b/clippy_lints/src/pub_underscore_fields.rs index 77b707567e4..db03657c9af 100644 --- a/clippy_lints/src/pub_underscore_fields.rs +++ b/clippy_lints/src/pub_underscore_fields.rs @@ -1,5 +1,5 @@ -use clippy_config::types::PubUnderscoreFieldsBehaviour; use clippy_config::Conf; +use clippy_config::types::PubUnderscoreFieldsBehaviour; use clippy_utils::attrs::is_doc_hidden; use clippy_utils::diagnostics::span_lint_hir_and_then; use clippy_utils::is_path_lang_item; diff --git a/clippy_lints/src/question_mark.rs b/clippy_lints/src/question_mark.rs index e1e3ded2c79..aa9a9001afb 100644 --- a/clippy_lints/src/question_mark.rs +++ b/clippy_lints/src/question_mark.rs @@ -1,8 +1,8 @@ use crate::manual_let_else::MANUAL_LET_ELSE; use crate::question_mark_used::QUESTION_MARK_USED; +use clippy_config::Conf; use clippy_config::msrvs::Msrv; use clippy_config::types::MatchLintBehaviour; -use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::{implements_trait, is_type_diagnostic_item}; @@ -12,8 +12,8 @@ use clippy_utils::{ span_contains_comment, }; use rustc_errors::Applicability; -use rustc_hir::def::Res; use rustc_hir::LangItem::{self, OptionNone, OptionSome, ResultErr, ResultOk}; +use rustc_hir::def::Res; use rustc_hir::{ BindingMode, Block, Body, ByRef, Expr, ExprKind, LetStmt, Mutability, Node, PatKind, PathSegment, QPath, Stmt, StmtKind, diff --git a/clippy_lints/src/ranges.rs b/clippy_lints/src/ranges.rs index 81189fe517c..21cd3367262 100644 --- a/clippy_lints/src/ranges.rs +++ b/clippy_lints/src/ranges.rs @@ -1,8 +1,8 @@ -use clippy_config::msrvs::{self, Msrv}; use clippy_config::Conf; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::consts::{ConstEvalCtxt, Constant}; use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then}; -use clippy_utils::source::{snippet, snippet_with_applicability, SpanRangeExt}; +use clippy_utils::source::{SpanRangeExt, snippet, snippet_with_applicability}; use clippy_utils::sugg::Sugg; use clippy_utils::{get_parent_expr, higher, is_in_const_context, is_integer_const, path_to_local}; use rustc_ast::ast::RangeLimits; @@ -11,8 +11,8 @@ use rustc_hir::{BinOpKind, Expr, ExprKind, HirId}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_session::impl_lint_pass; -use rustc_span::source_map::Spanned; use rustc_span::Span; +use rustc_span::source_map::Spanned; use std::cmp::Ordering; declare_clippy_lint! { diff --git a/clippy_lints/src/rc_clone_in_vec_init.rs b/clippy_lints/src/rc_clone_in_vec_init.rs index d0b45b59526..e877f5d6ed4 100644 --- a/clippy_lints/src/rc_clone_in_vec_init.rs +++ b/clippy_lints/src/rc_clone_in_vec_init.rs @@ -8,7 +8,7 @@ use rustc_hir::{Expr, ExprKind, QPath, TyKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_session::declare_lint_pass; -use rustc_span::{sym, Span, Symbol}; +use rustc_span::{Span, Symbol, sym}; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/read_zero_byte_vec.rs b/clippy_lints/src/read_zero_byte_vec.rs index 7f4735c6a88..6bd68dd4109 100644 --- a/clippy_lints/src/read_zero_byte_vec.rs +++ b/clippy_lints/src/read_zero_byte_vec.rs @@ -1,13 +1,13 @@ use clippy_utils::diagnostics::{span_lint_hir, span_lint_hir_and_then}; use clippy_utils::get_enclosing_block; -use clippy_utils::higher::{get_vec_init_kind, VecInitKind}; +use clippy_utils::higher::{VecInitKind, get_vec_init_kind}; use clippy_utils::source::snippet; use hir::{Expr, ExprKind, HirId, LetStmt, PatKind, PathSegment, QPath, StmtKind}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::def::Res; -use rustc_hir::intravisit::{walk_expr, Visitor}; +use rustc_hir::intravisit::{Visitor, walk_expr}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; diff --git a/clippy_lints/src/redundant_clone.rs b/clippy_lints/src/redundant_clone.rs index 4e24ddad83a..b9e0106fc86 100644 --- a/clippy_lints/src/redundant_clone.rs +++ b/clippy_lints/src/redundant_clone.rs @@ -1,17 +1,17 @@ use clippy_utils::diagnostics::{span_lint_hir, span_lint_hir_and_then}; -use clippy_utils::mir::{visit_local_usage, LocalUsage, PossibleBorrowerMap}; +use clippy_utils::fn_has_unsatisfiable_preds; +use clippy_utils::mir::{LocalUsage, PossibleBorrowerMap, visit_local_usage}; use clippy_utils::source::SpanRangeExt; use clippy_utils::ty::{has_drop, is_copy, is_type_diagnostic_item, is_type_lang_item, walk_ptrs_ty_depth}; -use clippy_utils::fn_has_unsatisfiable_preds; use rustc_errors::Applicability; use rustc_hir::intravisit::FnKind; -use rustc_hir::{def_id, Body, FnDecl, LangItem}; +use rustc_hir::{Body, FnDecl, LangItem, def_id}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::mir; use rustc_middle::ty::{self, Ty}; use rustc_session::declare_lint_pass; use rustc_span::def_id::LocalDefId; -use rustc_span::{sym, BytePos, Span}; +use rustc_span::{BytePos, Span, sym}; macro_rules! unwrap_or_continue { ($x:expr) => { @@ -349,14 +349,10 @@ fn visit_clone_usage(cloned: mir::Local, clone: mir::Local, mir: &mir::Body<'_>, local_use_locs: _, local_consume_or_mutate_locs: clone_consume_or_mutate_locs, }, - )) = visit_local_usage( - &[cloned, clone], - mir, - mir::Location { - block: bb, - statement_index: mir.basic_blocks[bb].statements.len(), - }, - ) + )) = visit_local_usage(&[cloned, clone], mir, mir::Location { + block: bb, + statement_index: mir.basic_blocks[bb].statements.len(), + }) .map(|mut vec| (vec.remove(0), vec.remove(0))) { CloneUsage { diff --git a/clippy_lints/src/redundant_closure_call.rs b/clippy_lints/src/redundant_closure_call.rs index bad9b979203..6930a01d48b 100644 --- a/clippy_lints/src/redundant_closure_call.rs +++ b/clippy_lints/src/redundant_closure_call.rs @@ -6,7 +6,7 @@ use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::intravisit::{Visitor as HirVisitor, Visitor}; use rustc_hir::{ - intravisit as hir_visit, ClosureKind, CoroutineDesugaring, CoroutineKind, CoroutineSource, ExprKind, Node, + ClosureKind, CoroutineDesugaring, CoroutineKind, CoroutineSource, ExprKind, Node, intravisit as hir_visit, }; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::hir::nested_filter; diff --git a/clippy_lints/src/redundant_else.rs b/clippy_lints/src/redundant_else.rs index 3bdf13dbbea..6a1d40334e7 100644 --- a/clippy_lints/src/redundant_else.rs +++ b/clippy_lints/src/redundant_else.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_help; use rustc_ast::ast::{Block, Expr, ExprKind, Stmt, StmtKind}; -use rustc_ast::visit::{walk_expr, Visitor}; +use rustc_ast::visit::{Visitor, walk_expr}; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_session::declare_lint_pass; diff --git a/clippy_lints/src/redundant_field_names.rs b/clippy_lints/src/redundant_field_names.rs index 0e637538615..d0dbff081f9 100644 --- a/clippy_lints/src/redundant_field_names.rs +++ b/clippy_lints/src/redundant_field_names.rs @@ -1,5 +1,5 @@ -use clippy_config::msrvs::{self, Msrv}; use clippy_config::Conf; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_sugg; use rustc_ast::ast::{Expr, ExprKind}; use rustc_errors::Applicability; diff --git a/clippy_lints/src/redundant_locals.rs b/clippy_lints/src/redundant_locals.rs index d94ca5bc7ec..4f46ca3c715 100644 --- a/clippy_lints/src/redundant_locals.rs +++ b/clippy_lints/src/redundant_locals.rs @@ -9,8 +9,8 @@ use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::UpvarCapture; use rustc_session::declare_lint_pass; -use rustc_span::symbol::Ident; use rustc_span::DesugaringKind; +use rustc_span::symbol::Ident; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/redundant_static_lifetimes.rs b/clippy_lints/src/redundant_static_lifetimes.rs index d6e741dd974..b27bb2e78af 100644 --- a/clippy_lints/src/redundant_static_lifetimes.rs +++ b/clippy_lints/src/redundant_static_lifetimes.rs @@ -1,5 +1,5 @@ -use clippy_config::msrvs::{self, Msrv}; use clippy_config::Conf; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet; use rustc_ast::ast::{ConstItem, Item, ItemKind, StaticItem, Ty, TyKind}; diff --git a/clippy_lints/src/reference.rs b/clippy_lints/src/reference.rs index 2b4ef21fc48..4bff37216ed 100644 --- a/clippy_lints/src/reference.rs +++ b/clippy_lints/src/reference.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::{snippet_with_applicability, SpanRangeExt}; +use clippy_utils::source::{SpanRangeExt, snippet_with_applicability}; use rustc_ast::ast::{Expr, ExprKind, Mutability, UnOp}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; diff --git a/clippy_lints/src/repeat_vec_with_capacity.rs b/clippy_lints/src/repeat_vec_with_capacity.rs index 08de10f69b0..f54cafffb83 100644 --- a/clippy_lints/src/repeat_vec_with_capacity.rs +++ b/clippy_lints/src/repeat_vec_with_capacity.rs @@ -8,7 +8,7 @@ use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/reserve_after_initialization.rs b/clippy_lints/src/reserve_after_initialization.rs index caf3fb8707d..6157adad059 100644 --- a/clippy_lints/src/reserve_after_initialization.rs +++ b/clippy_lints/src/reserve_after_initialization.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::higher::{get_vec_init_kind, VecInitKind}; +use clippy_utils::higher::{VecInitKind, get_vec_init_kind}; use clippy_utils::source::snippet; use clippy_utils::{is_from_proc_macro, path_to_local_id}; use rustc_errors::Applicability; diff --git a/clippy_lints/src/return_self_not_must_use.rs b/clippy_lints/src/return_self_not_must_use.rs index 5962e8be959..42d9cf2c88c 100644 --- a/clippy_lints/src/return_self_not_must_use.rs +++ b/clippy_lints/src/return_self_not_must_use.rs @@ -7,7 +7,7 @@ use rustc_hir::{Body, FnDecl, OwnerId, TraitItem, TraitItemKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_session::declare_lint_pass; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/returns.rs b/clippy_lints/src/returns.rs index 1e709649695..3754fdddedf 100644 --- a/clippy_lints/src/returns.rs +++ b/clippy_lints/src/returns.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_hir_and_then}; -use clippy_utils::source::{snippet_with_context, SpanRangeExt}; +use clippy_utils::source::{SpanRangeExt, snippet_with_context}; use clippy_utils::sugg::has_enclosing_paren; -use clippy_utils::visitors::{for_each_expr, for_each_unconsumed_temporary, Descend}; +use clippy_utils::visitors::{Descend, for_each_expr, for_each_unconsumed_temporary}; use clippy_utils::{ binary_expr_needs_parentheses, fn_def_id, is_from_proc_macro, is_inside_let_else, is_res_lang_ctor, path_res, path_to_local_id, span_contains_cfg, span_find_starting_semi, @@ -9,8 +9,8 @@ use clippy_utils::{ use core::ops::ControlFlow; use rustc_ast::NestedMetaItem; use rustc_errors::Applicability; -use rustc_hir::intravisit::FnKind; use rustc_hir::LangItem::ResultErr; +use rustc_hir::intravisit::FnKind; use rustc_hir::{ Block, Body, Expr, ExprKind, FnDecl, HirId, ItemKind, LangItem, MatchSource, Node, OwnerNode, PatKind, QPath, Stmt, StmtKind, @@ -21,7 +21,7 @@ use rustc_middle::ty::adjustment::Adjust; use rustc_middle::ty::{self, GenericArgKind, Ty}; use rustc_session::declare_lint_pass; use rustc_span::def_id::LocalDefId; -use rustc_span::{sym, BytePos, Pos, Span}; +use rustc_span::{BytePos, Pos, Span, sym}; use std::borrow::Cow; use std::fmt::Display; diff --git a/clippy_lints/src/same_name_method.rs b/clippy_lints/src/same_name_method.rs index 508f3ae6def..8d31641d483 100644 --- a/clippy_lints/src/same_name_method.rs +++ b/clippy_lints/src/same_name_method.rs @@ -5,8 +5,8 @@ use rustc_hir::{HirId, Impl, ItemKind, Node, Path, QPath, TraitRef, TyKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::AssocKind; use rustc_session::declare_lint_pass; -use rustc_span::symbol::Symbol; use rustc_span::Span; +use rustc_span::symbol::Symbol; use std::collections::{BTreeMap, BTreeSet}; declare_clippy_lint! { @@ -62,13 +62,10 @@ impl<'tcx> LateLintPass<'tcx> for SameNameMethod { && let TyKind::Path(QPath::Resolved(_, Path { res, .. })) = self_ty.kind { if !map.contains_key(res) { - map.insert( - *res, - ExistingName { - impl_methods: BTreeMap::new(), - trait_methods: BTreeMap::new(), - }, - ); + map.insert(*res, ExistingName { + impl_methods: BTreeMap::new(), + trait_methods: BTreeMap::new(), + }); } let existing_name = map.get_mut(res).unwrap(); diff --git a/clippy_lints/src/set_contains_or_insert.rs b/clippy_lints/src/set_contains_or_insert.rs index bc2a71c42b9..1185d67b125 100644 --- a/clippy_lints/src/set_contains_or_insert.rs +++ b/clippy_lints/src/set_contains_or_insert.rs @@ -3,12 +3,12 @@ use std::ops::ControlFlow; use clippy_utils::diagnostics::span_lint; use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::visitors::for_each_expr; -use clippy_utils::{higher, peel_hir_expr_while, SpanlessEq}; +use clippy_utils::{SpanlessEq, higher, peel_hir_expr_while}; use rustc_hir::{Expr, ExprKind, UnOp}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; use rustc_span::symbol::Symbol; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/significant_drop_tightening.rs b/clippy_lints/src/significant_drop_tightening.rs index 979d6dc77ae..d1114cb29f7 100644 --- a/clippy_lints/src/significant_drop_tightening.rs +++ b/clippy_lints/src/significant_drop_tightening.rs @@ -4,13 +4,13 @@ use clippy_utils::{expr_or_init, get_attr, path_to_local, peel_hir_expr_unary}; use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::intravisit::{walk_expr, Visitor}; +use rustc_hir::intravisit::{Visitor, walk_expr}; use rustc_hir::{self as hir, HirId}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::ty::{GenericArgKind, Ty}; use rustc_session::impl_lint_pass; use rustc_span::symbol::Ident; -use rustc_span::{sym, Span, DUMMY_SP}; +use rustc_span::{DUMMY_SP, Span, sym}; use std::borrow::Cow; use std::collections::hash_map::Entry; diff --git a/clippy_lints/src/single_component_path_imports.rs b/clippy_lints/src/single_component_path_imports.rs index acf44a9bb5a..c986c3e8aa6 100644 --- a/clippy_lints/src/single_component_path_imports.rs +++ b/clippy_lints/src/single_component_path_imports.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg}; use rustc_ast::node_id::{NodeId, NodeMap}; use rustc_ast::ptr::P; -use rustc_ast::visit::{walk_expr, Visitor}; +use rustc_ast::visit::{Visitor, walk_expr}; use rustc_ast::{Crate, Expr, ExprKind, Item, ItemKind, MacroDef, ModKind, Ty, TyKind, UseTreeKind}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; diff --git a/clippy_lints/src/slow_vector_initialization.rs b/clippy_lints/src/slow_vector_initialization.rs index 04c16281ec4..5129bbf2665 100644 --- a/clippy_lints/src/slow_vector_initialization.rs +++ b/clippy_lints/src/slow_vector_initialization.rs @@ -2,11 +2,10 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::macros::matching_root_macro_call; use clippy_utils::sugg::Sugg; use clippy_utils::{ - get_enclosing_block, is_integer_literal, is_path_diagnostic_item, path_to_local, - path_to_local_id, SpanlessEq, + SpanlessEq, get_enclosing_block, is_integer_literal, is_path_diagnostic_item, path_to_local, path_to_local_id, }; use rustc_errors::Applicability; -use rustc_hir::intravisit::{walk_block, walk_expr, walk_stmt, Visitor}; +use rustc_hir::intravisit::{Visitor, walk_block, walk_expr, walk_stmt}; use rustc_hir::{BindingMode, Block, Expr, ExprKind, HirId, PatKind, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; diff --git a/clippy_lints/src/std_instead_of_core.rs b/clippy_lints/src/std_instead_of_core.rs index 44283a49e84..8dd99858793 100644 --- a/clippy_lints/src/std_instead_of_core.rs +++ b/clippy_lints/src/std_instead_of_core.rs @@ -1,5 +1,5 @@ -use clippy_config::msrvs::Msrv; use clippy_config::Conf; +use clippy_config::msrvs::Msrv; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::is_from_proc_macro; use rustc_attr::{StabilityLevel, StableSince}; @@ -11,7 +11,7 @@ use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_session::impl_lint_pass; use rustc_span::symbol::kw; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/string_patterns.rs b/clippy_lints/src/string_patterns.rs index 8af50ca87d6..ba2ddac2ec3 100644 --- a/clippy_lints/src/string_patterns.rs +++ b/clippy_lints/src/string_patterns.rs @@ -1,13 +1,13 @@ use std::ops::ControlFlow; -use clippy_config::msrvs::{self, Msrv}; use clippy_config::Conf; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; use clippy_utils::eager_or_lazy::switch_to_eager_eval; use clippy_utils::macros::matching_root_macro_call; use clippy_utils::path_to_local_id; use clippy_utils::source::{snippet, str_literal_to_char_literal}; -use clippy_utils::visitors::{for_each_expr, Descend}; +use clippy_utils::visitors::{Descend, for_each_expr}; use itertools::Itertools; use rustc_ast::{BinOpKind, LitKind}; use rustc_errors::Applicability; @@ -15,7 +15,7 @@ use rustc_hir::{Expr, ExprKind, PatKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_session::impl_lint_pass; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/strings.rs b/clippy_lints/src/strings.rs index 6ca4ca000e9..1fb82b66ab8 100644 --- a/clippy_lints/src/strings.rs +++ b/clippy_lints/src/strings.rs @@ -2,8 +2,8 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_the use clippy_utils::source::{snippet, snippet_with_applicability}; use clippy_utils::ty::is_type_lang_item; use clippy_utils::{ - get_expr_use_or_unification_node, get_parent_expr, is_lint_allowed, is_path_diagnostic_item, method_calls, - peel_blocks, SpanlessEq, + SpanlessEq, get_expr_use_or_unification_node, get_parent_expr, is_lint_allowed, is_path_diagnostic_item, + method_calls, peel_blocks, }; use rustc_errors::Applicability; use rustc_hir::def_id::DefId; diff --git a/clippy_lints/src/suspicious_operation_groupings.rs b/clippy_lints/src/suspicious_operation_groupings.rs index 1c1de805db0..be32dc0aab0 100644 --- a/clippy_lints/src/suspicious_operation_groupings.rs +++ b/clippy_lints/src/suspicious_operation_groupings.rs @@ -1,4 +1,4 @@ -use clippy_utils::ast_utils::{eq_id, is_useless_with_eq_exprs, IdentIter}; +use clippy_utils::ast_utils::{IdentIter, eq_id, is_useless_with_eq_exprs}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; use core::ops::{Add, AddAssign}; @@ -7,9 +7,9 @@ use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_session::declare_lint_pass; +use rustc_span::Span; use rustc_span::source_map::Spanned; use rustc_span::symbol::Ident; -use rustc_span::Span; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/suspicious_trait_impl.rs b/clippy_lints/src/suspicious_trait_impl.rs index 744d6392e06..e9779d437d4 100644 --- a/clippy_lints/src/suspicious_trait_impl.rs +++ b/clippy_lints/src/suspicious_trait_impl.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint; use clippy_utils::visitors::for_each_expr_without_closures; -use clippy_utils::{binop_traits, trait_ref_of_method, BINOP_TRAITS, OP_ASSIGN_TRAITS}; +use clippy_utils::{BINOP_TRAITS, OP_ASSIGN_TRAITS, binop_traits, trait_ref_of_method}; use core::ops::ControlFlow; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; diff --git a/clippy_lints/src/swap.rs b/clippy_lints/src/swap.rs index 197011cde3a..e05fa4095b8 100644 --- a/clippy_lints/src/swap.rs +++ b/clippy_lints/src/swap.rs @@ -6,7 +6,7 @@ use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::{can_mut_borrow_both, eq_expr_value, is_in_const_context, std_or_core}; use itertools::Itertools; -use rustc_hir::intravisit::{walk_expr, Visitor}; +use rustc_hir::intravisit::{Visitor, walk_expr}; use crate::FxHashSet; use rustc_errors::Applicability; @@ -17,7 +17,7 @@ use rustc_middle::ty; use rustc_session::declare_lint_pass; use rustc_span::source_map::Spanned; use rustc_span::symbol::Ident; -use rustc_span::{sym, Span, SyntaxContext}; +use rustc_span::{Span, SyntaxContext, sym}; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/swap_ptr_to_ref.rs b/clippy_lints/src/swap_ptr_to_ref.rs index 20e9608a15d..8c5cf93ab6e 100644 --- a/clippy_lints/src/swap_ptr_to_ref.rs +++ b/clippy_lints/src/swap_ptr_to_ref.rs @@ -5,7 +5,7 @@ use rustc_errors::Applicability; use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability, UnOp}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; -use rustc_span::{sym, Span, SyntaxContext}; +use rustc_span::{Span, SyntaxContext, sym}; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/tests_outside_test_module.rs b/clippy_lints/src/tests_outside_test_module.rs index 25d0a16e2ab..3cd4fefffad 100644 --- a/clippy_lints/src/tests_outside_test_module.rs +++ b/clippy_lints/src/tests_outside_test_module.rs @@ -4,8 +4,8 @@ use rustc_hir::intravisit::FnKind; use rustc_hir::{Body, FnDecl}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; -use rustc_span::def_id::LocalDefId; use rustc_span::Span; +use rustc_span::def_id::LocalDefId; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/to_digit_is_some.rs b/clippy_lints/src/to_digit_is_some.rs index dafe9e38818..4f96a566b63 100644 --- a/clippy_lints/src/to_digit_is_some.rs +++ b/clippy_lints/src/to_digit_is_some.rs @@ -56,11 +56,13 @@ impl<'tcx> LateLintPass<'tcx> for ToDigitIsSome { && let hir::ExprKind::Path(to_digits_path) = &to_digits_call.kind && let to_digits_call_res = cx.qpath_res(to_digits_path, to_digits_call.hir_id) && let Some(to_digits_def_id) = to_digits_call_res.opt_def_id() - && match_def_path( - cx, - to_digits_def_id, - &["core", "char", "methods", "", "to_digit"], - ) + && match_def_path(cx, to_digits_def_id, &[ + "core", + "char", + "methods", + "", + "to_digit", + ]) { Some((false, char_arg, radix_arg)) } else { diff --git a/clippy_lints/src/trait_bounds.rs b/clippy_lints/src/trait_bounds.rs index 2e87d36df31..00277593622 100644 --- a/clippy_lints/src/trait_bounds.rs +++ b/clippy_lints/src/trait_bounds.rs @@ -1,8 +1,8 @@ -use clippy_config::msrvs::{self, Msrv}; use clippy_config::Conf; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg}; -use clippy_utils::source::{snippet, snippet_with_applicability, SpanRangeExt}; -use clippy_utils::{is_from_proc_macro, SpanlessEq, SpanlessHash}; +use clippy_utils::source::{SpanRangeExt, snippet, snippet_with_applicability}; +use clippy_utils::{SpanlessEq, SpanlessHash, is_from_proc_macro}; use core::hash::{Hash, Hasher}; use itertools::Itertools; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; diff --git a/clippy_lints/src/transmute/mod.rs b/clippy_lints/src/transmute/mod.rs index ced53a808f9..25fec9f688c 100644 --- a/clippy_lints/src/transmute/mod.rs +++ b/clippy_lints/src/transmute/mod.rs @@ -19,8 +19,8 @@ mod useless_transmute; mod utils; mod wrong_transmute; -use clippy_config::msrvs::Msrv; use clippy_config::Conf; +use clippy_config::msrvs::Msrv; use clippy_utils::is_in_const_context; use rustc_hir::{Expr, ExprKind, QPath}; use rustc_lint::{LateContext, LateLintPass}; diff --git a/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs b/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs index ba8c7d6bfcb..fca332dba40 100644 --- a/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs +++ b/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs @@ -6,8 +6,8 @@ use rustc_errors::Applicability; use rustc_hir::{Expr, Node}; use rustc_hir_typeck::cast::check_cast; use rustc_lint::LateContext; -use rustc_middle::ty::cast::CastKind; use rustc_middle::ty::Ty; +use rustc_middle::ty::cast::CastKind; /// Checks for `transmutes_expressible_as_ptr_casts` lint. /// Returns `true` if it's triggered, otherwise returns `false`. diff --git a/clippy_lints/src/transmute/unsound_collection_transmute.rs b/clippy_lints/src/transmute/unsound_collection_transmute.rs index 35e93830766..f46e95b0b83 100644 --- a/clippy_lints/src/transmute/unsound_collection_transmute.rs +++ b/clippy_lints/src/transmute/unsound_collection_transmute.rs @@ -1,5 +1,5 @@ -use super::utils::is_layout_incompatible; use super::UNSOUND_COLLECTION_TRANSMUTE; +use super::utils::is_layout_incompatible; use clippy_utils::diagnostics::span_lint; use rustc_hir::Expr; use rustc_lint::LateContext; diff --git a/clippy_lints/src/tuple_array_conversions.rs b/clippy_lints/src/tuple_array_conversions.rs index 1d0de932754..3da8a449a7c 100644 --- a/clippy_lints/src/tuple_array_conversions.rs +++ b/clippy_lints/src/tuple_array_conversions.rs @@ -1,5 +1,5 @@ -use clippy_config::msrvs::{self, Msrv}; use clippy_config::Conf; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::visitors::for_each_local_use_after_expr; use clippy_utils::{is_from_proc_macro, path_to_local}; diff --git a/clippy_lints/src/types/box_collection.rs b/clippy_lints/src/types/box_collection.rs index 9ac73394548..24fe4e08a5b 100644 --- a/clippy_lints/src/types/box_collection.rs +++ b/clippy_lints/src/types/box_collection.rs @@ -3,7 +3,7 @@ use clippy_utils::{path_def_id, qpath_generic_tys}; use rustc_hir::def_id::DefId; use rustc_hir::{self as hir, QPath}; use rustc_lint::LateContext; -use rustc_span::{sym, Symbol}; +use rustc_span::{Symbol, sym}; use super::BOX_COLLECTION; diff --git a/clippy_lints/src/types/mod.rs b/clippy_lints/src/types/mod.rs index 120d5ffbbd3..363aea8be72 100644 --- a/clippy_lints/src/types/mod.rs +++ b/clippy_lints/src/types/mod.rs @@ -18,8 +18,8 @@ use rustc_hir::{ }; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::impl_lint_pass; -use rustc_span::def_id::LocalDefId; use rustc_span::Span; +use rustc_span::def_id::LocalDefId; declare_clippy_lint! { /// ### What it does @@ -386,30 +386,22 @@ impl<'tcx> LateLintPass<'tcx> for Types { let is_exported = cx.effective_visibilities.is_exported(def_id); - self.check_fn_decl( - cx, - decl, - CheckTyContext { - is_in_trait_impl, - is_exported, - in_body: matches!(fn_kind, FnKind::Closure), - ..CheckTyContext::default() - }, - ); + self.check_fn_decl(cx, decl, CheckTyContext { + is_in_trait_impl, + is_exported, + in_body: matches!(fn_kind, FnKind::Closure), + ..CheckTyContext::default() + }); } fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) { let is_exported = cx.effective_visibilities.is_exported(item.owner_id.def_id); match item.kind { - ItemKind::Static(ty, _, _) | ItemKind::Const(ty, _, _) => self.check_ty( - cx, - ty, - CheckTyContext { - is_exported, - ..CheckTyContext::default() - }, - ), + ItemKind::Static(ty, _, _) | ItemKind::Const(ty, _, _) => self.check_ty(cx, ty, CheckTyContext { + is_exported, + ..CheckTyContext::default() + }), // functions, enums, structs, impls and traits are covered _ => (), } @@ -427,14 +419,10 @@ impl<'tcx> LateLintPass<'tcx> for Types { false }; - self.check_ty( - cx, - ty, - CheckTyContext { - is_in_trait_impl, - ..CheckTyContext::default() - }, - ); + self.check_ty(cx, ty, CheckTyContext { + is_in_trait_impl, + ..CheckTyContext::default() + }); }, // Methods are covered by check_fn. // Type aliases are ignored because oftentimes it's impossible to @@ -450,14 +438,10 @@ impl<'tcx> LateLintPass<'tcx> for Types { let is_exported = cx.effective_visibilities.is_exported(field.def_id); - self.check_ty( - cx, - field.ty, - CheckTyContext { - is_exported, - ..CheckTyContext::default() - }, - ); + self.check_ty(cx, field.ty, CheckTyContext { + is_exported, + ..CheckTyContext::default() + }); } fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &TraitItem<'tcx>) { @@ -485,14 +469,10 @@ impl<'tcx> LateLintPass<'tcx> for Types { fn check_local(&mut self, cx: &LateContext<'tcx>, local: &LetStmt<'tcx>) { if let Some(ty) = local.ty { - self.check_ty( - cx, - ty, - CheckTyContext { - in_body: true, - ..CheckTyContext::default() - }, - ); + self.check_ty(cx, ty, CheckTyContext { + in_body: true, + ..CheckTyContext::default() + }); } } } diff --git a/clippy_lints/src/types/redundant_allocation.rs b/clippy_lints/src/types/redundant_allocation.rs index 0801eace4fc..1a656088b17 100644 --- a/clippy_lints/src/types/redundant_allocation.rs +++ b/clippy_lints/src/types/redundant_allocation.rs @@ -9,7 +9,7 @@ use rustc_lint::LateContext; use rustc_middle::ty::TypeVisitableExt; use rustc_span::symbol::sym; -use super::{utils, REDUNDANT_ALLOCATION}; +use super::{REDUNDANT_ALLOCATION, utils}; pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, hir_ty: &hir::Ty<'tcx>, qpath: &QPath<'tcx>, def_id: DefId) -> bool { let mut applicability = Applicability::MaybeIncorrect; diff --git a/clippy_lints/src/types/type_complexity.rs b/clippy_lints/src/types/type_complexity.rs index 7fcfd5c8f35..0b64fddb447 100644 --- a/clippy_lints/src/types/type_complexity.rs +++ b/clippy_lints/src/types/type_complexity.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint; use rustc_hir as hir; -use rustc_hir::intravisit::{walk_inf, walk_ty, Visitor}; +use rustc_hir::intravisit::{Visitor, walk_inf, walk_ty}; use rustc_hir::{GenericParamKind, TyKind}; use rustc_lint::LateContext; use rustc_target::spec::abi::Abi; diff --git a/clippy_lints/src/types/vec_box.rs b/clippy_lints/src/types/vec_box.rs index 29996a6f783..230239335c6 100644 --- a/clippy_lints/src/types/vec_box.rs +++ b/clippy_lints/src/types/vec_box.rs @@ -6,8 +6,8 @@ use rustc_hir::def_id::DefId; use rustc_hir::{self as hir, GenericArg, LangItem, QPath, TyKind}; use rustc_hir_analysis::lower_ty; use rustc_lint::LateContext; -use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::TypeVisitableExt; +use rustc_middle::ty::layout::LayoutOf; use rustc_span::symbol::sym; use super::VEC_BOX; diff --git a/clippy_lints/src/unconditional_recursion.rs b/clippy_lints/src/unconditional_recursion.rs index 42100e1d755..3fc08e8192d 100644 --- a/clippy_lints/src/unconditional_recursion.rs +++ b/clippy_lints/src/unconditional_recursion.rs @@ -5,7 +5,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, LocalDefId}; -use rustc_hir::intravisit::{walk_body, walk_expr, FnKind, Visitor}; +use rustc_hir::intravisit::{FnKind, Visitor, walk_body, walk_expr}; use rustc_hir::{Body, Expr, ExprKind, FnDecl, HirId, Item, ItemKind, Node, QPath, TyKind}; use rustc_hir_analysis::lower_ty; use rustc_lint::{LateContext, LateLintPass}; @@ -13,8 +13,8 @@ use rustc_middle::hir::map::Map; use rustc_middle::hir::nested_filter; use rustc_middle::ty::{self, AssocKind, Ty, TyCtxt}; use rustc_session::impl_lint_pass; -use rustc_span::symbol::{kw, Ident}; -use rustc_span::{sym, Span}; +use rustc_span::symbol::{Ident, kw}; +use rustc_span::{Span, sym}; use rustc_trait_selection::error_reporting::traits::suggestions::ReturnsVisitor; use std::ops::ControlFlow; @@ -257,13 +257,10 @@ fn is_default_method_on_current_ty<'tcx>(tcx: TyCtxt<'tcx>, qpath: QPath<'tcx>, } if matches!( ty.kind, - TyKind::Path(QPath::Resolved( - _, - hir::Path { - res: Res::SelfTyAlias { .. }, - .. - }, - )) + TyKind::Path(QPath::Resolved(_, hir::Path { + res: Res::SelfTyAlias { .. }, + .. + },)) ) { return true; } diff --git a/clippy_lints/src/undocumented_unsafe_blocks.rs b/clippy_lints/src/undocumented_unsafe_blocks.rs index f51c5f74d99..44eb0a6c593 100644 --- a/clippy_lints/src/undocumented_unsafe_blocks.rs +++ b/clippy_lints/src/undocumented_unsafe_blocks.rs @@ -4,12 +4,12 @@ use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::is_lint_allowed; use clippy_utils::source::walk_span_to_context; -use clippy_utils::visitors::{for_each_expr, Descend}; +use clippy_utils::visitors::{Descend, for_each_expr}; use hir::HirId; use rustc_data_structures::sync::Lrc; use rustc_hir as hir; use rustc_hir::{Block, BlockCheckMode, ItemKind, Node, UnsafeSource}; -use rustc_lexer::{tokenize, TokenKind}; +use rustc_lexer::{TokenKind, tokenize}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_session::impl_lint_pass; diff --git a/clippy_lints/src/uninhabited_references.rs b/clippy_lints/src/uninhabited_references.rs index 88039372ebd..cfa565cf803 100644 --- a/clippy_lints/src/uninhabited_references.rs +++ b/clippy_lints/src/uninhabited_references.rs @@ -5,8 +5,8 @@ use rustc_hir_analysis::lower_ty; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::lint::in_external_macro; use rustc_session::declare_lint_pass; -use rustc_span::def_id::LocalDefId; use rustc_span::Span; +use rustc_span::def_id::LocalDefId; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/uninit_vec.rs b/clippy_lints/src/uninit_vec.rs index 9ffcfcc0f50..93ed15777e0 100644 --- a/clippy_lints/src/uninit_vec.rs +++ b/clippy_lints/src/uninit_vec.rs @@ -1,13 +1,13 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; -use clippy_utils::higher::{get_vec_init_kind, VecInitKind}; +use clippy_utils::higher::{VecInitKind, get_vec_init_kind}; use clippy_utils::ty::{is_type_diagnostic_item, is_uninit_value_valid_for_ty}; -use clippy_utils::{is_integer_literal, is_lint_allowed, path_to_local_id, peel_hir_expr_while, SpanlessEq}; +use clippy_utils::{SpanlessEq, is_integer_literal, is_lint_allowed, path_to_local_id, peel_hir_expr_while}; use rustc_hir::{Block, Expr, ExprKind, HirId, PatKind, PathSegment, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty; use rustc_session::declare_lint_pass; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; // TODO: add `ReadBuf` (RFC 2930) in "How to fix" once it is available in std declare_clippy_lint! { diff --git a/clippy_lints/src/unit_return_expecting_ord.rs b/clippy_lints/src/unit_return_expecting_ord.rs index a8cc2f97963..87478a120dd 100644 --- a/clippy_lints/src/unit_return_expecting_ord.rs +++ b/clippy_lints/src/unit_return_expecting_ord.rs @@ -5,7 +5,7 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_middle::ty::{ClauseKind, GenericPredicates, ProjectionPredicate, TraitPredicate}; use rustc_session::declare_lint_pass; -use rustc_span::{sym, BytePos, Span}; +use rustc_span::{BytePos, Span, sym}; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/unit_types/let_unit_value.rs b/clippy_lints/src/unit_types/let_unit_value.rs index 80b661a757c..bf2d75ea1a9 100644 --- a/clippy_lints/src/unit_types/let_unit_value.rs +++ b/clippy_lints/src/unit_types/let_unit_value.rs @@ -4,7 +4,7 @@ use clippy_utils::visitors::{for_each_local_assignment, for_each_value_source, i use core::ops::ControlFlow; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::intravisit::{walk_body, Visitor}; +use rustc_hir::intravisit::{Visitor, walk_body}; use rustc_hir::{Expr, ExprKind, HirId, HirIdSet, LetStmt, MatchSource, Node, PatKind, QPath, TyKind}; use rustc_lint::{LateContext, LintContext}; use rustc_middle::lint::{in_external_macro, is_from_async_await}; diff --git a/clippy_lints/src/unit_types/unit_arg.rs b/clippy_lints/src/unit_types/unit_arg.rs index 978d49f09c3..41b2ca5d268 100644 --- a/clippy_lints/src/unit_types/unit_arg.rs +++ b/clippy_lints/src/unit_types/unit_arg.rs @@ -1,11 +1,11 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::is_from_proc_macro; -use clippy_utils::source::{indent_of, reindent_multiline, SourceText, SpanRangeExt}; +use clippy_utils::source::{SourceText, SpanRangeExt, indent_of, reindent_multiline}; use rustc_errors::Applicability; use rustc_hir::{Block, Expr, ExprKind, MatchSource, Node, StmtKind}; use rustc_lint::LateContext; -use super::{utils, UNIT_ARG}; +use super::{UNIT_ARG, utils}; pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { if expr.span.from_expansion() { diff --git a/clippy_lints/src/unnecessary_wraps.rs b/clippy_lints/src/unnecessary_wraps.rs index 080efe983c2..937e35dea96 100644 --- a/clippy_lints/src/unnecessary_wraps.rs +++ b/clippy_lints/src/unnecessary_wraps.rs @@ -4,15 +4,15 @@ use clippy_utils::source::snippet; use clippy_utils::visitors::find_all_ret_expressions; use clippy_utils::{contains_return, is_res_lang_ctor, path_res, return_ty}; use rustc_errors::Applicability; -use rustc_hir::intravisit::FnKind; use rustc_hir::LangItem::{OptionSome, ResultOk}; +use rustc_hir::intravisit::FnKind; use rustc_hir::{Body, ExprKind, FnDecl, Impl, ItemKind, Node}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_session::impl_lint_pass; +use rustc_span::Span; use rustc_span::def_id::LocalDefId; use rustc_span::symbol::sym; -use rustc_span::Span; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/unnested_or_patterns.rs b/clippy_lints/src/unnested_or_patterns.rs index 98f0be3135d..104be63bb15 100644 --- a/clippy_lints/src/unnested_or_patterns.rs +++ b/clippy_lints/src/unnested_or_patterns.rs @@ -1,14 +1,14 @@ #![allow(clippy::wildcard_imports, clippy::enum_glob_use)] -use clippy_config::msrvs::{self, Msrv}; use clippy_config::Conf; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::ast_utils::{eq_field_pat, eq_id, eq_maybe_qself, eq_pat, eq_path}; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::over; +use rustc_ast::PatKind::*; use rustc_ast::mut_visit::*; use rustc_ast::ptr::P; -use rustc_ast::PatKind::*; -use rustc_ast::{self as ast, Mutability, Pat, PatKind, DUMMY_NODE_ID}; +use rustc_ast::{self as ast, DUMMY_NODE_ID, Mutability, Pat, PatKind}; use rustc_ast_pretty::pprust; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; @@ -16,7 +16,7 @@ use rustc_session::impl_lint_pass; use rustc_span::DUMMY_SP; use std::cell::Cell; use std::mem; -use thin_vec::{thin_vec, ThinVec}; +use thin_vec::{ThinVec, thin_vec}; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/unsafe_removed_from_name.rs b/clippy_lints/src/unsafe_removed_from_name.rs index 309eaedac8d..e70d2a2dafe 100644 --- a/clippy_lints/src/unsafe_removed_from_name.rs +++ b/clippy_lints/src/unsafe_removed_from_name.rs @@ -2,8 +2,8 @@ use clippy_utils::diagnostics::span_lint; use rustc_ast::ast::{Item, ItemKind, UseTree, UseTreeKind}; use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_session::declare_lint_pass; -use rustc_span::symbol::Ident; use rustc_span::Span; +use rustc_span::symbol::Ident; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/unused_async.rs b/clippy_lints/src/unused_async.rs index 738fba54fa8..a1f08cf6623 100644 --- a/clippy_lints/src/unused_async.rs +++ b/clippy_lints/src/unused_async.rs @@ -1,13 +1,13 @@ use clippy_utils::diagnostics::span_lint_hir_and_then; use clippy_utils::is_def_id_trait_method; use rustc_hir::def::DefKind; -use rustc_hir::intravisit::{walk_expr, walk_fn, FnKind, Visitor}; +use rustc_hir::intravisit::{FnKind, Visitor, walk_expr, walk_fn}; use rustc_hir::{Body, Expr, ExprKind, FnDecl, Node, YieldSource}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::nested_filter; use rustc_session::impl_lint_pass; -use rustc_span::def_id::{LocalDefId, LocalDefIdSet}; use rustc_span::Span; +use rustc_span::def_id::{LocalDefId, LocalDefIdSet}; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/unused_io_amount.rs b/clippy_lints/src/unused_io_amount.rs index af7abd009d2..d2a21b11ef4 100644 --- a/clippy_lints/src/unused_io_amount.rs +++ b/clippy_lints/src/unused_io_amount.rs @@ -5,7 +5,7 @@ use hir::{ExprKind, HirId, PatKind}; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/unused_peekable.rs b/clippy_lints/src/unused_peekable.rs index 86a811e17ca..71aa57e0a14 100644 --- a/clippy_lints/src/unused_peekable.rs +++ b/clippy_lints/src/unused_peekable.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_hir_and_then; use clippy_utils::ty::{is_type_diagnostic_item, peel_mid_ty_refs_is_mutable}; use clippy_utils::{fn_def_id, is_trait_method, path_to_local_id, peel_ref_operators}; use rustc_ast::Mutability; -use rustc_hir::intravisit::{walk_expr, Visitor}; +use rustc_hir::intravisit::{Visitor, walk_expr}; use rustc_hir::{Block, Expr, ExprKind, HirId, LetStmt, Node, PatKind, PathSegment, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::nested_filter::OnlyBodies; diff --git a/clippy_lints/src/unused_trait_names.rs b/clippy_lints/src/unused_trait_names.rs index c1cf58dcfce..9fd6ebccd02 100644 --- a/clippy_lints/src/unused_trait_names.rs +++ b/clippy_lints/src/unused_trait_names.rs @@ -1,5 +1,5 @@ -use clippy_config::msrvs::{self, Msrv}; use clippy_config::Conf; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::is_from_proc_macro; use clippy_utils::source::snippet_opt; diff --git a/clippy_lints/src/unused_unit.rs b/clippy_lints/src/unused_unit.rs index 65f431d338b..d5309aade7a 100644 --- a/clippy_lints/src/unused_unit.rs +++ b/clippy_lints/src/unused_unit.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::{position_before_rarrow, SpanRangeExt}; +use clippy_utils::source::{SpanRangeExt, position_before_rarrow}; use rustc_ast::visit::FnKind; -use rustc_ast::{ast, ClosureBinder}; +use rustc_ast::{ClosureBinder, ast}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_session::declare_lint_pass; diff --git a/clippy_lints/src/unwrap.rs b/clippy_lints/src/unwrap.rs index 0b4ea0752b6..596f0fd9c8b 100644 --- a/clippy_lints/src/unwrap.rs +++ b/clippy_lints/src/unwrap.rs @@ -3,7 +3,7 @@ use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::usage::is_potentially_local_place; use clippy_utils::{higher, path_to_local}; use rustc_errors::Applicability; -use rustc_hir::intravisit::{walk_expr, walk_fn, FnKind, Visitor}; +use rustc_hir::intravisit::{FnKind, Visitor, walk_expr, walk_fn}; use rustc_hir::{BinOpKind, Body, Expr, ExprKind, FnDecl, HirId, Node, PathSegment, UnOp}; use rustc_hir_typeck::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceWithHirId}; use rustc_lint::{LateContext, LateLintPass}; @@ -13,7 +13,7 @@ use rustc_middle::mir::FakeReadCause; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_session::declare_lint_pass; use rustc_span::def_id::LocalDefId; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/unwrap_in_result.rs b/clippy_lints/src/unwrap_in_result.rs index f77badd97b7..9b9a2ffbbc8 100644 --- a/clippy_lints/src/unwrap_in_result.rs +++ b/clippy_lints/src/unwrap_in_result.rs @@ -7,7 +7,7 @@ use rustc_hir as hir; use rustc_hir::ImplItemKind; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/use_self.rs b/clippy_lints/src/use_self.rs index 5da48f4f7fb..e340b419bd0 100644 --- a/clippy_lints/src/use_self.rs +++ b/clippy_lints/src/use_self.rs @@ -1,5 +1,5 @@ -use clippy_config::msrvs::{self, Msrv}; use clippy_config::Conf; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::is_from_proc_macro; use clippy_utils::ty::same_type_and_consts; @@ -7,7 +7,7 @@ use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; use rustc_hir::def::{CtorOf, DefKind, Res}; use rustc_hir::def_id::LocalDefId; -use rustc_hir::intravisit::{walk_inf, walk_ty, Visitor}; +use rustc_hir::intravisit::{Visitor, walk_inf, walk_ty}; use rustc_hir::{ self as hir, Expr, ExprKind, FnRetTy, FnSig, GenericArgsParentheses, GenericParam, GenericParamKind, HirId, Impl, ImplItemKind, Item, ItemKind, Pat, PatKind, Path, QPath, Ty, TyKind, diff --git a/clippy_lints/src/useless_conversion.rs b/clippy_lints/src/useless_conversion.rs index 1890b3fdd40..29a7949b343 100644 --- a/clippy_lints/src/useless_conversion.rs +++ b/clippy_lints/src/useless_conversion.rs @@ -12,7 +12,7 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::traits::ObligationCause; use rustc_middle::ty::{self, EarlyBinder, GenericArg, GenericArgsRef, Ty, TypeVisitableExt}; use rustc_session::impl_lint_pass; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; declare_clippy_lint! { diff --git a/clippy_lints/src/utils/author.rs b/clippy_lints/src/utils/author.rs index 0cce45290cf..31f9d84f5e4 100644 --- a/clippy_lints/src/utils/author.rs +++ b/clippy_lints/src/utils/author.rs @@ -1,6 +1,6 @@ use clippy_utils::{get_attr, higher}; -use rustc_ast::ast::{LitFloatType, LitKind}; use rustc_ast::LitIntType; +use rustc_ast::ast::{LitFloatType, LitKind}; use rustc_data_structures::fx::FxHashMap; use rustc_hir::{ self as hir, ArrayLen, BindingMode, CaptureBy, Closure, ClosureKind, ConstArg, ConstArgKind, CoroutineKind, diff --git a/clippy_lints/src/utils/format_args_collector.rs b/clippy_lints/src/utils/format_args_collector.rs index f50ce6c99de..8f314ce7a60 100644 --- a/clippy_lints/src/utils/format_args_collector.rs +++ b/clippy_lints/src/utils/format_args_collector.rs @@ -3,10 +3,10 @@ use clippy_utils::source::SpanRangeExt; use itertools::Itertools; use rustc_ast::{Crate, Expr, ExprKind, FormatArgs}; use rustc_data_structures::fx::FxHashMap; -use rustc_lexer::{tokenize, TokenKind}; +use rustc_lexer::{TokenKind, tokenize}; use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_session::impl_lint_pass; -use rustc_span::{hygiene, Span}; +use rustc_span::{Span, hygiene}; use std::iter::once; use std::mem; diff --git a/clippy_lints/src/utils/internal_lints/collapsible_calls.rs b/clippy_lints/src/utils/internal_lints/collapsible_calls.rs index f7529682675..d8f101a8614 100644 --- a/clippy_lints/src/utils/internal_lints/collapsible_calls.rs +++ b/clippy_lints/src/utils/internal_lints/collapsible_calls.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet; -use clippy_utils::{is_expr_path_def_path, is_lint_allowed, peel_blocks_with_stmt, SpanlessEq}; +use clippy_utils::{SpanlessEq, is_expr_path_def_path, is_lint_allowed, peel_blocks_with_stmt}; use rustc_errors::Applicability; use rustc_hir::{Closure, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; diff --git a/clippy_lints/src/utils/internal_lints/invalid_paths.rs b/clippy_lints/src/utils/internal_lints/invalid_paths.rs index 0ffcb433481..d444ad45087 100644 --- a/clippy_lints/src/utils/internal_lints/invalid_paths.rs +++ b/clippy_lints/src/utils/internal_lints/invalid_paths.rs @@ -2,11 +2,11 @@ use clippy_utils::consts::{ConstEvalCtxt, Constant}; use clippy_utils::def_path_res; use clippy_utils::diagnostics::span_lint; use rustc_hir as hir; -use rustc_hir::def::DefKind; use rustc_hir::Item; +use rustc_hir::def::DefKind; use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::ty::fast_reject::SimplifiedType; use rustc_middle::ty::FloatTy; +use rustc_middle::ty::fast_reject::SimplifiedType; use rustc_session::declare_lint_pass; use rustc_span::symbol::Symbol; 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 20526113d69..7c45a5b2f09 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 @@ -12,7 +12,7 @@ use rustc_middle::hir::nested_filter; use rustc_session::impl_lint_pass; use rustc_span::source_map::Spanned; use rustc_span::symbol::Symbol; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; use {rustc_ast as ast, rustc_hir as hir}; declare_clippy_lint! { diff --git a/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs b/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs index 41183700f09..76b0a52621b 100644 --- a/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs +++ b/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs @@ -8,12 +8,12 @@ use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; use rustc_hir::{Expr, ExprKind, LetStmt, Mutability, Node}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::mir::interpret::{Allocation, GlobalAlloc}; use rustc_middle::mir::ConstValue; +use rustc_middle::mir::interpret::{Allocation, GlobalAlloc}; use rustc_middle::ty::{self, Ty}; use rustc_session::impl_lint_pass; -use rustc_span::symbol::Symbol; use rustc_span::Span; +use rustc_span::symbol::Symbol; use std::str; diff --git a/clippy_lints/src/vec.rs b/clippy_lints/src/vec.rs index d3e49bff422..ce4f41e854d 100644 --- a/clippy_lints/src/vec.rs +++ b/clippy_lints/src/vec.rs @@ -1,8 +1,8 @@ use std::collections::BTreeMap; use std::ops::ControlFlow; -use clippy_config::msrvs::{self, Msrv}; use clippy_config::Conf; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::consts::{ConstEvalCtxt, Constant}; use clippy_utils::diagnostics::span_lint_hir_and_then; use clippy_utils::source::SpanRangeExt; @@ -15,7 +15,7 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_middle::ty::layout::LayoutOf; use rustc_session::impl_lint_pass; -use rustc_span::{sym, DesugaringKind, Span}; +use rustc_span::{DesugaringKind, Span, sym}; #[expect(clippy::module_name_repetitions)] pub struct UselessVec { diff --git a/clippy_lints/src/vec_init_then_push.rs b/clippy_lints/src/vec_init_then_push.rs index a599415a2dd..91dff5a9523 100644 --- a/clippy_lints/src/vec_init_then_push.rs +++ b/clippy_lints/src/vec_init_then_push.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::higher::{get_vec_init_kind, VecInitKind}; +use clippy_utils::higher::{VecInitKind, get_vec_init_kind}; use clippy_utils::source::snippet; use clippy_utils::visitors::for_each_local_use_after_expr; use clippy_utils::{get_parent_expr, path_to_local_id}; diff --git a/clippy_lints/src/visibility.rs b/clippy_lints/src/visibility.rs index 7a85196ceca..2e5fc5834e2 100644 --- a/clippy_lints/src/visibility.rs +++ b/clippy_lints/src/visibility.rs @@ -5,8 +5,8 @@ use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_session::declare_lint_pass; -use rustc_span::symbol::kw; use rustc_span::Span; +use rustc_span::symbol::kw; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/wildcard_imports.rs b/clippy_lints/src/wildcard_imports.rs index 7d9e58ad2f8..405310512df 100644 --- a/clippy_lints/src/wildcard_imports.rs +++ b/clippy_lints/src/wildcard_imports.rs @@ -10,7 +10,7 @@ use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::ty; use rustc_session::impl_lint_pass; use rustc_span::symbol::kw; -use rustc_span::{sym, BytePos}; +use rustc_span::{BytePos, sym}; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/write.rs b/clippy_lints/src/write.rs index ec5a5896fb2..1dd46ed5a89 100644 --- a/clippy_lints/src/write.rs +++ b/clippy_lints/src/write.rs @@ -1,8 +1,8 @@ use clippy_config::Conf; use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; use clippy_utils::is_in_test; -use clippy_utils::macros::{format_arg_removal_span, root_macro_call_first_node, FormatArgsStorage, MacroCall}; -use clippy_utils::source::{expand_past_previous_comma, SpanRangeExt}; +use clippy_utils::macros::{FormatArgsStorage, MacroCall, format_arg_removal_span, root_macro_call_first_node}; +use clippy_utils::source::{SpanRangeExt, expand_past_previous_comma}; use rustc_ast::token::LitKind; use rustc_ast::{ FormatArgPosition, FormatArgPositionKind, FormatArgs, FormatArgsPiece, FormatOptions, FormatPlaceholder, @@ -12,7 +12,7 @@ use rustc_errors::Applicability; use rustc_hir::{Expr, Impl, Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_session::impl_lint_pass; -use rustc_span::{sym, BytePos, Span}; +use rustc_span::{BytePos, Span, sym}; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/zombie_processes.rs b/clippy_lints/src/zombie_processes.rs index eda3d7820c1..ba2a80ee66b 100644 --- a/clippy_lints/src/zombie_processes.rs +++ b/clippy_lints/src/zombie_processes.rs @@ -1,14 +1,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_errors::Applicability; -use rustc_hir::intravisit::{walk_block, walk_expr, walk_local, Visitor}; +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_session::declare_lint_pass; use rustc_span::sym; use std::ops::ControlFlow; -use ControlFlow::{Break, Continue}; declare_clippy_lint! { /// ### What it does diff --git a/clippy_utils/src/ast_utils/ident_iter.rs b/clippy_utils/src/ast_utils/ident_iter.rs index eefcbabd835..032cd3ed739 100644 --- a/clippy_utils/src/ast_utils/ident_iter.rs +++ b/clippy_utils/src/ast_utils/ident_iter.rs @@ -1,5 +1,5 @@ use core::iter::FusedIterator; -use rustc_ast::visit::{walk_attribute, walk_expr, Visitor}; +use rustc_ast::visit::{Visitor, walk_attribute, walk_expr}; use rustc_ast::{Attribute, Expr}; use rustc_span::symbol::Ident; diff --git a/clippy_utils/src/attrs.rs b/clippy_utils/src/attrs.rs index 935a1686c0a..edc9c6ccdff 100644 --- a/clippy_utils/src/attrs.rs +++ b/clippy_utils/src/attrs.rs @@ -4,7 +4,7 @@ use rustc_lexer::TokenKind; use rustc_lint::LateContext; use rustc_middle::ty::{AdtDef, TyCtxt}; use rustc_session::Session; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; use std::str::FromStr; use crate::source::SpanRangeExt; diff --git a/clippy_utils/src/check_proc_macro.rs b/clippy_utils/src/check_proc_macro.rs index 2bd6837d973..9143d292f67 100644 --- a/clippy_utils/src/check_proc_macro.rs +++ b/clippy_utils/src/check_proc_macro.rs @@ -12,9 +12,9 @@ //! code was written, and check if the span contains that text. Note this will only work correctly //! if the span is not from a `macro_rules` based macro. +use rustc_ast::AttrStyle; use rustc_ast::ast::{AttrKind, Attribute, IntTy, LitIntType, LitKind, StrStyle, TraitObjectSyntax, UintTy}; use rustc_ast::token::CommentKind; -use rustc_ast::AttrStyle; use rustc_hir::intravisit::FnKind; use rustc_hir::{ Block, BlockCheckMode, Body, Closure, Destination, Expr, ExprKind, FieldDef, FnHeader, FnRetTy, HirId, Impl, @@ -24,7 +24,7 @@ use rustc_hir::{ use rustc_lint::{LateContext, LintContext}; use rustc_middle::ty::TyCtxt; use rustc_session::Session; -use rustc_span::symbol::{kw, Ident}; +use rustc_span::symbol::{Ident, kw}; use rustc_span::{Span, Symbol}; use rustc_target::spec::abi::Abi; diff --git a/clippy_utils/src/consts.rs b/clippy_utils/src/consts.rs index 760d5bc95f7..bf47cf6d372 100644 --- a/clippy_utils/src/consts.rs +++ b/clippy_utils/src/consts.rs @@ -1,24 +1,24 @@ #![allow(clippy::float_cmp)] use crate::macros::HirNode; -use crate::source::{walk_span_to_context, SpanRangeExt}; +use crate::source::{SpanRangeExt, walk_span_to_context}; use crate::{clip, is_direct_expn_of, sext, unsext}; -use rustc_apfloat::ieee::{Half, Quad}; use rustc_apfloat::Float; +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_lexer::tokenize; use rustc_lint::LateContext; -use rustc_middle::mir::interpret::{alloc_range, Scalar}; use rustc_middle::mir::ConstValue; +use rustc_middle::mir::interpret::{Scalar, alloc_range}; use rustc_middle::ty::{self, FloatTy, IntTy, ParamEnv, ScalarInt, Ty, TyCtxt, TypeckResults, UintTy}; use rustc_middle::{bug, mir, span_bug}; use rustc_span::def_id::DefId; use rustc_span::symbol::Ident; -use rustc_span::{sym, SyntaxContext}; +use rustc_span::{SyntaxContext, sym}; use rustc_target::abi::Size; use std::cell::Cell; use std::cmp::Ordering; @@ -581,7 +581,7 @@ impl<'tcx> ConstEvalCtxt<'tcx> { } fn constant_negate(&self, o: &Constant<'tcx>, ty: Ty<'_>) -> Option> { - use self::Constant::{Int, F32, F64}; + use self::Constant::{F32, F64, Int}; match *o { Int(value) => { let ty::Int(ity) = *ty.kind() else { return None }; diff --git a/clippy_utils/src/eager_or_lazy.rs b/clippy_utils/src/eager_or_lazy.rs index a6dd12a28c5..9420d84b959 100644 --- a/clippy_utils/src/eager_or_lazy.rs +++ b/clippy_utils/src/eager_or_lazy.rs @@ -14,12 +14,12 @@ use crate::ty::{all_predicates_of, is_copy}; use crate::visitors::is_const_evaluatable; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; -use rustc_hir::intravisit::{walk_expr, Visitor}; +use rustc_hir::intravisit::{Visitor, walk_expr}; use rustc_hir::{BinOpKind, Block, Expr, ExprKind, QPath, UnOp}; use rustc_lint::LateContext; use rustc_middle::ty; use rustc_middle::ty::adjustment::Adjust; -use rustc_span::{sym, Symbol}; +use rustc_span::{Symbol, sym}; use std::{cmp, ops}; #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] diff --git a/clippy_utils/src/higher.rs b/clippy_utils/src/higher.rs index e09cc9edf3a..3175a9a1dd3 100644 --- a/clippy_utils/src/higher.rs +++ b/clippy_utils/src/higher.rs @@ -3,14 +3,14 @@ #![deny(clippy::missing_docs_in_private_items)] use crate::consts::{ConstEvalCtxt, Constant}; -use crate::ty::is_type_diagnostic_item; use crate::is_expn_of; +use crate::ty::is_type_diagnostic_item; use rustc_ast::ast; use rustc_hir as hir; use rustc_hir::{Arm, Block, Expr, ExprKind, HirId, LoopSource, MatchSource, Node, Pat, QPath}; use rustc_lint::LateContext; -use rustc_span::{sym, symbol, Span}; +use rustc_span::{Span, sym, symbol}; /// The essential nodes of a desugared for loop as well as the entire span: /// `for pat in arg { body }` becomes `(pat, arg, body)`. Returns `(pat, arg, body, span)`. diff --git a/clippy_utils/src/hir_utils.rs b/clippy_utils/src/hir_utils.rs index c1e21ec4e39..76900379ac7 100644 --- a/clippy_utils/src/hir_utils.rs +++ b/clippy_utils/src/hir_utils.rs @@ -1,20 +1,20 @@ use crate::consts::ConstEvalCtxt; use crate::macros::macro_backtrace; -use crate::source::{walk_span_to_context, SpanRange, SpanRangeExt}; +use crate::source::{SpanRange, SpanRangeExt, walk_span_to_context}; use crate::tokenize_with_text; use rustc_ast::ast::InlineAsmTemplatePiece; use rustc_data_structures::fx::FxHasher; -use rustc_hir::def::Res; use rustc_hir::MatchSource::TryDesugar; +use rustc_hir::def::Res; use rustc_hir::{ ArrayLen, 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, Ty, TyKind, }; -use rustc_lexer::{tokenize, TokenKind}; +use rustc_lexer::{TokenKind, tokenize}; use rustc_lint::LateContext; use rustc_middle::ty::TypeckResults; -use rustc_span::{sym, BytePos, ExpnKind, MacroKind, Symbol, SyntaxContext}; +use rustc_span::{BytePos, ExpnKind, MacroKind, Symbol, SyntaxContext, sym}; use std::hash::{Hash, Hasher}; use std::ops::Range; diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 5a68b0860bc..a925549b0bf 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -78,7 +78,7 @@ pub mod visitors; pub use self::attrs::*; pub use self::check_proc_macro::{is_from_proc_macro, is_span_if, is_span_match}; pub use self::hir_utils::{ - both, count_eq, eq_expr_value, hash_expr, hash_stmt, is_bool, over, HirEqInterExpr, SpanlessEq, SpanlessHash, + HirEqInterExpr, SpanlessEq, SpanlessHash, both, count_eq, eq_expr_value, hash_expr, hash_stmt, is_bool, over, }; use core::mem; @@ -94,20 +94,20 @@ use rustc_ast::ast::{self, LitKind, RangeLimits}; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::packed::Pu128; use rustc_data_structures::unhash::UnhashMap; +use rustc_hir::LangItem::{OptionNone, OptionSome, ResultErr, ResultOk}; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, LocalModDefId, LOCAL_CRATE}; +use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LOCAL_CRATE, LocalDefId, LocalModDefId}; use rustc_hir::definitions::{DefPath, DefPathData}; use rustc_hir::hir_id::{HirIdMap, HirIdSet}; -use rustc_hir::intravisit::{walk_expr, FnKind, Visitor}; -use rustc_hir::LangItem::{OptionNone, OptionSome, ResultErr, ResultOk}; +use rustc_hir::intravisit::{FnKind, Visitor, walk_expr}; use rustc_hir::{ - self as hir, def, Arm, ArrayLen, BindingMode, Block, BlockCheckMode, Body, ByRef, Closure, ConstArgKind, - ConstContext, Destination, Expr, ExprField, ExprKind, FnDecl, FnRetTy, GenericArgs, HirId, Impl, ImplItem, - ImplItemKind, ImplItemRef, Item, ItemKind, LangItem, LetStmt, MatchSource, Mutability, Node, OwnerId, OwnerNode, - Param, Pat, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, TraitItem, TraitItemKind, TraitItemRef, - TraitRef, TyKind, UnOp, + self as hir, Arm, ArrayLen, BindingMode, Block, BlockCheckMode, Body, ByRef, Closure, ConstArgKind, ConstContext, + Destination, Expr, ExprField, ExprKind, FnDecl, FnRetTy, GenericArgs, HirId, Impl, ImplItem, ImplItemKind, + ImplItemRef, Item, ItemKind, LangItem, LetStmt, MatchSource, Mutability, Node, OwnerId, OwnerNode, Param, Pat, + PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, TraitItem, TraitItemKind, TraitItemRef, TraitRef, + TyKind, UnOp, def, }; -use rustc_lexer::{tokenize, TokenKind}; +use rustc_lexer::{TokenKind, tokenize}; use rustc_lint::{LateContext, Level, Lint, LintContext}; use rustc_middle::hir::place::PlaceBase; use rustc_middle::mir::Const; @@ -120,12 +120,12 @@ use rustc_middle::ty::{ }; use rustc_span::hygiene::{ExpnKind, MacroKind}; use rustc_span::source_map::SourceMap; -use rustc_span::symbol::{kw, Ident, Symbol}; -use rustc_span::{sym, InnerSpan, Span}; +use rustc_span::symbol::{Ident, Symbol, kw}; +use rustc_span::{InnerSpan, Span, sym}; use rustc_target::abi::Integer; use visitors::Visitable; -use crate::consts::{mir_to_const, ConstEvalCtxt, Constant}; +use crate::consts::{ConstEvalCtxt, Constant, mir_to_const}; use crate::higher::Range; use crate::ty::{adt_and_variant_of_res, can_partially_move_ty, expr_sig, is_copy, is_recursively_primitive_type}; use crate::visitors::for_each_expr_without_closures; @@ -263,9 +263,13 @@ pub fn is_res_lang_ctor(cx: &LateContext<'_>, res: Res, lang_item: LangItem) -> } } - /// Checks if `{ctor_call_id}(...)` is `{enum_item}::{variant_name}(...)`. -pub fn is_enum_variant_ctor(cx: &LateContext<'_>, enum_item: Symbol, variant_name: Symbol, ctor_call_id: DefId) -> bool { +pub fn is_enum_variant_ctor( + cx: &LateContext<'_>, + enum_item: Symbol, + variant_name: Symbol, + ctor_call_id: DefId, +) -> bool { let Some(enum_def_id) = cx.tcx.get_diagnostic_item(enum_item) else { return false; }; diff --git a/clippy_utils/src/macros.rs b/clippy_utils/src/macros.rs index 1d7479bff82..9c4d19ac1f1 100644 --- a/clippy_utils/src/macros.rs +++ b/clippy_utils/src/macros.rs @@ -1,6 +1,6 @@ #![allow(clippy::similar_names)] // `expr` and `expn` -use crate::visitors::{for_each_expr_without_closures, Descend}; +use crate::visitors::{Descend, for_each_expr_without_closures}; use arrayvec::ArrayVec; use rustc_ast::{FormatArgs, FormatArgument, FormatPlaceholder}; @@ -10,7 +10,7 @@ use rustc_hir::{self as hir, Expr, ExprKind, HirId, Node, QPath}; use rustc_lint::LateContext; use rustc_span::def_id::DefId; use rustc_span::hygiene::{self, MacroKind, SyntaxContext}; -use rustc_span::{sym, BytePos, ExpnData, ExpnId, ExpnKind, Span, SpanData, Symbol}; +use rustc_span::{BytePos, ExpnData, ExpnId, ExpnKind, Span, SpanData, Symbol, sym}; use std::ops::ControlFlow; const FORMAT_MACRO_DIAG_ITEMS: &[Symbol] = &[ diff --git a/clippy_utils/src/mir/mod.rs b/clippy_utils/src/mir/mod.rs index 654fb564848..59bb5e35cda 100644 --- a/clippy_utils/src/mir/mod.rs +++ b/clippy_utils/src/mir/mod.rs @@ -2,7 +2,7 @@ use rustc_hir::{Expr, HirId}; use rustc_index::bit_set::BitSet; use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor}; use rustc_middle::mir::{ - traversal, BasicBlock, Body, InlineAsmOperand, Local, Location, Place, StatementKind, TerminatorKind, START_BLOCK, + BasicBlock, Body, InlineAsmOperand, Local, Location, Place, START_BLOCK, StatementKind, TerminatorKind, traversal, }; use rustc_middle::ty::TyCtxt; @@ -112,14 +112,10 @@ pub fn block_in_cycle(body: &Body<'_>, block: BasicBlock) -> bool { /// Convenience wrapper around `visit_local_usage`. pub fn used_exactly_once(mir: &Body<'_>, local: Local) -> Option { - visit_local_usage( - &[local], - mir, - Location { - block: START_BLOCK, - statement_index: 0, - }, - ) + visit_local_usage(&[local], mir, Location { + block: START_BLOCK, + statement_index: 0, + }) .map(|mut vec| { let LocalUsage { local_use_locs, .. } = vec.remove(0); let mut locations = local_use_locs diff --git a/clippy_utils/src/ptr.rs b/clippy_utils/src/ptr.rs index 991ea428dc3..273c1b0defa 100644 --- a/clippy_utils/src/ptr.rs +++ b/clippy_utils/src/ptr.rs @@ -1,5 +1,5 @@ use crate::source::snippet; -use crate::visitors::{for_each_expr_without_closures, Descend}; +use crate::visitors::{Descend, for_each_expr_without_closures}; use crate::{path_to_local_id, strip_pat_refs}; use core::ops::ControlFlow; use rustc_hir::{Body, BodyId, ExprKind, HirId, PatKind}; diff --git a/clippy_utils/src/qualify_min_const_fn.rs b/clippy_utils/src/qualify_min_const_fn.rs index d9befb3c157..2ed20b7202c 100644 --- a/clippy_utils/src/qualify_min_const_fn.rs +++ b/clippy_utils/src/qualify_min_const_fn.rs @@ -18,8 +18,8 @@ use rustc_middle::mir::{ use rustc_middle::traits::{BuiltinImplSource, ImplSource, ObligationCause}; use rustc_middle::ty::adjustment::PointerCoercion; use rustc_middle::ty::{self, GenericArgKind, TraitRef, Ty, TyCtxt}; -use rustc_span::symbol::sym; use rustc_span::Span; +use rustc_span::symbol::sym; use rustc_trait_selection::traits::{ObligationCtxt, SelectionContext}; use std::borrow::Cow; diff --git a/clippy_utils/src/source.rs b/clippy_utils/src/source.rs index f97fb4a6471..4ad7575e720 100644 --- a/clippy_utils/src/source.rs +++ b/clippy_utils/src/source.rs @@ -9,10 +9,10 @@ use rustc_hir::{BlockCheckMode, Expr, ExprKind, UnsafeSource}; use rustc_lint::{EarlyContext, LateContext}; use rustc_middle::ty::TyCtxt; use rustc_session::Session; -use rustc_span::source_map::{original_sp, SourceMap}; +use rustc_span::source_map::{SourceMap, original_sp}; use rustc_span::{ - hygiene, BytePos, FileNameDisplayPreference, Pos, SourceFile, SourceFileAndLine, Span, SpanData, SyntaxContext, - DUMMY_SP, + BytePos, DUMMY_SP, FileNameDisplayPreference, Pos, SourceFile, SourceFileAndLine, Span, SpanData, SyntaxContext, + hygiene, }; use std::borrow::Cow; use std::fmt; @@ -725,15 +725,12 @@ pub fn str_literal_to_char_literal( &snip[1..(snip.len() - 1)] }; - let hint = format!( - "'{}'", - match ch { - "'" => "\\'", - r"\" => "\\\\", - "\\\"" => "\"", // no need to escape `"` in `'"'` - _ => ch, - } - ); + let hint = format!("'{}'", match ch { + "'" => "\\'", + r"\" => "\\\\", + "\\\"" => "\"", // no need to escape `"` in `'"'` + _ => ch, + }); Some(hint) } else { diff --git a/clippy_utils/src/str_utils.rs b/clippy_utils/src/str_utils.rs index 421b25a77fe..1588ee452da 100644 --- a/clippy_utils/src/str_utils.rs +++ b/clippy_utils/src/str_utils.rs @@ -370,9 +370,11 @@ mod test { assert_eq!(camel_case_split("AbcDef"), vec!["Abc", "Def"]); assert_eq!(camel_case_split("Abc"), vec!["Abc"]); assert_eq!(camel_case_split("abcDef"), vec!["abc", "Def"]); - assert_eq!( - camel_case_split("\u{f6}\u{f6}AabABcd"), - vec!["\u{f6}\u{f6}", "Aab", "A", "Bcd"] - ); + assert_eq!(camel_case_split("\u{f6}\u{f6}AabABcd"), vec![ + "\u{f6}\u{f6}", + "Aab", + "A", + "Bcd" + ]); } } diff --git a/clippy_utils/src/ty.rs b/clippy_utils/src/ty.rs index 9c5e761abe4..775a98fe361 100644 --- a/clippy_utils/src/ty.rs +++ b/clippy_utils/src/ty.rs @@ -12,8 +12,8 @@ use rustc_hir::def_id::DefId; use rustc_hir::{Expr, FnDecl, LangItem, Safety, TyKind}; use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::LateContext; -use rustc_middle::mir::interpret::Scalar; use rustc_middle::mir::ConstValue; +use rustc_middle::mir::interpret::Scalar; use rustc_middle::traits::EvaluationResult; use rustc_middle::ty::layout::ValidityRequirement; use rustc_middle::ty::{ @@ -22,7 +22,7 @@ use rustc_middle::ty::{ TypeVisitable, TypeVisitableExt, TypeVisitor, UintTy, Upcast, VariantDef, VariantDiscr, }; use rustc_span::symbol::Ident; -use rustc_span::{sym, Span, Symbol, DUMMY_SP}; +use rustc_span::{DUMMY_SP, Span, Symbol, sym}; use rustc_target::abi::VariantIdx; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _; use rustc_trait_selection::traits::query::normalize::QueryNormalizeExt; diff --git a/clippy_utils/src/ty/type_certainty/mod.rs b/clippy_utils/src/ty/type_certainty/mod.rs index 875ddec259e..e612e9c6cb6 100644 --- a/clippy_utils/src/ty/type_certainty/mod.rs +++ b/clippy_utils/src/ty/type_certainty/mod.rs @@ -14,14 +14,14 @@ use crate::def_path_res; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; -use rustc_hir::intravisit::{walk_qpath, walk_ty, Visitor}; +use rustc_hir::intravisit::{Visitor, walk_qpath, walk_ty}; use rustc_hir::{self as hir, Expr, ExprKind, GenericArgs, HirId, Node, PathSegment, QPath, TyKind}; use rustc_lint::LateContext; use rustc_middle::ty::{self, AdtDef, GenericArgKind, Ty}; use rustc_span::{Span, Symbol}; mod certainty; -use certainty::{join, meet, Certainty, Meet}; +use certainty::{Certainty, Meet, join, meet}; pub fn expr_type_is_certain(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { expr_type_certainty(cx, expr).is_certain() diff --git a/clippy_utils/src/usage.rs b/clippy_utils/src/usage.rs index fbf3d95365a..1230b60c3a6 100644 --- a/clippy_utils/src/usage.rs +++ b/clippy_utils/src/usage.rs @@ -1,4 +1,4 @@ -use crate::visitors::{for_each_expr, for_each_expr_without_closures, Descend, Visitable}; +use crate::visitors::{Descend, Visitable, for_each_expr, for_each_expr_without_closures}; use crate::{self as utils, get_enclosing_loop_or_multi_call_closure}; use core::ops::ControlFlow; use hir::def::Res; diff --git a/clippy_utils/src/visitors.rs b/clippy_utils/src/visitors.rs index e5b6d3965e9..6d9a85a1181 100644 --- a/clippy_utils/src/visitors.rs +++ b/clippy_utils/src/visitors.rs @@ -1,10 +1,10 @@ use crate::ty::needs_ordered_drop; use crate::{get_enclosing_block, path_to_local_id}; use core::ops::ControlFlow; -use rustc_ast::visit::{try_visit, VisitorResult}; +use rustc_ast::visit::{VisitorResult, try_visit}; use rustc_hir as hir; use rustc_hir::def::{CtorKind, DefKind, Res}; -use rustc_hir::intravisit::{self, walk_block, walk_expr, Visitor}; +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, Safety, Stmt, UnOp, UnsafeSource, diff --git a/declare_clippy_lint/src/lib.rs b/declare_clippy_lint/src/lib.rs index 6aa24329b06..fefc1a0a6c4 100644 --- a/declare_clippy_lint/src/lib.rs +++ b/declare_clippy_lint/src/lib.rs @@ -5,7 +5,7 @@ use proc_macro::TokenStream; use quote::{format_ident, quote}; use syn::parse::{Parse, ParseStream}; -use syn::{parse_macro_input, Attribute, Error, Expr, ExprLit, Ident, Lit, LitStr, Meta, Result, Token}; +use syn::{Attribute, Error, Expr, ExprLit, Ident, Lit, LitStr, Meta, Result, Token, parse_macro_input}; fn parse_attr(path: [&'static str; LEN], attr: &Attribute) -> Option { if let Meta::NameValue(name_value) = &attr.meta { @@ -140,15 +140,12 @@ pub fn declare_clippy_lint(input: TokenStream) -> TokenStream { let mut category = category.to_string(); - let level = format_ident!( - "{}", - match category.as_str() { - "correctness" => "Deny", - "style" | "suspicious" | "complexity" | "perf" => "Warn", - "pedantic" | "restriction" | "cargo" | "nursery" | "internal" => "Allow", - _ => panic!("unknown category {category}"), - }, - ); + let level = format_ident!("{}", match category.as_str() { + "correctness" => "Deny", + "style" | "suspicious" | "complexity" | "perf" => "Warn", + "pedantic" | "restriction" | "cargo" | "nursery" | "internal" => "Allow", + _ => panic!("unknown category {category}"), + },); let info_name = format_ident!("{name}_INFO"); diff --git a/lintcheck/src/driver.rs b/lintcheck/src/driver.rs index 2fda2b00f87..87ab14ba0cf 100644 --- a/lintcheck/src/driver.rs +++ b/lintcheck/src/driver.rs @@ -1,4 +1,4 @@ -use crate::recursive::{deserialize_line, serialize_line, DriverInfo}; +use crate::recursive::{DriverInfo, deserialize_line, serialize_line}; use std::io::{self, BufReader, Write}; use std::net::TcpStream; diff --git a/lintcheck/src/recursive.rs b/lintcheck/src/recursive.rs index 6a662970ae8..57073f52364 100644 --- a/lintcheck/src/recursive.rs +++ b/lintcheck/src/recursive.rs @@ -3,8 +3,8 @@ //! [`LintcheckServer`] to ask if it should be skipped, and if not sends the stderr of running //! clippy on the crate to the server -use crate::input::RecursiveOptions; use crate::ClippyWarning; +use crate::input::RecursiveOptions; use std::collections::HashSet; use std::io::{BufRead, BufReader, Read, Write}; diff --git a/src/driver.rs b/src/driver.rs index 414957938a4..324f754e615 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -15,9 +15,9 @@ extern crate rustc_session; extern crate rustc_span; use rustc_interface::interface; +use rustc_session::EarlyDiagCtxt; use rustc_session::config::ErrorOutputType; use rustc_session::parse::ParseSess; -use rustc_session::EarlyDiagCtxt; use rustc_span::symbol::Symbol; use std::env; diff --git a/tests/compile-test.rs b/tests/compile-test.rs index c7243348ce4..af2aa519257 100644 --- a/tests/compile-test.rs +++ b/tests/compile-test.rs @@ -2,25 +2,25 @@ #![warn(rust_2018_idioms, unused_lifetimes)] #![allow(unused_extern_crates)] -use cargo_metadata::diagnostic::{Applicability, Diagnostic}; use cargo_metadata::Message; +use cargo_metadata::diagnostic::{Applicability, Diagnostic}; use clippy_config::ClippyConfiguration; +use clippy_lints::LintInfo; use clippy_lints::declared_lints::LINTS; use clippy_lints::deprecated_lints::{DEPRECATED, DEPRECATED_VERSION, RENAMED}; -use clippy_lints::LintInfo; use serde::{Deserialize, Serialize}; use test_utils::IS_RUSTC_TEST_SUITE; -use ui_test::custom_flags::rustfix::RustfixMode; use ui_test::custom_flags::Flag; +use ui_test::custom_flags::rustfix::RustfixMode; use ui_test::spanned::Spanned; -use ui_test::{status_emitter, Args, CommandBuilder, Config, Match, OutputConflictHandling}; +use ui_test::{Args, CommandBuilder, Config, Match, OutputConflictHandling, status_emitter}; use std::collections::{BTreeMap, HashMap}; use std::env::{self, set_var, var_os}; use std::ffi::{OsStr, OsString}; use std::fmt::Write; use std::path::{Path, PathBuf}; -use std::sync::mpsc::{channel, Sender}; +use std::sync::mpsc::{Sender, channel}; use std::{fs, iter, thread}; // Test dependencies may need an `extern crate` here to ensure that they show up diff --git a/tests/config-metadata.rs b/tests/config-metadata.rs index 3e3711873ba..628dfc8f758 100644 --- a/tests/config-metadata.rs +++ b/tests/config-metadata.rs @@ -1,6 +1,6 @@ #![feature(rustc_private)] -use clippy_config::{get_configuration_metadata, ClippyConfiguration}; +use clippy_config::{ClippyConfiguration, get_configuration_metadata}; use itertools::Itertools; use regex::Regex; use std::borrow::Cow; diff --git a/tests/ui-internal/unnecessary_def_path.fixed b/tests/ui-internal/unnecessary_def_path.fixed index 04d990896e5..0a994842834 100644 --- a/tests/ui-internal/unnecessary_def_path.fixed +++ b/tests/ui-internal/unnecessary_def_path.fixed @@ -22,8 +22,8 @@ use rustc_hir::LangItem; #[allow(unused)] use rustc_span::sym; -use rustc_hir::def_id::DefId; use rustc_hir::Expr; +use rustc_hir::def_id::DefId; use rustc_lint::LateContext; use rustc_middle::ty::Ty; diff --git a/tests/ui-internal/unnecessary_def_path.rs b/tests/ui-internal/unnecessary_def_path.rs index ade5e9280e3..ba68de6c6d0 100644 --- a/tests/ui-internal/unnecessary_def_path.rs +++ b/tests/ui-internal/unnecessary_def_path.rs @@ -22,8 +22,8 @@ use rustc_hir::LangItem; #[allow(unused)] use rustc_span::sym; -use rustc_hir::def_id::DefId; use rustc_hir::Expr; +use rustc_hir::def_id::DefId; use rustc_lint::LateContext; use rustc_middle::ty::Ty; diff --git a/tests/ui-toml/missing_enforced_import_rename/conf_missing_enforced_import_rename.fixed b/tests/ui-toml/missing_enforced_import_rename/conf_missing_enforced_import_rename.fixed index 5f4f007cf5c..a6072111dc0 100644 --- a/tests/ui-toml/missing_enforced_import_rename/conf_missing_enforced_import_rename.fixed +++ b/tests/ui-toml/missing_enforced_import_rename/conf_missing_enforced_import_rename.fixed @@ -2,7 +2,7 @@ use std::alloc as colla; use std::option::Option as Maybe; -use std::process::{exit as goodbye, Child as Kid}; +use std::process::{Child as Kid, exit as goodbye}; use std::thread::sleep as thread_sleep; #[rustfmt::skip] use std::{ diff --git a/tests/ui-toml/missing_enforced_import_rename/conf_missing_enforced_import_rename.rs b/tests/ui-toml/missing_enforced_import_rename/conf_missing_enforced_import_rename.rs index f60058c8628..c2b61aab5b3 100644 --- a/tests/ui-toml/missing_enforced_import_rename/conf_missing_enforced_import_rename.rs +++ b/tests/ui-toml/missing_enforced_import_rename/conf_missing_enforced_import_rename.rs @@ -2,7 +2,7 @@ use std::alloc as colla; use std::option::Option as Maybe; -use std::process::{exit as wrong_exit, Child as Kid}; +use std::process::{Child as Kid, exit as wrong_exit}; use std::thread::sleep; #[rustfmt::skip] use std::{ diff --git a/tests/ui-toml/missing_enforced_import_rename/conf_missing_enforced_import_rename.stderr b/tests/ui-toml/missing_enforced_import_rename/conf_missing_enforced_import_rename.stderr index f66938c83fb..d3bb07ec47f 100644 --- a/tests/ui-toml/missing_enforced_import_rename/conf_missing_enforced_import_rename.stderr +++ b/tests/ui-toml/missing_enforced_import_rename/conf_missing_enforced_import_rename.stderr @@ -1,8 +1,8 @@ error: this import should be renamed - --> tests/ui-toml/missing_enforced_import_rename/conf_missing_enforced_import_rename.rs:5:20 + --> tests/ui-toml/missing_enforced_import_rename/conf_missing_enforced_import_rename.rs:5:34 | -LL | use std::process::{exit as wrong_exit, Child as Kid}; - | ^^^^^^^^^^^^^^^^^^ help: try: `exit as goodbye` +LL | use std::process::{Child as Kid, exit as wrong_exit}; + | ^^^^^^^^^^^^^^^^^^ help: try: `exit as goodbye` | = note: `-D clippy::missing-enforced-import-renames` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::missing_enforced_import_renames)]` diff --git a/tests/ui/arithmetic_side_effects.rs b/tests/ui/arithmetic_side_effects.rs index 0838d064a5f..3f204073085 100644 --- a/tests/ui/arithmetic_side_effects.rs +++ b/tests/ui/arithmetic_side_effects.rs @@ -2,7 +2,6 @@ #![feature(f128)] #![feature(f16)] - #![allow( clippy::assign_op_pattern, clippy::erasing_op, diff --git a/tests/ui/arithmetic_side_effects.stderr b/tests/ui/arithmetic_side_effects.stderr index 78914667bf3..78b1aca4b8a 100644 --- a/tests/ui/arithmetic_side_effects.stderr +++ b/tests/ui/arithmetic_side_effects.stderr @@ -1,5 +1,5 @@ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:167:13 + --> tests/ui/arithmetic_side_effects.rs:166:13 | LL | let _ = 1f16 + 1f16; | ^^^^^^^^^^^ @@ -8,733 +8,733 @@ LL | let _ = 1f16 + 1f16; = help: to override `-D warnings` add `#[allow(clippy::arithmetic_side_effects)]` error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:170:13 + --> tests/ui/arithmetic_side_effects.rs:169:13 | LL | let _ = 1f128 + 1f128; | ^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:308:5 + --> tests/ui/arithmetic_side_effects.rs:307:5 | LL | _n += 1; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:309:5 + --> tests/ui/arithmetic_side_effects.rs:308:5 | LL | _n += &1; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:310:5 + --> tests/ui/arithmetic_side_effects.rs:309:5 | LL | _n -= 1; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:311:5 + --> tests/ui/arithmetic_side_effects.rs:310:5 | LL | _n -= &1; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:312:5 + --> tests/ui/arithmetic_side_effects.rs:311:5 | LL | _n /= 0; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:313:5 + --> tests/ui/arithmetic_side_effects.rs:312:5 | LL | _n /= &0; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:314:5 + --> tests/ui/arithmetic_side_effects.rs:313:5 | LL | _n %= 0; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:315:5 + --> tests/ui/arithmetic_side_effects.rs:314:5 | LL | _n %= &0; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:316:5 + --> tests/ui/arithmetic_side_effects.rs:315:5 | LL | _n *= 2; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:317:5 + --> tests/ui/arithmetic_side_effects.rs:316:5 | LL | _n *= &2; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:318:5 + --> tests/ui/arithmetic_side_effects.rs:317:5 | LL | _n += -1; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:319:5 + --> tests/ui/arithmetic_side_effects.rs:318:5 | LL | _n += &-1; | ^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:320:5 + --> tests/ui/arithmetic_side_effects.rs:319:5 | LL | _n -= -1; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:321:5 + --> tests/ui/arithmetic_side_effects.rs:320:5 | LL | _n -= &-1; | ^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:322:5 + --> tests/ui/arithmetic_side_effects.rs:321:5 | LL | _n /= -0; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:323:5 + --> tests/ui/arithmetic_side_effects.rs:322:5 | LL | _n /= &-0; | ^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:324:5 + --> tests/ui/arithmetic_side_effects.rs:323:5 | LL | _n %= -0; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:325:5 + --> tests/ui/arithmetic_side_effects.rs:324:5 | LL | _n %= &-0; | ^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:326:5 + --> tests/ui/arithmetic_side_effects.rs:325:5 | LL | _n *= -2; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:327:5 + --> tests/ui/arithmetic_side_effects.rs:326:5 | LL | _n *= &-2; | ^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:328:5 + --> tests/ui/arithmetic_side_effects.rs:327:5 | LL | _custom += Custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:329:5 + --> tests/ui/arithmetic_side_effects.rs:328:5 | LL | _custom += &Custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:330:5 + --> tests/ui/arithmetic_side_effects.rs:329:5 | LL | _custom -= Custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:331:5 + --> tests/ui/arithmetic_side_effects.rs:330:5 | LL | _custom -= &Custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:332:5 + --> tests/ui/arithmetic_side_effects.rs:331:5 | LL | _custom /= Custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:333:5 + --> tests/ui/arithmetic_side_effects.rs:332:5 | LL | _custom /= &Custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:334:5 + --> tests/ui/arithmetic_side_effects.rs:333:5 | LL | _custom %= Custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:335:5 + --> tests/ui/arithmetic_side_effects.rs:334:5 | LL | _custom %= &Custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:336:5 + --> tests/ui/arithmetic_side_effects.rs:335:5 | LL | _custom *= Custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:337:5 + --> tests/ui/arithmetic_side_effects.rs:336:5 | LL | _custom *= &Custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:338:5 + --> tests/ui/arithmetic_side_effects.rs:337:5 | LL | _custom >>= Custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:339:5 + --> tests/ui/arithmetic_side_effects.rs:338:5 | LL | _custom >>= &Custom; | ^^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:340:5 + --> tests/ui/arithmetic_side_effects.rs:339:5 | LL | _custom <<= Custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:341:5 + --> tests/ui/arithmetic_side_effects.rs:340:5 | LL | _custom <<= &Custom; | ^^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:342:5 + --> tests/ui/arithmetic_side_effects.rs:341:5 | LL | _custom += -Custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:343:5 + --> tests/ui/arithmetic_side_effects.rs:342:5 | LL | _custom += &-Custom; | ^^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:344:5 + --> tests/ui/arithmetic_side_effects.rs:343:5 | LL | _custom -= -Custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:345:5 + --> tests/ui/arithmetic_side_effects.rs:344:5 | LL | _custom -= &-Custom; | ^^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:346:5 + --> tests/ui/arithmetic_side_effects.rs:345:5 | LL | _custom /= -Custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:347:5 + --> tests/ui/arithmetic_side_effects.rs:346:5 | LL | _custom /= &-Custom; | ^^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:348:5 + --> tests/ui/arithmetic_side_effects.rs:347:5 | LL | _custom %= -Custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:349:5 + --> tests/ui/arithmetic_side_effects.rs:348:5 | LL | _custom %= &-Custom; | ^^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:350:5 + --> tests/ui/arithmetic_side_effects.rs:349:5 | LL | _custom *= -Custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:351:5 + --> tests/ui/arithmetic_side_effects.rs:350:5 | LL | _custom *= &-Custom; | ^^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:352:5 + --> tests/ui/arithmetic_side_effects.rs:351:5 | LL | _custom >>= -Custom; | ^^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:353:5 + --> tests/ui/arithmetic_side_effects.rs:352:5 | LL | _custom >>= &-Custom; | ^^^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:354:5 + --> tests/ui/arithmetic_side_effects.rs:353:5 | LL | _custom <<= -Custom; | ^^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:355:5 + --> tests/ui/arithmetic_side_effects.rs:354:5 | LL | _custom <<= &-Custom; | ^^^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:358:10 + --> tests/ui/arithmetic_side_effects.rs:357:10 | LL | _n = _n + 1; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:359:10 + --> tests/ui/arithmetic_side_effects.rs:358:10 | LL | _n = _n + &1; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:360:10 + --> tests/ui/arithmetic_side_effects.rs:359:10 | LL | _n = 1 + _n; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:361:10 + --> tests/ui/arithmetic_side_effects.rs:360:10 | LL | _n = &1 + _n; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:362:10 + --> tests/ui/arithmetic_side_effects.rs:361:10 | LL | _n = _n - 1; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:363:10 + --> tests/ui/arithmetic_side_effects.rs:362:10 | LL | _n = _n - &1; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:364:10 + --> tests/ui/arithmetic_side_effects.rs:363:10 | LL | _n = 1 - _n; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:365:10 + --> tests/ui/arithmetic_side_effects.rs:364:10 | LL | _n = &1 - _n; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:366:10 + --> tests/ui/arithmetic_side_effects.rs:365:10 | LL | _n = _n / 0; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:367:10 + --> tests/ui/arithmetic_side_effects.rs:366:10 | LL | _n = _n / &0; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:368:10 + --> tests/ui/arithmetic_side_effects.rs:367:10 | LL | _n = _n % 0; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:369:10 + --> tests/ui/arithmetic_side_effects.rs:368:10 | LL | _n = _n % &0; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:370:10 + --> tests/ui/arithmetic_side_effects.rs:369:10 | LL | _n = _n * 2; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:371:10 + --> tests/ui/arithmetic_side_effects.rs:370:10 | LL | _n = _n * &2; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:372:10 + --> tests/ui/arithmetic_side_effects.rs:371:10 | LL | _n = 2 * _n; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:373:10 + --> tests/ui/arithmetic_side_effects.rs:372:10 | LL | _n = &2 * _n; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:374:10 + --> tests/ui/arithmetic_side_effects.rs:373:10 | LL | _n = 23 + &85; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:375:10 + --> tests/ui/arithmetic_side_effects.rs:374:10 | LL | _n = &23 + 85; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:376:10 + --> tests/ui/arithmetic_side_effects.rs:375:10 | LL | _n = &23 + &85; | ^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:377:15 + --> tests/ui/arithmetic_side_effects.rs:376:15 | LL | _custom = _custom + _custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:378:15 + --> tests/ui/arithmetic_side_effects.rs:377:15 | LL | _custom = _custom + &_custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:379:15 + --> tests/ui/arithmetic_side_effects.rs:378:15 | LL | _custom = Custom + _custom; | ^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:380:15 + --> tests/ui/arithmetic_side_effects.rs:379:15 | LL | _custom = &Custom + _custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:381:15 + --> tests/ui/arithmetic_side_effects.rs:380:15 | LL | _custom = _custom - Custom; | ^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:382:15 + --> tests/ui/arithmetic_side_effects.rs:381:15 | LL | _custom = _custom - &Custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:383:15 + --> tests/ui/arithmetic_side_effects.rs:382:15 | LL | _custom = Custom - _custom; | ^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:384:15 + --> tests/ui/arithmetic_side_effects.rs:383:15 | LL | _custom = &Custom - _custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:385:15 + --> tests/ui/arithmetic_side_effects.rs:384:15 | LL | _custom = _custom / Custom; | ^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:386:15 + --> tests/ui/arithmetic_side_effects.rs:385:15 | LL | _custom = _custom / &Custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:387:15 + --> tests/ui/arithmetic_side_effects.rs:386:15 | LL | _custom = _custom % Custom; | ^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:388:15 + --> tests/ui/arithmetic_side_effects.rs:387:15 | LL | _custom = _custom % &Custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:389:15 + --> tests/ui/arithmetic_side_effects.rs:388:15 | LL | _custom = _custom * Custom; | ^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:390:15 + --> tests/ui/arithmetic_side_effects.rs:389:15 | LL | _custom = _custom * &Custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:391:15 + --> tests/ui/arithmetic_side_effects.rs:390:15 | LL | _custom = Custom * _custom; | ^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:392:15 + --> tests/ui/arithmetic_side_effects.rs:391:15 | LL | _custom = &Custom * _custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:393:15 + --> tests/ui/arithmetic_side_effects.rs:392:15 | LL | _custom = Custom + &Custom; | ^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:394:15 + --> tests/ui/arithmetic_side_effects.rs:393:15 | LL | _custom = &Custom + Custom; | ^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:395:15 + --> tests/ui/arithmetic_side_effects.rs:394:15 | LL | _custom = &Custom + &Custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:396:15 + --> tests/ui/arithmetic_side_effects.rs:395:15 | LL | _custom = _custom >> _custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:397:15 + --> tests/ui/arithmetic_side_effects.rs:396:15 | LL | _custom = _custom >> &_custom; | ^^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:398:15 + --> tests/ui/arithmetic_side_effects.rs:397:15 | LL | _custom = Custom << _custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:399:15 + --> tests/ui/arithmetic_side_effects.rs:398:15 | LL | _custom = &Custom << _custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:402:23 + --> tests/ui/arithmetic_side_effects.rs:401:23 | LL | _n.saturating_div(0); | ^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:403:21 + --> tests/ui/arithmetic_side_effects.rs:402:21 | LL | _n.wrapping_div(0); | ^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:404:21 + --> tests/ui/arithmetic_side_effects.rs:403:21 | LL | _n.wrapping_rem(0); | ^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:405:28 + --> tests/ui/arithmetic_side_effects.rs:404:28 | LL | _n.wrapping_rem_euclid(0); | ^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:407:23 + --> tests/ui/arithmetic_side_effects.rs:406:23 | LL | _n.saturating_div(_n); | ^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:408:21 + --> tests/ui/arithmetic_side_effects.rs:407:21 | LL | _n.wrapping_div(_n); | ^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:409:21 + --> tests/ui/arithmetic_side_effects.rs:408:21 | LL | _n.wrapping_rem(_n); | ^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:410:28 + --> tests/ui/arithmetic_side_effects.rs:409:28 | LL | _n.wrapping_rem_euclid(_n); | ^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:413:10 + --> tests/ui/arithmetic_side_effects.rs:412:10 | LL | _n = -_n; | ^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:414:10 + --> tests/ui/arithmetic_side_effects.rs:413:10 | LL | _n = -&_n; | ^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:415:15 + --> tests/ui/arithmetic_side_effects.rs:414:15 | LL | _custom = -_custom; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:416:15 + --> tests/ui/arithmetic_side_effects.rs:415:15 | LL | _custom = -&_custom; | ^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:425:5 + --> tests/ui/arithmetic_side_effects.rs:424:5 | LL | 1 + i; | ^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:426:5 + --> tests/ui/arithmetic_side_effects.rs:425:5 | LL | i * 2; | ^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:427:5 + --> tests/ui/arithmetic_side_effects.rs:426:5 | LL | 1 % i / 2; | ^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:428:5 + --> tests/ui/arithmetic_side_effects.rs:427:5 | LL | i - 2 + 2 - i; | ^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:429:5 + --> tests/ui/arithmetic_side_effects.rs:428:5 | LL | -i; | ^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:440:5 + --> tests/ui/arithmetic_side_effects.rs:439:5 | LL | i += 1; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:441:5 + --> tests/ui/arithmetic_side_effects.rs:440:5 | LL | i -= 1; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:442:5 + --> tests/ui/arithmetic_side_effects.rs:441:5 | LL | i *= 2; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:444:5 + --> tests/ui/arithmetic_side_effects.rs:443:5 | LL | i /= 0; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:446:5 + --> tests/ui/arithmetic_side_effects.rs:445:5 | LL | i /= var1; | ^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:447:5 + --> tests/ui/arithmetic_side_effects.rs:446:5 | LL | i /= var2; | ^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:449:5 + --> tests/ui/arithmetic_side_effects.rs:448:5 | LL | i %= 0; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:451:5 + --> tests/ui/arithmetic_side_effects.rs:450:5 | LL | i %= var1; | ^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:452:5 + --> tests/ui/arithmetic_side_effects.rs:451:5 | LL | i %= var2; | ^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:462:5 + --> tests/ui/arithmetic_side_effects.rs:461:5 | LL | 10 / a | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:516:9 + --> tests/ui/arithmetic_side_effects.rs:515:9 | LL | x / maybe_zero | ^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:520:9 + --> tests/ui/arithmetic_side_effects.rs:519:9 | LL | x % maybe_zero | ^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:531:5 + --> tests/ui/arithmetic_side_effects.rs:530:5 | LL | one.add_assign(1); | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:535:5 + --> tests/ui/arithmetic_side_effects.rs:534:5 | LL | one.sub_assign(1); | ^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/auxiliary/proc_macro_attr.rs b/tests/ui/auxiliary/proc_macro_attr.rs index f6fdebaf252..e72d6b6cead 100644 --- a/tests/ui/auxiliary/proc_macro_attr.rs +++ b/tests/ui/auxiliary/proc_macro_attr.rs @@ -11,8 +11,8 @@ use quote::{quote, quote_spanned}; use syn::spanned::Spanned; use syn::token::Star; use syn::{ - parse_macro_input, parse_quote, FnArg, ImplItem, ItemFn, ItemImpl, ItemStruct, ItemTrait, Lifetime, Pat, PatIdent, - PatType, Signature, TraitItem, Type, Visibility, + FnArg, ImplItem, ItemFn, ItemImpl, ItemStruct, ItemTrait, Lifetime, Pat, PatIdent, PatType, Signature, TraitItem, + Type, Visibility, parse_macro_input, parse_quote, }; #[proc_macro_attribute] diff --git a/tests/ui/auxiliary/proc_macro_derive.rs b/tests/ui/auxiliary/proc_macro_derive.rs index 4c3df472269..bd90042c1da 100644 --- a/tests/ui/auxiliary/proc_macro_derive.rs +++ b/tests/ui/auxiliary/proc_macro_derive.rs @@ -5,7 +5,7 @@ extern crate proc_macro; -use proc_macro::{quote, Delimiter, Group, Ident, Literal, Punct, Spacing, Span, TokenStream, TokenTree}; +use proc_macro::{Delimiter, Group, Ident, Literal, Punct, Spacing, Span, TokenStream, TokenTree, quote}; #[proc_macro_derive(DeriveSomething)] pub fn derive(_: TokenStream) -> TokenStream { diff --git a/tests/ui/auxiliary/proc_macro_suspicious_else_formatting.rs b/tests/ui/auxiliary/proc_macro_suspicious_else_formatting.rs index 79e8eff3aa1..3d6f164d358 100644 --- a/tests/ui/auxiliary/proc_macro_suspicious_else_formatting.rs +++ b/tests/ui/auxiliary/proc_macro_suspicious_else_formatting.rs @@ -1,5 +1,5 @@ extern crate proc_macro; -use proc_macro::{token_stream, Delimiter, Group, Ident, Span, TokenStream, TokenTree}; +use proc_macro::{Delimiter, Group, Ident, Span, TokenStream, TokenTree, token_stream}; fn read_ident(iter: &mut token_stream::IntoIter) -> Ident { match iter.next() { diff --git a/tests/ui/auxiliary/proc_macros.rs b/tests/ui/auxiliary/proc_macros.rs index ed7412f7c40..1a2a4ec2311 100644 --- a/tests/ui/auxiliary/proc_macros.rs +++ b/tests/ui/auxiliary/proc_macros.rs @@ -5,9 +5,9 @@ extern crate proc_macro; use core::mem; -use proc_macro::token_stream::IntoIter; use proc_macro::Delimiter::{self, Brace, Parenthesis}; use proc_macro::Spacing::{self, Alone, Joint}; +use proc_macro::token_stream::IntoIter; use proc_macro::{Group, Ident, Literal, Punct, Span, TokenStream, TokenTree as TT}; use syn::spanned::Spanned; diff --git a/tests/ui/borrow_interior_mutable_const/others.rs b/tests/ui/borrow_interior_mutable_const/others.rs index 452d1b19813..de220505c3e 100644 --- a/tests/ui/borrow_interior_mutable_const/others.rs +++ b/tests/ui/borrow_interior_mutable_const/others.rs @@ -5,8 +5,8 @@ use std::borrow::Cow; use std::cell::{Cell, UnsafeCell}; use std::fmt::Display; -use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::Once; +use std::sync::atomic::{AtomicUsize, Ordering}; const ATOMIC: AtomicUsize = AtomicUsize::new(5); const CELL: Cell = Cell::new(6); diff --git a/tests/ui/declare_interior_mutable_const/others.rs b/tests/ui/declare_interior_mutable_const/others.rs index 9dafad8b784..0dccf18c493 100644 --- a/tests/ui/declare_interior_mutable_const/others.rs +++ b/tests/ui/declare_interior_mutable_const/others.rs @@ -4,8 +4,8 @@ use std::borrow::Cow; use std::cell::Cell; use std::fmt::Display; use std::ptr; -use std::sync::atomic::AtomicUsize; use std::sync::Once; +use std::sync::atomic::AtomicUsize; const ATOMIC: AtomicUsize = AtomicUsize::new(5); //~ ERROR: interior mutable const CELL: Cell = Cell::new(6); //~ ERROR: interior mutable diff --git a/tests/ui/field_reassign_with_default.rs b/tests/ui/field_reassign_with_default.rs index 620cffb4f04..2a432751952 100644 --- a/tests/ui/field_reassign_with_default.rs +++ b/tests/ui/field_reassign_with_default.rs @@ -192,8 +192,8 @@ struct WrapperMulti { } mod issue6312 { - use std::sync::atomic::AtomicBool; use std::sync::Arc; + use std::sync::atomic::AtomicBool; // do not lint: type implements `Drop` but not all fields are `Copy` #[derive(Clone, Default)] diff --git a/tests/ui/format_args.fixed b/tests/ui/format_args.fixed index 4d812f6bf1d..20d1e3d9050 100644 --- a/tests/ui/format_args.fixed +++ b/tests/ui/format_args.fixed @@ -8,7 +8,7 @@ clippy::uninlined_format_args )] -use std::io::{stdout, Write}; +use std::io::{Write, stdout}; use std::ops::Deref; use std::panic::Location; diff --git a/tests/ui/format_args.rs b/tests/ui/format_args.rs index d242623feb6..18ab223db78 100644 --- a/tests/ui/format_args.rs +++ b/tests/ui/format_args.rs @@ -8,7 +8,7 @@ clippy::uninlined_format_args )] -use std::io::{stdout, Write}; +use std::io::{Write, stdout}; use std::ops::Deref; use std::panic::Location; diff --git a/tests/ui/format_args_unfixable.rs b/tests/ui/format_args_unfixable.rs index b7492e38b25..f04715f4f01 100644 --- a/tests/ui/format_args_unfixable.rs +++ b/tests/ui/format_args_unfixable.rs @@ -2,7 +2,7 @@ #![allow(unused)] #![allow(clippy::assertions_on_constants, clippy::eq_op, clippy::uninlined_format_args)] -use std::io::{stdout, Error, ErrorKind, Write}; +use std::io::{Error, ErrorKind, Write, stdout}; use std::ops::Deref; use std::panic::Location; diff --git a/tests/ui/ignored_unit_patterns.fixed b/tests/ui/ignored_unit_patterns.fixed index 118f0b48895..fde40437309 100644 --- a/tests/ui/ignored_unit_patterns.fixed +++ b/tests/ui/ignored_unit_patterns.fixed @@ -21,15 +21,12 @@ fn main() { let _ = foo().map_err(|()| todo!()); //~^ ERROR: matching over `()` is more explicit - println!( - "{:?}", - match foo() { - Ok(()) => {}, - //~^ ERROR: matching over `()` is more explicit - Err(()) => {}, - //~^ ERROR: matching over `()` is more explicit - } - ); + println!("{:?}", match foo() { + Ok(()) => {}, + //~^ ERROR: matching over `()` is more explicit + Err(()) => {}, + //~^ ERROR: matching over `()` is more explicit + }); } // ignored_unit_patterns in derive macro should be ok diff --git a/tests/ui/ignored_unit_patterns.rs b/tests/ui/ignored_unit_patterns.rs index 92feb9e6c28..528844d76e0 100644 --- a/tests/ui/ignored_unit_patterns.rs +++ b/tests/ui/ignored_unit_patterns.rs @@ -21,15 +21,12 @@ fn main() { let _ = foo().map_err(|_| todo!()); //~^ ERROR: matching over `()` is more explicit - println!( - "{:?}", - match foo() { - Ok(_) => {}, - //~^ ERROR: matching over `()` is more explicit - Err(_) => {}, - //~^ ERROR: matching over `()` is more explicit - } - ); + println!("{:?}", match foo() { + Ok(_) => {}, + //~^ ERROR: matching over `()` is more explicit + Err(_) => {}, + //~^ ERROR: matching over `()` is more explicit + }); } // ignored_unit_patterns in derive macro should be ok diff --git a/tests/ui/ignored_unit_patterns.stderr b/tests/ui/ignored_unit_patterns.stderr index 00a254e3919..54ff4454d6b 100644 --- a/tests/ui/ignored_unit_patterns.stderr +++ b/tests/ui/ignored_unit_patterns.stderr @@ -26,31 +26,31 @@ LL | let _ = foo().map_err(|_| todo!()); | ^ help: use `()` instead of `_`: `()` error: matching over `()` is more explicit - --> tests/ui/ignored_unit_patterns.rs:27:16 + --> tests/ui/ignored_unit_patterns.rs:25:12 | -LL | Ok(_) => {}, - | ^ help: use `()` instead of `_`: `()` +LL | Ok(_) => {}, + | ^ help: use `()` instead of `_`: `()` error: matching over `()` is more explicit - --> tests/ui/ignored_unit_patterns.rs:29:17 + --> tests/ui/ignored_unit_patterns.rs:27:13 | -LL | Err(_) => {}, - | ^ help: use `()` instead of `_`: `()` +LL | Err(_) => {}, + | ^ help: use `()` instead of `_`: `()` error: matching over `()` is more explicit - --> tests/ui/ignored_unit_patterns.rs:41:9 + --> tests/ui/ignored_unit_patterns.rs:38:9 | LL | let _ = foo().unwrap(); | ^ help: use `()` instead of `_`: `()` error: matching over `()` is more explicit - --> tests/ui/ignored_unit_patterns.rs:50:13 + --> tests/ui/ignored_unit_patterns.rs:47:13 | LL | (1, _) => unimplemented!(), | ^ help: use `()` instead of `_`: `()` error: matching over `()` is more explicit - --> tests/ui/ignored_unit_patterns.rs:57:13 + --> tests/ui/ignored_unit_patterns.rs:54:13 | LL | for (x, _) in v { | ^ help: use `()` instead of `_`: `()` diff --git a/tests/ui/incompatible_msrv.rs b/tests/ui/incompatible_msrv.rs index 8ef1f554bc3..c23df223d50 100644 --- a/tests/ui/incompatible_msrv.rs +++ b/tests/ui/incompatible_msrv.rs @@ -2,8 +2,8 @@ #![feature(custom_inner_attributes)] #![clippy::msrv = "1.3.0"] -use std::collections::hash_map::Entry; use std::collections::HashMap; +use std::collections::hash_map::Entry; use std::future::Future; use std::thread::sleep; use std::time::Duration; diff --git a/tests/ui/legacy_numeric_constants.fixed b/tests/ui/legacy_numeric_constants.fixed index a6ef8f8c119..3a2294ef4c5 100644 --- a/tests/ui/legacy_numeric_constants.fixed +++ b/tests/ui/legacy_numeric_constants.fixed @@ -22,8 +22,8 @@ macro_rules! b { }; } -use std::u32::MAX; use std::u8::MIN; +use std::u32::MAX; use std::{f64, u32}; #[warn(clippy::legacy_numeric_constants)] @@ -99,8 +99,8 @@ fn allow() { ::std::primitive::u8::MIN; ::std::u8::MIN; ::std::primitive::u8::min_value(); - use std::u64; use std::u8::MIN; + use std::u64; } #[warn(clippy::legacy_numeric_constants)] diff --git a/tests/ui/legacy_numeric_constants.rs b/tests/ui/legacy_numeric_constants.rs index cd633545372..6cb3e694ea1 100644 --- a/tests/ui/legacy_numeric_constants.rs +++ b/tests/ui/legacy_numeric_constants.rs @@ -22,8 +22,8 @@ macro_rules! b { }; } -use std::u32::MAX; use std::u8::MIN; +use std::u32::MAX; use std::{f64, u32}; #[warn(clippy::legacy_numeric_constants)] @@ -99,8 +99,8 @@ fn allow() { ::std::primitive::u8::MIN; ::std::u8::MIN; ::std::primitive::u8::min_value(); - use std::u64; use std::u8::MIN; + use std::u64; } #[warn(clippy::legacy_numeric_constants)] diff --git a/tests/ui/manual_saturating_arithmetic.fixed b/tests/ui/manual_saturating_arithmetic.fixed index 41a32df32ee..528a65790c4 100644 --- a/tests/ui/manual_saturating_arithmetic.fixed +++ b/tests/ui/manual_saturating_arithmetic.fixed @@ -1,6 +1,6 @@ #![allow(clippy::legacy_numeric_constants, unused_imports)] -use std::{i128, i32, u128, u32}; +use std::{i32, i128, u32, u128}; fn main() { let _ = 1u32.saturating_add(1); diff --git a/tests/ui/manual_saturating_arithmetic.rs b/tests/ui/manual_saturating_arithmetic.rs index 3a6b32d8069..55f3720dfcc 100644 --- a/tests/ui/manual_saturating_arithmetic.rs +++ b/tests/ui/manual_saturating_arithmetic.rs @@ -1,6 +1,6 @@ #![allow(clippy::legacy_numeric_constants, unused_imports)] -use std::{i128, i32, u128, u32}; +use std::{i32, i128, u32, u128}; fn main() { let _ = 1u32.checked_add(1).unwrap_or(u32::max_value()); diff --git a/tests/ui/must_use_candidates.fixed b/tests/ui/must_use_candidates.fixed index adb266ffbc8..2459af60688 100644 --- a/tests/ui/must_use_candidates.fixed +++ b/tests/ui/must_use_candidates.fixed @@ -7,8 +7,8 @@ )] #![warn(clippy::must_use_candidate)] use std::rc::Rc; -use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::Arc; +use std::sync::atomic::{AtomicBool, Ordering}; pub struct MyAtomic(AtomicBool); pub struct MyPure; diff --git a/tests/ui/must_use_candidates.rs b/tests/ui/must_use_candidates.rs index 49bb16af788..5f9b2449552 100644 --- a/tests/ui/must_use_candidates.rs +++ b/tests/ui/must_use_candidates.rs @@ -7,8 +7,8 @@ )] #![warn(clippy::must_use_candidate)] use std::rc::Rc; -use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::Arc; +use std::sync::atomic::{AtomicBool, Ordering}; pub struct MyAtomic(AtomicBool); pub struct MyPure; diff --git a/tests/ui/mut_key.rs b/tests/ui/mut_key.rs index 81d8732b3b2..43ff705c477 100644 --- a/tests/ui/mut_key.rs +++ b/tests/ui/mut_key.rs @@ -2,9 +2,9 @@ use std::cell::Cell; use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet}; use std::hash::{Hash, Hasher}; use std::rc::Rc; +use std::sync::Arc; use std::sync::atomic::AtomicUsize; use std::sync::atomic::Ordering::Relaxed; -use std::sync::Arc; struct Key(AtomicUsize); diff --git a/tests/ui/non_zero_suggestions.fixed b/tests/ui/non_zero_suggestions.fixed index 9851063782e..e67c992fdde 100644 --- a/tests/ui/non_zero_suggestions.fixed +++ b/tests/ui/non_zero_suggestions.fixed @@ -1,5 +1,5 @@ #![warn(clippy::non_zero_suggestions)] -use std::num::{NonZeroI16, NonZeroI8, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize}; +use std::num::{NonZeroI8, NonZeroI16, NonZeroU8, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroUsize}; fn main() { /// Positive test cases (lint should trigger) diff --git a/tests/ui/non_zero_suggestions.rs b/tests/ui/non_zero_suggestions.rs index 1605c459248..de82371a8f2 100644 --- a/tests/ui/non_zero_suggestions.rs +++ b/tests/ui/non_zero_suggestions.rs @@ -1,5 +1,5 @@ #![warn(clippy::non_zero_suggestions)] -use std::num::{NonZeroI16, NonZeroI8, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize}; +use std::num::{NonZeroI8, NonZeroI16, NonZeroU8, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroUsize}; fn main() { /// Positive test cases (lint should trigger) diff --git a/tests/ui/non_zero_suggestions_unfixable.rs b/tests/ui/non_zero_suggestions_unfixable.rs index 4eb22a8d4c7..193c710e589 100644 --- a/tests/ui/non_zero_suggestions_unfixable.rs +++ b/tests/ui/non_zero_suggestions_unfixable.rs @@ -1,6 +1,6 @@ #![warn(clippy::non_zero_suggestions)] //@no-rustfix -use std::num::{NonZeroI16, NonZeroI8, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize}; +use std::num::{NonZeroI8, NonZeroI16, NonZeroU8, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroUsize}; fn main() { let x: u64 = u64::from(NonZeroU32::new(5).unwrap().get()); diff --git a/tests/ui/single_match.fixed b/tests/ui/single_match.fixed index dcf5a1d33c2..4016b2699d6 100644 --- a/tests/ui/single_match.fixed +++ b/tests/ui/single_match.fixed @@ -39,8 +39,8 @@ enum Foo { Bar, Baz(u8), } -use std::borrow::Cow; use Foo::*; +use std::borrow::Cow; fn single_match_know_enum() { let x = Some(1u8); diff --git a/tests/ui/single_match.rs b/tests/ui/single_match.rs index 3ba5eebd01b..75edaa60605 100644 --- a/tests/ui/single_match.rs +++ b/tests/ui/single_match.rs @@ -51,8 +51,8 @@ enum Foo { Bar, Baz(u8), } -use std::borrow::Cow; use Foo::*; +use std::borrow::Cow; fn single_match_know_enum() { let x = Some(1u8); diff --git a/tests/ui/suspicious_to_owned.rs b/tests/ui/suspicious_to_owned.rs index f32b07d45f6..794c2e7174a 100644 --- a/tests/ui/suspicious_to_owned.rs +++ b/tests/ui/suspicious_to_owned.rs @@ -3,7 +3,7 @@ #![warn(clippy::implicit_clone)] #![allow(clippy::redundant_clone)] use std::borrow::Cow; -use std::ffi::{c_char, CStr}; +use std::ffi::{CStr, c_char}; fn main() { let moo = "Moooo"; diff --git a/tests/ui/transmute_collection.rs b/tests/ui/transmute_collection.rs index e30b34a5d7d..6748b66e0eb 100644 --- a/tests/ui/transmute_collection.rs +++ b/tests/ui/transmute_collection.rs @@ -2,7 +2,7 @@ #![allow(clippy::missing_transmute_annotations)] use std::collections::{BTreeMap, BTreeSet, BinaryHeap, HashMap, HashSet, VecDeque}; -use std::mem::{transmute, MaybeUninit}; +use std::mem::{MaybeUninit, transmute}; fn main() { unsafe { diff --git a/tests/ui/transmute_undefined_repr.rs b/tests/ui/transmute_undefined_repr.rs index dd4bac7f1ed..5b16d71f114 100644 --- a/tests/ui/transmute_undefined_repr.rs +++ b/tests/ui/transmute_undefined_repr.rs @@ -8,7 +8,7 @@ use core::any::TypeId; use core::ffi::c_void; -use core::mem::{size_of, transmute, MaybeUninit}; +use core::mem::{MaybeUninit, size_of, transmute}; use core::ptr::NonNull; fn value() -> T { From 009134d079a9b5c55de7877a070ee8de1d9843b5 Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Sun, 22 Sep 2024 20:52:58 +0200 Subject: [PATCH 181/683] Bump nightly version -> 2024-09-22 --- rust-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain b/rust-toolchain index 854fcda2dab..b431599c224 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,4 +1,4 @@ [toolchain] -channel = "nightly-2024-09-05" +channel = "nightly-2024-09-22" components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"] profile = "minimal" From cc2f447f073abdd103b749ce6725c9c6f60934f1 Mon Sep 17 00:00:00 2001 From: Samuel Tardieu Date: Thu, 12 Sep 2024 11:34:07 +0200 Subject: [PATCH 182/683] Check that #[deny(allow_attributes)] do not issue spurious messages --- tests/ui/allow_attributes.fixed | 7 +++++++ tests/ui/allow_attributes.rs | 7 +++++++ 2 files changed, 14 insertions(+) diff --git a/tests/ui/allow_attributes.fixed b/tests/ui/allow_attributes.fixed index 49ee3ee17c7..058dbb77a32 100644 --- a/tests/ui/allow_attributes.fixed +++ b/tests/ui/allow_attributes.fixed @@ -58,3 +58,10 @@ fn msrv_1_80() { #[allow(unused)] let x = 1; } + +#[deny(clippy::allow_attributes)] +fn deny_allow_attributes() -> Option { + let allow = None; + allow?; + Some(42) +} diff --git a/tests/ui/allow_attributes.rs b/tests/ui/allow_attributes.rs index 854acf8348d..6d94ce50e4c 100644 --- a/tests/ui/allow_attributes.rs +++ b/tests/ui/allow_attributes.rs @@ -58,3 +58,10 @@ fn msrv_1_80() { #[allow(unused)] let x = 1; } + +#[deny(clippy::allow_attributes)] +fn deny_allow_attributes() -> Option { + let allow = None; + allow?; + Some(42) +} From acff51187115444038662ff4e9e23403a96d085d Mon Sep 17 00:00:00 2001 From: Samuel Tardieu Date: Sat, 21 Sep 2024 19:13:37 +0200 Subject: [PATCH 183/683] Lint comparison to empty slice using `PartialEq` methods --- clippy_lints/src/len_zero.rs | 15 ++++++++++++++- tests/ui/comparison_to_empty.fixed | 8 ++++++++ tests/ui/comparison_to_empty.rs | 8 ++++++++ tests/ui/comparison_to_empty.stderr | 26 +++++++++++++++++++++++++- 4 files changed, 55 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/len_zero.rs b/clippy_lints/src/len_zero.rs index c1ba66de57e..3cd5f76e6b6 100644 --- a/clippy_lints/src/len_zero.rs +++ b/clippy_lints/src/len_zero.rs @@ -1,7 +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::{get_item_name, get_parent_as_impl, is_lint_allowed, peel_ref_operators}; +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; use rustc_hir::def::Res; @@ -185,6 +185,19 @@ impl<'tcx> LateLintPass<'tcx> for LenZero { ); } + if let ExprKind::MethodCall(method, lhs_expr, [rhs_expr], _) = expr.kind + && is_trait_method(cx, expr, sym::PartialEq) + && !expr.span.from_expansion() + { + check_empty_expr( + cx, + expr.span, + lhs_expr, + peel_ref_operators(cx, rhs_expr), + (method.ident.name == sym::ne).then_some("!").unwrap_or_default(), + ); + } + if let ExprKind::Binary(Spanned { node: cmp, .. }, left, right) = expr.kind && !expr.span.from_expansion() { diff --git a/tests/ui/comparison_to_empty.fixed b/tests/ui/comparison_to_empty.fixed index e102b13a761..a2a3dd9086d 100644 --- a/tests/ui/comparison_to_empty.fixed +++ b/tests/ui/comparison_to_empty.fixed @@ -33,4 +33,12 @@ fn main() { if let [0] = &*s && s == [0] {} + + // Also lint the `PartialEq` methods + let s = String::new(); + let _ = s.is_empty(); + let _ = !s.is_empty(); + let v = vec![0]; + let _ = v.is_empty(); + let _ = !v.is_empty(); } diff --git a/tests/ui/comparison_to_empty.rs b/tests/ui/comparison_to_empty.rs index 69a6c967d38..7c5689a4bbe 100644 --- a/tests/ui/comparison_to_empty.rs +++ b/tests/ui/comparison_to_empty.rs @@ -33,4 +33,12 @@ fn main() { if let [0] = &*s && s == [0] {} + + // Also lint the `PartialEq` methods + let s = String::new(); + let _ = s.eq(""); + let _ = s.ne(""); + let v = vec![0]; + let _ = v.eq(&[]); + let _ = v.ne(&[]); } diff --git a/tests/ui/comparison_to_empty.stderr b/tests/ui/comparison_to_empty.stderr index 6b027459ed3..2ee0efc7dbb 100644 --- a/tests/ui/comparison_to_empty.stderr +++ b/tests/ui/comparison_to_empty.stderr @@ -55,5 +55,29 @@ error: comparison to empty slice LL | && s == [] | ^^^^^^^ help: using `is_empty` is clearer and more explicit: `s.is_empty()` -error: aborting due to 9 previous errors +error: comparison to empty slice + --> tests/ui/comparison_to_empty.rs:39:13 + | +LL | let _ = s.eq(""); + | ^^^^^^^^ help: using `is_empty` is clearer and more explicit: `s.is_empty()` + +error: comparison to empty slice + --> tests/ui/comparison_to_empty.rs:40:13 + | +LL | let _ = s.ne(""); + | ^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!s.is_empty()` + +error: comparison to empty slice + --> tests/ui/comparison_to_empty.rs:42:13 + | +LL | let _ = v.eq(&[]); + | ^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `v.is_empty()` + +error: comparison to empty slice + --> tests/ui/comparison_to_empty.rs:43:13 + | +LL | let _ = v.ne(&[]); + | ^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!v.is_empty()` + +error: aborting due to 13 previous errors From e7e0dc70fa8c83fcfa5ec4009a8181bc597ae9d5 Mon Sep 17 00:00:00 2001 From: Kyle J Strand Date: Sun, 15 Sep 2024 16:26:46 -0600 Subject: [PATCH 184/683] reword edge-conditions documentation on all slice 'sort' functions; resolves #130122 --- library/alloc/src/slice.rs | 67 ++++++++++++++++++++++++++------------ 1 file changed, 47 insertions(+), 20 deletions(-) diff --git a/library/alloc/src/slice.rs b/library/alloc/src/slice.rs index 8cdba166c9d..4f39f731013 100644 --- a/library/alloc/src/slice.rs +++ b/library/alloc/src/slice.rs @@ -180,10 +180,9 @@ impl [T] { /// This sort is stable (i.e., does not reorder equal elements) and *O*(*n* \* log(*n*)) /// worst-case. /// - /// If the implementation of [`Ord`] for `T` does not implement a [total order] the resulting - /// order of elements in the slice is unspecified. All original elements will remain in the - /// slice and any possible modifications via interior mutability are observed in the input. Same - /// is true if the implementation of [`Ord`] for `T` panics. + /// If the implementation of [`Ord`] for `T` does not implement a [total order], the function + /// may panic; even if the function exits normally, the resulting order of elements in the slice + /// is unspecified. See also the note on panicking below. /// /// When applicable, unstable sorting is preferred because it is generally faster than stable /// sorting and it doesn't allocate auxiliary memory. See @@ -212,7 +211,15 @@ impl [T] { /// /// # Panics /// - /// May panic if the implementation of [`Ord`] for `T` does not implement a [total order]. + /// May panic if the implementation of [`Ord`] for `T` does not implement a [total order], or if + /// the [`Ord`] implementation itself panics. + /// + /// All safe functions on slices preserve the invariant that even if the function panics, all + /// original elements will remain in the slice and any possible modifications via interior + /// mutability are observed in the input. This ensures that recovery code (for instance inside + /// of a `Drop` or following a `catch_unwind`) will still have access to all the original + /// elements. For instance, if the slice belongs to a `Vec`, the `Vec::drop` method will be able + /// to dispose of all contained elements. /// /// # Examples /// @@ -241,10 +248,9 @@ impl [T] { /// This sort is stable (i.e., does not reorder equal elements) and *O*(*n* \* log(*n*)) /// worst-case. /// - /// If the comparison function `compare` does not implement a [total order] the resulting order - /// of elements in the slice is unspecified. All original elements will remain in the slice and - /// any possible modifications via interior mutability are observed in the input. Same is true - /// if `compare` panics. + /// If the comparison function `compare` does not implement a [total order], the function may + /// panic; even if the function exits normally, the resulting order of elements in the slice is + /// unspecified. See also the note on panicking below. /// /// For example `|a, b| (a - b).cmp(a)` is a comparison function that is neither transitive nor /// reflexive nor total, `a < b < c < a` with `a = 1, b = 2, c = 3`. For more information and @@ -263,7 +269,14 @@ impl [T] { /// /// # Panics /// - /// May panic if `compare` does not implement a [total order]. + /// May panic if `compare` does not implement a [total order], or if `compare` itself panics. + /// + /// All safe functions on slices preserve the invariant that even if the function panics, all + /// original elements will remain in the slice and any possible modifications via interior + /// mutability are observed in the input. This ensures that recovery code (for instance inside + /// of a `Drop` or following a `catch_unwind`) will still have access to all the original + /// elements. For instance, if the slice belongs to a `Vec`, the `Vec::drop` method will be able + /// to dispose of all contained elements. /// /// # Examples /// @@ -295,10 +308,9 @@ impl [T] { /// This sort is stable (i.e., does not reorder equal elements) and *O*(*m* \* *n* \* log(*n*)) /// worst-case, where the key function is *O*(*m*). /// - /// If the implementation of [`Ord`] for `K` does not implement a [total order] the resulting - /// order of elements in the slice is unspecified. All original elements will remain in the - /// slice and any possible modifications via interior mutability are observed in the input. Same - /// is true if the implementation of [`Ord`] for `K` panics. + /// If the implementation of [`Ord`] for `K` does not implement a [total order], the function + /// may panic; even if the function exits normally, the resulting order of elements in the slice + /// is unspecified. See also the note on panicking below. /// /// # Current implementation /// @@ -313,7 +325,15 @@ impl [T] { /// /// # Panics /// - /// May panic if the implementation of [`Ord`] for `K` does not implement a [total order]. + /// May panic if the implementation of [`Ord`] for `K` does not implement a [total order], or if + /// the [`Ord`] implementation or the key-function `f` panics. + /// + /// All safe functions on slices preserve the invariant that even if the function panics, all + /// original elements will remain in the slice and any possible modifications via interior + /// mutability are observed in the input. This ensures that recovery code (for instance inside + /// of a `Drop` or following a `catch_unwind`) will still have access to all the original + /// elements. For instance, if the slice belongs to a `Vec`, the `Vec::drop` method will be able + /// to dispose of all contained elements. /// /// # Examples /// @@ -347,10 +367,9 @@ impl [T] { /// storage to remember the results of key evaluation. The order of calls to the key function is /// unspecified and may change in future versions of the standard library. /// - /// If the implementation of [`Ord`] for `K` does not implement a [total order] the resulting - /// order of elements in the slice is unspecified. All original elements will remain in the - /// slice and any possible modifications via interior mutability are observed in the input. Same - /// is true if the implementation of [`Ord`] for `K` panics. + /// If the implementation of [`Ord`] for `K` does not implement a [total order], the function + /// may panic; even if the function exits normally, the resulting order of elements in the slice + /// is unspecified. See also the note on panicking below. /// /// For simple key functions (e.g., functions that are property accesses or basic operations), /// [`sort_by_key`](slice::sort_by_key) is likely to be faster. @@ -369,7 +388,15 @@ impl [T] { /// /// # Panics /// - /// May panic if the implementation of [`Ord`] for `K` does not implement a [total order]. + /// May panic if the implementation of [`Ord`] for `K` does not implement a [total order], or if + /// the [`Ord`] implementation panics. + /// + /// All safe functions on slices preserve the invariant that even if the function panics, all + /// original elements will remain in the slice and any possible modifications via interior + /// mutability are observed in the input. This ensures that recovery code (for instance inside + /// of a `Drop` or following a `catch_unwind`) will still have access to all the original + /// elements. For instance, if the slice belongs to a `Vec`, the `Vec::drop` method will be able + /// to dispose of all contained elements. /// /// # Examples /// From 9cd668beed38a8e98933733854a224c70998bf16 Mon Sep 17 00:00:00 2001 From: Pavel Grigorenko Date: Mon, 23 Sep 2024 02:12:53 +0300 Subject: [PATCH 185/683] Parser: better error messages for `@` in struct patterns --- compiler/rustc_parse/messages.ftl | 7 ++ compiler/rustc_parse/src/errors.rs | 19 +++++ compiler/rustc_parse/src/parser/pat.rs | 54 +++++++++++---- tests/ui/pattern/at-in-struct-patterns.rs | 14 ++++ tests/ui/pattern/at-in-struct-patterns.stderr | 69 +++++++++++++++++++ 5 files changed, 150 insertions(+), 13 deletions(-) create mode 100644 tests/ui/pattern/at-in-struct-patterns.rs create mode 100644 tests/ui/pattern/at-in-struct-patterns.stderr diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index 6cb851eb8df..5d1c300b453 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -26,6 +26,13 @@ parse_async_move_block_in_2015 = `async move` blocks are only allowed in Rust 20 parse_async_move_order_incorrect = the order of `move` and `async` is incorrect .suggestion = try switching the order +parse_at_dot_dot_in_struct_pattern = `@ ..` is not supported in struct patterns + .suggestion = bind to each field separately or, if you don't need them, just remove `{$ident} @` + +parse_at_in_struct_pattern = Unexpected `@` in struct pattern + .note = struct patterns use `field: pattern` syntax to bind to fields + .help = consider replacing `new_name @ field_name` with `field_name: new_name` if that is what you intended + parse_attr_after_generic = trailing attribute after generic parameter .label = attributes must go before parameters diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index e9fe2e6c1dd..e16ab5b4b06 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -2583,6 +2583,25 @@ pub(crate) struct EnumPatternInsteadOfIdentifier { pub span: Span, } +#[derive(Diagnostic)] +#[diag(parse_at_dot_dot_in_struct_pattern)] +pub(crate) struct AtDotDotInStructPattern { + #[primary_span] + pub span: Span, + #[suggestion(code = "", style = "verbose", applicability = "machine-applicable")] + pub remove: Span, + pub ident: Ident, +} + +#[derive(Diagnostic)] +#[diag(parse_at_in_struct_pattern)] +#[note] +#[help] +pub(crate) struct AtInStructPattern { + #[primary_span] + pub span: Span, +} + #[derive(Diagnostic)] #[diag(parse_dot_dot_dot_for_remaining_fields)] pub(crate) struct DotDotDotForRemainingFields { diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index 647df25c82e..b4cbe1accf4 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -17,15 +17,16 @@ use thin_vec::{thin_vec, ThinVec}; use super::{ForceCollect, Parser, PathStyle, Restrictions, Trailing, UsePreAttrPos}; use crate::errors::{ - self, AmbiguousRangePattern, DotDotDotForRemainingFields, DotDotDotRangeToPatternNotAllowed, - DotDotDotRestPattern, EnumPatternInsteadOfIdentifier, ExpectedBindingLeftOfAt, - ExpectedCommaAfterPatternField, GenericArgsInPatRequireTurbofishSyntax, - InclusiveRangeExtraEquals, InclusiveRangeMatchArrow, InclusiveRangeNoEnd, InvalidMutInPattern, - ParenRangeSuggestion, PatternOnWrongSideOfAt, RemoveLet, RepeatedMutInPattern, - SwitchRefBoxOrder, TopLevelOrPatternNotAllowed, TopLevelOrPatternNotAllowedSugg, - TrailingVertNotAllowed, UnexpectedExpressionInPattern, UnexpectedExpressionInPatternSugg, - UnexpectedLifetimeInPattern, UnexpectedParenInRangePat, UnexpectedParenInRangePatSugg, - UnexpectedVertVertBeforeFunctionParam, UnexpectedVertVertInPattern, WrapInParens, + self, AmbiguousRangePattern, AtDotDotInStructPattern, AtInStructPattern, + DotDotDotForRemainingFields, DotDotDotRangeToPatternNotAllowed, DotDotDotRestPattern, + EnumPatternInsteadOfIdentifier, ExpectedBindingLeftOfAt, ExpectedCommaAfterPatternField, + GenericArgsInPatRequireTurbofishSyntax, InclusiveRangeExtraEquals, InclusiveRangeMatchArrow, + InclusiveRangeNoEnd, InvalidMutInPattern, ParenRangeSuggestion, PatternOnWrongSideOfAt, + RemoveLet, RepeatedMutInPattern, SwitchRefBoxOrder, TopLevelOrPatternNotAllowed, + TopLevelOrPatternNotAllowedSugg, TrailingVertNotAllowed, UnexpectedExpressionInPattern, + UnexpectedExpressionInPatternSugg, UnexpectedLifetimeInPattern, UnexpectedParenInRangePat, + UnexpectedParenInRangePatSugg, UnexpectedVertVertBeforeFunctionParam, + UnexpectedVertVertInPattern, WrapInParens, }; use crate::parser::expr::{could_be_unclosed_char_literal, DestructuredFloat}; use crate::{maybe_recover_from_interpolated_ty_qpath, maybe_whole}; @@ -1433,7 +1434,7 @@ impl<'a> Parser<'a> { /// Parses the fields of a struct-like pattern. fn parse_pat_fields(&mut self) -> PResult<'a, (ThinVec, PatFieldsRest)> { - let mut fields = ThinVec::new(); + let mut fields: ThinVec = ThinVec::new(); let mut etc = PatFieldsRest::None; let mut ate_comma = true; let mut delayed_err: Option> = None; @@ -1454,12 +1455,22 @@ impl<'a> Parser<'a> { // check that a comma comes after every field if !ate_comma { - let mut err = - self.dcx().create_err(ExpectedCommaAfterPatternField { span: self.token.span }); + let err = if self.token == token::At { + let prev_field = fields + .last() + .expect("Unreachable on first iteration, not empty otherwise") + .ident; + self.report_misplaced_at_in_struct_pat(prev_field) + } else { + let mut err = self + .dcx() + .create_err(ExpectedCommaAfterPatternField { span: self.token.span }); + self.recover_misplaced_pattern_modifiers(&fields, &mut err); + err + }; if let Some(delayed) = delayed_err { delayed.emit(); } - self.recover_misplaced_pattern_modifiers(&fields, &mut err); return Err(err); } ate_comma = false; @@ -1594,6 +1605,23 @@ impl<'a> Parser<'a> { Ok((fields, etc)) } + #[deny(rustc::untranslatable_diagnostic)] + fn report_misplaced_at_in_struct_pat(&self, prev_field: Ident) -> Diag<'a> { + debug_assert_eq!(self.token, token::At); + let span = prev_field.span.to(self.token.span); + if let Some(dot_dot_span) = + self.look_ahead(1, |t| if t == &token::DotDot { Some(t.span) } else { None }) + { + self.dcx().create_err(AtDotDotInStructPattern { + span: span.to(dot_dot_span), + remove: span.until(dot_dot_span), + ident: prev_field, + }) + } else { + self.dcx().create_err(AtInStructPattern { span: span }) + } + } + /// If the user writes `S { ref field: name }` instead of `S { field: ref name }`, we suggest /// the correct code. fn recover_misplaced_pattern_modifiers(&self, fields: &ThinVec, err: &mut Diag<'a>) { diff --git a/tests/ui/pattern/at-in-struct-patterns.rs b/tests/ui/pattern/at-in-struct-patterns.rs new file mode 100644 index 00000000000..e8fad61f317 --- /dev/null +++ b/tests/ui/pattern/at-in-struct-patterns.rs @@ -0,0 +1,14 @@ +struct Foo { + field1: u8, + field2: u8, +} + +fn main() { + let foo = Foo { field1: 1, field2: 2 }; + let Foo { var @ field1, .. } = foo; //~ ERROR Unexpected `@` in struct pattern + dbg!(var); //~ ERROR cannot find value `var` in this scope + let Foo { field1: _, bar @ .. } = foo; //~ ERROR `@ ..` is not supported in struct patterns + let Foo { bar @ .. } = foo; //~ ERROR `@ ..` is not supported in struct patterns + let Foo { @ } = foo; //~ ERROR expected identifier, found `@` + let Foo { @ .. } = foo; //~ ERROR expected identifier, found `@` +} diff --git a/tests/ui/pattern/at-in-struct-patterns.stderr b/tests/ui/pattern/at-in-struct-patterns.stderr new file mode 100644 index 00000000000..ff75edfe681 --- /dev/null +++ b/tests/ui/pattern/at-in-struct-patterns.stderr @@ -0,0 +1,69 @@ +error: Unexpected `@` in struct pattern + --> $DIR/at-in-struct-patterns.rs:8:15 + | +LL | let Foo { var @ field1, .. } = foo; + | --- ^^^^^ + | | + | while parsing the fields for this pattern + | + = note: struct patterns use `field: pattern` syntax to bind to fields + = help: consider replacing `new_name @ field_name` with `field_name: new_name` if that is what you intended + +error: `@ ..` is not supported in struct patterns + --> $DIR/at-in-struct-patterns.rs:10:26 + | +LL | let Foo { field1: _, bar @ .. } = foo; + | --- ^^^^^^^^ + | | + | while parsing the fields for this pattern + | +help: bind to each field separately or, if you don't need them, just remove `bar @` + | +LL - let Foo { field1: _, bar @ .. } = foo; +LL + let Foo { field1: _, .. } = foo; + | + +error: `@ ..` is not supported in struct patterns + --> $DIR/at-in-struct-patterns.rs:11:15 + | +LL | let Foo { bar @ .. } = foo; + | --- ^^^^^^^^ + | | + | while parsing the fields for this pattern + | +help: bind to each field separately or, if you don't need them, just remove `bar @` + | +LL - let Foo { bar @ .. } = foo; +LL + let Foo { .. } = foo; + | + +error: expected identifier, found `@` + --> $DIR/at-in-struct-patterns.rs:12:15 + | +LL | let Foo { @ } = foo; + | --- ^ expected identifier + | | + | while parsing the fields for this pattern + +error: expected identifier, found `@` + --> $DIR/at-in-struct-patterns.rs:13:15 + | +LL | let Foo { @ .. } = foo; + | --- ^ expected identifier + | | + | while parsing the fields for this pattern + +error[E0425]: cannot find value `var` in this scope + --> $DIR/at-in-struct-patterns.rs:9:10 + | +LL | dbg!(var); + | ^^^ not found in this scope + | +help: consider importing this function + | +LL + use std::env::var; + | + +error: aborting due to 6 previous errors + +For more information about this error, try `rustc --explain E0425`. From 6658c8e2449fb6a674ac606823e43c44f3caf275 Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Sun, 15 Sep 2024 07:43:16 +0300 Subject: [PATCH 186/683] check if the LLVM submodule is fetched in `is_ci_llvm_modified` Signed-off-by: onur-ozkan --- src/bootstrap/src/core/build_steps/llvm.rs | 12 +++++++++++- src/bootstrap/src/lib.rs | 2 -- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs index 08e24ecc340..81a48000cf1 100644 --- a/src/bootstrap/src/core/build_steps/llvm.rs +++ b/src/bootstrap/src/core/build_steps/llvm.rs @@ -241,7 +241,17 @@ pub(crate) fn is_ci_llvm_available(config: &Config, asserts: bool) -> bool { /// Returns true if we're running in CI with modified LLVM (and thus can't download it) pub(crate) fn is_ci_llvm_modified(config: &Config) -> bool { - CiEnv::is_ci() && config.rust_info.is_managed_git_subrepository() && { + // If the LLVM submodule is unavailable (which is the case when `llvm.download-ci-llvm` is set to true), + // LLVM cannot be modified which means it is unnecessary to run the git logic below. + // + // This is very unlikely to happen on our (rust-lang/rust) CI runners, as we intentionally fetch all + // submodules in CI and most of the time (probably always) prefer `llvm.download-ci-llvm` to be set + // to "if-unchanged" or true. + if config.in_tree_llvm_info.is_managed_git_subrepository() { + return false; + } + + CiEnv::is_ci() && { // We assume we have access to git, so it's okay to unconditionally pass // `true` here. let llvm_sha = detect_llvm_sha(config, true); diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs index 6467f4e3591..9a48b7d36d9 100644 --- a/src/bootstrap/src/lib.rs +++ b/src/bootstrap/src/lib.rs @@ -312,8 +312,6 @@ impl Build { let miri_info = config.miri_info.clone(); let rustfmt_info = config.rustfmt_info.clone(); let enzyme_info = config.enzyme_info.clone(); - - // we always try to use git for LLVM builds let in_tree_llvm_info = config.in_tree_llvm_info.clone(); let in_tree_gcc_info = config.in_tree_gcc_info.clone(); From 16093faea8a004832053146f2299b4aed6990fa0 Mon Sep 17 00:00:00 2001 From: Luv-Ray Date: Mon, 23 Sep 2024 15:25:52 +0800 Subject: [PATCH 187/683] fix ices on vfe about principal trait --- compiler/rustc_codegen_ssa/src/base.rs | 9 +-- compiler/rustc_codegen_ssa/src/meth.rs | 67 +++++++++++-------- .../rustc_codegen_ssa/src/mir/intrinsic.rs | 2 +- compiler/rustc_codegen_ssa/src/size_of_val.rs | 4 +- tests/crashes/123955.rs | 6 -- tests/crashes/124092.rs | 7 -- .../codegen/virtual-function-elimination.rs | 17 +++++ 7 files changed, 61 insertions(+), 51 deletions(-) delete mode 100644 tests/crashes/123955.rs delete mode 100644 tests/crashes/124092.rs create mode 100644 tests/ui/codegen/virtual-function-elimination.rs diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index f6b45eb4466..b9a2230c8bc 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -37,6 +37,7 @@ use crate::back::write::{ submit_post_lto_module_to_llvm, submit_pre_lto_module_to_llvm, ComputedLtoType, OngoingCodegen, }; use crate::common::{self, IntPredicate, RealPredicate, TypeKind}; +use crate::meth::load_vtable; use crate::mir::operand::OperandValue; use crate::mir::place::PlaceRef; use crate::traits::*; @@ -135,14 +136,8 @@ fn unsized_info<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( if let Some(entry_idx) = vptr_entry_idx { let ptr_size = bx.data_layout().pointer_size; - let ptr_align = bx.data_layout().pointer_align.abi; let vtable_byte_offset = u64::try_from(entry_idx).unwrap() * ptr_size.bytes(); - let gep = bx.inbounds_ptradd(old_info, bx.const_usize(vtable_byte_offset)); - let new_vptr = bx.load(bx.type_ptr(), gep, ptr_align); - bx.nonnull_metadata(new_vptr); - // VTable loads are invariant. - bx.set_invariant_load(new_vptr); - new_vptr + load_vtable(bx, old_info, bx.type_ptr(), vtable_byte_offset, source, true) } else { old_info } diff --git a/compiler/rustc_codegen_ssa/src/meth.rs b/compiler/rustc_codegen_ssa/src/meth.rs index ecc3b2b24f1..7eb0ecd12ff 100644 --- a/compiler/rustc_codegen_ssa/src/meth.rs +++ b/compiler/rustc_codegen_ssa/src/meth.rs @@ -28,27 +28,9 @@ impl<'a, 'tcx> VirtualIndex { let llty = bx.fn_ptr_backend_type(fn_abi); let ptr_size = bx.data_layout().pointer_size; - let ptr_align = bx.data_layout().pointer_align.abi; let vtable_byte_offset = self.0 * ptr_size.bytes(); - if bx.cx().sess().opts.unstable_opts.virtual_function_elimination - && bx.cx().sess().lto() == Lto::Fat - { - let typeid = bx - .typeid_metadata(typeid_for_trait_ref(bx.tcx(), expect_dyn_trait_in_self(ty))) - .unwrap(); - let func = bx.type_checked_load(llvtable, vtable_byte_offset, typeid); - func - } else { - let gep = bx.inbounds_ptradd(llvtable, bx.const_usize(vtable_byte_offset)); - let ptr = bx.load(llty, gep, ptr_align); - // VTable loads are invariant. - bx.set_invariant_load(ptr); - if nonnull { - bx.nonnull_metadata(ptr); - } - ptr - } + load_vtable(bx, llvtable, llty, vtable_byte_offset, ty, nonnull) } pub(crate) fn get_optional_fn>( @@ -75,31 +57,27 @@ impl<'a, 'tcx> VirtualIndex { self, bx: &mut Bx, llvtable: Bx::Value, + ty: Ty<'tcx>, ) -> Bx::Value { // Load the data pointer from the object. debug!("get_int({:?}, {:?})", llvtable, self); let llty = bx.type_isize(); let ptr_size = bx.data_layout().pointer_size; - let ptr_align = bx.data_layout().pointer_align.abi; let vtable_byte_offset = self.0 * ptr_size.bytes(); - let gep = bx.inbounds_ptradd(llvtable, bx.const_usize(vtable_byte_offset)); - let ptr = bx.load(llty, gep, ptr_align); - // VTable loads are invariant. - bx.set_invariant_load(ptr); - ptr + load_vtable(bx, llvtable, llty, vtable_byte_offset, ty, false) } } /// This takes a valid `self` receiver type and extracts the principal trait -/// ref of the type. -fn expect_dyn_trait_in_self(ty: Ty<'_>) -> ty::PolyExistentialTraitRef<'_> { +/// ref of the type. Return `None` if there is no principal trait. +fn dyn_trait_in_self(ty: Ty<'_>) -> Option> { for arg in ty.peel_refs().walk() { if let GenericArgKind::Type(ty) = arg.unpack() && let ty::Dynamic(data, _, _) = ty.kind() { - return data.principal().expect("expected principal trait object"); + return data.principal(); } } @@ -138,3 +116,36 @@ pub(crate) fn get_vtable<'tcx, Cx: CodegenMethods<'tcx>>( cx.vtables().borrow_mut().insert((ty, trait_ref), vtable); vtable } + +/// Call this function whenever you need to load a vtable. +pub(crate) fn load_vtable<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( + bx: &mut Bx, + llvtable: Bx::Value, + llty: Bx::Type, + vtable_byte_offset: u64, + ty: Ty<'tcx>, + nonnull: bool, +) -> Bx::Value { + let ptr_align = bx.data_layout().pointer_align.abi; + + if bx.cx().sess().opts.unstable_opts.virtual_function_elimination + && bx.cx().sess().lto() == Lto::Fat + { + if let Some(trait_ref) = dyn_trait_in_self(ty) { + let typeid = bx.typeid_metadata(typeid_for_trait_ref(bx.tcx(), trait_ref)).unwrap(); + let func = bx.type_checked_load(llvtable, vtable_byte_offset, typeid); + return func; + } else if nonnull { + bug!("load nonnull value from a vtable without a principal trait") + } + } + + let gep = bx.inbounds_ptradd(llvtable, bx.const_usize(vtable_byte_offset)); + let ptr = bx.load(llty, gep, ptr_align); + // VTable loads are invariant. + bx.set_invariant_load(ptr); + if nonnull { + bx.nonnull_metadata(ptr); + } + ptr +} diff --git a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs index 4acbc04c505..c7af81b77bd 100644 --- a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs +++ b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs @@ -126,7 +126,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { sym::vtable_align => ty::COMMON_VTABLE_ENTRIES_ALIGN, _ => bug!(), }; - let value = meth::VirtualIndex::from_index(idx).get_usize(bx, vtable); + let value = meth::VirtualIndex::from_index(idx).get_usize(bx, vtable, callee_ty); match name { // Size is always <= isize::MAX. sym::vtable_size => { diff --git a/compiler/rustc_codegen_ssa/src/size_of_val.rs b/compiler/rustc_codegen_ssa/src/size_of_val.rs index 3f3ae21035d..827b939217e 100644 --- a/compiler/rustc_codegen_ssa/src/size_of_val.rs +++ b/compiler/rustc_codegen_ssa/src/size_of_val.rs @@ -28,9 +28,9 @@ pub fn size_and_align_of_dst<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( // Load size/align from vtable. let vtable = info.unwrap(); let size = meth::VirtualIndex::from_index(ty::COMMON_VTABLE_ENTRIES_SIZE) - .get_usize(bx, vtable); + .get_usize(bx, vtable, t); let align = meth::VirtualIndex::from_index(ty::COMMON_VTABLE_ENTRIES_ALIGN) - .get_usize(bx, vtable); + .get_usize(bx, vtable, t); // Size is always <= isize::MAX. let size_bound = bx.data_layout().ptr_sized_integer().signed_max() as u128; diff --git a/tests/crashes/123955.rs b/tests/crashes/123955.rs deleted file mode 100644 index fdd58c84794..00000000000 --- a/tests/crashes/123955.rs +++ /dev/null @@ -1,6 +0,0 @@ -//@ known-bug: #123955 -//@ compile-flags: -Clto -Zvirtual-function-elimination -//@ only-x86_64 -pub fn main() { - _ = Box::new(()) as Box; -} diff --git a/tests/crashes/124092.rs b/tests/crashes/124092.rs deleted file mode 100644 index c03db384e76..00000000000 --- a/tests/crashes/124092.rs +++ /dev/null @@ -1,7 +0,0 @@ -//@ known-bug: #124092 -//@ compile-flags: -Zvirtual-function-elimination=true -Clto=true -//@ only-x86_64 -const X: for<'b> fn(&'b ()) = |&()| (); -fn main() { - let dyn_debug = Box::new(X) as Box as Box; -} diff --git a/tests/ui/codegen/virtual-function-elimination.rs b/tests/ui/codegen/virtual-function-elimination.rs new file mode 100644 index 00000000000..3cbeb1293e5 --- /dev/null +++ b/tests/ui/codegen/virtual-function-elimination.rs @@ -0,0 +1,17 @@ +//@ build-pass +//@ compile-flags: -Zvirtual-function-elimination=true -Clto=true +//@ only-x86_64 +//@ no-prefer-dynamic + +// issue #123955 +pub fn test0() { + _ = Box::new(()) as Box; +} + +// issue #124092 +const X: for<'b> fn(&'b ()) = |&()| (); +pub fn test1() { + let _dyn_debug = Box::new(X) as Box as Box; +} + +fn main() {} From d099ceddadde4197b08c2de404100a627d3ba605 Mon Sep 17 00:00:00 2001 From: GnomedDev Date: Sat, 21 Sep 2024 16:11:15 +0100 Subject: [PATCH 188/683] Split def_path_res into two parts --- clippy_utils/src/lib.rs | 40 +++++++++++++++++++++++++--------------- 1 file changed, 25 insertions(+), 15 deletions(-) diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index a925549b0bf..2fee6473910 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -671,6 +671,17 @@ fn item_children_by_name(tcx: TyCtxt<'_>, def_id: DefId, name: Symbol) -> Vec, name: Symbol) -> Vec { + tcx.crates(()) + .iter() + .copied() + .filter(move |&num| tcx.crate_name(num) == name) + .map(CrateNum::as_def_id) + .map(|id| Res::Def(tcx.def_kind(id), id)) + .collect() +} + /// Resolves a def path like `std::vec::Vec`. /// /// Can return multiple resolutions when there are multiple versions of the same crate, e.g. @@ -681,15 +692,7 @@ fn item_children_by_name(tcx: TyCtxt<'_>, def_id: DefId, name: Symbol) -> Vec, path: &[&str]) -> Vec { - fn find_crates(tcx: TyCtxt<'_>, name: Symbol) -> impl Iterator + '_ { - tcx.crates(()) - .iter() - .copied() - .filter(move |&num| tcx.crate_name(num) == name) - .map(CrateNum::as_def_id) - } - - let (base, mut path) = match *path { + let (base, path) = match *path { [primitive] => { return vec![PrimTy::from_name(Symbol::intern(primitive)).map_or(Res::Err, Res::PrimTy)]; }, @@ -705,18 +708,25 @@ pub fn def_path_res(tcx: TyCtxt<'_>, path: &[&str]) -> Vec { None }; - let starts = find_primitive_impls(tcx, base) - .chain(find_crates(tcx, base_sym)) + let crates = find_primitive_impls(tcx, base) .chain(local_crate) - .map(|id| Res::Def(tcx.def_kind(id), id)); + .map(|id| Res::Def(tcx.def_kind(id), id)) + .chain(find_crates(tcx, base_sym)) + .collect(); - let mut resolutions: Vec = starts.collect(); + def_path_res_with_base(tcx, crates, path) +} +/// Resolves a def path like `vec::Vec` with the base `std`. +/// +/// This is lighter than [`def_path_res`], and should be called with [`find_crates`] looking up +/// items from the same crate repeatedly, although should still be used sparingly. +pub fn def_path_res_with_base(tcx: TyCtxt<'_>, mut base: Vec, mut path: &[&str]) -> Vec { while let [segment, rest @ ..] = path { path = rest; let segment = Symbol::intern(segment); - resolutions = resolutions + base = base .into_iter() .filter_map(|res| res.opt_def_id()) .flat_map(|def_id| { @@ -735,7 +745,7 @@ pub fn def_path_res(tcx: TyCtxt<'_>, path: &[&str]) -> Vec { .collect(); } - resolutions + base } /// Resolves a def path like `std::vec::Vec` to its [`DefId`]s, see [`def_path_res`]. From 6b34c8df2cd5db6626e00564446b886b3827b080 Mon Sep 17 00:00:00 2001 From: GnomedDev Date: Sat, 21 Sep 2024 16:21:05 +0100 Subject: [PATCH 189/683] Avoid looking regex crate up multiple times --- clippy_lints/src/regex.rs | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/clippy_lints/src/regex.rs b/clippy_lints/src/regex.rs index f6ef02b7c23..12cbdb854ef 100644 --- a/clippy_lints/src/regex.rs +++ b/clippy_lints/src/regex.rs @@ -3,7 +3,7 @@ use std::fmt::Display; use clippy_utils::consts::{ConstEvalCtxt, Constant}; use clippy_utils::diagnostics::{span_lint, span_lint_and_help}; use clippy_utils::source::SpanRangeExt; -use clippy_utils::{def_path_def_ids, path_def_id, paths}; +use clippy_utils::{def_path_res_with_base, find_crates, path_def_id, paths}; use rustc_ast::ast::{LitKind, StrStyle}; use rustc_hir::def_id::DefIdMap; use rustc_hir::{BorrowKind, Expr, ExprKind}; @@ -75,11 +75,14 @@ impl<'tcx> LateLintPass<'tcx> for Regex { // We don't use `match_def_path` here because that relies on matching the exact path, which changed // between regex 1.8 and 1.9 // - // `def_path_def_ids` will resolve through re-exports but is relatively heavy, so we only perform - // the operation once and store the results - let mut resolve = |path, kind| { - for id in def_path_def_ids(cx.tcx, path) { - self.definitions.insert(id, kind); + // `def_path_res_with_base` will resolve through re-exports but is relatively heavy, so we only + // perform the operation once and store the results + let regex_crates = find_crates(cx.tcx, sym!(regex)); + let mut resolve = |path: &[&str], kind: RegexKind| { + for res in def_path_res_with_base(cx.tcx, regex_crates.clone(), &path[1..]) { + if let Some(id) = res.opt_def_id() { + self.definitions.insert(id, kind); + } } }; From e393f56d37857d3b690b687fe54e8413bb9d5b3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rn=20Horstmann?= Date: Wed, 10 Apr 2024 22:22:18 +0200 Subject: [PATCH 190/683] Improve autovectorization of to_lowercase / to_uppercase functions Refactor the code in the `convert_while_ascii` helper function to make it more suitable for auto-vectorization and also process the full ascii prefix of the string. The generic case conversion logic will only be invoked starting from the first non-ascii character. The runtime on microbenchmarks with ascii-only inputs improves between 1.5x for short and 4x for long inputs on x86_64 and aarch64. The new implementation also encapsulates all unsafe inside the `convert_while_ascii` function. Fixes #123712 --- library/alloc/benches/str.rs | 2 + library/alloc/src/str.rs | 129 +++++++++++------- library/alloc/tests/str.rs | 3 + ...e-123712-str-to-lower-autovectorization.rs | 23 ++++ 4 files changed, 105 insertions(+), 52 deletions(-) create mode 100644 tests/codegen/issues/issue-123712-str-to-lower-autovectorization.rs diff --git a/library/alloc/benches/str.rs b/library/alloc/benches/str.rs index f020638e992..98c7c5413ca 100644 --- a/library/alloc/benches/str.rs +++ b/library/alloc/benches/str.rs @@ -347,3 +347,5 @@ make_test!(rsplitn_space_char, s, s.rsplitn(10, ' ').count()); make_test!(split_space_str, s, s.split(" ").count()); make_test!(split_ad_str, s, s.split("ad").count()); + +make_test!(to_lowercase, s, s.to_lowercase()); diff --git a/library/alloc/src/str.rs b/library/alloc/src/str.rs index 32212b61c6e..42501f9c315 100644 --- a/library/alloc/src/str.rs +++ b/library/alloc/src/str.rs @@ -9,6 +9,7 @@ use core::borrow::{Borrow, BorrowMut}; use core::iter::FusedIterator; +use core::mem::MaybeUninit; #[stable(feature = "encode_utf16", since = "1.8.0")] pub use core::str::EncodeUtf16; #[stable(feature = "split_ascii_whitespace", since = "1.34.0")] @@ -365,14 +366,9 @@ impl str { without modifying the original"] #[stable(feature = "unicode_case_mapping", since = "1.2.0")] pub fn to_lowercase(&self) -> String { - let out = convert_while_ascii(self.as_bytes(), u8::to_ascii_lowercase); + let (mut s, rest) = convert_while_ascii(self, u8::to_ascii_lowercase); - // Safety: we know this is a valid char boundary since - // out.len() is only progressed if ascii bytes are found - let rest = unsafe { self.get_unchecked(out.len()..) }; - - // Safety: We have written only valid ASCII to our vec - let mut s = unsafe { String::from_utf8_unchecked(out) }; + let prefix_len = s.len(); for (i, c) in rest.char_indices() { if c == 'Σ' { @@ -381,8 +377,7 @@ impl str { // in `SpecialCasing.txt`, // so hard-code it rather than have a generic "condition" mechanism. // See https://github.com/rust-lang/rust/issues/26035 - let out_len = self.len() - rest.len(); - let sigma_lowercase = map_uppercase_sigma(&self, i + out_len); + let sigma_lowercase = map_uppercase_sigma(self, prefix_len + i); s.push(sigma_lowercase); } else { match conversions::to_lower(c) { @@ -458,14 +453,7 @@ impl str { without modifying the original"] #[stable(feature = "unicode_case_mapping", since = "1.2.0")] pub fn to_uppercase(&self) -> String { - let out = convert_while_ascii(self.as_bytes(), u8::to_ascii_uppercase); - - // Safety: we know this is a valid char boundary since - // out.len() is only progressed if ascii bytes are found - let rest = unsafe { self.get_unchecked(out.len()..) }; - - // Safety: We have written only valid ASCII to our vec - let mut s = unsafe { String::from_utf8_unchecked(out) }; + let (mut s, rest) = convert_while_ascii(self, u8::to_ascii_uppercase); for c in rest.chars() { match conversions::to_upper(c) { @@ -614,50 +602,87 @@ pub unsafe fn from_boxed_utf8_unchecked(v: Box<[u8]>) -> Box { unsafe { Box::from_raw(Box::into_raw(v) as *mut str) } } -/// Converts the bytes while the bytes are still ascii. +/// Converts leading ascii bytes in `s` by calling the `convert` function. +/// /// For better average performance, this happens in chunks of `2*size_of::()`. -/// Returns a vec with the converted bytes. +/// +/// Returns a tuple of the converted prefix and the remainder starting from +/// the first non-ascii character. +/// +/// This function is only public so that it can be verified in a codegen test, +/// see `issue-123712-str-to-lower-autovectorization.rs`. +#[unstable(feature = "str_internals", issue = "none")] +#[doc(hidden)] #[inline] #[cfg(not(test))] #[cfg(not(no_global_oom_handling))] -fn convert_while_ascii(b: &[u8], convert: fn(&u8) -> u8) -> Vec { - let mut out = Vec::with_capacity(b.len()); +pub fn convert_while_ascii(s: &str, convert: fn(&u8) -> u8) -> (String, &str) { + // Process the input in chunks of 16 bytes to enable auto-vectorization. + // Previously the chunk size depended on the size of `usize`, + // but on 32-bit platforms with sse or neon is also the better choice. + // The only downside on other platforms would be a bit more loop-unrolling. + const N: usize = 16; - const USIZE_SIZE: usize = mem::size_of::(); - const MAGIC_UNROLL: usize = 2; - const N: usize = USIZE_SIZE * MAGIC_UNROLL; - const NONASCII_MASK: usize = usize::from_ne_bytes([0x80; USIZE_SIZE]); + let mut slice = s.as_bytes(); + let mut out = Vec::with_capacity(slice.len()); + let mut out_slice = out.spare_capacity_mut(); - let mut i = 0; - unsafe { - while i + N <= b.len() { - // Safety: we have checks the sizes `b` and `out` to know that our - let in_chunk = b.get_unchecked(i..i + N); - let out_chunk = out.spare_capacity_mut().get_unchecked_mut(i..i + N); + let mut ascii_prefix_len = 0_usize; + let mut is_ascii = [false; N]; - let mut bits = 0; - for j in 0..MAGIC_UNROLL { - // read the bytes 1 usize at a time (unaligned since we haven't checked the alignment) - // safety: in_chunk is valid bytes in the range - bits |= in_chunk.as_ptr().cast::().add(j).read_unaligned(); - } - // if our chunks aren't ascii, then return only the prior bytes as init - if bits & NONASCII_MASK != 0 { - break; - } + while slice.len() >= N { + // SAFETY: checked in loop condition + let chunk = unsafe { slice.get_unchecked(..N) }; + // SAFETY: out_slice has at least same length as input slice and gets sliced with the same offsets + let out_chunk = unsafe { out_slice.get_unchecked_mut(..N) }; - // perform the case conversions on N bytes (gets heavily autovec'd) - for j in 0..N { - // safety: in_chunk and out_chunk is valid bytes in the range - let out = out_chunk.get_unchecked_mut(j); - out.write(convert(in_chunk.get_unchecked(j))); - } - - // mark these bytes as initialised - i += N; + for j in 0..N { + is_ascii[j] = chunk[j] <= 127; } - out.set_len(i); + + // Auto-vectorization for this check is a bit fragile, sum and comparing against the chunk + // size gives the best result, specifically a pmovmsk instruction on x86. + // See https://github.com/llvm/llvm-project/issues/96395 for why llvm currently does not + // currently recognize other similar idioms. + if is_ascii.iter().map(|x| *x as u8).sum::() as usize != N { + break; + } + + for j in 0..N { + out_chunk[j] = MaybeUninit::new(convert(&chunk[j])); + } + + ascii_prefix_len += N; + slice = unsafe { slice.get_unchecked(N..) }; + out_slice = unsafe { out_slice.get_unchecked_mut(N..) }; } - out + // handle the remainder as individual bytes + while slice.len() > 0 { + let byte = slice[0]; + if byte > 127 { + break; + } + // SAFETY: out_slice has at least same length as input slice + unsafe { + *out_slice.get_unchecked_mut(0) = MaybeUninit::new(convert(&byte)); + } + ascii_prefix_len += 1; + slice = unsafe { slice.get_unchecked(1..) }; + out_slice = unsafe { out_slice.get_unchecked_mut(1..) }; + } + + unsafe { + // SAFETY: ascii_prefix_len bytes have been initialized above + out.set_len(ascii_prefix_len); + + // SAFETY: We have written only valid ascii to the output vec + let ascii_string = String::from_utf8_unchecked(out); + + // SAFETY: we know this is a valid char boundary + // since we only skipped over leading ascii bytes + let rest = core::str::from_utf8_unchecked(slice); + + (ascii_string, rest) + } } diff --git a/library/alloc/tests/str.rs b/library/alloc/tests/str.rs index a80e5275dab..6f930ab0853 100644 --- a/library/alloc/tests/str.rs +++ b/library/alloc/tests/str.rs @@ -1854,7 +1854,10 @@ fn to_lowercase() { assert_eq!("ΑΣ''Α".to_lowercase(), "ασ''α"); // https://github.com/rust-lang/rust/issues/124714 + // input lengths around the boundary of the chunk size used by the ascii prefix optimization + assert_eq!("abcdefghijklmnoΣ".to_lowercase(), "abcdefghijklmnoς"); assert_eq!("abcdefghijklmnopΣ".to_lowercase(), "abcdefghijklmnopς"); + assert_eq!("abcdefghijklmnopqΣ".to_lowercase(), "abcdefghijklmnopqς"); // a really long string that has it's lowercase form // even longer. this tests that implementations don't assume diff --git a/tests/codegen/issues/issue-123712-str-to-lower-autovectorization.rs b/tests/codegen/issues/issue-123712-str-to-lower-autovectorization.rs new file mode 100644 index 00000000000..11ee10e8cc3 --- /dev/null +++ b/tests/codegen/issues/issue-123712-str-to-lower-autovectorization.rs @@ -0,0 +1,23 @@ +//@ only-x86_64 +//@ compile-flags: -C opt-level=3 +#![crate_type = "lib"] +#![no_std] +#![feature(str_internals)] + +extern crate alloc; + +/// Ensure that the ascii-prefix loop for `str::to_lowercase` and `str::to_uppercase` uses vector +/// instructions. +/// +/// The llvm ir should be the same for all targets that support some form of simd. Only targets +/// without any simd instructions would see scalarized ir. +/// Unfortunately, there is no `only-simd` directive to only run this test on only such platforms, +/// and using test revisions would still require the core libraries for all platforms. +// CHECK-LABEL: @lower_while_ascii +// CHECK: [[A:%[0-9]]] = load <16 x i8> +// CHECK-NEXT: [[B:%[0-9]]] = icmp slt <16 x i8> [[A]], zeroinitializer +// CHECK-NEXT: [[C:%[0-9]]] = bitcast <16 x i1> [[B]] to i16 +#[no_mangle] +pub fn lower_while_ascii(s: &str) -> (alloc::string::String, &str) { + alloc::str::convert_while_ascii(s, u8::to_ascii_lowercase) +} From 0332581327dc23fdc08a37fecaaa4a062b65ad4d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 23 Sep 2024 11:47:09 +0200 Subject: [PATCH 191/683] add test for new abort_unwind function --- .../miri/tests/fail/panic/abort_unwind.rs | 11 +++++++ .../miri/tests/fail/panic/abort_unwind.stderr | 33 +++++++++++++++++++ 2 files changed, 44 insertions(+) create mode 100644 src/tools/miri/tests/fail/panic/abort_unwind.rs create mode 100644 src/tools/miri/tests/fail/panic/abort_unwind.stderr diff --git a/src/tools/miri/tests/fail/panic/abort_unwind.rs b/src/tools/miri/tests/fail/panic/abort_unwind.rs new file mode 100644 index 00000000000..e313d9c11de --- /dev/null +++ b/src/tools/miri/tests/fail/panic/abort_unwind.rs @@ -0,0 +1,11 @@ +//@error-in-other-file: the program aborted execution +//@normalize-stderr-test: "unsafe \{ libc::abort\(\) \}|crate::intrinsics::abort\(\);" -> "ABORT();" +//@normalize-stderr-test: "\| +\^+" -> "| ^" +//@normalize-stderr-test: "\n +[0-9]+:[^\n]+" -> "" +//@normalize-stderr-test: "\n +at [^\n]+" -> "" + +#![feature(abort_unwind)] + +fn main() { + std::panic::abort_unwind(|| panic!("PANIC!!!")); +} diff --git a/src/tools/miri/tests/fail/panic/abort_unwind.stderr b/src/tools/miri/tests/fail/panic/abort_unwind.stderr new file mode 100644 index 00000000000..e9c5413693e --- /dev/null +++ b/src/tools/miri/tests/fail/panic/abort_unwind.stderr @@ -0,0 +1,33 @@ +thread 'main' panicked at tests/fail/panic/abort_unwind.rs:LL:CC: +PANIC!!! +note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace +note: in Miri, you may have to set `MIRIFLAGS=-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect +thread 'main' panicked at RUSTLIB/core/src/panicking.rs:LL:CC: +panic in a function that cannot unwind +stack backtrace: +thread caused non-unwinding panic. aborting. +error: abnormal termination: the program aborted execution + --> RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC + | +LL | ABORT(); + | ^ the program aborted execution + | + = note: BACKTRACE: + = note: inside `std::sys::pal::PLATFORM::abort_internal` at RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC + = note: inside `std::panicking::rust_panic_with_hook` at RUSTLIB/std/src/panicking.rs:LL:CC + = note: inside closure at RUSTLIB/std/src/panicking.rs:LL:CC + = note: inside `std::sys::backtrace::__rust_end_short_backtrace::<{closure@std::panicking::begin_panic_handler::{closure#0}}, !>` at RUSTLIB/std/src/sys/backtrace.rs:LL:CC + = note: inside `std::panicking::begin_panic_handler` at RUSTLIB/std/src/panicking.rs:LL:CC + = note: inside `core::panicking::panic_nounwind` at RUSTLIB/core/src/panicking.rs:LL:CC + = note: inside `core::panicking::panic_cannot_unwind` at RUSTLIB/core/src/panicking.rs:LL:CC + = note: inside `std::panic::abort_unwind::<{closure@tests/fail/panic/abort_unwind.rs:LL:CC}, ()>` at RUSTLIB/core/src/panic.rs:LL:CC +note: inside `main` + --> tests/fail/panic/abort_unwind.rs:LL:CC + | +LL | std::panic::abort_unwind(|| panic!("PANIC!!!")); + | ^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + From e424a8c01f454ba73e4e75b9b1d648208ba9744e Mon Sep 17 00:00:00 2001 From: Yoh Deadfall Date: Mon, 23 Sep 2024 12:54:07 +0300 Subject: [PATCH 192/683] Clarifications for set_nonblocking methods --- library/std/src/net/tcp.rs | 2 +- library/std/src/net/udp.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library/std/src/net/tcp.rs b/library/std/src/net/tcp.rs index 22d2dfe65a2..ef9ccb90a91 100644 --- a/library/std/src/net/tcp.rs +++ b/library/std/src/net/tcp.rs @@ -561,7 +561,7 @@ impl TcpStream { /// Moves this TCP stream into or out of nonblocking mode. /// - /// This will result in `read`, `write`, `recv` and `send` operations + /// This will result in `read`, `write`, `recv` and `send` system operations /// becoming nonblocking, i.e., immediately returning from their calls. /// If the IO operation is successful, `Ok` is returned and no further /// action is required. If the IO operation could not be completed and needs diff --git a/library/std/src/net/udp.rs b/library/std/src/net/udp.rs index 32e9086003d..14b0bee7eac 100644 --- a/library/std/src/net/udp.rs +++ b/library/std/src/net/udp.rs @@ -764,7 +764,7 @@ impl UdpSocket { /// Moves this UDP socket into or out of nonblocking mode. /// - /// This will result in `recv`, `recv_from`, `send`, and `send_to` + /// This will result in `recv`, `recv_from`, `send`, and `send_to` system /// operations becoming nonblocking, i.e., immediately returning from their /// calls. If the IO operation is successful, `Ok` is returned and no /// further action is required. If the IO operation could not be completed From 51d90bbc8d6c2e4bbaaf4f9b1ef1c7b928826e51 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 23 Sep 2024 12:56:17 +0200 Subject: [PATCH 193/683] fix workflow permissions --- src/tools/miri/.github/workflows/ci.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/tools/miri/.github/workflows/ci.yml b/src/tools/miri/.github/workflows/ci.yml index b9441236bcd..6e4815c0b91 100644 --- a/src/tools/miri/.github/workflows/ci.yml +++ b/src/tools/miri/.github/workflows/ci.yml @@ -13,7 +13,8 @@ on: - cron: '44 4 * * *' # At 4:44 UTC every day. permissions: - contents: write + contents: read + pull-requests: write defaults: run: From 6e387c90f9970c1db15494b73cecdffd27176033 Mon Sep 17 00:00:00 2001 From: Alex Macleod Date: Mon, 23 Sep 2024 15:26:43 +0000 Subject: [PATCH 194/683] Add reasons for or remove some `//@no-rustfix` annotations --- tests/ui/as_ptr_cast_mut.rs | 2 +- tests/ui/borrow_box.fixed | 132 ++++++++++++++++++ tests/ui/borrow_box.rs | 17 ++- tests/ui/borrow_box.stderr | 20 +-- tests/ui/bytecount.rs | 2 +- tests/ui/deref_addrof_double_trigger.rs | 4 +- tests/ui/float_cmp.rs | 2 +- tests/ui/float_cmp_const.rs | 3 +- tests/ui/float_cmp_const.stderr | 16 +-- tests/ui/float_equality_without_abs.rs | 2 +- tests/ui/unused_format_specs.1.fixed | 35 +++++ tests/ui/unused_format_specs.2.fixed | 35 +++++ ...cs_unfixable.rs => unused_format_specs.rs} | 2 +- ...able.stderr => unused_format_specs.stderr} | 8 +- 14 files changed, 242 insertions(+), 38 deletions(-) create mode 100644 tests/ui/borrow_box.fixed create mode 100644 tests/ui/unused_format_specs.1.fixed create mode 100644 tests/ui/unused_format_specs.2.fixed rename tests/ui/{unused_format_specs_unfixable.rs => unused_format_specs.rs} (98%) rename tests/ui/{unused_format_specs_unfixable.stderr => unused_format_specs.stderr} (89%) diff --git a/tests/ui/as_ptr_cast_mut.rs b/tests/ui/as_ptr_cast_mut.rs index 297a53b1bbf..9e862320f4e 100644 --- a/tests/ui/as_ptr_cast_mut.rs +++ b/tests/ui/as_ptr_cast_mut.rs @@ -1,7 +1,7 @@ #![allow(unused)] #![warn(clippy::as_ptr_cast_mut)] #![allow(clippy::wrong_self_convention, clippy::unnecessary_cast)] -//@no-rustfix +//@no-rustfix: incorrect suggestion struct MutPtrWrapper(Vec); impl MutPtrWrapper { diff --git a/tests/ui/borrow_box.fixed b/tests/ui/borrow_box.fixed new file mode 100644 index 00000000000..5984cc4e930 --- /dev/null +++ b/tests/ui/borrow_box.fixed @@ -0,0 +1,132 @@ +#![deny(clippy::borrowed_box)] +#![allow(dead_code, unused_variables)] +#![allow( + clippy::uninlined_format_args, + clippy::disallowed_names, + clippy::needless_pass_by_ref_mut +)] + +use std::fmt::Display; + +pub fn test1(foo: &mut Box) { + // Although this function could be changed to "&mut bool", + // avoiding the Box, mutable references to boxes are not + // flagged by this lint. + // + // This omission is intentional: By passing a mutable Box, + // the memory location of the pointed-to object could be + // modified. By passing a mutable reference, the contents + // could change, but not the location. + println!("{:?}", foo) +} + +pub fn test2() { + let foo: &bool; + //~^ ERROR: you seem to be trying to use `&Box`. Consider using just `&T` +} + +struct Test3<'a> { + foo: &'a bool, + //~^ ERROR: you seem to be trying to use `&Box`. Consider using just `&T` +} + +trait Test4 { + fn test4(a: &bool); + //~^ ERROR: you seem to be trying to use `&Box`. Consider using just `&T` +} + +use std::any::Any; + +pub fn test5(foo: &mut Box) { + println!("{:?}", foo) +} + +pub fn test6() { + let foo: &Box; +} + +struct Test7<'a> { + foo: &'a Box, +} + +trait Test8 { + fn test8(a: &Box); +} + +impl<'a> Test8 for Test7<'a> { + fn test8(a: &Box) { + unimplemented!(); + } +} + +pub fn test9(foo: &mut Box) { + let _ = foo; +} + +pub fn test10() { + let foo: &Box; +} + +struct Test11<'a> { + foo: &'a Box, +} + +trait Test12 { + fn test4(a: &Box); +} + +impl<'a> Test12 for Test11<'a> { + fn test4(a: &Box) { + unimplemented!(); + } +} + +pub fn test13(boxed_slice: &mut Box<[i32]>) { + // Unconditionally replaces the box pointer. + // + // This cannot be accomplished if "&mut [i32]" is passed, + // and provides a test case where passing a reference to + // a Box is valid. + let mut data = vec![12]; + *boxed_slice = data.into_boxed_slice(); +} + +// The suggestion should include proper parentheses to avoid a syntax error. +pub fn test14(_display: &dyn Display) {} +//~^ ERROR: you seem to be trying to use `&Box`. Consider using just `&T` +pub fn test15(_display: &(dyn Display + Send)) {} +//~^ ERROR: you seem to be trying to use `&Box`. Consider using just `&T` +pub fn test16<'a>(_display: &'a (dyn Display + 'a)) {} +//~^ ERROR: you seem to be trying to use `&Box`. Consider using just `&T` + +pub fn test17(_display: &impl Display) {} +//~^ ERROR: you seem to be trying to use `&Box`. Consider using just `&T` +pub fn test18(_display: &(impl Display + Send)) {} +//~^ ERROR: you seem to be trying to use `&Box`. Consider using just `&T` +pub fn test19<'a>(_display: &'a (impl Display + 'a)) {} +//~^ ERROR: you seem to be trying to use `&Box`. Consider using just `&T` + +// This exists only to check what happens when parentheses are already present. +// Even though the current implementation doesn't put extra parentheses, +// it's fine that unnecessary parentheses appear in the future for some reason. +pub fn test20(_display: &(dyn Display + Send)) {} +//~^ ERROR: you seem to be trying to use `&Box`. Consider using just `&T` + +#[allow(clippy::borrowed_box)] +trait Trait { + fn f(b: &Box); +} + +// Trait impls are not linted +impl Trait for () { + fn f(_: &Box) {} +} + +fn main() { + test1(&mut Box::new(false)); + test2(); + test5(&mut (Box::new(false) as Box)); + test6(); + test9(&mut (Box::new(false) as Box)); + test10(); +} diff --git a/tests/ui/borrow_box.rs b/tests/ui/borrow_box.rs index e9994aac845..7f15fc83a1d 100644 --- a/tests/ui/borrow_box.rs +++ b/tests/ui/borrow_box.rs @@ -5,7 +5,6 @@ clippy::disallowed_names, clippy::needless_pass_by_ref_mut )] -//@no-rustfix use std::fmt::Display; @@ -36,12 +35,6 @@ trait Test4 { //~^ ERROR: you seem to be trying to use `&Box`. Consider using just `&T` } -impl<'a> Test4 for Test3<'a> { - fn test4(a: &Box) { - unimplemented!(); - } -} - use std::any::Any; pub fn test5(foo: &mut Box) { @@ -119,6 +112,16 @@ pub fn test19<'a>(_display: &'a Box) {} pub fn test20(_display: &Box<(dyn Display + Send)>) {} //~^ ERROR: you seem to be trying to use `&Box`. Consider using just `&T` +#[allow(clippy::borrowed_box)] +trait Trait { + fn f(b: &Box); +} + +// Trait impls are not linted +impl Trait for () { + fn f(_: &Box) {} +} + fn main() { test1(&mut Box::new(false)); test2(); diff --git a/tests/ui/borrow_box.stderr b/tests/ui/borrow_box.stderr index 34e8f11dfd7..ed4308161bb 100644 --- a/tests/ui/borrow_box.stderr +++ b/tests/ui/borrow_box.stderr @@ -1,5 +1,5 @@ error: you seem to be trying to use `&Box`. Consider using just `&T` - --> tests/ui/borrow_box.rs:25:14 + --> tests/ui/borrow_box.rs:24:14 | LL | let foo: &Box; | ^^^^^^^^^^ help: try: `&bool` @@ -11,55 +11,55 @@ LL | #![deny(clippy::borrowed_box)] | ^^^^^^^^^^^^^^^^^^^^ error: you seem to be trying to use `&Box`. Consider using just `&T` - --> tests/ui/borrow_box.rs:30:10 + --> tests/ui/borrow_box.rs:29:10 | LL | foo: &'a Box, | ^^^^^^^^^^^^^ help: try: `&'a bool` error: you seem to be trying to use `&Box`. Consider using just `&T` - --> tests/ui/borrow_box.rs:35:17 + --> tests/ui/borrow_box.rs:34:17 | LL | fn test4(a: &Box); | ^^^^^^^^^^ help: try: `&bool` error: you seem to be trying to use `&Box`. Consider using just `&T` - --> tests/ui/borrow_box.rs:102:25 + --> tests/ui/borrow_box.rs:95:25 | LL | pub fn test14(_display: &Box) {} | ^^^^^^^^^^^^^^^^^ help: try: `&dyn Display` error: you seem to be trying to use `&Box`. Consider using just `&T` - --> tests/ui/borrow_box.rs:104:25 + --> tests/ui/borrow_box.rs:97:25 | LL | pub fn test15(_display: &Box) {} | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&(dyn Display + Send)` error: you seem to be trying to use `&Box`. Consider using just `&T` - --> tests/ui/borrow_box.rs:106:29 + --> tests/ui/borrow_box.rs:99:29 | LL | pub fn test16<'a>(_display: &'a Box) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&'a (dyn Display + 'a)` error: you seem to be trying to use `&Box`. Consider using just `&T` - --> tests/ui/borrow_box.rs:109:25 + --> tests/ui/borrow_box.rs:102:25 | LL | pub fn test17(_display: &Box) {} | ^^^^^^^^^^^^^^^^^^ help: try: `&impl Display` error: you seem to be trying to use `&Box`. Consider using just `&T` - --> tests/ui/borrow_box.rs:111:25 + --> tests/ui/borrow_box.rs:104:25 | LL | pub fn test18(_display: &Box) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&(impl Display + Send)` error: you seem to be trying to use `&Box`. Consider using just `&T` - --> tests/ui/borrow_box.rs:113:29 + --> tests/ui/borrow_box.rs:106:29 | LL | pub fn test19<'a>(_display: &'a Box) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&'a (impl Display + 'a)` error: you seem to be trying to use `&Box`. Consider using just `&T` - --> tests/ui/borrow_box.rs:119:25 + --> tests/ui/borrow_box.rs:112:25 | LL | pub fn test20(_display: &Box<(dyn Display + Send)>) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&(dyn Display + Send)` diff --git a/tests/ui/bytecount.rs b/tests/ui/bytecount.rs index 3794fc5d441..f3b02fda8a8 100644 --- a/tests/ui/bytecount.rs +++ b/tests/ui/bytecount.rs @@ -1,4 +1,4 @@ -//@no-rustfix +//@no-rustfix: suggests external crate #![allow(clippy::needless_borrow, clippy::useless_vec)] diff --git a/tests/ui/deref_addrof_double_trigger.rs b/tests/ui/deref_addrof_double_trigger.rs index 32582a3a8bf..6f997875777 100644 --- a/tests/ui/deref_addrof_double_trigger.rs +++ b/tests/ui/deref_addrof_double_trigger.rs @@ -1,5 +1,5 @@ -// This test can't work with run-rustfix because it needs two passes of test+fix -//@no-rustfix +//@no-rustfix: this test can't work with run-rustfix because it needs two passes of test+fix + #[warn(clippy::deref_addrof)] #[allow(unused_variables, unused_mut)] fn main() { diff --git a/tests/ui/float_cmp.rs b/tests/ui/float_cmp.rs index 78dd2c6c01c..a1dfd1954fc 100644 --- a/tests/ui/float_cmp.rs +++ b/tests/ui/float_cmp.rs @@ -8,7 +8,7 @@ clippy::unnecessary_operation, clippy::cast_lossless )] -//@no-rustfix +//@no-rustfix: suggestions have an error margin placeholder use std::ops::Add; const ZERO: f32 = 0.0; diff --git a/tests/ui/float_cmp_const.rs b/tests/ui/float_cmp_const.rs index 08180556437..ba760a18f28 100644 --- a/tests/ui/float_cmp_const.rs +++ b/tests/ui/float_cmp_const.rs @@ -1,5 +1,4 @@ -// does not test any rustfixable lints -//@no-rustfix +//@no-rustfix: suggestions have an error margin placeholder #![warn(clippy::float_cmp_const)] #![allow(clippy::float_cmp)] #![allow(unused, clippy::no_effect, clippy::unnecessary_operation)] diff --git a/tests/ui/float_cmp_const.stderr b/tests/ui/float_cmp_const.stderr index 4f88746e958..e0cd6faf4b3 100644 --- a/tests/ui/float_cmp_const.stderr +++ b/tests/ui/float_cmp_const.stderr @@ -1,5 +1,5 @@ error: strict comparison of `f32` or `f64` constant - --> tests/ui/float_cmp_const.rs:16:5 + --> tests/ui/float_cmp_const.rs:15:5 | LL | 1f32 == ONE; | ^^^^^^^^^^^ help: consider comparing them within some margin of error: `(1f32 - ONE).abs() < error_margin` @@ -8,43 +8,43 @@ LL | 1f32 == ONE; = help: to override `-D warnings` add `#[allow(clippy::float_cmp_const)]` error: strict comparison of `f32` or `f64` constant - --> tests/ui/float_cmp_const.rs:18:5 + --> tests/ui/float_cmp_const.rs:17:5 | LL | TWO == ONE; | ^^^^^^^^^^ help: consider comparing them within some margin of error: `(TWO - ONE).abs() < error_margin` error: strict comparison of `f32` or `f64` constant - --> tests/ui/float_cmp_const.rs:20:5 + --> tests/ui/float_cmp_const.rs:19:5 | LL | TWO != ONE; | ^^^^^^^^^^ help: consider comparing them within some margin of error: `(TWO - ONE).abs() > error_margin` error: strict comparison of `f32` or `f64` constant - --> tests/ui/float_cmp_const.rs:22:5 + --> tests/ui/float_cmp_const.rs:21:5 | LL | ONE + ONE == TWO; | ^^^^^^^^^^^^^^^^ help: consider comparing them within some margin of error: `(ONE + ONE - TWO).abs() < error_margin` error: strict comparison of `f32` or `f64` constant - --> tests/ui/float_cmp_const.rs:25:5 + --> tests/ui/float_cmp_const.rs:24:5 | LL | x as f32 == ONE; | ^^^^^^^^^^^^^^^ help: consider comparing them within some margin of error: `(x as f32 - ONE).abs() < error_margin` error: strict comparison of `f32` or `f64` constant - --> tests/ui/float_cmp_const.rs:29:5 + --> tests/ui/float_cmp_const.rs:28:5 | LL | v == ONE; | ^^^^^^^^ help: consider comparing them within some margin of error: `(v - ONE).abs() < error_margin` error: strict comparison of `f32` or `f64` constant - --> tests/ui/float_cmp_const.rs:31:5 + --> tests/ui/float_cmp_const.rs:30:5 | LL | v != ONE; | ^^^^^^^^ help: consider comparing them within some margin of error: `(v - ONE).abs() > error_margin` error: strict comparison of `f32` or `f64` constant arrays - --> tests/ui/float_cmp_const.rs:64:5 + --> tests/ui/float_cmp_const.rs:63:5 | LL | NON_ZERO_ARRAY == NON_ZERO_ARRAY2; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/float_equality_without_abs.rs b/tests/ui/float_equality_without_abs.rs index 2b67c8bec10..500b3035390 100644 --- a/tests/ui/float_equality_without_abs.rs +++ b/tests/ui/float_equality_without_abs.rs @@ -1,5 +1,5 @@ #![warn(clippy::float_equality_without_abs)] -//@no-rustfix +//@no-rustfix: suggestions cause type ambiguity // FIXME(f16_f128): add tests for these types when abs is available diff --git a/tests/ui/unused_format_specs.1.fixed b/tests/ui/unused_format_specs.1.fixed new file mode 100644 index 00000000000..b7d1cce2870 --- /dev/null +++ b/tests/ui/unused_format_specs.1.fixed @@ -0,0 +1,35 @@ +#![warn(clippy::unused_format_specs)] +#![allow(unused)] + +macro_rules! format_args_from_macro { + () => { + format_args!("from macro") + }; +} + +fn main() { + // prints `.`, not ` .` + println!("{:5}.", format!("")); + //~^ ERROR: format specifiers have no effect on `format_args!()` + //~| NOTE: `-D clippy::unused-format-specs` implied by `-D warnings` + //prints `abcde`, not `abc` + println!("{:.3}", format!("abcde")); + //~^ ERROR: format specifiers have no effect on `format_args!()` + + println!("{}.", format_args_from_macro!()); + //~^ ERROR: format specifiers have no effect on `format_args!()` + + let args = format_args!(""); + println!("{args}"); + //~^ ERROR: format specifiers have no effect on `format_args!()` +} + +fn should_not_lint() { + println!("{}", format_args!("")); + // Technically the same as `{}`, but the `format_args` docs specifically mention that you can use + // debug formatting so allow it + println!("{:?}", format_args!("")); + + let args = format_args!(""); + println!("{args}"); +} diff --git a/tests/ui/unused_format_specs.2.fixed b/tests/ui/unused_format_specs.2.fixed new file mode 100644 index 00000000000..94bb6b7036b --- /dev/null +++ b/tests/ui/unused_format_specs.2.fixed @@ -0,0 +1,35 @@ +#![warn(clippy::unused_format_specs)] +#![allow(unused)] + +macro_rules! format_args_from_macro { + () => { + format_args!("from macro") + }; +} + +fn main() { + // prints `.`, not ` .` + println!("{}.", format_args!("")); + //~^ ERROR: format specifiers have no effect on `format_args!()` + //~| NOTE: `-D clippy::unused-format-specs` implied by `-D warnings` + //prints `abcde`, not `abc` + println!("{}", format_args!("abcde")); + //~^ ERROR: format specifiers have no effect on `format_args!()` + + println!("{}.", format_args_from_macro!()); + //~^ ERROR: format specifiers have no effect on `format_args!()` + + let args = format_args!(""); + println!("{args}"); + //~^ ERROR: format specifiers have no effect on `format_args!()` +} + +fn should_not_lint() { + println!("{}", format_args!("")); + // Technically the same as `{}`, but the `format_args` docs specifically mention that you can use + // debug formatting so allow it + println!("{:?}", format_args!("")); + + let args = format_args!(""); + println!("{args}"); +} diff --git a/tests/ui/unused_format_specs_unfixable.rs b/tests/ui/unused_format_specs.rs similarity index 98% rename from tests/ui/unused_format_specs_unfixable.rs rename to tests/ui/unused_format_specs.rs index be991935366..2c85e371149 100644 --- a/tests/ui/unused_format_specs_unfixable.rs +++ b/tests/ui/unused_format_specs.rs @@ -1,6 +1,6 @@ #![warn(clippy::unused_format_specs)] #![allow(unused)] -//@no-rustfix + macro_rules! format_args_from_macro { () => { format_args!("from macro") diff --git a/tests/ui/unused_format_specs_unfixable.stderr b/tests/ui/unused_format_specs.stderr similarity index 89% rename from tests/ui/unused_format_specs_unfixable.stderr rename to tests/ui/unused_format_specs.stderr index d3b334c6092..2b5c81c63d6 100644 --- a/tests/ui/unused_format_specs_unfixable.stderr +++ b/tests/ui/unused_format_specs.stderr @@ -1,5 +1,5 @@ error: format specifiers have no effect on `format_args!()` - --> tests/ui/unused_format_specs_unfixable.rs:12:15 + --> tests/ui/unused_format_specs.rs:12:15 | LL | println!("{:5}.", format_args!("")); | ^^^^ @@ -17,7 +17,7 @@ LL + println!("{}.", format_args!("")); | error: format specifiers have no effect on `format_args!()` - --> tests/ui/unused_format_specs_unfixable.rs:16:15 + --> tests/ui/unused_format_specs.rs:16:15 | LL | println!("{:.3}", format_args!("abcde")); | ^^^^^ @@ -33,7 +33,7 @@ LL + println!("{}", format_args!("abcde")); | error: format specifiers have no effect on `format_args!()` - --> tests/ui/unused_format_specs_unfixable.rs:19:15 + --> tests/ui/unused_format_specs.rs:19:15 | LL | println!("{:5}.", format_args_from_macro!()); | ^^^^ @@ -46,7 +46,7 @@ LL + println!("{}.", format_args_from_macro!()); | error: format specifiers have no effect on `format_args!()` - --> tests/ui/unused_format_specs_unfixable.rs:23:15 + --> tests/ui/unused_format_specs.rs:23:15 | LL | println!("{args:5}"); | ^^^^^^^^ From 7f30dafa9b669379471f48ba6765c2f20e24dc14 Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Mon, 23 Sep 2024 17:56:32 +0200 Subject: [PATCH 195/683] Use contiguous spans for empty_line_after_* suggestion Replacing an empty span (which an empty line is) with an empty string triggers a debug assertion in rustc. This fixes the debug assertion by using contiguous spans, with the same resulting suggestion. --- clippy_lints/src/doc/empty_line_after.rs | 20 +++++++++++++++++-- .../empty_line_after/outer_attribute.1.fixed | 5 +++++ .../empty_line_after/outer_attribute.2.fixed | 5 +++++ tests/ui/empty_line_after/outer_attribute.rs | 7 +++++++ .../empty_line_after/outer_attribute.stderr | 15 +++++++++++++- 5 files changed, 49 insertions(+), 3 deletions(-) diff --git a/clippy_lints/src/doc/empty_line_after.rs b/clippy_lints/src/doc/empty_line_after.rs index 125b9077061..de7a2c2433f 100644 --- a/clippy_lints/src/doc/empty_line_after.rs +++ b/clippy_lints/src/doc/empty_line_after.rs @@ -8,7 +8,7 @@ use rustc_errors::{Applicability, Diag, SuggestionStyle}; use rustc_hir::{ItemKind, Node}; use rustc_lexer::TokenKind; use rustc_lint::LateContext; -use rustc_span::{ExpnKind, InnerSpan, Span, SpanData}; +use rustc_span::{BytePos, ExpnKind, InnerSpan, Span, SpanData}; use super::{EMPTY_LINE_AFTER_DOC_COMMENTS, EMPTY_LINE_AFTER_OUTER_ATTR}; @@ -144,6 +144,19 @@ impl<'a> Gap<'a> { prev_chunk, }) } + + fn contiguous_empty_lines(&self) -> impl Iterator + '_ { + self.empty_lines + // The `+ BytePos(1)` means "next line", because each empty line span is "N:1-N:1". + .chunk_by(|a, b| a.hi() + BytePos(1) == b.lo()) + .map(|chunk| { + let first = chunk.first().expect("at least one empty line"); + let last = chunk.last().expect("at least one empty line"); + // The BytePos subtraction here is safe, as before an empty line, there must be at least one + // attribute/comment. The span needs to start at the end of the previous line. + first.with_lo(first.lo() - BytePos(1)).with_hi(last.hi()) + }) + } } /// If the node the attributes/docs apply to is the first in the module/crate suggest converting @@ -192,6 +205,7 @@ fn check_gaps(cx: &LateContext<'_>, gaps: &[Gap<'_>]) -> bool { return false; }; let empty_lines = || gaps.iter().flat_map(|gap| gap.empty_lines.iter().copied()); + let contiguous_empty_lines = || gaps.iter().flat_map(Gap::contiguous_empty_lines); let mut has_comment = false; let mut has_attr = false; for gap in gaps { @@ -227,7 +241,9 @@ fn check_gaps(cx: &LateContext<'_>, gaps: &[Gap<'_>]) -> bool { diag.multipart_suggestion_with_style( format!("if the empty {lines} {are} unintentional remove {them}"), - empty_lines().map(|empty_line| (empty_line, String::new())).collect(), + contiguous_empty_lines() + .map(|empty_lines| (empty_lines, String::new())) + .collect(), Applicability::MaybeIncorrect, SuggestionStyle::HideCodeAlways, ); diff --git a/tests/ui/empty_line_after/outer_attribute.1.fixed b/tests/ui/empty_line_after/outer_attribute.1.fixed index cd7ea24b6be..36d80a2c95b 100644 --- a/tests/ui/empty_line_after/outer_attribute.1.fixed +++ b/tests/ui/empty_line_after/outer_attribute.1.fixed @@ -51,6 +51,11 @@ mod foo {} // Still lint cases where the empty line does not immediately follow the attribute fn comment_before_empty_line() {} +//~v empty_line_after_outer_attr +#[allow(unused)] +// This comment is isolated +pub fn isolated_comment() {} + #[doc = " Returns the escaped value of the textual representation of diff --git a/tests/ui/empty_line_after/outer_attribute.2.fixed b/tests/ui/empty_line_after/outer_attribute.2.fixed index 1b044d2fcde..0e8e4129e85 100644 --- a/tests/ui/empty_line_after/outer_attribute.2.fixed +++ b/tests/ui/empty_line_after/outer_attribute.2.fixed @@ -54,6 +54,11 @@ mod foo {} // Still lint cases where the empty line does not immediately follow the attribute fn comment_before_empty_line() {} +//~v empty_line_after_outer_attr +#[allow(unused)] +// This comment is isolated +pub fn isolated_comment() {} + #[doc = " Returns the escaped value of the textual representation of diff --git a/tests/ui/empty_line_after/outer_attribute.rs b/tests/ui/empty_line_after/outer_attribute.rs index 81e1a7ab8ed..1295088ac00 100644 --- a/tests/ui/empty_line_after/outer_attribute.rs +++ b/tests/ui/empty_line_after/outer_attribute.rs @@ -60,6 +60,13 @@ mod foo {} fn comment_before_empty_line() {} +//~v empty_line_after_outer_attr +#[allow(unused)] + +// This comment is isolated + +pub fn isolated_comment() {} + #[doc = " Returns the escaped value of the textual representation of diff --git a/tests/ui/empty_line_after/outer_attribute.stderr b/tests/ui/empty_line_after/outer_attribute.stderr index b73ebb4f662..958b40424a9 100644 --- a/tests/ui/empty_line_after/outer_attribute.stderr +++ b/tests/ui/empty_line_after/outer_attribute.stderr @@ -99,5 +99,18 @@ LL | fn comment_before_empty_line() {} | = help: if the empty line is unintentional remove it -error: aborting due to 8 previous errors +error: empty lines after outer attribute + --> tests/ui/empty_line_after/outer_attribute.rs:64:1 + | +LL | / #[allow(unused)] +LL | | +LL | | // This comment is isolated +LL | | + | |_ +LL | pub fn isolated_comment() {} + | ------------------------- the attribute applies to this function + | + = help: if the empty lines are unintentional remove them + +error: aborting due to 9 previous errors From 97fbcf6773fa2d00675cbd7ea8dcdac1d6772072 Mon Sep 17 00:00:00 2001 From: Eric Holk Date: Thu, 19 Sep 2024 17:23:46 -0700 Subject: [PATCH 196/683] Allow reborrowing Pin<&mut Self> --- .../rustc_hir_typeck/src/method/confirm.rs | 9 ++++++ .../src/method/prelude_edition_lints.rs | 32 +++++++++++++++---- compiler/rustc_hir_typeck/src/method/probe.rs | 32 ++++++++++++++----- tests/ui/async-await/pin-reborrow-self.rs | 20 +++++++++--- 4 files changed, 74 insertions(+), 19 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/method/confirm.rs b/compiler/rustc_hir_typeck/src/method/confirm.rs index e3b0fa78eb7..0d11df11334 100644 --- a/compiler/rustc_hir_typeck/src/method/confirm.rs +++ b/compiler/rustc_hir_typeck/src/method/confirm.rs @@ -235,6 +235,15 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { target, }); } + + Some(probe::AutorefOrPtrAdjustment::ReborrowPin(mutbl)) => { + let region = self.next_region_var(infer::Autoref(self.span)); + + adjustments.push(Adjustment { + kind: Adjust::ReborrowPin(region, mutbl), + target, + }); + } None => {} } 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 a8b5b6165db..b20592c85d2 100644 --- a/compiler/rustc_hir_typeck/src/method/prelude_edition_lints.rs +++ b/compiler/rustc_hir_typeck/src/method/prelude_edition_lints.rs @@ -121,16 +121,27 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { mutbl.ref_prefix_str() } Some(probe::AutorefOrPtrAdjustment::ToConstPtr) | None => "", + Some(probe::AutorefOrPtrAdjustment::ReborrowPin(mutbl)) => match mutbl { + hir::Mutability::Mut => "Pin<&mut ", + hir::Mutability::Not => "Pin<&", + }, }; if let Ok(self_expr) = self.sess().source_map().span_to_snippet(self_expr.span) { - let self_adjusted = if let Some(probe::AutorefOrPtrAdjustment::ToConstPtr) = + let mut self_adjusted = + if let Some(probe::AutorefOrPtrAdjustment::ToConstPtr) = + pick.autoref_or_ptr_adjustment + { + format!("{derefs}{self_expr} as *const _") + } else { + format!("{autoref}{derefs}{self_expr}") + }; + + if let Some(probe::AutorefOrPtrAdjustment::ReborrowPin(_)) = pick.autoref_or_ptr_adjustment { - format!("{derefs}{self_expr} as *const _") - } else { - format!("{autoref}{derefs}{self_expr}") - }; + self_adjusted.push('>'); + } lint.span_suggestion( sp, @@ -400,6 +411,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let autoref = match pick.autoref_or_ptr_adjustment { Some(probe::AutorefOrPtrAdjustment::Autoref { mutbl, .. }) => mutbl.ref_prefix_str(), Some(probe::AutorefOrPtrAdjustment::ToConstPtr) | None => "", + Some(probe::AutorefOrPtrAdjustment::ReborrowPin(mutbl)) => match mutbl { + hir::Mutability::Mut => "Pin<&mut ", + hir::Mutability::Not => "Pin<&", + }, }; let (expr_text, precise) = if let Some(expr_text) = expr @@ -412,7 +427,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ("(..)".to_string(), false) }; - let adjusted_text = if let Some(probe::AutorefOrPtrAdjustment::ToConstPtr) = + let mut adjusted_text = if let Some(probe::AutorefOrPtrAdjustment::ToConstPtr) = pick.autoref_or_ptr_adjustment { format!("{derefs}{expr_text} as *const _") @@ -420,6 +435,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { format!("{autoref}{derefs}{expr_text}") }; + if let Some(probe::AutorefOrPtrAdjustment::ReborrowPin(_)) = pick.autoref_or_ptr_adjustment + { + adjusted_text.push('>'); + } + (adjusted_text, precise) } } diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index 3828b40b885..43481c9704a 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -136,7 +136,7 @@ enum ProbeResult { /// `mut`), or it has type `*mut T` and we convert it to `*const T`. #[derive(Debug, PartialEq, Copy, Clone)] pub(crate) enum AutorefOrPtrAdjustment { - /// Receiver has type `T`, add `&` or `&mut` (it `T` is `mut`), and maybe also "unsize" it. + /// Receiver has type `T`, add `&` or `&mut` (if `T` is `mut`), and maybe also "unsize" it. /// Unsizing is used to convert a `[T; N]` to `[T]`, which only makes sense when autorefing. Autoref { mutbl: hir::Mutability, @@ -147,6 +147,9 @@ pub(crate) enum AutorefOrPtrAdjustment { }, /// Receiver has type `*mut T`, convert to `*const T` ToConstPtr, + + /// Reborrow a `Pin<&mut T>` or `Pin<&T>`. + ReborrowPin(hir::Mutability), } impl AutorefOrPtrAdjustment { @@ -154,6 +157,7 @@ impl AutorefOrPtrAdjustment { match self { AutorefOrPtrAdjustment::Autoref { mutbl: _, unsize } => *unsize, AutorefOrPtrAdjustment::ToConstPtr => false, + AutorefOrPtrAdjustment::ReborrowPin(_) => false, } } } @@ -1133,13 +1137,25 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { r.map(|mut pick| { pick.autoderefs = step.autoderefs; - // Insert a `&*` or `&mut *` if this is a reference type: - if let ty::Ref(_, _, mutbl) = *step.self_ty.value.value.kind() { - pick.autoderefs += 1; - pick.autoref_or_ptr_adjustment = Some(AutorefOrPtrAdjustment::Autoref { - mutbl, - unsize: pick.autoref_or_ptr_adjustment.is_some_and(|a| a.get_unsize()), - }) + match *step.self_ty.value.value.kind() { + // Insert a `&*` or `&mut *` if this is a reference type: + ty::Ref(_, _, mutbl) => { + pick.autoderefs += 1; + pick.autoref_or_ptr_adjustment = Some(AutorefOrPtrAdjustment::Autoref { + mutbl, + unsize: pick.autoref_or_ptr_adjustment.is_some_and(|a| a.get_unsize()), + }) + } + + ty::Adt(def, args) if self.tcx.is_lang_item(def.did(), hir::LangItem::Pin) => { + // make sure this is a pinned reference (and not a `Pin` or something) + if let ty::Ref(_, _, mutbl) = args[0].expect_ty().kind() { + pick.autoref_or_ptr_adjustment = + Some(AutorefOrPtrAdjustment::ReborrowPin(*mutbl)); + } + } + + _ => (), } pick diff --git a/tests/ui/async-await/pin-reborrow-self.rs b/tests/ui/async-await/pin-reborrow-self.rs index b60b6982bb8..ab36ce575e1 100644 --- a/tests/ui/async-await/pin-reborrow-self.rs +++ b/tests/ui/async-await/pin-reborrow-self.rs @@ -1,24 +1,34 @@ //@ check-pass -//@ignore-test - -// Currently ignored due to self reborrowing not being implemented for Pin #![feature(pin_ergonomics)] #![allow(incomplete_features)] use std::pin::Pin; -struct Foo; +pub struct Foo; impl Foo { fn foo(self: Pin<&mut Self>) { } + + fn baz(self: Pin<&Self>) { + } } -fn bar(x: Pin<&mut Foo>) { +pub fn bar(x: Pin<&mut Foo>) { x.foo(); x.foo(); // for this to work we need to automatically reborrow, // as if the user had written `x.as_mut().foo()`. + + Foo::baz(x); + + // FIXME: We should allow downgrading a Pin<&mut T> to Pin<&T> + // x.baz(); +} + +pub fn baaz(x: Pin<&Foo>) { + x.baz(); + x.baz(); } fn main() {} From 3dfb30c70a2a8da87eefa01a56d753d1698866c9 Mon Sep 17 00:00:00 2001 From: Eric Holk Date: Thu, 19 Sep 2024 19:35:01 -0700 Subject: [PATCH 197/683] Allow reborrowing pinned self methods --- .../rustc_hir_typeck/src/method/confirm.rs | 16 ++++-- compiler/rustc_hir_typeck/src/method/probe.rs | 49 ++++++++++++++++++- compiler/rustc_middle/src/ty/sty.rs | 10 ++++ tests/ui/async-await/pin-reborrow-self.rs | 3 +- .../feature-gate-pin_ergonomics.rs | 8 +++ .../feature-gate-pin_ergonomics.stderr | 47 ++++++++++++++++-- 6 files changed, 123 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/method/confirm.rs b/compiler/rustc_hir_typeck/src/method/confirm.rs index 0d11df11334..f955c62a443 100644 --- a/compiler/rustc_hir_typeck/src/method/confirm.rs +++ b/compiler/rustc_hir_typeck/src/method/confirm.rs @@ -239,10 +239,18 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { Some(probe::AutorefOrPtrAdjustment::ReborrowPin(mutbl)) => { let region = self.next_region_var(infer::Autoref(self.span)); - adjustments.push(Adjustment { - kind: Adjust::ReborrowPin(region, mutbl), - target, - }); + target = match target.kind() { + ty::Adt(pin, args) if self.tcx.is_lang_item(pin.did(), hir::LangItem::Pin) => { + let inner_ty = match args[0].expect_ty().kind() { + ty::Ref(_, ty, _) => *ty, + _ => bug!("Expected a reference type for argument to Pin"), + }; + Ty::new_pinned_ref(self.tcx, region, inner_ty, mutbl) + } + _ => bug!("Cannot adjust receiver type for reborrowing pin of {target:?}"), + }; + + adjustments.push(Adjustment { kind: Adjust::ReborrowPin(region, mutbl), target }); } None => {} } diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index 43481c9704a..86584860b79 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -1113,6 +1113,13 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { unstable_candidates.as_deref_mut(), ) }) + .or_else(|| { + self.pick_reborrow_pin_method( + step, + self_ty, + unstable_candidates.as_deref_mut(), + ) + }) }) }) } @@ -1147,7 +1154,10 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { }) } - ty::Adt(def, args) if self.tcx.is_lang_item(def.did(), hir::LangItem::Pin) => { + ty::Adt(def, args) + if self.tcx.features().pin_ergonomics + && self.tcx.is_lang_item(def.did(), hir::LangItem::Pin) => + { // make sure this is a pinned reference (and not a `Pin` or something) if let ty::Ref(_, _, mutbl) = args[0].expect_ty().kind() { pick.autoref_or_ptr_adjustment = @@ -1186,6 +1196,43 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { }) } + /// Looks for applicable methods if we reborrow a `Pin<&mut T>` as a `Pin<&T>`. + #[instrument(level = "debug", skip(self, step, unstable_candidates))] + fn pick_reborrow_pin_method( + &self, + step: &CandidateStep<'tcx>, + self_ty: Ty<'tcx>, + unstable_candidates: Option<&mut Vec<(Candidate<'tcx>, Symbol)>>, + ) -> Option> { + if !self.tcx.features().pin_ergonomics { + return None; + } + + // make sure self is a Pin<&mut T> + let inner_ty = match self_ty.kind() { + ty::Adt(def, args) if self.tcx.is_lang_item(def.did(), hir::LangItem::Pin) => { + match args[0].expect_ty().kind() { + ty::Ref(_, ty, hir::Mutability::Mut) => *ty, + _ => { + return None; + } + } + } + _ => return None, + }; + + let region = self.tcx.lifetimes.re_erased; + let autopin_ty = Ty::new_pinned_ref(self.tcx, region, inner_ty, hir::Mutability::Not); + self.pick_method(autopin_ty, unstable_candidates).map(|r| { + r.map(|mut pick| { + pick.autoderefs = step.autoderefs; + pick.autoref_or_ptr_adjustment = + Some(AutorefOrPtrAdjustment::ReborrowPin(hir::Mutability::Not)); + pick + }) + }) + } + /// If `self_ty` is `*mut T` then this picks `*const T` methods. The reason why we have a /// special case for this is because going from `*mut T` to `*const T` with autoderefs and /// autorefs would require dereferencing the pointer, which is not safe. diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index db9978a7f53..fc4fb917283 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -584,6 +584,16 @@ impl<'tcx> Ty<'tcx> { Ty::new_ref(tcx, r, ty, hir::Mutability::Not) } + pub fn new_pinned_ref( + tcx: TyCtxt<'tcx>, + r: Region<'tcx>, + ty: Ty<'tcx>, + mutbl: ty::Mutability, + ) -> Ty<'tcx> { + let pin = tcx.adt_def(tcx.require_lang_item(LangItem::Pin, None)); + Ty::new_adt(tcx, pin, tcx.mk_args(&[Ty::new_ref(tcx, r, ty, mutbl).into()])) + } + #[inline] pub fn new_ptr(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, mutbl: ty::Mutability) -> Ty<'tcx> { Ty::new(tcx, ty::RawPtr(ty, mutbl)) diff --git a/tests/ui/async-await/pin-reborrow-self.rs b/tests/ui/async-await/pin-reborrow-self.rs index ab36ce575e1..ee617617da0 100644 --- a/tests/ui/async-await/pin-reborrow-self.rs +++ b/tests/ui/async-await/pin-reborrow-self.rs @@ -22,8 +22,7 @@ pub fn bar(x: Pin<&mut Foo>) { Foo::baz(x); - // FIXME: We should allow downgrading a Pin<&mut T> to Pin<&T> - // x.baz(); + x.baz(); } pub fn baaz(x: Pin<&Foo>) { diff --git a/tests/ui/feature-gates/feature-gate-pin_ergonomics.rs b/tests/ui/feature-gates/feature-gate-pin_ergonomics.rs index d694531d53a..d56a046fd62 100644 --- a/tests/ui/feature-gates/feature-gate-pin_ergonomics.rs +++ b/tests/ui/feature-gates/feature-gate-pin_ergonomics.rs @@ -4,12 +4,20 @@ use std::pin::Pin; struct Foo; +impl Foo { + fn foo(self: Pin<&mut Self>) { + } +} + fn foo(_: Pin<&mut Foo>) { } fn bar(mut x: Pin<&mut Foo>) { foo(x); foo(x); //~ ERROR use of moved value: `x` + + x.foo(); //~ ERROR use of moved value: `x` + x.foo(); //~ ERROR use of moved value: `x` } fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-pin_ergonomics.stderr b/tests/ui/feature-gates/feature-gate-pin_ergonomics.stderr index 6c9029d8176..bc49088f3d7 100644 --- a/tests/ui/feature-gates/feature-gate-pin_ergonomics.stderr +++ b/tests/ui/feature-gates/feature-gate-pin_ergonomics.stderr @@ -1,5 +1,5 @@ error[E0382]: use of moved value: `x` - --> $DIR/feature-gate-pin_ergonomics.rs:12:9 + --> $DIR/feature-gate-pin_ergonomics.rs:17:9 | LL | fn bar(mut x: Pin<&mut Foo>) { | ----- move occurs because `x` has type `Pin<&mut Foo>`, which does not implement the `Copy` trait @@ -9,13 +9,54 @@ LL | foo(x); | ^ value used here after move | note: consider changing this parameter type in function `foo` to borrow instead if owning the value isn't necessary - --> $DIR/feature-gate-pin_ergonomics.rs:7:11 + --> $DIR/feature-gate-pin_ergonomics.rs:12:11 | LL | fn foo(_: Pin<&mut Foo>) { | --- ^^^^^^^^^^^^^ this parameter takes ownership of the value | | | in this function -error: aborting due to 1 previous error +error[E0382]: use of moved value: `x` + --> $DIR/feature-gate-pin_ergonomics.rs:19:5 + | +LL | fn bar(mut x: Pin<&mut Foo>) { + | ----- move occurs because `x` has type `Pin<&mut Foo>`, which does not implement the `Copy` trait +LL | foo(x); +LL | foo(x); + | - value moved here +LL | +LL | x.foo(); + | ^ value used here after move + | +note: consider changing this parameter type in function `foo` to borrow instead if owning the value isn't necessary + --> $DIR/feature-gate-pin_ergonomics.rs:12:11 + | +LL | fn foo(_: Pin<&mut Foo>) { + | --- ^^^^^^^^^^^^^ this parameter takes ownership of the value + | | + | in this function + +error[E0382]: use of moved value: `x` + --> $DIR/feature-gate-pin_ergonomics.rs:20:5 + | +LL | fn bar(mut x: Pin<&mut Foo>) { + | ----- move occurs because `x` has type `Pin<&mut Foo>`, which does not implement the `Copy` trait +... +LL | x.foo(); + | ----- `x` moved due to this method call +LL | x.foo(); + | ^ value used here after move + | +note: `Foo::foo` takes ownership of the receiver `self`, which moves `x` + --> $DIR/feature-gate-pin_ergonomics.rs:8:12 + | +LL | fn foo(self: Pin<&mut Self>) { + | ^^^^ +help: consider reborrowing the `Pin` instead of moving it + | +LL | x.as_mut().foo(); + | +++++++++ + +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0382`. From 8cf861db3a396b56eaabdb928b88b933056ae2a1 Mon Sep 17 00:00:00 2001 From: Veera Date: Sun, 22 Sep 2024 21:43:46 -0400 Subject: [PATCH 198/683] Reorganize Test Headers --- .../ctfe-simple-loop.allow.stderr | 4 +- .../stable-metric/ctfe-simple-loop.rs | 3 +- .../ctfe-simple-loop.warn.stderr | 54 +++++++++---------- .../evade-deduplication-issue-118612.rs | 2 +- 4 files changed, 32 insertions(+), 31 deletions(-) diff --git a/tests/ui/consts/const-eval/stable-metric/ctfe-simple-loop.allow.stderr b/tests/ui/consts/const-eval/stable-metric/ctfe-simple-loop.allow.stderr index 30550f93ac1..7f6625bcfcd 100644 --- a/tests/ui/consts/const-eval/stable-metric/ctfe-simple-loop.allow.stderr +++ b/tests/ui/consts/const-eval/stable-metric/ctfe-simple-loop.allow.stderr @@ -1,5 +1,5 @@ warning: constant evaluation is taking a long time - --> $DIR/ctfe-simple-loop.rs:9:5 + --> $DIR/ctfe-simple-loop.rs:10:5 | LL | / while index < n { LL | | @@ -10,7 +10,7 @@ LL | | } | |_____^ the const evaluator is currently interpreting this expression | help: the constant being evaluated - --> $DIR/ctfe-simple-loop.rs:19:1 + --> $DIR/ctfe-simple-loop.rs:20:1 | LL | const Y: u32 = simple_loop(35); | ^^^^^^^^^^^^ diff --git a/tests/ui/consts/const-eval/stable-metric/ctfe-simple-loop.rs b/tests/ui/consts/const-eval/stable-metric/ctfe-simple-loop.rs index 42b93383c2b..7fa338f025a 100644 --- a/tests/ui/consts/const-eval/stable-metric/ctfe-simple-loop.rs +++ b/tests/ui/consts/const-eval/stable-metric/ctfe-simple-loop.rs @@ -1,9 +1,10 @@ //@ check-pass //@ revisions: warn allow +//@ compile-flags: -Z tiny-const-eval-limit + #![cfg_attr(warn, warn(long_running_const_eval))] #![cfg_attr(allow, allow(long_running_const_eval))] -//@ compile-flags: -Z tiny-const-eval-limit const fn simple_loop(n: u32) -> u32 { let mut index = 0; while index < n { diff --git a/tests/ui/consts/const-eval/stable-metric/ctfe-simple-loop.warn.stderr b/tests/ui/consts/const-eval/stable-metric/ctfe-simple-loop.warn.stderr index 40fc4a876e9..657f0e5bcba 100644 --- a/tests/ui/consts/const-eval/stable-metric/ctfe-simple-loop.warn.stderr +++ b/tests/ui/consts/const-eval/stable-metric/ctfe-simple-loop.warn.stderr @@ -1,29 +1,5 @@ warning: constant evaluation is taking a long time - --> $DIR/ctfe-simple-loop.rs:9:5 - | -LL | / while index < n { -LL | | -LL | | -LL | | -LL | | index = index + 1; -LL | | } - | |_____^ - | - = note: this lint makes sure the compiler doesn't get stuck due to infinite loops in const eval. - If your compilation actually takes a long time, you can safely allow the lint. -help: the constant being evaluated - --> $DIR/ctfe-simple-loop.rs:18:1 - | -LL | const X: u32 = simple_loop(19); - | ^^^^^^^^^^^^ -note: the lint level is defined here - --> $DIR/ctfe-simple-loop.rs:3:24 - | -LL | #![cfg_attr(warn, warn(long_running_const_eval))] - | ^^^^^^^^^^^^^^^^^^^^^^^ - -warning: constant evaluation is taking a long time - --> $DIR/ctfe-simple-loop.rs:9:5 + --> $DIR/ctfe-simple-loop.rs:10:5 | LL | / while index < n { LL | | @@ -38,11 +14,35 @@ LL | | } help: the constant being evaluated --> $DIR/ctfe-simple-loop.rs:19:1 | +LL | const X: u32 = simple_loop(19); + | ^^^^^^^^^^^^ +note: the lint level is defined here + --> $DIR/ctfe-simple-loop.rs:5:24 + | +LL | #![cfg_attr(warn, warn(long_running_const_eval))] + | ^^^^^^^^^^^^^^^^^^^^^^^ + +warning: constant evaluation is taking a long time + --> $DIR/ctfe-simple-loop.rs:10:5 + | +LL | / while index < n { +LL | | +LL | | +LL | | +LL | | index = index + 1; +LL | | } + | |_____^ + | + = note: this lint makes sure the compiler doesn't get stuck due to infinite loops in const eval. + If your compilation actually takes a long time, you can safely allow the lint. +help: the constant being evaluated + --> $DIR/ctfe-simple-loop.rs:20:1 + | LL | const Y: u32 = simple_loop(35); | ^^^^^^^^^^^^ warning: constant evaluation is taking a long time - --> $DIR/ctfe-simple-loop.rs:9:5 + --> $DIR/ctfe-simple-loop.rs:10:5 | LL | / while index < n { LL | | @@ -53,7 +53,7 @@ LL | | } | |_____^ the const evaluator is currently interpreting this expression | help: the constant being evaluated - --> $DIR/ctfe-simple-loop.rs:19:1 + --> $DIR/ctfe-simple-loop.rs:20:1 | LL | const Y: u32 = simple_loop(35); | ^^^^^^^^^^^^ diff --git a/tests/ui/consts/const-eval/stable-metric/evade-deduplication-issue-118612.rs b/tests/ui/consts/const-eval/stable-metric/evade-deduplication-issue-118612.rs index a2d34eaa384..43b14bae56f 100644 --- a/tests/ui/consts/const-eval/stable-metric/evade-deduplication-issue-118612.rs +++ b/tests/ui/consts/const-eval/stable-metric/evade-deduplication-issue-118612.rs @@ -1,8 +1,8 @@ //@ check-pass +//@ compile-flags: -Z tiny-const-eval-limit -Z deduplicate-diagnostics=yes #![allow(long_running_const_eval)] -//@ compile-flags: -Z tiny-const-eval-limit -Z deduplicate-diagnostics=yes const FOO: () = { let mut i = 0; loop { From ba3b536e204df7108def541a86bbe5d7d599cfbb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20du=20Garreau?= Date: Wed, 22 May 2024 11:37:02 +0200 Subject: [PATCH 199/683] Fix `io::Take::read_buf` --- library/std/src/io/mod.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index 0b57d01f273..98e7b40bdc6 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -2941,7 +2941,7 @@ impl Read for Take { } let mut cursor = sliced_buf.unfilled(); - self.inner.read_buf(cursor.reborrow())?; + let result = self.inner.read_buf(cursor.reborrow()); let new_init = cursor.init_ref().len(); let filled = sliced_buf.len(); @@ -2956,13 +2956,14 @@ impl Read for Take { } self.limit -= filled as u64; + + result } else { let written = buf.written(); - self.inner.read_buf(buf.reborrow())?; + let result = self.inner.read_buf(buf.reborrow()); self.limit -= (buf.written() - written) as u64; + result } - - Ok(()) } } From 04710e27d260b82865b3d4949e2e84b59c35ed66 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20du=20Garreau?= Date: Wed, 22 May 2024 11:41:19 +0200 Subject: [PATCH 200/683] Fix `io::BufReader` uses of `read_buf` --- library/std/src/io/buffered/bufreader.rs | 2 +- library/std/src/io/buffered/bufreader/buffer.rs | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/library/std/src/io/buffered/bufreader.rs b/library/std/src/io/buffered/bufreader.rs index e51dde994de..438df70505b 100644 --- a/library/std/src/io/buffered/bufreader.rs +++ b/library/std/src/io/buffered/bufreader.rs @@ -349,7 +349,7 @@ impl Read for BufReader { let prev = cursor.written(); let mut rem = self.fill_buf()?; - rem.read_buf(cursor.reborrow())?; + rem.read_buf(cursor.reborrow())?; // actually never fails self.consume(cursor.written() - prev); //slice impl of read_buf known to never unfill buf diff --git a/library/std/src/io/buffered/bufreader/buffer.rs b/library/std/src/io/buffered/bufreader/buffer.rs index 1bf84d8bef3..68b024bb98a 100644 --- a/library/std/src/io/buffered/bufreader/buffer.rs +++ b/library/std/src/io/buffered/bufreader/buffer.rs @@ -133,11 +133,13 @@ impl Buffer { buf.set_init(self.initialized); } - reader.read_buf(buf.unfilled())?; + let result = reader.read_buf(buf.unfilled()); self.pos = 0; self.filled = buf.len(); self.initialized = buf.init_len(); + + result?; } Ok(self.buffer()) } From bf768886d1c040d323165999cd0aeb6c86e2a71b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20du=20Garreau?= Date: Wed, 22 May 2024 11:47:58 +0200 Subject: [PATCH 201/683] Fix `io::default_read_to_end` uses of `read_buf` --- library/std/src/io/mod.rs | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index 98e7b40bdc6..954062a489c 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -474,18 +474,28 @@ pub(crate) fn default_read_to_end( } let mut cursor = read_buf.unfilled(); - loop { + let result = loop { match r.read_buf(cursor.reborrow()) { - Ok(()) => break, Err(e) if e.is_interrupted() => continue, - Err(e) => return Err(e), + // Do not stop now in case of error: we might have received both data + // and an error + res => break res, } - } + }; let unfilled_but_initialized = cursor.init_ref().len(); let bytes_read = cursor.written(); let was_fully_initialized = read_buf.init_len() == buf_len; + // SAFETY: BorrowedBuf's invariants mean this much memory is initialized. + unsafe { + let new_len = bytes_read + buf.len(); + buf.set_len(new_len); + } + + // Now that all data is pushed to the vector, we can fail without data loss + result?; + if bytes_read == 0 { return Ok(buf.len() - start_len); } @@ -499,12 +509,6 @@ pub(crate) fn default_read_to_end( // store how much was initialized but not filled initialized = unfilled_but_initialized; - // SAFETY: BorrowedBuf's invariants mean this much memory is initialized. - unsafe { - let new_len = bytes_read + buf.len(); - buf.set_len(new_len); - } - // Use heuristics to determine the max read size if no initial size hint was provided if size_hint.is_none() { // The reader is returning short reads but it doesn't call ensure_init(). From 4b8a66c908be909ab9d451565d3959ffea45357d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20du=20Garreau?= Date: Mon, 23 Sep 2024 17:38:18 +0200 Subject: [PATCH 202/683] Add tests --- library/std/src/io/tests.rs | 63 +++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/library/std/src/io/tests.rs b/library/std/src/io/tests.rs index f551dcd401e..56b71c47dc7 100644 --- a/library/std/src/io/tests.rs +++ b/library/std/src/io/tests.rs @@ -735,6 +735,69 @@ fn read_buf_full_read() { assert_eq!(BufReader::new(FullRead).fill_buf().unwrap().len(), DEFAULT_BUF_SIZE); } +struct DataAndErrorReader(&'static [u8]); + +impl Read for DataAndErrorReader { + fn read(&mut self, _buf: &mut [u8]) -> io::Result { + panic!("We want tests to use `read_buf`") + } + + fn read_buf(&mut self, buf: io::BorrowedCursor<'_>) -> io::Result<()> { + self.0.read_buf(buf).unwrap(); + Err(io::Error::other("error")) + } +} + +#[test] +fn read_buf_data_and_error_take() { + let mut buf = [0; 64]; + let mut buf = io::BorrowedBuf::from(buf.as_mut_slice()); + + let mut r = DataAndErrorReader(&[4, 5, 6]).take(1); + assert!(r.read_buf(buf.unfilled()).is_err()); + assert_eq!(buf.filled(), &[4]); + + assert!(r.read_buf(buf.unfilled()).is_ok()); + assert_eq!(buf.filled(), &[4]); + assert_eq!(r.get_ref().0, &[5, 6]); +} + +#[test] +fn read_buf_data_and_error_buf() { + let mut r = BufReader::new(DataAndErrorReader(&[4, 5, 6])); + + assert!(r.fill_buf().is_err()); + assert_eq!(r.fill_buf().unwrap(), &[4, 5, 6]); +} + +#[test] +fn read_buf_data_and_error_read_to_end() { + let mut r = DataAndErrorReader(&[4, 5, 6]); + + let mut v = Vec::with_capacity(200); + assert!(r.read_to_end(&mut v).is_err()); + + assert_eq!(v, &[4, 5, 6]); +} + +#[test] +fn read_to_end_error() { + struct ErrorReader; + + impl Read for ErrorReader { + fn read(&mut self, _buf: &mut [u8]) -> io::Result { + Err(io::Error::other("error")) + } + } + + let mut r = [4, 5, 6].chain(ErrorReader); + + let mut v = Vec::with_capacity(200); + assert!(r.read_to_end(&mut v).is_err()); + + assert_eq!(v, &[4, 5, 6]); +} + #[test] // Miri does not support signalling OOM #[cfg_attr(miri, ignore)] From d77664bed945fbbd5ab102f59a38b1ef0e728b10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20du=20Garreau?= Date: Mon, 23 Sep 2024 17:40:04 +0200 Subject: [PATCH 203/683] Add a comment to `Read::read_buf` --- library/std/src/io/mod.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index 954062a489c..dd6458c38c6 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -978,6 +978,8 @@ pub trait Read { /// with uninitialized buffers. The new data will be appended to any existing contents of `buf`. /// /// The default implementation delegates to `read`. + /// + /// This method makes it possible to return both data and an error but it is advised against. #[unstable(feature = "read_buf", issue = "78485")] fn read_buf(&mut self, buf: BorrowedCursor<'_>) -> Result<()> { default_read_buf(|b| self.read(b), buf) From f7b940ae7c6fbf81e78056999bcdfedf84aad503 Mon Sep 17 00:00:00 2001 From: Trivikram Kamat <16024985+trivikr@users.noreply.github.com> Date: Mon, 23 Sep 2024 22:08:54 -0700 Subject: [PATCH 204/683] Update actions/setup-node to v4 --- .github/workflows/remark.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/remark.yml b/.github/workflows/remark.yml index 348d52020fd..a1b011dc32d 100644 --- a/.github/workflows/remark.yml +++ b/.github/workflows/remark.yml @@ -19,7 +19,7 @@ jobs: uses: actions/checkout@v4 - name: Setup Node.js - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: '18.x' From 3a108a75f70211c8d6c677de79fa293a4e790aa7 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 24 Sep 2024 08:53:10 +0200 Subject: [PATCH 205/683] looks like we need more permissions --- src/tools/miri/.github/workflows/ci.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/tools/miri/.github/workflows/ci.yml b/src/tools/miri/.github/workflows/ci.yml index 6e4815c0b91..7d8c7203b32 100644 --- a/src/tools/miri/.github/workflows/ci.yml +++ b/src/tools/miri/.github/workflows/ci.yml @@ -13,7 +13,9 @@ on: - cron: '44 4 * * *' # At 4:44 UTC every day. permissions: - contents: read + # The cronjob needs to be able to push to the repo... + contents: write + # ... and create a PR. pull-requests: write defaults: From 24f622cf801a840b0ad879ce5907f2cf316e26e8 Mon Sep 17 00:00:00 2001 From: Huang Qi Date: Thu, 19 Sep 2024 16:00:56 +0800 Subject: [PATCH 206/683] Initial std library support for NuttX Signed-off-by: Huang Qi --- library/panic_unwind/src/lib.rs | 2 +- library/std/build.rs | 1 + library/std/src/os/mod.rs | 2 + library/std/src/os/nuttx/fs.rs | 92 +++++++++++++++++++++ library/std/src/os/nuttx/mod.rs | 4 + library/std/src/os/nuttx/raw.rs | 33 ++++++++ library/std/src/os/unix/mod.rs | 2 + library/std/src/sys/pal/unix/args.rs | 1 + library/std/src/sys/pal/unix/env.rs | 11 +++ library/std/src/sys/pal/unix/fd.rs | 42 ++++++++-- library/std/src/sys/pal/unix/fs.rs | 19 ++++- library/std/src/sys/pal/unix/mod.rs | 3 +- library/std/src/sys/pal/unix/net.rs | 6 +- library/std/src/sys/pal/unix/os.rs | 4 + library/std/src/sys/pal/unix/process/mod.rs | 6 +- library/std/src/sys/pal/unix/thread.rs | 14 +++- library/std/src/sys/personality/mod.rs | 2 +- library/std/src/sys/random/mod.rs | 1 + library/std/src/sys_common/net.rs | 1 + library/unwind/src/lib.rs | 1 + 20 files changed, 225 insertions(+), 22 deletions(-) create mode 100644 library/std/src/os/nuttx/fs.rs create mode 100644 library/std/src/os/nuttx/mod.rs create mode 100644 library/std/src/os/nuttx/raw.rs diff --git a/library/panic_unwind/src/lib.rs b/library/panic_unwind/src/lib.rs index 4552fb68d26..6cd4dffb8aa 100644 --- a/library/panic_unwind/src/lib.rs +++ b/library/panic_unwind/src/lib.rs @@ -48,7 +48,7 @@ cfg_if::cfg_if! { target_os = "psp", target_os = "xous", target_os = "solid_asp3", - all(target_family = "unix", not(any(target_os = "espidf", target_os = "rtems"))), + all(target_family = "unix", not(any(target_os = "espidf", target_os = "rtems", target_os = "nuttx"))), all(target_vendor = "fortanix", target_env = "sgx"), target_family = "wasm", ))] { diff --git a/library/std/build.rs b/library/std/build.rs index ba1eece46f3..359ae4f20ee 100644 --- a/library/std/build.rs +++ b/library/std/build.rs @@ -54,6 +54,7 @@ fn main() { || target_os == "teeos" || target_os == "zkvm" || target_os == "rtems" + || target_os == "nuttx" // See src/bootstrap/src/core/build_steps/synthetic_targets.rs || env::var("RUSTC_BOOTSTRAP_SYNTHETIC_TARGET").is_ok() diff --git a/library/std/src/os/mod.rs b/library/std/src/os/mod.rs index a2496baa63f..6701173d1e0 100644 --- a/library/std/src/os/mod.rs +++ b/library/std/src/os/mod.rs @@ -139,6 +139,8 @@ pub mod macos; pub mod netbsd; #[cfg(target_os = "nto")] pub mod nto; +#[cfg(target_os = "nuttx")] +pub mod nuttx; #[cfg(target_os = "openbsd")] pub mod openbsd; #[cfg(target_os = "redox")] diff --git a/library/std/src/os/nuttx/fs.rs b/library/std/src/os/nuttx/fs.rs new file mode 100644 index 00000000000..7d6d8d16eca --- /dev/null +++ b/library/std/src/os/nuttx/fs.rs @@ -0,0 +1,92 @@ +#![stable(feature = "metadata_ext", since = "1.1.0")] + +use crate::fs::Metadata; +use crate::sys_common::AsInner; + +#[stable(feature = "metadata_ext", since = "1.1.0")] +pub trait MetadataExt { + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_dev(&self) -> u64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_ino(&self) -> u64; + #[stable(feature = "metadata_ext", since = "1.1.0")] + fn st_mode(&self) -> u32; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_nlink(&self) -> u64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_uid(&self) -> u32; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_gid(&self) -> u32; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_rdev(&self) -> u64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_size(&self) -> u64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_atime(&self) -> i64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_atime_nsec(&self) -> i64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_mtime(&self) -> i64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_mtime_nsec(&self) -> i64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_ctime(&self) -> i64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_ctime_nsec(&self) -> i64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_blksize(&self) -> u64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_blocks(&self) -> u64; +} + +#[stable(feature = "metadata_ext", since = "1.1.0")] +impl MetadataExt for Metadata { + fn st_dev(&self) -> u64 { + self.as_inner().as_inner().st_dev as u64 + } + fn st_ino(&self) -> u64 { + self.as_inner().as_inner().st_ino as u64 + } + fn st_mode(&self) -> u32 { + self.as_inner().as_inner().st_mode as u32 + } + fn st_nlink(&self) -> u64 { + self.as_inner().as_inner().st_nlink as u64 + } + fn st_uid(&self) -> u32 { + self.as_inner().as_inner().st_uid as u32 + } + fn st_gid(&self) -> u32 { + self.as_inner().as_inner().st_gid as u32 + } + fn st_rdev(&self) -> u64 { + self.as_inner().as_inner().st_rdev as u64 + } + fn st_size(&self) -> u64 { + self.as_inner().as_inner().st_size as u64 + } + fn st_atime(&self) -> i64 { + self.as_inner().as_inner().st_atim.tv_sec as i64 + } + fn st_atime_nsec(&self) -> i64 { + self.as_inner().as_inner().st_atim.tv_nsec as i64 + } + fn st_mtime(&self) -> i64 { + self.as_inner().as_inner().st_mtim.tv_sec as i64 + } + fn st_mtime_nsec(&self) -> i64 { + self.as_inner().as_inner().st_mtim.tv_nsec as i64 + } + fn st_ctime(&self) -> i64 { + self.as_inner().as_inner().st_ctim.tv_sec as i64 + } + fn st_ctime_nsec(&self) -> i64 { + self.as_inner().as_inner().st_ctim.tv_nsec as i64 + } + fn st_blksize(&self) -> u64 { + self.as_inner().as_inner().st_blksize as u64 + } + fn st_blocks(&self) -> u64 { + self.as_inner().as_inner().st_blocks as u64 + } +} diff --git a/library/std/src/os/nuttx/mod.rs b/library/std/src/os/nuttx/mod.rs new file mode 100644 index 00000000000..7275bfd1765 --- /dev/null +++ b/library/std/src/os/nuttx/mod.rs @@ -0,0 +1,4 @@ +#![stable(feature = "raw_ext", since = "1.1.0")] +#![forbid(unsafe_op_in_unsafe_fn)] +pub mod fs; +pub(crate) mod raw; diff --git a/library/std/src/os/nuttx/raw.rs b/library/std/src/os/nuttx/raw.rs new file mode 100644 index 00000000000..113079cf4ab --- /dev/null +++ b/library/std/src/os/nuttx/raw.rs @@ -0,0 +1,33 @@ +//! rtems raw type definitions + +#![stable(feature = "raw_ext", since = "1.1.0")] +#![deprecated( + since = "1.8.0", + note = "these type aliases are no longer supported by \ + the standard library, the `libc` crate on \ + crates.io should be used instead for the correct \ + definitions" +)] +#![allow(deprecated)] + +#[stable(feature = "pthread_t", since = "1.8.0")] +pub type pthread_t = libc::pthread_t; + +#[stable(feature = "raw_ext", since = "1.1.0")] +pub type blkcnt_t = libc::blkcnt_t; + +#[stable(feature = "raw_ext", since = "1.1.0")] +pub type blksize_t = libc::blksize_t; +#[stable(feature = "raw_ext", since = "1.1.0")] +pub type dev_t = libc::dev_t; +#[stable(feature = "raw_ext", since = "1.1.0")] +pub type ino_t = libc::ino_t; +#[stable(feature = "raw_ext", since = "1.1.0")] +pub type mode_t = libc::mode_t; +#[stable(feature = "raw_ext", since = "1.1.0")] +pub type nlink_t = libc::nlink_t; +#[stable(feature = "raw_ext", since = "1.1.0")] +pub type off_t = libc::off_t; + +#[stable(feature = "raw_ext", since = "1.1.0")] +pub type time_t = libc::time_t; diff --git a/library/std/src/os/unix/mod.rs b/library/std/src/os/unix/mod.rs index 7d2f0bd4efe..5c2ec8ef994 100644 --- a/library/std/src/os/unix/mod.rs +++ b/library/std/src/os/unix/mod.rs @@ -69,6 +69,8 @@ mod platform { pub use crate::os::netbsd::*; #[cfg(target_os = "nto")] pub use crate::os::nto::*; + #[cfg(target_os = "nuttx")] + pub use crate::os::nuttx::*; #[cfg(target_os = "openbsd")] pub use crate::os::openbsd::*; #[cfg(target_os = "redox")] diff --git a/library/std/src/sys/pal/unix/args.rs b/library/std/src/sys/pal/unix/args.rs index a943e3a581a..8438a61e90f 100644 --- a/library/std/src/sys/pal/unix/args.rs +++ b/library/std/src/sys/pal/unix/args.rs @@ -113,6 +113,7 @@ impl DoubleEndedIterator for Args { target_os = "nto", target_os = "hurd", target_os = "rtems", + target_os = "nuttx", ))] mod imp { use crate::ffi::c_char; diff --git a/library/std/src/sys/pal/unix/env.rs b/library/std/src/sys/pal/unix/env.rs index b2d399b8791..2aee0b5d460 100644 --- a/library/std/src/sys/pal/unix/env.rs +++ b/library/std/src/sys/pal/unix/env.rs @@ -283,3 +283,14 @@ pub mod os { pub const EXE_SUFFIX: &str = ""; pub const EXE_EXTENSION: &str = ""; } + +#[cfg(target_os = "nuttx")] +pub mod os { + pub const FAMILY: &str = "unix"; + pub const OS: &str = "nuttx"; + pub const DLL_PREFIX: &str = "lib"; + pub const DLL_SUFFIX: &str = ".so"; + pub const DLL_EXTENSION: &str = "so"; + pub const EXE_SUFFIX: &str = ""; + pub const EXE_EXTENSION: &str = ""; +} diff --git a/library/std/src/sys/pal/unix/fd.rs b/library/std/src/sys/pal/unix/fd.rs index 135042779ad..6a28799ca55 100644 --- a/library/std/src/sys/pal/unix/fd.rs +++ b/library/std/src/sys/pal/unix/fd.rs @@ -98,7 +98,12 @@ impl FileDesc { Ok(ret as usize) } - #[cfg(not(any(target_os = "espidf", target_os = "horizon", target_os = "vita")))] + #[cfg(not(any( + target_os = "espidf", + target_os = "horizon", + target_os = "vita", + target_os = "nuttx" + )))] pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { let ret = cvt(unsafe { libc::readv( @@ -110,14 +115,24 @@ impl FileDesc { Ok(ret as usize) } - #[cfg(any(target_os = "espidf", target_os = "horizon", target_os = "vita"))] + #[cfg(any( + target_os = "espidf", + target_os = "horizon", + target_os = "vita", + target_os = "nuttx" + ))] pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { io::default_read_vectored(|b| self.read(b), bufs) } #[inline] pub fn is_read_vectored(&self) -> bool { - cfg!(not(any(target_os = "espidf", target_os = "horizon", target_os = "vita"))) + cfg!(not(any( + target_os = "espidf", + target_os = "horizon", + target_os = "vita", + target_os = "nuttx" + ))) } pub fn read_to_end(&self, buf: &mut Vec) -> io::Result { @@ -297,7 +312,12 @@ impl FileDesc { Ok(ret as usize) } - #[cfg(not(any(target_os = "espidf", target_os = "horizon", target_os = "vita")))] + #[cfg(not(any( + target_os = "espidf", + target_os = "horizon", + target_os = "vita", + target_os = "nuttx" + )))] pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result { let ret = cvt(unsafe { libc::writev( @@ -309,14 +329,24 @@ impl FileDesc { Ok(ret as usize) } - #[cfg(any(target_os = "espidf", target_os = "horizon", target_os = "vita"))] + #[cfg(any( + target_os = "espidf", + target_os = "horizon", + target_os = "vita", + target_os = "nuttx" + ))] pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result { io::default_write_vectored(|b| self.write(b), bufs) } #[inline] pub fn is_write_vectored(&self) -> bool { - cfg!(not(any(target_os = "espidf", target_os = "horizon", target_os = "vita"))) + cfg!(not(any( + target_os = "espidf", + target_os = "horizon", + target_os = "vita", + target_os = "nuttx" + ))) } #[cfg_attr(target_os = "vxworks", allow(unused_unsafe))] diff --git a/library/std/src/sys/pal/unix/fs.rs b/library/std/src/sys/pal/unix/fs.rs index dade6d6bbae..86342c2add0 100644 --- a/library/std/src/sys/pal/unix/fs.rs +++ b/library/std/src/sys/pal/unix/fs.rs @@ -479,6 +479,7 @@ impl FileAttr { target_os = "vita", target_os = "hurd", target_os = "rtems", + target_os = "nuttx", )))] pub fn modified(&self) -> io::Result { #[cfg(target_pointer_width = "32")] @@ -501,7 +502,7 @@ impl FileAttr { SystemTime::new(self.stat.st_mtime as i64, 0) } - #[cfg(any(target_os = "horizon", target_os = "hurd"))] + #[cfg(any(target_os = "horizon", target_os = "hurd", target_os = "nuttx"))] pub fn modified(&self) -> io::Result { SystemTime::new(self.stat.st_mtim.tv_sec as i64, self.stat.st_mtim.tv_nsec as i64) } @@ -513,6 +514,7 @@ impl FileAttr { target_os = "vita", target_os = "hurd", target_os = "rtems", + target_os = "nuttx", )))] pub fn accessed(&self) -> io::Result { #[cfg(target_pointer_width = "32")] @@ -535,7 +537,7 @@ impl FileAttr { SystemTime::new(self.stat.st_atime as i64, 0) } - #[cfg(any(target_os = "horizon", target_os = "hurd"))] + #[cfg(any(target_os = "horizon", target_os = "hurd", target_os = "nuttx"))] pub fn accessed(&self) -> io::Result { SystemTime::new(self.stat.st_atim.tv_sec as i64, self.stat.st_atim.tv_nsec as i64) } @@ -866,6 +868,7 @@ impl Drop for Dir { target_os = "horizon", target_os = "vxworks", target_os = "rtems", + target_os = "nuttx", )))] { let fd = unsafe { libc::dirfd(self.0) }; @@ -1000,6 +1003,13 @@ impl DirEntry { self.entry.d_fileno as u64 } + #[cfg(target_os = "nuttx")] + pub fn ino(&self) -> u64 { + // Leave this 0 for now, as NuttX does not provide an inode number + // in its directory entries. + 0 + } + #[cfg(any( target_os = "netbsd", target_os = "openbsd", @@ -1327,7 +1337,8 @@ impl File { target_os = "redox", target_os = "espidf", target_os = "horizon", - target_os = "vxworks" + target_os = "vxworks", + target_os = "nuttx", )))] let to_timespec = |time: Option| match time { Some(time) if let Some(ts) = time.t.to_timespec() => Ok(ts), @@ -1342,7 +1353,7 @@ impl File { None => Ok(libc::timespec { tv_sec: 0, tv_nsec: libc::UTIME_OMIT as _ }), }; cfg_if::cfg_if! { - if #[cfg(any(target_os = "redox", target_os = "espidf", target_os = "horizon", target_os = "vxworks"))] { + if #[cfg(any(target_os = "redox", target_os = "espidf", target_os = "horizon", target_os = "vxworks", target_os = "nuttx"))] { // Redox doesn't appear to support `UTIME_OMIT`. // ESP-IDF and HorizonOS do not support `futimens` at all and the behavior for those OS is therefore // the same as for Redox. diff --git a/library/std/src/sys/pal/unix/mod.rs b/library/std/src/sys/pal/unix/mod.rs index 1c9159e5fba..11c6f54d43b 100644 --- a/library/std/src/sys/pal/unix/mod.rs +++ b/library/std/src/sys/pal/unix/mod.rs @@ -222,6 +222,7 @@ static ON_BROKEN_PIPE_FLAG_USED: crate::sync::atomic::AtomicBool = target_os = "horizon", target_os = "vxworks", target_os = "vita", + target_os = "nuttx", )))] pub(crate) fn on_broken_pipe_flag_used() -> bool { ON_BROKEN_PIPE_FLAG_USED.load(crate::sync::atomic::Ordering::Relaxed) @@ -424,7 +425,7 @@ cfg_if::cfg_if! { } } -#[cfg(any(target_os = "espidf", target_os = "horizon", target_os = "vita"))] +#[cfg(any(target_os = "espidf", target_os = "horizon", target_os = "vita", target_os = "nuttx"))] mod unsupported { use crate::io; diff --git a/library/std/src/sys/pal/unix/net.rs b/library/std/src/sys/pal/unix/net.rs index e98232ba89a..0f2e015bbcd 100644 --- a/library/std/src/sys/pal/unix/net.rs +++ b/library/std/src/sys/pal/unix/net.rs @@ -38,19 +38,19 @@ pub fn cvt_gai(err: c_int) -> io::Result<()> { // We may need to trigger a glibc workaround. See on_resolver_failure() for details. on_resolver_failure(); - #[cfg(not(target_os = "espidf"))] + #[cfg(not(any(target_os = "espidf", target_os = "nuttx")))] if err == libc::EAI_SYSTEM { return Err(io::Error::last_os_error()); } - #[cfg(not(target_os = "espidf"))] + #[cfg(not(any(target_os = "espidf", target_os = "nuttx")))] let detail = unsafe { // We can't always expect a UTF-8 environment. When we don't get that luxury, // it's better to give a low-quality error message than none at all. CStr::from_ptr(libc::gai_strerror(err)).to_string_lossy() }; - #[cfg(target_os = "espidf")] + #[cfg(any(target_os = "espidf", target_os = "nuttx"))] let detail = ""; Err(io::Error::new( diff --git a/library/std/src/sys/pal/unix/os.rs b/library/std/src/sys/pal/unix/os.rs index 503f8915256..d99bde2f9a5 100644 --- a/library/std/src/sys/pal/unix/os.rs +++ b/library/std/src/sys/pal/unix/os.rs @@ -48,6 +48,7 @@ extern "C" { target_os = "openbsd", target_os = "android", target_os = "redox", + target_os = "nuttx", target_env = "newlib" ), link_name = "__errno" @@ -399,6 +400,7 @@ pub fn current_exe() -> io::Result { target_os = "linux", target_os = "hurd", target_os = "android", + target_os = "nuttx", target_os = "emscripten" ))] pub fn current_exe() -> io::Result { @@ -717,6 +719,7 @@ pub fn home_dir() -> Option { target_os = "espidf", target_os = "horizon", target_os = "vita", + target_os = "nuttx", all(target_vendor = "apple", not(target_os = "macos")), ))] unsafe fn fallback() -> Option { @@ -730,6 +733,7 @@ pub fn home_dir() -> Option { target_os = "espidf", target_os = "horizon", target_os = "vita", + target_os = "nuttx", all(target_vendor = "apple", not(target_os = "macos")), )))] unsafe fn fallback() -> Option { diff --git a/library/std/src/sys/pal/unix/process/mod.rs b/library/std/src/sys/pal/unix/process/mod.rs index 074f0a105e3..2751d51c44d 100644 --- a/library/std/src/sys/pal/unix/process/mod.rs +++ b/library/std/src/sys/pal/unix/process/mod.rs @@ -2,10 +2,10 @@ pub use self::process_common::{Command, CommandArgs, ExitCode, Stdio, StdioPipes pub use self::process_inner::{ExitStatus, ExitStatusError, Process}; pub use crate::ffi::OsString as EnvKey; -#[cfg_attr(any(target_os = "espidf", target_os = "horizon"), allow(unused))] +#[cfg_attr(any(target_os = "espidf", target_os = "horizon", target_os = "nuttx"), allow(unused))] mod process_common; -#[cfg(any(target_os = "espidf", target_os = "horizon", target_os = "vita"))] +#[cfg(any(target_os = "espidf", target_os = "horizon", target_os = "vita", target_os = "nuttx"))] mod process_unsupported; cfg_if::cfg_if! { @@ -16,7 +16,7 @@ cfg_if::cfg_if! { } else if #[cfg(target_os = "vxworks")] { #[path = "process_vxworks.rs"] mod process_inner; - } else if #[cfg(any(target_os = "espidf", target_os = "horizon", target_os = "vita"))] { + } else if #[cfg(any(target_os = "espidf", target_os = "horizon", target_os = "vita", target_os = "nuttx"))] { mod process_inner { pub use super::process_unsupported::*; } diff --git a/library/std/src/sys/pal/unix/thread.rs b/library/std/src/sys/pal/unix/thread.rs index 7fe9b6c3e52..a0cf3b32103 100644 --- a/library/std/src/sys/pal/unix/thread.rs +++ b/library/std/src/sys/pal/unix/thread.rs @@ -140,7 +140,12 @@ impl Thread { } } - #[cfg(any(target_os = "freebsd", target_os = "dragonfly", target_os = "openbsd"))] + #[cfg(any( + target_os = "freebsd", + target_os = "dragonfly", + target_os = "openbsd", + target_os = "nuttx" + ))] pub fn set_name(name: &CStr) { unsafe { libc::pthread_set_name_np(libc::pthread_self(), name.as_ptr()); @@ -747,12 +752,15 @@ unsafe fn min_stack_size(attr: *const libc::pthread_attr_t) -> usize { } // No point in looking up __pthread_get_minstack() on non-glibc platforms. -#[cfg(all(not(all(target_os = "linux", target_env = "gnu")), not(target_os = "netbsd")))] +#[cfg(all( + not(all(target_os = "linux", target_env = "gnu")), + not(any(target_os = "netbsd", target_os = "nuttx")) +))] unsafe fn min_stack_size(_: *const libc::pthread_attr_t) -> usize { libc::PTHREAD_STACK_MIN } -#[cfg(target_os = "netbsd")] +#[cfg(any(target_os = "netbsd", target_os = "nuttx"))] unsafe fn min_stack_size(_: *const libc::pthread_attr_t) -> usize { static STACK: crate::sync::OnceLock = crate::sync::OnceLock::new(); diff --git a/library/std/src/sys/personality/mod.rs b/library/std/src/sys/personality/mod.rs index 68085d026c4..9754e840d15 100644 --- a/library/std/src/sys/personality/mod.rs +++ b/library/std/src/sys/personality/mod.rs @@ -31,7 +31,7 @@ cfg_if::cfg_if! { target_os = "psp", target_os = "xous", target_os = "solid_asp3", - all(target_family = "unix", not(target_os = "espidf"), not(target_os = "l4re"), not(target_os = "rtems")), + all(target_family = "unix", not(target_os = "espidf"), not(target_os = "l4re"), not(target_os = "rtems"), not(target_os = "nuttx")), all(target_vendor = "fortanix", target_env = "sgx"), ))] { mod gcc; diff --git a/library/std/src/sys/random/mod.rs b/library/std/src/sys/random/mod.rs index 16fb8c64c9b..d625814d15b 100644 --- a/library/std/src/sys/random/mod.rs +++ b/library/std/src/sys/random/mod.rs @@ -42,6 +42,7 @@ cfg_if::cfg_if! { target_os = "hurd", target_os = "l4re", target_os = "nto", + target_os = "nuttx", ))] { mod unix_legacy; pub use unix_legacy::fill_bytes; diff --git a/library/std/src/sys_common/net.rs b/library/std/src/sys_common/net.rs index 85a82b088cd..57f07d05cae 100644 --- a/library/std/src/sys_common/net.rs +++ b/library/std/src/sys_common/net.rs @@ -21,6 +21,7 @@ cfg_if::cfg_if! { target_os = "haiku", target_os = "l4re", target_os = "nto", + target_os = "nuttx", target_vendor = "apple", ))] { use crate::sys::net::netc::IPV6_JOIN_GROUP as IPV6_ADD_MEMBERSHIP; diff --git a/library/unwind/src/lib.rs b/library/unwind/src/lib.rs index 26ed00bfbd5..46026324d2f 100644 --- a/library/unwind/src/lib.rs +++ b/library/unwind/src/lib.rs @@ -23,6 +23,7 @@ cfg_if::cfg_if! { target_os = "none", target_os = "espidf", target_os = "rtems", + target_os = "nuttx", ))] { // These "unix" family members do not have unwinder. } else if #[cfg(any( From 8885ae9b253bc44e0a35359855381a2248361e06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Tue, 24 Sep 2024 09:21:41 +0200 Subject: [PATCH 207/683] Scope CI permissions to the job that needs it --- src/tools/miri/.github/workflows/ci.yml | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/tools/miri/.github/workflows/ci.yml b/src/tools/miri/.github/workflows/ci.yml index 7d8c7203b32..8b0916f5111 100644 --- a/src/tools/miri/.github/workflows/ci.yml +++ b/src/tools/miri/.github/workflows/ci.yml @@ -12,12 +12,6 @@ on: schedule: - cron: '44 4 * * *' # At 4:44 UTC every day. -permissions: - # The cronjob needs to be able to push to the repo... - contents: write - # ... and create a PR. - pull-requests: write - defaults: run: shell: bash @@ -93,6 +87,11 @@ jobs: cron-fail-notify: name: cronjob failure notification runs-on: ubuntu-latest + permissions: + # The cronjob needs to be able to push to the repo... + contents: write + # ... and create a PR. + pull-requests: write needs: [build, style] if: github.event_name == 'schedule' && failure() steps: From b61fcbee76f8e862c1de7523058e7e8a8b4ed4ef Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Tue, 24 Sep 2024 11:58:04 +0200 Subject: [PATCH 208/683] Merge commit '7901289135257ca0fbed3a5522526f95b0f5edba' into clippy-subtree-update --- .github/deploy.sh | 9 +- .github/workflows/clippy_bors.yml | 4 +- CHANGELOG.md | 65 +++- Cargo.toml | 11 +- book/src/lint_configuration.md | 1 + clippy_config/Cargo.toml | 2 +- clippy_config/src/conf.rs | 5 +- clippy_config/src/lib.rs | 2 +- clippy_config/src/msrvs.rs | 6 +- clippy_config/src/types.rs | 2 +- clippy_dev/src/fmt.rs | 2 +- clippy_dev/src/new_lint.rs | 2 +- clippy_dev/src/serve.rs | 3 +- clippy_dev/src/update_lints.rs | 30 +- clippy_lints/Cargo.toml | 2 +- clippy_lints/src/absolute_paths.rs | 4 +- clippy_lints/src/almost_complete_range.rs | 2 +- clippy_lints/src/approx_const.rs | 4 +- clippy_lints/src/arc_with_non_send_sync.rs | 2 +- clippy_lints/src/assertions_on_constants.rs | 2 +- .../src/assertions_on_result_states.rs | 2 +- clippy_lints/src/assigning_clones.rs | 4 +- .../attrs/allow_attributes_without_reason.rs | 4 +- .../attrs/blanket_clippy_restriction_lints.rs | 4 +- clippy_lints/src/attrs/deprecated_cfg_attr.rs | 2 +- .../src/attrs/duplicated_attributes.rs | 4 +- clippy_lints/src/attrs/empty_line_after.rs | 52 --- clippy_lints/src/attrs/inline_always.rs | 4 +- clippy_lints/src/attrs/mod.rs | 97 +---- clippy_lints/src/attrs/useless_attribute.rs | 3 +- clippy_lints/src/await_holding_invalid.rs | 2 +- clippy_lints/src/booleans.rs | 4 +- clippy_lints/src/box_default.rs | 2 +- clippy_lints/src/byte_char_slices.rs | 2 +- .../src/cargo/lint_groups_priority.rs | 2 +- clippy_lints/src/casts/cast_lossless.rs | 2 +- .../src/casts/cast_possible_truncation.rs | 2 +- clippy_lints/src/casts/cast_possible_wrap.rs | 2 +- clippy_lints/src/casts/cast_precision_loss.rs | 2 +- clippy_lints/src/casts/cast_sign_loss.rs | 2 +- clippy_lints/src/casts/fn_to_numeric_cast.rs | 2 +- .../fn_to_numeric_cast_with_truncation.rs | 2 +- clippy_lints/src/casts/mod.rs | 13 +- clippy_lints/src/casts/ptr_cast_constness.rs | 79 +++- clippy_lints/src/casts/ref_as_ptr.rs | 2 +- clippy_lints/src/casts/unnecessary_cast.rs | 4 +- clippy_lints/src/casts/utils.rs | 2 +- clippy_lints/src/cfg_not_test.rs | 2 +- clippy_lints/src/checked_conversions.rs | 4 +- clippy_lints/src/cognitive_complexity.rs | 4 +- clippy_lints/src/collection_is_never_read.rs | 2 +- clippy_lints/src/comparison_chain.rs | 2 +- clippy_lints/src/copies.rs | 11 +- clippy_lints/src/crate_in_macro_def.rs | 2 +- clippy_lints/src/dbg_macro.rs | 4 +- clippy_lints/src/declared_lints.rs | 13 +- clippy_lints/src/default.rs | 2 +- .../src/default_constructed_unit_structs.rs | 2 +- .../src/default_instead_of_iter_empty.rs | 4 +- clippy_lints/src/default_numeric_fallback.rs | 2 +- clippy_lints/src/dereference.rs | 73 ++-- clippy_lints/src/derivable_impls.rs | 2 +- clippy_lints/src/derive.rs | 4 +- clippy_lints/src/doc/empty_line_after.rs | 342 ++++++++++++++++ clippy_lints/src/doc/lazy_continuation.rs | 24 -- clippy_lints/src/doc/link_with_quotes.rs | 2 +- clippy_lints/src/doc/missing_headers.rs | 2 +- clippy_lints/src/doc/mod.rs | 93 ++++- clippy_lints/src/doc/needless_doctest_main.rs | 2 +- .../src/doc/suspicious_doc_comments.rs | 6 +- .../src/doc/too_long_first_doc_paragraph.rs | 9 +- clippy_lints/src/entry.rs | 8 +- clippy_lints/src/enum_clike.rs | 2 +- clippy_lints/src/escape.rs | 4 +- clippy_lints/src/excessive_bools.rs | 2 +- clippy_lints/src/excessive_nesting.rs | 2 +- clippy_lints/src/explicit_write.rs | 4 +- .../src/extra_unused_type_parameters.rs | 4 +- clippy_lints/src/fallible_impl_from.rs | 2 +- .../src/field_scoped_visibility_modifiers.rs | 2 +- clippy_lints/src/floating_point_arithmetic.rs | 2 +- clippy_lints/src/format.rs | 6 +- clippy_lints/src/format_args.rs | 11 +- clippy_lints/src/format_impl.rs | 4 +- clippy_lints/src/format_push_string.rs | 2 +- clippy_lints/src/from_over_into.rs | 4 +- clippy_lints/src/from_str_radix_10.rs | 2 +- clippy_lints/src/functions/mod.rs | 2 +- clippy_lints/src/functions/must_use.rs | 2 +- .../src/functions/not_unsafe_ptr_arg_deref.rs | 2 +- .../src/functions/renamed_function_params.rs | 2 +- clippy_lints/src/functions/result.rs | 4 +- clippy_lints/src/future_not_send.rs | 2 +- clippy_lints/src/if_then_some_else_none.rs | 4 +- clippy_lints/src/implicit_hasher.rs | 6 +- clippy_lints/src/implicit_saturating_sub.rs | 365 ++++++++++++++---- clippy_lints/src/incompatible_msrv.rs | 4 +- clippy_lints/src/index_refutable_slice.rs | 6 +- clippy_lints/src/ineffective_open_options.rs | 2 +- clippy_lints/src/instant_subtraction.rs | 2 +- clippy_lints/src/item_name_repetitions.rs | 2 +- clippy_lints/src/items_after_test_module.rs | 2 +- .../src/iter_not_returning_iterator.rs | 2 +- clippy_lints/src/iter_over_hash_type.rs | 4 +- clippy_lints/src/large_enum_variant.rs | 2 +- clippy_lints/src/large_stack_arrays.rs | 2 +- clippy_lints/src/legacy_numeric_constants.rs | 4 +- clippy_lints/src/len_zero.rs | 19 +- clippy_lints/src/lib.rs | 19 +- clippy_lints/src/lifetimes.rs | 16 +- .../src/loops/explicit_counter_loop.rs | 2 +- clippy_lints/src/loops/infinite_loop.rs | 2 +- clippy_lints/src/loops/manual_find.rs | 2 +- clippy_lints/src/loops/manual_flatten.rs | 2 +- .../src/loops/manual_while_let_some.rs | 4 +- clippy_lints/src/loops/mod.rs | 18 +- clippy_lints/src/loops/needless_range_loop.rs | 6 +- clippy_lints/src/loops/never_loop.rs | 4 +- clippy_lints/src/loops/same_item_push.rs | 4 +- clippy_lints/src/loops/single_element_loop.rs | 4 +- clippy_lints/src/loops/utils.rs | 4 +- .../src/loops/while_immutable_condition.rs | 2 +- .../src/loops/while_let_on_iterator.rs | 4 +- clippy_lints/src/macro_metavars_in_unsafe.rs | 6 +- clippy_lints/src/macro_use.rs | 2 +- clippy_lints/src/manual_async_fn.rs | 4 +- clippy_lints/src/manual_bits.rs | 2 +- clippy_lints/src/manual_clamp.rs | 8 +- clippy_lints/src/manual_div_ceil.rs | 158 ++++++++ clippy_lints/src/manual_hash_one.rs | 2 +- clippy_lints/src/manual_is_ascii_check.rs | 6 +- clippy_lints/src/manual_is_power_of_two.rs | 142 +++++++ clippy_lints/src/manual_let_else.rs | 4 +- clippy_lints/src/manual_main_separator_str.rs | 2 +- clippy_lints/src/manual_non_exhaustive.rs | 186 ++++----- clippy_lints/src/manual_range_patterns.rs | 7 +- clippy_lints/src/manual_rem_euclid.rs | 2 +- clippy_lints/src/manual_retain.rs | 8 +- clippy_lints/src/manual_string_new.rs | 2 +- clippy_lints/src/manual_strip.rs | 6 +- clippy_lints/src/map_unit_fn.rs | 2 +- clippy_lints/src/matches/collapsible_match.rs | 4 +- clippy_lints/src/matches/manual_filter.rs | 4 +- clippy_lints/src/matches/manual_map.rs | 2 +- clippy_lints/src/matches/manual_unwrap_or.rs | 4 +- clippy_lints/src/matches/manual_utils.rs | 8 +- clippy_lints/src/matches/match_same_arms.rs | 2 +- .../src/matches/match_str_case_mismatch.rs | 4 +- clippy_lints/src/matches/mod.rs | 2 +- clippy_lints/src/matches/overlapping_arms.rs | 2 +- clippy_lints/src/matches/redundant_guards.rs | 4 +- .../src/matches/redundant_pattern_match.rs | 6 +- .../matches/significant_drop_in_scrutinee.rs | 2 +- clippy_lints/src/matches/single_match.rs | 31 +- clippy_lints/src/mem_replace.rs | 4 +- .../src/methods/bind_instead_of_map.rs | 2 +- ...se_sensitive_file_extension_comparisons.rs | 4 +- clippy_lints/src/methods/clear_with_drain.rs | 2 +- clippy_lints/src/methods/clone_on_copy.rs | 2 +- clippy_lints/src/methods/clone_on_ref_ptr.rs | 2 +- .../src/methods/cloned_instead_of_copied.rs | 2 +- .../src/methods/collapsible_str_replace.rs | 2 +- clippy_lints/src/methods/drain_collect.rs | 2 +- clippy_lints/src/methods/err_expect.rs | 2 +- clippy_lints/src/methods/expect_fun_call.rs | 4 +- clippy_lints/src/methods/filetype_is_file.rs | 2 +- clippy_lints/src/methods/filter_map.rs | 4 +- .../src/methods/filter_map_bool_then.rs | 4 +- .../src/methods/filter_map_identity.rs | 2 +- clippy_lints/src/methods/flat_map_identity.rs | 2 +- clippy_lints/src/methods/flat_map_option.rs | 2 +- clippy_lints/src/methods/get_last_with_len.rs | 2 +- .../src/methods/inefficient_to_string.rs | 2 +- clippy_lints/src/methods/inspect_for_each.rs | 2 +- clippy_lints/src/methods/into_iter_on_ref.rs | 2 +- clippy_lints/src/methods/iter_filter.rs | 2 +- clippy_lints/src/methods/iter_kv_map.rs | 1 - clippy_lints/src/methods/iter_nth.rs | 2 +- .../iter_on_single_or_empty_collections.rs | 2 +- clippy_lints/src/methods/iter_with_drain.rs | 2 +- .../src/methods/join_absolute_paths.rs | 2 +- .../src/methods/manual_c_str_literals.rs | 2 +- clippy_lints/src/methods/manual_inspect.rs | 4 +- .../src/methods/manual_is_variant_and.rs | 2 +- clippy_lints/src/methods/manual_ok_or.rs | 2 +- clippy_lints/src/methods/manual_try_fold.rs | 2 +- clippy_lints/src/methods/map_clone.rs | 2 +- clippy_lints/src/methods/map_flatten.rs | 2 +- clippy_lints/src/methods/map_identity.rs | 2 +- clippy_lints/src/methods/mod.rs | 63 ++- clippy_lints/src/methods/mut_mutex_lock.rs | 2 +- .../methods/needless_character_iteration.rs | 2 +- clippy_lints/src/methods/needless_collect.rs | 8 +- .../src/methods/needless_option_as_deref.rs | 2 +- clippy_lints/src/methods/no_effect_replace.rs | 2 +- clippy_lints/src/methods/open_options.rs | 16 +- .../src/methods/option_as_ref_cloned.rs | 4 +- .../src/methods/option_as_ref_deref.rs | 10 +- .../src/methods/option_map_unwrap_or.rs | 4 +- clippy_lints/src/methods/or_fun_call.rs | 2 +- clippy_lints/src/methods/or_then_unwrap.rs | 2 +- .../src/methods/range_zip_with_len.rs | 2 +- clippy_lints/src/methods/search_is_some.rs | 2 +- clippy_lints/src/methods/seek_from_current.rs | 2 +- .../seek_to_start_instead_of_rewind.rs | 4 +- clippy_lints/src/methods/str_splitn.rs | 4 +- .../methods/suspicious_command_arg_space.rs | 2 +- clippy_lints/src/methods/type_id_on_box.rs | 2 +- .../unnecessary_fallible_conversions.rs | 2 +- .../src/methods/unnecessary_filter_map.rs | 2 +- .../methods/unnecessary_first_then_check.rs | 56 +++ clippy_lints/src/methods/unnecessary_fold.rs | 66 +--- .../src/methods/unnecessary_get_then_check.rs | 2 +- .../src/methods/unnecessary_iter_cloned.rs | 2 +- .../src/methods/unnecessary_literal_unwrap.rs | 2 +- .../src/methods/unnecessary_min_or_max.rs | 45 ++- .../methods/unnecessary_result_map_or_else.rs | 2 +- .../src/methods/unnecessary_to_owned.rs | 9 +- .../src/methods/unused_enumerate_index.rs | 4 +- clippy_lints/src/methods/useless_asref.rs | 2 +- clippy_lints/src/methods/utils.rs | 4 +- .../src/methods/vec_resize_to_zero.rs | 2 +- clippy_lints/src/methods/waker_clone_wake.rs | 2 +- clippy_lints/src/min_ident_chars.rs | 2 +- clippy_lints/src/misc.rs | 188 ++++++--- clippy_lints/src/missing_assert_message.rs | 2 +- .../src/missing_asserts_for_indexing.rs | 4 +- clippy_lints/src/missing_const_for_fn.rs | 4 +- .../src/missing_const_for_thread_local.rs | 4 +- clippy_lints/src/missing_doc.rs | 2 +- clippy_lints/src/missing_fields_in_debug.rs | 4 +- clippy_lints/src/missing_inline.rs | 2 +- .../src/mixed_read_write_in_expression.rs | 8 +- .../src/multiple_unsafe_ops_per_block.rs | 25 +- clippy_lints/src/mut_key.rs | 2 +- clippy_lints/src/mutable_debug_assertion.rs | 2 +- .../src/needless_arbitrary_self_type.rs | 2 +- clippy_lints/src/needless_bool.rs | 6 +- .../src/needless_borrows_for_generic_args.rs | 6 +- clippy_lints/src/needless_for_each.rs | 4 +- clippy_lints/src/needless_maybe_sized.rs | 2 +- clippy_lints/src/needless_pass_by_ref_mut.rs | 2 +- clippy_lints/src/needless_pass_by_value.rs | 32 +- clippy_lints/src/no_effect.rs | 4 +- clippy_lints/src/non_copy_const.rs | 4 +- clippy_lints/src/non_expressive_names.rs | 4 +- .../src/non_octal_unix_permissions.rs | 2 +- clippy_lints/src/non_zero_suggestions.rs | 143 +++++++ clippy_lints/src/nonstandard_macro_braces.rs | 4 +- clippy_lints/src/only_used_in_recursion.rs | 2 +- .../operators/absurd_extreme_comparisons.rs | 2 +- .../src/operators/const_comparisons.rs | 4 +- .../operators/float_equality_without_abs.rs | 3 +- clippy_lints/src/option_if_let_else.rs | 6 +- clippy_lints/src/panic_in_result_fn.rs | 16 +- clippy_lints/src/panic_unimplemented.rs | 78 ++-- clippy_lints/src/pass_by_ref_or_value.rs | 2 +- clippy_lints/src/pathbuf_init_then_push.rs | 4 +- clippy_lints/src/pattern_type_mismatch.rs | 4 +- .../src/pointers_in_nomem_asm_block.rs | 88 +++++ clippy_lints/src/ptr.rs | 108 +++--- clippy_lints/src/pub_underscore_fields.rs | 2 +- clippy_lints/src/question_mark.rs | 4 +- clippy_lints/src/ranges.rs | 6 +- clippy_lints/src/rc_clone_in_vec_init.rs | 2 +- clippy_lints/src/read_zero_byte_vec.rs | 4 +- clippy_lints/src/redundant_clone.rs | 20 +- clippy_lints/src/redundant_closure_call.rs | 2 +- clippy_lints/src/redundant_else.rs | 2 +- clippy_lints/src/redundant_field_names.rs | 2 +- clippy_lints/src/redundant_locals.rs | 2 +- .../src/redundant_static_lifetimes.rs | 2 +- clippy_lints/src/reference.rs | 2 +- clippy_lints/src/regex.rs | 15 +- clippy_lints/src/repeat_vec_with_capacity.rs | 2 +- .../src/reserve_after_initialization.rs | 2 +- clippy_lints/src/return_self_not_must_use.rs | 2 +- clippy_lints/src/returns.rs | 28 +- clippy_lints/src/same_name_method.rs | 13 +- clippy_lints/src/set_contains_or_insert.rs | 6 +- .../src/significant_drop_tightening.rs | 4 +- .../src/single_component_path_imports.rs | 2 +- .../src/slow_vector_initialization.rs | 5 +- clippy_lints/src/std_instead_of_core.rs | 4 +- clippy_lints/src/string_patterns.rs | 8 +- clippy_lints/src/strings.rs | 4 +- .../src/suspicious_operation_groupings.rs | 4 +- clippy_lints/src/suspicious_trait_impl.rs | 2 +- clippy_lints/src/swap.rs | 4 +- clippy_lints/src/swap_ptr_to_ref.rs | 2 +- clippy_lints/src/tests_outside_test_module.rs | 2 +- clippy_lints/src/to_digit_is_some.rs | 12 +- clippy_lints/src/trait_bounds.rs | 6 +- clippy_lints/src/transmute/mod.rs | 34 +- .../transmutes_expressible_as_ptr_casts.rs | 2 +- .../transmute/unsound_collection_transmute.rs | 2 +- clippy_lints/src/tuple_array_conversions.rs | 2 +- clippy_lints/src/types/box_collection.rs | 2 +- clippy_lints/src/types/mod.rs | 121 +++--- .../src/types/redundant_allocation.rs | 2 +- clippy_lints/src/types/type_complexity.rs | 2 +- clippy_lints/src/types/vec_box.rs | 2 +- clippy_lints/src/unconditional_recursion.rs | 17 +- .../src/undocumented_unsafe_blocks.rs | 4 +- clippy_lints/src/uninhabited_references.rs | 2 +- clippy_lints/src/uninit_vec.rs | 6 +- clippy_lints/src/unit_return_expecting_ord.rs | 2 +- clippy_lints/src/unit_types/let_unit_value.rs | 2 +- clippy_lints/src/unit_types/unit_arg.rs | 4 +- clippy_lints/src/unnecessary_wraps.rs | 4 +- clippy_lints/src/unnested_or_patterns.rs | 8 +- clippy_lints/src/unsafe_removed_from_name.rs | 2 +- clippy_lints/src/unused_async.rs | 4 +- clippy_lints/src/unused_io_amount.rs | 2 +- clippy_lints/src/unused_peekable.rs | 2 +- clippy_lints/src/unused_trait_names.rs | 94 +++++ clippy_lints/src/unused_unit.rs | 4 +- clippy_lints/src/unwrap.rs | 4 +- clippy_lints/src/unwrap_in_result.rs | 2 +- clippy_lints/src/use_self.rs | 4 +- clippy_lints/src/useless_conversion.rs | 6 +- clippy_lints/src/utils/author.rs | 2 +- .../src/utils/format_args_collector.rs | 4 +- .../utils/internal_lints/collapsible_calls.rs | 2 +- .../src/utils/internal_lints/invalid_paths.rs | 4 +- .../internal_lints/lint_without_lint_pass.rs | 2 +- .../internal_lints/unnecessary_def_path.rs | 4 +- clippy_lints/src/vec.rs | 4 +- clippy_lints/src/vec_init_then_push.rs | 2 +- clippy_lints/src/visibility.rs | 2 +- clippy_lints/src/wildcard_imports.rs | 2 +- clippy_lints/src/write.rs | 6 +- clippy_lints/src/zombie_processes.rs | 334 ++++++++++++++++ clippy_utils/Cargo.toml | 2 +- clippy_utils/src/ast_utils.rs | 15 +- clippy_utils/src/ast_utils/ident_iter.rs | 2 +- clippy_utils/src/attrs.rs | 10 +- clippy_utils/src/check_proc_macro.rs | 4 +- clippy_utils/src/consts.rs | 10 +- clippy_utils/src/eager_or_lazy.rs | 4 +- clippy_utils/src/higher.rs | 4 +- clippy_utils/src/hir_utils.rs | 12 +- clippy_utils/src/lib.rs | 87 +++-- clippy_utils/src/macros.rs | 4 +- clippy_utils/src/mir/mod.rs | 14 +- clippy_utils/src/paths.rs | 6 +- clippy_utils/src/ptr.rs | 2 +- clippy_utils/src/qualify_min_const_fn.rs | 2 +- clippy_utils/src/source.rs | 81 +--- clippy_utils/src/str_utils.rs | 10 +- clippy_utils/src/sugg.rs | 38 +- clippy_utils/src/ty.rs | 15 +- clippy_utils/src/ty/type_certainty/mod.rs | 4 +- clippy_utils/src/usage.rs | 2 +- clippy_utils/src/visitors.rs | 4 +- declare_clippy_lint/Cargo.toml | 2 +- declare_clippy_lint/src/lib.rs | 17 +- lintcheck/src/driver.rs | 2 +- lintcheck/src/recursive.rs | 2 +- rust-toolchain | 2 +- src/driver.rs | 4 +- tests/compile-test.rs | 20 +- tests/config-metadata.rs | 2 +- tests/dogfood.rs | 49 +-- tests/ui-internal/unnecessary_def_path.fixed | 4 +- tests/ui-internal/unnecessary_def_path.rs | 4 +- .../disallowed_names.rs | 2 +- .../disallowed_names.rs | 2 +- .../conf_missing_enforced_import_rename.fixed | 2 +- .../conf_missing_enforced_import_rename.rs | 2 +- ...conf_missing_enforced_import_rename.stderr | 6 +- tests/ui-toml/panic/panic.rs | 5 + tests/ui-toml/panic/panic.stderr | 10 +- tests/ui/allow_attributes.fixed | 7 + tests/ui/allow_attributes.rs | 7 + tests/ui/allow_attributes_without_reason.rs | 1 - .../ui/allow_attributes_without_reason.stderr | 4 +- tests/ui/arithmetic_side_effects.rs | 1 - tests/ui/arithmetic_side_effects.stderr | 246 ++++++------ tests/ui/asm_syntax_not_x86.rs | 3 +- tests/ui/asm_syntax_x86.rs | 4 +- tests/ui/asm_syntax_x86.stderr | 70 ++++ tests/ui/auxiliary/external_item.rs | 7 + tests/ui/auxiliary/proc_macro_attr.rs | 4 +- tests/ui/auxiliary/proc_macro_derive.rs | 2 +- .../proc_macro_suspicious_else_formatting.rs | 2 +- tests/ui/auxiliary/proc_macros.rs | 2 +- .../borrow_interior_mutable_const/others.rs | 2 +- tests/ui/cast_alignment.rs | 8 +- tests/ui/cmp_owned/without_suggestion.rs | 4 +- tests/ui/collapsible_else_if.fixed | 5 +- tests/ui/collapsible_else_if.rs | 5 +- tests/ui/collapsible_else_if.stderr | 16 +- tests/ui/comparison_to_empty.fixed | 8 + tests/ui/comparison_to_empty.rs | 8 + tests/ui/comparison_to_empty.stderr | 26 +- tests/ui/crashes/associated-constant-ice.rs | 2 +- tests/ui/crashes/cc_seme.rs | 4 +- tests/ui/crashes/ice-11230.rs | 2 +- tests/ui/crashes/ice-1588.rs | 2 +- tests/ui/crashes/ice-1969.rs | 2 +- tests/ui/crashes/ice-2499.rs | 6 +- tests/ui/crashes/ice-2594.rs | 1 - tests/ui/crashes/ice-2727.rs | 2 +- tests/ui/crashes/ice-2760.rs | 8 +- tests/ui/crashes/ice-2862.rs | 2 +- tests/ui/crashes/ice-2865.rs | 2 +- tests/ui/crashes/ice-3151.rs | 2 +- tests/ui/crashes/ice-3462.rs | 2 +- tests/ui/crashes/ice-3747.rs | 2 +- tests/ui/crashes/ice-3969.rs | 4 +- tests/ui/crashes/ice-6251.rs | 2 +- tests/ui/crashes/ice-700.rs | 2 +- tests/ui/crashes/ice-7410.rs | 3 +- tests/ui/crashes/ice_exact_size.rs | 2 +- tests/ui/crashes/if_same_then_else.rs | 2 +- tests/ui/crashes/inherent_impl.rs | 2 +- tests/ui/crashes/issue-825.rs | 2 +- tests/ui/crashes/match_same_arms_const.rs | 2 +- ...needless_pass_by_value-w-late-bound.stderr | 2 +- tests/ui/crashes/returns.rs | 2 +- .../entrypoint_recursion.rs | 2 +- .../no_std_main_recursion.rs | 2 +- .../declare_interior_mutable_const/others.rs | 2 +- tests/ui/def_id_nocore.rs | 2 +- tests/ui/diverging_sub_expression.rs | 6 + tests/ui/doc/doc_lazy_blank_line.fixed | 47 --- tests/ui/doc/doc_lazy_blank_line.rs | 43 --- tests/ui/doc/doc_lazy_blank_line.stderr | 56 --- tests/ui/doc/doc_lazy_list.fixed | 9 +- tests/ui/doc/doc_lazy_list.stderr | 27 +- tests/ui/duplicate_underscore_argument.rs | 1 - tests/ui/duplicate_underscore_argument.stderr | 2 +- tests/ui/duplicated_attributes.rs | 4 + .../ui/empty_line_after/doc_comments.1.fixed | 135 +++++++ .../ui/empty_line_after/doc_comments.2.fixed | 144 +++++++ tests/ui/empty_line_after/doc_comments.rs | 147 +++++++ tests/ui/empty_line_after/doc_comments.stderr | 176 +++++++++ .../empty_line_after/outer_attribute.1.fixed | 108 ++++++ .../empty_line_after/outer_attribute.2.fixed | 111 ++++++ tests/ui/empty_line_after/outer_attribute.rs | 119 ++++++ .../empty_line_after/outer_attribute.stderr | 116 ++++++ tests/ui/empty_line_after_doc_comments.rs | 132 ------- tests/ui/empty_line_after_doc_comments.stderr | 37 -- tests/ui/empty_line_after_outer_attribute.rs | 120 ------ .../empty_line_after_outer_attribute.stderr | 54 --- tests/ui/empty_loop_no_std.rs | 2 +- tests/ui/enum_clike_unportable_variant.rs | 2 +- tests/ui/exit1.rs | 2 +- tests/ui/exit2.rs | 2 +- tests/ui/exit3.rs | 2 +- tests/ui/expect_fun_call.fixed | 2 - tests/ui/expect_fun_call.rs | 2 - tests/ui/expect_fun_call.stderr | 30 +- tests/ui/field_reassign_with_default.rs | 2 +- tests/ui/floating_point_arithmetic_nostd.rs | 2 +- tests/ui/format_args.fixed | 2 +- tests/ui/format_args.rs | 2 +- tests/ui/format_args_unfixable.rs | 2 +- tests/ui/if_then_some_else_none.fixed | 4 + tests/ui/if_then_some_else_none.rs | 4 + tests/ui/if_then_some_else_none.stderr | 8 +- tests/ui/ignored_unit_patterns.fixed | 15 +- tests/ui/ignored_unit_patterns.rs | 15 +- tests/ui/ignored_unit_patterns.stderr | 18 +- tests/ui/implicit_saturating_sub.fixed | 13 +- tests/ui/implicit_saturating_sub.rs | 13 +- tests/ui/incompatible_msrv.rs | 2 +- tests/ui/legacy_numeric_constants.fixed | 4 +- tests/ui/legacy_numeric_constants.rs | 4 +- tests/ui/macro_use_imports.fixed | 2 +- tests/ui/macro_use_imports.rs | 2 +- tests/ui/macro_use_imports_expect.rs | 2 +- tests/ui/manual_arithmetic_check-2.rs | 35 ++ tests/ui/manual_arithmetic_check-2.stderr | 75 ++++ tests/ui/manual_arithmetic_check.fixed | 24 ++ tests/ui/manual_arithmetic_check.rs | 24 ++ tests/ui/manual_arithmetic_check.stderr | 29 ++ tests/ui/manual_div_ceil.fixed | 30 ++ tests/ui/manual_div_ceil.rs | 30 ++ tests/ui/manual_div_ceil.stderr | 35 ++ tests/ui/manual_div_ceil_with_feature.fixed | 25 ++ tests/ui/manual_div_ceil_with_feature.rs | 25 ++ tests/ui/manual_div_ceil_with_feature.stderr | 47 +++ tests/ui/manual_is_power_of_two.fixed | 20 + tests/ui/manual_is_power_of_two.rs | 20 + tests/ui/manual_is_power_of_two.stderr | 41 ++ tests/ui/manual_non_exhaustive_enum.rs | 24 +- tests/ui/manual_non_exhaustive_enum.stderr | 22 +- tests/ui/manual_non_exhaustive_struct.rs | 50 ++- tests/ui/manual_non_exhaustive_struct.stderr | 64 +-- tests/ui/manual_range_patterns.fixed | 8 + tests/ui/manual_range_patterns.rs | 8 + tests/ui/manual_saturating_arithmetic.fixed | 2 +- tests/ui/manual_saturating_arithmetic.rs | 2 +- tests/ui/match_overlapping_arm.rs | 2 - tests/ui/match_overlapping_arm.stderr | 32 +- tests/ui/mixed_attributes_style.rs | 3 +- tests/ui/mixed_attributes_style.stderr | 3 +- tests/ui/must_use_candidates.fixed | 2 +- tests/ui/must_use_candidates.rs | 2 +- tests/ui/mut_key.rs | 2 +- tests/ui/needless_pass_by_value.rs | 12 +- tests/ui/needless_pass_by_value.stderr | 18 +- tests/ui/needless_return.fixed | 4 + tests/ui/needless_return.rs | 4 + tests/ui/needless_return.stderr | 14 +- tests/ui/non_octal_unix_permissions.fixed | 2 +- tests/ui/non_octal_unix_permissions.rs | 2 +- tests/ui/non_zero_suggestions.fixed | 65 ++++ tests/ui/non_zero_suggestions.rs | 65 ++++ tests/ui/non_zero_suggestions.stderr | 41 ++ tests/ui/non_zero_suggestions_unfixable.rs | 23 ++ .../ui/non_zero_suggestions_unfixable.stderr | 23 ++ tests/ui/panic_in_result_fn.rs | 9 + tests/ui/pointers_in_nomem_asm_block.rs | 33 ++ tests/ui/pointers_in_nomem_asm_block.stderr | 34 ++ tests/ui/ptr_arg.rs | 22 ++ tests/ui/ptr_arg.stderr | 14 +- tests/ui/ptr_cast_constness.fixed | 17 + tests/ui/ptr_cast_constness.rs | 17 + tests/ui/ptr_cast_constness.stderr | 42 +- tests/ui/result_large_err.rs | 2 +- tests/ui/single_call_fn.rs | 2 +- tests/ui/single_match.fixed | 26 +- tests/ui/single_match.rs | 44 ++- tests/ui/single_match.stderr | 67 +++- tests/ui/single_match_else.fixed | 4 + tests/ui/single_match_else.rs | 10 + tests/ui/single_match_else.stderr | 14 +- tests/ui/string_slice.rs | 6 +- tests/ui/suspicious_command_arg_space.fixed | 1 + tests/ui/suspicious_command_arg_space.rs | 1 + tests/ui/suspicious_command_arg_space.stderr | 4 +- tests/ui/suspicious_to_owned.rs | 2 +- tests/ui/tabs_in_doc_comments.fixed | 1 - tests/ui/tabs_in_doc_comments.rs | 1 - tests/ui/tabs_in_doc_comments.stderr | 16 +- tests/ui/too_long_first_doc_paragraph.rs | 10 + tests/ui/too_long_first_doc_paragraph.stderr | 28 +- tests/ui/transmute_32bit.rs | 2 +- tests/ui/transmute_64bit.rs | 2 +- tests/ui/transmute_collection.rs | 2 +- tests/ui/transmute_undefined_repr.rs | 2 +- tests/ui/uninit_vec.rs | 32 ++ tests/ui/uninit_vec.stderr | 24 +- tests/ui/unnecessary_first_then_check.fixed | 22 ++ tests/ui/unnecessary_first_then_check.rs | 22 ++ tests/ui/unnecessary_first_then_check.stderr | 47 +++ tests/ui/unnecessary_min_or_max.fixed | 29 ++ tests/ui/unnecessary_min_or_max.rs | 29 ++ tests/ui/unsafe_removed_from_name.rs | 2 +- tests/ui/unused_trait_names.fixed | 286 ++++++++++++++ tests/ui/unused_trait_names.rs | 286 ++++++++++++++ tests/ui/unused_trait_names.stderr | 73 ++++ tests/ui/used_underscore_binding.stderr | 24 +- tests/ui/used_underscore_items.rs | 63 +++ tests/ui/used_underscore_items.stderr | 112 ++++++ tests/ui/zombie_processes.rs | 138 +++++++ tests/ui/zombie_processes.stderr | 64 +++ tests/ui/zombie_processes_fixable.fixed | 26 ++ tests/ui/zombie_processes_fixable.rs | 26 ++ tests/ui/zombie_processes_fixable.stderr | 40 ++ triagebot.toml | 1 - util/gh-pages/versions.html | 121 +++--- util/versions.py | 41 +- 566 files changed, 7442 insertions(+), 2576 deletions(-) delete mode 100644 clippy_lints/src/attrs/empty_line_after.rs create mode 100644 clippy_lints/src/doc/empty_line_after.rs create mode 100644 clippy_lints/src/manual_div_ceil.rs create mode 100644 clippy_lints/src/manual_is_power_of_two.rs create mode 100644 clippy_lints/src/methods/unnecessary_first_then_check.rs create mode 100644 clippy_lints/src/non_zero_suggestions.rs create mode 100644 clippy_lints/src/pointers_in_nomem_asm_block.rs create mode 100644 clippy_lints/src/unused_trait_names.rs create mode 100644 clippy_lints/src/zombie_processes.rs create mode 100644 tests/ui/asm_syntax_x86.stderr create mode 100644 tests/ui/auxiliary/external_item.rs delete mode 100644 tests/ui/doc/doc_lazy_blank_line.fixed delete mode 100644 tests/ui/doc/doc_lazy_blank_line.rs delete mode 100644 tests/ui/doc/doc_lazy_blank_line.stderr create mode 100644 tests/ui/empty_line_after/doc_comments.1.fixed create mode 100644 tests/ui/empty_line_after/doc_comments.2.fixed create mode 100644 tests/ui/empty_line_after/doc_comments.rs create mode 100644 tests/ui/empty_line_after/doc_comments.stderr create mode 100644 tests/ui/empty_line_after/outer_attribute.1.fixed create mode 100644 tests/ui/empty_line_after/outer_attribute.2.fixed create mode 100644 tests/ui/empty_line_after/outer_attribute.rs create mode 100644 tests/ui/empty_line_after/outer_attribute.stderr delete mode 100644 tests/ui/empty_line_after_doc_comments.rs delete mode 100644 tests/ui/empty_line_after_doc_comments.stderr delete mode 100644 tests/ui/empty_line_after_outer_attribute.rs delete mode 100644 tests/ui/empty_line_after_outer_attribute.stderr create mode 100644 tests/ui/manual_arithmetic_check-2.rs create mode 100644 tests/ui/manual_arithmetic_check-2.stderr create mode 100644 tests/ui/manual_arithmetic_check.fixed create mode 100644 tests/ui/manual_arithmetic_check.rs create mode 100644 tests/ui/manual_arithmetic_check.stderr create mode 100644 tests/ui/manual_div_ceil.fixed create mode 100644 tests/ui/manual_div_ceil.rs create mode 100644 tests/ui/manual_div_ceil.stderr create mode 100644 tests/ui/manual_div_ceil_with_feature.fixed create mode 100644 tests/ui/manual_div_ceil_with_feature.rs create mode 100644 tests/ui/manual_div_ceil_with_feature.stderr create mode 100644 tests/ui/manual_is_power_of_two.fixed create mode 100644 tests/ui/manual_is_power_of_two.rs create mode 100644 tests/ui/manual_is_power_of_two.stderr create mode 100644 tests/ui/non_zero_suggestions.fixed create mode 100644 tests/ui/non_zero_suggestions.rs create mode 100644 tests/ui/non_zero_suggestions.stderr create mode 100644 tests/ui/non_zero_suggestions_unfixable.rs create mode 100644 tests/ui/non_zero_suggestions_unfixable.stderr create mode 100644 tests/ui/pointers_in_nomem_asm_block.rs create mode 100644 tests/ui/pointers_in_nomem_asm_block.stderr create mode 100644 tests/ui/unnecessary_first_then_check.fixed create mode 100644 tests/ui/unnecessary_first_then_check.rs create mode 100644 tests/ui/unnecessary_first_then_check.stderr create mode 100644 tests/ui/unused_trait_names.fixed create mode 100644 tests/ui/unused_trait_names.rs create mode 100644 tests/ui/unused_trait_names.stderr create mode 100644 tests/ui/used_underscore_items.rs create mode 100644 tests/ui/used_underscore_items.stderr create mode 100644 tests/ui/zombie_processes.rs create mode 100644 tests/ui/zombie_processes.stderr create mode 100644 tests/ui/zombie_processes_fixable.fixed create mode 100644 tests/ui/zombie_processes_fixable.rs create mode 100644 tests/ui/zombie_processes_fixable.stderr diff --git a/.github/deploy.sh b/.github/deploy.sh index d937661c0f8..5b4b4be4e36 100644 --- a/.github/deploy.sh +++ b/.github/deploy.sh @@ -25,16 +25,15 @@ if [[ $BETA = "true" ]]; then fi # Generate version index that is shown as root index page -cp util/gh-pages/versions.html out/index.html - -echo "Making the versions.json file" -python3 ./util/versions.py out +python3 ./util/versions.py ./util/gh-pages/versions.html out # Now let's go have some fun with the cloned repo cd out git config user.name "GHA CI" git config user.email "gha@ci.invalid" +git status + if [[ -n $TAG_NAME ]]; then # track files, so that the following check works git add --intent-to-add "$TAG_NAME" @@ -46,8 +45,6 @@ if [[ -n $TAG_NAME ]]; then git add "$TAG_NAME" # Update the symlink git add stable - # Update versions file - git add versions.json git commit -m "Add documentation for ${TAG_NAME} release: ${SHA}" elif [[ $BETA = "true" ]]; then if git diff --exit-code --quiet -- beta/; then diff --git a/.github/workflows/clippy_bors.yml b/.github/workflows/clippy_bors.yml index 2aa13313fa5..026771e6fcf 100644 --- a/.github/workflows/clippy_bors.yml +++ b/.github/workflows/clippy_bors.yml @@ -162,7 +162,7 @@ jobs: find $DIR ! -executable -o -type d ! -path $DIR | xargs rm -rf - name: Upload Binaries - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: binaries path: target/debug @@ -202,7 +202,7 @@ jobs: # Download - name: Download target dir - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: name: binaries path: target/debug diff --git a/CHANGELOG.md b/CHANGELOG.md index 9bc4ad9698d..41a86e8ce51 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,61 @@ document. ## Unreleased / Beta / In Rust Nightly -[c9139bd5...master](https://github.com/rust-lang/rust-clippy/compare/c9139bd5...master) +[b794b8e0...master](https://github.com/rust-lang/rust-clippy/compare/b794b8e0...master) + +## Rust 1.81 + +Current stable, released 2024-09-05 + +### New Lints + +* Added [`cfg_not_test`] to `restriction` + [#11293](https://github.com/rust-lang/rust-clippy/pull/11293) +* Added [`byte_char_slices`] to `style` + [#10155](https://github.com/rust-lang/rust-clippy/pull/10155) +* Added [`set_contains_or_insert`] to `nursery` + [#12873](https://github.com/rust-lang/rust-clippy/pull/12873) +* Added [`manual_rotate`] to `style` + [#12983](https://github.com/rust-lang/rust-clippy/pull/12983) +* Added [`unnecessary_min_or_max`] to `complexity` + [#12368](https://github.com/rust-lang/rust-clippy/pull/12368) +* Added [`manual_inspect`] to `complexity` + [#12287](https://github.com/rust-lang/rust-clippy/pull/12287) +* Added [`field_scoped_visibility_modifiers`] to `restriction` + [#12893](https://github.com/rust-lang/rust-clippy/pull/12893) +* Added [`manual_pattern_char_comparison`] to `style` + [#12849](https://github.com/rust-lang/rust-clippy/pull/12849) +* Added [`needless_maybe_sized`] to `suspicious` + [#10632](https://github.com/rust-lang/rust-clippy/pull/10632) +* Added [`needless_character_iteration`] to `suspicious` + [#12815](https://github.com/rust-lang/rust-clippy/pull/12815) + +### Moves and Deprecations + +* [`allow_attributes`], [`allow_attributes_without_reason`]: Now work on stable + [rust#120924](https://github.com/rust-lang/rust/pull/120924) +* Renamed `overflow_check_conditional` to [`panicking_overflow_checks`] + [#12944](https://github.com/rust-lang/rust-clippy/pull/12944) +* Moved [`panicking_overflow_checks`] to `correctness` (From `complexity` now deny-by-default) + [#12944](https://github.com/rust-lang/rust-clippy/pull/12944) +* Renamed `thread_local_initializer_can_be_made_const` to [`missing_const_for_thread_local`] + [#12974](https://github.com/rust-lang/rust-clippy/pull/12974) +* Deprecated [`maybe_misused_cfg`] and [`mismatched_target_os`] as they are now caught by cargo + and rustc + [#12875](https://github.com/rust-lang/rust-clippy/pull/12875) + +### Enhancements + +* [`significant_drop_in_scrutinee`]: Now also checks scrutinies of `while let` and `for let` + expressions + [#12870](https://github.com/rust-lang/rust-clippy/pull/12870) +* [`std_instead_of_core`]: Now respects the `msrv` configuration + [#13168](https://github.com/rust-lang/rust-clippy/pull/13168) + +### ICE Fixes + +* [`suboptimal_flops`]: No longer crashes on custom `.log()` functions + [#12884](https://github.com/rust-lang/rust-clippy/pull/12884) ## Rust 1.80 @@ -5500,6 +5554,7 @@ Released 2018-09-13 [`invalid_regex`]: https://rust-lang.github.io/rust-clippy/master/index.html#invalid_regex [`invalid_upcast_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#invalid_upcast_comparisons [`invalid_utf8_in_unchecked`]: https://rust-lang.github.io/rust-clippy/master/index.html#invalid_utf8_in_unchecked +[`inverted_saturating_sub`]: https://rust-lang.github.io/rust-clippy/master/index.html#inverted_saturating_sub [`invisible_characters`]: https://rust-lang.github.io/rust-clippy/master/index.html#invisible_characters [`is_digit_ascii_radix`]: https://rust-lang.github.io/rust-clippy/master/index.html#is_digit_ascii_radix [`items_after_statements`]: https://rust-lang.github.io/rust-clippy/master/index.html#items_after_statements @@ -5559,6 +5614,7 @@ Released 2018-09-13 [`manual_bits`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_bits [`manual_c_str_literals`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_c_str_literals [`manual_clamp`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_clamp +[`manual_div_ceil`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_div_ceil [`manual_filter`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_filter [`manual_filter_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_filter_map [`manual_find`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_find @@ -5570,6 +5626,7 @@ Released 2018-09-13 [`manual_is_ascii_check`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_is_ascii_check [`manual_is_finite`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_is_finite [`manual_is_infinite`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_is_infinite +[`manual_is_power_of_two`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_is_power_of_two [`manual_is_variant_and`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_is_variant_and [`manual_let_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_let_else [`manual_main_separator_str`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_main_separator_str @@ -5716,6 +5773,7 @@ Released 2018-09-13 [`non_minimal_cfg`]: https://rust-lang.github.io/rust-clippy/master/index.html#non_minimal_cfg [`non_octal_unix_permissions`]: https://rust-lang.github.io/rust-clippy/master/index.html#non_octal_unix_permissions [`non_send_fields_in_send_ty`]: https://rust-lang.github.io/rust-clippy/master/index.html#non_send_fields_in_send_ty +[`non_zero_suggestions`]: https://rust-lang.github.io/rust-clippy/master/index.html#non_zero_suggestions [`nonminimal_bool`]: https://rust-lang.github.io/rust-clippy/master/index.html#nonminimal_bool [`nonsensical_open_options`]: https://rust-lang.github.io/rust-clippy/master/index.html#nonsensical_open_options [`nonstandard_macro_braces`]: https://rust-lang.github.io/rust-clippy/master/index.html#nonstandard_macro_braces @@ -5757,6 +5815,7 @@ Released 2018-09-13 [`pathbuf_init_then_push`]: https://rust-lang.github.io/rust-clippy/master/index.html#pathbuf_init_then_push [`pattern_type_mismatch`]: https://rust-lang.github.io/rust-clippy/master/index.html#pattern_type_mismatch [`permissions_set_readonly_false`]: https://rust-lang.github.io/rust-clippy/master/index.html#permissions_set_readonly_false +[`pointers_in_nomem_asm_block`]: https://rust-lang.github.io/rust-clippy/master/index.html#pointers_in_nomem_asm_block [`positional_named_format_parameters`]: https://rust-lang.github.io/rust-clippy/master/index.html#positional_named_format_parameters [`possible_missing_comma`]: https://rust-lang.github.io/rust-clippy/master/index.html#possible_missing_comma [`precedence`]: https://rust-lang.github.io/rust-clippy/master/index.html#precedence @@ -5962,6 +6021,7 @@ Released 2018-09-13 [`unnecessary_fallible_conversions`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_fallible_conversions [`unnecessary_filter_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_filter_map [`unnecessary_find_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_find_map +[`unnecessary_first_then_check`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_first_then_check [`unnecessary_fold`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_fold [`unnecessary_get_then_check`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_get_then_check [`unnecessary_join`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_join @@ -6003,6 +6063,7 @@ Released 2018-09-13 [`unused_result_ok`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_result_ok [`unused_rounding`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_rounding [`unused_self`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_self +[`unused_trait_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_trait_names [`unused_unit`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_unit [`unusual_byte_groupings`]: https://rust-lang.github.io/rust-clippy/master/index.html#unusual_byte_groupings [`unwrap_in_result`]: https://rust-lang.github.io/rust-clippy/master/index.html#unwrap_in_result @@ -6013,6 +6074,7 @@ Released 2018-09-13 [`use_debug`]: https://rust-lang.github.io/rust-clippy/master/index.html#use_debug [`use_self`]: https://rust-lang.github.io/rust-clippy/master/index.html#use_self [`used_underscore_binding`]: https://rust-lang.github.io/rust-clippy/master/index.html#used_underscore_binding +[`used_underscore_items`]: https://rust-lang.github.io/rust-clippy/master/index.html#used_underscore_items [`useless_asref`]: https://rust-lang.github.io/rust-clippy/master/index.html#useless_asref [`useless_attribute`]: https://rust-lang.github.io/rust-clippy/master/index.html#useless_attribute [`useless_conversion`]: https://rust-lang.github.io/rust-clippy/master/index.html#useless_conversion @@ -6047,6 +6109,7 @@ Released 2018-09-13 [`zero_repeat_side_effects`]: https://rust-lang.github.io/rust-clippy/master/index.html#zero_repeat_side_effects [`zero_sized_map_values`]: https://rust-lang.github.io/rust-clippy/master/index.html#zero_sized_map_values [`zero_width_space`]: https://rust-lang.github.io/rust-clippy/master/index.html#zero_width_space +[`zombie_processes`]: https://rust-lang.github.io/rust-clippy/master/index.html#zombie_processes [`zst_offset`]: https://rust-lang.github.io/rust-clippy/master/index.html#zst_offset diff --git a/Cargo.toml b/Cargo.toml index b48b881097f..ddc27179ef2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clippy" -version = "0.1.82" +version = "0.1.83" description = "A bunch of helpful lints to avoid common pitfalls in Rust" repository = "https://github.com/rust-lang/rust-clippy" readme = "README.md" @@ -31,7 +31,7 @@ anstream = "0.6.0" [dev-dependencies] cargo_metadata = "0.18.1" -ui_test = "0.25" +ui_test = "0.26.4" regex = "1.5.5" serde = { version = "1.0.145", features = ["derive"] } serde_json = "1.0.122" @@ -67,3 +67,10 @@ harness = false [[test]] name = "dogfood" harness = false + +# quine-mc_cluskey makes up a significant part of the runtime in dogfood +# due to the number of conditions in the clippy_lints crate +# and enabling optimizations for that specific dependency helps a bit +# without increasing total build times. +[profile.dev.package.quine-mc_cluskey] +opt-level = 3 diff --git a/book/src/lint_configuration.md b/book/src/lint_configuration.md index 78348797588..91159bc79c5 100644 --- a/book/src/lint_configuration.md +++ b/book/src/lint_configuration.md @@ -727,6 +727,7 @@ The minimum rust version that the project supports. Defaults to the `rust-versio * [`uninlined_format_args`](https://rust-lang.github.io/rust-clippy/master/index.html#uninlined_format_args) * [`unnecessary_lazy_evaluations`](https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_lazy_evaluations) * [`unnested_or_patterns`](https://rust-lang.github.io/rust-clippy/master/index.html#unnested_or_patterns) +* [`unused_trait_names`](https://rust-lang.github.io/rust-clippy/master/index.html#unused_trait_names) * [`use_self`](https://rust-lang.github.io/rust-clippy/master/index.html#use_self) diff --git a/clippy_config/Cargo.toml b/clippy_config/Cargo.toml index 5c4e0761dbc..9da7112345d 100644 --- a/clippy_config/Cargo.toml +++ b/clippy_config/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clippy_config" -version = "0.1.82" +version = "0.1.83" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/clippy_config/src/conf.rs b/clippy_config/src/conf.rs index a6f1b958bfb..757620341cc 100644 --- a/clippy_config/src/conf.rs +++ b/clippy_config/src/conf.rs @@ -1,6 +1,6 @@ +use crate::ClippyConfiguration; use crate::msrvs::Msrv; use crate::types::{DisallowedPath, MacroMatcher, MatchLintBehaviour, PubUnderscoreFieldsBehaviour, Rename}; -use crate::ClippyConfiguration; use rustc_errors::Applicability; use rustc_session::Session; use rustc_span::edit_distance::edit_distance; @@ -563,6 +563,7 @@ define_Conf! { uninlined_format_args, unnecessary_lazy_evaluations, unnested_or_patterns, + unused_trait_names, use_self, )] msrv: Msrv = Msrv::empty(), @@ -864,7 +865,7 @@ fn calculate_dimensions(fields: &[&str]) -> (usize, Vec) { cmp::max(1, terminal_width / (SEPARATOR_WIDTH + max_field_width)) }); - let rows = (fields.len() + (columns - 1)) / columns; + let rows = fields.len().div_ceil(columns); let column_widths = (0..columns) .map(|column| { diff --git a/clippy_config/src/lib.rs b/clippy_config/src/lib.rs index ac838cc81d2..c63d98a0a13 100644 --- a/clippy_config/src/lib.rs +++ b/clippy_config/src/lib.rs @@ -26,5 +26,5 @@ mod metadata; pub mod msrvs; pub mod types; -pub use conf::{get_configuration_metadata, lookup_conf_file, Conf}; +pub use conf::{Conf, get_configuration_metadata, lookup_conf_file}; pub use metadata::ClippyConfiguration; diff --git a/clippy_config/src/msrvs.rs b/clippy_config/src/msrvs.rs index a2b4b6e256f..e30df3d3234 100644 --- a/clippy_config/src/msrvs.rs +++ b/clippy_config/src/msrvs.rs @@ -1,7 +1,7 @@ use rustc_ast::Attribute; use rustc_attr::parse_version; use rustc_session::{RustcVersion, Session}; -use rustc_span::{sym, Symbol}; +use rustc_span::{Symbol, sym}; use serde::Deserialize; use std::fmt; @@ -23,6 +23,7 @@ msrv_aliases! { 1,80,0 { BOX_INTO_ITER} 1,77,0 { C_STR_LITERALS } 1,76,0 { PTR_FROM_REF, OPTION_RESULT_INSPECT } + 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 } 1,68,0 { PATH_MAIN_SEPARATOR_STR } @@ -38,7 +39,7 @@ msrv_aliases! { 1,52,0 { STR_SPLIT_ONCE, REM_EUCLID_CONST } 1,51,0 { BORROW_AS_PTR, SEEK_FROM_CURRENT, UNSIGNED_ABS } 1,50,0 { BOOL_THEN, CLAMP } - 1,47,0 { TAU, IS_ASCII_DIGIT_CONST, ARRAY_IMPL_ANY_LEN } + 1,47,0 { TAU, IS_ASCII_DIGIT_CONST, ARRAY_IMPL_ANY_LEN, SATURATING_SUB_CONST } 1,46,0 { CONST_IF_MATCH } 1,45,0 { STR_STRIP_PREFIX } 1,43,0 { LOG2_10, LOG10_2, NUMERIC_ASSOCIATED_CONSTANTS } @@ -50,6 +51,7 @@ msrv_aliases! { 1,36,0 { ITERATOR_COPIED } 1,35,0 { OPTION_COPIED, RANGE_CONTAINS } 1,34,0 { TRY_FROM } + 1,33,0 { UNDERSCORE_IMPORTS } 1,30,0 { ITERATOR_FIND_MAP, TOOL_ATTRIBUTES } 1,29,0 { ITER_FLATTEN } 1,28,0 { FROM_BOOL } diff --git a/clippy_config/src/types.rs b/clippy_config/src/types.rs index d47e34bb5bc..bab63911182 100644 --- a/clippy_config/src/types.rs +++ b/clippy_config/src/types.rs @@ -1,5 +1,5 @@ use serde::de::{self, Deserializer, Visitor}; -use serde::{ser, Deserialize, Serialize}; +use serde::{Deserialize, Serialize, ser}; use std::fmt; #[derive(Debug, Deserialize)] diff --git a/clippy_dev/src/fmt.rs b/clippy_dev/src/fmt.rs index 5fc4365c6e7..8c61c35533c 100644 --- a/clippy_dev/src/fmt.rs +++ b/clippy_dev/src/fmt.rs @@ -1,6 +1,6 @@ use crate::clippy_project_root; use itertools::Itertools; -use rustc_lexer::{tokenize, TokenKind}; +use rustc_lexer::{TokenKind, tokenize}; use shell_escape::escape; use std::ffi::{OsStr, OsString}; use std::ops::ControlFlow; diff --git a/clippy_dev/src/new_lint.rs b/clippy_dev/src/new_lint.rs index 87117832fb9..5fd65017cfb 100644 --- a/clippy_dev/src/new_lint.rs +++ b/clippy_dev/src/new_lint.rs @@ -441,7 +441,7 @@ fn create_lint_for_ty(lint: &LintData<'_>, enable_msrv: bool, ty: &str) -> io::R #[allow(clippy::too_many_lines)] fn setup_mod_file(path: &Path, lint: &LintData<'_>) -> io::Result<&'static str> { - use super::update_lints::{match_tokens, LintDeclSearchResult}; + use super::update_lints::{LintDeclSearchResult, match_tokens}; use rustc_lexer::TokenKind; let lint_name_upper = lint.name.to_uppercase(); diff --git a/clippy_dev/src/serve.rs b/clippy_dev/src/serve.rs index 19560b31fd3..cc14cd8dae6 100644 --- a/clippy_dev/src/serve.rs +++ b/clippy_dev/src/serve.rs @@ -29,7 +29,7 @@ pub fn run(port: u16, lint: Option) -> ! { } if let Some(url) = url.take() { thread::spawn(move || { - Command::new(PYTHON) + let mut child = Command::new(PYTHON) .arg("-m") .arg("http.server") .arg(port.to_string()) @@ -40,6 +40,7 @@ pub fn run(port: u16, lint: Option) -> ! { thread::sleep(Duration::from_millis(500)); // Launch browser after first export.py has completed and http.server is up let _result = opener::open(url); + child.wait().unwrap(); }); } thread::sleep(Duration::from_millis(1000)); diff --git a/clippy_dev/src/update_lints.rs b/clippy_dev/src/update_lints.rs index 8dbda1c634c..d6ed36d52f4 100644 --- a/clippy_dev/src/update_lints.rs +++ b/clippy_dev/src/update_lints.rs @@ -1,7 +1,7 @@ use crate::clippy_project_root; use aho_corasick::AhoCorasickBuilder; use itertools::Itertools; -use rustc_lexer::{tokenize, unescape, LiteralKind, TokenKind}; +use rustc_lexer::{LiteralKind, TokenKind, tokenize, unescape}; use std::collections::{HashMap, HashSet}; use std::ffi::OsStr; use std::fmt::{self, Write}; @@ -1048,23 +1048,17 @@ mod tests { Lint::new("incorrect_match", "group1", "\"abc\"", "module_name", Range::default()), ]; let mut expected: HashMap> = HashMap::new(); - expected.insert( - "group1".to_string(), - vec![ - Lint::new("should_assert_eq", "group1", "\"abc\"", "module_name", Range::default()), - Lint::new("incorrect_match", "group1", "\"abc\"", "module_name", Range::default()), - ], - ); - expected.insert( - "group2".to_string(), - vec![Lint::new( - "should_assert_eq2", - "group2", - "\"abc\"", - "module_name", - Range::default(), - )], - ); + expected.insert("group1".to_string(), vec![ + Lint::new("should_assert_eq", "group1", "\"abc\"", "module_name", Range::default()), + Lint::new("incorrect_match", "group1", "\"abc\"", "module_name", Range::default()), + ]); + expected.insert("group2".to_string(), vec![Lint::new( + "should_assert_eq2", + "group2", + "\"abc\"", + "module_name", + Range::default(), + )]); assert_eq!(expected, Lint::by_lint_group(lints.into_iter())); } } diff --git a/clippy_lints/Cargo.toml b/clippy_lints/Cargo.toml index fbd4566da58..d1188940b46 100644 --- a/clippy_lints/Cargo.toml +++ b/clippy_lints/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clippy_lints" -version = "0.1.82" +version = "0.1.83" description = "A bunch of helpful lints to avoid common pitfalls in Rust" repository = "https://github.com/rust-lang/rust-clippy" readme = "README.md" diff --git a/clippy_lints/src/absolute_paths.rs b/clippy_lints/src/absolute_paths.rs index c72b3f1318c..1af6d448a93 100644 --- a/clippy_lints/src/absolute_paths.rs +++ b/clippy_lints/src/absolute_paths.rs @@ -3,12 +3,12 @@ use clippy_utils::diagnostics::span_lint; use clippy_utils::is_from_proc_macro; use rustc_data_structures::fx::FxHashSet; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX}; +use rustc_hir::def_id::{CRATE_DEF_INDEX, DefId}; use rustc_hir::{HirId, ItemKind, Node, Path}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::impl_lint_pass; -use rustc_span::symbol::kw; use rustc_span::Symbol; +use rustc_span::symbol::kw; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/almost_complete_range.rs b/clippy_lints/src/almost_complete_range.rs index 451bae95987..370f0c482fd 100644 --- a/clippy_lints/src/almost_complete_range.rs +++ b/clippy_lints/src/almost_complete_range.rs @@ -1,5 +1,5 @@ -use clippy_config::msrvs::{self, Msrv}; use clippy_config::Conf; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::{trim_span, walk_span_to_context}; use rustc_ast::ast::{Expr, ExprKind, LitKind, Pat, PatKind, RangeEnd, RangeLimits}; diff --git a/clippy_lints/src/approx_const.rs b/clippy_lints/src/approx_const.rs index 56f5e903dc3..4f8f091a095 100644 --- a/clippy_lints/src/approx_const.rs +++ b/clippy_lints/src/approx_const.rs @@ -1,10 +1,10 @@ -use clippy_config::msrvs::{self, Msrv}; use clippy_config::Conf; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_help; use rustc_ast::ast::{FloatTy, LitFloatType, LitKind}; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{impl_lint_pass, RustcVersion}; +use rustc_session::{RustcVersion, impl_lint_pass}; use rustc_span::symbol; use std::f64::consts as f64; diff --git a/clippy_lints/src/arc_with_non_send_sync.rs b/clippy_lints/src/arc_with_non_send_sync.rs index 4eafa330faf..2643f850879 100644 --- a/clippy_lints/src/arc_with_non_send_sync.rs +++ b/clippy_lints/src/arc_with_non_send_sync.rs @@ -4,8 +4,8 @@ use clippy_utils::ty::{implements_trait, is_type_diagnostic_item}; use rustc_hir::{Expr, ExprKind, QPath}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; -use rustc_middle::ty::print::with_forced_trimmed_paths; use rustc_middle::ty::GenericArgKind; +use rustc_middle::ty::print::with_forced_trimmed_paths; use rustc_session::declare_lint_pass; use rustc_span::symbol::sym; diff --git a/clippy_lints/src/assertions_on_constants.rs b/clippy_lints/src/assertions_on_constants.rs index 7eaac80f969..b6684825835 100644 --- a/clippy_lints/src/assertions_on_constants.rs +++ b/clippy_lints/src/assertions_on_constants.rs @@ -1,7 +1,7 @@ use clippy_utils::consts::{ConstEvalCtxt, Constant}; use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::is_inside_always_const_context; -use clippy_utils::macros::{find_assert_args, root_macro_call_first_node, PanicExpn}; +use clippy_utils::macros::{PanicExpn, find_assert_args, root_macro_call_first_node}; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; diff --git a/clippy_lints/src/assertions_on_result_states.rs b/clippy_lints/src/assertions_on_result_states.rs index f1cb4a05af8..c073dee855e 100644 --- a/clippy_lints/src/assertions_on_result_states.rs +++ b/clippy_lints/src/assertions_on_result_states.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::macros::{find_assert_args, root_macro_call_first_node, PanicExpn}; +use clippy_utils::macros::{PanicExpn, find_assert_args, root_macro_call_first_node}; use clippy_utils::source::snippet_with_context; use clippy_utils::ty::{has_debug_impl, is_copy, is_type_diagnostic_item}; use clippy_utils::usage::local_used_after_expr; diff --git a/clippy_lints/src/assigning_clones.rs b/clippy_lints/src/assigning_clones.rs index 55645d04eef..0b82c0cd04c 100644 --- a/clippy_lints/src/assigning_clones.rs +++ b/clippy_lints/src/assigning_clones.rs @@ -1,7 +1,7 @@ -use clippy_config::msrvs::{self, Msrv}; use clippy_config::Conf; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::mir::{enclosing_mir, PossibleBorrowerMap}; +use clippy_utils::mir::{PossibleBorrowerMap, enclosing_mir}; use clippy_utils::sugg::Sugg; use clippy_utils::{is_diag_trait_item, is_in_test, last_path_segment, local_is_initialized, path_to_local}; use rustc_errors::Applicability; diff --git a/clippy_lints/src/attrs/allow_attributes_without_reason.rs b/clippy_lints/src/attrs/allow_attributes_without_reason.rs index 4ab97118df1..40959eccd3a 100644 --- a/clippy_lints/src/attrs/allow_attributes_without_reason.rs +++ b/clippy_lints/src/attrs/allow_attributes_without_reason.rs @@ -1,4 +1,4 @@ -use super::{Attribute, ALLOW_ATTRIBUTES_WITHOUT_REASON}; +use super::{ALLOW_ATTRIBUTES_WITHOUT_REASON, Attribute}; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::is_from_proc_macro; use rustc_ast::{MetaItemKind, NestedMetaItem}; @@ -26,7 +26,7 @@ pub(super) fn check<'cx>(cx: &LateContext<'cx>, name: Symbol, items: &[NestedMet cx, ALLOW_ATTRIBUTES_WITHOUT_REASON, attr.span, - format!("`{}` attribute without specifying a reason", name.as_str()), + format!("`{name}` attribute without specifying a reason"), |diag| { diag.help("try adding a reason at the end with `, reason = \"..\"`"); }, diff --git a/clippy_lints/src/attrs/blanket_clippy_restriction_lints.rs b/clippy_lints/src/attrs/blanket_clippy_restriction_lints.rs index 9b08fd6d654..508963a20ea 100644 --- a/clippy_lints/src/attrs/blanket_clippy_restriction_lints.rs +++ b/clippy_lints/src/attrs/blanket_clippy_restriction_lints.rs @@ -1,10 +1,10 @@ -use super::utils::extract_clippy_lint; use super::BLANKET_CLIPPY_RESTRICTION_LINTS; +use super::utils::extract_clippy_lint; use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_then}; use rustc_ast::NestedMetaItem; use rustc_lint::{LateContext, Level, LintContext}; use rustc_span::symbol::Symbol; -use rustc_span::{sym, DUMMY_SP}; +use rustc_span::{DUMMY_SP, sym}; pub(super) fn check(cx: &LateContext<'_>, name: Symbol, items: &[NestedMetaItem]) { for lint in items { diff --git a/clippy_lints/src/attrs/deprecated_cfg_attr.rs b/clippy_lints/src/attrs/deprecated_cfg_attr.rs index e872ab6b4b5..abf924f7542 100644 --- a/clippy_lints/src/attrs/deprecated_cfg_attr.rs +++ b/clippy_lints/src/attrs/deprecated_cfg_attr.rs @@ -1,4 +1,4 @@ -use super::{unnecessary_clippy_cfg, Attribute, DEPRECATED_CFG_ATTR, DEPRECATED_CLIPPY_CFG_ATTR}; +use super::{Attribute, DEPRECATED_CFG_ATTR, DEPRECATED_CLIPPY_CFG_ATTR, unnecessary_clippy_cfg}; use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_sugg; use rustc_ast::AttrStyle; diff --git a/clippy_lints/src/attrs/duplicated_attributes.rs b/clippy_lints/src/attrs/duplicated_attributes.rs index 40a1c4e2884..55f8e1072db 100644 --- a/clippy_lints/src/attrs/duplicated_attributes.rs +++ b/clippy_lints/src/attrs/duplicated_attributes.rs @@ -3,7 +3,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use rustc_ast::{Attribute, MetaItem}; use rustc_data_structures::fx::FxHashMap; use rustc_lint::LateContext; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; use std::collections::hash_map::Entry; fn emit_if_duplicated( @@ -36,7 +36,7 @@ fn check_duplicated_attr( } let Some(ident) = attr.ident() else { return }; let name = ident.name; - if name == sym::doc || name == sym::cfg_attr || name == sym::rustc_on_unimplemented { + if name == sym::doc || name == sym::cfg_attr || name == sym::rustc_on_unimplemented || name == sym::reason { // FIXME: Would be nice to handle `cfg_attr` as well. Only problem is to check that cfg // conditions are the same. // `#[rustc_on_unimplemented]` contains duplicated subattributes, that's expected. diff --git a/clippy_lints/src/attrs/empty_line_after.rs b/clippy_lints/src/attrs/empty_line_after.rs deleted file mode 100644 index 7ff644b4c44..00000000000 --- a/clippy_lints/src/attrs/empty_line_after.rs +++ /dev/null @@ -1,52 +0,0 @@ -use super::{EMPTY_LINE_AFTER_DOC_COMMENTS, EMPTY_LINE_AFTER_OUTER_ATTR}; -use clippy_utils::diagnostics::span_lint; -use clippy_utils::source::{is_present_in_source, without_block_comments, SpanRangeExt}; -use rustc_ast::{AttrKind, AttrStyle}; -use rustc_lint::EarlyContext; -use rustc_span::Span; - -/// Check for empty lines after outer attributes. -/// -/// Attributes and documentation comments are both considered outer attributes -/// by the AST. However, the average user likely considers them to be different. -/// Checking for empty lines after each of these attributes is split into two different -/// lints but can share the same logic. -pub(super) fn check(cx: &EarlyContext<'_>, item: &rustc_ast::Item) { - let mut iter = item.attrs.iter().peekable(); - while let Some(attr) = iter.next() { - if (matches!(attr.kind, AttrKind::Normal(..)) || matches!(attr.kind, AttrKind::DocComment(..))) - && attr.style == AttrStyle::Outer - && is_present_in_source(cx, attr.span) - { - let begin_of_attr_to_item = Span::new(attr.span.lo(), item.span.lo(), item.span.ctxt(), item.span.parent()); - let end_of_attr_to_next_attr_or_item = Span::new( - attr.span.hi(), - iter.peek().map_or(item.span.lo(), |next_attr| next_attr.span.lo()), - item.span.ctxt(), - item.span.parent(), - ); - - if let Some(snippet) = end_of_attr_to_next_attr_or_item.get_source_text(cx) { - let lines = snippet.split('\n').collect::>(); - let lines = without_block_comments(lines); - - if lines.iter().filter(|l| l.trim().is_empty()).count() > 2 { - let (lint_msg, lint_type) = match attr.kind { - AttrKind::DocComment(..) => ( - "found an empty line after a doc comment. \ - Perhaps you need to use `//!` to make a comment on a module, remove the empty line, or make a regular comment with `//`?", - EMPTY_LINE_AFTER_DOC_COMMENTS, - ), - AttrKind::Normal(..) => ( - "found an empty line after an outer attribute. \ - Perhaps you forgot to add a `!` to make it an inner attribute?", - EMPTY_LINE_AFTER_OUTER_ATTR, - ), - }; - - span_lint(cx, lint_type, begin_of_attr_to_item, lint_msg); - } - } - } - } -} diff --git a/clippy_lints/src/attrs/inline_always.rs b/clippy_lints/src/attrs/inline_always.rs index 3b5b80ffefa..d41bb580c6c 100644 --- a/clippy_lints/src/attrs/inline_always.rs +++ b/clippy_lints/src/attrs/inline_always.rs @@ -1,10 +1,10 @@ -use super::utils::is_word; use super::INLINE_ALWAYS; +use super::utils::is_word; use clippy_utils::diagnostics::span_lint; use rustc_ast::Attribute; use rustc_lint::LateContext; use rustc_span::symbol::Symbol; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; pub(super) fn check(cx: &LateContext<'_>, span: Span, name: Symbol, attrs: &[Attribute]) { if span.from_expansion() { diff --git a/clippy_lints/src/attrs/mod.rs b/clippy_lints/src/attrs/mod.rs index 3b14e9aee7f..888f28fa225 100644 --- a/clippy_lints/src/attrs/mod.rs +++ b/clippy_lints/src/attrs/mod.rs @@ -4,7 +4,6 @@ mod blanket_clippy_restriction_lints; mod deprecated_cfg_attr; mod deprecated_semver; mod duplicated_attributes; -mod empty_line_after; mod inline_always; mod mixed_attributes_style; mod non_minimal_cfg; @@ -13,8 +12,8 @@ mod unnecessary_clippy_cfg; mod useless_attribute; mod utils; -use clippy_config::msrvs::{self, Msrv}; use clippy_config::Conf; +use clippy_config::msrvs::{self, Msrv}; use rustc_ast::{Attribute, MetaItemKind, NestedMetaItem}; use rustc_hir::{ImplItem, Item, ItemKind, TraitItem}; use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass}; @@ -126,94 +125,6 @@ declare_clippy_lint! { "use of `#[deprecated(since = \"x\")]` where x is not semver" } -declare_clippy_lint! { - /// ### What it does - /// Checks for empty lines after outer attributes - /// - /// ### Why is this bad? - /// Most likely the attribute was meant to be an inner attribute using a '!'. - /// If it was meant to be an outer attribute, then the following item - /// should not be separated by empty lines. - /// - /// ### Known problems - /// Can cause false positives. - /// - /// From the clippy side it's difficult to detect empty lines between an attributes and the - /// following item because empty lines and comments are not part of the AST. The parsing - /// currently works for basic cases but is not perfect. - /// - /// ### Example - /// ```no_run - /// #[allow(dead_code)] - /// - /// fn not_quite_good_code() { } - /// ``` - /// - /// Use instead: - /// ```no_run - /// // Good (as inner attribute) - /// #![allow(dead_code)] - /// - /// fn this_is_fine() { } - /// - /// // or - /// - /// // Good (as outer attribute) - /// #[allow(dead_code)] - /// fn this_is_fine_too() { } - /// ``` - #[clippy::version = "pre 1.29.0"] - pub EMPTY_LINE_AFTER_OUTER_ATTR, - nursery, - "empty line after outer attribute" -} - -declare_clippy_lint! { - /// ### What it does - /// Checks for empty lines after documentation comments. - /// - /// ### Why is this bad? - /// The documentation comment was most likely meant to be an inner attribute or regular comment. - /// If it was intended to be a documentation comment, then the empty line should be removed to - /// be more idiomatic. - /// - /// ### Known problems - /// Only detects empty lines immediately following the documentation. If the doc comment is followed - /// by an attribute and then an empty line, this lint will not trigger. Use `empty_line_after_outer_attr` - /// in combination with this lint to detect both cases. - /// - /// Does not detect empty lines after doc attributes (e.g. `#[doc = ""]`). - /// - /// ### Example - /// ```no_run - /// /// Some doc comment with a blank line after it. - /// - /// fn not_quite_good_code() { } - /// ``` - /// - /// Use instead: - /// ```no_run - /// /// Good (no blank line) - /// fn this_is_fine() { } - /// ``` - /// - /// ```no_run - /// // Good (convert to a regular comment) - /// - /// fn this_is_fine_too() { } - /// ``` - /// - /// ```no_run - /// //! Good (convert to a comment on an inner attribute) - /// - /// fn this_is_fine_as_well() { } - /// ``` - #[clippy::version = "1.70.0"] - pub EMPTY_LINE_AFTER_DOC_COMMENTS, - nursery, - "empty line after documentation comments" -} - declare_clippy_lint! { /// ### What it does /// Checks for `warn`/`deny`/`forbid` attributes targeting the whole clippy::restriction category. @@ -601,18 +512,12 @@ impl EarlyAttributes { impl_lint_pass!(EarlyAttributes => [ DEPRECATED_CFG_ATTR, - EMPTY_LINE_AFTER_OUTER_ATTR, - EMPTY_LINE_AFTER_DOC_COMMENTS, NON_MINIMAL_CFG, DEPRECATED_CLIPPY_CFG_ATTR, UNNECESSARY_CLIPPY_CFG, ]); impl EarlyLintPass for EarlyAttributes { - fn check_item(&mut self, cx: &EarlyContext<'_>, item: &rustc_ast::Item) { - empty_line_after::check(cx, item); - } - fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &Attribute) { deprecated_cfg_attr::check(cx, attr, &self.msrv); deprecated_cfg_attr::check_clippy(cx, attr); diff --git a/clippy_lints/src/attrs/useless_attribute.rs b/clippy_lints/src/attrs/useless_attribute.rs index 67ba605a59f..12668c616c1 100644 --- a/clippy_lints/src/attrs/useless_attribute.rs +++ b/clippy_lints/src/attrs/useless_attribute.rs @@ -1,7 +1,7 @@ use super::utils::{extract_clippy_lint, is_lint_level, is_word}; use super::{Attribute, USELESS_ATTRIBUTE}; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::{first_line_of_span, SpanRangeExt}; +use clippy_utils::source::{SpanRangeExt, first_line_of_span}; use rustc_ast::NestedMetaItem; use rustc_errors::Applicability; use rustc_hir::{Item, ItemKind}; @@ -51,6 +51,7 @@ pub(super) fn check(cx: &LateContext<'_>, item: &Item<'_>, attrs: &[Attribute]) | "module_name_repetitions" | "single_component_path_imports" | "disallowed_types" + | "unused_trait_names" ) }) { return; diff --git a/clippy_lints/src/await_holding_invalid.rs b/clippy_lints/src/await_holding_invalid.rs index d5f017b2650..9952d0af99e 100644 --- a/clippy_lints/src/await_holding_invalid.rs +++ b/clippy_lints/src/await_holding_invalid.rs @@ -7,7 +7,7 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::mir::CoroutineLayout; use rustc_middle::ty::TyCtxt; use rustc_session::impl_lint_pass; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/booleans.rs b/clippy_lints/src/booleans.rs index e933fdf1d6e..3c2af72624f 100644 --- a/clippy_lints/src/booleans.rs +++ b/clippy_lints/src/booleans.rs @@ -4,12 +4,12 @@ use clippy_utils::source::SpanRangeExt; use clippy_utils::ty::{implements_trait, is_type_diagnostic_item}; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; -use rustc_hir::intravisit::{walk_expr, FnKind, Visitor}; +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_session::declare_lint_pass; use rustc_span::def_id::LocalDefId; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/box_default.rs b/clippy_lints/src/box_default.rs index 8459f051d3d..8261c65354f 100644 --- a/clippy_lints/src/box_default.rs +++ b/clippy_lints/src/box_default.rs @@ -4,7 +4,7 @@ use clippy_utils::ty::expr_sig; use clippy_utils::{is_default_equivalent, path_def_id}; use rustc_errors::Applicability; use rustc_hir::def::Res; -use rustc_hir::intravisit::{walk_ty, Visitor}; +use rustc_hir::intravisit::{Visitor, walk_ty}; use rustc_hir::{Block, Expr, ExprKind, LetStmt, Node, QPath, Ty, TyKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; diff --git a/clippy_lints/src/byte_char_slices.rs b/clippy_lints/src/byte_char_slices.rs index a9fe190f177..dd2620b0b9d 100644 --- a/clippy_lints/src/byte_char_slices.rs +++ b/clippy_lints/src/byte_char_slices.rs @@ -22,7 +22,7 @@ declare_clippy_lint! { /// ```ignore /// b"Hello" /// ``` - #[clippy::version = "1.68.0"] + #[clippy::version = "1.81.0"] pub BYTE_CHAR_SLICES, style, "hard to read byte char slice" diff --git a/clippy_lints/src/cargo/lint_groups_priority.rs b/clippy_lints/src/cargo/lint_groups_priority.rs index e924542fea2..ffd6c520c9a 100644 --- a/clippy_lints/src/cargo/lint_groups_priority.rs +++ b/clippy_lints/src/cargo/lint_groups_priority.rs @@ -2,7 +2,7 @@ use super::LINT_GROUPS_PRIORITY; use clippy_utils::diagnostics::span_lint_and_then; use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; -use rustc_lint::{unerased_lint_store, LateContext}; +use rustc_lint::{LateContext, unerased_lint_store}; use rustc_span::{BytePos, Pos, SourceFile, Span, SyntaxContext}; use serde::{Deserialize, Serialize}; use std::collections::BTreeMap; diff --git a/clippy_lints/src/casts/cast_lossless.rs b/clippy_lints/src/casts/cast_lossless.rs index 346aed7e9f1..84a44b14dde 100644 --- a/clippy_lints/src/casts/cast_lossless.rs +++ b/clippy_lints/src/casts/cast_lossless.rs @@ -10,7 +10,7 @@ use rustc_lint::LateContext; use rustc_middle::ty::{self, FloatTy, Ty}; use rustc_span::hygiene; -use super::{utils, CAST_LOSSLESS}; +use super::{CAST_LOSSLESS, utils}; pub(super) fn check( cx: &LateContext<'_>, diff --git a/clippy_lints/src/casts/cast_possible_truncation.rs b/clippy_lints/src/casts/cast_possible_truncation.rs index 5708aae3f3e..40a1a9d1ce8 100644 --- a/clippy_lints/src/casts/cast_possible_truncation.rs +++ b/clippy_lints/src/casts/cast_possible_truncation.rs @@ -12,7 +12,7 @@ use rustc_middle::ty::{self, FloatTy, Ty}; use rustc_span::Span; use rustc_target::abi::IntegerType; -use super::{utils, CAST_ENUM_TRUNCATION, CAST_POSSIBLE_TRUNCATION}; +use super::{CAST_ENUM_TRUNCATION, CAST_POSSIBLE_TRUNCATION, utils}; fn constant_int(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option { if let Some(Constant::Int(c)) = ConstEvalCtxt::new(cx).eval(expr) { diff --git a/clippy_lints/src/casts/cast_possible_wrap.rs b/clippy_lints/src/casts/cast_possible_wrap.rs index 11274383595..3cf4a43b0d4 100644 --- a/clippy_lints/src/casts/cast_possible_wrap.rs +++ b/clippy_lints/src/casts/cast_possible_wrap.rs @@ -3,7 +3,7 @@ use rustc_hir::Expr; use rustc_lint::LateContext; use rustc_middle::ty::Ty; -use super::{utils, CAST_POSSIBLE_WRAP}; +use super::{CAST_POSSIBLE_WRAP, utils}; // this should be kept in sync with the allowed bit widths of `usize` and `isize` const ALLOWED_POINTER_SIZES: [u64; 3] = [16, 32, 64]; diff --git a/clippy_lints/src/casts/cast_precision_loss.rs b/clippy_lints/src/casts/cast_precision_loss.rs index 035666e4d4c..1eb115ce6bd 100644 --- a/clippy_lints/src/casts/cast_precision_loss.rs +++ b/clippy_lints/src/casts/cast_precision_loss.rs @@ -4,7 +4,7 @@ use rustc_hir::Expr; use rustc_lint::LateContext; use rustc_middle::ty::{self, FloatTy, Ty}; -use super::{utils, CAST_PRECISION_LOSS}; +use super::{CAST_PRECISION_LOSS, utils}; pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>) { if !cast_from.is_integral() || cast_to.is_integral() { diff --git a/clippy_lints/src/casts/cast_sign_loss.rs b/clippy_lints/src/casts/cast_sign_loss.rs index 9daf237344a..4be53ace687 100644 --- a/clippy_lints/src/casts/cast_sign_loss.rs +++ b/clippy_lints/src/casts/cast_sign_loss.rs @@ -3,7 +3,7 @@ use std::ops::ControlFlow; use clippy_utils::consts::{ConstEvalCtxt, Constant}; use clippy_utils::diagnostics::span_lint; -use clippy_utils::visitors::{for_each_expr_without_closures, Descend}; +use clippy_utils::visitors::{Descend, for_each_expr_without_closures}; use clippy_utils::{method_chain_args, sext}; use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::LateContext; diff --git a/clippy_lints/src/casts/fn_to_numeric_cast.rs b/clippy_lints/src/casts/fn_to_numeric_cast.rs index dbe03e4ae80..ac1a355c8d9 100644 --- a/clippy_lints/src/casts/fn_to_numeric_cast.rs +++ b/clippy_lints/src/casts/fn_to_numeric_cast.rs @@ -5,7 +5,7 @@ use rustc_hir::Expr; use rustc_lint::LateContext; use rustc_middle::ty::{self, Ty, UintTy}; -use super::{utils, FN_TO_NUMERIC_CAST}; +use super::{FN_TO_NUMERIC_CAST, utils}; pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>) { // We only want to check casts to `ty::Uint` or `ty::Int` diff --git a/clippy_lints/src/casts/fn_to_numeric_cast_with_truncation.rs b/clippy_lints/src/casts/fn_to_numeric_cast_with_truncation.rs index dfbae1618ac..18e7798452e 100644 --- a/clippy_lints/src/casts/fn_to_numeric_cast_with_truncation.rs +++ b/clippy_lints/src/casts/fn_to_numeric_cast_with_truncation.rs @@ -5,7 +5,7 @@ use rustc_hir::Expr; use rustc_lint::LateContext; use rustc_middle::ty::{self, Ty}; -use super::{utils, FN_TO_NUMERIC_CAST_WITH_TRUNCATION}; +use super::{FN_TO_NUMERIC_CAST_WITH_TRUNCATION, utils}; pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>) { // We only want to check casts to `ty::Uint` or `ty::Int` diff --git a/clippy_lints/src/casts/mod.rs b/clippy_lints/src/casts/mod.rs index c31716fbcee..3acd4eca420 100644 --- a/clippy_lints/src/casts/mod.rs +++ b/clippy_lints/src/casts/mod.rs @@ -23,8 +23,8 @@ mod unnecessary_cast; mod utils; mod zero_ptr; -use clippy_config::msrvs::{self, Msrv}; use clippy_config::Conf; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::is_hir_ty_cfg_dependant; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; @@ -410,19 +410,27 @@ declare_clippy_lint! { /// ### Why is this bad? /// Though `as` casts between raw pointers are not terrible, `pointer::cast_mut` and /// `pointer::cast_const` are safer because they cannot accidentally cast the pointer to another - /// type. + /// type. Or, when null pointers are involved, `null()` and `null_mut()` can be used directly. /// /// ### Example /// ```no_run /// let ptr: *const u32 = &42_u32; /// let mut_ptr = ptr as *mut u32; /// let ptr = mut_ptr as *const u32; + /// let ptr1 = std::ptr::null::() as *mut u32; + /// let ptr2 = std::ptr::null_mut::() as *const u32; + /// let ptr3 = std::ptr::null::().cast_mut(); + /// let ptr4 = std::ptr::null_mut::().cast_const(); /// ``` /// Use instead: /// ```no_run /// let ptr: *const u32 = &42_u32; /// let mut_ptr = ptr.cast_mut(); /// let ptr = mut_ptr.cast_const(); + /// let ptr1 = std::ptr::null_mut::(); + /// let ptr2 = std::ptr::null::(); + /// let ptr3 = std::ptr::null_mut::(); + /// let ptr4 = std::ptr::null::(); /// ``` #[clippy::version = "1.72.0"] pub PTR_CAST_CONSTNESS, @@ -809,6 +817,7 @@ impl<'tcx> LateLintPass<'tcx> for Casts { char_lit_as_u8::check(cx, expr); ptr_as_ptr::check(cx, expr, &self.msrv); cast_slice_different_sizes::check(cx, expr, &self.msrv); + ptr_cast_constness::check_null_ptr_cast_method(cx, expr); } extract_msrv_attr!(LateContext); diff --git a/clippy_lints/src/casts/ptr_cast_constness.rs b/clippy_lints/src/casts/ptr_cast_constness.rs index 7513e18d408..7518dd2435a 100644 --- a/clippy_lints/src/casts/ptr_cast_constness.rs +++ b/clippy_lints/src/casts/ptr_cast_constness.rs @@ -1,10 +1,12 @@ use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::std_or_core; use clippy_utils::sugg::Sugg; use rustc_errors::Applicability; -use rustc_hir::{Expr, Mutability}; +use rustc_hir::{Expr, ExprKind, Mutability, QPath}; use rustc_lint::LateContext; use rustc_middle::ty::{self, Ty, TypeVisitableExt}; +use rustc_span::sym; use super::PTR_CAST_CONSTNESS; @@ -16,8 +18,7 @@ pub(super) fn check<'tcx>( cast_to: Ty<'tcx>, msrv: &Msrv, ) { - if msrv.meets(msrvs::POINTER_CAST_CONSTNESS) - && let ty::RawPtr(from_ty, from_mutbl) = cast_from.kind() + if let ty::RawPtr(from_ty, from_mutbl) = cast_from.kind() && let ty::RawPtr(to_ty, to_mutbl) = cast_to.kind() && matches!( (from_mutbl, to_mutbl), @@ -26,20 +27,74 @@ pub(super) fn check<'tcx>( && from_ty == to_ty && !from_ty.has_erased_regions() { - let sugg = Sugg::hir(cx, cast_expr, "_"); - let constness = match *to_mutbl { - Mutability::Not => "const", - Mutability::Mut => "mut", - }; + if let ExprKind::Call(func, []) = cast_expr.kind + && let ExprKind::Path(QPath::Resolved(None, path)) = func.kind + && let Some(defid) = path.res.opt_def_id() + && let Some(prefix) = std_or_core(cx) + && let mut app = Applicability::MachineApplicable + && let sugg = format!("{}", Sugg::hir_with_applicability(cx, cast_expr, "_", &mut app)) + && let Some((_, after_lt)) = sugg.split_once("::<") + && let Some((source, target, target_func)) = match cx.tcx.get_diagnostic_name(defid) { + Some(sym::ptr_null) => Some(("const", "mutable", "null_mut")), + Some(sym::ptr_null_mut) => Some(("mutable", "const", "null")), + _ => None, + } + { + span_lint_and_sugg( + cx, + PTR_CAST_CONSTNESS, + expr.span, + format!("`as` casting to make a {source} null pointer into a {target} null pointer"), + format!("use `{target_func}()` directly instead"), + format!("{prefix}::ptr::{target_func}::<{after_lt}"), + app, + ); + return; + } + if msrv.meets(msrvs::POINTER_CAST_CONSTNESS) { + let sugg = Sugg::hir(cx, cast_expr, "_"); + let constness = match *to_mutbl { + Mutability::Not => "const", + Mutability::Mut => "mut", + }; + + span_lint_and_sugg( + cx, + PTR_CAST_CONSTNESS, + expr.span, + "`as` casting between raw pointers while changing only its constness", + format!("try `pointer::cast_{constness}`, a safer alternative"), + format!("{}.cast_{constness}()", sugg.maybe_par()), + Applicability::MachineApplicable, + ); + } + } +} + +pub(super) fn check_null_ptr_cast_method(cx: &LateContext<'_>, expr: &Expr<'_>) { + if let ExprKind::MethodCall(method, cast_expr, [], _) = expr.kind + && let ExprKind::Call(func, []) = cast_expr.kind + && let ExprKind::Path(QPath::Resolved(None, path)) = func.kind + && let Some(defid) = path.res.opt_def_id() + && let method = match (cx.tcx.get_diagnostic_name(defid), method.ident.as_str()) { + (Some(sym::ptr_null), "cast_mut") => "null_mut", + (Some(sym::ptr_null_mut), "cast_const") => "null", + _ => return, + } + && let Some(prefix) = std_or_core(cx) + && let mut app = Applicability::MachineApplicable + && let sugg = format!("{}", Sugg::hir_with_applicability(cx, cast_expr, "_", &mut app)) + && let Some((_, after_lt)) = sugg.split_once("::<") + { span_lint_and_sugg( cx, PTR_CAST_CONSTNESS, expr.span, - "`as` casting between raw pointers while changing only its constness", - format!("try `pointer::cast_{constness}`, a safer alternative"), - format!("{}.cast_{constness}()", sugg.maybe_par()), - Applicability::MachineApplicable, + "changing constness of a null pointer", + format!("use `{method}()` directly instead"), + format!("{prefix}::ptr::{method}::<{after_lt}"), + app, ); } } diff --git a/clippy_lints/src/casts/ref_as_ptr.rs b/clippy_lints/src/casts/ref_as_ptr.rs index 5f48b8bd206..dfa240ccec6 100644 --- a/clippy_lints/src/casts/ref_as_ptr.rs +++ b/clippy_lints/src/casts/ref_as_ptr.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; use clippy_utils::sugg::Sugg; -use clippy_utils::{expr_use_ctxt, is_no_std_crate, ExprUseNode}; +use clippy_utils::{ExprUseNode, expr_use_ctxt, is_no_std_crate}; use rustc_errors::Applicability; use rustc_hir::{Expr, Mutability, Ty, TyKind}; use rustc_lint::LateContext; diff --git a/clippy_lints/src/casts/unnecessary_cast.rs b/clippy_lints/src/casts/unnecessary_cast.rs index 566adc83d69..811d33c8bde 100644 --- a/clippy_lints/src/casts/unnecessary_cast.rs +++ b/clippy_lints/src/casts/unnecessary_cast.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::numeric_literal::NumericLiteral; -use clippy_utils::source::{snippet_opt, SpanRangeExt}; -use clippy_utils::visitors::{for_each_expr_without_closures, Visitable}; +use clippy_utils::source::{SpanRangeExt, snippet_opt}; +use clippy_utils::visitors::{Visitable, for_each_expr_without_closures}; use clippy_utils::{get_parent_expr, is_hir_ty_cfg_dependant, is_ty_alias, path_to_local}; use rustc_ast::{LitFloatType, LitIntType, LitKind}; use rustc_errors::Applicability; diff --git a/clippy_lints/src/casts/utils.rs b/clippy_lints/src/casts/utils.rs index 5a4f20f0990..5ccba92a0af 100644 --- a/clippy_lints/src/casts/utils.rs +++ b/clippy_lints/src/casts/utils.rs @@ -1,4 +1,4 @@ -use clippy_utils::ty::{read_explicit_enum_value, EnumValue}; +use clippy_utils::ty::{EnumValue, read_explicit_enum_value}; use rustc_middle::ty::{self, AdtDef, IntTy, Ty, TyCtxt, UintTy, VariantDiscr}; /// Returns the size in bits of an integral type. diff --git a/clippy_lints/src/cfg_not_test.rs b/clippy_lints/src/cfg_not_test.rs index d820c1e0720..884d15cabff 100644 --- a/clippy_lints/src/cfg_not_test.rs +++ b/clippy_lints/src/cfg_not_test.rs @@ -22,7 +22,7 @@ declare_clippy_lint! { /// # fn important_check() {} /// important_check(); /// ``` - #[clippy::version = "1.73.0"] + #[clippy::version = "1.81.0"] pub CFG_NOT_TEST, restriction, "enforce against excluding code from test builds" diff --git a/clippy_lints/src/checked_conversions.rs b/clippy_lints/src/checked_conversions.rs index dd7c34d1e46..d3aa2fd1ea1 100644 --- a/clippy_lints/src/checked_conversions.rs +++ b/clippy_lints/src/checked_conversions.rs @@ -1,8 +1,8 @@ -use clippy_config::msrvs::{self, Msrv}; use clippy_config::Conf; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; -use clippy_utils::{is_in_const_context, is_integer_literal, SpanlessEq}; +use clippy_utils::{SpanlessEq, is_in_const_context, is_integer_literal}; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind, QPath, TyKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; diff --git a/clippy_lints/src/cognitive_complexity.rs b/clippy_lints/src/cognitive_complexity.rs index 0099eefbc8d..495d8ce3fa7 100644 --- a/clippy_lints/src/cognitive_complexity.rs +++ b/clippy_lints/src/cognitive_complexity.rs @@ -3,7 +3,7 @@ use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::source::{IntoSpan, SpanRangeExt}; use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::visitors::for_each_expr_without_closures; -use clippy_utils::{get_async_fn_body, is_async_fn, LimitStack}; +use clippy_utils::{LimitStack, get_async_fn_body, is_async_fn}; use core::ops::ControlFlow; use rustc_ast::ast::Attribute; use rustc_hir::intravisit::FnKind; @@ -11,7 +11,7 @@ use rustc_hir::{Body, Expr, ExprKind, FnDecl}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_session::impl_lint_pass; use rustc_span::def_id::LocalDefId; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/collection_is_never_read.rs b/clippy_lints/src/collection_is_never_read.rs index c6847411c75..8276e53648c 100644 --- a/clippy_lints/src/collection_is_never_read.rs +++ b/clippy_lints/src/collection_is_never_read.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint; use clippy_utils::ty::{get_type_diagnostic_name, is_type_lang_item}; -use clippy_utils::visitors::{for_each_expr, Visitable}; +use clippy_utils::visitors::{Visitable, for_each_expr}; use clippy_utils::{get_enclosing_block, path_to_local_id}; use core::ops::ControlFlow; use rustc_hir::{Body, ExprKind, HirId, LangItem, LetStmt, Node, PatKind}; diff --git a/clippy_lints/src/comparison_chain.rs b/clippy_lints/src/comparison_chain.rs index 5d78744e9b5..b9baf9af248 100644 --- a/clippy_lints/src/comparison_chain.rs +++ b/clippy_lints/src/comparison_chain.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::ty::implements_trait; -use clippy_utils::{if_sequence, is_else_clause, is_in_const_context, SpanlessEq}; +use clippy_utils::{SpanlessEq, if_sequence, is_else_clause, is_in_const_context}; use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; diff --git a/clippy_lints/src/copies.rs b/clippy_lints/src/copies.rs index 86e0368c4e4..d90a22bb62a 100644 --- a/clippy_lints/src/copies.rs +++ b/clippy_lints/src/copies.rs @@ -1,16 +1,17 @@ use clippy_config::Conf; use clippy_utils::diagnostics::{span_lint_and_note, span_lint_and_then}; -use clippy_utils::source::{first_line_of_span, indent_of, reindent_multiline, snippet, IntoSpan, SpanRangeExt}; -use clippy_utils::ty::{needs_ordered_drop, InteriorMut}; +use clippy_utils::source::{IntoSpan, SpanRangeExt, first_line_of_span, indent_of, reindent_multiline, snippet}; +use clippy_utils::ty::{InteriorMut, needs_ordered_drop}; use clippy_utils::visitors::for_each_expr_without_closures; use clippy_utils::{ - capture_local_usage, eq_expr_value, find_binding_init, get_enclosing_block, hash_expr, hash_stmt, if_sequence, - is_else_clause, is_lint_allowed, path_to_local, search_same, ContainsName, HirEqInterExpr, SpanlessEq, + ContainsName, HirEqInterExpr, SpanlessEq, capture_local_usage, eq_expr_value, find_binding_init, + get_enclosing_block, hash_expr, hash_stmt, if_sequence, is_else_clause, is_lint_allowed, path_to_local, + search_same, }; use core::iter; use core::ops::ControlFlow; use rustc_errors::Applicability; -use rustc_hir::{intravisit, BinOpKind, Block, Expr, ExprKind, HirId, HirIdSet, Stmt, StmtKind}; +use rustc_hir::{BinOpKind, Block, Expr, ExprKind, HirId, HirIdSet, Stmt, StmtKind, intravisit}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::TyCtxt; use rustc_session::impl_lint_pass; diff --git a/clippy_lints/src/crate_in_macro_def.rs b/clippy_lints/src/crate_in_macro_def.rs index 678bdbc0ffb..c8f81413728 100644 --- a/clippy_lints/src/crate_in_macro_def.rs +++ b/clippy_lints/src/crate_in_macro_def.rs @@ -5,8 +5,8 @@ use rustc_ast::tokenstream::{TokenStream, TokenTree}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_session::declare_lint_pass; -use rustc_span::symbol::sym; use rustc_span::Span; +use rustc_span::symbol::sym; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/dbg_macro.rs b/clippy_lints/src/dbg_macro.rs index 93c8fff05e9..a96c86f0765 100644 --- a/clippy_lints/src/dbg_macro.rs +++ b/clippy_lints/src/dbg_macro.rs @@ -1,7 +1,7 @@ use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::is_in_test; -use clippy_utils::macros::{macro_backtrace, MacroCall}; +use clippy_utils::macros::{MacroCall, macro_backtrace}; use clippy_utils::source::snippet_with_applicability; use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; @@ -9,7 +9,7 @@ use rustc_hir::{Expr, ExprKind, Node}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_session::impl_lint_pass; -use rustc_span::{sym, Span, SyntaxContext}; +use rustc_span::{Span, SyntaxContext, sym}; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index 60e51713173..2b229d2fe6a 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -49,8 +49,6 @@ pub static LINTS: &[&crate::LintInfo] = &[ crate::attrs::DEPRECATED_CLIPPY_CFG_ATTR_INFO, crate::attrs::DEPRECATED_SEMVER_INFO, crate::attrs::DUPLICATED_ATTRIBUTES_INFO, - crate::attrs::EMPTY_LINE_AFTER_DOC_COMMENTS_INFO, - crate::attrs::EMPTY_LINE_AFTER_OUTER_ATTR_INFO, crate::attrs::INLINE_ALWAYS_INFO, crate::attrs::MIXED_ATTRIBUTES_STYLE_INFO, crate::attrs::NON_MINIMAL_CFG_INFO, @@ -138,6 +136,8 @@ pub static LINTS: &[&crate::LintInfo] = &[ crate::doc::DOC_LINK_WITH_QUOTES_INFO, crate::doc::DOC_MARKDOWN_INFO, crate::doc::EMPTY_DOCS_INFO, + crate::doc::EMPTY_LINE_AFTER_DOC_COMMENTS_INFO, + crate::doc::EMPTY_LINE_AFTER_OUTER_ATTR_INFO, crate::doc::MISSING_ERRORS_DOC_INFO, crate::doc::MISSING_PANICS_DOC_INFO, crate::doc::MISSING_SAFETY_DOC_INFO, @@ -217,6 +217,7 @@ pub static LINTS: &[&crate::LintInfo] = &[ crate::implicit_return::IMPLICIT_RETURN_INFO, crate::implicit_saturating_add::IMPLICIT_SATURATING_ADD_INFO, crate::implicit_saturating_sub::IMPLICIT_SATURATING_SUB_INFO, + crate::implicit_saturating_sub::INVERTED_SATURATING_SUB_INFO, crate::implied_bounds_in_impls::IMPLIED_BOUNDS_IN_IMPLS_INFO, crate::incompatible_msrv::INCOMPATIBLE_MSRV_INFO, crate::inconsistent_struct_constructor::INCONSISTENT_STRUCT_CONSTRUCTOR_INFO, @@ -300,10 +301,12 @@ pub static LINTS: &[&crate::LintInfo] = &[ crate::manual_async_fn::MANUAL_ASYNC_FN_INFO, crate::manual_bits::MANUAL_BITS_INFO, crate::manual_clamp::MANUAL_CLAMP_INFO, + crate::manual_div_ceil::MANUAL_DIV_CEIL_INFO, crate::manual_float_methods::MANUAL_IS_FINITE_INFO, crate::manual_float_methods::MANUAL_IS_INFINITE_INFO, crate::manual_hash_one::MANUAL_HASH_ONE_INFO, crate::manual_is_ascii_check::MANUAL_IS_ASCII_CHECK_INFO, + crate::manual_is_power_of_two::MANUAL_IS_POWER_OF_TWO_INFO, crate::manual_let_else::MANUAL_LET_ELSE_INFO, crate::manual_main_separator_str::MANUAL_MAIN_SEPARATOR_STR_INFO, crate::manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE_INFO, @@ -464,6 +467,7 @@ pub static LINTS: &[&crate::LintInfo] = &[ crate::methods::UNNECESSARY_FALLIBLE_CONVERSIONS_INFO, crate::methods::UNNECESSARY_FILTER_MAP_INFO, crate::methods::UNNECESSARY_FIND_MAP_INFO, + crate::methods::UNNECESSARY_FIRST_THEN_CHECK_INFO, crate::methods::UNNECESSARY_FOLD_INFO, crate::methods::UNNECESSARY_GET_THEN_CHECK_INFO, crate::methods::UNNECESSARY_JOIN_INFO, @@ -486,6 +490,7 @@ pub static LINTS: &[&crate::LintInfo] = &[ crate::misc::SHORT_CIRCUIT_STATEMENT_INFO, crate::misc::TOPLEVEL_REF_ARG_INFO, crate::misc::USED_UNDERSCORE_BINDING_INFO, + crate::misc::USED_UNDERSCORE_ITEMS_INFO, crate::misc_early::BUILTIN_TYPE_SHADOW_INFO, crate::misc_early::DOUBLE_NEG_INFO, crate::misc_early::DUPLICATE_UNDERSCORE_ARGUMENT_INFO, @@ -553,6 +558,7 @@ pub static LINTS: &[&crate::LintInfo] = &[ crate::non_expressive_names::SIMILAR_NAMES_INFO, crate::non_octal_unix_permissions::NON_OCTAL_UNIX_PERMISSIONS_INFO, crate::non_send_fields_in_send_ty::NON_SEND_FIELDS_IN_SEND_TY_INFO, + crate::non_zero_suggestions::NON_ZERO_SUGGESTIONS_INFO, crate::nonstandard_macro_braces::NONSTANDARD_MACRO_BRACES_INFO, crate::octal_escapes::OCTAL_ESCAPES_INFO, crate::only_used_in_recursion::ONLY_USED_IN_RECURSION_INFO, @@ -598,6 +604,7 @@ pub static LINTS: &[&crate::LintInfo] = &[ crate::pathbuf_init_then_push::PATHBUF_INIT_THEN_PUSH_INFO, crate::pattern_type_mismatch::PATTERN_TYPE_MISMATCH_INFO, crate::permissions_set_readonly_false::PERMISSIONS_SET_READONLY_FALSE_INFO, + crate::pointers_in_nomem_asm_block::POINTERS_IN_NOMEM_ASM_BLOCK_INFO, crate::precedence::PRECEDENCE_INFO, crate::ptr::CMP_NULL_INFO, crate::ptr::INVALID_NULL_PTR_USAGE_INFO, @@ -741,6 +748,7 @@ pub static LINTS: &[&crate::LintInfo] = &[ crate::unused_result_ok::UNUSED_RESULT_OK_INFO, crate::unused_rounding::UNUSED_ROUNDING_INFO, crate::unused_self::UNUSED_SELF_INFO, + crate::unused_trait_names::UNUSED_TRAIT_NAMES_INFO, crate::unused_unit::UNUSED_UNIT_INFO, crate::unwrap::PANICKING_UNWRAP_INFO, crate::unwrap::UNNECESSARY_UNWRAP_INFO, @@ -767,4 +775,5 @@ pub static LINTS: &[&crate::LintInfo] = &[ crate::zero_div_zero::ZERO_DIVIDED_BY_ZERO_INFO, crate::zero_repeat_side_effects::ZERO_REPEAT_SIDE_EFFECTS_INFO, crate::zero_sized_map_values::ZERO_SIZED_MAP_VALUES_INFO, + crate::zombie_processes::ZOMBIE_PROCESSES_INFO, ]; diff --git a/clippy_lints/src/default.rs b/clippy_lints/src/default.rs index 0b7279f2b36..dc10b64698b 100644 --- a/clippy_lints/src/default.rs +++ b/clippy_lints/src/default.rs @@ -11,7 +11,7 @@ use rustc_middle::ty; use rustc_middle::ty::print::with_forced_trimmed_paths; use rustc_session::impl_lint_pass; use rustc_span::symbol::{Ident, Symbol}; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/default_constructed_unit_structs.rs b/clippy_lints/src/default_constructed_unit_structs.rs index 13778175496..33a97222b8f 100644 --- a/clippy_lints/src/default_constructed_unit_structs.rs +++ b/clippy_lints/src/default_constructed_unit_structs.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::is_ty_alias; -use hir::def::Res; use hir::ExprKind; +use hir::def::Res; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; diff --git a/clippy_lints/src/default_instead_of_iter_empty.rs b/clippy_lints/src/default_instead_of_iter_empty.rs index ac49e6f1a48..056e39c02af 100644 --- a/clippy_lints/src/default_instead_of_iter_empty.rs +++ b/clippy_lints/src/default_instead_of_iter_empty.rs @@ -2,10 +2,10 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_context; use clippy_utils::{last_path_segment, std_or_core}; use rustc_errors::Applicability; -use rustc_hir::{def, Expr, ExprKind, GenericArg, QPath, TyKind}; +use rustc_hir::{Expr, ExprKind, GenericArg, QPath, TyKind, def}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; -use rustc_span::{sym, SyntaxContext}; +use rustc_span::{SyntaxContext, sym}; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/default_numeric_fallback.rs b/clippy_lints/src/default_numeric_fallback.rs index 05c3cd3c814..a065dc2cf7e 100644 --- a/clippy_lints/src/default_numeric_fallback.rs +++ b/clippy_lints/src/default_numeric_fallback.rs @@ -3,7 +3,7 @@ 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::{walk_expr, walk_stmt, Visitor}; +use rustc_hir::intravisit::{Visitor, walk_expr, walk_stmt}; use rustc_hir::{Block, Body, ConstContext, Expr, ExprKind, FnRetTy, HirId, Lit, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; diff --git a/clippy_lints/src/dereference.rs b/clippy_lints/src/dereference.rs index 0e55d3db469..f34f5e05606 100644 --- a/clippy_lints/src/dereference.rs +++ b/clippy_lints/src/dereference.rs @@ -3,14 +3,14 @@ use clippy_utils::source::{snippet_with_applicability, snippet_with_context}; use clippy_utils::sugg::has_enclosing_paren; use clippy_utils::ty::{implements_trait, is_manually_drop}; use clippy_utils::{ - expr_use_ctxt, get_parent_expr, is_block_like, is_lint_allowed, path_to_local, peel_middle_ty_refs, DefinedTy, - ExprUseNode, + DefinedTy, ExprUseNode, expr_use_ctxt, get_parent_expr, is_block_like, is_lint_allowed, path_to_local, + peel_middle_ty_refs, }; use core::mem; use rustc_ast::util::parser::{PREC_PREFIX, PREC_UNAMBIGUOUS}; use rustc_data_structures::fx::FxIndexMap; use rustc_errors::Applicability; -use rustc_hir::intravisit::{walk_ty, Visitor}; +use rustc_hir::intravisit::{Visitor, walk_ty}; use rustc_hir::{ self as hir, BindingMode, Body, BodyId, BorrowKind, Expr, ExprKind, HirId, MatchSource, Mutability, Node, Pat, PatKind, Path, QPath, TyKind, UnOp, @@ -290,13 +290,10 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> { && let Some(ty) = use_node.defined_ty(cx) && TyCoercionStability::for_defined_ty(cx, ty, use_node.is_return()).is_deref_stable() { - self.state = Some(( - State::ExplicitDeref { mutability: None }, - StateData { - first_expr: expr, - adjusted_ty, - }, - )); + self.state = Some((State::ExplicitDeref { mutability: None }, StateData { + first_expr: expr, + adjusted_ty, + })); } }, RefOp::Method { mutbl, is_ufcs } @@ -458,13 +455,10 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> { && next_adjust.map_or(true, |a| matches!(a.kind, Adjust::Deref(_) | Adjust::Borrow(_))) && iter.all(|a| matches!(a.kind, Adjust::Deref(_) | Adjust::Borrow(_))) { - self.state = Some(( - State::Borrow { mutability }, - StateData { - first_expr: expr, - adjusted_ty, - }, - )); + self.state = Some((State::Borrow { mutability }, StateData { + first_expr: expr, + adjusted_ty, + })); } }, _ => {}, @@ -508,13 +502,10 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> { let stability = state.stability; report(cx, expr, State::DerefedBorrow(state), data, typeck); if stability.is_deref_stable() { - self.state = Some(( - State::Borrow { mutability }, - StateData { - first_expr: expr, - adjusted_ty, - }, - )); + self.state = Some((State::Borrow { mutability }, StateData { + first_expr: expr, + adjusted_ty, + })); } }, (Some((State::DerefedBorrow(state), data)), RefOp::Deref) => { @@ -539,13 +530,10 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> { } else if stability.is_deref_stable() && let Some(parent) = get_parent_expr(cx, expr) { - self.state = Some(( - State::ExplicitDeref { mutability: None }, - StateData { - first_expr: parent, - adjusted_ty, - }, - )); + self.state = Some((State::ExplicitDeref { mutability: None }, StateData { + first_expr: parent, + adjusted_ty, + })); } }, @@ -1138,20 +1126,17 @@ impl<'tcx> Dereferencing<'tcx> { if let Some(outer_pat) = self.ref_locals.get_mut(&local) { if let Some(pat) = outer_pat { // Check for auto-deref - if !matches!( - cx.typeck_results().expr_adjustments(e), - [ - Adjustment { - kind: Adjust::Deref(_), - .. - }, - Adjustment { - kind: Adjust::Deref(_), - .. - }, + if !matches!(cx.typeck_results().expr_adjustments(e), [ + Adjustment { + kind: Adjust::Deref(_), .. - ] - ) { + }, + Adjustment { + kind: Adjust::Deref(_), + .. + }, + .. + ]) { match get_parent_expr(cx, e) { // Field accesses are the same no matter the number of references. Some(Expr { diff --git a/clippy_lints/src/derivable_impls.rs b/clippy_lints/src/derivable_impls.rs index f27f68e2cbc..2920bbb4c81 100644 --- a/clippy_lints/src/derivable_impls.rs +++ b/clippy_lints/src/derivable_impls.rs @@ -1,5 +1,5 @@ -use clippy_config::msrvs::{self, Msrv}; use clippy_config::Conf; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::indent_of; use clippy_utils::{is_default_equivalent, peel_blocks}; diff --git a/clippy_lints/src/derive.rs b/clippy_lints/src/derive.rs index 636698e96f6..61c151d4f9d 100644 --- a/clippy_lints/src/derive.rs +++ b/clippy_lints/src/derive.rs @@ -3,7 +3,7 @@ use clippy_utils::ty::{implements_trait, implements_trait_with_env, is_copy}; use clippy_utils::{has_non_exhaustive_attr, is_lint_allowed, match_def_path, paths}; use rustc_errors::Applicability; use rustc_hir::def_id::DefId; -use rustc_hir::intravisit::{walk_expr, walk_fn, walk_item, FnKind, Visitor}; +use rustc_hir::intravisit::{FnKind, Visitor, walk_expr, walk_fn, walk_item}; use rustc_hir::{ self as hir, BlockCheckMode, BodyId, Expr, ExprKind, FnDecl, Impl, Item, ItemKind, Safety, UnsafeSource, }; @@ -15,7 +15,7 @@ use rustc_middle::ty::{ }; use rustc_session::declare_lint_pass; use rustc_span::def_id::LocalDefId; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/doc/empty_line_after.rs b/clippy_lints/src/doc/empty_line_after.rs new file mode 100644 index 00000000000..de7a2c2433f --- /dev/null +++ b/clippy_lints/src/doc/empty_line_after.rs @@ -0,0 +1,342 @@ +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::source::{SpanRangeExt, snippet_indent}; +use clippy_utils::tokenize_with_text; +use itertools::Itertools; +use rustc_ast::token::CommentKind; +use rustc_ast::{AttrKind, AttrStyle, Attribute}; +use rustc_errors::{Applicability, Diag, SuggestionStyle}; +use rustc_hir::{ItemKind, Node}; +use rustc_lexer::TokenKind; +use rustc_lint::LateContext; +use rustc_span::{BytePos, ExpnKind, InnerSpan, Span, SpanData}; + +use super::{EMPTY_LINE_AFTER_DOC_COMMENTS, EMPTY_LINE_AFTER_OUTER_ATTR}; + +#[derive(Debug, PartialEq, Clone, Copy)] +enum StopKind { + Attr, + Doc(CommentKind), +} + +impl StopKind { + fn is_doc(self) -> bool { + matches!(self, StopKind::Doc(_)) + } +} + +#[derive(Debug)] +struct Stop { + span: Span, + kind: StopKind, + first: usize, + last: usize, +} + +impl Stop { + fn convert_to_inner(&self) -> (Span, String) { + let inner = match self.kind { + // #|[...] + StopKind::Attr => InnerSpan::new(1, 1), + // /// or /** + // ^ ^ + StopKind::Doc(_) => InnerSpan::new(2, 3), + }; + (self.span.from_inner(inner), "!".into()) + } + + fn comment_out(&self, cx: &LateContext<'_>, suggestions: &mut Vec<(Span, String)>) { + match self.kind { + StopKind::Attr => { + if cx.tcx.sess.source_map().is_multiline(self.span) { + suggestions.extend([ + (self.span.shrink_to_lo(), "/* ".into()), + (self.span.shrink_to_hi(), " */".into()), + ]); + } else { + suggestions.push((self.span.shrink_to_lo(), "// ".into())); + } + }, + StopKind::Doc(CommentKind::Line) => suggestions.push((self.span.shrink_to_lo(), "// ".into())), + StopKind::Doc(CommentKind::Block) => { + // /** outer */ /*! inner */ + // ^ ^ + let asterisk = self.span.from_inner(InnerSpan::new(1, 2)); + suggestions.push((asterisk, String::new())); + }, + } + } + + fn from_attr(cx: &LateContext<'_>, attr: &Attribute) -> Option { + let SpanData { lo, hi, .. } = attr.span.data(); + let file = cx.tcx.sess.source_map().lookup_source_file(lo); + + Some(Self { + span: attr.span, + kind: match attr.kind { + AttrKind::Normal(_) => StopKind::Attr, + AttrKind::DocComment(comment_kind, _) => StopKind::Doc(comment_kind), + }, + first: file.lookup_line(file.relative_position(lo))?, + last: file.lookup_line(file.relative_position(hi))?, + }) + } +} + +/// Represents a set of attrs/doc comments separated by 1 or more empty lines +/// +/// ```ignore +/// /// chunk 1 docs +/// // not an empty line so also part of chunk 1 +/// #[chunk_1_attrs] // <-- prev_stop +/// +/// /* gap */ +/// +/// /// chunk 2 docs // <-- next_stop +/// #[chunk_2_attrs] +/// ``` +struct Gap<'a> { + /// The span of individual empty lines including the newline at the end of the line + empty_lines: Vec, + has_comment: bool, + next_stop: &'a Stop, + prev_stop: &'a Stop, + /// The chunk that includes [`prev_stop`](Self::prev_stop) + prev_chunk: &'a [Stop], +} + +impl<'a> Gap<'a> { + fn new(cx: &LateContext<'_>, prev_chunk: &'a [Stop], next_chunk: &'a [Stop]) -> Option { + let prev_stop = prev_chunk.last()?; + let next_stop = next_chunk.first()?; + let gap_span = prev_stop.span.between(next_stop.span); + let gap_snippet = gap_span.get_source_text(cx)?; + + let mut has_comment = false; + let mut empty_lines = Vec::new(); + + for (token, source, inner_span) in tokenize_with_text(&gap_snippet) { + match token { + TokenKind::BlockComment { + doc_style: None, + terminated: true, + } + | TokenKind::LineComment { doc_style: None } => has_comment = true, + TokenKind::Whitespace => { + let newlines = source.bytes().positions(|b| b == b'\n'); + empty_lines.extend( + newlines + .tuple_windows() + .map(|(a, b)| InnerSpan::new(inner_span.start + a + 1, inner_span.start + b)) + .map(|inner_span| gap_span.from_inner(inner_span)), + ); + }, + // Ignore cfg_attr'd out attributes as they may contain empty lines, could also be from macro + // shenanigans + _ => return None, + } + } + + (!empty_lines.is_empty()).then_some(Self { + empty_lines, + has_comment, + next_stop, + prev_stop, + prev_chunk, + }) + } + + fn contiguous_empty_lines(&self) -> impl Iterator + '_ { + self.empty_lines + // The `+ BytePos(1)` means "next line", because each empty line span is "N:1-N:1". + .chunk_by(|a, b| a.hi() + BytePos(1) == b.lo()) + .map(|chunk| { + let first = chunk.first().expect("at least one empty line"); + let last = chunk.last().expect("at least one empty line"); + // The BytePos subtraction here is safe, as before an empty line, there must be at least one + // attribute/comment. The span needs to start at the end of the previous line. + first.with_lo(first.lo() - BytePos(1)).with_hi(last.hi()) + }) + } +} + +/// If the node the attributes/docs apply to is the first in the module/crate suggest converting +/// them to inner attributes/docs +fn suggest_inner(cx: &LateContext<'_>, diag: &mut Diag<'_, ()>, kind: StopKind, gaps: &[Gap<'_>]) { + let Some(owner) = cx.last_node_with_lint_attrs.as_owner() else { + return; + }; + let parent_desc = match cx.tcx.parent_hir_node(owner.into()) { + Node::Item(item) + if let ItemKind::Mod(parent_mod) = item.kind + && let [first, ..] = parent_mod.item_ids + && first.owner_id == owner => + { + "parent module" + }, + Node::Crate(crate_mod) + if let Some(first) = crate_mod + .item_ids + .iter() + .map(|&id| cx.tcx.hir().item(id)) + // skip prelude imports + .find(|item| !matches!(item.span.ctxt().outer_expn_data().kind, ExpnKind::AstPass(_))) + && first.owner_id == owner => + { + "crate" + }, + _ => return, + }; + + diag.multipart_suggestion_verbose( + match kind { + StopKind::Attr => format!("if the attribute should apply to the {parent_desc} use an inner attribute"), + StopKind::Doc(_) => format!("if the comment should document the {parent_desc} use an inner doc comment"), + }, + gaps.iter() + .flat_map(|gap| gap.prev_chunk) + .map(Stop::convert_to_inner) + .collect(), + Applicability::MaybeIncorrect, + ); +} + +fn check_gaps(cx: &LateContext<'_>, gaps: &[Gap<'_>]) -> bool { + let Some(first_gap) = gaps.first() else { + return false; + }; + let empty_lines = || gaps.iter().flat_map(|gap| gap.empty_lines.iter().copied()); + let contiguous_empty_lines = || gaps.iter().flat_map(Gap::contiguous_empty_lines); + let mut has_comment = false; + let mut has_attr = false; + for gap in gaps { + has_comment |= gap.has_comment; + if !has_attr { + has_attr = gap.prev_chunk.iter().any(|stop| stop.kind == StopKind::Attr); + } + } + let kind = first_gap.prev_stop.kind; + let (lint, kind_desc) = match kind { + StopKind::Attr => (EMPTY_LINE_AFTER_OUTER_ATTR, "outer attribute"), + StopKind::Doc(_) => (EMPTY_LINE_AFTER_DOC_COMMENTS, "doc comment"), + }; + let (lines, are, them) = if empty_lines().nth(1).is_some() { + ("lines", "are", "them") + } else { + ("line", "is", "it") + }; + span_lint_and_then( + cx, + lint, + 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() { + let def_id = owner.to_def_id(); + let def_descr = cx.tcx.def_descr(def_id); + diag.span_label(cx.tcx.def_span(def_id), match kind { + StopKind::Attr => format!("the attribute applies to this {def_descr}"), + StopKind::Doc(_) => format!("the comment documents this {def_descr}"), + }); + } + + diag.multipart_suggestion_with_style( + format!("if the empty {lines} {are} unintentional remove {them}"), + contiguous_empty_lines() + .map(|empty_lines| (empty_lines, String::new())) + .collect(), + Applicability::MaybeIncorrect, + SuggestionStyle::HideCodeAlways, + ); + + if has_comment && kind.is_doc() { + // Likely doc comments that applied to some now commented out code + // + // /// Old docs for Foo + // // struct Foo; + + let mut suggestions = Vec::new(); + for stop in gaps.iter().flat_map(|gap| gap.prev_chunk) { + stop.comment_out(cx, &mut suggestions); + } + let name = match cx.tcx.hir().opt_name(cx.last_node_with_lint_attrs) { + Some(name) => format!("`{name}`"), + None => "this".into(), + }; + diag.multipart_suggestion_verbose( + format!("if the doc comment should not document {name} comment it out"), + suggestions, + Applicability::MaybeIncorrect, + ); + } else { + suggest_inner(cx, diag, kind, gaps); + } + + if kind == StopKind::Doc(CommentKind::Line) + && gaps + .iter() + .all(|gap| !gap.has_comment && gap.next_stop.kind == StopKind::Doc(CommentKind::Line)) + { + // Commentless empty gaps between line doc comments, possibly intended to be part of the markdown + + let indent = snippet_indent(cx, first_gap.prev_stop.span).unwrap_or_default(); + diag.multipart_suggestion_verbose( + format!("if the documentation should include the empty {lines} include {them} in the comment"), + empty_lines() + .map(|empty_line| (empty_line, format!("{indent}///"))) + .collect(), + Applicability::MaybeIncorrect, + ); + } + }, + ); + kind.is_doc() +} + +/// Returns `true` if [`EMPTY_LINE_AFTER_DOC_COMMENTS`] triggered, used to skip other doc comment +/// lints where they would be confusing +/// +/// [`EMPTY_LINE_AFTER_OUTER_ATTR`] is also here to share an implementation but does not return +/// `true` if it triggers +pub(super) fn check(cx: &LateContext<'_>, attrs: &[Attribute]) -> bool { + let mut outer = attrs + .iter() + .filter(|attr| attr.style == AttrStyle::Outer && !attr.span.from_expansion()) + .map(|attr| Stop::from_attr(cx, attr)) + .collect::>>() + .unwrap_or_default(); + + if outer.is_empty() { + return false; + } + + // Push a fake attribute Stop for the item itself so we check for gaps between the last outer + // attr/doc comment and the item they apply to + let span = cx.tcx.hir().span(cx.last_node_with_lint_attrs); + if !span.from_expansion() + && let Ok(line) = cx.tcx.sess.source_map().lookup_line(span.lo()) + { + outer.push(Stop { + span, + kind: StopKind::Attr, + first: line.line, + // last doesn't need to be accurate here, we don't compare it with anything + last: line.line, + }); + } + + let mut gaps = Vec::new(); + let mut last = 0; + for pos in outer + .array_windows() + .positions(|[a, b]| b.first.saturating_sub(a.last) > 1) + { + // we want to be after the first stop in the window + let pos = pos + 1; + if let Some(gap) = Gap::new(cx, &outer[last..pos], &outer[pos..]) { + last = pos; + gaps.push(gap); + } + } + + check_gaps(cx, &gaps) +} diff --git a/clippy_lints/src/doc/lazy_continuation.rs b/clippy_lints/src/doc/lazy_continuation.rs index 771bcac2441..f9e4a43c0e7 100644 --- a/clippy_lints/src/doc/lazy_continuation.rs +++ b/clippy_lints/src/doc/lazy_continuation.rs @@ -22,7 +22,6 @@ pub(super) fn check( range: Range, mut span: Span, containers: &[super::Container], - line_break_span: Span, ) { if doc[range.clone()].contains('\t') { // We don't do tab stops correctly. @@ -52,29 +51,6 @@ pub(super) fn check( "doc list item without indentation" }; span_lint_and_then(cx, DOC_LAZY_CONTINUATION, span, msg, |diag| { - let snippet = clippy_utils::source::snippet(cx, line_break_span, ""); - if snippet.chars().filter(|&c| c == '\n').count() > 1 - && let Some(doc_comment_start) = snippet.rfind('\n') - && let doc_comment = snippet[doc_comment_start..].trim() - && (doc_comment == "///" || doc_comment == "//!") - { - // suggest filling in a blank line - diag.span_suggestion_verbose( - line_break_span.shrink_to_lo(), - "if this should be its own paragraph, add a blank doc comment line", - format!("\n{doc_comment}"), - Applicability::MaybeIncorrect, - ); - if ccount > 0 || blockquote_level > 0 { - diag.help("if this not intended to be a quote at all, escape it with `\\>`"); - } else { - let indent = list_indentation - lcount; - diag.help(format!( - "if this is intended to be part of the list, indent {indent} spaces" - )); - } - return; - } if ccount == 0 && blockquote_level == 0 { // simpler suggestion style for indentation let indent = list_indentation - lcount; diff --git a/clippy_lints/src/doc/link_with_quotes.rs b/clippy_lints/src/doc/link_with_quotes.rs index 01191e811b0..1d4345e4541 100644 --- a/clippy_lints/src/doc/link_with_quotes.rs +++ b/clippy_lints/src/doc/link_with_quotes.rs @@ -3,7 +3,7 @@ use std::ops::Range; use clippy_utils::diagnostics::span_lint; use rustc_lint::LateContext; -use super::{Fragments, DOC_LINK_WITH_QUOTES}; +use super::{DOC_LINK_WITH_QUOTES, Fragments}; pub fn check(cx: &LateContext<'_>, trimmed_text: &str, range: Range, fragments: Fragments<'_>) { if ((trimmed_text.starts_with('\'') && trimmed_text.ends_with('\'')) diff --git a/clippy_lints/src/doc/missing_headers.rs b/clippy_lints/src/doc/missing_headers.rs index e3d74840726..c9173030a55 100644 --- a/clippy_lints/src/doc/missing_headers.rs +++ b/clippy_lints/src/doc/missing_headers.rs @@ -5,7 +5,7 @@ use clippy_utils::{is_doc_hidden, return_ty}; use rustc_hir::{BodyId, FnSig, OwnerId, Safety}; use rustc_lint::LateContext; use rustc_middle::ty; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; pub fn check( cx: &LateContext<'_>, diff --git a/clippy_lints/src/doc/mod.rs b/clippy_lints/src/doc/mod.rs index 790579b21c9..0ae1fad5692 100644 --- a/clippy_lints/src/doc/mod.rs +++ b/clippy_lints/src/doc/mod.rs @@ -23,15 +23,16 @@ use rustc_middle::hir::nested_filter; use rustc_middle::lint::in_external_macro; use rustc_middle::ty; use rustc_resolve::rustdoc::{ - add_doc_fragment, attrs_to_doc_fragments, main_body_opts, source_span_for_markdown_range, span_of_fragments, - DocFragment, + DocFragment, add_doc_fragment, attrs_to_doc_fragments, main_body_opts, source_span_for_markdown_range, + span_of_fragments, }; use rustc_session::impl_lint_pass; use rustc_span::edition::Edition; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; use std::ops::Range; use url::Url; +mod empty_line_after; mod link_with_quotes; mod markdown; mod missing_headers; @@ -449,13 +450,88 @@ declare_clippy_lint! { /// /// and probably spanning a many rows. /// struct Foo {} /// ``` - #[clippy::version = "1.81.0"] + #[clippy::version = "1.82.0"] pub TOO_LONG_FIRST_DOC_PARAGRAPH, style, "ensure that the first line of a documentation paragraph isn't too long" } -#[derive(Clone)] +declare_clippy_lint! { + /// ### What it does + /// Checks for empty lines after outer attributes + /// + /// ### Why is this bad? + /// The attribute may have meant to be an inner attribute (`#![attr]`). If + /// it was meant to be an outer attribute (`#[attr]`) then the empty line + /// should be removed + /// + /// ### Example + /// ```no_run + /// #[allow(dead_code)] + /// + /// fn not_quite_good_code() {} + /// ``` + /// + /// Use instead: + /// ```no_run + /// // Good (as inner attribute) + /// #![allow(dead_code)] + /// + /// fn this_is_fine() {} + /// + /// // or + /// + /// // Good (as outer attribute) + /// #[allow(dead_code)] + /// fn this_is_fine_too() {} + /// ``` + #[clippy::version = "pre 1.29.0"] + pub EMPTY_LINE_AFTER_OUTER_ATTR, + suspicious, + "empty line after outer attribute" +} + +declare_clippy_lint! { + /// ### What it does + /// Checks for empty lines after doc comments. + /// + /// ### Why is this bad? + /// The doc comment may have meant to be an inner doc comment, regular + /// comment or applied to some old code that is now commented out. If it was + /// intended to be a doc comment, then the empty line should be removed. + /// + /// ### Example + /// ```no_run + /// /// Some doc comment with a blank line after it. + /// + /// fn f() {} + /// + /// /// Docs for `old_code` + /// // fn old_code() {} + /// + /// fn new_code() {} + /// ``` + /// + /// Use instead: + /// ```no_run + /// //! Convert it to an inner doc comment + /// + /// // Or a regular comment + /// + /// /// Or remove the empty line + /// fn f() {} + /// + /// // /// Docs for `old_code` + /// // fn old_code() {} + /// + /// fn new_code() {} + /// ``` + #[clippy::version = "1.70.0"] + pub EMPTY_LINE_AFTER_DOC_COMMENTS, + suspicious, + "empty line after doc comments" +} + pub struct Documentation { valid_idents: FxHashSet, check_private_items: bool, @@ -482,6 +558,8 @@ impl_lint_pass!(Documentation => [ SUSPICIOUS_DOC_COMMENTS, EMPTY_DOCS, DOC_LAZY_CONTINUATION, + EMPTY_LINE_AFTER_OUTER_ATTR, + EMPTY_LINE_AFTER_DOC_COMMENTS, TOO_LONG_FIRST_DOC_PARAGRAPH, ]); @@ -612,12 +690,10 @@ fn check_attrs(cx: &LateContext<'_>, valid_idents: &FxHashSet, attrs: &[ Some(("fake".into(), "fake".into())) } - if is_doc_hidden(attrs) { + if suspicious_doc_comments::check(cx, attrs) || empty_line_after::check(cx, attrs) || is_doc_hidden(attrs) { return None; } - suspicious_doc_comments::check(cx, attrs); - let (fragments, _) = attrs_to_doc_fragments( attrs.iter().filter_map(|attr| { if in_external_macro(cx.sess(), attr.span) { @@ -816,7 +892,6 @@ fn check_doc<'a, Events: Iterator, Range, attrs: &[Attribute]) { +pub fn check(cx: &LateContext<'_>, attrs: &[Attribute]) -> bool { let replacements: Vec<_> = collect_doc_replacements(attrs); if let Some((&(lo_span, _), &(hi_span, _))) = replacements.first().zip(replacements.last()) { @@ -24,6 +24,10 @@ pub fn check(cx: &LateContext<'_>, attrs: &[Attribute]) { ); }, ); + + true + } else { + false } } 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 7bb3bb12f2c..0165d24c7df 100644 --- a/clippy_lints/src/doc/too_long_first_doc_paragraph.rs +++ b/clippy_lints/src/doc/too_long_first_doc_paragraph.rs @@ -79,10 +79,17 @@ pub(super) fn check( && let new_span = first_span.with_hi(second_span.lo()).with_lo(first_span.hi()) && let Some(snippet) = snippet_opt(cx, new_span) { + let Some(first) = snippet_opt(cx, first_span) else { + return; + }; + let Some(comment_form) = first.get(..3) else { + return; + }; + diag.span_suggestion( new_span, "add an empty line", - format!("{snippet}///\n"), + format!("{snippet}{comment_form}{snippet}"), Applicability::MachineApplicable, ); } diff --git a/clippy_lints/src/entry.rs b/clippy_lints/src/entry.rs index 9c5100a8c1a..70524e458c7 100644 --- a/clippy_lints/src/entry.rs +++ b/clippy_lints/src/entry.rs @@ -1,17 +1,17 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::{reindent_multiline, snippet_indent, snippet_with_applicability, snippet_with_context}; use clippy_utils::{ - can_move_expr_to_closure_no_visit, higher, is_expr_final_block_expr, is_expr_used_or_unified, - peel_hir_expr_while, SpanlessEq, + SpanlessEq, can_move_expr_to_closure_no_visit, higher, is_expr_final_block_expr, is_expr_used_or_unified, + peel_hir_expr_while, }; use core::fmt::{self, Write}; use rustc_errors::Applicability; use rustc_hir::hir_id::HirIdSet; -use rustc_hir::intravisit::{walk_expr, Visitor}; +use rustc_hir::intravisit::{Visitor, walk_expr}; use rustc_hir::{Block, Expr, ExprKind, HirId, Pat, Stmt, StmtKind, UnOp}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; -use rustc_span::{sym, Span, SyntaxContext, DUMMY_SP}; +use rustc_span::{DUMMY_SP, Span, SyntaxContext, sym}; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/enum_clike.rs b/clippy_lints/src/enum_clike.rs index 4755cefe784..e9e9d00907e 100644 --- a/clippy_lints/src/enum_clike.rs +++ b/clippy_lints/src/enum_clike.rs @@ -1,4 +1,4 @@ -use clippy_utils::consts::{mir_to_const, Constant}; +use clippy_utils::consts::{Constant, mir_to_const}; use clippy_utils::diagnostics::span_lint; use rustc_hir::{Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; diff --git a/clippy_lints/src/escape.rs b/clippy_lints/src/escape.rs index 80360697941..5588124e791 100644 --- a/clippy_lints/src/escape.rs +++ b/clippy_lints/src/escape.rs @@ -1,15 +1,15 @@ use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_hir; -use rustc_hir::{intravisit, AssocItemKind, Body, FnDecl, HirId, HirIdSet, Impl, ItemKind, Node, Pat, PatKind}; +use rustc_hir::{AssocItemKind, Body, FnDecl, HirId, HirIdSet, Impl, ItemKind, Node, Pat, PatKind, intravisit}; use rustc_hir_typeck::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::mir::FakeReadCause; use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::{self, TraitRef, Ty, TyCtxt}; use rustc_session::impl_lint_pass; +use rustc_span::Span; use rustc_span::def_id::LocalDefId; use rustc_span::symbol::kw; -use rustc_span::Span; use rustc_target::spec::abi::Abi; pub struct BoxedLocal { diff --git a/clippy_lints/src/excessive_bools.rs b/clippy_lints/src/excessive_bools.rs index 8f469efb1b5..c88fb50b5af 100644 --- a/clippy_lints/src/excessive_bools.rs +++ b/clippy_lints/src/excessive_bools.rs @@ -5,8 +5,8 @@ use rustc_hir::intravisit::FnKind; use rustc_hir::{Body, FnDecl, Item, ItemKind, TraitFn, TraitItem, TraitItemKind, Ty}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::impl_lint_pass; -use rustc_span::def_id::LocalDefId; use rustc_span::Span; +use rustc_span::def_id::LocalDefId; use rustc_target::spec::abi::Abi; declare_clippy_lint! { diff --git a/clippy_lints/src/excessive_nesting.rs b/clippy_lints/src/excessive_nesting.rs index 5154edd4399..ce0e0faa014 100644 --- a/clippy_lints/src/excessive_nesting.rs +++ b/clippy_lints/src/excessive_nesting.rs @@ -2,7 +2,7 @@ use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::source::snippet; use rustc_ast::node_id::NodeSet; -use rustc_ast::visit::{walk_block, walk_item, Visitor}; +use rustc_ast::visit::{Visitor, walk_block, walk_item}; use rustc_ast::{Block, Crate, Inline, Item, ItemKind, ModKind, NodeId}; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; use rustc_middle::lint::in_external_macro; diff --git a/clippy_lints/src/explicit_write.rs b/clippy_lints/src/explicit_write.rs index 3c4a043a732..5b423a96918 100644 --- a/clippy_lints/src/explicit_write.rs +++ b/clippy_lints/src/explicit_write.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::macros::{format_args_inputs_span, FormatArgsStorage}; +use clippy_utils::macros::{FormatArgsStorage, format_args_inputs_span}; use clippy_utils::source::snippet_with_applicability; use clippy_utils::{is_expn_of, path_def_id}; use rustc_errors::Applicability; @@ -7,7 +7,7 @@ use rustc_hir::def::Res; use rustc_hir::{BindingMode, Block, BlockCheckMode, Expr, ExprKind, Node, PatKind, QPath, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::impl_lint_pass; -use rustc_span::{sym, ExpnId}; +use rustc_span::{ExpnId, sym}; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/extra_unused_type_parameters.rs b/clippy_lints/src/extra_unused_type_parameters.rs index bfe4e253ae4..bf9388b4a70 100644 --- a/clippy_lints/src/extra_unused_type_parameters.rs +++ b/clippy_lints/src/extra_unused_type_parameters.rs @@ -3,7 +3,7 @@ use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_then}; use clippy_utils::{is_from_proc_macro, trait_ref_of_method}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::Applicability; -use rustc_hir::intravisit::{walk_impl_item, walk_item, walk_param_bound, walk_ty, Visitor}; +use rustc_hir::intravisit::{Visitor, walk_impl_item, walk_item, walk_param_bound, walk_ty}; use rustc_hir::{ BodyId, ExprKind, GenericBound, GenericParam, GenericParamKind, Generics, ImplItem, ImplItemKind, Item, ItemKind, PredicateOrigin, Ty, TyKind, WherePredicate, @@ -12,8 +12,8 @@ use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::hir::nested_filter; use rustc_middle::lint::in_external_macro; use rustc_session::impl_lint_pass; -use rustc_span::def_id::{DefId, LocalDefId}; use rustc_span::Span; +use rustc_span::def_id::{DefId, LocalDefId}; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/fallible_impl_from.rs b/clippy_lints/src/fallible_impl_from.rs index 0446943321a..747ea9a4344 100644 --- a/clippy_lints/src/fallible_impl_from.rs +++ b/clippy_lints/src/fallible_impl_from.rs @@ -6,7 +6,7 @@ use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_session::declare_lint_pass; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/field_scoped_visibility_modifiers.rs b/clippy_lints/src/field_scoped_visibility_modifiers.rs index 95b8e882da7..ba2b37fbf11 100644 --- a/clippy_lints/src/field_scoped_visibility_modifiers.rs +++ b/clippy_lints/src/field_scoped_visibility_modifiers.rs @@ -41,7 +41,7 @@ declare_clippy_lint! { /// } /// } /// ``` - #[clippy::version = "1.78.0"] + #[clippy::version = "1.81.0"] pub FIELD_SCOPED_VISIBILITY_MODIFIERS, restriction, "checks for usage of a scoped visibility modifier, like `pub(crate)`, on fields" diff --git a/clippy_lints/src/floating_point_arithmetic.rs b/clippy_lints/src/floating_point_arithmetic.rs index bf4bcabfe89..8da6623f34d 100644 --- a/clippy_lints/src/floating_point_arithmetic.rs +++ b/clippy_lints/src/floating_point_arithmetic.rs @@ -1,4 +1,4 @@ -use clippy_utils::consts::Constant::{Int, F32, F64}; +use clippy_utils::consts::Constant::{F32, F64, Int}; use clippy_utils::consts::{ConstEvalCtxt, Constant}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::{ diff --git a/clippy_lints/src/format.rs b/clippy_lints/src/format.rs index 4dedff69b9a..5e3f6b6a137 100644 --- a/clippy_lints/src/format.rs +++ b/clippy_lints/src/format.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::macros::{find_format_arg_expr, root_macro_call_first_node, FormatArgsStorage}; -use clippy_utils::source::{snippet_with_context, SpanRangeExt}; +use clippy_utils::macros::{FormatArgsStorage, find_format_arg_expr, root_macro_call_first_node}; +use clippy_utils::source::{SpanRangeExt, snippet_with_context}; use clippy_utils::sugg::Sugg; use rustc_ast::{FormatArgsPiece, FormatOptions, FormatTrait}; use rustc_errors::Applicability; @@ -8,7 +8,7 @@ use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_session::impl_lint_pass; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/format_args.rs b/clippy_lints/src/format_args.rs index 020c0c5440d..83ab9f6557b 100644 --- a/clippy_lints/src/format_args.rs +++ b/clippy_lints/src/format_args.rs @@ -1,11 +1,12 @@ use arrayvec::ArrayVec; -use clippy_config::msrvs::{self, Msrv}; use clippy_config::Conf; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; use clippy_utils::is_diag_trait_item; use clippy_utils::macros::{ - find_format_arg_expr, format_arg_removal_span, format_placeholder_format_span, is_assert_macro, is_format_macro, - is_panic, matching_root_macro_call, root_macro_call_first_node, FormatArgsStorage, FormatParamUsage, MacroCall, + FormatArgsStorage, FormatParamUsage, MacroCall, find_format_arg_expr, format_arg_removal_span, + format_placeholder_format_span, is_assert_macro, is_format_macro, is_panic, matching_root_macro_call, + root_macro_call_first_node, }; use clippy_utils::source::SpanRangeExt; use clippy_utils::ty::{implements_trait, is_type_lang_item}; @@ -18,11 +19,11 @@ use rustc_errors::Applicability; use rustc_errors::SuggestionStyle::{CompletelyHidden, ShowCode}; use rustc_hir::{Expr, ExprKind, LangItem}; use rustc_lint::{LateContext, LateLintPass, LintContext}; -use rustc_middle::ty::adjustment::{Adjust, Adjustment}; use rustc_middle::ty::Ty; +use rustc_middle::ty::adjustment::{Adjust, Adjustment}; use rustc_session::impl_lint_pass; use rustc_span::edition::Edition::Edition2021; -use rustc_span::{sym, Span, Symbol}; +use rustc_span::{Span, Symbol, sym}; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/format_impl.rs b/clippy_lints/src/format_impl.rs index 7cd12ac7db8..c196f404ce6 100644 --- a/clippy_lints/src/format_impl.rs +++ b/clippy_lints/src/format_impl.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg}; -use clippy_utils::macros::{find_format_arg_expr, is_format_macro, root_macro_call_first_node, FormatArgsStorage}; +use clippy_utils::macros::{FormatArgsStorage, find_format_arg_expr, is_format_macro, root_macro_call_first_node}; use clippy_utils::{get_parent_as_impl, is_diag_trait_item, path_to_local, peel_ref_operators}; use rustc_ast::{FormatArgsPiece, FormatTrait}; use rustc_errors::Applicability; @@ -7,7 +7,7 @@ use rustc_hir::{Expr, ExprKind, Impl, ImplItem, ImplItemKind, QPath}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::impl_lint_pass; use rustc_span::symbol::kw; -use rustc_span::{sym, Symbol}; +use rustc_span::{Symbol, sym}; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/format_push_string.rs b/clippy_lints/src/format_push_string.rs index c6f03c3a7cf..8b1f86cbb91 100644 --- a/clippy_lints/src/format_push_string.rs +++ b/clippy_lints/src/format_push_string.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::ty::is_type_lang_item; use clippy_utils::higher; +use clippy_utils::ty::is_type_lang_item; use rustc_hir::{BinOpKind, Expr, ExprKind, LangItem, MatchSource}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; diff --git a/clippy_lints/src/from_over_into.rs b/clippy_lints/src/from_over_into.rs index b84bf7c821c..8832cd42dd9 100644 --- a/clippy_lints/src/from_over_into.rs +++ b/clippy_lints/src/from_over_into.rs @@ -1,11 +1,11 @@ -use clippy_config::msrvs::{self, Msrv}; use clippy_config::Conf; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::macros::span_is_local; use clippy_utils::path_def_id; use clippy_utils::source::SpanRangeExt; use rustc_errors::Applicability; -use rustc_hir::intravisit::{walk_path, Visitor}; +use rustc_hir::intravisit::{Visitor, walk_path}; use rustc_hir::{ FnRetTy, GenericArg, GenericArgs, HirId, Impl, ImplItemKind, ImplItemRef, Item, ItemKind, PatKind, Path, PathSegment, Ty, TyKind, diff --git a/clippy_lints/src/from_str_radix_10.rs b/clippy_lints/src/from_str_radix_10.rs index e5fa67d6964..7361546153c 100644 --- a/clippy_lints/src/from_str_radix_10.rs +++ b/clippy_lints/src/from_str_radix_10.rs @@ -3,7 +3,7 @@ use clippy_utils::sugg::Sugg; use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item}; use clippy_utils::{is_in_const_context, is_integer_literal}; use rustc_errors::Applicability; -use rustc_hir::{def, Expr, ExprKind, LangItem, PrimTy, QPath, TyKind}; +use rustc_hir::{Expr, ExprKind, LangItem, PrimTy, QPath, TyKind, def}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::Ty; use rustc_session::declare_lint_pass; diff --git a/clippy_lints/src/functions/mod.rs b/clippy_lints/src/functions/mod.rs index 0f48941783b..ba8a459c917 100644 --- a/clippy_lints/src/functions/mod.rs +++ b/clippy_lints/src/functions/mod.rs @@ -14,8 +14,8 @@ use rustc_hir::intravisit; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::TyCtxt; use rustc_session::impl_lint_pass; -use rustc_span::def_id::{DefIdSet, LocalDefId}; use rustc_span::Span; +use rustc_span::def_id::{DefIdSet, LocalDefId}; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/functions/must_use.rs b/clippy_lints/src/functions/must_use.rs index 93828121047..cfd11e9339f 100644 --- a/clippy_lints/src/functions/must_use.rs +++ b/clippy_lints/src/functions/must_use.rs @@ -8,7 +8,7 @@ use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::{LateContext, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::{self, Ty}; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; use clippy_utils::attrs::is_proc_macro; use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_then}; diff --git a/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs b/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs index 1aeefe73cf6..c2b40ae01d4 100644 --- a/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs +++ b/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs @@ -1,4 +1,4 @@ -use rustc_hir::{self as hir, intravisit, HirId, HirIdSet}; +use rustc_hir::{self as hir, HirId, HirIdSet, intravisit}; use rustc_lint::LateContext; use rustc_middle::ty; use rustc_span::def_id::LocalDefId; diff --git a/clippy_lints/src/functions/renamed_function_params.rs b/clippy_lints/src/functions/renamed_function_params.rs index c7de0385c02..ac2e866e4ff 100644 --- a/clippy_lints/src/functions/renamed_function_params.rs +++ b/clippy_lints/src/functions/renamed_function_params.rs @@ -4,8 +4,8 @@ use rustc_hir::def_id::{DefId, DefIdSet}; use rustc_hir::hir_id::OwnerId; use rustc_hir::{Impl, ImplItem, ImplItemKind, ImplItemRef, ItemKind, Node, TraitRef}; use rustc_lint::LateContext; -use rustc_span::symbol::{kw, Ident, Symbol}; use rustc_span::Span; +use rustc_span::symbol::{Ident, Symbol, kw}; use super::RENAMED_FUNCTION_PARAMS; diff --git a/clippy_lints/src/functions/result.rs b/clippy_lints/src/functions/result.rs index c3a0b40a677..d4eaa166320 100644 --- a/clippy_lints/src/functions/result.rs +++ b/clippy_lints/src/functions/result.rs @@ -3,11 +3,11 @@ use rustc_hir as hir; use rustc_lint::{LateContext, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::{self, Ty}; -use rustc_span::{sym, Span}; +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::{approx_ty_size, is_type_diagnostic_item, AdtVariantInfo}; +use clippy_utils::ty::{AdtVariantInfo, approx_ty_size, is_type_diagnostic_item}; use super::{RESULT_LARGE_ERR, RESULT_UNIT_ERR}; diff --git a/clippy_lints/src/future_not_send.rs b/clippy_lints/src/future_not_send.rs index 9488ba75686..a4dbe134f36 100644 --- a/clippy_lints/src/future_not_send.rs +++ b/clippy_lints/src/future_not_send.rs @@ -8,7 +8,7 @@ use rustc_middle::ty::print::PrintTraitRefExt; use rustc_middle::ty::{self, AliasTy, ClauseKind, PredicateKind}; use rustc_session::declare_lint_pass; use rustc_span::def_id::LocalDefId; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::traits::{self, FulfillmentError, ObligationCtxt}; diff --git a/clippy_lints/src/if_then_some_else_none.rs b/clippy_lints/src/if_then_some_else_none.rs index 0bca53c1536..d63c18c0eda 100644 --- a/clippy_lints/src/if_then_some_else_none.rs +++ b/clippy_lints/src/if_then_some_else_none.rs @@ -1,5 +1,5 @@ -use clippy_config::msrvs::{self, Msrv}; use clippy_config::Conf; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::eager_or_lazy::switch_to_eager_eval; use clippy_utils::source::snippet_with_context; @@ -105,6 +105,8 @@ impl<'tcx> LateLintPass<'tcx> for IfThenSomeElseNone { snippet_with_context(cx, first_stmt.span.until(then_arg.span), ctxt, "..", &mut app); let closure = if method_name == "then" { "|| " } else { "" }; format!("{closure} {{ {block_snippet}; {arg_snip} }}") + } else if method_name == "then" { + (std::borrow::Cow::Borrowed("|| ") + arg_snip).into_owned() } else { arg_snip.into_owned() }; diff --git a/clippy_lints/src/implicit_hasher.rs b/clippy_lints/src/implicit_hasher.rs index e56f33f8dcf..f683925145a 100644 --- a/clippy_lints/src/implicit_hasher.rs +++ b/clippy_lints/src/implicit_hasher.rs @@ -3,18 +3,18 @@ use std::collections::BTreeMap; use rustc_errors::{Applicability, Diag}; use rustc_hir as hir; -use rustc_hir::intravisit::{walk_body, walk_expr, walk_inf, walk_ty, Visitor}; +use rustc_hir::intravisit::{Visitor, walk_body, walk_expr, walk_inf, walk_ty}; use rustc_hir::{Body, Expr, ExprKind, GenericArg, Item, ItemKind, QPath, TyKind}; use rustc_hir_analysis::lower_ty; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::nested_filter; use rustc_middle::ty::{Ty, TypeckResults}; use rustc_session::declare_lint_pass; -use rustc_span::symbol::sym; use rustc_span::Span; +use rustc_span::symbol::sym; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::{snippet, IntoSpan, SpanRangeExt}; +use clippy_utils::source::{IntoSpan, SpanRangeExt, snippet}; use clippy_utils::ty::is_type_diagnostic_item; declare_clippy_lint! { diff --git a/clippy_lints/src/implicit_saturating_sub.rs b/clippy_lints/src/implicit_saturating_sub.rs index 127c73ed637..f4a64f5c20b 100644 --- a/clippy_lints/src/implicit_saturating_sub.rs +++ b/clippy_lints/src/implicit_saturating_sub.rs @@ -1,11 +1,17 @@ -use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::{higher, is_integer_literal, peel_blocks_with_stmt, SpanlessEq}; +use clippy_config::Conf; +use clippy_config::msrvs::{self, Msrv}; +use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; +use clippy_utils::source::snippet_opt; +use clippy_utils::{ + SpanlessEq, higher, is_in_const_context, is_integer_literal, path_to_local, peel_blocks, peel_blocks_with_stmt, +}; use rustc_ast::ast::LitKind; use rustc_data_structures::packed::Pu128; use rustc_errors::Applicability; -use rustc_hir::{BinOpKind, Expr, ExprKind, QPath}; +use rustc_hir::{BinOp, BinOpKind, Expr, ExprKind, HirId, QPath}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::declare_lint_pass; +use rustc_session::impl_lint_pass; +use rustc_span::Span; declare_clippy_lint! { /// ### What it does @@ -39,7 +45,49 @@ declare_clippy_lint! { "Perform saturating subtraction instead of implicitly checking lower bound of data type" } -declare_lint_pass!(ImplicitSaturatingSub => [IMPLICIT_SATURATING_SUB]); +declare_clippy_lint! { + /// ### What it does + /// Checks for comparisons between integers, followed by subtracting the greater value from the + /// lower one. + /// + /// ### Why is this bad? + /// This could result in an underflow and is most likely not what the user wants. If this was + /// intended to be a saturated subtraction, consider using the `saturating_sub` method directly. + /// + /// ### Example + /// ```no_run + /// let a = 12u32; + /// let b = 13u32; + /// + /// let result = if a > b { b - a } else { 0 }; + /// ``` + /// + /// Use instead: + /// ```no_run + /// let a = 12u32; + /// let b = 13u32; + /// + /// let result = a.saturating_sub(b); + /// ``` + #[clippy::version = "1.44.0"] + pub INVERTED_SATURATING_SUB, + correctness, + "Check if a variable is smaller than another one and still subtract from it even if smaller" +} + +pub struct ImplicitSaturatingSub { + msrv: Msrv, +} + +impl_lint_pass!(ImplicitSaturatingSub => [IMPLICIT_SATURATING_SUB, INVERTED_SATURATING_SUB]); + +impl ImplicitSaturatingSub { + pub fn new(conf: &'static Conf) -> Self { + Self { + msrv: conf.msrv.clone(), + } + } +} impl<'tcx> LateLintPass<'tcx> for ImplicitSaturatingSub { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { @@ -50,73 +98,260 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitSaturatingSub { // Check if the conditional expression is a binary operation && let ExprKind::Binary(ref cond_op, cond_left, cond_right) = cond.kind - - // Ensure that the binary operator is >, !=, or < - && (BinOpKind::Ne == cond_op.node || BinOpKind::Gt == cond_op.node || BinOpKind::Lt == cond_op.node) - - // Check if assign operation is done - && let Some(target) = subtracts_one(cx, then) - - // Extracting out the variable name - && let ExprKind::Path(QPath::Resolved(_, ares_path)) = target.kind { - // Handle symmetric conditions in the if statement - let (cond_var, cond_num_val) = if SpanlessEq::new(cx).eq_expr(cond_left, target) { - if BinOpKind::Gt == cond_op.node || BinOpKind::Ne == cond_op.node { - (cond_left, cond_right) - } else { - return; - } - } else if SpanlessEq::new(cx).eq_expr(cond_right, target) { - if BinOpKind::Lt == cond_op.node || BinOpKind::Ne == cond_op.node { - (cond_right, cond_left) - } else { - return; - } + check_with_condition(cx, expr, cond_op.node, cond_left, cond_right, then); + } else if let Some(higher::If { + cond, + then: if_block, + r#else: Some(else_block), + }) = higher::If::hir(expr) + && let ExprKind::Binary(ref cond_op, cond_left, cond_right) = cond.kind + { + check_manual_check( + cx, expr, cond_op, cond_left, cond_right, if_block, else_block, &self.msrv, + ); + } + } + + extract_msrv_attr!(LateContext); +} + +#[allow(clippy::too_many_arguments)] +fn check_manual_check<'tcx>( + cx: &LateContext<'tcx>, + expr: &Expr<'tcx>, + condition: &BinOp, + left_hand: &Expr<'tcx>, + right_hand: &Expr<'tcx>, + if_block: &Expr<'tcx>, + else_block: &Expr<'tcx>, + msrv: &Msrv, +) { + let ty = cx.typeck_results().expr_ty(left_hand); + if ty.is_numeric() && !ty.is_signed() { + match condition.node { + BinOpKind::Gt | BinOpKind::Ge => check_gt( + cx, + condition.span, + expr.span, + left_hand, + right_hand, + if_block, + else_block, + msrv, + ), + BinOpKind::Lt | BinOpKind::Le => check_gt( + cx, + condition.span, + expr.span, + right_hand, + left_hand, + if_block, + else_block, + msrv, + ), + _ => {}, + } + } +} + +#[allow(clippy::too_many_arguments)] +fn check_gt( + cx: &LateContext<'_>, + condition_span: Span, + expr_span: Span, + big_var: &Expr<'_>, + little_var: &Expr<'_>, + if_block: &Expr<'_>, + else_block: &Expr<'_>, + msrv: &Msrv, +) { + if let Some(big_var) = Var::new(big_var) + && let Some(little_var) = Var::new(little_var) + { + check_subtraction( + cx, + condition_span, + expr_span, + big_var, + little_var, + if_block, + else_block, + msrv, + ); + } +} + +struct Var { + span: Span, + hir_id: HirId, +} + +impl Var { + fn new(expr: &Expr<'_>) -> Option { + path_to_local(expr).map(|hir_id| Self { + span: expr.span, + hir_id, + }) + } +} + +#[allow(clippy::too_many_arguments)] +fn check_subtraction( + cx: &LateContext<'_>, + condition_span: Span, + expr_span: Span, + big_var: Var, + little_var: Var, + if_block: &Expr<'_>, + else_block: &Expr<'_>, + msrv: &Msrv, +) { + let if_block = peel_blocks(if_block); + let else_block = peel_blocks(else_block); + if is_integer_literal(if_block, 0) { + // We need to check this case as well to prevent infinite recursion. + if is_integer_literal(else_block, 0) { + // Well, seems weird but who knows? + return; + } + // If the subtraction is done in the `else` block, then we need to also revert the two + // variables as it means that the check was reverted too. + check_subtraction( + cx, + condition_span, + expr_span, + little_var, + big_var, + else_block, + if_block, + msrv, + ); + return; + } + if is_integer_literal(else_block, 0) + && let ExprKind::Binary(op, left, right) = if_block.kind + && let BinOpKind::Sub = op.node + { + let local_left = path_to_local(left); + let local_right = path_to_local(right); + if Some(big_var.hir_id) == local_left && Some(little_var.hir_id) == local_right { + // This part of the condition is voluntarily split from the one before to ensure that + // if `snippet_opt` fails, it won't try the next conditions. + if let Some(big_var_snippet) = snippet_opt(cx, big_var.span) + && let Some(little_var_snippet) = snippet_opt(cx, little_var.span) + && (!is_in_const_context(cx) || msrv.meets(msrvs::SATURATING_SUB_CONST)) + { + span_lint_and_sugg( + cx, + IMPLICIT_SATURATING_SUB, + expr_span, + "manual arithmetic check found", + "replace it with", + format!("{big_var_snippet}.saturating_sub({little_var_snippet})"), + Applicability::MachineApplicable, + ); + } + } else if Some(little_var.hir_id) == local_left + && Some(big_var.hir_id) == local_right + && let Some(big_var_snippet) = snippet_opt(cx, big_var.span) + && let Some(little_var_snippet) = snippet_opt(cx, little_var.span) + { + span_lint_and_then( + cx, + INVERTED_SATURATING_SUB, + condition_span, + "inverted arithmetic check before subtraction", + |diag| { + diag.span_note( + if_block.span, + format!("this subtraction underflows when `{little_var_snippet} < {big_var_snippet}`"), + ); + diag.span_suggestion( + if_block.span, + "try replacing it with", + format!("{big_var_snippet} - {little_var_snippet}"), + Applicability::MaybeIncorrect, + ); + }, + ); + } + } +} + +fn check_with_condition<'tcx>( + cx: &LateContext<'tcx>, + expr: &Expr<'tcx>, + cond_op: BinOpKind, + cond_left: &Expr<'tcx>, + cond_right: &Expr<'tcx>, + then: &Expr<'tcx>, +) { + // Ensure that the binary operator is >, !=, or < + if (BinOpKind::Ne == cond_op || BinOpKind::Gt == cond_op || BinOpKind::Lt == cond_op) + + // Check if assign operation is done + && let Some(target) = subtracts_one(cx, then) + + // Extracting out the variable name + && let ExprKind::Path(QPath::Resolved(_, ares_path)) = target.kind + { + // Handle symmetric conditions in the if statement + let (cond_var, cond_num_val) = if SpanlessEq::new(cx).eq_expr(cond_left, target) { + if BinOpKind::Gt == cond_op || BinOpKind::Ne == cond_op { + (cond_left, cond_right) } else { return; - }; - - // Check if the variable in the condition statement is an integer - if !cx.typeck_results().expr_ty(cond_var).is_integral() { + } + } else if SpanlessEq::new(cx).eq_expr(cond_right, target) { + if BinOpKind::Lt == cond_op || BinOpKind::Ne == cond_op { + (cond_right, cond_left) + } else { return; } + } else { + return; + }; - // Get the variable name - let var_name = ares_path.segments[0].ident.name.as_str(); - match cond_num_val.kind { - ExprKind::Lit(cond_lit) => { - // Check if the constant is zero - if let LitKind::Int(Pu128(0), _) = cond_lit.node { - if cx.typeck_results().expr_ty(cond_left).is_signed() { - } else { - print_lint_and_sugg(cx, var_name, expr); - }; - } - }, - ExprKind::Path(QPath::TypeRelative(_, name)) => { - if name.ident.as_str() == "MIN" - && let Some(const_id) = cx.typeck_results().type_dependent_def_id(cond_num_val.hir_id) - && let Some(impl_id) = cx.tcx.impl_of_method(const_id) - && let None = cx.tcx.impl_trait_ref(impl_id) // An inherent impl - && cx.tcx.type_of(impl_id).instantiate_identity().is_integral() - { + // Check if the variable in the condition statement is an integer + if !cx.typeck_results().expr_ty(cond_var).is_integral() { + return; + } + + // Get the variable name + let var_name = ares_path.segments[0].ident.name.as_str(); + match cond_num_val.kind { + ExprKind::Lit(cond_lit) => { + // Check if the constant is zero + if let LitKind::Int(Pu128(0), _) = cond_lit.node { + if cx.typeck_results().expr_ty(cond_left).is_signed() { + } else { print_lint_and_sugg(cx, var_name, expr); - } - }, - ExprKind::Call(func, []) => { - if let ExprKind::Path(QPath::TypeRelative(_, name)) = func.kind - && name.ident.as_str() == "min_value" - && let Some(func_id) = cx.typeck_results().type_dependent_def_id(func.hir_id) - && let Some(impl_id) = cx.tcx.impl_of_method(func_id) - && let None = cx.tcx.impl_trait_ref(impl_id) // An inherent impl - && cx.tcx.type_of(impl_id).instantiate_identity().is_integral() - { - print_lint_and_sugg(cx, var_name, expr); - } - }, - _ => (), - } + }; + } + }, + ExprKind::Path(QPath::TypeRelative(_, name)) => { + if name.ident.as_str() == "MIN" + && let Some(const_id) = cx.typeck_results().type_dependent_def_id(cond_num_val.hir_id) + && let Some(impl_id) = cx.tcx.impl_of_method(const_id) + && let None = cx.tcx.impl_trait_ref(impl_id) // An inherent impl + && cx.tcx.type_of(impl_id).instantiate_identity().is_integral() + { + print_lint_and_sugg(cx, var_name, expr); + } + }, + ExprKind::Call(func, []) => { + if let ExprKind::Path(QPath::TypeRelative(_, name)) = func.kind + && name.ident.as_str() == "min_value" + && let Some(func_id) = cx.typeck_results().type_dependent_def_id(func.hir_id) + && let Some(impl_id) = cx.tcx.impl_of_method(func_id) + && let None = cx.tcx.impl_trait_ref(impl_id) // An inherent impl + && cx.tcx.type_of(impl_id).instantiate_identity().is_integral() + { + print_lint_and_sugg(cx, var_name, expr); + } + }, + _ => (), } } } diff --git a/clippy_lints/src/incompatible_msrv.rs b/clippy_lints/src/incompatible_msrv.rs index 2ad045e1268..0b3a6ee1bea 100644 --- a/clippy_lints/src/incompatible_msrv.rs +++ b/clippy_lints/src/incompatible_msrv.rs @@ -1,5 +1,5 @@ -use clippy_config::msrvs::Msrv; use clippy_config::Conf; +use clippy_config::msrvs::Msrv; use clippy_utils::diagnostics::span_lint; use clippy_utils::is_in_test; use rustc_attr::{StabilityLevel, StableSince}; @@ -7,7 +7,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc_hir::{Expr, ExprKind, HirId}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::TyCtxt; -use rustc_session::{impl_lint_pass, RustcVersion}; +use rustc_session::{RustcVersion, impl_lint_pass}; use rustc_span::def_id::DefId; use rustc_span::{ExpnKind, Span}; diff --git a/clippy_lints/src/index_refutable_slice.rs b/clippy_lints/src/index_refutable_slice.rs index 2f9661c9ea3..39afb6810b8 100644 --- a/clippy_lints/src/index_refutable_slice.rs +++ b/clippy_lints/src/index_refutable_slice.rs @@ -1,5 +1,5 @@ -use clippy_config::msrvs::{self, Msrv}; use clippy_config::Conf; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::consts::{ConstEvalCtxt, Constant}; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::higher::IfLet; @@ -8,14 +8,14 @@ use clippy_utils::{is_expn_of, is_lint_allowed, path_to_local}; use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; use rustc_errors::Applicability; use rustc_hir as hir; -use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::HirId; +use rustc_hir::intravisit::{self, Visitor}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::nested_filter; use rustc_middle::ty; use rustc_session::impl_lint_pass; -use rustc_span::symbol::Ident; use rustc_span::Span; +use rustc_span::symbol::Ident; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/ineffective_open_options.rs b/clippy_lints/src/ineffective_open_options.rs index af5b1f95739..3a28553b55e 100644 --- a/clippy_lints/src/ineffective_open_options.rs +++ b/clippy_lints/src/ineffective_open_options.rs @@ -7,7 +7,7 @@ use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_session::declare_lint_pass; -use rustc_span::{sym, BytePos, Span}; +use rustc_span::{BytePos, Span, sym}; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/instant_subtraction.rs b/clippy_lints/src/instant_subtraction.rs index 6d6820311b6..66931a7f98c 100644 --- a/clippy_lints/src/instant_subtraction.rs +++ b/clippy_lints/src/instant_subtraction.rs @@ -1,5 +1,5 @@ -use clippy_config::msrvs::{self, Msrv}; use clippy_config::Conf; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_context; use clippy_utils::sugg::Sugg; diff --git a/clippy_lints/src/item_name_repetitions.rs b/clippy_lints/src/item_name_repetitions.rs index 74bf82f58bd..66a8a3167a4 100644 --- a/clippy_lints/src/item_name_repetitions.rs +++ b/clippy_lints/src/item_name_repetitions.rs @@ -8,8 +8,8 @@ use rustc_data_structures::fx::FxHashSet; use rustc_hir::{EnumDef, FieldDef, Item, ItemKind, OwnerId, Variant, VariantData}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::impl_lint_pass; -use rustc_span::symbol::Symbol; use rustc_span::Span; +use rustc_span::symbol::Symbol; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/items_after_test_module.rs b/clippy_lints/src/items_after_test_module.rs index 8caa484bb99..1ac549b74ac 100644 --- a/clippy_lints/src/items_after_test_module.rs +++ b/clippy_lints/src/items_after_test_module.rs @@ -6,7 +6,7 @@ use rustc_hir::{HirId, Item, ItemKind, Mod}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; use rustc_span::hygiene::AstPass; -use rustc_span::{sym, ExpnKind}; +use rustc_span::{ExpnKind, sym}; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/iter_not_returning_iterator.rs b/clippy_lints/src/iter_not_returning_iterator.rs index ba0cd5d6eb3..b19b348c743 100644 --- a/clippy_lints/src/iter_not_returning_iterator.rs +++ b/clippy_lints/src/iter_not_returning_iterator.rs @@ -4,7 +4,7 @@ use rustc_hir::def_id::LocalDefId; use rustc_hir::{FnSig, ImplItem, ImplItemKind, Item, ItemKind, Node, TraitItem, TraitItemKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; -use rustc_span::{sym, Symbol}; +use rustc_span::{Symbol, sym}; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/iter_over_hash_type.rs b/clippy_lints/src/iter_over_hash_type.rs index f162948bb44..5131f5b7269 100644 --- a/clippy_lints/src/iter_over_hash_type.rs +++ b/clippy_lints/src/iter_over_hash_type.rs @@ -55,7 +55,9 @@ impl LateLintPass<'_> for IterOverHashType { if let Some(for_loop) = ForLoop::hir(expr) && !for_loop.body.span.from_expansion() && let ty = cx.typeck_results().expr_ty(for_loop.arg).peel_refs() - && hash_iter_tys.into_iter().any(|sym| is_type_diagnostic_item(cx, ty, sym)) + && hash_iter_tys + .into_iter() + .any(|sym| is_type_diagnostic_item(cx, ty, sym)) { span_lint( cx, diff --git a/clippy_lints/src/large_enum_variant.rs b/clippy_lints/src/large_enum_variant.rs index 2f027c11707..923089c7223 100644 --- a/clippy_lints/src/large_enum_variant.rs +++ b/clippy_lints/src/large_enum_variant.rs @@ -1,7 +1,7 @@ use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet_with_applicability; -use clippy_utils::ty::{approx_ty_size, is_copy, AdtVariantInfo}; +use clippy_utils::ty::{AdtVariantInfo, approx_ty_size, is_copy}; use rustc_errors::Applicability; use rustc_hir::{Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; diff --git a/clippy_lints/src/large_stack_arrays.rs b/clippy_lints/src/large_stack_arrays.rs index 15a75b06089..0f061d6de50 100644 --- a/clippy_lints/src/large_stack_arrays.rs +++ b/clippy_lints/src/large_stack_arrays.rs @@ -8,7 +8,7 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::{self, ConstKind}; use rustc_session::impl_lint_pass; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/legacy_numeric_constants.rs b/clippy_lints/src/legacy_numeric_constants.rs index ccab1e27d3b..e17d6213679 100644 --- a/clippy_lints/src/legacy_numeric_constants.rs +++ b/clippy_lints/src/legacy_numeric_constants.rs @@ -1,5 +1,5 @@ -use clippy_config::msrvs::{Msrv, NUMERIC_ASSOCIATED_CONSTANTS}; use clippy_config::Conf; +use clippy_config::msrvs::{Msrv, NUMERIC_ASSOCIATED_CONSTANTS}; use clippy_utils::diagnostics::{span_lint_and_then, span_lint_hir_and_then}; use clippy_utils::{get_parent_expr, is_from_proc_macro}; use hir::def_id::DefId; @@ -10,7 +10,7 @@ use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_session::impl_lint_pass; use rustc_span::symbol::kw; -use rustc_span::{sym, Symbol}; +use rustc_span::{Symbol, sym}; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/len_zero.rs b/clippy_lints/src/len_zero.rs index 0bc7fc2dd9d..3cd5f76e6b6 100644 --- a/clippy_lints/src/len_zero.rs +++ b/clippy_lints/src/len_zero.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then}; -use clippy_utils::source::{snippet_with_context, SpanRangeExt}; -use clippy_utils::sugg::{has_enclosing_paren, Sugg}; -use clippy_utils::{get_item_name, get_parent_as_impl, is_lint_allowed, peel_ref_operators}; +use clippy_utils::source::{SpanRangeExt, snippet_with_context}; +use clippy_utils::sugg::{Sugg, has_enclosing_paren}; +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; use rustc_hir::def::Res; @@ -185,6 +185,19 @@ impl<'tcx> LateLintPass<'tcx> for LenZero { ); } + if let ExprKind::MethodCall(method, lhs_expr, [rhs_expr], _) = expr.kind + && is_trait_method(cx, expr, sym::PartialEq) + && !expr.span.from_expansion() + { + check_empty_expr( + cx, + expr.span, + lhs_expr, + peel_ref_operators(cx, rhs_expr), + (method.ident.name == sym::ne).then_some("!").unwrap_or_default(), + ); + } + if let ExprKind::Binary(Spanned { node: cmp, .. }, left, right) = expr.kind && !expr.span.from_expansion() { diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 2ac06b360be..1d41f568f37 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -203,9 +203,11 @@ mod manual_assert; mod manual_async_fn; mod manual_bits; mod manual_clamp; +mod manual_div_ceil; mod manual_float_methods; mod manual_hash_one; mod manual_is_ascii_check; +mod manual_is_power_of_two; mod manual_let_else; mod manual_main_separator_str; mod manual_non_exhaustive; @@ -271,6 +273,7 @@ mod non_copy_const; mod non_expressive_names; mod non_octal_unix_permissions; mod non_send_fields_in_send_ty; +mod non_zero_suggestions; mod nonstandard_macro_braces; mod octal_escapes; mod only_used_in_recursion; @@ -287,6 +290,7 @@ mod pass_by_ref_or_value; mod pathbuf_init_then_push; mod pattern_type_mismatch; mod permissions_set_readonly_false; +mod pointers_in_nomem_asm_block; mod precedence; mod ptr; mod ptr_offset_with_cast; @@ -372,6 +376,7 @@ mod unused_peekable; mod unused_result_ok; mod unused_rounding; mod unused_self; +mod unused_trait_names; mod unused_unit; mod unwrap; mod unwrap_in_result; @@ -386,9 +391,10 @@ mod write; mod zero_div_zero; mod zero_repeat_side_effects; mod zero_sized_map_values; +mod zombie_processes; // end lints modules, do not remove this comment, it’s used in `update_lints` -use clippy_config::{get_configuration_metadata, Conf}; +use clippy_config::{Conf, get_configuration_metadata}; use clippy_utils::macros::FormatArgsStorage; use rustc_data_structures::fx::FxHashSet; use rustc_lint::{Lint, LintId}; @@ -623,7 +629,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { store.register_late_pass(|_| Box::new(unit_return_expecting_ord::UnitReturnExpectingOrd)); store.register_late_pass(|_| Box::new(strings::StringAdd)); store.register_late_pass(|_| Box::new(implicit_return::ImplicitReturn)); - store.register_late_pass(|_| Box::new(implicit_saturating_sub::ImplicitSaturatingSub)); + 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(|_| Box::new(non_octal_unix_permissions::NonOctalUnixPermissions)); @@ -632,8 +638,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { let format_args = format_args_storage.clone(); store.register_late_pass(move |_| Box::new(methods::Methods::new(conf, format_args.clone()))); store.register_late_pass(move |_| Box::new(matches::Matches::new(conf))); - store.register_early_pass(move || Box::new(manual_non_exhaustive::ManualNonExhaustiveStruct::new(conf))); - store.register_late_pass(move |_| Box::new(manual_non_exhaustive::ManualNonExhaustiveEnum::new(conf))); + store.register_late_pass(move |_| Box::new(manual_non_exhaustive::ManualNonExhaustive::new(conf))); store.register_late_pass(move |_| Box::new(manual_strip::ManualStrip::new(conf))); store.register_early_pass(move || Box::new(redundant_static_lifetimes::RedundantStaticLifetimes::new(conf))); store.register_early_pass(move || Box::new(redundant_field_names::RedundantFieldNames::new(conf))); @@ -933,5 +938,11 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { store.register_late_pass(|_| Box::new(set_contains_or_insert::SetContainsOrInsert)); store.register_early_pass(|| Box::new(byte_char_slices::ByteCharSlice)); store.register_early_pass(|| Box::new(cfg_not_test::CfgNotTest)); + store.register_late_pass(|_| Box::new(zombie_processes::ZombieProcesses)); + store.register_late_pass(|_| Box::new(pointers_in_nomem_asm_block::PointersInNomemAsmBlock)); + store.register_late_pass(move |_| Box::new(manual_div_ceil::ManualDivCeil::new(conf))); + store.register_late_pass(|_| Box::new(manual_is_power_of_two::ManualIsPowerOfTwo)); + store.register_late_pass(|_| Box::new(non_zero_suggestions::NonZeroSuggestions)); + store.register_late_pass(move |_| Box::new(unused_trait_names::UnusedTraitNames::new(conf))); // add lints here, do not remove this comment, it's used in `new_lint` } diff --git a/clippy_lints/src/lifetimes.rs b/clippy_lints/src/lifetimes.rs index ba34af9c100..755afe959b3 100644 --- a/clippy_lints/src/lifetimes.rs +++ b/clippy_lints/src/lifetimes.rs @@ -3,25 +3,25 @@ use clippy_utils::trait_ref_of_method; use itertools::Itertools; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::Applicability; +use rustc_hir::FnRetTy::Return; use rustc_hir::intravisit::nested_filter::{self as hir_nested_filter, NestedFilter}; use rustc_hir::intravisit::{ - walk_fn_decl, walk_generic_param, walk_generics, walk_impl_item_ref, walk_item, walk_param_bound, - walk_poly_trait_ref, walk_trait_ref, walk_ty, Visitor, + Visitor, walk_fn_decl, walk_generic_param, walk_generics, walk_impl_item_ref, walk_item, walk_param_bound, + walk_poly_trait_ref, walk_trait_ref, walk_ty, }; -use rustc_hir::FnRetTy::Return; use rustc_hir::{ - lang_items, BareFnTy, BodyId, FnDecl, FnSig, GenericArg, GenericBound, GenericParam, GenericParamKind, Generics, - Impl, ImplItem, ImplItemKind, Item, ItemKind, Lifetime, LifetimeName, LifetimeParamKind, Node, PolyTraitRef, - PredicateOrigin, TraitFn, TraitItem, TraitItemKind, Ty, TyKind, WherePredicate, + BareFnTy, BodyId, FnDecl, FnSig, GenericArg, GenericBound, GenericParam, GenericParamKind, Generics, Impl, + ImplItem, ImplItemKind, Item, ItemKind, Lifetime, LifetimeName, LifetimeParamKind, Node, PolyTraitRef, + PredicateOrigin, TraitFn, TraitItem, TraitItemKind, Ty, TyKind, WherePredicate, lang_items, }; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::hir::map::Map; use rustc_middle::hir::nested_filter as middle_nested_filter; use rustc_middle::lint::in_external_macro; use rustc_session::declare_lint_pass; -use rustc_span::def_id::LocalDefId; -use rustc_span::symbol::{kw, Ident, Symbol}; use rustc_span::Span; +use rustc_span::def_id::LocalDefId; +use rustc_span::symbol::{Ident, Symbol, kw}; use std::ops::ControlFlow; declare_clippy_lint! { diff --git a/clippy_lints/src/loops/explicit_counter_loop.rs b/clippy_lints/src/loops/explicit_counter_loop.rs index 73a23615c2d..9aa4d2f0adc 100644 --- a/clippy_lints/src/loops/explicit_counter_loop.rs +++ b/clippy_lints/src/loops/explicit_counter_loop.rs @@ -1,4 +1,4 @@ -use super::{make_iterator_snippet, IncrementVisitor, InitializeVisitor, EXPLICIT_COUNTER_LOOP}; +use super::{EXPLICIT_COUNTER_LOOP, IncrementVisitor, InitializeVisitor, make_iterator_snippet}; use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; use clippy_utils::source::snippet_with_applicability; use clippy_utils::{get_enclosing_block, is_integer_const}; diff --git a/clippy_lints/src/loops/infinite_loop.rs b/clippy_lints/src/loops/infinite_loop.rs index 5b5bb88c179..858e3be5093 100644 --- a/clippy_lints/src/loops/infinite_loop.rs +++ b/clippy_lints/src/loops/infinite_loop.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::{fn_def_id, is_from_proc_macro, is_lint_allowed}; -use hir::intravisit::{walk_expr, Visitor}; +use hir::intravisit::{Visitor, walk_expr}; use hir::{Expr, ExprKind, FnRetTy, FnSig, Node}; use rustc_ast::Label; use rustc_errors::Applicability; diff --git a/clippy_lints/src/loops/manual_find.rs b/clippy_lints/src/loops/manual_find.rs index b27528c11d4..bfe2e68b5d1 100644 --- a/clippy_lints/src/loops/manual_find.rs +++ b/clippy_lints/src/loops/manual_find.rs @@ -1,5 +1,5 @@ -use super::utils::make_iterator_snippet; use super::MANUAL_FIND; +use super::utils::make_iterator_snippet; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::implements_trait; diff --git a/clippy_lints/src/loops/manual_flatten.rs b/clippy_lints/src/loops/manual_flatten.rs index dbc094a6d73..366c310592f 100644 --- a/clippy_lints/src/loops/manual_flatten.rs +++ b/clippy_lints/src/loops/manual_flatten.rs @@ -1,5 +1,5 @@ -use super::utils::make_iterator_snippet; use super::MANUAL_FLATTEN; +use super::utils::make_iterator_snippet; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::visitors::is_local_used; use clippy_utils::{higher, path_to_local_id, peel_blocks_with_stmt}; diff --git a/clippy_lints/src/loops/manual_while_let_some.rs b/clippy_lints/src/loops/manual_while_let_some.rs index 55d1b9ee676..7476a87267f 100644 --- a/clippy_lints/src/loops/manual_while_let_some.rs +++ b/clippy_lints/src/loops/manual_while_let_some.rs @@ -1,10 +1,10 @@ +use clippy_utils::SpanlessEq; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet; -use clippy_utils::SpanlessEq; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, Pat, Stmt, StmtKind, UnOp}; use rustc_lint::LateContext; -use rustc_span::{sym, Symbol, Span}; +use rustc_span::{Span, Symbol, sym}; use std::borrow::Cow; use super::MANUAL_WHILE_LET_SOME; diff --git a/clippy_lints/src/loops/mod.rs b/clippy_lints/src/loops/mod.rs index 92ccc0cc0a1..17215621d2a 100644 --- a/clippy_lints/src/loops/mod.rs +++ b/clippy_lints/src/loops/mod.rs @@ -22,15 +22,15 @@ mod while_immutable_condition; mod while_let_loop; mod while_let_on_iterator; -use clippy_config::msrvs::Msrv; use clippy_config::Conf; +use clippy_config::msrvs::Msrv; use clippy_utils::higher; use rustc_ast::Label; use rustc_hir::{Expr, ExprKind, LoopSource, Pat}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::impl_lint_pass; use rustc_span::Span; -use utils::{make_iterator_snippet, IncrementVisitor, InitializeVisitor}; +use utils::{IncrementVisitor, InitializeVisitor, make_iterator_snippet}; declare_clippy_lint! { /// ### What it does @@ -188,22 +188,22 @@ declare_clippy_lint! { /// The `while let` loop is usually shorter and more /// readable. /// - /// ### Known problems - /// Sometimes the wrong binding is displayed ([#383](https://github.com/rust-lang/rust-clippy/issues/383)). - /// /// ### Example /// ```rust,no_run - /// # let y = Some(1); + /// let y = Some(1); /// loop { /// let x = match y { /// Some(x) => x, /// None => break, /// }; - /// // .. do something with x + /// // .. /// } - /// // is easier written as + /// ``` + /// Use instead: + /// ```rust,no_run + /// let y = Some(1); /// while let Some(x) = y { - /// // .. do something with x + /// // .. /// }; /// ``` #[clippy::version = "pre 1.29.0"] diff --git a/clippy_lints/src/loops/needless_range_loop.rs b/clippy_lints/src/loops/needless_range_loop.rs index e18e4374667..20dd5a311dc 100644 --- a/clippy_lints/src/loops/needless_range_loop.rs +++ b/clippy_lints/src/loops/needless_range_loop.rs @@ -3,17 +3,17 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet; use clippy_utils::ty::has_iter_method; use clippy_utils::visitors::is_local_used; -use clippy_utils::{contains_name, higher, is_integer_const, sugg, SpanlessEq}; +use clippy_utils::{SpanlessEq, contains_name, higher, is_integer_const, sugg}; use rustc_ast::ast; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::intravisit::{walk_expr, Visitor}; +use rustc_hir::intravisit::{Visitor, walk_expr}; use rustc_hir::{BinOpKind, BorrowKind, Closure, Expr, ExprKind, HirId, Mutability, Pat, PatKind, QPath}; use rustc_lint::LateContext; use rustc_middle::middle::region; use rustc_middle::ty::{self, Ty}; -use rustc_span::symbol::{sym, Symbol}; +use rustc_span::symbol::{Symbol, sym}; use std::{iter, mem}; /// Checks for looping over a range and then indexing a sequence with it. diff --git a/clippy_lints/src/loops/never_loop.rs b/clippy_lints/src/loops/never_loop.rs index 313a5bfefbc..1c55e3e22e8 100644 --- a/clippy_lints/src/loops/never_loop.rs +++ b/clippy_lints/src/loops/never_loop.rs @@ -1,5 +1,5 @@ -use super::utils::make_iterator_snippet; use super::NEVER_LOOP; +use super::utils::make_iterator_snippet; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::higher::ForLoop; use clippy_utils::macros::root_macro_call_first_node; @@ -7,7 +7,7 @@ use clippy_utils::source::snippet; use rustc_errors::Applicability; use rustc_hir::{Block, Destination, Expr, ExprKind, HirId, InlineAsmOperand, Pat, Stmt, StmtKind}; use rustc_lint::LateContext; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; use std::iter::once; pub(super) fn check<'tcx>( diff --git a/clippy_lints/src/loops/same_item_push.rs b/clippy_lints/src/loops/same_item_push.rs index 9185cf1f8b2..5662d3013e1 100644 --- a/clippy_lints/src/loops/same_item_push.rs +++ b/clippy_lints/src/loops/same_item_push.rs @@ -6,11 +6,11 @@ use clippy_utils::ty::{implements_trait, is_type_diagnostic_item}; use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::intravisit::{walk_expr, Visitor}; +use rustc_hir::intravisit::{Visitor, walk_expr}; use rustc_hir::{BindingMode, Block, Expr, ExprKind, HirId, Mutability, Node, Pat, PatKind, Stmt, StmtKind}; use rustc_lint::LateContext; -use rustc_span::symbol::sym; use rustc_span::SyntaxContext; +use rustc_span::symbol::sym; /// Detects for loop pushing the same item into a Vec pub(super) fn check<'tcx>( diff --git a/clippy_lints/src/loops/single_element_loop.rs b/clippy_lints/src/loops/single_element_loop.rs index 2b41911e8ec..70f76ced09a 100644 --- a/clippy_lints/src/loops/single_element_loop.rs +++ b/clippy_lints/src/loops/single_element_loop.rs @@ -2,10 +2,10 @@ use super::SINGLE_ELEMENT_LOOP; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::{indent_of, snippet, snippet_with_applicability}; use clippy_utils::visitors::contains_break_or_continue; -use rustc_ast::util::parser::PREC_PREFIX; use rustc_ast::Mutability; +use rustc_ast::util::parser::PREC_PREFIX; use rustc_errors::Applicability; -use rustc_hir::{is_range_literal, BorrowKind, Expr, ExprKind, Pat, PatKind}; +use rustc_hir::{BorrowKind, Expr, ExprKind, Pat, PatKind, is_range_literal}; use rustc_lint::LateContext; use rustc_span::edition::Edition; use rustc_span::sym; diff --git a/clippy_lints/src/loops/utils.rs b/clippy_lints/src/loops/utils.rs index 7b45cc95431..9a89a41d2b3 100644 --- a/clippy_lints/src/loops/utils.rs +++ b/clippy_lints/src/loops/utils.rs @@ -2,13 +2,13 @@ use clippy_utils::ty::{has_iter_method, implements_trait}; use clippy_utils::{get_parent_expr, is_integer_const, path_to_local, path_to_local_id, sugg}; use rustc_ast::ast::{LitIntType, LitKind}; use rustc_errors::Applicability; -use rustc_hir::intravisit::{walk_expr, walk_local, Visitor}; +use rustc_hir::intravisit::{Visitor, walk_expr, walk_local}; use rustc_hir::{BinOpKind, BorrowKind, Expr, ExprKind, HirId, HirIdMap, LetStmt, Mutability, PatKind}; use rustc_lint::LateContext; use rustc_middle::hir::nested_filter; use rustc_middle::ty::{self, Ty}; use rustc_span::source_map::Spanned; -use rustc_span::symbol::{sym, Symbol}; +use rustc_span::symbol::{Symbol, sym}; #[derive(Debug, PartialEq, Eq)] enum IncrementVisitorVarState { diff --git a/clippy_lints/src/loops/while_immutable_condition.rs b/clippy_lints/src/loops/while_immutable_condition.rs index cc1bd5929d0..eab096e9a22 100644 --- a/clippy_lints/src/loops/while_immutable_condition.rs +++ b/clippy_lints/src/loops/while_immutable_condition.rs @@ -4,7 +4,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::usage::mutated_variables; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefIdMap; -use rustc_hir::intravisit::{walk_expr, Visitor}; +use rustc_hir::intravisit::{Visitor, walk_expr}; use rustc_hir::{Expr, ExprKind, HirIdSet, QPath}; use rustc_lint::LateContext; use std::ops::ControlFlow; diff --git a/clippy_lints/src/loops/while_let_on_iterator.rs b/clippy_lints/src/loops/while_let_on_iterator.rs index c171fa1c622..7d9fbaf3cea 100644 --- a/clippy_lints/src/loops/while_let_on_iterator.rs +++ b/clippy_lints/src/loops/while_let_on_iterator.rs @@ -5,13 +5,13 @@ use clippy_utils::visitors::is_res_used; use clippy_utils::{get_enclosing_loop_or_multi_call_closure, higher, is_refutable, is_res_lang_ctor, is_trait_method}; use rustc_errors::Applicability; use rustc_hir::def::Res; -use rustc_hir::intravisit::{walk_expr, Visitor}; +use rustc_hir::intravisit::{Visitor, walk_expr}; use rustc_hir::{Closure, Expr, ExprKind, HirId, LangItem, LetStmt, Mutability, PatKind, UnOp}; use rustc_lint::LateContext; use rustc_middle::hir::nested_filter::OnlyBodies; use rustc_middle::ty::adjustment::Adjust; -use rustc_span::symbol::sym; use rustc_span::Symbol; +use rustc_span::symbol::sym; pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { if let Some(higher::WhileLet { if_then, let_pat, let_expr, label, .. }) = higher::WhileLet::hir(expr) diff --git a/clippy_lints/src/macro_metavars_in_unsafe.rs b/clippy_lints/src/macro_metavars_in_unsafe.rs index e215097142b..ccc554042d6 100644 --- a/clippy_lints/src/macro_metavars_in_unsafe.rs +++ b/clippy_lints/src/macro_metavars_in_unsafe.rs @@ -3,13 +3,13 @@ use clippy_utils::diagnostics::span_lint_hir_and_then; use clippy_utils::is_lint_allowed; use itertools::Itertools; use rustc_hir::def_id::LocalDefId; -use rustc_hir::intravisit::{walk_block, walk_expr, walk_stmt, Visitor}; +use rustc_hir::intravisit::{Visitor, walk_block, walk_expr, walk_stmt}; use rustc_hir::{BlockCheckMode, Expr, ExprKind, HirId, Stmt, UnsafeSource}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::impl_lint_pass; -use rustc_span::{sym, Span, SyntaxContext}; -use std::collections::btree_map::Entry; +use rustc_span::{Span, SyntaxContext, sym}; use std::collections::BTreeMap; +use std::collections::btree_map::Entry; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/macro_use.rs b/clippy_lints/src/macro_use.rs index 067384b0901..bd6b3f1a47b 100644 --- a/clippy_lints/src/macro_use.rs +++ b/clippy_lints/src/macro_use.rs @@ -8,7 +8,7 @@ use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_session::impl_lint_pass; use rustc_span::edition::Edition; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; use std::collections::BTreeMap; declare_clippy_lint! { diff --git a/clippy_lints/src/manual_async_fn.rs b/clippy_lints/src/manual_async_fn.rs index 61723aec590..fc3bba9e512 100644 --- a/clippy_lints/src/manual_async_fn.rs +++ b/clippy_lints/src/manual_async_fn.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::{position_before_rarrow, snippet_block, SpanRangeExt}; +use clippy_utils::source::{SpanRangeExt, position_before_rarrow, snippet_block}; use rustc_errors::Applicability; use rustc_hir::intravisit::FnKind; use rustc_hir::{ @@ -9,7 +9,7 @@ use rustc_hir::{ use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; use rustc_span::def_id::LocalDefId; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/manual_bits.rs b/clippy_lints/src/manual_bits.rs index 5cbdc7f864a..c0e87e8a1fa 100644 --- a/clippy_lints/src/manual_bits.rs +++ b/clippy_lints/src/manual_bits.rs @@ -1,5 +1,5 @@ -use clippy_config::msrvs::{self, Msrv}; use clippy_config::Conf; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::get_parent_expr; use clippy_utils::source::snippet_with_context; diff --git a/clippy_lints/src/manual_clamp.rs b/clippy_lints/src/manual_clamp.rs index 4123c933660..788649fd4f9 100644 --- a/clippy_lints/src/manual_clamp.rs +++ b/clippy_lints/src/manual_clamp.rs @@ -1,5 +1,5 @@ -use clippy_config::msrvs::{self, Msrv}; use clippy_config::Conf; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::consts::{ConstEvalCtxt, Constant}; use clippy_utils::diagnostics::{span_lint_and_then, span_lint_hir_and_then}; use clippy_utils::higher::If; @@ -7,8 +7,8 @@ use clippy_utils::sugg::Sugg; use clippy_utils::ty::implements_trait; use clippy_utils::visitors::is_const_evaluatable; use clippy_utils::{ - eq_expr_value, is_diag_trait_item, is_in_const_context, is_trait_method, path_res, path_to_local_id, peel_blocks, - peel_blocks_with_stmt, MaybePath, + MaybePath, eq_expr_value, is_diag_trait_item, is_in_const_context, is_trait_method, path_res, path_to_local_id, + peel_blocks, peel_blocks_with_stmt, }; use itertools::Itertools; use rustc_errors::{Applicability, Diag}; @@ -17,8 +17,8 @@ use rustc_hir::{Arm, BinOpKind, Block, Expr, ExprKind, HirId, PatKind, PathSegme use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::Ty; use rustc_session::impl_lint_pass; -use rustc_span::symbol::sym; use rustc_span::Span; +use rustc_span::symbol::sym; use std::cmp::Ordering; use std::ops::Deref; diff --git a/clippy_lints/src/manual_div_ceil.rs b/clippy_lints/src/manual_div_ceil.rs new file mode 100644 index 00000000000..00e02e2a336 --- /dev/null +++ b/clippy_lints/src/manual_div_ceil.rs @@ -0,0 +1,158 @@ +use clippy_config::msrvs::{self, Msrv}; +use clippy_utils::SpanlessEq; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet_with_applicability; +use clippy_utils::sugg::Sugg; +use rustc_ast::{BinOpKind, LitKind}; +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::symbol::Symbol; + +use clippy_config::Conf; + +declare_clippy_lint! { + /// ### What it does + /// Checks for an expression like `(x + (y - 1)) / y` which is a common manual reimplementation + /// of `x.div_ceil(y)`. + /// + /// ### Why is this bad? + /// It's simpler, clearer and more readable. + /// + /// ### Example + /// ```no_run + /// let x: i32 = 7; + /// let y: i32 = 4; + /// let div = (x + (y - 1)) / y; + /// ``` + /// Use instead: + /// ```no_run + /// #![feature(int_roundings)] + /// let x: i32 = 7; + /// let y: i32 = 4; + /// let div = x.div_ceil(y); + /// ``` + #[clippy::version = "1.81.0"] + pub MANUAL_DIV_CEIL, + complexity, + "manually reimplementing `div_ceil`" +} + +pub struct ManualDivCeil { + msrv: Msrv, +} + +impl ManualDivCeil { + #[must_use] + pub fn new(conf: &'static Conf) -> Self { + Self { + msrv: conf.msrv.clone(), + } + } +} + +impl_lint_pass!(ManualDivCeil => [MANUAL_DIV_CEIL]); + +impl<'tcx> LateLintPass<'tcx> for ManualDivCeil { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'_>) { + if !self.msrv.meets(msrvs::MANUAL_DIV_CEIL) { + return; + } + + let mut applicability = Applicability::MachineApplicable; + + if let ExprKind::Binary(div_op, div_lhs, div_rhs) = expr.kind + && div_op.node == BinOpKind::Div + && check_int_ty_and_feature(cx, div_lhs) + && check_int_ty_and_feature(cx, div_rhs) + && let ExprKind::Binary(inner_op, inner_lhs, inner_rhs) = div_lhs.kind + { + // (x + (y - 1)) / y + if let ExprKind::Binary(sub_op, sub_lhs, sub_rhs) = inner_rhs.kind + && inner_op.node == BinOpKind::Add + && sub_op.node == BinOpKind::Sub + && check_literal(sub_rhs) + && check_eq_expr(cx, sub_lhs, div_rhs) + { + build_suggestion(cx, expr, inner_lhs, div_rhs, &mut applicability); + return; + } + + // ((y - 1) + x) / y + if let ExprKind::Binary(sub_op, sub_lhs, sub_rhs) = inner_lhs.kind + && inner_op.node == BinOpKind::Add + && sub_op.node == BinOpKind::Sub + && check_literal(sub_rhs) + && check_eq_expr(cx, sub_lhs, div_rhs) + { + build_suggestion(cx, expr, inner_rhs, div_rhs, &mut applicability); + return; + } + + // (x + y - 1) / y + if let ExprKind::Binary(add_op, add_lhs, add_rhs) = inner_lhs.kind + && inner_op.node == BinOpKind::Sub + && add_op.node == BinOpKind::Add + && check_literal(inner_rhs) + && check_eq_expr(cx, add_rhs, div_rhs) + { + build_suggestion(cx, expr, add_lhs, div_rhs, &mut applicability); + } + } + } + + extract_msrv_attr!(LateContext); +} + +fn check_int_ty_and_feature(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { + let expr_ty = cx.typeck_results().expr_ty(expr); + match expr_ty.peel_refs().kind() { + ty::Uint(_) => true, + ty::Int(_) => cx + .tcx + .features() + .declared_features + .contains(&Symbol::intern("int_roundings")), + + _ => false, + } +} + +fn check_literal(expr: &Expr<'_>) -> bool { + if let ExprKind::Lit(lit) = expr.kind + && let LitKind::Int(Pu128(1), _) = lit.node + { + return true; + } + false +} + +fn check_eq_expr(cx: &LateContext<'_>, lhs: &Expr<'_>, rhs: &Expr<'_>) -> bool { + SpanlessEq::new(cx).eq_expr(lhs, rhs) +} + +fn build_suggestion( + cx: &LateContext<'_>, + expr: &Expr<'_>, + lhs: &Expr<'_>, + rhs: &Expr<'_>, + applicability: &mut Applicability, +) { + let dividend_sugg = Sugg::hir_with_applicability(cx, lhs, "..", applicability).maybe_par(); + let divisor_snippet = snippet_with_applicability(cx, rhs.span.source_callsite(), "..", applicability); + + let sugg = format!("{dividend_sugg}.div_ceil({divisor_snippet})"); + + span_lint_and_sugg( + cx, + MANUAL_DIV_CEIL, + expr.span, + "manually reimplementing `div_ceil`", + "consider using `.div_ceil()`", + sugg, + *applicability, + ); +} diff --git a/clippy_lints/src/manual_hash_one.rs b/clippy_lints/src/manual_hash_one.rs index 11716a539ab..c62bd65bea6 100644 --- a/clippy_lints/src/manual_hash_one.rs +++ b/clippy_lints/src/manual_hash_one.rs @@ -1,5 +1,5 @@ -use clippy_config::msrvs::{self, Msrv}; use clippy_config::Conf; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_hir_and_then; use clippy_utils::source::SpanRangeExt; use clippy_utils::visitors::{is_local_used, local_used_once}; diff --git a/clippy_lints/src/manual_is_ascii_check.rs b/clippy_lints/src/manual_is_ascii_check.rs index 31c37c3bc3b..24207705743 100644 --- a/clippy_lints/src/manual_is_ascii_check.rs +++ b/clippy_lints/src/manual_is_ascii_check.rs @@ -1,17 +1,17 @@ -use clippy_config::msrvs::{self, Msrv}; use clippy_config::Conf; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::macros::matching_root_macro_call; use clippy_utils::sugg::Sugg; use clippy_utils::{higher, is_in_const_context, path_to_local, peel_ref_operators}; -use rustc_ast::ast::RangeLimits; 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_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_session::impl_lint_pass; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/manual_is_power_of_two.rs b/clippy_lints/src/manual_is_power_of_two.rs new file mode 100644 index 00000000000..da2a982ee17 --- /dev/null +++ b/clippy_lints/src/manual_is_power_of_two.rs @@ -0,0 +1,142 @@ +use clippy_utils::SpanlessEq; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet_with_applicability; +use rustc_ast::LitKind; +use rustc_data_structures::packed::Pu128; +use rustc_errors::Applicability; +use rustc_hir::{BinOpKind, Expr, ExprKind}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty::Uint; +use rustc_session::declare_lint_pass; + +declare_clippy_lint! { + /// ### What it does + /// Checks for expressions like `x.count_ones() == 1` or `x & (x - 1) == 0`, with x and unsigned integer, which are manual + /// reimplementations of `x.is_power_of_two()`. + /// ### Why is this bad? + /// Manual reimplementations of `is_power_of_two` increase code complexity for little benefit. + /// ### Example + /// ```no_run + /// let a: u32 = 4; + /// let result = a.count_ones() == 1; + /// ``` + /// Use instead: + /// ```no_run + /// let a: u32 = 4; + /// let result = a.is_power_of_two(); + /// ``` + #[clippy::version = "1.82.0"] + pub MANUAL_IS_POWER_OF_TWO, + complexity, + "manually reimplementing `is_power_of_two`" +} + +declare_lint_pass!(ManualIsPowerOfTwo => [MANUAL_IS_POWER_OF_TWO]); + +impl LateLintPass<'_> for ManualIsPowerOfTwo { + fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { + let mut applicability = Applicability::MachineApplicable; + + if let ExprKind::Binary(bin_op, left, right) = expr.kind + && bin_op.node == BinOpKind::Eq + { + // a.count_ones() == 1 + if let ExprKind::MethodCall(method_name, reciever, _, _) = left.kind + && method_name.ident.as_str() == "count_ones" + && let &Uint(_) = cx.typeck_results().expr_ty(reciever).kind() + && check_lit(right, 1) + { + build_sugg(cx, expr, reciever, &mut applicability); + } + + // 1 == a.count_ones() + if let ExprKind::MethodCall(method_name, reciever, _, _) = right.kind + && method_name.ident.as_str() == "count_ones" + && let &Uint(_) = cx.typeck_results().expr_ty(reciever).kind() + && check_lit(left, 1) + { + build_sugg(cx, expr, reciever, &mut applicability); + } + + // a & (a - 1) == 0 + if let ExprKind::Binary(op1, left1, right1) = left.kind + && op1.node == BinOpKind::BitAnd + && let ExprKind::Binary(op2, left2, right2) = right1.kind + && op2.node == BinOpKind::Sub + && check_eq_expr(cx, left1, left2) + && let &Uint(_) = cx.typeck_results().expr_ty(left1).kind() + && check_lit(right2, 1) + && check_lit(right, 0) + { + build_sugg(cx, expr, left1, &mut applicability); + } + + // (a - 1) & a == 0; + if let ExprKind::Binary(op1, left1, right1) = left.kind + && op1.node == BinOpKind::BitAnd + && let ExprKind::Binary(op2, left2, right2) = left1.kind + && op2.node == BinOpKind::Sub + && check_eq_expr(cx, right1, left2) + && let &Uint(_) = cx.typeck_results().expr_ty(right1).kind() + && check_lit(right2, 1) + && check_lit(right, 0) + { + build_sugg(cx, expr, right1, &mut applicability); + } + + // 0 == a & (a - 1); + if let ExprKind::Binary(op1, left1, right1) = right.kind + && op1.node == BinOpKind::BitAnd + && let ExprKind::Binary(op2, left2, right2) = right1.kind + && op2.node == BinOpKind::Sub + && check_eq_expr(cx, left1, left2) + && let &Uint(_) = cx.typeck_results().expr_ty(left1).kind() + && check_lit(right2, 1) + && check_lit(left, 0) + { + build_sugg(cx, expr, left1, &mut applicability); + } + + // 0 == (a - 1) & a + if let ExprKind::Binary(op1, left1, right1) = right.kind + && op1.node == BinOpKind::BitAnd + && let ExprKind::Binary(op2, left2, right2) = left1.kind + && op2.node == BinOpKind::Sub + && check_eq_expr(cx, right1, left2) + && let &Uint(_) = cx.typeck_results().expr_ty(right1).kind() + && check_lit(right2, 1) + && check_lit(left, 0) + { + build_sugg(cx, expr, right1, &mut applicability); + } + } + } +} + +fn build_sugg(cx: &LateContext<'_>, expr: &Expr<'_>, reciever: &Expr<'_>, applicability: &mut Applicability) { + let snippet = snippet_with_applicability(cx, reciever.span, "..", applicability); + + span_lint_and_sugg( + cx, + MANUAL_IS_POWER_OF_TWO, + expr.span, + "manually reimplementing `is_power_of_two`", + "consider using `.is_power_of_two()`", + format!("{snippet}.is_power_of_two()"), + *applicability, + ); +} + +fn check_lit(expr: &Expr<'_>, expected_num: u128) -> bool { + if let ExprKind::Lit(lit) = expr.kind + && let LitKind::Int(Pu128(num), _) = lit.node + && num == expected_num + { + return true; + } + false +} + +fn check_eq_expr(cx: &LateContext<'_>, lhs: &Expr<'_>, rhs: &Expr<'_>) -> bool { + SpanlessEq::new(cx).eq_expr(lhs, rhs) +} diff --git a/clippy_lints/src/manual_let_else.rs b/clippy_lints/src/manual_let_else.rs index ebebdf679a8..17185df5d76 100644 --- a/clippy_lints/src/manual_let_else.rs +++ b/clippy_lints/src/manual_let_else.rs @@ -1,4 +1,4 @@ -use crate::question_mark::{QuestionMark, QUESTION_MARK}; +use crate::question_mark::{QUESTION_MARK, QuestionMark}; use clippy_config::msrvs; use clippy_config::types::MatchLintBehaviour; use clippy_utils::diagnostics::span_lint_and_then; @@ -12,8 +12,8 @@ use rustc_hir::{Expr, ExprKind, MatchSource, Pat, PatKind, QPath, Stmt, StmtKind use rustc_lint::{LateContext, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_span::symbol::{sym, Symbol}; use rustc_span::Span; +use rustc_span::symbol::{Symbol, sym}; use std::slice; declare_clippy_lint! { diff --git a/clippy_lints/src/manual_main_separator_str.rs b/clippy_lints/src/manual_main_separator_str.rs index 5198d7838a2..85e99a92cf5 100644 --- a/clippy_lints/src/manual_main_separator_str.rs +++ b/clippy_lints/src/manual_main_separator_str.rs @@ -1,5 +1,5 @@ -use clippy_config::msrvs::{self, Msrv}; use clippy_config::Conf; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::{is_trait_method, peel_hir_expr_refs}; use rustc_errors::Applicability; diff --git a/clippy_lints/src/manual_non_exhaustive.rs b/clippy_lints/src/manual_non_exhaustive.rs index 6b1d90483cc..25868ccae40 100644 --- a/clippy_lints/src/manual_non_exhaustive.rs +++ b/clippy_lints/src/manual_non_exhaustive.rs @@ -1,18 +1,18 @@ -use clippy_config::msrvs::{self, Msrv}; use clippy_config::Conf; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::{span_lint_and_then, span_lint_hir_and_then}; use clippy_utils::is_doc_hidden; -use clippy_utils::source::SpanRangeExt; -use rustc_ast::ast::{self, VisibilityKind}; +use clippy_utils::source::snippet_indent; +use itertools::Itertools; use rustc_ast::attr; use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res}; -use rustc_hir::{self as hir, Expr, ExprKind, QPath}; -use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext}; +use rustc_hir::{Expr, ExprKind, Item, ItemKind, QPath, TyKind, VariantData}; +use rustc_lint::{LateContext, LateLintPass}; use rustc_session::impl_lint_pass; -use rustc_span::def_id::{DefId, LocalDefId}; -use rustc_span::{sym, Span}; +use rustc_span::def_id::LocalDefId; +use rustc_span::{Span, sym}; declare_clippy_lint! { /// ### What it does @@ -62,29 +62,13 @@ declare_clippy_lint! { "manual implementations of the non-exhaustive pattern can be simplified using #[non_exhaustive]" } -#[expect(clippy::module_name_repetitions)] -pub struct ManualNonExhaustiveStruct { +pub struct ManualNonExhaustive { msrv: Msrv, -} - -impl ManualNonExhaustiveStruct { - pub fn new(conf: &'static Conf) -> Self { - Self { - msrv: conf.msrv.clone(), - } - } -} - -impl_lint_pass!(ManualNonExhaustiveStruct => [MANUAL_NON_EXHAUSTIVE]); - -#[expect(clippy::module_name_repetitions)] -pub struct ManualNonExhaustiveEnum { - msrv: Msrv, - constructed_enum_variants: FxHashSet<(DefId, DefId)>, + constructed_enum_variants: FxHashSet, potential_enums: Vec<(LocalDefId, LocalDefId, Span, Span)>, } -impl ManualNonExhaustiveEnum { +impl ManualNonExhaustive { pub fn new(conf: &'static Conf) -> Self { Self { msrv: conf.msrv.clone(), @@ -94,96 +78,78 @@ impl ManualNonExhaustiveEnum { } } -impl_lint_pass!(ManualNonExhaustiveEnum => [MANUAL_NON_EXHAUSTIVE]); +impl_lint_pass!(ManualNonExhaustive => [MANUAL_NON_EXHAUSTIVE]); -impl EarlyLintPass for ManualNonExhaustiveStruct { - fn check_item(&mut self, cx: &EarlyContext<'_>, item: &ast::Item) { - if let ast::ItemKind::Struct(variant_data, _) = &item.kind - && let (fields, delimiter) = match variant_data { - ast::VariantData::Struct { fields, .. } => (&**fields, '{'), - ast::VariantData::Tuple(fields, _) => (&**fields, '('), - ast::VariantData::Unit(_) => return, - } - && fields.len() > 1 - && self.msrv.meets(msrvs::NON_EXHAUSTIVE) - { - let mut iter = fields.iter().filter_map(|f| match f.vis.kind { - VisibilityKind::Public => None, - VisibilityKind::Inherited => Some(Ok(f)), - VisibilityKind::Restricted { .. } => Some(Err(())), - }); - if let Some(Ok(field)) = iter.next() - && iter.next().is_none() - && field.ty.kind.is_unit() - { - span_lint_and_then( - cx, - MANUAL_NON_EXHAUSTIVE, - item.span, - "this seems like a manual implementation of the non-exhaustive pattern", - |diag| { - if !item.attrs.iter().any(|attr| attr.has_name(sym::non_exhaustive)) - && let header_span = cx.sess().source_map().span_until_char(item.span, delimiter) - && let Some(snippet) = header_span.get_source_text(cx) - { - diag.span_suggestion( - header_span, - "add the attribute", - format!("#[non_exhaustive] {snippet}"), - Applicability::Unspecified, - ); - } - diag.span_help(field.span, "remove this field"); - }, - ); - } - } - } - - extract_msrv_attr!(EarlyContext); -} - -impl<'tcx> LateLintPass<'tcx> for ManualNonExhaustiveEnum { - fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) { - if !self.msrv.meets(msrvs::NON_EXHAUSTIVE) { +impl<'tcx> LateLintPass<'tcx> for ManualNonExhaustive { + fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) { + if !self.msrv.meets(msrvs::NON_EXHAUSTIVE) || !cx.effective_visibilities.is_exported(item.owner_id.def_id) { return; } - if let hir::ItemKind::Enum(def, _) = &item.kind - && def.variants.len() > 1 - { - let mut iter = def.variants.iter().filter_map(|v| { - (matches!(v.data, hir::VariantData::Unit(_, _)) - && is_doc_hidden(cx.tcx.hir().attrs(v.hir_id)) - && !attr::contains_name(cx.tcx.hir().attrs(item.hir_id()), sym::non_exhaustive)) - .then_some((v.def_id, v.span)) - }); - if let Some((id, span)) = iter.next() - && iter.next().is_none() - { - self.potential_enums.push((item.owner_id.def_id, id, item.span, span)); - } + match item.kind { + ItemKind::Enum(def, _) if def.variants.len() > 1 => { + let iter = def.variants.iter().filter_map(|v| { + (matches!(v.data, VariantData::Unit(_, _)) && is_doc_hidden(cx.tcx.hir().attrs(v.hir_id))) + .then_some((v.def_id, v.span)) + }); + if let Ok((id, span)) = iter.exactly_one() + && !attr::contains_name(cx.tcx.hir().attrs(item.hir_id()), sym::non_exhaustive) + { + self.potential_enums.push((item.owner_id.def_id, id, item.span, span)); + } + }, + ItemKind::Struct(variant_data, _) => { + let fields = variant_data.fields(); + let private_fields = fields + .iter() + .filter(|field| !cx.effective_visibilities.is_exported(field.def_id)); + if fields.len() > 1 + && let Ok(field) = private_fields.exactly_one() + && let TyKind::Tup([]) = field.ty.kind + { + span_lint_and_then( + cx, + MANUAL_NON_EXHAUSTIVE, + item.span, + "this seems like a manual implementation of the non-exhaustive pattern", + |diag| { + if let Some(non_exhaustive) = + attr::find_by_name(cx.tcx.hir().attrs(item.hir_id()), sym::non_exhaustive) + { + diag.span_note(non_exhaustive.span, "the struct is already non-exhaustive"); + } else { + let indent = snippet_indent(cx, item.span).unwrap_or_default(); + diag.span_suggestion_verbose( + item.span.shrink_to_lo(), + "use the `#[non_exhaustive]` attribute instead", + format!("#[non_exhaustive]\n{indent}"), + Applicability::MaybeIncorrect, + ); + } + diag.span_help(field.span, "remove this field"); + }, + ); + } + }, + _ => {}, } } fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) { if let ExprKind::Path(QPath::Resolved(None, p)) = &e.kind - && let Res::Def(DefKind::Ctor(CtorOf::Variant, CtorKind::Const), id) = p.res + && let Res::Def(DefKind::Ctor(CtorOf::Variant, CtorKind::Const), ctor_id) = p.res + && let Some(local_ctor) = ctor_id.as_local() { - let variant_id = cx.tcx.parent(id); - let enum_id = cx.tcx.parent(variant_id); - - self.constructed_enum_variants.insert((enum_id, variant_id)); + let variant_id = cx.tcx.local_parent(local_ctor); + self.constructed_enum_variants.insert(variant_id); } } fn check_crate_post(&mut self, cx: &LateContext<'tcx>) { - for &(enum_id, _, enum_span, variant_span) in - self.potential_enums.iter().filter(|&&(enum_id, variant_id, _, _)| { - !self - .constructed_enum_variants - .contains(&(enum_id.to_def_id(), variant_id.to_def_id())) - }) + for &(enum_id, _, enum_span, variant_span) in self + .potential_enums + .iter() + .filter(|(_, variant_id, _, _)| !self.constructed_enum_variants.contains(variant_id)) { let hir_id = cx.tcx.local_def_id_to_hir_id(enum_id); span_lint_hir_and_then( @@ -193,15 +159,13 @@ impl<'tcx> LateLintPass<'tcx> for ManualNonExhaustiveEnum { enum_span, "this seems like a manual implementation of the non-exhaustive pattern", |diag| { - let header_span = cx.sess().source_map().span_until_char(enum_span, '{'); - if let Some(snippet) = header_span.get_source_text(cx) { - diag.span_suggestion( - header_span, - "add the attribute", - format!("#[non_exhaustive] {snippet}"), - Applicability::Unspecified, - ); - } + let indent = snippet_indent(cx, enum_span).unwrap_or_default(); + diag.span_suggestion_verbose( + enum_span.shrink_to_lo(), + "use the `#[non_exhaustive]` attribute instead", + format!("#[non_exhaustive]\n{indent}"), + Applicability::MaybeIncorrect, + ); diag.span_help(variant_span, "remove this variant"); }, ); diff --git a/clippy_lints/src/manual_range_patterns.rs b/clippy_lints/src/manual_range_patterns.rs index 9afb2b5bc84..ffa3eacf354 100644 --- a/clippy_lints/src/manual_range_patterns.rs +++ b/clippy_lints/src/manual_range_patterns.rs @@ -7,7 +7,7 @@ use rustc_hir::{Expr, ExprKind, PatKind, RangeEnd, UnOp}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_session::declare_lint_pass; -use rustc_span::{Span, DUMMY_SP}; +use rustc_span::{DUMMY_SP, Span}; declare_clippy_lint! { /// ### What it does @@ -77,9 +77,10 @@ impl Num { impl LateLintPass<'_> for ManualRangePatterns { fn check_pat(&mut self, cx: &LateContext<'_>, pat: &'_ rustc_hir::Pat<'_>) { // a pattern like 1 | 2 seems fine, lint if there are at least 3 alternatives - // or at least one range + // or more then one range (exclude triggering on stylistic using OR with one element + // like described https://github.com/rust-lang/rust-clippy/issues/11825) if let PatKind::Or(pats) = pat.kind - && (pats.len() >= 3 || pats.iter().any(|p| matches!(p.kind, PatKind::Range(..)))) + && (pats.len() >= 3 || (pats.len() > 1 && pats.iter().any(|p| matches!(p.kind, PatKind::Range(..))))) && !in_external_macro(cx.sess(), pat.span) { let mut min = Num::dummy(i128::MAX); diff --git a/clippy_lints/src/manual_rem_euclid.rs b/clippy_lints/src/manual_rem_euclid.rs index 6cf5d272d7d..86293169ea2 100644 --- a/clippy_lints/src/manual_rem_euclid.rs +++ b/clippy_lints/src/manual_rem_euclid.rs @@ -1,5 +1,5 @@ -use clippy_config::msrvs::{self, Msrv}; use clippy_config::Conf; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::consts::{ConstEvalCtxt, FullInt}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_context; diff --git a/clippy_lints/src/manual_retain.rs b/clippy_lints/src/manual_retain.rs index a35b0f914e0..a60163be770 100644 --- a/clippy_lints/src/manual_retain.rs +++ b/clippy_lints/src/manual_retain.rs @@ -1,17 +1,17 @@ -use clippy_config::msrvs::{self, Msrv}; use clippy_config::Conf; +use clippy_config::msrvs::{self, Msrv}; +use clippy_utils::SpanlessEq; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet; use clippy_utils::ty::{get_type_diagnostic_name, is_type_lang_item}; -use clippy_utils::SpanlessEq; use rustc_errors::Applicability; use rustc_hir as hir; -use rustc_hir::def_id::DefId; use rustc_hir::ExprKind::Assign; +use rustc_hir::def_id::DefId; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::impl_lint_pass; -use rustc_span::symbol::{sym, Symbol}; use rustc_span::Span; +use rustc_span::symbol::{Symbol, sym}; const ACCEPTABLE_METHODS: [Symbol; 5] = [ sym::binaryheap_iter, diff --git a/clippy_lints/src/manual_string_new.rs b/clippy_lints/src/manual_string_new.rs index 781db4b97f0..198f7aaddc7 100644 --- a/clippy_lints/src/manual_string_new.rs +++ b/clippy_lints/src/manual_string_new.rs @@ -5,7 +5,7 @@ use rustc_hir::{Expr, ExprKind, PathSegment, QPath, TyKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_session::declare_lint_pass; -use rustc_span::{sym, symbol, Span}; +use rustc_span::{Span, sym, symbol}; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/manual_strip.rs b/clippy_lints/src/manual_strip.rs index 02d433ecc5a..9aceca66bf7 100644 --- a/clippy_lints/src/manual_strip.rs +++ b/clippy_lints/src/manual_strip.rs @@ -1,5 +1,5 @@ -use clippy_config::msrvs::{self, Msrv}; use clippy_config::Conf; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::consts::{ConstEvalCtxt, Constant}; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet; @@ -8,13 +8,13 @@ use clippy_utils::{eq_expr_value, higher}; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; use rustc_hir::def::Res; -use rustc_hir::intravisit::{walk_expr, Visitor}; +use rustc_hir::intravisit::{Visitor, walk_expr}; use rustc_hir::{BinOpKind, BorrowKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_session::impl_lint_pass; use rustc_span::source_map::Spanned; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; use std::iter; declare_clippy_lint! { diff --git a/clippy_lints/src/map_unit_fn.rs b/clippy_lints/src/map_unit_fn.rs index 2db71b1f7a3..a97dbbbc33f 100644 --- a/clippy_lints/src/map_unit_fn.rs +++ b/clippy_lints/src/map_unit_fn.rs @@ -7,7 +7,7 @@ use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{self, Ty}; use rustc_session::declare_lint_pass; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/matches/collapsible_match.rs b/clippy_lints/src/matches/collapsible_match.rs index b666e77c09e..50e6dfc6298 100644 --- a/clippy_lints/src/matches/collapsible_match.rs +++ b/clippy_lints/src/matches/collapsible_match.rs @@ -4,7 +4,7 @@ use clippy_utils::higher::IfLetOrMatch; use clippy_utils::source::snippet; use clippy_utils::visitors::is_local_used; use clippy_utils::{ - is_res_lang_ctor, is_unit_expr, path_to_local, peel_blocks_with_stmt, peel_ref_operators, SpanlessEq, + SpanlessEq, is_res_lang_ctor, is_unit_expr, path_to_local, peel_blocks_with_stmt, peel_ref_operators, }; use rustc_errors::MultiSpan; use rustc_hir::LangItem::OptionNone; @@ -12,7 +12,7 @@ use rustc_hir::{Arm, Expr, HirId, Pat, PatKind}; use rustc_lint::LateContext; use rustc_span::Span; -use super::{pat_contains_disallowed_or, COLLAPSIBLE_MATCH}; +use super::{COLLAPSIBLE_MATCH, pat_contains_disallowed_or}; pub(super) fn check_match<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>], msrv: &Msrv) { if let Some(els_arm) = arms.iter().rfind(|arm| arm_is_wild_like(cx, arm)) { diff --git a/clippy_lints/src/matches/manual_filter.rs b/clippy_lints/src/matches/manual_filter.rs index 619ec83127a..cfa054706d6 100644 --- a/clippy_lints/src/matches/manual_filter.rs +++ b/clippy_lints/src/matches/manual_filter.rs @@ -6,10 +6,10 @@ use clippy_utils::{is_res_lang_ctor, path_res, path_to_local_id}; use rustc_hir::LangItem::{OptionNone, OptionSome}; use rustc_hir::{Arm, Expr, ExprKind, HirId, Pat, PatKind}; use rustc_lint::LateContext; -use rustc_span::{sym, SyntaxContext}; +use rustc_span::{SyntaxContext, sym}; -use super::manual_utils::{check_with, SomeExpr}; use super::MANUAL_FILTER; +use super::manual_utils::{SomeExpr, check_with}; // Function called on the of `[&+]Some((ref | ref mut) x) => ` // Need to check if it's of the form `=if {} else {}` diff --git a/clippy_lints/src/matches/manual_map.rs b/clippy_lints/src/matches/manual_map.rs index ed3d8b09fdc..de57d1eee92 100644 --- a/clippy_lints/src/matches/manual_map.rs +++ b/clippy_lints/src/matches/manual_map.rs @@ -1,5 +1,5 @@ -use super::manual_utils::{check_with, SomeExpr}; use super::MANUAL_MAP; +use super::manual_utils::{SomeExpr, check_with}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::{is_res_lang_ctor, path_res}; diff --git a/clippy_lints/src/matches/manual_unwrap_or.rs b/clippy_lints/src/matches/manual_unwrap_or.rs index d5d83df9347..59d37520011 100644 --- a/clippy_lints/src/matches/manual_unwrap_or.rs +++ b/clippy_lints/src/matches/manual_unwrap_or.rs @@ -1,12 +1,12 @@ use clippy_utils::consts::ConstEvalCtxt; use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::{indent_of, reindent_multiline, SpanRangeExt}; +use clippy_utils::source::{SpanRangeExt, indent_of, reindent_multiline}; use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::usage::contains_return_break_continue_macro; use clippy_utils::{is_res_lang_ctor, path_to_local_id, peel_blocks, sugg}; use rustc_errors::Applicability; -use rustc_hir::def::{DefKind, Res}; use rustc_hir::LangItem::{OptionNone, ResultErr}; +use rustc_hir::def::{DefKind, Res}; use rustc_hir::{Arm, Expr, Pat, PatKind}; use rustc_lint::LateContext; use rustc_middle::ty::Ty; diff --git a/clippy_lints/src/matches/manual_utils.rs b/clippy_lints/src/matches/manual_utils.rs index be80aebed6d..d38560998a5 100644 --- a/clippy_lints/src/matches/manual_utils.rs +++ b/clippy_lints/src/matches/manual_utils.rs @@ -4,16 +4,16 @@ use clippy_utils::source::{snippet_with_applicability, snippet_with_context}; use clippy_utils::sugg::Sugg; use clippy_utils::ty::{is_copy, is_type_diagnostic_item, peel_mid_ty_refs_is_mutable, type_is_unsafe_function}; use clippy_utils::{ - can_move_expr_to_closure, is_else_clause, is_lint_allowed, is_res_lang_ctor, path_res, path_to_local_id, - peel_blocks, peel_hir_expr_refs, peel_hir_expr_while, CaptureKind, + CaptureKind, can_move_expr_to_closure, is_else_clause, is_lint_allowed, is_res_lang_ctor, path_res, + path_to_local_id, peel_blocks, peel_hir_expr_refs, peel_hir_expr_while, }; use rustc_ast::util::parser::PREC_UNAMBIGUOUS; use rustc_errors::Applicability; -use rustc_hir::def::Res; use rustc_hir::LangItem::{OptionNone, OptionSome}; +use rustc_hir::def::Res; use rustc_hir::{BindingMode, Expr, ExprKind, HirId, Mutability, Pat, PatKind, Path, QPath}; use rustc_lint::LateContext; -use rustc_span::{sym, SyntaxContext}; +use rustc_span::{SyntaxContext, sym}; #[expect(clippy::too_many_arguments)] #[expect(clippy::too_many_lines)] diff --git a/clippy_lints/src/matches/match_same_arms.rs b/clippy_lints/src/matches/match_same_arms.rs index da8c918a62b..f9ffbc5dc0b 100644 --- a/clippy_lints/src/matches/match_same_arms.rs +++ b/clippy_lints/src/matches/match_same_arms.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_hir_and_then; use clippy_utils::source::snippet_with_applicability; -use clippy_utils::{is_lint_allowed, path_to_local, search_same, SpanlessEq, SpanlessHash}; +use clippy_utils::{SpanlessEq, SpanlessHash, is_lint_allowed, path_to_local, search_same}; use core::cmp::Ordering; use core::{iter, slice}; use rustc_arena::DroplessArena; diff --git a/clippy_lints/src/matches/match_str_case_mismatch.rs b/clippy_lints/src/matches/match_str_case_mismatch.rs index 322e9c3ebe5..40518ce2ca7 100644 --- a/clippy_lints/src/matches/match_str_case_mismatch.rs +++ b/clippy_lints/src/matches/match_str_case_mismatch.rs @@ -2,12 +2,12 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::ty::is_type_lang_item; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; -use rustc_hir::intravisit::{walk_expr, Visitor}; +use rustc_hir::intravisit::{Visitor, walk_expr}; use rustc_hir::{Arm, Expr, ExprKind, LangItem, PatKind}; use rustc_lint::LateContext; use rustc_middle::ty; -use rustc_span::symbol::Symbol; use rustc_span::Span; +use rustc_span::symbol::Symbol; use super::MATCH_STR_CASE_MISMATCH; diff --git a/clippy_lints/src/matches/mod.rs b/clippy_lints/src/matches/mod.rs index cf5377e0725..686fc4a0fa0 100644 --- a/clippy_lints/src/matches/mod.rs +++ b/clippy_lints/src/matches/mod.rs @@ -24,8 +24,8 @@ mod single_match; mod try_err; mod wild_in_or_pats; -use clippy_config::msrvs::{self, Msrv}; use clippy_config::Conf; +use clippy_config::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 rustc_hir::{Arm, Expr, ExprKind, LetStmt, MatchSource, Pat, PatKind}; diff --git a/clippy_lints/src/matches/overlapping_arms.rs b/clippy_lints/src/matches/overlapping_arms.rs index 71f211be925..6a4c553cee0 100644 --- a/clippy_lints/src/matches/overlapping_arms.rs +++ b/clippy_lints/src/matches/overlapping_arms.rs @@ -1,4 +1,4 @@ -use clippy_utils::consts::{mir_to_const, ConstEvalCtxt, FullInt}; +use clippy_utils::consts::{ConstEvalCtxt, FullInt, mir_to_const}; use clippy_utils::diagnostics::span_lint_and_note; use core::cmp::Ordering; use rustc_hir::{Arm, Expr, PatKind, RangeEnd}; diff --git a/clippy_lints/src/matches/redundant_guards.rs b/clippy_lints/src/matches/redundant_guards.rs index 8222c3057f7..564c598a334 100644 --- a/clippy_lints/src/matches/redundant_guards.rs +++ b/clippy_lints/src/matches/redundant_guards.rs @@ -10,11 +10,11 @@ use rustc_hir::def::{DefKind, Res}; use rustc_hir::{Arm, BinOpKind, Expr, ExprKind, MatchSource, Node, PatKind, UnOp}; use rustc_lint::LateContext; use rustc_span::symbol::Ident; -use rustc_span::{sym, Span, Symbol}; +use rustc_span::{Span, Symbol, sym}; use std::borrow::Cow; use std::ops::ControlFlow; -use super::{pat_contains_disallowed_or, REDUNDANT_GUARDS}; +use super::{REDUNDANT_GUARDS, pat_contains_disallowed_or}; pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'tcx>], msrv: &Msrv) { for outer_arm in arms { diff --git a/clippy_lints/src/matches/redundant_pattern_match.rs b/clippy_lints/src/matches/redundant_pattern_match.rs index 0e4b2d9d34a..b646e87a439 100644 --- a/clippy_lints/src/matches/redundant_pattern_match.rs +++ b/clippy_lints/src/matches/redundant_pattern_match.rs @@ -1,18 +1,18 @@ 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::sugg::{make_unop, Sugg}; +use clippy_utils::sugg::{Sugg, make_unop}; use clippy_utils::ty::{is_type_diagnostic_item, needs_ordered_drop}; use clippy_utils::visitors::{any_temporaries_need_ordered_drop, for_each_expr_without_closures}; use clippy_utils::{higher, is_expn_of, is_trait_method}; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; -use rustc_hir::def::{DefKind, Res}; 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_lint::LateContext; use rustc_middle::ty::{self, GenericArgKind, Ty}; -use rustc_span::{sym, Span, Symbol}; +use rustc_span::{Span, Symbol, sym}; use std::fmt::Write; use std::ops::ControlFlow; diff --git a/clippy_lints/src/matches/significant_drop_in_scrutinee.rs b/clippy_lints/src/matches/significant_drop_in_scrutinee.rs index 9c2f42d2187..537f7272f7f 100644 --- a/clippy_lints/src/matches/significant_drop_in_scrutinee.rs +++ b/clippy_lints/src/matches/significant_drop_in_scrutinee.rs @@ -8,7 +8,7 @@ use clippy_utils::{get_attr, is_lint_allowed}; use itertools::Itertools; use rustc_ast::Mutability; use rustc_errors::{Applicability, Diag}; -use rustc_hir::intravisit::{walk_expr, Visitor}; +use rustc_hir::intravisit::{Visitor, walk_expr}; use rustc_hir::{Arm, Expr, ExprKind, MatchSource}; use rustc_lint::{LateContext, LintContext}; use rustc_middle::ty::{GenericArgKind, Region, RegionKind, Ty, TyCtxt, TypeVisitable, TypeVisitor}; diff --git a/clippy_lints/src/matches/single_match.rs b/clippy_lints/src/matches/single_match.rs index b6930f7b9d1..2eda238ae8c 100644 --- a/clippy_lints/src/matches/single_match.rs +++ b/clippy_lints/src/matches/single_match.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::{expr_block, snippet, SpanRangeExt}; +use clippy_utils::source::{SpanRangeExt, expr_block, snippet, snippet_block_with_context}; use clippy_utils::ty::implements_trait; use clippy_utils::{ is_lint_allowed, is_unit_expr, peel_blocks, peel_hir_pat_refs, peel_middle_ty_refs, peel_n_hir_expr_refs, @@ -8,11 +8,11 @@ use core::ops::ControlFlow; use rustc_arena::DroplessArena; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::intravisit::{walk_pat, Visitor}; -use rustc_hir::{Arm, Expr, ExprKind, HirId, Pat, PatKind, QPath}; +use rustc_hir::intravisit::{Visitor, walk_pat}; +use rustc_hir::{Arm, Expr, ExprKind, HirId, Node, Pat, PatKind, QPath, StmtKind}; use rustc_lint::LateContext; use rustc_middle::ty::{self, AdtDef, ParamEnv, TyCtxt, TypeckResults, VariantDef}; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; use super::{MATCH_BOOL, SINGLE_MATCH, SINGLE_MATCH_ELSE}; @@ -91,6 +91,29 @@ fn report_single_pattern(cx: &LateContext<'_>, ex: &Expr<'_>, arm: &Arm<'_>, exp format!(" else {}", expr_block(cx, els, ctxt, "..", Some(expr.span), &mut app)) }); + if snippet(cx, ex.span, "..") == snippet(cx, arm.pat.span, "..") { + let msg = "this pattern is irrefutable, `match` is useless"; + let (sugg, help) = if is_unit_expr(arm.body) { + (String::new(), "`match` expression can be removed") + } else { + let mut sugg = snippet_block_with_context(cx, arm.body.span, ctxt, "..", Some(expr.span), &mut app) + .0 + .to_string(); + if let Node::Stmt(stmt) = cx.tcx.parent_hir_node(expr.hir_id) + && let StmtKind::Expr(_) = stmt.kind + && match arm.body.kind { + ExprKind::Block(block, _) => block.span.from_expansion(), + _ => true, + } + { + sugg.push(';'); + } + (sugg, "try") + }; + span_lint_and_sugg(cx, lint, expr.span, msg, help, sugg.to_string(), app); + return; + } + let (pat, pat_ref_count) = peel_hir_pat_refs(arm.pat); let (msg, sugg) = if let PatKind::Path(_) | PatKind::Lit(_) = pat.kind && let (ty, ty_ref_count) = peel_middle_ty_refs(cx.typeck_results().expr_ty(ex)) diff --git a/clippy_lints/src/mem_replace.rs b/clippy_lints/src/mem_replace.rs index 72a5945ad9b..146748734cf 100644 --- a/clippy_lints/src/mem_replace.rs +++ b/clippy_lints/src/mem_replace.rs @@ -1,5 +1,5 @@ -use clippy_config::msrvs::{self, Msrv}; use clippy_config::Conf; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg, span_lint_and_then}; use clippy_utils::source::{snippet, snippet_with_applicability}; use clippy_utils::sugg::Sugg; @@ -13,8 +13,8 @@ use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::lint::in_external_macro; use rustc_session::impl_lint_pass; -use rustc_span::symbol::sym; use rustc_span::Span; +use rustc_span::symbol::sym; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/methods/bind_instead_of_map.rs b/clippy_lints/src/methods/bind_instead_of_map.rs index 2a8a5fcc3b6..91a5de16e96 100644 --- a/clippy_lints/src/methods/bind_instead_of_map.rs +++ b/clippy_lints/src/methods/bind_instead_of_map.rs @@ -1,4 +1,4 @@ -use super::{contains_return, BIND_INSTEAD_OF_MAP}; +use super::{BIND_INSTEAD_OF_MAP, contains_return}; use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; use clippy_utils::peel_blocks; use clippy_utils::source::{snippet, snippet_with_context}; diff --git a/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs b/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs index 740cce0a6c2..76bdbe55e2f 100644 --- a/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs +++ b/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs @@ -1,12 +1,12 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::{indent_of, reindent_multiline, SpanRangeExt}; +use clippy_utils::source::{SpanRangeExt, indent_of, reindent_multiline}; use clippy_utils::ty::is_type_lang_item; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, LangItem}; use rustc_lint::LateContext; -use rustc_span::source_map::Spanned; use rustc_span::Span; +use rustc_span::source_map::Spanned; use super::CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS; diff --git a/clippy_lints/src/methods/clear_with_drain.rs b/clippy_lints/src/methods/clear_with_drain.rs index 5389861245a..6e24cabca8b 100644 --- a/clippy_lints/src/methods/clear_with_drain.rs +++ b/clippy_lints/src/methods/clear_with_drain.rs @@ -4,8 +4,8 @@ use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item}; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, LangItem, QPath}; use rustc_lint::LateContext; -use rustc_span::symbol::sym; use rustc_span::Span; +use rustc_span::symbol::sym; use super::CLEAR_WITH_DRAIN; diff --git a/clippy_lints/src/methods/clone_on_copy.rs b/clippy_lints/src/methods/clone_on_copy.rs index e7a2060be04..79a473e0e6f 100644 --- a/clippy_lints/src/methods/clone_on_copy.rs +++ b/clippy_lints/src/methods/clone_on_copy.rs @@ -7,7 +7,7 @@ use rustc_lint::LateContext; use rustc_middle::ty::adjustment::Adjust; use rustc_middle::ty::print::with_forced_trimmed_paths; use rustc_middle::ty::{self}; -use rustc_span::symbol::{sym, Symbol}; +use rustc_span::symbol::{Symbol, sym}; use super::CLONE_ON_COPY; diff --git a/clippy_lints/src/methods/clone_on_ref_ptr.rs b/clippy_lints/src/methods/clone_on_ref_ptr.rs index e0826b53004..96e2de0dc1c 100644 --- a/clippy_lints/src/methods/clone_on_ref_ptr.rs +++ b/clippy_lints/src/methods/clone_on_ref_ptr.rs @@ -4,7 +4,7 @@ use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; use rustc_middle::ty; -use rustc_span::symbol::{sym, Symbol}; +use rustc_span::symbol::{Symbol, sym}; use super::CLONE_ON_REF_PTR; diff --git a/clippy_lints/src/methods/cloned_instead_of_copied.rs b/clippy_lints/src/methods/cloned_instead_of_copied.rs index fcafa162236..fa04f74eec1 100644 --- a/clippy_lints/src/methods/cloned_instead_of_copied.rs +++ b/clippy_lints/src/methods/cloned_instead_of_copied.rs @@ -6,7 +6,7 @@ use rustc_errors::Applicability; use rustc_hir::Expr; use rustc_lint::LateContext; use rustc_middle::ty; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; use super::CLONED_INSTEAD_OF_COPIED; diff --git a/clippy_lints/src/methods/collapsible_str_replace.rs b/clippy_lints/src/methods/collapsible_str_replace.rs index 1fab6c0e499..f7bf8764bde 100644 --- a/clippy_lints/src/methods/collapsible_str_replace.rs +++ b/clippy_lints/src/methods/collapsible_str_replace.rs @@ -8,7 +8,7 @@ use rustc_hir as hir; use rustc_lint::LateContext; use std::collections::VecDeque; -use super::{method_call, COLLAPSIBLE_STR_REPLACE}; +use super::{COLLAPSIBLE_STR_REPLACE, method_call}; pub(super) fn check<'tcx>( cx: &LateContext<'tcx>, diff --git a/clippy_lints/src/methods/drain_collect.rs b/clippy_lints/src/methods/drain_collect.rs index 56171a13452..10360b4817b 100644 --- a/clippy_lints/src/methods/drain_collect.rs +++ b/clippy_lints/src/methods/drain_collect.rs @@ -8,7 +8,7 @@ use rustc_hir::{Expr, ExprKind, LangItem, Path, QPath}; use rustc_lint::LateContext; use rustc_middle::ty; use rustc_middle::ty::Ty; -use rustc_span::{sym, Symbol}; +use rustc_span::{Symbol, sym}; /// Checks if both types match the given diagnostic item, e.g.: /// diff --git a/clippy_lints/src/methods/err_expect.rs b/clippy_lints/src/methods/err_expect.rs index dc978c8a584..3b1adb16b80 100644 --- a/clippy_lints/src/methods/err_expect.rs +++ b/clippy_lints/src/methods/err_expect.rs @@ -6,7 +6,7 @@ use rustc_errors::Applicability; use rustc_lint::LateContext; use rustc_middle::ty; use rustc_middle::ty::Ty; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; pub(super) fn check( cx: &LateContext<'_>, diff --git a/clippy_lints/src/methods/expect_fun_call.rs b/clippy_lints/src/methods/expect_fun_call.rs index c9f56e1d980..2922086522c 100644 --- a/clippy_lints/src/methods/expect_fun_call.rs +++ b/clippy_lints/src/methods/expect_fun_call.rs @@ -1,13 +1,13 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::macros::{format_args_inputs_span, root_macro_call_first_node, FormatArgsStorage}; +use clippy_utils::macros::{FormatArgsStorage, format_args_inputs_span, root_macro_call_first_node}; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; use rustc_middle::ty; -use rustc_span::symbol::sym; use rustc_span::Span; +use rustc_span::symbol::sym; use std::borrow::Cow; use super::EXPECT_FUN_CALL; diff --git a/clippy_lints/src/methods/filetype_is_file.rs b/clippy_lints/src/methods/filetype_is_file.rs index 2ab0401947c..35008c39c08 100644 --- a/clippy_lints/src/methods/filetype_is_file.rs +++ b/clippy_lints/src/methods/filetype_is_file.rs @@ -3,7 +3,7 @@ use clippy_utils::get_parent_expr; use clippy_utils::ty::is_type_diagnostic_item; use rustc_hir as hir; use rustc_lint::LateContext; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; use super::FILETYPE_IS_FILE; diff --git a/clippy_lints/src/methods/filter_map.rs b/clippy_lints/src/methods/filter_map.rs index 02a11257007..06482a743dd 100644 --- a/clippy_lints/src/methods/filter_map.rs +++ b/clippy_lints/src/methods/filter_map.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; use clippy_utils::macros::{is_panic, matching_root_macro_call, root_macro_call}; use clippy_utils::source::{indent_of, reindent_multiline, snippet}; use clippy_utils::ty::is_type_diagnostic_item; -use clippy_utils::{higher, is_trait_method, path_to_local_id, peel_blocks, SpanlessEq}; +use clippy_utils::{SpanlessEq, higher, is_trait_method, path_to_local_id, peel_blocks}; use hir::{Body, HirId, MatchSource, Pat}; use rustc_errors::Applicability; use rustc_hir as hir; @@ -10,8 +10,8 @@ use rustc_hir::def::Res; use rustc_hir::{Closure, Expr, ExprKind, PatKind, PathSegment, QPath, UnOp}; use rustc_lint::LateContext; use rustc_middle::ty::adjustment::Adjust; -use rustc_span::symbol::{sym, Ident, Symbol}; use rustc_span::Span; +use rustc_span::symbol::{Ident, Symbol, sym}; use std::borrow::Cow; use super::{MANUAL_FILTER_MAP, MANUAL_FIND_MAP, OPTION_FILTER_MAP, RESULT_FILTER_MAP}; diff --git a/clippy_lints/src/methods/filter_map_bool_then.rs b/clippy_lints/src/methods/filter_map_bool_then.rs index 77a62fbb4fb..129e6925428 100644 --- a/clippy_lints/src/methods/filter_map_bool_then.rs +++ b/clippy_lints/src/methods/filter_map_bool_then.rs @@ -7,9 +7,9 @@ use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_middle::ty::adjustment::Adjust; use rustc_middle::ty::Binder; -use rustc_span::{sym, Span}; +use rustc_middle::ty::adjustment::Adjust; +use rustc_span::{Span, sym}; pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, arg: &Expr<'_>, call_span: Span) { if !in_external_macro(cx.sess(), expr.span) diff --git a/clippy_lints/src/methods/filter_map_identity.rs b/clippy_lints/src/methods/filter_map_identity.rs index 999df875c75..cf7f276dabb 100644 --- a/clippy_lints/src/methods/filter_map_identity.rs +++ b/clippy_lints/src/methods/filter_map_identity.rs @@ -3,7 +3,7 @@ use clippy_utils::{is_expr_identity_function, is_expr_untyped_identity_function, use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; use super::FILTER_MAP_IDENTITY; diff --git a/clippy_lints/src/methods/flat_map_identity.rs b/clippy_lints/src/methods/flat_map_identity.rs index 651ea34f9d0..0c2ecfbc8ff 100644 --- a/clippy_lints/src/methods/flat_map_identity.rs +++ b/clippy_lints/src/methods/flat_map_identity.rs @@ -3,7 +3,7 @@ use clippy_utils::{is_expr_untyped_identity_function, is_trait_method}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; use super::FLAT_MAP_IDENTITY; diff --git a/clippy_lints/src/methods/flat_map_option.rs b/clippy_lints/src/methods/flat_map_option.rs index 0a4a381b861..3242dcadb70 100644 --- a/clippy_lints/src/methods/flat_map_option.rs +++ b/clippy_lints/src/methods/flat_map_option.rs @@ -4,7 +4,7 @@ use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; use rustc_middle::ty; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; use super::FLAT_MAP_OPTION; use clippy_utils::ty::is_type_diagnostic_item; diff --git a/clippy_lints/src/methods/get_last_with_len.rs b/clippy_lints/src/methods/get_last_with_len.rs index 62037651134..5f6fb4c821d 100644 --- a/clippy_lints/src/methods/get_last_with_len.rs +++ b/clippy_lints/src/methods/get_last_with_len.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; -use clippy_utils::{is_integer_literal, SpanlessEq}; +use clippy_utils::{SpanlessEq, is_integer_literal}; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::LateContext; diff --git a/clippy_lints/src/methods/inefficient_to_string.rs b/clippy_lints/src/methods/inefficient_to_string.rs index 230a8eb2ec4..4ed7de81ea3 100644 --- a/clippy_lints/src/methods/inefficient_to_string.rs +++ b/clippy_lints/src/methods/inefficient_to_string.rs @@ -5,7 +5,7 @@ use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; use rustc_middle::ty::{self, Ty}; -use rustc_span::symbol::{sym, Symbol}; +use rustc_span::symbol::{Symbol, sym}; use super::INEFFICIENT_TO_STRING; diff --git a/clippy_lints/src/methods/inspect_for_each.rs b/clippy_lints/src/methods/inspect_for_each.rs index ad4b6fa130e..3706f3b670b 100644 --- a/clippy_lints/src/methods/inspect_for_each.rs +++ b/clippy_lints/src/methods/inspect_for_each.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::is_trait_method; use rustc_hir as hir; use rustc_lint::LateContext; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; use super::INSPECT_FOR_EACH; diff --git a/clippy_lints/src/methods/into_iter_on_ref.rs b/clippy_lints/src/methods/into_iter_on_ref.rs index bbc7ce8d78a..bedeb63367d 100644 --- a/clippy_lints/src/methods/into_iter_on_ref.rs +++ b/clippy_lints/src/methods/into_iter_on_ref.rs @@ -5,8 +5,8 @@ use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; use rustc_middle::ty::{self, Ty}; -use rustc_span::symbol::{sym, Symbol}; use rustc_span::Span; +use rustc_span::symbol::{Symbol, sym}; use super::INTO_ITER_ON_REF; diff --git a/clippy_lints/src/methods/iter_filter.rs b/clippy_lints/src/methods/iter_filter.rs index b93d51eac64..f6612c984a7 100644 --- a/clippy_lints/src/methods/iter_filter.rs +++ b/clippy_lints/src/methods/iter_filter.rs @@ -10,8 +10,8 @@ use clippy_utils::{get_parent_expr, is_trait_method, peel_blocks, span_contains_ use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::QPath; -use rustc_span::symbol::{sym, Ident, Symbol}; use rustc_span::Span; +use rustc_span::symbol::{Ident, Symbol, sym}; use std::borrow::Cow; /// diff --git a/clippy_lints/src/methods/iter_kv_map.rs b/clippy_lints/src/methods/iter_kv_map.rs index 33de3b87abc..390dd24b505 100644 --- a/clippy_lints/src/methods/iter_kv_map.rs +++ b/clippy_lints/src/methods/iter_kv_map.rs @@ -14,7 +14,6 @@ use rustc_span::sym; /// - `hashmap.into_iter().map(|(_, v)| v)` /// /// on `HashMaps` and `BTreeMaps` in std - pub(super) fn check<'tcx>( cx: &LateContext<'tcx>, map_type: &'tcx str, // iter / into_iter diff --git a/clippy_lints/src/methods/iter_nth.rs b/clippy_lints/src/methods/iter_nth.rs index e31fa2f777d..82bda5d9512 100644 --- a/clippy_lints/src/methods/iter_nth.rs +++ b/clippy_lints/src/methods/iter_nth.rs @@ -3,8 +3,8 @@ use clippy_utils::ty::get_type_diagnostic_name; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; -use rustc_span::symbol::sym; use rustc_span::Span; +use rustc_span::symbol::sym; use super::ITER_NTH; diff --git a/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs b/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs index 7f6b666e434..9d562f5e51d 100644 --- a/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs +++ b/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs @@ -5,9 +5,9 @@ use clippy_utils::source::snippet; use clippy_utils::{get_expr_use_or_unification_node, is_res_lang_ctor, path_res, std_or_core}; use rustc_errors::Applicability; +use rustc_hir::LangItem::{OptionNone, OptionSome}; use rustc_hir::def_id::DefId; use rustc_hir::hir_id::HirId; -use rustc_hir::LangItem::{OptionNone, OptionSome}; use rustc_hir::{Expr, ExprKind, Node}; use rustc_lint::LateContext; diff --git a/clippy_lints/src/methods/iter_with_drain.rs b/clippy_lints/src/methods/iter_with_drain.rs index 1378a07cbc4..16305871337 100644 --- a/clippy_lints/src/methods/iter_with_drain.rs +++ b/clippy_lints/src/methods/iter_with_drain.rs @@ -3,8 +3,8 @@ use clippy_utils::is_range_full; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, QPath}; use rustc_lint::LateContext; -use rustc_span::symbol::sym; use rustc_span::Span; +use rustc_span::symbol::sym; use super::ITER_WITH_DRAIN; diff --git a/clippy_lints/src/methods/join_absolute_paths.rs b/clippy_lints/src/methods/join_absolute_paths.rs index 2dad7fcf3c1..2ad070793cb 100644 --- a/clippy_lints/src/methods/join_absolute_paths.rs +++ b/clippy_lints/src/methods/join_absolute_paths.rs @@ -6,8 +6,8 @@ use rustc_ast::ast::LitKind; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::LateContext; -use rustc_span::symbol::sym; use rustc_span::Span; +use rustc_span::symbol::sym; use super::JOIN_ABSOLUTE_PATHS; diff --git a/clippy_lints/src/methods/manual_c_str_literals.rs b/clippy_lints/src/methods/manual_c_str_literals.rs index cb9fb373c10..96af9db1af7 100644 --- a/clippy_lints/src/methods/manual_c_str_literals.rs +++ b/clippy_lints/src/methods/manual_c_str_literals.rs @@ -6,7 +6,7 @@ use rustc_ast::{LitKind, StrStyle}; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, Node, QPath, TyKind}; use rustc_lint::LateContext; -use rustc_span::{sym, Span, Symbol}; +use rustc_span::{Span, Symbol, sym}; use super::MANUAL_C_STR_LITERALS; diff --git a/clippy_lints/src/methods/manual_inspect.rs b/clippy_lints/src/methods/manual_inspect.rs index cac2e11f591..64c19c327b2 100644 --- a/clippy_lints/src/methods/manual_inspect.rs +++ b/clippy_lints/src/methods/manual_inspect.rs @@ -3,13 +3,13 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::{IntoSpan, SpanRangeExt}; use clippy_utils::ty::get_field_by_name; use clippy_utils::visitors::{for_each_expr, for_each_expr_without_closures}; -use clippy_utils::{expr_use_ctxt, is_diag_item_method, is_diag_trait_item, path_to_local_id, ExprUseNode}; +use clippy_utils::{ExprUseNode, expr_use_ctxt, is_diag_item_method, is_diag_trait_item, path_to_local_id}; use core::ops::ControlFlow; use rustc_errors::Applicability; use rustc_hir::{BindingMode, BorrowKind, ByRef, ClosureKind, Expr, ExprKind, Mutability, Node, PatKind}; use rustc_lint::LateContext; use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability}; -use rustc_span::{sym, Span, Symbol, DUMMY_SP}; +use rustc_span::{DUMMY_SP, Span, Symbol, sym}; use super::MANUAL_INSPECT; diff --git a/clippy_lints/src/methods/manual_is_variant_and.rs b/clippy_lints/src/methods/manual_is_variant_and.rs index d29acd4622a..c377abd6237 100644 --- a/clippy_lints/src/methods/manual_is_variant_and.rs +++ b/clippy_lints/src/methods/manual_is_variant_and.rs @@ -4,7 +4,7 @@ use clippy_utils::source::snippet; use clippy_utils::ty::is_type_diagnostic_item; use rustc_errors::Applicability; use rustc_lint::LateContext; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; use super::MANUAL_IS_VARIANT_AND; diff --git a/clippy_lints/src/methods/manual_ok_or.rs b/clippy_lints/src/methods/manual_ok_or.rs index b1a8e1e5e47..4321dd6b0e0 100644 --- a/clippy_lints/src/methods/manual_ok_or.rs +++ b/clippy_lints/src/methods/manual_ok_or.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::{indent_of, reindent_multiline, SpanRangeExt}; +use clippy_utils::source::{SpanRangeExt, indent_of, reindent_multiline}; use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::{is_res_lang_ctor, path_res, path_to_local_id}; use rustc_errors::Applicability; diff --git a/clippy_lints/src/methods/manual_try_fold.rs b/clippy_lints/src/methods/manual_try_fold.rs index 11fba35c16e..31449d41770 100644 --- a/clippy_lints/src/methods/manual_try_fold.rs +++ b/clippy_lints/src/methods/manual_try_fold.rs @@ -8,7 +8,7 @@ use rustc_hir::def::{DefKind, Res}; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; use super::MANUAL_TRY_FOLD; diff --git a/clippy_lints/src/methods/map_clone.rs b/clippy_lints/src/methods/map_clone.rs index 08ce7e204dd..ac378ff3702 100644 --- a/clippy_lints/src/methods/map_clone.rs +++ b/clippy_lints/src/methods/map_clone.rs @@ -11,7 +11,7 @@ use rustc_middle::mir::Mutability; use rustc_middle::ty; use rustc_middle::ty::adjustment::Adjust; use rustc_span::symbol::Ident; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; use super::MAP_CLONE; diff --git a/clippy_lints/src/methods/map_flatten.rs b/clippy_lints/src/methods/map_flatten.rs index 22a03825194..07a7a12b162 100644 --- a/clippy_lints/src/methods/map_flatten.rs +++ b/clippy_lints/src/methods/map_flatten.rs @@ -6,8 +6,8 @@ use rustc_errors::Applicability; use rustc_hir::Expr; use rustc_lint::LateContext; use rustc_middle::ty; -use rustc_span::symbol::sym; use rustc_span::Span; +use rustc_span::symbol::sym; use super::MAP_FLATTEN; diff --git a/clippy_lints/src/methods/map_identity.rs b/clippy_lints/src/methods/map_identity.rs index 5dd7b1b02ad..1f204de01da 100644 --- a/clippy_lints/src/methods/map_identity.rs +++ b/clippy_lints/src/methods/map_identity.rs @@ -4,7 +4,7 @@ use clippy_utils::{is_expr_untyped_identity_function, is_trait_method}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; use super::MAP_IDENTITY; diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index f61bb3a6bf4..7696dd16b25 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -111,6 +111,7 @@ mod uninit_assumed_init; mod unit_hash; mod unnecessary_fallible_conversions; mod unnecessary_filter_map; +mod unnecessary_first_then_check; mod unnecessary_fold; mod unnecessary_get_then_check; mod unnecessary_iter_cloned; @@ -131,8 +132,8 @@ mod waker_clone_wake; mod wrong_self_convention; mod zst_offset; -use clippy_config::msrvs::{self, Msrv}; use clippy_config::Conf; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::consts::{ConstEvalCtxt, Constant}; use clippy_utils::diagnostics::{span_lint, span_lint_and_help}; use clippy_utils::macros::FormatArgsStorage; @@ -146,7 +147,7 @@ use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::{self, TraitRef, Ty}; use rustc_session::impl_lint_pass; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; declare_clippy_lint! { /// ### What it does @@ -441,6 +442,17 @@ declare_clippy_lint! { /// } /// } /// ``` + /// + /// Use instead: + /// ```no_run + /// # struct X; + /// impl X { + /// fn as_str(&self) -> &'static str { + /// // .. + /// # "" + /// } + /// } + /// ``` #[clippy::version = "pre 1.29.0"] pub WRONG_SELF_CONVENTION, style, @@ -3964,7 +3976,7 @@ declare_clippy_lint! { /// ```no_run /// let _ = 0; /// ``` - #[clippy::version = "1.78.0"] + #[clippy::version = "1.81.0"] pub UNNECESSARY_MIN_OR_MAX, complexity, "using 'min()/max()' when there is no need for it" @@ -4025,7 +4037,7 @@ declare_clippy_lint! { /// ``` #[clippy::version = "1.78.0"] pub MANUAL_C_STR_LITERALS, - pedantic, + complexity, r#"creating a `CStr` through functions when `c""` literals can be used"# } @@ -4099,7 +4111,7 @@ declare_clippy_lint! { /// ```no_run /// "foo".is_ascii(); /// ``` - #[clippy::version = "1.80.0"] + #[clippy::version = "1.81.0"] pub NEEDLESS_CHARACTER_ITERATION, suspicious, "is_ascii() called on a char iterator" @@ -4126,6 +4138,34 @@ declare_clippy_lint! { "use of `map` returning the original item" } +declare_clippy_lint! { + /// ### What it does + /// Checks the usage of `.first().is_some()` or `.first().is_none()` to check if a slice is + /// empty. + /// + /// ### Why is this bad? + /// Using `.is_empty()` is shorter and better communicates the intention. + /// + /// ### Example + /// ```no_run + /// let v = vec![1, 2, 3]; + /// if v.first().is_none() { + /// // The vector is empty... + /// } + /// ``` + /// Use instead: + /// ```no_run + /// let v = vec![1, 2, 3]; + /// if v.is_empty() { + /// // The vector is empty... + /// } + /// ``` + #[clippy::version = "1.83.0"] + pub UNNECESSARY_FIRST_THEN_CHECK, + complexity, + "calling `.first().is_some()` or `.first().is_none()` instead of `.is_empty()`" +} + pub struct Methods { avoid_breaking_exported_api: bool, msrv: Msrv, @@ -4283,6 +4323,7 @@ impl_lint_pass!(Methods => [ UNNECESSARY_RESULT_MAP_OR_ELSE, MANUAL_C_STR_LITERALS, UNNECESSARY_GET_THEN_CHECK, + UNNECESSARY_FIRST_THEN_CHECK, NEEDLESS_CHARACTER_ITERATION, MANUAL_INSPECT, UNNECESSARY_MIN_OR_MAX, @@ -5055,6 +5096,9 @@ fn check_is_some_is_none(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, Some(("get", f_recv, [arg], _, _)) => { unnecessary_get_then_check::check(cx, call_span, recv, f_recv, arg, is_some); }, + Some(("first", f_recv, [], _, _)) => { + unnecessary_first_then_check::check(cx, call_span, recv, f_recv, is_some); + }, _ => {}, } } @@ -5130,12 +5174,9 @@ impl ShouldImplTraitCase { fn lifetime_param_cond(&self, impl_item: &hir::ImplItem<'_>) -> bool { self.lint_explicit_lifetime || !impl_item.generics.params.iter().any(|p| { - matches!( - p.kind, - hir::GenericParamKind::Lifetime { - kind: hir::LifetimeParamKind::Explicit - } - ) + matches!(p.kind, hir::GenericParamKind::Lifetime { + kind: hir::LifetimeParamKind::Explicit + }) }) } } diff --git a/clippy_lints/src/methods/mut_mutex_lock.rs b/clippy_lints/src/methods/mut_mutex_lock.rs index 1a0fce2876d..83e8370f939 100644 --- a/clippy_lints/src/methods/mut_mutex_lock.rs +++ b/clippy_lints/src/methods/mut_mutex_lock.rs @@ -5,7 +5,7 @@ use rustc_errors::Applicability; use rustc_hir::{Expr, Mutability}; use rustc_lint::LateContext; use rustc_middle::ty; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; use super::MUT_MUTEX_LOCK; diff --git a/clippy_lints/src/methods/needless_character_iteration.rs b/clippy_lints/src/methods/needless_character_iteration.rs index 332da722a37..348f740e7dd 100644 --- a/clippy_lints/src/methods/needless_character_iteration.rs +++ b/clippy_lints/src/methods/needless_character_iteration.rs @@ -4,8 +4,8 @@ use rustc_lint::LateContext; use rustc_middle::ty; use rustc_span::Span; -use super::utils::get_last_chain_binding_hir_id; use super::NEEDLESS_CHARACTER_ITERATION; +use super::utils::get_last_chain_binding_hir_id; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::SpanRangeExt; use clippy_utils::{match_def_path, path_to_local_id, peel_blocks}; diff --git a/clippy_lints/src/methods/needless_collect.rs b/clippy_lints/src/methods/needless_collect.rs index f61923e5bf5..421c7a5e070 100644 --- a/clippy_lints/src/methods/needless_collect.rs +++ b/clippy_lints/src/methods/needless_collect.rs @@ -4,12 +4,12 @@ use clippy_utils::source::{snippet, snippet_with_applicability}; use clippy_utils::sugg::Sugg; use clippy_utils::ty::{get_type_diagnostic_name, make_normalized_projection, make_projection}; use clippy_utils::{ - can_move_expr_to_closure, fn_def_id, get_enclosing_block, higher, is_trait_method, path_to_local, path_to_local_id, - CaptureKind, + CaptureKind, can_move_expr_to_closure, fn_def_id, get_enclosing_block, higher, is_trait_method, path_to_local, + path_to_local_id, }; use rustc_data_structures::fx::FxHashMap; use rustc_errors::{Applicability, MultiSpan}; -use rustc_hir::intravisit::{walk_block, walk_expr, Visitor}; +use rustc_hir::intravisit::{Visitor, walk_block, walk_expr}; use rustc_hir::{ BindingMode, Block, Expr, ExprKind, HirId, HirIdSet, LetStmt, Mutability, Node, PatKind, Stmt, StmtKind, }; @@ -17,7 +17,7 @@ use rustc_lint::LateContext; use rustc_middle::hir::nested_filter; use rustc_middle::ty::{self, AssocKind, ClauseKind, EarlyBinder, GenericArg, GenericArgKind, Ty}; use rustc_span::symbol::Ident; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; const NEEDLESS_COLLECT_MSG: &str = "avoid using `collect()` when not needed"; diff --git a/clippy_lints/src/methods/needless_option_as_deref.rs b/clippy_lints/src/methods/needless_option_as_deref.rs index 9f714fdd47b..538aa9097a4 100644 --- a/clippy_lints/src/methods/needless_option_as_deref.rs +++ b/clippy_lints/src/methods/needless_option_as_deref.rs @@ -4,8 +4,8 @@ use clippy_utils::source::SpanRangeExt; use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::usage::local_used_after_expr; use rustc_errors::Applicability; -use rustc_hir::def::Res; use rustc_hir::Expr; +use rustc_hir::def::Res; use rustc_lint::LateContext; use rustc_span::sym; diff --git a/clippy_lints/src/methods/no_effect_replace.rs b/clippy_lints/src/methods/no_effect_replace.rs index a301a5f7d65..32f32f1b216 100644 --- a/clippy_lints/src/methods/no_effect_replace.rs +++ b/clippy_lints/src/methods/no_effect_replace.rs @@ -1,6 +1,6 @@ +use clippy_utils::SpanlessEq; use clippy_utils::diagnostics::span_lint; use clippy_utils::ty::is_type_lang_item; -use clippy_utils::SpanlessEq; use rustc_ast::LitKind; use rustc_hir::{ExprKind, LangItem}; use rustc_lint::LateContext; diff --git a/clippy_lints/src/methods/open_options.rs b/clippy_lints/src/methods/open_options.rs index f1a3c81cebb..da084871402 100644 --- a/clippy_lints/src/methods/open_options.rs +++ b/clippy_lints/src/methods/open_options.rs @@ -8,7 +8,7 @@ use rustc_hir::{Expr, ExprKind}; use rustc_lint::LateContext; use rustc_middle::ty::Ty; use rustc_span::source_map::Spanned; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; use super::{NONSENSICAL_OPEN_OPTIONS, SUSPICIOUS_OPEN_OPTIONS}; @@ -126,17 +126,13 @@ fn get_open_options( && let ExprKind::Path(path) = callee.kind && let Some(did) = cx.qpath_res(&path, callee.hir_id).opt_def_id() { - let std_file_options = [ - sym::file_options, - sym::open_options_new, - ]; + let std_file_options = [sym::file_options, sym::open_options_new]; - let tokio_file_options: &[&[&str]] = &[ - &paths::TOKIO_IO_OPEN_OPTIONS_NEW, - &paths::TOKIO_FILE_OPTIONS, - ]; + let tokio_file_options: &[&[&str]] = &[&paths::TOKIO_IO_OPEN_OPTIONS_NEW, &paths::TOKIO_FILE_OPTIONS]; - let is_std_options = std_file_options.into_iter().any(|sym| cx.tcx.is_diagnostic_item(sym, did)); + let is_std_options = std_file_options + .into_iter() + .any(|sym| cx.tcx.is_diagnostic_item(sym, did)); is_std_options || match_any_def_paths(cx, did, tokio_file_options).is_some() } else { false diff --git a/clippy_lints/src/methods/option_as_ref_cloned.rs b/clippy_lints/src/methods/option_as_ref_cloned.rs index ba167f9d9c2..9b22494888f 100644 --- a/clippy_lints/src/methods/option_as_ref_cloned.rs +++ b/clippy_lints/src/methods/option_as_ref_cloned.rs @@ -3,9 +3,9 @@ use clippy_utils::ty::is_type_diagnostic_item; use rustc_errors::Applicability; use rustc_hir::Expr; use rustc_lint::LateContext; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; -use super::{method_call, OPTION_AS_REF_CLONED}; +use super::{OPTION_AS_REF_CLONED, method_call}; pub(super) fn check(cx: &LateContext<'_>, cloned_recv: &Expr<'_>, cloned_ident_span: Span) { if let Some((method @ ("as_ref" | "as_mut"), as_ref_recv, [], as_ref_ident_span, _)) = method_call(cloned_recv) diff --git a/clippy_lints/src/methods/option_as_ref_deref.rs b/clippy_lints/src/methods/option_as_ref_deref.rs index 9a18d8a1421..389e02056b2 100644 --- a/clippy_lints/src/methods/option_as_ref_deref.rs +++ b/clippy_lints/src/methods/option_as_ref_deref.rs @@ -7,7 +7,7 @@ use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; use rustc_middle::ty; -use rustc_span::{sym, Symbol}; +use rustc_span::{Symbol, sym}; use super::OPTION_AS_REF_DEREF; @@ -48,7 +48,9 @@ pub(super) fn check( .map_or(false, |fun_def_id| { cx.tcx.is_diagnostic_item(sym::deref_method, fun_def_id) || cx.tcx.is_diagnostic_item(sym::deref_mut_method, fun_def_id) - || deref_aliases.iter().any(|&sym| cx.tcx.is_diagnostic_item(sym, fun_def_id)) + || deref_aliases + .iter() + .any(|&sym| cx.tcx.is_diagnostic_item(sym, fun_def_id)) }) }, hir::ExprKind::Closure(&hir::Closure { body, .. }) => { @@ -69,7 +71,9 @@ pub(super) fn check( let method_did = cx.typeck_results().type_dependent_def_id(closure_expr.hir_id).unwrap(); cx.tcx.is_diagnostic_item(sym::deref_method, method_did) || cx.tcx.is_diagnostic_item(sym::deref_mut_method, method_did) - || deref_aliases.iter().any(|&sym| cx.tcx.is_diagnostic_item(sym, method_did)) + || deref_aliases + .iter() + .any(|&sym| cx.tcx.is_diagnostic_item(sym, method_did)) } else { false } diff --git a/clippy_lints/src/methods/option_map_unwrap_or.rs b/clippy_lints/src/methods/option_map_unwrap_or.rs index ed3bed42eb3..b160ab6de8e 100644 --- a/clippy_lints/src/methods/option_map_unwrap_or.rs +++ b/clippy_lints/src/methods/option_map_unwrap_or.rs @@ -5,11 +5,11 @@ use clippy_utils::ty::{is_copy, is_type_diagnostic_item}; use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; use rustc_hir::def::Res; -use rustc_hir::intravisit::{walk_path, Visitor}; +use rustc_hir::intravisit::{Visitor, walk_path}; use rustc_hir::{ExprKind, HirId, Node, PatKind, Path, QPath}; use rustc_lint::LateContext; use rustc_middle::hir::nested_filter; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; use std::ops::ControlFlow; use super::MAP_UNWRAP_OR; diff --git a/clippy_lints/src/methods/or_fun_call.rs b/clippy_lints/src/methods/or_fun_call.rs index e4326cb958e..8a7e72b63bb 100644 --- a/clippy_lints/src/methods/or_fun_call.rs +++ b/clippy_lints/src/methods/or_fun_call.rs @@ -11,8 +11,8 @@ use clippy_utils::{ use rustc_errors::Applicability; use rustc_lint::LateContext; use rustc_middle::ty; -use rustc_span::symbol::{self, sym, Symbol}; use rustc_span::Span; +use rustc_span::symbol::{self, Symbol, sym}; use {rustc_ast as ast, rustc_hir as hir}; use super::{OR_FUN_CALL, UNWRAP_OR_DEFAULT}; diff --git a/clippy_lints/src/methods/or_then_unwrap.rs b/clippy_lints/src/methods/or_then_unwrap.rs index 7b0bdcf99e7..3e64e15dc86 100644 --- a/clippy_lints/src/methods/or_then_unwrap.rs +++ b/clippy_lints/src/methods/or_then_unwrap.rs @@ -6,7 +6,7 @@ use rustc_errors::Applicability; use rustc_hir::lang_items::LangItem; use rustc_hir::{Expr, ExprKind}; use rustc_lint::LateContext; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; use super::OR_THEN_UNWRAP; diff --git a/clippy_lints/src/methods/range_zip_with_len.rs b/clippy_lints/src/methods/range_zip_with_len.rs index 28ca76832eb..f4d206c5307 100644 --- a/clippy_lints/src/methods/range_zip_with_len.rs +++ b/clippy_lints/src/methods/range_zip_with_len.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint; use clippy_utils::source::snippet; -use clippy_utils::{higher, is_integer_const, is_trait_method, SpanlessEq}; +use clippy_utils::{SpanlessEq, higher, is_integer_const, is_trait_method}; use rustc_hir::{Expr, ExprKind, QPath}; use rustc_lint::LateContext; use rustc_span::sym; diff --git a/clippy_lints/src/methods/search_is_some.rs b/clippy_lints/src/methods/search_is_some.rs index 3b2dd285b8c..4ab165a5528 100644 --- a/clippy_lints/src/methods/search_is_some.rs +++ b/clippy_lints/src/methods/search_is_some.rs @@ -8,8 +8,8 @@ use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::PatKind; use rustc_lint::LateContext; -use rustc_span::symbol::sym; use rustc_span::Span; +use rustc_span::symbol::sym; use super::SEARCH_IS_SOME; diff --git a/clippy_lints/src/methods/seek_from_current.rs b/clippy_lints/src/methods/seek_from_current.rs index 8bc535ac47a..7ef07fe899c 100644 --- a/clippy_lints/src/methods/seek_from_current.rs +++ b/clippy_lints/src/methods/seek_from_current.rs @@ -6,9 +6,9 @@ use rustc_lint::LateContext; use rustc_span::sym; use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::is_enum_variant_ctor; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::implements_trait; -use clippy_utils::is_enum_variant_ctor; use super::SEEK_FROM_CURRENT; diff --git a/clippy_lints/src/methods/seek_to_start_instead_of_rewind.rs b/clippy_lints/src/methods/seek_to_start_instead_of_rewind.rs index 7c09cc252e1..9c966f010f1 100644 --- a/clippy_lints/src/methods/seek_to_start_instead_of_rewind.rs +++ b/clippy_lints/src/methods/seek_to_start_instead_of_rewind.rs @@ -1,12 +1,12 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::ty::implements_trait; -use clippy_utils::{is_expr_used_or_unified, is_enum_variant_ctor}; +use clippy_utils::{is_enum_variant_ctor, is_expr_used_or_unified}; use rustc_ast::ast::{LitIntType, LitKind}; use rustc_data_structures::packed::Pu128; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::LateContext; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; use super::SEEK_TO_START_INSTEAD_OF_REWIND; diff --git a/clippy_lints/src/methods/str_splitn.rs b/clippy_lints/src/methods/str_splitn.rs index 12cabd43cb1..69032776b2b 100644 --- a/clippy_lints/src/methods/str_splitn.rs +++ b/clippy_lints/src/methods/str_splitn.rs @@ -3,7 +3,7 @@ use clippy_utils::consts::{ConstEvalCtxt, Constant}; use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; use clippy_utils::source::snippet_with_context; use clippy_utils::usage::local_used_after_expr; -use clippy_utils::visitors::{for_each_expr, Descend}; +use clippy_utils::visitors::{Descend, for_each_expr}; use clippy_utils::{is_diag_item_method, match_def_path, path_to_local_id, paths}; use core::ops::ControlFlow; use rustc_errors::Applicability; @@ -12,7 +12,7 @@ use rustc_hir::{ }; use rustc_lint::LateContext; use rustc_middle::ty; -use rustc_span::{sym, Span, Symbol, SyntaxContext}; +use rustc_span::{Span, Symbol, SyntaxContext, sym}; use super::{MANUAL_SPLIT_ONCE, NEEDLESS_SPLITN}; diff --git a/clippy_lints/src/methods/suspicious_command_arg_space.rs b/clippy_lints/src/methods/suspicious_command_arg_space.rs index 38f2c916912..c60a49067ec 100644 --- a/clippy_lints/src/methods/suspicious_command_arg_space.rs +++ b/clippy_lints/src/methods/suspicious_command_arg_space.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::ty::is_type_diagnostic_item; use rustc_errors::{Applicability, Diag}; use rustc_lint::LateContext; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; use {rustc_ast as ast, rustc_hir as hir}; use super::SUSPICIOUS_COMMAND_ARG_SPACE; diff --git a/clippy_lints/src/methods/type_id_on_box.rs b/clippy_lints/src/methods/type_id_on_box.rs index db8cc4595d4..e67ba5c4d31 100644 --- a/clippy_lints/src/methods/type_id_on_box.rs +++ b/clippy_lints/src/methods/type_id_on_box.rs @@ -7,7 +7,7 @@ use rustc_lint::LateContext; use rustc_middle::ty::adjustment::{Adjust, Adjustment}; use rustc_middle::ty::print::with_forced_trimmed_paths; use rustc_middle::ty::{self, ExistentialPredicate, Ty}; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; /// Checks if the given type is `dyn Any`, or a trait object that has `Any` as a supertrait. /// Only in those cases will its vtable have a `type_id` method that returns the implementor's diff --git a/clippy_lints/src/methods/unnecessary_fallible_conversions.rs b/clippy_lints/src/methods/unnecessary_fallible_conversions.rs index d46b584f8f4..ce81282ddfe 100644 --- a/clippy_lints/src/methods/unnecessary_fallible_conversions.rs +++ b/clippy_lints/src/methods/unnecessary_fallible_conversions.rs @@ -6,7 +6,7 @@ use rustc_hir::{Expr, ExprKind, QPath}; use rustc_lint::LateContext; use rustc_middle::ty; use rustc_middle::ty::print::with_forced_trimmed_paths; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; use super::UNNECESSARY_FALLIBLE_CONVERSIONS; diff --git a/clippy_lints/src/methods/unnecessary_filter_map.rs b/clippy_lints/src/methods/unnecessary_filter_map.rs index c9b9d98dbe6..ca46da81fa0 100644 --- a/clippy_lints/src/methods/unnecessary_filter_map.rs +++ b/clippy_lints/src/methods/unnecessary_filter_map.rs @@ -2,7 +2,7 @@ use super::utils::clone_or_copy_needed; use clippy_utils::diagnostics::span_lint; use clippy_utils::ty::is_copy; use clippy_utils::usage::mutated_variables; -use clippy_utils::visitors::{for_each_expr_without_closures, Descend}; +use clippy_utils::visitors::{Descend, for_each_expr_without_closures}; use clippy_utils::{is_res_lang_ctor, is_trait_method, path_res, path_to_local_id}; use core::ops::ControlFlow; use rustc_hir as hir; diff --git a/clippy_lints/src/methods/unnecessary_first_then_check.rs b/clippy_lints/src/methods/unnecessary_first_then_check.rs new file mode 100644 index 00000000000..7ae1bb54e60 --- /dev/null +++ b/clippy_lints/src/methods/unnecessary_first_then_check.rs @@ -0,0 +1,56 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::SpanRangeExt; + +use rustc_errors::Applicability; +use rustc_hir::{Expr, ExprKind}; +use rustc_lint::LateContext; +use rustc_span::Span; + +use super::UNNECESSARY_FIRST_THEN_CHECK; + +pub(super) fn check( + cx: &LateContext<'_>, + call_span: Span, + first_call: &Expr<'_>, + first_caller: &Expr<'_>, + is_some: bool, +) { + if !cx + .typeck_results() + .expr_ty_adjusted(first_caller) + .peel_refs() + .is_slice() + { + return; + } + + let ExprKind::MethodCall(_, _, _, first_call_span) = first_call.kind else { + return; + }; + + let both_calls_span = first_call_span.with_hi(call_span.hi()); + if let Some(both_calls_snippet) = both_calls_span.get_source_text(cx) + && let Some(first_caller_snippet) = first_caller.span.get_source_text(cx) + { + let (sugg_span, suggestion) = if is_some { + ( + first_caller.span.with_hi(call_span.hi()), + format!("!{first_caller_snippet}.is_empty()"), + ) + } else { + (both_calls_span, "is_empty()".to_owned()) + }; + span_lint_and_sugg( + cx, + UNNECESSARY_FIRST_THEN_CHECK, + sugg_span, + format!( + "unnecessary use of `{both_calls_snippet}` to check if slice {}", + if is_some { "is not empty" } else { "is empty" } + ), + "replace this with", + suggestion, + Applicability::MaybeIncorrect, + ); + } +} diff --git a/clippy_lints/src/methods/unnecessary_fold.rs b/clippy_lints/src/methods/unnecessary_fold.rs index ccc8d17970e..b5d8972d7aa 100644 --- a/clippy_lints/src/methods/unnecessary_fold.rs +++ b/clippy_lints/src/methods/unnecessary_fold.rs @@ -8,7 +8,7 @@ use rustc_hir as hir; use rustc_hir::PatKind; use rustc_lint::LateContext; use rustc_middle::ty; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; use super::UNNECESSARY_FOLD; @@ -123,58 +123,32 @@ pub(super) fn check( if let hir::ExprKind::Lit(lit) = init.kind { match lit.node { ast::LitKind::Bool(false) => { - check_fold_with_op( - cx, - expr, - acc, - fold_span, - hir::BinOpKind::Or, - Replacement { - has_args: true, - has_generic_return: false, - method_name: "any", - }, - ); + check_fold_with_op(cx, expr, acc, fold_span, hir::BinOpKind::Or, Replacement { + 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 { - has_args: true, - has_generic_return: false, - method_name: "all", - }, - ); + check_fold_with_op(cx, expr, acc, fold_span, hir::BinOpKind::And, Replacement { + 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 { + ast::LitKind::Int(Pu128(0), _) => { + check_fold_with_op(cx, expr, acc, fold_span, hir::BinOpKind::Add, Replacement { 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 { - has_args: false, - has_generic_return: needs_turbofish(cx, expr), - method_name: "product", - }, - ); + check_fold_with_op(cx, expr, acc, fold_span, hir::BinOpKind::Mul, Replacement { + has_args: false, + has_generic_return: needs_turbofish(cx, expr), + method_name: "product", + }); }, _ => (), } diff --git a/clippy_lints/src/methods/unnecessary_get_then_check.rs b/clippy_lints/src/methods/unnecessary_get_then_check.rs index 64eb8411795..39fce2c40c9 100644 --- a/clippy_lints/src/methods/unnecessary_get_then_check.rs +++ b/clippy_lints/src/methods/unnecessary_get_then_check.rs @@ -6,7 +6,7 @@ use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::LateContext; use rustc_middle::ty::Ty; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; use super::UNNECESSARY_GET_THEN_CHECK; diff --git a/clippy_lints/src/methods/unnecessary_iter_cloned.rs b/clippy_lints/src/methods/unnecessary_iter_cloned.rs index 4d18bc7ac77..029704882dd 100644 --- a/clippy_lints/src/methods/unnecessary_iter_cloned.rs +++ b/clippy_lints/src/methods/unnecessary_iter_cloned.rs @@ -10,7 +10,7 @@ use rustc_errors::Applicability; use rustc_hir::def_id::DefId; use rustc_hir::{BindingMode, Expr, ExprKind, Node, PatKind}; use rustc_lint::LateContext; -use rustc_span::{sym, Symbol}; +use rustc_span::{Symbol, sym}; use super::UNNECESSARY_TO_OWNED; diff --git a/clippy_lints/src/methods/unnecessary_literal_unwrap.rs b/clippy_lints/src/methods/unnecessary_literal_unwrap.rs index 494d71fc053..6dc8adb42df 100644 --- a/clippy_lints/src/methods/unnecessary_literal_unwrap.rs +++ b/clippy_lints/src/methods/unnecessary_literal_unwrap.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::{is_res_lang_ctor, last_path_segment, path_res, MaybePath}; +use clippy_utils::{MaybePath, is_res_lang_ctor, last_path_segment, path_res}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; diff --git a/clippy_lints/src/methods/unnecessary_min_or_max.rs b/clippy_lints/src/methods/unnecessary_min_or_max.rs index 86c0a6322b6..062d1348555 100644 --- a/clippy_lints/src/methods/unnecessary_min_or_max.rs +++ b/clippy_lints/src/methods/unnecessary_min_or_max.rs @@ -1,16 +1,15 @@ use std::cmp::Ordering; use super::UNNECESSARY_MIN_OR_MAX; -use clippy_utils::diagnostics::span_lint_and_sugg; - use clippy_utils::consts::{ConstEvalCtxt, Constant, ConstantSource, FullInt}; +use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet; use rustc_errors::Applicability; use rustc_hir::Expr; use rustc_lint::LateContext; use rustc_middle::ty; -use rustc_span::Span; +use rustc_span::{Span, sym}; pub(super) fn check<'tcx>( cx: &LateContext<'tcx>, @@ -21,26 +20,30 @@ pub(super) fn check<'tcx>( ) { let typeck_results = cx.typeck_results(); let ecx = ConstEvalCtxt::with_env(cx.tcx, cx.param_env, typeck_results); - if let Some((left, ConstantSource::Local | ConstantSource::CoreConstant)) = ecx.eval_with_source(recv) - && let Some((right, ConstantSource::Local | ConstantSource::CoreConstant)) = ecx.eval_with_source(arg) + if let Some(id) = typeck_results.type_dependent_def_id(expr.hir_id) + && (cx.tcx.is_diagnostic_item(sym::cmp_ord_min, id) || cx.tcx.is_diagnostic_item(sym::cmp_ord_max, id)) { - let Some(ord) = Constant::partial_cmp(cx.tcx, typeck_results.expr_ty(recv), &left, &right) else { - return; - }; + if let Some((left, ConstantSource::Local | ConstantSource::CoreConstant)) = ecx.eval_with_source(recv) + && let Some((right, ConstantSource::Local | ConstantSource::CoreConstant)) = ecx.eval_with_source(arg) + { + let Some(ord) = Constant::partial_cmp(cx.tcx, typeck_results.expr_ty(recv), &left, &right) else { + return; + }; - lint(cx, expr, name, recv.span, arg.span, ord); - } else if let Some(extrema) = detect_extrema(cx, recv) { - let ord = match extrema { - Extrema::Minimum => Ordering::Less, - Extrema::Maximum => Ordering::Greater, - }; - lint(cx, expr, name, recv.span, arg.span, ord); - } else if let Some(extrema) = detect_extrema(cx, arg) { - let ord = match extrema { - Extrema::Minimum => Ordering::Greater, - Extrema::Maximum => Ordering::Less, - }; - lint(cx, expr, name, recv.span, arg.span, ord); + lint(cx, expr, name, recv.span, arg.span, ord); + } else if let Some(extrema) = detect_extrema(cx, recv) { + let ord = match extrema { + Extrema::Minimum => Ordering::Less, + Extrema::Maximum => Ordering::Greater, + }; + lint(cx, expr, name, recv.span, arg.span, ord); + } else if let Some(extrema) = detect_extrema(cx, arg) { + let ord = match extrema { + Extrema::Minimum => Ordering::Greater, + Extrema::Maximum => Ordering::Less, + }; + lint(cx, expr, name, recv.span, arg.span, ord); + } } } diff --git a/clippy_lints/src/methods/unnecessary_result_map_or_else.rs b/clippy_lints/src/methods/unnecessary_result_map_or_else.rs index c14a87c1534..dc50717112d 100644 --- a/clippy_lints/src/methods/unnecessary_result_map_or_else.rs +++ b/clippy_lints/src/methods/unnecessary_result_map_or_else.rs @@ -8,8 +8,8 @@ use rustc_hir::{Closure, Expr, ExprKind, HirId, QPath}; use rustc_lint::LateContext; use rustc_span::symbol::sym; -use super::utils::get_last_chain_binding_hir_id; use super::UNNECESSARY_RESULT_MAP_OR_ELSE; +use super::utils::get_last_chain_binding_hir_id; fn emit_lint(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, def_arg: &Expr<'_>) { let msg = "unused \"map closure\" when calling `Result::map_or_else` value"; diff --git a/clippy_lints/src/methods/unnecessary_to_owned.rs b/clippy_lints/src/methods/unnecessary_to_owned.rs index bf7555a29e2..cfa1fdb8137 100644 --- a/clippy_lints/src/methods/unnecessary_to_owned.rs +++ b/clippy_lints/src/methods/unnecessary_to_owned.rs @@ -2,12 +2,11 @@ use super::implicit_clone::is_clone_like; use super::unnecessary_iter_cloned::{self, is_into_iter}; use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; -use clippy_utils::source::{snippet, SpanRangeExt}; +use clippy_utils::source::{SpanRangeExt, snippet}; use clippy_utils::ty::{get_iterator_item_ty, implements_trait, is_copy, is_type_diagnostic_item, is_type_lang_item}; use clippy_utils::visitors::find_all_ret_expressions; use clippy_utils::{ - fn_def_id, get_parent_expr, is_diag_item_method, is_diag_trait_item, peel_middle_ty_refs, - return_ty, + fn_def_id, get_parent_expr, is_diag_item_method, is_diag_trait_item, peel_middle_ty_refs, return_ty, }; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; @@ -20,7 +19,7 @@ use rustc_middle::ty::adjustment::{Adjust, Adjustment, OverloadedDeref}; use rustc_middle::ty::{ self, ClauseKind, GenericArg, GenericArgKind, GenericArgsRef, ParamTy, ProjectionPredicate, TraitPredicate, Ty, }; -use rustc_span::{sym, Symbol}; +use rustc_span::{Symbol, sym}; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _; use rustc_trait_selection::traits::{Obligation, ObligationCause}; @@ -717,7 +716,7 @@ fn check_if_applicable_to_argument<'tcx>(cx: &LateContext<'tcx>, arg: &Expr<'tcx // check that: // 1. This is a method with only one argument that doesn't come from a trait. // 2. That it has `Borrow` in its generic predicates. -// 3. `Self` is a std "map type" (ie `HashSet`, `HashMap`, BTreeSet`, `BTreeMap`). +// 3. `Self` is a std "map type" (ie `HashSet`, `HashMap`, `BTreeSet`, `BTreeMap`). fn check_borrow_predicate<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) { if let ExprKind::MethodCall(_, caller, &[arg], _) = expr.kind && let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) diff --git a/clippy_lints/src/methods/unused_enumerate_index.rs b/clippy_lints/src/methods/unused_enumerate_index.rs index ee5177d1ffa..6c2ae9cc6bf 100644 --- a/clippy_lints/src/methods/unused_enumerate_index.rs +++ b/clippy_lints/src/methods/unused_enumerate_index.rs @@ -1,11 +1,11 @@ use clippy_utils::diagnostics::span_lint_hir_and_then; -use clippy_utils::source::{snippet, SpanRangeExt}; +use clippy_utils::source::{SpanRangeExt, snippet}; use clippy_utils::{expr_or_init, is_trait_method, pat_is_wild}; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, FnDecl, PatKind, TyKind}; use rustc_lint::LateContext; use rustc_middle::ty::AdtDef; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; use crate::loops::UNUSED_ENUMERATE_INDEX; diff --git a/clippy_lints/src/methods/useless_asref.rs b/clippy_lints/src/methods/useless_asref.rs index ebad4ae6ee9..eafe7486bb0 100644 --- a/clippy_lints/src/methods/useless_asref.rs +++ b/clippy_lints/src/methods/useless_asref.rs @@ -9,7 +9,7 @@ use rustc_hir::{self as hir, LangItem}; use rustc_lint::LateContext; use rustc_middle::ty::adjustment::Adjust; use rustc_middle::ty::{Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor}; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; use core::ops::ControlFlow; diff --git a/clippy_lints/src/methods/utils.rs b/clippy_lints/src/methods/utils.rs index fe860e5ae26..4e33dc1df54 100644 --- a/clippy_lints/src/methods/utils.rs +++ b/clippy_lints/src/methods/utils.rs @@ -1,12 +1,12 @@ use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::{get_parent_expr, path_to_local_id, usage}; -use rustc_hir::intravisit::{walk_expr, Visitor}; +use rustc_hir::intravisit::{Visitor, walk_expr}; use rustc_hir::{BorrowKind, Expr, ExprKind, HirId, Mutability, Pat, QPath, Stmt, StmtKind}; use rustc_lint::LateContext; use rustc_middle::hir::nested_filter; use rustc_middle::ty::{self, Ty}; -use rustc_span::symbol::sym; use rustc_span::Span; +use rustc_span::symbol::sym; pub(super) fn derefs_to_slice<'tcx>( cx: &LateContext<'tcx>, diff --git a/clippy_lints/src/methods/vec_resize_to_zero.rs b/clippy_lints/src/methods/vec_resize_to_zero.rs index 3e271a60611..5ea4ada128a 100644 --- a/clippy_lints/src/methods/vec_resize_to_zero.rs +++ b/clippy_lints/src/methods/vec_resize_to_zero.rs @@ -6,7 +6,7 @@ use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::LateContext; use rustc_span::source_map::Spanned; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; use super::VEC_RESIZE_TO_ZERO; diff --git a/clippy_lints/src/methods/waker_clone_wake.rs b/clippy_lints/src/methods/waker_clone_wake.rs index 9b64cc7589c..b5f34a9be2e 100644 --- a/clippy_lints/src/methods/waker_clone_wake.rs +++ b/clippy_lints/src/methods/waker_clone_wake.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::snippet_with_applicability; use clippy_utils::is_trait_method; +use clippy_utils::source::snippet_with_applicability; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::LateContext; diff --git a/clippy_lints/src/min_ident_chars.rs b/clippy_lints/src/min_ident_chars.rs index c83e5198c27..a99e21d938c 100644 --- a/clippy_lints/src/min_ident_chars.rs +++ b/clippy_lints/src/min_ident_chars.rs @@ -3,7 +3,7 @@ use clippy_utils::diagnostics::span_lint; use clippy_utils::is_from_proc_macro; use rustc_data_structures::fx::FxHashSet; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::intravisit::{walk_item, walk_trait_item, Visitor}; +use rustc_hir::intravisit::{Visitor, walk_item, walk_trait_item}; use rustc_hir::{GenericParamKind, HirId, Item, ItemKind, ItemLocalId, Node, Pat, PatKind, TraitItem, UsePath}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; diff --git a/clippy_lints/src/misc.rs b/clippy_lints/src/misc.rs index a9aafe7ed56..408dbef9cb1 100644 --- a/clippy_lints/src/misc.rs +++ b/clippy_lints/src/misc.rs @@ -2,11 +2,12 @@ use clippy_utils::diagnostics::{span_lint_and_then, span_lint_hir, span_lint_hir use clippy_utils::source::{snippet, snippet_with_context}; use clippy_utils::sugg::Sugg; use clippy_utils::{ - fulfill_or_allowed, get_parent_expr, in_automatically_derived, is_lint_allowed, iter_input_pats, last_path_segment, - SpanlessEq, + SpanlessEq, fulfill_or_allowed, get_parent_expr, in_automatically_derived, is_lint_allowed, iter_input_pats, + last_path_segment, }; use rustc_errors::Applicability; use rustc_hir::def::Res; +use rustc_hir::def_id::LOCAL_CRATE; use rustc_hir::intravisit::FnKind; use rustc_hir::{ BinOpKind, BindingMode, Body, ByRef, Expr, ExprKind, FnDecl, Mutability, PatKind, QPath, Stmt, StmtKind, @@ -14,8 +15,8 @@ use rustc_hir::{ use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_session::declare_lint_pass; -use rustc_span::def_id::LocalDefId; use rustc_span::Span; +use rustc_span::def_id::LocalDefId; use crate::ref_patterns::REF_PATTERNS; @@ -80,6 +81,45 @@ declare_clippy_lint! { "using a binding which is prefixed with an underscore" } +declare_clippy_lint! { + /// ### What it does + /// Checks for the use of item with a single leading + /// underscore. + /// + /// ### Why is this bad? + /// A single leading underscore is usually used to indicate + /// that a item will not be used. Using such a item breaks this + /// expectation. + /// + /// ### Example + /// ```no_run + /// fn _foo() {} + /// + /// struct _FooStruct {} + /// + /// fn main() { + /// _foo(); + /// let _ = _FooStruct{}; + /// } + /// ``` + /// + /// Use instead: + /// ```no_run + /// fn foo() {} + /// + /// struct FooStruct {} + /// + /// fn main() { + /// foo(); + /// let _ = FooStruct{}; + /// } + /// ``` + #[clippy::version = "pre 1.29.0"] + pub USED_UNDERSCORE_ITEMS, + pedantic, + "using a item which is prefixed with an underscore" +} + declare_clippy_lint! { /// ### What it does /// Checks for the use of short circuit boolean conditions as @@ -104,6 +144,7 @@ declare_clippy_lint! { declare_lint_pass!(LintPass => [ TOPLEVEL_REF_ARG, USED_UNDERSCORE_BINDING, + USED_UNDERSCORE_ITEMS, SHORT_CIRCUIT_STATEMENT, ]); @@ -205,51 +246,104 @@ impl<'tcx> LateLintPass<'tcx> for LintPass { { return; } - let (definition_hir_id, ident) = match expr.kind { - ExprKind::Path(ref qpath) => { - if let QPath::Resolved(None, path) = qpath - && let Res::Local(id) = path.res - && is_used(cx, expr) - { - (id, last_path_segment(qpath).ident) - } else { - return; - } - }, - ExprKind::Field(recv, ident) => { - if let Some(adt_def) = cx.typeck_results().expr_ty_adjusted(recv).ty_adt_def() - && let Some(field) = adt_def.all_fields().find(|field| field.name == ident.name) - && let Some(local_did) = field.did.as_local() - && !cx.tcx.type_of(field.did).skip_binder().is_phantom_data() - { - (cx.tcx.local_def_id_to_hir_id(local_did), ident) - } else { - return; - } - }, - _ => return, - }; - let name = ident.name.as_str(); - if name.starts_with('_') - && !name.starts_with("__") - && let definition_span = cx.tcx.hir().span(definition_hir_id) - && !definition_span.from_expansion() - && !fulfill_or_allowed(cx, USED_UNDERSCORE_BINDING, [expr.hir_id, definition_hir_id]) - { - span_lint_and_then( - cx, - USED_UNDERSCORE_BINDING, - expr.span, - format!( - "used binding `{name}` which is prefixed with an underscore. A leading \ - underscore signals that a binding will not be used" - ), - |diag| { - diag.span_note(definition_span, format!("`{name}` is defined here")); - }, - ); - } + used_underscore_binding(cx, expr); + used_underscore_items(cx, expr); + } +} + +fn used_underscore_items<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { + let (def_id, ident) = match expr.kind { + ExprKind::Call(func, ..) => { + if let ExprKind::Path(QPath::Resolved(.., path)) = func.kind + && let Some(last_segment) = path.segments.last() + && let Res::Def(_, def_id) = last_segment.res + { + (def_id, last_segment.ident) + } else { + return; + } + }, + ExprKind::MethodCall(path, ..) => { + if let Some(def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) { + (def_id, path.ident) + } else { + return; + } + }, + ExprKind::Struct(QPath::Resolved(_, path), ..) => { + if let Some(last_segment) = path.segments.last() + && let Res::Def(_, def_id) = last_segment.res + { + (def_id, last_segment.ident) + } else { + return; + } + }, + _ => return, + }; + + let name = ident.name.as_str(); + let definition_span = cx.tcx.def_span(def_id); + if name.starts_with('_') + && !name.starts_with("__") + && !definition_span.from_expansion() + && def_id.krate == LOCAL_CRATE + { + span_lint_and_then( + cx, + USED_UNDERSCORE_ITEMS, + expr.span, + "used underscore-prefixed item".to_string(), + |diag| { + diag.span_note(definition_span, "item is defined here".to_string()); + }, + ); + } +} + +fn used_underscore_binding<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { + let (definition_hir_id, ident) = match expr.kind { + ExprKind::Path(ref qpath) => { + if let QPath::Resolved(None, path) = qpath + && let Res::Local(id) = path.res + && is_used(cx, expr) + { + (id, last_path_segment(qpath).ident) + } else { + return; + } + }, + ExprKind::Field(recv, ident) => { + if let Some(adt_def) = cx.typeck_results().expr_ty_adjusted(recv).ty_adt_def() + && let Some(field) = adt_def.all_fields().find(|field| field.name == ident.name) + && let Some(local_did) = field.did.as_local() + && !cx.tcx.type_of(field.did).skip_binder().is_phantom_data() + { + (cx.tcx.local_def_id_to_hir_id(local_did), ident) + } else { + return; + } + }, + _ => return, + }; + + let name = ident.name.as_str(); + if name.starts_with('_') + && !name.starts_with("__") + && let definition_span = cx.tcx.hir().span(definition_hir_id) + && !definition_span.from_expansion() + && !fulfill_or_allowed(cx, USED_UNDERSCORE_BINDING, [expr.hir_id, definition_hir_id]) + { + span_lint_and_then( + cx, + USED_UNDERSCORE_BINDING, + expr.span, + "used underscore-prefixed binding".to_string(), + |diag| { + diag.span_note(definition_span, "binding is defined here".to_string()); + }, + ); } } diff --git a/clippy_lints/src/missing_assert_message.rs b/clippy_lints/src/missing_assert_message.rs index a9ea11f4c2b..86348f04600 100644 --- a/clippy_lints/src/missing_assert_message.rs +++ b/clippy_lints/src/missing_assert_message.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::is_in_test; -use clippy_utils::macros::{find_assert_args, find_assert_eq_args, root_macro_call_first_node, PanicExpn}; +use clippy_utils::macros::{PanicExpn, find_assert_args, find_assert_eq_args, root_macro_call_first_node}; use rustc_hir::Expr; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; diff --git a/clippy_lints/src/missing_asserts_for_indexing.rs b/clippy_lints/src/missing_asserts_for_indexing.rs index 94c91b09517..b40d7eba15e 100644 --- a/clippy_lints/src/missing_asserts_for_indexing.rs +++ b/clippy_lints/src/missing_asserts_for_indexing.rs @@ -1,7 +1,7 @@ use std::mem; use std::ops::ControlFlow; -use clippy_utils::comparisons::{normalize_comparison, Rel}; +use clippy_utils::comparisons::{Rel, normalize_comparison}; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet; use clippy_utils::visitors::for_each_expr_without_closures; @@ -14,7 +14,7 @@ use rustc_hir::{BinOp, Block, Body, Expr, ExprKind, UnOp}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; use rustc_span::source_map::Spanned; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/missing_const_for_fn.rs b/clippy_lints/src/missing_const_for_fn.rs index 859afe1b963..eea0459e026 100644 --- a/clippy_lints/src/missing_const_for_fn.rs +++ b/clippy_lints/src/missing_const_for_fn.rs @@ -1,5 +1,5 @@ -use clippy_config::msrvs::{self, Msrv}; use clippy_config::Conf; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_then; 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}; @@ -11,8 +11,8 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty; use rustc_session::impl_lint_pass; -use rustc_span::def_id::LocalDefId; use rustc_span::Span; +use rustc_span::def_id::LocalDefId; use rustc_target::spec::abi::Abi; declare_clippy_lint! { diff --git a/clippy_lints/src/missing_const_for_thread_local.rs b/clippy_lints/src/missing_const_for_thread_local.rs index 954216038fb..c2f524a6353 100644 --- a/clippy_lints/src/missing_const_for_thread_local.rs +++ b/clippy_lints/src/missing_const_for_thread_local.rs @@ -1,12 +1,12 @@ -use clippy_config::msrvs::{self, Msrv}; use clippy_config::Conf; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::macros::macro_backtrace; use clippy_utils::qualify_min_const_fn::is_min_const_fn; use clippy_utils::source::snippet; use clippy_utils::{fn_has_unsatisfiable_preds, peel_blocks}; use rustc_errors::Applicability; -use rustc_hir::{intravisit, Expr, ExprKind}; +use rustc_hir::{Expr, ExprKind, intravisit}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::impl_lint_pass; use rustc_span::sym::{self, thread_local_macro}; diff --git a/clippy_lints/src/missing_doc.rs b/clippy_lints/src/missing_doc.rs index 2166b0fe5a0..64fc1a8a1a5 100644 --- a/clippy_lints/src/missing_doc.rs +++ b/clippy_lints/src/missing_doc.rs @@ -17,7 +17,7 @@ use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::ty::Visibility; use rustc_session::impl_lint_pass; use rustc_span::def_id::CRATE_DEF_ID; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/missing_fields_in_debug.rs b/clippy_lints/src/missing_fields_in_debug.rs index 77595b121aa..fc01b6753f1 100644 --- a/clippy_lints/src/missing_fields_in_debug.rs +++ b/clippy_lints/src/missing_fields_in_debug.rs @@ -3,7 +3,7 @@ use std::ops::ControlFlow; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::is_path_lang_item; use clippy_utils::ty::is_type_diagnostic_item; -use clippy_utils::visitors::{for_each_expr, Visitable}; +use clippy_utils::visitors::{Visitable, for_each_expr}; use rustc_ast::LitKind; use rustc_data_structures::fx::FxHashSet; use rustc_hir::def::{DefKind, Res}; @@ -13,7 +13,7 @@ use rustc_hir::{ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{Ty, TypeckResults}; use rustc_session::declare_lint_pass; -use rustc_span::{sym, Span, Symbol}; +use rustc_span::{Span, Symbol, sym}; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/missing_inline.rs b/clippy_lints/src/missing_inline.rs index 33a14d8b7fe..d342be4545c 100644 --- a/clippy_lints/src/missing_inline.rs +++ b/clippy_lints/src/missing_inline.rs @@ -3,7 +3,7 @@ use rustc_ast::ast; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_session::declare_lint_pass; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/mixed_read_write_in_expression.rs b/clippy_lints/src/mixed_read_write_in_expression.rs index 0b3769ecb7c..d333b71edb1 100644 --- a/clippy_lints/src/mixed_read_write_in_expression.rs +++ b/clippy_lints/src/mixed_read_write_in_expression.rs @@ -1,6 +1,7 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; +use clippy_utils::macros::root_macro_call_first_node; use clippy_utils::{get_parent_expr, path_to_local, path_to_local_id}; -use rustc_hir::intravisit::{walk_expr, Visitor}; +use rustc_hir::intravisit::{Visitor, walk_expr}; use rustc_hir::{BinOpKind, Block, Expr, ExprKind, HirId, LetStmt, Node, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; @@ -134,6 +135,11 @@ impl<'a, 'tcx> DivergenceVisitor<'a, 'tcx> { } fn report_diverging_sub_expr(&mut self, e: &Expr<'_>) { + if let Some(macro_call) = root_macro_call_first_node(self.cx, e) { + if self.cx.tcx.item_name(macro_call.def_id).as_str() == "todo" { + return; + } + } span_lint(self.cx, DIVERGING_SUB_EXPRESSION, e.span, "sub-expression diverges"); } } diff --git a/clippy_lints/src/multiple_unsafe_ops_per_block.rs b/clippy_lints/src/multiple_unsafe_ops_per_block.rs index 0bde0da3cd8..12bcc608174 100644 --- a/clippy_lints/src/multiple_unsafe_ops_per_block.rs +++ b/clippy_lints/src/multiple_unsafe_ops_per_block.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::visitors::{for_each_expr, Descend, Visitable}; +use clippy_utils::visitors::{Descend, Visitable, for_each_expr}; use core::ops::ControlFlow::Continue; use hir::def::{DefKind, Res}; use hir::{BlockCheckMode, ExprKind, QPath, Safety, UnOp}; @@ -153,19 +153,16 @@ fn collect_unsafe_exprs<'tcx>( ExprKind::AssignOp(_, lhs, rhs) | ExprKind::Assign(lhs, rhs, _) => { if matches!( lhs.kind, - ExprKind::Path(QPath::Resolved( - _, - hir::Path { - res: Res::Def( - DefKind::Static { - mutability: Mutability::Mut, - .. - }, - _ - ), - .. - } - )) + ExprKind::Path(QPath::Resolved(_, hir::Path { + res: Res::Def( + DefKind::Static { + mutability: Mutability::Mut, + .. + }, + _ + ), + .. + })) ) { unsafe_ops.push(("modification of a mutable static occurs here", expr.span)); collect_unsafe_exprs(cx, rhs, unsafe_ops); diff --git a/clippy_lints/src/mut_key.rs b/clippy_lints/src/mut_key.rs index f52b3a6a5a1..8118c14bd4a 100644 --- a/clippy_lints/src/mut_key.rs +++ b/clippy_lints/src/mut_key.rs @@ -6,9 +6,9 @@ use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_session::impl_lint_pass; +use rustc_span::Span; use rustc_span::def_id::LocalDefId; use rustc_span::symbol::sym; -use rustc_span::Span; use std::iter; declare_clippy_lint! { diff --git a/clippy_lints/src/mutable_debug_assertion.rs b/clippy_lints/src/mutable_debug_assertion.rs index e92ba93942e..785bf70a3ec 100644 --- a/clippy_lints/src/mutable_debug_assertion.rs +++ b/clippy_lints/src/mutable_debug_assertion.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint; use clippy_utils::macros::{find_assert_eq_args, root_macro_call_first_node}; -use rustc_hir::intravisit::{walk_expr, Visitor}; +use rustc_hir::intravisit::{Visitor, walk_expr}; use rustc_hir::{BorrowKind, Expr, ExprKind, MatchSource, Mutability}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::nested_filter; diff --git a/clippy_lints/src/needless_arbitrary_self_type.rs b/clippy_lints/src/needless_arbitrary_self_type.rs index 60c44382059..3c47d0edfdc 100644 --- a/clippy_lints/src/needless_arbitrary_self_type.rs +++ b/clippy_lints/src/needless_arbitrary_self_type.rs @@ -3,8 +3,8 @@ use rustc_ast::ast::{BindingMode, ByRef, Lifetime, Mutability, Param, PatKind, P use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_session::declare_lint_pass; -use rustc_span::symbol::kw; use rustc_span::Span; +use rustc_span::symbol::kw; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/needless_bool.rs b/clippy_lints/src/needless_bool.rs index df155a7a412..2eacd6875d6 100644 --- a/clippy_lints/src/needless_bool.rs +++ b/clippy_lints/src/needless_bool.rs @@ -2,16 +2,16 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg}; use clippy_utils::source::snippet_with_applicability; use clippy_utils::sugg::Sugg; use clippy_utils::{ - get_parent_expr, higher, is_block_like, is_else_clause, is_expn_of, is_parent_stmt, is_receiver_of_method_call, - peel_blocks, peel_blocks_with_stmt, span_extract_comment, SpanlessEq, + SpanlessEq, get_parent_expr, higher, is_block_like, is_else_clause, is_expn_of, is_parent_stmt, + is_receiver_of_method_call, peel_blocks, peel_blocks_with_stmt, span_extract_comment, }; use rustc_ast::ast::LitKind; 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::source_map::Spanned; use rustc_span::Span; +use rustc_span::source_map::Spanned; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/needless_borrows_for_generic_args.rs b/clippy_lints/src/needless_borrows_for_generic_args.rs index 32e7fde03b2..f6db12ed84e 100644 --- a/clippy_lints/src/needless_borrows_for_generic_args.rs +++ b/clippy_lints/src/needless_borrows_for_generic_args.rs @@ -1,10 +1,10 @@ -use clippy_config::msrvs::{self, Msrv}; use clippy_config::Conf; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::mir::{enclosing_mir, expr_local, local_assignments, used_exactly_once, PossibleBorrowerMap}; +use clippy_utils::mir::{PossibleBorrowerMap, enclosing_mir, expr_local, local_assignments, used_exactly_once}; use clippy_utils::source::snippet_with_context; use clippy_utils::ty::{implements_trait, is_copy}; -use clippy_utils::{expr_use_ctxt, peel_n_hir_expr_refs, DefinedTy, ExprUseNode}; +use clippy_utils::{DefinedTy, ExprUseNode, expr_use_ctxt, peel_n_hir_expr_refs}; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, LocalDefId}; diff --git a/clippy_lints/src/needless_for_each.rs b/clippy_lints/src/needless_for_each.rs index 6390e51f916..b54eb164e81 100644 --- a/clippy_lints/src/needless_for_each.rs +++ b/clippy_lints/src/needless_for_each.rs @@ -1,9 +1,9 @@ use rustc_errors::Applicability; -use rustc_hir::intravisit::{walk_expr, Visitor}; +use rustc_hir::intravisit::{Visitor, walk_expr}; use rustc_hir::{Block, BlockCheckMode, Closure, Expr, ExprKind, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::is_trait_method; diff --git a/clippy_lints/src/needless_maybe_sized.rs b/clippy_lints/src/needless_maybe_sized.rs index 62e41088f37..bb44ff37b20 100644 --- a/clippy_lints/src/needless_maybe_sized.rs +++ b/clippy_lints/src/needless_maybe_sized.rs @@ -26,7 +26,7 @@ declare_clippy_lint! { /// /// // or choose alternative bounds for `T` so that it can be unsized /// ``` - #[clippy::version = "1.79.0"] + #[clippy::version = "1.81.0"] pub NEEDLESS_MAYBE_SIZED, suspicious, "a `?Sized` bound that is unusable due to a `Sized` requirement" diff --git a/clippy_lints/src/needless_pass_by_ref_mut.rs b/clippy_lints/src/needless_pass_by_ref_mut.rs index d543fd467ab..19cbf595908 100644 --- a/clippy_lints/src/needless_pass_by_ref_mut.rs +++ b/clippy_lints/src/needless_pass_by_ref_mut.rs @@ -17,9 +17,9 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::mir::FakeReadCause; use rustc_middle::ty::{self, Ty, TyCtxt, UpvarId, UpvarPath}; use rustc_session::impl_lint_pass; +use rustc_span::Span; use rustc_span::def_id::LocalDefId; use rustc_span::symbol::kw; -use rustc_span::Span; use rustc_target::spec::abi::Abi; declare_clippy_lint! { diff --git a/clippy_lints/src/needless_pass_by_value.rs b/clippy_lints/src/needless_pass_by_value.rs index addb4b1aee8..0775d7abdbb 100644 --- a/clippy_lints/src/needless_pass_by_value.rs +++ b/clippy_lints/src/needless_pass_by_value.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::is_self; use clippy_utils::ptr::get_spans; -use clippy_utils::source::{snippet, SpanRangeExt}; +use clippy_utils::source::{SpanRangeExt, snippet}; use clippy_utils::ty::{ implements_trait, implements_trait_with_env_from_iter, is_copy, is_type_diagnostic_item, is_type_lang_item, }; @@ -19,7 +19,7 @@ use rustc_middle::ty::{self, Ty, TypeVisitableExt}; use rustc_session::declare_lint_pass; use rustc_span::def_id::LocalDefId; use rustc_span::symbol::kw; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; use rustc_target::spec::abi::Abi; use rustc_trait_selection::traits; use rustc_trait_selection::traits::misc::type_allowed_to_implement_copy; @@ -129,7 +129,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue { }) .collect::>(); - // Collect moved variables and spans which will need dereferencings from the + // Collect moved variables and spans which will need dereferencing from the // function body. let MovedVariablesCtxt { moved_vars } = { let mut ctx = MovedVariablesCtxt::default(); @@ -148,12 +148,13 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue { return; } - // Ignore `self`s. - if idx == 0 { - if let PatKind::Binding(.., ident, _) = arg.pat.kind { - if ident.name == kw::SelfLower { - continue; - } + // Ignore `self`s and params whose variable name starts with an underscore + if let PatKind::Binding(.., ident, _) = arg.pat.kind { + if idx == 0 && ident.name == kw::SelfLower { + continue; + } + if ident.name.as_str().starts_with('_') { + continue; } } @@ -181,14 +182,9 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue { && !is_copy(cx, ty) && ty.is_sized(cx.tcx, cx.param_env) && !allowed_traits.iter().any(|&t| { - implements_trait_with_env_from_iter( - cx.tcx, - cx.param_env, - ty, - t, - None, - [Option::>::None], - ) + implements_trait_with_env_from_iter(cx.tcx, cx.param_env, ty, t, None, [Option::< + ty::GenericArg<'tcx>, + >::None]) }) && !implements_borrow_trait && !all_borrowable_trait @@ -207,7 +203,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue { ) .is_ok() { - diag.span_help(span, "consider marking this type as `Copy`"); + diag.span_help(span, "or consider marking this type as `Copy`"); } } } diff --git a/clippy_lints/src/no_effect.rs b/clippy_lints/src/no_effect.rs index b181791699a..392cfcb813e 100644 --- a/clippy_lints/src/no_effect.rs +++ b/clippy_lints/src/no_effect.rs @@ -7,8 +7,8 @@ use clippy_utils::{ use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; use rustc_hir::{ - is_range_literal, BinOpKind, BlockCheckMode, Expr, ExprKind, HirId, HirIdMap, ItemKind, LocalSource, Node, PatKind, - Stmt, StmtKind, UnsafeSource, + BinOpKind, BlockCheckMode, Expr, ExprKind, HirId, HirIdMap, ItemKind, LocalSource, Node, PatKind, Stmt, StmtKind, + UnsafeSource, is_range_literal, }; use rustc_infer::infer::TyCtxtInferExt as _; use rustc_lint::{LateContext, LateLintPass, LintContext}; diff --git a/clippy_lints/src/non_copy_const.rs b/clippy_lints/src/non_copy_const.rs index 25f547f1a43..5e20b406426 100644 --- a/clippy_lints/src/non_copy_const.rs +++ b/clippy_lints/src/non_copy_const.rs @@ -4,7 +4,7 @@ use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::is_in_const_context; use clippy_utils::macros::macro_backtrace; -use clippy_utils::ty::{implements_trait, InteriorMut}; +use clippy_utils::ty::{InteriorMut, implements_trait}; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; use rustc_hir::{ @@ -15,7 +15,7 @@ use rustc_middle::mir::interpret::{ErrorHandled, EvalToValTreeResult, GlobalId}; use rustc_middle::ty::adjustment::Adjust; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_session::impl_lint_pass; -use rustc_span::{sym, Span, DUMMY_SP}; +use rustc_span::{DUMMY_SP, Span, sym}; use rustc_target::abi::VariantIdx; // FIXME: this is a correctness problem but there's no suitable diff --git a/clippy_lints/src/non_expressive_names.rs b/clippy_lints/src/non_expressive_names.rs index 832518d2d35..d85032e9eee 100644 --- a/clippy_lints/src/non_expressive_names.rs +++ b/clippy_lints/src/non_expressive_names.rs @@ -3,12 +3,12 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; use rustc_ast::ast::{ self, Arm, AssocItem, AssocItemKind, Attribute, Block, FnDecl, Item, ItemKind, Local, Pat, PatKind, }; -use rustc_ast::visit::{walk_block, walk_expr, walk_pat, Visitor}; +use rustc_ast::visit::{Visitor, walk_block, walk_expr, walk_pat}; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_session::impl_lint_pass; use rustc_span::symbol::{Ident, Symbol}; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; use std::cmp::Ordering; declare_clippy_lint! { diff --git a/clippy_lints/src/non_octal_unix_permissions.rs b/clippy_lints/src/non_octal_unix_permissions.rs index cfc15d92715..3f156aa5510 100644 --- a/clippy_lints/src/non_octal_unix_permissions.rs +++ b/clippy_lints/src/non_octal_unix_permissions.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::{snippet_with_applicability, SpanRangeExt}; +use clippy_utils::source::{SpanRangeExt, snippet_with_applicability}; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; diff --git a/clippy_lints/src/non_zero_suggestions.rs b/clippy_lints/src/non_zero_suggestions.rs new file mode 100644 index 00000000000..90a9f2e994b --- /dev/null +++ b/clippy_lints/src/non_zero_suggestions.rs @@ -0,0 +1,143 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet; +use rustc_ast::ast::BinOpKind; +use rustc_errors::Applicability; +use rustc_hir::{Expr, ExprKind}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty::{self, Ty}; +use rustc_session::declare_lint_pass; +use rustc_span::symbol::sym; + +declare_clippy_lint! { + /// ### What it does + /// Checks for conversions from `NonZero` types to regular integer types, + /// and suggests using `NonZero` types for the target as well. + /// + /// ### Why is this bad? + /// Converting from `NonZero` types to regular integer types and then back to `NonZero` + /// types is less efficient and loses the type-safety guarantees provided by `NonZero` types. + /// Using `NonZero` types consistently can lead to more optimized code and prevent + /// certain classes of errors related to zero values. + /// + /// ### Example + /// ```no_run + /// use std::num::{NonZeroU32, NonZeroU64}; + /// + /// fn example(x: u64, y: NonZeroU32) { + /// // Bad: Converting NonZeroU32 to u64 unnecessarily + /// let r1 = x / u64::from(y.get()); + /// let r2 = x % u64::from(y.get()); + /// } + /// ``` + /// Use instead: + /// ```no_run + /// use std::num::{NonZeroU32, NonZeroU64}; + /// + /// fn example(x: u64, y: NonZeroU32) { + /// // Good: Preserving the NonZero property + /// let r1 = x / NonZeroU64::from(y); + /// let r2 = x % NonZeroU64::from(y); + /// } + /// ``` + #[clippy::version = "1.81.0"] + pub NON_ZERO_SUGGESTIONS, + restriction, + "suggests using `NonZero#` from `u#` or `i#` for more efficient and type-safe conversions" +} + +declare_lint_pass!(NonZeroSuggestions => [NON_ZERO_SUGGESTIONS]); + +impl<'tcx> LateLintPass<'tcx> for NonZeroSuggestions { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { + if let ExprKind::Binary(op, _, rhs) = expr.kind + && matches!(op.node, BinOpKind::Div | BinOpKind::Rem) + { + check_non_zero_conversion(cx, rhs, Applicability::MachineApplicable); + } else { + // Check if the parent expression is a binary operation + let parent_is_binary = cx.tcx.hir().parent_iter(expr.hir_id).any(|(_, node)| { + matches!(node, rustc_hir::Node::Expr(parent_expr) if matches!(parent_expr.kind, ExprKind::Binary(..))) + }); + + if !parent_is_binary { + check_non_zero_conversion(cx, expr, Applicability::MaybeIncorrect); + } + } + } +} + +fn check_non_zero_conversion(cx: &LateContext<'_>, expr: &Expr<'_>, applicability: Applicability) { + // Check if the expression is a function call with one argument + if let ExprKind::Call(func, [arg]) = expr.kind + && let ExprKind::Path(qpath) = &func.kind + && let Some(def_id) = cx.qpath_res(qpath, func.hir_id).opt_def_id() + && let ExprKind::MethodCall(rcv_path, receiver, _, _) = &arg.kind + && rcv_path.ident.name.as_str() == "get" + { + let fn_name = cx.tcx.item_name(def_id); + let target_ty = cx.typeck_results().expr_ty(expr); + let receiver_ty = cx.typeck_results().expr_ty(receiver); + + // Check if the receiver type is a NonZero type + if let ty::Adt(adt_def, _) = receiver_ty.kind() + && adt_def.is_struct() + && cx.tcx.get_diagnostic_name(adt_def.did()) == Some(sym::NonZero) + { + if let Some(target_non_zero_type) = get_target_non_zero_type(target_ty) { + let arg_snippet = get_arg_snippet(cx, arg, rcv_path); + suggest_non_zero_conversion(cx, expr, fn_name, target_non_zero_type, &arg_snippet, applicability); + } + } + } +} + +fn get_arg_snippet(cx: &LateContext<'_>, arg: &Expr<'_>, rcv_path: &rustc_hir::PathSegment<'_>) -> String { + let arg_snippet = snippet(cx, arg.span, ".."); + if let Some(index) = arg_snippet.rfind(&format!(".{}", rcv_path.ident.name)) { + arg_snippet[..index].trim().to_string() + } else { + arg_snippet.to_string() + } +} + +fn suggest_non_zero_conversion( + cx: &LateContext<'_>, + expr: &Expr<'_>, + fn_name: rustc_span::Symbol, + target_non_zero_type: &str, + arg_snippet: &str, + applicability: Applicability, +) { + let suggestion = format!("{target_non_zero_type}::{fn_name}({arg_snippet})"); + span_lint_and_sugg( + cx, + NON_ZERO_SUGGESTIONS, + expr.span, + format!("consider using `{target_non_zero_type}::{fn_name}()` for more efficient and type-safe conversion"), + "replace with", + suggestion, + applicability, + ); +} + +fn get_target_non_zero_type(ty: Ty<'_>) -> Option<&'static str> { + match ty.kind() { + ty::Uint(uint_ty) => Some(match uint_ty { + ty::UintTy::U8 => "NonZeroU8", + ty::UintTy::U16 => "NonZeroU16", + ty::UintTy::U32 => "NonZeroU32", + ty::UintTy::U64 => "NonZeroU64", + ty::UintTy::U128 => "NonZeroU128", + ty::UintTy::Usize => "NonZeroUsize", + }), + ty::Int(int_ty) => Some(match int_ty { + ty::IntTy::I8 => "NonZeroI8", + ty::IntTy::I16 => "NonZeroI16", + ty::IntTy::I32 => "NonZeroI32", + ty::IntTy::I64 => "NonZeroI64", + ty::IntTy::I128 => "NonZeroI128", + ty::IntTy::Isize => "NonZeroIsize", + }), + _ => None, + } +} diff --git a/clippy_lints/src/nonstandard_macro_braces.rs b/clippy_lints/src/nonstandard_macro_braces.rs index 51ba29d7389..a13391a5945 100644 --- a/clippy_lints/src/nonstandard_macro_braces.rs +++ b/clippy_lints/src/nonstandard_macro_braces.rs @@ -1,5 +1,5 @@ -use clippy_config::types::MacroMatcher; use clippy_config::Conf; +use clippy_config::types::MacroMatcher; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::{SourceText, SpanRangeExt}; use rustc_ast::ast; @@ -8,8 +8,8 @@ use rustc_errors::Applicability; use rustc_hir::def_id::DefId; use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_session::impl_lint_pass; -use rustc_span::hygiene::{ExpnKind, MacroKind}; use rustc_span::Span; +use rustc_span::hygiene::{ExpnKind, MacroKind}; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/only_used_in_recursion.rs b/clippy_lints/src/only_used_in_recursion.rs index aadd729f32a..372128ac16f 100644 --- a/clippy_lints/src/only_used_in_recursion.rs +++ b/clippy_lints/src/only_used_in_recursion.rs @@ -9,8 +9,8 @@ use rustc_hir::{Body, Expr, ExprKind, HirId, ImplItem, ImplItemKind, Node, PatKi use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{self, ConstKind, EarlyBinder, GenericArgKind, GenericArgsRef}; use rustc_session::impl_lint_pass; -use rustc_span::symbol::{kw, Ident}; use rustc_span::Span; +use rustc_span::symbol::{Ident, kw}; use std::iter; declare_clippy_lint! { diff --git a/clippy_lints/src/operators/absurd_extreme_comparisons.rs b/clippy_lints/src/operators/absurd_extreme_comparisons.rs index a0de5ea711c..dbc9948eeed 100644 --- a/clippy_lints/src/operators/absurd_extreme_comparisons.rs +++ b/clippy_lints/src/operators/absurd_extreme_comparisons.rs @@ -2,7 +2,7 @@ use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::LateContext; use rustc_middle::ty; -use clippy_utils::comparisons::{normalize_comparison, Rel}; +use clippy_utils::comparisons::{Rel, normalize_comparison}; use clippy_utils::consts::{ConstEvalCtxt, Constant}; use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::source::snippet; diff --git a/clippy_lints/src/operators/const_comparisons.rs b/clippy_lints/src/operators/const_comparisons.rs index c1317524396..5d94cfab3b0 100644 --- a/clippy_lints/src/operators/const_comparisons.rs +++ b/clippy_lints/src/operators/const_comparisons.rs @@ -7,12 +7,12 @@ use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::LateContext; use rustc_middle::ty::layout::HasTyCtxt; use rustc_middle::ty::{Ty, TypeckResults}; -use rustc_span::source_map::Spanned; use rustc_span::Span; +use rustc_span::source_map::Spanned; +use clippy_utils::SpanlessEq; use clippy_utils::diagnostics::span_lint_and_note; use clippy_utils::source::snippet; -use clippy_utils::SpanlessEq; use super::{IMPOSSIBLE_COMPARISONS, REDUNDANT_COMPARISONS}; diff --git a/clippy_lints/src/operators/float_equality_without_abs.rs b/clippy_lints/src/operators/float_equality_without_abs.rs index be97ad389bf..34f7dbea84e 100644 --- a/clippy_lints/src/operators/float_equality_without_abs.rs +++ b/clippy_lints/src/operators/float_equality_without_abs.rs @@ -6,7 +6,8 @@ use rustc_hir::def::{DefKind, Res}; use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::LateContext; use rustc_middle::ty; -use rustc_span::{sym, source_map::Spanned}; +use rustc_span::source_map::Spanned; +use rustc_span::sym; use super::FLOAT_EQUALITY_WITHOUT_ABS; diff --git a/clippy_lints/src/option_if_let_else.rs b/clippy_lints/src/option_if_let_else.rs index ae02d22512e..6d9e75f51d6 100644 --- a/clippy_lints/src/option_if_let_else.rs +++ b/clippy_lints/src/option_if_let_else.rs @@ -1,12 +1,12 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::sugg::Sugg; use clippy_utils::{ - can_move_expr_to_closure, eager_or_lazy, higher, is_else_clause, is_in_const_context, is_res_lang_ctor, - peel_blocks, peel_hir_expr_while, CaptureKind, + CaptureKind, can_move_expr_to_closure, eager_or_lazy, higher, is_else_clause, is_in_const_context, + is_res_lang_ctor, peel_blocks, peel_hir_expr_while, }; use rustc_errors::Applicability; -use rustc_hir::def::Res; use rustc_hir::LangItem::{OptionNone, OptionSome, ResultErr, ResultOk}; +use rustc_hir::def::Res; use rustc_hir::{Arm, BindingMode, Expr, ExprKind, MatchSource, Mutability, Pat, PatKind, Path, QPath, UnOp}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; diff --git a/clippy_lints/src/panic_in_result_fn.rs b/clippy_lints/src/panic_in_result_fn.rs index 381975199d2..eebc62e2a5a 100644 --- a/clippy_lints/src/panic_in_result_fn.rs +++ b/clippy_lints/src/panic_in_result_fn.rs @@ -1,15 +1,15 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::macros::root_macro_call_first_node; -use clippy_utils::return_ty; use clippy_utils::ty::is_type_diagnostic_item; -use clippy_utils::visitors::{for_each_expr, Descend}; +use clippy_utils::visitors::{Descend, for_each_expr}; +use clippy_utils::{is_inside_always_const_context, return_ty}; use core::ops::ControlFlow; use rustc_hir as hir; use rustc_hir::intravisit::FnKind; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; use rustc_span::def_id::LocalDefId; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; declare_clippy_lint! { /// ### What it does @@ -68,10 +68,12 @@ fn lint_impl_body<'tcx>(cx: &LateContext<'tcx>, impl_span: Span, body: &'tcx hir let Some(macro_call) = root_macro_call_first_node(cx, e) else { return ControlFlow::Continue(Descend::Yes); }; - if matches!( - cx.tcx.item_name(macro_call.def_id).as_str(), - "panic" | "assert" | "assert_eq" | "assert_ne" - ) { + if !is_inside_always_const_context(cx.tcx, e.hir_id) + && matches!( + cx.tcx.item_name(macro_call.def_id).as_str(), + "panic" | "assert" | "assert_eq" | "assert_ne" + ) + { panics.push(macro_call.span); ControlFlow::Continue(Descend::No) } else { diff --git a/clippy_lints/src/panic_unimplemented.rs b/clippy_lints/src/panic_unimplemented.rs index 4eefd0065f6..fa5b02a5a41 100644 --- a/clippy_lints/src/panic_unimplemented.rs +++ b/clippy_lints/src/panic_unimplemented.rs @@ -1,8 +1,9 @@ use clippy_config::Conf; use clippy_utils::diagnostics::span_lint; -use clippy_utils::is_in_test; use clippy_utils::macros::{is_panic, root_macro_call_first_node}; -use rustc_hir::Expr; +use clippy_utils::{is_in_test, match_def_path, paths}; +use rustc_hir::def::{DefKind, Res}; +use rustc_hir::{Expr, ExprKind, QPath}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::impl_lint_pass; @@ -95,10 +96,49 @@ impl_lint_pass!(PanicUnimplemented => [UNIMPLEMENTED, UNREACHABLE, TODO, PANIC]) impl<'tcx> LateLintPass<'tcx> for PanicUnimplemented { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - let Some(macro_call) = root_macro_call_first_node(cx, expr) else { - return; - }; - if is_panic(cx, macro_call.def_id) { + if let Some(macro_call) = root_macro_call_first_node(cx, expr) { + if is_panic(cx, macro_call.def_id) { + if cx.tcx.hir().is_inside_const_context(expr.hir_id) + || self.allow_panic_in_tests && is_in_test(cx.tcx, expr.hir_id) + { + return; + } + + span_lint( + cx, + PANIC, + macro_call.span, + "`panic` should not be present in production code", + ); + return; + } + match cx.tcx.item_name(macro_call.def_id).as_str() { + "todo" => { + span_lint( + cx, + TODO, + macro_call.span, + "`todo` should not be present in production code", + ); + }, + "unimplemented" => { + span_lint( + cx, + UNIMPLEMENTED, + macro_call.span, + "`unimplemented` should not be present in production code", + ); + }, + "unreachable" => { + span_lint(cx, UNREACHABLE, macro_call.span, "usage of the `unreachable!` macro"); + }, + _ => {}, + } + } else if let ExprKind::Call(func, [_]) = expr.kind + && let ExprKind::Path(QPath::Resolved(None, expr_path)) = func.kind + && let Res::Def(DefKind::Fn, def_id) = expr_path.res + && match_def_path(cx, def_id, &paths::PANIC_ANY) + { if cx.tcx.hir().is_inside_const_context(expr.hir_id) || self.allow_panic_in_tests && is_in_test(cx.tcx, expr.hir_id) { @@ -108,32 +148,10 @@ impl<'tcx> LateLintPass<'tcx> for PanicUnimplemented { span_lint( cx, PANIC, - macro_call.span, - "`panic` should not be present in production code", + expr.span, + "`panic_any` should not be present in production code", ); return; } - match cx.tcx.item_name(macro_call.def_id).as_str() { - "todo" => { - span_lint( - cx, - TODO, - macro_call.span, - "`todo` should not be present in production code", - ); - }, - "unimplemented" => { - span_lint( - cx, - UNIMPLEMENTED, - macro_call.span, - "`unimplemented` should not be present in production code", - ); - }, - "unreachable" => { - span_lint(cx, UNREACHABLE, macro_call.span, "usage of the `unreachable!` macro"); - }, - _ => {}, - } } } diff --git a/clippy_lints/src/pass_by_ref_or_value.rs b/clippy_lints/src/pass_by_ref_or_value.rs index 5ca244f0141..75d8c09f2b0 100644 --- a/clippy_lints/src/pass_by_ref_or_value.rs +++ b/clippy_lints/src/pass_by_ref_or_value.rs @@ -18,7 +18,7 @@ use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::{self, RegionKind, TyCtxt}; use rustc_session::impl_lint_pass; use rustc_span::def_id::LocalDefId; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; use rustc_target::spec::abi::Abi; declare_clippy_lint! { diff --git a/clippy_lints/src/pathbuf_init_then_push.rs b/clippy_lints/src/pathbuf_init_then_push.rs index d7fa48c1e38..1b9a5a44382 100644 --- a/clippy_lints/src/pathbuf_init_then_push.rs +++ b/clippy_lints/src/pathbuf_init_then_push.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::path_to_local_id; -use clippy_utils::source::{snippet, SpanRangeExt}; +use clippy_utils::source::{SpanRangeExt, snippet}; use clippy_utils::ty::is_type_diagnostic_item; use rustc_ast::{LitKind, StrStyle}; use rustc_errors::Applicability; @@ -9,7 +9,7 @@ use rustc_hir::{BindingMode, Block, Expr, ExprKind, HirId, LetStmt, PatKind, QPa use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_session::impl_lint_pass; -use rustc_span::{sym, Span, Symbol}; +use rustc_span::{Span, Symbol, sym}; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/pattern_type_mismatch.rs b/clippy_lints/src/pattern_type_mismatch.rs index c1296b04387..42fbba8ef6d 100644 --- a/clippy_lints/src/pattern_type_mismatch.rs +++ b/clippy_lints/src/pattern_type_mismatch.rs @@ -1,13 +1,13 @@ use clippy_utils::diagnostics::span_lint_and_then; use rustc_hir::{ - intravisit, Body, Expr, ExprKind, FnDecl, LetExpr, LocalSource, Mutability, Pat, PatKind, Stmt, StmtKind, + Body, Expr, ExprKind, FnDecl, LetExpr, LocalSource, Mutability, Pat, PatKind, Stmt, StmtKind, intravisit, }; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty; use rustc_session::declare_lint_pass; -use rustc_span::def_id::LocalDefId; use rustc_span::Span; +use rustc_span::def_id::LocalDefId; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/pointers_in_nomem_asm_block.rs b/clippy_lints/src/pointers_in_nomem_asm_block.rs new file mode 100644 index 00000000000..385f634a150 --- /dev/null +++ b/clippy_lints/src/pointers_in_nomem_asm_block.rs @@ -0,0 +1,88 @@ +use clippy_utils::diagnostics::span_lint_and_then; +use rustc_ast::InlineAsmOptions; +use rustc_hir::{Expr, ExprKind, InlineAsm, InlineAsmOperand}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_session::declare_lint_pass; +use rustc_span::Span; + +declare_clippy_lint! { + /// ### What it does + /// Checks if any pointer is being passed to an asm! block with `nomem` option. + /// + /// ### Why is this bad? + /// `nomem` forbids any reads or writes to memory and passing a pointer suggests + /// that either of those will happen. + /// + /// ### Example + /// ```no_run + /// fn f(p: *mut u32) { + /// unsafe { core::arch::asm!("mov [{p}], 42", p = in(reg) p, options(nomem, nostack)); } + /// } + /// ``` + /// Use instead: + /// ```no_run + /// fn f(p: *mut u32) { + /// unsafe { core::arch::asm!("mov [{p}], 42", p = in(reg) p, options(nostack)); } + /// } + /// ``` + #[clippy::version = "1.81.0"] + pub POINTERS_IN_NOMEM_ASM_BLOCK, + suspicious, + "pointers in nomem asm block" +} + +declare_lint_pass!(PointersInNomemAsmBlock => [POINTERS_IN_NOMEM_ASM_BLOCK]); + +impl<'tcx> LateLintPass<'tcx> for PointersInNomemAsmBlock { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) { + if let ExprKind::InlineAsm(asm) = &expr.kind { + check_asm(cx, asm); + } + } +} + +fn check_asm(cx: &LateContext<'_>, asm: &InlineAsm<'_>) { + if !asm.options.contains(InlineAsmOptions::NOMEM) { + return; + } + + let spans = asm + .operands + .iter() + .filter(|(op, _span)| has_in_operand_pointer(cx, op)) + .map(|(_op, span)| *span) + .collect::>(); + + if spans.is_empty() { + return; + } + + span_lint_and_then( + cx, + POINTERS_IN_NOMEM_ASM_BLOCK, + spans, + "passing pointers to nomem asm block", + additional_notes, + ); +} + +fn has_in_operand_pointer(cx: &LateContext<'_>, asm_op: &InlineAsmOperand<'_>) -> bool { + let asm_in_expr = match asm_op { + InlineAsmOperand::SymStatic { .. } + | InlineAsmOperand::Out { .. } + | InlineAsmOperand::Const { .. } + | InlineAsmOperand::SymFn { .. } + | InlineAsmOperand::Label { .. } => return false, + InlineAsmOperand::SplitInOut { in_expr, .. } => in_expr, + InlineAsmOperand::In { expr, .. } | InlineAsmOperand::InOut { expr, .. } => expr, + }; + + // This checks for raw ptrs, refs and function pointers - the last one + // also technically counts as reading memory. + cx.typeck_results().expr_ty(asm_in_expr).is_any_ptr() +} + +fn additional_notes(diag: &mut rustc_errors::Diag<'_, ()>) { + diag.note("`nomem` means that no memory write or read happens inside the asm! block"); + diag.note("if this is intentional and no pointers are read or written to, consider allowing the lint"); +} diff --git a/clippy_lints/src/ptr.rs b/clippy_lints/src/ptr.rs index 125f694996c..807636bb642 100644 --- a/clippy_lints/src/ptr.rs +++ b/clippy_lints/src/ptr.rs @@ -1,13 +1,11 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then, span_lint_hir_and_then}; use clippy_utils::source::SpanRangeExt; -use clippy_utils::ty::expr_sig; use clippy_utils::visitors::contains_unsafe_block; use clippy_utils::{get_expr_use_or_unification_node, is_lint_allowed, path_def_id, path_to_local}; use hir::LifetimeName; use rustc_errors::{Applicability, MultiSpan}; -use rustc_hir::def_id::DefId; use rustc_hir::hir_id::{HirId, HirIdMap}; -use rustc_hir::intravisit::{walk_expr, Visitor}; +use rustc_hir::intravisit::{Visitor, walk_expr}; use rustc_hir::{ self as hir, AnonConst, BinOpKind, BindingMode, Body, Expr, ExprKind, FnRetTy, FnSig, GenericArg, ImplItemKind, ItemKind, Lifetime, Mutability, Node, Param, PatKind, QPath, Safety, TraitFn, TraitItem, TraitItemKind, TyKind, @@ -19,7 +17,7 @@ use rustc_middle::hir::nested_filter; use rustc_middle::ty::{self, Binder, ClauseKind, ExistentialPredicate, List, PredicateKind, Ty}; use rustc_session::declare_lint_pass; use rustc_span::symbol::Symbol; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; use rustc_target::spec::abi::Abi; use rustc_trait_selection::infer::InferCtxtExt as _; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _; @@ -34,7 +32,7 @@ declare_clippy_lint! { /// with the appropriate `.to_owned()`/`to_string()` calls. /// /// ### Why is this bad? - /// Requiring the argument to be of the specific size + /// Requiring the argument to be of the specific type /// makes the function less useful for no benefit; slices in the form of `&[T]` /// or `&str` usually suffice and can be obtained from other types, too. /// @@ -323,7 +321,6 @@ struct PtrArg<'tcx> { idx: usize, emission_id: HirId, span: Span, - ty_did: DefId, ty_name: Symbol, method_renames: &'static [(&'static str, &'static str)], ref_prefix: RefPrefix, @@ -411,7 +408,6 @@ impl<'tcx> DerefTy<'tcx> { } } -#[expect(clippy::too_many_lines)] fn check_fn_args<'cx, 'tcx: 'cx>( cx: &'cx LateContext<'tcx>, fn_sig: ty::FnSig<'tcx>, @@ -514,7 +510,6 @@ fn check_fn_args<'cx, 'tcx: 'cx>( idx: i, emission_id, span: hir_ty.span, - ty_did: adt.did(), ty_name: name.ident.name, method_renames, ref_prefix: RefPrefix { lt: *lt, mutability }, @@ -610,65 +605,50 @@ fn check_ptr_arg_usage<'tcx>(cx: &LateContext<'tcx>, body: &Body<'tcx>, args: &[ set_skip_flag(); } }, - Some((Node::Expr(e), child_id)) => match e.kind { - ExprKind::Call(f, expr_args) => { - let i = expr_args.iter().position(|arg| arg.hir_id == child_id).unwrap_or(0); - if expr_sig(self.cx, f).and_then(|sig| sig.input(i)).map_or(true, |ty| { - match *ty.skip_binder().peel_refs().kind() { - ty::Dynamic(preds, _, _) => !matches_preds(self.cx, args.deref_ty.ty(self.cx), preds), - ty::Param(_) => true, - ty::Adt(def, _) => def.did() == args.ty_did, - _ => false, - } - }) { - // Passed to a function taking the non-dereferenced type. - set_skip_flag(); - } - }, - ExprKind::MethodCall(name, self_arg, expr_args, _) => { - let i = iter::once(self_arg) - .chain(expr_args.iter()) - .position(|arg| arg.hir_id == child_id) - .unwrap_or(0); - if i == 0 { - // Check if the method can be renamed. - let name = name.ident.as_str(); - if let Some((_, replacement)) = args.method_renames.iter().find(|&&(x, _)| x == name) { - result.replacements.push(PtrArgReplacement { - expr_span: e.span, - self_span: self_arg.span, - replacement, - }); - return; - } - } + Some((Node::Expr(use_expr), child_id)) => { + if let ExprKind::Index(e, ..) = use_expr.kind + && e.hir_id == child_id + { + // Indexing works with both owned and its dereferenced type + return; + } - let Some(id) = self.cx.typeck_results().type_dependent_def_id(e.hir_id) else { - set_skip_flag(); + if let ExprKind::MethodCall(name, receiver, ..) = use_expr.kind + && receiver.hir_id == child_id + { + let name = name.ident.as_str(); + + // Check if the method can be renamed. + if let Some((_, replacement)) = args.method_renames.iter().find(|&&(x, _)| x == name) { + result.replacements.push(PtrArgReplacement { + expr_span: use_expr.span, + self_span: receiver.span, + replacement, + }); return; - }; - - match *self.cx.tcx.fn_sig(id).instantiate_identity().skip_binder().inputs()[i] - .peel_refs() - .kind() - { - ty::Dynamic(preds, _, _) if !matches_preds(self.cx, args.deref_ty.ty(self.cx), preds) => { - set_skip_flag(); - }, - ty::Param(_) => { - set_skip_flag(); - }, - // If the types match check for methods which exist on both types. e.g. `Vec::len` and - // `slice::len` - ty::Adt(def, _) if def.did() == args.ty_did && !is_allowed_vec_method(self.cx, e) => { - set_skip_flag(); - }, - _ => (), } - }, - // Indexing is fine for currently supported types. - ExprKind::Index(e, _, _) if e.hir_id == child_id => (), - _ => set_skip_flag(), + + // Some methods exist on both `[T]` and `Vec`, such as `len`, where the receiver type + // doesn't coerce to a slice and our adjusted type check below isn't enough, + // but it would still be valid to call with a slice + if is_allowed_vec_method(self.cx, use_expr) { + return; + } + } + + let deref_ty = args.deref_ty.ty(self.cx); + let adjusted_ty = self.cx.typeck_results().expr_ty_adjusted(e).peel_refs(); + if adjusted_ty == deref_ty { + return; + } + + if let ty::Dynamic(preds, ..) = adjusted_ty.kind() + && matches_preds(self.cx, deref_ty, preds) + { + return; + } + + set_skip_flag(); }, _ => set_skip_flag(), } diff --git a/clippy_lints/src/pub_underscore_fields.rs b/clippy_lints/src/pub_underscore_fields.rs index 77b707567e4..db03657c9af 100644 --- a/clippy_lints/src/pub_underscore_fields.rs +++ b/clippy_lints/src/pub_underscore_fields.rs @@ -1,5 +1,5 @@ -use clippy_config::types::PubUnderscoreFieldsBehaviour; use clippy_config::Conf; +use clippy_config::types::PubUnderscoreFieldsBehaviour; use clippy_utils::attrs::is_doc_hidden; use clippy_utils::diagnostics::span_lint_hir_and_then; use clippy_utils::is_path_lang_item; diff --git a/clippy_lints/src/question_mark.rs b/clippy_lints/src/question_mark.rs index e1e3ded2c79..aa9a9001afb 100644 --- a/clippy_lints/src/question_mark.rs +++ b/clippy_lints/src/question_mark.rs @@ -1,8 +1,8 @@ use crate::manual_let_else::MANUAL_LET_ELSE; use crate::question_mark_used::QUESTION_MARK_USED; +use clippy_config::Conf; use clippy_config::msrvs::Msrv; use clippy_config::types::MatchLintBehaviour; -use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::{implements_trait, is_type_diagnostic_item}; @@ -12,8 +12,8 @@ use clippy_utils::{ span_contains_comment, }; use rustc_errors::Applicability; -use rustc_hir::def::Res; use rustc_hir::LangItem::{self, OptionNone, OptionSome, ResultErr, ResultOk}; +use rustc_hir::def::Res; use rustc_hir::{ BindingMode, Block, Body, ByRef, Expr, ExprKind, LetStmt, Mutability, Node, PatKind, PathSegment, QPath, Stmt, StmtKind, diff --git a/clippy_lints/src/ranges.rs b/clippy_lints/src/ranges.rs index 81189fe517c..21cd3367262 100644 --- a/clippy_lints/src/ranges.rs +++ b/clippy_lints/src/ranges.rs @@ -1,8 +1,8 @@ -use clippy_config::msrvs::{self, Msrv}; use clippy_config::Conf; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::consts::{ConstEvalCtxt, Constant}; use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then}; -use clippy_utils::source::{snippet, snippet_with_applicability, SpanRangeExt}; +use clippy_utils::source::{SpanRangeExt, snippet, snippet_with_applicability}; use clippy_utils::sugg::Sugg; use clippy_utils::{get_parent_expr, higher, is_in_const_context, is_integer_const, path_to_local}; use rustc_ast::ast::RangeLimits; @@ -11,8 +11,8 @@ use rustc_hir::{BinOpKind, Expr, ExprKind, HirId}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_session::impl_lint_pass; -use rustc_span::source_map::Spanned; use rustc_span::Span; +use rustc_span::source_map::Spanned; use std::cmp::Ordering; declare_clippy_lint! { diff --git a/clippy_lints/src/rc_clone_in_vec_init.rs b/clippy_lints/src/rc_clone_in_vec_init.rs index d0b45b59526..e877f5d6ed4 100644 --- a/clippy_lints/src/rc_clone_in_vec_init.rs +++ b/clippy_lints/src/rc_clone_in_vec_init.rs @@ -8,7 +8,7 @@ use rustc_hir::{Expr, ExprKind, QPath, TyKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_session::declare_lint_pass; -use rustc_span::{sym, Span, Symbol}; +use rustc_span::{Span, Symbol, sym}; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/read_zero_byte_vec.rs b/clippy_lints/src/read_zero_byte_vec.rs index 7f4735c6a88..6bd68dd4109 100644 --- a/clippy_lints/src/read_zero_byte_vec.rs +++ b/clippy_lints/src/read_zero_byte_vec.rs @@ -1,13 +1,13 @@ use clippy_utils::diagnostics::{span_lint_hir, span_lint_hir_and_then}; use clippy_utils::get_enclosing_block; -use clippy_utils::higher::{get_vec_init_kind, VecInitKind}; +use clippy_utils::higher::{VecInitKind, get_vec_init_kind}; use clippy_utils::source::snippet; use hir::{Expr, ExprKind, HirId, LetStmt, PatKind, PathSegment, QPath, StmtKind}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::def::Res; -use rustc_hir::intravisit::{walk_expr, Visitor}; +use rustc_hir::intravisit::{Visitor, walk_expr}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; diff --git a/clippy_lints/src/redundant_clone.rs b/clippy_lints/src/redundant_clone.rs index 4e24ddad83a..b9e0106fc86 100644 --- a/clippy_lints/src/redundant_clone.rs +++ b/clippy_lints/src/redundant_clone.rs @@ -1,17 +1,17 @@ use clippy_utils::diagnostics::{span_lint_hir, span_lint_hir_and_then}; -use clippy_utils::mir::{visit_local_usage, LocalUsage, PossibleBorrowerMap}; +use clippy_utils::fn_has_unsatisfiable_preds; +use clippy_utils::mir::{LocalUsage, PossibleBorrowerMap, visit_local_usage}; use clippy_utils::source::SpanRangeExt; use clippy_utils::ty::{has_drop, is_copy, is_type_diagnostic_item, is_type_lang_item, walk_ptrs_ty_depth}; -use clippy_utils::fn_has_unsatisfiable_preds; use rustc_errors::Applicability; use rustc_hir::intravisit::FnKind; -use rustc_hir::{def_id, Body, FnDecl, LangItem}; +use rustc_hir::{Body, FnDecl, LangItem, def_id}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::mir; use rustc_middle::ty::{self, Ty}; use rustc_session::declare_lint_pass; use rustc_span::def_id::LocalDefId; -use rustc_span::{sym, BytePos, Span}; +use rustc_span::{BytePos, Span, sym}; macro_rules! unwrap_or_continue { ($x:expr) => { @@ -349,14 +349,10 @@ fn visit_clone_usage(cloned: mir::Local, clone: mir::Local, mir: &mir::Body<'_>, local_use_locs: _, local_consume_or_mutate_locs: clone_consume_or_mutate_locs, }, - )) = visit_local_usage( - &[cloned, clone], - mir, - mir::Location { - block: bb, - statement_index: mir.basic_blocks[bb].statements.len(), - }, - ) + )) = visit_local_usage(&[cloned, clone], mir, mir::Location { + block: bb, + statement_index: mir.basic_blocks[bb].statements.len(), + }) .map(|mut vec| (vec.remove(0), vec.remove(0))) { CloneUsage { diff --git a/clippy_lints/src/redundant_closure_call.rs b/clippy_lints/src/redundant_closure_call.rs index bad9b979203..6930a01d48b 100644 --- a/clippy_lints/src/redundant_closure_call.rs +++ b/clippy_lints/src/redundant_closure_call.rs @@ -6,7 +6,7 @@ use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::intravisit::{Visitor as HirVisitor, Visitor}; use rustc_hir::{ - intravisit as hir_visit, ClosureKind, CoroutineDesugaring, CoroutineKind, CoroutineSource, ExprKind, Node, + ClosureKind, CoroutineDesugaring, CoroutineKind, CoroutineSource, ExprKind, Node, intravisit as hir_visit, }; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::hir::nested_filter; diff --git a/clippy_lints/src/redundant_else.rs b/clippy_lints/src/redundant_else.rs index 3bdf13dbbea..6a1d40334e7 100644 --- a/clippy_lints/src/redundant_else.rs +++ b/clippy_lints/src/redundant_else.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_help; use rustc_ast::ast::{Block, Expr, ExprKind, Stmt, StmtKind}; -use rustc_ast::visit::{walk_expr, Visitor}; +use rustc_ast::visit::{Visitor, walk_expr}; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_session::declare_lint_pass; diff --git a/clippy_lints/src/redundant_field_names.rs b/clippy_lints/src/redundant_field_names.rs index 0e637538615..d0dbff081f9 100644 --- a/clippy_lints/src/redundant_field_names.rs +++ b/clippy_lints/src/redundant_field_names.rs @@ -1,5 +1,5 @@ -use clippy_config::msrvs::{self, Msrv}; use clippy_config::Conf; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_sugg; use rustc_ast::ast::{Expr, ExprKind}; use rustc_errors::Applicability; diff --git a/clippy_lints/src/redundant_locals.rs b/clippy_lints/src/redundant_locals.rs index d94ca5bc7ec..4f46ca3c715 100644 --- a/clippy_lints/src/redundant_locals.rs +++ b/clippy_lints/src/redundant_locals.rs @@ -9,8 +9,8 @@ use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::UpvarCapture; use rustc_session::declare_lint_pass; -use rustc_span::symbol::Ident; use rustc_span::DesugaringKind; +use rustc_span::symbol::Ident; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/redundant_static_lifetimes.rs b/clippy_lints/src/redundant_static_lifetimes.rs index d6e741dd974..b27bb2e78af 100644 --- a/clippy_lints/src/redundant_static_lifetimes.rs +++ b/clippy_lints/src/redundant_static_lifetimes.rs @@ -1,5 +1,5 @@ -use clippy_config::msrvs::{self, Msrv}; use clippy_config::Conf; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet; use rustc_ast::ast::{ConstItem, Item, ItemKind, StaticItem, Ty, TyKind}; diff --git a/clippy_lints/src/reference.rs b/clippy_lints/src/reference.rs index 2b4ef21fc48..4bff37216ed 100644 --- a/clippy_lints/src/reference.rs +++ b/clippy_lints/src/reference.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::{snippet_with_applicability, SpanRangeExt}; +use clippy_utils::source::{SpanRangeExt, snippet_with_applicability}; use rustc_ast::ast::{Expr, ExprKind, Mutability, UnOp}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; diff --git a/clippy_lints/src/regex.rs b/clippy_lints/src/regex.rs index f6ef02b7c23..12cbdb854ef 100644 --- a/clippy_lints/src/regex.rs +++ b/clippy_lints/src/regex.rs @@ -3,7 +3,7 @@ use std::fmt::Display; use clippy_utils::consts::{ConstEvalCtxt, Constant}; use clippy_utils::diagnostics::{span_lint, span_lint_and_help}; use clippy_utils::source::SpanRangeExt; -use clippy_utils::{def_path_def_ids, path_def_id, paths}; +use clippy_utils::{def_path_res_with_base, find_crates, path_def_id, paths}; use rustc_ast::ast::{LitKind, StrStyle}; use rustc_hir::def_id::DefIdMap; use rustc_hir::{BorrowKind, Expr, ExprKind}; @@ -75,11 +75,14 @@ impl<'tcx> LateLintPass<'tcx> for Regex { // We don't use `match_def_path` here because that relies on matching the exact path, which changed // between regex 1.8 and 1.9 // - // `def_path_def_ids` will resolve through re-exports but is relatively heavy, so we only perform - // the operation once and store the results - let mut resolve = |path, kind| { - for id in def_path_def_ids(cx.tcx, path) { - self.definitions.insert(id, kind); + // `def_path_res_with_base` will resolve through re-exports but is relatively heavy, so we only + // perform the operation once and store the results + let regex_crates = find_crates(cx.tcx, sym!(regex)); + let mut resolve = |path: &[&str], kind: RegexKind| { + for res in def_path_res_with_base(cx.tcx, regex_crates.clone(), &path[1..]) { + if let Some(id) = res.opt_def_id() { + self.definitions.insert(id, kind); + } } }; diff --git a/clippy_lints/src/repeat_vec_with_capacity.rs b/clippy_lints/src/repeat_vec_with_capacity.rs index 08de10f69b0..f54cafffb83 100644 --- a/clippy_lints/src/repeat_vec_with_capacity.rs +++ b/clippy_lints/src/repeat_vec_with_capacity.rs @@ -8,7 +8,7 @@ use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/reserve_after_initialization.rs b/clippy_lints/src/reserve_after_initialization.rs index caf3fb8707d..6157adad059 100644 --- a/clippy_lints/src/reserve_after_initialization.rs +++ b/clippy_lints/src/reserve_after_initialization.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::higher::{get_vec_init_kind, VecInitKind}; +use clippy_utils::higher::{VecInitKind, get_vec_init_kind}; use clippy_utils::source::snippet; use clippy_utils::{is_from_proc_macro, path_to_local_id}; use rustc_errors::Applicability; diff --git a/clippy_lints/src/return_self_not_must_use.rs b/clippy_lints/src/return_self_not_must_use.rs index 5962e8be959..42d9cf2c88c 100644 --- a/clippy_lints/src/return_self_not_must_use.rs +++ b/clippy_lints/src/return_self_not_must_use.rs @@ -7,7 +7,7 @@ use rustc_hir::{Body, FnDecl, OwnerId, TraitItem, TraitItemKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_session::declare_lint_pass; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/returns.rs b/clippy_lints/src/returns.rs index 5ce091b7a7a..3754fdddedf 100644 --- a/clippy_lints/src/returns.rs +++ b/clippy_lints/src/returns.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_hir_and_then}; -use clippy_utils::source::{snippet_with_context, SpanRangeExt}; +use clippy_utils::source::{SpanRangeExt, snippet_with_context}; use clippy_utils::sugg::has_enclosing_paren; -use clippy_utils::visitors::{for_each_expr, Descend}; +use clippy_utils::visitors::{Descend, for_each_expr, for_each_unconsumed_temporary}; use clippy_utils::{ binary_expr_needs_parentheses, fn_def_id, is_from_proc_macro, is_inside_let_else, is_res_lang_ctor, path_res, path_to_local_id, span_contains_cfg, span_find_starting_semi, @@ -9,8 +9,8 @@ use clippy_utils::{ use core::ops::ControlFlow; use rustc_ast::NestedMetaItem; use rustc_errors::Applicability; -use rustc_hir::intravisit::FnKind; use rustc_hir::LangItem::ResultErr; +use rustc_hir::intravisit::FnKind; use rustc_hir::{ Block, Body, Expr, ExprKind, FnDecl, HirId, ItemKind, LangItem, MatchSource, Node, OwnerNode, PatKind, QPath, Stmt, StmtKind, @@ -21,7 +21,7 @@ use rustc_middle::ty::adjustment::Adjust; use rustc_middle::ty::{self, GenericArgKind, Ty}; use rustc_session::declare_lint_pass; use rustc_span::def_id::LocalDefId; -use rustc_span::{sym, BytePos, Pos, Span}; +use rustc_span::{BytePos, Pos, Span, sym}; use std::borrow::Cow; use std::fmt::Display; @@ -389,10 +389,24 @@ fn check_final_expr<'tcx>( } }; - let borrows = inner.map_or(false, |inner| last_statement_borrows(cx, inner)); - if borrows { - return; + if let Some(inner) = inner { + if for_each_unconsumed_temporary(cx, inner, |temporary_ty| { + if temporary_ty.has_significant_drop(cx.tcx, cx.param_env) + && temporary_ty + .walk() + .any(|arg| matches!(arg.unpack(), GenericArgKind::Lifetime(re) if !re.is_static())) + { + ControlFlow::Break(()) + } else { + ControlFlow::Continue(()) + } + }) + .is_break() + { + return; + } } + if ret_span.from_expansion() { return; } diff --git a/clippy_lints/src/same_name_method.rs b/clippy_lints/src/same_name_method.rs index 508f3ae6def..8d31641d483 100644 --- a/clippy_lints/src/same_name_method.rs +++ b/clippy_lints/src/same_name_method.rs @@ -5,8 +5,8 @@ use rustc_hir::{HirId, Impl, ItemKind, Node, Path, QPath, TraitRef, TyKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::AssocKind; use rustc_session::declare_lint_pass; -use rustc_span::symbol::Symbol; use rustc_span::Span; +use rustc_span::symbol::Symbol; use std::collections::{BTreeMap, BTreeSet}; declare_clippy_lint! { @@ -62,13 +62,10 @@ impl<'tcx> LateLintPass<'tcx> for SameNameMethod { && let TyKind::Path(QPath::Resolved(_, Path { res, .. })) = self_ty.kind { if !map.contains_key(res) { - map.insert( - *res, - ExistingName { - impl_methods: BTreeMap::new(), - trait_methods: BTreeMap::new(), - }, - ); + map.insert(*res, ExistingName { + impl_methods: BTreeMap::new(), + trait_methods: BTreeMap::new(), + }); } let existing_name = map.get_mut(res).unwrap(); diff --git a/clippy_lints/src/set_contains_or_insert.rs b/clippy_lints/src/set_contains_or_insert.rs index e6fe7649397..1185d67b125 100644 --- a/clippy_lints/src/set_contains_or_insert.rs +++ b/clippy_lints/src/set_contains_or_insert.rs @@ -3,12 +3,12 @@ use std::ops::ControlFlow; use clippy_utils::diagnostics::span_lint; use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::visitors::for_each_expr; -use clippy_utils::{higher, peel_hir_expr_while, SpanlessEq}; +use clippy_utils::{SpanlessEq, higher, peel_hir_expr_while}; use rustc_hir::{Expr, ExprKind, UnOp}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; use rustc_span::symbol::Symbol; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; declare_clippy_lint! { /// ### What it does @@ -42,7 +42,7 @@ declare_clippy_lint! { /// println!("inserted {value:?}"); /// } /// ``` - #[clippy::version = "1.80.0"] + #[clippy::version = "1.81.0"] pub SET_CONTAINS_OR_INSERT, nursery, "call to `::contains` followed by `::insert`" diff --git a/clippy_lints/src/significant_drop_tightening.rs b/clippy_lints/src/significant_drop_tightening.rs index 979d6dc77ae..d1114cb29f7 100644 --- a/clippy_lints/src/significant_drop_tightening.rs +++ b/clippy_lints/src/significant_drop_tightening.rs @@ -4,13 +4,13 @@ use clippy_utils::{expr_or_init, get_attr, path_to_local, peel_hir_expr_unary}; use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::intravisit::{walk_expr, Visitor}; +use rustc_hir::intravisit::{Visitor, walk_expr}; use rustc_hir::{self as hir, HirId}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::ty::{GenericArgKind, Ty}; use rustc_session::impl_lint_pass; use rustc_span::symbol::Ident; -use rustc_span::{sym, Span, DUMMY_SP}; +use rustc_span::{DUMMY_SP, Span, sym}; use std::borrow::Cow; use std::collections::hash_map::Entry; diff --git a/clippy_lints/src/single_component_path_imports.rs b/clippy_lints/src/single_component_path_imports.rs index acf44a9bb5a..c986c3e8aa6 100644 --- a/clippy_lints/src/single_component_path_imports.rs +++ b/clippy_lints/src/single_component_path_imports.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg}; use rustc_ast::node_id::{NodeId, NodeMap}; use rustc_ast::ptr::P; -use rustc_ast::visit::{walk_expr, Visitor}; +use rustc_ast::visit::{Visitor, walk_expr}; use rustc_ast::{Crate, Expr, ExprKind, Item, ItemKind, MacroDef, ModKind, Ty, TyKind, UseTreeKind}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; diff --git a/clippy_lints/src/slow_vector_initialization.rs b/clippy_lints/src/slow_vector_initialization.rs index 04c16281ec4..5129bbf2665 100644 --- a/clippy_lints/src/slow_vector_initialization.rs +++ b/clippy_lints/src/slow_vector_initialization.rs @@ -2,11 +2,10 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::macros::matching_root_macro_call; use clippy_utils::sugg::Sugg; use clippy_utils::{ - get_enclosing_block, is_integer_literal, is_path_diagnostic_item, path_to_local, - path_to_local_id, SpanlessEq, + SpanlessEq, get_enclosing_block, is_integer_literal, is_path_diagnostic_item, path_to_local, path_to_local_id, }; use rustc_errors::Applicability; -use rustc_hir::intravisit::{walk_block, walk_expr, walk_stmt, Visitor}; +use rustc_hir::intravisit::{Visitor, walk_block, walk_expr, walk_stmt}; use rustc_hir::{BindingMode, Block, Expr, ExprKind, HirId, PatKind, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; diff --git a/clippy_lints/src/std_instead_of_core.rs b/clippy_lints/src/std_instead_of_core.rs index 44283a49e84..8dd99858793 100644 --- a/clippy_lints/src/std_instead_of_core.rs +++ b/clippy_lints/src/std_instead_of_core.rs @@ -1,5 +1,5 @@ -use clippy_config::msrvs::Msrv; use clippy_config::Conf; +use clippy_config::msrvs::Msrv; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::is_from_proc_macro; use rustc_attr::{StabilityLevel, StableSince}; @@ -11,7 +11,7 @@ use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_session::impl_lint_pass; use rustc_span::symbol::kw; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/string_patterns.rs b/clippy_lints/src/string_patterns.rs index 7e211d64da1..ba2ddac2ec3 100644 --- a/clippy_lints/src/string_patterns.rs +++ b/clippy_lints/src/string_patterns.rs @@ -1,13 +1,13 @@ use std::ops::ControlFlow; -use clippy_config::msrvs::{self, Msrv}; use clippy_config::Conf; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; use clippy_utils::eager_or_lazy::switch_to_eager_eval; use clippy_utils::macros::matching_root_macro_call; use clippy_utils::path_to_local_id; use clippy_utils::source::{snippet, str_literal_to_char_literal}; -use clippy_utils::visitors::{for_each_expr, Descend}; +use clippy_utils::visitors::{Descend, for_each_expr}; use itertools::Itertools; use rustc_ast::{BinOpKind, LitKind}; use rustc_errors::Applicability; @@ -15,7 +15,7 @@ use rustc_hir::{Expr, ExprKind, PatKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_session::impl_lint_pass; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; declare_clippy_lint! { /// ### What it does @@ -33,7 +33,7 @@ declare_clippy_lint! { /// ```no_run /// "Hello World!".trim_end_matches(['.', ',', '!', '?']); /// ``` - #[clippy::version = "1.80.0"] + #[clippy::version = "1.81.0"] pub MANUAL_PATTERN_CHAR_COMPARISON, style, "manual char comparison in string patterns" diff --git a/clippy_lints/src/strings.rs b/clippy_lints/src/strings.rs index 6ca4ca000e9..1fb82b66ab8 100644 --- a/clippy_lints/src/strings.rs +++ b/clippy_lints/src/strings.rs @@ -2,8 +2,8 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_the use clippy_utils::source::{snippet, snippet_with_applicability}; use clippy_utils::ty::is_type_lang_item; use clippy_utils::{ - get_expr_use_or_unification_node, get_parent_expr, is_lint_allowed, is_path_diagnostic_item, method_calls, - peel_blocks, SpanlessEq, + SpanlessEq, get_expr_use_or_unification_node, get_parent_expr, is_lint_allowed, is_path_diagnostic_item, + method_calls, peel_blocks, }; use rustc_errors::Applicability; use rustc_hir::def_id::DefId; diff --git a/clippy_lints/src/suspicious_operation_groupings.rs b/clippy_lints/src/suspicious_operation_groupings.rs index 1c1de805db0..be32dc0aab0 100644 --- a/clippy_lints/src/suspicious_operation_groupings.rs +++ b/clippy_lints/src/suspicious_operation_groupings.rs @@ -1,4 +1,4 @@ -use clippy_utils::ast_utils::{eq_id, is_useless_with_eq_exprs, IdentIter}; +use clippy_utils::ast_utils::{IdentIter, eq_id, is_useless_with_eq_exprs}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; use core::ops::{Add, AddAssign}; @@ -7,9 +7,9 @@ use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_session::declare_lint_pass; +use rustc_span::Span; use rustc_span::source_map::Spanned; use rustc_span::symbol::Ident; -use rustc_span::Span; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/suspicious_trait_impl.rs b/clippy_lints/src/suspicious_trait_impl.rs index 744d6392e06..e9779d437d4 100644 --- a/clippy_lints/src/suspicious_trait_impl.rs +++ b/clippy_lints/src/suspicious_trait_impl.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint; use clippy_utils::visitors::for_each_expr_without_closures; -use clippy_utils::{binop_traits, trait_ref_of_method, BINOP_TRAITS, OP_ASSIGN_TRAITS}; +use clippy_utils::{BINOP_TRAITS, OP_ASSIGN_TRAITS, binop_traits, trait_ref_of_method}; use core::ops::ControlFlow; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; diff --git a/clippy_lints/src/swap.rs b/clippy_lints/src/swap.rs index 197011cde3a..e05fa4095b8 100644 --- a/clippy_lints/src/swap.rs +++ b/clippy_lints/src/swap.rs @@ -6,7 +6,7 @@ use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::{can_mut_borrow_both, eq_expr_value, is_in_const_context, std_or_core}; use itertools::Itertools; -use rustc_hir::intravisit::{walk_expr, Visitor}; +use rustc_hir::intravisit::{Visitor, walk_expr}; use crate::FxHashSet; use rustc_errors::Applicability; @@ -17,7 +17,7 @@ use rustc_middle::ty; use rustc_session::declare_lint_pass; use rustc_span::source_map::Spanned; use rustc_span::symbol::Ident; -use rustc_span::{sym, Span, SyntaxContext}; +use rustc_span::{Span, SyntaxContext, sym}; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/swap_ptr_to_ref.rs b/clippy_lints/src/swap_ptr_to_ref.rs index 20e9608a15d..8c5cf93ab6e 100644 --- a/clippy_lints/src/swap_ptr_to_ref.rs +++ b/clippy_lints/src/swap_ptr_to_ref.rs @@ -5,7 +5,7 @@ use rustc_errors::Applicability; use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability, UnOp}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; -use rustc_span::{sym, Span, SyntaxContext}; +use rustc_span::{Span, SyntaxContext, sym}; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/tests_outside_test_module.rs b/clippy_lints/src/tests_outside_test_module.rs index 25d0a16e2ab..3cd4fefffad 100644 --- a/clippy_lints/src/tests_outside_test_module.rs +++ b/clippy_lints/src/tests_outside_test_module.rs @@ -4,8 +4,8 @@ use rustc_hir::intravisit::FnKind; use rustc_hir::{Body, FnDecl}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; -use rustc_span::def_id::LocalDefId; use rustc_span::Span; +use rustc_span::def_id::LocalDefId; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/to_digit_is_some.rs b/clippy_lints/src/to_digit_is_some.rs index dafe9e38818..4f96a566b63 100644 --- a/clippy_lints/src/to_digit_is_some.rs +++ b/clippy_lints/src/to_digit_is_some.rs @@ -56,11 +56,13 @@ impl<'tcx> LateLintPass<'tcx> for ToDigitIsSome { && let hir::ExprKind::Path(to_digits_path) = &to_digits_call.kind && let to_digits_call_res = cx.qpath_res(to_digits_path, to_digits_call.hir_id) && let Some(to_digits_def_id) = to_digits_call_res.opt_def_id() - && match_def_path( - cx, - to_digits_def_id, - &["core", "char", "methods", "", "to_digit"], - ) + && match_def_path(cx, to_digits_def_id, &[ + "core", + "char", + "methods", + "", + "to_digit", + ]) { Some((false, char_arg, radix_arg)) } else { diff --git a/clippy_lints/src/trait_bounds.rs b/clippy_lints/src/trait_bounds.rs index 2e87d36df31..00277593622 100644 --- a/clippy_lints/src/trait_bounds.rs +++ b/clippy_lints/src/trait_bounds.rs @@ -1,8 +1,8 @@ -use clippy_config::msrvs::{self, Msrv}; use clippy_config::Conf; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg}; -use clippy_utils::source::{snippet, snippet_with_applicability, SpanRangeExt}; -use clippy_utils::{is_from_proc_macro, SpanlessEq, SpanlessHash}; +use clippy_utils::source::{SpanRangeExt, snippet, snippet_with_applicability}; +use clippy_utils::{SpanlessEq, SpanlessHash, is_from_proc_macro}; use core::hash::{Hash, Hasher}; use itertools::Itertools; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; diff --git a/clippy_lints/src/transmute/mod.rs b/clippy_lints/src/transmute/mod.rs index da7906b1183..25fec9f688c 100644 --- a/clippy_lints/src/transmute/mod.rs +++ b/clippy_lints/src/transmute/mod.rs @@ -19,8 +19,8 @@ mod useless_transmute; mod utils; mod wrong_transmute; -use clippy_config::msrvs::Msrv; use clippy_config::Conf; +use clippy_config::msrvs::Msrv; use clippy_utils::is_in_const_context; use rustc_hir::{Expr, ExprKind, QPath}; use rustc_lint::{LateContext, LateLintPass}; @@ -527,24 +527,44 @@ declare_clippy_lint! { /// Checks if transmute calls have all generics specified. /// /// ### Why is this bad? - /// If not set, some unexpected output type could be retrieved instead of the expected one, - /// potentially leading to invalid code. + /// If not, one or more unexpected types could be used during `transmute()`, potentially leading + /// to Undefined Behavior or other problems. /// - /// This is particularly dangerous in case a seemingly innocent/unrelated change can cause type - /// inference to start inferring a different type. E.g. the transmute is the tail expression of - /// an `if` branch, and a different branches type changes, causing the transmute to silently - /// have a different type, instead of a proper error. + /// This is particularly dangerous in case a seemingly innocent/unrelated change causes type + /// inference to result in a different type. For example, if `transmute()` is the tail + /// expression of an `if`-branch, and the `else`-branch type changes, the compiler may silently + /// infer a different type to be returned by `transmute()`. That is because the compiler is + /// free to change the inference of a type as long as that inference is technically correct, + /// regardless of the programmer's unknown expectation. + /// + /// Both type-parameters, the input- and the output-type, to any `transmute()` should + /// be given explicitly: Setting the input-type explicitly avoids confusion about what the + /// argument's type actually is. Setting the output-type explicitly avoids type-inference + /// to infer a technically correct yet unexpected type. /// /// ### Example /// ```no_run /// # unsafe { + /// // Avoid "naked" calls to `transmute()`! /// let x: i32 = std::mem::transmute([1u16, 2u16]); + /// + /// // `first_answers` is intended to transmute a slice of bool to a slice of u8. + /// // But the programmer forgot to index the first element of the outer slice, + /// // so we are actually transmuting from "pointers to slices" instead of + /// // transmuting from "a slice of bool", causing a nonsensical result. + /// let the_answers: &[&[bool]] = &[&[true, false, true]]; + /// let first_answers: &[u8] = std::mem::transmute(the_answers); /// # } /// ``` /// Use instead: /// ```no_run /// # unsafe { /// let x = std::mem::transmute::<[u16; 2], i32>([1u16, 2u16]); + /// + /// // The explicit type parameters on `transmute()` makes the intention clear, + /// // and cause a type-error if the actual types don't match our expectation. + /// let the_answers: &[&[bool]] = &[&[true, false, true]]; + /// let first_answers: &[u8] = std::mem::transmute::<&[bool], &[u8]>(the_answers[0]); /// # } /// ``` #[clippy::version = "1.79.0"] diff --git a/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs b/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs index ba8c7d6bfcb..fca332dba40 100644 --- a/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs +++ b/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs @@ -6,8 +6,8 @@ use rustc_errors::Applicability; use rustc_hir::{Expr, Node}; use rustc_hir_typeck::cast::check_cast; use rustc_lint::LateContext; -use rustc_middle::ty::cast::CastKind; use rustc_middle::ty::Ty; +use rustc_middle::ty::cast::CastKind; /// Checks for `transmutes_expressible_as_ptr_casts` lint. /// Returns `true` if it's triggered, otherwise returns `false`. diff --git a/clippy_lints/src/transmute/unsound_collection_transmute.rs b/clippy_lints/src/transmute/unsound_collection_transmute.rs index 35e93830766..f46e95b0b83 100644 --- a/clippy_lints/src/transmute/unsound_collection_transmute.rs +++ b/clippy_lints/src/transmute/unsound_collection_transmute.rs @@ -1,5 +1,5 @@ -use super::utils::is_layout_incompatible; use super::UNSOUND_COLLECTION_TRANSMUTE; +use super::utils::is_layout_incompatible; use clippy_utils::diagnostics::span_lint; use rustc_hir::Expr; use rustc_lint::LateContext; diff --git a/clippy_lints/src/tuple_array_conversions.rs b/clippy_lints/src/tuple_array_conversions.rs index 1d0de932754..3da8a449a7c 100644 --- a/clippy_lints/src/tuple_array_conversions.rs +++ b/clippy_lints/src/tuple_array_conversions.rs @@ -1,5 +1,5 @@ -use clippy_config::msrvs::{self, Msrv}; use clippy_config::Conf; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::visitors::for_each_local_use_after_expr; use clippy_utils::{is_from_proc_macro, path_to_local}; diff --git a/clippy_lints/src/types/box_collection.rs b/clippy_lints/src/types/box_collection.rs index 9ac73394548..24fe4e08a5b 100644 --- a/clippy_lints/src/types/box_collection.rs +++ b/clippy_lints/src/types/box_collection.rs @@ -3,7 +3,7 @@ use clippy_utils::{path_def_id, qpath_generic_tys}; use rustc_hir::def_id::DefId; use rustc_hir::{self as hir, QPath}; use rustc_lint::LateContext; -use rustc_span::{sym, Symbol}; +use rustc_span::{Symbol, sym}; use super::BOX_COLLECTION; diff --git a/clippy_lints/src/types/mod.rs b/clippy_lints/src/types/mod.rs index 3a14927802b..363aea8be72 100644 --- a/clippy_lints/src/types/mod.rs +++ b/clippy_lints/src/types/mod.rs @@ -18,8 +18,8 @@ use rustc_hir::{ }; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::impl_lint_pass; -use rustc_span::def_id::LocalDefId; use rustc_span::Span; +use rustc_span::def_id::LocalDefId; declare_clippy_lint! { /// ### What it does @@ -261,8 +261,59 @@ declare_clippy_lint! { /// ### Example /// ```no_run /// # use std::rc::Rc; - /// struct Foo { - /// inner: Rc>>>, + /// struct PointMatrixContainer { + /// matrix: Rc>>>, + /// } + /// + /// fn main() { + /// let point_matrix: Vec>> = vec![ + /// vec![ + /// Box::new((1, 2, 3, 4)), + /// Box::new((5, 6, 7, 8)), + /// ], + /// vec![ + /// Box::new((9, 10, 11, 12)), + /// ], + /// ]; + /// + /// let shared_point_matrix: Rc>>> = Rc::new(point_matrix); + /// + /// let container = PointMatrixContainer { + /// matrix: shared_point_matrix, + /// }; + /// + /// // ... + /// } + /// ``` + /// Use instead: + /// ### Example + /// ```no_run + /// # use std::rc::Rc; + /// type PointMatrix = Vec>>; + /// type SharedPointMatrix = Rc; + /// + /// struct PointMatrixContainer { + /// matrix: SharedPointMatrix, + /// } + /// + /// fn main() { + /// let point_matrix: PointMatrix = vec![ + /// vec![ + /// Box::new((1, 2, 3, 4)), + /// Box::new((5, 6, 7, 8)), + /// ], + /// vec![ + /// Box::new((9, 10, 11, 12)), + /// ], + /// ]; + /// + /// let shared_point_matrix: SharedPointMatrix = Rc::new(point_matrix); + /// + /// let container = PointMatrixContainer { + /// matrix: shared_point_matrix, + /// }; + /// + /// // ... /// } /// ``` #[clippy::version = "pre 1.29.0"] @@ -335,30 +386,22 @@ impl<'tcx> LateLintPass<'tcx> for Types { let is_exported = cx.effective_visibilities.is_exported(def_id); - self.check_fn_decl( - cx, - decl, - CheckTyContext { - is_in_trait_impl, - is_exported, - in_body: matches!(fn_kind, FnKind::Closure), - ..CheckTyContext::default() - }, - ); + self.check_fn_decl(cx, decl, CheckTyContext { + is_in_trait_impl, + is_exported, + in_body: matches!(fn_kind, FnKind::Closure), + ..CheckTyContext::default() + }); } fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) { let is_exported = cx.effective_visibilities.is_exported(item.owner_id.def_id); match item.kind { - ItemKind::Static(ty, _, _) | ItemKind::Const(ty, _, _) => self.check_ty( - cx, - ty, - CheckTyContext { - is_exported, - ..CheckTyContext::default() - }, - ), + ItemKind::Static(ty, _, _) | ItemKind::Const(ty, _, _) => self.check_ty(cx, ty, CheckTyContext { + is_exported, + ..CheckTyContext::default() + }), // functions, enums, structs, impls and traits are covered _ => (), } @@ -376,14 +419,10 @@ impl<'tcx> LateLintPass<'tcx> for Types { false }; - self.check_ty( - cx, - ty, - CheckTyContext { - is_in_trait_impl, - ..CheckTyContext::default() - }, - ); + self.check_ty(cx, ty, CheckTyContext { + is_in_trait_impl, + ..CheckTyContext::default() + }); }, // Methods are covered by check_fn. // Type aliases are ignored because oftentimes it's impossible to @@ -399,14 +438,10 @@ impl<'tcx> LateLintPass<'tcx> for Types { let is_exported = cx.effective_visibilities.is_exported(field.def_id); - self.check_ty( - cx, - field.ty, - CheckTyContext { - is_exported, - ..CheckTyContext::default() - }, - ); + self.check_ty(cx, field.ty, CheckTyContext { + is_exported, + ..CheckTyContext::default() + }); } fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &TraitItem<'tcx>) { @@ -434,14 +469,10 @@ impl<'tcx> LateLintPass<'tcx> for Types { fn check_local(&mut self, cx: &LateContext<'tcx>, local: &LetStmt<'tcx>) { if let Some(ty) = local.ty { - self.check_ty( - cx, - ty, - CheckTyContext { - in_body: true, - ..CheckTyContext::default() - }, - ); + self.check_ty(cx, ty, CheckTyContext { + in_body: true, + ..CheckTyContext::default() + }); } } } diff --git a/clippy_lints/src/types/redundant_allocation.rs b/clippy_lints/src/types/redundant_allocation.rs index 0801eace4fc..1a656088b17 100644 --- a/clippy_lints/src/types/redundant_allocation.rs +++ b/clippy_lints/src/types/redundant_allocation.rs @@ -9,7 +9,7 @@ use rustc_lint::LateContext; use rustc_middle::ty::TypeVisitableExt; use rustc_span::symbol::sym; -use super::{utils, REDUNDANT_ALLOCATION}; +use super::{REDUNDANT_ALLOCATION, utils}; pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, hir_ty: &hir::Ty<'tcx>, qpath: &QPath<'tcx>, def_id: DefId) -> bool { let mut applicability = Applicability::MaybeIncorrect; diff --git a/clippy_lints/src/types/type_complexity.rs b/clippy_lints/src/types/type_complexity.rs index 7fcfd5c8f35..0b64fddb447 100644 --- a/clippy_lints/src/types/type_complexity.rs +++ b/clippy_lints/src/types/type_complexity.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint; use rustc_hir as hir; -use rustc_hir::intravisit::{walk_inf, walk_ty, Visitor}; +use rustc_hir::intravisit::{Visitor, walk_inf, walk_ty}; use rustc_hir::{GenericParamKind, TyKind}; use rustc_lint::LateContext; use rustc_target::spec::abi::Abi; diff --git a/clippy_lints/src/types/vec_box.rs b/clippy_lints/src/types/vec_box.rs index 29996a6f783..230239335c6 100644 --- a/clippy_lints/src/types/vec_box.rs +++ b/clippy_lints/src/types/vec_box.rs @@ -6,8 +6,8 @@ use rustc_hir::def_id::DefId; use rustc_hir::{self as hir, GenericArg, LangItem, QPath, TyKind}; use rustc_hir_analysis::lower_ty; use rustc_lint::LateContext; -use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::TypeVisitableExt; +use rustc_middle::ty::layout::LayoutOf; use rustc_span::symbol::sym; use super::VEC_BOX; diff --git a/clippy_lints/src/unconditional_recursion.rs b/clippy_lints/src/unconditional_recursion.rs index 42100e1d755..3fc08e8192d 100644 --- a/clippy_lints/src/unconditional_recursion.rs +++ b/clippy_lints/src/unconditional_recursion.rs @@ -5,7 +5,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, LocalDefId}; -use rustc_hir::intravisit::{walk_body, walk_expr, FnKind, Visitor}; +use rustc_hir::intravisit::{FnKind, Visitor, walk_body, walk_expr}; use rustc_hir::{Body, Expr, ExprKind, FnDecl, HirId, Item, ItemKind, Node, QPath, TyKind}; use rustc_hir_analysis::lower_ty; use rustc_lint::{LateContext, LateLintPass}; @@ -13,8 +13,8 @@ use rustc_middle::hir::map::Map; use rustc_middle::hir::nested_filter; use rustc_middle::ty::{self, AssocKind, Ty, TyCtxt}; use rustc_session::impl_lint_pass; -use rustc_span::symbol::{kw, Ident}; -use rustc_span::{sym, Span}; +use rustc_span::symbol::{Ident, kw}; +use rustc_span::{Span, sym}; use rustc_trait_selection::error_reporting::traits::suggestions::ReturnsVisitor; use std::ops::ControlFlow; @@ -257,13 +257,10 @@ fn is_default_method_on_current_ty<'tcx>(tcx: TyCtxt<'tcx>, qpath: QPath<'tcx>, } if matches!( ty.kind, - TyKind::Path(QPath::Resolved( - _, - hir::Path { - res: Res::SelfTyAlias { .. }, - .. - }, - )) + TyKind::Path(QPath::Resolved(_, hir::Path { + res: Res::SelfTyAlias { .. }, + .. + },)) ) { return true; } diff --git a/clippy_lints/src/undocumented_unsafe_blocks.rs b/clippy_lints/src/undocumented_unsafe_blocks.rs index f51c5f74d99..44eb0a6c593 100644 --- a/clippy_lints/src/undocumented_unsafe_blocks.rs +++ b/clippy_lints/src/undocumented_unsafe_blocks.rs @@ -4,12 +4,12 @@ use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::is_lint_allowed; use clippy_utils::source::walk_span_to_context; -use clippy_utils::visitors::{for_each_expr, Descend}; +use clippy_utils::visitors::{Descend, for_each_expr}; use hir::HirId; use rustc_data_structures::sync::Lrc; use rustc_hir as hir; use rustc_hir::{Block, BlockCheckMode, ItemKind, Node, UnsafeSource}; -use rustc_lexer::{tokenize, TokenKind}; +use rustc_lexer::{TokenKind, tokenize}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_session::impl_lint_pass; diff --git a/clippy_lints/src/uninhabited_references.rs b/clippy_lints/src/uninhabited_references.rs index 88039372ebd..cfa565cf803 100644 --- a/clippy_lints/src/uninhabited_references.rs +++ b/clippy_lints/src/uninhabited_references.rs @@ -5,8 +5,8 @@ use rustc_hir_analysis::lower_ty; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::lint::in_external_macro; use rustc_session::declare_lint_pass; -use rustc_span::def_id::LocalDefId; use rustc_span::Span; +use rustc_span::def_id::LocalDefId; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/uninit_vec.rs b/clippy_lints/src/uninit_vec.rs index 9ffcfcc0f50..93ed15777e0 100644 --- a/clippy_lints/src/uninit_vec.rs +++ b/clippy_lints/src/uninit_vec.rs @@ -1,13 +1,13 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; -use clippy_utils::higher::{get_vec_init_kind, VecInitKind}; +use clippy_utils::higher::{VecInitKind, get_vec_init_kind}; use clippy_utils::ty::{is_type_diagnostic_item, is_uninit_value_valid_for_ty}; -use clippy_utils::{is_integer_literal, is_lint_allowed, path_to_local_id, peel_hir_expr_while, SpanlessEq}; +use clippy_utils::{SpanlessEq, is_integer_literal, is_lint_allowed, path_to_local_id, peel_hir_expr_while}; use rustc_hir::{Block, Expr, ExprKind, HirId, PatKind, PathSegment, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty; use rustc_session::declare_lint_pass; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; // TODO: add `ReadBuf` (RFC 2930) in "How to fix" once it is available in std declare_clippy_lint! { diff --git a/clippy_lints/src/unit_return_expecting_ord.rs b/clippy_lints/src/unit_return_expecting_ord.rs index a8cc2f97963..87478a120dd 100644 --- a/clippy_lints/src/unit_return_expecting_ord.rs +++ b/clippy_lints/src/unit_return_expecting_ord.rs @@ -5,7 +5,7 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_middle::ty::{ClauseKind, GenericPredicates, ProjectionPredicate, TraitPredicate}; use rustc_session::declare_lint_pass; -use rustc_span::{sym, BytePos, Span}; +use rustc_span::{BytePos, Span, sym}; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/unit_types/let_unit_value.rs b/clippy_lints/src/unit_types/let_unit_value.rs index 80b661a757c..bf2d75ea1a9 100644 --- a/clippy_lints/src/unit_types/let_unit_value.rs +++ b/clippy_lints/src/unit_types/let_unit_value.rs @@ -4,7 +4,7 @@ use clippy_utils::visitors::{for_each_local_assignment, for_each_value_source, i use core::ops::ControlFlow; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::intravisit::{walk_body, Visitor}; +use rustc_hir::intravisit::{Visitor, walk_body}; use rustc_hir::{Expr, ExprKind, HirId, HirIdSet, LetStmt, MatchSource, Node, PatKind, QPath, TyKind}; use rustc_lint::{LateContext, LintContext}; use rustc_middle::lint::{in_external_macro, is_from_async_await}; diff --git a/clippy_lints/src/unit_types/unit_arg.rs b/clippy_lints/src/unit_types/unit_arg.rs index 978d49f09c3..41b2ca5d268 100644 --- a/clippy_lints/src/unit_types/unit_arg.rs +++ b/clippy_lints/src/unit_types/unit_arg.rs @@ -1,11 +1,11 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::is_from_proc_macro; -use clippy_utils::source::{indent_of, reindent_multiline, SourceText, SpanRangeExt}; +use clippy_utils::source::{SourceText, SpanRangeExt, indent_of, reindent_multiline}; use rustc_errors::Applicability; use rustc_hir::{Block, Expr, ExprKind, MatchSource, Node, StmtKind}; use rustc_lint::LateContext; -use super::{utils, UNIT_ARG}; +use super::{UNIT_ARG, utils}; pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { if expr.span.from_expansion() { diff --git a/clippy_lints/src/unnecessary_wraps.rs b/clippy_lints/src/unnecessary_wraps.rs index 080efe983c2..937e35dea96 100644 --- a/clippy_lints/src/unnecessary_wraps.rs +++ b/clippy_lints/src/unnecessary_wraps.rs @@ -4,15 +4,15 @@ use clippy_utils::source::snippet; use clippy_utils::visitors::find_all_ret_expressions; use clippy_utils::{contains_return, is_res_lang_ctor, path_res, return_ty}; use rustc_errors::Applicability; -use rustc_hir::intravisit::FnKind; use rustc_hir::LangItem::{OptionSome, ResultOk}; +use rustc_hir::intravisit::FnKind; use rustc_hir::{Body, ExprKind, FnDecl, Impl, ItemKind, Node}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_session::impl_lint_pass; +use rustc_span::Span; use rustc_span::def_id::LocalDefId; use rustc_span::symbol::sym; -use rustc_span::Span; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/unnested_or_patterns.rs b/clippy_lints/src/unnested_or_patterns.rs index 98f0be3135d..104be63bb15 100644 --- a/clippy_lints/src/unnested_or_patterns.rs +++ b/clippy_lints/src/unnested_or_patterns.rs @@ -1,14 +1,14 @@ #![allow(clippy::wildcard_imports, clippy::enum_glob_use)] -use clippy_config::msrvs::{self, Msrv}; use clippy_config::Conf; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::ast_utils::{eq_field_pat, eq_id, eq_maybe_qself, eq_pat, eq_path}; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::over; +use rustc_ast::PatKind::*; use rustc_ast::mut_visit::*; use rustc_ast::ptr::P; -use rustc_ast::PatKind::*; -use rustc_ast::{self as ast, Mutability, Pat, PatKind, DUMMY_NODE_ID}; +use rustc_ast::{self as ast, DUMMY_NODE_ID, Mutability, Pat, PatKind}; use rustc_ast_pretty::pprust; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; @@ -16,7 +16,7 @@ use rustc_session::impl_lint_pass; use rustc_span::DUMMY_SP; use std::cell::Cell; use std::mem; -use thin_vec::{thin_vec, ThinVec}; +use thin_vec::{ThinVec, thin_vec}; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/unsafe_removed_from_name.rs b/clippy_lints/src/unsafe_removed_from_name.rs index 309eaedac8d..e70d2a2dafe 100644 --- a/clippy_lints/src/unsafe_removed_from_name.rs +++ b/clippy_lints/src/unsafe_removed_from_name.rs @@ -2,8 +2,8 @@ use clippy_utils::diagnostics::span_lint; use rustc_ast::ast::{Item, ItemKind, UseTree, UseTreeKind}; use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_session::declare_lint_pass; -use rustc_span::symbol::Ident; use rustc_span::Span; +use rustc_span::symbol::Ident; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/unused_async.rs b/clippy_lints/src/unused_async.rs index 738fba54fa8..a1f08cf6623 100644 --- a/clippy_lints/src/unused_async.rs +++ b/clippy_lints/src/unused_async.rs @@ -1,13 +1,13 @@ use clippy_utils::diagnostics::span_lint_hir_and_then; use clippy_utils::is_def_id_trait_method; use rustc_hir::def::DefKind; -use rustc_hir::intravisit::{walk_expr, walk_fn, FnKind, Visitor}; +use rustc_hir::intravisit::{FnKind, Visitor, walk_expr, walk_fn}; use rustc_hir::{Body, Expr, ExprKind, FnDecl, Node, YieldSource}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::nested_filter; use rustc_session::impl_lint_pass; -use rustc_span::def_id::{LocalDefId, LocalDefIdSet}; use rustc_span::Span; +use rustc_span::def_id::{LocalDefId, LocalDefIdSet}; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/unused_io_amount.rs b/clippy_lints/src/unused_io_amount.rs index af7abd009d2..d2a21b11ef4 100644 --- a/clippy_lints/src/unused_io_amount.rs +++ b/clippy_lints/src/unused_io_amount.rs @@ -5,7 +5,7 @@ use hir::{ExprKind, HirId, PatKind}; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/unused_peekable.rs b/clippy_lints/src/unused_peekable.rs index 86a811e17ca..71aa57e0a14 100644 --- a/clippy_lints/src/unused_peekable.rs +++ b/clippy_lints/src/unused_peekable.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_hir_and_then; use clippy_utils::ty::{is_type_diagnostic_item, peel_mid_ty_refs_is_mutable}; use clippy_utils::{fn_def_id, is_trait_method, path_to_local_id, peel_ref_operators}; use rustc_ast::Mutability; -use rustc_hir::intravisit::{walk_expr, Visitor}; +use rustc_hir::intravisit::{Visitor, walk_expr}; use rustc_hir::{Block, Expr, ExprKind, HirId, LetStmt, Node, PatKind, PathSegment, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::nested_filter::OnlyBodies; diff --git a/clippy_lints/src/unused_trait_names.rs b/clippy_lints/src/unused_trait_names.rs new file mode 100644 index 00000000000..9fd6ebccd02 --- /dev/null +++ b/clippy_lints/src/unused_trait_names.rs @@ -0,0 +1,94 @@ +use clippy_config::Conf; +use clippy_config::msrvs::{self, Msrv}; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::is_from_proc_macro; +use clippy_utils::source::snippet_opt; +use rustc_errors::Applicability; +use rustc_hir::def::{DefKind, Res}; +use rustc_hir::{Item, ItemKind, UseKind}; +use rustc_lint::{LateContext, LateLintPass, LintContext as _}; +use rustc_middle::lint::in_external_macro; +use rustc_middle::ty::Visibility; +use rustc_session::impl_lint_pass; +use rustc_span::symbol::kw; + +declare_clippy_lint! { + /// ### What it does + /// Checks for `use Trait` where the Trait is only used for its methods and not referenced by a path directly. + /// + /// ### Why is this bad? + /// Traits imported that aren't used directly can be imported anonymously with `use Trait as _`. + /// It is more explicit, avoids polluting the current scope with unused names and can be useful to show which imports are required for traits. + /// + /// ### Example + /// ```no_run + /// use std::fmt::Write; + /// + /// fn main() { + /// let mut s = String::new(); + /// let _ = write!(s, "hello, world!"); + /// println!("{s}"); + /// } + /// ``` + /// Use instead: + /// ```no_run + /// use std::fmt::Write as _; + /// + /// fn main() { + /// let mut s = String::new(); + /// let _ = write!(s, "hello, world!"); + /// println!("{s}"); + /// } + /// ``` + #[clippy::version = "1.83.0"] + pub UNUSED_TRAIT_NAMES, + restriction, + "use items that import a trait but only use it anonymously" +} + +pub struct UnusedTraitNames { + msrv: Msrv, +} + +impl UnusedTraitNames { + pub fn new(conf: &'static Conf) -> Self { + Self { + msrv: conf.msrv.clone(), + } + } +} + +impl_lint_pass!(UnusedTraitNames => [UNUSED_TRAIT_NAMES]); + +impl<'tcx> LateLintPass<'tcx> for UnusedTraitNames { + fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) { + if self.msrv.meets(msrvs::UNDERSCORE_IMPORTS) + && !in_external_macro(cx.sess(), item.span) + && let ItemKind::Use(path, UseKind::Single) = item.kind + // Ignore imports that already use Underscore + && item.ident.name != kw::Underscore + // Only check traits + && let Some(Res::Def(DefKind::Trait, _)) = path.res.first() + && cx.tcx.maybe_unused_trait_imports(()).contains(&item.owner_id.def_id) + // Only check this import if it is visible to its module only (no pub, pub(crate), ...) + && let module = cx.tcx.parent_module_from_def_id(item.owner_id.def_id) + && cx.tcx.visibility(item.owner_id.def_id) == Visibility::Restricted(module.to_def_id()) + && let Some(last_segment) = path.segments.last() + && let Some(snip) = snippet_opt(cx, last_segment.ident.span) + && !is_from_proc_macro(cx, &last_segment.ident) + { + let complete_span = last_segment.ident.span.to(item.ident.span); + span_lint_and_sugg( + cx, + UNUSED_TRAIT_NAMES, + complete_span, + "importing trait that is only used anonymously", + "use", + format!("{snip} as _"), + Applicability::MachineApplicable, + ); + } + } + + extract_msrv_attr!(LateContext); +} diff --git a/clippy_lints/src/unused_unit.rs b/clippy_lints/src/unused_unit.rs index 65f431d338b..d5309aade7a 100644 --- a/clippy_lints/src/unused_unit.rs +++ b/clippy_lints/src/unused_unit.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::{position_before_rarrow, SpanRangeExt}; +use clippy_utils::source::{SpanRangeExt, position_before_rarrow}; use rustc_ast::visit::FnKind; -use rustc_ast::{ast, ClosureBinder}; +use rustc_ast::{ClosureBinder, ast}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_session::declare_lint_pass; diff --git a/clippy_lints/src/unwrap.rs b/clippy_lints/src/unwrap.rs index 0b4ea0752b6..596f0fd9c8b 100644 --- a/clippy_lints/src/unwrap.rs +++ b/clippy_lints/src/unwrap.rs @@ -3,7 +3,7 @@ use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::usage::is_potentially_local_place; use clippy_utils::{higher, path_to_local}; use rustc_errors::Applicability; -use rustc_hir::intravisit::{walk_expr, walk_fn, FnKind, Visitor}; +use rustc_hir::intravisit::{FnKind, Visitor, walk_expr, walk_fn}; use rustc_hir::{BinOpKind, Body, Expr, ExprKind, FnDecl, HirId, Node, PathSegment, UnOp}; use rustc_hir_typeck::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceWithHirId}; use rustc_lint::{LateContext, LateLintPass}; @@ -13,7 +13,7 @@ use rustc_middle::mir::FakeReadCause; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_session::declare_lint_pass; use rustc_span::def_id::LocalDefId; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/unwrap_in_result.rs b/clippy_lints/src/unwrap_in_result.rs index f77badd97b7..9b9a2ffbbc8 100644 --- a/clippy_lints/src/unwrap_in_result.rs +++ b/clippy_lints/src/unwrap_in_result.rs @@ -7,7 +7,7 @@ use rustc_hir as hir; use rustc_hir::ImplItemKind; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/use_self.rs b/clippy_lints/src/use_self.rs index 5da48f4f7fb..e340b419bd0 100644 --- a/clippy_lints/src/use_self.rs +++ b/clippy_lints/src/use_self.rs @@ -1,5 +1,5 @@ -use clippy_config::msrvs::{self, Msrv}; use clippy_config::Conf; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::is_from_proc_macro; use clippy_utils::ty::same_type_and_consts; @@ -7,7 +7,7 @@ use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; use rustc_hir::def::{CtorOf, DefKind, Res}; use rustc_hir::def_id::LocalDefId; -use rustc_hir::intravisit::{walk_inf, walk_ty, Visitor}; +use rustc_hir::intravisit::{Visitor, walk_inf, walk_ty}; use rustc_hir::{ self as hir, Expr, ExprKind, FnRetTy, FnSig, GenericArgsParentheses, GenericParam, GenericParamKind, HirId, Impl, ImplItemKind, Item, ItemKind, Pat, PatKind, Path, QPath, Ty, TyKind, diff --git a/clippy_lints/src/useless_conversion.rs b/clippy_lints/src/useless_conversion.rs index 2f7d54e73ed..29a7949b343 100644 --- a/clippy_lints/src/useless_conversion.rs +++ b/clippy_lints/src/useless_conversion.rs @@ -12,7 +12,7 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::traits::ObligationCause; use rustc_middle::ty::{self, EarlyBinder, GenericArg, GenericArgsRef, Ty, TypeVisitableExt}; use rustc_session::impl_lint_pass; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; declare_clippy_lint! { @@ -217,12 +217,12 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { }, ExprKind::MethodCall(.., args, _) => { cx.typeck_results().type_dependent_def_id(parent.hir_id).map(|did| { - return ( + ( did, args, cx.typeck_results().node_args(parent.hir_id), MethodOrFunction::Method, - ); + ) }) }, _ => None, diff --git a/clippy_lints/src/utils/author.rs b/clippy_lints/src/utils/author.rs index 0cce45290cf..31f9d84f5e4 100644 --- a/clippy_lints/src/utils/author.rs +++ b/clippy_lints/src/utils/author.rs @@ -1,6 +1,6 @@ use clippy_utils::{get_attr, higher}; -use rustc_ast::ast::{LitFloatType, LitKind}; use rustc_ast::LitIntType; +use rustc_ast::ast::{LitFloatType, LitKind}; use rustc_data_structures::fx::FxHashMap; use rustc_hir::{ self as hir, ArrayLen, BindingMode, CaptureBy, Closure, ClosureKind, ConstArg, ConstArgKind, CoroutineKind, diff --git a/clippy_lints/src/utils/format_args_collector.rs b/clippy_lints/src/utils/format_args_collector.rs index f50ce6c99de..8f314ce7a60 100644 --- a/clippy_lints/src/utils/format_args_collector.rs +++ b/clippy_lints/src/utils/format_args_collector.rs @@ -3,10 +3,10 @@ use clippy_utils::source::SpanRangeExt; use itertools::Itertools; use rustc_ast::{Crate, Expr, ExprKind, FormatArgs}; use rustc_data_structures::fx::FxHashMap; -use rustc_lexer::{tokenize, TokenKind}; +use rustc_lexer::{TokenKind, tokenize}; use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_session::impl_lint_pass; -use rustc_span::{hygiene, Span}; +use rustc_span::{Span, hygiene}; use std::iter::once; use std::mem; diff --git a/clippy_lints/src/utils/internal_lints/collapsible_calls.rs b/clippy_lints/src/utils/internal_lints/collapsible_calls.rs index f7529682675..d8f101a8614 100644 --- a/clippy_lints/src/utils/internal_lints/collapsible_calls.rs +++ b/clippy_lints/src/utils/internal_lints/collapsible_calls.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet; -use clippy_utils::{is_expr_path_def_path, is_lint_allowed, peel_blocks_with_stmt, SpanlessEq}; +use clippy_utils::{SpanlessEq, is_expr_path_def_path, is_lint_allowed, peel_blocks_with_stmt}; use rustc_errors::Applicability; use rustc_hir::{Closure, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; diff --git a/clippy_lints/src/utils/internal_lints/invalid_paths.rs b/clippy_lints/src/utils/internal_lints/invalid_paths.rs index 0ffcb433481..d444ad45087 100644 --- a/clippy_lints/src/utils/internal_lints/invalid_paths.rs +++ b/clippy_lints/src/utils/internal_lints/invalid_paths.rs @@ -2,11 +2,11 @@ use clippy_utils::consts::{ConstEvalCtxt, Constant}; use clippy_utils::def_path_res; use clippy_utils::diagnostics::span_lint; use rustc_hir as hir; -use rustc_hir::def::DefKind; use rustc_hir::Item; +use rustc_hir::def::DefKind; use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::ty::fast_reject::SimplifiedType; use rustc_middle::ty::FloatTy; +use rustc_middle::ty::fast_reject::SimplifiedType; use rustc_session::declare_lint_pass; use rustc_span::symbol::Symbol; 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 20526113d69..7c45a5b2f09 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 @@ -12,7 +12,7 @@ use rustc_middle::hir::nested_filter; use rustc_session::impl_lint_pass; use rustc_span::source_map::Spanned; use rustc_span::symbol::Symbol; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; use {rustc_ast as ast, rustc_hir as hir}; declare_clippy_lint! { diff --git a/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs b/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs index 41183700f09..76b0a52621b 100644 --- a/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs +++ b/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs @@ -8,12 +8,12 @@ use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; use rustc_hir::{Expr, ExprKind, LetStmt, Mutability, Node}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::mir::interpret::{Allocation, GlobalAlloc}; use rustc_middle::mir::ConstValue; +use rustc_middle::mir::interpret::{Allocation, GlobalAlloc}; use rustc_middle::ty::{self, Ty}; use rustc_session::impl_lint_pass; -use rustc_span::symbol::Symbol; use rustc_span::Span; +use rustc_span::symbol::Symbol; use std::str; diff --git a/clippy_lints/src/vec.rs b/clippy_lints/src/vec.rs index d3e49bff422..ce4f41e854d 100644 --- a/clippy_lints/src/vec.rs +++ b/clippy_lints/src/vec.rs @@ -1,8 +1,8 @@ use std::collections::BTreeMap; use std::ops::ControlFlow; -use clippy_config::msrvs::{self, Msrv}; use clippy_config::Conf; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::consts::{ConstEvalCtxt, Constant}; use clippy_utils::diagnostics::span_lint_hir_and_then; use clippy_utils::source::SpanRangeExt; @@ -15,7 +15,7 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_middle::ty::layout::LayoutOf; use rustc_session::impl_lint_pass; -use rustc_span::{sym, DesugaringKind, Span}; +use rustc_span::{DesugaringKind, Span, sym}; #[expect(clippy::module_name_repetitions)] pub struct UselessVec { diff --git a/clippy_lints/src/vec_init_then_push.rs b/clippy_lints/src/vec_init_then_push.rs index a599415a2dd..91dff5a9523 100644 --- a/clippy_lints/src/vec_init_then_push.rs +++ b/clippy_lints/src/vec_init_then_push.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::higher::{get_vec_init_kind, VecInitKind}; +use clippy_utils::higher::{VecInitKind, get_vec_init_kind}; use clippy_utils::source::snippet; use clippy_utils::visitors::for_each_local_use_after_expr; use clippy_utils::{get_parent_expr, path_to_local_id}; diff --git a/clippy_lints/src/visibility.rs b/clippy_lints/src/visibility.rs index 7a85196ceca..2e5fc5834e2 100644 --- a/clippy_lints/src/visibility.rs +++ b/clippy_lints/src/visibility.rs @@ -5,8 +5,8 @@ use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_session::declare_lint_pass; -use rustc_span::symbol::kw; use rustc_span::Span; +use rustc_span::symbol::kw; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/wildcard_imports.rs b/clippy_lints/src/wildcard_imports.rs index 7d9e58ad2f8..405310512df 100644 --- a/clippy_lints/src/wildcard_imports.rs +++ b/clippy_lints/src/wildcard_imports.rs @@ -10,7 +10,7 @@ use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::ty; use rustc_session::impl_lint_pass; use rustc_span::symbol::kw; -use rustc_span::{sym, BytePos}; +use rustc_span::{BytePos, sym}; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/write.rs b/clippy_lints/src/write.rs index ec5a5896fb2..1dd46ed5a89 100644 --- a/clippy_lints/src/write.rs +++ b/clippy_lints/src/write.rs @@ -1,8 +1,8 @@ use clippy_config::Conf; use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; use clippy_utils::is_in_test; -use clippy_utils::macros::{format_arg_removal_span, root_macro_call_first_node, FormatArgsStorage, MacroCall}; -use clippy_utils::source::{expand_past_previous_comma, SpanRangeExt}; +use clippy_utils::macros::{FormatArgsStorage, MacroCall, format_arg_removal_span, root_macro_call_first_node}; +use clippy_utils::source::{SpanRangeExt, expand_past_previous_comma}; use rustc_ast::token::LitKind; use rustc_ast::{ FormatArgPosition, FormatArgPositionKind, FormatArgs, FormatArgsPiece, FormatOptions, FormatPlaceholder, @@ -12,7 +12,7 @@ use rustc_errors::Applicability; use rustc_hir::{Expr, Impl, Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_session::impl_lint_pass; -use rustc_span::{sym, BytePos, Span}; +use rustc_span::{BytePos, Span, sym}; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/zombie_processes.rs b/clippy_lints/src/zombie_processes.rs new file mode 100644 index 00000000000..ba2a80ee66b --- /dev/null +++ b/clippy_lints/src/zombie_processes.rs @@ -0,0 +1,334 @@ +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_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_session::declare_lint_pass; +use rustc_span::sym; +use std::ops::ControlFlow; + +declare_clippy_lint! { + /// ### What it does + /// Looks for code that spawns a process but never calls `wait()` on the child. + /// + /// ### Why is this bad? + /// As explained in the [standard library documentation](https://doc.rust-lang.org/stable/std/process/struct.Child.html#warning), + /// calling `wait()` is necessary on Unix platforms to properly release all OS resources associated with the process. + /// Not doing so will effectively leak process IDs and/or other limited global resources, + /// which can eventually lead to resource exhaustion, so it's recommended to call `wait()` in long-running applications. + /// Such processes are called "zombie processes". + /// + /// ### Example + /// ```rust + /// use std::process::Command; + /// + /// let _child = Command::new("ls").spawn().expect("failed to execute child"); + /// ``` + /// Use instead: + /// ```rust + /// use std::process::Command; + /// + /// let mut child = Command::new("ls").spawn().expect("failed to execute child"); + /// child.wait().expect("failed to wait on child"); + /// ``` + #[clippy::version = "1.74.0"] + pub ZOMBIE_PROCESSES, + suspicious, + "not waiting on a spawned child process" +} +declare_lint_pass!(ZombieProcesses => [ZOMBIE_PROCESSES]); + +impl<'tcx> LateLintPass<'tcx> for ZombieProcesses { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { + if let ExprKind::Call(..) | ExprKind::MethodCall(..) = expr.kind + && let Some(child_adt) = cx.typeck_results().expr_ty(expr).ty_adt_def() + && match_def_path(cx, child_adt.did(), &paths::CHILD) + { + match cx.tcx.parent_hir_node(expr.hir_id) { + Node::LetStmt(local) + 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; + } + + // Don't emit a suggestion since the binding is used later + check(cx, expr, false); + }, + Node::LetStmt(&LetStmt { pat, .. }) if let PatKind::Wild = pat.kind => { + // `let _ = child;`, also dropped immediately without `wait()`ing + check(cx, expr, true); + }, + Node::Stmt(&Stmt { + kind: StmtKind::Semi(_), + .. + }) => { + // Immediately dropped. E.g. `std::process::Command::new("echo").spawn().unwrap();` + check(cx, expr, true); + }, + _ => {}, + } + } + } +} + +enum BreakReason { + WaitFound, + EarlyReturn, +} + +/// 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}`) +/// - calling `id` or `kill` +/// - no use at all (e.g. `let _x = child;`) +/// - taking a shared reference (`&`), `wait()` can't go through that +/// +/// 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), +} + +impl<'a, 'tcx> Visitor<'tcx> for WaitFinder<'a, 'tcx> { + type Result = ControlFlow; + + fn visit_local(&mut self, l: &'tcx LetStmt<'tcx>) -> Self::Result { + if let Self::WalkUpTo(cx, local_id) = *self + && let PatKind::Binding(_, pat_id, ..) = l.pat.kind + && local_id == pat_id + { + *self = Self::Found(cx, local_id); + } + + walk_local(self, l) + } + + fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) -> Self::Result { + let Self::Found(cx, local_id) = *self else { + return walk_expr(self, ex); + }; + + if path_to_local_id(ex, local_id) { + match cx.tcx.parent_hir_node(ex.hir_id) { + Node::Stmt(Stmt { + kind: StmtKind::Semi(_), + .. + }) => {}, + 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() => {}, + + // Conservatively assume that all other kinds of nodes call `.wait()` somehow. + _ => return Break(BreakReason::WaitFound), + } + } else { + match ex.kind { + ExprKind::Ret(..) => return Break(BreakReason::EarlyReturn), + 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); + } + + return Continue(()); + }, + + 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(())) + + // `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); + }, + + // Propagate early returns in either branch + (Break(BreakReason::EarlyReturn), _) | (_, Break(BreakReason::EarlyReturn)) => { + return Break(BreakReason::EarlyReturn); + }, + } + + return Continue(()); + }, + _ => {}, + } + } + + walk_expr(self, ex) + } +} + +/// This function has shared logic between the different kinds of nodes that can trigger the lint. +/// +/// In particular, `let = ;` requires some custom additional logic +/// such as checking that the binding is not used in certain ways, which isn't necessary for +/// `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) { + let Some(block) = get_enclosing_block(cx, spawn_expr.hir_id) else { + return; + }; + + let mut vis = ExitPointFinder { + cx, + state: ExitPointState::WalkUpTo(spawn_expr.hir_id), + }; + if let Break(ExitCallFound) = vis.visit_block(block) { + // Visitor found an unconditional `exit()` call, so don't lint. + 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, + ); + } else { + diag.note("consider calling `.wait()`"); + } + + 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. +fn is_exit_expression(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { + fn_def_id(cx, expr).is_some_and(|fn_did| { + cx.tcx.is_diagnostic_item(sym::process_exit, fn_did) || match_def_path(cx, fn_did, &paths::ABORT) + }) +} + +#[derive(Debug)] +enum ExitPointState { + /// Still walking up to the expression that initiated the visitor. + WalkUpTo(HirId), + /// We're inside of a control flow construct (e.g. `if`, `match`, `loop`) + /// Within this, we shouldn't accept any `exit()` calls in here, but we can leave all of these + /// constructs later and still continue looking for an `exit()` call afterwards. Example: + /// ```ignore + /// Command::new("").spawn().unwrap(); + /// + /// if true { // depth=1 + /// if true { // depth=2 + /// match () { // depth=3 + /// () => loop { // depth=4 + /// + /// std::process::exit(); + /// ^^^^^^^^^^^^^^^^^^^^^ conditional exit call, ignored + /// + /// } // depth=3 + /// } // depth=2 + /// } // depth=1 + /// } // depth=0 + /// + /// std::process::exit(); + /// ^^^^^^^^^^^^^^^^^^^^^ this exit call is accepted because we're now unconditionally calling it + /// ``` + /// We can only get into this state from `NoExit`. + InControlFlow { depth: u32 }, + /// No exit call found yet, but looking for one. + NoExit, +} + +fn expr_enters_control_flow(expr: &Expr<'_>) -> bool { + matches!(expr.kind, ExprKind::If(..) | ExprKind::Match(..) | ExprKind::Loop(..)) +} + +struct ExitPointFinder<'a, 'tcx> { + state: ExitPointState, + cx: &'a LateContext<'tcx>, +} + +struct ExitCallFound; + +impl<'a, 'tcx> Visitor<'tcx> for ExitPointFinder<'a, 'tcx> { + type Result = ControlFlow; + + fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) -> Self::Result { + match self.state { + ExitPointState::WalkUpTo(id) if expr.hir_id == id => { + self.state = ExitPointState::NoExit; + walk_expr(self, expr) + }, + ExitPointState::NoExit if expr_enters_control_flow(expr) => { + self.state = ExitPointState::InControlFlow { depth: 1 }; + walk_expr(self, expr)?; + if let ExitPointState::InControlFlow { .. } = self.state { + self.state = ExitPointState::NoExit; + } + Continue(()) + }, + ExitPointState::NoExit if is_exit_expression(self.cx, expr) => Break(ExitCallFound), + ExitPointState::InControlFlow { ref mut depth } if expr_enters_control_flow(expr) => { + *depth += 1; + walk_expr(self, expr)?; + match self.state { + ExitPointState::InControlFlow { depth: 1 } => self.state = ExitPointState::NoExit, + ExitPointState::InControlFlow { ref mut depth } => *depth -= 1, + _ => {}, + } + Continue(()) + }, + _ => Continue(()), + } + } +} diff --git a/clippy_utils/Cargo.toml b/clippy_utils/Cargo.toml index 629ce9d04d4..fe30b10c435 100644 --- a/clippy_utils/Cargo.toml +++ b/clippy_utils/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clippy_utils" -version = "0.1.82" +version = "0.1.83" edition = "2021" publish = false diff --git a/clippy_utils/src/ast_utils.rs b/clippy_utils/src/ast_utils.rs index de8bbb619f8..49323492e12 100644 --- a/clippy_utils/src/ast_utils.rs +++ b/clippy_utils/src/ast_utils.rs @@ -242,13 +242,16 @@ pub fn eq_expr(l: &Expr, r: &Expr) -> bool { } fn eq_coroutine_kind(a: Option, b: Option) -> bool { - match (a, b) { + matches!( + (a, b), (Some(CoroutineKind::Async { .. }), Some(CoroutineKind::Async { .. })) - | (Some(CoroutineKind::Gen { .. }), Some(CoroutineKind::Gen { .. })) - | (Some(CoroutineKind::AsyncGen { .. }), Some(CoroutineKind::AsyncGen { .. })) - | (None, None) => true, - _ => false, - } + | (Some(CoroutineKind::Gen { .. }), Some(CoroutineKind::Gen { .. })) + | ( + Some(CoroutineKind::AsyncGen { .. }), + Some(CoroutineKind::AsyncGen { .. }) + ) + | (None, None) + ) } pub fn eq_field(l: &ExprField, r: &ExprField) -> bool { diff --git a/clippy_utils/src/ast_utils/ident_iter.rs b/clippy_utils/src/ast_utils/ident_iter.rs index eefcbabd835..032cd3ed739 100644 --- a/clippy_utils/src/ast_utils/ident_iter.rs +++ b/clippy_utils/src/ast_utils/ident_iter.rs @@ -1,5 +1,5 @@ use core::iter::FusedIterator; -use rustc_ast::visit::{walk_attribute, walk_expr, Visitor}; +use rustc_ast::visit::{Visitor, walk_attribute, walk_expr}; use rustc_ast::{Attribute, Expr}; use rustc_span::symbol::Ident; diff --git a/clippy_utils/src/attrs.rs b/clippy_utils/src/attrs.rs index 42c8b218d14..edc9c6ccdff 100644 --- a/clippy_utils/src/attrs.rs +++ b/clippy_utils/src/attrs.rs @@ -4,7 +4,7 @@ use rustc_lexer::TokenKind; use rustc_lint::LateContext; use rustc_middle::ty::{AdtDef, TyCtxt}; use rustc_session::Session; -use rustc_span::{sym, Span}; +use rustc_span::{Span, sym}; use std::str::FromStr; use crate::source::SpanRangeExt; @@ -183,15 +183,15 @@ pub fn span_contains_cfg(cx: &LateContext<'_>, s: Span) -> bool { let mut iter = tokenize_with_text(src); // Search for the token sequence [`#`, `[`, `cfg`] - while iter.any(|(t, _)| matches!(t, TokenKind::Pound)) { - let mut iter = iter.by_ref().skip_while(|(t, _)| { + while iter.any(|(t, ..)| matches!(t, TokenKind::Pound)) { + let mut iter = iter.by_ref().skip_while(|(t, ..)| { matches!( t, TokenKind::Whitespace | TokenKind::LineComment { .. } | TokenKind::BlockComment { .. } ) }); - if matches!(iter.next(), Some((TokenKind::OpenBracket, _))) - && matches!(iter.next(), Some((TokenKind::Ident, "cfg"))) + if matches!(iter.next(), Some((TokenKind::OpenBracket, ..))) + && matches!(iter.next(), Some((TokenKind::Ident, "cfg", _))) { return true; } diff --git a/clippy_utils/src/check_proc_macro.rs b/clippy_utils/src/check_proc_macro.rs index 2bd6837d973..9143d292f67 100644 --- a/clippy_utils/src/check_proc_macro.rs +++ b/clippy_utils/src/check_proc_macro.rs @@ -12,9 +12,9 @@ //! code was written, and check if the span contains that text. Note this will only work correctly //! if the span is not from a `macro_rules` based macro. +use rustc_ast::AttrStyle; use rustc_ast::ast::{AttrKind, Attribute, IntTy, LitIntType, LitKind, StrStyle, TraitObjectSyntax, UintTy}; use rustc_ast::token::CommentKind; -use rustc_ast::AttrStyle; use rustc_hir::intravisit::FnKind; use rustc_hir::{ Block, BlockCheckMode, Body, Closure, Destination, Expr, ExprKind, FieldDef, FnHeader, FnRetTy, HirId, Impl, @@ -24,7 +24,7 @@ use rustc_hir::{ use rustc_lint::{LateContext, LintContext}; use rustc_middle::ty::TyCtxt; use rustc_session::Session; -use rustc_span::symbol::{kw, Ident}; +use rustc_span::symbol::{Ident, kw}; use rustc_span::{Span, Symbol}; use rustc_target::spec::abi::Abi; diff --git a/clippy_utils/src/consts.rs b/clippy_utils/src/consts.rs index 760d5bc95f7..bf47cf6d372 100644 --- a/clippy_utils/src/consts.rs +++ b/clippy_utils/src/consts.rs @@ -1,24 +1,24 @@ #![allow(clippy::float_cmp)] use crate::macros::HirNode; -use crate::source::{walk_span_to_context, SpanRangeExt}; +use crate::source::{SpanRangeExt, walk_span_to_context}; use crate::{clip, is_direct_expn_of, sext, unsext}; -use rustc_apfloat::ieee::{Half, Quad}; use rustc_apfloat::Float; +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_lexer::tokenize; use rustc_lint::LateContext; -use rustc_middle::mir::interpret::{alloc_range, Scalar}; use rustc_middle::mir::ConstValue; +use rustc_middle::mir::interpret::{Scalar, alloc_range}; use rustc_middle::ty::{self, FloatTy, IntTy, ParamEnv, ScalarInt, Ty, TyCtxt, TypeckResults, UintTy}; use rustc_middle::{bug, mir, span_bug}; use rustc_span::def_id::DefId; use rustc_span::symbol::Ident; -use rustc_span::{sym, SyntaxContext}; +use rustc_span::{SyntaxContext, sym}; use rustc_target::abi::Size; use std::cell::Cell; use std::cmp::Ordering; @@ -581,7 +581,7 @@ impl<'tcx> ConstEvalCtxt<'tcx> { } fn constant_negate(&self, o: &Constant<'tcx>, ty: Ty<'_>) -> Option> { - use self::Constant::{Int, F32, F64}; + use self::Constant::{F32, F64, Int}; match *o { Int(value) => { let ty::Int(ity) = *ty.kind() else { return None }; diff --git a/clippy_utils/src/eager_or_lazy.rs b/clippy_utils/src/eager_or_lazy.rs index a6dd12a28c5..9420d84b959 100644 --- a/clippy_utils/src/eager_or_lazy.rs +++ b/clippy_utils/src/eager_or_lazy.rs @@ -14,12 +14,12 @@ use crate::ty::{all_predicates_of, is_copy}; use crate::visitors::is_const_evaluatable; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; -use rustc_hir::intravisit::{walk_expr, Visitor}; +use rustc_hir::intravisit::{Visitor, walk_expr}; use rustc_hir::{BinOpKind, Block, Expr, ExprKind, QPath, UnOp}; use rustc_lint::LateContext; use rustc_middle::ty; use rustc_middle::ty::adjustment::Adjust; -use rustc_span::{sym, Symbol}; +use rustc_span::{Symbol, sym}; use std::{cmp, ops}; #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] diff --git a/clippy_utils/src/higher.rs b/clippy_utils/src/higher.rs index e09cc9edf3a..3175a9a1dd3 100644 --- a/clippy_utils/src/higher.rs +++ b/clippy_utils/src/higher.rs @@ -3,14 +3,14 @@ #![deny(clippy::missing_docs_in_private_items)] use crate::consts::{ConstEvalCtxt, Constant}; -use crate::ty::is_type_diagnostic_item; use crate::is_expn_of; +use crate::ty::is_type_diagnostic_item; use rustc_ast::ast; use rustc_hir as hir; use rustc_hir::{Arm, Block, Expr, ExprKind, HirId, LoopSource, MatchSource, Node, Pat, QPath}; use rustc_lint::LateContext; -use rustc_span::{sym, symbol, Span}; +use rustc_span::{Span, sym, symbol}; /// The essential nodes of a desugared for loop as well as the entire span: /// `for pat in arg { body }` becomes `(pat, arg, body)`. Returns `(pat, arg, body, span)`. diff --git a/clippy_utils/src/hir_utils.rs b/clippy_utils/src/hir_utils.rs index f61ef9ac1b0..76900379ac7 100644 --- a/clippy_utils/src/hir_utils.rs +++ b/clippy_utils/src/hir_utils.rs @@ -1,20 +1,20 @@ use crate::consts::ConstEvalCtxt; use crate::macros::macro_backtrace; -use crate::source::{walk_span_to_context, SpanRange, SpanRangeExt}; +use crate::source::{SpanRange, SpanRangeExt, walk_span_to_context}; use crate::tokenize_with_text; use rustc_ast::ast::InlineAsmTemplatePiece; use rustc_data_structures::fx::FxHasher; -use rustc_hir::def::Res; use rustc_hir::MatchSource::TryDesugar; +use rustc_hir::def::Res; use rustc_hir::{ ArrayLen, 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, Ty, TyKind, }; -use rustc_lexer::{tokenize, TokenKind}; +use rustc_lexer::{TokenKind, tokenize}; use rustc_lint::LateContext; use rustc_middle::ty::TypeckResults; -use rustc_span::{sym, BytePos, ExpnKind, MacroKind, Symbol, SyntaxContext}; +use rustc_span::{BytePos, ExpnKind, MacroKind, Symbol, SyntaxContext, sym}; use std::hash::{Hash, Hasher}; use std::ops::Range; @@ -1194,8 +1194,8 @@ fn eq_span_tokens( && let Some(rsrc) = right.get_source_range(cx) && let Some(rsrc) = rsrc.as_str() { - let pred = |t: &(_, _)| pred(t.0); - let map = |(_, x)| x; + let pred = |&(token, ..): &(TokenKind, _, _)| pred(token); + let map = |(_, source, _)| source; let ltok = tokenize_with_text(lsrc).filter(pred).map(map); let rtok = tokenize_with_text(rsrc).filter(pred).map(map); diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 0d0d6219c5e..2fee6473910 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -78,7 +78,7 @@ pub mod visitors; pub use self::attrs::*; pub use self::check_proc_macro::{is_from_proc_macro, is_span_if, is_span_match}; pub use self::hir_utils::{ - both, count_eq, eq_expr_value, hash_expr, hash_stmt, is_bool, over, HirEqInterExpr, SpanlessEq, SpanlessHash, + HirEqInterExpr, SpanlessEq, SpanlessHash, both, count_eq, eq_expr_value, hash_expr, hash_stmt, is_bool, over, }; use core::mem; @@ -94,20 +94,20 @@ use rustc_ast::ast::{self, LitKind, RangeLimits}; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::packed::Pu128; use rustc_data_structures::unhash::UnhashMap; +use rustc_hir::LangItem::{OptionNone, OptionSome, ResultErr, ResultOk}; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, LocalModDefId, LOCAL_CRATE}; +use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LOCAL_CRATE, LocalDefId, LocalModDefId}; use rustc_hir::definitions::{DefPath, DefPathData}; use rustc_hir::hir_id::{HirIdMap, HirIdSet}; -use rustc_hir::intravisit::{walk_expr, FnKind, Visitor}; -use rustc_hir::LangItem::{OptionNone, OptionSome, ResultErr, ResultOk}; +use rustc_hir::intravisit::{FnKind, Visitor, walk_expr}; use rustc_hir::{ - self as hir, def, Arm, ArrayLen, BindingMode, Block, BlockCheckMode, Body, ByRef, Closure, ConstArgKind, - ConstContext, Destination, Expr, ExprField, ExprKind, FnDecl, FnRetTy, GenericArgs, HirId, Impl, ImplItem, - ImplItemKind, ImplItemRef, Item, ItemKind, LangItem, LetStmt, MatchSource, Mutability, Node, OwnerId, OwnerNode, - Param, Pat, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, TraitItem, TraitItemKind, TraitItemRef, - TraitRef, TyKind, UnOp, + self as hir, Arm, ArrayLen, BindingMode, Block, BlockCheckMode, Body, ByRef, Closure, ConstArgKind, ConstContext, + Destination, Expr, ExprField, ExprKind, FnDecl, FnRetTy, GenericArgs, HirId, Impl, ImplItem, ImplItemKind, + ImplItemRef, Item, ItemKind, LangItem, LetStmt, MatchSource, Mutability, Node, OwnerId, OwnerNode, Param, Pat, + PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, TraitItem, TraitItemKind, TraitItemRef, TraitRef, + TyKind, UnOp, def, }; -use rustc_lexer::{tokenize, TokenKind}; +use rustc_lexer::{TokenKind, tokenize}; use rustc_lint::{LateContext, Level, Lint, LintContext}; use rustc_middle::hir::place::PlaceBase; use rustc_middle::mir::Const; @@ -120,12 +120,12 @@ use rustc_middle::ty::{ }; use rustc_span::hygiene::{ExpnKind, MacroKind}; use rustc_span::source_map::SourceMap; -use rustc_span::symbol::{kw, Ident, Symbol}; -use rustc_span::{sym, Span}; +use rustc_span::symbol::{Ident, Symbol, kw}; +use rustc_span::{InnerSpan, Span, sym}; use rustc_target::abi::Integer; use visitors::Visitable; -use crate::consts::{mir_to_const, ConstEvalCtxt, Constant}; +use crate::consts::{ConstEvalCtxt, Constant, mir_to_const}; use crate::higher::Range; use crate::ty::{adt_and_variant_of_res, can_partially_move_ty, expr_sig, is_copy, is_recursively_primitive_type}; use crate::visitors::for_each_expr_without_closures; @@ -263,9 +263,13 @@ pub fn is_res_lang_ctor(cx: &LateContext<'_>, res: Res, lang_item: LangItem) -> } } - /// Checks if `{ctor_call_id}(...)` is `{enum_item}::{variant_name}(...)`. -pub fn is_enum_variant_ctor(cx: &LateContext<'_>, enum_item: Symbol, variant_name: Symbol, ctor_call_id: DefId) -> bool { +pub fn is_enum_variant_ctor( + cx: &LateContext<'_>, + enum_item: Symbol, + variant_name: Symbol, + ctor_call_id: DefId, +) -> bool { let Some(enum_def_id) = cx.tcx.get_diagnostic_item(enum_item) else { return false; }; @@ -667,6 +671,17 @@ fn item_children_by_name(tcx: TyCtxt<'_>, def_id: DefId, name: Symbol) -> Vec, name: Symbol) -> Vec { + tcx.crates(()) + .iter() + .copied() + .filter(move |&num| tcx.crate_name(num) == name) + .map(CrateNum::as_def_id) + .map(|id| Res::Def(tcx.def_kind(id), id)) + .collect() +} + /// Resolves a def path like `std::vec::Vec`. /// /// Can return multiple resolutions when there are multiple versions of the same crate, e.g. @@ -677,15 +692,7 @@ fn item_children_by_name(tcx: TyCtxt<'_>, def_id: DefId, name: Symbol) -> Vec, path: &[&str]) -> Vec { - fn find_crates(tcx: TyCtxt<'_>, name: Symbol) -> impl Iterator + '_ { - tcx.crates(()) - .iter() - .copied() - .filter(move |&num| tcx.crate_name(num) == name) - .map(CrateNum::as_def_id) - } - - let (base, mut path) = match *path { + let (base, path) = match *path { [primitive] => { return vec![PrimTy::from_name(Symbol::intern(primitive)).map_or(Res::Err, Res::PrimTy)]; }, @@ -701,18 +708,25 @@ pub fn def_path_res(tcx: TyCtxt<'_>, path: &[&str]) -> Vec { None }; - let starts = find_primitive_impls(tcx, base) - .chain(find_crates(tcx, base_sym)) + let crates = find_primitive_impls(tcx, base) .chain(local_crate) - .map(|id| Res::Def(tcx.def_kind(id), id)); + .map(|id| Res::Def(tcx.def_kind(id), id)) + .chain(find_crates(tcx, base_sym)) + .collect(); - let mut resolutions: Vec = starts.collect(); + def_path_res_with_base(tcx, crates, path) +} +/// Resolves a def path like `vec::Vec` with the base `std`. +/// +/// This is lighter than [`def_path_res`], and should be called with [`find_crates`] looking up +/// items from the same crate repeatedly, although should still be used sparingly. +pub fn def_path_res_with_base(tcx: TyCtxt<'_>, mut base: Vec, mut path: &[&str]) -> Vec { while let [segment, rest @ ..] = path { path = rest; let segment = Symbol::intern(segment); - resolutions = resolutions + base = base .into_iter() .filter_map(|res| res.opt_def_id()) .flat_map(|def_id| { @@ -731,7 +745,7 @@ pub fn def_path_res(tcx: TyCtxt<'_>, path: &[&str]) -> Vec { .collect(); } - resolutions + base } /// Resolves a def path like `std::vec::Vec` to its [`DefId`]s, see [`def_path_res`]. @@ -2944,13 +2958,14 @@ pub fn expr_use_ctxt<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'tcx>) -> ExprU } /// Tokenizes the input while keeping the text associated with each token. -pub fn tokenize_with_text(s: &str) -> impl Iterator { +pub fn tokenize_with_text(s: &str) -> impl Iterator { let mut pos = 0; tokenize(s).map(move |t| { let end = pos + t.len; let range = pos as usize..end as usize; + let inner = InnerSpan::new(range.start, range.end); pos = end; - (t.kind, s.get(range).unwrap_or_default()) + (t.kind, s.get(range).unwrap_or_default(), inner) }) } @@ -2974,8 +2989,8 @@ pub fn span_contains_comment(sm: &SourceMap, span: Span) -> bool { pub fn span_extract_comment(sm: &SourceMap, span: Span) -> String { let snippet = sm.span_to_snippet(span).unwrap_or_default(); let res = tokenize_with_text(&snippet) - .filter(|(t, _)| matches!(t, TokenKind::BlockComment { .. } | TokenKind::LineComment { .. })) - .map(|(_, s)| s) + .filter(|(t, ..)| matches!(t, TokenKind::BlockComment { .. } | TokenKind::LineComment { .. })) + .map(|(_, s, _)| s) .join("\n"); res } @@ -2995,7 +3010,7 @@ pub fn span_find_starting_semi(sm: &SourceMap, span: Span) -> Span { /// pat: Some(a) /// else_body: return None /// ``` - +/// /// And for this example: /// ```ignore /// let Some(FooBar { a, b }) = ex else { return None }; @@ -3005,7 +3020,7 @@ pub fn span_find_starting_semi(sm: &SourceMap, span: Span) -> Span { /// pat: Some(FooBar { a, b }) /// else_body: return None /// ``` - +/// /// We output `Some(a)` in the first instance, and `Some(FooBar { a, b })` in the second, because /// the question mark operator is applicable here. Callers have to check whether we are in a /// constant or not. diff --git a/clippy_utils/src/macros.rs b/clippy_utils/src/macros.rs index 1d7479bff82..9c4d19ac1f1 100644 --- a/clippy_utils/src/macros.rs +++ b/clippy_utils/src/macros.rs @@ -1,6 +1,6 @@ #![allow(clippy::similar_names)] // `expr` and `expn` -use crate::visitors::{for_each_expr_without_closures, Descend}; +use crate::visitors::{Descend, for_each_expr_without_closures}; use arrayvec::ArrayVec; use rustc_ast::{FormatArgs, FormatArgument, FormatPlaceholder}; @@ -10,7 +10,7 @@ use rustc_hir::{self as hir, Expr, ExprKind, HirId, Node, QPath}; use rustc_lint::LateContext; use rustc_span::def_id::DefId; use rustc_span::hygiene::{self, MacroKind, SyntaxContext}; -use rustc_span::{sym, BytePos, ExpnData, ExpnId, ExpnKind, Span, SpanData, Symbol}; +use rustc_span::{BytePos, ExpnData, ExpnId, ExpnKind, Span, SpanData, Symbol, sym}; use std::ops::ControlFlow; const FORMAT_MACRO_DIAG_ITEMS: &[Symbol] = &[ diff --git a/clippy_utils/src/mir/mod.rs b/clippy_utils/src/mir/mod.rs index 654fb564848..59bb5e35cda 100644 --- a/clippy_utils/src/mir/mod.rs +++ b/clippy_utils/src/mir/mod.rs @@ -2,7 +2,7 @@ use rustc_hir::{Expr, HirId}; use rustc_index::bit_set::BitSet; use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor}; use rustc_middle::mir::{ - traversal, BasicBlock, Body, InlineAsmOperand, Local, Location, Place, StatementKind, TerminatorKind, START_BLOCK, + BasicBlock, Body, InlineAsmOperand, Local, Location, Place, START_BLOCK, StatementKind, TerminatorKind, traversal, }; use rustc_middle::ty::TyCtxt; @@ -112,14 +112,10 @@ pub fn block_in_cycle(body: &Body<'_>, block: BasicBlock) -> bool { /// Convenience wrapper around `visit_local_usage`. pub fn used_exactly_once(mir: &Body<'_>, local: Local) -> Option { - visit_local_usage( - &[local], - mir, - Location { - block: START_BLOCK, - statement_index: 0, - }, - ) + visit_local_usage(&[local], mir, Location { + block: START_BLOCK, + statement_index: 0, + }) .map(|mut vec| { let LocalUsage { local_use_locs, .. } = vec.remove(0); let mut locations = local_use_locs diff --git a/clippy_utils/src/paths.rs b/clippy_utils/src/paths.rs index a30edc48fff..11a98b02f33 100644 --- a/clippy_utils/src/paths.rs +++ b/clippy_utils/src/paths.rs @@ -29,7 +29,11 @@ pub const SYM_MODULE: [&str; 3] = ["rustc_span", "symbol", "sym"]; pub const SYNTAX_CONTEXT: [&str; 3] = ["rustc_span", "hygiene", "SyntaxContext"]; // Paths in `core`/`alloc`/`std`. This should be avoided and cleaned up by adding diagnostic items. -// ... none currently! +pub const ABORT: [&str; 3] = ["std", "process", "abort"]; +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"]; // Paths in clippy itself pub const MSRV: [&str; 3] = ["clippy_config", "msrvs", "Msrv"]; diff --git a/clippy_utils/src/ptr.rs b/clippy_utils/src/ptr.rs index 991ea428dc3..273c1b0defa 100644 --- a/clippy_utils/src/ptr.rs +++ b/clippy_utils/src/ptr.rs @@ -1,5 +1,5 @@ use crate::source::snippet; -use crate::visitors::{for_each_expr_without_closures, Descend}; +use crate::visitors::{Descend, for_each_expr_without_closures}; use crate::{path_to_local_id, strip_pat_refs}; use core::ops::ControlFlow; use rustc_hir::{Body, BodyId, ExprKind, HirId, PatKind}; diff --git a/clippy_utils/src/qualify_min_const_fn.rs b/clippy_utils/src/qualify_min_const_fn.rs index d9befb3c157..2ed20b7202c 100644 --- a/clippy_utils/src/qualify_min_const_fn.rs +++ b/clippy_utils/src/qualify_min_const_fn.rs @@ -18,8 +18,8 @@ use rustc_middle::mir::{ use rustc_middle::traits::{BuiltinImplSource, ImplSource, ObligationCause}; use rustc_middle::ty::adjustment::PointerCoercion; use rustc_middle::ty::{self, GenericArgKind, TraitRef, Ty, TyCtxt}; -use rustc_span::symbol::sym; use rustc_span::Span; +use rustc_span::symbol::sym; use rustc_trait_selection::traits::{ObligationCtxt, SelectionContext}; use std::borrow::Cow; diff --git a/clippy_utils/src/source.rs b/clippy_utils/src/source.rs index 482e1e0147b..4ad7575e720 100644 --- a/clippy_utils/src/source.rs +++ b/clippy_utils/src/source.rs @@ -9,10 +9,10 @@ use rustc_hir::{BlockCheckMode, Expr, ExprKind, UnsafeSource}; use rustc_lint::{EarlyContext, LateContext}; use rustc_middle::ty::TyCtxt; use rustc_session::Session; -use rustc_span::source_map::{original_sp, SourceMap}; +use rustc_span::source_map::{SourceMap, original_sp}; use rustc_span::{ - hygiene, BytePos, FileNameDisplayPreference, Pos, SourceFile, SourceFileAndLine, Span, SpanData, SyntaxContext, - DUMMY_SP, + BytePos, DUMMY_SP, FileNameDisplayPreference, Pos, SourceFile, SourceFileAndLine, Span, SpanData, SyntaxContext, + hygiene, }; use std::borrow::Cow; use std::fmt; @@ -666,39 +666,6 @@ pub fn walk_span_to_context(span: Span, outer: SyntaxContext) -> Option { (outer_span.ctxt() == outer).then_some(outer_span) } -/// Removes block comments from the given `Vec` of lines. -/// -/// # Examples -/// -/// ```rust,ignore -/// without_block_comments(vec!["/*", "foo", "*/"]); -/// // => vec![] -/// -/// without_block_comments(vec!["bar", "/*", "foo", "*/"]); -/// // => vec!["bar"] -/// ``` -pub fn without_block_comments(lines: Vec<&str>) -> Vec<&str> { - let mut without = vec![]; - - let mut nest_level = 0; - - for line in lines { - if line.contains("/*") { - nest_level += 1; - continue; - } else if line.contains("*/") { - nest_level -= 1; - continue; - } - - if nest_level == 0 { - without.push(line); - } - } - - without -} - /// Trims the whitespace from the start and the end of the span. pub fn trim_span(sm: &SourceMap, span: Span) -> Span { let data = span.data(); @@ -758,15 +725,12 @@ pub fn str_literal_to_char_literal( &snip[1..(snip.len() - 1)] }; - let hint = format!( - "'{}'", - match ch { - "'" => "\\'", - r"\" => "\\\\", - "\\\"" => "\"", // no need to escape `"` in `'"'` - _ => ch, - } - ); + let hint = format!("'{}'", match ch { + "'" => "\\'", + r"\" => "\\\\", + "\\\"" => "\"", // no need to escape `"` in `'"'` + _ => ch, + }); Some(hint) } else { @@ -776,7 +740,7 @@ pub fn str_literal_to_char_literal( #[cfg(test)] mod test { - use super::{reindent_multiline, without_block_comments}; + use super::reindent_multiline; #[test] fn test_reindent_multiline_single_line() { @@ -844,29 +808,4 @@ mod test { z }".into(), true, Some(8))); } - - #[test] - fn test_without_block_comments_lines_without_block_comments() { - let result = without_block_comments(vec!["/*", "", "*/"]); - println!("result: {result:?}"); - assert!(result.is_empty()); - - let result = without_block_comments(vec!["", "/*", "", "*/", "#[crate_type = \"lib\"]", "/*", "", "*/", ""]); - assert_eq!(result, vec!["", "#[crate_type = \"lib\"]", ""]); - - let result = without_block_comments(vec!["/* rust", "", "*/"]); - assert!(result.is_empty()); - - let result = without_block_comments(vec!["/* one-line comment */"]); - assert!(result.is_empty()); - - let result = without_block_comments(vec!["/* nested", "/* multi-line", "comment", "*/", "test", "*/"]); - assert!(result.is_empty()); - - let result = without_block_comments(vec!["/* nested /* inline /* comment */ test */ */"]); - assert!(result.is_empty()); - - let result = without_block_comments(vec!["foo", "bar", "baz"]); - assert_eq!(result, vec!["foo", "bar", "baz"]); - } } diff --git a/clippy_utils/src/str_utils.rs b/clippy_utils/src/str_utils.rs index 421b25a77fe..1588ee452da 100644 --- a/clippy_utils/src/str_utils.rs +++ b/clippy_utils/src/str_utils.rs @@ -370,9 +370,11 @@ mod test { assert_eq!(camel_case_split("AbcDef"), vec!["Abc", "Def"]); assert_eq!(camel_case_split("Abc"), vec!["Abc"]); assert_eq!(camel_case_split("abcDef"), vec!["abc", "Def"]); - assert_eq!( - camel_case_split("\u{f6}\u{f6}AabABcd"), - vec!["\u{f6}\u{f6}", "Aab", "A", "Bcd"] - ); + assert_eq!(camel_case_split("\u{f6}\u{f6}AabABcd"), vec![ + "\u{f6}\u{f6}", + "Aab", + "A", + "Bcd" + ]); } } diff --git a/clippy_utils/src/sugg.rs b/clippy_utils/src/sugg.rs index 0f86d89c980..3255c51d009 100644 --- a/clippy_utils/src/sugg.rs +++ b/clippy_utils/src/sugg.rs @@ -180,8 +180,10 @@ impl<'a> Sugg<'a> { ) -> Self { use rustc_ast::ast::RangeLimits; + let mut snippet = |span: Span| snippet_with_context(cx, span, ctxt, default, app).0; + match expr.kind { - _ if expr.span.ctxt() != ctxt => Sugg::NonParen(snippet_with_context(cx, expr.span, ctxt, default, app).0), + _ if expr.span.ctxt() != ctxt => Sugg::NonParen(snippet(expr.span)), ast::ExprKind::AddrOf(..) | ast::ExprKind::Closure { .. } | ast::ExprKind::If(..) @@ -224,46 +226,38 @@ impl<'a> Sugg<'a> { | ast::ExprKind::While(..) | ast::ExprKind::Await(..) | ast::ExprKind::Err(_) - | ast::ExprKind::Dummy => Sugg::NonParen(snippet_with_context(cx, expr.span, ctxt, default, app).0), + | ast::ExprKind::Dummy => Sugg::NonParen(snippet(expr.span)), ast::ExprKind::Range(ref lhs, ref rhs, RangeLimits::HalfOpen) => Sugg::BinOp( AssocOp::DotDot, - lhs.as_ref().map_or("".into(), |lhs| { - snippet_with_context(cx, lhs.span, ctxt, default, app).0 - }), - rhs.as_ref().map_or("".into(), |rhs| { - snippet_with_context(cx, rhs.span, ctxt, default, app).0 - }), + lhs.as_ref().map_or("".into(), |lhs| snippet(lhs.span)), + rhs.as_ref().map_or("".into(), |rhs| snippet(rhs.span)), ), ast::ExprKind::Range(ref lhs, ref rhs, RangeLimits::Closed) => Sugg::BinOp( AssocOp::DotDotEq, - lhs.as_ref().map_or("".into(), |lhs| { - snippet_with_context(cx, lhs.span, ctxt, default, app).0 - }), - rhs.as_ref().map_or("".into(), |rhs| { - snippet_with_context(cx, rhs.span, ctxt, default, app).0 - }), + lhs.as_ref().map_or("".into(), |lhs| snippet(lhs.span)), + rhs.as_ref().map_or("".into(), |rhs| snippet(rhs.span)), ), ast::ExprKind::Assign(ref lhs, ref rhs, _) => Sugg::BinOp( AssocOp::Assign, - snippet_with_context(cx, lhs.span, ctxt, default, app).0, - snippet_with_context(cx, rhs.span, ctxt, default, app).0, + snippet(lhs.span), + snippet(rhs.span), ), ast::ExprKind::AssignOp(op, ref lhs, ref rhs) => Sugg::BinOp( astbinop2assignop(op), - snippet_with_context(cx, lhs.span, ctxt, default, app).0, - snippet_with_context(cx, rhs.span, ctxt, default, app).0, + snippet(lhs.span), + snippet(rhs.span), ), ast::ExprKind::Binary(op, ref lhs, ref rhs) => Sugg::BinOp( AssocOp::from_ast_binop(op.node), - snippet_with_context(cx, lhs.span, ctxt, default, app).0, - snippet_with_context(cx, rhs.span, ctxt, default, app).0, + snippet(lhs.span), + snippet(rhs.span), ), ast::ExprKind::Cast(ref lhs, ref ty) | //FIXME(chenyukang), remove this after type ascription is removed from AST ast::ExprKind::Type(ref lhs, ref ty) => Sugg::BinOp( AssocOp::As, - snippet_with_context(cx, lhs.span, ctxt, default, app).0, - snippet_with_context(cx, ty.span, ctxt, default, app).0, + snippet(lhs.span), + snippet(ty.span), ), } } diff --git a/clippy_utils/src/ty.rs b/clippy_utils/src/ty.rs index 585134209ca..775a98fe361 100644 --- a/clippy_utils/src/ty.rs +++ b/clippy_utils/src/ty.rs @@ -12,8 +12,8 @@ use rustc_hir::def_id::DefId; use rustc_hir::{Expr, FnDecl, LangItem, Safety, TyKind}; use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::LateContext; -use rustc_middle::mir::interpret::Scalar; use rustc_middle::mir::ConstValue; +use rustc_middle::mir::interpret::Scalar; use rustc_middle::traits::EvaluationResult; use rustc_middle::ty::layout::ValidityRequirement; use rustc_middle::ty::{ @@ -22,7 +22,7 @@ use rustc_middle::ty::{ TypeVisitable, TypeVisitableExt, TypeVisitor, UintTy, Upcast, VariantDef, VariantDiscr, }; use rustc_span::symbol::Ident; -use rustc_span::{sym, Span, Symbol, DUMMY_SP}; +use rustc_span::{DUMMY_SP, Span, Symbol, sym}; use rustc_target::abi::VariantIdx; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _; use rustc_trait_selection::traits::query::normalize::QueryNormalizeExt; @@ -606,10 +606,13 @@ fn is_uninit_value_valid_for_ty_fallback<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'t ty::Tuple(types) => types.iter().all(|ty| is_uninit_value_valid_for_ty(cx, ty)), // Unions are always fine right now. // This includes MaybeUninit, the main way people use uninitialized memory. - // For ADTs, we could look at all fields just like for tuples, but that's potentially - // exponential, so let's avoid doing that for now. Code doing that is sketchy enough to - // just use an `#[allow()]`. - ty::Adt(adt, _) => adt.is_union(), + ty::Adt(adt, _) if adt.is_union() => true, + // Types (e.g. `UnsafeCell>`) that recursively contain only types that can be uninit + // can themselves be uninit too. + // This purposefully ignores enums as they may have a discriminant that can't be uninit. + ty::Adt(adt, args) if adt.is_struct() => adt + .all_fields() + .all(|field| is_uninit_value_valid_for_ty(cx, field.ty(cx.tcx, args))), // For the rest, conservatively assume that they cannot be uninit. _ => false, } diff --git a/clippy_utils/src/ty/type_certainty/mod.rs b/clippy_utils/src/ty/type_certainty/mod.rs index 875ddec259e..e612e9c6cb6 100644 --- a/clippy_utils/src/ty/type_certainty/mod.rs +++ b/clippy_utils/src/ty/type_certainty/mod.rs @@ -14,14 +14,14 @@ use crate::def_path_res; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; -use rustc_hir::intravisit::{walk_qpath, walk_ty, Visitor}; +use rustc_hir::intravisit::{Visitor, walk_qpath, walk_ty}; use rustc_hir::{self as hir, Expr, ExprKind, GenericArgs, HirId, Node, PathSegment, QPath, TyKind}; use rustc_lint::LateContext; use rustc_middle::ty::{self, AdtDef, GenericArgKind, Ty}; use rustc_span::{Span, Symbol}; mod certainty; -use certainty::{join, meet, Certainty, Meet}; +use certainty::{Certainty, Meet, join, meet}; pub fn expr_type_is_certain(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { expr_type_certainty(cx, expr).is_certain() diff --git a/clippy_utils/src/usage.rs b/clippy_utils/src/usage.rs index fbf3d95365a..1230b60c3a6 100644 --- a/clippy_utils/src/usage.rs +++ b/clippy_utils/src/usage.rs @@ -1,4 +1,4 @@ -use crate::visitors::{for_each_expr, for_each_expr_without_closures, Descend, Visitable}; +use crate::visitors::{Descend, Visitable, for_each_expr, for_each_expr_without_closures}; use crate::{self as utils, get_enclosing_loop_or_multi_call_closure}; use core::ops::ControlFlow; use hir::def::Res; diff --git a/clippy_utils/src/visitors.rs b/clippy_utils/src/visitors.rs index e5b6d3965e9..6d9a85a1181 100644 --- a/clippy_utils/src/visitors.rs +++ b/clippy_utils/src/visitors.rs @@ -1,10 +1,10 @@ use crate::ty::needs_ordered_drop; use crate::{get_enclosing_block, path_to_local_id}; use core::ops::ControlFlow; -use rustc_ast::visit::{try_visit, VisitorResult}; +use rustc_ast::visit::{VisitorResult, try_visit}; use rustc_hir as hir; use rustc_hir::def::{CtorKind, DefKind, Res}; -use rustc_hir::intravisit::{self, walk_block, walk_expr, Visitor}; +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, Safety, Stmt, UnOp, UnsafeSource, diff --git a/declare_clippy_lint/Cargo.toml b/declare_clippy_lint/Cargo.toml index 31270241b0b..67a1f7cc72c 100644 --- a/declare_clippy_lint/Cargo.toml +++ b/declare_clippy_lint/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "declare_clippy_lint" -version = "0.1.82" +version = "0.1.83" edition = "2021" publish = false diff --git a/declare_clippy_lint/src/lib.rs b/declare_clippy_lint/src/lib.rs index 6aa24329b06..fefc1a0a6c4 100644 --- a/declare_clippy_lint/src/lib.rs +++ b/declare_clippy_lint/src/lib.rs @@ -5,7 +5,7 @@ use proc_macro::TokenStream; use quote::{format_ident, quote}; use syn::parse::{Parse, ParseStream}; -use syn::{parse_macro_input, Attribute, Error, Expr, ExprLit, Ident, Lit, LitStr, Meta, Result, Token}; +use syn::{Attribute, Error, Expr, ExprLit, Ident, Lit, LitStr, Meta, Result, Token, parse_macro_input}; fn parse_attr(path: [&'static str; LEN], attr: &Attribute) -> Option { if let Meta::NameValue(name_value) = &attr.meta { @@ -140,15 +140,12 @@ pub fn declare_clippy_lint(input: TokenStream) -> TokenStream { let mut category = category.to_string(); - let level = format_ident!( - "{}", - match category.as_str() { - "correctness" => "Deny", - "style" | "suspicious" | "complexity" | "perf" => "Warn", - "pedantic" | "restriction" | "cargo" | "nursery" | "internal" => "Allow", - _ => panic!("unknown category {category}"), - }, - ); + let level = format_ident!("{}", match category.as_str() { + "correctness" => "Deny", + "style" | "suspicious" | "complexity" | "perf" => "Warn", + "pedantic" | "restriction" | "cargo" | "nursery" | "internal" => "Allow", + _ => panic!("unknown category {category}"), + },); let info_name = format_ident!("{name}_INFO"); diff --git a/lintcheck/src/driver.rs b/lintcheck/src/driver.rs index 2fda2b00f87..87ab14ba0cf 100644 --- a/lintcheck/src/driver.rs +++ b/lintcheck/src/driver.rs @@ -1,4 +1,4 @@ -use crate::recursive::{deserialize_line, serialize_line, DriverInfo}; +use crate::recursive::{DriverInfo, deserialize_line, serialize_line}; use std::io::{self, BufReader, Write}; use std::net::TcpStream; diff --git a/lintcheck/src/recursive.rs b/lintcheck/src/recursive.rs index 6a662970ae8..57073f52364 100644 --- a/lintcheck/src/recursive.rs +++ b/lintcheck/src/recursive.rs @@ -3,8 +3,8 @@ //! [`LintcheckServer`] to ask if it should be skipped, and if not sends the stderr of running //! clippy on the crate to the server -use crate::input::RecursiveOptions; use crate::ClippyWarning; +use crate::input::RecursiveOptions; use std::collections::HashSet; use std::io::{BufRead, BufReader, Read, Write}; diff --git a/rust-toolchain b/rust-toolchain index 0be2e81810e..b431599c224 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,4 +1,4 @@ [toolchain] -channel = "nightly-2024-08-23" +channel = "nightly-2024-09-22" 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 0ac3f35b446..324f754e615 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -15,9 +15,9 @@ extern crate rustc_session; extern crate rustc_span; use rustc_interface::interface; +use rustc_session::EarlyDiagCtxt; use rustc_session::config::ErrorOutputType; use rustc_session::parse::ParseSess; -use rustc_session::EarlyDiagCtxt; use rustc_span::symbol::Symbol; use std::env; @@ -268,8 +268,6 @@ pub fn main() { }, _ => Some(s.to_string()), }) - // FIXME: remove this line in 1.79 to only keep `--cfg clippy`. - .chain(vec!["--cfg".into(), r#"feature="cargo-clippy""#.into()]) .chain(vec!["--cfg".into(), "clippy".into()]) .collect::>(); diff --git a/tests/compile-test.rs b/tests/compile-test.rs index 9754254cdd0..af2aa519257 100644 --- a/tests/compile-test.rs +++ b/tests/compile-test.rs @@ -2,26 +2,25 @@ #![warn(rust_2018_idioms, unused_lifetimes)] #![allow(unused_extern_crates)] -use cargo_metadata::diagnostic::{Applicability, Diagnostic}; use cargo_metadata::Message; +use cargo_metadata::diagnostic::{Applicability, Diagnostic}; use clippy_config::ClippyConfiguration; +use clippy_lints::LintInfo; use clippy_lints::declared_lints::LINTS; use clippy_lints::deprecated_lints::{DEPRECATED, DEPRECATED_VERSION, RENAMED}; -use clippy_lints::LintInfo; use serde::{Deserialize, Serialize}; use test_utils::IS_RUSTC_TEST_SUITE; -use ui_test::custom_flags::rustfix::RustfixMode; use ui_test::custom_flags::Flag; +use ui_test::custom_flags::rustfix::RustfixMode; use ui_test::spanned::Spanned; -use ui_test::test_result::TestRun; -use ui_test::{status_emitter, Args, CommandBuilder, Config, Match, OutputConflictHandling}; +use ui_test::{Args, CommandBuilder, Config, Match, OutputConflictHandling, status_emitter}; use std::collections::{BTreeMap, HashMap}; use std::env::{self, set_var, var_os}; use std::ffi::{OsStr, OsString}; use std::fmt::Write; use std::path::{Path, PathBuf}; -use std::sync::mpsc::{channel, Sender}; +use std::sync::mpsc::{Sender, channel}; use std::{fs, iter, thread}; // Test dependencies may need an `extern crate` here to ensure that they show up @@ -469,15 +468,14 @@ fn applicability_ord(applicability: &Applicability) -> u8 { impl Flag for DiagnosticCollector { fn post_test_action( &self, - _config: &ui_test::per_test_config::TestConfig<'_>, - _cmd: &mut std::process::Command, + _config: &ui_test::per_test_config::TestConfig, output: &std::process::Output, - _build_manager: &ui_test::build_manager::BuildManager<'_>, - ) -> Result, ui_test::Errored> { + _build_manager: &ui_test::build_manager::BuildManager, + ) -> Result<(), ui_test::Errored> { if !output.stderr.is_empty() { self.sender.send(output.stderr.clone()).unwrap(); } - Ok(Vec::new()) + Ok(()) } fn clone_inner(&self) -> Box { diff --git a/tests/config-metadata.rs b/tests/config-metadata.rs index 3e3711873ba..628dfc8f758 100644 --- a/tests/config-metadata.rs +++ b/tests/config-metadata.rs @@ -1,6 +1,6 @@ #![feature(rustc_private)] -use clippy_config::{get_configuration_metadata, ClippyConfiguration}; +use clippy_config::{ClippyConfiguration, get_configuration_metadata}; use itertools::Itertools; use regex::Regex; use std::borrow::Cow; diff --git a/tests/dogfood.rs b/tests/dogfood.rs index 8d10d5e7161..858be389a9e 100644 --- a/tests/dogfood.rs +++ b/tests/dogfood.rs @@ -6,11 +6,9 @@ #![warn(rust_2018_idioms, unused_lifetimes)] use itertools::Itertools; -use std::fs::File; use std::io::{self, IsTerminal}; use std::path::PathBuf; use std::process::Command; -use std::time::SystemTime; use test_utils::IS_RUSTC_TEST_SUITE; use ui_test::Args; @@ -28,11 +26,7 @@ fn main() { println!("dogfood: test"); } } else if !args.skip.iter().any(|arg| arg == "dogfood") { - if args.filters.iter().any(|arg| arg == "collect_metadata") { - collect_metadata(); - } else { - dogfood(); - } + dogfood(); } } @@ -61,47 +55,6 @@ fn dogfood() { ); } -fn collect_metadata() { - assert!(cfg!(feature = "internal")); - - // Setup for validation - let metadata_output_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("util/gh-pages/lints.json"); - let start_time = SystemTime::now(); - - // Run collection as is - std::env::set_var("ENABLE_METADATA_COLLECTION", "1"); - assert!(run_clippy_for_package( - "clippy_lints", - &["-A", "unfulfilled_lint_expectations"] - )); - - // Check if cargo caching got in the way - if let Ok(file) = File::open(metadata_output_path) { - if let Ok(metadata) = file.metadata() { - if let Ok(last_modification) = metadata.modified() { - if last_modification > start_time { - // The output file has been modified. Most likely by a hungry - // metadata collection monster. So We'll return. - return; - } - } - } - } - - // Force cargo to invalidate the caches - filetime::set_file_mtime( - PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("clippy_lints/src/lib.rs"), - filetime::FileTime::now(), - ) - .unwrap(); - - // Running the collection again - assert!(run_clippy_for_package( - "clippy_lints", - &["-A", "unfulfilled_lint_expectations"] - )); -} - #[must_use] fn run_clippy_for_package(project: &str, args: &[&str]) -> bool { let root_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")); diff --git a/tests/ui-internal/unnecessary_def_path.fixed b/tests/ui-internal/unnecessary_def_path.fixed index 3908411da82..0a994842834 100644 --- a/tests/ui-internal/unnecessary_def_path.fixed +++ b/tests/ui-internal/unnecessary_def_path.fixed @@ -13,7 +13,7 @@ extern crate rustc_span; use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item, match_type}; #[allow(unused)] use clippy_utils::{ - is_expr_path_def_path, is_path_diagnostic_item, is_res_diagnostic_ctor, is_res_lang_ctor, is_trait_method, + is_enum_variant_ctor, is_expr_path_def_path, is_path_diagnostic_item, is_res_lang_ctor, is_trait_method, match_def_path, match_trait_method, path_res, }; @@ -22,8 +22,8 @@ use rustc_hir::LangItem; #[allow(unused)] use rustc_span::sym; -use rustc_hir::def_id::DefId; use rustc_hir::Expr; +use rustc_hir::def_id::DefId; use rustc_lint::LateContext; use rustc_middle::ty::Ty; diff --git a/tests/ui-internal/unnecessary_def_path.rs b/tests/ui-internal/unnecessary_def_path.rs index 632e26215a4..ba68de6c6d0 100644 --- a/tests/ui-internal/unnecessary_def_path.rs +++ b/tests/ui-internal/unnecessary_def_path.rs @@ -13,7 +13,7 @@ extern crate rustc_span; use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item, match_type}; #[allow(unused)] use clippy_utils::{ - is_expr_path_def_path, is_path_diagnostic_item, is_res_diagnostic_ctor, is_res_lang_ctor, is_trait_method, + is_enum_variant_ctor, is_expr_path_def_path, is_path_diagnostic_item, is_res_lang_ctor, is_trait_method, match_def_path, match_trait_method, path_res, }; @@ -22,8 +22,8 @@ use rustc_hir::LangItem; #[allow(unused)] use rustc_span::sym; -use rustc_hir::def_id::DefId; use rustc_hir::Expr; +use rustc_hir::def_id::DefId; use rustc_lint::LateContext; use rustc_middle::ty::Ty; diff --git a/tests/ui-toml/disallowed_names_append/disallowed_names.rs b/tests/ui-toml/disallowed_names_append/disallowed_names.rs index a2e2b46c426..61ae8de8e33 100644 --- a/tests/ui-toml/disallowed_names_append/disallowed_names.rs +++ b/tests/ui-toml/disallowed_names_append/disallowed_names.rs @@ -1,4 +1,4 @@ -#[warn(clippy::disallowed_names)] +#![warn(clippy::disallowed_names)] fn main() { // `foo` is part of the default configuration diff --git a/tests/ui-toml/disallowed_names_replace/disallowed_names.rs b/tests/ui-toml/disallowed_names_replace/disallowed_names.rs index a2e2b46c426..61ae8de8e33 100644 --- a/tests/ui-toml/disallowed_names_replace/disallowed_names.rs +++ b/tests/ui-toml/disallowed_names_replace/disallowed_names.rs @@ -1,4 +1,4 @@ -#[warn(clippy::disallowed_names)] +#![warn(clippy::disallowed_names)] fn main() { // `foo` is part of the default configuration diff --git a/tests/ui-toml/missing_enforced_import_rename/conf_missing_enforced_import_rename.fixed b/tests/ui-toml/missing_enforced_import_rename/conf_missing_enforced_import_rename.fixed index 5f4f007cf5c..a6072111dc0 100644 --- a/tests/ui-toml/missing_enforced_import_rename/conf_missing_enforced_import_rename.fixed +++ b/tests/ui-toml/missing_enforced_import_rename/conf_missing_enforced_import_rename.fixed @@ -2,7 +2,7 @@ use std::alloc as colla; use std::option::Option as Maybe; -use std::process::{exit as goodbye, Child as Kid}; +use std::process::{Child as Kid, exit as goodbye}; use std::thread::sleep as thread_sleep; #[rustfmt::skip] use std::{ diff --git a/tests/ui-toml/missing_enforced_import_rename/conf_missing_enforced_import_rename.rs b/tests/ui-toml/missing_enforced_import_rename/conf_missing_enforced_import_rename.rs index f60058c8628..c2b61aab5b3 100644 --- a/tests/ui-toml/missing_enforced_import_rename/conf_missing_enforced_import_rename.rs +++ b/tests/ui-toml/missing_enforced_import_rename/conf_missing_enforced_import_rename.rs @@ -2,7 +2,7 @@ use std::alloc as colla; use std::option::Option as Maybe; -use std::process::{exit as wrong_exit, Child as Kid}; +use std::process::{Child as Kid, exit as wrong_exit}; use std::thread::sleep; #[rustfmt::skip] use std::{ diff --git a/tests/ui-toml/missing_enforced_import_rename/conf_missing_enforced_import_rename.stderr b/tests/ui-toml/missing_enforced_import_rename/conf_missing_enforced_import_rename.stderr index f66938c83fb..d3bb07ec47f 100644 --- a/tests/ui-toml/missing_enforced_import_rename/conf_missing_enforced_import_rename.stderr +++ b/tests/ui-toml/missing_enforced_import_rename/conf_missing_enforced_import_rename.stderr @@ -1,8 +1,8 @@ error: this import should be renamed - --> tests/ui-toml/missing_enforced_import_rename/conf_missing_enforced_import_rename.rs:5:20 + --> tests/ui-toml/missing_enforced_import_rename/conf_missing_enforced_import_rename.rs:5:34 | -LL | use std::process::{exit as wrong_exit, Child as Kid}; - | ^^^^^^^^^^^^^^^^^^ help: try: `exit as goodbye` +LL | use std::process::{Child as Kid, exit as wrong_exit}; + | ^^^^^^^^^^^^^^^^^^ help: try: `exit as goodbye` | = note: `-D clippy::missing-enforced-import-renames` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::missing_enforced_import_renames)]` diff --git a/tests/ui-toml/panic/panic.rs b/tests/ui-toml/panic/panic.rs index 618a37ddfc5..b6264c950e4 100644 --- a/tests/ui-toml/panic/panic.rs +++ b/tests/ui-toml/panic/panic.rs @@ -1,5 +1,6 @@ //@compile-flags: --test #![warn(clippy::panic)] +use std::panic::panic_any; fn main() { enum Enam { @@ -12,6 +13,10 @@ fn main() { } } +fn issue_13292() { + panic_any("should lint") +} + #[test] fn lonely_test() { enum Enam { diff --git a/tests/ui-toml/panic/panic.stderr b/tests/ui-toml/panic/panic.stderr index bf7503e086c..a034207d919 100644 --- a/tests/ui-toml/panic/panic.stderr +++ b/tests/ui-toml/panic/panic.stderr @@ -1,5 +1,5 @@ error: `panic` should not be present in production code - --> tests/ui-toml/panic/panic.rs:11:14 + --> tests/ui-toml/panic/panic.rs:12:14 | LL | _ => panic!(""), | ^^^^^^^^^^ @@ -7,5 +7,11 @@ LL | _ => panic!(""), = note: `-D clippy::panic` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::panic)]` -error: aborting due to 1 previous error +error: `panic_any` should not be present in production code + --> tests/ui-toml/panic/panic.rs:17:5 + | +LL | panic_any("should lint") + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors diff --git a/tests/ui/allow_attributes.fixed b/tests/ui/allow_attributes.fixed index 49ee3ee17c7..058dbb77a32 100644 --- a/tests/ui/allow_attributes.fixed +++ b/tests/ui/allow_attributes.fixed @@ -58,3 +58,10 @@ fn msrv_1_80() { #[allow(unused)] let x = 1; } + +#[deny(clippy::allow_attributes)] +fn deny_allow_attributes() -> Option { + let allow = None; + allow?; + Some(42) +} diff --git a/tests/ui/allow_attributes.rs b/tests/ui/allow_attributes.rs index 854acf8348d..6d94ce50e4c 100644 --- a/tests/ui/allow_attributes.rs +++ b/tests/ui/allow_attributes.rs @@ -58,3 +58,10 @@ fn msrv_1_80() { #[allow(unused)] let x = 1; } + +#[deny(clippy::allow_attributes)] +fn deny_allow_attributes() -> Option { + let allow = None; + allow?; + Some(42) +} diff --git a/tests/ui/allow_attributes_without_reason.rs b/tests/ui/allow_attributes_without_reason.rs index 86f6b2c5742..334e7ddd9d2 100644 --- a/tests/ui/allow_attributes_without_reason.rs +++ b/tests/ui/allow_attributes_without_reason.rs @@ -15,7 +15,6 @@ use proc_macros::{external, with_span}; #[warn(deref_nullptr)] #[deny(deref_nullptr)] #[forbid(deref_nullptr)] - fn main() { external! { #[allow(dead_code)] diff --git a/tests/ui/allow_attributes_without_reason.stderr b/tests/ui/allow_attributes_without_reason.stderr index 9bc3ca0f2af..86d7845df04 100644 --- a/tests/ui/allow_attributes_without_reason.stderr +++ b/tests/ui/allow_attributes_without_reason.stderr @@ -36,7 +36,7 @@ LL | #[expect(dead_code)] = help: try adding a reason at the end with `, reason = ".."` error: `allow` attribute without specifying a reason - --> tests/ui/allow_attributes_without_reason.rs:47:5 + --> tests/ui/allow_attributes_without_reason.rs:46:5 | LL | #[allow(unused)] | ^^^^^^^^^^^^^^^^ @@ -44,7 +44,7 @@ LL | #[allow(unused)] = help: try adding a reason at the end with `, reason = ".."` error: `allow` attribute without specifying a reason - --> tests/ui/allow_attributes_without_reason.rs:47:5 + --> tests/ui/allow_attributes_without_reason.rs:46:5 | LL | #[allow(unused)] | ^^^^^^^^^^^^^^^^ diff --git a/tests/ui/arithmetic_side_effects.rs b/tests/ui/arithmetic_side_effects.rs index 0838d064a5f..3f204073085 100644 --- a/tests/ui/arithmetic_side_effects.rs +++ b/tests/ui/arithmetic_side_effects.rs @@ -2,7 +2,6 @@ #![feature(f128)] #![feature(f16)] - #![allow( clippy::assign_op_pattern, clippy::erasing_op, diff --git a/tests/ui/arithmetic_side_effects.stderr b/tests/ui/arithmetic_side_effects.stderr index 78914667bf3..78b1aca4b8a 100644 --- a/tests/ui/arithmetic_side_effects.stderr +++ b/tests/ui/arithmetic_side_effects.stderr @@ -1,5 +1,5 @@ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:167:13 + --> tests/ui/arithmetic_side_effects.rs:166:13 | LL | let _ = 1f16 + 1f16; | ^^^^^^^^^^^ @@ -8,733 +8,733 @@ LL | let _ = 1f16 + 1f16; = help: to override `-D warnings` add `#[allow(clippy::arithmetic_side_effects)]` error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:170:13 + --> tests/ui/arithmetic_side_effects.rs:169:13 | LL | let _ = 1f128 + 1f128; | ^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:308:5 + --> tests/ui/arithmetic_side_effects.rs:307:5 | LL | _n += 1; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:309:5 + --> tests/ui/arithmetic_side_effects.rs:308:5 | LL | _n += &1; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:310:5 + --> tests/ui/arithmetic_side_effects.rs:309:5 | LL | _n -= 1; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:311:5 + --> tests/ui/arithmetic_side_effects.rs:310:5 | LL | _n -= &1; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:312:5 + --> tests/ui/arithmetic_side_effects.rs:311:5 | LL | _n /= 0; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:313:5 + --> tests/ui/arithmetic_side_effects.rs:312:5 | LL | _n /= &0; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:314:5 + --> tests/ui/arithmetic_side_effects.rs:313:5 | LL | _n %= 0; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:315:5 + --> tests/ui/arithmetic_side_effects.rs:314:5 | LL | _n %= &0; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:316:5 + --> tests/ui/arithmetic_side_effects.rs:315:5 | LL | _n *= 2; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:317:5 + --> tests/ui/arithmetic_side_effects.rs:316:5 | LL | _n *= &2; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:318:5 + --> tests/ui/arithmetic_side_effects.rs:317:5 | LL | _n += -1; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:319:5 + --> tests/ui/arithmetic_side_effects.rs:318:5 | LL | _n += &-1; | ^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:320:5 + --> tests/ui/arithmetic_side_effects.rs:319:5 | LL | _n -= -1; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:321:5 + --> tests/ui/arithmetic_side_effects.rs:320:5 | LL | _n -= &-1; | ^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:322:5 + --> tests/ui/arithmetic_side_effects.rs:321:5 | LL | _n /= -0; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:323:5 + --> tests/ui/arithmetic_side_effects.rs:322:5 | LL | _n /= &-0; | ^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:324:5 + --> tests/ui/arithmetic_side_effects.rs:323:5 | LL | _n %= -0; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:325:5 + --> tests/ui/arithmetic_side_effects.rs:324:5 | LL | _n %= &-0; | ^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:326:5 + --> tests/ui/arithmetic_side_effects.rs:325:5 | LL | _n *= -2; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:327:5 + --> tests/ui/arithmetic_side_effects.rs:326:5 | LL | _n *= &-2; | ^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:328:5 + --> tests/ui/arithmetic_side_effects.rs:327:5 | LL | _custom += Custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:329:5 + --> tests/ui/arithmetic_side_effects.rs:328:5 | LL | _custom += &Custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:330:5 + --> tests/ui/arithmetic_side_effects.rs:329:5 | LL | _custom -= Custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:331:5 + --> tests/ui/arithmetic_side_effects.rs:330:5 | LL | _custom -= &Custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:332:5 + --> tests/ui/arithmetic_side_effects.rs:331:5 | LL | _custom /= Custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:333:5 + --> tests/ui/arithmetic_side_effects.rs:332:5 | LL | _custom /= &Custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:334:5 + --> tests/ui/arithmetic_side_effects.rs:333:5 | LL | _custom %= Custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:335:5 + --> tests/ui/arithmetic_side_effects.rs:334:5 | LL | _custom %= &Custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:336:5 + --> tests/ui/arithmetic_side_effects.rs:335:5 | LL | _custom *= Custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:337:5 + --> tests/ui/arithmetic_side_effects.rs:336:5 | LL | _custom *= &Custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:338:5 + --> tests/ui/arithmetic_side_effects.rs:337:5 | LL | _custom >>= Custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:339:5 + --> tests/ui/arithmetic_side_effects.rs:338:5 | LL | _custom >>= &Custom; | ^^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:340:5 + --> tests/ui/arithmetic_side_effects.rs:339:5 | LL | _custom <<= Custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:341:5 + --> tests/ui/arithmetic_side_effects.rs:340:5 | LL | _custom <<= &Custom; | ^^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:342:5 + --> tests/ui/arithmetic_side_effects.rs:341:5 | LL | _custom += -Custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:343:5 + --> tests/ui/arithmetic_side_effects.rs:342:5 | LL | _custom += &-Custom; | ^^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:344:5 + --> tests/ui/arithmetic_side_effects.rs:343:5 | LL | _custom -= -Custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:345:5 + --> tests/ui/arithmetic_side_effects.rs:344:5 | LL | _custom -= &-Custom; | ^^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:346:5 + --> tests/ui/arithmetic_side_effects.rs:345:5 | LL | _custom /= -Custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:347:5 + --> tests/ui/arithmetic_side_effects.rs:346:5 | LL | _custom /= &-Custom; | ^^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:348:5 + --> tests/ui/arithmetic_side_effects.rs:347:5 | LL | _custom %= -Custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:349:5 + --> tests/ui/arithmetic_side_effects.rs:348:5 | LL | _custom %= &-Custom; | ^^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:350:5 + --> tests/ui/arithmetic_side_effects.rs:349:5 | LL | _custom *= -Custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:351:5 + --> tests/ui/arithmetic_side_effects.rs:350:5 | LL | _custom *= &-Custom; | ^^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:352:5 + --> tests/ui/arithmetic_side_effects.rs:351:5 | LL | _custom >>= -Custom; | ^^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:353:5 + --> tests/ui/arithmetic_side_effects.rs:352:5 | LL | _custom >>= &-Custom; | ^^^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:354:5 + --> tests/ui/arithmetic_side_effects.rs:353:5 | LL | _custom <<= -Custom; | ^^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:355:5 + --> tests/ui/arithmetic_side_effects.rs:354:5 | LL | _custom <<= &-Custom; | ^^^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:358:10 + --> tests/ui/arithmetic_side_effects.rs:357:10 | LL | _n = _n + 1; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:359:10 + --> tests/ui/arithmetic_side_effects.rs:358:10 | LL | _n = _n + &1; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:360:10 + --> tests/ui/arithmetic_side_effects.rs:359:10 | LL | _n = 1 + _n; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:361:10 + --> tests/ui/arithmetic_side_effects.rs:360:10 | LL | _n = &1 + _n; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:362:10 + --> tests/ui/arithmetic_side_effects.rs:361:10 | LL | _n = _n - 1; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:363:10 + --> tests/ui/arithmetic_side_effects.rs:362:10 | LL | _n = _n - &1; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:364:10 + --> tests/ui/arithmetic_side_effects.rs:363:10 | LL | _n = 1 - _n; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:365:10 + --> tests/ui/arithmetic_side_effects.rs:364:10 | LL | _n = &1 - _n; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:366:10 + --> tests/ui/arithmetic_side_effects.rs:365:10 | LL | _n = _n / 0; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:367:10 + --> tests/ui/arithmetic_side_effects.rs:366:10 | LL | _n = _n / &0; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:368:10 + --> tests/ui/arithmetic_side_effects.rs:367:10 | LL | _n = _n % 0; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:369:10 + --> tests/ui/arithmetic_side_effects.rs:368:10 | LL | _n = _n % &0; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:370:10 + --> tests/ui/arithmetic_side_effects.rs:369:10 | LL | _n = _n * 2; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:371:10 + --> tests/ui/arithmetic_side_effects.rs:370:10 | LL | _n = _n * &2; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:372:10 + --> tests/ui/arithmetic_side_effects.rs:371:10 | LL | _n = 2 * _n; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:373:10 + --> tests/ui/arithmetic_side_effects.rs:372:10 | LL | _n = &2 * _n; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:374:10 + --> tests/ui/arithmetic_side_effects.rs:373:10 | LL | _n = 23 + &85; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:375:10 + --> tests/ui/arithmetic_side_effects.rs:374:10 | LL | _n = &23 + 85; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:376:10 + --> tests/ui/arithmetic_side_effects.rs:375:10 | LL | _n = &23 + &85; | ^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:377:15 + --> tests/ui/arithmetic_side_effects.rs:376:15 | LL | _custom = _custom + _custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:378:15 + --> tests/ui/arithmetic_side_effects.rs:377:15 | LL | _custom = _custom + &_custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:379:15 + --> tests/ui/arithmetic_side_effects.rs:378:15 | LL | _custom = Custom + _custom; | ^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:380:15 + --> tests/ui/arithmetic_side_effects.rs:379:15 | LL | _custom = &Custom + _custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:381:15 + --> tests/ui/arithmetic_side_effects.rs:380:15 | LL | _custom = _custom - Custom; | ^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:382:15 + --> tests/ui/arithmetic_side_effects.rs:381:15 | LL | _custom = _custom - &Custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:383:15 + --> tests/ui/arithmetic_side_effects.rs:382:15 | LL | _custom = Custom - _custom; | ^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:384:15 + --> tests/ui/arithmetic_side_effects.rs:383:15 | LL | _custom = &Custom - _custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:385:15 + --> tests/ui/arithmetic_side_effects.rs:384:15 | LL | _custom = _custom / Custom; | ^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:386:15 + --> tests/ui/arithmetic_side_effects.rs:385:15 | LL | _custom = _custom / &Custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:387:15 + --> tests/ui/arithmetic_side_effects.rs:386:15 | LL | _custom = _custom % Custom; | ^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:388:15 + --> tests/ui/arithmetic_side_effects.rs:387:15 | LL | _custom = _custom % &Custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:389:15 + --> tests/ui/arithmetic_side_effects.rs:388:15 | LL | _custom = _custom * Custom; | ^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:390:15 + --> tests/ui/arithmetic_side_effects.rs:389:15 | LL | _custom = _custom * &Custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:391:15 + --> tests/ui/arithmetic_side_effects.rs:390:15 | LL | _custom = Custom * _custom; | ^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:392:15 + --> tests/ui/arithmetic_side_effects.rs:391:15 | LL | _custom = &Custom * _custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:393:15 + --> tests/ui/arithmetic_side_effects.rs:392:15 | LL | _custom = Custom + &Custom; | ^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:394:15 + --> tests/ui/arithmetic_side_effects.rs:393:15 | LL | _custom = &Custom + Custom; | ^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:395:15 + --> tests/ui/arithmetic_side_effects.rs:394:15 | LL | _custom = &Custom + &Custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:396:15 + --> tests/ui/arithmetic_side_effects.rs:395:15 | LL | _custom = _custom >> _custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:397:15 + --> tests/ui/arithmetic_side_effects.rs:396:15 | LL | _custom = _custom >> &_custom; | ^^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:398:15 + --> tests/ui/arithmetic_side_effects.rs:397:15 | LL | _custom = Custom << _custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:399:15 + --> tests/ui/arithmetic_side_effects.rs:398:15 | LL | _custom = &Custom << _custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:402:23 + --> tests/ui/arithmetic_side_effects.rs:401:23 | LL | _n.saturating_div(0); | ^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:403:21 + --> tests/ui/arithmetic_side_effects.rs:402:21 | LL | _n.wrapping_div(0); | ^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:404:21 + --> tests/ui/arithmetic_side_effects.rs:403:21 | LL | _n.wrapping_rem(0); | ^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:405:28 + --> tests/ui/arithmetic_side_effects.rs:404:28 | LL | _n.wrapping_rem_euclid(0); | ^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:407:23 + --> tests/ui/arithmetic_side_effects.rs:406:23 | LL | _n.saturating_div(_n); | ^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:408:21 + --> tests/ui/arithmetic_side_effects.rs:407:21 | LL | _n.wrapping_div(_n); | ^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:409:21 + --> tests/ui/arithmetic_side_effects.rs:408:21 | LL | _n.wrapping_rem(_n); | ^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:410:28 + --> tests/ui/arithmetic_side_effects.rs:409:28 | LL | _n.wrapping_rem_euclid(_n); | ^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:413:10 + --> tests/ui/arithmetic_side_effects.rs:412:10 | LL | _n = -_n; | ^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:414:10 + --> tests/ui/arithmetic_side_effects.rs:413:10 | LL | _n = -&_n; | ^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:415:15 + --> tests/ui/arithmetic_side_effects.rs:414:15 | LL | _custom = -_custom; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:416:15 + --> tests/ui/arithmetic_side_effects.rs:415:15 | LL | _custom = -&_custom; | ^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:425:5 + --> tests/ui/arithmetic_side_effects.rs:424:5 | LL | 1 + i; | ^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:426:5 + --> tests/ui/arithmetic_side_effects.rs:425:5 | LL | i * 2; | ^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:427:5 + --> tests/ui/arithmetic_side_effects.rs:426:5 | LL | 1 % i / 2; | ^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:428:5 + --> tests/ui/arithmetic_side_effects.rs:427:5 | LL | i - 2 + 2 - i; | ^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:429:5 + --> tests/ui/arithmetic_side_effects.rs:428:5 | LL | -i; | ^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:440:5 + --> tests/ui/arithmetic_side_effects.rs:439:5 | LL | i += 1; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:441:5 + --> tests/ui/arithmetic_side_effects.rs:440:5 | LL | i -= 1; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:442:5 + --> tests/ui/arithmetic_side_effects.rs:441:5 | LL | i *= 2; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:444:5 + --> tests/ui/arithmetic_side_effects.rs:443:5 | LL | i /= 0; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:446:5 + --> tests/ui/arithmetic_side_effects.rs:445:5 | LL | i /= var1; | ^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:447:5 + --> tests/ui/arithmetic_side_effects.rs:446:5 | LL | i /= var2; | ^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:449:5 + --> tests/ui/arithmetic_side_effects.rs:448:5 | LL | i %= 0; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:451:5 + --> tests/ui/arithmetic_side_effects.rs:450:5 | LL | i %= var1; | ^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:452:5 + --> tests/ui/arithmetic_side_effects.rs:451:5 | LL | i %= var2; | ^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:462:5 + --> tests/ui/arithmetic_side_effects.rs:461:5 | LL | 10 / a | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:516:9 + --> tests/ui/arithmetic_side_effects.rs:515:9 | LL | x / maybe_zero | ^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:520:9 + --> tests/ui/arithmetic_side_effects.rs:519:9 | LL | x % maybe_zero | ^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:531:5 + --> tests/ui/arithmetic_side_effects.rs:530:5 | LL | one.add_assign(1); | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:535:5 + --> tests/ui/arithmetic_side_effects.rs:534:5 | LL | one.sub_assign(1); | ^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/asm_syntax_not_x86.rs b/tests/ui/asm_syntax_not_x86.rs index 33cea480681..a7d29cc239e 100644 --- a/tests/ui/asm_syntax_not_x86.rs +++ b/tests/ui/asm_syntax_not_x86.rs @@ -1,5 +1,4 @@ -//@ignore-target-i686 -//@ignore-target-x86 +//@ignore-target: i686 x86 //@needs-asm-support #[warn(clippy::inline_asm_x86_intel_syntax)] diff --git a/tests/ui/asm_syntax_x86.rs b/tests/ui/asm_syntax_x86.rs index 835943b4389..5ceaceb7527 100644 --- a/tests/ui/asm_syntax_x86.rs +++ b/tests/ui/asm_syntax_x86.rs @@ -1,6 +1,4 @@ -//@revisions: i686 x86_64 -//@[i686] only-target-i686 -//@[x86_64] only-target-x86_64 +//@only-target: i686 x86_64 #[warn(clippy::inline_asm_x86_intel_syntax)] mod warn_intel { diff --git a/tests/ui/asm_syntax_x86.stderr b/tests/ui/asm_syntax_x86.stderr new file mode 100644 index 00000000000..1911ef66e23 --- /dev/null +++ b/tests/ui/asm_syntax_x86.stderr @@ -0,0 +1,70 @@ +error: Intel x86 assembly syntax used + --> tests/ui/asm_syntax_x86.rs:8:9 + | +LL | asm!(""); + | ^^^^^^^^ + | + = help: use AT&T x86 assembly syntax + = note: `-D clippy::inline-asm-x86-intel-syntax` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::inline_asm_x86_intel_syntax)]` + +error: Intel x86 assembly syntax used + --> tests/ui/asm_syntax_x86.rs:10:9 + | +LL | asm!("", options()); + | ^^^^^^^^^^^^^^^^^^^ + | + = help: use AT&T x86 assembly syntax + +error: Intel x86 assembly syntax used + --> tests/ui/asm_syntax_x86.rs:12:9 + | +LL | asm!("", options(nostack)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use AT&T x86 assembly syntax + +error: Intel x86 assembly syntax used + --> tests/ui/asm_syntax_x86.rs:18:5 + | +LL | global_asm!(""); + | ^^^^^^^^^^^^^^^ + | + = help: use AT&T x86 assembly syntax + +error: Intel x86 assembly syntax used + --> tests/ui/asm_syntax_x86.rs:20:5 + | +LL | global_asm!("", options()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use AT&T x86 assembly syntax + +error: AT&T x86 assembly syntax used + --> tests/ui/asm_syntax_x86.rs:33:9 + | +LL | asm!("", options(att_syntax)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use Intel x86 assembly syntax + = note: `-D clippy::inline-asm-x86-att-syntax` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::inline_asm_x86_att_syntax)]` + +error: AT&T x86 assembly syntax used + --> tests/ui/asm_syntax_x86.rs:35:9 + | +LL | asm!("", options(nostack, att_syntax)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use Intel x86 assembly syntax + +error: AT&T x86 assembly syntax used + --> tests/ui/asm_syntax_x86.rs:41:5 + | +LL | global_asm!("", options(att_syntax)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use Intel x86 assembly syntax + +error: aborting due to 8 previous errors + diff --git a/tests/ui/auxiliary/external_item.rs b/tests/ui/auxiliary/external_item.rs new file mode 100644 index 00000000000..ca4bc369e44 --- /dev/null +++ b/tests/ui/auxiliary/external_item.rs @@ -0,0 +1,7 @@ +pub struct _ExternalStruct {} + +impl _ExternalStruct { + pub fn _foo(self) {} +} + +pub fn _exernal_foo() {} diff --git a/tests/ui/auxiliary/proc_macro_attr.rs b/tests/ui/auxiliary/proc_macro_attr.rs index f6fdebaf252..e72d6b6cead 100644 --- a/tests/ui/auxiliary/proc_macro_attr.rs +++ b/tests/ui/auxiliary/proc_macro_attr.rs @@ -11,8 +11,8 @@ use quote::{quote, quote_spanned}; use syn::spanned::Spanned; use syn::token::Star; use syn::{ - parse_macro_input, parse_quote, FnArg, ImplItem, ItemFn, ItemImpl, ItemStruct, ItemTrait, Lifetime, Pat, PatIdent, - PatType, Signature, TraitItem, Type, Visibility, + FnArg, ImplItem, ItemFn, ItemImpl, ItemStruct, ItemTrait, Lifetime, Pat, PatIdent, PatType, Signature, TraitItem, + Type, Visibility, parse_macro_input, parse_quote, }; #[proc_macro_attribute] diff --git a/tests/ui/auxiliary/proc_macro_derive.rs b/tests/ui/auxiliary/proc_macro_derive.rs index 4c3df472269..bd90042c1da 100644 --- a/tests/ui/auxiliary/proc_macro_derive.rs +++ b/tests/ui/auxiliary/proc_macro_derive.rs @@ -5,7 +5,7 @@ extern crate proc_macro; -use proc_macro::{quote, Delimiter, Group, Ident, Literal, Punct, Spacing, Span, TokenStream, TokenTree}; +use proc_macro::{Delimiter, Group, Ident, Literal, Punct, Spacing, Span, TokenStream, TokenTree, quote}; #[proc_macro_derive(DeriveSomething)] pub fn derive(_: TokenStream) -> TokenStream { diff --git a/tests/ui/auxiliary/proc_macro_suspicious_else_formatting.rs b/tests/ui/auxiliary/proc_macro_suspicious_else_formatting.rs index 79e8eff3aa1..3d6f164d358 100644 --- a/tests/ui/auxiliary/proc_macro_suspicious_else_formatting.rs +++ b/tests/ui/auxiliary/proc_macro_suspicious_else_formatting.rs @@ -1,5 +1,5 @@ extern crate proc_macro; -use proc_macro::{token_stream, Delimiter, Group, Ident, Span, TokenStream, TokenTree}; +use proc_macro::{Delimiter, Group, Ident, Span, TokenStream, TokenTree, token_stream}; fn read_ident(iter: &mut token_stream::IntoIter) -> Ident { match iter.next() { diff --git a/tests/ui/auxiliary/proc_macros.rs b/tests/ui/auxiliary/proc_macros.rs index ed7412f7c40..1a2a4ec2311 100644 --- a/tests/ui/auxiliary/proc_macros.rs +++ b/tests/ui/auxiliary/proc_macros.rs @@ -5,9 +5,9 @@ extern crate proc_macro; use core::mem; -use proc_macro::token_stream::IntoIter; use proc_macro::Delimiter::{self, Brace, Parenthesis}; use proc_macro::Spacing::{self, Alone, Joint}; +use proc_macro::token_stream::IntoIter; use proc_macro::{Group, Ident, Literal, Punct, Span, TokenStream, TokenTree as TT}; use syn::spanned::Spanned; diff --git a/tests/ui/borrow_interior_mutable_const/others.rs b/tests/ui/borrow_interior_mutable_const/others.rs index 452d1b19813..de220505c3e 100644 --- a/tests/ui/borrow_interior_mutable_const/others.rs +++ b/tests/ui/borrow_interior_mutable_const/others.rs @@ -5,8 +5,8 @@ use std::borrow::Cow; use std::cell::{Cell, UnsafeCell}; use std::fmt::Display; -use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::Once; +use std::sync::atomic::{AtomicUsize, Ordering}; const ATOMIC: AtomicUsize = AtomicUsize::new(5); const CELL: Cell = Cell::new(6); diff --git a/tests/ui/cast_alignment.rs b/tests/ui/cast_alignment.rs index 98ef5e36f94..72f5d4268cc 100644 --- a/tests/ui/cast_alignment.rs +++ b/tests/ui/cast_alignment.rs @@ -2,16 +2,16 @@ #![feature(rustc_private)] #![feature(core_intrinsics)] -extern crate libc; - -#[warn(clippy::cast_ptr_alignment)] -#[allow( +#![warn(clippy::cast_ptr_alignment)] +#![allow( clippy::no_effect, clippy::unnecessary_operation, clippy::cast_lossless, clippy::borrow_as_ptr )] +extern crate libc; + fn main() { /* These should be warned against */ diff --git a/tests/ui/cmp_owned/without_suggestion.rs b/tests/ui/cmp_owned/without_suggestion.rs index ec45d635c17..913aab72747 100644 --- a/tests/ui/cmp_owned/without_suggestion.rs +++ b/tests/ui/cmp_owned/without_suggestion.rs @@ -1,5 +1,5 @@ -#[allow(clippy::unnecessary_operation)] -#[allow(clippy::implicit_clone)] +#![allow(clippy::unnecessary_operation)] +#![allow(clippy::implicit_clone)] fn main() { let x = &Baz; diff --git a/tests/ui/collapsible_else_if.fixed b/tests/ui/collapsible_else_if.fixed index 3b410b2f17b..c2d76146c64 100644 --- a/tests/ui/collapsible_else_if.fixed +++ b/tests/ui/collapsible_else_if.fixed @@ -1,9 +1,7 @@ #![allow(clippy::assertions_on_constants, clippy::equatable_if_let, clippy::needless_if)] +#![warn(clippy::collapsible_if, clippy::collapsible_else_if)] #[rustfmt::skip] -#[warn(clippy::collapsible_if)] -#[warn(clippy::collapsible_else_if)] - fn main() { let x = "hello"; let y = "world"; @@ -76,7 +74,6 @@ fn main() { } #[rustfmt::skip] -#[allow(dead_code)] fn issue_7318() { if true { println!("I've been resolved!") }else if false {} diff --git a/tests/ui/collapsible_else_if.rs b/tests/ui/collapsible_else_if.rs index 772ef6f9fc6..3579e46cd44 100644 --- a/tests/ui/collapsible_else_if.rs +++ b/tests/ui/collapsible_else_if.rs @@ -1,9 +1,7 @@ #![allow(clippy::assertions_on_constants, clippy::equatable_if_let, clippy::needless_if)] +#![warn(clippy::collapsible_if, clippy::collapsible_else_if)] #[rustfmt::skip] -#[warn(clippy::collapsible_if)] -#[warn(clippy::collapsible_else_if)] - fn main() { let x = "hello"; let y = "world"; @@ -90,7 +88,6 @@ fn main() { } #[rustfmt::skip] -#[allow(dead_code)] fn issue_7318() { if true { println!("I've been resolved!") }else{ diff --git a/tests/ui/collapsible_else_if.stderr b/tests/ui/collapsible_else_if.stderr index dc19d90b4d1..395c2dcf68d 100644 --- a/tests/ui/collapsible_else_if.stderr +++ b/tests/ui/collapsible_else_if.stderr @@ -1,5 +1,5 @@ error: this `else { if .. }` block can be collapsed - --> tests/ui/collapsible_else_if.rs:13:12 + --> tests/ui/collapsible_else_if.rs:11:12 | LL | } else { | ____________^ @@ -19,7 +19,7 @@ LL + } | error: this `else { if .. }` block can be collapsed - --> tests/ui/collapsible_else_if.rs:21:12 + --> tests/ui/collapsible_else_if.rs:19:12 | LL | } else { | ____________^ @@ -37,7 +37,7 @@ LL + } | error: this `else { if .. }` block can be collapsed - --> tests/ui/collapsible_else_if.rs:29:12 + --> tests/ui/collapsible_else_if.rs:27:12 | LL | } else { | ____________^ @@ -60,7 +60,7 @@ LL + } | error: this `else { if .. }` block can be collapsed - --> tests/ui/collapsible_else_if.rs:40:12 + --> tests/ui/collapsible_else_if.rs:38:12 | LL | } else { | ____________^ @@ -83,7 +83,7 @@ LL + } | error: this `else { if .. }` block can be collapsed - --> tests/ui/collapsible_else_if.rs:51:12 + --> tests/ui/collapsible_else_if.rs:49:12 | LL | } else { | ____________^ @@ -106,7 +106,7 @@ LL + } | error: this `else { if .. }` block can be collapsed - --> tests/ui/collapsible_else_if.rs:62:12 + --> tests/ui/collapsible_else_if.rs:60:12 | LL | } else { | ____________^ @@ -129,7 +129,7 @@ LL + } | error: this `else { if .. }` block can be collapsed - --> tests/ui/collapsible_else_if.rs:73:12 + --> tests/ui/collapsible_else_if.rs:71:12 | LL | } else { | ____________^ @@ -152,7 +152,7 @@ LL + } | error: this `else { if .. }` block can be collapsed - --> tests/ui/collapsible_else_if.rs:96:10 + --> tests/ui/collapsible_else_if.rs:93:10 | LL | }else{ | __________^ diff --git a/tests/ui/comparison_to_empty.fixed b/tests/ui/comparison_to_empty.fixed index e102b13a761..a2a3dd9086d 100644 --- a/tests/ui/comparison_to_empty.fixed +++ b/tests/ui/comparison_to_empty.fixed @@ -33,4 +33,12 @@ fn main() { if let [0] = &*s && s == [0] {} + + // Also lint the `PartialEq` methods + let s = String::new(); + let _ = s.is_empty(); + let _ = !s.is_empty(); + let v = vec![0]; + let _ = v.is_empty(); + let _ = !v.is_empty(); } diff --git a/tests/ui/comparison_to_empty.rs b/tests/ui/comparison_to_empty.rs index 69a6c967d38..7c5689a4bbe 100644 --- a/tests/ui/comparison_to_empty.rs +++ b/tests/ui/comparison_to_empty.rs @@ -33,4 +33,12 @@ fn main() { if let [0] = &*s && s == [0] {} + + // Also lint the `PartialEq` methods + let s = String::new(); + let _ = s.eq(""); + let _ = s.ne(""); + let v = vec![0]; + let _ = v.eq(&[]); + let _ = v.ne(&[]); } diff --git a/tests/ui/comparison_to_empty.stderr b/tests/ui/comparison_to_empty.stderr index 6b027459ed3..2ee0efc7dbb 100644 --- a/tests/ui/comparison_to_empty.stderr +++ b/tests/ui/comparison_to_empty.stderr @@ -55,5 +55,29 @@ error: comparison to empty slice LL | && s == [] | ^^^^^^^ help: using `is_empty` is clearer and more explicit: `s.is_empty()` -error: aborting due to 9 previous errors +error: comparison to empty slice + --> tests/ui/comparison_to_empty.rs:39:13 + | +LL | let _ = s.eq(""); + | ^^^^^^^^ help: using `is_empty` is clearer and more explicit: `s.is_empty()` + +error: comparison to empty slice + --> tests/ui/comparison_to_empty.rs:40:13 + | +LL | let _ = s.ne(""); + | ^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!s.is_empty()` + +error: comparison to empty slice + --> tests/ui/comparison_to_empty.rs:42:13 + | +LL | let _ = v.eq(&[]); + | ^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `v.is_empty()` + +error: comparison to empty slice + --> tests/ui/comparison_to_empty.rs:43:13 + | +LL | let _ = v.ne(&[]); + | ^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!v.is_empty()` + +error: aborting due to 13 previous errors diff --git a/tests/ui/crashes/associated-constant-ice.rs b/tests/ui/crashes/associated-constant-ice.rs index 948deba3ea6..fec16671eeb 100644 --- a/tests/ui/crashes/associated-constant-ice.rs +++ b/tests/ui/crashes/associated-constant-ice.rs @@ -1,4 +1,4 @@ -/// Test for https://github.com/rust-lang/rust-clippy/issues/1698 +// Test for https://github.com/rust-lang/rust-clippy/issues/1698 pub trait Trait { const CONSTANT: u8; diff --git a/tests/ui/crashes/cc_seme.rs b/tests/ui/crashes/cc_seme.rs index 98588be9cf8..98897d6d7aa 100644 --- a/tests/ui/crashes/cc_seme.rs +++ b/tests/ui/crashes/cc_seme.rs @@ -1,6 +1,4 @@ -#[allow(dead_code)] - -/// Test for https://github.com/rust-lang/rust-clippy/issues/478 +// Test for https://github.com/rust-lang/rust-clippy/issues/478 enum Baz { One, diff --git a/tests/ui/crashes/ice-11230.rs b/tests/ui/crashes/ice-11230.rs index 5761882273e..94044e9435e 100644 --- a/tests/ui/crashes/ice-11230.rs +++ b/tests/ui/crashes/ice-11230.rs @@ -1,4 +1,4 @@ -/// Test for https://github.com/rust-lang/rust-clippy/issues/11230 +// Test for https://github.com/rust-lang/rust-clippy/issues/11230 fn main() { const A: &[for<'a> fn(&'a ())] = &[]; diff --git a/tests/ui/crashes/ice-1588.rs b/tests/ui/crashes/ice-1588.rs index b0a3d11bce4..9ec093721c1 100644 --- a/tests/ui/crashes/ice-1588.rs +++ b/tests/ui/crashes/ice-1588.rs @@ -1,6 +1,6 @@ #![allow(clippy::all)] -/// Test for https://github.com/rust-lang/rust-clippy/issues/1588 +// Test for https://github.com/rust-lang/rust-clippy/issues/1588 fn main() { match 1 { diff --git a/tests/ui/crashes/ice-1969.rs b/tests/ui/crashes/ice-1969.rs index 96a8fe6c24d..eb901c76729 100644 --- a/tests/ui/crashes/ice-1969.rs +++ b/tests/ui/crashes/ice-1969.rs @@ -1,6 +1,6 @@ #![allow(clippy::all)] -/// Test for https://github.com/rust-lang/rust-clippy/issues/1969 +// Test for https://github.com/rust-lang/rust-clippy/issues/1969 fn main() {} diff --git a/tests/ui/crashes/ice-2499.rs b/tests/ui/crashes/ice-2499.rs index 45b3b1869dd..732f331ad14 100644 --- a/tests/ui/crashes/ice-2499.rs +++ b/tests/ui/crashes/ice-2499.rs @@ -1,8 +1,8 @@ #![allow(dead_code, clippy::char_lit_as_u8, clippy::needless_bool)] -/// Should not trigger an ICE in `SpanlessHash` / `consts::constant` -/// -/// Issue: https://github.com/rust-lang/rust-clippy/issues/2499 +// Should not trigger an ICE in `SpanlessHash` / `consts::constant` +// +// Issue: https://github.com/rust-lang/rust-clippy/issues/2499 fn f(s: &[u8]) -> bool { let t = s[0] as char; diff --git a/tests/ui/crashes/ice-2594.rs b/tests/ui/crashes/ice-2594.rs index 3f3986b6fc6..dddf860bd17 100644 --- a/tests/ui/crashes/ice-2594.rs +++ b/tests/ui/crashes/ice-2594.rs @@ -3,7 +3,6 @@ /// Should not trigger an ICE in `SpanlessHash` / `consts::constant` /// /// Issue: https://github.com/rust-lang/rust-clippy/issues/2594 - fn spanless_hash_ice() { let txt = "something"; let empty_header: [u8; 1] = [1; 1]; diff --git a/tests/ui/crashes/ice-2727.rs b/tests/ui/crashes/ice-2727.rs index 56024abc8f5..59fb9b04b86 100644 --- a/tests/ui/crashes/ice-2727.rs +++ b/tests/ui/crashes/ice-2727.rs @@ -1,4 +1,4 @@ -/// Test for https://github.com/rust-lang/rust-clippy/issues/2727 +// Test for https://github.com/rust-lang/rust-clippy/issues/2727 pub fn f(new: fn()) { new(); diff --git a/tests/ui/crashes/ice-2760.rs b/tests/ui/crashes/ice-2760.rs index 61ef2480498..5f7d91abf99 100644 --- a/tests/ui/crashes/ice-2760.rs +++ b/tests/ui/crashes/ice-2760.rs @@ -5,10 +5,10 @@ dead_code )] -/// This should not compile-fail with: -/// -/// error[E0277]: the trait bound `T: Foo` is not satisfied -// See rust-lang/rust-clippy#2760. +// This should not compile-fail with: +// +// error[E0277]: the trait bound `T: Foo` is not satisfied +// See https://github.com/rust-lang/rust-clippy/issues/2760 trait Foo { type Bar; diff --git a/tests/ui/crashes/ice-2862.rs b/tests/ui/crashes/ice-2862.rs index 8326e3663b0..2573b571f55 100644 --- a/tests/ui/crashes/ice-2862.rs +++ b/tests/ui/crashes/ice-2862.rs @@ -1,4 +1,4 @@ -/// Test for https://github.com/rust-lang/rust-clippy/issues/2862 +// Test for https://github.com/rust-lang/rust-clippy/issues/2862 pub trait FooMap { fn map B>(&self, f: F) -> B; diff --git a/tests/ui/crashes/ice-2865.rs b/tests/ui/crashes/ice-2865.rs index c6298139601..28363707acc 100644 --- a/tests/ui/crashes/ice-2865.rs +++ b/tests/ui/crashes/ice-2865.rs @@ -1,6 +1,6 @@ #![allow(dead_code, clippy::extra_unused_lifetimes)] -/// Test for https://github.com/rust-lang/rust-clippy/issues/2865 +// Test for https://github.com/rust-lang/rust-clippy/issues/2865 struct Ice { size: String, diff --git a/tests/ui/crashes/ice-3151.rs b/tests/ui/crashes/ice-3151.rs index 268ba86fc7a..f88a26cb485 100644 --- a/tests/ui/crashes/ice-3151.rs +++ b/tests/ui/crashes/ice-3151.rs @@ -1,4 +1,4 @@ -/// Test for https://github.com/rust-lang/rust-clippy/issues/3151 +// Test for https://github.com/rust-lang/rust-clippy/issues/3151 #[derive(Clone)] pub struct HashMap { diff --git a/tests/ui/crashes/ice-3462.rs b/tests/ui/crashes/ice-3462.rs index 21cd9d337cd..ccd617e305d 100644 --- a/tests/ui/crashes/ice-3462.rs +++ b/tests/ui/crashes/ice-3462.rs @@ -2,7 +2,7 @@ #![allow(clippy::disallowed_names, clippy::equatable_if_let, clippy::needless_if)] #![allow(unused)] -/// Test for https://github.com/rust-lang/rust-clippy/issues/3462 +// Test for https://github.com/rust-lang/rust-clippy/issues/3462 enum Foo { Bar, diff --git a/tests/ui/crashes/ice-3747.rs b/tests/ui/crashes/ice-3747.rs index cdf018cbc88..44b1d7ed1b2 100644 --- a/tests/ui/crashes/ice-3747.rs +++ b/tests/ui/crashes/ice-3747.rs @@ -1,4 +1,4 @@ -/// Test for https://github.com/rust-lang/rust-clippy/issues/3747 +// Test for https://github.com/rust-lang/rust-clippy/issues/3747 macro_rules! a { ( $pub:tt $($attr:tt)* ) => { diff --git a/tests/ui/crashes/ice-3969.rs b/tests/ui/crashes/ice-3969.rs index d5676cbd91d..ac09ce08753 100644 --- a/tests/ui/crashes/ice-3969.rs +++ b/tests/ui/crashes/ice-3969.rs @@ -1,7 +1,7 @@ // https://github.com/rust-lang/rust-clippy/issues/3969 // used to crash: error: internal compiler error: // src/librustc_traits/normalize_erasing_regions.rs:43: could not fully normalize `::Item test from rustc ./ui/trivial-bounds/trivial-bounds-inconsistent.rs +// std::iter::Iterator>::Item` test from rustc ./ui/trivial-bounds/trivial-bounds-inconsistent.rs // Check that tautalogically false bounds are accepted, and are used // in type inference. @@ -18,7 +18,7 @@ struct Dst { struct TwoStrs(str, str) where str: Sized; -//~^ ERROR: trait bound str: std::marker::Sized does not depend on any type or lifetim +//~^ ERROR: trait bound str: std::marker::Sized does not depend on any type or lifetime //~| NOTE: `-D trivial-bounds` implied by `-D warnings` fn unsized_local() diff --git a/tests/ui/crashes/ice-6251.rs b/tests/ui/crashes/ice-6251.rs index a81137a6465..73e919b6dd2 100644 --- a/tests/ui/crashes/ice-6251.rs +++ b/tests/ui/crashes/ice-6251.rs @@ -1,5 +1,5 @@ // originally from glacier/fixed/77329.rs -// assertion failed: `(left == right) ; different DefIds +// assertion failed: `(left == right)` ; different DefIds //@no-rustfix fn bug() -> impl Iterator { std::iter::empty() diff --git a/tests/ui/crashes/ice-700.rs b/tests/ui/crashes/ice-700.rs index 0cbceedbd6b..5e004b94330 100644 --- a/tests/ui/crashes/ice-700.rs +++ b/tests/ui/crashes/ice-700.rs @@ -1,6 +1,6 @@ #![deny(clippy::all)] -/// Test for https://github.com/rust-lang/rust-clippy/issues/700 +// Test for https://github.com/rust-lang/rust-clippy/issues/700 fn core() {} diff --git a/tests/ui/crashes/ice-7410.rs b/tests/ui/crashes/ice-7410.rs index a2683b3ce34..ccf6d7ff94f 100644 --- a/tests/ui/crashes/ice-7410.rs +++ b/tests/ui/crashes/ice-7410.rs @@ -1,6 +1,5 @@ //@compile-flags: -Clink-arg=-nostartfiles -//@ignore-target-apple -//@ignore-target-windows +//@ignore-target: apple windows #![feature(lang_items, start, libc)] #![no_std] diff --git a/tests/ui/crashes/ice_exact_size.rs b/tests/ui/crashes/ice_exact_size.rs index 30e4b11ec0b..c0671eaff14 100644 --- a/tests/ui/crashes/ice_exact_size.rs +++ b/tests/ui/crashes/ice_exact_size.rs @@ -1,6 +1,6 @@ #![deny(clippy::all)] -/// Test for https://github.com/rust-lang/rust-clippy/issues/1336 +// Test for https://github.com/rust-lang/rust-clippy/issues/1336 #[allow(dead_code)] struct Foo; diff --git a/tests/ui/crashes/if_same_then_else.rs b/tests/ui/crashes/if_same_then_else.rs index 2f913292995..a900fe5e6bc 100644 --- a/tests/ui/crashes/if_same_then_else.rs +++ b/tests/ui/crashes/if_same_then_else.rs @@ -1,7 +1,7 @@ #![allow(clippy::comparison_chain)] #![deny(clippy::if_same_then_else)] -/// Test for https://github.com/rust-lang/rust-clippy/issues/2426 +// Test for https://github.com/rust-lang/rust-clippy/issues/2426 fn main() {} diff --git a/tests/ui/crashes/inherent_impl.rs b/tests/ui/crashes/inherent_impl.rs index aeb27b5ba8c..800a5a383f6 100644 --- a/tests/ui/crashes/inherent_impl.rs +++ b/tests/ui/crashes/inherent_impl.rs @@ -1,6 +1,6 @@ #![deny(clippy::multiple_inherent_impl)] -/// Test for https://github.com/rust-lang/rust-clippy/issues/4578 +// Test for https://github.com/rust-lang/rust-clippy/issues/4578 macro_rules! impl_foo { ($struct:ident) => { diff --git a/tests/ui/crashes/issue-825.rs b/tests/ui/crashes/issue-825.rs index 05696e3d7d5..e8b455a0ec6 100644 --- a/tests/ui/crashes/issue-825.rs +++ b/tests/ui/crashes/issue-825.rs @@ -1,6 +1,6 @@ #![allow(warnings)] -/// Test for https://github.com/rust-lang/rust-clippy/issues/825 +// Test for https://github.com/rust-lang/rust-clippy/issues/825 // this should compile in a reasonable amount of time fn rust_type_id(name: &str) { diff --git a/tests/ui/crashes/match_same_arms_const.rs b/tests/ui/crashes/match_same_arms_const.rs index 94c939665e6..626179c0015 100644 --- a/tests/ui/crashes/match_same_arms_const.rs +++ b/tests/ui/crashes/match_same_arms_const.rs @@ -1,6 +1,6 @@ #![deny(clippy::match_same_arms)] -/// Test for https://github.com/rust-lang/rust-clippy/issues/2427 +// Test for https://github.com/rust-lang/rust-clippy/issues/2427 const PRICE_OF_SWEETS: u32 = 5; const PRICE_OF_KINDNESS: u32 = 0; diff --git a/tests/ui/crashes/needless_pass_by_value-w-late-bound.stderr b/tests/ui/crashes/needless_pass_by_value-w-late-bound.stderr index 90076d4338a..28479570006 100644 --- a/tests/ui/crashes/needless_pass_by_value-w-late-bound.stderr +++ b/tests/ui/crashes/needless_pass_by_value-w-late-bound.stderr @@ -4,7 +4,7 @@ error: this argument is passed by value, but not consumed in the function body LL | fn test(x: Foo<'_>) {} | ^^^^^^^ help: consider taking a reference instead: `&Foo<'_>` | -help: consider marking this type as `Copy` +help: or consider marking this type as `Copy` --> tests/ui/crashes/needless_pass_by_value-w-late-bound.rs:5:1 | LL | struct Foo<'a>(&'a [(); 100]); diff --git a/tests/ui/crashes/returns.rs b/tests/ui/crashes/returns.rs index 8021ed4607d..91cdb5306c8 100644 --- a/tests/ui/crashes/returns.rs +++ b/tests/ui/crashes/returns.rs @@ -1,4 +1,4 @@ -/// Test for https://github.com/rust-lang/rust-clippy/issues/1346 +// Test for https://github.com/rust-lang/rust-clippy/issues/1346 #[deny(warnings)] fn cfg_return() -> i32 { diff --git a/tests/ui/crate_level_checks/entrypoint_recursion.rs b/tests/ui/crate_level_checks/entrypoint_recursion.rs index aa76688d801..5d853d97bc3 100644 --- a/tests/ui/crate_level_checks/entrypoint_recursion.rs +++ b/tests/ui/crate_level_checks/entrypoint_recursion.rs @@ -1,4 +1,4 @@ -//@ignore-target-apple +//@ignore-target: apple #![feature(rustc_attrs)] diff --git a/tests/ui/crate_level_checks/no_std_main_recursion.rs b/tests/ui/crate_level_checks/no_std_main_recursion.rs index 32eba969592..9e5b2a48903 100644 --- a/tests/ui/crate_level_checks/no_std_main_recursion.rs +++ b/tests/ui/crate_level_checks/no_std_main_recursion.rs @@ -1,5 +1,5 @@ //@compile-flags: -Clink-arg=-nostartfiles -//@ignore-target-apple +//@ignore-target: apple #![feature(lang_items, start, libc)] #![no_std] diff --git a/tests/ui/declare_interior_mutable_const/others.rs b/tests/ui/declare_interior_mutable_const/others.rs index 9dafad8b784..0dccf18c493 100644 --- a/tests/ui/declare_interior_mutable_const/others.rs +++ b/tests/ui/declare_interior_mutable_const/others.rs @@ -4,8 +4,8 @@ use std::borrow::Cow; use std::cell::Cell; use std::fmt::Display; use std::ptr; -use std::sync::atomic::AtomicUsize; use std::sync::Once; +use std::sync::atomic::AtomicUsize; const ATOMIC: AtomicUsize = AtomicUsize::new(5); //~ ERROR: interior mutable const CELL: Cell = Cell::new(6); //~ ERROR: interior mutable diff --git a/tests/ui/def_id_nocore.rs b/tests/ui/def_id_nocore.rs index 190d636ebf3..c9650312db8 100644 --- a/tests/ui/def_id_nocore.rs +++ b/tests/ui/def_id_nocore.rs @@ -1,4 +1,4 @@ -//@ignore-target-apple +//@ignore-target: apple #![feature(no_core, lang_items, start)] #![no_core] diff --git a/tests/ui/diverging_sub_expression.rs b/tests/ui/diverging_sub_expression.rs index e0acf050949..1abba60fd34 100644 --- a/tests/ui/diverging_sub_expression.rs +++ b/tests/ui/diverging_sub_expression.rs @@ -67,3 +67,9 @@ fn foobar() { }; } } + +#[allow(unused)] +fn ignore_todo() { + let x: u32 = todo!(); + println!("{x}"); +} diff --git a/tests/ui/doc/doc_lazy_blank_line.fixed b/tests/ui/doc/doc_lazy_blank_line.fixed deleted file mode 100644 index 1aaa26afe7f..00000000000 --- a/tests/ui/doc/doc_lazy_blank_line.fixed +++ /dev/null @@ -1,47 +0,0 @@ -// https://github.com/rust-lang/rust-clippy/issues/12917 -#![warn(clippy::doc_lazy_continuation)] - -/// This is a constant. -/// -/// The meaning of which should not be explained. -pub const A: i32 = 42; - -/// This is another constant, no longer used. -/// -/// This block of documentation has a long -/// explanation and derivation to explain -/// why it is what it is, and how it's used. -/// -/// It is left here for historical reasons, and -/// for reference. -/// -/// Reasons it's great: -/// - First reason -/// - Second reason -/// -//pub const B: i32 = 1337; - -/// This is yet another constant. -/// -/// This has a similar fate as `B`. -/// -/// Reasons it's useful: -/// 1. First reason -/// 2. Second reason -/// -//pub const C: i32 = 8008; - -/// This is still in use. -pub const D: i32 = 20; - -/// > blockquote code path -/// - -/// bottom text -pub const E: i32 = 20; - -/// > blockquote code path -/// -#[repr(C)] -/// bottom text -pub struct Foo(i32); diff --git a/tests/ui/doc/doc_lazy_blank_line.rs b/tests/ui/doc/doc_lazy_blank_line.rs deleted file mode 100644 index e1ab8fc8389..00000000000 --- a/tests/ui/doc/doc_lazy_blank_line.rs +++ /dev/null @@ -1,43 +0,0 @@ -// https://github.com/rust-lang/rust-clippy/issues/12917 -#![warn(clippy::doc_lazy_continuation)] - -/// This is a constant. -/// -/// The meaning of which should not be explained. -pub const A: i32 = 42; - -/// This is another constant, no longer used. -/// -/// This block of documentation has a long -/// explanation and derivation to explain -/// why it is what it is, and how it's used. -/// -/// It is left here for historical reasons, and -/// for reference. -/// -/// Reasons it's great: -/// - First reason -/// - Second reason -//pub const B: i32 = 1337; - -/// This is yet another constant. -/// -/// This has a similar fate as `B`. -/// -/// Reasons it's useful: -/// 1. First reason -/// 2. Second reason -//pub const C: i32 = 8008; - -/// This is still in use. -pub const D: i32 = 20; - -/// > blockquote code path - -/// bottom text -pub const E: i32 = 20; - -/// > blockquote code path -#[repr(C)] -/// bottom text -pub struct Foo(i32); diff --git a/tests/ui/doc/doc_lazy_blank_line.stderr b/tests/ui/doc/doc_lazy_blank_line.stderr deleted file mode 100644 index 854906a7474..00000000000 --- a/tests/ui/doc/doc_lazy_blank_line.stderr +++ /dev/null @@ -1,56 +0,0 @@ -error: doc list item without indentation - --> tests/ui/doc/doc_lazy_blank_line.rs:23:5 - | -LL | /// This is yet another constant. - | ^ - | - = help: if this is intended to be part of the list, indent 3 spaces - = note: `-D clippy::doc-lazy-continuation` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::doc_lazy_continuation)]` -help: if this should be its own paragraph, add a blank doc comment line - | -LL ~ /// - Second reason -LL + /// - | - -error: doc list item without indentation - --> tests/ui/doc/doc_lazy_blank_line.rs:32:5 - | -LL | /// This is still in use. - | ^ - | - = help: if this is intended to be part of the list, indent 4 spaces -help: if this should be its own paragraph, add a blank doc comment line - | -LL ~ /// 2. Second reason -LL + /// - | - -error: doc quote line without `>` marker - --> tests/ui/doc/doc_lazy_blank_line.rs:37:5 - | -LL | /// bottom text - | ^ - | - = help: if this not intended to be a quote at all, escape it with `\>` -help: if this should be its own paragraph, add a blank doc comment line - | -LL ~ /// > blockquote code path -LL + /// - | - -error: doc quote line without `>` marker - --> tests/ui/doc/doc_lazy_blank_line.rs:42:5 - | -LL | /// bottom text - | ^ - | - = help: if this not intended to be a quote at all, escape it with `\>` -help: if this should be its own paragraph, add a blank doc comment line - | -LL ~ /// > blockquote code path -LL + /// - | - -error: aborting due to 4 previous errors - diff --git a/tests/ui/doc/doc_lazy_list.fixed b/tests/ui/doc/doc_lazy_list.fixed index ea59ae4c01c..da537518a2b 100644 --- a/tests/ui/doc/doc_lazy_list.fixed +++ b/tests/ui/doc/doc_lazy_list.fixed @@ -7,9 +7,8 @@ fn one() {} /// 1. first line /// lazy list continuations don't make warnings with this lint -/// //~^ ERROR: doc list item without indentation -/// because they don't have the +/// because they don't have the //~^ ERROR: doc list item without indentation fn two() {} @@ -20,9 +19,8 @@ fn three() {} /// - first line /// lazy list continuations don't make warnings with this lint -/// //~^ ERROR: doc list item without indentation -/// because they don't have the +/// because they don't have the //~^ ERROR: doc list item without indentation fn four() {} @@ -33,9 +31,8 @@ fn five() {} /// - - first line /// this will warn on the lazy continuation -/// //~^ ERROR: doc list item without indentation -/// and so should this +/// and so should this //~^ ERROR: doc list item without indentation fn six() {} diff --git a/tests/ui/doc/doc_lazy_list.stderr b/tests/ui/doc/doc_lazy_list.stderr index 52aa74df894..b38f43b7555 100644 --- a/tests/ui/doc/doc_lazy_list.stderr +++ b/tests/ui/doc/doc_lazy_list.stderr @@ -30,12 +30,11 @@ error: doc list item without indentation LL | /// because they don't have the | ^ | - = help: if this is intended to be part of the list, indent 3 spaces -help: if this should be its own paragraph, add a blank doc comment line - | -LL ~ /// lazy list continuations don't make warnings with this lint -LL + /// + = help: if this is supposed to be its own paragraph, add a blank line +help: indent this line | +LL | /// because they don't have the + | +++ error: doc list item without indentation --> tests/ui/doc/doc_lazy_list.rs:16:5 @@ -67,12 +66,11 @@ error: doc list item without indentation LL | /// because they don't have the | ^ | - = help: if this is intended to be part of the list, indent 4 spaces -help: if this should be its own paragraph, add a blank doc comment line - | -LL ~ /// lazy list continuations don't make warnings with this lint -LL + /// + = help: if this is supposed to be its own paragraph, add a blank line +help: indent this line | +LL | /// because they don't have the + | ++++ error: doc list item without indentation --> tests/ui/doc/doc_lazy_list.rs:28:5 @@ -104,12 +102,11 @@ error: doc list item without indentation LL | /// and so should this | ^^^^ | - = help: if this is intended to be part of the list, indent 2 spaces -help: if this should be its own paragraph, add a blank doc comment line - | -LL ~ /// this will warn on the lazy continuation -LL + /// + = help: if this is supposed to be its own paragraph, add a blank line +help: indent this line | +LL | /// and so should this + | ++ error: doc list item without indentation --> tests/ui/doc/doc_lazy_list.rs:56:5 diff --git a/tests/ui/duplicate_underscore_argument.rs b/tests/ui/duplicate_underscore_argument.rs index 118f6e4a34c..a725538436c 100644 --- a/tests/ui/duplicate_underscore_argument.rs +++ b/tests/ui/duplicate_underscore_argument.rs @@ -1,5 +1,4 @@ #![warn(clippy::duplicate_underscore_argument)] -#[allow(dead_code, unused)] fn join_the_dark_side(darth: i32, _darth: i32) {} //~^ ERROR: `darth` already exists, having another argument having almost the same name ma diff --git a/tests/ui/duplicate_underscore_argument.stderr b/tests/ui/duplicate_underscore_argument.stderr index 40a24b823d1..74979b15788 100644 --- a/tests/ui/duplicate_underscore_argument.stderr +++ b/tests/ui/duplicate_underscore_argument.stderr @@ -1,5 +1,5 @@ error: `darth` already exists, having another argument having almost the same name makes code comprehension and documentation more difficult - --> tests/ui/duplicate_underscore_argument.rs:4:23 + --> tests/ui/duplicate_underscore_argument.rs:3:23 | LL | fn join_the_dark_side(darth: i32, _darth: i32) {} | ^^^^^ diff --git a/tests/ui/duplicated_attributes.rs b/tests/ui/duplicated_attributes.rs index 97cf4a69682..874f5d22075 100644 --- a/tests/ui/duplicated_attributes.rs +++ b/tests/ui/duplicated_attributes.rs @@ -27,4 +27,8 @@ trait Abc {} #[proc_macro_attr::duplicated_attr()] // Should not warn! fn babar() {} +#[allow(missing_docs, reason = "library for internal use only")] +#[allow(exported_private_dependencies, reason = "library for internal use only")] +fn duplicate_reason() {} + fn main() {} diff --git a/tests/ui/empty_line_after/doc_comments.1.fixed b/tests/ui/empty_line_after/doc_comments.1.fixed new file mode 100644 index 00000000000..fd6a94b6a80 --- /dev/null +++ b/tests/ui/empty_line_after/doc_comments.1.fixed @@ -0,0 +1,135 @@ +#![warn(clippy::empty_line_after_outer_attr, clippy::empty_line_after_doc_comments)] + +//~vvv empty_line_after_doc_comments +/// Meant to be an +/// inner doc comment +/// for the crate +fn first_in_crate() {} + +mod m { + //~vvv empty_line_after_doc_comments + /// Meant to be an + /// inner doc comment + /// for the module + fn first_in_module() {} +} + +mod some_mod { + //! This doc comment should *NOT* produce a warning + + mod some_inner_mod { + fn some_noop() {} + } + + //~v empty_line_after_doc_comments + /// # Indented + /// Blank line + fn indented() {} +} + +//~v empty_line_after_doc_comments +/// This should produce a warning +fn with_doc_and_newline() {} + +// This should *NOT* produce a warning +#[crate_type = "lib"] +/// some comment +fn with_no_newline_and_comment() {} + +//~v empty_line_after_doc_comments +/// This doc comment should produce a warning +/** This is also a doc comment and is part of the warning + */ +#[allow(non_camel_case_types)] +#[allow(missing_docs)] +#[allow(dead_code)] +fn three_attributes() {} + +mod misattributed { + //~v empty_line_after_doc_comments + /// docs for `old_code` + // fn old_code() {} + fn new_code() {} + + //~vv empty_line_after_doc_comments + /// Docs + /// for OldA + // struct OldA; + /// Docs + /// for OldB + // struct OldB; + /// Docs + /// for Multiple + #[allow(dead_code)] + struct Multiple; +} + +mod block_comments { + //~v empty_line_after_doc_comments + /** + * Meant to be inner doc comment + */ + fn first_in_module() {} + + //~v empty_line_after_doc_comments + /** + * Docs for `old_code` + */ + /* fn old_code() {} */ + /** + * Docs for `new_code` + */ + fn new_code() {} + + //~v empty_line_after_doc_comments + /// Docs for `old_code2` + /* fn old_code2() {} */ + /// Docs for `new_code2` + fn new_code2() {} +} + +// This should *NOT* produce a warning +#[doc = " +Returns the escaped value of the textual representation of + +"] +pub fn function() -> bool { + true +} + +// This should *NOT* produce a warning +#[derive(Clone, Copy)] +pub enum FooFighter { + Bar1, + + Bar2, + + Bar3, + + Bar4, +} + +/// Should not lint +// some line comment +/// gaps without an empty line +struct LineComment; + +/// This should *NOT* produce a warning because the empty line is inside a block comment +/* + +*/ +pub struct EmptyInBlockComment; + +/// This should *NOT* produce a warning +/* test */ +pub struct BlockComment; + +/// Ignore the empty line inside a cfg_attr'd out attribute +#[cfg_attr(any(), multiline( + foo = 1 + + bar = 2 +))] +fn empty_line_in_cfg_attr() {} + +fn main() {} diff --git a/tests/ui/empty_line_after/doc_comments.2.fixed b/tests/ui/empty_line_after/doc_comments.2.fixed new file mode 100644 index 00000000000..7a57dcd9233 --- /dev/null +++ b/tests/ui/empty_line_after/doc_comments.2.fixed @@ -0,0 +1,144 @@ +#![warn(clippy::empty_line_after_outer_attr, clippy::empty_line_after_doc_comments)] + +//~vvv empty_line_after_doc_comments +//! Meant to be an +//! inner doc comment +//! for the crate + +fn first_in_crate() {} + +mod m { + //~vvv empty_line_after_doc_comments + //! Meant to be an + //! inner doc comment + //! for the module + + fn first_in_module() {} +} + +mod some_mod { + //! This doc comment should *NOT* produce a warning + + mod some_inner_mod { + fn some_noop() {} + } + + //~v empty_line_after_doc_comments + /// # Indented + /// + /// Blank line + fn indented() {} +} + +//~v empty_line_after_doc_comments +/// This should produce a warning +fn with_doc_and_newline() {} + +// This should *NOT* produce a warning +#[crate_type = "lib"] +/// some comment +fn with_no_newline_and_comment() {} + +//~v empty_line_after_doc_comments +/// This doc comment should produce a warning +/** This is also a doc comment and is part of the warning + */ +#[allow(non_camel_case_types)] +#[allow(missing_docs)] +#[allow(dead_code)] +fn three_attributes() {} + +mod misattributed { + //~v empty_line_after_doc_comments + // /// docs for `old_code` + // fn old_code() {} + + fn new_code() {} + + //~vv empty_line_after_doc_comments + // /// Docs + // /// for OldA + // struct OldA; + + // /// Docs + // /// for OldB + // struct OldB; + + /// Docs + /// for Multiple + #[allow(dead_code)] + struct Multiple; +} + +mod block_comments { + //~v empty_line_after_doc_comments + /*! + * Meant to be inner doc comment + */ + + fn first_in_module() {} + + //~v empty_line_after_doc_comments + /* + * Docs for `old_code` + */ + /* fn old_code() {} */ + + /** + * Docs for `new_code` + */ + fn new_code() {} + + //~v empty_line_after_doc_comments + // /// Docs for `old_code2` + /* fn old_code2() {} */ + + /// Docs for `new_code2` + fn new_code2() {} +} + +// This should *NOT* produce a warning +#[doc = " +Returns the escaped value of the textual representation of + +"] +pub fn function() -> bool { + true +} + +// This should *NOT* produce a warning +#[derive(Clone, Copy)] +pub enum FooFighter { + Bar1, + + Bar2, + + Bar3, + + Bar4, +} + +/// Should not lint +// some line comment +/// gaps without an empty line +struct LineComment; + +/// This should *NOT* produce a warning because the empty line is inside a block comment +/* + +*/ +pub struct EmptyInBlockComment; + +/// This should *NOT* produce a warning +/* test */ +pub struct BlockComment; + +/// Ignore the empty line inside a cfg_attr'd out attribute +#[cfg_attr(any(), multiline( + foo = 1 + + bar = 2 +))] +fn empty_line_in_cfg_attr() {} + +fn main() {} diff --git a/tests/ui/empty_line_after/doc_comments.rs b/tests/ui/empty_line_after/doc_comments.rs new file mode 100644 index 00000000000..1da761a5c3d --- /dev/null +++ b/tests/ui/empty_line_after/doc_comments.rs @@ -0,0 +1,147 @@ +#![warn(clippy::empty_line_after_outer_attr, clippy::empty_line_after_doc_comments)] + +//~vvv empty_line_after_doc_comments +/// Meant to be an +/// inner doc comment +/// for the crate + +fn first_in_crate() {} + +mod m { + //~vvv empty_line_after_doc_comments + /// Meant to be an + /// inner doc comment + /// for the module + + fn first_in_module() {} +} + +mod some_mod { + //! This doc comment should *NOT* produce a warning + + mod some_inner_mod { + fn some_noop() {} + } + + //~v empty_line_after_doc_comments + /// # Indented + + /// Blank line + fn indented() {} +} + +//~v empty_line_after_doc_comments +/// This should produce a warning + +fn with_doc_and_newline() {} + +// This should *NOT* produce a warning +#[crate_type = "lib"] +/// some comment +fn with_no_newline_and_comment() {} + +//~v empty_line_after_doc_comments +/// This doc comment should produce a warning + +/** This is also a doc comment and is part of the warning + */ + +#[allow(non_camel_case_types)] +#[allow(missing_docs)] +#[allow(dead_code)] +fn three_attributes() {} + +mod misattributed { + //~v empty_line_after_doc_comments + /// docs for `old_code` + // fn old_code() {} + + fn new_code() {} + + //~vv empty_line_after_doc_comments + /// Docs + /// for OldA + // struct OldA; + + /// Docs + /// for OldB + // struct OldB; + + /// Docs + /// for Multiple + #[allow(dead_code)] + struct Multiple; +} + +mod block_comments { + //~v empty_line_after_doc_comments + /** + * Meant to be inner doc comment + */ + + fn first_in_module() {} + + //~v empty_line_after_doc_comments + /** + * Docs for `old_code` + */ + /* fn old_code() {} */ + + /** + * Docs for `new_code` + */ + fn new_code() {} + + //~v empty_line_after_doc_comments + /// Docs for `old_code2` + /* fn old_code2() {} */ + + /// Docs for `new_code2` + fn new_code2() {} +} + +// This should *NOT* produce a warning +#[doc = " +Returns the escaped value of the textual representation of + +"] +pub fn function() -> bool { + true +} + +// This should *NOT* produce a warning +#[derive(Clone, Copy)] +pub enum FooFighter { + Bar1, + + Bar2, + + Bar3, + + Bar4, +} + +/// Should not lint +// some line comment +/// gaps without an empty line +struct LineComment; + +/// This should *NOT* produce a warning because the empty line is inside a block comment +/* + +*/ +pub struct EmptyInBlockComment; + +/// This should *NOT* produce a warning +/* test */ +pub struct BlockComment; + +/// Ignore the empty line inside a cfg_attr'd out attribute +#[cfg_attr(any(), multiline( + foo = 1 + + bar = 2 +))] +fn empty_line_in_cfg_attr() {} + +fn main() {} diff --git a/tests/ui/empty_line_after/doc_comments.stderr b/tests/ui/empty_line_after/doc_comments.stderr new file mode 100644 index 00000000000..c238b4c9a17 --- /dev/null +++ b/tests/ui/empty_line_after/doc_comments.stderr @@ -0,0 +1,176 @@ +error: empty line after doc comment + --> tests/ui/empty_line_after/doc_comments.rs:6:1 + | +LL | / /// for the crate +LL | | + | |_ +LL | fn first_in_crate() {} + | ------------------- the comment documents this function + | + = note: `-D clippy::empty-line-after-doc-comments` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::empty_line_after_doc_comments)]` + = help: if the empty line is unintentional remove it +help: if the comment should document the crate use an inner doc comment + | +LL ~ //! Meant to be an +LL ~ //! inner doc comment +LL ~ //! for the crate + | + +error: empty line after doc comment + --> tests/ui/empty_line_after/doc_comments.rs:14:5 + | +LL | / /// for the module +LL | | + | |_ +LL | fn first_in_module() {} + | -------------------- the comment documents this function + | + = help: if the empty line is unintentional remove it +help: if the comment should document the parent module use an inner doc comment + | +LL ~ //! Meant to be an +LL ~ //! inner doc comment +LL ~ //! for the module + | + +error: empty line after doc comment + --> tests/ui/empty_line_after/doc_comments.rs:27:5 + | +LL | / /// # Indented +LL | | + | |_ +LL | /// Blank line +LL | fn indented() {} + | ------------- the comment documents this function + | + = help: if the empty line is unintentional remove it +help: if the documentation should include the empty line include it in the comment + | +LL | /// + | + +error: empty line after doc comment + --> tests/ui/empty_line_after/doc_comments.rs:34:1 + | +LL | / /// This should produce a warning +LL | | + | |_ +LL | fn with_doc_and_newline() {} + | ------------------------- the comment documents this function + | + = help: if the empty line is unintentional remove it + +error: empty lines after doc comment + --> tests/ui/empty_line_after/doc_comments.rs:44:1 + | +LL | / /// This doc comment should produce a warning +LL | | +LL | | /** This is also a doc comment and is part of the warning +LL | | */ +LL | | + | |_ +... +LL | fn three_attributes() {} + | --------------------- the comment documents this function + | + = help: if the empty lines are unintentional remove them + +error: empty line after doc comment + --> tests/ui/empty_line_after/doc_comments.rs:56:5 + | +LL | / /// docs for `old_code` +LL | | // fn old_code() {} +LL | | + | |_ +LL | fn new_code() {} + | ------------- the comment documents this function + | + = help: if the empty line is unintentional remove it +help: if the doc comment should not document `new_code` comment it out + | +LL | // /// docs for `old_code` + | ++ + +error: empty lines after doc comment + --> tests/ui/empty_line_after/doc_comments.rs:63:5 + | +LL | / /// for OldA +LL | | // struct OldA; +LL | | +LL | | /// Docs +LL | | /// for OldB +LL | | // struct OldB; +LL | | + | |_ +... +LL | struct Multiple; + | --------------- the comment documents this struct + | + = help: if the empty lines are unintentional remove them +help: if the doc comment should not document `Multiple` comment it out + | +LL ~ // /// Docs +LL ~ // /// for OldA +LL | // struct OldA; +LL | +LL ~ // /// Docs +LL ~ // /// for OldB + | + +error: empty line after doc comment + --> tests/ui/empty_line_after/doc_comments.rs:78:5 + | +LL | / /** +LL | | * Meant to be inner doc comment +LL | | */ +LL | | + | |_ +LL | fn first_in_module() {} + | -------------------- the comment documents this function + | + = help: if the empty line is unintentional remove it +help: if the comment should document the parent module use an inner doc comment + | +LL | /*! + | ~ + +error: empty line after doc comment + --> tests/ui/empty_line_after/doc_comments.rs:85:5 + | +LL | / /** +LL | | * Docs for `old_code` +LL | | */ +LL | | /* fn old_code() {} */ +LL | | + | |_ +... +LL | fn new_code() {} + | ------------- the comment documents this function + | + = help: if the empty line is unintentional remove it +help: if the doc comment should not document `new_code` comment it out + | +LL - /** +LL + /* + | + +error: empty line after doc comment + --> tests/ui/empty_line_after/doc_comments.rs:96:5 + | +LL | / /// Docs for `old_code2` +LL | | /* fn old_code2() {} */ +LL | | + | |_ +LL | /// Docs for `new_code2` +LL | fn new_code2() {} + | -------------- the comment documents this function + | + = help: if the empty line is unintentional remove it +help: if the doc comment should not document `new_code2` comment it out + | +LL | // /// Docs for `old_code2` + | ++ + +error: aborting due to 10 previous errors + diff --git a/tests/ui/empty_line_after/outer_attribute.1.fixed b/tests/ui/empty_line_after/outer_attribute.1.fixed new file mode 100644 index 00000000000..36d80a2c95b --- /dev/null +++ b/tests/ui/empty_line_after/outer_attribute.1.fixed @@ -0,0 +1,108 @@ +//@aux-build:../auxiliary/proc_macro_attr.rs +#![warn(clippy::empty_line_after_outer_attr, clippy::empty_line_after_doc_comments)] + +//~v empty_line_after_outer_attr +#[crate_type = "lib"] +fn first_in_crate() {} + +#[macro_use] +extern crate proc_macro_attr; + +//~v empty_line_after_outer_attr +#[inline] +/// some comment +fn with_one_newline_and_comment() {} + +#[inline] +/// some comment +fn with_no_newline_and_comment() {} + +//~v empty_line_after_outer_attr +#[inline] +fn with_one_newline() {} + +#[rustfmt::skip] +mod two_lines { + //~v empty_line_after_outer_attr + #[crate_type = "lib"] + fn with_two_newlines() {} +} + +//~v empty_line_after_outer_attr +#[doc = "doc attributes should be considered attributes"] +enum Baz { + One, + Two, +} + +//~v empty_line_after_outer_attr +#[repr(C)] +struct Foo { + one: isize, + two: isize, +} + +//~v empty_line_after_outer_attr +#[allow(dead_code)] +mod foo {} + +//~v empty_line_after_outer_attr +#[inline] +// Still lint cases where the empty line does not immediately follow the attribute +fn comment_before_empty_line() {} + +//~v empty_line_after_outer_attr +#[allow(unused)] +// This comment is isolated +pub fn isolated_comment() {} + +#[doc = " +Returns the escaped value of the textual representation of + +"] +pub fn function() -> bool { + true +} + +#[derive(Clone, Copy)] +pub enum FooFighter { + Bar1, + + Bar2, + + Bar3, + + Bar4, +} + +#[crate_type = "lib"] +/* + +*/ +pub struct EmptyLineInBlockComment; + +#[crate_type = "lib"] +/* test */ +pub struct BlockComment; + +// See https://github.com/rust-lang/rust-clippy/issues/5567 +#[rustfmt::skip] +#[fake_async_trait] +pub trait Bazz { + fn foo() -> Vec { + let _i = ""; + + + + vec![] + } +} + +#[derive(Clone, Copy)] +#[dummy(string = "first line + +second line +")] +pub struct Args; + +fn main() {} diff --git a/tests/ui/empty_line_after/outer_attribute.2.fixed b/tests/ui/empty_line_after/outer_attribute.2.fixed new file mode 100644 index 00000000000..0e8e4129e85 --- /dev/null +++ b/tests/ui/empty_line_after/outer_attribute.2.fixed @@ -0,0 +1,111 @@ +//@aux-build:../auxiliary/proc_macro_attr.rs +#![warn(clippy::empty_line_after_outer_attr, clippy::empty_line_after_doc_comments)] + +//~v empty_line_after_outer_attr +#![crate_type = "lib"] + +fn first_in_crate() {} + +#[macro_use] +extern crate proc_macro_attr; + +//~v empty_line_after_outer_attr +#[inline] +/// some comment +fn with_one_newline_and_comment() {} + +#[inline] +/// some comment +fn with_no_newline_and_comment() {} + +//~v empty_line_after_outer_attr +#[inline] +fn with_one_newline() {} + +#[rustfmt::skip] +mod two_lines { + //~v empty_line_after_outer_attr + #![crate_type = "lib"] + + + fn with_two_newlines() {} +} + +//~v empty_line_after_outer_attr +#[doc = "doc attributes should be considered attributes"] +enum Baz { + One, + Two, +} + +//~v empty_line_after_outer_attr +#[repr(C)] +struct Foo { + one: isize, + two: isize, +} + +//~v empty_line_after_outer_attr +#[allow(dead_code)] +mod foo {} + +//~v empty_line_after_outer_attr +#[inline] +// Still lint cases where the empty line does not immediately follow the attribute +fn comment_before_empty_line() {} + +//~v empty_line_after_outer_attr +#[allow(unused)] +// This comment is isolated +pub fn isolated_comment() {} + +#[doc = " +Returns the escaped value of the textual representation of + +"] +pub fn function() -> bool { + true +} + +#[derive(Clone, Copy)] +pub enum FooFighter { + Bar1, + + Bar2, + + Bar3, + + Bar4, +} + +#[crate_type = "lib"] +/* + +*/ +pub struct EmptyLineInBlockComment; + +#[crate_type = "lib"] +/* test */ +pub struct BlockComment; + +// See https://github.com/rust-lang/rust-clippy/issues/5567 +#[rustfmt::skip] +#[fake_async_trait] +pub trait Bazz { + fn foo() -> Vec { + let _i = ""; + + + + vec![] + } +} + +#[derive(Clone, Copy)] +#[dummy(string = "first line + +second line +")] +pub struct Args; + +fn main() {} diff --git a/tests/ui/empty_line_after/outer_attribute.rs b/tests/ui/empty_line_after/outer_attribute.rs new file mode 100644 index 00000000000..1295088ac00 --- /dev/null +++ b/tests/ui/empty_line_after/outer_attribute.rs @@ -0,0 +1,119 @@ +//@aux-build:../auxiliary/proc_macro_attr.rs +#![warn(clippy::empty_line_after_outer_attr, clippy::empty_line_after_doc_comments)] + +//~v empty_line_after_outer_attr +#[crate_type = "lib"] + +fn first_in_crate() {} + +#[macro_use] +extern crate proc_macro_attr; + +//~v empty_line_after_outer_attr +#[inline] + +/// some comment +fn with_one_newline_and_comment() {} + +#[inline] +/// some comment +fn with_no_newline_and_comment() {} + +//~v empty_line_after_outer_attr +#[inline] + +fn with_one_newline() {} + +#[rustfmt::skip] +mod two_lines { + //~v empty_line_after_outer_attr + #[crate_type = "lib"] + + + fn with_two_newlines() {} +} + +//~v empty_line_after_outer_attr +#[doc = "doc attributes should be considered attributes"] + +enum Baz { + One, + Two, +} + +//~v empty_line_after_outer_attr +#[repr(C)] + +struct Foo { + one: isize, + two: isize, +} + +//~v empty_line_after_outer_attr +#[allow(dead_code)] + +mod foo {} + +//~v empty_line_after_outer_attr +#[inline] +// Still lint cases where the empty line does not immediately follow the attribute + +fn comment_before_empty_line() {} + +//~v empty_line_after_outer_attr +#[allow(unused)] + +// This comment is isolated + +pub fn isolated_comment() {} + +#[doc = " +Returns the escaped value of the textual representation of + +"] +pub fn function() -> bool { + true +} + +#[derive(Clone, Copy)] +pub enum FooFighter { + Bar1, + + Bar2, + + Bar3, + + Bar4, +} + +#[crate_type = "lib"] +/* + +*/ +pub struct EmptyLineInBlockComment; + +#[crate_type = "lib"] +/* test */ +pub struct BlockComment; + +// See https://github.com/rust-lang/rust-clippy/issues/5567 +#[rustfmt::skip] +#[fake_async_trait] +pub trait Bazz { + fn foo() -> Vec { + let _i = ""; + + + + vec![] + } +} + +#[derive(Clone, Copy)] +#[dummy(string = "first line + +second line +")] +pub struct Args; + +fn main() {} diff --git a/tests/ui/empty_line_after/outer_attribute.stderr b/tests/ui/empty_line_after/outer_attribute.stderr new file mode 100644 index 00000000000..958b40424a9 --- /dev/null +++ b/tests/ui/empty_line_after/outer_attribute.stderr @@ -0,0 +1,116 @@ +error: empty line after outer attribute + --> tests/ui/empty_line_after/outer_attribute.rs:5:1 + | +LL | / #[crate_type = "lib"] +LL | | + | |_ +LL | fn first_in_crate() {} + | ------------------- the attribute applies to this function + | + = note: `-D clippy::empty-line-after-outer-attr` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::empty_line_after_outer_attr)]` + = help: if the empty line is unintentional remove it +help: if the attribute should apply to the crate use an inner attribute + | +LL | #![crate_type = "lib"] + | + + +error: empty line after outer attribute + --> tests/ui/empty_line_after/outer_attribute.rs:13:1 + | +LL | / #[inline] +LL | | + | |_ +LL | /// some comment +LL | fn with_one_newline_and_comment() {} + | --------------------------------- the attribute applies to this function + | + = help: if the empty line is unintentional remove it + +error: empty line after outer attribute + --> tests/ui/empty_line_after/outer_attribute.rs:23:1 + | +LL | / #[inline] +LL | | + | |_ +LL | fn with_one_newline() {} + | --------------------- the attribute applies to this function + | + = help: if the empty line is unintentional remove it + +error: empty lines after outer attribute + --> tests/ui/empty_line_after/outer_attribute.rs:30:5 + | +LL | / #[crate_type = "lib"] +LL | | +LL | | + | |_ +LL | fn with_two_newlines() {} + | ---------------------- the attribute applies to this function + | + = help: if the empty lines are unintentional remove them +help: if the attribute should apply to the parent module use an inner attribute + | +LL | #![crate_type = "lib"] + | + + +error: empty line after outer attribute + --> tests/ui/empty_line_after/outer_attribute.rs:37:1 + | +LL | / #[doc = "doc attributes should be considered attributes"] +LL | | + | |_ +LL | enum Baz { + | -------- the attribute applies to this enum + | + = help: if the empty line is unintentional remove it + +error: empty line after outer attribute + --> tests/ui/empty_line_after/outer_attribute.rs:45:1 + | +LL | / #[repr(C)] +LL | | + | |_ +LL | struct Foo { + | ---------- the attribute applies to this struct + | + = help: if the empty line is unintentional remove it + +error: empty line after outer attribute + --> tests/ui/empty_line_after/outer_attribute.rs:53:1 + | +LL | / #[allow(dead_code)] +LL | | + | |_ +LL | mod foo {} + | ------- the attribute applies to this module + | + = help: if the empty line is unintentional remove it + +error: empty line after outer attribute + --> tests/ui/empty_line_after/outer_attribute.rs:58:1 + | +LL | / #[inline] +LL | | // Still lint cases where the empty line does not immediately follow the attribute +LL | | + | |_ +LL | fn comment_before_empty_line() {} + | ------------------------------ the attribute applies to this function + | + = help: if the empty line is unintentional remove it + +error: empty lines after outer attribute + --> tests/ui/empty_line_after/outer_attribute.rs:64:1 + | +LL | / #[allow(unused)] +LL | | +LL | | // This comment is isolated +LL | | + | |_ +LL | pub fn isolated_comment() {} + | ------------------------- the attribute applies to this function + | + = help: if the empty lines are unintentional remove them + +error: aborting due to 9 previous errors + diff --git a/tests/ui/empty_line_after_doc_comments.rs b/tests/ui/empty_line_after_doc_comments.rs deleted file mode 100644 index dd78491749c..00000000000 --- a/tests/ui/empty_line_after_doc_comments.rs +++ /dev/null @@ -1,132 +0,0 @@ -//@aux-build:proc_macro_attr.rs -#![warn(clippy::empty_line_after_doc_comments)] -#![allow(clippy::assertions_on_constants, clippy::duplicated_attributes)] -#![feature(custom_inner_attributes)] -#![rustfmt::skip] - -#[macro_use] -extern crate proc_macro_attr; - -mod some_mod { - //! This doc comment should *NOT* produce a warning - - mod some_inner_mod { - fn some_noop() {} - } -} - -/// This should produce a warning - -fn with_doc_and_newline() { assert!(true)} - -// This should *NOT* produce a warning -#[crate_type = "lib"] - -/// some comment -fn with_one_newline_and_comment() { assert!(true) } - -// This should *NOT* produce a warning -#[crate_type = "lib"] -/// some comment -fn with_no_newline_and_comment() { assert!(true) } - - -// This should *NOT* produce a warning -#[crate_type = "lib"] - -fn with_one_newline() { assert!(true) } - -// This should *NOT* produce a warning -#[crate_type = "lib"] - - -fn with_two_newlines() { assert!(true) } - - -// This should *NOT* produce a warning -#[crate_type = "lib"] - -enum Baz { - One, - Two -} - -// This should *NOT* produce a warning -#[crate_type = "lib"] - -struct Foo { - one: isize, - two: isize -} - -// This should *NOT* produce a warning -#[crate_type = "lib"] - -mod foo { -} - -/// This doc comment should produce a warning - -/** This is also a doc comment and should produce a warning - */ - -// This should *NOT* produce a warning -#[allow(non_camel_case_types)] -#[allow(missing_docs)] -#[allow(missing_docs)] -fn three_attributes() { assert!(true) } - -// This should *NOT* produce a warning -#[doc = " -Returns the escaped value of the textual representation of - -"] -pub fn function() -> bool { - true -} - -// This should *NOT* produce a warning -#[derive(Clone, Copy)] -pub enum FooFighter { - Bar1, - - Bar2, - - Bar3, - - Bar4 -} - -// This should *NOT* produce a warning because the empty line is inside a block comment -#[crate_type = "lib"] -/* - -*/ -pub struct S; - -// This should *NOT* produce a warning -#[crate_type = "lib"] -/* test */ -pub struct T; - -// This should *NOT* produce a warning -// See https://github.com/rust-lang/rust-clippy/issues/5567 -#[fake_async_trait] -pub trait Bazz { - fn foo() -> Vec { - let _i = ""; - - - - vec![] - } -} - -#[derive(Clone, Copy)] -#[dummy(string = "first line - -second line -")] -pub struct Args; - -fn main() {} diff --git a/tests/ui/empty_line_after_doc_comments.stderr b/tests/ui/empty_line_after_doc_comments.stderr deleted file mode 100644 index 889ccf6ba19..00000000000 --- a/tests/ui/empty_line_after_doc_comments.stderr +++ /dev/null @@ -1,37 +0,0 @@ -error: found an empty line after a doc comment. Perhaps you need to use `//!` to make a comment on a module, remove the empty line, or make a regular comment with `//`? - --> tests/ui/empty_line_after_doc_comments.rs:18:1 - | -LL | / /// This should produce a warning -LL | | -LL | | fn with_doc_and_newline() { assert!(true)} - | |_ - | - = note: `-D clippy::empty-line-after-doc-comments` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::empty_line_after_doc_comments)]` - -error: found an empty line after a doc comment. Perhaps you need to use `//!` to make a comment on a module, remove the empty line, or make a regular comment with `//`? - --> tests/ui/empty_line_after_doc_comments.rs:68:1 - | -LL | / /// This doc comment should produce a warning -LL | | -LL | | /** This is also a doc comment and should produce a warning -LL | | */ -... | -LL | | #[allow(missing_docs)] -LL | | fn three_attributes() { assert!(true) } - | |_ - -error: found an empty line after a doc comment. Perhaps you need to use `//!` to make a comment on a module, remove the empty line, or make a regular comment with `//`? - --> tests/ui/empty_line_after_doc_comments.rs:70:1 - | -LL | / /** This is also a doc comment and should produce a warning -LL | | */ -LL | | -LL | | // This should *NOT* produce a warning -... | -LL | | #[allow(missing_docs)] -LL | | fn three_attributes() { assert!(true) } - | |_ - -error: aborting due to 3 previous errors - diff --git a/tests/ui/empty_line_after_outer_attribute.rs b/tests/ui/empty_line_after_outer_attribute.rs deleted file mode 100644 index f147cf2cd5d..00000000000 --- a/tests/ui/empty_line_after_outer_attribute.rs +++ /dev/null @@ -1,120 +0,0 @@ -//@aux-build:proc_macro_attr.rs -#![warn(clippy::empty_line_after_outer_attr)] -#![allow(clippy::assertions_on_constants, clippy::duplicated_attributes)] -#![feature(custom_inner_attributes)] -#![rustfmt::skip] - -#[macro_use] -extern crate proc_macro_attr; - -// This should produce a warning -#[crate_type = "lib"] - -/// some comment -fn with_one_newline_and_comment() { assert!(true) } - -// This should not produce a warning -#[crate_type = "lib"] -/// some comment -fn with_no_newline_and_comment() { assert!(true) } - - -// This should produce a warning -#[crate_type = "lib"] - -fn with_one_newline() { assert!(true) } - -// This should produce a warning, too -#[crate_type = "lib"] - - -fn with_two_newlines() { assert!(true) } - - -// This should produce a warning -#[crate_type = "lib"] - -enum Baz { - One, - Two -} - -// This should produce a warning -#[crate_type = "lib"] - -struct Foo { - one: isize, - two: isize -} - -// This should produce a warning -#[crate_type = "lib"] - -mod foo { -} - -/// This doc comment should not produce a warning - -/** This is also a doc comment and should not produce a warning - */ - -// This should not produce a warning -#[allow(non_camel_case_types)] -#[allow(missing_docs)] -#[allow(missing_docs)] -fn three_attributes() { assert!(true) } - -// This should not produce a warning -#[doc = " -Returns the escaped value of the textual representation of - -"] -pub fn function() -> bool { - true -} - -// This should not produce a warning -#[derive(Clone, Copy)] -pub enum FooFighter { - Bar1, - - Bar2, - - Bar3, - - Bar4 -} - -// This should not produce a warning because the empty line is inside a block comment -#[crate_type = "lib"] -/* - -*/ -pub struct S; - -// This should not produce a warning -#[crate_type = "lib"] -/* test */ -pub struct T; - -// This should not produce a warning -// See https://github.com/rust-lang/rust-clippy/issues/5567 -#[fake_async_trait] -pub trait Bazz { - fn foo() -> Vec { - let _i = ""; - - - - vec![] - } -} - -#[derive(Clone, Copy)] -#[dummy(string = "first line - -second line -")] -pub struct Args; - -fn main() {} diff --git a/tests/ui/empty_line_after_outer_attribute.stderr b/tests/ui/empty_line_after_outer_attribute.stderr deleted file mode 100644 index b43e6e30da2..00000000000 --- a/tests/ui/empty_line_after_outer_attribute.stderr +++ /dev/null @@ -1,54 +0,0 @@ -error: found an empty line after an outer attribute. Perhaps you forgot to add a `!` to make it an inner attribute? - --> tests/ui/empty_line_after_outer_attribute.rs:11:1 - | -LL | / #[crate_type = "lib"] -LL | | -LL | | /// some comment -LL | | fn with_one_newline_and_comment() { assert!(true) } - | |_ - | - = note: `-D clippy::empty-line-after-outer-attr` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::empty_line_after_outer_attr)]` - -error: found an empty line after an outer attribute. Perhaps you forgot to add a `!` to make it an inner attribute? - --> tests/ui/empty_line_after_outer_attribute.rs:23:1 - | -LL | / #[crate_type = "lib"] -LL | | -LL | | fn with_one_newline() { assert!(true) } - | |_ - -error: found an empty line after an outer attribute. Perhaps you forgot to add a `!` to make it an inner attribute? - --> tests/ui/empty_line_after_outer_attribute.rs:28:1 - | -LL | / #[crate_type = "lib"] -... | -LL | | fn with_two_newlines() { assert!(true) } - | |_ - -error: found an empty line after an outer attribute. Perhaps you forgot to add a `!` to make it an inner attribute? - --> tests/ui/empty_line_after_outer_attribute.rs:35:1 - | -LL | / #[crate_type = "lib"] -LL | | -LL | | enum Baz { - | |_ - -error: found an empty line after an outer attribute. Perhaps you forgot to add a `!` to make it an inner attribute? - --> tests/ui/empty_line_after_outer_attribute.rs:43:1 - | -LL | / #[crate_type = "lib"] -LL | | -LL | | struct Foo { - | |_ - -error: found an empty line after an outer attribute. Perhaps you forgot to add a `!` to make it an inner attribute? - --> tests/ui/empty_line_after_outer_attribute.rs:51:1 - | -LL | / #[crate_type = "lib"] -LL | | -LL | | mod foo { - | |_ - -error: aborting due to 6 previous errors - diff --git a/tests/ui/empty_loop_no_std.rs b/tests/ui/empty_loop_no_std.rs index 5fe32351ed4..1bb895bda75 100644 --- a/tests/ui/empty_loop_no_std.rs +++ b/tests/ui/empty_loop_no_std.rs @@ -1,5 +1,5 @@ //@compile-flags: -Clink-arg=-nostartfiles -//@ignore-target-apple +//@ignore-target: apple #![warn(clippy::empty_loop)] #![feature(lang_items, start, libc)] diff --git a/tests/ui/enum_clike_unportable_variant.rs b/tests/ui/enum_clike_unportable_variant.rs index c50404c5047..37849179d6a 100644 --- a/tests/ui/enum_clike_unportable_variant.rs +++ b/tests/ui/enum_clike_unportable_variant.rs @@ -1,4 +1,4 @@ -//@ignore-32bit +//@ignore-bitwidth: 32 #![warn(clippy::enum_clike_unportable_variant)] #![allow(unused, non_upper_case_globals)] diff --git a/tests/ui/exit1.rs b/tests/ui/exit1.rs index a89f6dd4ca0..36b3c42fd99 100644 --- a/tests/ui/exit1.rs +++ b/tests/ui/exit1.rs @@ -1,4 +1,4 @@ -#[warn(clippy::exit)] +#![warn(clippy::exit)] fn not_main() { if true { diff --git a/tests/ui/exit2.rs b/tests/ui/exit2.rs index d5ff93fb9cc..9bbb7b073a4 100644 --- a/tests/ui/exit2.rs +++ b/tests/ui/exit2.rs @@ -1,4 +1,4 @@ -#[warn(clippy::exit)] +#![warn(clippy::exit)] fn also_not_main() { std::process::exit(3); diff --git a/tests/ui/exit3.rs b/tests/ui/exit3.rs index 9dc0e1015a4..cab908aafd3 100644 --- a/tests/ui/exit3.rs +++ b/tests/ui/exit3.rs @@ -1,4 +1,4 @@ -#[warn(clippy::exit)] +#![warn(clippy::exit)] fn main() { if true { diff --git a/tests/ui/expect_fun_call.fixed b/tests/ui/expect_fun_call.fixed index 6ac3c43ad29..8f800c71941 100644 --- a/tests/ui/expect_fun_call.fixed +++ b/tests/ui/expect_fun_call.fixed @@ -5,8 +5,6 @@ clippy::unnecessary_literal_unwrap )] -/// Checks implementation of the `EXPECT_FUN_CALL` lint - macro_rules! one { () => { 1 diff --git a/tests/ui/expect_fun_call.rs b/tests/ui/expect_fun_call.rs index 22ea2db504f..b5cfafb2993 100644 --- a/tests/ui/expect_fun_call.rs +++ b/tests/ui/expect_fun_call.rs @@ -5,8 +5,6 @@ clippy::unnecessary_literal_unwrap )] -/// Checks implementation of the `EXPECT_FUN_CALL` lint - macro_rules! one { () => { 1 diff --git a/tests/ui/expect_fun_call.stderr b/tests/ui/expect_fun_call.stderr index b41904d04fa..bae853ac5c1 100644 --- a/tests/ui/expect_fun_call.stderr +++ b/tests/ui/expect_fun_call.stderr @@ -1,5 +1,5 @@ error: use of `expect` followed by a function call - --> tests/ui/expect_fun_call.rs:37:26 + --> tests/ui/expect_fun_call.rs:35:26 | LL | with_none_and_format.expect(&format!("Error {}: fake error", error_code)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| panic!("Error {}: fake error", error_code))` @@ -8,85 +8,85 @@ LL | with_none_and_format.expect(&format!("Error {}: fake error", error_code = help: to override `-D warnings` add `#[allow(clippy::expect_fun_call)]` error: use of `expect` followed by a function call - --> tests/ui/expect_fun_call.rs:40:26 + --> tests/ui/expect_fun_call.rs:38:26 | LL | with_none_and_as_str.expect(format!("Error {}: fake error", error_code).as_str()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| panic!("Error {}: fake error", error_code))` error: use of `expect` followed by a function call - --> tests/ui/expect_fun_call.rs:43:37 + --> tests/ui/expect_fun_call.rs:41:37 | LL | with_none_and_format_with_macro.expect(format!("Error {}: fake error", one!()).as_str()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| panic!("Error {}: fake error", one!()))` error: use of `expect` followed by a function call - --> tests/ui/expect_fun_call.rs:53:25 + --> tests/ui/expect_fun_call.rs:51:25 | LL | with_err_and_format.expect(&format!("Error {}: fake error", error_code)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|_| panic!("Error {}: fake error", error_code))` error: use of `expect` followed by a function call - --> tests/ui/expect_fun_call.rs:56:25 + --> tests/ui/expect_fun_call.rs:54:25 | LL | with_err_and_as_str.expect(format!("Error {}: fake error", error_code).as_str()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|_| panic!("Error {}: fake error", error_code))` error: use of `expect` followed by a function call - --> tests/ui/expect_fun_call.rs:68:17 + --> tests/ui/expect_fun_call.rs:66:17 | LL | Some("foo").expect(format!("{} {}", 1, 2).as_ref()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| panic!("{} {}", 1, 2))` error: use of `expect` followed by a function call - --> tests/ui/expect_fun_call.rs:89:21 + --> tests/ui/expect_fun_call.rs:87:21 | LL | Some("foo").expect(&get_string()); | ^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| { panic!("{}", get_string()) })` error: use of `expect` followed by a function call - --> tests/ui/expect_fun_call.rs:90:21 + --> tests/ui/expect_fun_call.rs:88:21 | LL | Some("foo").expect(get_string().as_ref()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| { panic!("{}", get_string()) })` error: use of `expect` followed by a function call - --> tests/ui/expect_fun_call.rs:91:21 + --> tests/ui/expect_fun_call.rs:89:21 | LL | Some("foo").expect(get_string().as_str()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| { panic!("{}", get_string()) })` error: use of `expect` followed by a function call - --> tests/ui/expect_fun_call.rs:93:21 + --> tests/ui/expect_fun_call.rs:91:21 | LL | Some("foo").expect(get_static_str()); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| { panic!("{}", get_static_str()) })` error: use of `expect` followed by a function call - --> tests/ui/expect_fun_call.rs:94:21 + --> tests/ui/expect_fun_call.rs:92:21 | LL | Some("foo").expect(get_non_static_str(&0)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| { panic!("{}", get_non_static_str(&0).to_string()) })` error: use of `expect` followed by a function call - --> tests/ui/expect_fun_call.rs:98:16 + --> tests/ui/expect_fun_call.rs:96:16 | LL | Some(true).expect(&format!("key {}, {}", 1, 2)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| panic!("key {}, {}", 1, 2))` error: use of `expect` followed by a function call - --> tests/ui/expect_fun_call.rs:104:17 + --> tests/ui/expect_fun_call.rs:102:17 | LL | opt_ref.expect(&format!("{:?}", opt_ref)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| panic!("{:?}", opt_ref))` error: use of `expect` followed by a function call - --> tests/ui/expect_fun_call.rs:108:20 + --> tests/ui/expect_fun_call.rs:106:20 | LL | format_capture.expect(&format!("{error_code}")); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| panic!("{error_code}"))` error: use of `expect` followed by a function call - --> tests/ui/expect_fun_call.rs:111:30 + --> tests/ui/expect_fun_call.rs:109:30 | LL | format_capture_and_value.expect(&format!("{error_code}, {}", 1)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| panic!("{error_code}, {}", 1))` diff --git a/tests/ui/field_reassign_with_default.rs b/tests/ui/field_reassign_with_default.rs index 620cffb4f04..2a432751952 100644 --- a/tests/ui/field_reassign_with_default.rs +++ b/tests/ui/field_reassign_with_default.rs @@ -192,8 +192,8 @@ struct WrapperMulti { } mod issue6312 { - use std::sync::atomic::AtomicBool; use std::sync::Arc; + use std::sync::atomic::AtomicBool; // do not lint: type implements `Drop` but not all fields are `Copy` #[derive(Clone, Default)] diff --git a/tests/ui/floating_point_arithmetic_nostd.rs b/tests/ui/floating_point_arithmetic_nostd.rs index 47c113d61c0..8ea75fae89b 100644 --- a/tests/ui/floating_point_arithmetic_nostd.rs +++ b/tests/ui/floating_point_arithmetic_nostd.rs @@ -4,7 +4,7 @@ #![no_std] // The following should not lint, as the suggested methods `{f16,f32,f64,f128}.mul_add()` -// and ``{f16,f32,f64,f128}::abs()` are not available in no_std +// and `{f16,f32,f64,f128}::abs()` are not available in no_std pub fn mul_add() { let a: f64 = 1234.567; diff --git a/tests/ui/format_args.fixed b/tests/ui/format_args.fixed index 4d812f6bf1d..20d1e3d9050 100644 --- a/tests/ui/format_args.fixed +++ b/tests/ui/format_args.fixed @@ -8,7 +8,7 @@ clippy::uninlined_format_args )] -use std::io::{stdout, Write}; +use std::io::{Write, stdout}; use std::ops::Deref; use std::panic::Location; diff --git a/tests/ui/format_args.rs b/tests/ui/format_args.rs index d242623feb6..18ab223db78 100644 --- a/tests/ui/format_args.rs +++ b/tests/ui/format_args.rs @@ -8,7 +8,7 @@ clippy::uninlined_format_args )] -use std::io::{stdout, Write}; +use std::io::{Write, stdout}; use std::ops::Deref; use std::panic::Location; diff --git a/tests/ui/format_args_unfixable.rs b/tests/ui/format_args_unfixable.rs index b7492e38b25..f04715f4f01 100644 --- a/tests/ui/format_args_unfixable.rs +++ b/tests/ui/format_args_unfixable.rs @@ -2,7 +2,7 @@ #![allow(unused)] #![allow(clippy::assertions_on_constants, clippy::eq_op, clippy::uninlined_format_args)] -use std::io::{stdout, Error, ErrorKind, Write}; +use std::io::{Error, ErrorKind, Write, stdout}; use std::ops::Deref; use std::panic::Location; diff --git a/tests/ui/if_then_some_else_none.fixed b/tests/ui/if_then_some_else_none.fixed index ad13372a68b..1f47dddcbc4 100644 --- a/tests/ui/if_then_some_else_none.fixed +++ b/tests/ui/if_then_some_else_none.fixed @@ -113,6 +113,10 @@ fn issue11394(b: bool, v: Result<(), ()>) -> Result<(), ()> { Ok(()) } +fn issue13407(s: &str) -> Option { + (s == "1").then(|| true) +} + const fn issue12103(x: u32) -> Option { // Should not issue an error in `const` context if x > 42 { Some(150) } else { None } diff --git a/tests/ui/if_then_some_else_none.rs b/tests/ui/if_then_some_else_none.rs index 73edbb7da2a..499f008fb87 100644 --- a/tests/ui/if_then_some_else_none.rs +++ b/tests/ui/if_then_some_else_none.rs @@ -131,6 +131,10 @@ fn issue11394(b: bool, v: Result<(), ()>) -> Result<(), ()> { Ok(()) } +fn issue13407(s: &str) -> Option { + if s == "1" { Some(true) } else { None } +} + const fn issue12103(x: u32) -> Option { // Should not issue an error in `const` context if x > 42 { Some(150) } else { None } diff --git a/tests/ui/if_then_some_else_none.stderr b/tests/ui/if_then_some_else_none.stderr index aed01e026cb..e7bc66b3ee8 100644 --- a/tests/ui/if_then_some_else_none.stderr +++ b/tests/ui/if_then_some_else_none.stderr @@ -52,5 +52,11 @@ LL | | None LL | | }; | |_____^ help: try: `foo().then(|| { println!("true!"); 150 })` -error: aborting due to 5 previous errors +error: this could be simplified with `bool::then` + --> tests/ui/if_then_some_else_none.rs:135:5 + | +LL | if s == "1" { Some(true) } else { None } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(s == "1").then(|| true)` + +error: aborting due to 6 previous errors diff --git a/tests/ui/ignored_unit_patterns.fixed b/tests/ui/ignored_unit_patterns.fixed index 118f0b48895..fde40437309 100644 --- a/tests/ui/ignored_unit_patterns.fixed +++ b/tests/ui/ignored_unit_patterns.fixed @@ -21,15 +21,12 @@ fn main() { let _ = foo().map_err(|()| todo!()); //~^ ERROR: matching over `()` is more explicit - println!( - "{:?}", - match foo() { - Ok(()) => {}, - //~^ ERROR: matching over `()` is more explicit - Err(()) => {}, - //~^ ERROR: matching over `()` is more explicit - } - ); + println!("{:?}", match foo() { + Ok(()) => {}, + //~^ ERROR: matching over `()` is more explicit + Err(()) => {}, + //~^ ERROR: matching over `()` is more explicit + }); } // ignored_unit_patterns in derive macro should be ok diff --git a/tests/ui/ignored_unit_patterns.rs b/tests/ui/ignored_unit_patterns.rs index 92feb9e6c28..528844d76e0 100644 --- a/tests/ui/ignored_unit_patterns.rs +++ b/tests/ui/ignored_unit_patterns.rs @@ -21,15 +21,12 @@ fn main() { let _ = foo().map_err(|_| todo!()); //~^ ERROR: matching over `()` is more explicit - println!( - "{:?}", - match foo() { - Ok(_) => {}, - //~^ ERROR: matching over `()` is more explicit - Err(_) => {}, - //~^ ERROR: matching over `()` is more explicit - } - ); + println!("{:?}", match foo() { + Ok(_) => {}, + //~^ ERROR: matching over `()` is more explicit + Err(_) => {}, + //~^ ERROR: matching over `()` is more explicit + }); } // ignored_unit_patterns in derive macro should be ok diff --git a/tests/ui/ignored_unit_patterns.stderr b/tests/ui/ignored_unit_patterns.stderr index 00a254e3919..54ff4454d6b 100644 --- a/tests/ui/ignored_unit_patterns.stderr +++ b/tests/ui/ignored_unit_patterns.stderr @@ -26,31 +26,31 @@ LL | let _ = foo().map_err(|_| todo!()); | ^ help: use `()` instead of `_`: `()` error: matching over `()` is more explicit - --> tests/ui/ignored_unit_patterns.rs:27:16 + --> tests/ui/ignored_unit_patterns.rs:25:12 | -LL | Ok(_) => {}, - | ^ help: use `()` instead of `_`: `()` +LL | Ok(_) => {}, + | ^ help: use `()` instead of `_`: `()` error: matching over `()` is more explicit - --> tests/ui/ignored_unit_patterns.rs:29:17 + --> tests/ui/ignored_unit_patterns.rs:27:13 | -LL | Err(_) => {}, - | ^ help: use `()` instead of `_`: `()` +LL | Err(_) => {}, + | ^ help: use `()` instead of `_`: `()` error: matching over `()` is more explicit - --> tests/ui/ignored_unit_patterns.rs:41:9 + --> tests/ui/ignored_unit_patterns.rs:38:9 | LL | let _ = foo().unwrap(); | ^ help: use `()` instead of `_`: `()` error: matching over `()` is more explicit - --> tests/ui/ignored_unit_patterns.rs:50:13 + --> tests/ui/ignored_unit_patterns.rs:47:13 | LL | (1, _) => unimplemented!(), | ^ help: use `()` instead of `_`: `()` error: matching over `()` is more explicit - --> tests/ui/ignored_unit_patterns.rs:57:13 + --> tests/ui/ignored_unit_patterns.rs:54:13 | LL | for (x, _) in v { | ^ help: use `()` instead of `_`: `()` diff --git a/tests/ui/implicit_saturating_sub.fixed b/tests/ui/implicit_saturating_sub.fixed index 27f679797dd..81cc1494914 100644 --- a/tests/ui/implicit_saturating_sub.fixed +++ b/tests/ui/implicit_saturating_sub.fixed @@ -184,18 +184,18 @@ fn main() { let mut m = Mock; let mut u_32 = 3000; let a = 200; - let mut _b = 8; + let mut b = 8; if m != 0 { m -= 1; } if a > 0 { - _b -= 1; + b -= 1; } if 0 > a { - _b -= 1; + b -= 1; } if u_32 > 0 { @@ -214,4 +214,11 @@ fn main() { } else if u_32 > 0 { u_32 -= 1; } + + let result = if a < b { + println!("we shouldn't remove this"); + 0 + } else { + a - b + }; } diff --git a/tests/ui/implicit_saturating_sub.rs b/tests/ui/implicit_saturating_sub.rs index 5d7b95d2c65..f73396ebd27 100644 --- a/tests/ui/implicit_saturating_sub.rs +++ b/tests/ui/implicit_saturating_sub.rs @@ -230,18 +230,18 @@ fn main() { let mut m = Mock; let mut u_32 = 3000; let a = 200; - let mut _b = 8; + let mut b = 8; if m != 0 { m -= 1; } if a > 0 { - _b -= 1; + b -= 1; } if 0 > a { - _b -= 1; + b -= 1; } if u_32 > 0 { @@ -260,4 +260,11 @@ fn main() { } else if u_32 > 0 { u_32 -= 1; } + + let result = if a < b { + println!("we shouldn't remove this"); + 0 + } else { + a - b + }; } diff --git a/tests/ui/incompatible_msrv.rs b/tests/ui/incompatible_msrv.rs index 8ef1f554bc3..c23df223d50 100644 --- a/tests/ui/incompatible_msrv.rs +++ b/tests/ui/incompatible_msrv.rs @@ -2,8 +2,8 @@ #![feature(custom_inner_attributes)] #![clippy::msrv = "1.3.0"] -use std::collections::hash_map::Entry; use std::collections::HashMap; +use std::collections::hash_map::Entry; use std::future::Future; use std::thread::sleep; use std::time::Duration; diff --git a/tests/ui/legacy_numeric_constants.fixed b/tests/ui/legacy_numeric_constants.fixed index a6ef8f8c119..3a2294ef4c5 100644 --- a/tests/ui/legacy_numeric_constants.fixed +++ b/tests/ui/legacy_numeric_constants.fixed @@ -22,8 +22,8 @@ macro_rules! b { }; } -use std::u32::MAX; use std::u8::MIN; +use std::u32::MAX; use std::{f64, u32}; #[warn(clippy::legacy_numeric_constants)] @@ -99,8 +99,8 @@ fn allow() { ::std::primitive::u8::MIN; ::std::u8::MIN; ::std::primitive::u8::min_value(); - use std::u64; use std::u8::MIN; + use std::u64; } #[warn(clippy::legacy_numeric_constants)] diff --git a/tests/ui/legacy_numeric_constants.rs b/tests/ui/legacy_numeric_constants.rs index cd633545372..6cb3e694ea1 100644 --- a/tests/ui/legacy_numeric_constants.rs +++ b/tests/ui/legacy_numeric_constants.rs @@ -22,8 +22,8 @@ macro_rules! b { }; } -use std::u32::MAX; use std::u8::MIN; +use std::u32::MAX; use std::{f64, u32}; #[warn(clippy::legacy_numeric_constants)] @@ -99,8 +99,8 @@ fn allow() { ::std::primitive::u8::MIN; ::std::u8::MIN; ::std::primitive::u8::min_value(); - use std::u64; use std::u8::MIN; + use std::u64; } #[warn(clippy::legacy_numeric_constants)] diff --git a/tests/ui/macro_use_imports.fixed b/tests/ui/macro_use_imports.fixed index 38ed5a957e7..28844fab747 100644 --- a/tests/ui/macro_use_imports.fixed +++ b/tests/ui/macro_use_imports.fixed @@ -2,7 +2,7 @@ //@aux-build:macro_use_helper.rs //@aux-build:proc_macro_derive.rs -//@ignore-32bit +//@ignore-bitwidth: 32 #![allow(unused_imports, unreachable_code, unused_variables, dead_code, unused_attributes)] #![allow(clippy::single_component_path_imports)] diff --git a/tests/ui/macro_use_imports.rs b/tests/ui/macro_use_imports.rs index ae6cc16ed27..5381f295989 100644 --- a/tests/ui/macro_use_imports.rs +++ b/tests/ui/macro_use_imports.rs @@ -2,7 +2,7 @@ //@aux-build:macro_use_helper.rs //@aux-build:proc_macro_derive.rs -//@ignore-32bit +//@ignore-bitwidth: 32 #![allow(unused_imports, unreachable_code, unused_variables, dead_code, unused_attributes)] #![allow(clippy::single_component_path_imports)] diff --git a/tests/ui/macro_use_imports_expect.rs b/tests/ui/macro_use_imports_expect.rs index df6d5b9fbab..60cce1d24a2 100644 --- a/tests/ui/macro_use_imports_expect.rs +++ b/tests/ui/macro_use_imports_expect.rs @@ -1,7 +1,7 @@ //@aux-build:macro_rules.rs //@aux-build:macro_use_helper.rs //@aux-build:proc_macro_derive.rs -//@ignore-32bit +//@ignore-bitwidth: 32 #![allow(unused_imports, unreachable_code, unused_variables, dead_code, unused_attributes)] #![allow(clippy::single_component_path_imports)] diff --git a/tests/ui/manual_arithmetic_check-2.rs b/tests/ui/manual_arithmetic_check-2.rs new file mode 100644 index 00000000000..e97e3bdfef7 --- /dev/null +++ b/tests/ui/manual_arithmetic_check-2.rs @@ -0,0 +1,35 @@ +//@no-rustfix +#![warn(clippy::implicit_saturating_sub)] +#![allow(arithmetic_overflow)] + +fn main() { + let a = 12u32; + let b = 13u32; + + let result = if a > b { b - a } else { 0 }; + //~^ ERROR: inverted arithmetic check before subtraction + let result = if b < a { b - a } else { 0 }; + //~^ ERROR: inverted arithmetic check before subtraction + + let result = if a > b { 0 } else { a - b }; + //~^ ERROR: inverted arithmetic check before subtraction + let result = if a >= b { 0 } else { a - b }; + //~^ ERROR: inverted arithmetic check before subtraction + let result = if b < a { 0 } else { a - b }; + //~^ ERROR: inverted arithmetic check before subtraction + let result = if b <= a { 0 } else { a - b }; + //~^ ERROR: inverted arithmetic check before subtraction + + let af = 12f32; + let bf = 13f32; + // Should not lint! + let result = if bf < af { 0. } else { af - bf }; + + // Should not lint! + let result = if a < b { + println!("we shouldn't remove this"); + 0 + } else { + a - b + }; +} diff --git a/tests/ui/manual_arithmetic_check-2.stderr b/tests/ui/manual_arithmetic_check-2.stderr new file mode 100644 index 00000000000..4121aa7464f --- /dev/null +++ b/tests/ui/manual_arithmetic_check-2.stderr @@ -0,0 +1,75 @@ +error: inverted arithmetic check before subtraction + --> tests/ui/manual_arithmetic_check-2.rs:9:23 + | +LL | let result = if a > b { b - a } else { 0 }; + | ^ ----- help: try replacing it with: `a - b` + | +note: this subtraction underflows when `b < a` + --> tests/ui/manual_arithmetic_check-2.rs:9:29 + | +LL | let result = if a > b { b - a } else { 0 }; + | ^^^^^ + = note: `#[deny(clippy::inverted_saturating_sub)]` on by default + +error: inverted arithmetic check before subtraction + --> tests/ui/manual_arithmetic_check-2.rs:11:23 + | +LL | let result = if b < a { b - a } else { 0 }; + | ^ ----- help: try replacing it with: `a - b` + | +note: this subtraction underflows when `b < a` + --> tests/ui/manual_arithmetic_check-2.rs:11:29 + | +LL | let result = if b < a { b - a } else { 0 }; + | ^^^^^ + +error: inverted arithmetic check before subtraction + --> tests/ui/manual_arithmetic_check-2.rs:14:23 + | +LL | let result = if a > b { 0 } else { a - b }; + | ^ ----- help: try replacing it with: `b - a` + | +note: this subtraction underflows when `a < b` + --> tests/ui/manual_arithmetic_check-2.rs:14:40 + | +LL | let result = if a > b { 0 } else { a - b }; + | ^^^^^ + +error: inverted arithmetic check before subtraction + --> tests/ui/manual_arithmetic_check-2.rs:16:23 + | +LL | let result = if a >= b { 0 } else { a - b }; + | ^^ ----- help: try replacing it with: `b - a` + | +note: this subtraction underflows when `a < b` + --> tests/ui/manual_arithmetic_check-2.rs:16:41 + | +LL | let result = if a >= b { 0 } else { a - b }; + | ^^^^^ + +error: inverted arithmetic check before subtraction + --> tests/ui/manual_arithmetic_check-2.rs:18:23 + | +LL | let result = if b < a { 0 } else { a - b }; + | ^ ----- help: try replacing it with: `b - a` + | +note: this subtraction underflows when `a < b` + --> tests/ui/manual_arithmetic_check-2.rs:18:40 + | +LL | let result = if b < a { 0 } else { a - b }; + | ^^^^^ + +error: inverted arithmetic check before subtraction + --> tests/ui/manual_arithmetic_check-2.rs:20:23 + | +LL | let result = if b <= a { 0 } else { a - b }; + | ^^ ----- help: try replacing it with: `b - a` + | +note: this subtraction underflows when `a < b` + --> tests/ui/manual_arithmetic_check-2.rs:20:41 + | +LL | let result = if b <= a { 0 } else { a - b }; + | ^^^^^ + +error: aborting due to 6 previous errors + diff --git a/tests/ui/manual_arithmetic_check.fixed b/tests/ui/manual_arithmetic_check.fixed new file mode 100644 index 00000000000..29ecbb9ad2a --- /dev/null +++ b/tests/ui/manual_arithmetic_check.fixed @@ -0,0 +1,24 @@ +#![warn(clippy::implicit_saturating_sub, clippy::inverted_saturating_sub)] +#![allow(clippy::if_same_then_else)] + +fn main() { + let a = 12u32; + let b = 13u32; + let c = 8u32; + + let result = a.saturating_sub(b); + //~^ ERROR: manual arithmetic check found + let result = a.saturating_sub(b); + //~^ ERROR: manual arithmetic check found + + let result = a.saturating_sub(b); + //~^ ERROR: manual arithmetic check found + let result = a.saturating_sub(b); + //~^ ERROR: manual arithmetic check found + + // Should not warn! + let result = if a > b { a - b } else { a - c }; + + // Just to check it won't break clippy. + let result = if b > a { 0 } else { 0 }; +} diff --git a/tests/ui/manual_arithmetic_check.rs b/tests/ui/manual_arithmetic_check.rs new file mode 100644 index 00000000000..69554c6b61c --- /dev/null +++ b/tests/ui/manual_arithmetic_check.rs @@ -0,0 +1,24 @@ +#![warn(clippy::implicit_saturating_sub, clippy::inverted_saturating_sub)] +#![allow(clippy::if_same_then_else)] + +fn main() { + let a = 12u32; + let b = 13u32; + let c = 8u32; + + let result = if a > b { a - b } else { 0 }; + //~^ ERROR: manual arithmetic check found + let result = if b < a { a - b } else { 0 }; + //~^ ERROR: manual arithmetic check found + + let result = if a < b { 0 } else { a - b }; + //~^ ERROR: manual arithmetic check found + let result = if b > a { 0 } else { a - b }; + //~^ ERROR: manual arithmetic check found + + // Should not warn! + let result = if a > b { a - b } else { a - c }; + + // Just to check it won't break clippy. + let result = if b > a { 0 } else { 0 }; +} diff --git a/tests/ui/manual_arithmetic_check.stderr b/tests/ui/manual_arithmetic_check.stderr new file mode 100644 index 00000000000..b0cf73cd915 --- /dev/null +++ b/tests/ui/manual_arithmetic_check.stderr @@ -0,0 +1,29 @@ +error: manual arithmetic check found + --> tests/ui/manual_arithmetic_check.rs:9:18 + | +LL | let result = if a > b { a - b } else { 0 }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `a.saturating_sub(b)` + | + = note: `-D clippy::implicit-saturating-sub` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::implicit_saturating_sub)]` + +error: manual arithmetic check found + --> tests/ui/manual_arithmetic_check.rs:11:18 + | +LL | let result = if b < a { a - b } else { 0 }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `a.saturating_sub(b)` + +error: manual arithmetic check found + --> tests/ui/manual_arithmetic_check.rs:14:18 + | +LL | let result = if a < b { 0 } else { a - b }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `a.saturating_sub(b)` + +error: manual arithmetic check found + --> tests/ui/manual_arithmetic_check.rs:16:18 + | +LL | let result = if b > a { 0 } else { a - b }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `a.saturating_sub(b)` + +error: aborting due to 4 previous errors + diff --git a/tests/ui/manual_div_ceil.fixed b/tests/ui/manual_div_ceil.fixed new file mode 100644 index 00000000000..e7801f7376a --- /dev/null +++ b/tests/ui/manual_div_ceil.fixed @@ -0,0 +1,30 @@ +#![warn(clippy::manual_div_ceil)] + +fn main() { + let x = 7_u32; + let y = 4_u32; + let z = 11_u32; + + // Lint + let _ = x.div_ceil(y); //~ ERROR: manually reimplementing `div_ceil` + let _ = x.div_ceil(y); //~ ERROR: manually reimplementing `div_ceil` + let _ = x.div_ceil(y); //~ ERROR: manually reimplementing `div_ceil` + + let _ = 7_u32.div_ceil(4); //~ ERROR: manually reimplementing `div_ceil` + let _ = (7_i32 as u32).div_ceil(4); //~ ERROR: manually reimplementing `div_ceil` + + // No lint + let _ = (x + (y - 2)) / y; + let _ = (x + (y + 1)) / y; + + let _ = (x + (y - 1)) / z; + + let x_i = 7_i32; + let y_i = 4_i32; + let z_i = 11_i32; + + // No lint because `int_roundings` feature is not enabled. + let _ = (z as i32 + (y_i - 1)) / y_i; + let _ = (7_u32 as i32 + (y_i - 1)) / y_i; + let _ = (7_u32 as i32 + (4 - 1)) / 4; +} diff --git a/tests/ui/manual_div_ceil.rs b/tests/ui/manual_div_ceil.rs new file mode 100644 index 00000000000..2de74c7eaa8 --- /dev/null +++ b/tests/ui/manual_div_ceil.rs @@ -0,0 +1,30 @@ +#![warn(clippy::manual_div_ceil)] + +fn main() { + let x = 7_u32; + let y = 4_u32; + let z = 11_u32; + + // Lint + let _ = (x + (y - 1)) / y; //~ ERROR: manually reimplementing `div_ceil` + let _ = ((y - 1) + x) / y; //~ ERROR: manually reimplementing `div_ceil` + let _ = (x + y - 1) / y; //~ ERROR: manually reimplementing `div_ceil` + + let _ = (7_u32 + (4 - 1)) / 4; //~ ERROR: manually reimplementing `div_ceil` + let _ = (7_i32 as u32 + (4 - 1)) / 4; //~ ERROR: manually reimplementing `div_ceil` + + // No lint + let _ = (x + (y - 2)) / y; + let _ = (x + (y + 1)) / y; + + let _ = (x + (y - 1)) / z; + + let x_i = 7_i32; + let y_i = 4_i32; + let z_i = 11_i32; + + // No lint because `int_roundings` feature is not enabled. + let _ = (z as i32 + (y_i - 1)) / y_i; + let _ = (7_u32 as i32 + (y_i - 1)) / y_i; + let _ = (7_u32 as i32 + (4 - 1)) / 4; +} diff --git a/tests/ui/manual_div_ceil.stderr b/tests/ui/manual_div_ceil.stderr new file mode 100644 index 00000000000..dc652dff405 --- /dev/null +++ b/tests/ui/manual_div_ceil.stderr @@ -0,0 +1,35 @@ +error: manually reimplementing `div_ceil` + --> tests/ui/manual_div_ceil.rs:9:13 + | +LL | let _ = (x + (y - 1)) / y; + | ^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `x.div_ceil(y)` + | + = note: `-D clippy::manual-div-ceil` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::manual_div_ceil)]` + +error: manually reimplementing `div_ceil` + --> tests/ui/manual_div_ceil.rs:10:13 + | +LL | let _ = ((y - 1) + x) / y; + | ^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `x.div_ceil(y)` + +error: manually reimplementing `div_ceil` + --> tests/ui/manual_div_ceil.rs:11:13 + | +LL | let _ = (x + y - 1) / y; + | ^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `x.div_ceil(y)` + +error: manually reimplementing `div_ceil` + --> tests/ui/manual_div_ceil.rs:13:13 + | +LL | let _ = (7_u32 + (4 - 1)) / 4; + | ^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `7_u32.div_ceil(4)` + +error: manually reimplementing `div_ceil` + --> tests/ui/manual_div_ceil.rs:14:13 + | +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 + diff --git a/tests/ui/manual_div_ceil_with_feature.fixed b/tests/ui/manual_div_ceil_with_feature.fixed new file mode 100644 index 00000000000..a1d678c6689 --- /dev/null +++ b/tests/ui/manual_div_ceil_with_feature.fixed @@ -0,0 +1,25 @@ +#![warn(clippy::manual_div_ceil)] +#![feature(int_roundings)] + +fn main() { + let x = 7_i32; + let y = 4_i32; + let z = 3_i32; + let z_u: u32 = 11; + + // Lint. + let _ = x.div_ceil(y); + let _ = x.div_ceil(y); + let _ = x.div_ceil(y); + + let _ = 7_i32.div_ceil(4); + let _ = (7_i32 as u32).div_ceil(4); + let _ = (7_u32 as i32).div_ceil(4); + let _ = z_u.div_ceil(4); + + // No lint. + let _ = (x + (y - 2)) / y; + let _ = (x + (y + 1)) / y; + + let _ = (x + (y - 1)) / z; +} diff --git a/tests/ui/manual_div_ceil_with_feature.rs b/tests/ui/manual_div_ceil_with_feature.rs new file mode 100644 index 00000000000..58cb1dbe34d --- /dev/null +++ b/tests/ui/manual_div_ceil_with_feature.rs @@ -0,0 +1,25 @@ +#![warn(clippy::manual_div_ceil)] +#![feature(int_roundings)] + +fn main() { + let x = 7_i32; + let y = 4_i32; + let z = 3_i32; + let z_u: u32 = 11; + + // Lint. + let _ = (x + (y - 1)) / y; + let _ = ((y - 1) + x) / y; + let _ = (x + y - 1) / y; + + let _ = (7_i32 + (4 - 1)) / 4; + let _ = (7_i32 as u32 + (4 - 1)) / 4; + let _ = (7_u32 as i32 + (4 - 1)) / 4; + let _ = (z_u + (4 - 1)) / 4; + + // No lint. + let _ = (x + (y - 2)) / y; + let _ = (x + (y + 1)) / y; + + let _ = (x + (y - 1)) / z; +} diff --git a/tests/ui/manual_div_ceil_with_feature.stderr b/tests/ui/manual_div_ceil_with_feature.stderr new file mode 100644 index 00000000000..361ef9bd9f4 --- /dev/null +++ b/tests/ui/manual_div_ceil_with_feature.stderr @@ -0,0 +1,47 @@ +error: manually reimplementing `div_ceil` + --> tests/ui/manual_div_ceil_with_feature.rs:11:13 + | +LL | let _ = (x + (y - 1)) / y; + | ^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `x.div_ceil(y)` + | + = note: `-D clippy::manual-div-ceil` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::manual_div_ceil)]` + +error: manually reimplementing `div_ceil` + --> tests/ui/manual_div_ceil_with_feature.rs:12:13 + | +LL | let _ = ((y - 1) + x) / y; + | ^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `x.div_ceil(y)` + +error: manually reimplementing `div_ceil` + --> tests/ui/manual_div_ceil_with_feature.rs:13:13 + | +LL | let _ = (x + y - 1) / y; + | ^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `x.div_ceil(y)` + +error: manually reimplementing `div_ceil` + --> tests/ui/manual_div_ceil_with_feature.rs:15:13 + | +LL | let _ = (7_i32 + (4 - 1)) / 4; + | ^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `7_i32.div_ceil(4)` + +error: manually reimplementing `div_ceil` + --> tests/ui/manual_div_ceil_with_feature.rs:16:13 + | +LL | let _ = (7_i32 as u32 + (4 - 1)) / 4; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `(7_i32 as u32).div_ceil(4)` + +error: manually reimplementing `div_ceil` + --> tests/ui/manual_div_ceil_with_feature.rs:17:13 + | +LL | let _ = (7_u32 as i32 + (4 - 1)) / 4; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `(7_u32 as i32).div_ceil(4)` + +error: manually reimplementing `div_ceil` + --> tests/ui/manual_div_ceil_with_feature.rs:18:13 + | +LL | let _ = (z_u + (4 - 1)) / 4; + | ^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `z_u.div_ceil(4)` + +error: aborting due to 7 previous errors + diff --git a/tests/ui/manual_is_power_of_two.fixed b/tests/ui/manual_is_power_of_two.fixed new file mode 100644 index 00000000000..dda5fe0ec3e --- /dev/null +++ b/tests/ui/manual_is_power_of_two.fixed @@ -0,0 +1,20 @@ +#![warn(clippy::manual_is_power_of_two)] + +fn main() { + let a = 16_u64; + + let _ = a.is_power_of_two(); + let _ = a.is_power_of_two(); + + // Test different orders of expression + let _ = a.is_power_of_two(); + let _ = a.is_power_of_two(); + let _ = a.is_power_of_two(); + let _ = a.is_power_of_two(); + + let b = 4_i64; + + // is_power_of_two only works for unsigned integers + let _ = b.count_ones() == 1; + let _ = b & (b - 1) == 0; +} diff --git a/tests/ui/manual_is_power_of_two.rs b/tests/ui/manual_is_power_of_two.rs new file mode 100644 index 00000000000..a1d3a95c410 --- /dev/null +++ b/tests/ui/manual_is_power_of_two.rs @@ -0,0 +1,20 @@ +#![warn(clippy::manual_is_power_of_two)] + +fn main() { + let a = 16_u64; + + let _ = a.count_ones() == 1; + let _ = a & (a - 1) == 0; + + // Test different orders of expression + let _ = 1 == a.count_ones(); + let _ = (a - 1) & a == 0; + let _ = 0 == a & (a - 1); + let _ = 0 == (a - 1) & a; + + let b = 4_i64; + + // is_power_of_two only works for unsigned integers + let _ = b.count_ones() == 1; + let _ = b & (b - 1) == 0; +} diff --git a/tests/ui/manual_is_power_of_two.stderr b/tests/ui/manual_is_power_of_two.stderr new file mode 100644 index 00000000000..3cfc6297abf --- /dev/null +++ b/tests/ui/manual_is_power_of_two.stderr @@ -0,0 +1,41 @@ +error: manually reimplementing `is_power_of_two` + --> tests/ui/manual_is_power_of_two.rs:6:13 + | +LL | let _ = a.count_ones() == 1; + | ^^^^^^^^^^^^^^^^^^^ help: consider using `.is_power_of_two()`: `a.is_power_of_two()` + | + = note: `-D clippy::manual-is-power-of-two` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::manual_is_power_of_two)]` + +error: manually reimplementing `is_power_of_two` + --> tests/ui/manual_is_power_of_two.rs:7:13 + | +LL | let _ = a & (a - 1) == 0; + | ^^^^^^^^^^^^^^^^ help: consider using `.is_power_of_two()`: `a.is_power_of_two()` + +error: manually reimplementing `is_power_of_two` + --> tests/ui/manual_is_power_of_two.rs:10:13 + | +LL | let _ = 1 == a.count_ones(); + | ^^^^^^^^^^^^^^^^^^^ help: consider using `.is_power_of_two()`: `a.is_power_of_two()` + +error: manually reimplementing `is_power_of_two` + --> tests/ui/manual_is_power_of_two.rs:11:13 + | +LL | let _ = (a - 1) & a == 0; + | ^^^^^^^^^^^^^^^^ help: consider using `.is_power_of_two()`: `a.is_power_of_two()` + +error: manually reimplementing `is_power_of_two` + --> tests/ui/manual_is_power_of_two.rs:12:13 + | +LL | let _ = 0 == a & (a - 1); + | ^^^^^^^^^^^^^^^^ help: consider using `.is_power_of_two()`: `a.is_power_of_two()` + +error: manually reimplementing `is_power_of_two` + --> tests/ui/manual_is_power_of_two.rs:13:13 + | +LL | let _ = 0 == (a - 1) & a; + | ^^^^^^^^^^^^^^^^ help: consider using `.is_power_of_two()`: `a.is_power_of_two()` + +error: aborting due to 6 previous errors + diff --git a/tests/ui/manual_non_exhaustive_enum.rs b/tests/ui/manual_non_exhaustive_enum.rs index 31c3cc80137..ffe2bb92467 100644 --- a/tests/ui/manual_non_exhaustive_enum.rs +++ b/tests/ui/manual_non_exhaustive_enum.rs @@ -1,8 +1,8 @@ #![warn(clippy::manual_non_exhaustive)] #![allow(unused)] //@no-rustfix -enum E { - //~^ ERROR: this seems like a manual implementation of the non-exhaustive pattern +pub enum E { + //~^ manual_non_exhaustive A, B, #[doc(hidden)] @@ -11,7 +11,7 @@ enum E { // if the user explicitly marks as nonexhaustive we shouldn't warn them #[non_exhaustive] -enum Ep { +pub enum Ep { A, B, #[doc(hidden)] @@ -19,14 +19,14 @@ enum Ep { } // marker variant does not have doc hidden attribute, should be ignored -enum NoDocHidden { +pub enum NoDocHidden { A, B, _C, } // name of variant with doc hidden does not start with underscore -enum NoUnderscore { +pub enum NoUnderscore { A, B, #[doc(hidden)] @@ -34,7 +34,7 @@ enum NoUnderscore { } // variant with doc hidden is not unit, should be ignored -enum NotUnit { +pub enum NotUnit { A, B, #[doc(hidden)] @@ -42,13 +42,13 @@ enum NotUnit { } // variant with doc hidden is the only one, should be ignored -enum OnlyMarker { +pub enum OnlyMarker { #[doc(hidden)] _A, } // variant with multiple markers, should be ignored -enum MultipleMarkers { +pub enum MultipleMarkers { A, #[doc(hidden)] _B, @@ -58,13 +58,13 @@ enum MultipleMarkers { // already non_exhaustive and no markers, should be ignored #[non_exhaustive] -enum NonExhaustive { +pub enum NonExhaustive { A, B, } // marked is used, don't lint -enum UsedHidden { +pub enum UsedHidden { #[doc(hidden)] _A, B, @@ -77,11 +77,9 @@ fn foo(x: &mut UsedHidden) { } #[expect(clippy::manual_non_exhaustive)] -enum ExpectLint { +pub enum ExpectLint { A, B, #[doc(hidden)] _C, } - -fn main() {} diff --git a/tests/ui/manual_non_exhaustive_enum.stderr b/tests/ui/manual_non_exhaustive_enum.stderr index dc669568dd2..0a9ac157f85 100644 --- a/tests/ui/manual_non_exhaustive_enum.stderr +++ b/tests/ui/manual_non_exhaustive_enum.stderr @@ -1,11 +1,7 @@ error: this seems like a manual implementation of the non-exhaustive pattern --> tests/ui/manual_non_exhaustive_enum.rs:4:1 | -LL | enum E { - | ^----- - | | - | _help: add the attribute: `#[non_exhaustive] enum E` - | | +LL | / pub enum E { LL | | LL | | A, LL | | B, @@ -21,15 +17,16 @@ LL | _C, | ^^ = note: `-D clippy::manual-non-exhaustive` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::manual_non_exhaustive)]` +help: use the `#[non_exhaustive]` attribute instead + | +LL + #[non_exhaustive] +LL | pub enum E { + | error: this seems like a manual implementation of the non-exhaustive pattern --> tests/ui/manual_non_exhaustive_enum.rs:29:1 | -LL | enum NoUnderscore { - | ^---------------- - | | - | _help: add the attribute: `#[non_exhaustive] enum NoUnderscore` - | | +LL | / pub enum NoUnderscore { LL | | A, LL | | B, LL | | #[doc(hidden)] @@ -42,6 +39,11 @@ help: remove this variant | LL | C, | ^ +help: use the `#[non_exhaustive]` attribute instead + | +LL + #[non_exhaustive] +LL | pub enum NoUnderscore { + | error: aborting due to 2 previous errors diff --git a/tests/ui/manual_non_exhaustive_struct.rs b/tests/ui/manual_non_exhaustive_struct.rs index 4b2803ccc4a..31dd50281fa 100644 --- a/tests/ui/manual_non_exhaustive_struct.rs +++ b/tests/ui/manual_non_exhaustive_struct.rs @@ -1,9 +1,9 @@ #![warn(clippy::manual_non_exhaustive)] #![allow(unused)] //@no-rustfix -mod structs { - struct S { - //~^ ERROR: this seems like a manual implementation of the non-exhaustive pattern +pub mod structs { + pub struct S { + //~^ manual_non_exhaustive pub a: i32, pub b: i32, _c: (), @@ -11,68 +11,76 @@ mod structs { // user forgot to remove the private field #[non_exhaustive] - struct Sp { - //~^ ERROR: this seems like a manual implementation of the non-exhaustive pattern + pub struct Sp { + //~^ manual_non_exhaustive pub a: i32, pub b: i32, _c: (), } // some other fields are private, should be ignored - struct PrivateFields { + pub struct PrivateFields { a: i32, pub b: i32, _c: (), } - // private field name does not start with underscore, should be ignored - struct NoUnderscore { + pub struct NoUnderscore { + //~^ manual_non_exhaustive pub a: i32, pub b: i32, c: (), } // private field is not unit type, should be ignored - struct NotUnit { + pub struct NotUnit { pub a: i32, pub b: i32, _c: i32, } // private field is the only field, should be ignored - struct OnlyMarker { + pub struct OnlyMarker { _a: (), } // already non exhaustive and no private fields, should be ignored #[non_exhaustive] - struct NonExhaustive { + pub struct NonExhaustive { pub a: i32, pub b: i32, } } -mod tuple_structs { - struct T(pub i32, pub i32, ()); - //~^ ERROR: this seems like a manual implementation of the non-exhaustive pattern +pub mod tuple_structs { + pub struct T(pub i32, pub i32, ()); + //~^ manual_non_exhaustive // user forgot to remove the private field #[non_exhaustive] - struct Tp(pub i32, pub i32, ()); - //~^ ERROR: this seems like a manual implementation of the non-exhaustive pattern + pub struct Tp(pub i32, pub i32, ()); + //~^ manual_non_exhaustive // some other fields are private, should be ignored - struct PrivateFields(pub i32, i32, ()); + pub struct PrivateFields(pub i32, i32, ()); // private field is not unit type, should be ignored - struct NotUnit(pub i32, pub i32, i32); + pub struct NotUnit(pub i32, pub i32, i32); // private field is the only field, should be ignored - struct OnlyMarker(()); + pub struct OnlyMarker(()); // already non exhaustive and no private fields, should be ignored #[non_exhaustive] - struct NonExhaustive(pub i32, pub i32); + pub struct NonExhaustive(pub i32, pub i32); } -fn main() {} +mod private { + // Don't lint structs that are not actually public as `#[non_exhaustive]` only applies to + // external crates. The manual pattern can still be used to get module local non exhaustiveness + pub struct NotPublic { + pub a: i32, + pub b: i32, + _c: (), + } +} diff --git a/tests/ui/manual_non_exhaustive_struct.stderr b/tests/ui/manual_non_exhaustive_struct.stderr index 1cab812988a..81de1e4f271 100644 --- a/tests/ui/manual_non_exhaustive_struct.stderr +++ b/tests/ui/manual_non_exhaustive_struct.stderr @@ -1,11 +1,7 @@ error: this seems like a manual implementation of the non-exhaustive pattern --> tests/ui/manual_non_exhaustive_struct.rs:5:5 | -LL | struct S { - | ^------- - | | - | _____help: add the attribute: `#[non_exhaustive] struct S` - | | +LL | / pub struct S { LL | | LL | | pub a: i32, LL | | pub b: i32, @@ -20,11 +16,16 @@ LL | _c: (), | ^^^^^^ = note: `-D clippy::manual-non-exhaustive` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::manual_non_exhaustive)]` +help: use the `#[non_exhaustive]` attribute instead + | +LL ~ #[non_exhaustive] +LL ~ pub struct S { + | error: this seems like a manual implementation of the non-exhaustive pattern --> tests/ui/manual_non_exhaustive_struct.rs:14:5 | -LL | / struct Sp { +LL | / pub struct Sp { LL | | LL | | pub a: i32, LL | | pub b: i32, @@ -32,6 +33,11 @@ LL | | _c: (), LL | | } | |_____^ | +note: the struct is already non-exhaustive + --> tests/ui/manual_non_exhaustive_struct.rs:13:5 + | +LL | #[non_exhaustive] + | ^^^^^^^^^^^^^^^^^ help: remove this field --> tests/ui/manual_non_exhaustive_struct.rs:18:9 | @@ -39,13 +45,10 @@ LL | _c: (), | ^^^^^^ error: this seems like a manual implementation of the non-exhaustive pattern - --> tests/ui/manual_non_exhaustive_struct.rs:29:5 + --> tests/ui/manual_non_exhaustive_struct.rs:28:5 | -LL | struct NoUnderscore { - | ^------------------ - | | - | _____help: add the attribute: `#[non_exhaustive] struct NoUnderscore` - | | +LL | / pub struct NoUnderscore { +LL | | LL | | pub a: i32, LL | | pub b: i32, LL | | c: (), @@ -57,32 +60,45 @@ help: remove this field | LL | c: (), | ^^^^^ +help: use the `#[non_exhaustive]` attribute instead + | +LL ~ #[non_exhaustive] +LL ~ pub struct NoUnderscore { + | error: this seems like a manual implementation of the non-exhaustive pattern --> tests/ui/manual_non_exhaustive_struct.rs:56:5 | -LL | struct T(pub i32, pub i32, ()); - | --------^^^^^^^^^^^^^^^^^^^^^^^ - | | - | help: add the attribute: `#[non_exhaustive] struct T` +LL | pub struct T(pub i32, pub i32, ()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: remove this field - --> tests/ui/manual_non_exhaustive_struct.rs:56:32 + --> tests/ui/manual_non_exhaustive_struct.rs:56:36 + | +LL | pub struct T(pub i32, pub i32, ()); + | ^^ +help: use the `#[non_exhaustive]` attribute instead + | +LL ~ #[non_exhaustive] +LL ~ pub struct T(pub i32, pub i32, ()); | -LL | struct T(pub i32, pub i32, ()); - | ^^ error: this seems like a manual implementation of the non-exhaustive pattern --> tests/ui/manual_non_exhaustive_struct.rs:61:5 | -LL | struct Tp(pub i32, pub i32, ()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | pub struct Tp(pub i32, pub i32, ()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | +note: the struct is already non-exhaustive + --> tests/ui/manual_non_exhaustive_struct.rs:60:5 + | +LL | #[non_exhaustive] + | ^^^^^^^^^^^^^^^^^ help: remove this field - --> tests/ui/manual_non_exhaustive_struct.rs:61:33 + --> tests/ui/manual_non_exhaustive_struct.rs:61:37 | -LL | struct Tp(pub i32, pub i32, ()); - | ^^ +LL | pub struct Tp(pub i32, pub i32, ()); + | ^^ error: aborting due to 5 previous errors diff --git a/tests/ui/manual_range_patterns.fixed b/tests/ui/manual_range_patterns.fixed index f1b99637afd..60467bf9e88 100644 --- a/tests/ui/manual_range_patterns.fixed +++ b/tests/ui/manual_range_patterns.fixed @@ -45,4 +45,12 @@ fn main() { }; } mac!(f); + + #[rustfmt::skip] + let _ = match f { + | 2..=15 => 4, + | 241..=254 => 5, + | 255 => 6, + | _ => 7, + }; } diff --git a/tests/ui/manual_range_patterns.rs b/tests/ui/manual_range_patterns.rs index 869ffbe80b9..9cd80333449 100644 --- a/tests/ui/manual_range_patterns.rs +++ b/tests/ui/manual_range_patterns.rs @@ -45,4 +45,12 @@ fn main() { }; } mac!(f); + + #[rustfmt::skip] + let _ = match f { + | 2..=15 => 4, + | 241..=254 => 5, + | 255 => 6, + | _ => 7, + }; } diff --git a/tests/ui/manual_saturating_arithmetic.fixed b/tests/ui/manual_saturating_arithmetic.fixed index 41a32df32ee..528a65790c4 100644 --- a/tests/ui/manual_saturating_arithmetic.fixed +++ b/tests/ui/manual_saturating_arithmetic.fixed @@ -1,6 +1,6 @@ #![allow(clippy::legacy_numeric_constants, unused_imports)] -use std::{i128, i32, u128, u32}; +use std::{i32, i128, u32, u128}; fn main() { let _ = 1u32.saturating_add(1); diff --git a/tests/ui/manual_saturating_arithmetic.rs b/tests/ui/manual_saturating_arithmetic.rs index 3a6b32d8069..55f3720dfcc 100644 --- a/tests/ui/manual_saturating_arithmetic.rs +++ b/tests/ui/manual_saturating_arithmetic.rs @@ -1,6 +1,6 @@ #![allow(clippy::legacy_numeric_constants, unused_imports)] -use std::{i128, i32, u128, u32}; +use std::{i32, i128, u32, u128}; fn main() { let _ = 1u32.checked_add(1).unwrap_or(u32::max_value()); diff --git a/tests/ui/match_overlapping_arm.rs b/tests/ui/match_overlapping_arm.rs index 4457ae73da2..a056fdeaa5d 100644 --- a/tests/ui/match_overlapping_arm.rs +++ b/tests/ui/match_overlapping_arm.rs @@ -2,8 +2,6 @@ #![allow(clippy::redundant_pattern_matching)] #![allow(clippy::if_same_then_else, clippy::equatable_if_let, clippy::needless_if)] -/// Tests for match_overlapping_arm - fn overlapping() { const FOO: u64 = 2; diff --git a/tests/ui/match_overlapping_arm.stderr b/tests/ui/match_overlapping_arm.stderr index 65092ffbb55..a60a09a0799 100644 --- a/tests/ui/match_overlapping_arm.stderr +++ b/tests/ui/match_overlapping_arm.stderr @@ -1,11 +1,11 @@ error: some ranges overlap - --> tests/ui/match_overlapping_arm.rs:11:9 + --> tests/ui/match_overlapping_arm.rs:9:9 | LL | 0..=10 => println!("0..=10"), | ^^^^^^ | note: overlaps with this - --> tests/ui/match_overlapping_arm.rs:13:9 + --> tests/ui/match_overlapping_arm.rs:11:9 | LL | 0..=11 => println!("0..=11"), | ^^^^^^ @@ -13,85 +13,85 @@ LL | 0..=11 => println!("0..=11"), = help: to override `-D warnings` add `#[allow(clippy::match_overlapping_arm)]` error: some ranges overlap - --> tests/ui/match_overlapping_arm.rs:18:9 + --> tests/ui/match_overlapping_arm.rs:16:9 | LL | 0..=5 => println!("0..=5"), | ^^^^^ | note: overlaps with this - --> tests/ui/match_overlapping_arm.rs:21:9 + --> tests/ui/match_overlapping_arm.rs:19:9 | LL | FOO..=11 => println!("FOO..=11"), | ^^^^^^^^ error: some ranges overlap - --> tests/ui/match_overlapping_arm.rs:56:9 + --> tests/ui/match_overlapping_arm.rs:54:9 | LL | 0..11 => println!("0..11"), | ^^^^^ | note: overlaps with this - --> tests/ui/match_overlapping_arm.rs:58:9 + --> tests/ui/match_overlapping_arm.rs:56:9 | LL | 0..=11 => println!("0..=11"), | ^^^^^^ error: some ranges overlap - --> tests/ui/match_overlapping_arm.rs:82:9 + --> tests/ui/match_overlapping_arm.rs:80:9 | LL | 0..=10 => println!("0..=10"), | ^^^^^^ | note: overlaps with this - --> tests/ui/match_overlapping_arm.rs:81:9 + --> tests/ui/match_overlapping_arm.rs:79:9 | LL | 5..14 => println!("5..14"), | ^^^^^ error: some ranges overlap - --> tests/ui/match_overlapping_arm.rs:88:9 + --> tests/ui/match_overlapping_arm.rs:86:9 | LL | 0..7 => println!("0..7"), | ^^^^ | note: overlaps with this - --> tests/ui/match_overlapping_arm.rs:90:9 + --> tests/ui/match_overlapping_arm.rs:88:9 | LL | 0..=10 => println!("0..=10"), | ^^^^^^ error: some ranges overlap - --> tests/ui/match_overlapping_arm.rs:101:9 + --> tests/ui/match_overlapping_arm.rs:99:9 | LL | ..=23 => println!("..=23"), | ^^^^^ | note: overlaps with this - --> tests/ui/match_overlapping_arm.rs:103:9 + --> tests/ui/match_overlapping_arm.rs:101:9 | LL | ..26 => println!("..26"), | ^^^^ error: some ranges overlap - --> tests/ui/match_overlapping_arm.rs:111:9 + --> tests/ui/match_overlapping_arm.rs:109:9 | LL | 21..=30 => (), | ^^^^^^^ | note: overlaps with this - --> tests/ui/match_overlapping_arm.rs:113:9 + --> tests/ui/match_overlapping_arm.rs:111:9 | LL | 21..=40 => (), | ^^^^^^^ error: some ranges overlap - --> tests/ui/match_overlapping_arm.rs:126:9 + --> tests/ui/match_overlapping_arm.rs:124:9 | LL | 0..=0x0000_0000_0000_00ff => (), | ^^^^^^^^^^^^^^^^^^^^^^^^^ | note: overlaps with this - --> tests/ui/match_overlapping_arm.rs:128:9 + --> tests/ui/match_overlapping_arm.rs:126:9 | LL | 0..=0x0000_0000_0000_ffff => (), | ^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/mixed_attributes_style.rs b/tests/ui/mixed_attributes_style.rs index 1a646c26522..93ab9392cf8 100644 --- a/tests/ui/mixed_attributes_style.rs +++ b/tests/ui/mixed_attributes_style.rs @@ -82,7 +82,8 @@ mod issue_12530 { #![allow(dead_code)] } } - /// Nested mod //~ ERROR: item has both inner and outer attributes + /// Nested mod + //~^ ERROR: item has both inner and outer attributes #[allow(unused)] mod nest_mod_2 { #![allow(unused)] diff --git a/tests/ui/mixed_attributes_style.stderr b/tests/ui/mixed_attributes_style.stderr index a1d3fc430f6..abdc2df23cf 100644 --- a/tests/ui/mixed_attributes_style.stderr +++ b/tests/ui/mixed_attributes_style.stderr @@ -46,13 +46,14 @@ error: item has both inner and outer attributes --> tests/ui/mixed_attributes_style.rs:85:5 | LL | / /// Nested mod +LL | | LL | | #[allow(unused)] LL | | mod nest_mod_2 { LL | | #![allow(unused)] | |_________________________^ error: item has both inner and outer attributes - --> tests/ui/mixed_attributes_style.rs:90:9 + --> tests/ui/mixed_attributes_style.rs:91:9 | LL | / #[allow(dead_code)] LL | | mod inner_mod { diff --git a/tests/ui/must_use_candidates.fixed b/tests/ui/must_use_candidates.fixed index adb266ffbc8..2459af60688 100644 --- a/tests/ui/must_use_candidates.fixed +++ b/tests/ui/must_use_candidates.fixed @@ -7,8 +7,8 @@ )] #![warn(clippy::must_use_candidate)] use std::rc::Rc; -use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::Arc; +use std::sync::atomic::{AtomicBool, Ordering}; pub struct MyAtomic(AtomicBool); pub struct MyPure; diff --git a/tests/ui/must_use_candidates.rs b/tests/ui/must_use_candidates.rs index 49bb16af788..5f9b2449552 100644 --- a/tests/ui/must_use_candidates.rs +++ b/tests/ui/must_use_candidates.rs @@ -7,8 +7,8 @@ )] #![warn(clippy::must_use_candidate)] use std::rc::Rc; -use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::Arc; +use std::sync::atomic::{AtomicBool, Ordering}; pub struct MyAtomic(AtomicBool); pub struct MyPure; diff --git a/tests/ui/mut_key.rs b/tests/ui/mut_key.rs index 81d8732b3b2..43ff705c477 100644 --- a/tests/ui/mut_key.rs +++ b/tests/ui/mut_key.rs @@ -2,9 +2,9 @@ use std::cell::Cell; use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet}; use std::hash::{Hash, Hasher}; use std::rc::Rc; +use std::sync::Arc; use std::sync::atomic::AtomicUsize; use std::sync::atomic::Ordering::Relaxed; -use std::sync::Arc; struct Key(AtomicUsize); diff --git a/tests/ui/needless_pass_by_value.rs b/tests/ui/needless_pass_by_value.rs index 14cba5a7eb5..9408b8c948f 100644 --- a/tests/ui/needless_pass_by_value.rs +++ b/tests/ui/needless_pass_by_value.rs @@ -84,7 +84,7 @@ trait Serialize {} impl<'a, T> Serialize for &'a T where T: Serialize {} impl Serialize for i32 {} -fn test_blanket_ref(_foo: T, _serializable: S) {} +fn test_blanket_ref(vals: T, serializable: S) {} //~^ ERROR: this argument is passed by value, but not consumed in the function body fn issue_2114(s: String, t: String, u: Vec, v: Vec) { @@ -116,7 +116,7 @@ impl S { ) { } - fn baz(&self, _u: U, _s: Self) {} + fn baz(&self, uu: U, ss: Self) {} //~^ ERROR: this argument is passed by value, but not consumed in the function body //~| ERROR: this argument is passed by value, but not consumed in the function body } @@ -162,13 +162,13 @@ fn test_destructure_copy(x: CopyWrapper, y: CopyWrapper, z: CopyWrapper) { // The following 3 lines should not cause an ICE. See #2831 trait Bar<'a, A> {} impl<'b, T> Bar<'b, T> for T {} -fn some_fun<'b, S: Bar<'b, ()>>(_item: S) {} +fn some_fun<'b, S: Bar<'b, ()>>(items: S) {} //~^ ERROR: this argument is passed by value, but not consumed in the function body // Also this should not cause an ICE. See #2831 trait Club<'a, A> {} impl Club<'static, T> for T {} -fn more_fun(_item: impl Club<'static, i32>) {} +fn more_fun(items: impl Club<'static, i32>) {} //~^ ERROR: this argument is passed by value, but not consumed in the function body fn is_sync(_: T) @@ -177,6 +177,10 @@ where { } +struct Obj(String); + +fn prefix_test(_unused_with_prefix: Obj) {} + fn main() { // This should not cause an ICE either // https://github.com/rust-lang/rust-clippy/issues/3144 diff --git a/tests/ui/needless_pass_by_value.stderr b/tests/ui/needless_pass_by_value.stderr index 827a200ba68..46ef8f3e8da 100644 --- a/tests/ui/needless_pass_by_value.stderr +++ b/tests/ui/needless_pass_by_value.stderr @@ -46,7 +46,7 @@ LL | fn test_destructure(x: Wrapper, y: Wrapper, z: Wrapper) { error: this argument is passed by value, but not consumed in the function body --> tests/ui/needless_pass_by_value.rs:87:49 | -LL | fn test_blanket_ref(_foo: T, _serializable: S) {} +LL | fn test_blanket_ref(vals: T, serializable: S) {} | ^ help: consider taking a reference instead: `&T` error: this argument is passed by value, but not consumed in the function body @@ -106,13 +106,13 @@ LL | t: String, error: this argument is passed by value, but not consumed in the function body --> tests/ui/needless_pass_by_value.rs:119:23 | -LL | fn baz(&self, _u: U, _s: Self) {} +LL | fn baz(&self, uu: U, ss: Self) {} | ^ help: consider taking a reference instead: `&U` error: this argument is passed by value, but not consumed in the function body --> tests/ui/needless_pass_by_value.rs:119:30 | -LL | fn baz(&self, _u: U, _s: Self) {} +LL | fn baz(&self, uu: U, ss: Self) {} | ^^^^ help: consider taking a reference instead: `&Self` error: this argument is passed by value, but not consumed in the function body @@ -121,7 +121,7 @@ error: this argument is passed by value, but not consumed in the function body LL | fn bar_copy(x: u32, y: CopyWrapper) { | ^^^^^^^^^^^ help: consider taking a reference instead: `&CopyWrapper` | -help: consider marking this type as `Copy` +help: or consider marking this type as `Copy` --> tests/ui/needless_pass_by_value.rs:141:1 | LL | struct CopyWrapper(u32); @@ -133,7 +133,7 @@ error: this argument is passed by value, but not consumed in the function body LL | fn test_destructure_copy(x: CopyWrapper, y: CopyWrapper, z: CopyWrapper) { | ^^^^^^^^^^^ help: consider taking a reference instead: `&CopyWrapper` | -help: consider marking this type as `Copy` +help: or consider marking this type as `Copy` --> tests/ui/needless_pass_by_value.rs:141:1 | LL | struct CopyWrapper(u32); @@ -145,7 +145,7 @@ error: this argument is passed by value, but not consumed in the function body LL | fn test_destructure_copy(x: CopyWrapper, y: CopyWrapper, z: CopyWrapper) { | ^^^^^^^^^^^ help: consider taking a reference instead: `&CopyWrapper` | -help: consider marking this type as `Copy` +help: or consider marking this type as `Copy` --> tests/ui/needless_pass_by_value.rs:141:1 | LL | struct CopyWrapper(u32); @@ -157,7 +157,7 @@ error: this argument is passed by value, but not consumed in the function body LL | fn test_destructure_copy(x: CopyWrapper, y: CopyWrapper, z: CopyWrapper) { | ^^^^^^^^^^^ help: consider taking a reference instead: `&CopyWrapper` | -help: consider marking this type as `Copy` +help: or consider marking this type as `Copy` --> tests/ui/needless_pass_by_value.rs:141:1 | LL | struct CopyWrapper(u32); @@ -166,13 +166,13 @@ LL | struct CopyWrapper(u32); error: this argument is passed by value, but not consumed in the function body --> tests/ui/needless_pass_by_value.rs:165:40 | -LL | fn some_fun<'b, S: Bar<'b, ()>>(_item: S) {} +LL | fn some_fun<'b, S: Bar<'b, ()>>(items: S) {} | ^ help: consider taking a reference instead: `&S` error: this argument is passed by value, but not consumed in the function body --> tests/ui/needless_pass_by_value.rs:171:20 | -LL | fn more_fun(_item: impl Club<'static, i32>) {} +LL | fn more_fun(items: impl Club<'static, i32>) {} | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider taking a reference instead: `&impl Club<'static, i32>` error: aborting due to 22 previous errors diff --git a/tests/ui/needless_return.fixed b/tests/ui/needless_return.fixed index fc4129e1db8..c5c570690b4 100644 --- a/tests/ui/needless_return.fixed +++ b/tests/ui/needless_return.fixed @@ -355,4 +355,8 @@ fn conjunctive_blocks() -> String { ({ "a".to_string() } + "b" + { "c" }) } +fn issue12907() -> String { + "".split("").next().unwrap().to_string() +} + fn main() {} diff --git a/tests/ui/needless_return.rs b/tests/ui/needless_return.rs index 61c7a02008f..738611391df 100644 --- a/tests/ui/needless_return.rs +++ b/tests/ui/needless_return.rs @@ -365,4 +365,8 @@ fn conjunctive_blocks() -> String { return { "a".to_string() } + "b" + { "c" }; } +fn issue12907() -> String { + return "".split("").next().unwrap().to_string(); +} + fn main() {} diff --git a/tests/ui/needless_return.stderr b/tests/ui/needless_return.stderr index ea9c230eafd..da0fa220d8c 100644 --- a/tests/ui/needless_return.stderr +++ b/tests/ui/needless_return.stderr @@ -665,5 +665,17 @@ LL - return { "a".to_string() } + "b" + { "c" }; LL + ({ "a".to_string() } + "b" + { "c" }) | -error: aborting due to 53 previous errors +error: unneeded `return` statement + --> tests/ui/needless_return.rs:369:5 + | +LL | return "".split("").next().unwrap().to_string(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove `return` + | +LL - return "".split("").next().unwrap().to_string(); +LL + "".split("").next().unwrap().to_string() + | + +error: aborting due to 54 previous errors diff --git a/tests/ui/non_octal_unix_permissions.fixed b/tests/ui/non_octal_unix_permissions.fixed index 237f5f5b97a..f68d5e30d27 100644 --- a/tests/ui/non_octal_unix_permissions.fixed +++ b/tests/ui/non_octal_unix_permissions.fixed @@ -1,4 +1,4 @@ -//@ignore-target-windows +//@ignore-target: windows #![warn(clippy::non_octal_unix_permissions)] use std::fs::{DirBuilder, File, OpenOptions, Permissions}; diff --git a/tests/ui/non_octal_unix_permissions.rs b/tests/ui/non_octal_unix_permissions.rs index c8da5dbcec2..647c3769d2c 100644 --- a/tests/ui/non_octal_unix_permissions.rs +++ b/tests/ui/non_octal_unix_permissions.rs @@ -1,4 +1,4 @@ -//@ignore-target-windows +//@ignore-target: windows #![warn(clippy::non_octal_unix_permissions)] use std::fs::{DirBuilder, File, OpenOptions, Permissions}; diff --git a/tests/ui/non_zero_suggestions.fixed b/tests/ui/non_zero_suggestions.fixed new file mode 100644 index 00000000000..e67c992fdde --- /dev/null +++ b/tests/ui/non_zero_suggestions.fixed @@ -0,0 +1,65 @@ +#![warn(clippy::non_zero_suggestions)] +use std::num::{NonZeroI8, NonZeroI16, NonZeroU8, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroUsize}; + +fn main() { + /// Positive test cases (lint should trigger) + // U32 -> U64 + let x: u64 = 100; + let y = NonZeroU32::new(10).unwrap(); + let r1 = x / NonZeroU64::from(y); + //~^ ERROR: consider using `NonZeroU64::from()` for more efficient and type-safe conversion + + let r2 = x % NonZeroU64::from(y); + //~^ ERROR: consider using `NonZeroU64::from()` for more efficient and type-safe conversion + + // U16 -> U32 + let a: u32 = 50; + let b = NonZeroU16::new(5).unwrap(); + let r3 = a / NonZeroU32::from(b); + //~^ ERROR: consider using `NonZeroU32::from()` for more efficient and type-safe conversion + + let x = NonZeroU64::from(NonZeroU32::new(5).unwrap()); + //~^ ERROR: consider using `NonZeroU64::from()` for more efficient and type-safe conversion + + /// Negative test cases (lint should not trigger) + // Left hand side expressions should not be triggered + let c: u32 = 50; + let d = NonZeroU16::new(5).unwrap(); + let r4 = u32::from(b.get()) / a; + + // Should not trigger for any other operand other than `/` and `%` + let r5 = a + u32::from(b.get()); + let r6 = a - u32::from(b.get()); + + // Same size types + let e: u32 = 200; + let f = NonZeroU32::new(20).unwrap(); + let r7 = e / f.get(); + + // Smaller to larger, but not NonZero + let g: u64 = 1000; + let h: u32 = 50; + let r8 = g / u64::from(h); + + // Using From correctly + let k: u64 = 300; + let l = NonZeroU32::new(15).unwrap(); + let r9 = k / NonZeroU64::from(l); +} + +// Additional function to test the lint in a different context +fn divide_numbers(x: u64, y: NonZeroU32) -> u64 { + x / NonZeroU64::from(y) + //~^ ERROR: consider using `NonZeroU64::from()` for more efficient and type-safe conversion +} + +struct Calculator { + value: u64, +} + +impl Calculator { + fn divide(&self, divisor: NonZeroU32) -> u64 { + self.value / NonZeroU64::from(divisor) + //~^ ERROR: consider using `NonZeroU64::from()` for more efficient and type-safe conversion + } +} diff --git a/tests/ui/non_zero_suggestions.rs b/tests/ui/non_zero_suggestions.rs new file mode 100644 index 00000000000..de82371a8f2 --- /dev/null +++ b/tests/ui/non_zero_suggestions.rs @@ -0,0 +1,65 @@ +#![warn(clippy::non_zero_suggestions)] +use std::num::{NonZeroI8, NonZeroI16, NonZeroU8, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroUsize}; + +fn main() { + /// Positive test cases (lint should trigger) + // U32 -> U64 + let x: u64 = 100; + let y = NonZeroU32::new(10).unwrap(); + let r1 = x / u64::from(y.get()); + //~^ ERROR: consider using `NonZeroU64::from()` for more efficient and type-safe conversion + + let r2 = x % u64::from(y.get()); + //~^ ERROR: consider using `NonZeroU64::from()` for more efficient and type-safe conversion + + // U16 -> U32 + let a: u32 = 50; + let b = NonZeroU16::new(5).unwrap(); + let r3 = a / u32::from(b.get()); + //~^ ERROR: consider using `NonZeroU32::from()` for more efficient and type-safe conversion + + let x = u64::from(NonZeroU32::new(5).unwrap().get()); + //~^ ERROR: consider using `NonZeroU64::from()` for more efficient and type-safe conversion + + /// Negative test cases (lint should not trigger) + // Left hand side expressions should not be triggered + let c: u32 = 50; + let d = NonZeroU16::new(5).unwrap(); + let r4 = u32::from(b.get()) / a; + + // Should not trigger for any other operand other than `/` and `%` + let r5 = a + u32::from(b.get()); + let r6 = a - u32::from(b.get()); + + // Same size types + let e: u32 = 200; + let f = NonZeroU32::new(20).unwrap(); + let r7 = e / f.get(); + + // Smaller to larger, but not NonZero + let g: u64 = 1000; + let h: u32 = 50; + let r8 = g / u64::from(h); + + // Using From correctly + let k: u64 = 300; + let l = NonZeroU32::new(15).unwrap(); + let r9 = k / NonZeroU64::from(l); +} + +// Additional function to test the lint in a different context +fn divide_numbers(x: u64, y: NonZeroU32) -> u64 { + x / u64::from(y.get()) + //~^ ERROR: consider using `NonZeroU64::from()` for more efficient and type-safe conversion +} + +struct Calculator { + value: u64, +} + +impl Calculator { + fn divide(&self, divisor: NonZeroU32) -> u64 { + self.value / u64::from(divisor.get()) + //~^ ERROR: consider using `NonZeroU64::from()` for more efficient and type-safe conversion + } +} diff --git a/tests/ui/non_zero_suggestions.stderr b/tests/ui/non_zero_suggestions.stderr new file mode 100644 index 00000000000..7a57f7983be --- /dev/null +++ b/tests/ui/non_zero_suggestions.stderr @@ -0,0 +1,41 @@ +error: consider using `NonZeroU64::from()` for more efficient and type-safe conversion + --> tests/ui/non_zero_suggestions.rs:9:18 + | +LL | let r1 = x / u64::from(y.get()); + | ^^^^^^^^^^^^^^^^^^ help: replace with: `NonZeroU64::from(y)` + | + = note: `-D clippy::non-zero-suggestions` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::non_zero_suggestions)]` + +error: consider using `NonZeroU64::from()` for more efficient and type-safe conversion + --> tests/ui/non_zero_suggestions.rs:12:18 + | +LL | let r2 = x % u64::from(y.get()); + | ^^^^^^^^^^^^^^^^^^ help: replace with: `NonZeroU64::from(y)` + +error: consider using `NonZeroU32::from()` for more efficient and type-safe conversion + --> tests/ui/non_zero_suggestions.rs:18:18 + | +LL | let r3 = a / u32::from(b.get()); + | ^^^^^^^^^^^^^^^^^^ help: replace with: `NonZeroU32::from(b)` + +error: consider using `NonZeroU64::from()` for more efficient and type-safe conversion + --> tests/ui/non_zero_suggestions.rs:21:13 + | +LL | let x = u64::from(NonZeroU32::new(5).unwrap().get()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `NonZeroU64::from(NonZeroU32::new(5).unwrap())` + +error: consider using `NonZeroU64::from()` for more efficient and type-safe conversion + --> tests/ui/non_zero_suggestions.rs:52:9 + | +LL | x / u64::from(y.get()) + | ^^^^^^^^^^^^^^^^^^ help: replace with: `NonZeroU64::from(y)` + +error: consider using `NonZeroU64::from()` for more efficient and type-safe conversion + --> tests/ui/non_zero_suggestions.rs:62:22 + | +LL | self.value / u64::from(divisor.get()) + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `NonZeroU64::from(divisor)` + +error: aborting due to 6 previous errors + diff --git a/tests/ui/non_zero_suggestions_unfixable.rs b/tests/ui/non_zero_suggestions_unfixable.rs new file mode 100644 index 00000000000..193c710e589 --- /dev/null +++ b/tests/ui/non_zero_suggestions_unfixable.rs @@ -0,0 +1,23 @@ +#![warn(clippy::non_zero_suggestions)] +//@no-rustfix +use std::num::{NonZeroI8, NonZeroI16, NonZeroU8, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroUsize}; + +fn main() { + let x: u64 = u64::from(NonZeroU32::new(5).unwrap().get()); + //~^ ERROR: consider using `NonZeroU64::from()` for more efficient and type-safe conversion + + let n = NonZeroU32::new(20).unwrap(); + let y = u64::from(n.get()); + //~^ ERROR: consider using `NonZeroU64::from()` for more efficient and type-safe conversion + some_fn_that_only_takes_u64(y); + + let m = NonZeroU32::try_from(1).unwrap(); + let _z: NonZeroU64 = m.into(); +} + +fn return_non_zero(x: u64, y: NonZeroU32) -> u64 { + u64::from(y.get()) + //~^ ERROR: consider using `NonZeroU64::from()` for more efficient and type-safe conversion +} + +fn some_fn_that_only_takes_u64(_: u64) {} diff --git a/tests/ui/non_zero_suggestions_unfixable.stderr b/tests/ui/non_zero_suggestions_unfixable.stderr new file mode 100644 index 00000000000..787179f2a2d --- /dev/null +++ b/tests/ui/non_zero_suggestions_unfixable.stderr @@ -0,0 +1,23 @@ +error: consider using `NonZeroU64::from()` for more efficient and type-safe conversion + --> tests/ui/non_zero_suggestions_unfixable.rs:6:18 + | +LL | let x: u64 = u64::from(NonZeroU32::new(5).unwrap().get()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `NonZeroU64::from(NonZeroU32::new(5).unwrap())` + | + = note: `-D clippy::non-zero-suggestions` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::non_zero_suggestions)]` + +error: consider using `NonZeroU64::from()` for more efficient and type-safe conversion + --> tests/ui/non_zero_suggestions_unfixable.rs:10:13 + | +LL | let y = u64::from(n.get()); + | ^^^^^^^^^^^^^^^^^^ help: replace with: `NonZeroU64::from(n)` + +error: consider using `NonZeroU64::from()` for more efficient and type-safe conversion + --> tests/ui/non_zero_suggestions_unfixable.rs:19:5 + | +LL | u64::from(y.get()) + | ^^^^^^^^^^^^^^^^^^ help: replace with: `NonZeroU64::from(y)` + +error: aborting due to 3 previous errors + diff --git a/tests/ui/panic_in_result_fn.rs b/tests/ui/panic_in_result_fn.rs index aaaf9a109ac..e2375aa996f 100644 --- a/tests/ui/panic_in_result_fn.rs +++ b/tests/ui/panic_in_result_fn.rs @@ -71,6 +71,15 @@ fn function_result_with_custom_todo() -> Result // should not emit Ok(true) } +fn issue_13381() -> Result<(), String> { + const { + if N == 0 { + panic!(); + } + } + Ok(()) +} + fn main() -> Result<(), String> { todo!("finish main method"); Ok(()) diff --git a/tests/ui/pointers_in_nomem_asm_block.rs b/tests/ui/pointers_in_nomem_asm_block.rs new file mode 100644 index 00000000000..b5abcbb3474 --- /dev/null +++ b/tests/ui/pointers_in_nomem_asm_block.rs @@ -0,0 +1,33 @@ +//@ needs-asm-support +#![warn(clippy::pointers_in_nomem_asm_block)] +#![crate_type = "lib"] +#![no_std] + +use core::arch::asm; + +unsafe fn nomem_bad(p: &i32) { + asm!( + "asdf {p1}, {p2}, {p3}", + p1 = in(reg) p, + //~^ ERROR: passing pointers to nomem asm block + p2 = in(reg) p as *const _ as usize, + p3 = in(reg) p, + options(nomem, nostack, preserves_flags) + ); +} + +unsafe fn nomem_good(p: &i32) { + asm!("asdf {p}", p = in(reg) p, options(readonly, nostack, preserves_flags)); + let p = p as *const i32 as usize; + asm!("asdf {p}", p = in(reg) p, options(nomem, nostack, preserves_flags)); +} + +unsafe fn nomem_bad2(p: &mut i32) { + asm!("asdf {p}", p = in(reg) p, options(nomem, nostack, preserves_flags)); + //~^ ERROR: passing pointers to nomem asm block +} + +unsafe fn nomem_fn(p: extern "C" fn()) { + asm!("call {p}", p = in(reg) p, options(nomem)); + //~^ ERROR: passing pointers to nomem asm block +} diff --git a/tests/ui/pointers_in_nomem_asm_block.stderr b/tests/ui/pointers_in_nomem_asm_block.stderr new file mode 100644 index 00000000000..cabeb37344f --- /dev/null +++ b/tests/ui/pointers_in_nomem_asm_block.stderr @@ -0,0 +1,34 @@ +error: passing pointers to nomem asm block + --> tests/ui/pointers_in_nomem_asm_block.rs:11:9 + | +LL | p1 = in(reg) p, + | ^^^^^^^^^^^^^^ +... +LL | p3 = in(reg) p, + | ^^^^^^^^^^^^^^ + | + = note: `nomem` means that no memory write or read happens inside the asm! block + = note: if this is intentional and no pointers are read or written to, consider allowing the lint + = note: `-D clippy::pointers-in-nomem-asm-block` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::pointers_in_nomem_asm_block)]` + +error: passing pointers to nomem asm block + --> tests/ui/pointers_in_nomem_asm_block.rs:26:22 + | +LL | asm!("asdf {p}", p = in(reg) p, options(nomem, nostack, preserves_flags)); + | ^^^^^^^^^^^^^ + | + = note: `nomem` means that no memory write or read happens inside the asm! block + = note: if this is intentional and no pointers are read or written to, consider allowing the lint + +error: passing pointers to nomem asm block + --> tests/ui/pointers_in_nomem_asm_block.rs:31:22 + | +LL | asm!("call {p}", p = in(reg) p, options(nomem)); + | ^^^^^^^^^^^^^ + | + = note: `nomem` means that no memory write or read happens inside the asm! block + = note: if this is intentional and no pointers are read or written to, consider allowing the lint + +error: aborting due to 3 previous errors + diff --git a/tests/ui/ptr_arg.rs b/tests/ui/ptr_arg.rs index e6ef6268121..e8b42d3b913 100644 --- a/tests/ui/ptr_arg.rs +++ b/tests/ui/ptr_arg.rs @@ -309,3 +309,25 @@ mod issue_11181 { extern "C" fn allowed(_v: &Vec) {} } } + +mod issue_13308 { + use std::ops::Deref; + + fn repro(source: &str, destination: &mut String) { + source.clone_into(destination); + } + fn repro2(source: &str, destination: &mut String) { + ToOwned::clone_into(source, destination); + } + + fn h1(_: &::Target) {} + fn h2(_: T, _: &T::Target) {} + + // Other cases that are still ok to lint and ideally shouldn't regress + fn good(v1: &String, v2: &String) { + //~^ ERROR: writing `&String` instead of `&str` + //~^^ ERROR: writing `&String` instead of `&str` + h1(v1); + h2(String::new(), v2); + } +} diff --git a/tests/ui/ptr_arg.stderr b/tests/ui/ptr_arg.stderr index 4246453e64c..1a6b3aa1f8d 100644 --- a/tests/ui/ptr_arg.stderr +++ b/tests/ui/ptr_arg.stderr @@ -221,5 +221,17 @@ error: using a reference to `Cow` is not recommended LL | fn cow_bad_ret_ty_2<'a, 'b>(input: &'a Cow<'a, str>) -> &'b str { | ^^^^^^^^^^^^^^^^ help: change this to: `&str` -error: aborting due to 25 previous errors +error: writing `&String` instead of `&str` involves a new object where a slice will do + --> tests/ui/ptr_arg.rs:327:17 + | +LL | fn good(v1: &String, v2: &String) { + | ^^^^^^^ help: change this to: `&str` + +error: writing `&String` instead of `&str` involves a new object where a slice will do + --> tests/ui/ptr_arg.rs:327:30 + | +LL | fn good(v1: &String, v2: &String) { + | ^^^^^^^ help: change this to: `&str` + +error: aborting due to 27 previous errors diff --git a/tests/ui/ptr_cast_constness.fixed b/tests/ui/ptr_cast_constness.fixed index 21ac42196e1..9a5272c7adc 100644 --- a/tests/ui/ptr_cast_constness.fixed +++ b/tests/ui/ptr_cast_constness.fixed @@ -68,3 +68,20 @@ fn _msrv_1_65() { let _ = ptr.cast_mut(); let _ = mut_ptr.cast_const(); } + +#[inline_macros] +fn null_pointers() { + use std::ptr; + let _ = std::ptr::null_mut::(); + let _ = std::ptr::null::(); + let _ = std::ptr::null_mut::(); + let _ = std::ptr::null::(); + + // Make sure the lint is triggered inside a macro + let _ = inline!(std::ptr::null_mut::()); + let _ = inline!(std::ptr::null_mut::()); + + // Do not lint inside macros from external crates + let _ = external!(ptr::null::() as *mut u32); + let _ = external!(ptr::null::().cast_mut()); +} diff --git a/tests/ui/ptr_cast_constness.rs b/tests/ui/ptr_cast_constness.rs index 5ce590b2b7e..43ab5f5ba7c 100644 --- a/tests/ui/ptr_cast_constness.rs +++ b/tests/ui/ptr_cast_constness.rs @@ -68,3 +68,20 @@ fn _msrv_1_65() { let _ = ptr as *mut u32; let _ = mut_ptr as *const u32; } + +#[inline_macros] +fn null_pointers() { + use std::ptr; + let _ = ptr::null::() as *mut String; + let _ = ptr::null_mut::() as *const u32; + let _ = ptr::null::().cast_mut(); + let _ = ptr::null_mut::().cast_const(); + + // Make sure the lint is triggered inside a macro + let _ = inline!(ptr::null::() as *mut u32); + let _ = inline!(ptr::null::().cast_mut()); + + // Do not lint inside macros from external crates + let _ = external!(ptr::null::() as *mut u32); + let _ = external!(ptr::null::().cast_mut()); +} diff --git a/tests/ui/ptr_cast_constness.stderr b/tests/ui/ptr_cast_constness.stderr index 2c52ebd3464..a693793a4ae 100644 --- a/tests/ui/ptr_cast_constness.stderr +++ b/tests/ui/ptr_cast_constness.stderr @@ -43,5 +43,45 @@ error: `as` casting between raw pointers while changing only its constness LL | let _ = mut_ptr as *const u32; | ^^^^^^^^^^^^^^^^^^^^^ help: try `pointer::cast_const`, a safer alternative: `mut_ptr.cast_const()` -error: aborting due to 7 previous errors +error: `as` casting to make a const null pointer into a mutable null pointer + --> tests/ui/ptr_cast_constness.rs:75:13 + | +LL | let _ = ptr::null::() as *mut String; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `null_mut()` directly instead: `std::ptr::null_mut::()` + +error: `as` casting to make a mutable null pointer into a const null pointer + --> tests/ui/ptr_cast_constness.rs:76:13 + | +LL | let _ = ptr::null_mut::() as *const u32; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `null()` directly instead: `std::ptr::null::()` + +error: changing constness of a null pointer + --> tests/ui/ptr_cast_constness.rs:77:13 + | +LL | let _ = ptr::null::().cast_mut(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `null_mut()` directly instead: `std::ptr::null_mut::()` + +error: changing constness of a null pointer + --> tests/ui/ptr_cast_constness.rs:78:13 + | +LL | let _ = ptr::null_mut::().cast_const(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `null()` directly instead: `std::ptr::null::()` + +error: `as` casting to make a const null pointer into a mutable null pointer + --> tests/ui/ptr_cast_constness.rs:81:21 + | +LL | let _ = inline!(ptr::null::() as *mut u32); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `null_mut()` directly instead: `std::ptr::null_mut::()` + | + = note: this error originates in the macro `__inline_mac_fn_null_pointers` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: changing constness of a null pointer + --> tests/ui/ptr_cast_constness.rs:82:21 + | +LL | let _ = inline!(ptr::null::().cast_mut()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `null_mut()` directly instead: `std::ptr::null_mut::()` + | + = note: this error originates in the macro `__inline_mac_fn_null_pointers` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 13 previous errors diff --git a/tests/ui/result_large_err.rs b/tests/ui/result_large_err.rs index b25348bf996..9c39f023da2 100644 --- a/tests/ui/result_large_err.rs +++ b/tests/ui/result_large_err.rs @@ -1,4 +1,4 @@ -//@ignore-32bit +//@ignore-bitwidth: 32 #![warn(clippy::result_large_err)] #![allow(clippy::large_enum_variant)] diff --git a/tests/ui/single_call_fn.rs b/tests/ui/single_call_fn.rs index 55e7508a957..a0597664da5 100644 --- a/tests/ui/single_call_fn.rs +++ b/tests/ui/single_call_fn.rs @@ -1,4 +1,4 @@ -//@ignore-32bit +//@ignore-bitwidth: 32 //@aux-build:proc_macros.rs #![allow(clippy::redundant_closure_call, unused)] #![warn(clippy::single_call_fn)] diff --git a/tests/ui/single_match.fixed b/tests/ui/single_match.fixed index 5249c440889..4016b2699d6 100644 --- a/tests/ui/single_match.fixed +++ b/tests/ui/single_match.fixed @@ -39,8 +39,8 @@ enum Foo { Bar, Baz(u8), } -use std::borrow::Cow; use Foo::*; +use std::borrow::Cow; fn single_match_know_enum() { let x = Some(1u8); @@ -296,3 +296,27 @@ fn issue11365() { if let Some(A | B) = &Some(A) { println!() } } + +#[derive(Eq, PartialEq)] +pub struct Data([u8; 4]); + +const DATA: Data = Data([1, 2, 3, 4]); +const CONST_I32: i32 = 1; + +fn irrefutable_match() { + println!(); + + println!(); + + let i = 0; + { + let a = 1; + let b = 2; + } + + + + + + println!() +} diff --git a/tests/ui/single_match.rs b/tests/ui/single_match.rs index 882098a56e7..75edaa60605 100644 --- a/tests/ui/single_match.rs +++ b/tests/ui/single_match.rs @@ -51,8 +51,8 @@ enum Foo { Bar, Baz(u8), } -use std::borrow::Cow; use Foo::*; +use std::borrow::Cow; fn single_match_know_enum() { let x = Some(1u8); @@ -360,3 +360,45 @@ fn issue11365() { None | Some(_) => {}, } } + +#[derive(Eq, PartialEq)] +pub struct Data([u8; 4]); + +const DATA: Data = Data([1, 2, 3, 4]); +const CONST_I32: i32 = 1; + +fn irrefutable_match() { + match DATA { + DATA => println!(), + _ => {}, + } + + match CONST_I32 { + CONST_I32 => println!(), + _ => {}, + } + + let i = 0; + match i { + i => { + let a = 1; + let b = 2; + }, + _ => {}, + } + + match i { + i => {}, + _ => {}, + } + + match i { + i => (), + _ => (), + } + + match CONST_I32 { + CONST_I32 => println!(), + _ => {}, + } +} diff --git a/tests/ui/single_match.stderr b/tests/ui/single_match.stderr index ceb2a193bf7..9240b09c50a 100644 --- a/tests/ui/single_match.stderr +++ b/tests/ui/single_match.stderr @@ -216,5 +216,70 @@ LL | | None | Some(_) => {}, LL | | } | |_____^ help: try: `if let Some(A | B) = &Some(A) { println!() }` -error: aborting due to 20 previous errors +error: this pattern is irrefutable, `match` is useless + --> tests/ui/single_match.rs:371:5 + | +LL | / match DATA { +LL | | DATA => println!(), +LL | | _ => {}, +LL | | } + | |_____^ help: try: `println!();` + +error: this pattern is irrefutable, `match` is useless + --> tests/ui/single_match.rs:376:5 + | +LL | / match CONST_I32 { +LL | | CONST_I32 => println!(), +LL | | _ => {}, +LL | | } + | |_____^ help: try: `println!();` + +error: this pattern is irrefutable, `match` is useless + --> tests/ui/single_match.rs:382:5 + | +LL | / match i { +LL | | i => { +LL | | let a = 1; +LL | | let b = 2; +LL | | }, +LL | | _ => {}, +LL | | } + | |_____^ + | +help: try + | +LL ~ { +LL + let a = 1; +LL + let b = 2; +LL + } + | + +error: this pattern is irrefutable, `match` is useless + --> tests/ui/single_match.rs:390:5 + | +LL | / match i { +LL | | i => {}, +LL | | _ => {}, +LL | | } + | |_____^ help: `match` expression can be removed + +error: this pattern is irrefutable, `match` is useless + --> tests/ui/single_match.rs:395:5 + | +LL | / match i { +LL | | i => (), +LL | | _ => (), +LL | | } + | |_____^ help: `match` expression can be removed + +error: this pattern is irrefutable, `match` is useless + --> tests/ui/single_match.rs:400:5 + | +LL | / match CONST_I32 { +LL | | CONST_I32 => println!(), +LL | | _ => {}, +LL | | } + | |_____^ help: try: `println!()` + +error: aborting due to 26 previous errors diff --git a/tests/ui/single_match_else.fixed b/tests/ui/single_match_else.fixed index 163be16ad8b..c2ca746976b 100644 --- a/tests/ui/single_match_else.fixed +++ b/tests/ui/single_match_else.fixed @@ -171,3 +171,7 @@ fn issue_10808(bar: Option) { }, } } + +fn irrefutable_match() -> Option<&'static ExprNode> { + Some(&NODE) +} diff --git a/tests/ui/single_match_else.rs b/tests/ui/single_match_else.rs index 3f1fd2b3183..2d9e877ee0f 100644 --- a/tests/ui/single_match_else.rs +++ b/tests/ui/single_match_else.rs @@ -199,3 +199,13 @@ fn issue_10808(bar: Option) { }, } } + +fn irrefutable_match() -> Option<&'static ExprNode> { + match ExprNode::Butterflies { + ExprNode::Butterflies => Some(&NODE), + _ => { + let x = 5; + None + }, + } +} diff --git a/tests/ui/single_match_else.stderr b/tests/ui/single_match_else.stderr index 61c348260d0..a2801751a43 100644 --- a/tests/ui/single_match_else.stderr +++ b/tests/ui/single_match_else.stderr @@ -197,5 +197,17 @@ LL + println!("None"); LL + } | -error: aborting due to 9 previous errors +error: this pattern is irrefutable, `match` is useless + --> tests/ui/single_match_else.rs:204:5 + | +LL | / match ExprNode::Butterflies { +LL | | ExprNode::Butterflies => Some(&NODE), +LL | | _ => { +LL | | let x = 5; +LL | | None +LL | | }, +LL | | } + | |_____^ help: try: `Some(&NODE)` + +error: aborting due to 10 previous errors diff --git a/tests/ui/string_slice.rs b/tests/ui/string_slice.rs index 1d1911aaa1d..dc519493a4d 100644 --- a/tests/ui/string_slice.rs +++ b/tests/ui/string_slice.rs @@ -1,7 +1,7 @@ -use std::borrow::Cow; +#![warn(clippy::string_slice)] +#![allow(clippy::no_effect)] -#[warn(clippy::string_slice)] -#[allow(clippy::no_effect)] +use std::borrow::Cow; fn main() { &"Ölkanne"[1..]; diff --git a/tests/ui/suspicious_command_arg_space.fixed b/tests/ui/suspicious_command_arg_space.fixed index 5d7b1e0c17f..704d6ea1bb8 100644 --- a/tests/ui/suspicious_command_arg_space.fixed +++ b/tests/ui/suspicious_command_arg_space.fixed @@ -1,3 +1,4 @@ +#![allow(clippy::zombie_processes)] fn main() { // Things it should warn about: std::process::Command::new("echo").args(["-n", "hello"]).spawn().unwrap(); diff --git a/tests/ui/suspicious_command_arg_space.rs b/tests/ui/suspicious_command_arg_space.rs index 8abd9803a0c..2a2a7557381 100644 --- a/tests/ui/suspicious_command_arg_space.rs +++ b/tests/ui/suspicious_command_arg_space.rs @@ -1,3 +1,4 @@ +#![allow(clippy::zombie_processes)] fn main() { // Things it should warn about: std::process::Command::new("echo").arg("-n hello").spawn().unwrap(); diff --git a/tests/ui/suspicious_command_arg_space.stderr b/tests/ui/suspicious_command_arg_space.stderr index d2517b66b56..6fd07d07d7b 100644 --- a/tests/ui/suspicious_command_arg_space.stderr +++ b/tests/ui/suspicious_command_arg_space.stderr @@ -1,5 +1,5 @@ error: single argument that looks like it should be multiple arguments - --> tests/ui/suspicious_command_arg_space.rs:3:44 + --> tests/ui/suspicious_command_arg_space.rs:4:44 | LL | std::process::Command::new("echo").arg("-n hello").spawn().unwrap(); | ^^^^^^^^^^ @@ -12,7 +12,7 @@ LL | std::process::Command::new("echo").args(["-n", "hello"]).spawn().unwrap | ~~~~ ~~~~~~~~~~~~~~~ error: single argument that looks like it should be multiple arguments - --> tests/ui/suspicious_command_arg_space.rs:6:43 + --> tests/ui/suspicious_command_arg_space.rs:7:43 | LL | std::process::Command::new("cat").arg("--number file").spawn().unwrap(); | ^^^^^^^^^^^^^^^ diff --git a/tests/ui/suspicious_to_owned.rs b/tests/ui/suspicious_to_owned.rs index f32b07d45f6..794c2e7174a 100644 --- a/tests/ui/suspicious_to_owned.rs +++ b/tests/ui/suspicious_to_owned.rs @@ -3,7 +3,7 @@ #![warn(clippy::implicit_clone)] #![allow(clippy::redundant_clone)] use std::borrow::Cow; -use std::ffi::{c_char, CStr}; +use std::ffi::{CStr, c_char}; fn main() { let moo = "Moooo"; diff --git a/tests/ui/tabs_in_doc_comments.fixed b/tests/ui/tabs_in_doc_comments.fixed index 26cc5c27e88..3536c1746df 100644 --- a/tests/ui/tabs_in_doc_comments.fixed +++ b/tests/ui/tabs_in_doc_comments.fixed @@ -1,5 +1,4 @@ #![warn(clippy::tabs_in_doc_comments)] -#[allow(dead_code)] /// /// Struct to hold two strings: diff --git a/tests/ui/tabs_in_doc_comments.rs b/tests/ui/tabs_in_doc_comments.rs index 14b06966ecc..033a685066e 100644 --- a/tests/ui/tabs_in_doc_comments.rs +++ b/tests/ui/tabs_in_doc_comments.rs @@ -1,5 +1,4 @@ #![warn(clippy::tabs_in_doc_comments)] -#[allow(dead_code)] /// /// Struct to hold two strings: diff --git a/tests/ui/tabs_in_doc_comments.stderr b/tests/ui/tabs_in_doc_comments.stderr index aef6c391452..f8d30b728e5 100644 --- a/tests/ui/tabs_in_doc_comments.stderr +++ b/tests/ui/tabs_in_doc_comments.stderr @@ -1,5 +1,5 @@ error: using tabs in doc comments is not recommended - --> tests/ui/tabs_in_doc_comments.rs:6:5 + --> tests/ui/tabs_in_doc_comments.rs:5:5 | LL | /// - first one | ^^^^ help: consider using four spaces per tab @@ -8,43 +8,43 @@ LL | /// - first one = help: to override `-D warnings` add `#[allow(clippy::tabs_in_doc_comments)]` error: using tabs in doc comments is not recommended - --> tests/ui/tabs_in_doc_comments.rs:6:13 + --> tests/ui/tabs_in_doc_comments.rs:5:13 | LL | /// - first one | ^^^^^^^^ help: consider using four spaces per tab error: using tabs in doc comments is not recommended - --> tests/ui/tabs_in_doc_comments.rs:7:5 + --> tests/ui/tabs_in_doc_comments.rs:6:5 | LL | /// - second one | ^^^^ help: consider using four spaces per tab error: using tabs in doc comments is not recommended - --> tests/ui/tabs_in_doc_comments.rs:7:14 + --> tests/ui/tabs_in_doc_comments.rs:6:14 | LL | /// - second one | ^^^^ help: consider using four spaces per tab error: using tabs in doc comments is not recommended - --> tests/ui/tabs_in_doc_comments.rs:10:9 + --> tests/ui/tabs_in_doc_comments.rs:9:9 | LL | /// - First String: | ^^^^ help: consider using four spaces per tab error: using tabs in doc comments is not recommended - --> tests/ui/tabs_in_doc_comments.rs:11:9 + --> tests/ui/tabs_in_doc_comments.rs:10:9 | LL | /// - needs to be inside here | ^^^^^^^^ help: consider using four spaces per tab error: using tabs in doc comments is not recommended - --> tests/ui/tabs_in_doc_comments.rs:14:9 + --> tests/ui/tabs_in_doc_comments.rs:13:9 | LL | /// - Second String: | ^^^^ help: consider using four spaces per tab error: using tabs in doc comments is not recommended - --> tests/ui/tabs_in_doc_comments.rs:15:9 + --> tests/ui/tabs_in_doc_comments.rs:14:9 | LL | /// - needs to be inside here | ^^^^^^^^ help: consider using four spaces per tab diff --git a/tests/ui/too_long_first_doc_paragraph.rs b/tests/ui/too_long_first_doc_paragraph.rs index 1042249c5b7..7d0a37cde46 100644 --- a/tests/ui/too_long_first_doc_paragraph.rs +++ b/tests/ui/too_long_first_doc_paragraph.rs @@ -2,6 +2,16 @@ #![warn(clippy::too_long_first_doc_paragraph)] +pub mod foo { + + // in foo.rs + //! A very short summary. + //! A much longer explanation that goes into a lot more detail about + //! how the thing works, possibly with doclinks and so one, + //! and probably spanning a many rows. Blablabla, it needs to be over + //! 200 characters so I needed to write something longeeeeeeer. +} + /// Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc turpis nunc, lacinia /// a dolor in, pellentesque aliquet enim. Cras nec maximus sem. Mauris arcu libero, /// gravida non lacinia at, rhoncus eu lacus. diff --git a/tests/ui/too_long_first_doc_paragraph.stderr b/tests/ui/too_long_first_doc_paragraph.stderr index 7f48e5cf884..39926647f54 100644 --- a/tests/ui/too_long_first_doc_paragraph.stderr +++ b/tests/ui/too_long_first_doc_paragraph.stderr @@ -1,16 +1,32 @@ error: first doc comment paragraph is too long - --> tests/ui/too_long_first_doc_paragraph.rs:5:1 + --> tests/ui/too_long_first_doc_paragraph.rs:8:5 + | +LL | / //! A very short summary. +LL | | //! A much longer explanation that goes into a lot more detail about +LL | | //! how the thing works, possibly with doclinks and so one, +LL | | //! and probably spanning a many rows. Blablabla, it needs to be over +LL | | //! 200 characters so I needed to write something longeeeeeeer. + | |____^ + | + = note: `-D clippy::too-long-first-doc-paragraph` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::too_long_first_doc_paragraph)]` +help: add an empty line + | +LL ~ //! A very short summary. +LL + //! +LL ~ //! A much longer explanation that goes into a lot more detail about + | + +error: first doc comment paragraph is too long + --> tests/ui/too_long_first_doc_paragraph.rs:15:1 | LL | / /// Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc turpis nunc, lacinia LL | | /// a dolor in, pellentesque aliquet enim. Cras nec maximus sem. Mauris arcu libero, LL | | /// gravida non lacinia at, rhoncus eu lacus. | |_ - | - = note: `-D clippy::too-long-first-doc-paragraph` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::too_long_first_doc_paragraph)]` error: first doc comment paragraph is too long - --> tests/ui/too_long_first_doc_paragraph.rs:26:1 + --> tests/ui/too_long_first_doc_paragraph.rs:36:1 | LL | / /// Lorem LL | | /// ipsum dolor sit amet, consectetur adipiscing elit. Nunc turpis nunc, lacinia @@ -18,5 +34,5 @@ LL | | /// a dolor in, pellentesque aliquet enim. Cras nec maximus sem. Mauris a LL | | /// gravida non lacinia at, rhoncus eu lacus. | |_ -error: aborting due to 2 previous errors +error: aborting due to 3 previous errors diff --git a/tests/ui/transmute_32bit.rs b/tests/ui/transmute_32bit.rs index 8e1316ca39d..e162bbb2d92 100644 --- a/tests/ui/transmute_32bit.rs +++ b/tests/ui/transmute_32bit.rs @@ -1,4 +1,4 @@ -//@ignore-64bit +//@ignore-bitwidth: 64 #[warn(clippy::wrong_transmute)] fn main() { diff --git a/tests/ui/transmute_64bit.rs b/tests/ui/transmute_64bit.rs index 767cc503a39..fd0ad74bcfa 100644 --- a/tests/ui/transmute_64bit.rs +++ b/tests/ui/transmute_64bit.rs @@ -1,4 +1,4 @@ -//@ignore-32bit +//@ignore-bitwidth: 32 #[warn(clippy::wrong_transmute)] fn main() { diff --git a/tests/ui/transmute_collection.rs b/tests/ui/transmute_collection.rs index e30b34a5d7d..6748b66e0eb 100644 --- a/tests/ui/transmute_collection.rs +++ b/tests/ui/transmute_collection.rs @@ -2,7 +2,7 @@ #![allow(clippy::missing_transmute_annotations)] use std::collections::{BTreeMap, BTreeSet, BinaryHeap, HashMap, HashSet, VecDeque}; -use std::mem::{transmute, MaybeUninit}; +use std::mem::{MaybeUninit, transmute}; fn main() { unsafe { diff --git a/tests/ui/transmute_undefined_repr.rs b/tests/ui/transmute_undefined_repr.rs index dd4bac7f1ed..5b16d71f114 100644 --- a/tests/ui/transmute_undefined_repr.rs +++ b/tests/ui/transmute_undefined_repr.rs @@ -8,7 +8,7 @@ use core::any::TypeId; use core::ffi::c_void; -use core::mem::{size_of, transmute, MaybeUninit}; +use core::mem::{MaybeUninit, size_of, transmute}; use core::ptr::NonNull; fn value() -> T { diff --git a/tests/ui/uninit_vec.rs b/tests/ui/uninit_vec.rs index 0cc77a8775d..464f88140bd 100644 --- a/tests/ui/uninit_vec.rs +++ b/tests/ui/uninit_vec.rs @@ -150,4 +150,36 @@ fn main() { vec.set_len(10); } } + + fn nested_union() { + let mut vec: Vec>> = Vec::with_capacity(1); + unsafe { + vec.set_len(1); + } + } + + struct Recursive(*const Recursive, MaybeUninit); + fn recursive_union() { + // Make sure we don't stack overflow on recursive types. + // The pointer acts as the base case because it can't be uninit regardless of its pointee. + + let mut vec: Vec> = Vec::with_capacity(1); + //~^ uninit_vec + unsafe { + vec.set_len(1); + } + } + + #[repr(u8)] + enum Enum { + Variant(T), + } + fn union_in_enum() { + // Enums can have a discriminant that can't be uninit, so this should still warn + let mut vec: Vec> = Vec::with_capacity(1); + //~^ uninit_vec + unsafe { + vec.set_len(1); + } + } } diff --git a/tests/ui/uninit_vec.stderr b/tests/ui/uninit_vec.stderr index e8b77d653f0..e7c81cf792f 100644 --- a/tests/ui/uninit_vec.stderr +++ b/tests/ui/uninit_vec.stderr @@ -125,5 +125,27 @@ LL | vec.set_len(10); | = help: initialize the buffer or wrap the content in `MaybeUninit` -error: aborting due to 12 previous errors +error: calling `set_len()` immediately after reserving a buffer creates uninitialized values + --> tests/ui/uninit_vec.rs:166:9 + | +LL | let mut vec: Vec> = Vec::with_capacity(1); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | vec.set_len(1); + | ^^^^^^^^^^^^^^ + | + = help: initialize the buffer or wrap the content in `MaybeUninit` + +error: calling `set_len()` immediately after reserving a buffer creates uninitialized values + --> tests/ui/uninit_vec.rs:179:9 + | +LL | let mut vec: Vec> = Vec::with_capacity(1); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | vec.set_len(1); + | ^^^^^^^^^^^^^^ + | + = help: initialize the buffer or wrap the content in `MaybeUninit` + +error: aborting due to 14 previous errors diff --git a/tests/ui/unnecessary_first_then_check.fixed b/tests/ui/unnecessary_first_then_check.fixed new file mode 100644 index 00000000000..7202e1bbd17 --- /dev/null +++ b/tests/ui/unnecessary_first_then_check.fixed @@ -0,0 +1,22 @@ +#![warn(clippy::unnecessary_first_then_check)] +#![allow(clippy::useless_vec, clippy::const_is_empty)] + +fn main() { + let s = [1, 2, 3]; + let _: bool = !s.is_empty(); + let _: bool = s.is_empty(); + + let v = vec![1, 2, 3]; + let _: bool = !v.is_empty(); + + let n = [[1, 2, 3], [4, 5, 6]]; + let _: bool = !n[0].is_empty(); + let _: bool = n[0].is_empty(); + + struct Foo { + bar: &'static [i32], + } + let f = [Foo { bar: &[] }]; + let _: bool = !f[0].bar.is_empty(); + let _: bool = f[0].bar.is_empty(); +} diff --git a/tests/ui/unnecessary_first_then_check.rs b/tests/ui/unnecessary_first_then_check.rs new file mode 100644 index 00000000000..762b9599928 --- /dev/null +++ b/tests/ui/unnecessary_first_then_check.rs @@ -0,0 +1,22 @@ +#![warn(clippy::unnecessary_first_then_check)] +#![allow(clippy::useless_vec, clippy::const_is_empty)] + +fn main() { + let s = [1, 2, 3]; + let _: bool = s.first().is_some(); + let _: bool = s.first().is_none(); + + let v = vec![1, 2, 3]; + let _: bool = v.first().is_some(); + + let n = [[1, 2, 3], [4, 5, 6]]; + let _: bool = n[0].first().is_some(); + let _: bool = n[0].first().is_none(); + + struct Foo { + bar: &'static [i32], + } + let f = [Foo { bar: &[] }]; + let _: bool = f[0].bar.first().is_some(); + let _: bool = f[0].bar.first().is_none(); +} diff --git a/tests/ui/unnecessary_first_then_check.stderr b/tests/ui/unnecessary_first_then_check.stderr new file mode 100644 index 00000000000..bbaf7e68eda --- /dev/null +++ b/tests/ui/unnecessary_first_then_check.stderr @@ -0,0 +1,47 @@ +error: unnecessary use of `first().is_some()` to check if slice is not empty + --> tests/ui/unnecessary_first_then_check.rs:6:19 + | +LL | let _: bool = s.first().is_some(); + | ^^^^^^^^^^^^^^^^^^^ help: replace this with: `!s.is_empty()` + | + = note: `-D clippy::unnecessary-first-then-check` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::unnecessary_first_then_check)]` + +error: unnecessary use of `first().is_none()` to check if slice is empty + --> tests/ui/unnecessary_first_then_check.rs:7:21 + | +LL | let _: bool = s.first().is_none(); + | ^^^^^^^^^^^^^^^^^ help: replace this with: `is_empty()` + +error: unnecessary use of `first().is_some()` to check if slice is not empty + --> tests/ui/unnecessary_first_then_check.rs:10:19 + | +LL | let _: bool = v.first().is_some(); + | ^^^^^^^^^^^^^^^^^^^ help: replace this with: `!v.is_empty()` + +error: unnecessary use of `first().is_some()` to check if slice is not empty + --> tests/ui/unnecessary_first_then_check.rs:13:19 + | +LL | let _: bool = n[0].first().is_some(); + | ^^^^^^^^^^^^^^^^^^^^^^ help: replace this with: `!n[0].is_empty()` + +error: unnecessary use of `first().is_none()` to check if slice is empty + --> tests/ui/unnecessary_first_then_check.rs:14:24 + | +LL | let _: bool = n[0].first().is_none(); + | ^^^^^^^^^^^^^^^^^ help: replace this with: `is_empty()` + +error: unnecessary use of `first().is_some()` to check if slice is not empty + --> tests/ui/unnecessary_first_then_check.rs:20:19 + | +LL | let _: bool = f[0].bar.first().is_some(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace this with: `!f[0].bar.is_empty()` + +error: unnecessary use of `first().is_none()` to check if slice is empty + --> tests/ui/unnecessary_first_then_check.rs:21:28 + | +LL | let _: bool = f[0].bar.first().is_none(); + | ^^^^^^^^^^^^^^^^^ help: replace this with: `is_empty()` + +error: aborting due to 7 previous errors + diff --git a/tests/ui/unnecessary_min_or_max.fixed b/tests/ui/unnecessary_min_or_max.fixed index 392f6dd1fee..1f3e131516c 100644 --- a/tests/ui/unnecessary_min_or_max.fixed +++ b/tests/ui/unnecessary_min_or_max.fixed @@ -65,3 +65,32 @@ fn random_u32() -> u32 { // random number generator 0 } + +struct Issue13191 { + min: u16, + max: u16, +} + +impl Issue13191 { + fn new() -> Self { + Self { min: 0, max: 0 } + } + + fn min(mut self, value: u16) -> Self { + self.min = value; + self + } + + fn max(mut self, value: u16) -> Self { + self.max = value; + self + } +} + +fn issue_13191() { + // should not fixed + Issue13191::new().min(0); + + // should not fixed + Issue13191::new().max(0); +} diff --git a/tests/ui/unnecessary_min_or_max.rs b/tests/ui/unnecessary_min_or_max.rs index b03755e6d23..58356b9d49e 100644 --- a/tests/ui/unnecessary_min_or_max.rs +++ b/tests/ui/unnecessary_min_or_max.rs @@ -65,3 +65,32 @@ fn random_u32() -> u32 { // random number generator 0 } + +struct Issue13191 { + min: u16, + max: u16, +} + +impl Issue13191 { + fn new() -> Self { + Self { min: 0, max: 0 } + } + + fn min(mut self, value: u16) -> Self { + self.min = value; + self + } + + fn max(mut self, value: u16) -> Self { + self.max = value; + self + } +} + +fn issue_13191() { + // should not fixed + Issue13191::new().min(0); + + // should not fixed + Issue13191::new().max(0); +} diff --git a/tests/ui/unsafe_removed_from_name.rs b/tests/ui/unsafe_removed_from_name.rs index e0e0ded140f..e9e6c8312f5 100644 --- a/tests/ui/unsafe_removed_from_name.rs +++ b/tests/ui/unsafe_removed_from_name.rs @@ -7,7 +7,7 @@ use std::cell::UnsafeCell as TotallySafeCell; //~| NOTE: `-D clippy::unsafe-removed-from-name` implied by `-D warnings` use std::cell::UnsafeCell as TotallySafeCellAgain; -//~^ ERROR: removed `unsafe` from the name of `UnsafeCell` in use as `TotallySafeCellAgain +//~^ ERROR: removed `unsafe` from the name of `UnsafeCell` in use as `TotallySafeCellAgain` // Shouldn't error use std::cell::RefCell as ProbablyNotUnsafe; diff --git a/tests/ui/unused_trait_names.fixed b/tests/ui/unused_trait_names.fixed new file mode 100644 index 00000000000..7dfd0db65aa --- /dev/null +++ b/tests/ui/unused_trait_names.fixed @@ -0,0 +1,286 @@ +//@aux-build:proc_macros.rs + +#![allow(unused)] +#![warn(clippy::unused_trait_names)] +#![feature(decl_macro)] + +extern crate proc_macros; + +fn main() {} + +fn bad() { + use std::any::Any as _; + + println!("{:?}", "foo".type_id()); +} + +fn good() { + use std::any::Any as _; + + println!("{:?}", "foo".type_id()); +} + +fn used_good() { + use std::any::Any; + + println!("{:?}", Any::type_id("foo")); + println!("{:?}", "foo".type_id()); +} + +fn multi_bad() { + use std::any::{self, Any as _, TypeId}; + + println!("{:?}", "foo".type_id()); +} + +fn multi_good() { + use std::any::{self, Any as _, TypeId}; + + println!("{:?}", "foo".type_id()); +} + +fn renamed_bad() { + use std::any::Any as _; + + println!("{:?}", "foo".type_id()); +} + +fn multi_renamed_bad() { + use std::any::{Any as _, TypeId as MyTypeId}; + + println!("{:?}", "foo".type_id()); +} + +mod pub_good { + pub use std::any::Any; + + fn foo() { + println!("{:?}", "foo".type_id()); + } +} + +mod used_mod_good { + use std::any::Any; + + fn foo() { + println!("{:?}", Any::type_id("foo")); + } +} + +mod mod_import_bad { + fn mod_import_bad() { + use std::any::Any as _; + + println!("{:?}", "foo".type_id()); + } +} + +mod nested_mod_used_good1 { + use std::any::Any; + + mod foo { + fn foo() { + super::Any::type_id("foo"); + } + } +} + +mod nested_mod_used_good2 { + use std::any::Any; + + mod foo { + use super::Any; + + fn foo() { + Any::type_id("foo"); + } + } +} + +mod nested_mod_used_good3 { + use std::any::Any; + + mod foo { + use crate::nested_mod_used_good3::Any; + + fn foo() { + println!("{:?}", Any::type_id("foo")); + } + } +} + +mod nested_mod_used_bad { + use std::any::Any as _; + + fn bar() { + println!("{:?}", "foo".type_id()); + } + + mod foo { + use std::any::Any; + + fn foo() { + println!("{:?}", Any::type_id("foo")); + } + } +} + +// More complex example where `use std::any::Any;` should be anonymised but `use std::any::Any as +// MyAny;` should not as it is used by a sub module. Even though if you removed `use std::any::Any;` +// the code would still compile. +mod nested_mod_used_bad1 { + use std::any::Any as _; + + use std::any::Any as MyAny; + + fn baz() { + println!("{:?}", "baz".type_id()); + } + + mod foo { + use crate::nested_mod_used_bad1::MyAny; + + fn foo() { + println!("{:?}", MyAny::type_id("foo")); + } + } +} + +// Example of nested import with an unused import to try and trick it +mod nested_mod_used_good5 { + use std::any::Any; + + mod foo { + use std::any::Any; + + fn baz() { + println!("{:?}", "baz".type_id()); + } + + mod bar { + use crate::nested_mod_used_good5::foo::Any; + + fn foo() { + println!("{:?}", Any::type_id("foo")); + } + } + } +} + +mod simple_trait { + pub trait MyTrait { + fn do_things(&self); + } + + pub struct MyStruct; + + impl MyTrait for MyStruct { + fn do_things(&self) {} + } +} + +// Underscore imports were stabilized in 1.33 +#[clippy::msrv = "1.32"] +fn msrv_1_32() { + use simple_trait::{MyStruct, MyTrait}; + MyStruct.do_things(); +} + +#[clippy::msrv = "1.33"] +fn msrv_1_33() { + use simple_trait::{MyStruct, MyTrait as _}; + MyStruct.do_things(); +} + +mod lint_inside_macro_expansion_bad { + macro_rules! foo { + () => { + use std::any::Any as _; + fn bar() { + "bar".type_id(); + } + }; + } + + foo!(); +} + +mod macro_and_trait_same_name { + pub macro Foo() {} + pub trait Foo { + fn bar(&self); + } + impl Foo for () { + fn bar(&self) {} + } +} + +fn call_macro_and_trait_good() { + // importing trait and macro but only using macro by path won't allow us to change this to + // `use macro_and_trait_same_name::Foo as _;` + use macro_and_trait_same_name::Foo; + Foo!(); + ().bar(); +} + +proc_macros::external!( + fn ignore_inside_external_proc_macro() { + use std::any::Any; + "foo".type_id(); + } +); + +proc_macros::with_span!( + span + + fn ignore_inside_with_span_proc_macro() { + use std::any::Any; + "foo".type_id(); + } +); + +// This should warn the import is unused but should not trigger unused_trait_names +#[warn(unused)] +mod unused_import { + +} + +#[allow(clippy::unused_trait_names)] +fn allow_lint_fn() { + use std::any::Any; + + "foo".type_id(); +} + +#[allow(clippy::unused_trait_names)] +mod allow_lint_mod { + use std::any::Any; + + fn foo() { + "foo".type_id(); + } +} + +mod allow_lint_import { + #[allow(clippy::unused_trait_names)] + use std::any::Any; + + fn foo() { + "foo".type_id(); + } +} + +// Limitation: Suggests `use std::any::Any as _::{self};` which looks weird +// fn use_trait_self_good() { +// use std::any::Any::{self}; +// "foo".type_id(); +// } + +// Limitation: Suggests `use std::any::{Any as _, Any as _};` +// mod repeated_renamed { +// use std::any::{Any, Any as MyAny}; + +// fn foo() { +// "foo".type_id(); +// } +// } diff --git a/tests/ui/unused_trait_names.rs b/tests/ui/unused_trait_names.rs new file mode 100644 index 00000000000..ce44eedbc79 --- /dev/null +++ b/tests/ui/unused_trait_names.rs @@ -0,0 +1,286 @@ +//@aux-build:proc_macros.rs + +#![allow(unused)] +#![warn(clippy::unused_trait_names)] +#![feature(decl_macro)] + +extern crate proc_macros; + +fn main() {} + +fn bad() { + use std::any::Any; + + println!("{:?}", "foo".type_id()); +} + +fn good() { + use std::any::Any as _; + + println!("{:?}", "foo".type_id()); +} + +fn used_good() { + use std::any::Any; + + println!("{:?}", Any::type_id("foo")); + println!("{:?}", "foo".type_id()); +} + +fn multi_bad() { + use std::any::{self, Any, TypeId}; + + println!("{:?}", "foo".type_id()); +} + +fn multi_good() { + use std::any::{self, Any as _, TypeId}; + + println!("{:?}", "foo".type_id()); +} + +fn renamed_bad() { + use std::any::Any as MyAny; + + println!("{:?}", "foo".type_id()); +} + +fn multi_renamed_bad() { + use std::any::{Any as MyAny, TypeId as MyTypeId}; + + println!("{:?}", "foo".type_id()); +} + +mod pub_good { + pub use std::any::Any; + + fn foo() { + println!("{:?}", "foo".type_id()); + } +} + +mod used_mod_good { + use std::any::Any; + + fn foo() { + println!("{:?}", Any::type_id("foo")); + } +} + +mod mod_import_bad { + fn mod_import_bad() { + use std::any::Any; + + println!("{:?}", "foo".type_id()); + } +} + +mod nested_mod_used_good1 { + use std::any::Any; + + mod foo { + fn foo() { + super::Any::type_id("foo"); + } + } +} + +mod nested_mod_used_good2 { + use std::any::Any; + + mod foo { + use super::Any; + + fn foo() { + Any::type_id("foo"); + } + } +} + +mod nested_mod_used_good3 { + use std::any::Any; + + mod foo { + use crate::nested_mod_used_good3::Any; + + fn foo() { + println!("{:?}", Any::type_id("foo")); + } + } +} + +mod nested_mod_used_bad { + use std::any::Any; + + fn bar() { + println!("{:?}", "foo".type_id()); + } + + mod foo { + use std::any::Any; + + fn foo() { + println!("{:?}", Any::type_id("foo")); + } + } +} + +// More complex example where `use std::any::Any;` should be anonymised but `use std::any::Any as +// MyAny;` should not as it is used by a sub module. Even though if you removed `use std::any::Any;` +// the code would still compile. +mod nested_mod_used_bad1 { + use std::any::Any; + + use std::any::Any as MyAny; + + fn baz() { + println!("{:?}", "baz".type_id()); + } + + mod foo { + use crate::nested_mod_used_bad1::MyAny; + + fn foo() { + println!("{:?}", MyAny::type_id("foo")); + } + } +} + +// Example of nested import with an unused import to try and trick it +mod nested_mod_used_good5 { + use std::any::Any; + + mod foo { + use std::any::Any; + + fn baz() { + println!("{:?}", "baz".type_id()); + } + + mod bar { + use crate::nested_mod_used_good5::foo::Any; + + fn foo() { + println!("{:?}", Any::type_id("foo")); + } + } + } +} + +mod simple_trait { + pub trait MyTrait { + fn do_things(&self); + } + + pub struct MyStruct; + + impl MyTrait for MyStruct { + fn do_things(&self) {} + } +} + +// Underscore imports were stabilized in 1.33 +#[clippy::msrv = "1.32"] +fn msrv_1_32() { + use simple_trait::{MyStruct, MyTrait}; + MyStruct.do_things(); +} + +#[clippy::msrv = "1.33"] +fn msrv_1_33() { + use simple_trait::{MyStruct, MyTrait}; + MyStruct.do_things(); +} + +mod lint_inside_macro_expansion_bad { + macro_rules! foo { + () => { + use std::any::Any; + fn bar() { + "bar".type_id(); + } + }; + } + + foo!(); +} + +mod macro_and_trait_same_name { + pub macro Foo() {} + pub trait Foo { + fn bar(&self); + } + impl Foo for () { + fn bar(&self) {} + } +} + +fn call_macro_and_trait_good() { + // importing trait and macro but only using macro by path won't allow us to change this to + // `use macro_and_trait_same_name::Foo as _;` + use macro_and_trait_same_name::Foo; + Foo!(); + ().bar(); +} + +proc_macros::external!( + fn ignore_inside_external_proc_macro() { + use std::any::Any; + "foo".type_id(); + } +); + +proc_macros::with_span!( + span + + fn ignore_inside_with_span_proc_macro() { + use std::any::Any; + "foo".type_id(); + } +); + +// This should warn the import is unused but should not trigger unused_trait_names +#[warn(unused)] +mod unused_import { + use std::any::Any; +} + +#[allow(clippy::unused_trait_names)] +fn allow_lint_fn() { + use std::any::Any; + + "foo".type_id(); +} + +#[allow(clippy::unused_trait_names)] +mod allow_lint_mod { + use std::any::Any; + + fn foo() { + "foo".type_id(); + } +} + +mod allow_lint_import { + #[allow(clippy::unused_trait_names)] + use std::any::Any; + + fn foo() { + "foo".type_id(); + } +} + +// Limitation: Suggests `use std::any::Any as _::{self};` which looks weird +// fn use_trait_self_good() { +// use std::any::Any::{self}; +// "foo".type_id(); +// } + +// Limitation: Suggests `use std::any::{Any as _, Any as _};` +// mod repeated_renamed { +// use std::any::{Any, Any as MyAny}; + +// fn foo() { +// "foo".type_id(); +// } +// } diff --git a/tests/ui/unused_trait_names.stderr b/tests/ui/unused_trait_names.stderr new file mode 100644 index 00000000000..f59d8f58a17 --- /dev/null +++ b/tests/ui/unused_trait_names.stderr @@ -0,0 +1,73 @@ +error: unused import: `std::any::Any` + --> tests/ui/unused_trait_names.rs:245:9 + | +LL | use std::any::Any; + | ^^^^^^^^^^^^^ + | + = note: `-D unused-imports` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(unused_imports)]` + +error: importing trait that is only used anonymously + --> tests/ui/unused_trait_names.rs:12:19 + | +LL | use std::any::Any; + | ^^^ help: use: `Any as _` + | + = note: `-D clippy::unused-trait-names` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::unused_trait_names)]` + +error: importing trait that is only used anonymously + --> tests/ui/unused_trait_names.rs:31:26 + | +LL | use std::any::{self, Any, TypeId}; + | ^^^ help: use: `Any as _` + +error: importing trait that is only used anonymously + --> tests/ui/unused_trait_names.rs:43:19 + | +LL | use std::any::Any as MyAny; + | ^^^^^^^^^^^^ help: use: `Any as _` + +error: importing trait that is only used anonymously + --> tests/ui/unused_trait_names.rs:49:20 + | +LL | use std::any::{Any as MyAny, TypeId as MyTypeId}; + | ^^^^^^^^^^^^ help: use: `Any as _` + +error: importing trait that is only used anonymously + --> tests/ui/unused_trait_names.rs:72:23 + | +LL | use std::any::Any; + | ^^^ help: use: `Any as _` + +error: importing trait that is only used anonymously + --> tests/ui/unused_trait_names.rs:113:19 + | +LL | use std::any::Any; + | ^^^ help: use: `Any as _` + +error: importing trait that is only used anonymously + --> tests/ui/unused_trait_names.rs:132:19 + | +LL | use std::any::Any; + | ^^^ help: use: `Any as _` + +error: importing trait that is only used anonymously + --> tests/ui/unused_trait_names.rs:191:34 + | +LL | use simple_trait::{MyStruct, MyTrait}; + | ^^^^^^^ help: use: `MyTrait as _` + +error: importing trait that is only used anonymously + --> tests/ui/unused_trait_names.rs:198:27 + | +LL | use std::any::Any; + | ^^^ help: use: `Any as _` +... +LL | foo!(); + | ------ in this macro invocation + | + = note: this error originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 10 previous errors + diff --git a/tests/ui/used_underscore_binding.stderr b/tests/ui/used_underscore_binding.stderr index 556e1792b3e..f9e8013d3ad 100644 --- a/tests/ui/used_underscore_binding.stderr +++ b/tests/ui/used_underscore_binding.stderr @@ -1,10 +1,10 @@ -error: used binding `_foo` which is prefixed with an underscore. A leading underscore signals that a binding will not be used +error: used underscore-prefixed binding --> tests/ui/used_underscore_binding.rs:23:5 | LL | _foo + 1 | ^^^^ | -note: `_foo` is defined here +note: binding is defined here --> tests/ui/used_underscore_binding.rs:22:22 | LL | fn prefix_underscore(_foo: u32) -> u32 { @@ -12,61 +12,61 @@ LL | fn prefix_underscore(_foo: u32) -> u32 { = note: `-D clippy::used-underscore-binding` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::used_underscore_binding)]` -error: used binding `_foo` which is prefixed with an underscore. A leading underscore signals that a binding will not be used +error: used underscore-prefixed binding --> tests/ui/used_underscore_binding.rs:28:20 | LL | println!("{}", _foo); | ^^^^ | -note: `_foo` is defined here +note: binding is defined here --> tests/ui/used_underscore_binding.rs:27:24 | LL | fn in_macro_or_desugar(_foo: u32) { | ^^^^ -error: used binding `_foo` which is prefixed with an underscore. A leading underscore signals that a binding will not be used +error: used underscore-prefixed binding --> tests/ui/used_underscore_binding.rs:29:16 | LL | assert_eq!(_foo, _foo); | ^^^^ | -note: `_foo` is defined here +note: binding is defined here --> tests/ui/used_underscore_binding.rs:27:24 | LL | fn in_macro_or_desugar(_foo: u32) { | ^^^^ -error: used binding `_foo` which is prefixed with an underscore. A leading underscore signals that a binding will not be used +error: used underscore-prefixed binding --> tests/ui/used_underscore_binding.rs:29:22 | LL | assert_eq!(_foo, _foo); | ^^^^ | -note: `_foo` is defined here +note: binding is defined here --> tests/ui/used_underscore_binding.rs:27:24 | LL | fn in_macro_or_desugar(_foo: u32) { | ^^^^ -error: used binding `_underscore_field` which is prefixed with an underscore. A leading underscore signals that a binding will not be used +error: used underscore-prefixed binding --> tests/ui/used_underscore_binding.rs:42:5 | LL | s._underscore_field += 1; | ^^^^^^^^^^^^^^^^^^^ | -note: `_underscore_field` is defined here +note: binding is defined here --> tests/ui/used_underscore_binding.rs:36:5 | LL | _underscore_field: u32, | ^^^^^^^^^^^^^^^^^^^^^^ -error: used binding `_i` which is prefixed with an underscore. A leading underscore signals that a binding will not be used +error: used underscore-prefixed binding --> tests/ui/used_underscore_binding.rs:103:16 | LL | uses_i(_i); | ^^ | -note: `_i` is defined here +note: binding is defined here --> tests/ui/used_underscore_binding.rs:102:13 | LL | let _i = 5; diff --git a/tests/ui/used_underscore_items.rs b/tests/ui/used_underscore_items.rs new file mode 100644 index 00000000000..223016a5c96 --- /dev/null +++ b/tests/ui/used_underscore_items.rs @@ -0,0 +1,63 @@ +//@aux-build:external_item.rs +#![allow(unused)] +#![warn(clippy::used_underscore_items)] + +extern crate external_item; + +// should not lint macro +macro_rules! macro_wrap_func { + () => { + fn _marco_foo() {} + }; +} + +macro_wrap_func!(); + +struct _FooStruct {} + +impl _FooStruct { + fn _method_call(self) {} +} + +fn _foo1() {} + +fn _foo2() -> i32 { + 0 +} + +mod a { + pub mod b { + pub mod c { + pub fn _foo3() {} + + pub struct _FooStruct2 {} + + impl _FooStruct2 { + pub fn _method_call(self) {} + } + } + } +} + +fn main() { + _foo1(); + let _ = _foo2(); + a::b::c::_foo3(); + let _ = &_FooStruct {}; + let _ = _FooStruct {}; + + let foo_struct = _FooStruct {}; + foo_struct._method_call(); + + let foo_struct2 = a::b::c::_FooStruct2 {}; + foo_struct2._method_call(); +} + +// should not lint exteranl crate. +// user cannot control how others name their items +fn external_item_call() { + let foo_struct3 = external_item::_ExternalStruct {}; + foo_struct3._foo(); + + external_item::_exernal_foo(); +} diff --git a/tests/ui/used_underscore_items.stderr b/tests/ui/used_underscore_items.stderr new file mode 100644 index 00000000000..93ac3a6fec6 --- /dev/null +++ b/tests/ui/used_underscore_items.stderr @@ -0,0 +1,112 @@ +error: used underscore-prefixed item + --> tests/ui/used_underscore_items.rs:43:5 + | +LL | _foo1(); + | ^^^^^^^ + | +note: item is defined here + --> tests/ui/used_underscore_items.rs:22:1 + | +LL | fn _foo1() {} + | ^^^^^^^^^^ + = note: `-D clippy::used-underscore-items` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::used_underscore_items)]` + +error: used underscore-prefixed item + --> tests/ui/used_underscore_items.rs:44:13 + | +LL | let _ = _foo2(); + | ^^^^^^^ + | +note: item is defined here + --> tests/ui/used_underscore_items.rs:24:1 + | +LL | fn _foo2() -> i32 { + | ^^^^^^^^^^^^^^^^^ + +error: used underscore-prefixed item + --> tests/ui/used_underscore_items.rs:45:5 + | +LL | a::b::c::_foo3(); + | ^^^^^^^^^^^^^^^^ + | +note: item is defined here + --> tests/ui/used_underscore_items.rs:31:13 + | +LL | pub fn _foo3() {} + | ^^^^^^^^^^^^^^ + +error: used underscore-prefixed item + --> tests/ui/used_underscore_items.rs:46:14 + | +LL | let _ = &_FooStruct {}; + | ^^^^^^^^^^^^^ + | +note: item is defined here + --> tests/ui/used_underscore_items.rs:16:1 + | +LL | struct _FooStruct {} + | ^^^^^^^^^^^^^^^^^ + +error: used underscore-prefixed item + --> tests/ui/used_underscore_items.rs:47:13 + | +LL | let _ = _FooStruct {}; + | ^^^^^^^^^^^^^ + | +note: item is defined here + --> tests/ui/used_underscore_items.rs:16:1 + | +LL | struct _FooStruct {} + | ^^^^^^^^^^^^^^^^^ + +error: used underscore-prefixed item + --> tests/ui/used_underscore_items.rs:49:22 + | +LL | let foo_struct = _FooStruct {}; + | ^^^^^^^^^^^^^ + | +note: item is defined here + --> tests/ui/used_underscore_items.rs:16:1 + | +LL | struct _FooStruct {} + | ^^^^^^^^^^^^^^^^^ + +error: used underscore-prefixed item + --> tests/ui/used_underscore_items.rs:50:5 + | +LL | foo_struct._method_call(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: item is defined here + --> tests/ui/used_underscore_items.rs:19:5 + | +LL | fn _method_call(self) {} + | ^^^^^^^^^^^^^^^^^^^^^ + +error: used underscore-prefixed item + --> tests/ui/used_underscore_items.rs:52:23 + | +LL | let foo_struct2 = a::b::c::_FooStruct2 {}; + | ^^^^^^^^^^^^^^^^^^^^^^^ + | +note: item is defined here + --> tests/ui/used_underscore_items.rs:33:13 + | +LL | pub struct _FooStruct2 {} + | ^^^^^^^^^^^^^^^^^^^^^^ + +error: used underscore-prefixed item + --> tests/ui/used_underscore_items.rs:53:5 + | +LL | foo_struct2._method_call(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: item is defined here + --> tests/ui/used_underscore_items.rs:36:17 + | +LL | pub fn _method_call(self) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 9 previous errors + diff --git a/tests/ui/zombie_processes.rs b/tests/ui/zombie_processes.rs new file mode 100644 index 00000000000..a2abc7fc3a1 --- /dev/null +++ b/tests/ui/zombie_processes.rs @@ -0,0 +1,138 @@ +#![warn(clippy::zombie_processes)] +#![allow(clippy::if_same_then_else, clippy::ifs_same_cond)] + +use std::process::{Child, Command}; + +fn main() { + { + // Check that #[expect] works + #[expect(clippy::zombie_processes)] + let mut x = Command::new("").spawn().unwrap(); + } + + { + let mut x = Command::new("").spawn().unwrap(); + //~^ ERROR: spawned process is never `wait()`ed on + x.kill(); + x.id(); + } + { + let mut x = Command::new("").spawn().unwrap(); + x.wait().unwrap(); // OK + } + { + let x = Command::new("").spawn().unwrap(); + x.wait_with_output().unwrap(); // OK + } + { + let mut x = Command::new("").spawn().unwrap(); + x.try_wait().unwrap(); // OK + } + { + let mut x = Command::new("").spawn().unwrap(); + let mut r = &mut x; + r.wait().unwrap(); // OK, not calling `.wait()` directly on `x` but through `r` -> `x` + } + { + let mut x = Command::new("").spawn().unwrap(); + process_child(x); // OK, other function might call `.wait()` so assume it does + } + { + let mut x = Command::new("").spawn().unwrap(); + //~^ ERROR: spawned process is never `wait()`ed on + let v = &x; + // (allow shared refs is fine because one cannot call `.wait()` through that) + } + + // https://github.com/rust-lang/rust-clippy/pull/11476#issuecomment-1718456033 + // Unconditionally exiting the process in various ways (should not lint) + { + let mut x = Command::new("").spawn().unwrap(); + std::process::exit(0); + } + { + let mut x = Command::new("").spawn().unwrap(); + std::process::abort(); // same as above, but abort instead of exit + } + { + let mut x = Command::new("").spawn().unwrap(); + if true { /* nothing */ } + std::process::abort(); // still unconditionally exits + } + + // Conditionally exiting + // 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 + if true { + std::process::exit(0); + } + } + { + let mut x = Command::new("").spawn().unwrap(); + //~^ ERROR: spawned process is never `wait()`ed on + if true { + while false {} + // Calling `exit()` after leaving a while loop should still be linted. + std::process::exit(0); + } + } + + { + let mut x = { Command::new("").spawn().unwrap() }; + x.wait().unwrap(); + } + + { + struct S { + c: Child, + } + + let mut s = S { + c: Command::new("").spawn().unwrap(), + }; + s.c.wait().unwrap(); + } + + { + let mut x = Command::new("").spawn().unwrap(); + //~^ ERROR: spawned process is never `wait()`ed on + if true { + return; + } + x.wait().unwrap(); + } + + { + let mut x = Command::new("").spawn().unwrap(); + //~^ ERROR: spawned process is never `wait()`ed on + if true { + x.wait().unwrap(); + } + } + + { + let mut x = Command::new("").spawn().unwrap(); + if true { + x.wait().unwrap(); + } else if true { + x.wait().unwrap(); + } else { + x.wait().unwrap(); + } + } + + { + let mut x = Command::new("").spawn().unwrap(); + if true { + x.wait().unwrap(); + return; + } + x.wait().unwrap(); + } +} + +fn process_child(c: Child) { + todo!() +} diff --git a/tests/ui/zombie_processes.stderr b/tests/ui/zombie_processes.stderr new file mode 100644 index 00000000000..eec821a4c8f --- /dev/null +++ b/tests/ui/zombie_processes.stderr @@ -0,0 +1,64 @@ +error: spawned process is never `wait()`ed on + --> tests/ui/zombie_processes.rs:14:21 + | +LL | let mut x = Command::new("").spawn().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: 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` + = help: to override `-D warnings` add `#[allow(clippy::zombie_processes)]` + +error: spawned process is never `wait()`ed on + --> tests/ui/zombie_processes.rs:41:21 + | +LL | let mut x = Command::new("").spawn().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: 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 + --> tests/ui/zombie_processes.rs:66:21 + | +LL | let mut x = Command::new("").spawn().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: 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 + --> tests/ui/zombie_processes.rs:73:21 + | +LL | let mut x = Command::new("").spawn().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: 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 + --> tests/ui/zombie_processes.rs:99:21 + | +LL | let mut x = Command::new("").spawn().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: 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 + --> tests/ui/zombie_processes.rs:108:21 + | +LL | let mut x = Command::new("").spawn().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: 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: aborting due to 6 previous errors + diff --git a/tests/ui/zombie_processes_fixable.fixed b/tests/ui/zombie_processes_fixable.fixed new file mode 100644 index 00000000000..6045262f519 --- /dev/null +++ b/tests/ui/zombie_processes_fixable.fixed @@ -0,0 +1,26 @@ +#![warn(clippy::zombie_processes)] +#![allow(clippy::needless_return)] + +use std::process::{Child, Command}; + +fn main() { + let _ = Command::new("").spawn().unwrap().wait(); + //~^ ERROR: spawned process is never `wait()`ed on + Command::new("").spawn().unwrap().wait(); + //~^ ERROR: spawned process is never `wait()`ed on + spawn_proc().wait(); + //~^ ERROR: spawned process is never `wait()`ed on + spawn_proc().wait().unwrap(); // OK +} + +fn not_main() { + Command::new("").spawn().unwrap().wait(); +} + +fn spawn_proc() -> Child { + Command::new("").spawn().unwrap() +} + +fn spawn_proc_2() -> Child { + return Command::new("").spawn().unwrap(); +} diff --git a/tests/ui/zombie_processes_fixable.rs b/tests/ui/zombie_processes_fixable.rs new file mode 100644 index 00000000000..e1ecb771641 --- /dev/null +++ b/tests/ui/zombie_processes_fixable.rs @@ -0,0 +1,26 @@ +#![warn(clippy::zombie_processes)] +#![allow(clippy::needless_return)] + +use std::process::{Child, Command}; + +fn main() { + let _ = Command::new("").spawn().unwrap(); + //~^ ERROR: spawned process is never `wait()`ed on + Command::new("").spawn().unwrap(); + //~^ ERROR: spawned process is never `wait()`ed on + spawn_proc(); + //~^ ERROR: spawned process is never `wait()`ed on + spawn_proc().wait().unwrap(); // OK +} + +fn not_main() { + Command::new("").spawn().unwrap(); +} + +fn spawn_proc() -> Child { + Command::new("").spawn().unwrap() +} + +fn spawn_proc_2() -> Child { + return Command::new("").spawn().unwrap(); +} diff --git a/tests/ui/zombie_processes_fixable.stderr b/tests/ui/zombie_processes_fixable.stderr new file mode 100644 index 00000000000..e1c40472c32 --- /dev/null +++ b/tests/ui/zombie_processes_fixable.stderr @@ -0,0 +1,40 @@ +error: spawned process is never `wait()`ed on + --> tests/ui/zombie_processes_fixable.rs:7:13 + | +LL | let _ = Command::new("").spawn().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- help: try: `.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` + = help: to override `-D warnings` add `#[allow(clippy::zombie_processes)]` + +error: spawned process is never `wait()`ed on + --> tests/ui/zombie_processes_fixable.rs:9:5 + | +LL | Command::new("").spawn().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- help: try: `.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 + --> tests/ui/zombie_processes_fixable.rs:11:5 + | +LL | spawn_proc(); + | ^^^^^^^^^^^^- help: try: `.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 + --> tests/ui/zombie_processes_fixable.rs:17:5 + | +LL | Command::new("").spawn().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- help: try: `.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: aborting due to 4 previous errors + diff --git a/triagebot.toml b/triagebot.toml index 99b3560a064..dcf00e4e384 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -20,7 +20,6 @@ new_pr = true [assign] contributing_url = "https://github.com/rust-lang/rust-clippy/blob/master/CONTRIBUTING.md" users_on_vacation = [ - "flip1995", "matthiaskrgr", "giraffate", ] diff --git a/util/gh-pages/versions.html b/util/gh-pages/versions.html index 31ce8819329..d38fe39a464 100644 --- a/util/gh-pages/versions.html +++ b/util/gh-pages/versions.html @@ -1,4 +1,5 @@ + @@ -7,26 +8,15 @@ Clippy lints documentation - -
+
-
- - - -
- - - - - - - + .github-corner:hover .octo-arm { + animation: octocat-wave 560ms ease-in-out; + } + @keyframes octocat-wave { + 0%, + 100% { + transform: rotate(0); + } + 20%, + 60% { + transform: rotate(-25deg); + } + 40%, + 80% { + transform: rotate(10deg); + } + } + @media (max-width: 500px) { + .github-corner:hover .octo-arm { + animation: none; + } + .github-corner .octo-arm { + animation: octocat-wave 560ms ease-in-out; + } + } + + diff --git a/util/versions.py b/util/versions.py index c041fc606a8..7a21a840a6d 100755 --- a/util/versions.py +++ b/util/versions.py @@ -1,22 +1,22 @@ #!/usr/bin/env python +from string import Template +import argparse import json -import logging as log import os import sys -log.basicConfig(level=log.INFO, format="%(levelname)s: %(message)s") - - def key(v): if v == "master": - return float("inf") - if v == "stable": return sys.maxsize - if v == "beta": + if v == "stable": return sys.maxsize - 1 + if v == "beta": + return sys.maxsize - 2 if v == "pre-1.29.0": return -1 + if not v.startswith("rust-"): + return None v = v.replace("rust-", "") @@ -26,26 +26,27 @@ def key(v): return s - def main(): - if len(sys.argv) < 2: - log.error("specify output directory") - return + parser = argparse.ArgumentParser() + parser.add_argument("input", help="path to the versions.html template", type=argparse.FileType("r")) + parser.add_argument("outdir", help="path to write the output HTML") + args = parser.parse_args() - outdir = sys.argv[1] versions = [ dir - for dir in os.listdir(outdir) - if not dir.startswith(".") - and not dir.startswith("v") - and os.path.isdir(os.path.join(outdir, dir)) + for dir in os.listdir(args.outdir) + if key(dir) is not None ] - versions.sort(key=key) + versions.sort(key=key, reverse=True) + links = [f'{version}' for version in versions] - with open(os.path.join(outdir, "versions.json"), "w") as fp: - json.dump(versions, fp, indent=2) - log.info("wrote JSON for great justice") + template = Template(args.input.read()) + html = template.substitute(list="\n".join(links)) + path = os.path.join(args.outdir, "index.html") + with open(path, "w") as out: + out.write(html) + print(f"wrote HTML to {path}") if __name__ == "__main__": main() From 907b6a1bc30f420c917e331ce006037b89d0e86e Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Tue, 24 Sep 2024 11:58:12 +0200 Subject: [PATCH 209/683] Update Cargo.lock --- Cargo.lock | 41 +++++++---------------------------------- 1 file changed, 7 insertions(+), 34 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e973d7f9a2a..7555fb415fd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -524,7 +524,7 @@ checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" [[package]] name = "clippy" -version = "0.1.82" +version = "0.1.83" dependencies = [ "anstream", "cargo_metadata 0.18.1", @@ -547,13 +547,13 @@ dependencies = [ "termize", "tokio", "toml 0.7.8", - "ui_test 0.25.0", + "ui_test", "walkdir", ] [[package]] name = "clippy_config" -version = "0.1.82" +version = "0.1.83" dependencies = [ "itertools", "serde", @@ -576,7 +576,7 @@ dependencies = [ [[package]] name = "clippy_lints" -version = "0.1.82" +version = "0.1.83" dependencies = [ "arrayvec", "cargo_metadata 0.18.1", @@ -600,7 +600,7 @@ dependencies = [ [[package]] name = "clippy_utils" -version = "0.1.82" +version = "0.1.83" dependencies = [ "arrayvec", "clippy_config", @@ -902,7 +902,7 @@ dependencies = [ [[package]] name = "declare_clippy_lint" -version = "0.1.82" +version = "0.1.83" dependencies = [ "itertools", "quote", @@ -2269,7 +2269,7 @@ dependencies = [ "rustc_version", "smallvec", "tempfile", - "ui_test 0.26.5", + "ui_test", "windows-sys 0.52.0", ] @@ -5485,33 +5485,6 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9" -[[package]] -name = "ui_test" -version = "0.25.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7e4f339f62edc873975c47115f9e71c5454ddaa37c1142b42fc0b2672c8dacb" -dependencies = [ - "annotate-snippets 0.11.4", - "anyhow", - "bstr", - "cargo-platform", - "cargo_metadata 0.18.1", - "color-eyre", - "colored", - "comma", - "crossbeam-channel", - "indicatif", - "lazy_static", - "levenshtein", - "prettydiff", - "regex", - "rustc_version", - "rustfix", - "serde", - "serde_json", - "spanned", -] - [[package]] name = "ui_test" version = "0.26.5" From f38b569ab64ae85308d7750af43863d11a74973c Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Tue, 24 Sep 2024 11:58:48 +0200 Subject: [PATCH 210/683] Hotfix: remove profile from clippy Cargo.toml --- src/tools/clippy/Cargo.toml | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/tools/clippy/Cargo.toml b/src/tools/clippy/Cargo.toml index ddc27179ef2..cf810798d8c 100644 --- a/src/tools/clippy/Cargo.toml +++ b/src/tools/clippy/Cargo.toml @@ -67,10 +67,3 @@ harness = false [[test]] name = "dogfood" harness = false - -# quine-mc_cluskey makes up a significant part of the runtime in dogfood -# due to the number of conditions in the clippy_lints crate -# and enabling optimizations for that specific dependency helps a bit -# without increasing total build times. -[profile.dev.package.quine-mc_cluskey] -opt-level = 3 From 4108c6e5a0d0f6839f7586ae9681fb7ca4fc2f49 Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Tue, 24 Sep 2024 11:58:48 +0200 Subject: [PATCH 211/683] Hotfix: remove profile from clippy Cargo.toml --- Cargo.toml | 7 ------- 1 file changed, 7 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index ddc27179ef2..cf810798d8c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -67,10 +67,3 @@ harness = false [[test]] name = "dogfood" harness = false - -# quine-mc_cluskey makes up a significant part of the runtime in dogfood -# due to the number of conditions in the clippy_lints crate -# and enabling optimizations for that specific dependency helps a bit -# without increasing total build times. -[profile.dev.package.quine-mc_cluskey] -opt-level = 3 From 802bf71ece2b2ae41ba39068a8a7533544fc1106 Mon Sep 17 00:00:00 2001 From: monkeydbobo Date: Tue, 24 Sep 2024 19:51:11 +0800 Subject: [PATCH 212/683] Fix up setting strip = true in Cargo.toml makes build scripts fail in release mode on MacOS --- compiler/rustc_codegen_ssa/src/back/link.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 892dfb91201..69693230ce0 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -1087,16 +1087,17 @@ fn link_natively( let strip = sess.opts.cg.strip; if sess.target.is_like_osx { + let stripcmd = "/usr/bin/strip"; match (strip, crate_type) { (Strip::Debuginfo, _) => { - strip_symbols_with_external_utility(sess, "strip", out_filename, Some("-S")) + strip_symbols_with_external_utility(sess, stripcmd, out_filename, Some("-S")) } // Per the manpage, `-x` is the maximum safe strip level for dynamic libraries. (#93988) (Strip::Symbols, CrateType::Dylib | CrateType::Cdylib | CrateType::ProcMacro) => { - strip_symbols_with_external_utility(sess, "strip", out_filename, Some("-x")) + strip_symbols_with_external_utility(sess, stripcmd, out_filename, Some("-x")) } (Strip::Symbols, _) => { - strip_symbols_with_external_utility(sess, "strip", out_filename, None) + strip_symbols_with_external_utility(sess, stripcmd, out_filename, None) } (Strip::None, _) => {} } From f203e1ede5d46b0281b2b83250d761350e85deda Mon Sep 17 00:00:00 2001 From: Liam Germain Date: Tue, 24 Sep 2024 09:52:11 -0400 Subject: [PATCH 213/683] Fix false positive invalid null usage warning for `ptr::slice_from_raw_parts_*` functions --- clippy_lints/src/ptr.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/clippy_lints/src/ptr.rs b/clippy_lints/src/ptr.rs index 807636bb642..d523ec2edff 100644 --- a/clippy_lints/src/ptr.rs +++ b/clippy_lints/src/ptr.rs @@ -277,8 +277,6 @@ fn check_invalid_ptr_usage<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { | sym::ptr_read_unaligned | sym::ptr_read_volatile | sym::ptr_replace - | sym::ptr_slice_from_raw_parts - | sym::ptr_slice_from_raw_parts_mut | sym::ptr_write | sym::ptr_write_bytes | sym::ptr_write_unaligned From f8969853ebcf591b20d38ca3ff3b72537be8f581 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 24 Sep 2024 10:11:23 -0400 Subject: [PATCH 214/683] Fix tools --- clippy_lints/src/derive.rs | 1 - clippy_lints/src/inherent_impl.rs | 4 +--- clippy_lints/src/len_zero.rs | 3 +-- clippy_lints/src/methods/or_fun_call.rs | 1 - clippy_utils/src/lib.rs | 8 ++------ clippy_utils/src/ty.rs | 2 +- 6 files changed, 5 insertions(+), 14 deletions(-) diff --git a/clippy_lints/src/derive.rs b/clippy_lints/src/derive.rs index 636698e96f6..649c480fb92 100644 --- a/clippy_lints/src/derive.rs +++ b/clippy_lints/src/derive.rs @@ -386,7 +386,6 @@ fn check_unsafe_derive_deserialize<'tcx>( .tcx .inherent_impls(def.did()) .into_iter() - .flatten() .map(|imp_did| cx.tcx.hir().expect_item(imp_did.expect_local())) .any(|imp| has_unsafe(cx, imp)) { diff --git a/clippy_lints/src/inherent_impl.rs b/clippy_lints/src/inherent_impl.rs index d39f910f993..309d2dfb28b 100644 --- a/clippy_lints/src/inherent_impl.rs +++ b/clippy_lints/src/inherent_impl.rs @@ -51,9 +51,7 @@ impl<'tcx> LateLintPass<'tcx> for MultipleInherentImpl { // List of spans to lint. (lint_span, first_span) let mut lint_spans = Vec::new(); - let Ok(impls) = cx.tcx.crate_inherent_impls(()) else { - return; - }; + let (impls, _) = cx.tcx.crate_inherent_impls(()); for (&id, impl_ids) in &impls.inherent_impls { if impl_ids.len() < 2 diff --git a/clippy_lints/src/len_zero.rs b/clippy_lints/src/len_zero.rs index 0bc7fc2dd9d..16f86b18e2e 100644 --- a/clippy_lints/src/len_zero.rs +++ b/clippy_lints/src/len_zero.rs @@ -448,7 +448,6 @@ fn check_for_is_empty( .tcx .inherent_impls(impl_ty) .into_iter() - .flatten() .flat_map(|&id| cx.tcx.associated_items(id).filter_by_name_unhygienic(is_empty)) .find(|item| item.kind == AssocKind::Fn); @@ -616,7 +615,7 @@ fn has_is_empty(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { /// Checks the inherent impl's items for an `is_empty(self)` method. fn has_is_empty_impl(cx: &LateContext<'_>, id: DefId) -> bool { let is_empty = sym!(is_empty); - cx.tcx.inherent_impls(id).into_iter().flatten().any(|imp| { + cx.tcx.inherent_impls(id).into_iter().any(|imp| { cx.tcx .associated_items(*imp) .filter_by_name_unhygienic(is_empty) diff --git a/clippy_lints/src/methods/or_fun_call.rs b/clippy_lints/src/methods/or_fun_call.rs index e4326cb958e..af71799f0a7 100644 --- a/clippy_lints/src/methods/or_fun_call.rs +++ b/clippy_lints/src/methods/or_fun_call.rs @@ -78,7 +78,6 @@ pub(super) fn check<'tcx>( cx.tcx .inherent_impls(adt_def.did()) .into_iter() - .flatten() .flat_map(|impl_id| cx.tcx.associated_items(impl_id).filter_by_name_unhygienic(sugg)) .find_map(|assoc| { if assoc.fn_has_self_parameter diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 0d0d6219c5e..aed0bc565d8 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -589,14 +589,11 @@ fn find_primitive_impls<'tcx>(tcx: TyCtxt<'tcx>, name: &str) -> impl Iterator SimplifiedType::Float(FloatTy::F32), "f64" => SimplifiedType::Float(FloatTy::F64), _ => { - return Result::<&[_], rustc_errors::ErrorGuaranteed>::Ok(&[]) - .into_iter() - .flatten() - .copied(); + return [].iter().copied(); }, }; - tcx.incoherent_impls(ty).into_iter().flatten().copied() + tcx.incoherent_impls(ty).into_iter().copied() } fn non_local_item_children_by_name(tcx: TyCtxt<'_>, def_id: DefId, name: Symbol) -> Vec { @@ -721,7 +718,6 @@ pub fn def_path_res(tcx: TyCtxt<'_>, path: &[&str]) -> Vec { let inherent_impl_children = tcx .inherent_impls(def_id) .into_iter() - .flatten() .flat_map(|&impl_def_id| item_children_by_name(tcx, impl_def_id, segment)); let direct_children = item_children_by_name(tcx, def_id, segment); diff --git a/clippy_utils/src/ty.rs b/clippy_utils/src/ty.rs index 585134209ca..22aaaa1b734 100644 --- a/clippy_utils/src/ty.rs +++ b/clippy_utils/src/ty.rs @@ -1316,7 +1316,7 @@ pub fn deref_chain<'cx, 'tcx>(cx: &'cx LateContext<'tcx>, ty: Ty<'tcx>) -> impl /// If you need this, you should wrap this call in `clippy_utils::ty::deref_chain().any(...)`. pub fn get_adt_inherent_method<'a>(cx: &'a LateContext<'_>, ty: Ty<'_>, method_name: Symbol) -> Option<&'a AssocItem> { if let Some(ty_did) = ty.ty_adt_def().map(AdtDef::did) { - cx.tcx.inherent_impls(ty_did).into_iter().flatten().find_map(|&did| { + cx.tcx.inherent_impls(ty_did).into_iter().find_map(|&did| { cx.tcx .associated_items(did) .filter_by_name_unhygienic(method_name) From ead569a06de7d1cc6758b88b4f3faa00d1196c6d Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 24 Sep 2024 10:53:19 -0400 Subject: [PATCH 215/683] Ban combination of GCE and new solver --- compiler/rustc_ast_passes/src/feature_gate.rs | 23 ++++++++++++++++++- .../unify-op-with-fn-call.stderr | 10 +++++++- .../const-generics/issues/issue-88119.stderr | 10 +++++++- .../const-trait-bounds.stderr | 10 +++++++- .../unsatisfied-const-trait-bound.rs | 5 ++-- .../unsatisfied-const-trait-bound.stderr | 16 +++++++++---- 6 files changed, 63 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 614a99a6e19..83931a8c1a9 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -4,9 +4,9 @@ use rustc_ast::{NodeId, PatKind, attr, token}; use rustc_feature::{AttributeGate, BUILTIN_ATTRIBUTE_MAP, BuiltinAttribute, Features, GateIssue}; use rustc_session::Session; use rustc_session::parse::{feature_err, feature_err_issue, feature_warn}; -use rustc_span::Span; use rustc_span::source_map::Spanned; use rustc_span::symbol::sym; +use rustc_span::{Span, Symbol}; use rustc_target::spec::abi; use thin_vec::ThinVec; @@ -483,6 +483,8 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) { maybe_stage_features(sess, features, krate); check_incompatible_features(sess, features); + check_new_solver_banned_features(sess, features); + let mut visitor = PostExpansionVisitor { sess, features }; let spans = sess.psess.gated_spans.spans.borrow(); @@ -662,3 +664,22 @@ fn check_incompatible_features(sess: &Session, features: &Features) { } } } + +fn check_new_solver_banned_features(sess: &Session, features: &Features) { + if !sess.opts.unstable_opts.next_solver.is_some_and(|n| n.globally) { + return; + } + + // Ban GCE with the new solver, because it does not implement GCE correctly. + if let Some(&(_, gce_span, _)) = features + .declared_lang_features + .iter() + .find(|&&(feat, _, _)| feat == sym::generic_const_exprs) + { + sess.dcx().emit_err(errors::IncompatibleFeatures { + spans: vec![gce_span], + f1: Symbol::intern("-Znext-solver=globally"), + f2: sym::generic_const_exprs, + }); + } +} diff --git a/tests/ui/const-generics/generic_const_exprs/unify-op-with-fn-call.stderr b/tests/ui/const-generics/generic_const_exprs/unify-op-with-fn-call.stderr index db93bcca60f..bae8249845c 100644 --- a/tests/ui/const-generics/generic_const_exprs/unify-op-with-fn-call.stderr +++ b/tests/ui/const-generics/generic_const_exprs/unify-op-with-fn-call.stderr @@ -1,3 +1,11 @@ +error: `-Znext-solver=globally` and `generic_const_exprs` are incompatible, using them at the same time is not allowed + --> $DIR/unify-op-with-fn-call.rs:3:12 + | +LL | #![feature(generic_const_exprs, adt_const_params, const_trait_impl, effects)] + | ^^^^^^^^^^^^^^^^^^^ + | + = help: remove one of these features + error: const `impl` for trait `Add` which is not marked with `#[const_trait]` --> $DIR/unify-op-with-fn-call.rs:10:12 | @@ -67,7 +75,7 @@ error[E0284]: type annotations needed: cannot normalize `foo2::{constant#0}` LL | bar2::<{ std::ops::Add::add(N, N) }>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot normalize `foo2::{constant#0}` -error: aborting due to 8 previous errors +error: aborting due to 9 previous errors Some errors have detailed explanations: E0284, E0741. For more information about an error, try `rustc --explain E0284`. diff --git a/tests/ui/const-generics/issues/issue-88119.stderr b/tests/ui/const-generics/issues/issue-88119.stderr index b5eec3046fd..98bb8196810 100644 --- a/tests/ui/const-generics/issues/issue-88119.stderr +++ b/tests/ui/const-generics/issues/issue-88119.stderr @@ -1,3 +1,11 @@ +error: `-Znext-solver=globally` and `generic_const_exprs` are incompatible, using them at the same time is not allowed + --> $DIR/issue-88119.rs:4:39 + | +LL | #![feature(const_trait_impl, effects, generic_const_exprs)] + | ^^^^^^^^^^^^^^^^^^^ + | + = help: remove one of these features + error[E0284]: type annotations needed: cannot normalize `<&T as ConstName>::{constant#0}` --> $DIR/issue-88119.rs:19:49 | @@ -28,6 +36,6 @@ LL | where LL | [(); name_len::()]:, | --------------------- unsatisfied trait bound introduced here -error: aborting due to 2 previous errors +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0284`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-trait-bounds.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-trait-bounds.stderr index 7db6a77c77b..698b1b5b578 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-trait-bounds.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-trait-bounds.stderr @@ -1,3 +1,11 @@ +error: `-Znext-solver=globally` and `generic_const_exprs` are incompatible, using them at the same time is not allowed + --> $DIR/const-trait-bounds.rs:4:39 + | +LL | #![feature(const_trait_impl, effects, generic_const_exprs)] + | ^^^^^^^^^^^^^^^^^^^ + | + = help: remove one of these features + error[E0284]: type annotations needed: cannot normalize `process::{constant#0}` --> $DIR/const-trait-bounds.rs:12:35 | @@ -16,6 +24,6 @@ error[E0284]: type annotations needed: cannot normalize `process::{constant#1 LL | input | ^^^^^ cannot normalize `process::{constant#1}` -error: aborting due to 3 previous errors +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0284`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/unsatisfied-const-trait-bound.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/unsatisfied-const-trait-bound.rs index c50c755f667..5fffe54fc1a 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/unsatisfied-const-trait-bound.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/unsatisfied-const-trait-bound.rs @@ -1,3 +1,4 @@ +//@ known-bug: unknown // Ensure that we print unsatisfied always-const trait bounds as `const Trait` in diagnostics. //@ compile-flags: -Znext-solver @@ -19,7 +20,7 @@ impl Trait for Ty { fn main() { // FIXME(effects): improve diagnostics on this - require::(); //~ ERROR the trait bound `Trait::{synthetic#0}: const Compat` is not satisfied + require::(); } struct Container; @@ -27,9 +28,7 @@ struct Container; // FIXME(effects): Somehow emit `the trait bound `T: const Trait` is not satisfied` here instead // and suggest changing `Trait` to `const Trait`. fn accept0(_: Container<{ T::make() }>) {} -//~^ ERROR mismatched types // FIXME(effects): Instead of suggesting `+ const Trait`, suggest // changing `~const Trait` to `const Trait`. const fn accept1(_: Container<{ T::make() }>) {} -//~^ ERROR mismatched types diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/unsatisfied-const-trait-bound.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/unsatisfied-const-trait-bound.stderr index b9f6c9e8835..0806ffa4b5d 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/unsatisfied-const-trait-bound.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/unsatisfied-const-trait-bound.stderr @@ -1,5 +1,13 @@ +error: `-Znext-solver=globally` and `generic_const_exprs` are incompatible, using them at the same time is not allowed + --> $DIR/unsatisfied-const-trait-bound.rs:5:39 + | +LL | #![feature(const_trait_impl, effects, generic_const_exprs)] + | ^^^^^^^^^^^^^^^^^^^ + | + = help: remove one of these features + error[E0308]: mismatched types - --> $DIR/unsatisfied-const-trait-bound.rs:29:37 + --> $DIR/unsatisfied-const-trait-bound.rs:30:37 | LL | fn accept0(_: Container<{ T::make() }>) {} | ^^^^^^^^^ expected `false`, found `true` @@ -17,18 +25,18 @@ LL | const fn accept1(_: Container<{ T::make() }>) {} found constant `host` error[E0277]: the trait bound `Trait::{synthetic#0}: const Compat` is not satisfied - --> $DIR/unsatisfied-const-trait-bound.rs:22:15 + --> $DIR/unsatisfied-const-trait-bound.rs:23:15 | LL | require::(); | ^^ the trait `const Compat` is not implemented for `Trait::{synthetic#0}` | note: required by a bound in `require` - --> $DIR/unsatisfied-const-trait-bound.rs:7:15 + --> $DIR/unsatisfied-const-trait-bound.rs:8:15 | LL | fn require() {} | ^^^^^^^^^^^ required by this bound in `require` -error: aborting due to 3 previous errors +error: aborting due to 4 previous errors Some errors have detailed explanations: E0277, E0308. For more information about an error, try `rustc --explain E0277`. From 11363c7bf275a98d87cfa3ec3b0501deb6804147 Mon Sep 17 00:00:00 2001 From: ljgermain Date: Tue, 24 Sep 2024 11:22:26 -0400 Subject: [PATCH 216/683] Fix failing UI test --- tests/ui/invalid_null_ptr_usage.fixed | 5 ---- tests/ui/invalid_null_ptr_usage.rs | 5 ---- tests/ui/invalid_null_ptr_usage.stderr | 36 +++++++------------------- 3 files changed, 9 insertions(+), 37 deletions(-) diff --git a/tests/ui/invalid_null_ptr_usage.fixed b/tests/ui/invalid_null_ptr_usage.fixed index eeddc2349a1..c8f1858b4f8 100644 --- a/tests/ui/invalid_null_ptr_usage.fixed +++ b/tests/ui/invalid_null_ptr_usage.fixed @@ -25,11 +25,6 @@ fn main() { let _a: A = std::ptr::replace(core::ptr::NonNull::dangling().as_ptr(), A); - let _slice: *const [usize] = std::ptr::slice_from_raw_parts(core::ptr::NonNull::dangling().as_ptr(), 0); - let _slice: *const [usize] = std::ptr::slice_from_raw_parts(core::ptr::NonNull::dangling().as_ptr(), 0); - - let _slice: *const [usize] = std::ptr::slice_from_raw_parts_mut(core::ptr::NonNull::dangling().as_ptr(), 0); - std::ptr::swap::(core::ptr::NonNull::dangling().as_ptr(), &mut A); std::ptr::swap::(&mut A, core::ptr::NonNull::dangling().as_ptr()); diff --git a/tests/ui/invalid_null_ptr_usage.rs b/tests/ui/invalid_null_ptr_usage.rs index 8569b774084..5f3fff8e90d 100644 --- a/tests/ui/invalid_null_ptr_usage.rs +++ b/tests/ui/invalid_null_ptr_usage.rs @@ -25,11 +25,6 @@ fn main() { let _a: A = std::ptr::replace(std::ptr::null_mut(), A); - let _slice: *const [usize] = std::ptr::slice_from_raw_parts(std::ptr::null(), 0); - let _slice: *const [usize] = std::ptr::slice_from_raw_parts(std::ptr::null_mut(), 0); - - let _slice: *const [usize] = std::ptr::slice_from_raw_parts_mut(std::ptr::null_mut(), 0); - std::ptr::swap::(std::ptr::null_mut(), &mut A); std::ptr::swap::(&mut A, std::ptr::null_mut()); diff --git a/tests/ui/invalid_null_ptr_usage.stderr b/tests/ui/invalid_null_ptr_usage.stderr index 54d79ba1aeb..ca7b8c133a5 100644 --- a/tests/ui/invalid_null_ptr_usage.stderr +++ b/tests/ui/invalid_null_ptr_usage.stderr @@ -85,70 +85,52 @@ LL | let _a: A = std::ptr::replace(std::ptr::null_mut(), A); | ^^^^^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()` error: pointer must be non-null - --> tests/ui/invalid_null_ptr_usage.rs:28:69 - | -LL | let _slice: *const [usize] = std::ptr::slice_from_raw_parts(std::ptr::null(), 0); - | ^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()` - -error: pointer must be non-null - --> tests/ui/invalid_null_ptr_usage.rs:29:69 - | -LL | let _slice: *const [usize] = std::ptr::slice_from_raw_parts(std::ptr::null_mut(), 0); - | ^^^^^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()` - -error: pointer must be non-null - --> tests/ui/invalid_null_ptr_usage.rs:31:73 - | -LL | let _slice: *const [usize] = std::ptr::slice_from_raw_parts_mut(std::ptr::null_mut(), 0); - | ^^^^^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()` - -error: pointer must be non-null - --> tests/ui/invalid_null_ptr_usage.rs:33:29 + --> tests/ui/invalid_null_ptr_usage.rs:28:29 | LL | std::ptr::swap::(std::ptr::null_mut(), &mut A); | ^^^^^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()` error: pointer must be non-null - --> tests/ui/invalid_null_ptr_usage.rs:34:37 + --> tests/ui/invalid_null_ptr_usage.rs:29:37 | LL | std::ptr::swap::(&mut A, std::ptr::null_mut()); | ^^^^^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()` error: pointer must be non-null - --> tests/ui/invalid_null_ptr_usage.rs:36:44 + --> tests/ui/invalid_null_ptr_usage.rs:31:44 | LL | std::ptr::swap_nonoverlapping::(std::ptr::null_mut(), &mut A, 0); | ^^^^^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()` error: pointer must be non-null - --> tests/ui/invalid_null_ptr_usage.rs:37:52 + --> tests/ui/invalid_null_ptr_usage.rs:32:52 | LL | std::ptr::swap_nonoverlapping::(&mut A, std::ptr::null_mut(), 0); | ^^^^^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()` error: pointer must be non-null - --> tests/ui/invalid_null_ptr_usage.rs:39:25 + --> tests/ui/invalid_null_ptr_usage.rs:34:25 | LL | std::ptr::write(std::ptr::null_mut(), A); | ^^^^^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()` error: pointer must be non-null - --> tests/ui/invalid_null_ptr_usage.rs:41:35 + --> tests/ui/invalid_null_ptr_usage.rs:36:35 | LL | std::ptr::write_unaligned(std::ptr::null_mut(), A); | ^^^^^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()` error: pointer must be non-null - --> tests/ui/invalid_null_ptr_usage.rs:43:34 + --> tests/ui/invalid_null_ptr_usage.rs:38:34 | LL | std::ptr::write_volatile(std::ptr::null_mut(), A); | ^^^^^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()` error: pointer must be non-null - --> tests/ui/invalid_null_ptr_usage.rs:45:40 + --> tests/ui/invalid_null_ptr_usage.rs:40:40 | LL | std::ptr::write_bytes::(std::ptr::null_mut(), 42, 0); | ^^^^^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()` -error: aborting due to 25 previous errors +error: aborting due to 22 previous errors From e60098bf8c09732eef92e9d2f2876508d9f39913 Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Tue, 24 Sep 2024 18:13:17 +0200 Subject: [PATCH 217/683] Remove unused import from Clippy versions.py file --- src/tools/clippy/util/versions.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/tools/clippy/util/versions.py b/src/tools/clippy/util/versions.py index 7a21a840a6d..fee0d292df1 100755 --- a/src/tools/clippy/util/versions.py +++ b/src/tools/clippy/util/versions.py @@ -2,7 +2,6 @@ from string import Template import argparse -import json import os import sys From 6c2e82496f523372e18f311eb61b6e53bafc0da8 Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Tue, 24 Sep 2024 18:13:17 +0200 Subject: [PATCH 218/683] Remove unused import from Clippy versions.py file --- util/versions.py | 1 - 1 file changed, 1 deletion(-) diff --git a/util/versions.py b/util/versions.py index 7a21a840a6d..fee0d292df1 100755 --- a/util/versions.py +++ b/util/versions.py @@ -2,7 +2,6 @@ from string import Template import argparse -import json import os import sys From 88445ee1c2ee96f97d72a102b60142943a817623 Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Tue, 24 Sep 2024 12:38:01 -0400 Subject: [PATCH 219/683] Add missing SIMD intrinsics --- libgccjit.version | 2 +- src/base.rs | 1 - src/builder.rs | 3 +- src/intrinsic/llvm.rs | 98 +++++++++++++++++++++++++++++++++++++------ 4 files changed, 88 insertions(+), 16 deletions(-) diff --git a/libgccjit.version b/libgccjit.version index e5f51a197a4..b9bbbd324c3 100644 --- a/libgccjit.version +++ b/libgccjit.version @@ -1 +1 @@ -a0cb76246d8d00ed9847d9874e5d5658049c332d +e744a9459d33864067214741daf5c5bc2a7b88c6 diff --git a/src/base.rs b/src/base.rs index d76011da980..b8f511b73a0 100644 --- a/src/base.rs +++ b/src/base.rs @@ -222,7 +222,6 @@ pub fn compile_codegen_unit( // ... and now that we have everything pre-defined, fill out those definitions. for &(mono_item, _) in &mono_items { - //println!("{:?}", mono_item); mono_item.define::>(&cx); } diff --git a/src/builder.rs b/src/builder.rs index f07c5a53f68..408b7bc3caa 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -275,7 +275,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { assert!( (!expected_ty.is_vector() || actual_ty.is_vector()) && (expected_ty.is_vector() || !actual_ty.is_vector()), - "{:?} ({}) -> {:?} ({}), index: {:?}[{}]", + "{:?} (is vector: {}) -> {:?} (is vector: {}), Function: {:?}[{}]", actual_ty, actual_ty.is_vector(), expected_ty, @@ -285,7 +285,6 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { ); // TODO(antoyo): perhaps use __builtin_convertvector for vector casting. // TODO: remove bitcast now that vector types can be compared? - println!("Name: {}", func_name); self.bitcast(actual_val, expected_ty) } } else { diff --git a/src/intrinsic/llvm.rs b/src/intrinsic/llvm.rs index 098c7fbb485..cc6bed1fc9a 100644 --- a/src/intrinsic/llvm.rs +++ b/src/intrinsic/llvm.rs @@ -153,7 +153,11 @@ pub fn adjust_intrinsic_arguments<'a, 'b, 'gcc, 'tcx>( | "__builtin_ia32_psrav16hi_mask" | "__builtin_ia32_psrav8hi_mask" | "__builtin_ia32_permvarhi256_mask" - | "__builtin_ia32_permvarhi128_mask" => { + | "__builtin_ia32_permvarhi128_mask" + | "__builtin_ia32_maxph128_mask" + | "__builtin_ia32_maxph256_mask" + | "__builtin_ia32_minph128_mask" + | "__builtin_ia32_minph256_mask" => { let mut new_args = args.to_vec(); let arg3_type = gcc_func.get_param_type(2); let vector_type = arg3_type.dyncast_vector().expect("vector type"); @@ -194,7 +198,13 @@ pub fn adjust_intrinsic_arguments<'a, 'b, 'gcc, 'tcx>( | "__builtin_ia32_cvtqq2ps256_mask" | "__builtin_ia32_cvtuqq2pd128_mask" | "__builtin_ia32_cvtuqq2pd256_mask" - | "__builtin_ia32_cvtuqq2ps256_mask" => { + | "__builtin_ia32_cvtuqq2ps256_mask" + | "__builtin_ia32_vcvtw2ph128_mask" + | "__builtin_ia32_vcvtw2ph256_mask" + | "__builtin_ia32_vcvtuw2ph128_mask" + | "__builtin_ia32_vcvtuw2ph256_mask" + | "__builtin_ia32_vcvtdq2ph256_mask" + | "__builtin_ia32_vcvtudq2ph256_mask" => { let mut new_args = args.to_vec(); // Remove last arg as it doesn't seem to be used in GCC and is always false. new_args.pop(); @@ -296,7 +306,8 @@ pub fn adjust_intrinsic_arguments<'a, 'b, 'gcc, 'tcx>( "__builtin_ia32_vfmaddsubps512_mask" | "__builtin_ia32_vfmaddsubpd512_mask" | "__builtin_ia32_cmpsh_mask_round" - | "__builtin_ia32_vfmaddph512_mask" => { + | "__builtin_ia32_vfmaddph512_mask" + | "__builtin_ia32_vfmaddsubph512_mask" => { let mut new_args = args.to_vec(); let last_arg = new_args.pop().expect("last arg"); let arg4_type = gcc_func.get_param_type(3); @@ -319,9 +330,6 @@ pub fn adjust_intrinsic_arguments<'a, 'b, 'gcc, 'tcx>( | "__builtin_ia32_vpermi2varpd128_mask" | "__builtin_ia32_vpmadd52huq512_mask" | "__builtin_ia32_vpmadd52luq512_mask" - | "__builtin_ia32_vpmadd52huq256_mask" - | "__builtin_ia32_vpmadd52luq256_mask" - | "__builtin_ia32_vpmadd52huq128_mask" | "__builtin_ia32_vfmaddsubph128_mask" | "__builtin_ia32_vfmaddsubph256_mask" => { let mut new_args = args.to_vec(); @@ -405,7 +413,14 @@ pub fn adjust_intrinsic_arguments<'a, 'b, 'gcc, 'tcx>( "__builtin_ia32_cvtqq2pd512_mask" | "__builtin_ia32_cvtqq2ps512_mask" | "__builtin_ia32_cvtuqq2pd512_mask" - | "__builtin_ia32_cvtuqq2ps512_mask" => { + | "__builtin_ia32_cvtuqq2ps512_mask" + | "__builtin_ia32_sqrtph512_mask_round" + | "__builtin_ia32_vcvtw2ph512_mask_round" + | "__builtin_ia32_vcvtuw2ph512_mask_round" + | "__builtin_ia32_vcvtdq2ph512_mask_round" + | "__builtin_ia32_vcvtudq2ph512_mask_round" + | "__builtin_ia32_vcvtqq2ph512_mask_round" + | "__builtin_ia32_vcvtuqq2ph512_mask_round" => { let mut old_args = args.to_vec(); let mut new_args = vec![]; new_args.push(old_args.swap_remove(0)); @@ -425,7 +440,9 @@ pub fn adjust_intrinsic_arguments<'a, 'b, 'gcc, 'tcx>( "__builtin_ia32_addph512_mask_round" | "__builtin_ia32_subph512_mask_round" | "__builtin_ia32_mulph512_mask_round" - | "__builtin_ia32_divph512_mask_round" => { + | "__builtin_ia32_divph512_mask_round" + | "__builtin_ia32_maxph512_mask_round" + | "__builtin_ia32_minph512_mask_round" => { let mut new_args = args.to_vec(); let last_arg = new_args.pop().expect("last arg"); @@ -460,7 +477,9 @@ pub fn adjust_intrinsic_arguments<'a, 'b, 'gcc, 'tcx>( } } else { match func_name { - "__builtin_ia32_rndscaless_mask_round" | "__builtin_ia32_rndscalesd_mask_round" => { + "__builtin_ia32_rndscaless_mask_round" + | "__builtin_ia32_rndscalesd_mask_round" + | "__builtin_ia32_reducesh_mask_round" => { let new_args = args.to_vec(); let arg3_type = gcc_func.get_param_type(2); let arg3 = builder.context.new_cast(None, new_args[4], arg3_type); @@ -585,6 +604,12 @@ pub fn adjust_intrinsic_arguments<'a, 'b, 'gcc, 'tcx>( new_args[2] = builder.context.new_cast(None, new_args[2], builder.double_type); args = new_args.into(); } + "__builtin_ia32_sqrtsh_mask_round" => { + // The first two arguments are inverted, so swap them. + let mut new_args = args.to_vec(); + new_args.swap(0, 1); + args = new_args.into(); + } _ => (), } } @@ -1090,9 +1115,9 @@ pub fn intrinsic<'gcc, 'tcx>(name: &str, cx: &CodegenCx<'gcc, 'tcx>) -> Function "llvm.x86.avx512.dbpsadbw.128" => "__builtin_ia32_dbpsadbw128_mask", "llvm.x86.avx512.vpmadd52h.uq.512" => "__builtin_ia32_vpmadd52huq512_mask", "llvm.x86.avx512.vpmadd52l.uq.512" => "__builtin_ia32_vpmadd52luq512_mask", - "llvm.x86.avx512.vpmadd52h.uq.256" => "__builtin_ia32_vpmadd52huq256_mask", - "llvm.x86.avx512.vpmadd52l.uq.256" => "__builtin_ia32_vpmadd52luq256_mask", - "llvm.x86.avx512.vpmadd52h.uq.128" => "__builtin_ia32_vpmadd52huq128_mask", + "llvm.x86.avx512.vpmadd52h.uq.256" => "__builtin_ia32_vpmadd52huq256", + "llvm.x86.avx512.vpmadd52l.uq.256" => "__builtin_ia32_vpmadd52luq256", + "llvm.x86.avx512.vpmadd52h.uq.128" => "__builtin_ia32_vpmadd52huq128", "llvm.x86.avx512.vpdpwssd.512" => "__builtin_ia32_vpdpwssd_v16si", "llvm.x86.avx512.vpdpwssd.256" => "__builtin_ia32_vpdpwssd_v8si", "llvm.x86.avx512.vpdpwssd.128" => "__builtin_ia32_vpdpwssd_v4si", @@ -1209,6 +1234,55 @@ pub fn intrinsic<'gcc, 'tcx>(name: &str, cx: &CodegenCx<'gcc, 'tcx>) -> Function "llvm.x86.avx512fp16.vfmadd.f16" => "__builtin_ia32_vfmaddsh3_mask", "llvm.x86.avx512fp16.vfmaddsub.ph.128" => "__builtin_ia32_vfmaddsubph128_mask", "llvm.x86.avx512fp16.vfmaddsub.ph.256" => "__builtin_ia32_vfmaddsubph256_mask", + "llvm.x86.avx512fp16.vfmaddsub.ph.512" => "__builtin_ia32_vfmaddsubph512_mask", + "llvm.x86.avx512fp16.sqrt.ph.512" => "__builtin_ia32_sqrtph512_mask_round", + "llvm.x86.avx512fp16.mask.sqrt.sh" => "__builtin_ia32_sqrtsh_mask_round", + "llvm.x86.avx512fp16.max.ph.128" => "__builtin_ia32_maxph128_mask", + "llvm.x86.avx512fp16.max.ph.256" => "__builtin_ia32_maxph256_mask", + "llvm.x86.avx512fp16.max.ph.512" => "__builtin_ia32_maxph512_mask_round", + "llvm.x86.avx512fp16.min.ph.128" => "__builtin_ia32_minph128_mask", + "llvm.x86.avx512fp16.min.ph.256" => "__builtin_ia32_minph256_mask", + "llvm.x86.avx512fp16.min.ph.512" => "__builtin_ia32_minph512_mask_round", + "llvm.x86.avx512fp16.mask.getexp.sh" => "__builtin_ia32_getexpsh_mask_round", + "llvm.x86.avx512fp16.mask.rndscale.ph.128" => "__builtin_ia32_rndscaleph128_mask", + "llvm.x86.avx512fp16.mask.rndscale.ph.256" => "__builtin_ia32_rndscaleph256_mask", + "llvm.x86.avx512fp16.mask.rndscale.ph.512" => "__builtin_ia32_rndscaleph512_mask_round", + "llvm.x86.avx512fp16.mask.scalef.ph.512" => "__builtin_ia32_scalefph512_mask_round", + "llvm.x86.avx512fp16.mask.reduce.ph.512" => "__builtin_ia32_reduceph512_mask_round", + "llvm.x86.avx512fp16.mask.reduce.sh" => "__builtin_ia32_reducesh_mask_round", + "llvm.x86.avx512.sitofp.round.v8f16.v8i16" => "__builtin_ia32_vcvtw2ph128_mask", + "llvm.x86.avx512.sitofp.round.v16f16.v16i16" => "__builtin_ia32_vcvtw2ph256_mask", + "llvm.x86.avx512.sitofp.round.v32f16.v32i16" => "__builtin_ia32_vcvtw2ph512_mask_round", + "llvm.x86.avx512.uitofp.round.v8f16.v8u16" => "__builtin_ia32_vcvtuw2ph128_mask", + "llvm.x86.avx512.uitofp.round.v16f16.v16u16" => "__builtin_ia32_vcvtuw2ph256_mask", + "llvm.x86.avx512.uitofp.round.v32f16.v32u16" => "__builtin_ia32_vcvtuw2ph512_mask_round", + "llvm.x86.avx512.sitofp.round.v8f16.v8i32" => "__builtin_ia32_vcvtdq2ph256_mask", + "llvm.x86.avx512.sitofp.round.v16f16.v16i32" => "__builtin_ia32_vcvtdq2ph512_mask_round", + "llvm.x86.avx512fp16.vcvtsi2sh" => "__builtin_ia32_vcvtsi2sh32_round", + "llvm.x86.avx512.uitofp.round.v8f16.v8u32" => "__builtin_ia32_vcvtudq2ph256_mask", + "llvm.x86.avx512.uitofp.round.v16f16.v16u32" => "__builtin_ia32_vcvtudq2ph512_mask_round", + "llvm.x86.avx512fp16.vcvtusi2sh" => "__builtin_ia32_vcvtusi2sh32_round", + "llvm.x86.avx512.sitofp.round.v8f16.v8i64" => "__builtin_ia32_vcvtqq2ph512_mask_round", + "llvm.x86.avx512.uitofp.round.v8f16.v8u64" => "__builtin_ia32_vcvtuqq2ph512_mask_round", + "llvm.x86.avx512fp16.mask.vcvtps2phx.512" => "__builtin_ia32_vcvtps2phx512_mask_round", + "llvm.x86.avx512fp16.mask.vcvtpd2ph.512" => "__builtin_ia32_vcvtpd2ph512_mask_round", + "llvm.x86.avx512fp16.mask.vcvtph2uw.512" => "__builtin_ia32_vcvtph2uw512_mask_round", + "llvm.x86.avx512fp16.mask.vcvttph2w.512" => "__builtin_ia32_vcvttph2w512_mask_round", + "llvm.x86.avx512fp16.mask.vcvttph2uw.512" => "__builtin_ia32_vcvttph2uw512_mask_round", + "llvm.x86.avx512fp16.mask.vcvtph2dq.512" => "__builtin_ia32_vcvtph2dq512_mask_round", + "llvm.x86.avx512fp16.vcvtsh2si32" => "__builtin_ia32_vcvtsh2si32_round", + "llvm.x86.avx512fp16.mask.vcvtph2udq.512" => "__builtin_ia32_vcvtph2udq512_mask_round", + "llvm.x86.avx512fp16.vcvtsh2usi32" => "__builtin_ia32_vcvtsh2usi32_round", + "llvm.x86.avx512fp16.mask.vcvttph2dq.512" => "__builtin_ia32_vcvttph2dq512_mask_round", + "llvm.x86.avx512fp16.vcvttsh2si32" => "__builtin_ia32_vcvttsh2si32_round", + "llvm.x86.avx512fp16.mask.vcvttph2udq.512" => "__builtin_ia32_vcvttph2udq512_mask_round", + "llvm.x86.avx512fp16.vcvttsh2usi32" => "__builtin_ia32_vcvttsh2usi32_round", + "llvm.x86.avx512fp16.mask.vcvtph2qq.512" => "__builtin_ia32_vcvtph2qq512_mask_round", + "llvm.x86.avx512fp16.mask.vcvtph2uqq.512" => "__builtin_ia32_vcvtph2uqq512_mask_round", + "llvm.x86.avx512fp16.mask.vcvttph2qq.512" => "__builtin_ia32_vcvttph2qq512_mask_round", + "llvm.x86.avx512fp16.mask.vcvttph2uqq.512" => "__builtin_ia32_vcvttph2uqq512_mask_round", + "llvm.x86.avx512fp16.mask.vcvtph2psx.512" => "__builtin_ia32_vcvtph2psx512_mask_round", + "llvm.x86.avx512fp16.mask.vcvtph2pd.512" => "__builtin_ia32_vcvtph2pd512_mask_round", // TODO: support the tile builtins: "llvm.x86.ldtilecfg" => "__builtin_trap", From 0791efaaace3927fb6cc716d127561b2028dfc71 Mon Sep 17 00:00:00 2001 From: Samuel Tardieu Date: Tue, 24 Sep 2024 18:59:58 +0200 Subject: [PATCH 220/683] Use std_or_core to determine the correct prefix Replace hand-crafted tests by the a call to the `std_or_core()` utility function. --- clippy_lints/src/casts/borrow_as_ptr.rs | 6 +++--- clippy_lints/src/casts/ref_as_ptr.rs | 6 +++--- clippy_lints/src/loops/missing_spin_loop.rs | 10 +++------- 3 files changed, 9 insertions(+), 13 deletions(-) diff --git a/clippy_lints/src/casts/borrow_as_ptr.rs b/clippy_lints/src/casts/borrow_as_ptr.rs index b7256dd2eae..4dd51dcbc9a 100644 --- a/clippy_lints/src/casts/borrow_as_ptr.rs +++ b/clippy_lints/src/casts/borrow_as_ptr.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::is_no_std_crate; use clippy_utils::source::snippet_with_context; +use clippy_utils::std_or_core; use rustc_errors::Applicability; use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability, Ty, TyKind}; use rustc_lint::LateContext; @@ -16,8 +16,8 @@ pub(super) fn check<'tcx>( ) { 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) { - let core_or_std = if is_no_std_crate(cx) { "core" } else { "std" }; let macro_name = match mutability { Mutability::Not => "addr_of", Mutability::Mut => "addr_of_mut", @@ -40,7 +40,7 @@ pub(super) fn check<'tcx>( expr.span, "borrow as raw pointer", "try", - format!("{core_or_std}::ptr::{macro_name}!({snip})"), + format!("{std_or_core}::ptr::{macro_name}!({snip})"), Applicability::MachineApplicable, ); } diff --git a/clippy_lints/src/casts/ref_as_ptr.rs b/clippy_lints/src/casts/ref_as_ptr.rs index dfa240ccec6..f699bba20ed 100644 --- a/clippy_lints/src/casts/ref_as_ptr.rs +++ b/clippy_lints/src/casts/ref_as_ptr.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; use clippy_utils::sugg::Sugg; -use clippy_utils::{ExprUseNode, expr_use_ctxt, is_no_std_crate}; +use clippy_utils::{ExprUseNode, expr_use_ctxt, std_or_core}; use rustc_errors::Applicability; use rustc_hir::{Expr, Mutability, Ty, TyKind}; use rustc_lint::LateContext; @@ -25,8 +25,8 @@ pub(super) fn check<'tcx>( && let use_cx = expr_use_ctxt(cx, expr) // TODO: only block the lint if `cast_expr` is a temporary && !matches!(use_cx.use_node(cx), ExprUseNode::LetStmt(_) | ExprUseNode::ConstStatic(_)) + && let Some(std_or_core) = std_or_core(cx) { - let core_or_std = if is_no_std_crate(cx) { "core" } else { "std" }; let fn_name = match to_mutbl { Mutability::Not => "from_ref", Mutability::Mut => "from_mut", @@ -56,7 +56,7 @@ pub(super) fn check<'tcx>( expr.span, "reference as raw pointer", "try", - format!("{core_or_std}::ptr::{fn_name}{turbofish}({cast_expr_sugg})"), + format!("{std_or_core}::ptr::{fn_name}{turbofish}({cast_expr_sugg})"), app, ); } diff --git a/clippy_lints/src/loops/missing_spin_loop.rs b/clippy_lints/src/loops/missing_spin_loop.rs index e405829b2f4..a9944d64ce2 100644 --- a/clippy_lints/src/loops/missing_spin_loop.rs +++ b/clippy_lints/src/loops/missing_spin_loop.rs @@ -1,6 +1,6 @@ use super::MISSING_SPIN_LOOP; use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::is_no_std_crate; +use clippy_utils::std_or_core; use rustc_errors::Applicability; use rustc_hir::{Block, Expr, ExprKind}; use rustc_lint::LateContext; @@ -41,6 +41,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, cond: &'tcx Expr<'_>, body: &' && [sym::load, sym::compare_exchange, sym::compare_exchange_weak].contains(&method.ident.name) && let ty::Adt(def, _args) = cx.typeck_results().expr_ty(callee).kind() && cx.tcx.is_diagnostic_item(sym::AtomicBool, def.did()) + && let Some(std_or_core) = std_or_core(cx) { span_lint_and_sugg( cx, @@ -48,12 +49,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, cond: &'tcx Expr<'_>, body: &' body.span, "busy-waiting loop should at least have a spin loop hint", "try", - (if is_no_std_crate(cx) { - "{ core::hint::spin_loop() }" - } else { - "{ std::hint::spin_loop() }" - }) - .into(), + format!("{{ {std_or_core}::hint::spin_loop() }}"), Applicability::MachineApplicable, ); } From 31bbe2cee3acb720e4d60d5829db2c292a447c14 Mon Sep 17 00:00:00 2001 From: ljgermain Date: Tue, 24 Sep 2024 15:17:52 -0400 Subject: [PATCH 221/683] Apply review suggestions --- clippy_lints/src/ptr.rs | 6 ++++++ tests/ui/invalid_null_ptr_usage.fixed | 2 ++ tests/ui/invalid_null_ptr_usage.rs | 2 ++ tests/ui/invalid_null_ptr_usage.stderr | 16 ++++++++-------- 4 files changed, 18 insertions(+), 8 deletions(-) diff --git a/clippy_lints/src/ptr.rs b/clippy_lints/src/ptr.rs index d523ec2edff..bb8a9b6fca8 100644 --- a/clippy_lints/src/ptr.rs +++ b/clippy_lints/src/ptr.rs @@ -271,6 +271,12 @@ fn check_invalid_ptr_usage<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { && let Some(fun_def_id) = cx.qpath_res(qpath, fun.hir_id).opt_def_id() && let Some(name) = cx.tcx.get_diagnostic_name(fun_def_id) { + // TODO: `ptr_slice_from_raw_parts` and its mutable variant should probably still be linted + // conditionally based on how the return value is used, but not universally like the other + // functions since there are valid uses for null slice pointers. + // + // See: https://github.com/rust-lang/rust-clippy/pull/13452/files#r1773772034 + // `arg` positions where null would cause U.B. let arg_indices: &[_] = match name { sym::ptr_read diff --git a/tests/ui/invalid_null_ptr_usage.fixed b/tests/ui/invalid_null_ptr_usage.fixed index c8f1858b4f8..092e875a255 100644 --- a/tests/ui/invalid_null_ptr_usage.fixed +++ b/tests/ui/invalid_null_ptr_usage.fixed @@ -24,6 +24,8 @@ fn main() { let _a: A = std::ptr::read_volatile(core::ptr::NonNull::dangling().as_ptr()); let _a: A = std::ptr::replace(core::ptr::NonNull::dangling().as_ptr(), A); + let _slice: *const [usize] = std::ptr::slice_from_raw_parts(std::ptr::null_mut(), 0); // shouldn't lint + let _slice: *const [usize] = std::ptr::slice_from_raw_parts_mut(std::ptr::null_mut(), 0); std::ptr::swap::(core::ptr::NonNull::dangling().as_ptr(), &mut A); std::ptr::swap::(&mut A, core::ptr::NonNull::dangling().as_ptr()); diff --git a/tests/ui/invalid_null_ptr_usage.rs b/tests/ui/invalid_null_ptr_usage.rs index 5f3fff8e90d..480b6642a3e 100644 --- a/tests/ui/invalid_null_ptr_usage.rs +++ b/tests/ui/invalid_null_ptr_usage.rs @@ -24,6 +24,8 @@ fn main() { let _a: A = std::ptr::read_volatile(std::ptr::null_mut()); let _a: A = std::ptr::replace(std::ptr::null_mut(), A); + let _slice: *const [usize] = std::ptr::slice_from_raw_parts(std::ptr::null_mut(), 0); // shouldn't lint + let _slice: *const [usize] = std::ptr::slice_from_raw_parts_mut(std::ptr::null_mut(), 0); std::ptr::swap::(std::ptr::null_mut(), &mut A); std::ptr::swap::(&mut A, std::ptr::null_mut()); diff --git a/tests/ui/invalid_null_ptr_usage.stderr b/tests/ui/invalid_null_ptr_usage.stderr index ca7b8c133a5..a0be2c0ad75 100644 --- a/tests/ui/invalid_null_ptr_usage.stderr +++ b/tests/ui/invalid_null_ptr_usage.stderr @@ -85,49 +85,49 @@ LL | let _a: A = std::ptr::replace(std::ptr::null_mut(), A); | ^^^^^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()` error: pointer must be non-null - --> tests/ui/invalid_null_ptr_usage.rs:28:29 + --> tests/ui/invalid_null_ptr_usage.rs:30:29 | LL | std::ptr::swap::(std::ptr::null_mut(), &mut A); | ^^^^^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()` error: pointer must be non-null - --> tests/ui/invalid_null_ptr_usage.rs:29:37 + --> tests/ui/invalid_null_ptr_usage.rs:31:37 | LL | std::ptr::swap::(&mut A, std::ptr::null_mut()); | ^^^^^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()` error: pointer must be non-null - --> tests/ui/invalid_null_ptr_usage.rs:31:44 + --> tests/ui/invalid_null_ptr_usage.rs:33:44 | LL | std::ptr::swap_nonoverlapping::(std::ptr::null_mut(), &mut A, 0); | ^^^^^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()` error: pointer must be non-null - --> tests/ui/invalid_null_ptr_usage.rs:32:52 + --> tests/ui/invalid_null_ptr_usage.rs:34:52 | LL | std::ptr::swap_nonoverlapping::(&mut A, std::ptr::null_mut(), 0); | ^^^^^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()` error: pointer must be non-null - --> tests/ui/invalid_null_ptr_usage.rs:34:25 + --> tests/ui/invalid_null_ptr_usage.rs:36:25 | LL | std::ptr::write(std::ptr::null_mut(), A); | ^^^^^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()` error: pointer must be non-null - --> tests/ui/invalid_null_ptr_usage.rs:36:35 + --> tests/ui/invalid_null_ptr_usage.rs:38:35 | LL | std::ptr::write_unaligned(std::ptr::null_mut(), A); | ^^^^^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()` error: pointer must be non-null - --> tests/ui/invalid_null_ptr_usage.rs:38:34 + --> tests/ui/invalid_null_ptr_usage.rs:40:34 | LL | std::ptr::write_volatile(std::ptr::null_mut(), A); | ^^^^^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()` error: pointer must be non-null - --> tests/ui/invalid_null_ptr_usage.rs:40:40 + --> tests/ui/invalid_null_ptr_usage.rs:42:40 | LL | std::ptr::write_bytes::(std::ptr::null_mut(), 42, 0); | ^^^^^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()` From d802a7a3c79e96be1f77c7ce3ecc7f8c650000f7 Mon Sep 17 00:00:00 2001 From: Lukas Markeffsky <@> Date: Sun, 15 Sep 2024 16:47:42 +0200 Subject: [PATCH 222/683] unify dyn* coercions with other pointer coercions --- clippy_utils/src/qualify_min_const_fn.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_utils/src/qualify_min_const_fn.rs b/clippy_utils/src/qualify_min_const_fn.rs index d9befb3c157..6434c2f42cf 100644 --- a/clippy_utils/src/qualify_min_const_fn.rs +++ b/clippy_utils/src/qualify_min_const_fn.rs @@ -154,7 +154,7 @@ fn check_rvalue<'tcx>( Rvalue::Cast(CastKind::PointerExposeProvenance, _, _) => { Err((span, "casting pointers to ints is unstable in const fn".into())) }, - Rvalue::Cast(CastKind::DynStar, _, _) => { + Rvalue::Cast(CastKind::PointerCoercion(PointerCoercion::DynStar), _, _) => { // FIXME(dyn-star) unimplemented!() }, From 0a52b6511382d79219798cf423f370786e9e13b7 Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Tue, 24 Sep 2024 12:45:52 -0400 Subject: [PATCH 223/683] Update to Ubuntu 24.04 to get a more recent GNU as --- .github/workflows/stdarch.yml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/.github/workflows/stdarch.yml b/.github/workflows/stdarch.yml index e24b25b7369..dde1ce21d7b 100644 --- a/.github/workflows/stdarch.yml +++ b/.github/workflows/stdarch.yml @@ -13,7 +13,7 @@ env: jobs: build: - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 strategy: fail-fast: false @@ -36,6 +36,12 @@ jobs: - name: Install packages run: sudo apt-get install ninja-build ripgrep + - name: Install more recent binutils + run: | + echo "deb http://archive.ubuntu.com/ubuntu oracular main universe" | sudo tee /etc/apt/sources.list.d/oracular-copies.list + sudo apt-get update + sudo apt-get install binutils + - name: Install Intel Software Development Emulator if: ${{ matrix.cargo_runner }} run: | From ee129b12ede79fd8cf7e398cf955941b62e58974 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Tue, 24 Sep 2024 13:32:29 -0700 Subject: [PATCH 224/683] Add `File::open_buffered` and `create_buffered` --- library/std/src/fs.rs | 71 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs index 55f3b628ce8..6d1005272c6 100644 --- a/library/std/src/fs.rs +++ b/library/std/src/fs.rs @@ -375,6 +375,41 @@ impl File { OpenOptions::new().read(true).open(path.as_ref()) } + /// Attempts to open a file in read-only mode with buffering. + /// + /// See the [`OpenOptions::open`] method, the [`BufReader`][io::BufReader] type, + /// and the [`BufRead`][io::BufRead] trait for more details. + /// + /// If you only need to read the entire file contents, + /// consider [`std::fs::read()`][self::read] or + /// [`std::fs::read_to_string()`][self::read_to_string] instead. + /// + /// # Errors + /// + /// This function will return an error if `path` does not already exist. + /// Other errors may also be returned according to [`OpenOptions::open`]. + /// + /// # Examples + /// + /// ```no_run + /// #![feature(file_buffered)] + /// use std::fs::File; + /// use std::io::BufRead; + /// + /// fn main() -> std::io::Result<()> { + /// let mut f = File::open_buffered("foo.txt")?; + /// assert!(f.capacity() > 0); + /// for (line, i) in f.lines().zip(1..) { + /// println!("{i:6}: {}", line?); + /// } + /// Ok(()) + /// } + /// ``` + #[unstable(feature = "file_buffered", issue = "none")] + pub fn open_buffered>(path: P) -> io::Result> { + File::open(path).map(io::BufReader::new) + } + /// Opens a file in write-only mode. /// /// This function will create a file if it does not exist, @@ -404,6 +439,42 @@ impl File { OpenOptions::new().write(true).create(true).truncate(true).open(path.as_ref()) } + /// Opens a file in write-only mode with buffering. + /// + /// This function will create a file if it does not exist, + /// and will truncate it if it does. + /// + /// Depending on the platform, this function may fail if the + /// full directory path does not exist. + /// + /// See the [`OpenOptions::open`] method and the + /// [`BufWriter`][io::BufWriter] type for more details. + /// + /// See also [`std::fs::write()`][self::write] for a simple function to + /// create a file with some given data. + /// + /// # Examples + /// + /// ```no_run + /// #![feature(file_buffered)] + /// use std::fs::File; + /// use std::io::Write; + /// + /// fn main() -> std::io::Result<()> { + /// let mut f = File::create_buffered("foo.txt")?; + /// assert!(f.capacity() > 0); + /// for i in 0..100 { + /// writeln!(&mut f, "{i}")?; + /// } + /// f.flush()?; + /// Ok(()) + /// } + /// ``` + #[unstable(feature = "file_buffered", issue = "none")] + pub fn create_buffered>(path: P) -> io::Result> { + File::create(path).map(io::BufWriter::new) + } + /// Creates a new file in read-write mode; error if the file exists. /// /// This function will create a file if it does not exist, or return an error if it does. This From 1e9a50dde8fe417348a9e4c74787975527502ec3 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Tue, 24 Sep 2024 13:33:31 -0700 Subject: [PATCH 225/683] Pre-allocate buffers in `File::open_buffered` and `create_buffered` --- library/std/src/fs.rs | 10 ++++++++-- library/std/src/io/buffered/bufreader.rs | 8 ++++++++ library/std/src/io/buffered/bufreader/buffer.rs | 12 +++++++++++- library/std/src/io/buffered/bufwriter.rs | 10 ++++++++++ library/std/src/lib.rs | 1 + 5 files changed, 38 insertions(+), 3 deletions(-) diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs index 6d1005272c6..b8e3f316beb 100644 --- a/library/std/src/fs.rs +++ b/library/std/src/fs.rs @@ -407,7 +407,10 @@ impl File { /// ``` #[unstable(feature = "file_buffered", issue = "none")] pub fn open_buffered>(path: P) -> io::Result> { - File::open(path).map(io::BufReader::new) + // Allocate the buffer *first* so we don't affect the filesystem otherwise. + let buffer = io::BufReader::::try_new_buffer()?; + let file = File::open(path)?; + Ok(io::BufReader::with_buffer(file, buffer)) } /// Opens a file in write-only mode. @@ -472,7 +475,10 @@ impl File { /// ``` #[unstable(feature = "file_buffered", issue = "none")] pub fn create_buffered>(path: P) -> io::Result> { - File::create(path).map(io::BufWriter::new) + // Allocate the buffer *first* so we don't affect the filesystem otherwise. + let buffer = io::BufWriter::::try_new_buffer()?; + let file = File::create(path)?; + Ok(io::BufWriter::with_buffer(file, buffer)) } /// Creates a new file in read-write mode; error if the file exists. diff --git a/library/std/src/io/buffered/bufreader.rs b/library/std/src/io/buffered/bufreader.rs index e51dde994de..fcb3e36027b 100644 --- a/library/std/src/io/buffered/bufreader.rs +++ b/library/std/src/io/buffered/bufreader.rs @@ -74,6 +74,14 @@ impl BufReader { BufReader::with_capacity(DEFAULT_BUF_SIZE, inner) } + pub(crate) fn try_new_buffer() -> io::Result { + Buffer::try_with_capacity(DEFAULT_BUF_SIZE) + } + + pub(crate) fn with_buffer(inner: R, buf: Buffer) -> Self { + Self { inner, buf } + } + /// Creates a new `BufReader` with the specified buffer capacity. /// /// # Examples diff --git a/library/std/src/io/buffered/bufreader/buffer.rs b/library/std/src/io/buffered/bufreader/buffer.rs index 1bf84d8bef3..3df7e3971da 100644 --- a/library/std/src/io/buffered/bufreader/buffer.rs +++ b/library/std/src/io/buffered/bufreader/buffer.rs @@ -10,7 +10,7 @@ //! without encountering any runtime bounds checks. use crate::cmp; -use crate::io::{self, BorrowedBuf, Read}; +use crate::io::{self, BorrowedBuf, ErrorKind, Read}; use crate::mem::MaybeUninit; pub struct Buffer { @@ -36,6 +36,16 @@ impl Buffer { Self { buf, pos: 0, filled: 0, initialized: 0 } } + #[inline] + pub fn try_with_capacity(capacity: usize) -> io::Result { + match Box::try_new_uninit_slice(capacity) { + Ok(buf) => Ok(Self { buf, pos: 0, filled: 0, initialized: 0 }), + Err(_) => { + Err(io::const_io_error!(ErrorKind::OutOfMemory, "failed to allocate read buffer")) + } + } + } + #[inline] pub fn buffer(&self) -> &[u8] { // SAFETY: self.pos and self.cap are valid, and self.cap => self.pos, and diff --git a/library/std/src/io/buffered/bufwriter.rs b/library/std/src/io/buffered/bufwriter.rs index 13516d3b961..c41bae2aa4e 100644 --- a/library/std/src/io/buffered/bufwriter.rs +++ b/library/std/src/io/buffered/bufwriter.rs @@ -94,6 +94,16 @@ impl BufWriter { BufWriter::with_capacity(DEFAULT_BUF_SIZE, inner) } + pub(crate) fn try_new_buffer() -> io::Result> { + Vec::try_with_capacity(DEFAULT_BUF_SIZE).map_err(|_| { + io::const_io_error!(ErrorKind::OutOfMemory, "failed to allocate write buffer") + }) + } + + pub(crate) fn with_buffer(inner: W, buf: Vec) -> Self { + Self { inner, buf, panicked: false } + } + /// Creates a new `BufWriter` with at least the specified buffer capacity. /// /// # Examples diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 4d93af6ea65..b81e7c18abb 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -374,6 +374,7 @@ #![feature(slice_concat_trait)] #![feature(thin_box)] #![feature(try_reserve_kind)] +#![feature(try_with_capacity)] #![feature(vec_into_raw_parts)] // tidy-alphabetical-end // From 08a8e68d2e9e4b637c2f0344314f6e836405aa77 Mon Sep 17 00:00:00 2001 From: Lukas Markeffsky <@> Date: Sun, 15 Sep 2024 19:35:06 +0200 Subject: [PATCH 226/683] be even more precise about "cast" vs "coercion" --- clippy_utils/src/qualify_min_const_fn.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/clippy_utils/src/qualify_min_const_fn.rs b/clippy_utils/src/qualify_min_const_fn.rs index 6434c2f42cf..ce1895b7fb1 100644 --- a/clippy_utils/src/qualify_min_const_fn.rs +++ b/clippy_utils/src/qualify_min_const_fn.rs @@ -123,7 +123,7 @@ fn check_rvalue<'tcx>( | CastKind::FloatToFloat | CastKind::FnPtrToPtr | CastKind::PtrToPtr - | CastKind::PointerCoercion(PointerCoercion::MutToConstPointer | PointerCoercion::ArrayToPointer), + | CastKind::PointerCoercion(PointerCoercion::MutToConstPointer | PointerCoercion::ArrayToPointer, _), operand, _, ) => check_operand(tcx, operand, span, body, msrv), @@ -131,12 +131,12 @@ fn check_rvalue<'tcx>( CastKind::PointerCoercion( PointerCoercion::UnsafeFnPointer | PointerCoercion::ClosureFnPointer(_) - | PointerCoercion::ReifyFnPointer, + | PointerCoercion::ReifyFnPointer, _ ), _, _, ) => Err((span, "function pointer casts are not allowed in const fn".into())), - Rvalue::Cast(CastKind::PointerCoercion(PointerCoercion::Unsize), op, cast_ty) => { + Rvalue::Cast(CastKind::PointerCoercion(PointerCoercion::Unsize, _), op, cast_ty) => { let Some(pointee_ty) = cast_ty.builtin_deref(true) else { // We cannot allow this for now. return Err((span, "unsizing casts are only allowed for references right now".into())); @@ -154,7 +154,7 @@ fn check_rvalue<'tcx>( Rvalue::Cast(CastKind::PointerExposeProvenance, _, _) => { Err((span, "casting pointers to ints is unstable in const fn".into())) }, - Rvalue::Cast(CastKind::PointerCoercion(PointerCoercion::DynStar), _, _) => { + Rvalue::Cast(CastKind::PointerCoercion(PointerCoercion::DynStar, _), _, _) => { // FIXME(dyn-star) unimplemented!() }, From 0999b019f8e0a96ca7aac9fd5ec095d59b0806ec Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Tue, 24 Sep 2024 14:25:16 -0700 Subject: [PATCH 227/683] Dogfood `feature(file_buffered)` --- compiler/rustc_borrowck/src/facts.rs | 4 ++-- compiler/rustc_borrowck/src/lib.rs | 1 + compiler/rustc_codegen_llvm/src/back/lto.rs | 7 +++---- compiler/rustc_codegen_llvm/src/lib.rs | 1 + compiler/rustc_codegen_ssa/src/back/linker.rs | 15 +++++++-------- compiler/rustc_codegen_ssa/src/lib.rs | 1 + compiler/rustc_data_structures/src/lib.rs | 1 + .../src/obligation_forest/graphviz.rs | 3 +-- .../rustc_incremental/src/assert_dep_graph.rs | 4 ++-- compiler/rustc_incremental/src/lib.rs | 1 + compiler/rustc_interface/src/lib.rs | 1 + compiler/rustc_interface/src/passes.rs | 2 +- compiler/rustc_metadata/src/fs.rs | 3 +-- compiler/rustc_metadata/src/lib.rs | 1 + compiler/rustc_middle/src/lib.rs | 1 + compiler/rustc_middle/src/mir/pretty.rs | 4 ++-- .../rustc_mir_dataflow/src/framework/engine.rs | 5 ++--- compiler/rustc_mir_dataflow/src/lib.rs | 1 + compiler/rustc_mir_transform/src/dump_mir.rs | 2 +- compiler/rustc_mir_transform/src/lib.rs | 1 + compiler/rustc_monomorphize/src/lib.rs | 1 + compiler/rustc_monomorphize/src/partitioning.rs | 5 ++--- library/std/src/sys/pal/unix/thread.rs | 4 ++-- library/test/src/lib.rs | 1 + library/test/src/term/terminfo/mod.rs | 6 ++---- src/librustdoc/html/render/write_shared.rs | 5 ++--- src/librustdoc/json/mod.rs | 2 +- src/librustdoc/lib.rs | 1 + 28 files changed, 44 insertions(+), 40 deletions(-) diff --git a/compiler/rustc_borrowck/src/facts.rs b/compiler/rustc_borrowck/src/facts.rs index 713452796c6..ef8e757a547 100644 --- a/compiler/rustc_borrowck/src/facts.rs +++ b/compiler/rustc_borrowck/src/facts.rs @@ -1,7 +1,7 @@ use std::error::Error; use std::fmt::Debug; use std::fs::{self, File}; -use std::io::{BufWriter, Write}; +use std::io::Write; use std::path::Path; use polonius_engine::{AllFacts as PoloniusFacts, Atom}; @@ -127,7 +127,7 @@ impl<'w> FactWriter<'w> { T: FactRow, { let file = &self.dir.join(file_name); - let mut file = BufWriter::new(File::create(file)?); + let mut file = File::create_buffered(file)?; for row in rows { row.write(&mut file, self.location_table)?; } diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 733fabe557e..a11eca0b9c7 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(control_flow_enum)] +#![feature(file_buffered)] #![feature(let_chains)] #![feature(never_type)] #![feature(rustc_attrs)] diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs index 5e510177818..1f7a923dd2c 100644 --- a/compiler/rustc_codegen_llvm/src/back/lto.rs +++ b/compiler/rustc_codegen_llvm/src/back/lto.rs @@ -808,8 +808,7 @@ struct ThinLTOKeysMap { impl ThinLTOKeysMap { fn save_to_file(&self, path: &Path) -> io::Result<()> { use std::io::Write; - let file = File::create(path)?; - let mut writer = io::BufWriter::new(file); + let mut writer = File::create_buffered(path)?; // The entries are loaded back into a hash map in `load_from_file()`, so // the order in which we write them to file here does not matter. for (module, key) in &self.keys { @@ -821,8 +820,8 @@ impl ThinLTOKeysMap { fn load_from_file(path: &Path) -> io::Result { use std::io::BufRead; let mut keys = BTreeMap::default(); - let file = File::open(path)?; - for line in io::BufReader::new(file).lines() { + let file = File::open_buffered(path)?; + for line in file.lines() { let line = line?; let mut split = line.split(' '); let module = split.next().unwrap(); diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index d69112612ba..bdfc0f626f8 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -11,6 +11,7 @@ #![feature(assert_matches)] #![feature(exact_size_is_empty)] #![feature(extern_types)] +#![feature(file_buffered)] #![feature(hash_raw_entry)] #![feature(impl_trait_in_assoc_type)] #![feature(iter_intersperse)] diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs index 84817e19844..a73ec83ee62 100644 --- a/compiler/rustc_codegen_ssa/src/back/linker.rs +++ b/compiler/rustc_codegen_ssa/src/back/linker.rs @@ -1,9 +1,8 @@ use std::ffi::{OsStr, OsString}; use std::fs::{self, File}; use std::io::prelude::*; -use std::io::{self, BufWriter}; use std::path::{Path, PathBuf}; -use std::{env, iter, mem, str}; +use std::{env, io, iter, mem, str}; use cc::windows_registry; use rustc_hir::def_id::{CrateNum, LOCAL_CRATE}; @@ -754,7 +753,7 @@ impl<'a> Linker for GccLinker<'a> { if self.sess.target.is_like_osx { // Write a plain, newline-separated list of symbols let res: io::Result<()> = try { - let mut f = BufWriter::new(File::create(&path)?); + let mut f = File::create_buffered(&path)?; for sym in symbols { debug!(" _{sym}"); writeln!(f, "_{sym}")?; @@ -765,7 +764,7 @@ impl<'a> Linker for GccLinker<'a> { } } else if is_windows { let res: io::Result<()> = try { - let mut f = BufWriter::new(File::create(&path)?); + let mut f = File::create_buffered(&path)?; // .def file similar to MSVC one but without LIBRARY section // because LD doesn't like when it's empty @@ -781,7 +780,7 @@ impl<'a> Linker for GccLinker<'a> { } else { // Write an LD version script let res: io::Result<()> = try { - let mut f = BufWriter::new(File::create(&path)?); + let mut f = File::create_buffered(&path)?; writeln!(f, "{{")?; if !symbols.is_empty() { writeln!(f, " global:")?; @@ -1059,7 +1058,7 @@ impl<'a> Linker for MsvcLinker<'a> { let path = tmpdir.join("lib.def"); let res: io::Result<()> = try { - let mut f = BufWriter::new(File::create(&path)?); + let mut f = File::create_buffered(&path)?; // Start off with the standard module name header and then go // straight to exports. @@ -1648,7 +1647,7 @@ impl<'a> Linker for AixLinker<'a> { fn export_symbols(&mut self, tmpdir: &Path, _crate_type: CrateType, symbols: &[String]) { let path = tmpdir.join("list.exp"); let res: io::Result<()> = try { - let mut f = BufWriter::new(File::create(&path)?); + let mut f = File::create_buffered(&path)?; // FIXME: use llvm-nm to generate export list. for symbol in symbols { debug!(" _{symbol}"); @@ -1961,7 +1960,7 @@ impl<'a> Linker for BpfLinker<'a> { fn export_symbols(&mut self, tmpdir: &Path, _crate_type: CrateType, symbols: &[String]) { let path = tmpdir.join("symbols"); let res: io::Result<()> = try { - let mut f = BufWriter::new(File::create(&path)?); + let mut f = File::create_buffered(&path)?; for sym in symbols { writeln!(f, "{sym}")?; } diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs index ec0520fbb09..162d14272a5 100644 --- a/compiler/rustc_codegen_ssa/src/lib.rs +++ b/compiler/rustc_codegen_ssa/src/lib.rs @@ -6,6 +6,7 @@ #![doc(rust_logo)] #![feature(assert_matches)] #![feature(box_patterns)] +#![feature(file_buffered)] #![feature(if_let_guard)] #![feature(let_chains)] #![feature(negative_impls)] diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs index a35f5b1f17d..f225684d99f 100644 --- a/compiler/rustc_data_structures/src/lib.rs +++ b/compiler/rustc_data_structures/src/lib.rs @@ -23,6 +23,7 @@ #![feature(cfg_match)] #![feature(core_intrinsics)] #![feature(extend_one)] +#![feature(file_buffered)] #![feature(hash_raw_entry)] #![feature(macro_metavar_expr)] #![feature(map_try_insert)] diff --git a/compiler/rustc_data_structures/src/obligation_forest/graphviz.rs b/compiler/rustc_data_structures/src/obligation_forest/graphviz.rs index 60cde9a52b4..65a24366db8 100644 --- a/compiler/rustc_data_structures/src/obligation_forest/graphviz.rs +++ b/compiler/rustc_data_structures/src/obligation_forest/graphviz.rs @@ -1,6 +1,5 @@ use std::env::var_os; use std::fs::File; -use std::io::BufWriter; use std::path::Path; use std::sync::atomic::{AtomicUsize, Ordering}; @@ -33,7 +32,7 @@ impl ObligationForest { let file_path = dir.as_ref().join(format!("{counter:010}_{description}.gv")); - let mut gv_file = BufWriter::new(File::create(file_path).unwrap()); + let mut gv_file = File::create_buffered(file_path).unwrap(); dot::render(&self, &mut gv_file).unwrap(); } diff --git a/compiler/rustc_incremental/src/assert_dep_graph.rs b/compiler/rustc_incremental/src/assert_dep_graph.rs index 646b9dbe133..a006786aa75 100644 --- a/compiler/rustc_incremental/src/assert_dep_graph.rs +++ b/compiler/rustc_incremental/src/assert_dep_graph.rs @@ -35,7 +35,7 @@ use std::env; use std::fs::{self, File}; -use std::io::{BufWriter, Write}; +use std::io::Write; use rustc_data_structures::fx::FxIndexSet; use rustc_data_structures::graph::implementation::{Direction, INCOMING, NodeIndex, OUTGOING}; @@ -245,7 +245,7 @@ fn dump_graph(query: &DepGraphQuery) { { // dump a .txt file with just the edges: let txt_path = format!("{path}.txt"); - let mut file = BufWriter::new(File::create(&txt_path).unwrap()); + let mut file = File::create_buffered(&txt_path).unwrap(); for (source, target) in &edges { write!(file, "{source:?} -> {target:?}\n").unwrap(); } diff --git a/compiler/rustc_incremental/src/lib.rs b/compiler/rustc_incremental/src/lib.rs index dda1232b80b..e8735cba9bd 100644 --- a/compiler/rustc_incremental/src/lib.rs +++ b/compiler/rustc_incremental/src/lib.rs @@ -5,6 +5,7 @@ #![deny(missing_docs)] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] +#![feature(file_buffered)] #![feature(rustdoc_internals)] #![warn(unreachable_pub)] // tidy-alphabetical-end diff --git a/compiler/rustc_interface/src/lib.rs b/compiler/rustc_interface/src/lib.rs index 94ebe51f213..b81a7402701 100644 --- a/compiler/rustc_interface/src/lib.rs +++ b/compiler/rustc_interface/src/lib.rs @@ -1,5 +1,6 @@ // tidy-alphabetical-start #![feature(decl_macro)] +#![feature(file_buffered)] #![feature(let_chains)] #![feature(try_blocks)] #![warn(unreachable_pub)] diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 617581cf667..bba517915a2 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -519,7 +519,7 @@ fn write_out_deps(tcx: TyCtxt<'_>, outputs: &OutputFilenames, out_filenames: &[P write_deps_to_file(&mut file)?; } OutFileName::Real(ref path) => { - let mut file = BufWriter::new(fs::File::create(path)?); + let mut file = fs::File::create_buffered(path)?; write_deps_to_file(&mut file)?; } } diff --git a/compiler/rustc_metadata/src/fs.rs b/compiler/rustc_metadata/src/fs.rs index a58f3c6b5ca..4450d050c8e 100644 --- a/compiler/rustc_metadata/src/fs.rs +++ b/compiler/rustc_metadata/src/fs.rs @@ -128,8 +128,7 @@ pub fn non_durable_rename(src: &Path, dst: &Path) -> std::io::Result<()> { } pub fn copy_to_stdout(from: &Path) -> io::Result<()> { - let file = fs::File::open(from)?; - let mut reader = io::BufReader::new(file); + let mut reader = fs::File::open_buffered(from)?; let mut stdout = io::stdout(); io::copy(&mut reader, &mut stdout)?; Ok(()) diff --git a/compiler/rustc_metadata/src/lib.rs b/compiler/rustc_metadata/src/lib.rs index 1759ea7d441..10f2087d1e6 100644 --- a/compiler/rustc_metadata/src/lib.rs +++ b/compiler/rustc_metadata/src/lib.rs @@ -8,6 +8,7 @@ #![feature(decl_macro)] #![feature(error_iter)] #![feature(extract_if)] +#![feature(file_buffered)] #![feature(if_let_guard)] #![feature(iter_from_coroutine)] #![feature(let_chains)] diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs index 23cd247e884..a32b19b067a 100644 --- a/compiler/rustc_middle/src/lib.rs +++ b/compiler/rustc_middle/src/lib.rs @@ -45,6 +45,7 @@ #![feature(discriminant_kind)] #![feature(extern_types)] #![feature(extract_if)] +#![feature(file_buffered)] #![feature(if_let_guard)] #![feature(intra_doc_pointers)] #![feature(iter_from_coroutine)] diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index 119aed1106d..48789565218 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -277,9 +277,9 @@ pub fn create_dump_file<'tcx>( ) })?; } - Ok(io::BufWriter::new(fs::File::create(&file_path).map_err(|e| { + Ok(fs::File::create_buffered(&file_path).map_err(|e| { io::Error::new(e.kind(), format!("IO error creating MIR dump file: {file_path:?}; {e}")) - })?)) + })?) } /////////////////////////////////////////////////////////////////////////// diff --git a/compiler/rustc_mir_dataflow/src/framework/engine.rs b/compiler/rustc_mir_dataflow/src/framework/engine.rs index 947bdf860b5..da01a974094 100644 --- a/compiler/rustc_mir_dataflow/src/framework/engine.rs +++ b/compiler/rustc_mir_dataflow/src/framework/engine.rs @@ -266,7 +266,7 @@ where A::Domain: DebugWithContext, { use std::fs; - use std::io::{self, Write}; + use std::io::Write; let def_id = body.source.def_id(); let Ok(attrs) = RustcMirAttrs::parse(tcx, def_id) else { @@ -281,8 +281,7 @@ where if let Some(parent) = path.parent() { fs::create_dir_all(parent)?; } - let f = fs::File::create(&path)?; - io::BufWriter::new(f) + fs::File::create_buffered(&path)? } None if dump_enabled(tcx, A::NAME, def_id) => { diff --git a/compiler/rustc_mir_dataflow/src/lib.rs b/compiler/rustc_mir_dataflow/src/lib.rs index cb7c7edc413..cd926c07641 100644 --- a/compiler/rustc_mir_dataflow/src/lib.rs +++ b/compiler/rustc_mir_dataflow/src/lib.rs @@ -3,6 +3,7 @@ #![feature(associated_type_defaults)] #![feature(box_patterns)] #![feature(exact_size_is_empty)] +#![feature(file_buffered)] #![feature(let_chains)] #![feature(try_blocks)] #![warn(unreachable_pub)] diff --git a/compiler/rustc_mir_transform/src/dump_mir.rs b/compiler/rustc_mir_transform/src/dump_mir.rs index d7c47360419..5dd84975b88 100644 --- a/compiler/rustc_mir_transform/src/dump_mir.rs +++ b/compiler/rustc_mir_transform/src/dump_mir.rs @@ -24,7 +24,7 @@ pub fn emit_mir(tcx: TyCtxt<'_>) -> io::Result<()> { write_mir_pretty(tcx, None, &mut f)?; } OutFileName::Real(path) => { - let mut f = io::BufWriter::new(File::create(&path)?); + let mut f = File::create_buffered(&path)?; write_mir_pretty(tcx, None, &mut f)?; if tcx.sess.opts.json_artifact_notifications { tcx.dcx().emit_artifact_notification(&path, "mir"); diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index 56268c1d201..4c090665992 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -3,6 +3,7 @@ #![feature(box_patterns)] #![feature(const_type_name)] #![feature(cow_is_borrowed)] +#![feature(file_buffered)] #![feature(if_let_guard)] #![feature(impl_trait_in_assoc_type)] #![feature(let_chains)] diff --git a/compiler/rustc_monomorphize/src/lib.rs b/compiler/rustc_monomorphize/src/lib.rs index 91101ddd590..e92e6978d0f 100644 --- a/compiler/rustc_monomorphize/src/lib.rs +++ b/compiler/rustc_monomorphize/src/lib.rs @@ -1,5 +1,6 @@ // tidy-alphabetical-start #![feature(array_windows)] +#![feature(file_buffered)] #![feature(if_let_guard)] #![feature(let_chains)] #![warn(unreachable_pub)] diff --git a/compiler/rustc_monomorphize/src/partitioning.rs b/compiler/rustc_monomorphize/src/partitioning.rs index 1c1e6164f2e..ad05cca66ca 100644 --- a/compiler/rustc_monomorphize/src/partitioning.rs +++ b/compiler/rustc_monomorphize/src/partitioning.rs @@ -95,7 +95,7 @@ use std::cmp; use std::collections::hash_map::Entry; use std::fs::{self, File}; -use std::io::{BufWriter, Write}; +use std::io::Write; use std::path::{Path, PathBuf}; use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; @@ -1243,8 +1243,7 @@ fn dump_mono_items_stats<'tcx>( let ext = format.extension(); let filename = format!("{crate_name}.mono_items.{ext}"); let output_path = output_directory.join(&filename); - let file = File::create(&output_path)?; - let mut file = BufWriter::new(file); + let mut file = File::create_buffered(&output_path)?; // Gather instantiated mono items grouped by def_id let mut items_per_def_id: FxIndexMap<_, Vec<_>> = Default::default(); diff --git a/library/std/src/sys/pal/unix/thread.rs b/library/std/src/sys/pal/unix/thread.rs index 7fe9b6c3e52..ce5e8ea5866 100644 --- a/library/std/src/sys/pal/unix/thread.rs +++ b/library/std/src/sys/pal/unix/thread.rs @@ -517,7 +517,7 @@ mod cgroups { use crate::borrow::Cow; use crate::ffi::OsString; use crate::fs::{File, exists}; - use crate::io::{BufRead, BufReader, Read}; + use crate::io::{BufRead, Read}; use crate::os::unix::ffi::OsStringExt; use crate::path::{Path, PathBuf}; use crate::str::from_utf8; @@ -690,7 +690,7 @@ mod cgroups { /// If the cgroupfs is a bind mount then `group_path` is adjusted to skip /// over the already-included prefix fn find_mountpoint(group_path: &Path) -> Option<(Cow<'static, str>, &Path)> { - let mut reader = BufReader::new(File::open("/proc/self/mountinfo").ok()?); + let mut reader = File::open_buffered("/proc/self/mountinfo").ok()?; let mut line = String::with_capacity(256); loop { line.clear(); diff --git a/library/test/src/lib.rs b/library/test/src/lib.rs index ebbe50cc651..4b2c65cfdf5 100644 --- a/library/test/src/lib.rs +++ b/library/test/src/lib.rs @@ -18,6 +18,7 @@ #![doc(test(attr(deny(warnings))))] #![doc(rust_logo)] #![feature(rustdoc_internals)] +#![feature(file_buffered)] #![feature(internal_output_capture)] #![feature(staged_api)] #![feature(process_exitcode_internals)] diff --git a/library/test/src/term/terminfo/mod.rs b/library/test/src/term/terminfo/mod.rs index ac10ec2b850..974b8afd598 100644 --- a/library/test/src/term/terminfo/mod.rs +++ b/library/test/src/term/terminfo/mod.rs @@ -3,9 +3,8 @@ use std::collections::HashMap; use std::fs::File; use std::io::prelude::*; -use std::io::{self, BufReader}; use std::path::Path; -use std::{env, error, fmt}; +use std::{env, error, fmt, io}; use parm::{Param, Variables, expand}; use parser::compiled::{msys_terminfo, parse}; @@ -102,8 +101,7 @@ impl TermInfo { } // Keep the metadata small fn _from_path(path: &Path) -> Result { - let file = File::open(path).map_err(Error::IoError)?; - let mut reader = BufReader::new(file); + let mut reader = File::open_buffered(path).map_err(Error::IoError)?; parse(&mut reader, false).map_err(Error::MalformedTerminfo) } } diff --git a/src/librustdoc/html/render/write_shared.rs b/src/librustdoc/html/render/write_shared.rs index 16253799215..12246b0d416 100644 --- a/src/librustdoc/html/render/write_shared.rs +++ b/src/librustdoc/html/render/write_shared.rs @@ -16,7 +16,7 @@ use std::cell::RefCell; use std::ffi::OsString; use std::fs::File; -use std::io::{self, BufWriter, Write as _}; +use std::io::{self, Write as _}; use std::iter::once; use std::marker::PhantomData; use std::path::{Component, Path, PathBuf}; @@ -1020,8 +1020,7 @@ where for part in parts { template.append(part); } - let file = try_err!(File::create(&path), &path); - let mut file = BufWriter::new(file); + let mut file = try_err!(File::create_buffered(&path), &path); try_err!(write!(file, "{template}"), &path); try_err!(file.flush(), &path); } diff --git a/src/librustdoc/json/mod.rs b/src/librustdoc/json/mod.rs index 7f82fb5c686..b7a683eed1c 100644 --- a/src/librustdoc/json/mod.rs +++ b/src/librustdoc/json/mod.rs @@ -286,7 +286,7 @@ impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> { self.serialize_and_write( output_crate, - BufWriter::new(try_err!(File::create(&p), p)), + try_err!(File::create_buffered(&p), p), &p.display().to_string(), ) } else { diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index dd75f4d7928..2be415e2e0e 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -5,6 +5,7 @@ #![feature(rustc_private)] #![feature(assert_matches)] #![feature(box_patterns)] +#![feature(file_buffered)] #![feature(if_let_guard)] #![feature(impl_trait_in_assoc_type)] #![feature(iter_intersperse)] From 458537ebc0e7d893103e03450f8830061bab1b2d Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Tue, 24 Sep 2024 15:06:55 -0700 Subject: [PATCH 228/683] Add a tracking issue for `file_buffered` --- library/std/src/fs.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs index b8e3f316beb..db7867337dd 100644 --- a/library/std/src/fs.rs +++ b/library/std/src/fs.rs @@ -405,7 +405,7 @@ impl File { /// Ok(()) /// } /// ``` - #[unstable(feature = "file_buffered", issue = "none")] + #[unstable(feature = "file_buffered", issue = "130804")] pub fn open_buffered>(path: P) -> io::Result> { // Allocate the buffer *first* so we don't affect the filesystem otherwise. let buffer = io::BufReader::::try_new_buffer()?; @@ -473,7 +473,7 @@ impl File { /// Ok(()) /// } /// ``` - #[unstable(feature = "file_buffered", issue = "none")] + #[unstable(feature = "file_buffered", issue = "130804")] pub fn create_buffered>(path: P) -> io::Result> { // Allocate the buffer *first* so we don't affect the filesystem otherwise. let buffer = io::BufWriter::::try_new_buffer()?; From 79a6e4eaa3cb48e0c75089840bd2b6859214aacd Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Tue, 24 Sep 2024 20:12:41 -0400 Subject: [PATCH 229/683] Add documentation for stdarch tests --- doc/debugging-gcc-lto.md | 3 --- doc/debugging.md | 38 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 3 deletions(-) delete mode 100644 doc/debugging-gcc-lto.md create mode 100644 doc/debugging.md diff --git a/doc/debugging-gcc-lto.md b/doc/debugging-gcc-lto.md deleted file mode 100644 index 93b150d7686..00000000000 --- a/doc/debugging-gcc-lto.md +++ /dev/null @@ -1,3 +0,0 @@ -# How to debug GCC LTO - -Run do the command with `-v -save-temps` and then extract the `lto1` line from the output and run that under the debugger. diff --git a/doc/debugging.md b/doc/debugging.md new file mode 100644 index 00000000000..6ff4edf8877 --- /dev/null +++ b/doc/debugging.md @@ -0,0 +1,38 @@ +# Debugging + +## How to debug GCC LTO + +Run do the command with `-v -save-temps` and then extract the `lto1` line from the output and run that under the debugger. + +## How to debug stdarch tests that cannot be ran locally + +First, run the tests normally: + +---- +cd build/build_sysroot/sysroot_src/library/stdarch/ +STDARCH_TEST_EVERYTHING=1 CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_RUNNER="sde -future -rtm_mode full --" TARGET=x86_64-unknown-linux-gnu ../../../../../y.sh cargo test +---- + +It will show the command it ran, something like this: + +---- + process didn't exit successfully: `sde -future -rtm_mode full -- /home/user/projects/rustc_codegen_gcc/build/build_sysroot/sysroot_src/library/stdarch/target/debug/deps/core_arch-fd2d75f89baae5c6` (signal: 11, SIGSEGV: invalid memory reference) +---- + +Then add the `-debug` flag to it: + +---- +sde -debug -future -rtm_mode full -- /home/user/projects/rustc_codegen_gcc/build/build_sysroot/sysroot_src/library/stdarch/target/debug/deps/core_arch-fd2d75f89baae5c6 +---- + +To see the symbols in `gdb`, specify the executable in your command: + +---- +gdb /home/user/projects/rustc_codegen_gcc/build/build_sysroot/sysroot_src/library/stdarch/target/debug/deps/core_arch-fd2d75f89baae5c6 +---- + +and then write the `gdb` command that `sde` tells you to use, something like: + +---- +target remote :51299 +---- From 7a966b918870485e9b364e77f50c511f8c2cc275 Mon Sep 17 00:00:00 2001 From: WANG Rui Date: Wed, 25 Sep 2024 10:23:59 +0800 Subject: [PATCH 230/683] Update llvm triple for OpenHarmony targets The `ohos` triple has been supported since LLVM 17, so it's time to update them. --- .../src/spec/targets/aarch64_unknown_linux_ohos.rs | 3 +-- .../rustc_target/src/spec/targets/armv7_unknown_linux_ohos.rs | 3 +-- .../src/spec/targets/loongarch64_unknown_linux_ohos.rs | 3 +-- .../rustc_target/src/spec/targets/x86_64_unknown_linux_ohos.rs | 3 +-- 4 files changed, 4 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_ohos.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_ohos.rs index 0942f5d896b..9d5bce05350 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_ohos.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_ohos.rs @@ -5,8 +5,7 @@ pub(crate) fn target() -> Target { base.max_atomic_width = Some(128); Target { - // LLVM 15 doesn't support OpenHarmony yet, use a linux target instead. - llvm_target: "aarch64-unknown-linux-musl".into(), + llvm_target: "aarch64-unknown-linux-ohos".into(), metadata: crate::spec::TargetMetadata { description: Some("ARM64 OpenHarmony".into()), tier: Some(2), diff --git a/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_ohos.rs b/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_ohos.rs index 04ea9e3468d..92b09bcc45c 100644 --- a/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_ohos.rs +++ b/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_ohos.rs @@ -7,8 +7,7 @@ pub(crate) fn target() -> Target { // Most of these settings are copied from the armv7_unknown_linux_musleabi // target. Target { - // LLVM 15 doesn't support OpenHarmony yet, use a linux target instead. - llvm_target: "armv7-unknown-linux-gnueabi".into(), + llvm_target: "armv7-unknown-linux-ohos".into(), metadata: crate::spec::TargetMetadata { description: Some("Armv7-A OpenHarmony".into()), tier: Some(2), diff --git a/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_ohos.rs b/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_ohos.rs index f9f7098684e..32a856be669 100644 --- a/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_ohos.rs +++ b/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_ohos.rs @@ -2,8 +2,7 @@ use crate::spec::{Target, TargetOptions, base}; pub(crate) fn target() -> Target { Target { - // LLVM 15 doesn't support OpenHarmony yet, use a linux target instead. - llvm_target: "loongarch64-unknown-linux-musl".into(), + llvm_target: "loongarch64-unknown-linux-ohos".into(), metadata: crate::spec::TargetMetadata { description: Some("LoongArch64 OpenHarmony".into()), tier: Some(3), diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_ohos.rs b/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_ohos.rs index e455aad5f51..522943c91a5 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_ohos.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_ohos.rs @@ -15,8 +15,7 @@ pub(crate) fn target() -> Target { base.supports_xray = true; Target { - // LLVM 15 doesn't support OpenHarmony yet, use a linux target instead. - llvm_target: "x86_64-unknown-linux-musl".into(), + llvm_target: "x86_64-unknown-linux-ohos".into(), metadata: crate::spec::TargetMetadata { description: Some("x86_64 OpenHarmony".into()), tier: Some(2), From 49d1c3b433d1ea53cc76a3822620f0591997bc4d Mon Sep 17 00:00:00 2001 From: kromych Date: Tue, 24 Sep 2024 19:52:14 -0700 Subject: [PATCH 231/683] Don't trap into the debugger on panics under Linux This breaks `rr`, see https://github.com/rust-lang/rust/pull/129019#issuecomment-2369361278 for the discussion CC @khuey @workingjubilee --- library/std/src/sys/dbg.rs | 79 +------------------------------------- 1 file changed, 1 insertion(+), 78 deletions(-) diff --git a/library/std/src/sys/dbg.rs b/library/std/src/sys/dbg.rs index 383ed84cfa2..7266a739e78 100644 --- a/library/std/src/sys/dbg.rs +++ b/library/std/src/sys/dbg.rs @@ -105,84 +105,7 @@ mod os { } } -#[cfg(target_os = "linux")] -mod os { - use super::DebuggerPresence; - use crate::fs::File; - use crate::io::Read; - - pub(super) fn is_debugger_present() -> Option { - // This function is crafted with the following goals: - // * Memory efficiency: It avoids crashing the panicking process due to - // out-of-memory (OOM) conditions by not using large heap buffers or - // allocating significant stack space, which could lead to stack overflow. - // * Minimal binary size: The function uses a minimal set of facilities - // from the standard library to avoid increasing the resulting binary size. - // - // To achieve these goals, the function does not use `[std::io::BufReader]` - // and instead reads the file byte by byte using a sliding window approach. - // It's important to note that the "/proc/self/status" pseudo-file is synthesized - // by the Virtual File System (VFS), meaning it is not read from a slow or - // non-volatile storage medium so buffering might not be as beneficial because - // all data is read from memory, though this approach does incur a syscall for - // each byte read. - // - // We cannot make assumptions about the file size or the position of the - // target prefix ("TracerPid:"), so the function does not use - // `[std::fs::read_to_string]` thus not employing UTF-8 to ASCII checking, - // conversion, or parsing as we're looking for an ASCII prefix. - // - // These condiderations make the function deviate from the familiar concise pattern - // of searching for a string in a text file. - - fn read_byte(file: &mut File) -> Option { - let mut buffer = [0]; - file.read_exact(&mut buffer).ok()?; - Some(buffer[0]) - } - - // The ASCII prefix of the datum we're interested in. - const TRACER_PID: &[u8] = b"TracerPid:\t"; - - let mut file = File::open("/proc/self/status").ok()?; - let mut matched = 0; - - // Look for the `TRACER_PID` prefix. - while let Some(byte) = read_byte(&mut file) { - if byte == TRACER_PID[matched] { - matched += 1; - if matched == TRACER_PID.len() { - break; - } - } else { - matched = 0; - } - } - - // Was the prefix found? - if matched != TRACER_PID.len() { - return None; - } - - // It was; get the ASCII representation of the first digit - // of the PID. That is enough to see if there is a debugger - // attached as the kernel does not pad the PID on the left - // with the leading zeroes. - let byte = read_byte(&mut file)?; - if byte.is_ascii_digit() && byte != b'0' { - Some(DebuggerPresence::Detected) - } else { - Some(DebuggerPresence::NotDetected) - } - } -} - -#[cfg(not(any( - target_os = "windows", - target_vendor = "apple", - target_os = "freebsd", - target_os = "linux" -)))] +#[cfg(not(any(target_os = "windows", target_vendor = "apple", target_os = "freebsd")))] mod os { pub(super) fn is_debugger_present() -> Option { None From 6d229f89ba9b828a0482b892eb87989a41c24af5 Mon Sep 17 00:00:00 2001 From: B I Mohammed Abbas Date: Wed, 25 Sep 2024 09:46:15 +0530 Subject: [PATCH 232/683] Vxworks riscv target specs: remove redundant zicsr feature --- compiler/rustc_target/src/spec/targets/riscv32_wrs_vxworks.rs | 4 ++-- compiler/rustc_target/src/spec/targets/riscv64_wrs_vxworks.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_target/src/spec/targets/riscv32_wrs_vxworks.rs b/compiler/rustc_target/src/spec/targets/riscv32_wrs_vxworks.rs index 5d4b7a3e946..4d3df78a563 100644 --- a/compiler/rustc_target/src/spec/targets/riscv32_wrs_vxworks.rs +++ b/compiler/rustc_target/src/spec/targets/riscv32_wrs_vxworks.rs @@ -1,4 +1,4 @@ -use crate::spec::{base, StackProbeType, Target, TargetOptions}; +use crate::spec::{StackProbeType, Target, TargetOptions, base}; pub(crate) fn target() -> Target { Target { @@ -16,7 +16,7 @@ pub(crate) fn target() -> Target { cpu: "generic-rv32".into(), llvm_abiname: "ilp32d".into(), max_atomic_width: Some(32), - features: "+m,+a,+f,+d,+c,+zicsr".into(), + features: "+m,+a,+f,+d,+c".into(), stack_probes: StackProbeType::Inline, ..base::vxworks::opts() }, diff --git a/compiler/rustc_target/src/spec/targets/riscv64_wrs_vxworks.rs b/compiler/rustc_target/src/spec/targets/riscv64_wrs_vxworks.rs index 5cddce29aa0..720549e6a01 100644 --- a/compiler/rustc_target/src/spec/targets/riscv64_wrs_vxworks.rs +++ b/compiler/rustc_target/src/spec/targets/riscv64_wrs_vxworks.rs @@ -1,4 +1,4 @@ -use crate::spec::{base, StackProbeType, Target, TargetOptions}; +use crate::spec::{StackProbeType, Target, TargetOptions, base}; pub(crate) fn target() -> Target { Target { @@ -16,7 +16,7 @@ pub(crate) fn target() -> Target { cpu: "generic-rv64".into(), llvm_abiname: "lp64d".into(), max_atomic_width: Some(64), - features: "+m,+a,+f,+d,+c,+zicsr".into(), + features: "+m,+a,+f,+d,+c".into(), stack_probes: StackProbeType::Inline, ..base::vxworks::opts() }, From f319ce73d7e657c11e39e74ac6db5035ca371a88 Mon Sep 17 00:00:00 2001 From: The Miri Cronjob Bot Date: Wed, 25 Sep 2024 05:06:18 +0000 Subject: [PATCH 233/683] Preparing for merge from rustc --- src/tools/miri/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index 76fe17316ac..79ed6cc7d74 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -6ce376774c0bc46ac8be247bca93ff5a1287a8fc +1b5aa96d6016bafe50e071b45d4d2e3c90fd766f From e057c1777685e6e80924b7dea3bed3098a8d1cf9 Mon Sep 17 00:00:00 2001 From: The Miri Cronjob Bot Date: Wed, 25 Sep 2024 05:15:00 +0000 Subject: [PATCH 234/683] fmt --- src/tools/miri/src/intrinsics/atomic.rs | 2 +- src/tools/miri/src/intrinsics/mod.rs | 2 +- src/tools/miri/src/shims/env.rs | 2 +- src/tools/miri/src/shims/foreign_items.rs | 2 +- src/tools/miri/src/shims/panic.rs | 2 +- src/tools/miri/src/shims/unix/fs.rs | 2 +- src/tools/miri/src/shims/unix/linux/foreign_items.rs | 8 ++++---- src/tools/miri/src/shims/unix/macos/foreign_items.rs | 3 ++- src/tools/miri/src/shims/windows/env.rs | 2 +- src/tools/miri/src/shims/windows/foreign_items.rs | 2 +- src/tools/miri/src/shims/windows/thread.rs | 2 +- src/tools/miri/src/shims/x86/mod.rs | 2 +- .../tests/fail/validity/wrong-dyn-trait-assoc-type.rs | 4 +++- 13 files changed, 19 insertions(+), 16 deletions(-) diff --git a/src/tools/miri/src/intrinsics/atomic.rs b/src/tools/miri/src/intrinsics/atomic.rs index 6365e0efd51..f38c3b82174 100644 --- a/src/tools/miri/src/intrinsics/atomic.rs +++ b/src/tools/miri/src/intrinsics/atomic.rs @@ -1,7 +1,7 @@ use rustc_middle::{mir, mir::BinOp, ty}; -use crate::*; use self::helpers::check_arg_count; +use crate::*; pub enum AtomicOp { /// The `bool` indicates whether the result of the operation should be negated (`UnOp::Not`, diff --git a/src/tools/miri/src/intrinsics/mod.rs b/src/tools/miri/src/intrinsics/mod.rs index b8352b575a4..d8d267f5ba6 100644 --- a/src/tools/miri/src/intrinsics/mod.rs +++ b/src/tools/miri/src/intrinsics/mod.rs @@ -12,10 +12,10 @@ use rustc_middle::{ use rustc_span::{Symbol, sym}; use rustc_target::abi::Size; -use crate::*; use self::atomic::EvalContextExt as _; use self::helpers::{ToHost, ToSoft, check_arg_count}; use self::simd::EvalContextExt as _; +use crate::*; impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {} pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { diff --git a/src/tools/miri/src/shims/env.rs b/src/tools/miri/src/shims/env.rs index 279df042dea..d12a0581b41 100644 --- a/src/tools/miri/src/shims/env.rs +++ b/src/tools/miri/src/shims/env.rs @@ -2,8 +2,8 @@ use std::ffi::{OsStr, OsString}; use rustc_data_structures::fx::FxHashMap; -use crate::*; use self::shims::{unix::UnixEnvVars, windows::WindowsEnvVars}; +use crate::*; #[derive(Default)] pub enum EnvVars<'tcx> { diff --git a/src/tools/miri/src/shims/foreign_items.rs b/src/tools/miri/src/shims/foreign_items.rs index 11cb9740e3e..c0484dde59b 100644 --- a/src/tools/miri/src/shims/foreign_items.rs +++ b/src/tools/miri/src/shims/foreign_items.rs @@ -12,10 +12,10 @@ use rustc_target::{ spec::abi::Abi, }; +use self::helpers::{ToHost, ToSoft}; use super::alloc::EvalContextExt as _; use super::backtrace::EvalContextExt as _; use crate::*; -use self::helpers::{ToHost, ToSoft}; /// Type of dynamic symbols (for `dlsym` et al) #[derive(Debug, Copy, Clone)] diff --git a/src/tools/miri/src/shims/panic.rs b/src/tools/miri/src/shims/panic.rs index 52c4394591c..55b814a09fa 100644 --- a/src/tools/miri/src/shims/panic.rs +++ b/src/tools/miri/src/shims/panic.rs @@ -16,8 +16,8 @@ use rustc_middle::{mir, ty}; use rustc_target::spec::PanicStrategy; use rustc_target::spec::abi::Abi; -use crate::*; use self::helpers::check_arg_count; +use crate::*; /// Holds all of the relevant data for when unwinding hits a `try` frame. #[derive(Debug)] diff --git a/src/tools/miri/src/shims/unix/fs.rs b/src/tools/miri/src/shims/unix/fs.rs index c90839138ce..1b657db5ccc 100644 --- a/src/tools/miri/src/shims/unix/fs.rs +++ b/src/tools/miri/src/shims/unix/fs.rs @@ -11,11 +11,11 @@ use std::time::SystemTime; use rustc_data_structures::fx::FxHashMap; use rustc_target::abi::Size; +use self::shims::time::system_time_to_duration; use crate::shims::os_str::bytes_to_os_str; use crate::shims::unix::fd::FileDescriptionRef; use crate::shims::unix::*; use crate::*; -use self::shims::time::system_time_to_duration; use self::fd::FlockOp; diff --git a/src/tools/miri/src/shims/unix/linux/foreign_items.rs b/src/tools/miri/src/shims/unix/linux/foreign_items.rs index 6418280d035..07527a9d6e3 100644 --- a/src/tools/miri/src/shims/unix/linux/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/linux/foreign_items.rs @@ -1,14 +1,14 @@ use rustc_span::Symbol; use rustc_target::spec::abi::Abi; -use crate::machine::SIGRTMAX; -use crate::machine::SIGRTMIN; -use crate::shims::unix::*; -use crate::*; use self::shims::unix::linux::epoll::EvalContextExt as _; use self::shims::unix::linux::eventfd::EvalContextExt as _; use self::shims::unix::linux::mem::EvalContextExt as _; use self::shims::unix::linux::sync::futex; +use crate::machine::SIGRTMAX; +use crate::machine::SIGRTMIN; +use crate::shims::unix::*; +use crate::*; pub fn is_dyn_sym(name: &str) -> bool { matches!(name, "statx") diff --git a/src/tools/miri/src/shims/unix/macos/foreign_items.rs b/src/tools/miri/src/shims/unix/macos/foreign_items.rs index 95a41752059..ce4ea0816f0 100644 --- a/src/tools/miri/src/shims/unix/macos/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/macos/foreign_items.rs @@ -80,7 +80,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Random data generation "CCRandomGenerateBytes" => { - let [bytes, count] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [bytes, count] = + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let bytes = this.read_pointer(bytes)?; let count = this.read_target_usize(count)?; let success = this.eval_libc_i32("kCCSuccess"); diff --git a/src/tools/miri/src/shims/windows/env.rs b/src/tools/miri/src/shims/windows/env.rs index 178b0a1a461..9707482b1e2 100644 --- a/src/tools/miri/src/shims/windows/env.rs +++ b/src/tools/miri/src/shims/windows/env.rs @@ -4,8 +4,8 @@ use std::io::ErrorKind; use rustc_data_structures::fx::FxHashMap; -use crate::*; use self::helpers::windows_check_buffer_size; +use crate::*; #[derive(Default)] pub struct WindowsEnvVars { diff --git a/src/tools/miri/src/shims/windows/foreign_items.rs b/src/tools/miri/src/shims/windows/foreign_items.rs index f385ed4ac11..998daddf520 100644 --- a/src/tools/miri/src/shims/windows/foreign_items.rs +++ b/src/tools/miri/src/shims/windows/foreign_items.rs @@ -8,10 +8,10 @@ use rustc_span::Symbol; use rustc_target::abi::{Align, Size}; use rustc_target::spec::abi::Abi; +use self::shims::windows::handle::{Handle, PseudoHandle}; use crate::shims::os_str::bytes_to_os_str; use crate::shims::windows::*; use crate::*; -use self::shims::windows::handle::{Handle, PseudoHandle}; pub fn is_dyn_sym(name: &str) -> bool { // std does dynamic detection for these symbols diff --git a/src/tools/miri/src/shims/windows/thread.rs b/src/tools/miri/src/shims/windows/thread.rs index 9f93fc5f081..a4c177311d4 100644 --- a/src/tools/miri/src/shims/windows/thread.rs +++ b/src/tools/miri/src/shims/windows/thread.rs @@ -1,8 +1,8 @@ use rustc_middle::ty::layout::LayoutOf; use rustc_target::spec::abi::Abi; -use crate::*; use self::shims::windows::handle::{EvalContextExt as _, Handle, PseudoHandle}; +use crate::*; impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {} diff --git a/src/tools/miri/src/shims/x86/mod.rs b/src/tools/miri/src/shims/x86/mod.rs index 9139156fd0e..211bd168af2 100644 --- a/src/tools/miri/src/shims/x86/mod.rs +++ b/src/tools/miri/src/shims/x86/mod.rs @@ -8,8 +8,8 @@ use rustc_span::Symbol; use rustc_target::abi::Size; use rustc_target::spec::abi::Abi; -use crate::*; use self::helpers::bool_to_simd_element; +use crate::*; mod aesni; mod avx; diff --git a/src/tools/miri/tests/fail/validity/wrong-dyn-trait-assoc-type.rs b/src/tools/miri/tests/fail/validity/wrong-dyn-trait-assoc-type.rs index 1478abedee0..566ddac2cc7 100644 --- a/src/tools/miri/tests/fail/validity/wrong-dyn-trait-assoc-type.rs +++ b/src/tools/miri/tests/fail/validity/wrong-dyn-trait-assoc-type.rs @@ -5,7 +5,9 @@ trait Trait { impl Trait for T { type Assoc = T; - fn foo(&self) -> T { *self } + fn foo(&self) -> T { + *self + } } fn main() { From cbe2ec05ac0be48f808464cc61ee108ac8315b9a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 25 Sep 2024 08:22:33 +0200 Subject: [PATCH 235/683] add test for std::random --- src/tools/miri/tests/pass/shims/random.rs | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 src/tools/miri/tests/pass/shims/random.rs diff --git a/src/tools/miri/tests/pass/shims/random.rs b/src/tools/miri/tests/pass/shims/random.rs new file mode 100644 index 00000000000..ae75ebdcd3f --- /dev/null +++ b/src/tools/miri/tests/pass/shims/random.rs @@ -0,0 +1,5 @@ +#![feature(random)] + +fn main() { + let _x: i32 = std::random::random(); +} From 1fe049ad57e4a60adce495ba7f1d592fdd0ec894 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 25 Sep 2024 08:25:36 +0200 Subject: [PATCH 236/683] add link from random() helper fn to extensive DefaultRandomSource docs --- library/std/src/random.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/std/src/random.rs b/library/std/src/random.rs index ecbf02eee84..604fa4df110 100644 --- a/library/std/src/random.rs +++ b/library/std/src/random.rs @@ -71,7 +71,8 @@ impl RandomSource for DefaultRandomSource { /// /// This is a convenience function for `T::random(&mut DefaultRandomSource)` and /// will sample according to the same distribution as the underlying [`Random`] -/// trait implementation. +/// trait implementation. See [`DefaultRandomSource`] for more information about +/// how randomness is sourced. /// /// **Warning:** Be careful when manipulating random values! The /// [`random`](Random::random) method on integers samples them with a uniform From 60265e456bdce6ca990968179c05f228d7f8669d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 25 Sep 2024 08:29:10 +0200 Subject: [PATCH 237/683] avoid using HashMap in fs test --- src/tools/miri/tests/pass/shims/fs.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/tools/miri/tests/pass/shims/fs.rs b/src/tools/miri/tests/pass/shims/fs.rs index 62424ca26b1..81151f4ac47 100644 --- a/src/tools/miri/tests/pass/shims/fs.rs +++ b/src/tools/miri/tests/pass/shims/fs.rs @@ -4,7 +4,7 @@ #![feature(io_error_more)] #![feature(io_error_uncategorized)] -use std::collections::HashMap; +use std::collections::BTreeMap; use std::ffi::OsString; use std::fs::{ File, OpenOptions, canonicalize, create_dir, read_dir, remove_dir, remove_dir_all, remove_file, @@ -262,7 +262,7 @@ fn test_directory() { create_dir(&dir_1).unwrap(); // Test that read_dir metadata calls succeed assert_eq!( - HashMap::from([ + BTreeMap::from([ (OsString::from("test_file_1"), true), (OsString::from("test_file_2"), true), (OsString::from("test_dir_1"), false) @@ -273,7 +273,7 @@ fn test_directory() { let e = e.unwrap(); (e.file_name(), e.metadata().unwrap().is_file()) }) - .collect::>() + .collect::>() ); // Deleting the directory should fail, since it is not empty. assert_eq!(ErrorKind::DirectoryNotEmpty, remove_dir(&dir_path).unwrap_err().kind()); From a374d1c5896bc06e8f059966710a98f261d3bc81 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 25 Sep 2024 08:30:26 +0200 Subject: [PATCH 238/683] update BASIC test list: no longer test HashMap, add libc-mem instead of 'align' for heap allocator coverage, move 'hello' to UNIX HashMap now needs pretty target-specific randomness functions. It still works on Android, but not on FreeBSD and Solarish. --- src/tools/miri/README.md | 2 +- src/tools/miri/ci/ci.sh | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/tools/miri/README.md b/src/tools/miri/README.md index d8636915ea8..f6349f45f43 100644 --- a/src/tools/miri/README.md +++ b/src/tools/miri/README.md @@ -219,7 +219,7 @@ degree documented below): - `solaris` / `illumos`: maintained by @devnexen. Supports `std::{env, thread, sync}`, but not `std::fs`. - `freebsd`: **maintainer wanted**. Supports `std::env` and parts of `std::{thread, fs}`, but not `std::sync`. - `android`: **maintainer wanted**. Support very incomplete, but a basic "hello world" works. - - `wasm`: **maintainer wanted**. Support very incomplete, not even standard output works, but an empty `main` function works. + - `wasi`: **maintainer wanted**. Support very incomplete, not even standard output works, but an empty `main` function works. - For targets on other operating systems, Miri might fail before even reaching the `main` function. However, even for targets that we do support, the degree of support for accessing platform APIs diff --git a/src/tools/miri/ci/ci.sh b/src/tools/miri/ci/ci.sh index c7be71662bd..251a5d63e15 100755 --- a/src/tools/miri/ci/ci.sh +++ b/src/tools/miri/ci/ci.sh @@ -148,15 +148,15 @@ case $HOST_TARGET in TEST_TARGET=arm-unknown-linux-gnueabi run_tests TEST_TARGET=s390x-unknown-linux-gnu run_tests # big-endian architecture of choice # Partially supported targets (tier 2) - BASIC="empty_main integer vec string btreemap hello hashmap heap_alloc align" # ensures we have the basics: stdout/stderr, system allocator, randomness (for HashMap initialization) - UNIX="panic/panic panic/unwind concurrency/simple atomic libc-mem libc-misc libc-random env num_cpus" # the things that are very similar across all Unixes, and hence easily supported there + BASIC="empty_main integer heap_alloc libc-mem vec string btreemap" # ensures we have the basics: pre-main code, system allocator + UNIX="hello panic/panic panic/unwind concurrency/simple atomic libc-mem libc-misc libc-random env num_cpus" # the things that are very similar across all Unixes, and hence easily supported there TEST_TARGET=x86_64-unknown-freebsd run_tests_minimal $BASIC $UNIX threadname pthread time fs TEST_TARGET=i686-unknown-freebsd run_tests_minimal $BASIC $UNIX threadname pthread time fs TEST_TARGET=x86_64-unknown-illumos run_tests_minimal $BASIC $UNIX thread sync available-parallelism time tls TEST_TARGET=x86_64-pc-solaris run_tests_minimal $BASIC $UNIX thread sync available-parallelism time tls - TEST_TARGET=aarch64-linux-android run_tests_minimal $BASIC $UNIX pthread --skip threadname --skip pthread_cond_timedwait - TEST_TARGET=wasm32-wasip2 run_tests_minimal empty_main wasm heap_alloc libc-mem - TEST_TARGET=wasm32-unknown-unknown run_tests_minimal empty_main wasm + TEST_TARGET=aarch64-linux-android run_tests_minimal $BASIC $UNIX hashmap pthread --skip threadname --skip pthread_cond_timedwait + TEST_TARGET=wasm32-wasip2 run_tests_minimal $BASIC wasm + TEST_TARGET=wasm32-unknown-unknown run_tests_minimal no_std empty_main wasm # this target doesn't really have std TEST_TARGET=thumbv7em-none-eabihf run_tests_minimal no_std # Custom target JSON file TEST_TARGET=tests/avr.json MIRI_NO_STD=1 run_tests_minimal no_std From 35bc50fc856862a7e74306d4842bbb313468f0ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Wed, 25 Sep 2024 10:41:24 +0300 Subject: [PATCH 239/683] Add missing rustc_private --- src/tools/rust-analyzer/crates/ide-assists/Cargo.toml | 3 +++ src/tools/rust-analyzer/crates/ide-assists/src/lib.rs | 2 ++ src/tools/rust-analyzer/crates/mbe/src/lib.rs | 2 ++ 3 files changed, 7 insertions(+) diff --git a/src/tools/rust-analyzer/crates/ide-assists/Cargo.toml b/src/tools/rust-analyzer/crates/ide-assists/Cargo.toml index df52562b6a1..2a14fbe1e0a 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/Cargo.toml +++ b/src/tools/rust-analyzer/crates/ide-assists/Cargo.toml @@ -34,5 +34,8 @@ expect-test = "1.4.0" test-utils.workspace = true test-fixture.workspace = true +[features] +in-rust-tree = [] + [lints] workspace = true diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs b/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs index b2ccd1fde81..c98655b4230 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs @@ -58,6 +58,8 @@ //! See also this post: //! +#![cfg_attr(feature = "in-rust-tree", feature(rustc_private))] + mod assist_config; mod assist_context; #[cfg(test)] diff --git a/src/tools/rust-analyzer/crates/mbe/src/lib.rs b/src/tools/rust-analyzer/crates/mbe/src/lib.rs index dd71e46db36..ca10a2be273 100644 --- a/src/tools/rust-analyzer/crates/mbe/src/lib.rs +++ b/src/tools/rust-analyzer/crates/mbe/src/lib.rs @@ -6,6 +6,8 @@ //! The tests for this functionality live in another crate: //! `hir_def::macro_expansion_tests::mbe`. +#![cfg_attr(feature = "in-rust-tree", feature(rustc_private))] + #[cfg(not(feature = "in-rust-tree"))] extern crate ra_ap_rustc_lexer as rustc_lexer; #[cfg(feature = "in-rust-tree")] From b466fa6db8db80bad78c8e4b2f7516525c493a6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Bj=C3=B8rnager=20Jensen?= Date: Wed, 25 Sep 2024 10:42:43 +0200 Subject: [PATCH 240/683] Add 'must_use' attribute to 'char::len_utf8' and 'char::len_utf16'; --- library/core/src/char/methods.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/library/core/src/char/methods.rs b/library/core/src/char/methods.rs index 3dcaab6a12b..55e67e5c255 100644 --- a/library/core/src/char/methods.rs +++ b/library/core/src/char/methods.rs @@ -606,6 +606,7 @@ impl char { #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_char_len_utf", since = "1.52.0")] #[inline] + #[must_use] pub const fn len_utf8(self) -> usize { len_utf8(self as u32) } @@ -637,6 +638,7 @@ impl char { #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_char_len_utf", since = "1.52.0")] #[inline] + #[must_use] pub const fn len_utf16(self) -> usize { len_utf16(self as u32) } @@ -1738,6 +1740,7 @@ impl EscapeDebugExtArgs { } #[inline] +#[must_use] const fn len_utf8(code: u32) -> usize { match code { ..MAX_ONE_B => 1, @@ -1748,6 +1751,7 @@ const fn len_utf8(code: u32) -> usize { } #[inline] +#[must_use] const fn len_utf16(code: u32) -> usize { if (code & 0xFFFF) == code { 1 } else { 2 } } From 986e20d5bb5df4274b390b4148aab0058081a241 Mon Sep 17 00:00:00 2001 From: Virginia Senioria <91khr@users.noreply.github.com> Date: Wed, 25 Sep 2024 07:34:53 +0000 Subject: [PATCH 241/683] Fixed diagnostics for coroutines with () as input. --- .../traits/fulfillment_errors.rs | 70 +++++++++---------- .../arg-count-mismatch-on-unit-input.rs | 11 +++ .../arg-count-mismatch-on-unit-input.stderr | 15 ++++ 3 files changed, 60 insertions(+), 36 deletions(-) create mode 100644 tests/ui/coroutine/arg-count-mismatch-on-unit-input.rs create mode 100644 tests/ui/coroutine/arg-count-mismatch-on-unit-input.stderr 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 19e2679ae4d..969f2528836 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 @@ -2635,49 +2635,47 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { // This shouldn't be common unless manually implementing one of the // traits manually, but don't make it more confusing when it does // happen. - Ok( - if Some(expected_trait_ref.def_id) != self.tcx.lang_items().coroutine_trait() - && not_tupled - { - self.report_and_explain_type_error( - TypeTrace::trait_refs( - &obligation.cause, - true, - expected_trait_ref, - found_trait_ref, - ), - ty::error::TypeError::Mismatch, - ) - } else if found.len() == expected.len() { - self.report_closure_arg_mismatch( - span, - found_span, - found_trait_ref, - expected_trait_ref, - obligation.cause.code(), - found_node, - obligation.param_env, - ) - } else { - let (closure_span, closure_arg_span, found) = found_did - .and_then(|did| { - let node = self.tcx.hir().get_if_local(did)?; - let (found_span, closure_arg_span, found) = - self.get_fn_like_arguments(node)?; - Some((Some(found_span), closure_arg_span, found)) - }) - .unwrap_or((found_span, None, found)); + if Some(expected_trait_ref.def_id) != self.tcx.lang_items().coroutine_trait() && not_tupled + { + return Ok(self.report_and_explain_type_error( + TypeTrace::trait_refs(&obligation.cause, true, expected_trait_ref, found_trait_ref), + ty::error::TypeError::Mismatch, + )); + } + if found.len() != expected.len() { + let (closure_span, closure_arg_span, found) = found_did + .and_then(|did| { + let node = self.tcx.hir().get_if_local(did)?; + let (found_span, closure_arg_span, found) = self.get_fn_like_arguments(node)?; + Some((Some(found_span), closure_arg_span, found)) + }) + .unwrap_or((found_span, None, found)); - self.report_arg_count_mismatch( + // If the coroutine take a single () as its argument, + // the trait argument would found the coroutine take 0 arguments, + // but get_fn_like_arguments would give 1 argument. + // This would result in "Expected to take 1 argument, but it takes 1 argument". + // Check again to avoid this. + if found.len() != expected.len() { + return Ok(self.report_arg_count_mismatch( span, closure_span, expected, found, found_trait_ty.is_closure(), closure_arg_span, - ) - }, - ) + )); + } + } + Ok(self.report_closure_arg_mismatch( + span, + found_span, + found_trait_ref, + expected_trait_ref, + obligation.cause.code(), + found_node, + obligation.param_env, + )) } /// Given some node representing a fn-like thing in the HIR map, diff --git a/tests/ui/coroutine/arg-count-mismatch-on-unit-input.rs b/tests/ui/coroutine/arg-count-mismatch-on-unit-input.rs new file mode 100644 index 00000000000..448c7100df6 --- /dev/null +++ b/tests/ui/coroutine/arg-count-mismatch-on-unit-input.rs @@ -0,0 +1,11 @@ +#![feature(coroutines, coroutine_trait, stmt_expr_attributes)] + +use std::ops::Coroutine; + +fn foo() -> impl Coroutine { + //~^ ERROR type mismatch in coroutine arguments + #[coroutine] + |_: ()| {} +} + +fn main() { } diff --git a/tests/ui/coroutine/arg-count-mismatch-on-unit-input.stderr b/tests/ui/coroutine/arg-count-mismatch-on-unit-input.stderr new file mode 100644 index 00000000000..c7d6507fd79 --- /dev/null +++ b/tests/ui/coroutine/arg-count-mismatch-on-unit-input.stderr @@ -0,0 +1,15 @@ +error[E0631]: type mismatch in coroutine arguments + --> $DIR/arg-count-mismatch-on-unit-input.rs:5:13 + | +LL | fn foo() -> impl Coroutine { + | ^^^^^^^^^^^^^^^^^^ expected due to this +... +LL | |_: ()| {} + | ------- found signature defined here + | + = note: expected coroutine signature `fn(u8) -> _` + found coroutine signature `fn(()) -> _` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0631`. From 94339583b89d4f04a2eae7a14e4fdf7c5a02347f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 25 Sep 2024 10:50:41 +0200 Subject: [PATCH 242/683] disable AVR test since it doesn't work --- src/tools/miri/ci/ci.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/tools/miri/ci/ci.sh b/src/tools/miri/ci/ci.sh index 251a5d63e15..2d4cf696d8c 100755 --- a/src/tools/miri/ci/ci.sh +++ b/src/tools/miri/ci/ci.sh @@ -159,7 +159,8 @@ case $HOST_TARGET in TEST_TARGET=wasm32-unknown-unknown run_tests_minimal no_std empty_main wasm # this target doesn't really have std TEST_TARGET=thumbv7em-none-eabihf run_tests_minimal no_std # Custom target JSON file - TEST_TARGET=tests/avr.json MIRI_NO_STD=1 run_tests_minimal no_std + # FIXME: disabled due to . + #TEST_TARGET=tests/avr.json MIRI_NO_STD=1 run_tests_minimal no_std ;; i686-pc-windows-msvc) # Host From b44888f7e981632381e395ed5660ddbff06b076f Mon Sep 17 00:00:00 2001 From: Yoh Deadfall Date: Tue, 24 Sep 2024 19:21:53 +0300 Subject: [PATCH 243/683] Android: Fixed tests for libc time API --- src/tools/miri/ci/ci.sh | 2 +- src/tools/miri/src/shims/time.rs | 4 +-- .../miri/tests/pass-dep/libc/libc-time.rs | 30 +++++++++++++++---- 3 files changed, 28 insertions(+), 8 deletions(-) diff --git a/src/tools/miri/ci/ci.sh b/src/tools/miri/ci/ci.sh index 2d4cf696d8c..fe0633135df 100755 --- a/src/tools/miri/ci/ci.sh +++ b/src/tools/miri/ci/ci.sh @@ -154,7 +154,7 @@ case $HOST_TARGET in TEST_TARGET=i686-unknown-freebsd run_tests_minimal $BASIC $UNIX threadname pthread time fs TEST_TARGET=x86_64-unknown-illumos run_tests_minimal $BASIC $UNIX thread sync available-parallelism time tls TEST_TARGET=x86_64-pc-solaris run_tests_minimal $BASIC $UNIX thread sync available-parallelism time tls - TEST_TARGET=aarch64-linux-android run_tests_minimal $BASIC $UNIX hashmap pthread --skip threadname --skip pthread_cond_timedwait + TEST_TARGET=aarch64-linux-android run_tests_minimal $BASIC $UNIX hashmap pthread time --skip threadname --skip pthread_cond_timedwait TEST_TARGET=wasm32-wasip2 run_tests_minimal $BASIC wasm TEST_TARGET=wasm32-unknown-unknown run_tests_minimal no_std empty_main wasm # this target doesn't really have std TEST_TARGET=thumbv7em-none-eabihf run_tests_minimal no_std diff --git a/src/tools/miri/src/shims/time.rs b/src/tools/miri/src/shims/time.rs index ebec1a70c5c..694c52b5465 100644 --- a/src/tools/miri/src/shims/time.rs +++ b/src/tools/miri/src/shims/time.rs @@ -36,8 +36,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let mut relative_clocks; match this.tcx.sess.target.os.as_ref() { - "linux" | "freebsd" => { - // Linux and FreeBSD have two main kinds of clocks. REALTIME clocks return the actual time since the + "linux" | "freebsd" | "android" => { + // Linux, Android, and FreeBSD have two main kinds of clocks. REALTIME clocks return the actual time since the // Unix epoch, including effects which may cause time to move backwards such as NTP. // Linux further distinguishes regular and "coarse" clocks, but the "coarse" version // is just specified to be "faster and less precise", so we implement both the same way. diff --git a/src/tools/miri/tests/pass-dep/libc/libc-time.rs b/src/tools/miri/tests/pass-dep/libc/libc-time.rs index c2c87586492..84dbd8ad768 100644 --- a/src/tools/miri/tests/pass-dep/libc/libc-time.rs +++ b/src/tools/miri/tests/pass-dep/libc/libc-time.rs @@ -15,7 +15,7 @@ fn test_clocks() { assert_eq!(is_error, 0); let is_error = unsafe { libc::clock_gettime(libc::CLOCK_MONOTONIC, tp.as_mut_ptr()) }; assert_eq!(is_error, 0); - #[cfg(any(target_os = "linux", target_os = "freebsd"))] + #[cfg(any(target_os = "linux", target_os = "freebsd", target_os = "android"))] { let is_error = unsafe { libc::clock_gettime(libc::CLOCK_REALTIME_COARSE, tp.as_mut_ptr()) }; assert_eq!(is_error, 0); @@ -63,9 +63,19 @@ fn test_localtime_r() { tm_wday: 0, tm_yday: 0, tm_isdst: 0, - #[cfg(any(target_os = "linux", target_os = "macos", target_os = "freebsd"))] + #[cfg(any( + target_os = "linux", + target_os = "macos", + target_os = "freebsd", + target_os = "android" + ))] tm_gmtoff: 0, - #[cfg(any(target_os = "linux", target_os = "macos", target_os = "freebsd"))] + #[cfg(any( + target_os = "linux", + target_os = "macos", + target_os = "freebsd", + target_os = "android" + ))] tm_zone: std::ptr::null_mut::(), }; let res = unsafe { libc::localtime_r(custom_time_ptr, &mut tm) }; @@ -79,9 +89,19 @@ fn test_localtime_r() { assert_eq!(tm.tm_wday, 0); assert_eq!(tm.tm_yday, 97); assert_eq!(tm.tm_isdst, -1); - #[cfg(any(target_os = "linux", target_os = "macos", target_os = "freebsd"))] + #[cfg(any( + target_os = "linux", + target_os = "macos", + target_os = "freebsd", + target_os = "android" + ))] assert_eq!(tm.tm_gmtoff, 0); - #[cfg(any(target_os = "linux", target_os = "macos", target_os = "freebsd"))] + #[cfg(any( + target_os = "linux", + target_os = "macos", + target_os = "freebsd", + target_os = "android" + ))] unsafe { assert_eq!(std::ffi::CStr::from_ptr(tm.tm_zone).to_str().unwrap(), "+00") }; From 701ccd3eadcf507a4e035668b45856c6f875fa83 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 16 Sep 2024 09:11:30 +1000 Subject: [PATCH 244/683] Remove `HirCollector::sess`. It's redundant w.r.t. `HirCollector::tcx`. This removes the unnecessary `'a` lifetime. --- src/librustdoc/doctest.rs | 1 - src/librustdoc/doctest/rust.rs | 17 +++++++---------- 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index 3ee6b24ac92..9ef203b4f12 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -186,7 +186,6 @@ pub(crate) fn run( let mut collector = CreateRunnableDocTests::new(options, opts); let hir_collector = HirCollector::new( - &compiler.sess, tcx.hir(), ErrorCodes::from(compiler.sess.opts.unstable_features.is_nightly_build()), enable_per_target_ignores, diff --git a/src/librustdoc/doctest/rust.rs b/src/librustdoc/doctest/rust.rs index cc85a73430b..7739790c310 100644 --- a/src/librustdoc/doctest/rust.rs +++ b/src/librustdoc/doctest/rust.rs @@ -10,7 +10,6 @@ use rustc_middle::hir::map::Map; use rustc_middle::hir::nested_filter; use rustc_middle::ty::TyCtxt; use rustc_resolve::rustdoc::span_of_fragments; -use rustc_session::Session; use rustc_span::source_map::SourceMap; use rustc_span::{BytePos, DUMMY_SP, FileName, Pos, Span}; @@ -63,8 +62,7 @@ impl DocTestVisitor for RustCollector { fn visit_header(&mut self, _name: &str, _level: u32) {} } -pub(super) struct HirCollector<'a, 'tcx> { - sess: &'a Session, +pub(super) struct HirCollector<'tcx> { map: Map<'tcx>, codes: ErrorCodes, tcx: TyCtxt<'tcx>, @@ -72,21 +70,20 @@ pub(super) struct HirCollector<'a, 'tcx> { collector: RustCollector, } -impl<'a, 'tcx> HirCollector<'a, 'tcx> { +impl<'tcx> HirCollector<'tcx> { pub fn new( - sess: &'a Session, map: Map<'tcx>, codes: ErrorCodes, enable_per_target_ignores: bool, tcx: TyCtxt<'tcx>, ) -> Self { let collector = RustCollector { - source_map: sess.psess.clone_source_map(), + source_map: tcx.sess.psess.clone_source_map(), cur_path: vec![], position: DUMMY_SP, tests: vec![], }; - Self { sess, map, codes, enable_per_target_ignores, tcx, collector } + Self { map, codes, enable_per_target_ignores, tcx, collector } } pub fn collect_crate(mut self) -> Vec { @@ -98,7 +95,7 @@ impl<'a, 'tcx> HirCollector<'a, 'tcx> { } } -impl<'a, 'tcx> HirCollector<'a, 'tcx> { +impl<'tcx> HirCollector<'tcx> { fn visit_testable( &mut self, name: String, @@ -108,7 +105,7 @@ impl<'a, 'tcx> HirCollector<'a, 'tcx> { ) { let ast_attrs = self.tcx.hir().attrs(self.tcx.local_def_id_to_hir_id(def_id)); if let Some(ref cfg) = ast_attrs.cfg(self.tcx, &FxHashSet::default()) { - if !cfg.matches(&self.sess.psess, Some(self.tcx.features())) { + if !cfg.matches(&self.tcx.sess.psess, Some(self.tcx.features())) { return; } } @@ -141,7 +138,7 @@ impl<'a, 'tcx> HirCollector<'a, 'tcx> { } } -impl<'a, 'tcx> intravisit::Visitor<'tcx> for HirCollector<'a, 'tcx> { +impl<'tcx> intravisit::Visitor<'tcx> for HirCollector<'tcx> { type NestedFilter = nested_filter::All; fn nested_visit_map(&mut self) -> Self::Map { From 711c91da7fa5882020c8d9f7a6edfa6d0b9c062f Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 16 Sep 2024 09:24:22 +1000 Subject: [PATCH 245/683] Remove `HirCollector::map`. Because `rustc_middle::hir::map::Map` is a trivial wrapper around `TyCtxt`, and `HirCollector` has a `TyCtxt` field. --- src/librustdoc/doctest.rs | 1 - src/librustdoc/doctest/rust.rs | 15 ++++----------- 2 files changed, 4 insertions(+), 12 deletions(-) diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index 9ef203b4f12..48272a41c93 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -186,7 +186,6 @@ pub(crate) fn run( let mut collector = CreateRunnableDocTests::new(options, opts); let hir_collector = HirCollector::new( - tcx.hir(), ErrorCodes::from(compiler.sess.opts.unstable_features.is_nightly_build()), enable_per_target_ignores, tcx, diff --git a/src/librustdoc/doctest/rust.rs b/src/librustdoc/doctest/rust.rs index 7739790c310..a9ab02e29cd 100644 --- a/src/librustdoc/doctest/rust.rs +++ b/src/librustdoc/doctest/rust.rs @@ -6,7 +6,6 @@ use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::sync::Lrc; use rustc_hir::def_id::{CRATE_DEF_ID, LocalDefId}; use rustc_hir::{self as hir, CRATE_HIR_ID, intravisit}; -use rustc_middle::hir::map::Map; use rustc_middle::hir::nested_filter; use rustc_middle::ty::TyCtxt; use rustc_resolve::rustdoc::span_of_fragments; @@ -63,7 +62,6 @@ impl DocTestVisitor for RustCollector { } pub(super) struct HirCollector<'tcx> { - map: Map<'tcx>, codes: ErrorCodes, tcx: TyCtxt<'tcx>, enable_per_target_ignores: bool, @@ -71,19 +69,14 @@ pub(super) struct HirCollector<'tcx> { } impl<'tcx> HirCollector<'tcx> { - pub fn new( - map: Map<'tcx>, - codes: ErrorCodes, - enable_per_target_ignores: bool, - tcx: TyCtxt<'tcx>, - ) -> Self { + pub fn new(codes: ErrorCodes, enable_per_target_ignores: bool, tcx: TyCtxt<'tcx>) -> Self { let collector = RustCollector { source_map: tcx.sess.psess.clone_source_map(), cur_path: vec![], position: DUMMY_SP, tests: vec![], }; - Self { map, codes, enable_per_target_ignores, tcx, collector } + Self { codes, enable_per_target_ignores, tcx, collector } } pub fn collect_crate(mut self) -> Vec { @@ -142,13 +135,13 @@ impl<'tcx> intravisit::Visitor<'tcx> for HirCollector<'tcx> { type NestedFilter = nested_filter::All; fn nested_visit_map(&mut self) -> Self::Map { - self.map + self.tcx.hir() } fn visit_item(&mut self, item: &'tcx hir::Item<'_>) { let name = match &item.kind { hir::ItemKind::Impl(impl_) => { - rustc_hir_pretty::id_to_string(&self.map, impl_.self_ty.hir_id) + rustc_hir_pretty::id_to_string(&self.tcx.hir(), impl_.self_ty.hir_id) } _ => item.ident.to_string(), }; From 0882ad57a5012be0bac72d2d37ea95bc32d901c6 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 16 Sep 2024 09:30:45 +1000 Subject: [PATCH 246/683] Rename `AstValidator::session` as `AstValidator::sess`. Because `sess` is the standard name used everywhere else. --- .../rustc_ast_passes/src/ast_validation.rs | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 229d04f8de2..5bdd9b6eda8 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -63,7 +63,7 @@ impl TraitOrTraitImpl { } struct AstValidator<'a> { - session: &'a Session, + sess: &'a Session, features: &'a Features, /// The span of the `extern` in an `extern { ... }` block, if any. @@ -267,7 +267,7 @@ impl<'a> AstValidator<'a> { } fn dcx(&self) -> DiagCtxtHandle<'a> { - self.session.dcx() + self.sess.dcx() } fn visibility_not_permitted(&self, vis: &Visibility, note: errors::VisibilityNotPermittedNote) { @@ -359,7 +359,7 @@ impl<'a> AstValidator<'a> { in_impl: matches!(parent, TraitOrTraitImpl::TraitImpl { .. }), const_context_label: parent_constness, remove_const_sugg: ( - self.session.source_map().span_extend_while_whitespace(span), + self.sess.source_map().span_extend_while_whitespace(span), match parent_constness { Some(_) => rustc_errors::Applicability::MachineApplicable, None => rustc_errors::Applicability::MaybeIncorrect, @@ -472,7 +472,7 @@ impl<'a> AstValidator<'a> { fn check_defaultness(&self, span: Span, defaultness: Defaultness) { if let Defaultness::Default(def_span) = defaultness { - let span = self.session.source_map().guess_head_span(span); + let span = self.sess.source_map().guess_head_span(span); self.dcx().emit_err(errors::ForbiddenDefault { span, def_span }); } } @@ -480,7 +480,7 @@ impl<'a> AstValidator<'a> { /// If `sp` ends with a semicolon, returns it as a `Span` /// Otherwise, returns `sp.shrink_to_hi()` fn ending_semi_or_hi(&self, sp: Span) -> Span { - let source_map = self.session.source_map(); + let source_map = self.sess.source_map(); let end = source_map.end_point(sp); if source_map.span_to_snippet(end).is_ok_and(|s| s == ";") { @@ -552,7 +552,7 @@ impl<'a> AstValidator<'a> { } fn current_extern_span(&self) -> Span { - self.session.source_map().guess_head_span(self.extern_mod.unwrap()) + self.sess.source_map().guess_head_span(self.extern_mod.unwrap()) } /// An `fn` in `extern { ... }` cannot have qualifiers, e.g. `async fn`. @@ -648,7 +648,7 @@ impl<'a> AstValidator<'a> { if ident.name.as_str().is_ascii() { return; } - let span = self.session.source_map().guess_head_span(item_span); + let span = self.sess.source_map().guess_head_span(item_span); self.dcx().emit_err(errors::NoMangleAscii { span }); } @@ -753,7 +753,7 @@ impl<'a> AstValidator<'a> { self.dcx().emit_err(errors::PatternFnPointer { span }); }); if let Extern::Implicit(_) = bfty.ext { - let sig_span = self.session.source_map().next_point(ty.span.shrink_to_lo()); + let sig_span = self.sess.source_map().next_point(ty.span.shrink_to_lo()); self.maybe_lint_missing_abi(sig_span, ty.id); } } @@ -795,7 +795,7 @@ impl<'a> AstValidator<'a> { // FIXME(davidtwco): This is a hack to detect macros which produce spans of the // call site which do not have a macro backtrace. See #61963. if self - .session + .sess .source_map() .span_to_snippet(span) .is_ok_and(|snippet| !snippet.starts_with("#[")) @@ -885,7 +885,7 @@ fn validate_generic_param_order(dcx: DiagCtxtHandle<'_>, generics: &[GenericPara impl<'a> Visitor<'a> for AstValidator<'a> { fn visit_attribute(&mut self, attr: &Attribute) { - validate_attr::check_attr(&self.session.psess, attr); + validate_attr::check_attr(&self.sess.psess, attr); } fn visit_ty(&mut self, ty: &'a Ty) { @@ -1192,7 +1192,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } else if where_clauses.after.has_where_token { self.dcx().emit_err(errors::WhereClauseAfterTypeAlias { span: where_clauses.after.span, - help: self.session.is_nightly_build(), + help: self.sess.is_nightly_build(), }); } } @@ -1328,7 +1328,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { (BoundKind::SuperTraits, BoundConstness::Never, BoundPolarity::Maybe(_)) if !self.features.more_maybe_bounds => { - self.session + self.sess .create_feature_err( errors::OptionalTraitSupertrait { span: trait_ref.span, @@ -1341,7 +1341,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { (BoundKind::TraitObject, BoundConstness::Never, BoundPolarity::Maybe(_)) if !self.features.more_maybe_bounds => { - self.session + self.sess .create_feature_err( errors::OptionalTraitObject { span: trait_ref.span }, sym::more_maybe_bounds, @@ -1752,13 +1752,13 @@ fn deny_equality_constraints( } pub fn check_crate( - session: &Session, + sess: &Session, features: &Features, krate: &Crate, lints: &mut LintBuffer, ) -> bool { let mut validator = AstValidator { - session, + sess, features, extern_mod: None, outer_trait_or_trait_impl: None, From 01a063f9df39fd7442874726afd8c9583987da44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Wed, 25 Sep 2024 10:38:40 +0200 Subject: [PATCH 247/683] Compiler: Rename "object safe" to "dyn compatible" --- .../rustc_const_eval/src/interpret/call.rs | 2 +- .../src/error_codes/E0038.md | 33 +++--- compiler/rustc_error_codes/src/lib.rs | 2 +- compiler/rustc_feature/src/unstable.rs | 5 +- compiler/rustc_hir_analysis/messages.ftl | 2 +- .../rustc_hir_analysis/src/check/wfcheck.rs | 11 +- .../rustc_hir_analysis/src/coherence/mod.rs | 7 +- .../src/coherence/orphan.rs | 10 +- ...{object_safety.rs => dyn_compatibility.rs} | 22 ++-- .../src/hir_ty_lowering/errors.rs | 14 +-- .../src/hir_ty_lowering/lint.rs | 22 ++-- .../src/hir_ty_lowering/mod.rs | 2 +- compiler/rustc_hir_typeck/src/coercion.rs | 2 +- .../rustc_hir_typeck/src/fn_ctxt/_impl.rs | 2 +- .../src/fn_ctxt/inspect_obligations.rs | 2 +- .../rustc_hir_typeck/src/method/confirm.rs | 2 +- compiler/rustc_hir_typeck/src/method/probe.rs | 4 +- compiler/rustc_interface/src/passes.rs | 2 +- compiler/rustc_lint/messages.ftl | 2 +- .../src/multiple_supertrait_upcastable.rs | 8 +- compiler/rustc_middle/src/arena.rs | 2 +- compiler/rustc_middle/src/query/mod.rs | 12 +- compiler/rustc_middle/src/traits/mod.rs | 104 +++++++++--------- compiler/rustc_middle/src/ty/context.rs | 4 +- compiler/rustc_middle/src/ty/flags.rs | 2 +- compiler/rustc_middle/src/ty/instance.rs | 2 +- compiler/rustc_middle/src/ty/predicate.rs | 8 +- compiler/rustc_middle/src/ty/print/pretty.rs | 4 +- compiler/rustc_middle/src/ty/util.rs | 2 +- compiler/rustc_monomorphize/src/collector.rs | 2 +- .../src/solve/assembly/mod.rs | 4 +- .../src/solve/eval_ctxt/mod.rs | 4 +- .../rustc_next_trait_solver/src/solve/mod.rs | 4 +- .../src/solve/trait_goals.rs | 4 +- .../cfi/typeid/itanium_cxx_abi/transform.rs | 4 +- .../rustc_smir/src/rustc_smir/convert/ty.rs | 4 +- .../traits/fulfillment_errors.rs | 16 +-- .../src/error_reporting/traits/mod.rs | 15 +-- .../src/solve/fulfill.rs | 2 +- .../src/traits/auto_trait.rs | 2 +- ...{object_safety.rs => dyn_compatibility.rs} | 78 +++++++------ .../src/traits/fulfill.rs | 6 +- .../rustc_trait_selection/src/traits/mod.rs | 12 +- .../query/type_op/implied_outlives_bounds.rs | 4 +- .../src/traits/select/candidate_assembly.rs | 2 +- .../src/traits/select/confirmation.rs | 10 +- .../src/traits/select/mod.rs | 4 +- .../rustc_trait_selection/src/traits/wf.rs | 2 +- .../src/normalize_erasing_regions.rs | 2 +- compiler/rustc_type_ir/src/interner.rs | 2 +- compiler/rustc_type_ir/src/predicate_kind.rs | 8 +- compiler/stable_mir/src/ty.rs | 2 +- src/librustdoc/clean/types.rs | 2 +- .../invalid_const_in_lifetime_position.stderr | 2 +- tests/rustdoc-ui/issues/issue-105742.stderr | 2 +- .../associated-const-in-trait.stderr | 4 +- tests/ui/associated-item/issue-48027.stderr | 2 +- .../suggest-assoc-ty-bound-on-eq-bound.stderr | 4 +- tests/ui/async-await/async-fn/dyn-pos.stderr | 8 +- .../async-await/in-trait/object-safety.stderr | 2 +- .../inference_var_self_argument.stderr | 2 +- ...ce-impl-trait-for-trait-object-safe.stderr | 2 +- .../const_param_ty_object_safety.stderr | 4 +- .../generic_const_exprs/issue-102768.stderr | 2 +- .../object-safety-err-ret.stderr | 4 +- .../object-safety-err-where-bounds.stderr | 4 +- .../not_wf_param_in_rpitit.stderr | 6 +- .../consts/const_refs_to_static-ice-121413.rs | 2 +- .../const_refs_to_static-ice-121413.stderr | 2 +- tests/ui/did_you_mean/bad-assoc-ty.stderr | 2 +- ...reference-without-parens-suggestion.stderr | 2 +- .../dyn-keyword/dyn-2018-edition-lint.stderr | 6 +- .../ui/dyn-keyword/dyn-angle-brackets.stderr | 2 +- tests/ui/error-codes/E0038.stderr | 4 +- ...dynless-turbofish-e0191-issue-91997.stderr | 2 +- ...gate-dispatch-from-dyn-missing-impl.stderr | 4 +- ...ature-gate-object_safe_for_dispatch.stderr | 10 +- ...t-in-trait-path-undeclared-lifetime.stderr | 2 +- .../gat-in-trait-path.base.stderr | 6 +- .../gat-trait-path-parenthesised-args.stderr | 4 +- .../issue-67510-pass.base.stderr | 2 +- .../issue-67510.stderr | 2 +- .../issue-71176.stderr | 4 +- .../issue-76535.base.stderr | 4 +- .../issue-78671.base.stderr | 2 +- .../issue-79422.base.stderr | 4 +- .../missing_lifetime_args.stderr | 2 +- ...it-path-type-error-once-implemented.stderr | 2 +- .../trait-objects.base.stderr | 6 +- .../trait-bounds/span-bug-issue-121597.stderr | 4 +- ...lifetime-from-bare-trait-obj-114664.stderr | 4 +- ...e-visibilities-during-object-safety.stderr | 6 +- .../in-trait/foreign-dyn-error.stderr | 2 +- .../impl-trait/in-trait/object-safety.stderr | 8 +- ...-trait-in-return-position-dyn-trait.stderr | 8 +- tests/ui/issues/issue-18959.stderr | 10 +- tests/ui/issues/issue-19380.stderr | 6 +- tests/ui/issues/issue-26056.stderr | 2 +- tests/ui/issues/issue-28344.stderr | 4 +- tests/ui/issues/issue-34373.stderr | 2 +- tests/ui/issues/issue-50781.stderr | 6 +- tests/ui/issues/issue-58734.stderr | 2 +- tests/ui/issues/issue-86756.stderr | 2 +- .../kindck-inherited-copy-bound.curr.stderr | 4 +- ...copy-bound.object_safe_for_dispatch.stderr | 2 +- tests/ui/lint/bare-trait-objects-path.stderr | 8 +- .../allowed-group-warn-by-default-lint.stderr | 2 +- .../ui/lint/force-warn/cap-lints-allow.stderr | 2 +- ...up-allowed-cli-warn-by-default-lint.stderr | 2 +- .../lint-group-allowed-lint-group.stderr | 2 +- ...-group-allowed-warn-by-default-lint.stderr | 2 +- .../almost-supertrait-associated-type.stderr | 6 +- .../assoc_type_bounds_sized_unnecessary.rs | 2 +- ...assoc_type_bounds_sized_unnecessary.stderr | 2 +- .../avoid-ice-on-warning-2.new.stderr | 2 +- .../avoid-ice-on-warning-2.old.stderr | 6 +- .../avoid-ice-on-warning-3.new.stderr | 4 +- .../avoid-ice-on-warning-3.old.stderr | 16 +-- .../avoid-ice-on-warning.old.stderr | 2 +- .../bare-trait-dont-suggest-dyn.new.stderr | 2 +- .../bare-trait-dont-suggest-dyn.old.stderr | 4 +- tests/ui/object-safety/issue-102762.stderr | 6 +- tests/ui/object-safety/issue-19538.stderr | 4 +- ...bject-safety-associated-consts.curr.stderr | 4 +- ...ted-consts.object_safe_for_dispatch.stderr | 2 +- .../object-safety/object-safety-bounds.stderr | 2 +- .../object-safety-generics.curr.stderr | 10 +- ...y-generics.object_safe_for_dispatch.stderr | 4 +- .../object-safety-issue-22040.stderr | 6 +- .../object-safety-mentions-Self.curr.stderr | 8 +- ...tions-Self.object_safe_for_dispatch.stderr | 4 +- .../object-safety-no-static.curr.stderr | 6 +- ...-no-static.object_safe_for_dispatch.stderr | 2 +- .../object-safety-sized-2.curr.stderr | 4 +- ...ty-sized-2.object_safe_for_dispatch.stderr | 2 +- .../object-safety-sized.curr.stderr | 4 +- ...fety-sized.object_safe_for_dispatch.stderr | 2 +- ...ject-safety-supertrait-mentions-GAT.stderr | 2 +- ...ect-safety-supertrait-mentions-Self.stderr | 2 +- .../parser/trait-object-trait-parens.stderr | 6 +- tests/ui/resolve/issue-3907-2.stderr | 2 +- ...ary-self-types-not-object-safe.curr.stderr | 4 +- ...bject-safe.object_safe_for_dispatch.stderr | 2 +- .../unsizing-wfcheck-issue-127299.stderr | 6 +- tests/ui/suggestions/issue-116434-2015.rs | 8 +- tests/ui/suggestions/issue-116434-2015.stderr | 12 +- tests/ui/suggestions/issue-116434-2021.stderr | 4 +- tests/ui/suggestions/issue-61963.stderr | 4 +- tests/ui/suggestions/issue-98500.stderr | 2 +- ...object-unsafe-trait-references-self.stderr | 4 +- ...it-should-use-self-2021-without-dyn.stderr | 18 +-- ...t-unsafe-trait-should-use-self-2021.stderr | 4 +- ...object-unsafe-trait-should-use-self.stderr | 4 +- ...unsafe-trait-should-use-where-sized.stderr | 2 +- .../suggest-swapping-self-ty-and-trait.stderr | 6 +- tests/ui/traits/alias/object-fail.stderr | 2 +- .../ui/traits/bound/not-on-bare-trait.stderr | 2 +- tests/ui/traits/issue-20692.stderr | 4 +- tests/ui/traits/issue-28576.stderr | 2 +- tests/ui/traits/issue-38404.stderr | 6 +- tests/ui/traits/issue-38604.stderr | 4 +- tests/ui/traits/issue-72410.stderr | 2 +- tests/ui/traits/issue-78372.stderr | 2 +- tests/ui/traits/item-privacy.stderr | 2 +- .../supertrait-object-safety.stderr | 6 +- ...alize-fresh-infer-vars-issue-103626.stderr | 2 +- tests/ui/traits/object/macro-matcher.stderr | 2 +- .../object-unsafe-missing-assoc-type.stderr | 8 +- tests/ui/traits/object/pretty.stderr | 2 +- tests/ui/traits/object/safety.stderr | 4 +- tests/ui/traits/test-2.stderr | 6 +- .../multiple_supertrait_upcastable.rs | 2 +- .../multiple_supertrait_upcastable.stderr | 2 +- .../unspecified-self-in-trait-ref.stderr | 10 +- ...ter-defaults-referencing-Self-ppaux.stderr | 2 +- ...ir-wf-check-anon-const-issue-122199.stderr | 18 +-- ...ir-wf-check-anon-const-issue-122989.stderr | 8 +- tests/ui/wf/issue-87495.stderr | 2 +- .../wf/wf-convert-unsafe-trait-obj-box.stderr | 6 +- .../ui/wf/wf-convert-unsafe-trait-obj.stderr | 6 +- tests/ui/wf/wf-fn-where-clause.stderr | 2 +- tests/ui/wf/wf-object-safe.stderr | 2 +- tests/ui/wf/wf-unsafe-trait-obj-match.stderr | 4 +- 183 files changed, 523 insertions(+), 510 deletions(-) rename compiler/rustc_hir_analysis/src/hir_ty_lowering/{object_safety.rs => dyn_compatibility.rs} (96%) rename compiler/rustc_trait_selection/src/traits/{object_safety.rs => dyn_compatibility.rs} (94%) diff --git a/compiler/rustc_const_eval/src/interpret/call.rs b/compiler/rustc_const_eval/src/interpret/call.rs index f5a0a2c0ee3..19aa76bf1ea 100644 --- a/compiler/rustc_const_eval/src/interpret/call.rs +++ b/compiler/rustc_const_eval/src/interpret/call.rs @@ -598,7 +598,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // codegen'd / interpreted as virtual calls through the vtable. ty::InstanceKind::Virtual(def_id, idx) => { let mut args = args.to_vec(); - // We have to implement all "object safe receivers". So we have to go search for a + // We have to implement all "dyn-compatible receivers". So we have to go search for a // pointer or `dyn Trait` type, but it could be wrapped in newtypes. So recursively // unwrap those newtypes until we are there. // An `InPlace` does nothing here, we keep the original receiver intact. We can't diff --git a/compiler/rustc_error_codes/src/error_codes/E0038.md b/compiler/rustc_error_codes/src/error_codes/E0038.md index 8f8eabb1519..014d8c4f761 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0038.md +++ b/compiler/rustc_error_codes/src/error_codes/E0038.md @@ -5,9 +5,9 @@ trait, written in type positions) but this was a bit too confusing, so we now write `dyn Trait`. Some traits are not allowed to be used as trait object types. The traits that -are allowed to be used as trait object types are called "object-safe" traits. -Attempting to use a trait object type for a trait that is not object-safe will -trigger error E0038. +are allowed to be used as trait object types are called "dyn-compatible"[^1] +traits. Attempting to use a trait object type for a trait that is not +dyn-compatible will trigger error E0038. Two general aspects of trait object types give rise to the restrictions: @@ -25,13 +25,16 @@ Two general aspects of trait object types give rise to the restrictions: objects with the same trait object type may point to vtables from different implementations. -The specific conditions that violate object-safety follow, most of which relate -to missing size information and vtable polymorphism arising from these aspects. +The specific conditions that violate dyn-compatibility follow, most of which +relate to missing size information and vtable polymorphism arising from these +aspects. + +[^1]: Formerly known as "object-safe". ### The trait requires `Self: Sized` Traits that are declared as `Trait: Sized` or which otherwise inherit a -constraint of `Self:Sized` are not object-safe. +constraint of `Self:Sized` are not dyn-compatible. The reasoning behind this is somewhat subtle. It derives from the fact that Rust requires (and defines) that every trait object type `dyn Trait` automatically @@ -58,7 +61,7 @@ implement a sized trait like `Trait:Sized`. So, rather than allow an exception to the rule that `dyn Trait` always implements `Trait`, Rust chooses to prohibit such a `dyn Trait` from existing at all. -Only unsized traits are considered object-safe. +Only unsized traits are considered dyn-compatible. Generally, `Self: Sized` is used to indicate that the trait should not be used as a trait object. If the trait comes from your own crate, consider removing @@ -103,8 +106,8 @@ fn call_foo(x: Box) { } ``` -If only some methods aren't object-safe, you can add a `where Self: Sized` bound -on them to mark them as explicitly unavailable to trait objects. The +If only some methods aren't dyn-compatible, you can add a `where Self: Sized` +bound on them to mark them as explicitly unavailable to trait objects. The functionality will still be available to all other implementers, including `Box` which is itself sized (assuming you `impl Trait for Box`). @@ -117,7 +120,7 @@ trait Trait { ``` Now, `foo()` can no longer be called on a trait object, but you will now be -allowed to make a trait object, and that will be able to call any object-safe +allowed to make a trait object, and that will be able to call any dyn-compatible methods. With such a bound, one can still call `foo()` on types implementing that trait that aren't behind trait objects. @@ -306,7 +309,7 @@ Here, the supertrait might have methods as follows: ``` trait Super { - fn get_a(&self) -> &A; // note that this is object safe! + fn get_a(&self) -> &A; // note that this is dyn-compatible! } ``` @@ -314,10 +317,10 @@ If the trait `Trait` was deriving from something like `Super` or `Super` (where `Foo` itself is `Foo`), this is okay, because given a type `get_a()` will definitely return an object of that type. -However, if it derives from `Super`, even though `Super` is object safe, -the method `get_a()` would return an object of unknown type when called on the -function. `Self` type parameters let us make object safe traits no longer safe, -so they are forbidden when specifying supertraits. +However, if it derives from `Super`, even though `Super` is +dyn-compatible, the method `get_a()` would return an object of unknown type when +called on the function. `Self` type parameters let us make dyn-compatible traits +no longer compatible, so they are forbidden when specifying supertraits. There's no easy fix for this. Generally, code will need to be refactored so that you no longer need to derive from `Super`. diff --git a/compiler/rustc_error_codes/src/lib.rs b/compiler/rustc_error_codes/src/lib.rs index 8631de65ec8..27a34d6003d 100644 --- a/compiler/rustc_error_codes/src/lib.rs +++ b/compiler/rustc_error_codes/src/lib.rs @@ -623,7 +623,7 @@ E0800: 0800, // E0314, // closure outlives stack frame // E0315, // cannot invoke closure outside of its lifetime // E0319, // trait impls for defaulted traits allowed just for structs/enums -// E0372, // coherence not object safe +// E0372, // coherence not dyn-compatible // E0385, // {} in an aliasable location // E0402, // cannot use an outer type parameter in this context // E0406, // merged into 420 diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 63b4b272f76..d304a52fbd5 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -548,9 +548,12 @@ declare_features! ( (unstable, non_exhaustive_omitted_patterns_lint, "1.57.0", Some(89554)), /// Allows `for` binders in where-clauses (incomplete, non_lifetime_binders, "1.69.0", Some(108185)), - /// Allows making `dyn Trait` well-formed even if `Trait` is not object safe. + /// Allows making `dyn Trait` well-formed even if `Trait` is not dyn-compatible[^1]. /// In that case, `dyn Trait: Trait` does not hold. Moreover, coercions and /// casts in safe Rust to `dyn Trait` for such a `Trait` is also forbidden. + /// + /// [^1]: Formerly known as "object safe". + // FIXME(dyn_compat_renaming): Rename feature. (unstable, object_safe_for_dispatch, "1.40.0", Some(43561)), /// Allows using enums in offset_of! (unstable, offset_of_enum, "1.75.0", Some(120141)), diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl index 09d466339ff..c73826c489f 100644 --- a/compiler/rustc_hir_analysis/messages.ftl +++ b/compiler/rustc_hir_analysis/messages.ftl @@ -558,7 +558,7 @@ hir_analysis_unrecognized_intrinsic_function = .help = if you're adding an intrinsic, be sure to update `check_intrinsic_type` hir_analysis_unused_associated_type_bounds = - unnecessary associated type bound for not object safe associated type + unnecessary associated type bound for dyn-incompatible associated type .note = this associated type has a `where Self: Sized` bound, and while the associated type can be specified, it cannot be used because trait objects are never `Sized` .suggestion = remove this bound diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index f8a19e93a41..a71e14ce463 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -374,7 +374,7 @@ fn check_trait_item<'tcx>( hir::TraitItemKind::Type(_bounds, Some(ty)) => (None, ty.span), _ => (None, trait_item.span), }; - check_object_unsafe_self_trait_by_name(tcx, trait_item); + check_dyn_incompatible_self_trait_by_name(tcx, trait_item); let mut res = check_associated_item(tcx, def_id, span, method_sig); if matches!(trait_item.kind, hir::TraitItemKind::Fn(..)) { @@ -838,9 +838,10 @@ fn could_be_self(trait_def_id: LocalDefId, ty: &hir::Ty<'_>) -> bool { } } -/// Detect when an object unsafe trait is referring to itself in one of its associated items. -/// When this is done, suggest using `Self` instead. -fn check_object_unsafe_self_trait_by_name(tcx: TyCtxt<'_>, item: &hir::TraitItem<'_>) { +/// Detect when a dyn-incompatible trait is referring to itself in one of its associated items. +/// +/// In such cases, suggest using `Self` instead. +fn check_dyn_incompatible_self_trait_by_name(tcx: TyCtxt<'_>, item: &hir::TraitItem<'_>) { let (trait_name, trait_def_id) = match tcx.hir_node_by_def_id(tcx.hir().get_parent_item(item.hir_id()).def_id) { hir::Node::Item(item) => match item.kind { @@ -872,7 +873,7 @@ fn check_object_unsafe_self_trait_by_name(tcx: TyCtxt<'_>, item: &hir::TraitItem _ => {} } if !trait_should_be_self.is_empty() { - if tcx.is_object_safe(trait_def_id) { + if tcx.is_dyn_compatible(trait_def_id) { return; } let sugg = trait_should_be_self.iter().map(|span| (*span, "Self".to_string())).collect(); diff --git a/compiler/rustc_hir_analysis/src/coherence/mod.rs b/compiler/rustc_hir_analysis/src/coherence/mod.rs index 185f3176f07..8c3c6875119 100644 --- a/compiler/rustc_hir_analysis/src/coherence/mod.rs +++ b/compiler/rustc_hir_analysis/src/coherence/mod.rs @@ -179,8 +179,8 @@ fn check_object_overlap<'tcx>( // check for overlap with the automatic `impl Trait for dyn Trait` if let ty::Dynamic(data, ..) = trait_ref.self_ty().kind() { - // This is something like impl Trait1 for Trait2. Illegal - // if Trait1 is a supertrait of Trait2 or Trait2 is not object safe. + // This is something like `impl Trait1 for Trait2`. Illegal if + // Trait1 is a supertrait of Trait2 or Trait2 is not dyn-compatible. let component_def_ids = data.iter().flat_map(|predicate| { match predicate.skip_binder() { @@ -193,7 +193,8 @@ fn check_object_overlap<'tcx>( }); for component_def_id in component_def_ids { - if !tcx.is_object_safe(component_def_id) { + if !tcx.is_dyn_compatible(component_def_id) { + // FIXME(dyn_compat_renaming): Rename test and update comment. // Without the 'object_safe_for_dispatch' feature this is an error // which will be reported by wfcheck. Ignore it here. // This is tested by `coherence-impl-trait-for-trait-object-safe.rs`. diff --git a/compiler/rustc_hir_analysis/src/coherence/orphan.rs b/compiler/rustc_hir_analysis/src/coherence/orphan.rs index 5fdaba41fb2..04770469132 100644 --- a/compiler/rustc_hir_analysis/src/coherence/orphan.rs +++ b/compiler/rustc_hir_analysis/src/coherence/orphan.rs @@ -109,16 +109,16 @@ pub(crate) fn orphan_check_impl( // // auto trait AutoTrait {} // - // trait ObjectSafeTrait { + // trait DynCompatibleTrait { // fn f(&self) where Self: AutoTrait; // } // - // We can allow f to be called on `dyn ObjectSafeTrait + AutoTrait`. + // We can allow f to be called on `dyn DynCompatibleTrait + AutoTrait`. // // If we didn't deny `impl AutoTrait for dyn Trait`, it would be unsound - // for the ObjectSafeTrait shown above to be object safe because someone - // could take some type implementing ObjectSafeTrait but not AutoTrait, - // unsize it to `dyn ObjectSafeTrait`, and call .f() which has no + // for the `DynCompatibleTrait` shown above to be dyn-compatible because someone + // could take some type implementing `DynCompatibleTrait` but not `AutoTrait`, + // unsize it to `dyn DynCompatibleTrait`, and call `.f()` which has no // concrete implementation (issue #50781). enum LocalImpl { Allow, diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/object_safety.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs similarity index 96% rename from compiler/rustc_hir_analysis/src/hir_ty_lowering/object_safety.rs rename to compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs index 87a240f626c..e7b8e6e69b0 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/object_safety.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs @@ -11,8 +11,8 @@ use rustc_middle::ty::{ self, DynKind, ExistentialPredicateStableCmpExt as _, Ty, TyCtxt, TypeFoldable, Upcast, }; use rustc_span::{ErrorGuaranteed, Span}; -use rustc_trait_selection::error_reporting::traits::report_object_safety_error; -use rustc_trait_selection::traits::{self, hir_ty_lowering_object_safety_violations}; +use rustc_trait_selection::error_reporting::traits::report_dyn_incompatibility; +use rustc_trait_selection::traits::{self, hir_ty_lowering_dyn_compatibility_violations}; use smallvec::{SmallVec, smallvec}; use tracing::{debug, instrument}; @@ -99,19 +99,19 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { return Ty::new_error(tcx, reported); } - // Check that there are no gross object safety violations; + // Check that there are no gross dyn-compatibility violations; // most importantly, that the supertraits don't contain `Self`, // to avoid ICEs. for item in ®ular_traits { - let object_safety_violations = - hir_ty_lowering_object_safety_violations(tcx, item.trait_ref().def_id()); - if !object_safety_violations.is_empty() { - let reported = report_object_safety_error( + let violations = + hir_ty_lowering_dyn_compatibility_violations(tcx, item.trait_ref().def_id()); + if !violations.is_empty() { + let reported = report_dyn_incompatibility( tcx, span, Some(hir_id), item.trait_ref().def_id(), - &object_safety_violations, + &violations, ) .emit(); return Ty::new_error(tcx, reported); @@ -275,8 +275,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { tcx.item_name(def_id), ) .with_note( - rustc_middle::traits::ObjectSafetyViolation::SupertraitSelf(smallvec![]) - .error_msg(), + rustc_middle::traits::DynCompatibilityViolation::SupertraitSelf( + smallvec![], + ) + .error_msg(), ) .emit(); } diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs index 5e3203e8473..eaecd6b9b61 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs @@ -19,9 +19,9 @@ use rustc_session::parse::feature_err; use rustc_span::edit_distance::find_best_match_for_name; use rustc_span::symbol::{Ident, kw, sym}; use rustc_span::{BytePos, DUMMY_SP, Span, Symbol}; -use rustc_trait_selection::error_reporting::traits::report_object_safety_error; +use rustc_trait_selection::error_reporting::traits::report_dyn_incompatibility; use rustc_trait_selection::traits::{ - FulfillmentError, TraitAliasExpansionInfo, object_safety_violations_for_assoc_item, + FulfillmentError, TraitAliasExpansionInfo, dyn_compatibility_violations_for_assoc_item, }; use crate::errors::{ @@ -739,7 +739,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { // Account for things like `dyn Foo + 'a`, like in tests `issue-22434.rs` and // `issue-22560.rs`. let mut trait_bound_spans: Vec = vec![]; - let mut object_safety_violations = false; + let mut dyn_compatibility_violations = false; for (span, items) in &associated_types { if !items.is_empty() { trait_bound_spans.push(*span); @@ -750,14 +750,14 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { names_len += 1; let violations = - object_safety_violations_for_assoc_item(tcx, trait_def_id, *assoc_item); + dyn_compatibility_violations_for_assoc_item(tcx, trait_def_id, *assoc_item); if !violations.is_empty() { - report_object_safety_error(tcx, *span, None, trait_def_id, &violations).emit(); - object_safety_violations = true; + report_dyn_incompatibility(tcx, *span, None, trait_def_id, &violations).emit(); + dyn_compatibility_violations = true; } } } - if object_safety_violations { + if dyn_compatibility_violations { return; } diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs index 1fbf70fa201..a70f881f5fe 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs @@ -77,7 +77,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { if self_ty.span.can_be_used_for_suggestions() && !self.maybe_suggest_impl_trait(self_ty, &mut diag) { - // FIXME: Only emit this suggestion if the trait is object safe. + // FIXME: Only emit this suggestion if the trait is dyn-compatible. diag.multipart_suggestion_verbose(label, sugg, Applicability::MachineApplicable); } // Check if the impl trait that we are considering is an impl of a local trait. @@ -89,7 +89,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { lint.primary_message("trait objects without an explicit `dyn` are deprecated"); if self_ty.span.can_be_used_for_suggestions() { lint.multipart_suggestion_verbose( - "if this is an object-safe trait, use `dyn`", + "if this is a dyn-compatible trait, use `dyn`", sugg, Applicability::MachineApplicable, ); @@ -196,7 +196,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let mut is_downgradable = true; // Check if trait object is safe for suggesting dynamic dispatch. - let is_object_safe = match self_ty.kind { + let is_dyn_compatible = match self_ty.kind { hir::TyKind::TraitObject(objects, ..) => { objects.iter().all(|(o, _)| match o.trait_ref.path.res { Res::Def(DefKind::Trait, id) => { @@ -204,7 +204,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { // For recursive traits, don't downgrade the error. (#119652) is_downgradable = false; } - tcx.is_object_safe(id) + tcx.is_dyn_compatible(id) } _ => false, }) @@ -221,8 +221,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { if let hir::FnRetTy::Return(ty) = sig.decl.output && ty.peel_refs().hir_id == self_ty.hir_id { - let pre = if !is_object_safe { - format!("`{trait_name}` is not object safe, ") + let pre = if !is_dyn_compatible { + format!("`{trait_name}` is dyn-incompatible, ") } else { String::new() }; @@ -234,7 +234,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { diag.multipart_suggestion_verbose(msg, impl_sugg, Applicability::MachineApplicable); // Suggest `Box` for return type - if is_object_safe { + if is_dyn_compatible { // If the return type is `&Trait`, we don't want // the ampersand to be displayed in the `Box` // suggestion. @@ -253,7 +253,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { Applicability::MachineApplicable, ); } else if is_downgradable { - // We'll emit the object safety error already, with a structured suggestion. + // We'll emit the dyn-compatibility error already, with a structured suggestion. diag.downgrade_to_delayed_bug(); } return true; @@ -276,10 +276,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { impl_sugg, Applicability::MachineApplicable, ); - if !is_object_safe { - diag.note(format!("`{trait_name}` it is not object safe, so it can't be `dyn`")); + if !is_dyn_compatible { + diag.note(format!("`{trait_name}` it is dyn-incompatible, so it can't be `dyn`")); if is_downgradable { - // We'll emit the object safety error already, with a structured suggestion. + // We'll emit the dyn-compatibility error already, with a structured suggestion. diag.downgrade_to_delayed_bug(); } } else { 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 e95b5142559..dfd2525c2b2 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -15,10 +15,10 @@ mod bounds; mod cmse; +mod dyn_compatibility; pub mod errors; pub mod generics; mod lint; -mod object_safety; use std::slice; diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index 7be91d78e19..2d4c7af4520 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -655,7 +655,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { return Err(TypeError::Mismatch); } - // Object safety violations or miscellaneous. + // Dyn-compatibility violations or miscellaneous. Err(err) => { self.err_ctxt().report_selection_error(obligation.clone(), &obligation, &err); // Treat this like an obligation and follow through diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index 2c469c0d52c..62107877283 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -757,7 +757,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // give us a `QPath::TypeRelative` with a trait object as // `qself`. In that case, we want to avoid registering a WF obligation // for `dyn MyTrait`, since we don't actually need the trait - // to be object-safe. + // to be dyn-compatible. // We manually call `register_wf_obligation` in the success path // below. let ty = self.lowerer().lower_ty(qself); diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs index 2dcab9ed004..2aad9a043f9 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs @@ -50,7 +50,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { | ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(..)) | ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(..)) | ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(..)) - | ty::PredicateKind::ObjectSafe(..) + | ty::PredicateKind::DynCompatible(..) | ty::PredicateKind::NormalizesTo(..) | ty::PredicateKind::AliasRelate(..) | ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..)) diff --git a/compiler/rustc_hir_typeck/src/method/confirm.rs b/compiler/rustc_hir_typeck/src/method/confirm.rs index e3b0fa78eb7..72842075fec 100644 --- a/compiler/rustc_hir_typeck/src/method/confirm.rs +++ b/compiler/rustc_hir_typeck/src/method/confirm.rs @@ -292,7 +292,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { // distinct types (e.g., if `Self` appeared as an // argument type), but those cases have already // been ruled out when we deemed the trait to be - // "object safe". + // "dyn-compatible". let original_poly_trait_ref = principal.with_self_ty(this.tcx, object_ty); let upcast_poly_trait_ref = this.upcast(original_poly_trait_ref, trait_def_id); let upcast_trait_ref = diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index 3828b40b885..c2e33c1bcd4 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -779,8 +779,8 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { }); // It is illegal to invoke a method on a trait instance that refers to - // the `Self` type. An [`ObjectSafetyViolation::SupertraitSelf`] error - // will be reported by `object_safety.rs` if the method refers to the + // the `Self` type. An [`DynCompatibilityViolation::SupertraitSelf`] error + // will be reported by `dyn_compatibility.rs` if the method refers to the // `Self` type anywhere other than the receiver. Here, we use a // instantiation that replaces `Self` with the object type itself. Hence, // a `&self` method will wind up with an argument type like `&dyn Trait`. diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 617581cf667..ce1e0ed2959 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -912,7 +912,7 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> { let traits = tcx.traits(LOCAL_CRATE); for &tr in traits { - if !tcx.is_object_safe(tr) { + if !tcx.is_dyn_compatible(tr) { continue; } diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index edfc7e547e5..fe1e93e415c 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -516,7 +516,7 @@ lint_mixed_script_confusables = .includes_note = the usage includes {$includes} .note = please recheck to make sure their usages are indeed what you want -lint_multiple_supertrait_upcastable = `{$ident}` is object-safe and has multiple supertraits +lint_multiple_supertrait_upcastable = `{$ident}` is dyn-compatible and has multiple supertraits lint_named_argument_used_positionally = named argument `{$named_arg_name}` is not used by name .label_named_arg = this named argument is referred to by position in formatting string diff --git a/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs b/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs index 78468020c4d..9fde35f82d8 100644 --- a/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs +++ b/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs @@ -4,7 +4,7 @@ use rustc_session::{declare_lint, declare_lint_pass}; use crate::{LateContext, LateLintPass, LintContext}; declare_lint! { - /// The `multiple_supertrait_upcastable` lint detects when an object-safe trait has multiple + /// The `multiple_supertrait_upcastable` lint detects when a dyn-compatible trait has multiple /// supertraits. /// /// ### Example @@ -28,7 +28,7 @@ declare_lint! { /// additional overhead is justified. pub MULTIPLE_SUPERTRAIT_UPCASTABLE, Allow, - "detect when an object-safe trait has multiple supertraits", + "detect when a dyn-compatible trait has multiple supertraits", @feature_gate = multiple_supertrait_upcastable; } @@ -37,10 +37,10 @@ declare_lint_pass!(MultipleSupertraitUpcastable => [MULTIPLE_SUPERTRAIT_UPCASTAB impl<'tcx> LateLintPass<'tcx> for MultipleSupertraitUpcastable { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) { let def_id = item.owner_id.to_def_id(); - // NOTE(nbdd0121): use `object_safety_violations` instead of `is_object_safe` because + // NOTE(nbdd0121): use `object_safety_violations` instead of `is_dyn_compatible` because // the latter will report `where_clause_object_safety` lint. if let hir::ItemKind::Trait(_, _, _, _, _) = item.kind - && cx.tcx.is_object_safe(def_id) + && cx.tcx.is_dyn_compatible(def_id) { let direct_super_traits_iter = cx .tcx diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs index 7050a06b8dc..52fe9956b47 100644 --- a/compiler/rustc_middle/src/arena.rs +++ b/compiler/rustc_middle/src/arena.rs @@ -83,7 +83,7 @@ macro_rules! arena_types { >, [] effective_visibilities: rustc_middle::middle::privacy::EffectiveVisibilities, [] upvars_mentioned: rustc_data_structures::fx::FxIndexMap, - [] object_safety_violations: rustc_middle::traits::ObjectSafetyViolation, + [] dyn_compatibility_violations: rustc_middle::traits::DynCompatibilityViolation, [] codegen_unit: rustc_middle::mir::mono::CodegenUnit<'tcx>, [decode] attribute: rustc_ast::Attribute, [] name_set: rustc_data_structures::unord::UnordSet, diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 00036097ef5..6eea5767095 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -70,8 +70,8 @@ use crate::traits::query::{ MethodAutoderefStepsResult, NoSolution, NormalizationResult, OutlivesBound, }; use crate::traits::{ - CodegenObligationError, EvaluationResult, ImplSource, ObjectSafetyViolation, ObligationCause, - OverflowError, WellFormedLoc, specialization_graph, + CodegenObligationError, DynCompatibilityViolation, EvaluationResult, ImplSource, + ObligationCause, OverflowError, WellFormedLoc, specialization_graph, }; use crate::ty::fast_reject::SimplifiedType; use crate::ty::layout::ValidityRequirement; @@ -1338,11 +1338,11 @@ rustc_queries! { cache_on_disk_if { true } ensure_forwards_result_if_red } - query object_safety_violations(trait_id: DefId) -> &'tcx [ObjectSafetyViolation] { - desc { |tcx| "determining object safety of trait `{}`", tcx.def_path_str(trait_id) } + query dyn_compatibility_violations(trait_id: DefId) -> &'tcx [DynCompatibilityViolation] { + desc { |tcx| "determining dyn-compatibility of trait `{}`", tcx.def_path_str(trait_id) } } - query is_object_safe(trait_id: DefId) -> bool { - desc { |tcx| "checking if trait `{}` is object safe", tcx.def_path_str(trait_id) } + query is_dyn_compatible(trait_id: DefId) -> bool { + desc { |tcx| "checking if trait `{}` is dyn-compatible", tcx.def_path_str(trait_id) } } /// Gets the ParameterEnvironment for a given item; this environment diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index c3295a9ce51..caa86da8a85 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -556,8 +556,8 @@ pub enum SelectionError<'tcx> { /// (which for closures includes the "input" type params) and they /// didn't resolve. See `confirm_poly_trait_refs` for more. SignatureMismatch(Box>), - /// The trait pointed by `DefId` is not object safe. - TraitNotObjectSafe(DefId), + /// The trait pointed by `DefId` is dyn-incompatible. + TraitDynIncompatible(DefId), /// A given constant couldn't be evaluated. NotConstEvaluatable(NotConstEvaluatable), /// Exceeded the recursion depth during type projection. @@ -690,7 +690,7 @@ pub struct ImplSourceUserDefinedData<'tcx, N> { } #[derive(Clone, Debug, PartialEq, Eq, Hash, HashStable, PartialOrd, Ord)] -pub enum ObjectSafetyViolation { +pub enum DynCompatibilityViolation { /// `Self: Sized` declared on the trait. SizedSelf(SmallVec<[Span; 1]>), @@ -711,11 +711,11 @@ pub enum ObjectSafetyViolation { GAT(Symbol, Span), } -impl ObjectSafetyViolation { +impl DynCompatibilityViolation { pub fn error_msg(&self) -> Cow<'static, str> { match self { - ObjectSafetyViolation::SizedSelf(_) => "it requires `Self: Sized`".into(), - ObjectSafetyViolation::SupertraitSelf(ref spans) => { + DynCompatibilityViolation::SizedSelf(_) => "it requires `Self: Sized`".into(), + DynCompatibilityViolation::SupertraitSelf(ref spans) => { if spans.iter().any(|sp| *sp != DUMMY_SP) { "it uses `Self` as a type parameter".into() } else { @@ -723,81 +723,87 @@ impl ObjectSafetyViolation { .into() } } - ObjectSafetyViolation::SupertraitNonLifetimeBinder(_) => { + DynCompatibilityViolation::SupertraitNonLifetimeBinder(_) => { "where clause cannot reference non-lifetime `for<...>` variables".into() } - ObjectSafetyViolation::Method(name, MethodViolationCode::StaticMethod(_), _) => { + DynCompatibilityViolation::Method(name, MethodViolationCode::StaticMethod(_), _) => { format!("associated function `{name}` has no `self` parameter").into() } - ObjectSafetyViolation::Method( + DynCompatibilityViolation::Method( name, MethodViolationCode::ReferencesSelfInput(_), DUMMY_SP, ) => format!("method `{name}` references the `Self` type in its parameters").into(), - ObjectSafetyViolation::Method(name, MethodViolationCode::ReferencesSelfInput(_), _) => { - format!("method `{name}` references the `Self` type in this parameter").into() - } - ObjectSafetyViolation::Method(name, MethodViolationCode::ReferencesSelfOutput, _) => { - format!("method `{name}` references the `Self` type in its return type").into() - } - ObjectSafetyViolation::Method( + DynCompatibilityViolation::Method( + name, + MethodViolationCode::ReferencesSelfInput(_), + _, + ) => format!("method `{name}` references the `Self` type in this parameter").into(), + DynCompatibilityViolation::Method( + name, + MethodViolationCode::ReferencesSelfOutput, + _, + ) => format!("method `{name}` references the `Self` type in its return type").into(), + DynCompatibilityViolation::Method( name, MethodViolationCode::ReferencesImplTraitInTrait(_), _, ) => { format!("method `{name}` references an `impl Trait` type in its return type").into() } - ObjectSafetyViolation::Method(name, MethodViolationCode::AsyncFn, _) => { + DynCompatibilityViolation::Method(name, MethodViolationCode::AsyncFn, _) => { format!("method `{name}` is `async`").into() } - ObjectSafetyViolation::Method( + DynCompatibilityViolation::Method( name, MethodViolationCode::WhereClauseReferencesSelf, _, ) => format!("method `{name}` references the `Self` type in its `where` clause").into(), - ObjectSafetyViolation::Method(name, MethodViolationCode::Generic, _) => { + DynCompatibilityViolation::Method(name, MethodViolationCode::Generic, _) => { format!("method `{name}` has generic type parameters").into() } - ObjectSafetyViolation::Method( + DynCompatibilityViolation::Method( name, MethodViolationCode::UndispatchableReceiver(_), _, ) => format!("method `{name}`'s `self` parameter cannot be dispatched on").into(), - ObjectSafetyViolation::AssocConst(name, DUMMY_SP) => { + DynCompatibilityViolation::AssocConst(name, DUMMY_SP) => { format!("it contains associated `const` `{name}`").into() } - ObjectSafetyViolation::AssocConst(..) => "it contains this associated `const`".into(), - ObjectSafetyViolation::GAT(name, _) => { + DynCompatibilityViolation::AssocConst(..) => { + "it contains this associated `const`".into() + } + DynCompatibilityViolation::GAT(name, _) => { format!("it contains the generic associated type `{name}`").into() } } } - pub fn solution(&self) -> ObjectSafetyViolationSolution { + pub fn solution(&self) -> DynCompatibilityViolationSolution { match self { - ObjectSafetyViolation::SizedSelf(_) - | ObjectSafetyViolation::SupertraitSelf(_) - | ObjectSafetyViolation::SupertraitNonLifetimeBinder(..) => { - ObjectSafetyViolationSolution::None + DynCompatibilityViolation::SizedSelf(_) + | DynCompatibilityViolation::SupertraitSelf(_) + | DynCompatibilityViolation::SupertraitNonLifetimeBinder(..) => { + DynCompatibilityViolationSolution::None } - ObjectSafetyViolation::Method( + DynCompatibilityViolation::Method( name, MethodViolationCode::StaticMethod(Some((add_self_sugg, make_sized_sugg))), _, - ) => ObjectSafetyViolationSolution::AddSelfOrMakeSized { + ) => DynCompatibilityViolationSolution::AddSelfOrMakeSized { name: *name, add_self_sugg: add_self_sugg.clone(), make_sized_sugg: make_sized_sugg.clone(), }, - ObjectSafetyViolation::Method( + DynCompatibilityViolation::Method( name, MethodViolationCode::UndispatchableReceiver(Some(span)), _, - ) => ObjectSafetyViolationSolution::ChangeToRefSelf(*name, *span), - ObjectSafetyViolation::AssocConst(name, _) - | ObjectSafetyViolation::GAT(name, _) - | ObjectSafetyViolation::Method(name, ..) => { - ObjectSafetyViolationSolution::MoveToAnotherTrait(*name) + ) => DynCompatibilityViolationSolution::ChangeToRefSelf(*name, *span), + DynCompatibilityViolation::AssocConst(name, _) + | DynCompatibilityViolation::GAT(name, _) + | DynCompatibilityViolation::Method(name, ..) => { + DynCompatibilityViolationSolution::MoveToAnotherTrait(*name) } } } @@ -806,12 +812,12 @@ impl ObjectSafetyViolation { // When `span` comes from a separate crate, it'll be `DUMMY_SP`. Treat it as `None` so // diagnostics use a `note` instead of a `span_label`. match self { - ObjectSafetyViolation::SupertraitSelf(spans) - | ObjectSafetyViolation::SizedSelf(spans) - | ObjectSafetyViolation::SupertraitNonLifetimeBinder(spans) => spans.clone(), - ObjectSafetyViolation::AssocConst(_, span) - | ObjectSafetyViolation::GAT(_, span) - | ObjectSafetyViolation::Method(_, _, span) + DynCompatibilityViolation::SupertraitSelf(spans) + | DynCompatibilityViolation::SizedSelf(spans) + | DynCompatibilityViolation::SupertraitNonLifetimeBinder(spans) => spans.clone(), + DynCompatibilityViolation::AssocConst(_, span) + | DynCompatibilityViolation::GAT(_, span) + | DynCompatibilityViolation::Method(_, _, span) if *span != DUMMY_SP => { smallvec![*span] @@ -822,7 +828,7 @@ impl ObjectSafetyViolation { } #[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -pub enum ObjectSafetyViolationSolution { +pub enum DynCompatibilityViolationSolution { None, AddSelfOrMakeSized { name: Symbol, @@ -833,11 +839,11 @@ pub enum ObjectSafetyViolationSolution { MoveToAnotherTrait(Symbol), } -impl ObjectSafetyViolationSolution { +impl DynCompatibilityViolationSolution { pub fn add_to(self, err: &mut Diag<'_, G>) { match self { - ObjectSafetyViolationSolution::None => {} - ObjectSafetyViolationSolution::AddSelfOrMakeSized { + DynCompatibilityViolationSolution::None => {} + DynCompatibilityViolationSolution::AddSelfOrMakeSized { name, add_self_sugg, make_sized_sugg, @@ -860,7 +866,7 @@ impl ObjectSafetyViolationSolution { Applicability::MaybeIncorrect, ); } - ObjectSafetyViolationSolution::ChangeToRefSelf(name, span) => { + DynCompatibilityViolationSolution::ChangeToRefSelf(name, span) => { err.span_suggestion( span, format!("consider changing method `{name}`'s `self` parameter to be `&self`"), @@ -868,14 +874,14 @@ impl ObjectSafetyViolationSolution { Applicability::MachineApplicable, ); } - ObjectSafetyViolationSolution::MoveToAnotherTrait(name) => { + DynCompatibilityViolationSolution::MoveToAnotherTrait(name) => { err.help(format!("consider moving `{name}` to another trait")); } } } } -/// Reasons a method might not be object-safe. +/// Reasons a method might not be dyn-compatible. #[derive(Clone, Debug, PartialEq, Eq, Hash, HashStable, PartialOrd, Ord)] pub enum MethodViolationCode { /// e.g., `fn foo()` diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index f017216489d..df60950a6b2 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -527,8 +527,8 @@ impl<'tcx> Interner for TyCtxt<'tcx> { self.trait_is_alias(trait_def_id) } - fn trait_is_object_safe(self, trait_def_id: DefId) -> bool { - self.is_object_safe(trait_def_id) + fn trait_is_dyn_compatible(self, trait_def_id: DefId) -> bool { + self.is_dyn_compatible(trait_def_id) } fn trait_is_fundamental(self, def_id: DefId) -> bool { diff --git a/compiler/rustc_middle/src/ty/flags.rs b/compiler/rustc_middle/src/ty/flags.rs index fc079592583..92a975c028e 100644 --- a/compiler/rustc_middle/src/ty/flags.rs +++ b/compiler/rustc_middle/src/ty/flags.rs @@ -301,7 +301,7 @@ impl FlagComputation { ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(arg)) => { self.add_args(slice::from_ref(&arg)); } - ty::PredicateKind::ObjectSafe(_def_id) => {} + ty::PredicateKind::DynCompatible(_def_id) => {} ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(uv)) => { self.add_const(uv); } diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index bfef4c4c8c6..b1c5ff50fdc 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -50,7 +50,7 @@ pub enum ReifyReason { /// * A vtable entry is directly converted to a function call (e.g. creating a fn ptr from a /// method on a `dyn` object). /// * A function with `#[track_caller]` is converted to a function pointer - /// * If KCFI is enabled, creating a function pointer from a method on an object-safe trait. + /// * If KCFI is enabled, creating a function pointer from a method on a dyn-compatible trait. /// This includes the case of converting `::call`-like methods on closure-likes to function /// pointers. FnPtr, diff --git a/compiler/rustc_middle/src/ty/predicate.rs b/compiler/rustc_middle/src/ty/predicate.rs index 534a8c99c5a..fd4e8f1cd4e 100644 --- a/compiler/rustc_middle/src/ty/predicate.rs +++ b/compiler/rustc_middle/src/ty/predicate.rs @@ -36,7 +36,7 @@ pub type PolyProjectionPredicate<'tcx> = ty::Binder<'tcx, ProjectionPredicate<'t /// A statement that can be proven by a trait solver. This includes things that may /// show up in where clauses, such as trait predicates and projection predicates, -/// and also things that are emitted as part of type checking such as `ObjectSafe` +/// and also things that are emitted as part of type checking such as `DynCompatible` /// predicate which is emitted when a type is coerced to a trait object. /// /// Use this rather than `PredicateKind`, whenever possible. @@ -147,7 +147,7 @@ impl<'tcx> Predicate<'tcx> { | PredicateKind::Clause(ClauseKind::TypeOutlives(_)) | PredicateKind::Clause(ClauseKind::Projection(_)) | PredicateKind::Clause(ClauseKind::ConstArgHasType(..)) - | PredicateKind::ObjectSafe(_) + | PredicateKind::DynCompatible(_) | PredicateKind::Subtype(_) | PredicateKind::Coerce(_) | PredicateKind::Clause(ClauseKind::ConstEvaluatable(_)) @@ -647,7 +647,7 @@ impl<'tcx> Predicate<'tcx> { | PredicateKind::Coerce(..) | PredicateKind::Clause(ClauseKind::RegionOutlives(..)) | PredicateKind::Clause(ClauseKind::WellFormed(..)) - | PredicateKind::ObjectSafe(..) + | PredicateKind::DynCompatible(..) | PredicateKind::Clause(ClauseKind::TypeOutlives(..)) | PredicateKind::Clause(ClauseKind::ConstEvaluatable(..)) | PredicateKind::ConstEquate(..) @@ -667,7 +667,7 @@ impl<'tcx> Predicate<'tcx> { | PredicateKind::Coerce(..) | PredicateKind::Clause(ClauseKind::RegionOutlives(..)) | PredicateKind::Clause(ClauseKind::WellFormed(..)) - | PredicateKind::ObjectSafe(..) + | PredicateKind::DynCompatible(..) | PredicateKind::Clause(ClauseKind::TypeOutlives(..)) | PredicateKind::Clause(ClauseKind::ConstEvaluatable(..)) | PredicateKind::ConstEquate(..) diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 5b4ee2791f8..8fd4c30457f 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -3088,8 +3088,8 @@ define_print! { } ty::PredicateKind::Subtype(predicate) => p!(print(predicate)), ty::PredicateKind::Coerce(predicate) => p!(print(predicate)), - ty::PredicateKind::ObjectSafe(trait_def_id) => { - p!("the trait `", print_def_path(trait_def_id, &[]), "` is object-safe") + ty::PredicateKind::DynCompatible(trait_def_id) => { + p!("the trait `", print_def_path(trait_def_id, &[]), "` is dyn-compatible") } ty::PredicateKind::ConstEquate(c1, c2) => { p!("the constant `", print(c1), "` equals `", print(c2), "`") diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index 321b51289fb..0a917120b3b 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -1602,7 +1602,7 @@ impl<'tcx> ExplicitSelf<'tcx> { /// `Other`. /// This is mainly used to require the arbitrary_self_types feature /// in the case of `Other`, to improve error messages in the common cases, - /// and to make `Other` non-object-safe. + /// and to make `Other` dyn-incompatible. /// /// Examples: /// diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 0cdd237dc00..d21bbce2ae2 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -120,7 +120,7 @@ //! #### Unsizing Casts //! A subtle way of introducing use edges is by casting to a trait object. //! Since the resulting fat-pointer contains a reference to a vtable, we need to -//! instantiate all object-safe methods of the trait, as we need to store +//! instantiate all dyn-compatible methods of the trait, as we need to store //! pointers to these functions even if they never get called anywhere. This can //! be seen as a special case of taking a function reference. //! diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs index 520afbeb645..cebeef76bfc 100644 --- a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs @@ -639,8 +639,8 @@ where ty::Dynamic(bounds, ..) => bounds, }; - // Do not consider built-in object impls for non-object-safe types. - if bounds.principal_def_id().is_some_and(|def_id| !cx.trait_is_object_safe(def_id)) { + // Do not consider built-in object impls for dyn-incompatible types. + if bounds.principal_def_id().is_some_and(|def_id| !cx.trait_is_dyn_compatible(def_id)) { return; } diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs index 12ad0724b5c..270d50b5af4 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs @@ -423,8 +423,8 @@ where ty::PredicateKind::Coerce(predicate) => { self.compute_coerce_goal(Goal { param_env, predicate }) } - ty::PredicateKind::ObjectSafe(trait_def_id) => { - self.compute_object_safe_goal(trait_def_id) + ty::PredicateKind::DynCompatible(trait_def_id) => { + self.compute_dyn_compatible_goal(trait_def_id) } ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(arg)) => { self.compute_well_formed_goal(Goal { param_env, predicate: arg }) diff --git a/compiler/rustc_next_trait_solver/src/solve/mod.rs b/compiler/rustc_next_trait_solver/src/solve/mod.rs index 536b502136a..309ab7f28d1 100644 --- a/compiler/rustc_next_trait_solver/src/solve/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/mod.rs @@ -111,8 +111,8 @@ where } } - fn compute_object_safe_goal(&mut self, trait_def_id: I::DefId) -> QueryResult { - if self.cx().trait_is_object_safe(trait_def_id) { + fn compute_dyn_compatible_goal(&mut self, trait_def_id: I::DefId) -> QueryResult { + if self.cx().trait_is_dyn_compatible(trait_def_id) { self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } else { Err(NoSolution) diff --git a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs index 781ca127e15..703e88d1339 100644 --- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs @@ -832,8 +832,8 @@ where let cx = self.cx(); let Goal { predicate: (a_ty, _), .. } = goal; - // Can only unsize to an object-safe trait. - if b_data.principal_def_id().is_some_and(|def_id| !cx.trait_is_object_safe(def_id)) { + // Can only unsize to an dyn-compatible trait. + if b_data.principal_def_id().is_some_and(|def_id| !cx.trait_is_dyn_compatible(def_id)) { return Err(NoSolution); } diff --git a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs index 80a9ba79c28..5f7184a4240 100644 --- a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs +++ b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs @@ -475,7 +475,7 @@ fn implemented_method<'tcx>( } else { return None; }; - let vtable_possible = - traits::is_vtable_safe_method(tcx, trait_id, trait_method) && tcx.is_object_safe(trait_id); + let vtable_possible = traits::is_vtable_safe_method(tcx, trait_id, trait_method) + && tcx.is_dyn_compatible(trait_id); vtable_possible.then_some((trait_ref, method_id, ancestor)) } diff --git a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs index e54ab1f7e24..271f46ea943 100644 --- a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs +++ b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs @@ -632,8 +632,8 @@ impl<'tcx> Stable<'tcx> for ty::PredicateKind<'tcx> { PredicateKind::Clause(clause_kind) => { stable_mir::ty::PredicateKind::Clause(clause_kind.stable(tables)) } - PredicateKind::ObjectSafe(did) => { - stable_mir::ty::PredicateKind::ObjectSafe(tables.trait_def(*did)) + PredicateKind::DynCompatible(did) => { + stable_mir::ty::PredicateKind::DynCompatible(tables.trait_def(*did)) } PredicateKind::Subtype(subtype_predicate) => { stable_mir::ty::PredicateKind::SubType(subtype_predicate.stable(tables)) 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 19e2679ae4d..b3a913c4c5b 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 @@ -37,7 +37,7 @@ use super::{ }; use crate::error_reporting::TypeErrCtxt; use crate::error_reporting::infer::TyCategory; -use crate::error_reporting::traits::report_object_safety_error; +use crate::error_reporting::traits::report_dyn_incompatibility; use crate::errors::{ AsyncClosureNotFn, ClosureFnMutLabel, ClosureFnOnceLabel, ClosureKindMismatch, }; @@ -46,7 +46,7 @@ use crate::traits::query::evaluate_obligation::InferCtxtExt as _; use crate::traits::{ MismatchedProjectionTypes, NormalizeExt, Obligation, ObligationCause, ObligationCauseCode, ObligationCtxt, Overflow, PredicateObligation, SelectionError, SignatureMismatch, - TraitNotObjectSafe, elaborate, + TraitDynIncompatible, elaborate, }; impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { @@ -547,9 +547,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ) } - ty::PredicateKind::ObjectSafe(trait_def_id) => { - let violations = self.tcx.object_safety_violations(trait_def_id); - report_object_safety_error(self.tcx, span, None, trait_def_id, violations) + ty::PredicateKind::DynCompatible(trait_def_id) => { + let violations = self.tcx.dyn_compatibility_violations(trait_def_id); + report_dyn_incompatibility(self.tcx, span, None, trait_def_id, violations) } ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(ty)) => { @@ -624,9 +624,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { def_id, ), - TraitNotObjectSafe(did) => { - let violations = self.tcx.object_safety_violations(did); - report_object_safety_error(self.tcx, span, None, did, violations) + TraitDynIncompatible(did) => { + let violations = self.tcx.dyn_compatibility_violations(did); + report_dyn_incompatibility(self.tcx, span, None, did, violations) } SelectionError::NotConstEvaluatable(NotConstEvaluatable::MentionsInfer) => { diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs index b229499a9f4..109bae10b54 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs @@ -12,8 +12,8 @@ use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::intravisit::Visitor; use rustc_hir::{self as hir, LangItem}; use rustc_infer::traits::{ - ObjectSafetyViolation, Obligation, ObligationCause, ObligationCauseCode, PredicateObligation, - SelectionError, + DynCompatibilityViolation, Obligation, ObligationCause, ObligationCauseCode, + PredicateObligation, SelectionError, }; use rustc_middle::ty::print::{PrintTraitRefExt as _, with_no_trimmed_paths}; use rustc_middle::ty::{self, Ty, TyCtxt}; @@ -406,12 +406,12 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } } -pub fn report_object_safety_error<'tcx>( +pub fn report_dyn_incompatibility<'tcx>( tcx: TyCtxt<'tcx>, span: Span, hir_id: Option, trait_def_id: DefId, - violations: &[ObjectSafetyViolation], + violations: &[DynCompatibilityViolation], ) -> Diag<'tcx> { let trait_str = tcx.def_path_str(trait_def_id); let trait_span = tcx.hir().get_if_local(trait_def_id).and_then(|node| match node { @@ -449,12 +449,12 @@ pub fn report_object_safety_error<'tcx>( let mut multi_span = vec![]; let mut messages = vec![]; for violation in violations { - if let ObjectSafetyViolation::SizedSelf(sp) = &violation + if let DynCompatibilityViolation::SizedSelf(sp) = &violation && !sp.is_empty() { // Do not report `SizedSelf` without spans pointing at `SizedSelf` obligations // with a `Span`. - reported_violations.insert(ObjectSafetyViolation::SizedSelf(vec![].into())); + reported_violations.insert(DynCompatibilityViolation::SizedSelf(vec![].into())); } if reported_violations.insert(violation.clone()) { let spans = violation.spans(); @@ -481,9 +481,10 @@ pub fn report_object_safety_error<'tcx>( for (span, msg) in iter::zip(multi_span, messages) { note_span.push_span_label(span, msg); } + // FIXME(dyn_compat_renaming): Update the URL. err.span_note( note_span, - "for a trait to be \"object safe\" it needs to allow building a vtable to allow the call \ + "for a trait to be \"dyn-compatible\" it needs to allow building a vtable to allow the call \ to be resolvable dynamically; for more information visit \ ", ); diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs index fc15f5b5906..c6e3ba3c957 100644 --- a/compiler/rustc_trait_selection/src/solve/fulfill.rs +++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs @@ -275,7 +275,7 @@ fn fulfillment_error_for_no_solution<'tcx>( FulfillmentErrorCode::Subtype(expected_found, TypeError::Sorts(expected_found)) } ty::PredicateKind::Clause(_) - | ty::PredicateKind::ObjectSafe(_) + | ty::PredicateKind::DynCompatible(_) | ty::PredicateKind::Ambiguous => { FulfillmentErrorCode::Select(SelectionError::Unimplemented) } diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs index f68e0583307..12aeee0d02f 100644 --- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs +++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs @@ -802,7 +802,7 @@ impl<'tcx> AutoTraitFinder<'tcx> { | ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(..)) | ty::PredicateKind::NormalizesTo(..) | ty::PredicateKind::AliasRelate(..) - | ty::PredicateKind::ObjectSafe(..) + | ty::PredicateKind::DynCompatible(..) | ty::PredicateKind::Subtype(..) // FIXME(generic_const_exprs): you can absolutely add this as a where clauses | ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..)) diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs similarity index 94% rename from compiler/rustc_trait_selection/src/traits/object_safety.rs rename to compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs index b6169f8508d..d5d7681a8d6 100644 --- a/compiler/rustc_trait_selection/src/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs @@ -28,43 +28,43 @@ use tracing::{debug, instrument}; use super::elaborate; use crate::infer::TyCtxtInferExt; -pub use crate::traits::ObjectSafetyViolation; +pub use crate::traits::DynCompatibilityViolation; use crate::traits::query::evaluate_obligation::InferCtxtExt; use crate::traits::{MethodViolationCode, Obligation, ObligationCause, util}; -/// Returns the object safety violations that affect HIR ty lowering. +/// Returns the dyn-compatibility violations that affect HIR ty lowering. /// /// Currently that is `Self` in supertraits. This is needed -/// because `object_safety_violations` can't be used during +/// because `dyn_compatibility_violations` can't be used during /// type collection. -#[instrument(level = "debug", skip(tcx))] -pub fn hir_ty_lowering_object_safety_violations( +#[instrument(level = "debug", skip(tcx), ret)] +pub fn hir_ty_lowering_dyn_compatibility_violations( tcx: TyCtxt<'_>, trait_def_id: DefId, -) -> Vec { +) -> Vec { debug_assert!(tcx.generics_of(trait_def_id).has_self); - let violations = tcx - .supertrait_def_ids(trait_def_id) + tcx.supertrait_def_ids(trait_def_id) .map(|def_id| predicates_reference_self(tcx, def_id, true)) .filter(|spans| !spans.is_empty()) - .map(ObjectSafetyViolation::SupertraitSelf) - .collect(); - debug!(?violations); - violations + .map(DynCompatibilityViolation::SupertraitSelf) + .collect() } -fn object_safety_violations(tcx: TyCtxt<'_>, trait_def_id: DefId) -> &'_ [ObjectSafetyViolation] { +fn dyn_compatibility_violations( + tcx: TyCtxt<'_>, + trait_def_id: DefId, +) -> &'_ [DynCompatibilityViolation] { debug_assert!(tcx.generics_of(trait_def_id).has_self); - debug!("object_safety_violations: {:?}", trait_def_id); + debug!("dyn_compatibility_violations: {:?}", trait_def_id); tcx.arena.alloc_from_iter( tcx.supertrait_def_ids(trait_def_id) - .flat_map(|def_id| object_safety_violations_for_trait(tcx, def_id)), + .flat_map(|def_id| dyn_compatibility_violations_for_trait(tcx, def_id)), ) } -fn is_object_safe(tcx: TyCtxt<'_>, trait_def_id: DefId) -> bool { - tcx.object_safety_violations(trait_def_id).is_empty() +fn is_dyn_compatible(tcx: TyCtxt<'_>, trait_def_id: DefId) -> bool { + tcx.dyn_compatibility_violations(trait_def_id).is_empty() } /// We say a method is *vtable safe* if it can be invoked on a trait @@ -82,34 +82,35 @@ pub fn is_vtable_safe_method(tcx: TyCtxt<'_>, trait_def_id: DefId, method: ty::A virtual_call_violations_for_method(tcx, trait_def_id, method).is_empty() } -fn object_safety_violations_for_trait( +#[instrument(level = "debug", skip(tcx), ret)] +fn dyn_compatibility_violations_for_trait( tcx: TyCtxt<'_>, trait_def_id: DefId, -) -> Vec { +) -> Vec { // Check assoc items for violations. let mut violations: Vec<_> = tcx .associated_items(trait_def_id) .in_definition_order() - .flat_map(|&item| object_safety_violations_for_assoc_item(tcx, trait_def_id, item)) + .flat_map(|&item| dyn_compatibility_violations_for_assoc_item(tcx, trait_def_id, item)) .collect(); // Check the trait itself. if trait_has_sized_self(tcx, trait_def_id) { // We don't want to include the requirement from `Sized` itself to be `Sized` in the list. let spans = get_sized_bounds(tcx, trait_def_id); - violations.push(ObjectSafetyViolation::SizedSelf(spans)); + violations.push(DynCompatibilityViolation::SizedSelf(spans)); } let spans = predicates_reference_self(tcx, trait_def_id, false); if !spans.is_empty() { - violations.push(ObjectSafetyViolation::SupertraitSelf(spans)); + violations.push(DynCompatibilityViolation::SupertraitSelf(spans)); } let spans = bounds_reference_self(tcx, trait_def_id); if !spans.is_empty() { - violations.push(ObjectSafetyViolation::SupertraitSelf(spans)); + violations.push(DynCompatibilityViolation::SupertraitSelf(spans)); } let spans = super_predicates_have_non_lifetime_binders(tcx, trait_def_id); if !spans.is_empty() { - violations.push(ObjectSafetyViolation::SupertraitNonLifetimeBinder(spans)); + violations.push(DynCompatibilityViolation::SupertraitNonLifetimeBinder(spans)); } if violations.is_empty() { @@ -120,11 +121,6 @@ fn object_safety_violations_for_trait( } } - debug!( - "object_safety_violations_for_trait(trait_def_id={:?}) = {:?}", - trait_def_id, violations - ); - violations } @@ -296,13 +292,13 @@ fn generics_require_sized_self(tcx: TyCtxt<'_>, def_id: DefId) -> bool { }) } -/// Returns `Some(_)` if this item makes the containing trait not object safe. +/// Returns `Some(_)` if this item makes the containing trait dyn-incompatible. #[instrument(level = "debug", skip(tcx), ret)] -pub fn object_safety_violations_for_assoc_item( +pub fn dyn_compatibility_violations_for_assoc_item( tcx: TyCtxt<'_>, trait_def_id: DefId, item: ty::AssocItem, -) -> Vec { +) -> Vec { // Any item that has a `Self : Sized` requisite is otherwise // exempt from the regulations. if tcx.generics_require_sized_self(item.def_id) { @@ -310,10 +306,10 @@ pub fn object_safety_violations_for_assoc_item( } match item.kind { - // Associated consts are never object safe, as they can't have `where` bounds yet at all, + // Associated consts are never dyn-compatible, as they can't have `where` bounds yet at all, // and associated const bounds in trait objects aren't a thing yet either. ty::AssocKind::Const => { - vec![ObjectSafetyViolation::AssocConst(item.name, item.ident(tcx).span)] + vec![DynCompatibilityViolation::AssocConst(item.name, item.ident(tcx).span)] } ty::AssocKind::Fn => virtual_call_violations_for_method(tcx, trait_def_id, item) .into_iter() @@ -330,16 +326,16 @@ pub fn object_safety_violations_for_assoc_item( _ => item.ident(tcx).span, }; - ObjectSafetyViolation::Method(item.name, v, span) + DynCompatibilityViolation::Method(item.name, v, span) }) .collect(), - // Associated types can only be object safe if they have `Self: Sized` bounds. + // Associated types can only be dyn-compatible if they have `Self: Sized` bounds. ty::AssocKind::Type => { if !tcx.features().generic_associated_types_extended && !tcx.generics_of(item.def_id).is_own_empty() && !item.is_impl_trait_in_trait() { - vec![ObjectSafetyViolation::GAT(item.name, item.ident(tcx).span)] + vec![DynCompatibilityViolation::GAT(item.name, item.ident(tcx).span)] } else { // We will permit associated types if they are explicitly mentioned in the trait object. // We can't check this here, as here we only check if it is guaranteed to not be possible. @@ -351,8 +347,8 @@ pub fn object_safety_violations_for_assoc_item( /// Returns `Some(_)` if this method cannot be called on a trait /// object; this does not necessarily imply that the enclosing trait -/// is not object safe, because the method might have a where clause -/// `Self:Sized`. +/// is dyn-incompatible, because the method might have a where clause +/// `Self: Sized`. fn virtual_call_violations_for_method<'tcx>( tcx: TyCtxt<'tcx>, trait_def_id: DefId, @@ -932,8 +928,8 @@ fn contains_illegal_impl_trait_in_trait<'tcx>( pub(crate) fn provide(providers: &mut Providers) { *providers = Providers { - object_safety_violations, - is_object_safe, + dyn_compatibility_violations, + is_dyn_compatible, generics_require_sized_self, ..*providers }; diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index fcd0936c055..33b8cf03701 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -363,7 +363,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { | ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(_)) | ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(..)) | ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(_)) - | ty::PredicateKind::ObjectSafe(_) + | ty::PredicateKind::DynCompatible(_) | ty::PredicateKind::Subtype(_) | ty::PredicateKind::Coerce(_) | ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..)) @@ -418,8 +418,8 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { ) } - ty::PredicateKind::ObjectSafe(trait_def_id) => { - if !self.selcx.tcx().is_object_safe(trait_def_id) { + ty::PredicateKind::DynCompatible(trait_def_id) => { + if !self.selcx.tcx().is_dyn_compatible(trait_def_id) { ProcessResult::Error(FulfillmentErrorCode::Select(Unimplemented)) } else { ProcessResult::Changed(vec![]) diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 61592d47784..655bef0bab7 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -5,11 +5,11 @@ pub mod auto_trait; pub(crate) mod coherence; pub mod const_evaluatable; +mod dyn_compatibility; mod engine; mod fulfill; pub mod misc; pub mod normalize; -mod object_safety; pub mod outlives_bounds; pub mod project; pub mod query; @@ -43,13 +43,13 @@ pub use self::coherence::{ InCrate, IsFirstInputType, OrphanCheckErr, OrphanCheckMode, OverlapResult, UncoveredTyParams, add_placeholder_note, orphan_check_trait_ref, overlapping_impls, }; +pub use self::dyn_compatibility::{ + DynCompatibilityViolation, dyn_compatibility_violations_for_assoc_item, + hir_ty_lowering_dyn_compatibility_violations, is_vtable_safe_method, +}; pub use self::engine::{ObligationCtxt, TraitEngineExt}; pub use self::fulfill::{FulfillmentContext, OldSolverError, PendingPredicateObligation}; pub use self::normalize::NormalizeExt; -pub use self::object_safety::{ - ObjectSafetyViolation, hir_ty_lowering_object_safety_violations, is_vtable_safe_method, - object_safety_violations_for_assoc_item, -}; pub use self::project::{normalize_inherent_projection, normalize_projection_ty}; pub use self::select::{ EvaluationCache, EvaluationResult, IntercrateAmbiguityCause, OverflowError, SelectionCache, @@ -593,7 +593,7 @@ fn is_impossible_associated_item( } pub fn provide(providers: &mut Providers) { - object_safety::provide(providers); + dyn_compatibility::provide(providers); vtable::provide(providers); *providers = Providers { specialization_graph_of: specialize::specialization_graph_provider, diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs index 3d9dc1a8d4d..bab038af9ed 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs @@ -113,7 +113,7 @@ pub fn compute_implied_outlives_bounds_inner<'tcx>( | ty::PredicateKind::Subtype(..) | ty::PredicateKind::Coerce(..) | ty::PredicateKind::Clause(ty::ClauseKind::Projection(..)) - | ty::PredicateKind::ObjectSafe(..) + | ty::PredicateKind::DynCompatible(..) | ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..)) | ty::PredicateKind::ConstEquate(..) | ty::PredicateKind::Ambiguous @@ -217,7 +217,7 @@ pub fn compute_implied_outlives_bounds_compat_inner<'tcx>( | ty::PredicateKind::Subtype(..) | ty::PredicateKind::Coerce(..) | ty::PredicateKind::Clause(ty::ClauseKind::Projection(..)) - | ty::PredicateKind::ObjectSafe(..) + | ty::PredicateKind::DynCompatible(..) | ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..)) | ty::PredicateKind::ConstEquate(..) | ty::PredicateKind::Ambiguous diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index e5f1d5c36da..084b61115db 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -883,7 +883,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { if let Some(principal) = data.principal() { if !self.infcx.tcx.features().object_safe_for_dispatch { principal.with_self_ty(self.tcx(), self_ty) - } else if self.tcx().is_object_safe(principal.def_id()) { + } else if self.tcx().is_dyn_compatible(principal.def_id()) { principal.with_self_ty(self.tcx(), self_ty) } else { return; diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index d15acd51c86..5141e969608 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -30,7 +30,7 @@ use crate::traits::util::{self, closure_trait_ref_and_return_type}; use crate::traits::{ ImplDerivedCause, ImplSource, ImplSourceUserDefinedData, Normalized, Obligation, ObligationCause, PolyTraitObligation, PredicateObligation, Selection, SelectionError, - SignatureMismatch, TraitNotObjectSafe, TraitObligation, Unimplemented, + SignatureMismatch, TraitDynIncompatible, TraitObligation, Unimplemented, }; impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { @@ -630,7 +630,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation.cause.span, "GATs in trait object shouldn't have been considered", ); - return Err(SelectionError::TraitNotObjectSafe(trait_predicate.trait_ref.def_id)); + return Err(SelectionError::TraitDynIncompatible(trait_predicate.trait_ref.def_id)); } // This maybe belongs in wf, but that can't (doesn't) handle @@ -1187,11 +1187,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ImplSource::Builtin(BuiltinImplSource::Misc, obligations) } - // `T` -> `Trait` + // `T` -> `dyn Trait` (_, &ty::Dynamic(data, r, ty::Dyn)) => { let mut object_dids = data.auto_traits().chain(data.principal_def_id()); - if let Some(did) = object_dids.find(|did| !tcx.is_object_safe(*did)) { - return Err(TraitNotObjectSafe(did)); + if let Some(did) = object_dids.find(|did| !tcx.is_dyn_compatible(*did)) { + return Err(TraitDynIncompatible(did)); } let predicate_to_obligation = |predicate| { diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index cbc17a058f6..20b540831aa 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -772,8 +772,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { Ok(EvaluatedToOkModuloRegions) } - ty::PredicateKind::ObjectSafe(trait_def_id) => { - if self.tcx().is_object_safe(trait_def_id) { + ty::PredicateKind::DynCompatible(trait_def_id) => { + if self.tcx().is_dyn_compatible(trait_def_id) { Ok(EvaluatedToOk) } else { Ok(EvaluatedToErr) diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index 354f3034b8a..7e140ecfee0 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -838,7 +838,7 @@ impl<'a, 'tcx> TypeVisitor> for WfPredicates<'a, 'tcx> { self.cause(ObligationCauseCode::WellFormed(None)), self.recursion_depth, self.param_env, - ty::Binder::dummy(ty::PredicateKind::ObjectSafe(principal)), + ty::Binder::dummy(ty::PredicateKind::DynCompatible(principal)), )); } } diff --git a/compiler/rustc_traits/src/normalize_erasing_regions.rs b/compiler/rustc_traits/src/normalize_erasing_regions.rs index c5ebc2d26a7..f01a12b0a00 100644 --- a/compiler/rustc_traits/src/normalize_erasing_regions.rs +++ b/compiler/rustc_traits/src/normalize_erasing_regions.rs @@ -59,7 +59,7 @@ fn not_outlives_predicate(p: ty::Predicate<'_>) -> bool { | ty::PredicateKind::NormalizesTo(..) | ty::PredicateKind::AliasRelate(..) | ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(..)) - | ty::PredicateKind::ObjectSafe(..) + | ty::PredicateKind::DynCompatible(..) | ty::PredicateKind::Subtype(..) | ty::PredicateKind::Coerce(..) | ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..)) diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index 8dec2133a45..b2ac67efef6 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -255,7 +255,7 @@ pub trait Interner: fn trait_is_alias(self, trait_def_id: Self::DefId) -> bool; - fn trait_is_object_safe(self, trait_def_id: Self::DefId) -> bool; + fn trait_is_dyn_compatible(self, trait_def_id: Self::DefId) -> bool; fn trait_is_fundamental(self, def_id: Self::DefId) -> bool; diff --git a/compiler/rustc_type_ir/src/predicate_kind.rs b/compiler/rustc_type_ir/src/predicate_kind.rs index c8a21028588..a5148a5e6da 100644 --- a/compiler/rustc_type_ir/src/predicate_kind.rs +++ b/compiler/rustc_type_ir/src/predicate_kind.rs @@ -46,8 +46,8 @@ pub enum PredicateKind { /// Prove a clause Clause(ClauseKind), - /// Trait must be object-safe. - ObjectSafe(I::DefId), + /// Trait must be dyn-compatible. + DynCompatible(I::DefId), /// `T1 <: T2` /// @@ -128,8 +128,8 @@ impl fmt::Debug for PredicateKind { PredicateKind::Clause(a) => a.fmt(f), PredicateKind::Subtype(pair) => pair.fmt(f), PredicateKind::Coerce(pair) => pair.fmt(f), - PredicateKind::ObjectSafe(trait_def_id) => { - write!(f, "ObjectSafe({trait_def_id:?})") + PredicateKind::DynCompatible(trait_def_id) => { + write!(f, "DynCompatible({trait_def_id:?})") } PredicateKind::ConstEquate(c1, c2) => write!(f, "ConstEquate({c1:?}, {c2:?})"), PredicateKind::Ambiguous => write!(f, "Ambiguous"), diff --git a/compiler/stable_mir/src/ty.rs b/compiler/stable_mir/src/ty.rs index b3dc4d9bb82..9e6fbc8ea0c 100644 --- a/compiler/stable_mir/src/ty.rs +++ b/compiler/stable_mir/src/ty.rs @@ -1420,7 +1420,7 @@ pub struct GenericPredicates { #[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub enum PredicateKind { Clause(ClauseKind), - ObjectSafe(TraitDef), + DynCompatible(TraitDef), SubType(SubtypePredicate), Coerce(CoercePredicate), ConstEquate(TyConst, TyConst), diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 31710bc014a..300745bcbac 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -1444,7 +1444,7 @@ impl Trait { tcx.trait_def(self.def_id).safety } pub(crate) fn is_object_safe(&self, tcx: TyCtxt<'_>) -> bool { - tcx.is_object_safe(self.def_id) + tcx.is_dyn_compatible(self.def_id) } } diff --git a/tests/rustdoc-ui/invalid_const_in_lifetime_position.stderr b/tests/rustdoc-ui/invalid_const_in_lifetime_position.stderr index ef551cbea3e..0c3826c5665 100644 --- a/tests/rustdoc-ui/invalid_const_in_lifetime_position.stderr +++ b/tests/rustdoc-ui/invalid_const_in_lifetime_position.stderr @@ -98,7 +98,7 @@ error[E0038]: the trait `X` cannot be made into an object LL | fn f<'a>(arg : Box = &'a ()>>) {} | ^^^^^^^^^^^^^^^^^^^^ `X` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/invalid_const_in_lifetime_position.rs:2:10 | LL | trait X { diff --git a/tests/rustdoc-ui/issues/issue-105742.stderr b/tests/rustdoc-ui/issues/issue-105742.stderr index 0f01bc59759..0f09d637f38 100644 --- a/tests/rustdoc-ui/issues/issue-105742.stderr +++ b/tests/rustdoc-ui/issues/issue-105742.stderr @@ -300,7 +300,7 @@ error[E0038]: the trait `SVec` cannot be made into an object LL | pub fn next<'a, T>(s: &'a mut dyn SVec) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `SVec` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/issue-105742.rs:14:17 | LL | pub trait SVec: Index< diff --git a/tests/ui/associated-consts/associated-const-in-trait.stderr b/tests/ui/associated-consts/associated-const-in-trait.stderr index 88360cd2dd5..b40c1005797 100644 --- a/tests/ui/associated-consts/associated-const-in-trait.stderr +++ b/tests/ui/associated-consts/associated-const-in-trait.stderr @@ -4,7 +4,7 @@ error[E0038]: the trait `Trait` cannot be made into an object LL | impl dyn Trait { | ^^^^^^^^^ `Trait` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/associated-const-in-trait.rs:4:11 | LL | trait Trait { @@ -19,7 +19,7 @@ error[E0038]: the trait `Trait` cannot be made into an object LL | const fn n() -> usize { Self::N } | ^^^^ `Trait` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/associated-const-in-trait.rs:4:11 | LL | trait Trait { diff --git a/tests/ui/associated-item/issue-48027.stderr b/tests/ui/associated-item/issue-48027.stderr index 45ea419336b..2883259ce2f 100644 --- a/tests/ui/associated-item/issue-48027.stderr +++ b/tests/ui/associated-item/issue-48027.stderr @@ -4,7 +4,7 @@ error[E0038]: the trait `Bar` cannot be made into an object LL | impl dyn Bar {} | ^^^^^^^ `Bar` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/issue-48027.rs:2:11 | LL | trait Bar { diff --git a/tests/ui/associated-type-bounds/suggest-assoc-ty-bound-on-eq-bound.stderr b/tests/ui/associated-type-bounds/suggest-assoc-ty-bound-on-eq-bound.stderr index 13be2162c52..bec60187e42 100644 --- a/tests/ui/associated-type-bounds/suggest-assoc-ty-bound-on-eq-bound.stderr +++ b/tests/ui/associated-type-bounds/suggest-assoc-ty-bound-on-eq-bound.stderr @@ -5,7 +5,7 @@ LL | fn f(_: impl Trait) {} | ^^^^^^^^ `Copy` cannot be made into an object | = note: the trait cannot be made into an object because it requires `Self: Sized` - = note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit + = note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit error[E0225]: only auto traits can be used as additional traits in a trait object --> $DIR/suggest-assoc-ty-bound-on-eq-bound.rs:10:42 @@ -24,7 +24,7 @@ error[E0038]: the trait `Eq` cannot be made into an object LL | fn g(_: impl Trait) {} | ^^^^^^^^^^^^^^^^^^^^ `Eq` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $SRC_DIR/core/src/cmp.rs:LL:COL | = note: the trait cannot be made into an object because it uses `Self` as a type parameter diff --git a/tests/ui/async-await/async-fn/dyn-pos.stderr b/tests/ui/async-await/async-fn/dyn-pos.stderr index 3bef5a27897..78e915d49e7 100644 --- a/tests/ui/async-await/async-fn/dyn-pos.stderr +++ b/tests/ui/async-await/async-fn/dyn-pos.stderr @@ -4,7 +4,7 @@ error[E0038]: the trait `AsyncFnMut` cannot be made into an object LL | fn foo(x: &dyn async Fn()) {} | ^^^^^^^^^^ `AsyncFnMut` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $SRC_DIR/core/src/ops/async_function.rs:LL:COL | = note: the trait cannot be made into an object because it contains the generic associated type `CallRefFuture` @@ -19,7 +19,7 @@ error[E0038]: the trait `AsyncFnMut` cannot be made into an object LL | fn foo(x: &dyn async Fn()) {} | ^^^^^^^^^^ `AsyncFnMut` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $SRC_DIR/core/src/ops/async_function.rs:LL:COL | = note: the trait cannot be made into an object because it contains the generic associated type `CallRefFuture` @@ -35,7 +35,7 @@ error[E0038]: the trait `AsyncFnMut` cannot be made into an object LL | fn foo(x: &dyn async Fn()) {} | ^^^^^^^^^^ `AsyncFnMut` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $SRC_DIR/core/src/ops/async_function.rs:LL:COL | = note: the trait cannot be made into an object because it contains the generic associated type `CallRefFuture` @@ -51,7 +51,7 @@ error[E0038]: the trait `AsyncFn` cannot be made into an object LL | fn foo(x: &dyn async Fn()) {} | ^^^^^^^^^^^^^^ `AsyncFn` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $SRC_DIR/core/src/ops/async_function.rs:LL:COL | = note: the trait cannot be made into an object because it contains the generic associated type `CallRefFuture` diff --git a/tests/ui/async-await/in-trait/object-safety.stderr b/tests/ui/async-await/in-trait/object-safety.stderr index f45e6a2c8bb..8e73abab933 100644 --- a/tests/ui/async-await/in-trait/object-safety.stderr +++ b/tests/ui/async-await/in-trait/object-safety.stderr @@ -4,7 +4,7 @@ error[E0038]: the trait `Foo` cannot be made into an object LL | let x: &dyn Foo = todo!(); | ^^^^^^^^ `Foo` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/object-safety.rs:5:14 | LL | trait Foo { diff --git a/tests/ui/async-await/inference_var_self_argument.stderr b/tests/ui/async-await/inference_var_self_argument.stderr index f94ae2a27c3..7bfa9be66dd 100644 --- a/tests/ui/async-await/inference_var_self_argument.stderr +++ b/tests/ui/async-await/inference_var_self_argument.stderr @@ -4,7 +4,7 @@ error[E0038]: the trait `Foo` cannot be made into an object LL | async fn foo(self: &dyn Foo) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `Foo` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/inference_var_self_argument.rs:5:14 | LL | trait Foo { diff --git a/tests/ui/coherence/coherence-impl-trait-for-trait-object-safe.stderr b/tests/ui/coherence/coherence-impl-trait-for-trait-object-safe.stderr index 1dcc30ee652..ce65e079ab4 100644 --- a/tests/ui/coherence/coherence-impl-trait-for-trait-object-safe.stderr +++ b/tests/ui/coherence/coherence-impl-trait-for-trait-object-safe.stderr @@ -4,7 +4,7 @@ error[E0038]: the trait `NotObjectSafe` cannot be made into an object LL | impl NotObjectSafe for dyn NotObjectSafe { } | ^^^^^^^^^^^^^^^^^ `NotObjectSafe` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/coherence-impl-trait-for-trait-object-safe.rs:6:43 | LL | trait NotObjectSafe { fn eq(&self, other: Self); } diff --git a/tests/ui/const-generics/adt_const_params/const_param_ty_object_safety.stderr b/tests/ui/const-generics/adt_const_params/const_param_ty_object_safety.stderr index ba38f63d5df..831b40887ac 100644 --- a/tests/ui/const-generics/adt_const_params/const_param_ty_object_safety.stderr +++ b/tests/ui/const-generics/adt_const_params/const_param_ty_object_safety.stderr @@ -4,7 +4,7 @@ error[E0038]: the trait `ConstParamTy_` cannot be made into an object LL | fn foo(a: &dyn ConstParamTy_) {} | ^^^^^^^^^^^^^^^^^ `ConstParamTy_` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $SRC_DIR/core/src/cmp.rs:LL:COL | = note: the trait cannot be made into an object because it uses `Self` as a type parameter @@ -19,7 +19,7 @@ error[E0038]: the trait `UnsizedConstParamTy` cannot be made into an object LL | fn bar(a: &dyn UnsizedConstParamTy) {} | ^^^^^^^^^^^^^^^^^^^^^^^ `UnsizedConstParamTy` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $SRC_DIR/core/src/cmp.rs:LL:COL | = note: the trait cannot be made into an object because it uses `Self` as a type parameter diff --git a/tests/ui/const-generics/generic_const_exprs/issue-102768.stderr b/tests/ui/const-generics/generic_const_exprs/issue-102768.stderr index 37e09a075fe..9a75f372879 100644 --- a/tests/ui/const-generics/generic_const_exprs/issue-102768.stderr +++ b/tests/ui/const-generics/generic_const_exprs/issue-102768.stderr @@ -98,7 +98,7 @@ error[E0038]: the trait `X` cannot be made into an object LL | fn f2<'a>(arg: Box = &'a ()>>) {} | ^^^^^^^^^^^^^^^^^^^^ `X` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/issue-102768.rs:5:10 | LL | trait X { diff --git a/tests/ui/const-generics/generic_const_exprs/object-safety-err-ret.stderr b/tests/ui/const-generics/generic_const_exprs/object-safety-err-ret.stderr index 31f271cc7ba..fb57da42bb2 100644 --- a/tests/ui/const-generics/generic_const_exprs/object-safety-err-ret.stderr +++ b/tests/ui/const-generics/generic_const_exprs/object-safety-err-ret.stderr @@ -4,7 +4,7 @@ error[E0038]: the trait `Foo` cannot be made into an object LL | fn use_dyn(v: &dyn Foo) { | ^^^^^^^ `Foo` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/object-safety-err-ret.rs:8:8 | LL | trait Foo { @@ -22,7 +22,7 @@ error[E0038]: the trait `Foo` cannot be made into an object LL | v.test(); | ^^^^^^^^ `Foo` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/object-safety-err-ret.rs:8:8 | LL | trait Foo { diff --git a/tests/ui/const-generics/generic_const_exprs/object-safety-err-where-bounds.stderr b/tests/ui/const-generics/generic_const_exprs/object-safety-err-where-bounds.stderr index fde5d3ce772..831bda71295 100644 --- a/tests/ui/const-generics/generic_const_exprs/object-safety-err-where-bounds.stderr +++ b/tests/ui/const-generics/generic_const_exprs/object-safety-err-where-bounds.stderr @@ -4,7 +4,7 @@ error[E0038]: the trait `Foo` cannot be made into an object LL | fn use_dyn(v: &dyn Foo) { | ^^^^^^^ `Foo` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/object-safety-err-where-bounds.rs:8:8 | LL | trait Foo { @@ -20,7 +20,7 @@ error[E0038]: the trait `Foo` cannot be made into an object LL | v.test(); | ^^^^^^^^ `Foo` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/object-safety-err-where-bounds.rs:8:8 | LL | trait Foo { diff --git a/tests/ui/const-generics/not_wf_param_in_rpitit.stderr b/tests/ui/const-generics/not_wf_param_in_rpitit.stderr index 9095948d22b..82e251f1306 100644 --- a/tests/ui/const-generics/not_wf_param_in_rpitit.stderr +++ b/tests/ui/const-generics/not_wf_param_in_rpitit.stderr @@ -24,7 +24,7 @@ error[E0038]: the trait `Trait` cannot be made into an object LL | trait Trait { | ^^^^^ `Trait` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/not_wf_param_in_rpitit.rs:11:14 | LL | trait Trait { @@ -47,7 +47,7 @@ error[E0038]: the trait `Trait` cannot be made into an object LL | trait Trait { | ^^^^^^^^^^^^^^^^^^^^ `Trait` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/not_wf_param_in_rpitit.rs:11:14 | LL | trait Trait { @@ -78,7 +78,7 @@ error[E0038]: the trait `Trait` cannot be made into an object LL | trait Trait { | ^^^^^^^^^^^^^^^^^^^^ `Trait` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/not_wf_param_in_rpitit.rs:11:14 | LL | trait Trait { diff --git a/tests/ui/consts/const_refs_to_static-ice-121413.rs b/tests/ui/consts/const_refs_to_static-ice-121413.rs index 8fc3912efd0..5afe80d9f8d 100644 --- a/tests/ui/consts/const_refs_to_static-ice-121413.rs +++ b/tests/ui/consts/const_refs_to_static-ice-121413.rs @@ -12,7 +12,7 @@ const REF_INTERIOR_MUT: &usize = { //~| ERROR the size for values of type `(dyn Sync + 'static)` cannot be known at compilation time //~| ERROR the size for values of type `(dyn Sync + 'static)` cannot be known at compilation time //~| WARN this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! - //~| HELP if this is an object-safe trait, use `dyn` + //~| HELP if this is a dyn-compatible trait, use `dyn` //~| HELP the trait `Sized` is not implemented for `(dyn Sync + 'static)` //~| HELP the trait `Sized` is not implemented for `(dyn Sync + 'static)` unsafe { &*(&FOO as *const _ as *const usize) } diff --git a/tests/ui/consts/const_refs_to_static-ice-121413.stderr b/tests/ui/consts/const_refs_to_static-ice-121413.stderr index fbe32a70293..48e6ee33346 100644 --- a/tests/ui/consts/const_refs_to_static-ice-121413.stderr +++ b/tests/ui/consts/const_refs_to_static-ice-121413.stderr @@ -18,7 +18,7 @@ LL | static FOO: Sync = AtomicUsize::new(0); = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! = note: for more information, see = note: `#[warn(bare_trait_objects)]` on by default -help: if this is an object-safe trait, use `dyn` +help: if this is a dyn-compatible trait, use `dyn` | LL | static FOO: dyn Sync = AtomicUsize::new(0); | +++ diff --git a/tests/ui/did_you_mean/bad-assoc-ty.stderr b/tests/ui/did_you_mean/bad-assoc-ty.stderr index b349332bcb9..41039ae82a6 100644 --- a/tests/ui/did_you_mean/bad-assoc-ty.stderr +++ b/tests/ui/did_you_mean/bad-assoc-ty.stderr @@ -182,7 +182,7 @@ LL | type H = Fn(u8) -> (u8)::Output; = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! = note: for more information, see = note: `#[warn(bare_trait_objects)]` on by default -help: if this is an object-safe trait, use `dyn` +help: if this is a dyn-compatible trait, use `dyn` | LL | type H = (u8)>::Output; | ++++ + diff --git a/tests/ui/did_you_mean/trait-object-reference-without-parens-suggestion.stderr b/tests/ui/did_you_mean/trait-object-reference-without-parens-suggestion.stderr index a33a8c776c8..8ef0d178444 100644 --- a/tests/ui/did_you_mean/trait-object-reference-without-parens-suggestion.stderr +++ b/tests/ui/did_you_mean/trait-object-reference-without-parens-suggestion.stderr @@ -27,7 +27,7 @@ LL | let _: &Copy + 'static; | ^^^^^ `Copy` cannot be made into an object | = note: the trait cannot be made into an object because it requires `Self: Sized` - = note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit + = note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit error: aborting due to 3 previous errors diff --git a/tests/ui/dyn-keyword/dyn-2018-edition-lint.stderr b/tests/ui/dyn-keyword/dyn-2018-edition-lint.stderr index 711bfa188ec..b930815d13b 100644 --- a/tests/ui/dyn-keyword/dyn-2018-edition-lint.stderr +++ b/tests/ui/dyn-keyword/dyn-2018-edition-lint.stderr @@ -11,7 +11,7 @@ note: the lint level is defined here | LL | #[deny(bare_trait_objects)] | ^^^^^^^^^^^^^^^^^^ -help: if this is an object-safe trait, use `dyn` +help: if this is a dyn-compatible trait, use `dyn` | LL | fn function(x: &dyn SomeTrait, y: Box) { | +++ @@ -24,7 +24,7 @@ LL | fn function(x: &SomeTrait, y: Box) { | = warning: this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2021! = note: for more information, see -help: if this is an object-safe trait, use `dyn` +help: if this is a dyn-compatible trait, use `dyn` | LL | fn function(x: &SomeTrait, y: Box) { | +++ @@ -37,7 +37,7 @@ LL | let _x: &SomeTrait = todo!(); | = warning: this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2021! = note: for more information, see -help: if this is an object-safe trait, use `dyn` +help: if this is a dyn-compatible trait, use `dyn` | LL | let _x: &dyn SomeTrait = todo!(); | +++ diff --git a/tests/ui/dyn-keyword/dyn-angle-brackets.stderr b/tests/ui/dyn-keyword/dyn-angle-brackets.stderr index 41298cc73c8..6a29dab0486 100644 --- a/tests/ui/dyn-keyword/dyn-angle-brackets.stderr +++ b/tests/ui/dyn-keyword/dyn-angle-brackets.stderr @@ -11,7 +11,7 @@ note: the lint level is defined here | LL | #![deny(bare_trait_objects)] | ^^^^^^^^^^^^^^^^^^ -help: if this is an object-safe trait, use `dyn` +help: if this is a dyn-compatible trait, use `dyn` | LL | ::fmt(self, f) | +++ diff --git a/tests/ui/error-codes/E0038.stderr b/tests/ui/error-codes/E0038.stderr index 6e8eaab8ddf..54b489c655f 100644 --- a/tests/ui/error-codes/E0038.stderr +++ b/tests/ui/error-codes/E0038.stderr @@ -4,7 +4,7 @@ error[E0038]: the trait `Trait` cannot be made into an object LL | fn call_foo(x: Box) { | ^^^^^^^^^ `Trait` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/E0038.rs:2:22 | LL | trait Trait { @@ -19,7 +19,7 @@ error[E0038]: the trait `Trait` cannot be made into an object LL | let y = x.foo(); | ^^^^^^^ `Trait` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/E0038.rs:2:22 | LL | trait Trait { diff --git a/tests/ui/errors/dynless-turbofish-e0191-issue-91997.stderr b/tests/ui/errors/dynless-turbofish-e0191-issue-91997.stderr index 68d8adc5a40..24f00cfa6be 100644 --- a/tests/ui/errors/dynless-turbofish-e0191-issue-91997.stderr +++ b/tests/ui/errors/dynless-turbofish-e0191-issue-91997.stderr @@ -7,7 +7,7 @@ LL | let _ = MyIterator::next; = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! = note: for more information, see = note: `#[warn(bare_trait_objects)]` on by default -help: if this is an object-safe trait, use `dyn` +help: if this is a dyn-compatible trait, use `dyn` | LL | let _ = ::next; | ++++ + diff --git a/tests/ui/feature-gates/feature-gate-dispatch-from-dyn-missing-impl.stderr b/tests/ui/feature-gates/feature-gate-dispatch-from-dyn-missing-impl.stderr index 00b8c0eef98..28caaf8356f 100644 --- a/tests/ui/feature-gates/feature-gate-dispatch-from-dyn-missing-impl.stderr +++ b/tests/ui/feature-gates/feature-gate-dispatch-from-dyn-missing-impl.stderr @@ -7,7 +7,7 @@ LL | fn ptr(self: Ptr); LL | Ptr(Box::new(4)) as Ptr; | ^^^^^^^^^^^^^^ `Trait` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/feature-gate-dispatch-from-dyn-missing-impl.rs:25:18 | LL | trait Trait { @@ -25,7 +25,7 @@ LL | fn ptr(self: Ptr); LL | Ptr(Box::new(4)) as Ptr; | ^^^^^^^^^^^^^^^^ `Trait` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/feature-gate-dispatch-from-dyn-missing-impl.rs:25:18 | LL | trait Trait { diff --git a/tests/ui/feature-gates/feature-gate-object_safe_for_dispatch.stderr b/tests/ui/feature-gates/feature-gate-object_safe_for_dispatch.stderr index d76c697fe73..fd5ed9c40f7 100644 --- a/tests/ui/feature-gates/feature-gate-object_safe_for_dispatch.stderr +++ b/tests/ui/feature-gates/feature-gate-object_safe_for_dispatch.stderr @@ -4,7 +4,7 @@ error[E0038]: the trait `NonObjectSafe1` cannot be made into an object LL | fn takes_non_object_safe_ref(obj: &dyn NonObjectSafe1) { | ^^^^^^^^^^^^^^^^^^ `NonObjectSafe1` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/feature-gate-object_safe_for_dispatch.rs:4:23 | LL | trait NonObjectSafe1: Sized {} @@ -18,7 +18,7 @@ error[E0038]: the trait `NonObjectSafe2` cannot be made into an object LL | fn return_non_object_safe_ref() -> &'static dyn NonObjectSafe2 { | ^^^^^^^^^^^^^^^^^^ `NonObjectSafe2` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/feature-gate-object_safe_for_dispatch.rs:7:8 | LL | trait NonObjectSafe2 { @@ -40,7 +40,7 @@ error[E0038]: the trait `NonObjectSafe3` cannot be made into an object LL | fn takes_non_object_safe_box(obj: Box) { | ^^^^^^^^^^^^^^^^^^ `NonObjectSafe3` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/feature-gate-object_safe_for_dispatch.rs:11:8 | LL | trait NonObjectSafe3 { @@ -55,7 +55,7 @@ error[E0038]: the trait `NonObjectSafe4` cannot be made into an object LL | fn return_non_object_safe_rc() -> std::rc::Rc { | ^^^^^^^^^^^^^^^^^^ `NonObjectSafe4` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/feature-gate-object_safe_for_dispatch.rs:15:22 | LL | trait NonObjectSafe4 { @@ -70,7 +70,7 @@ error[E0038]: the trait `NonObjectSafe1` cannot be made into an object LL | impl Trait for dyn NonObjectSafe1 {} | ^^^^^^^^^^^^^^^^^^ `NonObjectSafe1` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/feature-gate-object_safe_for_dispatch.rs:4:23 | LL | trait NonObjectSafe1: Sized {} diff --git a/tests/ui/generic-associated-types/gat-in-trait-path-undeclared-lifetime.stderr b/tests/ui/generic-associated-types/gat-in-trait-path-undeclared-lifetime.stderr index 4a56b20eb59..867f55b0dee 100644 --- a/tests/ui/generic-associated-types/gat-in-trait-path-undeclared-lifetime.stderr +++ b/tests/ui/generic-associated-types/gat-in-trait-path-undeclared-lifetime.stderr @@ -42,7 +42,7 @@ error[E0038]: the trait `X` cannot be made into an object LL | fn _f(arg : Box X = &'a [u32]>>) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `X` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/gat-in-trait-path-undeclared-lifetime.rs:2:8 | LL | trait X { diff --git a/tests/ui/generic-associated-types/gat-in-trait-path.base.stderr b/tests/ui/generic-associated-types/gat-in-trait-path.base.stderr index 37491ca12b0..34642f8fdc6 100644 --- a/tests/ui/generic-associated-types/gat-in-trait-path.base.stderr +++ b/tests/ui/generic-associated-types/gat-in-trait-path.base.stderr @@ -4,7 +4,7 @@ error[E0038]: the trait `Foo` cannot be made into an object LL | fn f(_arg : Box Foo = &'a ()>>) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `Foo` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/gat-in-trait-path.rs:10:10 | LL | trait Foo { @@ -22,7 +22,7 @@ error[E0038]: the trait `Foo` cannot be made into an object LL | f(Box::new(foo)); | ^^^^^^^^^^^^^ `Foo` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/gat-in-trait-path.rs:10:10 | LL | trait Foo { @@ -40,7 +40,7 @@ error[E0038]: the trait `Foo` cannot be made into an object LL | f(Box::new(foo)); | ^^^^^^^^^^^^^ `Foo` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/gat-in-trait-path.rs:10:10 | LL | trait Foo { diff --git a/tests/ui/generic-associated-types/gat-trait-path-parenthesised-args.stderr b/tests/ui/generic-associated-types/gat-trait-path-parenthesised-args.stderr index 9d8e91c02ca..97b7019b385 100644 --- a/tests/ui/generic-associated-types/gat-trait-path-parenthesised-args.stderr +++ b/tests/ui/generic-associated-types/gat-trait-path-parenthesised-args.stderr @@ -129,7 +129,7 @@ error[E0038]: the trait `X` cannot be made into an object LL | fn foo<'a>(arg: Box>) {} | ^^^^^^^^^^^^^^^^^^^^^ `X` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/gat-trait-path-parenthesised-args.rs:2:8 | LL | trait X { @@ -194,7 +194,7 @@ error[E0038]: the trait `X` cannot be made into an object LL | fn bar<'a>(arg: Box>) {} | ^^^^^^^^^^^^^^^ `X` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/gat-trait-path-parenthesised-args.rs:2:8 | LL | trait X { diff --git a/tests/ui/generic-associated-types/issue-67510-pass.base.stderr b/tests/ui/generic-associated-types/issue-67510-pass.base.stderr index f39d0055428..cac8010018e 100644 --- a/tests/ui/generic-associated-types/issue-67510-pass.base.stderr +++ b/tests/ui/generic-associated-types/issue-67510-pass.base.stderr @@ -4,7 +4,7 @@ error[E0038]: the trait `X` cannot be made into an object LL | fn _func1<'a>(_x: Box=&'a ()>>) {} | ^^^^^^^^^^^^^^^^^^^ `X` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/issue-67510-pass.rs:9:10 | LL | trait X { diff --git a/tests/ui/generic-associated-types/issue-67510.stderr b/tests/ui/generic-associated-types/issue-67510.stderr index d25c5b0f387..416f04ac2fd 100644 --- a/tests/ui/generic-associated-types/issue-67510.stderr +++ b/tests/ui/generic-associated-types/issue-67510.stderr @@ -35,7 +35,7 @@ error[E0038]: the trait `X` cannot be made into an object LL | fn f(x: Box = &'a ()>>) {} | ^^^^^^^^^^^^^^^^^^^^^ `X` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/issue-67510.rs:2:10 | LL | trait X { diff --git a/tests/ui/generic-associated-types/issue-71176.stderr b/tests/ui/generic-associated-types/issue-71176.stderr index 9f83c162c02..15d5a3df6f2 100644 --- a/tests/ui/generic-associated-types/issue-71176.stderr +++ b/tests/ui/generic-associated-types/issue-71176.stderr @@ -54,7 +54,7 @@ error[E0038]: the trait `Provider` cannot be made into an object LL | inner: Box>, | ^^^^^^^^^^^^^^^^^^^ `Provider` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/issue-71176.rs:2:10 | LL | trait Provider { @@ -70,7 +70,7 @@ error[E0038]: the trait `Provider` cannot be made into an object LL | inner: Box::new(()), | ^^^^^^^^^^^^ `Provider` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/issue-71176.rs:2:10 | LL | trait Provider { diff --git a/tests/ui/generic-associated-types/issue-76535.base.stderr b/tests/ui/generic-associated-types/issue-76535.base.stderr index 88c08051da7..a44c8dc51e7 100644 --- a/tests/ui/generic-associated-types/issue-76535.base.stderr +++ b/tests/ui/generic-associated-types/issue-76535.base.stderr @@ -20,7 +20,7 @@ error[E0038]: the trait `SuperTrait` cannot be made into an object LL | let sub: Box> = Box::new(SuperStruct::new(0)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `SuperTrait` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/issue-76535.rs:9:10 | LL | pub trait SuperTrait { @@ -37,7 +37,7 @@ error[E0038]: the trait `SuperTrait` cannot be made into an object LL | let sub: Box> = Box::new(SuperStruct::new(0)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `SuperTrait` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/issue-76535.rs:9:10 | LL | pub trait SuperTrait { diff --git a/tests/ui/generic-associated-types/issue-78671.base.stderr b/tests/ui/generic-associated-types/issue-78671.base.stderr index bad8c1c9dba..9f2be785460 100644 --- a/tests/ui/generic-associated-types/issue-78671.base.stderr +++ b/tests/ui/generic-associated-types/issue-78671.base.stderr @@ -20,7 +20,7 @@ error[E0038]: the trait `CollectionFamily` cannot be made into an object LL | Box::new(Family) as &dyn CollectionFamily | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `CollectionFamily` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/issue-78671.rs:7:10 | LL | trait CollectionFamily { diff --git a/tests/ui/generic-associated-types/issue-79422.base.stderr b/tests/ui/generic-associated-types/issue-79422.base.stderr index 551ad2a8fdf..3ea62bdbb27 100644 --- a/tests/ui/generic-associated-types/issue-79422.base.stderr +++ b/tests/ui/generic-associated-types/issue-79422.base.stderr @@ -20,7 +20,7 @@ error[E0038]: the trait `MapLike` cannot be made into an object LL | as Box>>; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `MapLike` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/issue-79422.rs:23:10 | LL | trait MapLike { @@ -38,7 +38,7 @@ error[E0038]: the trait `MapLike` cannot be made into an object LL | let m = Box::new(std::collections::BTreeMap::::new()) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `MapLike` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/issue-79422.rs:23:10 | LL | trait MapLike { diff --git a/tests/ui/generic-associated-types/missing_lifetime_args.stderr b/tests/ui/generic-associated-types/missing_lifetime_args.stderr index 18c2d8c7eed..61cf4f3dd4a 100644 --- a/tests/ui/generic-associated-types/missing_lifetime_args.stderr +++ b/tests/ui/generic-associated-types/missing_lifetime_args.stderr @@ -54,7 +54,7 @@ error[E0038]: the trait `X` cannot be made into an object LL | fn foo<'c, 'd>(_arg: Box>) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `X` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/missing_lifetime_args.rs:2:10 | LL | trait X { diff --git a/tests/ui/generic-associated-types/parse/trait-path-type-error-once-implemented.stderr b/tests/ui/generic-associated-types/parse/trait-path-type-error-once-implemented.stderr index 539b6695e9e..91f0f7b3fcf 100644 --- a/tests/ui/generic-associated-types/parse/trait-path-type-error-once-implemented.stderr +++ b/tests/ui/generic-associated-types/parse/trait-path-type-error-once-implemented.stderr @@ -98,7 +98,7 @@ error[E0038]: the trait `X` cannot be made into an object LL | fn f2<'a>(arg : Box = &'a ()>>) {} | ^^^^^^^^^^^^^^^^^^^^ `X` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/trait-path-type-error-once-implemented.rs:2:10 | LL | trait X { diff --git a/tests/ui/generic-associated-types/trait-objects.base.stderr b/tests/ui/generic-associated-types/trait-objects.base.stderr index 2b5060289ab..0b5a9b9f7fb 100644 --- a/tests/ui/generic-associated-types/trait-objects.base.stderr +++ b/tests/ui/generic-associated-types/trait-objects.base.stderr @@ -4,7 +4,7 @@ error[E0038]: the trait `StreamingIterator` cannot be made into an object LL | fn min_size(x: &mut dyn for<'a> StreamingIterator = &'a i32>) -> usize { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `StreamingIterator` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/trait-objects.rs:7:10 | LL | trait StreamingIterator { @@ -19,7 +19,7 @@ error[E0038]: the trait `StreamingIterator` cannot be made into an object LL | x.size_hint().0 | ^^^^^^^^^ `StreamingIterator` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/trait-objects.rs:7:10 | LL | trait StreamingIterator { @@ -34,7 +34,7 @@ error[E0038]: the trait `StreamingIterator` cannot be made into an object LL | x.size_hint().0 | ^^^^^^^^^^^^^ `StreamingIterator` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/trait-objects.rs:7:10 | LL | trait StreamingIterator { diff --git a/tests/ui/higher-ranked/trait-bounds/span-bug-issue-121597.stderr b/tests/ui/higher-ranked/trait-bounds/span-bug-issue-121597.stderr index 27f82563aae..d48bf8a471d 100644 --- a/tests/ui/higher-ranked/trait-bounds/span-bug-issue-121597.stderr +++ b/tests/ui/higher-ranked/trait-bounds/span-bug-issue-121597.stderr @@ -4,7 +4,7 @@ error[E0038]: the trait `Foo` cannot be made into an object LL | let x: &dyn Foo = &(); | ^^^ `Foo` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/span-bug-issue-121597.rs:4:12 | LL | trait Foo: for Bar {} @@ -19,7 +19,7 @@ error[E0038]: the trait `Foo` cannot be made into an object LL | let x: &dyn Foo = &(); | ^^^^^^^^ `Foo` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/span-bug-issue-121597.rs:4:12 | LL | trait Foo: for Bar {} diff --git a/tests/ui/impl-trait/fresh-lifetime-from-bare-trait-obj-114664.stderr b/tests/ui/impl-trait/fresh-lifetime-from-bare-trait-obj-114664.stderr index d82b2c0f606..418f9acf589 100644 --- a/tests/ui/impl-trait/fresh-lifetime-from-bare-trait-obj-114664.stderr +++ b/tests/ui/impl-trait/fresh-lifetime-from-bare-trait-obj-114664.stderr @@ -7,7 +7,7 @@ LL | fn ice() -> impl AsRef { = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! = note: for more information, see = note: `#[warn(bare_trait_objects)]` on by default -help: if this is an object-safe trait, use `dyn` +help: if this is a dyn-compatible trait, use `dyn` | LL | fn ice() -> impl AsRef { | +++ @@ -21,7 +21,7 @@ LL | fn ice() -> impl AsRef { = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! = note: for more information, see = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -help: if this is an object-safe trait, use `dyn` +help: if this is a dyn-compatible trait, use `dyn` | LL | fn ice() -> impl AsRef { | +++ diff --git a/tests/ui/impl-trait/in-trait/cycle-effective-visibilities-during-object-safety.stderr b/tests/ui/impl-trait/in-trait/cycle-effective-visibilities-during-object-safety.stderr index 90285d512ef..af624e2a758 100644 --- a/tests/ui/impl-trait/in-trait/cycle-effective-visibilities-during-object-safety.stderr +++ b/tests/ui/impl-trait/in-trait/cycle-effective-visibilities-during-object-safety.stderr @@ -14,7 +14,7 @@ error[E0038]: the trait `MyTrait` cannot be made into an object LL | MyTrait::foo(&self) | ^^^^^^^^^^^^ `MyTrait` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/cycle-effective-visibilities-during-object-safety.rs:5:22 | LL | trait MyTrait { @@ -38,7 +38,7 @@ error[E0038]: the trait `MyTrait` cannot be made into an object LL | impl dyn MyTrait { | ^^^^^^^^^^^ `MyTrait` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/cycle-effective-visibilities-during-object-safety.rs:5:22 | LL | trait MyTrait { @@ -54,7 +54,7 @@ error[E0038]: the trait `MyTrait` cannot be made into an object LL | fn other(&self) -> impl Marker { | ^^^^ `MyTrait` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/cycle-effective-visibilities-during-object-safety.rs:5:22 | LL | trait MyTrait { diff --git a/tests/ui/impl-trait/in-trait/foreign-dyn-error.stderr b/tests/ui/impl-trait/in-trait/foreign-dyn-error.stderr index a0840699268..895d8686742 100644 --- a/tests/ui/impl-trait/in-trait/foreign-dyn-error.stderr +++ b/tests/ui/impl-trait/in-trait/foreign-dyn-error.stderr @@ -4,7 +4,7 @@ error[E0038]: the trait `Foo` cannot be made into an object LL | let _: &dyn rpitit::Foo = todo!(); | ^^^^^^^^^^^^^^^^ `Foo` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/auxiliary/rpitit.rs:4:21 | LL | fn bar(self) -> impl Deref; diff --git a/tests/ui/impl-trait/in-trait/object-safety.stderr b/tests/ui/impl-trait/in-trait/object-safety.stderr index a7be0516cd3..e2f23bca621 100644 --- a/tests/ui/impl-trait/in-trait/object-safety.stderr +++ b/tests/ui/impl-trait/in-trait/object-safety.stderr @@ -4,7 +4,7 @@ error[E0038]: the trait `Foo` cannot be made into an object LL | let i = Box::new(42_u32) as Box; | ^^^^^^^^^^^^ `Foo` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/object-safety.rs:4:22 | LL | trait Foo { @@ -20,7 +20,7 @@ error[E0038]: the trait `Foo` cannot be made into an object LL | let s = i.baz(); | ^^^ `Foo` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/object-safety.rs:4:22 | LL | trait Foo { @@ -36,7 +36,7 @@ error[E0038]: the trait `Foo` cannot be made into an object LL | let s = i.baz(); | ^^^^^^^ `Foo` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/object-safety.rs:4:22 | LL | trait Foo { @@ -52,7 +52,7 @@ error[E0038]: the trait `Foo` cannot be made into an object LL | let i = Box::new(42_u32) as Box; | ^^^^^^^^^^^^^^^^ `Foo` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/object-safety.rs:4:22 | LL | trait Foo { diff --git a/tests/ui/impl-trait/object-unsafe-trait-in-return-position-dyn-trait.stderr b/tests/ui/impl-trait/object-unsafe-trait-in-return-position-dyn-trait.stderr index 09a689e6396..2a36824e292 100644 --- a/tests/ui/impl-trait/object-unsafe-trait-in-return-position-dyn-trait.stderr +++ b/tests/ui/impl-trait/object-unsafe-trait-in-return-position-dyn-trait.stderr @@ -4,7 +4,7 @@ error[E0038]: the trait `NotObjectSafe` cannot be made into an object LL | fn car() -> dyn NotObjectSafe { | ^^^^^^^^^^^^^^^^^ `NotObjectSafe` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/object-unsafe-trait-in-return-position-dyn-trait.rs:3:8 | LL | trait NotObjectSafe { @@ -29,7 +29,7 @@ error[E0038]: the trait `NotObjectSafe` cannot be made into an object LL | fn cat() -> Box { | ^^^^^^^^^^^^^^^^^ `NotObjectSafe` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/object-unsafe-trait-in-return-position-dyn-trait.rs:3:8 | LL | trait NotObjectSafe { @@ -71,7 +71,7 @@ error[E0038]: the trait `NotObjectSafe` cannot be made into an object LL | return Box::new(A); | ^^^^^^^^^^^ `NotObjectSafe` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/object-unsafe-trait-in-return-position-dyn-trait.rs:3:8 | LL | trait NotObjectSafe { @@ -97,7 +97,7 @@ error[E0038]: the trait `NotObjectSafe` cannot be made into an object LL | Box::new(B) | ^^^^^^^^^^^ `NotObjectSafe` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/object-unsafe-trait-in-return-position-dyn-trait.rs:3:8 | LL | trait NotObjectSafe { diff --git a/tests/ui/issues/issue-18959.stderr b/tests/ui/issues/issue-18959.stderr index 83d46f0331c..5bb452250aa 100644 --- a/tests/ui/issues/issue-18959.stderr +++ b/tests/ui/issues/issue-18959.stderr @@ -4,7 +4,7 @@ error[E0038]: the trait `Bar` cannot be made into an object LL | fn foo(b: &dyn Bar) { | ^^^^^^^ `Bar` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/issue-18959.rs:1:20 | LL | pub trait Foo { fn foo(&self, ext_thing: &T); } @@ -19,7 +19,7 @@ error[E0038]: the trait `Bar` cannot be made into an object LL | b.foo(&0) | ^^^^^^^^^ `Bar` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/issue-18959.rs:1:20 | LL | pub trait Foo { fn foo(&self, ext_thing: &T); } @@ -34,7 +34,7 @@ error[E0038]: the trait `Bar` cannot be made into an object LL | let test: &dyn Bar = &mut thing; | ^^^^^^^^ `Bar` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/issue-18959.rs:1:20 | LL | pub trait Foo { fn foo(&self, ext_thing: &T); } @@ -49,7 +49,7 @@ error[E0038]: the trait `Bar` cannot be made into an object LL | let test: &dyn Bar = &mut thing; | ^^^^^^^^^^ `Bar` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/issue-18959.rs:1:20 | LL | pub trait Foo { fn foo(&self, ext_thing: &T); } @@ -65,7 +65,7 @@ error[E0038]: the trait `Bar` cannot be made into an object LL | foo(test); | ^^^^ `Bar` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/issue-18959.rs:1:20 | LL | pub trait Foo { fn foo(&self, ext_thing: &T); } diff --git a/tests/ui/issues/issue-19380.stderr b/tests/ui/issues/issue-19380.stderr index 1d7aa6bd459..afbe67befa1 100644 --- a/tests/ui/issues/issue-19380.stderr +++ b/tests/ui/issues/issue-19380.stderr @@ -4,7 +4,7 @@ error[E0038]: the trait `Qiz` cannot be made into an object LL | foos: &'static [&'static (dyn Qiz + 'static)] | ^^^^^^^^^^^^^^^^^ `Qiz` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/issue-19380.rs:2:6 | LL | trait Qiz { @@ -27,7 +27,7 @@ error[E0038]: the trait `Qiz` cannot be made into an object LL | const BAR : Bar = Bar { foos: &[&FOO]}; | ^^^^ `Qiz` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/issue-19380.rs:2:6 | LL | trait Qiz { @@ -51,7 +51,7 @@ error[E0038]: the trait `Qiz` cannot be made into an object LL | const BAR : Bar = Bar { foos: &[&FOO]}; | ^^^^^^^ `Qiz` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/issue-19380.rs:2:6 | LL | trait Qiz { diff --git a/tests/ui/issues/issue-26056.stderr b/tests/ui/issues/issue-26056.stderr index f1f553adf0f..be5453ec19d 100644 --- a/tests/ui/issues/issue-26056.stderr +++ b/tests/ui/issues/issue-26056.stderr @@ -4,7 +4,7 @@ error[E0038]: the trait `Map` cannot be made into an object LL | as &dyn Map; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `Map` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/issue-26056.rs:9:12 | LL | trait Map: MapLookup<::Key> { diff --git a/tests/ui/issues/issue-28344.stderr b/tests/ui/issues/issue-28344.stderr index b7e0790f679..261f8b67b52 100644 --- a/tests/ui/issues/issue-28344.stderr +++ b/tests/ui/issues/issue-28344.stderr @@ -7,7 +7,7 @@ LL | let x: u8 = BitXor::bitor(0 as u8, 0 as u8); = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! = note: for more information, see = note: `#[warn(bare_trait_objects)]` on by default -help: if this is an object-safe trait, use `dyn` +help: if this is a dyn-compatible trait, use `dyn` | LL | let x: u8 = ::bitor(0 as u8, 0 as u8); | ++++ + @@ -35,7 +35,7 @@ LL | let g = BitXor::bitor; | = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! = note: for more information, see -help: if this is an object-safe trait, use `dyn` +help: if this is a dyn-compatible trait, use `dyn` | LL | let g = ::bitor; | ++++ + diff --git a/tests/ui/issues/issue-34373.stderr b/tests/ui/issues/issue-34373.stderr index 784fe935bf8..4e8e7c61fee 100644 --- a/tests/ui/issues/issue-34373.stderr +++ b/tests/ui/issues/issue-34373.stderr @@ -23,7 +23,7 @@ error[E0038]: the trait `Trait` cannot be made into an object LL | pub struct Foo>>; | ^^^^^^^^^^^^^^^^^ `Trait` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/issue-34373.rs:4:8 | LL | trait Trait { diff --git a/tests/ui/issues/issue-50781.stderr b/tests/ui/issues/issue-50781.stderr index 6b0b42ca53a..3e54a53aa95 100644 --- a/tests/ui/issues/issue-50781.stderr +++ b/tests/ui/issues/issue-50781.stderr @@ -4,7 +4,7 @@ error[E0038]: the trait `X` cannot be made into an object LL | impl Trait for dyn X {} | ^^^^^ `X` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/issue-50781.rs:4:8 | LL | trait X { @@ -20,7 +20,7 @@ error[E0038]: the trait `X` cannot be made into an object LL | ::foo(&()); | ^^^ `X` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/issue-50781.rs:4:8 | LL | trait X { @@ -37,7 +37,7 @@ error[E0038]: the trait `X` cannot be made into an object LL | ::foo(&()); | ^^^^^ `X` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/issue-50781.rs:4:8 | LL | trait X { diff --git a/tests/ui/issues/issue-58734.stderr b/tests/ui/issues/issue-58734.stderr index 71581e96844..a2acd9dcf81 100644 --- a/tests/ui/issues/issue-58734.stderr +++ b/tests/ui/issues/issue-58734.stderr @@ -7,7 +7,7 @@ LL | Trait::nonexistent(()); = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! = note: for more information, see = note: `#[warn(bare_trait_objects)]` on by default -help: if this is an object-safe trait, use `dyn` +help: if this is a dyn-compatible trait, use `dyn` | LL | ::nonexistent(()); | ++++ + diff --git a/tests/ui/issues/issue-86756.stderr b/tests/ui/issues/issue-86756.stderr index d0906a6fa74..728d7ea7095 100644 --- a/tests/ui/issues/issue-86756.stderr +++ b/tests/ui/issues/issue-86756.stderr @@ -21,7 +21,7 @@ LL | eq:: = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! = note: for more information, see = note: `#[warn(bare_trait_objects)]` on by default -help: if this is an object-safe trait, use `dyn` +help: if this is a dyn-compatible trait, use `dyn` | LL | eq:: | +++ diff --git a/tests/ui/kindck/kindck-inherited-copy-bound.curr.stderr b/tests/ui/kindck/kindck-inherited-copy-bound.curr.stderr index 979525ff407..e797ca01f4b 100644 --- a/tests/ui/kindck/kindck-inherited-copy-bound.curr.stderr +++ b/tests/ui/kindck/kindck-inherited-copy-bound.curr.stderr @@ -25,7 +25,7 @@ error[E0038]: the trait `Foo` cannot be made into an object LL | let z = &x as &dyn Foo; | ^^^^^^^^ `Foo` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/kindck-inherited-copy-bound.rs:10:13 | LL | trait Foo : Copy { @@ -39,7 +39,7 @@ error[E0038]: the trait `Foo` cannot be made into an object LL | let z = &x as &dyn Foo; | ^^ `Foo` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/kindck-inherited-copy-bound.rs:10:13 | LL | trait Foo : Copy { diff --git a/tests/ui/kindck/kindck-inherited-copy-bound.object_safe_for_dispatch.stderr b/tests/ui/kindck/kindck-inherited-copy-bound.object_safe_for_dispatch.stderr index 30f90b88160..b4424f4750e 100644 --- a/tests/ui/kindck/kindck-inherited-copy-bound.object_safe_for_dispatch.stderr +++ b/tests/ui/kindck/kindck-inherited-copy-bound.object_safe_for_dispatch.stderr @@ -25,7 +25,7 @@ error[E0038]: the trait `Foo` cannot be made into an object LL | let z = &x as &dyn Foo; | ^^ `Foo` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/kindck-inherited-copy-bound.rs:10:13 | LL | trait Foo : Copy { diff --git a/tests/ui/lint/bare-trait-objects-path.stderr b/tests/ui/lint/bare-trait-objects-path.stderr index da1d9f248a0..d2d139dd025 100644 --- a/tests/ui/lint/bare-trait-objects-path.stderr +++ b/tests/ui/lint/bare-trait-objects-path.stderr @@ -7,7 +7,7 @@ LL | let _: Dyn::Ty; = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! = note: for more information, see = note: `#[warn(bare_trait_objects)]` on by default -help: if this is an object-safe trait, use `dyn` +help: if this is a dyn-compatible trait, use `dyn` | LL | let _: ::Ty; | ++++ + @@ -26,7 +26,7 @@ LL | Dyn::func(); | = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! = note: for more information, see -help: if this is an object-safe trait, use `dyn` +help: if this is a dyn-compatible trait, use `dyn` | LL | ::func(); | ++++ + @@ -39,7 +39,7 @@ LL | ::Dyn::func(); | = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! = note: for more information, see -help: if this is an object-safe trait, use `dyn` +help: if this is a dyn-compatible trait, use `dyn` | LL | ::func(); | ++++++ ++ @@ -52,7 +52,7 @@ LL | Dyn::CONST; | = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! = note: for more information, see -help: if this is an object-safe trait, use `dyn` +help: if this is a dyn-compatible trait, use `dyn` | LL | ::CONST; | ++++ + diff --git a/tests/ui/lint/force-warn/allowed-group-warn-by-default-lint.stderr b/tests/ui/lint/force-warn/allowed-group-warn-by-default-lint.stderr index 388dc6160cb..a1aa29dd697 100644 --- a/tests/ui/lint/force-warn/allowed-group-warn-by-default-lint.stderr +++ b/tests/ui/lint/force-warn/allowed-group-warn-by-default-lint.stderr @@ -7,7 +7,7 @@ LL | pub fn function(_x: Box) {} = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! = note: for more information, see = note: requested on the command line with `--force-warn bare-trait-objects` -help: if this is an object-safe trait, use `dyn` +help: if this is a dyn-compatible trait, use `dyn` | LL | pub fn function(_x: Box) {} | +++ diff --git a/tests/ui/lint/force-warn/cap-lints-allow.stderr b/tests/ui/lint/force-warn/cap-lints-allow.stderr index a037fb671af..0d10a43a14d 100644 --- a/tests/ui/lint/force-warn/cap-lints-allow.stderr +++ b/tests/ui/lint/force-warn/cap-lints-allow.stderr @@ -7,7 +7,7 @@ LL | pub fn function(_x: Box) {} = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! = note: for more information, see = note: requested on the command line with `--force-warn bare-trait-objects` -help: if this is an object-safe trait, use `dyn` +help: if this is a dyn-compatible trait, use `dyn` | LL | pub fn function(_x: Box) {} | +++ diff --git a/tests/ui/lint/force-warn/lint-group-allowed-cli-warn-by-default-lint.stderr b/tests/ui/lint/force-warn/lint-group-allowed-cli-warn-by-default-lint.stderr index dc85e8cf961..d52bd67e36a 100644 --- a/tests/ui/lint/force-warn/lint-group-allowed-cli-warn-by-default-lint.stderr +++ b/tests/ui/lint/force-warn/lint-group-allowed-cli-warn-by-default-lint.stderr @@ -7,7 +7,7 @@ LL | pub fn function(_x: Box) {} = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! = note: for more information, see = note: `--force-warn bare-trait-objects` implied by `--force-warn rust-2018-idioms` -help: if this is an object-safe trait, use `dyn` +help: if this is a dyn-compatible trait, use `dyn` | LL | pub fn function(_x: Box) {} | +++ diff --git a/tests/ui/lint/force-warn/lint-group-allowed-lint-group.stderr b/tests/ui/lint/force-warn/lint-group-allowed-lint-group.stderr index 55cfad838f8..22483a3d874 100644 --- a/tests/ui/lint/force-warn/lint-group-allowed-lint-group.stderr +++ b/tests/ui/lint/force-warn/lint-group-allowed-lint-group.stderr @@ -7,7 +7,7 @@ LL | pub fn function(_x: Box) {} = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! = note: for more information, see = note: `--force-warn bare-trait-objects` implied by `--force-warn rust-2018-idioms` -help: if this is an object-safe trait, use `dyn` +help: if this is a dyn-compatible trait, use `dyn` | LL | pub fn function(_x: Box) {} | +++ diff --git a/tests/ui/lint/force-warn/lint-group-allowed-warn-by-default-lint.stderr b/tests/ui/lint/force-warn/lint-group-allowed-warn-by-default-lint.stderr index b7bf0c4ee21..aa183b9ba54 100644 --- a/tests/ui/lint/force-warn/lint-group-allowed-warn-by-default-lint.stderr +++ b/tests/ui/lint/force-warn/lint-group-allowed-warn-by-default-lint.stderr @@ -7,7 +7,7 @@ LL | pub fn function(_x: Box) {} = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! = note: for more information, see = note: `--force-warn bare-trait-objects` implied by `--force-warn rust-2018-idioms` -help: if this is an object-safe trait, use `dyn` +help: if this is a dyn-compatible trait, use `dyn` | LL | pub fn function(_x: Box) {} | +++ diff --git a/tests/ui/object-safety/almost-supertrait-associated-type.stderr b/tests/ui/object-safety/almost-supertrait-associated-type.stderr index 97a51c2f381..99bcccc20c0 100644 --- a/tests/ui/object-safety/almost-supertrait-associated-type.stderr +++ b/tests/ui/object-safety/almost-supertrait-associated-type.stderr @@ -4,7 +4,7 @@ error[E0038]: the trait `Foo` cannot be made into an object LL | impl Dyn for dyn Foo + '_ { | ^^^^^^^^^^^^^^^^^^ `Foo` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/almost-supertrait-associated-type.rs:33:34 | LL | trait Foo: Super @@ -21,7 +21,7 @@ error[E0038]: the trait `Foo` cannot be made into an object LL | (&PhantomData:: as &dyn Foo).transmute(t) | ^^^^^^^^^^^^^^ `Foo` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/almost-supertrait-associated-type.rs:33:34 | LL | trait Foo: Super @@ -38,7 +38,7 @@ error[E0038]: the trait `Foo` cannot be made into an object LL | (&PhantomData:: as &dyn Foo).transmute(t) | ^^^^^^^^^^^^^^^^^ `Foo` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/almost-supertrait-associated-type.rs:33:34 | LL | trait Foo: Super diff --git a/tests/ui/object-safety/assoc_type_bounds_sized_unnecessary.rs b/tests/ui/object-safety/assoc_type_bounds_sized_unnecessary.rs index 711bed808cc..e9216da5927 100644 --- a/tests/ui/object-safety/assoc_type_bounds_sized_unnecessary.rs +++ b/tests/ui/object-safety/assoc_type_bounds_sized_unnecessary.rs @@ -7,7 +7,7 @@ trait Foo { } fn foo(_: &dyn Foo) {} -//~^ WARN: unnecessary associated type bound for not object safe associated type +//~^ WARN: unnecessary associated type bound for dyn-incompatible associated type #[allow(unused_associated_type_bounds)] fn bar(_: &dyn Foo) {} diff --git a/tests/ui/object-safety/assoc_type_bounds_sized_unnecessary.stderr b/tests/ui/object-safety/assoc_type_bounds_sized_unnecessary.stderr index 7cd6175a5ad..aaadc4ed7b1 100644 --- a/tests/ui/object-safety/assoc_type_bounds_sized_unnecessary.stderr +++ b/tests/ui/object-safety/assoc_type_bounds_sized_unnecessary.stderr @@ -1,4 +1,4 @@ -warning: unnecessary associated type bound for not object safe associated type +warning: unnecessary associated type bound for dyn-incompatible associated type --> $DIR/assoc_type_bounds_sized_unnecessary.rs:9:20 | LL | fn foo(_: &dyn Foo) {} diff --git a/tests/ui/object-safety/avoid-ice-on-warning-2.new.stderr b/tests/ui/object-safety/avoid-ice-on-warning-2.new.stderr index 0bc396390d7..3ac1ebb30e2 100644 --- a/tests/ui/object-safety/avoid-ice-on-warning-2.new.stderr +++ b/tests/ui/object-safety/avoid-ice-on-warning-2.new.stderr @@ -5,7 +5,7 @@ LL | fn id(f: Copy) -> usize { | ^^^^ `Copy` cannot be made into an object | = note: the trait cannot be made into an object because it requires `Self: Sized` - = note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit + = note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit error[E0618]: expected function, found `(dyn Copy + 'static)` --> $DIR/avoid-ice-on-warning-2.rs:11:5 diff --git a/tests/ui/object-safety/avoid-ice-on-warning-2.old.stderr b/tests/ui/object-safety/avoid-ice-on-warning-2.old.stderr index f1f33a6c6d6..3a586450fc5 100644 --- a/tests/ui/object-safety/avoid-ice-on-warning-2.old.stderr +++ b/tests/ui/object-safety/avoid-ice-on-warning-2.old.stderr @@ -7,7 +7,7 @@ LL | fn id(f: Copy) -> usize { = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! = note: for more information, see = note: `#[warn(bare_trait_objects)]` on by default -help: if this is an object-safe trait, use `dyn` +help: if this is a dyn-compatible trait, use `dyn` | LL | fn id(f: dyn Copy) -> usize { | +++ @@ -21,7 +21,7 @@ LL | fn id(f: Copy) -> usize { = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! = note: for more information, see = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -help: if this is an object-safe trait, use `dyn` +help: if this is a dyn-compatible trait, use `dyn` | LL | fn id(f: dyn Copy) -> usize { | +++ @@ -33,7 +33,7 @@ LL | fn id(f: Copy) -> usize { | ^^^^ `Copy` cannot be made into an object | = note: the trait cannot be made into an object because it requires `Self: Sized` - = note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit + = note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit error[E0618]: expected function, found `(dyn Copy + 'static)` --> $DIR/avoid-ice-on-warning-2.rs:11:5 diff --git a/tests/ui/object-safety/avoid-ice-on-warning-3.new.stderr b/tests/ui/object-safety/avoid-ice-on-warning-3.new.stderr index fd92d43ef9a..fdd3e8ab507 100644 --- a/tests/ui/object-safety/avoid-ice-on-warning-3.new.stderr +++ b/tests/ui/object-safety/avoid-ice-on-warning-3.new.stderr @@ -4,7 +4,7 @@ error[E0038]: the trait `A` cannot be made into an object LL | trait B { fn f(a: A) -> A; } | ^ `A` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/avoid-ice-on-warning-3.rs:12:14 | LL | trait A { fn g(b: B) -> B; } @@ -26,7 +26,7 @@ error[E0038]: the trait `B` cannot be made into an object LL | trait A { fn g(b: B) -> B; } | ^ `B` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/avoid-ice-on-warning-3.rs:4:14 | LL | trait B { fn f(a: A) -> A; } diff --git a/tests/ui/object-safety/avoid-ice-on-warning-3.old.stderr b/tests/ui/object-safety/avoid-ice-on-warning-3.old.stderr index f499e2d946f..bd362abb355 100644 --- a/tests/ui/object-safety/avoid-ice-on-warning-3.old.stderr +++ b/tests/ui/object-safety/avoid-ice-on-warning-3.old.stderr @@ -7,7 +7,7 @@ LL | trait B { fn f(a: A) -> A; } = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! = note: for more information, see = note: `#[warn(bare_trait_objects)]` on by default -help: if this is an object-safe trait, use `dyn` +help: if this is a dyn-compatible trait, use `dyn` | LL | trait B { fn f(a: dyn A) -> A; } | +++ @@ -20,7 +20,7 @@ LL | trait B { fn f(a: A) -> A; } | = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! = note: for more information, see -help: if this is an object-safe trait, use `dyn` +help: if this is a dyn-compatible trait, use `dyn` | LL | trait B { fn f(a: A) -> dyn A; } | +++ @@ -33,7 +33,7 @@ LL | trait A { fn g(b: B) -> B; } | = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! = note: for more information, see -help: if this is an object-safe trait, use `dyn` +help: if this is a dyn-compatible trait, use `dyn` | LL | trait A { fn g(b: dyn B) -> B; } | +++ @@ -46,7 +46,7 @@ LL | trait A { fn g(b: B) -> B; } | = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! = note: for more information, see -help: if this is an object-safe trait, use `dyn` +help: if this is a dyn-compatible trait, use `dyn` | LL | trait A { fn g(b: B) -> dyn B; } | +++ @@ -60,7 +60,7 @@ LL | trait B { fn f(a: A) -> A; } = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! = note: for more information, see = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -help: if this is an object-safe trait, use `dyn` +help: if this is a dyn-compatible trait, use `dyn` | LL | trait B { fn f(a: dyn A) -> A; } | +++ @@ -71,7 +71,7 @@ error[E0038]: the trait `A` cannot be made into an object LL | trait B { fn f(a: A) -> A; } | ^ `A` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/avoid-ice-on-warning-3.rs:12:14 | LL | trait A { fn g(b: B) -> B; } @@ -96,7 +96,7 @@ LL | trait A { fn g(b: B) -> B; } = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! = note: for more information, see = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -help: if this is an object-safe trait, use `dyn` +help: if this is a dyn-compatible trait, use `dyn` | LL | trait A { fn g(b: dyn B) -> B; } | +++ @@ -107,7 +107,7 @@ error[E0038]: the trait `B` cannot be made into an object LL | trait A { fn g(b: B) -> B; } | ^ `B` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/avoid-ice-on-warning-3.rs:4:14 | LL | trait B { fn f(a: A) -> A; } diff --git a/tests/ui/object-safety/avoid-ice-on-warning.old.stderr b/tests/ui/object-safety/avoid-ice-on-warning.old.stderr index de45ec8c405..646fb57af9e 100644 --- a/tests/ui/object-safety/avoid-ice-on-warning.old.stderr +++ b/tests/ui/object-safety/avoid-ice-on-warning.old.stderr @@ -24,7 +24,7 @@ LL | fn call_this(f: F) : Fn(&str) + call_that {} = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! = note: for more information, see = note: `#[warn(bare_trait_objects)]` on by default -help: if this is an object-safe trait, use `dyn` +help: if this is a dyn-compatible trait, use `dyn` | LL | fn call_this(f: F) : dyn Fn(&str) + call_that {} | +++ diff --git a/tests/ui/object-safety/bare-trait-dont-suggest-dyn.new.stderr b/tests/ui/object-safety/bare-trait-dont-suggest-dyn.new.stderr index efddab6dff6..bb2bf6ddcda 100644 --- a/tests/ui/object-safety/bare-trait-dont-suggest-dyn.new.stderr +++ b/tests/ui/object-safety/bare-trait-dont-suggest-dyn.new.stderr @@ -4,7 +4,7 @@ error[E0038]: the trait `Ord` cannot be made into an object LL | fn ord_prefer_dot(s: String) -> Ord { | ^^^ `Ord` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $SRC_DIR/core/src/cmp.rs:LL:COL | = note: the trait cannot be made into an object because it uses `Self` as a type parameter diff --git a/tests/ui/object-safety/bare-trait-dont-suggest-dyn.old.stderr b/tests/ui/object-safety/bare-trait-dont-suggest-dyn.old.stderr index 0545a1afcc1..45c9b0ce5d9 100644 --- a/tests/ui/object-safety/bare-trait-dont-suggest-dyn.old.stderr +++ b/tests/ui/object-safety/bare-trait-dont-suggest-dyn.old.stderr @@ -11,7 +11,7 @@ note: the lint level is defined here | LL | #![deny(bare_trait_objects)] | ^^^^^^^^^^^^^^^^^^ -help: if this is an object-safe trait, use `dyn` +help: if this is a dyn-compatible trait, use `dyn` | LL | fn ord_prefer_dot(s: String) -> dyn Ord { | +++ @@ -22,7 +22,7 @@ error[E0038]: the trait `Ord` cannot be made into an object LL | fn ord_prefer_dot(s: String) -> Ord { | ^^^ `Ord` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $SRC_DIR/core/src/cmp.rs:LL:COL | = note: the trait cannot be made into an object because it uses `Self` as a type parameter diff --git a/tests/ui/object-safety/issue-102762.stderr b/tests/ui/object-safety/issue-102762.stderr index e746628aa37..05451eb8399 100644 --- a/tests/ui/object-safety/issue-102762.stderr +++ b/tests/ui/object-safety/issue-102762.stderr @@ -7,7 +7,7 @@ LL | fn get<'a>(self: &'a Box) -> Pin> LL | fn fetcher() -> Box { | ^^^^^^^^^^^ `Fetcher` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/issue-102762.rs:10:22 | LL | pub trait Fetcher: Send + Sync { @@ -24,7 +24,7 @@ LL | fn get<'a>(self: &'a Box) -> Pin> LL | let fetcher = fetcher(); | ^^^^^^^^^ `Fetcher` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/issue-102762.rs:10:22 | LL | pub trait Fetcher: Send + Sync { @@ -41,7 +41,7 @@ LL | fn get<'a>(self: &'a Box) -> Pin> LL | let _ = fetcher.get(); | ^^^^^^^^^^^^^ `Fetcher` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/issue-102762.rs:10:22 | LL | pub trait Fetcher: Send + Sync { diff --git a/tests/ui/object-safety/issue-19538.stderr b/tests/ui/object-safety/issue-19538.stderr index 31657501e25..3dbe389686a 100644 --- a/tests/ui/object-safety/issue-19538.stderr +++ b/tests/ui/object-safety/issue-19538.stderr @@ -4,7 +4,7 @@ error[E0038]: the trait `Bar` cannot be made into an object LL | let test: &mut dyn Bar = &mut thing; | ^^^^^^^^^^^^ `Bar` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/issue-19538.rs:2:8 | LL | fn foo(&self, val: T); @@ -21,7 +21,7 @@ error[E0038]: the trait `Bar` cannot be made into an object LL | let test: &mut dyn Bar = &mut thing; | ^^^^^^^^^^ `Bar` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/issue-19538.rs:2:8 | LL | fn foo(&self, val: T); diff --git a/tests/ui/object-safety/object-safety-associated-consts.curr.stderr b/tests/ui/object-safety/object-safety-associated-consts.curr.stderr index bd558d36f73..3c070f17c82 100644 --- a/tests/ui/object-safety/object-safety-associated-consts.curr.stderr +++ b/tests/ui/object-safety/object-safety-associated-consts.curr.stderr @@ -4,7 +4,7 @@ error[E0038]: the trait `Bar` cannot be made into an object LL | fn make_bar(t: &T) -> &dyn Bar { | ^^^^^^^ `Bar` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/object-safety-associated-consts.rs:9:11 | LL | trait Bar { @@ -19,7 +19,7 @@ error[E0038]: the trait `Bar` cannot be made into an object LL | t | ^ `Bar` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/object-safety-associated-consts.rs:9:11 | LL | trait Bar { diff --git a/tests/ui/object-safety/object-safety-associated-consts.object_safe_for_dispatch.stderr b/tests/ui/object-safety/object-safety-associated-consts.object_safe_for_dispatch.stderr index d0c78f9cd69..5b98cc35505 100644 --- a/tests/ui/object-safety/object-safety-associated-consts.object_safe_for_dispatch.stderr +++ b/tests/ui/object-safety/object-safety-associated-consts.object_safe_for_dispatch.stderr @@ -4,7 +4,7 @@ error[E0038]: the trait `Bar` cannot be made into an object LL | t | ^ `Bar` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/object-safety-associated-consts.rs:9:11 | LL | trait Bar { diff --git a/tests/ui/object-safety/object-safety-bounds.stderr b/tests/ui/object-safety/object-safety-bounds.stderr index bf3c055f4e3..96a81a69639 100644 --- a/tests/ui/object-safety/object-safety-bounds.stderr +++ b/tests/ui/object-safety/object-safety-bounds.stderr @@ -4,7 +4,7 @@ error[E0038]: the trait `X` cannot be made into an object LL | fn f() -> Box> { | ^^^^^^^^^^^^^^ `X` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/object-safety-bounds.rs:4:13 | LL | trait X { diff --git a/tests/ui/object-safety/object-safety-generics.curr.stderr b/tests/ui/object-safety/object-safety-generics.curr.stderr index 85adeace3c7..7528785d90b 100644 --- a/tests/ui/object-safety/object-safety-generics.curr.stderr +++ b/tests/ui/object-safety/object-safety-generics.curr.stderr @@ -4,7 +4,7 @@ error[E0038]: the trait `Bar` cannot be made into an object LL | fn make_bar(t: &T) -> &dyn Bar { | ^^^^^^^ `Bar` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/object-safety-generics.rs:10:8 | LL | trait Bar { @@ -19,7 +19,7 @@ error[E0038]: the trait `Bar` cannot be made into an object LL | fn make_bar_explicit(t: &T) -> &dyn Bar { | ^^^^^^^ `Bar` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/object-safety-generics.rs:10:8 | LL | trait Bar { @@ -34,7 +34,7 @@ error[E0038]: the trait `Bar` cannot be made into an object LL | t | ^ `Bar` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/object-safety-generics.rs:10:8 | LL | trait Bar { @@ -50,7 +50,7 @@ error[E0038]: the trait `Bar` cannot be made into an object LL | t as &dyn Bar | ^^^^^^^^ `Bar` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/object-safety-generics.rs:10:8 | LL | trait Bar { @@ -65,7 +65,7 @@ error[E0038]: the trait `Bar` cannot be made into an object LL | t as &dyn Bar | ^ `Bar` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/object-safety-generics.rs:10:8 | LL | trait Bar { diff --git a/tests/ui/object-safety/object-safety-generics.object_safe_for_dispatch.stderr b/tests/ui/object-safety/object-safety-generics.object_safe_for_dispatch.stderr index 498ad0d8a5e..4686b994b33 100644 --- a/tests/ui/object-safety/object-safety-generics.object_safe_for_dispatch.stderr +++ b/tests/ui/object-safety/object-safety-generics.object_safe_for_dispatch.stderr @@ -4,7 +4,7 @@ error[E0038]: the trait `Bar` cannot be made into an object LL | t | ^ `Bar` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/object-safety-generics.rs:10:8 | LL | trait Bar { @@ -20,7 +20,7 @@ error[E0038]: the trait `Bar` cannot be made into an object LL | t as &dyn Bar | ^ `Bar` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/object-safety-generics.rs:10:8 | LL | trait Bar { diff --git a/tests/ui/object-safety/object-safety-issue-22040.stderr b/tests/ui/object-safety/object-safety-issue-22040.stderr index 767c232c6ce..e5723f12258 100644 --- a/tests/ui/object-safety/object-safety-issue-22040.stderr +++ b/tests/ui/object-safety/object-safety-issue-22040.stderr @@ -4,7 +4,7 @@ error[E0038]: the trait `Expr` cannot be made into an object LL | elements: Vec>, | ^^^^^^^^^^^^^ `Expr` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/object-safety-issue-22040.rs:5:21 | LL | trait Expr: Debug + PartialEq { @@ -19,7 +19,7 @@ error[E0038]: the trait `Expr` cannot be made into an object LL | let a: Box = Box::new(SExpr::new()); | ^^^^^^^^ `Expr` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/object-safety-issue-22040.rs:5:21 | LL | trait Expr: Debug + PartialEq { @@ -34,7 +34,7 @@ error[E0038]: the trait `Expr` cannot be made into an object LL | let b: Box = Box::new(SExpr::new()); | ^^^^^^^^ `Expr` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/object-safety-issue-22040.rs:5:21 | LL | trait Expr: Debug + PartialEq { diff --git a/tests/ui/object-safety/object-safety-mentions-Self.curr.stderr b/tests/ui/object-safety/object-safety-mentions-Self.curr.stderr index 28c9c9d64a0..7efb6ec3542 100644 --- a/tests/ui/object-safety/object-safety-mentions-Self.curr.stderr +++ b/tests/ui/object-safety/object-safety-mentions-Self.curr.stderr @@ -4,7 +4,7 @@ error[E0038]: the trait `Bar` cannot be made into an object LL | fn make_bar(t: &T) -> &dyn Bar { | ^^^^^^^ `Bar` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/object-safety-mentions-Self.rs:11:22 | LL | trait Bar { @@ -19,7 +19,7 @@ error[E0038]: the trait `Baz` cannot be made into an object LL | fn make_baz(t: &T) -> &dyn Baz { | ^^^^^^^ `Baz` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/object-safety-mentions-Self.rs:15:22 | LL | trait Baz { @@ -34,7 +34,7 @@ error[E0038]: the trait `Bar` cannot be made into an object LL | t | ^ `Bar` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/object-safety-mentions-Self.rs:11:22 | LL | trait Bar { @@ -50,7 +50,7 @@ error[E0038]: the trait `Baz` cannot be made into an object LL | t | ^ `Baz` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/object-safety-mentions-Self.rs:15:22 | LL | trait Baz { diff --git a/tests/ui/object-safety/object-safety-mentions-Self.object_safe_for_dispatch.stderr b/tests/ui/object-safety/object-safety-mentions-Self.object_safe_for_dispatch.stderr index 414614d8d0b..d0efb9c587e 100644 --- a/tests/ui/object-safety/object-safety-mentions-Self.object_safe_for_dispatch.stderr +++ b/tests/ui/object-safety/object-safety-mentions-Self.object_safe_for_dispatch.stderr @@ -4,7 +4,7 @@ error[E0038]: the trait `Bar` cannot be made into an object LL | t | ^ `Bar` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/object-safety-mentions-Self.rs:11:22 | LL | trait Bar { @@ -20,7 +20,7 @@ error[E0038]: the trait `Baz` cannot be made into an object LL | t | ^ `Baz` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/object-safety-mentions-Self.rs:15:22 | LL | trait Baz { diff --git a/tests/ui/object-safety/object-safety-no-static.curr.stderr b/tests/ui/object-safety/object-safety-no-static.curr.stderr index 8e5b0cbf9dd..91c3d89602e 100644 --- a/tests/ui/object-safety/object-safety-no-static.curr.stderr +++ b/tests/ui/object-safety/object-safety-no-static.curr.stderr @@ -4,7 +4,7 @@ error[E0038]: the trait `Foo` cannot be made into an object LL | fn diverges() -> Box { | ^^^^^^^ `Foo` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/object-safety-no-static.rs:9:8 | LL | trait Foo { @@ -27,7 +27,7 @@ error[E0038]: the trait `Foo` cannot be made into an object LL | let b: Box = Box::new(Bar); | ^^^^^^^^^^^^ `Foo` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/object-safety-no-static.rs:9:8 | LL | trait Foo { @@ -50,7 +50,7 @@ error[E0038]: the trait `Foo` cannot be made into an object LL | let b: Box = Box::new(Bar); | ^^^^^^^^^^^^^ `Foo` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/object-safety-no-static.rs:9:8 | LL | trait Foo { diff --git a/tests/ui/object-safety/object-safety-no-static.object_safe_for_dispatch.stderr b/tests/ui/object-safety/object-safety-no-static.object_safe_for_dispatch.stderr index e155a350f89..52f6865b6f3 100644 --- a/tests/ui/object-safety/object-safety-no-static.object_safe_for_dispatch.stderr +++ b/tests/ui/object-safety/object-safety-no-static.object_safe_for_dispatch.stderr @@ -4,7 +4,7 @@ error[E0038]: the trait `Foo` cannot be made into an object LL | let b: Box = Box::new(Bar); | ^^^^^^^^^^^^^ `Foo` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/object-safety-no-static.rs:9:8 | LL | trait Foo { diff --git a/tests/ui/object-safety/object-safety-sized-2.curr.stderr b/tests/ui/object-safety/object-safety-sized-2.curr.stderr index 03b078c2a44..4ce7ac5704e 100644 --- a/tests/ui/object-safety/object-safety-sized-2.curr.stderr +++ b/tests/ui/object-safety/object-safety-sized-2.curr.stderr @@ -4,7 +4,7 @@ error[E0038]: the trait `Bar` cannot be made into an object LL | fn make_bar(t: &T) -> &dyn Bar { | ^^^^^^^ `Bar` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/object-safety-sized-2.rs:9:18 | LL | trait Bar @@ -18,7 +18,7 @@ error[E0038]: the trait `Bar` cannot be made into an object LL | t | ^ `Bar` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/object-safety-sized-2.rs:9:18 | LL | trait Bar diff --git a/tests/ui/object-safety/object-safety-sized-2.object_safe_for_dispatch.stderr b/tests/ui/object-safety/object-safety-sized-2.object_safe_for_dispatch.stderr index 69af9bfe92b..99066c104b7 100644 --- a/tests/ui/object-safety/object-safety-sized-2.object_safe_for_dispatch.stderr +++ b/tests/ui/object-safety/object-safety-sized-2.object_safe_for_dispatch.stderr @@ -4,7 +4,7 @@ error[E0038]: the trait `Bar` cannot be made into an object LL | t | ^ `Bar` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/object-safety-sized-2.rs:9:18 | LL | trait Bar diff --git a/tests/ui/object-safety/object-safety-sized.curr.stderr b/tests/ui/object-safety/object-safety-sized.curr.stderr index 0513780a81f..b61f968d902 100644 --- a/tests/ui/object-safety/object-safety-sized.curr.stderr +++ b/tests/ui/object-safety/object-safety-sized.curr.stderr @@ -4,7 +4,7 @@ error[E0038]: the trait `Bar` cannot be made into an object LL | fn make_bar(t: &T) -> &dyn Bar { | ^^^^^^^ `Bar` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/object-safety-sized.rs:8:12 | LL | trait Bar: Sized { @@ -18,7 +18,7 @@ error[E0038]: the trait `Bar` cannot be made into an object LL | t | ^ `Bar` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/object-safety-sized.rs:8:12 | LL | trait Bar: Sized { diff --git a/tests/ui/object-safety/object-safety-sized.object_safe_for_dispatch.stderr b/tests/ui/object-safety/object-safety-sized.object_safe_for_dispatch.stderr index d988293c0e9..5ce713375a4 100644 --- a/tests/ui/object-safety/object-safety-sized.object_safe_for_dispatch.stderr +++ b/tests/ui/object-safety/object-safety-sized.object_safe_for_dispatch.stderr @@ -4,7 +4,7 @@ error[E0038]: the trait `Bar` cannot be made into an object LL | t | ^ `Bar` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/object-safety-sized.rs:8:12 | LL | trait Bar: Sized { diff --git a/tests/ui/object-safety/object-safety-supertrait-mentions-GAT.stderr b/tests/ui/object-safety/object-safety-supertrait-mentions-GAT.stderr index 2d2bb27b8f3..4d44627e779 100644 --- a/tests/ui/object-safety/object-safety-supertrait-mentions-GAT.stderr +++ b/tests/ui/object-safety/object-safety-supertrait-mentions-GAT.stderr @@ -26,7 +26,7 @@ error[E0038]: the trait `SuperTrait` cannot be made into an object LL | fn c(&self) -> dyn SuperTrait; | ^^^^^^^^^^^^^^^^^ `SuperTrait` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/object-safety-supertrait-mentions-GAT.rs:4:10 | LL | type Gat<'a> diff --git a/tests/ui/object-safety/object-safety-supertrait-mentions-Self.stderr b/tests/ui/object-safety/object-safety-supertrait-mentions-Self.stderr index 6beb04e5b93..b1a70fb859d 100644 --- a/tests/ui/object-safety/object-safety-supertrait-mentions-Self.stderr +++ b/tests/ui/object-safety/object-safety-supertrait-mentions-Self.stderr @@ -24,7 +24,7 @@ error[E0038]: the trait `Baz` cannot be made into an object LL | fn make_baz(t: &T) -> &dyn Baz { | ^^^^^^^ `Baz` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/object-safety-supertrait-mentions-Self.rs:8:13 | LL | trait Baz : Bar { diff --git a/tests/ui/parser/trait-object-trait-parens.stderr b/tests/ui/parser/trait-object-trait-parens.stderr index ff32b173d49..d75352b6811 100644 --- a/tests/ui/parser/trait-object-trait-parens.stderr +++ b/tests/ui/parser/trait-object-trait-parens.stderr @@ -34,7 +34,7 @@ LL | let _: Box<(Obj) + (?Sized) + (for<'a> Trait<'a>)>; = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! = note: for more information, see = note: `#[warn(bare_trait_objects)]` on by default -help: if this is an object-safe trait, use `dyn` +help: if this is a dyn-compatible trait, use `dyn` | LL | let _: Box Trait<'a>)>; | +++ @@ -58,7 +58,7 @@ LL | let _: Box Trait<'a>) + (Obj)>; | = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! = note: for more information, see -help: if this is an object-safe trait, use `dyn` +help: if this is a dyn-compatible trait, use `dyn` | LL | let _: Box Trait<'a>) + (Obj)>; | +++ @@ -82,7 +82,7 @@ LL | let _: Box Trait<'a> + (Obj) + (?Sized)>; | = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! = note: for more information, see -help: if this is an object-safe trait, use `dyn` +help: if this is a dyn-compatible trait, use `dyn` | LL | let _: Box Trait<'a> + (Obj) + (?Sized)>; | +++ diff --git a/tests/ui/resolve/issue-3907-2.stderr b/tests/ui/resolve/issue-3907-2.stderr index 364edb788c6..7c966ba9891 100644 --- a/tests/ui/resolve/issue-3907-2.stderr +++ b/tests/ui/resolve/issue-3907-2.stderr @@ -4,7 +4,7 @@ error[E0038]: the trait `issue_3907::Foo` cannot be made into an object LL | fn bar(_x: Foo) {} | ^^^ `issue_3907::Foo` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/auxiliary/issue-3907.rs:2:8 | LL | fn bar(); diff --git a/tests/ui/self/arbitrary-self-types-not-object-safe.curr.stderr b/tests/ui/self/arbitrary-self-types-not-object-safe.curr.stderr index fdd18c6b37b..e2d73fc08f6 100644 --- a/tests/ui/self/arbitrary-self-types-not-object-safe.curr.stderr +++ b/tests/ui/self/arbitrary-self-types-not-object-safe.curr.stderr @@ -7,7 +7,7 @@ LL | fn foo(self: &Rc) -> usize; LL | let x = Rc::new(5usize) as Rc; | ^^^^^^^^^^^ `Foo` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/arbitrary-self-types-not-object-safe.rs:8:18 | LL | trait Foo { @@ -25,7 +25,7 @@ LL | fn foo(self: &Rc) -> usize; LL | let x = Rc::new(5usize) as Rc; | ^^^^^^^^^^^^^^^ `Foo` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/arbitrary-self-types-not-object-safe.rs:8:18 | LL | trait Foo { diff --git a/tests/ui/self/arbitrary-self-types-not-object-safe.object_safe_for_dispatch.stderr b/tests/ui/self/arbitrary-self-types-not-object-safe.object_safe_for_dispatch.stderr index 363ba072c81..fda07765c66 100644 --- a/tests/ui/self/arbitrary-self-types-not-object-safe.object_safe_for_dispatch.stderr +++ b/tests/ui/self/arbitrary-self-types-not-object-safe.object_safe_for_dispatch.stderr @@ -7,7 +7,7 @@ LL | fn foo(self: &Rc) -> usize; LL | let x = Rc::new(5usize) as Rc; | ^^^^^^^^^^^^^^^ `Foo` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/arbitrary-self-types-not-object-safe.rs:8:18 | LL | trait Foo { diff --git a/tests/ui/statics/unsizing-wfcheck-issue-127299.stderr b/tests/ui/statics/unsizing-wfcheck-issue-127299.stderr index 49e8d87f354..59e09e48523 100644 --- a/tests/ui/statics/unsizing-wfcheck-issue-127299.stderr +++ b/tests/ui/statics/unsizing-wfcheck-issue-127299.stderr @@ -4,7 +4,7 @@ error[E0038]: the trait `Qux` cannot be made into an object LL | pub desc: &'static dyn Qux, | ^^^^^^^ `Qux` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/unsizing-wfcheck-issue-127299.rs:4:8 | LL | trait Qux { @@ -42,7 +42,7 @@ error[E0038]: the trait `Qux` cannot be made into an object LL | static FOO: &Lint = &Lint { desc: "desc" }; | ^^^^^^ `Qux` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/unsizing-wfcheck-issue-127299.rs:4:8 | LL | trait Qux { @@ -65,7 +65,7 @@ error[E0038]: the trait `Qux` cannot be made into an object LL | static FOO: &Lint = &Lint { desc: "desc" }; | ^^^^^^ `Qux` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/unsizing-wfcheck-issue-127299.rs:4:8 | LL | trait Qux { diff --git a/tests/ui/suggestions/issue-116434-2015.rs b/tests/ui/suggestions/issue-116434-2015.rs index a53e2a044e9..2e94473eb1a 100644 --- a/tests/ui/suggestions/issue-116434-2015.rs +++ b/tests/ui/suggestions/issue-116434-2015.rs @@ -3,10 +3,10 @@ trait Foo { fn foo() -> Clone; //~^ WARNING trait objects without an explicit `dyn` are deprecated [bare_trait_objects] //~| WARNING this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! - //~| HELP if this is an object-safe trait, use `dyn` + //~| HELP if this is a dyn-compatible trait, use `dyn` //~| WARNING trait objects without an explicit `dyn` are deprecated [bare_trait_objects] //~| WARNING this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! - //~| HELP if this is an object-safe trait, use `dyn` + //~| HELP if this is a dyn-compatible trait, use `dyn` //~| ERROR the trait `Clone` cannot be made into an object [E0038] //~| HELP there is an associated type with the same name } @@ -18,10 +18,10 @@ trait DbInterface { fn handle() -> DbHandle; //~^ WARNING trait objects without an explicit `dyn` are deprecated [bare_trait_objects] //~| WARNING this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! - //~| HELP if this is an object-safe trait, use `dyn` + //~| HELP if this is a dyn-compatible trait, use `dyn` //~| WARNING trait objects without an explicit `dyn` are deprecated [bare_trait_objects] //~| WARNING this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! - //~| HELP if this is an object-safe trait, use `dyn` + //~| HELP if this is a dyn-compatible trait, use `dyn` //~| ERROR the trait `DbHandle` cannot be made into an object [E0038] //~| HELP there is an associated type with the same name } diff --git a/tests/ui/suggestions/issue-116434-2015.stderr b/tests/ui/suggestions/issue-116434-2015.stderr index 73a1cfa9c1d..24fc87f765f 100644 --- a/tests/ui/suggestions/issue-116434-2015.stderr +++ b/tests/ui/suggestions/issue-116434-2015.stderr @@ -7,7 +7,7 @@ LL | fn foo() -> Clone; = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! = note: for more information, see = note: `#[warn(bare_trait_objects)]` on by default -help: if this is an object-safe trait, use `dyn` +help: if this is a dyn-compatible trait, use `dyn` | LL | fn foo() -> dyn Clone; | +++ @@ -20,7 +20,7 @@ LL | fn handle() -> DbHandle; | = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! = note: for more information, see -help: if this is an object-safe trait, use `dyn` +help: if this is a dyn-compatible trait, use `dyn` | LL | fn handle() -> dyn DbHandle; | +++ @@ -34,7 +34,7 @@ LL | fn foo() -> Clone; = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! = note: for more information, see = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -help: if this is an object-safe trait, use `dyn` +help: if this is a dyn-compatible trait, use `dyn` | LL | fn foo() -> dyn Clone; | +++ @@ -46,7 +46,7 @@ LL | fn foo() -> Clone; | ^^^^^ `Clone` cannot be made into an object | = note: the trait cannot be made into an object because it requires `Self: Sized` - = note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit + = note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit help: there is an associated type with the same name | LL | fn foo() -> Self::Clone; @@ -61,7 +61,7 @@ LL | fn handle() -> DbHandle; = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! = note: for more information, see = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -help: if this is an object-safe trait, use `dyn` +help: if this is a dyn-compatible trait, use `dyn` | LL | fn handle() -> dyn DbHandle; | +++ @@ -72,7 +72,7 @@ error[E0038]: the trait `DbHandle` cannot be made into an object LL | fn handle() -> DbHandle; | ^^^^^^^^ `DbHandle` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/issue-116434-2015.rs:14:17 | LL | trait DbHandle: Sized {} diff --git a/tests/ui/suggestions/issue-116434-2021.stderr b/tests/ui/suggestions/issue-116434-2021.stderr index a10d6ef6da4..7f8cc147210 100644 --- a/tests/ui/suggestions/issue-116434-2021.stderr +++ b/tests/ui/suggestions/issue-116434-2021.stderr @@ -5,7 +5,7 @@ LL | fn foo() -> Clone; | ^^^^^ `Clone` cannot be made into an object | = note: the trait cannot be made into an object because it requires `Self: Sized` - = note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit + = note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit help: there is an associated type with the same name | LL | fn foo() -> Self::Clone; @@ -17,7 +17,7 @@ error[E0038]: the trait `DbHandle` cannot be made into an object LL | fn handle() -> DbHandle; | ^^^^^^^^ `DbHandle` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/issue-116434-2021.rs:10:17 | LL | trait DbHandle: Sized {} diff --git a/tests/ui/suggestions/issue-61963.stderr b/tests/ui/suggestions/issue-61963.stderr index 084b0cbeef2..734c88f3fd6 100644 --- a/tests/ui/suggestions/issue-61963.stderr +++ b/tests/ui/suggestions/issue-61963.stderr @@ -11,7 +11,7 @@ note: the lint level is defined here | LL | #![deny(bare_trait_objects)] | ^^^^^^^^^^^^^^^^^^ -help: if this is an object-safe trait, use `dyn` +help: if this is a dyn-compatible trait, use `dyn` | LL | bar: Box, | +++ @@ -24,7 +24,7 @@ LL | pub struct Foo { | = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! = note: for more information, see -help: if this is an object-safe trait, use `dyn` +help: if this is a dyn-compatible trait, use `dyn` | LL | dyn pub struct Foo { | +++ diff --git a/tests/ui/suggestions/issue-98500.stderr b/tests/ui/suggestions/issue-98500.stderr index aa66a9aa1e7..c4b446763af 100644 --- a/tests/ui/suggestions/issue-98500.stderr +++ b/tests/ui/suggestions/issue-98500.stderr @@ -4,7 +4,7 @@ error[E0038]: the trait `B` cannot be made into an object LL | struct S(Box); | ^^^^^ `B` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/auxiliary/not-object-safe.rs:4:8 | LL | fn f(); diff --git a/tests/ui/suggestions/object-unsafe-trait-references-self.stderr b/tests/ui/suggestions/object-unsafe-trait-references-self.stderr index 64270068471..6af55e7bcae 100644 --- a/tests/ui/suggestions/object-unsafe-trait-references-self.stderr +++ b/tests/ui/suggestions/object-unsafe-trait-references-self.stderr @@ -4,7 +4,7 @@ error[E0038]: the trait `Trait` cannot be made into an object LL | fn bar(x: &dyn Trait) {} | ^^^^^^^^^ `Trait` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/object-unsafe-trait-references-self.rs:2:22 | LL | trait Trait { @@ -23,7 +23,7 @@ error[E0038]: the trait `Other` cannot be made into an object LL | fn foo(x: &dyn Other) {} | ^^^^^^^^^ `Other` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/object-unsafe-trait-references-self.rs:11:14 | LL | trait Other: Sized {} diff --git a/tests/ui/suggestions/object-unsafe-trait-should-use-self-2021-without-dyn.stderr b/tests/ui/suggestions/object-unsafe-trait-should-use-self-2021-without-dyn.stderr index 60eb72ab4f7..a17f821ebec 100644 --- a/tests/ui/suggestions/object-unsafe-trait-should-use-self-2021-without-dyn.stderr +++ b/tests/ui/suggestions/object-unsafe-trait-should-use-self-2021-without-dyn.stderr @@ -17,7 +17,7 @@ error[E0038]: the trait `A` cannot be made into an object LL | fn f(a: A) -> A; | ^ `A` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/object-unsafe-trait-should-use-self-2021-without-dyn.rs:3:10 | LL | trait A: Sized { @@ -44,7 +44,7 @@ error[E0038]: the trait `B` cannot be made into an object LL | fn f(b: B) -> B; | ^ `B` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/object-unsafe-trait-should-use-self-2021-without-dyn.rs:11:8 | LL | trait B { @@ -81,7 +81,7 @@ LL | fn f(&self, c: C) -> C; | | | help: consider changing method `f`'s `self` parameter to be `&self` (notice the capitalization): `&Self` | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/object-unsafe-trait-should-use-self-2021-without-dyn.rs:18:10 | LL | trait C { @@ -95,7 +95,7 @@ error[E0782]: trait objects must include the `dyn` keyword LL | fn f(a: A) -> A; | ^ | - = note: `A` it is not object safe, so it can't be `dyn` + = note: `A` it is dyn-incompatible, so it can't be `dyn` help: use a new generic type parameter, constrained by `A` | LL | fn f(a: T) -> A; @@ -111,7 +111,7 @@ error[E0782]: trait objects must include the `dyn` keyword LL | fn f(a: A) -> A; | ^ | -help: `A` is not object safe, use `impl A` to return an opaque type, as long as you return a single underlying type +help: `A` is dyn-incompatible, use `impl A` to return an opaque type, as long as you return a single underlying type | LL | fn f(a: A) -> impl A; | ++++ @@ -122,7 +122,7 @@ error[E0782]: trait objects must include the `dyn` keyword LL | fn f(b: B) -> B; | ^ | - = note: `B` it is not object safe, so it can't be `dyn` + = note: `B` it is dyn-incompatible, so it can't be `dyn` help: use a new generic type parameter, constrained by `B` | LL | fn f(b: T) -> B; @@ -138,7 +138,7 @@ error[E0782]: trait objects must include the `dyn` keyword LL | fn f(b: B) -> B; | ^ | -help: `B` is not object safe, use `impl B` to return an opaque type, as long as you return a single underlying type +help: `B` is dyn-incompatible, use `impl B` to return an opaque type, as long as you return a single underlying type | LL | fn f(b: B) -> impl B; | ++++ @@ -149,7 +149,7 @@ error[E0782]: trait objects must include the `dyn` keyword LL | fn f(&self, c: C) -> C; | ^ | - = note: `C` it is not object safe, so it can't be `dyn` + = note: `C` it is dyn-incompatible, so it can't be `dyn` help: use a new generic type parameter, constrained by `C` | LL | fn f(&self, c: T) -> C; @@ -165,7 +165,7 @@ error[E0782]: trait objects must include the `dyn` keyword LL | fn f(&self, c: C) -> C; | ^ | -help: `C` is not object safe, use `impl C` to return an opaque type, as long as you return a single underlying type +help: `C` is dyn-incompatible, use `impl C` to return an opaque type, as long as you return a single underlying type | LL | fn f(&self, c: C) -> impl C; | ++++ diff --git a/tests/ui/suggestions/object-unsafe-trait-should-use-self-2021.stderr b/tests/ui/suggestions/object-unsafe-trait-should-use-self-2021.stderr index d6376be9c04..a7d36d9ebee 100644 --- a/tests/ui/suggestions/object-unsafe-trait-should-use-self-2021.stderr +++ b/tests/ui/suggestions/object-unsafe-trait-should-use-self-2021.stderr @@ -17,7 +17,7 @@ error[E0038]: the trait `A` cannot be made into an object LL | fn f(a: dyn A) -> dyn A; | ^^^^^ `A` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/object-unsafe-trait-should-use-self-2021.rs:3:10 | LL | trait A: Sized { @@ -44,7 +44,7 @@ error[E0038]: the trait `B` cannot be made into an object LL | fn f(a: dyn B) -> dyn B; | ^^^^^ `B` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/object-unsafe-trait-should-use-self-2021.rs:9:8 | LL | trait B { diff --git a/tests/ui/suggestions/object-unsafe-trait-should-use-self.stderr b/tests/ui/suggestions/object-unsafe-trait-should-use-self.stderr index 55047b42698..28952933c64 100644 --- a/tests/ui/suggestions/object-unsafe-trait-should-use-self.stderr +++ b/tests/ui/suggestions/object-unsafe-trait-should-use-self.stderr @@ -17,7 +17,7 @@ error[E0038]: the trait `A` cannot be made into an object LL | fn f(a: A) -> A; | ^ `A` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/object-unsafe-trait-should-use-self.rs:2:10 | LL | trait A: Sized { @@ -44,7 +44,7 @@ error[E0038]: the trait `B` cannot be made into an object LL | fn f(a: B) -> B; | ^ `B` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/object-unsafe-trait-should-use-self.rs:8:8 | LL | trait B { diff --git a/tests/ui/suggestions/object-unsafe-trait-should-use-where-sized.stderr b/tests/ui/suggestions/object-unsafe-trait-should-use-where-sized.stderr index abbf56cfac8..5e3a0290d42 100644 --- a/tests/ui/suggestions/object-unsafe-trait-should-use-where-sized.stderr +++ b/tests/ui/suggestions/object-unsafe-trait-should-use-where-sized.stderr @@ -4,7 +4,7 @@ error[E0038]: the trait `Trait` cannot be made into an object LL | fn bar(x: &dyn Trait) {} | ^^^^^^^^^ `Trait` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/object-unsafe-trait-should-use-where-sized.rs:5:8 | LL | trait Trait { diff --git a/tests/ui/suggestions/suggest-swapping-self-ty-and-trait.stderr b/tests/ui/suggestions/suggest-swapping-self-ty-and-trait.stderr index 5d805d97a43..d1da9a89c19 100644 --- a/tests/ui/suggestions/suggest-swapping-self-ty-and-trait.stderr +++ b/tests/ui/suggestions/suggest-swapping-self-ty-and-trait.stderr @@ -67,7 +67,7 @@ LL | impl<'a, T> Struct for Trait<'a, T> {} = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! = note: for more information, see = note: `#[warn(bare_trait_objects)]` on by default -help: if this is an object-safe trait, use `dyn` +help: if this is a dyn-compatible trait, use `dyn` | LL | impl<'a, T> Struct for dyn Trait<'a, T> {} | +++ @@ -80,7 +80,7 @@ LL | impl<'a, T> Enum for Trait<'a, T> {} | = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! = note: for more information, see -help: if this is an object-safe trait, use `dyn` +help: if this is a dyn-compatible trait, use `dyn` | LL | impl<'a, T> Enum for dyn Trait<'a, T> {} | +++ @@ -93,7 +93,7 @@ LL | impl<'a, T> Union for Trait<'a, T> {} | = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! = note: for more information, see -help: if this is an object-safe trait, use `dyn` +help: if this is a dyn-compatible trait, use `dyn` | LL | impl<'a, T> Union for dyn Trait<'a, T> {} | +++ diff --git a/tests/ui/traits/alias/object-fail.stderr b/tests/ui/traits/alias/object-fail.stderr index a27a3ea0ec0..1b89b87db9f 100644 --- a/tests/ui/traits/alias/object-fail.stderr +++ b/tests/ui/traits/alias/object-fail.stderr @@ -4,7 +4,7 @@ error[E0038]: the trait `Eq` cannot be made into an object LL | let _: &dyn EqAlias = &123; | ^^^^^^^^^^^ `Eq` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $SRC_DIR/core/src/cmp.rs:LL:COL | = note: the trait cannot be made into an object because it uses `Self` as a type parameter diff --git a/tests/ui/traits/bound/not-on-bare-trait.stderr b/tests/ui/traits/bound/not-on-bare-trait.stderr index f1e7a28654a..1e385f73823 100644 --- a/tests/ui/traits/bound/not-on-bare-trait.stderr +++ b/tests/ui/traits/bound/not-on-bare-trait.stderr @@ -7,7 +7,7 @@ LL | fn foo(_x: Foo + Send) { = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! = note: for more information, see = note: `#[warn(bare_trait_objects)]` on by default -help: if this is an object-safe trait, use `dyn` +help: if this is a dyn-compatible trait, use `dyn` | LL | fn foo(_x: dyn Foo + Send) { | +++ diff --git a/tests/ui/traits/issue-20692.stderr b/tests/ui/traits/issue-20692.stderr index 30e3c9da1a0..5e6a967fdc4 100644 --- a/tests/ui/traits/issue-20692.stderr +++ b/tests/ui/traits/issue-20692.stderr @@ -4,7 +4,7 @@ error[E0038]: the trait `Array` cannot be made into an object LL | &dyn Array; | ^^^^^^^^^^ `Array` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/issue-20692.rs:1:14 | LL | trait Array: Sized + Copy {} @@ -19,7 +19,7 @@ error[E0038]: the trait `Array` cannot be made into an object LL | let _ = x | ^ `Array` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/issue-20692.rs:1:14 | LL | trait Array: Sized + Copy {} diff --git a/tests/ui/traits/issue-28576.stderr b/tests/ui/traits/issue-28576.stderr index 7e0f52bc4fe..23581f2ee51 100644 --- a/tests/ui/traits/issue-28576.stderr +++ b/tests/ui/traits/issue-28576.stderr @@ -25,7 +25,7 @@ LL | / dyn Bar LL | | | |________________________^ `Bar` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/issue-28576.rs:5:16 | LL | pub trait Bar: Foo { diff --git a/tests/ui/traits/issue-38404.stderr b/tests/ui/traits/issue-38404.stderr index 19d4035b54c..145eeb88dd5 100644 --- a/tests/ui/traits/issue-38404.stderr +++ b/tests/ui/traits/issue-38404.stderr @@ -4,7 +4,7 @@ error[E0038]: the trait `B` cannot be made into an object LL | trait C: A> {} | ^^^^^^^^^^^^^^^^^^^^^^^^ `B` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/issue-38404.rs:1:13 | LL | trait A: std::ops::Add + Sized {} @@ -18,7 +18,7 @@ error[E0038]: the trait `B` cannot be made into an object LL | trait C: A> {} | ^^^^^^^^^^^^^^^^^^^^^^^^ `B` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/issue-38404.rs:1:13 | LL | trait A: std::ops::Add + Sized {} @@ -33,7 +33,7 @@ error[E0038]: the trait `B` cannot be made into an object LL | trait C: A> {} | ^^^^^^^^^^^^^^^^^^^^^^^^ `B` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/issue-38404.rs:1:13 | LL | trait A: std::ops::Add + Sized {} diff --git a/tests/ui/traits/issue-38604.stderr b/tests/ui/traits/issue-38604.stderr index 3ab9af21bc4..5c788b0c85d 100644 --- a/tests/ui/traits/issue-38604.stderr +++ b/tests/ui/traits/issue-38604.stderr @@ -4,7 +4,7 @@ error[E0038]: the trait `Foo` cannot be made into an object LL | let _f: Box = | ^^^^^^^^^^^^ `Foo` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/issue-38604.rs:2:22 | LL | trait Foo where u32: Q { @@ -19,7 +19,7 @@ error[E0038]: the trait `Foo` cannot be made into an object LL | Box::new(()); | ^^^^^^^^^^^^ `Foo` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/issue-38604.rs:2:22 | LL | trait Foo where u32: Q { diff --git a/tests/ui/traits/issue-72410.stderr b/tests/ui/traits/issue-72410.stderr index 58266e1842e..6d56a198fc1 100644 --- a/tests/ui/traits/issue-72410.stderr +++ b/tests/ui/traits/issue-72410.stderr @@ -4,7 +4,7 @@ error[E0038]: the trait `Bar` cannot be made into an object LL | where for<'a> &'a mut [dyn Bar]: ; | ^^^^^^^^^^^^^^^^^ `Bar` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/issue-72410.rs:13:8 | LL | pub trait Bar { diff --git a/tests/ui/traits/issue-78372.stderr b/tests/ui/traits/issue-78372.stderr index cdcb0cdf259..9b93ffe8efb 100644 --- a/tests/ui/traits/issue-78372.stderr +++ b/tests/ui/traits/issue-78372.stderr @@ -64,7 +64,7 @@ LL | fn foo(self: Smaht); LL | impl Marker for dyn Foo {} | ^^^^^^^ `Foo` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/issue-78372.rs:9:18 | LL | trait Foo: X {} diff --git a/tests/ui/traits/item-privacy.stderr b/tests/ui/traits/item-privacy.stderr index fd474fac155..c20d2f723c5 100644 --- a/tests/ui/traits/item-privacy.stderr +++ b/tests/ui/traits/item-privacy.stderr @@ -142,7 +142,7 @@ error[E0038]: the trait `assoc_const::C` cannot be made into an object LL | ::A; | ^^^^^ `assoc_const::C` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/item-privacy.rs:25:15 | LL | const A: u8 = 0; diff --git a/tests/ui/traits/non_lifetime_binders/supertrait-object-safety.stderr b/tests/ui/traits/non_lifetime_binders/supertrait-object-safety.stderr index b6e540c5ffc..0854ea28150 100644 --- a/tests/ui/traits/non_lifetime_binders/supertrait-object-safety.stderr +++ b/tests/ui/traits/non_lifetime_binders/supertrait-object-safety.stderr @@ -13,7 +13,7 @@ error[E0038]: the trait `Foo` cannot be made into an object LL | let x: &dyn Foo = &(); | ^^^ `Foo` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/supertrait-object-safety.rs:4:12 | LL | trait Foo: for Bar {} @@ -29,7 +29,7 @@ error[E0038]: the trait `Foo` cannot be made into an object LL | let x: &dyn Foo = &(); | ^^^^^^^^ `Foo` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/supertrait-object-safety.rs:4:12 | LL | trait Foo: for Bar {} @@ -44,7 +44,7 @@ error[E0038]: the trait `Foo` cannot be made into an object LL | needs_bar(x); | ^^^^^^^^^ `Foo` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/supertrait-object-safety.rs:4:12 | LL | trait Foo: for Bar {} diff --git a/tests/ui/traits/object/canonicalize-fresh-infer-vars-issue-103626.stderr b/tests/ui/traits/object/canonicalize-fresh-infer-vars-issue-103626.stderr index d5e9b1be63b..960802e2f8f 100644 --- a/tests/ui/traits/object/canonicalize-fresh-infer-vars-issue-103626.stderr +++ b/tests/ui/traits/object/canonicalize-fresh-infer-vars-issue-103626.stderr @@ -12,7 +12,7 @@ error[E0038]: the trait `FromResidual` cannot be made into an object LL | let b: &dyn FromResidual = &(); | ^^^^^^^^^^^^^^^^^ `FromResidual` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/canonicalize-fresh-infer-vars-issue-103626.rs:2:8 | LL | trait FromResidual::Residual> { diff --git a/tests/ui/traits/object/macro-matcher.stderr b/tests/ui/traits/object/macro-matcher.stderr index 6d1e236c048..7924c86e294 100644 --- a/tests/ui/traits/object/macro-matcher.stderr +++ b/tests/ui/traits/object/macro-matcher.stderr @@ -11,7 +11,7 @@ LL | m!(dyn Copy + Send + 'static); | ^^^^^^^^^^^^^^^^^^^^^^^^^ `Copy` cannot be made into an object | = note: the trait cannot be made into an object because it requires `Self: Sized` - = note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit + = note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit error: aborting due to 2 previous errors diff --git a/tests/ui/traits/object/object-unsafe-missing-assoc-type.stderr b/tests/ui/traits/object/object-unsafe-missing-assoc-type.stderr index 4c636c5e922..9258b38f26c 100644 --- a/tests/ui/traits/object/object-unsafe-missing-assoc-type.stderr +++ b/tests/ui/traits/object/object-unsafe-missing-assoc-type.stderr @@ -4,7 +4,7 @@ error[E0038]: the trait `Foo` cannot be made into an object LL | fn bar(x: &dyn Foo) {} | ^^^ `Foo` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/object-unsafe-missing-assoc-type.rs:2:10 | LL | trait Foo { @@ -19,7 +19,7 @@ error[E0038]: the trait `Foo` cannot be made into an object LL | fn bar(x: &dyn Foo) {} | ^^^ `Foo` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/object-unsafe-missing-assoc-type.rs:2:10 | LL | trait Foo { @@ -35,7 +35,7 @@ error[E0038]: the trait `Foo` cannot be made into an object LL | fn bar(x: &dyn Foo) {} | ^^^ `Foo` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/object-unsafe-missing-assoc-type.rs:2:10 | LL | trait Foo { @@ -51,7 +51,7 @@ error[E0038]: the trait `Foo` cannot be made into an object LL | fn bar(x: &dyn Foo) {} | ^^^^^^^ `Foo` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/object-unsafe-missing-assoc-type.rs:2:10 | LL | trait Foo { diff --git a/tests/ui/traits/object/pretty.stderr b/tests/ui/traits/object/pretty.stderr index 6964d97c08e..ca56bdbb67a 100644 --- a/tests/ui/traits/object/pretty.stderr +++ b/tests/ui/traits/object/pretty.stderr @@ -1,4 +1,4 @@ -warning: unnecessary associated type bound for not object safe associated type +warning: unnecessary associated type bound for dyn-incompatible associated type --> $DIR/pretty.rs:41:35 | LL | fn dyn_has_gat(x: &dyn HasGat = ()>) { x } diff --git a/tests/ui/traits/object/safety.stderr b/tests/ui/traits/object/safety.stderr index 19a46a502c2..a2cb656b08d 100644 --- a/tests/ui/traits/object/safety.stderr +++ b/tests/ui/traits/object/safety.stderr @@ -4,7 +4,7 @@ error[E0038]: the trait `Tr` cannot be made into an object LL | let _: &dyn Tr = &St; | ^^^ `Tr` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/safety.rs:4:8 | LL | trait Tr { @@ -28,7 +28,7 @@ error[E0038]: the trait `Tr` cannot be made into an object LL | let _: &dyn Tr = &St; | ^^^^^^^ `Tr` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/safety.rs:4:8 | LL | trait Tr { diff --git a/tests/ui/traits/test-2.stderr b/tests/ui/traits/test-2.stderr index 0ee64cc0952..3da95b47844 100644 --- a/tests/ui/traits/test-2.stderr +++ b/tests/ui/traits/test-2.stderr @@ -32,7 +32,7 @@ error[E0038]: the trait `bar` cannot be made into an object LL | (Box::new(10) as Box).dup(); | ^^^^^^^^^^^^ `bar` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/test-2.rs:4:30 | LL | trait bar { fn dup(&self) -> Self; fn blah(&self); } @@ -52,7 +52,7 @@ error[E0038]: the trait `bar` cannot be made into an object LL | (Box::new(10) as Box).dup(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `bar` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/test-2.rs:4:30 | LL | trait bar { fn dup(&self) -> Self; fn blah(&self); } @@ -72,7 +72,7 @@ error[E0038]: the trait `bar` cannot be made into an object LL | (Box::new(10) as Box).dup(); | ^^^^^^^^^^^^ `bar` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/test-2.rs:4:30 | LL | trait bar { fn dup(&self) -> Self; fn blah(&self); } diff --git a/tests/ui/traits/trait-upcasting/multiple_supertrait_upcastable.rs b/tests/ui/traits/trait-upcasting/multiple_supertrait_upcastable.rs index 3c6ab86e4c6..626630e60b7 100644 --- a/tests/ui/traits/trait-upcasting/multiple_supertrait_upcastable.rs +++ b/tests/ui/traits/trait-upcasting/multiple_supertrait_upcastable.rs @@ -5,6 +5,6 @@ trait A {} trait B {} trait C: A + B {} -//~^ ERROR `C` is object-safe and has multiple supertraits +//~^ ERROR `C` is dyn-compatible and has multiple supertraits fn main() {} diff --git a/tests/ui/traits/trait-upcasting/multiple_supertrait_upcastable.stderr b/tests/ui/traits/trait-upcasting/multiple_supertrait_upcastable.stderr index d075102b2e8..fab781026b1 100644 --- a/tests/ui/traits/trait-upcasting/multiple_supertrait_upcastable.stderr +++ b/tests/ui/traits/trait-upcasting/multiple_supertrait_upcastable.stderr @@ -1,4 +1,4 @@ -error: `C` is object-safe and has multiple supertraits +error: `C` is dyn-compatible and has multiple supertraits --> $DIR/multiple_supertrait_upcastable.rs:7:1 | LL | trait C: A + B {} diff --git a/tests/ui/traits/unspecified-self-in-trait-ref.stderr b/tests/ui/traits/unspecified-self-in-trait-ref.stderr index 3614348ceed..22dceadc10d 100644 --- a/tests/ui/traits/unspecified-self-in-trait-ref.stderr +++ b/tests/ui/traits/unspecified-self-in-trait-ref.stderr @@ -7,7 +7,7 @@ LL | let a = Foo::lol(); = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! = note: for more information, see = note: `#[warn(bare_trait_objects)]` on by default -help: if this is an object-safe trait, use `dyn` +help: if this is a dyn-compatible trait, use `dyn` | LL | let a = ::lol(); | ++++ + @@ -26,7 +26,7 @@ LL | let b = Foo::<_>::lol(); | = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! = note: for more information, see -help: if this is an object-safe trait, use `dyn` +help: if this is a dyn-compatible trait, use `dyn` | LL | let b = >::lol(); | ++++ + @@ -45,7 +45,7 @@ LL | let c = Bar::lol(); | = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! = note: for more information, see -help: if this is an object-safe trait, use `dyn` +help: if this is a dyn-compatible trait, use `dyn` | LL | let c = ::lol(); | ++++ + @@ -64,7 +64,7 @@ LL | let d = Bar::::lol(); | = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! = note: for more information, see -help: if this is an object-safe trait, use `dyn` +help: if this is a dyn-compatible trait, use `dyn` | LL | let d = >::lol(); | ++++ + @@ -83,7 +83,7 @@ LL | let e = Bar::::lol(); | = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! = note: for more information, see -help: if this is an object-safe trait, use `dyn` +help: if this is a dyn-compatible trait, use `dyn` | LL | let e = >::lol(); | ++++ + diff --git a/tests/ui/type/type-parameter-defaults-referencing-Self-ppaux.stderr b/tests/ui/type/type-parameter-defaults-referencing-Self-ppaux.stderr index 4412c49eadd..2d5bcf1fbc4 100644 --- a/tests/ui/type/type-parameter-defaults-referencing-Self-ppaux.stderr +++ b/tests/ui/type/type-parameter-defaults-referencing-Self-ppaux.stderr @@ -16,7 +16,7 @@ error[E0038]: the trait `MyAdd` cannot be made into an object LL | let y = x as dyn MyAdd; | ^^^^^^^^^^^^^^ `MyAdd` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/type-parameter-defaults-referencing-Self-ppaux.rs:6:55 | LL | trait MyAdd { fn add(&self, other: &Rhs) -> Self; } diff --git a/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122199.stderr b/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122199.stderr index f2456f99e62..6b309c223af 100644 --- a/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122199.stderr +++ b/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122199.stderr @@ -34,7 +34,7 @@ LL | trait Trait { = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! = note: for more information, see = note: `#[warn(bare_trait_objects)]` on by default -help: if this is an object-safe trait, use `dyn` +help: if this is a dyn-compatible trait, use `dyn` | LL | trait Trait { | +++ @@ -67,7 +67,7 @@ LL | fn fnc(&self) -> Trait { | = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! = note: for more information, see -help: if this is an object-safe trait, use `dyn` +help: if this is a dyn-compatible trait, use `dyn` | LL | fn fnc(&self) -> Trait { | +++ @@ -80,7 +80,7 @@ LL | fn fnc(&self) -> Trait { | = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! = note: for more information, see -help: if this is an object-safe trait, use `dyn` +help: if this is a dyn-compatible trait, use `dyn` | LL | fn fnc(&self) -> dyn Trait { | +++ @@ -94,7 +94,7 @@ LL | trait Trait { = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! = note: for more information, see = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -help: if this is an object-safe trait, use `dyn` +help: if this is a dyn-compatible trait, use `dyn` | LL | trait Trait { | +++ @@ -105,7 +105,7 @@ error[E0038]: the trait `Trait` cannot be made into an object LL | trait Trait { | ^^^^^ `Trait` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:12:8 | LL | trait Trait { @@ -121,7 +121,7 @@ error[E0038]: the trait `Trait` cannot be made into an object LL | trait Trait { | ^^^^^^^^^^^^^^^^^^^^ `Trait` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:12:8 | LL | trait Trait { @@ -162,7 +162,7 @@ LL | fn fnc(&self) -> Trait { = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! = note: for more information, see = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -help: if this is an object-safe trait, use `dyn` +help: if this is a dyn-compatible trait, use `dyn` | LL | fn fnc(&self) -> Trait { | +++ @@ -173,7 +173,7 @@ error[E0038]: the trait `Trait` cannot be made into an object LL | fn fnc(&self) -> Trait { | ^^^^^ `Trait` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:12:8 | LL | trait Trait { @@ -189,7 +189,7 @@ error[E0038]: the trait `Trait` cannot be made into an object LL | trait Trait { | ^^^^^^^^^^^^^^^^^^^^ `Trait` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:12:8 | LL | trait Trait { diff --git a/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122989.stderr b/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122989.stderr index a0fd11de2dc..d2b0e2d92e0 100644 --- a/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122989.stderr +++ b/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122989.stderr @@ -7,7 +7,7 @@ LL | trait Foo> { = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! = note: for more information, see = note: `#[warn(bare_trait_objects)]` on by default -help: if this is an object-safe trait, use `dyn` +help: if this is a dyn-compatible trait, use `dyn` | LL | trait Foo> { | +++ @@ -20,7 +20,7 @@ LL | trait Bar> {} | = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! = note: for more information, see -help: if this is an object-safe trait, use `dyn` +help: if this is a dyn-compatible trait, use `dyn` | LL | trait Bar> {} | +++ @@ -50,7 +50,7 @@ error[E0038]: the trait `Foo` cannot be made into an object LL | trait Foo> { | ^ `Foo` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/ice-hir-wf-check-anon-const-issue-122989.rs:8:8 | LL | trait Foo> { @@ -81,7 +81,7 @@ error[E0038]: the trait `Foo` cannot be made into an object LL | trait Bar> {} | ^^^^^^^^^^^^^^^ `Foo` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/ice-hir-wf-check-anon-const-issue-122989.rs:8:8 | LL | trait Foo> { diff --git a/tests/ui/wf/issue-87495.stderr b/tests/ui/wf/issue-87495.stderr index 3ccfd7f8d79..5973fff3e00 100644 --- a/tests/ui/wf/issue-87495.stderr +++ b/tests/ui/wf/issue-87495.stderr @@ -4,7 +4,7 @@ error[E0038]: the trait `T` cannot be made into an object LL | const CONST: (bool, dyn T); | ^^^^^ `T` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/issue-87495.rs:4:11 | LL | trait T { diff --git a/tests/ui/wf/wf-convert-unsafe-trait-obj-box.stderr b/tests/ui/wf/wf-convert-unsafe-trait-obj-box.stderr index 85f5073364f..2565e25a242 100644 --- a/tests/ui/wf/wf-convert-unsafe-trait-obj-box.stderr +++ b/tests/ui/wf/wf-convert-unsafe-trait-obj-box.stderr @@ -4,7 +4,7 @@ error[E0038]: the trait `Trait` cannot be made into an object LL | let t_box: Box = Box::new(S); | ^^^^^^^^^^^ `Trait` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/wf-convert-unsafe-trait-obj-box.rs:6:14 | LL | trait Trait: Sized {} @@ -20,7 +20,7 @@ error[E0038]: the trait `Trait` cannot be made into an object LL | takes_box(Box::new(S)); | ^^^^^^^^^^^ `Trait` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/wf-convert-unsafe-trait-obj-box.rs:6:14 | LL | trait Trait: Sized {} @@ -36,7 +36,7 @@ error[E0038]: the trait `Trait` cannot be made into an object LL | Box::new(S) as Box; | ^^^^^^^^^^^ `Trait` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/wf-convert-unsafe-trait-obj-box.rs:6:14 | LL | trait Trait: Sized {} diff --git a/tests/ui/wf/wf-convert-unsafe-trait-obj.stderr b/tests/ui/wf/wf-convert-unsafe-trait-obj.stderr index a2a19631649..97f6bcd0428 100644 --- a/tests/ui/wf/wf-convert-unsafe-trait-obj.stderr +++ b/tests/ui/wf/wf-convert-unsafe-trait-obj.stderr @@ -4,7 +4,7 @@ error[E0038]: the trait `Trait` cannot be made into an object LL | let t: &dyn Trait = &S; | ^^ `Trait` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/wf-convert-unsafe-trait-obj.rs:6:14 | LL | trait Trait: Sized {} @@ -20,7 +20,7 @@ error[E0038]: the trait `Trait` cannot be made into an object LL | takes_trait(&S); | ^^ `Trait` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/wf-convert-unsafe-trait-obj.rs:6:14 | LL | trait Trait: Sized {} @@ -36,7 +36,7 @@ error[E0038]: the trait `Trait` cannot be made into an object LL | &S as &dyn Trait; | ^^ `Trait` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/wf-convert-unsafe-trait-obj.rs:6:14 | LL | trait Trait: Sized {} diff --git a/tests/ui/wf/wf-fn-where-clause.stderr b/tests/ui/wf/wf-fn-where-clause.stderr index 40f2f452639..fbfe42ac624 100644 --- a/tests/ui/wf/wf-fn-where-clause.stderr +++ b/tests/ui/wf/wf-fn-where-clause.stderr @@ -21,7 +21,7 @@ LL | fn bar() where Vec:, {} | ^^^^^^^^^^^^^ `Copy` cannot be made into an object | = note: the trait cannot be made into an object because it requires `Self: Sized` - = note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit + = note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit error[E0277]: the size for values of type `(dyn Copy + 'static)` cannot be known at compilation time --> $DIR/wf-fn-where-clause.rs:12:16 diff --git a/tests/ui/wf/wf-object-safe.stderr b/tests/ui/wf/wf-object-safe.stderr index cc5351346b3..7c14f3d2f8b 100644 --- a/tests/ui/wf/wf-object-safe.stderr +++ b/tests/ui/wf/wf-object-safe.stderr @@ -4,7 +4,7 @@ error[E0038]: the trait `A` cannot be made into an object LL | let _x: &dyn A; | ^^^^^^ `A` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/wf-object-safe.rs:5:23 | LL | trait A { diff --git a/tests/ui/wf/wf-unsafe-trait-obj-match.stderr b/tests/ui/wf/wf-unsafe-trait-obj-match.stderr index 8d5b377988c..edbdec6a5ef 100644 --- a/tests/ui/wf/wf-unsafe-trait-obj-match.stderr +++ b/tests/ui/wf/wf-unsafe-trait-obj-match.stderr @@ -18,7 +18,7 @@ error[E0038]: the trait `Trait` cannot be made into an object LL | Some(()) => &S, | ^^ `Trait` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/wf-unsafe-trait-obj-match.rs:6:14 | LL | trait Trait: Sized {} @@ -40,7 +40,7 @@ LL | | None => &R, LL | | }; | |_____^ `Trait` cannot be made into an object | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/wf-unsafe-trait-obj-match.rs:6:14 | LL | trait Trait: Sized {} From c69b457ac211a2da93a0784e221b06f09df297de Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 25 Sep 2024 15:07:21 +0200 Subject: [PATCH 248/683] enable pthread_cond_timedwait test on Android --- src/tools/miri/ci/ci.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri/ci/ci.sh b/src/tools/miri/ci/ci.sh index fe0633135df..1cbb78d8254 100755 --- a/src/tools/miri/ci/ci.sh +++ b/src/tools/miri/ci/ci.sh @@ -154,7 +154,7 @@ case $HOST_TARGET in TEST_TARGET=i686-unknown-freebsd run_tests_minimal $BASIC $UNIX threadname pthread time fs TEST_TARGET=x86_64-unknown-illumos run_tests_minimal $BASIC $UNIX thread sync available-parallelism time tls TEST_TARGET=x86_64-pc-solaris run_tests_minimal $BASIC $UNIX thread sync available-parallelism time tls - TEST_TARGET=aarch64-linux-android run_tests_minimal $BASIC $UNIX hashmap pthread time --skip threadname --skip pthread_cond_timedwait + TEST_TARGET=aarch64-linux-android run_tests_minimal $BASIC $UNIX hashmap pthread time --skip threadname TEST_TARGET=wasm32-wasip2 run_tests_minimal $BASIC wasm TEST_TARGET=wasm32-unknown-unknown run_tests_minimal no_std empty_main wasm # this target doesn't really have std TEST_TARGET=thumbv7em-none-eabihf run_tests_minimal no_std From 7d4d356bddbf3328fb4978322c541e667a387fa5 Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Wed, 25 Sep 2024 09:15:55 -0400 Subject: [PATCH 249/683] Enable the cfg stdarch_intel_sde to fix the segfault when running the tests under SDE --- .github/workflows/stdarch.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/stdarch.yml b/.github/workflows/stdarch.yml index dde1ce21d7b..95f40ff2861 100644 --- a/.github/workflows/stdarch.yml +++ b/.github/workflows/stdarch.yml @@ -36,6 +36,7 @@ jobs: - name: Install packages run: sudo apt-get install ninja-build ripgrep + # TODO: remove when we have binutils version 2.43 in the repo. - name: Install more recent binutils run: | echo "deb http://archive.ubuntu.com/ubuntu oracular main universe" | sudo tee /etc/apt/sources.list.d/oracular-copies.list @@ -102,4 +103,5 @@ jobs: run: | # FIXME: these tests fail when the sysroot is compiled with LTO because of a missing symbol in proc-macro. # TODO: remove --skip test_mm512_stream_ps when stdarch is updated in rustc. - STDARCH_TEST_EVERYTHING=1 CHANNEL=release CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_RUNNER="${{ matrix.cargo_runner }}" TARGET=x86_64-unknown-linux-gnu CG_RUSTFLAGS="-Ainternal_features" ./y.sh cargo test --manifest-path build/build_sysroot/sysroot_src/library/stdarch/Cargo.toml -- --skip rtm --skip tbm --skip sse4a --skip test_mm512_stream_ps + # TODO: remove --skip test_tile_ when it's implemented. + STDARCH_TEST_EVERYTHING=1 CHANNEL=release CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_RUNNER="${{ matrix.cargo_runner }}" TARGET=x86_64-unknown-linux-gnu CG_RUSTFLAGS="-Ainternal_features --cfg stdarch_intel_sde" ./y.sh cargo test --manifest-path build/build_sysroot/sysroot_src/library/stdarch/Cargo.toml -- --skip rtm --skip tbm --skip sse4a --skip test_mm512_stream_ps --skip test_tile_ From 1151eb1c8467a454ceb65a0f9f5e71104a591ef3 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 25 Sep 2024 15:21:08 +0200 Subject: [PATCH 250/683] fix some cfg logic around optimize_for_size and 16-bit targets --- library/core/src/slice/sort/shared/mod.rs | 2 +- library/core/src/slice/sort/stable/mod.rs | 14 +++++++------- library/core/src/slice/sort/unstable/mod.rs | 6 +++--- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/library/core/src/slice/sort/shared/mod.rs b/library/core/src/slice/sort/shared/mod.rs index e0f8d475a2e..e2cdcb3dd51 100644 --- a/library/core/src/slice/sort/shared/mod.rs +++ b/library/core/src/slice/sort/shared/mod.rs @@ -1,4 +1,4 @@ -#![cfg_attr(feature = "optimize_for_size", allow(dead_code))] +#![cfg_attr(any(feature = "optimize_for_size", target_pointer_width = "16"), allow(dead_code))] use crate::marker::Freeze; diff --git a/library/core/src/slice/sort/stable/mod.rs b/library/core/src/slice/sort/stable/mod.rs index e13fbc37e80..7adcc83b818 100644 --- a/library/core/src/slice/sort/stable/mod.rs +++ b/library/core/src/slice/sort/stable/mod.rs @@ -1,22 +1,22 @@ //! This module contains the entry points for `slice::sort`. -#[cfg(not(feature = "optimize_for_size"))] +#[cfg(not(any(feature = "optimize_for_size", target_pointer_width = "16")))] use crate::cmp; use crate::intrinsics; use crate::mem::{self, MaybeUninit, SizedTypeProperties}; -#[cfg(not(feature = "optimize_for_size"))] +#[cfg(not(any(feature = "optimize_for_size", target_pointer_width = "16")))] use crate::slice::sort::shared::smallsort::{ SMALL_SORT_GENERAL_SCRATCH_LEN, StableSmallSortTypeImpl, insertion_sort_shift_left, }; pub(crate) mod merge; -#[cfg(not(feature = "optimize_for_size"))] +#[cfg(not(any(feature = "optimize_for_size", target_pointer_width = "16")))] pub(crate) mod drift; -#[cfg(not(feature = "optimize_for_size"))] +#[cfg(not(any(feature = "optimize_for_size", target_pointer_width = "16")))] pub(crate) mod quicksort; -#[cfg(feature = "optimize_for_size")] +#[cfg(any(feature = "optimize_for_size", target_pointer_width = "16"))] pub(crate) mod tiny; /// Stable sort called driftsort by Orson Peters and Lukas Bergdoll. @@ -45,7 +45,7 @@ pub fn sort bool, BufT: BufGuard>(v: &mut [T], is_less cfg_if! { if #[cfg(target_pointer_width = "16")] { - let heap_buf = BufT::with_capacity(alloc_len); + let mut heap_buf = BufT::with_capacity(alloc_len); let scratch = heap_buf.as_uninit_slice_mut(); } else { // For small inputs 4KiB of stack storage suffices, which allows us to avoid @@ -85,7 +85,7 @@ pub fn sort bool, BufT: BufGuard>(v: &mut [T], is_less /// /// Deliberately don't inline the main sorting routine entrypoint to ensure the /// inlined insertion sort i-cache footprint remains minimal. -#[cfg(not(feature = "optimize_for_size"))] +#[cfg(not(any(feature = "optimize_for_size", target_pointer_width = "16")))] #[inline(never)] fn driftsort_main bool, BufT: BufGuard>(v: &mut [T], is_less: &mut F) { // By allocating n elements of memory we can ensure the entire input can diff --git a/library/core/src/slice/sort/unstable/mod.rs b/library/core/src/slice/sort/unstable/mod.rs index 8bbd85443d4..2eb653c4601 100644 --- a/library/core/src/slice/sort/unstable/mod.rs +++ b/library/core/src/slice/sort/unstable/mod.rs @@ -2,9 +2,9 @@ use crate::intrinsics; use crate::mem::SizedTypeProperties; -#[cfg(not(feature = "optimize_for_size"))] +#[cfg(not(any(feature = "optimize_for_size", target_pointer_width = "16")))] use crate::slice::sort::shared::find_existing_run; -#[cfg(not(feature = "optimize_for_size"))] +#[cfg(not(any(feature = "optimize_for_size", target_pointer_width = "16")))] use crate::slice::sort::shared::smallsort::insertion_sort_shift_left; pub(crate) mod heapsort; @@ -55,7 +55,7 @@ pub fn sort bool>(v: &mut [T], is_less: &mut F) { /// /// Deliberately don't inline the main sorting routine entrypoint to ensure the /// inlined insertion sort i-cache footprint remains minimal. -#[cfg(not(feature = "optimize_for_size"))] +#[cfg(not(any(feature = "optimize_for_size", target_pointer_width = "16")))] #[inline(never)] fn ipnsort(v: &mut [T], is_less: &mut F) where From 540e41f8b3822661d2f9d0768bbfe1dd3bb65e4d Mon Sep 17 00:00:00 2001 From: Alice Ryhl Date: Wed, 25 Sep 2024 10:23:30 +0200 Subject: [PATCH 251/683] Add missing module flags for function-return=thunk-extern --- compiler/rustc_codegen_llvm/src/context.rs | 14 +++++++++++++- tests/codegen/function-return.rs | 6 ++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index 2b8912d1db2..81b82840472 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -19,7 +19,7 @@ use rustc_middle::ty::{self, Instance, Ty, TyCtxt}; use rustc_middle::{bug, span_bug}; use rustc_session::Session; use rustc_session::config::{ - BranchProtection, CFGuard, CFProtection, CrateType, DebugInfo, PAuthKey, PacRet, + BranchProtection, CFGuard, CFProtection, CrateType, DebugInfo, FunctionReturn, PAuthKey, PacRet, }; use rustc_span::source_map::Spanned; use rustc_span::{DUMMY_SP, Span}; @@ -378,6 +378,18 @@ pub(crate) unsafe fn create_module<'ll>( } } + match sess.opts.unstable_opts.function_return { + FunctionReturn::Keep => {} + FunctionReturn::ThunkExtern => unsafe { + llvm::LLVMRustAddModuleFlagU32( + llmod, + llvm::LLVMModFlagBehavior::Override, + c"function_return_thunk_extern".as_ptr(), + 1, + ) + }, + } + match (sess.opts.unstable_opts.small_data_threshold, sess.target.small_data_threshold_support()) { // Set up the small-data optimization limit for architectures that use diff --git a/tests/codegen/function-return.rs b/tests/codegen/function-return.rs index 0ca1a41ee86..2b9de4e1478 100644 --- a/tests/codegen/function-return.rs +++ b/tests/codegen/function-return.rs @@ -26,3 +26,9 @@ pub fn foo() { // keep-thunk-extern: attributes #0 = { {{.*}}fn_ret_thunk_extern{{.*}} } // thunk-extern-keep-NOT: fn_ret_thunk_extern } + +// unset-NOT: !{{[0-9]+}} = !{i32 4, !"function_return_thunk_extern", i32 1} +// keep-NOT: !{{[0-9]+}} = !{i32 4, !"function_return_thunk_extern", i32 1} +// thunk-extern: !{{[0-9]+}} = !{i32 4, !"function_return_thunk_extern", i32 1} +// keep-thunk-extern: !{{[0-9]+}} = !{i32 4, !"function_return_thunk_extern", i32 1} +// thunk-extern-keep-NOT: !{{[0-9]+}} = !{i32 4, !"function_return_thunk_extern", i32 1} From 897e94179763e5ec4cde76154abdf2a9392bef65 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 25 Sep 2024 16:37:04 +0200 Subject: [PATCH 252/683] switch custom target JSON test to a less exotic target --- src/tools/miri/ci/ci.sh | 3 +-- src/tools/miri/tests/avr.json | 25 ------------------- .../miri/tests/x86_64-unknown-kernel.json | 24 ++++++++++++++++++ 3 files changed, 25 insertions(+), 27 deletions(-) delete mode 100644 src/tools/miri/tests/avr.json create mode 100644 src/tools/miri/tests/x86_64-unknown-kernel.json diff --git a/src/tools/miri/ci/ci.sh b/src/tools/miri/ci/ci.sh index 2d4cf696d8c..284a1fa9b99 100755 --- a/src/tools/miri/ci/ci.sh +++ b/src/tools/miri/ci/ci.sh @@ -159,8 +159,7 @@ case $HOST_TARGET in TEST_TARGET=wasm32-unknown-unknown run_tests_minimal no_std empty_main wasm # this target doesn't really have std TEST_TARGET=thumbv7em-none-eabihf run_tests_minimal no_std # Custom target JSON file - # FIXME: disabled due to . - #TEST_TARGET=tests/avr.json MIRI_NO_STD=1 run_tests_minimal no_std + TEST_TARGET=tests/x86_64-unknown-kernel.json MIRI_NO_STD=1 run_tests_minimal no_std ;; i686-pc-windows-msvc) # Host diff --git a/src/tools/miri/tests/avr.json b/src/tools/miri/tests/avr.json deleted file mode 100644 index 1e00b0f57ef..00000000000 --- a/src/tools/miri/tests/avr.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "arch": "avr", - "cpu": "atmega328p", - "data-layout": "e-P1-p:16:8-i8:8-i16:8-i32:8-i64:8-f32:8-f64:8-n8-a:8", - "env": "", - "executables": true, - "linker": "avr-gcc", - "linker-flavor": "gcc", - "linker-is-gnu": true, - "llvm-target": "avr-unknown-unknown", - "os": "unknown", - "position-independent-executables": false, - "exe-suffix": ".elf", - "eh-frame-header": false, - "pre-link-args": { - "gcc": ["-mmcu=atmega328p"] - }, - "late-link-args": { - "gcc": ["-lgcc"] - }, - "target-c-int-width": "16", - "target-endian": "little", - "target-pointer-width": "16", - "vendor": "unknown" -} diff --git a/src/tools/miri/tests/x86_64-unknown-kernel.json b/src/tools/miri/tests/x86_64-unknown-kernel.json new file mode 100644 index 00000000000..8135b618d0d --- /dev/null +++ b/src/tools/miri/tests/x86_64-unknown-kernel.json @@ -0,0 +1,24 @@ +{ + "llvm-target": "x86_64-unknown-none", + "target-endian": "little", + "target-pointer-width": "64", + "target-c-int-width": "32", + "data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128", + "arch": "x86_64", + "os": "none", + "env": "", + "vendor": "unknown", + "linker": "rust-lld", + "linker-flavor": "gnu-lld", + "features": "-mmx,-sse,-sse2,-sse3,-ssse3,-sse4.1,-sse4.2,-avx,-avx2,+soft-float", + "dynamic-linking": false, + "executables": true, + "relocation-model": "static", + "code-model": "kernel", + "disable-redzone": true, + "frame-pointer": "always", + "exe-suffix": "", + "has-rpath": false, + "no-default-libraries": true, + "position-independent-executables": false +} From 8fc8e03150ed69cc37a3e21b319a4d9bf247292f Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 23 Sep 2024 03:56:20 -0400 Subject: [PATCH 253/683] Validate unsize coercion in MIR validation --- compiler/rustc_mir_transform/src/validate.rs | 50 +++++++++++++++++-- tests/crashes/129219.rs | 26 ---------- tests/ui/mir/validate/validate-unsize-cast.rs | 33 ++++++++++++ .../mir/validate/validate-unsize-cast.stderr | 20 ++++++++ 4 files changed, 100 insertions(+), 29 deletions(-) delete mode 100644 tests/crashes/129219.rs create mode 100644 tests/ui/mir/validate/validate-unsize-cast.rs create mode 100644 tests/ui/mir/validate/validate-unsize-cast.stderr diff --git a/compiler/rustc_mir_transform/src/validate.rs b/compiler/rustc_mir_transform/src/validate.rs index eda0b8c75f3..c9a844e4734 100644 --- a/compiler/rustc_mir_transform/src/validate.rs +++ b/compiler/rustc_mir_transform/src/validate.rs @@ -4,7 +4,8 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir::LangItem; use rustc_index::IndexVec; use rustc_index::bit_set::BitSet; -use rustc_infer::traits::Reveal; +use rustc_infer::infer::TyCtxtInferExt; +use rustc_infer::traits::{Obligation, ObligationCause, Reveal}; use rustc_middle::mir::coverage::CoverageKind; use rustc_middle::mir::visit::{NonUseContext, PlaceContext, Visitor}; use rustc_middle::mir::*; @@ -16,6 +17,8 @@ use rustc_middle::ty::{ use rustc_middle::{bug, span_bug}; use rustc_target::abi::{FIRST_VARIANT, Size}; use rustc_target::spec::abi::Abi; +use rustc_trait_selection::traits::ObligationCtxt; +use rustc_type_ir::Upcast; use crate::util::{is_within_packed, relate_types}; @@ -586,6 +589,22 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { crate::util::relate_types(self.tcx, self.param_env, variance, src, dest) } + + /// Check that the given predicate definitely holds in the param-env of this MIR body. + fn predicate_must_hold_modulo_regions( + &self, + pred: impl Upcast, ty::Predicate<'tcx>>, + ) -> bool { + let infcx = self.tcx.infer_ctxt().build(); + let ocx = ObligationCtxt::new(&infcx); + ocx.register_obligation(Obligation::new( + self.tcx, + ObligationCause::dummy(), + self.param_env, + pred, + )); + ocx.select_all_or_error().is_empty() + } } impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { @@ -1202,8 +1221,33 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { } } CastKind::PointerCoercion(PointerCoercion::Unsize, _) => { - // This is used for all `CoerceUnsized` types, - // not just pointers/references, so is hard to check. + // Pointers being unsize coerced should at least implement + // `CoerceUnsized`. + if !self.predicate_must_hold_modulo_regions(ty::TraitRef::new( + self.tcx, + self.tcx.require_lang_item( + LangItem::CoerceUnsized, + Some(self.body.source_info(location).span), + ), + [op_ty, *target_type], + )) { + self.fail(location, format!("Unsize coercion, but `{op_ty}` isn't coercible to `{target_type}`")); + } + + // FIXME: Codegen has an additional assumption, where if the + // principal trait def id of what's being casted doesn't change, + // then we don't need to adjust the vtable at all. This + // corresponds to the fact that `dyn Tr: Unsize>` + // requires that `A = B`; we don't allow *upcasting* objects + // between the same trait with different args. Nothing actually + // validates this, though. While it's true right now, if we for + // some reason were to relax the `Unsize` trait, it could become + // unsound. We should eventually validate that, but it would + // require peeling `&Box, ..>>` down to + // the trait object that's being unsized, and that's rather + // annoying, and also it would need to be opportunistic since + // this MIR is not yet fully monomorphized, so we may bottom + // out in an alias or a projection or something. } CastKind::PointerCoercion(PointerCoercion::DynStar, _) => { // FIXME(dyn-star): make sure nothing needs to be done here. diff --git a/tests/crashes/129219.rs b/tests/crashes/129219.rs deleted file mode 100644 index effbfcd8b8e..00000000000 --- a/tests/crashes/129219.rs +++ /dev/null @@ -1,26 +0,0 @@ -//@ known-bug: rust-lang/rust#129219 -//@ compile-flags: -Zmir-opt-level=5 -Zvalidate-mir --edition=2018 - -use core::marker::Unsize; - -pub trait CastTo: Unsize {} - -impl CastTo for U {} - -impl Cast for T {} -pub trait Cast { - fn cast(&self) -> &T - where - Self: CastTo, - { - self - } -} - -pub trait Foo {} -impl Foo for [i32; 0] {} - -fn main() { - let x: &dyn Foo = &[]; - let x = x.cast::<[i32]>(); -} diff --git a/tests/ui/mir/validate/validate-unsize-cast.rs b/tests/ui/mir/validate/validate-unsize-cast.rs new file mode 100644 index 00000000000..198af8d2e13 --- /dev/null +++ b/tests/ui/mir/validate/validate-unsize-cast.rs @@ -0,0 +1,33 @@ +//@ compile-flags: -Zmir-opt-level=0 -Zmir-enable-passes=+Inline,+GVN -Zvalidate-mir + +#![feature(unsize)] + +use std::marker::Unsize; + +pub trait CastTo: Unsize {} + +// Not well-formed! +impl CastTo for T {} +//~^ ERROR the trait bound `T: Unsize` is not satisfied + +pub trait Cast { + fn cast(&self) + where + Self: CastTo; +} +impl Cast for T { + #[inline(always)] + fn cast(&self) + where + Self: CastTo, + { + let x: &U = self; + } +} + +fn main() { + // When we inline this call, then we run GVN, then + // GVN tries to evaluate the `() -> [i32]` unsize. + // That's invalid! + ().cast::<[i32]>(); +} diff --git a/tests/ui/mir/validate/validate-unsize-cast.stderr b/tests/ui/mir/validate/validate-unsize-cast.stderr new file mode 100644 index 00000000000..cfb47b34e98 --- /dev/null +++ b/tests/ui/mir/validate/validate-unsize-cast.stderr @@ -0,0 +1,20 @@ +error[E0277]: the trait bound `T: Unsize` is not satisfied + --> $DIR/validate-unsize-cast.rs:10:42 + | +LL | impl CastTo for T {} + | ^ the trait `Unsize` is not implemented for `T` + | + = note: all implementations of `Unsize` are provided automatically by the compiler, see for more information +note: required by a bound in `CastTo` + --> $DIR/validate-unsize-cast.rs:7:30 + | +LL | pub trait CastTo: Unsize {} + | ^^^^^^^^^ required by this bound in `CastTo` +help: consider further restricting this bound + | +LL | impl, U: ?Sized> CastTo for T {} + | ++++++++++++++++++++++++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. From 3209943604a9b3565a3cef4c43b567f65cfdf192 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 23 Sep 2024 13:52:02 -0400 Subject: [PATCH 254/683] Add a debug assertion in codegen that unsize casts of the same principal trait def id are truly NOPs --- .../rustc_codegen_cranelift/src/unsize.rs | 17 ++++++++++++- compiler/rustc_codegen_ssa/src/base.rs | 24 +++++++++++++++++-- compiler/rustc_mir_transform/src/validate.rs | 15 ------------ 3 files changed, 38 insertions(+), 18 deletions(-) diff --git a/compiler/rustc_codegen_cranelift/src/unsize.rs b/compiler/rustc_codegen_cranelift/src/unsize.rs index 8cfe93b4d9c..339628053a9 100644 --- a/compiler/rustc_codegen_cranelift/src/unsize.rs +++ b/compiler/rustc_codegen_cranelift/src/unsize.rs @@ -34,7 +34,22 @@ pub(crate) fn unsized_info<'tcx>( let old_info = old_info.expect("unsized_info: missing old info for trait upcasting coercion"); if data_a.principal_def_id() == data_b.principal_def_id() { - // A NOP cast that doesn't actually change anything, should be allowed even with invalid vtables. + // Codegen takes advantage of the additional assumption, where if the + // principal trait def id of what's being casted doesn't change, + // then we don't need to adjust the vtable at all. This + // corresponds to the fact that `dyn Tr: Unsize>` + // requires that `A = B`; we don't allow *upcasting* objects + // between the same trait with different args. If we, for + // some reason, were to relax the `Unsize` trait, it could become + // unsound, so let's assert here that the trait refs are *equal*. + // + // We can use `assert_eq` because the binders should have been anonymized, + // and because higher-ranked equality now requires the binders are equal. + debug_assert_eq!( + data_a.principal(), + data_b.principal(), + "NOP unsize vtable changed principal trait ref: {data_a} -> {data_b}" + ); return old_info; } diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index fcf48d3e4a3..5c67600e4ee 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -125,8 +125,28 @@ fn unsized_info<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( let old_info = old_info.expect("unsized_info: missing old info for trait upcasting coercion"); if data_a.principal_def_id() == data_b.principal_def_id() { - // A NOP cast that doesn't actually change anything, should be allowed even with - // invalid vtables. + // Codegen takes advantage of the additional assumption, where if the + // principal trait def id of what's being casted doesn't change, + // then we don't need to adjust the vtable at all. This + // corresponds to the fact that `dyn Tr: Unsize>` + // requires that `A = B`; we don't allow *upcasting* objects + // between the same trait with different args. If we, for + // some reason, were to relax the `Unsize` trait, it could become + // unsound, so let's assert here that the trait refs are *equal*. + // + // We can use `assert_eq` because the binders should have been anonymized, + // and because higher-ranked equality now requires the binders are equal. + debug_assert_eq!( + data_a.principal(), + data_b.principal(), + "NOP unsize vtable changed principal trait ref: {data_a} -> {data_b}" + ); + + // A NOP cast that doesn't actually change anything, let's avoid any + // unnecessary work. This relies on the assumption that if the principal + // traits are equal, then the associated type bounds (`dyn Trait`) + // are also equal, which is ensured by the fact that normalization is + // a function and we do not allow overlapping impls. return old_info; } diff --git a/compiler/rustc_mir_transform/src/validate.rs b/compiler/rustc_mir_transform/src/validate.rs index c9a844e4734..e353be6a105 100644 --- a/compiler/rustc_mir_transform/src/validate.rs +++ b/compiler/rustc_mir_transform/src/validate.rs @@ -1233,21 +1233,6 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { )) { self.fail(location, format!("Unsize coercion, but `{op_ty}` isn't coercible to `{target_type}`")); } - - // FIXME: Codegen has an additional assumption, where if the - // principal trait def id of what's being casted doesn't change, - // then we don't need to adjust the vtable at all. This - // corresponds to the fact that `dyn Tr: Unsize>` - // requires that `A = B`; we don't allow *upcasting* objects - // between the same trait with different args. Nothing actually - // validates this, though. While it's true right now, if we for - // some reason were to relax the `Unsize` trait, it could become - // unsound. We should eventually validate that, but it would - // require peeling `&Box, ..>>` down to - // the trait object that's being unsized, and that's rather - // annoying, and also it would need to be opportunistic since - // this MIR is not yet fully monomorphized, so we may bottom - // out in an alias or a projection or something. } CastKind::PointerCoercion(PointerCoercion::DynStar, _) => { // FIXME(dyn-star): make sure nothing needs to be done here. From ded22ea18174b47e8531d880b85e78f0471d7cb4 Mon Sep 17 00:00:00 2001 From: nora <48135649+Noratrieb@users.noreply.github.com> Date: Wed, 25 Sep 2024 17:40:55 +0200 Subject: [PATCH 255/683] Add tracking issue for io_error_inprogress --- library/std/src/io/error.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/io/error.rs b/library/std/src/io/error.rs index 795cc64e957..f20814dd95c 100644 --- a/library/std/src/io/error.rs +++ b/library/std/src/io/error.rs @@ -402,7 +402,7 @@ pub enum ErrorKind { /// The operation was partially successful and needs to be checked /// later on due to not blocking. - #[unstable(feature = "io_error_inprogress", issue = "none")] + #[unstable(feature = "io_error_inprogress", issue = "130840")] InProgress, // "Unusual" error kinds which do not correspond simply to (sets From c39ae569d6ab2fa3e8be19cb68d42732bbf082d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eduardo=20S=C3=A1nchez=20Mu=C3=B1oz?= Date: Mon, 9 Sep 2024 18:20:27 +0200 Subject: [PATCH 256/683] Revert "Avoid invalid NaN lint machine-applicable suggestion in const context" Reverts PR https://github.com/rust-lang/rust/pull/114486 (commit 1305a43d0a0c02cb224ab626745bd94af59c6098) --- compiler/rustc_lint/src/lints.rs | 2 +- compiler/rustc_lint/src/types.rs | 22 +++++++++------------ tests/ui/float/classify-runtime-const.rs | 1 - tests/ui/float/conv-bits-runtime-const.rs | 1 - tests/ui/lint/invalid-nan-comparison.stderr | 5 +++++ 5 files changed, 15 insertions(+), 16 deletions(-) diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index e49b102cb39..6ead71d96a8 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -1739,7 +1739,7 @@ pub(crate) enum InvalidNanComparisons { #[diag(lint_invalid_nan_comparisons_eq_ne)] EqNe { #[subdiagnostic] - suggestion: Option, + suggestion: InvalidNanComparisonsSuggestion, }, #[diag(lint_invalid_nan_comparisons_lt_le_gt_ge)] LtLeGtGe, diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index b5e501b92f0..fdc6e95e368 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -605,36 +605,32 @@ fn lint_nan<'tcx>( } fn eq_ne( - cx: &LateContext<'_>, e: &hir::Expr<'_>, l: &hir::Expr<'_>, r: &hir::Expr<'_>, f: impl FnOnce(Span, Span) -> InvalidNanComparisonsSuggestion, ) -> InvalidNanComparisons { - // FIXME(#72505): This suggestion can be restored if `f{32,64}::is_nan` is made const. - let suggestion = (!cx.tcx.hir().is_inside_const_context(e.hir_id)).then(|| { - if let Some(l_span) = l.span.find_ancestor_inside(e.span) - && let Some(r_span) = r.span.find_ancestor_inside(e.span) - { - f(l_span, r_span) - } else { - InvalidNanComparisonsSuggestion::Spanless - } - }); + let suggestion = if let Some(l_span) = l.span.find_ancestor_inside(e.span) + && let Some(r_span) = r.span.find_ancestor_inside(e.span) + { + f(l_span, r_span) + } else { + InvalidNanComparisonsSuggestion::Spanless + }; InvalidNanComparisons::EqNe { suggestion } } let lint = match binop.node { hir::BinOpKind::Eq | hir::BinOpKind::Ne if is_nan(cx, l) => { - eq_ne(cx, e, l, r, |l_span, r_span| InvalidNanComparisonsSuggestion::Spanful { + eq_ne(e, l, r, |l_span, r_span| InvalidNanComparisonsSuggestion::Spanful { nan_plus_binop: l_span.until(r_span), float: r_span.shrink_to_hi(), neg: (binop.node == hir::BinOpKind::Ne).then(|| r_span.shrink_to_lo()), }) } hir::BinOpKind::Eq | hir::BinOpKind::Ne if is_nan(cx, r) => { - eq_ne(cx, e, l, r, |l_span, r_span| InvalidNanComparisonsSuggestion::Spanful { + eq_ne(e, l, r, |l_span, r_span| InvalidNanComparisonsSuggestion::Spanful { nan_plus_binop: l_span.shrink_to_hi().to(r_span), float: l_span.shrink_to_hi(), neg: (binop.node == hir::BinOpKind::Ne).then(|| l_span.shrink_to_lo()), diff --git a/tests/ui/float/classify-runtime-const.rs b/tests/ui/float/classify-runtime-const.rs index 59a232c255e..49b623db02c 100644 --- a/tests/ui/float/classify-runtime-const.rs +++ b/tests/ui/float/classify-runtime-const.rs @@ -6,7 +6,6 @@ #![feature(f16_const)] #![feature(f128_const)] -#![feature(const_float_classify)] use std::hint::black_box; use std::num::FpCategory::*; diff --git a/tests/ui/float/conv-bits-runtime-const.rs b/tests/ui/float/conv-bits-runtime-const.rs index e85a889d2c2..60c45cc4cc1 100644 --- a/tests/ui/float/conv-bits-runtime-const.rs +++ b/tests/ui/float/conv-bits-runtime-const.rs @@ -3,7 +3,6 @@ // This tests the float classification functions, for regular runtime code and for const evaluation. -#![feature(const_float_classify)] #![feature(f16)] #![feature(f128)] #![feature(f16_const)] diff --git a/tests/ui/lint/invalid-nan-comparison.stderr b/tests/ui/lint/invalid-nan-comparison.stderr index f2d55c107ba..054c06d38b3 100644 --- a/tests/ui/lint/invalid-nan-comparison.stderr +++ b/tests/ui/lint/invalid-nan-comparison.stderr @@ -5,6 +5,11 @@ LL | const TEST: bool = 5f32 == f32::NAN; | ^^^^^^^^^^^^^^^^ | = note: `#[warn(invalid_nan_comparisons)]` on by default +help: use `f32::is_nan()` or `f64::is_nan()` instead + | +LL - const TEST: bool = 5f32 == f32::NAN; +LL + const TEST: bool = 5f32.is_nan(); + | warning: incorrect NaN comparison, NaN cannot be directly compared to itself --> $DIR/invalid-nan-comparison.rs:14:5 From 2dacf7ac61bdea8321ff623a28dd2b56cf54701c Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 4 Mar 2024 19:59:09 +0000 Subject: [PATCH 257/683] Collect relevant item bounds from trait clauses for nested rigid projections, GATs --- .../src/collect/item_bounds.rs | 226 +++++++++++++++++- .../imply-relevant-nested-item-bounds-2.rs | 28 +++ ...ply-relevant-nested-item-bounds-for-gat.rs | 19 ++ .../imply-relevant-nested-item-bounds.rs | 23 ++ 4 files changed, 286 insertions(+), 10 deletions(-) create mode 100644 tests/ui/associated-types/imply-relevant-nested-item-bounds-2.rs create mode 100644 tests/ui/associated-types/imply-relevant-nested-item-bounds-for-gat.rs create mode 100644 tests/ui/associated-types/imply-relevant-nested-item-bounds.rs diff --git a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs index c64741625a4..3e2adaad370 100644 --- a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs +++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs @@ -1,8 +1,9 @@ -use rustc_data_structures::fx::FxIndexSet; +use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_hir as hir; use rustc_infer::traits::util; +use rustc_middle::ty::fold::shift_vars; use rustc_middle::ty::{ - self, GenericArgs, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, + self, GenericArgs, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt, }; use rustc_middle::{bug, span_bug}; use rustc_span::Span; @@ -42,14 +43,110 @@ fn associated_type_bounds<'tcx>( let trait_def_id = tcx.local_parent(assoc_item_def_id); let trait_predicates = tcx.trait_explicit_predicates_and_bounds(trait_def_id); - let bounds_from_parent = trait_predicates.predicates.iter().copied().filter(|(pred, _)| { - match pred.kind().skip_binder() { - ty::ClauseKind::Trait(tr) => tr.self_ty() == item_ty, - ty::ClauseKind::Projection(proj) => proj.projection_term.self_ty() == item_ty, - ty::ClauseKind::TypeOutlives(outlives) => outlives.0 == item_ty, - _ => false, - } - }); + let item_trait_ref = ty::TraitRef::identity(tcx, tcx.parent(assoc_item_def_id.to_def_id())); + let bounds_from_parent = + trait_predicates.predicates.iter().copied().filter_map(|(pred, span)| { + let mut clause_ty = match pred.kind().skip_binder() { + ty::ClauseKind::Trait(tr) => tr.self_ty(), + ty::ClauseKind::Projection(proj) => proj.projection_term.self_ty(), + ty::ClauseKind::TypeOutlives(outlives) => outlives.0, + _ => return None, + }; + + // The code below is quite involved, so let me explain. + // + // We loop here, because we also want to collect vars for nested associated items as + // well. For example, given a clause like `Self::A::B`, we want to add that to the + // item bounds for `A`, so that we may use that bound in the case that `Self::A::B` is + // rigid. + // + // Secondly, regarding bound vars, when we see a where clause that mentions a GAT + // like `for<'a, ...> Self::Assoc<'a, ...>: Bound<'b, ...>`, we want to turn that into + // an item bound on the GAT, where all of the GAT args are substituted with the GAT's + // param regions, and then keep all of the other late-bound vars in the bound around. + // We need to "compress" the binder so that it doesn't mention any of those vars that + // were mapped to params. + let gat_vars = loop { + if let ty::Alias(ty::Projection, alias_ty) = *clause_ty.kind() { + if alias_ty.trait_ref(tcx) == item_trait_ref + && alias_ty.def_id == assoc_item_def_id.to_def_id() + { + break &alias_ty.args[item_trait_ref.args.len()..]; + } else { + // Only collect *self* type bounds if the filter is for self. + match filter { + PredicateFilter::SelfOnly | PredicateFilter::SelfThatDefines(_) => { + return None; + } + PredicateFilter::All | PredicateFilter::SelfAndAssociatedTypeBounds => { + } + } + + clause_ty = alias_ty.self_ty(); + continue; + } + } + + return None; + }; + // Special-case: No GAT vars, no mapping needed. + if gat_vars.is_empty() { + return Some((pred, span)); + } + + // First, check that all of the GAT args are substituted with a unique late-bound arg. + // If we find a duplicate, then it can't be mapped to the definition's params. + let mut mapping = FxIndexMap::default(); + let generics = tcx.generics_of(assoc_item_def_id); + for (param, var) in std::iter::zip(&generics.own_params, gat_vars) { + let existing = match var.unpack() { + ty::GenericArgKind::Lifetime(re) => { + if let ty::RegionKind::ReBound(ty::INNERMOST, bv) = re.kind() { + mapping.insert(bv.var, tcx.mk_param_from_def(param)) + } else { + return None; + } + } + ty::GenericArgKind::Type(ty) => { + if let ty::Bound(ty::INNERMOST, bv) = *ty.kind() { + mapping.insert(bv.var, tcx.mk_param_from_def(param)) + } else { + return None; + } + } + ty::GenericArgKind::Const(ct) => { + if let ty::ConstKind::Bound(ty::INNERMOST, bv) = ct.kind() { + mapping.insert(bv, tcx.mk_param_from_def(param)) + } else { + return None; + } + } + }; + + if existing.is_some() { + return None; + } + } + + // Finally, map all of the args in the GAT to the params we expect, and compress + // the remaining late-bound vars so that they count up from var 0. + let mut folder = MapAndCompressBoundVars { + tcx, + binder: ty::INNERMOST, + still_bound_vars: vec![], + mapping, + }; + let pred = pred.kind().skip_binder().fold_with(&mut folder); + + Some(( + ty::Binder::bind_with_vars( + pred, + tcx.mk_bound_variable_kinds(&folder.still_bound_vars), + ) + .upcast(tcx), + span, + )) + }); let all_bounds = tcx.arena.alloc_from_iter(bounds.clauses(tcx).chain(bounds_from_parent)); debug!( @@ -63,6 +160,115 @@ fn associated_type_bounds<'tcx>( all_bounds } +struct MapAndCompressBoundVars<'tcx> { + tcx: TyCtxt<'tcx>, + /// How deep are we? Makes sure we don't touch the vars of nested binders. + binder: ty::DebruijnIndex, + /// List of bound vars that remain unsubstituted because they were not + /// mentioned in the GAT's args. + still_bound_vars: Vec, + /// Subtle invariant: If the `GenericArg` is bound, then it should be + /// stored with the debruijn index of `INNERMOST` so it can be shifted + /// correctly during substitution. + mapping: FxIndexMap>, +} + +impl<'tcx> TypeFolder> for MapAndCompressBoundVars<'tcx> { + fn cx(&self) -> TyCtxt<'tcx> { + self.tcx + } + + fn fold_binder(&mut self, t: ty::Binder<'tcx, T>) -> ty::Binder<'tcx, T> + where + ty::Binder<'tcx, T>: TypeSuperFoldable>, + { + self.binder.shift_in(1); + let out = t.super_fold_with(self); + self.binder.shift_out(1); + out + } + + fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { + if !ty.has_bound_vars() { + return ty; + } + + if let ty::Bound(binder, old_bound) = *ty.kind() + && self.binder == binder + { + let mapped = if let Some(mapped) = self.mapping.get(&old_bound.var) { + mapped.expect_ty() + } else { + // If we didn't find a mapped generic, then make a new one. + // Allocate a new var idx, and insert a new bound ty. + let var = ty::BoundVar::from_usize(self.still_bound_vars.len()); + self.still_bound_vars.push(ty::BoundVariableKind::Ty(old_bound.kind)); + let mapped = Ty::new_bound(self.tcx, ty::INNERMOST, ty::BoundTy { + var, + kind: old_bound.kind, + }); + self.mapping.insert(old_bound.var, mapped.into()); + mapped + }; + + shift_vars(self.tcx, mapped, self.binder.as_u32()) + } else { + ty.super_fold_with(self) + } + } + + fn fold_region(&mut self, re: ty::Region<'tcx>) -> ty::Region<'tcx> { + if let ty::ReBound(binder, old_bound) = re.kind() + && self.binder == binder + { + let mapped = if let Some(mapped) = self.mapping.get(&old_bound.var) { + mapped.expect_region() + } else { + let var = ty::BoundVar::from_usize(self.still_bound_vars.len()); + self.still_bound_vars.push(ty::BoundVariableKind::Region(old_bound.kind)); + let mapped = ty::Region::new_bound(self.tcx, ty::INNERMOST, ty::BoundRegion { + var, + kind: old_bound.kind, + }); + self.mapping.insert(old_bound.var, mapped.into()); + mapped + }; + + shift_vars(self.tcx, mapped, self.binder.as_u32()) + } else { + re + } + } + + fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> { + if !ct.has_bound_vars() { + return ct; + } + + if let ty::ConstKind::Bound(binder, old_var) = ct.kind() + && self.binder == binder + { + let mapped = if let Some(mapped) = self.mapping.get(&old_var) { + mapped.expect_const() + } else { + let var = ty::BoundVar::from_usize(self.still_bound_vars.len()); + self.still_bound_vars.push(ty::BoundVariableKind::Const); + let mapped = ty::Const::new_bound(self.tcx, ty::INNERMOST, var); + self.mapping.insert(old_var, mapped.into()); + mapped + }; + + shift_vars(self.tcx, mapped, self.binder.as_u32()) + } else { + ct.super_fold_with(self) + } + } + + fn fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> { + if !p.has_bound_vars() { p } else { p.super_fold_with(self) } + } +} + /// Opaque types don't inherit bounds from their parent: for return position /// impl trait it isn't possible to write a suitable predicate on the /// containing function and for type-alias impl trait we don't have a backwards diff --git a/tests/ui/associated-types/imply-relevant-nested-item-bounds-2.rs b/tests/ui/associated-types/imply-relevant-nested-item-bounds-2.rs new file mode 100644 index 00000000000..864c3189350 --- /dev/null +++ b/tests/ui/associated-types/imply-relevant-nested-item-bounds-2.rs @@ -0,0 +1,28 @@ +//@ check-pass +//@ revisions: current next +//@[next] compile-flags: -Znext-solver + +trait Trait +where + Self::Assoc: Clone, +{ + type Assoc; +} + +fn foo(x: &T::Assoc) -> T::Assoc { + x.clone() +} + +trait Trait2 +where + Self::Assoc: Iterator, + ::Item: Clone, +{ + type Assoc; +} + +fn foo2(x: &::Item) -> ::Item { + x.clone() +} + +fn main() {} diff --git a/tests/ui/associated-types/imply-relevant-nested-item-bounds-for-gat.rs b/tests/ui/associated-types/imply-relevant-nested-item-bounds-for-gat.rs new file mode 100644 index 00000000000..4e3b0b3b148 --- /dev/null +++ b/tests/ui/associated-types/imply-relevant-nested-item-bounds-for-gat.rs @@ -0,0 +1,19 @@ +//@ check-pass + +// Test that `for<'a> Self::Gat<'a>: Debug` is implied in the definition of `Foo`, +// just as it would be if it weren't a GAT but just a regular associated type. + +use std::fmt::Debug; + +trait Foo +where + for<'a> Self::Gat<'a>: Debug, +{ + type Gat<'a>; +} + +fn test(x: T::Gat<'static>) { + println!("{:?}", x); +} + +fn main() {} diff --git a/tests/ui/associated-types/imply-relevant-nested-item-bounds.rs b/tests/ui/associated-types/imply-relevant-nested-item-bounds.rs new file mode 100644 index 00000000000..5a477a5b349 --- /dev/null +++ b/tests/ui/associated-types/imply-relevant-nested-item-bounds.rs @@ -0,0 +1,23 @@ +//@ check-pass +//@ revisions: current next +//@[next] compile-flags: -Znext-solver + +trait Foo +where + Self::Iterator: Iterator, + ::Item: Bar, +{ + type Iterator; + + fn iter() -> Self::Iterator; +} + +trait Bar { + fn bar(&self); +} + +fn x() { + T::iter().next().unwrap().bar(); +} + +fn main() {} From 149bd877de8c84870c303399e62770cf2a72fcf7 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 21 Sep 2024 14:19:03 -0400 Subject: [PATCH 258/683] Pull out into helper function --- .../src/collect/item_bounds.rs | 211 ++++++++++-------- 1 file changed, 112 insertions(+), 99 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs index 3e2adaad370..39b697bbfc1 100644 --- a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs +++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs @@ -45,107 +45,15 @@ fn associated_type_bounds<'tcx>( let item_trait_ref = ty::TraitRef::identity(tcx, tcx.parent(assoc_item_def_id.to_def_id())); let bounds_from_parent = - trait_predicates.predicates.iter().copied().filter_map(|(pred, span)| { - let mut clause_ty = match pred.kind().skip_binder() { - ty::ClauseKind::Trait(tr) => tr.self_ty(), - ty::ClauseKind::Projection(proj) => proj.projection_term.self_ty(), - ty::ClauseKind::TypeOutlives(outlives) => outlives.0, - _ => return None, - }; - - // The code below is quite involved, so let me explain. - // - // We loop here, because we also want to collect vars for nested associated items as - // well. For example, given a clause like `Self::A::B`, we want to add that to the - // item bounds for `A`, so that we may use that bound in the case that `Self::A::B` is - // rigid. - // - // Secondly, regarding bound vars, when we see a where clause that mentions a GAT - // like `for<'a, ...> Self::Assoc<'a, ...>: Bound<'b, ...>`, we want to turn that into - // an item bound on the GAT, where all of the GAT args are substituted with the GAT's - // param regions, and then keep all of the other late-bound vars in the bound around. - // We need to "compress" the binder so that it doesn't mention any of those vars that - // were mapped to params. - let gat_vars = loop { - if let ty::Alias(ty::Projection, alias_ty) = *clause_ty.kind() { - if alias_ty.trait_ref(tcx) == item_trait_ref - && alias_ty.def_id == assoc_item_def_id.to_def_id() - { - break &alias_ty.args[item_trait_ref.args.len()..]; - } else { - // Only collect *self* type bounds if the filter is for self. - match filter { - PredicateFilter::SelfOnly | PredicateFilter::SelfThatDefines(_) => { - return None; - } - PredicateFilter::All | PredicateFilter::SelfAndAssociatedTypeBounds => { - } - } - - clause_ty = alias_ty.self_ty(); - continue; - } - } - - return None; - }; - // Special-case: No GAT vars, no mapping needed. - if gat_vars.is_empty() { - return Some((pred, span)); - } - - // First, check that all of the GAT args are substituted with a unique late-bound arg. - // If we find a duplicate, then it can't be mapped to the definition's params. - let mut mapping = FxIndexMap::default(); - let generics = tcx.generics_of(assoc_item_def_id); - for (param, var) in std::iter::zip(&generics.own_params, gat_vars) { - let existing = match var.unpack() { - ty::GenericArgKind::Lifetime(re) => { - if let ty::RegionKind::ReBound(ty::INNERMOST, bv) = re.kind() { - mapping.insert(bv.var, tcx.mk_param_from_def(param)) - } else { - return None; - } - } - ty::GenericArgKind::Type(ty) => { - if let ty::Bound(ty::INNERMOST, bv) = *ty.kind() { - mapping.insert(bv.var, tcx.mk_param_from_def(param)) - } else { - return None; - } - } - ty::GenericArgKind::Const(ct) => { - if let ty::ConstKind::Bound(ty::INNERMOST, bv) = ct.kind() { - mapping.insert(bv, tcx.mk_param_from_def(param)) - } else { - return None; - } - } - }; - - if existing.is_some() { - return None; - } - } - - // Finally, map all of the args in the GAT to the params we expect, and compress - // the remaining late-bound vars so that they count up from var 0. - let mut folder = MapAndCompressBoundVars { + trait_predicates.predicates.iter().copied().filter_map(|(clause, span)| { + remap_gat_vars_and_recurse_into_nested_projections( tcx, - binder: ty::INNERMOST, - still_bound_vars: vec![], - mapping, - }; - let pred = pred.kind().skip_binder().fold_with(&mut folder); - - Some(( - ty::Binder::bind_with_vars( - pred, - tcx.mk_bound_variable_kinds(&folder.still_bound_vars), - ) - .upcast(tcx), + filter, + item_trait_ref, + assoc_item_def_id, span, - )) + clause, + ) }); let all_bounds = tcx.arena.alloc_from_iter(bounds.clauses(tcx).chain(bounds_from_parent)); @@ -160,6 +68,111 @@ fn associated_type_bounds<'tcx>( all_bounds } +/// The code below is quite involved, so let me explain. +/// +/// We loop here, because we also want to collect vars for nested associated items as +/// well. For example, given a clause like `Self::A::B`, we want to add that to the +/// item bounds for `A`, so that we may use that bound in the case that `Self::A::B` is +/// rigid. +/// +/// Secondly, regarding bound vars, when we see a where clause that mentions a GAT +/// like `for<'a, ...> Self::Assoc<'a, ...>: Bound<'b, ...>`, we want to turn that into +/// an item bound on the GAT, where all of the GAT args are substituted with the GAT's +/// param regions, and then keep all of the other late-bound vars in the bound around. +/// We need to "compress" the binder so that it doesn't mention any of those vars that +/// were mapped to params. +fn remap_gat_vars_and_recurse_into_nested_projections<'tcx>( + tcx: TyCtxt<'tcx>, + filter: PredicateFilter, + item_trait_ref: ty::TraitRef<'tcx>, + assoc_item_def_id: LocalDefId, + span: Span, + clause: ty::Clause<'tcx>, +) -> Option<(ty::Clause<'tcx>, Span)> { + let mut clause_ty = match clause.kind().skip_binder() { + ty::ClauseKind::Trait(tr) => tr.self_ty(), + ty::ClauseKind::Projection(proj) => proj.projection_term.self_ty(), + ty::ClauseKind::TypeOutlives(outlives) => outlives.0, + _ => return None, + }; + + let gat_vars = loop { + if let ty::Alias(ty::Projection, alias_ty) = *clause_ty.kind() { + if alias_ty.trait_ref(tcx) == item_trait_ref + && alias_ty.def_id == assoc_item_def_id.to_def_id() + { + // We have found the GAT in question... + // Return the vars, since we may need to remap them. + break &alias_ty.args[item_trait_ref.args.len()..]; + } else { + // Only collect *self* type bounds if the filter is for self. + match filter { + PredicateFilter::SelfOnly | PredicateFilter::SelfThatDefines(_) => { + return None; + } + PredicateFilter::All | PredicateFilter::SelfAndAssociatedTypeBounds => {} + } + + clause_ty = alias_ty.self_ty(); + continue; + } + } + + return None; + }; + + // Special-case: No GAT vars, no mapping needed. + if gat_vars.is_empty() { + return Some((clause, span)); + } + + // First, check that all of the GAT args are substituted with a unique late-bound arg. + // If we find a duplicate, then it can't be mapped to the definition's params. + let mut mapping = FxIndexMap::default(); + let generics = tcx.generics_of(assoc_item_def_id); + for (param, var) in std::iter::zip(&generics.own_params, gat_vars) { + let existing = match var.unpack() { + ty::GenericArgKind::Lifetime(re) => { + if let ty::RegionKind::ReBound(ty::INNERMOST, bv) = re.kind() { + mapping.insert(bv.var, tcx.mk_param_from_def(param)) + } else { + return None; + } + } + ty::GenericArgKind::Type(ty) => { + if let ty::Bound(ty::INNERMOST, bv) = *ty.kind() { + mapping.insert(bv.var, tcx.mk_param_from_def(param)) + } else { + return None; + } + } + ty::GenericArgKind::Const(ct) => { + if let ty::ConstKind::Bound(ty::INNERMOST, bv) = ct.kind() { + mapping.insert(bv, tcx.mk_param_from_def(param)) + } else { + return None; + } + } + }; + + if existing.is_some() { + return None; + } + } + + // Finally, map all of the args in the GAT to the params we expect, and compress + // the remaining late-bound vars so that they count up from var 0. + let mut folder = + MapAndCompressBoundVars { tcx, binder: ty::INNERMOST, still_bound_vars: vec![], mapping }; + let pred = clause.kind().skip_binder().fold_with(&mut folder); + + Some(( + ty::Binder::bind_with_vars(pred, tcx.mk_bound_variable_kinds(&folder.still_bound_vars)) + .upcast(tcx), + span, + )) +} + struct MapAndCompressBoundVars<'tcx> { tcx: TyCtxt<'tcx>, /// How deep are we? Makes sure we don't touch the vars of nested binders. From c5914753ad438fe53c3b97a079b595136dc862c9 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 21 Sep 2024 14:32:36 -0400 Subject: [PATCH 259/683] Add a few more tests, comments --- .../src/collect/item_bounds.rs | 6 ++++ ...ed-associated-type-bound-incompleteness.rs | 28 +++++++++++++++++ ...ssociated-type-bound-incompleteness.stderr | 16 ++++++++++ .../nested-gat-projection.rs | 31 +++++++++++++++++++ 4 files changed, 81 insertions(+) create mode 100644 tests/ui/associated-type-bounds/nested-associated-type-bound-incompleteness.rs create mode 100644 tests/ui/associated-type-bounds/nested-associated-type-bound-incompleteness.stderr create mode 100644 tests/ui/associated-type-bounds/nested-gat-projection.rs diff --git a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs index 39b697bbfc1..7557219aaa6 100644 --- a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs +++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs @@ -173,6 +173,12 @@ fn remap_gat_vars_and_recurse_into_nested_projections<'tcx>( )) } +/// Given some where clause like `for<'b, 'c> >::Gat<'b>: Bound<'c>`, +/// the mapping will map `'b` back to the GAT's `'b_identity`. Then we need to compress the +/// remaining bound var `'c` to index 0. +/// +/// This folder gives us: `for<'c> >::Gat<'b_identity>: Bound<'c>`, +/// which is sufficient for an item bound for `Gat`, since all of the GAT's args are identity. struct MapAndCompressBoundVars<'tcx> { tcx: TyCtxt<'tcx>, /// How deep are we? Makes sure we don't touch the vars of nested binders. diff --git a/tests/ui/associated-type-bounds/nested-associated-type-bound-incompleteness.rs b/tests/ui/associated-type-bounds/nested-associated-type-bound-incompleteness.rs new file mode 100644 index 00000000000..eb616631d1d --- /dev/null +++ b/tests/ui/associated-type-bounds/nested-associated-type-bound-incompleteness.rs @@ -0,0 +1,28 @@ +// Demonstrates a mostly-theoretical inference guidance now that we turn the where +// clause on `Trait` into an item bound, given that we prefer item bounds somewhat +// greedily in trait selection. + +trait Bound {} +impl Bound for U {} + +trait Trait +where + <::Assoc as Other>::Assoc: Bound, +{ + type Assoc: Other; +} + +trait Other { + type Assoc; +} + +fn impls_trait, U>() -> Vec { vec![] } + +fn foo() { + let mut vec_u = impls_trait::<<::Assoc as Other>::Assoc, _>(); + vec_u.sort(); + drop::>(vec_u); + //~^ ERROR mismatched types +} + +fn main() {} diff --git a/tests/ui/associated-type-bounds/nested-associated-type-bound-incompleteness.stderr b/tests/ui/associated-type-bounds/nested-associated-type-bound-incompleteness.stderr new file mode 100644 index 00000000000..c77400f3822 --- /dev/null +++ b/tests/ui/associated-type-bounds/nested-associated-type-bound-incompleteness.stderr @@ -0,0 +1,16 @@ +error[E0308]: mismatched types + --> $DIR/nested-associated-type-bound-incompleteness.rs:24:21 + | +LL | drop::>(vec_u); + | --------------- ^^^^^ expected `Vec`, found `Vec` + | | + | arguments to this function are incorrect + | + = note: expected struct `Vec` + found struct `Vec` +note: function defined here + --> $SRC_DIR/core/src/mem/mod.rs:LL:COL + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/associated-type-bounds/nested-gat-projection.rs b/tests/ui/associated-type-bounds/nested-gat-projection.rs new file mode 100644 index 00000000000..ad37da9ed19 --- /dev/null +++ b/tests/ui/associated-type-bounds/nested-gat-projection.rs @@ -0,0 +1,31 @@ +//@ check-pass + +trait Trait +where + for<'a> Self::Gat<'a>: OtherTrait, + for<'a, 'b, 'c> as OtherTrait>::OtherGat<'b>: HigherRanked<'c>, +{ + type Gat<'a>; +} + +trait OtherTrait { + type OtherGat<'b>; +} + +trait HigherRanked<'c> {} + +fn lower_ranked OtherTrait: HigherRanked<'c>>>() {} + +fn higher_ranked() +where + for<'a> T::Gat<'a>: OtherTrait, + for<'a, 'b, 'c> as OtherTrait>::OtherGat<'b>: HigherRanked<'c>, +{ +} + +fn test() { + lower_ranked::>(); + higher_ranked::(); +} + +fn main() {} From 8f1ed9b2e2930ded9c273fec566131519205a866 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 25 Sep 2024 19:45:37 +0200 Subject: [PATCH 260/683] Utf8Chunks: add link to Utf8Chunk --- library/core/src/str/lossy.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/library/core/src/str/lossy.rs b/library/core/src/str/lossy.rs index 3f31107acf0..e7677c8317a 100644 --- a/library/core/src/str/lossy.rs +++ b/library/core/src/str/lossy.rs @@ -8,6 +8,8 @@ impl [u8] { /// Creates an iterator over the contiguous valid UTF-8 ranges of this /// slice, and the non-UTF-8 fragments in between. /// + /// See the [`Utf8Chunk`] type for documenation of the items yielded by this iterator. + /// /// # Examples /// /// This function formats arbitrary but mostly-UTF-8 bytes into Rust source @@ -148,6 +150,8 @@ impl fmt::Debug for Debug<'_> { /// If you want a simple conversion from UTF-8 byte slices to string slices, /// [`from_utf8`] is easier to use. /// +/// See the [`Utf8Chunk`] type for documenation of the items yielded by this iterator. +/// /// [byteslice]: slice /// [`from_utf8`]: super::from_utf8 /// From 55fcd46f8803f8e1a5de98a04f14578cea5fcc04 Mon Sep 17 00:00:00 2001 From: Samuel Moelius Date: Sun, 18 Aug 2024 07:24:11 -0400 Subject: [PATCH 261/683] Extend `needless_lifetimes` to suggest eliding `impl` lifetimes --- clippy_lints/src/lifetimes.rs | 229 +++++++++++++++++++++++----------- 1 file changed, 159 insertions(+), 70 deletions(-) diff --git a/clippy_lints/src/lifetimes.rs b/clippy_lints/src/lifetimes.rs index 755afe959b3..dc6043ae981 100644 --- a/clippy_lints/src/lifetimes.rs +++ b/clippy_lints/src/lifetimes.rs @@ -6,8 +6,8 @@ use rustc_errors::Applicability; use rustc_hir::FnRetTy::Return; use rustc_hir::intravisit::nested_filter::{self as hir_nested_filter, NestedFilter}; use rustc_hir::intravisit::{ - Visitor, walk_fn_decl, walk_generic_param, walk_generics, walk_impl_item_ref, walk_item, walk_param_bound, - walk_poly_trait_ref, walk_trait_ref, walk_ty, + Visitor, walk_fn_decl, walk_generic_arg, walk_generics, walk_impl_item_ref, walk_item, walk_param_bound, + walk_poly_trait_ref, walk_trait_ref, walk_ty, walk_where_predicate, }; use rustc_hir::{ BareFnTy, BodyId, FnDecl, FnSig, GenericArg, GenericBound, GenericParam, GenericParamKind, Generics, Impl, @@ -21,7 +21,7 @@ use rustc_middle::lint::in_external_macro; use rustc_session::declare_lint_pass; use rustc_span::Span; use rustc_span::def_id::LocalDefId; -use rustc_span::symbol::{Ident, Symbol, kw}; +use rustc_span::symbol::{Ident, kw}; use std::ops::ControlFlow; declare_clippy_lint! { @@ -191,45 +191,10 @@ fn check_fn_inner<'tcx>( if usages.iter().any(|usage| !usage.ident.span.eq_ctxt(span)) { return; } - - let lts = elidable_lts - .iter() - // In principle, the result of the call to `Node::ident` could be `unwrap`ped, as `DefId` should refer to a - // `Node::GenericParam`. - .filter_map(|&def_id| cx.tcx.hir_node_by_def_id(def_id).ident()) - .map(|ident| ident.to_string()) - .collect::>() - .join(", "); - - span_lint_and_then( - cx, - NEEDLESS_LIFETIMES, - elidable_lts - .iter() - .map(|<| cx.tcx.def_span(lt)) - .chain(usages.iter().filter_map(|usage| { - if let LifetimeName::Param(def_id) = usage.res - && elidable_lts.contains(&def_id) - { - return Some(usage.ident.span); - } - - None - })) - .collect_vec(), - format!("the following explicit lifetimes could be elided: {lts}"), - |diag| { - if sig.header.is_async() { - // async functions have usages whose spans point at the lifetime declaration which messes up - // suggestions - return; - }; - - if let Some(suggestions) = elision_suggestions(cx, generics, &elidable_lts, &usages) { - diag.multipart_suggestion("elide the lifetimes", suggestions, Applicability::MachineApplicable); - } - }, - ); + // async functions have usages whose spans point at the lifetime declaration which messes up + // suggestions + let include_suggestions = !sig.header.is_async(); + report_elidable_lifetimes(cx, generics, &elidable_lts, &usages, include_suggestions); } if report_extra_lifetimes { @@ -237,6 +202,52 @@ fn check_fn_inner<'tcx>( } } +/// Generate diagnostic messages for elidable lifetimes. +fn report_elidable_lifetimes( + cx: &LateContext<'_>, + generics: &Generics<'_>, + elidable_lts: &[LocalDefId], + usages: &[Lifetime], + include_suggestions: bool, +) { + let lts = elidable_lts + .iter() + // In principle, the result of the call to `Node::ident` could be `unwrap`ped, as `DefId` should refer to a + // `Node::GenericParam`. + .filter_map(|&def_id| cx.tcx.hir_node_by_def_id(def_id).ident()) + .map(|ident| ident.to_string()) + .collect::>() + .join(", "); + + span_lint_and_then( + cx, + NEEDLESS_LIFETIMES, + elidable_lts + .iter() + .map(|<| cx.tcx.def_span(lt)) + .chain(usages.iter().filter_map(|usage| { + if let LifetimeName::Param(def_id) = usage.res + && elidable_lts.contains(&def_id) + { + return Some(usage.ident.span); + } + + None + })) + .collect_vec(), + format!("the following explicit lifetimes could be elided: {lts}"), + |diag| { + if !include_suggestions { + return; + }; + + if let Some(suggestions) = elision_suggestions(cx, generics, elidable_lts, usages) { + diag.multipart_suggestion("elide the lifetimes", suggestions, Applicability::MachineApplicable); + } + }, + ); +} + fn elision_suggestions( cx: &LateContext<'_>, generics: &Generics<'_>, @@ -594,23 +605,34 @@ fn has_where_lifetimes<'tcx>(cx: &LateContext<'tcx>, generics: &'tcx Generics<'_ false } +struct Usage { + lifetime: Lifetime, + in_where_predicate: bool, + in_generic_arg: bool, +} + struct LifetimeChecker<'cx, 'tcx, F> { cx: &'cx LateContext<'tcx>, - map: FxHashMap, + map: FxHashMap>, + where_predicate_depth: usize, + generic_arg_depth: usize, phantom: std::marker::PhantomData, } impl<'cx, 'tcx, F> LifetimeChecker<'cx, 'tcx, F> { - fn new(cx: &'cx LateContext<'tcx>, map: FxHashMap) -> LifetimeChecker<'cx, 'tcx, F> { + fn new(cx: &'cx LateContext<'tcx>, def_ids: Vec) -> LifetimeChecker<'cx, 'tcx, F> { + let map = def_ids.into_iter().map(|def_id| (def_id, Vec::new())).collect(); Self { cx, map, + where_predicate_depth: 0, + generic_arg_depth: 0, phantom: std::marker::PhantomData, } } } -impl<'cx, 'tcx, F> Visitor<'tcx> for LifetimeChecker<'cx, 'tcx, F> +impl<'tcx, F> Visitor<'tcx> for LifetimeChecker<'_, 'tcx, F> where F: NestedFilter<'tcx>, { @@ -619,18 +641,27 @@ where // for lifetimes as parameters of generics fn visit_lifetime(&mut self, lifetime: &'tcx Lifetime) { - self.map.remove(&lifetime.ident.name); + if let LifetimeName::Param(def_id) = lifetime.res + && let Some(usages) = self.map.get_mut(&def_id) + { + usages.push(Usage { + lifetime: *lifetime, + in_where_predicate: self.where_predicate_depth != 0, + in_generic_arg: self.generic_arg_depth != 0, + }); + } } - fn visit_generic_param(&mut self, param: &'tcx GenericParam<'_>) { - // don't actually visit `<'a>` or `<'a: 'b>` - // we've already visited the `'a` declarations and - // don't want to spuriously remove them - // `'b` in `'a: 'b` is useless unless used elsewhere in - // a non-lifetime bound - if let GenericParamKind::Type { .. } = param.kind { - walk_generic_param(self, param); - } + fn visit_where_predicate(&mut self, predicate: &'tcx WherePredicate<'tcx>) { + self.where_predicate_depth += 1; + walk_where_predicate(self, predicate); + self.where_predicate_depth -= 1; + } + + fn visit_generic_arg(&mut self, generic_arg: &'tcx GenericArg<'tcx>) -> Self::Result { + self.generic_arg_depth += 1; + walk_generic_arg(self, generic_arg); + self.generic_arg_depth -= 1; } fn nested_visit_map(&mut self) -> Self::Map { @@ -639,44 +670,49 @@ where } fn report_extra_lifetimes<'tcx>(cx: &LateContext<'tcx>, func: &'tcx FnDecl<'_>, generics: &'tcx Generics<'_>) { - let hs = generics + let def_ids = generics .params .iter() .filter_map(|par| match par.kind { GenericParamKind::Lifetime { kind: LifetimeParamKind::Explicit, - } => Some((par.name.ident().name, par.span)), + } => Some(par.def_id), _ => None, }) .collect(); - let mut checker = LifetimeChecker::::new(cx, hs); + let mut checker = LifetimeChecker::::new(cx, def_ids); walk_generics(&mut checker, generics); walk_fn_decl(&mut checker, func); - for &v in checker.map.values() { - span_lint( - cx, - EXTRA_UNUSED_LIFETIMES, - v, - "this lifetime isn't used in the function definition", - ); + for (def_id, usages) in checker.map { + if usages + .iter() + .all(|usage| usage.in_where_predicate && !usage.in_generic_arg) + { + span_lint( + cx, + EXTRA_UNUSED_LIFETIMES, + cx.tcx.def_span(def_id), + "this lifetime isn't used in the function definition", + ); + } } } fn report_extra_impl_lifetimes<'tcx>(cx: &LateContext<'tcx>, impl_: &'tcx Impl<'_>) { - let hs = impl_ + let def_ids = impl_ .generics .params .iter() .filter_map(|par| match par.kind { GenericParamKind::Lifetime { kind: LifetimeParamKind::Explicit, - } => Some((par.name.ident().name, par.span)), + } => Some(par.def_id), _ => None, }) .collect(); - let mut checker = LifetimeChecker::::new(cx, hs); + let mut checker = LifetimeChecker::::new(cx, def_ids); walk_generics(&mut checker, impl_.generics); if let Some(ref trait_ref) = impl_.of_trait { @@ -687,9 +723,62 @@ fn report_extra_impl_lifetimes<'tcx>(cx: &LateContext<'tcx>, impl_: &'tcx Impl<' walk_impl_item_ref(&mut checker, item); } - for &v in checker.map.values() { - span_lint(cx, EXTRA_UNUSED_LIFETIMES, v, "this lifetime isn't used in the impl"); + for (&def_id, usages) in &checker.map { + if usages + .iter() + .all(|usage| usage.in_where_predicate && !usage.in_generic_arg) + { + span_lint( + cx, + EXTRA_UNUSED_LIFETIMES, + cx.tcx.def_span(def_id), + "this lifetime isn't used in the impl", + ); + } } + + report_elidable_impl_lifetimes(cx, impl_, &checker.map); +} + +// An `impl` lifetime is elidable if it satisfies the following conditions: +// - It is used exactly once. +// - That single use is not in a `GenericArg` in a `WherePredicate`. (Note that a `GenericArg` is +// different from a `GenericParam`.) +fn report_elidable_impl_lifetimes<'tcx>( + cx: &LateContext<'tcx>, + impl_: &'tcx Impl<'_>, + map: &FxHashMap>, +) { + let single_usages = map + .iter() + .filter_map(|(def_id, usages)| { + if let [ + Usage { + lifetime, + in_where_predicate: false, + .. + } + | Usage { + lifetime, + in_generic_arg: false, + .. + }, + ] = usages.as_slice() + { + Some((def_id, lifetime)) + } else { + None + } + }) + .collect::>(); + + if single_usages.is_empty() { + return; + } + + let (elidable_lts, usages): (Vec<_>, Vec<_>) = single_usages.into_iter().unzip(); + + report_elidable_lifetimes(cx, impl_.generics, &elidable_lts, &usages, true); } struct BodyLifetimeChecker; From 0a11c5c49ac7412492fc3bc73100912ea11c6360 Mon Sep 17 00:00:00 2001 From: Samuel Moelius Date: Sun, 18 Aug 2024 07:04:22 -0400 Subject: [PATCH 262/683] Reorder functions --- clippy_lints/src/lifetimes.rs | 274 +++++++++++++++++----------------- 1 file changed, 137 insertions(+), 137 deletions(-) diff --git a/clippy_lints/src/lifetimes.rs b/clippy_lints/src/lifetimes.rs index dc6043ae981..42083b1a879 100644 --- a/clippy_lints/src/lifetimes.rs +++ b/clippy_lints/src/lifetimes.rs @@ -202,143 +202,6 @@ fn check_fn_inner<'tcx>( } } -/// Generate diagnostic messages for elidable lifetimes. -fn report_elidable_lifetimes( - cx: &LateContext<'_>, - generics: &Generics<'_>, - elidable_lts: &[LocalDefId], - usages: &[Lifetime], - include_suggestions: bool, -) { - let lts = elidable_lts - .iter() - // In principle, the result of the call to `Node::ident` could be `unwrap`ped, as `DefId` should refer to a - // `Node::GenericParam`. - .filter_map(|&def_id| cx.tcx.hir_node_by_def_id(def_id).ident()) - .map(|ident| ident.to_string()) - .collect::>() - .join(", "); - - span_lint_and_then( - cx, - NEEDLESS_LIFETIMES, - elidable_lts - .iter() - .map(|<| cx.tcx.def_span(lt)) - .chain(usages.iter().filter_map(|usage| { - if let LifetimeName::Param(def_id) = usage.res - && elidable_lts.contains(&def_id) - { - return Some(usage.ident.span); - } - - None - })) - .collect_vec(), - format!("the following explicit lifetimes could be elided: {lts}"), - |diag| { - if !include_suggestions { - return; - }; - - if let Some(suggestions) = elision_suggestions(cx, generics, elidable_lts, usages) { - diag.multipart_suggestion("elide the lifetimes", suggestions, Applicability::MachineApplicable); - } - }, - ); -} - -fn elision_suggestions( - cx: &LateContext<'_>, - generics: &Generics<'_>, - elidable_lts: &[LocalDefId], - usages: &[Lifetime], -) -> Option> { - let explicit_params = generics - .params - .iter() - .filter(|param| !param.is_elided_lifetime() && !param.is_impl_trait()) - .collect::>(); - - let mut suggestions = if elidable_lts.len() == explicit_params.len() { - // if all the params are elided remove the whole generic block - // - // fn x<'a>() {} - // ^^^^ - vec![(generics.span, String::new())] - } else { - elidable_lts - .iter() - .map(|&id| { - let pos = explicit_params.iter().position(|param| param.def_id == id)?; - let param = explicit_params.get(pos)?; - - let span = if let Some(next) = explicit_params.get(pos + 1) { - // fn x<'prev, 'a, 'next>() {} - // ^^^^ - param.span.until(next.span) - } else { - // `pos` should be at least 1 here, because the param in position 0 would either have a `next` - // param or would have taken the `elidable_lts.len() == explicit_params.len()` branch. - let prev = explicit_params.get(pos - 1)?; - - // fn x<'prev, 'a>() {} - // ^^^^ - param.span.with_lo(prev.span.hi()) - }; - - Some((span, String::new())) - }) - .collect::>>()? - }; - - suggestions.extend( - usages - .iter() - .filter(|usage| named_lifetime(usage).map_or(false, |id| elidable_lts.contains(&id))) - .map(|usage| { - match cx.tcx.parent_hir_node(usage.hir_id) { - Node::Ty(Ty { - kind: TyKind::Ref(..), .. - }) => { - // expand `&'a T` to `&'a T` - // ^^ ^^^ - let span = cx.sess().source_map().span_extend_while_whitespace(usage.ident.span); - - (span, String::new()) - }, - // `T<'a>` and `impl Foo + 'a` should be replaced by `'_` - _ => (usage.ident.span, String::from("'_")), - } - }), - ); - - Some(suggestions) -} - -// elision doesn't work for explicit self types, see rust-lang/rust#69064 -fn explicit_self_type<'tcx>(cx: &LateContext<'tcx>, func: &FnDecl<'tcx>, ident: Option) -> bool { - if let Some(ident) = ident - && ident.name == kw::SelfLower - && !func.implicit_self.has_implicit_self() - && let Some(self_ty) = func.inputs.first() - { - let mut visitor = RefVisitor::new(cx); - visitor.visit_ty(self_ty); - - !visitor.all_lts().is_empty() - } else { - false - } -} - -fn named_lifetime(lt: &Lifetime) -> Option { - match lt.res { - LifetimeName::Param(id) if !lt.is_anonymous() => Some(id), - _ => None, - } -} - fn could_use_elision<'tcx>( cx: &LateContext<'tcx>, func: &'tcx FnDecl<'_>, @@ -461,6 +324,22 @@ fn allowed_lts_from(named_generics: &[GenericParam<'_>]) -> FxHashSet(cx: &LateContext<'tcx>, func: &FnDecl<'tcx>, ident: Option) -> bool { + if let Some(ident) = ident + && ident.name == kw::SelfLower + && !func.implicit_self.has_implicit_self() + && let Some(self_ty) = func.inputs.first() + { + let mut visitor = RefVisitor::new(cx); + visitor.visit_ty(self_ty); + + !visitor.all_lts().is_empty() + } else { + false + } +} + /// Number of times each named lifetime occurs in the given slice. Returns a vector to preserve /// relative order. #[must_use] @@ -481,6 +360,13 @@ fn named_lifetime_occurrences(lts: &[Lifetime]) -> Vec<(LocalDefId, usize)> { occurrences } +fn named_lifetime(lt: &Lifetime) -> Option { + match lt.res { + LifetimeName::Param(id) if !lt.is_anonymous() => Some(id), + _ => None, + } +} + struct RefVisitor<'a, 'tcx> { cx: &'a LateContext<'tcx>, lts: Vec, @@ -781,6 +667,120 @@ fn report_elidable_impl_lifetimes<'tcx>( report_elidable_lifetimes(cx, impl_.generics, &elidable_lts, &usages, true); } +/// Generate diagnostic messages for elidable lifetimes. +fn report_elidable_lifetimes( + cx: &LateContext<'_>, + generics: &Generics<'_>, + elidable_lts: &[LocalDefId], + usages: &[Lifetime], + include_suggestions: bool, +) { + let lts = elidable_lts + .iter() + // In principle, the result of the call to `Node::ident` could be `unwrap`ped, as `DefId` should refer to a + // `Node::GenericParam`. + .filter_map(|&def_id| cx.tcx.hir_node_by_def_id(def_id).ident()) + .map(|ident| ident.to_string()) + .collect::>() + .join(", "); + + span_lint_and_then( + cx, + NEEDLESS_LIFETIMES, + elidable_lts + .iter() + .map(|<| cx.tcx.def_span(lt)) + .chain(usages.iter().filter_map(|usage| { + if let LifetimeName::Param(def_id) = usage.res + && elidable_lts.contains(&def_id) + { + return Some(usage.ident.span); + } + + None + })) + .collect_vec(), + format!("the following explicit lifetimes could be elided: {lts}"), + |diag| { + if !include_suggestions { + return; + }; + + if let Some(suggestions) = elision_suggestions(cx, generics, elidable_lts, usages) { + diag.multipart_suggestion("elide the lifetimes", suggestions, Applicability::MachineApplicable); + } + }, + ); +} + +fn elision_suggestions( + cx: &LateContext<'_>, + generics: &Generics<'_>, + elidable_lts: &[LocalDefId], + usages: &[Lifetime], +) -> Option> { + let explicit_params = generics + .params + .iter() + .filter(|param| !param.is_elided_lifetime() && !param.is_impl_trait()) + .collect::>(); + + let mut suggestions = if elidable_lts.len() == explicit_params.len() { + // if all the params are elided remove the whole generic block + // + // fn x<'a>() {} + // ^^^^ + vec![(generics.span, String::new())] + } else { + elidable_lts + .iter() + .map(|&id| { + let pos = explicit_params.iter().position(|param| param.def_id == id)?; + let param = explicit_params.get(pos)?; + + let span = if let Some(next) = explicit_params.get(pos + 1) { + // fn x<'prev, 'a, 'next>() {} + // ^^^^ + param.span.until(next.span) + } else { + // `pos` should be at least 1 here, because the param in position 0 would either have a `next` + // param or would have taken the `elidable_lts.len() == explicit_params.len()` branch. + let prev = explicit_params.get(pos - 1)?; + + // fn x<'prev, 'a>() {} + // ^^^^ + param.span.with_lo(prev.span.hi()) + }; + + Some((span, String::new())) + }) + .collect::>>()? + }; + + suggestions.extend( + usages + .iter() + .filter(|usage| named_lifetime(usage).map_or(false, |id| elidable_lts.contains(&id))) + .map(|usage| { + match cx.tcx.parent_hir_node(usage.hir_id) { + Node::Ty(Ty { + kind: TyKind::Ref(..), .. + }) => { + // expand `&'a T` to `&'a T` + // ^^ ^^^ + let span = cx.sess().source_map().span_extend_while_whitespace(usage.ident.span); + + (span, String::new()) + }, + // `T<'a>` and `impl Foo + 'a` should be replaced by `'_` + _ => (usage.ident.span, String::from("'_")), + } + }), + ); + + Some(suggestions) +} + struct BodyLifetimeChecker; impl<'tcx> Visitor<'tcx> for BodyLifetimeChecker { From f2495a17772e0f90fa00fc8838c12b30b4a1c46e Mon Sep 17 00:00:00 2001 From: Samuel Moelius Date: Sun, 18 Aug 2024 07:31:03 -0400 Subject: [PATCH 263/683] Fix lifetime tests --- .../needless_lifetimes_impl_trait.fixed | 2 +- .../needless_lifetimes_impl_trait.stderr | 20 +++++++++++++++---- tests/ui/extra_unused_lifetimes.rs | 8 ++++++++ tests/ui/extra_unused_lifetimes.stderr | 8 +++++++- tests/ui/needless_lifetimes.fixed | 2 +- tests/ui/needless_lifetimes.stderr | 14 ++++++++++++- 6 files changed, 46 insertions(+), 8 deletions(-) diff --git a/tests/ui/crashes/needless_lifetimes_impl_trait.fixed b/tests/ui/crashes/needless_lifetimes_impl_trait.fixed index 8bd9eea75bb..837069cae6d 100644 --- a/tests/ui/crashes/needless_lifetimes_impl_trait.fixed +++ b/tests/ui/crashes/needless_lifetimes_impl_trait.fixed @@ -9,7 +9,7 @@ struct Baz<'a> { bar: &'a Bar, } -impl<'a> Foo for Baz<'a> {} +impl Foo for Baz<'_> {} impl Bar { fn baz(&self) -> impl Foo + '_ { diff --git a/tests/ui/crashes/needless_lifetimes_impl_trait.stderr b/tests/ui/crashes/needless_lifetimes_impl_trait.stderr index 3a2d1f4410e..bed6aab25c4 100644 --- a/tests/ui/crashes/needless_lifetimes_impl_trait.stderr +++ b/tests/ui/crashes/needless_lifetimes_impl_trait.stderr @@ -1,8 +1,8 @@ error: the following explicit lifetimes could be elided: 'a - --> tests/ui/crashes/needless_lifetimes_impl_trait.rs:15:12 + --> tests/ui/crashes/needless_lifetimes_impl_trait.rs:12:6 | -LL | fn baz<'a>(&'a self) -> impl Foo + 'a { - | ^^ ^^ ^^ +LL | impl<'a> Foo for Baz<'a> {} + | ^^ ^^ | note: the lint level is defined here --> tests/ui/crashes/needless_lifetimes_impl_trait.rs:1:9 @@ -11,9 +11,21 @@ LL | #![deny(clippy::needless_lifetimes)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: elide the lifetimes | +LL - impl<'a> Foo for Baz<'a> {} +LL + impl Foo for Baz<'_> {} + | + +error: the following explicit lifetimes could be elided: 'a + --> tests/ui/crashes/needless_lifetimes_impl_trait.rs:15:12 + | +LL | fn baz<'a>(&'a self) -> impl Foo + 'a { + | ^^ ^^ ^^ + | +help: elide the lifetimes + | LL - fn baz<'a>(&'a self) -> impl Foo + 'a { LL + fn baz(&self) -> impl Foo + '_ { | -error: aborting due to 1 previous error +error: aborting due to 2 previous errors diff --git a/tests/ui/extra_unused_lifetimes.rs b/tests/ui/extra_unused_lifetimes.rs index cdfaf8d3afe..17d2ed9f50c 100644 --- a/tests/ui/extra_unused_lifetimes.rs +++ b/tests/ui/extra_unused_lifetimes.rs @@ -114,9 +114,17 @@ mod second_case { fn hey(); } + // Should lint. The response to the above comment incorrectly called this a false positive. The + // lifetime `'a` can be removed, as demonstrated below. impl<'a, T: Source + ?Sized + 'a> Source for Box { fn hey() {} } + + struct OtherBox(Box); + + impl Source for OtherBox { + fn hey() {} + } } // Should not lint diff --git a/tests/ui/extra_unused_lifetimes.stderr b/tests/ui/extra_unused_lifetimes.stderr index 56292cb5d1a..85fbb7568ff 100644 --- a/tests/ui/extra_unused_lifetimes.stderr +++ b/tests/ui/extra_unused_lifetimes.stderr @@ -37,5 +37,11 @@ error: this lifetime isn't used in the function definition LL | pub fn something<'c>() -> Self { | ^^ -error: aborting due to 6 previous errors +error: this lifetime isn't used in the impl + --> tests/ui/extra_unused_lifetimes.rs:119:10 + | +LL | impl<'a, T: Source + ?Sized + 'a> Source for Box { + | ^^ + +error: aborting due to 7 previous errors diff --git a/tests/ui/needless_lifetimes.fixed b/tests/ui/needless_lifetimes.fixed index d1787b35abd..e4bb7f86d12 100644 --- a/tests/ui/needless_lifetimes.fixed +++ b/tests/ui/needless_lifetimes.fixed @@ -329,7 +329,7 @@ mod issue2944 { bar: &'a Bar, } - impl<'a> Foo for Baz<'a> {} + impl Foo for Baz<'_> {} impl Bar { fn baz(&self) -> impl Foo + '_ { Baz { bar: self } diff --git a/tests/ui/needless_lifetimes.stderr b/tests/ui/needless_lifetimes.stderr index 50f845e2d92..166e6d0eabf 100644 --- a/tests/ui/needless_lifetimes.stderr +++ b/tests/ui/needless_lifetimes.stderr @@ -335,6 +335,18 @@ LL - fn needless_lt<'a>(_x: &'a u8) {} LL + fn needless_lt(_x: &u8) {} | +error: the following explicit lifetimes could be elided: 'a + --> tests/ui/needless_lifetimes.rs:332:10 + | +LL | impl<'a> Foo for Baz<'a> {} + | ^^ ^^ + | +help: elide the lifetimes + | +LL - impl<'a> Foo for Baz<'a> {} +LL + impl Foo for Baz<'_> {} + | + error: the following explicit lifetimes could be elided: 'a --> tests/ui/needless_lifetimes.rs:334:16 | @@ -564,5 +576,5 @@ LL - fn one_input<'a>(x: &'a u8) -> &'a u8 { LL + fn one_input(x: &u8) -> &u8 { | -error: aborting due to 47 previous errors +error: aborting due to 48 previous errors From 877585089e015ed5b32de6ccb1d970a7f32960ba Mon Sep 17 00:00:00 2001 From: Samuel Moelius Date: Sun, 18 Aug 2024 07:31:47 -0400 Subject: [PATCH 264/683] Fix non-lifetime tests --- tests/ui-toml/suppress_lint_in_const/test.rs | 3 +- .../suppress_lint_in_const/test.stderr | 12 +-- tests/ui/borrow_box.fixed | 3 +- tests/ui/borrow_box.rs | 3 +- tests/ui/borrow_box.stderr | 20 ++-- tests/ui/boxed_local.rs | 3 +- tests/ui/boxed_local.stderr | 8 +- tests/ui/derive.rs | 7 +- tests/ui/derive.stderr | 20 ++-- tests/ui/eta.fixed | 3 +- tests/ui/eta.rs | 3 +- tests/ui/eta.stderr | 68 +++++++------- tests/ui/explicit_auto_deref.fixed | 3 +- tests/ui/explicit_auto_deref.rs | 3 +- tests/ui/explicit_auto_deref.stderr | 92 +++++++++---------- .../if_let_slice_binding.rs | 2 +- tests/ui/iter_without_into_iter.rs | 1 + tests/ui/iter_without_into_iter.stderr | 16 ++-- tests/ui/mem_replace.fixed | 3 +- tests/ui/mem_replace.rs | 3 +- tests/ui/mem_replace.stderr | 48 +++++----- tests/ui/mem_replace_no_std.fixed | 3 +- tests/ui/mem_replace_no_std.rs | 3 +- tests/ui/mem_replace_no_std.stderr | 14 +-- tests/ui/mismatching_type_param_order.rs | 2 +- tests/ui/needless_borrow.fixed | 3 +- tests/ui/needless_borrow.rs | 3 +- tests/ui/needless_borrow.stderr | 56 +++++------ tests/ui/needless_pass_by_value.rs | 3 +- tests/ui/needless_pass_by_value.stderr | 52 +++++------ tests/ui/new_without_default.fixed | 3 +- tests/ui/new_without_default.rs | 3 +- tests/ui/new_without_default.stderr | 18 ++-- tests/ui/ref_as_ptr.fixed | 2 +- tests/ui/ref_as_ptr.rs | 2 +- tests/ui/serde.rs | 2 +- tests/ui/significant_drop_in_scrutinee.rs | 7 +- tests/ui/significant_drop_in_scrutinee.stderr | 58 ++++++------ tests/ui/str_split.fixed | 1 + tests/ui/str_split.rs | 1 + tests/ui/str_split.stderr | 20 ++-- tests/ui/temporary_assignment.rs | 1 + tests/ui/temporary_assignment.stderr | 8 +- tests/ui/unconditional_recursion.rs | 3 +- tests/ui/unconditional_recursion.stderr | 90 +++++++++--------- tests/ui/useful_asref.rs | 1 + 46 files changed, 354 insertions(+), 329 deletions(-) diff --git a/tests/ui-toml/suppress_lint_in_const/test.rs b/tests/ui-toml/suppress_lint_in_const/test.rs index 232bccf6a15..4613a74b85d 100644 --- a/tests/ui-toml/suppress_lint_in_const/test.rs +++ b/tests/ui-toml/suppress_lint_in_const/test.rs @@ -7,7 +7,8 @@ clippy::no_effect, clippy::unnecessary_operation, clippy::useless_vec, - clippy::out_of_bounds_indexing + clippy::out_of_bounds_indexing, + clippy::needless_lifetimes )] const ARR: [i32; 2] = [1, 2]; diff --git a/tests/ui-toml/suppress_lint_in_const/test.stderr b/tests/ui-toml/suppress_lint_in_const/test.stderr index 5ce2ed2ffae..120f5c35cb0 100644 --- a/tests/ui-toml/suppress_lint_in_const/test.stderr +++ b/tests/ui-toml/suppress_lint_in_const/test.stderr @@ -1,5 +1,5 @@ error: indexing may panic - --> tests/ui-toml/suppress_lint_in_const/test.rs:26:5 + --> tests/ui-toml/suppress_lint_in_const/test.rs:27:5 | LL | x[index]; | ^^^^^^^^ @@ -9,7 +9,7 @@ LL | x[index]; = help: to override `-D warnings` add `#[allow(clippy::indexing_slicing)]` error: indexing may panic - --> tests/ui-toml/suppress_lint_in_const/test.rs:41:5 + --> tests/ui-toml/suppress_lint_in_const/test.rs:42:5 | LL | v[0]; | ^^^^ @@ -17,7 +17,7 @@ LL | v[0]; = help: consider using `.get(n)` or `.get_mut(n)` instead error: indexing may panic - --> tests/ui-toml/suppress_lint_in_const/test.rs:42:5 + --> tests/ui-toml/suppress_lint_in_const/test.rs:43:5 | LL | v[10]; | ^^^^^ @@ -25,7 +25,7 @@ LL | v[10]; = help: consider using `.get(n)` or `.get_mut(n)` instead error: indexing may panic - --> tests/ui-toml/suppress_lint_in_const/test.rs:43:5 + --> tests/ui-toml/suppress_lint_in_const/test.rs:44:5 | LL | v[1 << 3]; | ^^^^^^^^^ @@ -33,7 +33,7 @@ LL | v[1 << 3]; = help: consider using `.get(n)` or `.get_mut(n)` instead error: indexing may panic - --> tests/ui-toml/suppress_lint_in_const/test.rs:49:5 + --> tests/ui-toml/suppress_lint_in_const/test.rs:50:5 | LL | v[N]; | ^^^^ @@ -41,7 +41,7 @@ LL | v[N]; = help: consider using `.get(n)` or `.get_mut(n)` instead error: indexing may panic - --> tests/ui-toml/suppress_lint_in_const/test.rs:50:5 + --> tests/ui-toml/suppress_lint_in_const/test.rs:51:5 | LL | v[M]; | ^^^^ diff --git a/tests/ui/borrow_box.fixed b/tests/ui/borrow_box.fixed index 5984cc4e930..08ea60583ea 100644 --- a/tests/ui/borrow_box.fixed +++ b/tests/ui/borrow_box.fixed @@ -3,7 +3,8 @@ #![allow( clippy::uninlined_format_args, clippy::disallowed_names, - clippy::needless_pass_by_ref_mut + clippy::needless_pass_by_ref_mut, + clippy::needless_lifetimes )] use std::fmt::Display; diff --git a/tests/ui/borrow_box.rs b/tests/ui/borrow_box.rs index 7f15fc83a1d..b55de1701da 100644 --- a/tests/ui/borrow_box.rs +++ b/tests/ui/borrow_box.rs @@ -3,7 +3,8 @@ #![allow( clippy::uninlined_format_args, clippy::disallowed_names, - clippy::needless_pass_by_ref_mut + clippy::needless_pass_by_ref_mut, + clippy::needless_lifetimes )] use std::fmt::Display; diff --git a/tests/ui/borrow_box.stderr b/tests/ui/borrow_box.stderr index ed4308161bb..6f80f86c3b3 100644 --- a/tests/ui/borrow_box.stderr +++ b/tests/ui/borrow_box.stderr @@ -1,5 +1,5 @@ error: you seem to be trying to use `&Box`. Consider using just `&T` - --> tests/ui/borrow_box.rs:24:14 + --> tests/ui/borrow_box.rs:25:14 | LL | let foo: &Box; | ^^^^^^^^^^ help: try: `&bool` @@ -11,55 +11,55 @@ LL | #![deny(clippy::borrowed_box)] | ^^^^^^^^^^^^^^^^^^^^ error: you seem to be trying to use `&Box`. Consider using just `&T` - --> tests/ui/borrow_box.rs:29:10 + --> tests/ui/borrow_box.rs:30:10 | LL | foo: &'a Box, | ^^^^^^^^^^^^^ help: try: `&'a bool` error: you seem to be trying to use `&Box`. Consider using just `&T` - --> tests/ui/borrow_box.rs:34:17 + --> tests/ui/borrow_box.rs:35:17 | LL | fn test4(a: &Box); | ^^^^^^^^^^ help: try: `&bool` error: you seem to be trying to use `&Box`. Consider using just `&T` - --> tests/ui/borrow_box.rs:95:25 + --> tests/ui/borrow_box.rs:96:25 | LL | pub fn test14(_display: &Box) {} | ^^^^^^^^^^^^^^^^^ help: try: `&dyn Display` error: you seem to be trying to use `&Box`. Consider using just `&T` - --> tests/ui/borrow_box.rs:97:25 + --> tests/ui/borrow_box.rs:98:25 | LL | pub fn test15(_display: &Box) {} | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&(dyn Display + Send)` error: you seem to be trying to use `&Box`. Consider using just `&T` - --> tests/ui/borrow_box.rs:99:29 + --> tests/ui/borrow_box.rs:100:29 | LL | pub fn test16<'a>(_display: &'a Box) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&'a (dyn Display + 'a)` error: you seem to be trying to use `&Box`. Consider using just `&T` - --> tests/ui/borrow_box.rs:102:25 + --> tests/ui/borrow_box.rs:103:25 | LL | pub fn test17(_display: &Box) {} | ^^^^^^^^^^^^^^^^^^ help: try: `&impl Display` error: you seem to be trying to use `&Box`. Consider using just `&T` - --> tests/ui/borrow_box.rs:104:25 + --> tests/ui/borrow_box.rs:105:25 | LL | pub fn test18(_display: &Box) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&(impl Display + Send)` error: you seem to be trying to use `&Box`. Consider using just `&T` - --> tests/ui/borrow_box.rs:106:29 + --> tests/ui/borrow_box.rs:107:29 | LL | pub fn test19<'a>(_display: &'a Box) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&'a (impl Display + 'a)` error: you seem to be trying to use `&Box`. Consider using just `&T` - --> tests/ui/borrow_box.rs:112:25 + --> tests/ui/borrow_box.rs:113:25 | LL | pub fn test20(_display: &Box<(dyn Display + Send)>) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&(dyn Display + Send)` diff --git a/tests/ui/boxed_local.rs b/tests/ui/boxed_local.rs index fbd9e12fc18..e2c27e585fc 100644 --- a/tests/ui/boxed_local.rs +++ b/tests/ui/boxed_local.rs @@ -3,7 +3,8 @@ clippy::needless_pass_by_value, clippy::unused_unit, clippy::redundant_clone, - clippy::match_single_binding + clippy::match_single_binding, + clippy::needless_lifetimes )] #![warn(clippy::boxed_local)] diff --git a/tests/ui/boxed_local.stderr b/tests/ui/boxed_local.stderr index 7710233fa4d..d3156c820b2 100644 --- a/tests/ui/boxed_local.stderr +++ b/tests/ui/boxed_local.stderr @@ -1,5 +1,5 @@ error: local variable doesn't need to be boxed here - --> tests/ui/boxed_local.rs:39:13 + --> tests/ui/boxed_local.rs:40:13 | LL | fn warn_arg(x: Box) { | ^ @@ -8,19 +8,19 @@ LL | fn warn_arg(x: Box) { = help: to override `-D warnings` add `#[allow(clippy::boxed_local)]` error: local variable doesn't need to be boxed here - --> tests/ui/boxed_local.rs:122:12 + --> tests/ui/boxed_local.rs:123:12 | LL | pub fn new(_needs_name: Box>) -> () {} | ^^^^^^^^^^^ error: local variable doesn't need to be boxed here - --> tests/ui/boxed_local.rs:187:44 + --> tests/ui/boxed_local.rs:188:44 | LL | fn default_impl_x(self: Box, x: Box) -> u32 { | ^ error: local variable doesn't need to be boxed here - --> tests/ui/boxed_local.rs:195:16 + --> tests/ui/boxed_local.rs:196:16 | LL | fn foo(x: Box) {} | ^ diff --git a/tests/ui/derive.rs b/tests/ui/derive.rs index 4ac21f2cb4b..3647b242505 100644 --- a/tests/ui/derive.rs +++ b/tests/ui/derive.rs @@ -1,4 +1,9 @@ -#![allow(clippy::non_canonical_clone_impl, clippy::non_canonical_partial_ord_impl, dead_code)] +#![allow( + clippy::non_canonical_clone_impl, + clippy::non_canonical_partial_ord_impl, + clippy::needless_lifetimes, + dead_code +)] #![warn(clippy::expl_impl_clone_on_copy)] #[derive(Copy)] diff --git a/tests/ui/derive.stderr b/tests/ui/derive.stderr index 486e6dc1b6b..c072a9a6277 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:7:1 + --> tests/ui/derive.rs:12:1 | LL | / impl Clone for Qux { LL | | @@ -10,7 +10,7 @@ LL | | } | |_^ | note: consider deriving `Clone` or removing `Copy` - --> tests/ui/derive.rs:7:1 + --> tests/ui/derive.rs:12: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:32:1 + --> tests/ui/derive.rs:37: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:32:1 + --> tests/ui/derive.rs:37: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:44:1 + --> tests/ui/derive.rs:49:1 | LL | / impl Clone for BigArray { LL | | @@ -56,7 +56,7 @@ LL | | } | |_^ | note: consider deriving `Clone` or removing `Copy` - --> tests/ui/derive.rs:44:1 + --> tests/ui/derive.rs:49: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:56:1 + --> tests/ui/derive.rs:61:1 | LL | / impl Clone for FnPtr { LL | | @@ -78,7 +78,7 @@ LL | | } | |_^ | note: consider deriving `Clone` or removing `Copy` - --> tests/ui/derive.rs:56:1 + --> tests/ui/derive.rs:61: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:77:1 + --> tests/ui/derive.rs:82:1 | LL | / impl Clone for Generic2 { LL | | @@ -100,7 +100,7 @@ LL | | } | |_^ | note: consider deriving `Clone` or removing `Copy` - --> tests/ui/derive.rs:77:1 + --> tests/ui/derive.rs:82:1 | LL | / impl Clone for Generic2 { LL | | diff --git a/tests/ui/eta.fixed b/tests/ui/eta.fixed index ca422ee29c1..f1baf28200e 100644 --- a/tests/ui/eta.fixed +++ b/tests/ui/eta.fixed @@ -9,7 +9,8 @@ clippy::redundant_closure_call, clippy::uninlined_format_args, clippy::useless_vec, - clippy::unnecessary_map_on_constructor + clippy::unnecessary_map_on_constructor, + clippy::needless_lifetimes )] use std::path::{Path, PathBuf}; diff --git a/tests/ui/eta.rs b/tests/ui/eta.rs index c0db91c03ef..c52a51880bf 100644 --- a/tests/ui/eta.rs +++ b/tests/ui/eta.rs @@ -9,7 +9,8 @@ clippy::redundant_closure_call, clippy::uninlined_format_args, clippy::useless_vec, - clippy::unnecessary_map_on_constructor + clippy::unnecessary_map_on_constructor, + clippy::needless_lifetimes )] use std::path::{Path, PathBuf}; diff --git a/tests/ui/eta.stderr b/tests/ui/eta.stderr index 5540261fc57..1731a4377f5 100644 --- a/tests/ui/eta.stderr +++ b/tests/ui/eta.stderr @@ -1,5 +1,5 @@ error: redundant closure - --> tests/ui/eta.rs:30:27 + --> tests/ui/eta.rs:31:27 | LL | let a = Some(1u8).map(|a| foo(a)); | ^^^^^^^^^^ help: replace the closure with the function itself: `foo` @@ -8,31 +8,31 @@ LL | let a = Some(1u8).map(|a| foo(a)); = help: to override `-D warnings` add `#[allow(clippy::redundant_closure)]` error: redundant closure - --> tests/ui/eta.rs:34:40 + --> tests/ui/eta.rs:35:40 | LL | let _: Option> = true.then(|| vec![]); // special case vec! | ^^^^^^^^^ help: replace the closure with `Vec::new`: `std::vec::Vec::new` error: redundant closure - --> tests/ui/eta.rs:35:35 + --> tests/ui/eta.rs:36:35 | LL | let d = Some(1u8).map(|a| foo((|b| foo2(b))(a))); //is adjusted? | ^^^^^^^^^^^^^ help: replace the closure with the function itself: `foo2` error: redundant closure - --> tests/ui/eta.rs:36:26 + --> tests/ui/eta.rs:37:26 | LL | all(&[1, 2, 3], &&2, |x, y| below(x, y)); //is adjusted | ^^^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `below` error: redundant closure - --> tests/ui/eta.rs:43:27 + --> tests/ui/eta.rs:44:27 | LL | let e = Some(1u8).map(|a| generic(a)); | ^^^^^^^^^^^^^^ help: replace the closure with the function itself: `generic` error: redundant closure - --> tests/ui/eta.rs:95:51 + --> tests/ui/eta.rs:96:51 | LL | let e = Some(TestStruct { some_ref: &i }).map(|a| a.foo()); | ^^^^^^^^^^^ help: replace the closure with the method itself: `TestStruct::foo` @@ -41,169 +41,169 @@ LL | let e = Some(TestStruct { some_ref: &i }).map(|a| a.foo()); = help: to override `-D warnings` add `#[allow(clippy::redundant_closure_for_method_calls)]` error: redundant closure - --> tests/ui/eta.rs:96:51 + --> tests/ui/eta.rs:97:51 | LL | let e = Some(TestStruct { some_ref: &i }).map(|a| a.trait_foo()); | ^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `TestTrait::trait_foo` error: redundant closure - --> tests/ui/eta.rs:98:42 + --> tests/ui/eta.rs:99:42 | LL | let e = Some(&mut vec![1, 2, 3]).map(|v| v.clear()); | ^^^^^^^^^^^^^ help: replace the closure with the method itself: `std::vec::Vec::clear` error: redundant closure - --> tests/ui/eta.rs:102:29 + --> tests/ui/eta.rs:103:29 | LL | let e = Some("str").map(|s| s.to_string()); | ^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `std::string::ToString::to_string` error: redundant closure - --> tests/ui/eta.rs:103:27 + --> tests/ui/eta.rs:104:27 | LL | let e = Some('a').map(|s| s.to_uppercase()); | ^^^^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `char::to_uppercase` error: redundant closure - --> tests/ui/eta.rs:105:65 + --> tests/ui/eta.rs:106:65 | LL | let e: std::vec::Vec = vec!['a', 'b', 'c'].iter().map(|c| c.to_ascii_uppercase()).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `char::to_ascii_uppercase` error: redundant closure - --> tests/ui/eta.rs:168:22 + --> tests/ui/eta.rs:169:22 | LL | requires_fn_once(|| x()); | ^^^^^^ help: replace the closure with the function itself: `x` error: redundant closure - --> tests/ui/eta.rs:175:27 + --> tests/ui/eta.rs:176:27 | LL | let a = Some(1u8).map(|a| foo_ptr(a)); | ^^^^^^^^^^^^^^ help: replace the closure with the function itself: `foo_ptr` error: redundant closure - --> tests/ui/eta.rs:180:27 + --> tests/ui/eta.rs:181:27 | LL | let a = Some(1u8).map(|a| closure(a)); | ^^^^^^^^^^^^^^ help: replace the closure with the function itself: `closure` error: redundant closure - --> tests/ui/eta.rs:212:28 + --> tests/ui/eta.rs:213:28 | LL | x.into_iter().for_each(|x| add_to_res(x)); | ^^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `&mut add_to_res` error: redundant closure - --> tests/ui/eta.rs:213:28 + --> tests/ui/eta.rs:214:28 | LL | y.into_iter().for_each(|x| add_to_res(x)); | ^^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `&mut add_to_res` error: redundant closure - --> tests/ui/eta.rs:214:28 + --> tests/ui/eta.rs:215:28 | LL | z.into_iter().for_each(|x| add_to_res(x)); | ^^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `add_to_res` error: redundant closure - --> tests/ui/eta.rs:221:21 + --> tests/ui/eta.rs:222:21 | LL | Some(1).map(|n| closure(n)); | ^^^^^^^^^^^^^^ help: replace the closure with the function itself: `&mut closure` error: redundant closure - --> tests/ui/eta.rs:225:21 + --> tests/ui/eta.rs:226:21 | LL | Some(1).map(|n| in_loop(n)); | ^^^^^^^^^^^^^^ help: replace the closure with the function itself: `in_loop` error: redundant closure - --> tests/ui/eta.rs:318:18 + --> tests/ui/eta.rs:319:18 | LL | takes_fn_mut(|| f()); | ^^^^^^ help: replace the closure with the function itself: `&mut f` error: redundant closure - --> tests/ui/eta.rs:321:19 + --> tests/ui/eta.rs:322:19 | LL | takes_fn_once(|| f()); | ^^^^^^ help: replace the closure with the function itself: `&mut f` error: redundant closure - --> tests/ui/eta.rs:325:26 + --> tests/ui/eta.rs:326:26 | LL | move || takes_fn_mut(|| f_used_once()) | ^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `&mut f_used_once` error: redundant closure - --> tests/ui/eta.rs:337:19 + --> tests/ui/eta.rs:338:19 | LL | array_opt.map(|a| a.as_slice()); | ^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `<[u8; 3]>::as_slice` error: redundant closure - --> tests/ui/eta.rs:340:19 + --> tests/ui/eta.rs:341:19 | LL | slice_opt.map(|s| s.len()); | ^^^^^^^^^^^ help: replace the closure with the method itself: `<[u8]>::len` error: redundant closure - --> tests/ui/eta.rs:343:17 + --> tests/ui/eta.rs:344:17 | LL | ptr_opt.map(|p| p.is_null()); | ^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `<*const usize>::is_null` error: redundant closure - --> tests/ui/eta.rs:347:17 + --> tests/ui/eta.rs:348:17 | LL | dyn_opt.map(|d| d.method_on_dyn()); | ^^^^^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `::method_on_dyn` error: redundant closure - --> tests/ui/eta.rs:407:19 + --> tests/ui/eta.rs:408:19 | LL | let _ = f(&0, |x, y| f2(x, y)); | ^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `f2` error: redundant closure - --> tests/ui/eta.rs:435:22 + --> tests/ui/eta.rs:436:22 | LL | test.map(|t| t.method()) | ^^^^^^^^^^^^^^ help: replace the closure with the method itself: `Test::method` error: redundant closure - --> tests/ui/eta.rs:439:22 + --> tests/ui/eta.rs:440:22 | LL | test.map(|t| t.method()) | ^^^^^^^^^^^^^^ help: replace the closure with the method itself: `super::Outer::method` error: redundant closure - --> tests/ui/eta.rs:452:18 + --> tests/ui/eta.rs:453:18 | LL | test.map(|t| t.method()) | ^^^^^^^^^^^^^^ help: replace the closure with the method itself: `test_mod::Test::method` error: redundant closure - --> tests/ui/eta.rs:459:30 + --> tests/ui/eta.rs:460:30 | LL | test.map(|t| t.method()) | ^^^^^^^^^^^^^^ help: replace the closure with the method itself: `crate::issue_10854::d::Test::method` error: redundant closure - --> tests/ui/eta.rs:478:38 + --> tests/ui/eta.rs:479:38 | LL | let x = Box::new(|| None.map(|x| f(x))); | ^^^^^^^^ help: replace the closure with the function itself: `&f` error: redundant closure - --> tests/ui/eta.rs:482:38 + --> tests/ui/eta.rs:483:38 | LL | let x = Box::new(|| None.map(|x| f(x))); | ^^^^^^^^ help: replace the closure with the function itself: `f` error: redundant closure - --> tests/ui/eta.rs:499:35 + --> tests/ui/eta.rs:500:35 | LL | let _field = bind.or_else(|| get_default()).unwrap(); | ^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `get_default` diff --git a/tests/ui/explicit_auto_deref.fixed b/tests/ui/explicit_auto_deref.fixed index 255b2c5a220..9d476259b87 100644 --- a/tests/ui/explicit_auto_deref.fixed +++ b/tests/ui/explicit_auto_deref.fixed @@ -10,7 +10,8 @@ clippy::redundant_field_names, clippy::too_many_arguments, clippy::borrow_deref_ref, - clippy::let_unit_value + clippy::let_unit_value, + clippy::needless_lifetimes )] trait CallableStr { diff --git a/tests/ui/explicit_auto_deref.rs b/tests/ui/explicit_auto_deref.rs index 99906999f01..23307c837f0 100644 --- a/tests/ui/explicit_auto_deref.rs +++ b/tests/ui/explicit_auto_deref.rs @@ -10,7 +10,8 @@ clippy::redundant_field_names, clippy::too_many_arguments, clippy::borrow_deref_ref, - clippy::let_unit_value + clippy::let_unit_value, + clippy::needless_lifetimes )] trait CallableStr { diff --git a/tests/ui/explicit_auto_deref.stderr b/tests/ui/explicit_auto_deref.stderr index 53784934f63..0b05a554eb1 100644 --- a/tests/ui/explicit_auto_deref.stderr +++ b/tests/ui/explicit_auto_deref.stderr @@ -1,5 +1,5 @@ error: deref which would be done by auto-deref - --> tests/ui/explicit_auto_deref.rs:68:19 + --> tests/ui/explicit_auto_deref.rs:69:19 | LL | let _: &str = &*s; | ^^^ help: try: `&s` @@ -8,271 +8,271 @@ LL | let _: &str = &*s; = help: to override `-D warnings` add `#[allow(clippy::explicit_auto_deref)]` error: deref which would be done by auto-deref - --> tests/ui/explicit_auto_deref.rs:69:19 + --> tests/ui/explicit_auto_deref.rs:70:19 | LL | let _: &str = &*{ String::new() }; | ^^^^^^^^^^^^^^^^^^^ help: try: `&{ String::new() }` error: deref which would be done by auto-deref - --> tests/ui/explicit_auto_deref.rs:70:19 + --> tests/ui/explicit_auto_deref.rs:71:19 | LL | let _: &str = &mut *{ String::new() }; | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&mut { String::new() }` error: deref which would be done by auto-deref - --> tests/ui/explicit_auto_deref.rs:74:11 + --> tests/ui/explicit_auto_deref.rs:75:11 | LL | f_str(&*s); | ^^^ help: try: `&s` error: deref which would be done by auto-deref - --> tests/ui/explicit_auto_deref.rs:78:13 + --> tests/ui/explicit_auto_deref.rs:79:13 | LL | f_str_t(&*s, &*s); // Don't lint second param. | ^^^ help: try: `&s` error: deref which would be done by auto-deref - --> tests/ui/explicit_auto_deref.rs:81:24 + --> tests/ui/explicit_auto_deref.rs:82:24 | LL | let _: &Box = &**b; | ^^^^ help: try: `&b` error: deref which would be done by auto-deref - --> tests/ui/explicit_auto_deref.rs:87:7 + --> tests/ui/explicit_auto_deref.rs:88:7 | LL | c(&*s); | ^^^ help: try: `&s` error: deref which would be done by auto-deref - --> tests/ui/explicit_auto_deref.rs:93:9 + --> tests/ui/explicit_auto_deref.rs:94:9 | LL | &**x | ^^^^ help: try: `x` error: deref which would be done by auto-deref - --> tests/ui/explicit_auto_deref.rs:97:11 + --> tests/ui/explicit_auto_deref.rs:98:11 | LL | { &**x } | ^^^^ help: try: `x` error: deref which would be done by auto-deref - --> tests/ui/explicit_auto_deref.rs:101:9 + --> tests/ui/explicit_auto_deref.rs:102:9 | LL | &**{ x } | ^^^^^^^^ help: try: `{ x }` error: deref which would be done by auto-deref - --> tests/ui/explicit_auto_deref.rs:105:9 + --> tests/ui/explicit_auto_deref.rs:106:9 | LL | &***x | ^^^^^ help: try: `x` error: deref which would be done by auto-deref - --> tests/ui/explicit_auto_deref.rs:122:12 + --> tests/ui/explicit_auto_deref.rs:123:12 | LL | f1(&*x); | ^^^ help: try: `&x` error: deref which would be done by auto-deref - --> tests/ui/explicit_auto_deref.rs:123:12 + --> tests/ui/explicit_auto_deref.rs:124:12 | LL | f2(&*x); | ^^^ help: try: `&x` error: deref which would be done by auto-deref - --> tests/ui/explicit_auto_deref.rs:124:12 + --> tests/ui/explicit_auto_deref.rs:125:12 | LL | f3(&*x); | ^^^ help: try: `&x` error: deref which would be done by auto-deref - --> tests/ui/explicit_auto_deref.rs:125:27 + --> tests/ui/explicit_auto_deref.rs:126:27 | LL | f4.callable_str()(&*x); | ^^^ help: try: `&x` error: deref which would be done by auto-deref - --> tests/ui/explicit_auto_deref.rs:126:12 + --> tests/ui/explicit_auto_deref.rs:127:12 | LL | f5(&*x); | ^^^ help: try: `&x` error: deref which would be done by auto-deref - --> tests/ui/explicit_auto_deref.rs:127:12 + --> tests/ui/explicit_auto_deref.rs:128:12 | LL | f6(&*x); | ^^^ help: try: `&x` error: deref which would be done by auto-deref - --> tests/ui/explicit_auto_deref.rs:128:27 + --> tests/ui/explicit_auto_deref.rs:129:27 | LL | f7.callable_str()(&*x); | ^^^ help: try: `&x` error: deref which would be done by auto-deref - --> tests/ui/explicit_auto_deref.rs:129:25 + --> tests/ui/explicit_auto_deref.rs:130:25 | LL | f8.callable_t()(&*x); | ^^^ help: try: `&x` error: deref which would be done by auto-deref - --> tests/ui/explicit_auto_deref.rs:130:12 + --> tests/ui/explicit_auto_deref.rs:131:12 | LL | f9(&*x); | ^^^ help: try: `&x` error: deref which would be done by auto-deref - --> tests/ui/explicit_auto_deref.rs:131:13 + --> tests/ui/explicit_auto_deref.rs:132:13 | LL | f10(&*x); | ^^^ help: try: `&x` error: deref which would be done by auto-deref - --> tests/ui/explicit_auto_deref.rs:132:26 + --> tests/ui/explicit_auto_deref.rs:133:26 | LL | f11.callable_t()(&*x); | ^^^ help: try: `&x` error: deref which would be done by auto-deref - --> tests/ui/explicit_auto_deref.rs:136:16 + --> tests/ui/explicit_auto_deref.rs:137:16 | LL | let _ = S1(&*s); | ^^^ help: try: `&s` error: deref which would be done by auto-deref - --> tests/ui/explicit_auto_deref.rs:141:21 + --> tests/ui/explicit_auto_deref.rs:142:21 | LL | let _ = S2 { s: &*s }; | ^^^ help: try: `&s` error: deref which would be done by auto-deref - --> tests/ui/explicit_auto_deref.rs:157:30 + --> tests/ui/explicit_auto_deref.rs:158:30 | LL | let _ = Self::S1(&**s); | ^^^^ help: try: `s` error: deref which would be done by auto-deref - --> tests/ui/explicit_auto_deref.rs:158:35 + --> tests/ui/explicit_auto_deref.rs:159:35 | LL | let _ = Self::S2 { s: &**s }; | ^^^^ help: try: `s` error: deref which would be done by auto-deref - --> tests/ui/explicit_auto_deref.rs:161:20 + --> tests/ui/explicit_auto_deref.rs:162:20 | LL | let _ = E1::S1(&*s); | ^^^ help: try: `&s` error: deref which would be done by auto-deref - --> tests/ui/explicit_auto_deref.rs:162:25 + --> tests/ui/explicit_auto_deref.rs:163:25 | LL | let _ = E1::S2 { s: &*s }; | ^^^ help: try: `&s` error: deref which would be done by auto-deref - --> tests/ui/explicit_auto_deref.rs:180:13 + --> tests/ui/explicit_auto_deref.rs:181:13 | LL | let _ = (*b).foo; | ^^^^ help: try: `b` error: deref which would be done by auto-deref - --> tests/ui/explicit_auto_deref.rs:181:13 + --> tests/ui/explicit_auto_deref.rs:182:13 | LL | let _ = (**b).foo; | ^^^^^ help: try: `b` error: deref which would be done by auto-deref - --> tests/ui/explicit_auto_deref.rs:196:19 + --> tests/ui/explicit_auto_deref.rs:197:19 | LL | let _ = f_str(*ref_str); | ^^^^^^^^ help: try: `ref_str` error: deref which would be done by auto-deref - --> tests/ui/explicit_auto_deref.rs:198:19 + --> tests/ui/explicit_auto_deref.rs:199:19 | LL | let _ = f_str(**ref_ref_str); | ^^^^^^^^^^^^^ help: try: `ref_ref_str` error: deref which would be done by auto-deref - --> tests/ui/explicit_auto_deref.rs:208:12 + --> tests/ui/explicit_auto_deref.rs:209:12 | LL | f_str(&&*ref_str); // `needless_borrow` will suggest removing both references | ^^^^^^^^^ help: try: `ref_str` error: deref which would be done by auto-deref - --> tests/ui/explicit_auto_deref.rs:209:12 + --> tests/ui/explicit_auto_deref.rs:210:12 | LL | f_str(&&**ref_str); // `needless_borrow` will suggest removing only one reference | ^^^^^^^^^^ help: try: `ref_str` error: deref which would be done by auto-deref - --> tests/ui/explicit_auto_deref.rs:218:41 + --> tests/ui/explicit_auto_deref.rs:219:41 | LL | let _ = || -> &'static str { return *s }; | ^^ help: try: `s` error: deref which would be done by auto-deref - --> tests/ui/explicit_auto_deref.rs:237:9 + --> tests/ui/explicit_auto_deref.rs:238:9 | LL | &**x | ^^^^ help: try: `x` error: deref which would be done by auto-deref - --> tests/ui/explicit_auto_deref.rs:260:8 + --> tests/ui/explicit_auto_deref.rs:261:8 | LL | c1(*x); | ^^ help: try: `x` error: deref which would be done by auto-deref - --> tests/ui/explicit_auto_deref.rs:263:20 + --> tests/ui/explicit_auto_deref.rs:264:20 | LL | return *x; | ^^ help: try: `x` error: deref which would be done by auto-deref - --> tests/ui/explicit_auto_deref.rs:265:9 + --> tests/ui/explicit_auto_deref.rs:266:9 | LL | *x | ^^ help: try: `x` error: deref which would be done by auto-deref - --> tests/ui/explicit_auto_deref.rs:299:20 + --> tests/ui/explicit_auto_deref.rs:300:20 | LL | Some(x) => &mut *x, | ^^^^^^^ help: try: `x` error: deref which would be done by auto-deref - --> tests/ui/explicit_auto_deref.rs:332:22 + --> tests/ui/explicit_auto_deref.rs:333:22 | LL | let _ = &mut (*{ x.u }).x; | ^^^^^^^^^^ help: try: `{ x.u }` error: deref which would be done by auto-deref - --> tests/ui/explicit_auto_deref.rs:338:22 + --> tests/ui/explicit_auto_deref.rs:339:22 | LL | let _ = &mut (**x.u).x; | ^^^^^^^ help: try: `(*x.u)` error: deref which would be done by auto-deref - --> tests/ui/explicit_auto_deref.rs:339:22 + --> tests/ui/explicit_auto_deref.rs:340:22 | LL | let _ = &mut (**{ x.u }).x; | ^^^^^^^^^^^ help: try: `{ x.u }` error: deref which would be done by auto-deref - --> tests/ui/explicit_auto_deref.rs:343:22 + --> tests/ui/explicit_auto_deref.rs:344:22 | LL | let _ = &mut (*x.u).x; | ^^^^^^ help: try: `x.u` error: deref which would be done by auto-deref - --> tests/ui/explicit_auto_deref.rs:344:22 + --> tests/ui/explicit_auto_deref.rs:345:22 | LL | let _ = &mut (*{ x.u }).x; | ^^^^^^^^^^ help: try: `{ x.u }` error: deref which would be done by auto-deref - --> tests/ui/explicit_auto_deref.rs:367:13 + --> tests/ui/explicit_auto_deref.rs:368:13 | LL | foo(&*wrapped_bar); | ^^^^^^^^^^^^^ help: try: `&wrapped_bar` 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 5bbdabcaad1..a4cb50bd682 100644 --- a/tests/ui/index_refutable_slice/if_let_slice_binding.rs +++ b/tests/ui/index_refutable_slice/if_let_slice_binding.rs @@ -1,5 +1,5 @@ #![deny(clippy::index_refutable_slice)] -#![allow(clippy::uninlined_format_args)] +#![allow(clippy::uninlined_format_args, clippy::needless_lifetimes)] //@no-rustfix: need to change the suggestion to a multipart suggestion diff --git a/tests/ui/iter_without_into_iter.rs b/tests/ui/iter_without_into_iter.rs index 3054d848efb..d5b28e45453 100644 --- a/tests/ui/iter_without_into_iter.rs +++ b/tests/ui/iter_without_into_iter.rs @@ -1,6 +1,7 @@ //@no-rustfix //@aux-build:proc_macros.rs #![warn(clippy::iter_without_into_iter)] +#![allow(clippy::needless_lifetimes)] extern crate proc_macros; pub struct S1; diff --git a/tests/ui/iter_without_into_iter.stderr b/tests/ui/iter_without_into_iter.stderr index 382a7606f48..7c42fa1dd89 100644 --- a/tests/ui/iter_without_into_iter.stderr +++ b/tests/ui/iter_without_into_iter.stderr @@ -1,5 +1,5 @@ error: `iter` method without an `IntoIterator` impl for `&S1` - --> tests/ui/iter_without_into_iter.rs:8:5 + --> tests/ui/iter_without_into_iter.rs:9:5 | LL | / pub fn iter(&self) -> std::slice::Iter<'_, u8> { LL | | @@ -22,7 +22,7 @@ LL + } | error: `iter_mut` method without an `IntoIterator` impl for `&mut S1` - --> tests/ui/iter_without_into_iter.rs:12:5 + --> tests/ui/iter_without_into_iter.rs:13:5 | LL | / pub fn iter_mut(&mut self) -> std::slice::IterMut<'_, u8> { LL | | @@ -43,7 +43,7 @@ LL + } | error: `iter` method without an `IntoIterator` impl for `&S3<'a>` - --> tests/ui/iter_without_into_iter.rs:28:5 + --> tests/ui/iter_without_into_iter.rs:29:5 | LL | / pub fn iter(&self) -> std::slice::Iter<'_, u8> { LL | | @@ -64,7 +64,7 @@ LL + } | error: `iter_mut` method without an `IntoIterator` impl for `&mut S3<'a>` - --> tests/ui/iter_without_into_iter.rs:32:5 + --> tests/ui/iter_without_into_iter.rs:33:5 | LL | / pub fn iter_mut(&mut self) -> std::slice::IterMut<'_, u8> { LL | | @@ -85,7 +85,7 @@ LL + } | error: `iter` method without an `IntoIterator` impl for `&S8` - --> tests/ui/iter_without_into_iter.rs:69:5 + --> tests/ui/iter_without_into_iter.rs:70:5 | LL | / pub fn iter(&self) -> std::slice::Iter<'static, T> { LL | | todo!() @@ -105,7 +105,7 @@ LL + } | error: `iter` method without an `IntoIterator` impl for `&S9` - --> tests/ui/iter_without_into_iter.rs:77:5 + --> tests/ui/iter_without_into_iter.rs:78:5 | LL | / pub fn iter(&self) -> std::slice::Iter<'_, T> { LL | | @@ -126,7 +126,7 @@ LL + } | error: `iter_mut` method without an `IntoIterator` impl for `&mut S9` - --> tests/ui/iter_without_into_iter.rs:81:5 + --> tests/ui/iter_without_into_iter.rs:82:5 | LL | / pub fn iter_mut(&mut self) -> std::slice::IterMut<'_, T> { LL | | @@ -147,7 +147,7 @@ LL + } | error: `iter` method without an `IntoIterator` impl for `&Issue12037` - --> tests/ui/iter_without_into_iter.rs:130:13 + --> tests/ui/iter_without_into_iter.rs:131:13 | LL | / fn iter(&self) -> std::slice::Iter<'_, u8> { LL | | todo!() diff --git a/tests/ui/mem_replace.fixed b/tests/ui/mem_replace.fixed index 78d8b3e9bce..4210dbbe82d 100644 --- a/tests/ui/mem_replace.fixed +++ b/tests/ui/mem_replace.fixed @@ -1,6 +1,5 @@ -#![allow(unused)] +#![allow(unused, clippy::needless_lifetimes)] #![warn( - clippy::all, clippy::style, clippy::mem_replace_option_with_none, clippy::mem_replace_with_default diff --git a/tests/ui/mem_replace.rs b/tests/ui/mem_replace.rs index 28915bf6dae..bd7ad78b2af 100644 --- a/tests/ui/mem_replace.rs +++ b/tests/ui/mem_replace.rs @@ -1,6 +1,5 @@ -#![allow(unused)] +#![allow(unused, clippy::needless_lifetimes)] #![warn( - clippy::all, clippy::style, clippy::mem_replace_option_with_none, clippy::mem_replace_with_default diff --git a/tests/ui/mem_replace.stderr b/tests/ui/mem_replace.stderr index 44be2c9b63d..c33f80b01b8 100644 --- a/tests/ui/mem_replace.stderr +++ b/tests/ui/mem_replace.stderr @@ -1,5 +1,5 @@ error: replacing an `Option` with `None` - --> tests/ui/mem_replace.rs:14:13 + --> tests/ui/mem_replace.rs:13:13 | LL | let _ = mem::replace(&mut an_option, None); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider `Option::take()` instead: `an_option.take()` @@ -8,13 +8,13 @@ LL | let _ = mem::replace(&mut an_option, None); = help: to override `-D warnings` add `#[allow(clippy::mem_replace_option_with_none)]` error: replacing an `Option` with `None` - --> tests/ui/mem_replace.rs:16:13 + --> tests/ui/mem_replace.rs:15:13 | LL | let _ = mem::replace(an_option, None); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider `Option::take()` instead: `an_option.take()` error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take` - --> tests/ui/mem_replace.rs:21:13 + --> tests/ui/mem_replace.rs:20:13 | LL | let _ = std::mem::replace(&mut s, String::default()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut s)` @@ -23,127 +23,127 @@ LL | let _ = std::mem::replace(&mut s, String::default()); = help: to override `-D warnings` add `#[allow(clippy::mem_replace_with_default)]` error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take` - --> tests/ui/mem_replace.rs:24:13 + --> tests/ui/mem_replace.rs:23:13 | LL | let _ = std::mem::replace(s, String::default()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(s)` error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take` - --> tests/ui/mem_replace.rs:25:13 + --> tests/ui/mem_replace.rs:24:13 | LL | let _ = std::mem::replace(s, Default::default()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(s)` error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take` - --> tests/ui/mem_replace.rs:28:13 + --> tests/ui/mem_replace.rs:27:13 | LL | let _ = std::mem::replace(&mut v, Vec::default()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut v)` error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take` - --> tests/ui/mem_replace.rs:29:13 + --> tests/ui/mem_replace.rs:28:13 | LL | let _ = std::mem::replace(&mut v, Default::default()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut v)` error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take` - --> tests/ui/mem_replace.rs:30:13 + --> tests/ui/mem_replace.rs:29:13 | LL | let _ = std::mem::replace(&mut v, Vec::new()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut v)` error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take` - --> tests/ui/mem_replace.rs:31:13 + --> tests/ui/mem_replace.rs:30:13 | LL | let _ = std::mem::replace(&mut v, vec![]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut v)` error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take` - --> tests/ui/mem_replace.rs:34:13 + --> tests/ui/mem_replace.rs:33:13 | LL | let _ = std::mem::replace(&mut hash_map, HashMap::new()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut hash_map)` error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take` - --> tests/ui/mem_replace.rs:37:13 + --> tests/ui/mem_replace.rs:36:13 | LL | let _ = std::mem::replace(&mut btree_map, BTreeMap::new()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut btree_map)` error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take` - --> tests/ui/mem_replace.rs:40:13 + --> tests/ui/mem_replace.rs:39:13 | LL | let _ = std::mem::replace(&mut vd, VecDeque::new()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut vd)` error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take` - --> tests/ui/mem_replace.rs:43:13 + --> tests/ui/mem_replace.rs:42:13 | LL | let _ = std::mem::replace(&mut hash_set, HashSet::new()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut hash_set)` error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take` - --> tests/ui/mem_replace.rs:46:13 + --> tests/ui/mem_replace.rs:45:13 | LL | let _ = std::mem::replace(&mut btree_set, BTreeSet::new()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut btree_set)` error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take` - --> tests/ui/mem_replace.rs:49:13 + --> tests/ui/mem_replace.rs:48:13 | LL | let _ = std::mem::replace(&mut list, LinkedList::new()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut list)` error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take` - --> tests/ui/mem_replace.rs:52:13 + --> tests/ui/mem_replace.rs:51:13 | LL | let _ = std::mem::replace(&mut binary_heap, BinaryHeap::new()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut binary_heap)` error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take` - --> tests/ui/mem_replace.rs:55:13 + --> tests/ui/mem_replace.rs:54:13 | LL | let _ = std::mem::replace(&mut tuple, (vec![], BinaryHeap::new())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut tuple)` error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take` - --> tests/ui/mem_replace.rs:58:13 + --> tests/ui/mem_replace.rs:57:13 | LL | let _ = std::mem::replace(&mut refstr, ""); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut refstr)` error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take` - --> tests/ui/mem_replace.rs:61:13 + --> tests/ui/mem_replace.rs:60:13 | LL | let _ = std::mem::replace(&mut slice, &[]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut slice)` error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take` - --> tests/ui/mem_replace.rs:97:13 + --> tests/ui/mem_replace.rs:96:13 | LL | let _ = std::mem::replace(&mut s, String::default()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut s)` error: replacing an `Option` with `None` - --> tests/ui/mem_replace.rs:127:13 + --> tests/ui/mem_replace.rs:126:13 | LL | let _ = std::mem::replace(&mut f.0, None); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider `Option::take()` instead: `f.0.take()` error: replacing an `Option` with `None` - --> tests/ui/mem_replace.rs:128:13 + --> tests/ui/mem_replace.rs:127:13 | LL | let _ = std::mem::replace(&mut *f, None); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider `Option::take()` instead: `(*f).take()` error: replacing an `Option` with `None` - --> tests/ui/mem_replace.rs:129:13 + --> tests/ui/mem_replace.rs:128:13 | LL | let _ = std::mem::replace(&mut b.opt, None); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider `Option::take()` instead: `b.opt.take()` error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take` - --> tests/ui/mem_replace.rs:131:13 + --> tests/ui/mem_replace.rs:130:13 | LL | let _ = std::mem::replace(&mut b.val, String::default()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut b.val)` diff --git a/tests/ui/mem_replace_no_std.fixed b/tests/ui/mem_replace_no_std.fixed index c970f2ba281..60f523c8ef1 100644 --- a/tests/ui/mem_replace_no_std.fixed +++ b/tests/ui/mem_replace_no_std.fixed @@ -1,6 +1,5 @@ -#![allow(unused)] +#![allow(unused, clippy::needless_lifetimes)] #![warn( - clippy::all, clippy::style, clippy::mem_replace_option_with_none, clippy::mem_replace_with_default diff --git a/tests/ui/mem_replace_no_std.rs b/tests/ui/mem_replace_no_std.rs index 673d5c7b4f4..d1cb9a5817b 100644 --- a/tests/ui/mem_replace_no_std.rs +++ b/tests/ui/mem_replace_no_std.rs @@ -1,6 +1,5 @@ -#![allow(unused)] +#![allow(unused, clippy::needless_lifetimes)] #![warn( - clippy::all, clippy::style, clippy::mem_replace_option_with_none, clippy::mem_replace_with_default diff --git a/tests/ui/mem_replace_no_std.stderr b/tests/ui/mem_replace_no_std.stderr index eea538da427..6ba6d2162a7 100644 --- a/tests/ui/mem_replace_no_std.stderr +++ b/tests/ui/mem_replace_no_std.stderr @@ -1,5 +1,5 @@ error: replacing an `Option` with `None` - --> tests/ui/mem_replace_no_std.rs:24:13 + --> tests/ui/mem_replace_no_std.rs:23:13 | LL | let _ = mem::replace(&mut an_option, None); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider `Option::take()` instead: `an_option.take()` @@ -8,13 +8,13 @@ LL | let _ = mem::replace(&mut an_option, None); = help: to override `-D warnings` add `#[allow(clippy::mem_replace_option_with_none)]` error: replacing an `Option` with `None` - --> tests/ui/mem_replace_no_std.rs:26:13 + --> tests/ui/mem_replace_no_std.rs:25:13 | LL | let _ = mem::replace(an_option, None); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider `Option::take()` instead: `an_option.take()` error: replacing a value of type `T` with `T::default()` is better expressed using `core::mem::take` - --> tests/ui/mem_replace_no_std.rs:31:13 + --> tests/ui/mem_replace_no_std.rs:30:13 | LL | let _ = mem::replace(&mut refstr, ""); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `core::mem::take(&mut refstr)` @@ -23,25 +23,25 @@ LL | let _ = mem::replace(&mut refstr, ""); = help: to override `-D warnings` add `#[allow(clippy::mem_replace_with_default)]` error: replacing a value of type `T` with `T::default()` is better expressed using `core::mem::take` - --> tests/ui/mem_replace_no_std.rs:34:13 + --> tests/ui/mem_replace_no_std.rs:33:13 | LL | let _ = mem::replace(&mut slice, &[]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `core::mem::take(&mut slice)` error: replacing an `Option` with `None` - --> tests/ui/mem_replace_no_std.rs:77:13 + --> tests/ui/mem_replace_no_std.rs:76:13 | LL | let _ = mem::replace(&mut f.0, None); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider `Option::take()` instead: `f.0.take()` error: replacing an `Option` with `None` - --> tests/ui/mem_replace_no_std.rs:78:13 + --> tests/ui/mem_replace_no_std.rs:77:13 | LL | let _ = mem::replace(&mut *f, None); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider `Option::take()` instead: `(*f).take()` error: replacing an `Option` with `None` - --> tests/ui/mem_replace_no_std.rs:79:13 + --> tests/ui/mem_replace_no_std.rs:78:13 | LL | let _ = mem::replace(&mut b.opt, None); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider `Option::take()` instead: `b.opt.take()` diff --git a/tests/ui/mismatching_type_param_order.rs b/tests/ui/mismatching_type_param_order.rs index af2882e41fb..a4560f9e9a9 100644 --- a/tests/ui/mismatching_type_param_order.rs +++ b/tests/ui/mismatching_type_param_order.rs @@ -1,5 +1,5 @@ #![warn(clippy::mismatching_type_param_order)] -#![allow(clippy::disallowed_names)] +#![allow(clippy::disallowed_names, clippy::needless_lifetimes)] fn main() { struct Foo { diff --git a/tests/ui/needless_borrow.fixed b/tests/ui/needless_borrow.fixed index cabdc22bda8..2763830e09c 100644 --- a/tests/ui/needless_borrow.fixed +++ b/tests/ui/needless_borrow.fixed @@ -4,7 +4,8 @@ clippy::uninlined_format_args, clippy::unnecessary_mut_passed, clippy::unnecessary_to_owned, - clippy::unnecessary_literal_unwrap + clippy::unnecessary_literal_unwrap, + clippy::needless_lifetimes )] #![warn(clippy::needless_borrow)] diff --git a/tests/ui/needless_borrow.rs b/tests/ui/needless_borrow.rs index 50062589645..b46f82b18c6 100644 --- a/tests/ui/needless_borrow.rs +++ b/tests/ui/needless_borrow.rs @@ -4,7 +4,8 @@ clippy::uninlined_format_args, clippy::unnecessary_mut_passed, clippy::unnecessary_to_owned, - clippy::unnecessary_literal_unwrap + clippy::unnecessary_literal_unwrap, + clippy::needless_lifetimes )] #![warn(clippy::needless_borrow)] diff --git a/tests/ui/needless_borrow.stderr b/tests/ui/needless_borrow.stderr index bf0e265c250..4b2b17e7e57 100644 --- a/tests/ui/needless_borrow.stderr +++ b/tests/ui/needless_borrow.stderr @@ -1,5 +1,5 @@ error: this expression creates a reference which is immediately dereferenced by the compiler - --> tests/ui/needless_borrow.rs:15:15 + --> tests/ui/needless_borrow.rs:16:15 | LL | let _ = x(&&a); // warn | ^^^ help: change this to: `&a` @@ -8,163 +8,163 @@ LL | let _ = x(&&a); // warn = help: to override `-D warnings` add `#[allow(clippy::needless_borrow)]` error: this expression creates a reference which is immediately dereferenced by the compiler - --> tests/ui/needless_borrow.rs:19:13 + --> tests/ui/needless_borrow.rs:20:13 | LL | mut_ref(&mut &mut b); // warn | ^^^^^^^^^^^ help: change this to: `&mut b` error: this expression creates a reference which is immediately dereferenced by the compiler - --> tests/ui/needless_borrow.rs:31:13 + --> tests/ui/needless_borrow.rs:32:13 | LL | &&a | ^^^ help: change this to: `&a` error: this expression creates a reference which is immediately dereferenced by the compiler - --> tests/ui/needless_borrow.rs:33:15 + --> tests/ui/needless_borrow.rs:34:15 | LL | 46 => &&a, | ^^^ help: change this to: `&a` error: this expression creates a reference which is immediately dereferenced by the compiler - --> tests/ui/needless_borrow.rs:39:27 + --> tests/ui/needless_borrow.rs:40:27 | LL | break &ref_a; | ^^^^^^ help: change this to: `ref_a` error: this expression creates a reference which is immediately dereferenced by the compiler - --> tests/ui/needless_borrow.rs:46:15 + --> tests/ui/needless_borrow.rs:47:15 | LL | let _ = x(&&&a); | ^^^^ help: change this to: `&a` error: this expression creates a reference which is immediately dereferenced by the compiler - --> tests/ui/needless_borrow.rs:47:15 + --> tests/ui/needless_borrow.rs:48:15 | LL | let _ = x(&mut &&a); | ^^^^^^^^ help: change this to: `&a` error: this expression creates a reference which is immediately dereferenced by the compiler - --> tests/ui/needless_borrow.rs:48:15 + --> tests/ui/needless_borrow.rs:49:15 | LL | let _ = x(&&&mut b); | ^^^^^^^^ help: change this to: `&mut b` error: this expression creates a reference which is immediately dereferenced by the compiler - --> tests/ui/needless_borrow.rs:49:15 + --> tests/ui/needless_borrow.rs:50:15 | LL | let _ = x(&&ref_a); | ^^^^^^^ help: change this to: `ref_a` error: this expression creates a reference which is immediately dereferenced by the compiler - --> tests/ui/needless_borrow.rs:52:11 + --> tests/ui/needless_borrow.rs:53:11 | LL | x(&b); | ^^ help: change this to: `b` error: this expression creates a reference which is immediately dereferenced by the compiler - --> tests/ui/needless_borrow.rs:59:13 + --> tests/ui/needless_borrow.rs:60:13 | LL | mut_ref(&mut x); | ^^^^^^ help: change this to: `x` error: this expression creates a reference which is immediately dereferenced by the compiler - --> tests/ui/needless_borrow.rs:60:13 + --> tests/ui/needless_borrow.rs:61:13 | LL | mut_ref(&mut &mut x); | ^^^^^^^^^^^ help: change this to: `x` error: this expression creates a reference which is immediately dereferenced by the compiler - --> tests/ui/needless_borrow.rs:61:23 + --> tests/ui/needless_borrow.rs:62:23 | LL | let y: &mut i32 = &mut x; | ^^^^^^ help: change this to: `x` error: this expression creates a reference which is immediately dereferenced by the compiler - --> tests/ui/needless_borrow.rs:62:23 + --> tests/ui/needless_borrow.rs:63:23 | LL | let y: &mut i32 = &mut &mut x; | ^^^^^^^^^^^ help: change this to: `x` error: this expression creates a reference which is immediately dereferenced by the compiler - --> tests/ui/needless_borrow.rs:71:14 + --> tests/ui/needless_borrow.rs:72:14 | LL | 0 => &mut x, | ^^^^^^ help: change this to: `x` error: this expression creates a reference which is immediately dereferenced by the compiler - --> tests/ui/needless_borrow.rs:77:14 + --> tests/ui/needless_borrow.rs:78:14 | LL | 0 => &mut x, | ^^^^^^ help: change this to: `x` error: this expression borrows a value the compiler would automatically borrow - --> tests/ui/needless_borrow.rs:89:13 + --> tests/ui/needless_borrow.rs:90:13 | LL | let _ = (&x).0; | ^^^^ help: change this to: `x` error: this expression borrows a value the compiler would automatically borrow - --> tests/ui/needless_borrow.rs:91:22 + --> tests/ui/needless_borrow.rs:92:22 | LL | let _ = unsafe { (&*x).0 }; | ^^^^^ help: change this to: `(*x)` error: this expression creates a reference which is immediately dereferenced by the compiler - --> tests/ui/needless_borrow.rs:101:5 + --> tests/ui/needless_borrow.rs:102:5 | LL | (&&()).foo(); | ^^^^^^ help: change this to: `(&())` error: this expression creates a reference which is immediately dereferenced by the compiler - --> tests/ui/needless_borrow.rs:110:5 + --> tests/ui/needless_borrow.rs:111:5 | LL | (&&5).foo(); | ^^^^^ help: change this to: `(&5)` error: this expression creates a reference which is immediately dereferenced by the compiler - --> tests/ui/needless_borrow.rs:136:23 + --> tests/ui/needless_borrow.rs:137:23 | LL | let x: (&str,) = (&"",); | ^^^ help: change this to: `""` error: this expression borrows a value the compiler would automatically borrow - --> tests/ui/needless_borrow.rs:178:13 + --> tests/ui/needless_borrow.rs:179:13 | LL | (&self.f)() | ^^^^^^^^^ help: change this to: `(self.f)` error: this expression borrows a value the compiler would automatically borrow - --> tests/ui/needless_borrow.rs:187:13 + --> tests/ui/needless_borrow.rs:188:13 | LL | (&mut self.f)() | ^^^^^^^^^^^^^ help: change this to: `(self.f)` error: this expression borrows a value the compiler would automatically borrow - --> tests/ui/needless_borrow.rs:224:22 + --> tests/ui/needless_borrow.rs:225:22 | LL | let _ = &mut (&mut { x.u }).x; | ^^^^^^^^^^^^^^ help: change this to: `{ x.u }` error: this expression borrows a value the compiler would automatically borrow - --> tests/ui/needless_borrow.rs:231:22 + --> tests/ui/needless_borrow.rs:232:22 | LL | let _ = &mut (&mut { x.u }).x; | ^^^^^^^^^^^^^^ help: change this to: `{ x.u }` error: this expression borrows a value the compiler would automatically borrow - --> tests/ui/needless_borrow.rs:235:22 + --> tests/ui/needless_borrow.rs:236:22 | LL | let _ = &mut (&mut x.u).x; | ^^^^^^^^^^ help: change this to: `x.u` error: this expression borrows a value the compiler would automatically borrow - --> tests/ui/needless_borrow.rs:236:22 + --> tests/ui/needless_borrow.rs:237:22 | LL | let _ = &mut (&mut { x.u }).x; | ^^^^^^^^^^^^^^ help: change this to: `{ x.u }` error: this expression creates a reference which is immediately dereferenced by the compiler - --> tests/ui/needless_borrow.rs:257:23 + --> tests/ui/needless_borrow.rs:258:23 | LL | option.unwrap_or((&x.0,)); | ^^^^ help: change this to: `x.0` diff --git a/tests/ui/needless_pass_by_value.rs b/tests/ui/needless_pass_by_value.rs index 9408b8c948f..a8d9db95dcc 100644 --- a/tests/ui/needless_pass_by_value.rs +++ b/tests/ui/needless_pass_by_value.rs @@ -5,7 +5,8 @@ clippy::redundant_clone, clippy::redundant_pattern_matching, clippy::single_match, - clippy::uninlined_format_args + clippy::uninlined_format_args, + clippy::needless_lifetimes )] //@no-rustfix use std::borrow::Borrow; diff --git a/tests/ui/needless_pass_by_value.stderr b/tests/ui/needless_pass_by_value.stderr index 46ef8f3e8da..2587d3f8c52 100644 --- a/tests/ui/needless_pass_by_value.stderr +++ b/tests/ui/needless_pass_by_value.stderr @@ -1,5 +1,5 @@ error: this argument is passed by value, but not consumed in the function body - --> tests/ui/needless_pass_by_value.rs:18:23 + --> tests/ui/needless_pass_by_value.rs:19:23 | LL | fn foo(v: Vec, w: Vec, mut x: Vec, y: Vec) -> Vec { | ^^^^^^ help: consider changing the type to: `&[T]` @@ -8,55 +8,55 @@ LL | fn foo(v: Vec, w: Vec, mut x: Vec, y: Vec) -> Vec tests/ui/needless_pass_by_value.rs:34:11 + --> tests/ui/needless_pass_by_value.rs:35:11 | LL | fn bar(x: String, y: Wrapper) { | ^^^^^^ help: consider changing the type to: `&str` error: this argument is passed by value, but not consumed in the function body - --> tests/ui/needless_pass_by_value.rs:34:22 + --> tests/ui/needless_pass_by_value.rs:35:22 | LL | fn bar(x: String, y: Wrapper) { | ^^^^^^^ help: consider taking a reference instead: `&Wrapper` error: this argument is passed by value, but not consumed in the function body - --> tests/ui/needless_pass_by_value.rs:42:71 + --> tests/ui/needless_pass_by_value.rs:43:71 | LL | fn test_borrow_trait, U: AsRef, V>(t: T, u: U, v: V) { | ^ help: consider taking a reference instead: `&V` error: this argument is passed by value, but not consumed in the function body - --> tests/ui/needless_pass_by_value.rs:55:18 + --> tests/ui/needless_pass_by_value.rs:56:18 | LL | fn test_match(x: Option>, y: Option>) { | ^^^^^^^^^^^^^^^^^^^^^^ help: consider taking a reference instead: `&Option>` error: this argument is passed by value, but not consumed in the function body - --> tests/ui/needless_pass_by_value.rs:69:24 + --> tests/ui/needless_pass_by_value.rs:70:24 | LL | fn test_destructure(x: Wrapper, y: Wrapper, z: Wrapper) { | ^^^^^^^ help: consider taking a reference instead: `&Wrapper` error: this argument is passed by value, but not consumed in the function body - --> tests/ui/needless_pass_by_value.rs:69:36 + --> tests/ui/needless_pass_by_value.rs:70:36 | LL | fn test_destructure(x: Wrapper, y: Wrapper, z: Wrapper) { | ^^^^^^^ help: consider taking a reference instead: `&Wrapper` error: this argument is passed by value, but not consumed in the function body - --> tests/ui/needless_pass_by_value.rs:87:49 + --> tests/ui/needless_pass_by_value.rs:88:49 | LL | fn test_blanket_ref(vals: T, serializable: S) {} | ^ help: consider taking a reference instead: `&T` error: this argument is passed by value, but not consumed in the function body - --> tests/ui/needless_pass_by_value.rs:90:18 + --> tests/ui/needless_pass_by_value.rs:91:18 | LL | fn issue_2114(s: String, t: String, u: Vec, v: Vec) { | ^^^^^^ help: consider taking a reference instead: `&String` error: this argument is passed by value, but not consumed in the function body - --> tests/ui/needless_pass_by_value.rs:90:29 + --> tests/ui/needless_pass_by_value.rs:91:29 | LL | fn issue_2114(s: String, t: String, u: Vec, v: Vec) { | ^^^^^^ @@ -71,13 +71,13 @@ LL | let _ = t.to_string(); | ~~~~~~~~~~~~~ error: this argument is passed by value, but not consumed in the function body - --> tests/ui/needless_pass_by_value.rs:90:40 + --> tests/ui/needless_pass_by_value.rs:91:40 | LL | fn issue_2114(s: String, t: String, u: Vec, v: Vec) { | ^^^^^^^^ help: consider taking a reference instead: `&Vec` error: this argument is passed by value, but not consumed in the function body - --> tests/ui/needless_pass_by_value.rs:90:53 + --> tests/ui/needless_pass_by_value.rs:91:53 | LL | fn issue_2114(s: String, t: String, u: Vec, v: Vec) { | ^^^^^^^^ @@ -92,85 +92,85 @@ LL | let _ = v.to_owned(); | ~~~~~~~~~~~~ error: this argument is passed by value, but not consumed in the function body - --> tests/ui/needless_pass_by_value.rs:107:12 + --> tests/ui/needless_pass_by_value.rs:108:12 | LL | s: String, | ^^^^^^ help: consider changing the type to: `&str` error: this argument is passed by value, but not consumed in the function body - --> tests/ui/needless_pass_by_value.rs:109:12 + --> tests/ui/needless_pass_by_value.rs:110:12 | LL | t: String, | ^^^^^^ help: consider taking a reference instead: `&String` error: this argument is passed by value, but not consumed in the function body - --> tests/ui/needless_pass_by_value.rs:119:23 + --> tests/ui/needless_pass_by_value.rs:120:23 | LL | fn baz(&self, uu: U, ss: Self) {} | ^ help: consider taking a reference instead: `&U` error: this argument is passed by value, but not consumed in the function body - --> tests/ui/needless_pass_by_value.rs:119:30 + --> tests/ui/needless_pass_by_value.rs:120:30 | LL | fn baz(&self, uu: U, ss: Self) {} | ^^^^ help: consider taking a reference instead: `&Self` error: this argument is passed by value, but not consumed in the function body - --> tests/ui/needless_pass_by_value.rs:143:24 + --> tests/ui/needless_pass_by_value.rs:144:24 | LL | fn bar_copy(x: u32, y: CopyWrapper) { | ^^^^^^^^^^^ help: consider taking a reference instead: `&CopyWrapper` | help: or consider marking this type as `Copy` - --> tests/ui/needless_pass_by_value.rs:141:1 + --> tests/ui/needless_pass_by_value.rs:142:1 | LL | struct CopyWrapper(u32); | ^^^^^^^^^^^^^^^^^^ error: this argument is passed by value, but not consumed in the function body - --> tests/ui/needless_pass_by_value.rs:150:29 + --> tests/ui/needless_pass_by_value.rs:151:29 | LL | fn test_destructure_copy(x: CopyWrapper, y: CopyWrapper, z: CopyWrapper) { | ^^^^^^^^^^^ help: consider taking a reference instead: `&CopyWrapper` | help: or consider marking this type as `Copy` - --> tests/ui/needless_pass_by_value.rs:141:1 + --> tests/ui/needless_pass_by_value.rs:142:1 | LL | struct CopyWrapper(u32); | ^^^^^^^^^^^^^^^^^^ error: this argument is passed by value, but not consumed in the function body - --> tests/ui/needless_pass_by_value.rs:150:45 + --> tests/ui/needless_pass_by_value.rs:151:45 | LL | fn test_destructure_copy(x: CopyWrapper, y: CopyWrapper, z: CopyWrapper) { | ^^^^^^^^^^^ help: consider taking a reference instead: `&CopyWrapper` | help: or consider marking this type as `Copy` - --> tests/ui/needless_pass_by_value.rs:141:1 + --> tests/ui/needless_pass_by_value.rs:142:1 | LL | struct CopyWrapper(u32); | ^^^^^^^^^^^^^^^^^^ error: this argument is passed by value, but not consumed in the function body - --> tests/ui/needless_pass_by_value.rs:150:61 + --> tests/ui/needless_pass_by_value.rs:151:61 | LL | fn test_destructure_copy(x: CopyWrapper, y: CopyWrapper, z: CopyWrapper) { | ^^^^^^^^^^^ help: consider taking a reference instead: `&CopyWrapper` | help: or consider marking this type as `Copy` - --> tests/ui/needless_pass_by_value.rs:141:1 + --> tests/ui/needless_pass_by_value.rs:142:1 | LL | struct CopyWrapper(u32); | ^^^^^^^^^^^^^^^^^^ error: this argument is passed by value, but not consumed in the function body - --> tests/ui/needless_pass_by_value.rs:165:40 + --> tests/ui/needless_pass_by_value.rs:166:40 | LL | fn some_fun<'b, S: Bar<'b, ()>>(items: S) {} | ^ help: consider taking a reference instead: `&S` error: this argument is passed by value, but not consumed in the function body - --> tests/ui/needless_pass_by_value.rs:171:20 + --> tests/ui/needless_pass_by_value.rs:172:20 | LL | fn more_fun(items: impl Club<'static, i32>) {} | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider taking a reference instead: `&impl Club<'static, i32>` diff --git a/tests/ui/new_without_default.fixed b/tests/ui/new_without_default.fixed index 85408c4e17f..5a6a92394a7 100644 --- a/tests/ui/new_without_default.fixed +++ b/tests/ui/new_without_default.fixed @@ -2,7 +2,8 @@ dead_code, clippy::missing_safety_doc, clippy::extra_unused_lifetimes, - clippy::extra_unused_type_parameters + clippy::extra_unused_type_parameters, + clippy::needless_lifetimes )] #![warn(clippy::new_without_default)] diff --git a/tests/ui/new_without_default.rs b/tests/ui/new_without_default.rs index 3ac7292c236..12ea729253a 100644 --- a/tests/ui/new_without_default.rs +++ b/tests/ui/new_without_default.rs @@ -2,7 +2,8 @@ dead_code, clippy::missing_safety_doc, clippy::extra_unused_lifetimes, - clippy::extra_unused_type_parameters + clippy::extra_unused_type_parameters, + clippy::needless_lifetimes )] #![warn(clippy::new_without_default)] diff --git a/tests/ui/new_without_default.stderr b/tests/ui/new_without_default.stderr index a30830ae7b2..57bf4bd847c 100644 --- a/tests/ui/new_without_default.stderr +++ b/tests/ui/new_without_default.stderr @@ -1,5 +1,5 @@ error: you should consider adding a `Default` implementation for `Foo` - --> tests/ui/new_without_default.rs:12:5 + --> tests/ui/new_without_default.rs:13:5 | LL | / pub fn new() -> Foo { LL | | @@ -20,7 +20,7 @@ LL + } | error: you should consider adding a `Default` implementation for `Bar` - --> tests/ui/new_without_default.rs:22:5 + --> tests/ui/new_without_default.rs:23:5 | LL | / pub fn new() -> Self { LL | | @@ -38,7 +38,7 @@ LL + } | error: you should consider adding a `Default` implementation for `LtKo<'c>` - --> tests/ui/new_without_default.rs:87:5 + --> tests/ui/new_without_default.rs:88:5 | LL | / pub fn new() -> LtKo<'c> { LL | | @@ -56,7 +56,7 @@ LL + } | error: you should consider adding a `Default` implementation for `Const` - --> tests/ui/new_without_default.rs:120:5 + --> tests/ui/new_without_default.rs:121:5 | LL | / pub const fn new() -> Const { LL | | Const @@ -73,7 +73,7 @@ LL + } | error: you should consider adding a `Default` implementation for `NewNotEqualToDerive` - --> tests/ui/new_without_default.rs:180:5 + --> tests/ui/new_without_default.rs:181:5 | LL | / pub fn new() -> Self { LL | | @@ -91,7 +91,7 @@ LL + } | error: you should consider adding a `Default` implementation for `FooGenerics` - --> tests/ui/new_without_default.rs:189:5 + --> tests/ui/new_without_default.rs:190:5 | LL | / pub fn new() -> Self { LL | | @@ -109,7 +109,7 @@ LL + } | error: you should consider adding a `Default` implementation for `BarGenerics` - --> tests/ui/new_without_default.rs:197:5 + --> tests/ui/new_without_default.rs:198:5 | LL | / pub fn new() -> Self { LL | | @@ -127,7 +127,7 @@ LL + } | error: you should consider adding a `Default` implementation for `Foo` - --> tests/ui/new_without_default.rs:209:9 + --> tests/ui/new_without_default.rs:210:9 | LL | / pub fn new() -> Self { LL | | @@ -147,7 +147,7 @@ LL ~ impl Foo { | error: you should consider adding a `Default` implementation for `MyStruct` - --> tests/ui/new_without_default.rs:255:5 + --> tests/ui/new_without_default.rs:256:5 | LL | / pub fn new() -> Self { LL | | Self { _kv: None } diff --git a/tests/ui/ref_as_ptr.fixed b/tests/ui/ref_as_ptr.fixed index 466a628a002..6048267092f 100644 --- a/tests/ui/ref_as_ptr.fixed +++ b/tests/ui/ref_as_ptr.fixed @@ -1,5 +1,5 @@ #![warn(clippy::ref_as_ptr)] -#![allow(clippy::unnecessary_mut_passed)] +#![allow(clippy::unnecessary_mut_passed, clippy::needless_lifetimes)] fn f(_: T) {} diff --git a/tests/ui/ref_as_ptr.rs b/tests/ui/ref_as_ptr.rs index 0fdc753dc22..7f1d59b856e 100644 --- a/tests/ui/ref_as_ptr.rs +++ b/tests/ui/ref_as_ptr.rs @@ -1,5 +1,5 @@ #![warn(clippy::ref_as_ptr)] -#![allow(clippy::unnecessary_mut_passed)] +#![allow(clippy::unnecessary_mut_passed, clippy::needless_lifetimes)] fn f(_: T) {} diff --git a/tests/ui/serde.rs b/tests/ui/serde.rs index 610a50020ec..af8b10f3e6a 100644 --- a/tests/ui/serde.rs +++ b/tests/ui/serde.rs @@ -1,5 +1,5 @@ #![warn(clippy::serde_api_misuse)] -#![allow(dead_code)] +#![allow(dead_code, clippy::needless_lifetimes)] extern crate serde; diff --git a/tests/ui/significant_drop_in_scrutinee.rs b/tests/ui/significant_drop_in_scrutinee.rs index 0db6fbfb7be..8468d1d7c7d 100644 --- a/tests/ui/significant_drop_in_scrutinee.rs +++ b/tests/ui/significant_drop_in_scrutinee.rs @@ -2,7 +2,12 @@ //@no-rustfix #![warn(clippy::significant_drop_in_scrutinee)] #![allow(dead_code, unused_assignments)] -#![allow(clippy::match_single_binding, clippy::single_match, clippy::uninlined_format_args)] +#![allow( + clippy::match_single_binding, + clippy::single_match, + clippy::uninlined_format_args, + clippy::needless_lifetimes +)] use std::num::ParseIntError; use std::ops::Deref; diff --git a/tests/ui/significant_drop_in_scrutinee.stderr b/tests/ui/significant_drop_in_scrutinee.stderr index c0c93cd10c0..62030cbe70e 100644 --- a/tests/ui/significant_drop_in_scrutinee.stderr +++ b/tests/ui/significant_drop_in_scrutinee.stderr @@ -1,5 +1,5 @@ error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> tests/ui/significant_drop_in_scrutinee.rs:55:11 + --> tests/ui/significant_drop_in_scrutinee.rs:60:11 | LL | match mutex.lock().unwrap().foo() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -20,7 +20,7 @@ LL ~ match value { | error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> tests/ui/significant_drop_in_scrutinee.rs:143:11 + --> tests/ui/significant_drop_in_scrutinee.rs:148:11 | LL | match s.lock_m().get_the_value() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -42,7 +42,7 @@ LL ~ match value { | error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> tests/ui/significant_drop_in_scrutinee.rs:166:11 + --> tests/ui/significant_drop_in_scrutinee.rs:171:11 | LL | match s.lock_m_m().get_the_value() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -64,7 +64,7 @@ LL ~ match value { | error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> tests/ui/significant_drop_in_scrutinee.rs:216:11 + --> tests/ui/significant_drop_in_scrutinee.rs:221:11 | LL | match counter.temp_increment().len() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -80,7 +80,7 @@ LL ~ match value { | error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> tests/ui/significant_drop_in_scrutinee.rs:241:16 + --> tests/ui/significant_drop_in_scrutinee.rs:246:16 | LL | match (mutex1.lock().unwrap().s.len(), true) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -99,7 +99,7 @@ LL ~ match (value, true) { | error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> tests/ui/significant_drop_in_scrutinee.rs:252:22 + --> tests/ui/significant_drop_in_scrutinee.rs:257:22 | LL | match (true, mutex1.lock().unwrap().s.len(), true) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -118,7 +118,7 @@ LL ~ match (true, value, true) { | error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> tests/ui/significant_drop_in_scrutinee.rs:264:16 + --> tests/ui/significant_drop_in_scrutinee.rs:269:16 | LL | match (mutex1.lock().unwrap().s.len(), true, mutex2.lock().unwrap().s.len()) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -139,7 +139,7 @@ LL ~ match (value, true, mutex2.lock().unwrap().s.len()) { | error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> tests/ui/significant_drop_in_scrutinee.rs:264:54 + --> tests/ui/significant_drop_in_scrutinee.rs:269:54 | LL | match (mutex1.lock().unwrap().s.len(), true, mutex2.lock().unwrap().s.len()) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -160,7 +160,7 @@ LL ~ match (mutex1.lock().unwrap().s.len(), true, value) { | error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> tests/ui/significant_drop_in_scrutinee.rs:319:11 + --> tests/ui/significant_drop_in_scrutinee.rs:324:11 | LL | match mutex.lock().unwrap().s.len() > 1 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -179,7 +179,7 @@ LL ~ match value > 1 { | error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> tests/ui/significant_drop_in_scrutinee.rs:328:15 + --> tests/ui/significant_drop_in_scrutinee.rs:333:15 | LL | match 1 < mutex.lock().unwrap().s.len() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -198,7 +198,7 @@ LL ~ match 1 < value { | error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> tests/ui/significant_drop_in_scrutinee.rs:348:11 + --> tests/ui/significant_drop_in_scrutinee.rs:353:11 | LL | match mutex1.lock().unwrap().s.len() < mutex2.lock().unwrap().s.len() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -219,7 +219,7 @@ LL ~ match value < mutex2.lock().unwrap().s.len() { | error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> tests/ui/significant_drop_in_scrutinee.rs:348:44 + --> tests/ui/significant_drop_in_scrutinee.rs:353:44 | LL | match mutex1.lock().unwrap().s.len() < mutex2.lock().unwrap().s.len() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -240,7 +240,7 @@ LL ~ match mutex1.lock().unwrap().s.len() < value { | error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> tests/ui/significant_drop_in_scrutinee.rs:361:11 + --> tests/ui/significant_drop_in_scrutinee.rs:366:11 | LL | match mutex1.lock().unwrap().s.len() >= mutex2.lock().unwrap().s.len() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -261,7 +261,7 @@ LL ~ match value >= mutex2.lock().unwrap().s.len() { | error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> tests/ui/significant_drop_in_scrutinee.rs:361:45 + --> tests/ui/significant_drop_in_scrutinee.rs:366:45 | LL | match mutex1.lock().unwrap().s.len() >= mutex2.lock().unwrap().s.len() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -282,7 +282,7 @@ LL ~ match mutex1.lock().unwrap().s.len() >= value { | error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> tests/ui/significant_drop_in_scrutinee.rs:398:11 + --> tests/ui/significant_drop_in_scrutinee.rs:403:11 | LL | match get_mutex_guard().s.len() > 1 { | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -301,7 +301,7 @@ LL ~ match value > 1 { | error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> tests/ui/significant_drop_in_scrutinee.rs:417:11 + --> tests/ui/significant_drop_in_scrutinee.rs:422:11 | LL | match match i { | ___________^ @@ -334,7 +334,7 @@ LL ~ match value | error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> tests/ui/significant_drop_in_scrutinee.rs:445:11 + --> tests/ui/significant_drop_in_scrutinee.rs:450:11 | LL | match if i > 1 { | ___________^ @@ -368,7 +368,7 @@ LL ~ match value | error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> tests/ui/significant_drop_in_scrutinee.rs:501:11 + --> tests/ui/significant_drop_in_scrutinee.rs:506:11 | LL | match s.lock().deref().deref() { | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -386,7 +386,7 @@ LL ~ match (&value) { | error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> tests/ui/significant_drop_in_scrutinee.rs:551:11 + --> tests/ui/significant_drop_in_scrutinee.rs:556:11 | LL | match mutex.lock().unwrap().i = i { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -405,7 +405,7 @@ LL ~ match () { | error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> tests/ui/significant_drop_in_scrutinee.rs:559:15 + --> tests/ui/significant_drop_in_scrutinee.rs:564:15 | LL | match i = mutex.lock().unwrap().i { | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -424,7 +424,7 @@ LL ~ match i = value { | error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> tests/ui/significant_drop_in_scrutinee.rs:567:11 + --> tests/ui/significant_drop_in_scrutinee.rs:572:11 | LL | match mutex.lock().unwrap().i += 1 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -443,7 +443,7 @@ LL ~ match () { | error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> tests/ui/significant_drop_in_scrutinee.rs:575:16 + --> tests/ui/significant_drop_in_scrutinee.rs:580:16 | LL | match i += mutex.lock().unwrap().i { | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -462,7 +462,7 @@ LL ~ match i += value { | error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> tests/ui/significant_drop_in_scrutinee.rs:640:11 + --> tests/ui/significant_drop_in_scrutinee.rs:645:11 | LL | match rwlock.read().unwrap().to_number() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -478,7 +478,7 @@ LL ~ match value { | error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> tests/ui/significant_drop_in_scrutinee.rs:668:11 + --> tests/ui/significant_drop_in_scrutinee.rs:673:11 | LL | match mutex.lock().unwrap().foo() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -494,7 +494,7 @@ LL ~ match value { | error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> tests/ui/significant_drop_in_scrutinee.rs:731:11 + --> tests/ui/significant_drop_in_scrutinee.rs:736:11 | LL | match guard.take().len() { | ^^^^^^^^^^^^^^^^^^ @@ -510,7 +510,7 @@ LL ~ match value { | error: temporary with significant `Drop` in `for` loop condition will live until the end of the `for` expression - --> tests/ui/significant_drop_in_scrutinee.rs:757:16 + --> tests/ui/significant_drop_in_scrutinee.rs:762:16 | LL | for val in mutex.lock().unwrap().copy_old_lifetime() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -526,7 +526,7 @@ LL ~ for val in value { | error: temporary with significant `Drop` in `for` loop condition will live until the end of the `for` expression - --> tests/ui/significant_drop_in_scrutinee.rs:797:17 + --> tests/ui/significant_drop_in_scrutinee.rs:802:17 | LL | for val in [mutex.lock().unwrap()[0], 2] { | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -542,7 +542,7 @@ LL ~ for val in [value, 2] { | error: temporary with significant `Drop` in `if let` scrutinee will live until the end of the `if let` expression - --> tests/ui/significant_drop_in_scrutinee.rs:807:24 + --> tests/ui/significant_drop_in_scrutinee.rs:812:24 | LL | if let Some(val) = mutex.lock().unwrap().first().copied() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -558,7 +558,7 @@ LL ~ if let Some(val) = value { | error: temporary with significant `Drop` in `while let` scrutinee will live until the end of the `while let` expression - --> tests/ui/significant_drop_in_scrutinee.rs:823:27 + --> tests/ui/significant_drop_in_scrutinee.rs:828:27 | LL | while let Some(val) = mutex.lock().unwrap().pop() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/str_split.fixed b/tests/ui/str_split.fixed index 4f33241da7a..57a3c315a87 100644 --- a/tests/ui/str_split.fixed +++ b/tests/ui/str_split.fixed @@ -1,4 +1,5 @@ #![warn(clippy::str_split_at_newline)] +#![allow(clippy::needless_lifetimes)] use core::str::Split; use std::ops::Deref; diff --git a/tests/ui/str_split.rs b/tests/ui/str_split.rs index f24caa61c30..fcff036f264 100644 --- a/tests/ui/str_split.rs +++ b/tests/ui/str_split.rs @@ -1,4 +1,5 @@ #![warn(clippy::str_split_at_newline)] +#![allow(clippy::needless_lifetimes)] use core::str::Split; use std::ops::Deref; diff --git a/tests/ui/str_split.stderr b/tests/ui/str_split.stderr index ebe0d4ef4d3..7b560468f12 100644 --- a/tests/ui/str_split.stderr +++ b/tests/ui/str_split.stderr @@ -1,5 +1,5 @@ error: using `str.trim().split()` with hard-coded newlines - --> tests/ui/str_split.rs:59:13 + --> tests/ui/str_split.rs:60:13 | LL | let _ = s1.trim().split('\n'); | ^^^^^^^^^^^^^^^^^^^^^ help: use `str.lines()` instead: `s1.lines()` @@ -8,55 +8,55 @@ LL | let _ = s1.trim().split('\n'); = help: to override `-D warnings` add `#[allow(clippy::str_split_at_newline)]` error: using `str.trim().split()` with hard-coded newlines - --> tests/ui/str_split.rs:61:13 + --> tests/ui/str_split.rs:62:13 | LL | let _ = s1.trim().split("\n"); | ^^^^^^^^^^^^^^^^^^^^^ help: use `str.lines()` instead: `s1.lines()` error: using `str.trim().split()` with hard-coded newlines - --> tests/ui/str_split.rs:62:13 + --> tests/ui/str_split.rs:63:13 | LL | let _ = s1.trim().split("\r\n"); | ^^^^^^^^^^^^^^^^^^^^^^^ help: use `str.lines()` instead: `s1.lines()` error: using `str.trim().split()` with hard-coded newlines - --> tests/ui/str_split.rs:65:13 + --> tests/ui/str_split.rs:66:13 | LL | let _ = s2.trim().split('\n'); | ^^^^^^^^^^^^^^^^^^^^^ help: use `str.lines()` instead: `s2.lines()` error: using `str.trim().split()` with hard-coded newlines - --> tests/ui/str_split.rs:67:13 + --> tests/ui/str_split.rs:68:13 | LL | let _ = s2.trim().split("\n"); | ^^^^^^^^^^^^^^^^^^^^^ help: use `str.lines()` instead: `s2.lines()` error: using `str.trim().split()` with hard-coded newlines - --> tests/ui/str_split.rs:68:13 + --> tests/ui/str_split.rs:69:13 | LL | let _ = s2.trim().split("\r\n"); | ^^^^^^^^^^^^^^^^^^^^^^^ help: use `str.lines()` instead: `s2.lines()` error: using `str.trim().split()` with hard-coded newlines - --> tests/ui/str_split.rs:72:13 + --> tests/ui/str_split.rs:73:13 | LL | let _ = s3.trim().split('\n'); | ^^^^^^^^^^^^^^^^^^^^^ help: use `str.lines()` instead: `s3.lines()` error: using `str.trim().split()` with hard-coded newlines - --> tests/ui/str_split.rs:74:13 + --> tests/ui/str_split.rs:75:13 | LL | let _ = s3.trim().split("\n"); | ^^^^^^^^^^^^^^^^^^^^^ help: use `str.lines()` instead: `s3.lines()` error: using `str.trim().split()` with hard-coded newlines - --> tests/ui/str_split.rs:75:13 + --> tests/ui/str_split.rs:76:13 | LL | let _ = s3.trim().split("\r\n"); | ^^^^^^^^^^^^^^^^^^^^^^^ help: use `str.lines()` instead: `s3.lines()` error: using `str.trim().split()` with hard-coded newlines - --> tests/ui/str_split.rs:78:13 + --> tests/ui/str_split.rs:79:13 | LL | let _ = make_str!(s1).trim().split('\n'); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `str.lines()` instead: `make_str!(s1).lines()` diff --git a/tests/ui/temporary_assignment.rs b/tests/ui/temporary_assignment.rs index e2b982aeaf5..d269f91b9fa 100644 --- a/tests/ui/temporary_assignment.rs +++ b/tests/ui/temporary_assignment.rs @@ -1,4 +1,5 @@ #![warn(clippy::temporary_assignment)] +#![allow(clippy::needless_lifetimes)] use std::ops::{Deref, DerefMut}; diff --git a/tests/ui/temporary_assignment.stderr b/tests/ui/temporary_assignment.stderr index 1b6007f0b98..8c284594075 100644 --- a/tests/ui/temporary_assignment.stderr +++ b/tests/ui/temporary_assignment.stderr @@ -1,5 +1,5 @@ error: assignment to temporary - --> tests/ui/temporary_assignment.rs:47:5 + --> tests/ui/temporary_assignment.rs:48:5 | LL | Struct { field: 0 }.field = 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -8,7 +8,7 @@ LL | Struct { field: 0 }.field = 1; = help: to override `-D warnings` add `#[allow(clippy::temporary_assignment)]` error: assignment to temporary - --> tests/ui/temporary_assignment.rs:50:5 + --> tests/ui/temporary_assignment.rs:51:5 | LL | / MultiStruct { LL | | @@ -19,13 +19,13 @@ LL | | .field = 1; | |______________^ error: assignment to temporary - --> tests/ui/temporary_assignment.rs:56:5 + --> tests/ui/temporary_assignment.rs:57:5 | LL | ArrayStruct { array: [0] }.array[0] = 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: assignment to temporary - --> tests/ui/temporary_assignment.rs:58:5 + --> tests/ui/temporary_assignment.rs:59:5 | LL | (0, 0).0 = 1; | ^^^^^^^^^^^^ diff --git a/tests/ui/unconditional_recursion.rs b/tests/ui/unconditional_recursion.rs index a51fc567f50..b8476a7088a 100644 --- a/tests/ui/unconditional_recursion.rs +++ b/tests/ui/unconditional_recursion.rs @@ -4,7 +4,8 @@ #![allow( clippy::partialeq_ne_impl, clippy::default_constructed_unit_structs, - clippy::only_used_in_recursion + clippy::only_used_in_recursion, + clippy::needless_lifetimes )] enum Foo { diff --git a/tests/ui/unconditional_recursion.stderr b/tests/ui/unconditional_recursion.stderr index 03c27bd8ed8..6a0078ee090 100644 --- a/tests/ui/unconditional_recursion.stderr +++ b/tests/ui/unconditional_recursion.stderr @@ -1,5 +1,5 @@ error: function cannot return without recursing - --> tests/ui/unconditional_recursion.rs:46:5 + --> tests/ui/unconditional_recursion.rs:47:5 | LL | fn ne(&self, other: &Self) -> bool { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing @@ -12,7 +12,7 @@ LL | self.ne(other) = help: to override `-D warnings` add `#[allow(unconditional_recursion)]` error: function cannot return without recursing - --> tests/ui/unconditional_recursion.rs:50:5 + --> tests/ui/unconditional_recursion.rs:51:5 | LL | fn eq(&self, other: &Self) -> bool { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing @@ -23,7 +23,7 @@ LL | self.eq(other) = help: a `loop` may express intention better if this is on purpose error: function cannot return without recursing - --> tests/ui/unconditional_recursion.rs:215:5 + --> tests/ui/unconditional_recursion.rs:216:5 | LL | fn to_string(&self) -> String { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing @@ -34,7 +34,7 @@ LL | self.to_string() = help: a `loop` may express intention better if this is on purpose error: function cannot return without recursing - --> tests/ui/unconditional_recursion.rs:225:5 + --> tests/ui/unconditional_recursion.rs:226:5 | LL | fn to_string(&self) -> String { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing @@ -45,7 +45,7 @@ LL | x.to_string() = help: a `loop` may express intention better if this is on purpose error: function cannot return without recursing - --> tests/ui/unconditional_recursion.rs:236:5 + --> tests/ui/unconditional_recursion.rs:237:5 | LL | fn to_string(&self) -> String { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing @@ -56,7 +56,7 @@ LL | (self as &Self).to_string() = help: a `loop` may express intention better if this is on purpose error: function cannot return without recursing - --> tests/ui/unconditional_recursion.rs:16:5 + --> tests/ui/unconditional_recursion.rs:17:5 | LL | / fn ne(&self, other: &Self) -> bool { LL | | @@ -65,7 +65,7 @@ LL | | } | |_____^ | note: recursive call site - --> tests/ui/unconditional_recursion.rs:18:9 + --> tests/ui/unconditional_recursion.rs:19:9 | LL | self != other | ^^^^^^^^^^^^^ @@ -73,7 +73,7 @@ LL | self != other = help: to override `-D warnings` add `#[allow(clippy::unconditional_recursion)]` error: function cannot return without recursing - --> tests/ui/unconditional_recursion.rs:20:5 + --> tests/ui/unconditional_recursion.rs:21:5 | LL | / fn eq(&self, other: &Self) -> bool { LL | | @@ -82,13 +82,13 @@ LL | | } | |_____^ | note: recursive call site - --> tests/ui/unconditional_recursion.rs:22:9 + --> tests/ui/unconditional_recursion.rs:23:9 | LL | self == other | ^^^^^^^^^^^^^ error: function cannot return without recursing - --> tests/ui/unconditional_recursion.rs:32:5 + --> tests/ui/unconditional_recursion.rs:33:5 | LL | / fn ne(&self, other: &Self) -> bool { LL | | self != &Foo2::B // no error here @@ -96,13 +96,13 @@ LL | | } | |_____^ | note: recursive call site - --> tests/ui/unconditional_recursion.rs:33:9 + --> tests/ui/unconditional_recursion.rs:34:9 | LL | self != &Foo2::B // no error here | ^^^^^^^^^^^^^^^^ error: function cannot return without recursing - --> tests/ui/unconditional_recursion.rs:35:5 + --> tests/ui/unconditional_recursion.rs:36:5 | LL | / fn eq(&self, other: &Self) -> bool { LL | | self == &Foo2::B // no error here @@ -110,13 +110,13 @@ LL | | } | |_____^ | note: recursive call site - --> tests/ui/unconditional_recursion.rs:36:9 + --> tests/ui/unconditional_recursion.rs:37:9 | LL | self == &Foo2::B // no error here | ^^^^^^^^^^^^^^^^ error: function cannot return without recursing - --> tests/ui/unconditional_recursion.rs:46:5 + --> tests/ui/unconditional_recursion.rs:47:5 | LL | / fn ne(&self, other: &Self) -> bool { LL | | @@ -125,13 +125,13 @@ LL | | } | |_____^ | note: recursive call site - --> tests/ui/unconditional_recursion.rs:48:9 + --> tests/ui/unconditional_recursion.rs:49:9 | LL | self.ne(other) | ^^^^^^^^^^^^^^ error: function cannot return without recursing - --> tests/ui/unconditional_recursion.rs:50:5 + --> tests/ui/unconditional_recursion.rs:51:5 | LL | / fn eq(&self, other: &Self) -> bool { LL | | @@ -140,13 +140,13 @@ LL | | } | |_____^ | note: recursive call site - --> tests/ui/unconditional_recursion.rs:52:9 + --> tests/ui/unconditional_recursion.rs:53:9 | LL | self.eq(other) | ^^^^^^^^^^^^^^ error: function cannot return without recursing - --> tests/ui/unconditional_recursion.rs:94:5 + --> tests/ui/unconditional_recursion.rs:95:5 | LL | / fn ne(&self, other: &Self) -> bool { LL | | @@ -155,13 +155,13 @@ LL | | } | |_____^ | note: recursive call site - --> tests/ui/unconditional_recursion.rs:96:9 + --> tests/ui/unconditional_recursion.rs:97:9 | LL | other != self | ^^^^^^^^^^^^^ error: function cannot return without recursing - --> tests/ui/unconditional_recursion.rs:98:5 + --> tests/ui/unconditional_recursion.rs:99:5 | LL | / fn eq(&self, other: &Self) -> bool { LL | | @@ -170,13 +170,13 @@ LL | | } | |_____^ | note: recursive call site - --> tests/ui/unconditional_recursion.rs:100:9 + --> tests/ui/unconditional_recursion.rs:101:9 | LL | other == self | ^^^^^^^^^^^^^ error: function cannot return without recursing - --> tests/ui/unconditional_recursion.rs:108:5 + --> tests/ui/unconditional_recursion.rs:109:5 | LL | / fn ne(&self, other: &Self) -> bool { LL | | @@ -185,13 +185,13 @@ LL | | } | |_____^ | note: recursive call site - --> tests/ui/unconditional_recursion.rs:110:9 + --> tests/ui/unconditional_recursion.rs:111:9 | LL | other != other | ^^^^^^^^^^^^^^ error: equal expressions as operands to `!=` - --> tests/ui/unconditional_recursion.rs:110:9 + --> tests/ui/unconditional_recursion.rs:111:9 | LL | other != other | ^^^^^^^^^^^^^^ @@ -199,7 +199,7 @@ LL | other != other = note: `#[deny(clippy::eq_op)]` on by default error: function cannot return without recursing - --> tests/ui/unconditional_recursion.rs:112:5 + --> tests/ui/unconditional_recursion.rs:113:5 | LL | / fn eq(&self, other: &Self) -> bool { LL | | @@ -208,19 +208,19 @@ LL | | } | |_____^ | note: recursive call site - --> tests/ui/unconditional_recursion.rs:114:9 + --> tests/ui/unconditional_recursion.rs:115:9 | LL | other == other | ^^^^^^^^^^^^^^ error: equal expressions as operands to `==` - --> tests/ui/unconditional_recursion.rs:114:9 + --> tests/ui/unconditional_recursion.rs:115:9 | LL | other == other | ^^^^^^^^^^^^^^ error: function cannot return without recursing - --> tests/ui/unconditional_recursion.rs:121:5 + --> tests/ui/unconditional_recursion.rs:122:5 | LL | / fn ne(&self, _other: &Self) -> bool { LL | | @@ -229,19 +229,19 @@ LL | | } | |_____^ | note: recursive call site - --> tests/ui/unconditional_recursion.rs:123:9 + --> tests/ui/unconditional_recursion.rs:124:9 | LL | self != self | ^^^^^^^^^^^^ error: equal expressions as operands to `!=` - --> tests/ui/unconditional_recursion.rs:123:9 + --> tests/ui/unconditional_recursion.rs:124:9 | LL | self != self | ^^^^^^^^^^^^ error: function cannot return without recursing - --> tests/ui/unconditional_recursion.rs:125:5 + --> tests/ui/unconditional_recursion.rs:126:5 | LL | / fn eq(&self, _other: &Self) -> bool { LL | | @@ -250,19 +250,19 @@ LL | | } | |_____^ | note: recursive call site - --> tests/ui/unconditional_recursion.rs:127:9 + --> tests/ui/unconditional_recursion.rs:128:9 | LL | self == self | ^^^^^^^^^^^^ error: equal expressions as operands to `==` - --> tests/ui/unconditional_recursion.rs:127:9 + --> tests/ui/unconditional_recursion.rs:128:9 | LL | self == self | ^^^^^^^^^^^^ error: function cannot return without recursing - --> tests/ui/unconditional_recursion.rs:153:13 + --> tests/ui/unconditional_recursion.rs:154:13 | LL | / fn eq(&self, other: &Self) -> bool { LL | | @@ -274,7 +274,7 @@ LL | impl_partial_eq!(S5); | -------------------- in this macro invocation | note: recursive call site - --> tests/ui/unconditional_recursion.rs:155:17 + --> tests/ui/unconditional_recursion.rs:156:17 | LL | self == other | ^^^^^^^^^^^^^ @@ -284,7 +284,7 @@ LL | impl_partial_eq!(S5); = note: this error originates in the macro `impl_partial_eq` (in Nightly builds, run with -Z macro-backtrace for more info) error: function cannot return without recursing - --> tests/ui/unconditional_recursion.rs:182:5 + --> tests/ui/unconditional_recursion.rs:183:5 | LL | / fn eq(&self, other: &Self) -> bool { LL | | @@ -295,13 +295,13 @@ LL | | } | |_____^ | note: recursive call site - --> tests/ui/unconditional_recursion.rs:186:9 + --> tests/ui/unconditional_recursion.rs:187:9 | LL | mine == theirs | ^^^^^^^^^^^^^^ error: function cannot return without recursing - --> tests/ui/unconditional_recursion.rs:251:5 + --> tests/ui/unconditional_recursion.rs:252:5 | LL | / fn new() -> Self { LL | | @@ -310,13 +310,13 @@ LL | | } | |_____^ | note: recursive call site - --> tests/ui/unconditional_recursion.rs:253:9 + --> tests/ui/unconditional_recursion.rs:254:9 | LL | Self::default() | ^^^^^^^^^^^^^^^ error: function cannot return without recursing - --> tests/ui/unconditional_recursion.rs:290:5 + --> tests/ui/unconditional_recursion.rs:291:5 | LL | / fn eq(&self, other: &Self) -> bool { LL | | @@ -327,13 +327,13 @@ LL | | } | |_____^ | note: recursive call site - --> tests/ui/unconditional_recursion.rs:294:9 + --> tests/ui/unconditional_recursion.rs:295:9 | LL | mine.eq(theirs) | ^^^^^^^^^^^^^^^ error: function cannot return without recursing - --> tests/ui/unconditional_recursion.rs:361:5 + --> tests/ui/unconditional_recursion.rs:362:5 | LL | / fn from(f: BadFromTy1<'a>) -> Self { LL | | f.into() @@ -341,13 +341,13 @@ LL | | } | |_____^ | note: recursive call site - --> tests/ui/unconditional_recursion.rs:362:9 + --> tests/ui/unconditional_recursion.rs:363:9 | LL | f.into() | ^^^^^^^^ error: function cannot return without recursing - --> tests/ui/unconditional_recursion.rs:370:5 + --> tests/ui/unconditional_recursion.rs:371:5 | LL | / fn from(f: BadFromTy2<'a>) -> Self { LL | | Into::into(f) @@ -355,7 +355,7 @@ LL | | } | |_____^ | note: recursive call site - --> tests/ui/unconditional_recursion.rs:371:9 + --> tests/ui/unconditional_recursion.rs:372:9 | LL | Into::into(f) | ^^^^^^^^^^^^^ diff --git a/tests/ui/useful_asref.rs b/tests/ui/useful_asref.rs index a9f0170a79c..d17db9371ee 100644 --- a/tests/ui/useful_asref.rs +++ b/tests/ui/useful_asref.rs @@ -1,4 +1,5 @@ #![deny(clippy::useless_asref)] +#![allow(clippy::needless_lifetimes)] trait Trait { fn as_ptr(&self); From 66f1f544afaf7e277fefa7702bcc91ca498879c5 Mon Sep 17 00:00:00 2001 From: Samuel Moelius Date: Sun, 18 Aug 2024 07:32:24 -0400 Subject: [PATCH 265/683] Fix `clippy_lints` and `clippy_utils` --- clippy_lints/src/booleans.rs | 8 ++++---- clippy_lints/src/box_default.rs | 2 +- clippy_lints/src/checked_conversions.rs | 2 +- clippy_lints/src/default_numeric_fallback.rs | 2 +- clippy_lints/src/doc/mod.rs | 2 +- clippy_lints/src/empty_enum.rs | 2 +- clippy_lints/src/escape.rs | 4 ++-- clippy_lints/src/excessive_nesting.rs | 2 +- clippy_lints/src/extra_unused_type_parameters.rs | 2 +- clippy_lints/src/fallible_impl_from.rs | 2 +- clippy_lints/src/format_args.rs | 2 +- clippy_lints/src/format_impl.rs | 2 +- clippy_lints/src/from_over_into.rs | 2 +- clippy_lints/src/implicit_hasher.rs | 4 ++-- clippy_lints/src/index_refutable_slice.rs | 2 +- clippy_lints/src/lifetimes.rs | 2 +- clippy_lints/src/loops/manual_memcpy.rs | 2 +- clippy_lints/src/loops/needless_range_loop.rs | 4 ++-- clippy_lints/src/loops/same_item_push.rs | 2 +- clippy_lints/src/loops/utils.rs | 4 ++-- clippy_lints/src/loops/while_immutable_condition.rs | 4 ++-- clippy_lints/src/loops/while_let_on_iterator.rs | 2 +- clippy_lints/src/macro_metavars_in_unsafe.rs | 2 +- clippy_lints/src/macro_use.rs | 2 +- clippy_lints/src/manual_clamp.rs | 2 +- clippy_lints/src/manual_strip.rs | 2 +- clippy_lints/src/map_unit_fn.rs | 2 +- clippy_lints/src/matches/match_str_case_mismatch.rs | 4 ++-- clippy_lints/src/matches/overlapping_arms.rs | 4 ++-- .../src/matches/significant_drop_in_scrutinee.rs | 4 ++-- clippy_lints/src/methods/needless_collect.rs | 2 +- clippy_lints/src/methods/option_map_unwrap_or.rs | 4 ++-- clippy_lints/src/methods/utils.rs | 4 ++-- clippy_lints/src/mixed_read_write_in_expression.rs | 6 +++--- clippy_lints/src/mut_mut.rs | 2 +- clippy_lints/src/mutable_debug_assertion.rs | 2 +- clippy_lints/src/needless_for_each.rs | 2 +- clippy_lints/src/needless_pass_by_ref_mut.rs | 2 +- clippy_lints/src/non_expressive_names.rs | 10 +++++----- clippy_lints/src/non_send_fields_in_send_ty.rs | 2 +- clippy_lints/src/pass_by_ref_or_value.rs | 4 ++-- clippy_lints/src/pathbuf_init_then_push.rs | 2 +- clippy_lints/src/redundant_closure_call.rs | 2 +- clippy_lints/src/returns.rs | 4 ++-- clippy_lints/src/significant_drop_tightening.rs | 2 +- clippy_lints/src/single_component_path_imports.rs | 2 +- clippy_lints/src/slow_vector_initialization.rs | 4 ++-- clippy_lints/src/swap.rs | 2 +- clippy_lints/src/unused_async.rs | 2 +- clippy_lints/src/unwrap.rs | 4 ++-- clippy_lints/src/use_self.rs | 2 +- .../src/utils/internal_lints/lint_without_lint_pass.rs | 2 +- clippy_lints/src/zombie_processes.rs | 4 ++-- clippy_utils/src/consts.rs | 6 +++--- clippy_utils/src/eager_or_lazy.rs | 2 +- clippy_utils/src/lib.rs | 4 ++-- clippy_utils/src/mir/mod.rs | 2 +- clippy_utils/src/mir/possible_borrower.rs | 6 +++--- clippy_utils/src/mir/possible_origin.rs | 2 +- clippy_utils/src/ty/type_certainty/mod.rs | 2 +- clippy_utils/src/usage.rs | 6 +++--- clippy_utils/src/visitors.rs | 4 ++-- 62 files changed, 94 insertions(+), 94 deletions(-) diff --git a/clippy_lints/src/booleans.rs b/clippy_lints/src/booleans.rs index 3c2af72624f..87aaf7ec16d 100644 --- a/clippy_lints/src/booleans.rs +++ b/clippy_lints/src/booleans.rs @@ -205,7 +205,7 @@ struct Hir2Qmm<'a, 'tcx, 'v> { cx: &'a LateContext<'tcx>, } -impl<'a, 'tcx, 'v> Hir2Qmm<'a, 'tcx, 'v> { +impl<'v> Hir2Qmm<'_, '_, 'v> { fn extract(&mut self, op: BinOpKind, a: &[&'v Expr<'_>], mut v: Vec) -> Result, String> { for a in a { if let ExprKind::Binary(binop, lhs, rhs) = &a.kind { @@ -292,7 +292,7 @@ struct SuggestContext<'a, 'tcx, 'v> { output: String, } -impl<'a, 'tcx, 'v> SuggestContext<'a, 'tcx, 'v> { +impl SuggestContext<'_, '_, '_> { fn recurse(&mut self, suggestion: &Bool) -> Option<()> { use quine_mc_cluskey::Bool::{And, False, Not, Or, Term, True}; match suggestion { @@ -475,7 +475,7 @@ fn terminal_stats(b: &Bool) -> Stats { stats } -impl<'a, 'tcx> NonminimalBoolVisitor<'a, 'tcx> { +impl<'tcx> NonminimalBoolVisitor<'_, 'tcx> { fn bool_expr(&self, e: &'tcx Expr<'_>) { let mut h2q = Hir2Qmm { terminals: Vec::new(), @@ -582,7 +582,7 @@ impl<'a, 'tcx> NonminimalBoolVisitor<'a, 'tcx> { } } -impl<'a, 'tcx> Visitor<'tcx> for NonminimalBoolVisitor<'a, 'tcx> { +impl<'tcx> Visitor<'tcx> for NonminimalBoolVisitor<'_, 'tcx> { fn visit_expr(&mut self, e: &'tcx Expr<'_>) { if !e.span.from_expansion() { match &e.kind { diff --git a/clippy_lints/src/box_default.rs b/clippy_lints/src/box_default.rs index 8261c65354f..40d154c0bdf 100644 --- a/clippy_lints/src/box_default.rs +++ b/clippy_lints/src/box_default.rs @@ -91,7 +91,7 @@ fn is_local_vec_expn(cx: &LateContext<'_>, expr: &Expr<'_>, ref_expr: &Expr<'_>) #[derive(Default)] struct InferVisitor(bool); -impl<'tcx> Visitor<'tcx> for InferVisitor { +impl Visitor<'_> for InferVisitor { fn visit_ty(&mut self, t: &Ty<'_>) { self.0 |= matches!(t.kind, TyKind::Infer | TyKind::OpaqueDef(..) | TyKind::TraitObject(..)); if !self.0 { diff --git a/clippy_lints/src/checked_conversions.rs b/clippy_lints/src/checked_conversions.rs index d3aa2fd1ea1..2e7f91a842e 100644 --- a/clippy_lints/src/checked_conversions.rs +++ b/clippy_lints/src/checked_conversions.rs @@ -48,7 +48,7 @@ impl CheckedConversions { impl_lint_pass!(CheckedConversions => [CHECKED_CONVERSIONS]); -impl<'tcx> LateLintPass<'tcx> for CheckedConversions { +impl LateLintPass<'_> for CheckedConversions { fn check_expr(&mut self, cx: &LateContext<'_>, item: &Expr<'_>) { if let ExprKind::Binary(op, lhs, rhs) = item.kind && let (lt1, gt1, op2) = match op.node { diff --git a/clippy_lints/src/default_numeric_fallback.rs b/clippy_lints/src/default_numeric_fallback.rs index a065dc2cf7e..4808c372754 100644 --- a/clippy_lints/src/default_numeric_fallback.rs +++ b/clippy_lints/src/default_numeric_fallback.rs @@ -119,7 +119,7 @@ impl<'a, 'tcx> NumericFallbackVisitor<'a, 'tcx> { } } -impl<'a, 'tcx> Visitor<'tcx> for NumericFallbackVisitor<'a, 'tcx> { +impl<'tcx> Visitor<'tcx> for NumericFallbackVisitor<'_, 'tcx> { fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { match &expr.kind { ExprKind::Block( diff --git a/clippy_lints/src/doc/mod.rs b/clippy_lints/src/doc/mod.rs index 0ae1fad5692..e090644ae44 100644 --- a/clippy_lints/src/doc/mod.rs +++ b/clippy_lints/src/doc/mod.rs @@ -970,7 +970,7 @@ impl<'a, 'tcx> FindPanicUnwrap<'a, 'tcx> { } } -impl<'a, 'tcx> Visitor<'tcx> for FindPanicUnwrap<'a, 'tcx> { +impl<'tcx> Visitor<'tcx> for FindPanicUnwrap<'_, 'tcx> { type NestedFilter = nested_filter::OnlyBodies; fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { diff --git a/clippy_lints/src/empty_enum.rs b/clippy_lints/src/empty_enum.rs index f4c55738cb8..70eb81fa09c 100644 --- a/clippy_lints/src/empty_enum.rs +++ b/clippy_lints/src/empty_enum.rs @@ -60,7 +60,7 @@ declare_clippy_lint! { declare_lint_pass!(EmptyEnum => [EMPTY_ENUM]); -impl<'tcx> LateLintPass<'tcx> for EmptyEnum { +impl LateLintPass<'_> for EmptyEnum { fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) { if let ItemKind::Enum(..) = item.kind // Only suggest the `never_type` if the feature is enabled diff --git a/clippy_lints/src/escape.rs b/clippy_lints/src/escape.rs index 5588124e791..a89f0d9c432 100644 --- a/clippy_lints/src/escape.rs +++ b/clippy_lints/src/escape.rs @@ -141,7 +141,7 @@ fn is_argument(tcx: TyCtxt<'_>, id: HirId) -> bool { matches!(tcx.parent_hir_node(id), Node::Param(_)) } -impl<'a, 'tcx> Delegate<'tcx> for EscapeDelegate<'a, 'tcx> { +impl<'tcx> Delegate<'tcx> for EscapeDelegate<'_, 'tcx> { fn consume(&mut self, cmt: &PlaceWithHirId<'tcx>, _: HirId) { if cmt.place.projections.is_empty() { if let PlaceBase::Local(lid) = cmt.place.base { @@ -188,7 +188,7 @@ impl<'a, 'tcx> Delegate<'tcx> for EscapeDelegate<'a, 'tcx> { fn fake_read(&mut self, _: &PlaceWithHirId<'tcx>, _: FakeReadCause, _: HirId) {} } -impl<'a, 'tcx> EscapeDelegate<'a, 'tcx> { +impl<'tcx> EscapeDelegate<'_, 'tcx> { fn is_large_box(&self, ty: Ty<'tcx>) -> bool { // Large types need to be boxed to avoid stack overflows. if let Some(boxed_ty) = ty.boxed_ty() { diff --git a/clippy_lints/src/excessive_nesting.rs b/clippy_lints/src/excessive_nesting.rs index ce0e0faa014..ffc76366983 100644 --- a/clippy_lints/src/excessive_nesting.rs +++ b/clippy_lints/src/excessive_nesting.rs @@ -135,7 +135,7 @@ impl NestingVisitor<'_, '_> { } } -impl<'conf, 'cx> Visitor<'_> for NestingVisitor<'conf, 'cx> { +impl Visitor<'_> for NestingVisitor<'_, '_> { fn visit_block(&mut self, block: &Block) { if block.span.from_expansion() { return; diff --git a/clippy_lints/src/extra_unused_type_parameters.rs b/clippy_lints/src/extra_unused_type_parameters.rs index bf9388b4a70..3b93d3ff93e 100644 --- a/clippy_lints/src/extra_unused_type_parameters.rs +++ b/clippy_lints/src/extra_unused_type_parameters.rs @@ -193,7 +193,7 @@ fn bound_to_trait_def_id(bound: &GenericBound<'_>) -> Option { bound.trait_ref()?.trait_def_id()?.as_local() } -impl<'cx, 'tcx> Visitor<'tcx> for TypeWalker<'cx, 'tcx> { +impl<'tcx> Visitor<'tcx> for TypeWalker<'_, 'tcx> { type NestedFilter = nested_filter::OnlyBodies; fn visit_ty(&mut self, t: &'tcx Ty<'tcx>) { diff --git a/clippy_lints/src/fallible_impl_from.rs b/clippy_lints/src/fallible_impl_from.rs index 747ea9a4344..f822432cce6 100644 --- a/clippy_lints/src/fallible_impl_from.rs +++ b/clippy_lints/src/fallible_impl_from.rs @@ -73,7 +73,7 @@ fn lint_impl_body(cx: &LateContext<'_>, impl_span: Span, impl_items: &[hir::Impl result: Vec, } - impl<'a, 'tcx> Visitor<'tcx> for FindPanicUnwrap<'a, 'tcx> { + impl<'tcx> Visitor<'tcx> for FindPanicUnwrap<'_, 'tcx> { fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { if let Some(macro_call) = root_macro_call_first_node(self.lcx, expr) { if is_panic(self.lcx, macro_call.def_id) { diff --git a/clippy_lints/src/format_args.rs b/clippy_lints/src/format_args.rs index 83ab9f6557b..4c043f8dc14 100644 --- a/clippy_lints/src/format_args.rs +++ b/clippy_lints/src/format_args.rs @@ -219,7 +219,7 @@ struct FormatArgsExpr<'a, 'tcx> { ignore_mixed: bool, } -impl<'a, 'tcx> FormatArgsExpr<'a, 'tcx> { +impl FormatArgsExpr<'_, '_> { fn check_templates(&self) { for piece in &self.format_args.template { if let FormatArgsPiece::Placeholder(placeholder) = piece diff --git a/clippy_lints/src/format_impl.rs b/clippy_lints/src/format_impl.rs index c196f404ce6..7c0515b8c56 100644 --- a/clippy_lints/src/format_impl.rs +++ b/clippy_lints/src/format_impl.rs @@ -148,7 +148,7 @@ struct FormatImplExpr<'a, 'tcx> { format_trait_impl: FormatTraitNames, } -impl<'a, 'tcx> FormatImplExpr<'a, 'tcx> { +impl FormatImplExpr<'_, '_> { fn check_to_string_in_display(&self) { if self.format_trait_impl.name == sym::Display && let ExprKind::MethodCall(path, self_arg, ..) = self.expr.kind diff --git a/clippy_lints/src/from_over_into.rs b/clippy_lints/src/from_over_into.rs index d716a624cc6..0aac81fa388 100644 --- a/clippy_lints/src/from_over_into.rs +++ b/clippy_lints/src/from_over_into.rs @@ -126,7 +126,7 @@ struct SelfFinder<'a, 'tcx> { invalid: bool, } -impl<'a, 'tcx> Visitor<'tcx> for SelfFinder<'a, 'tcx> { +impl<'tcx> Visitor<'tcx> for SelfFinder<'_, 'tcx> { type NestedFilter = OnlyBodies; fn nested_visit_map(&mut self) -> Self::Map { diff --git a/clippy_lints/src/implicit_hasher.rs b/clippy_lints/src/implicit_hasher.rs index f683925145a..4c5375730b8 100644 --- a/clippy_lints/src/implicit_hasher.rs +++ b/clippy_lints/src/implicit_hasher.rs @@ -281,7 +281,7 @@ impl<'a, 'tcx> ImplicitHasherTypeVisitor<'a, 'tcx> { } } -impl<'a, 'tcx> Visitor<'tcx> for ImplicitHasherTypeVisitor<'a, 'tcx> { +impl<'tcx> Visitor<'tcx> for ImplicitHasherTypeVisitor<'_, 'tcx> { fn visit_ty(&mut self, t: &'tcx hir::Ty<'_>) { if let Some(target) = ImplicitHasherType::new(self.cx, t) { self.found.push(target); @@ -318,7 +318,7 @@ impl<'a, 'b, 'tcx> ImplicitHasherConstructorVisitor<'a, 'b, 'tcx> { } } -impl<'a, 'b, 'tcx> Visitor<'tcx> for ImplicitHasherConstructorVisitor<'a, 'b, 'tcx> { +impl<'tcx> Visitor<'tcx> for ImplicitHasherConstructorVisitor<'_, '_, 'tcx> { type NestedFilter = nested_filter::OnlyBodies; fn visit_body(&mut self, body: &Body<'tcx>) { diff --git a/clippy_lints/src/index_refutable_slice.rs b/clippy_lints/src/index_refutable_slice.rs index 39afb6810b8..73ebe6aec15 100644 --- a/clippy_lints/src/index_refutable_slice.rs +++ b/clippy_lints/src/index_refutable_slice.rs @@ -226,7 +226,7 @@ struct SliceIndexLintingVisitor<'a, 'tcx> { max_suggested_slice: u64, } -impl<'a, 'tcx> Visitor<'tcx> for SliceIndexLintingVisitor<'a, 'tcx> { +impl<'tcx> Visitor<'tcx> for SliceIndexLintingVisitor<'_, 'tcx> { type NestedFilter = nested_filter::OnlyBodies; fn nested_visit_map(&mut self) -> Self::Map { diff --git a/clippy_lints/src/lifetimes.rs b/clippy_lints/src/lifetimes.rs index 42083b1a879..5a3c749cab1 100644 --- a/clippy_lints/src/lifetimes.rs +++ b/clippy_lints/src/lifetimes.rs @@ -397,7 +397,7 @@ impl<'a, 'tcx> RefVisitor<'a, 'tcx> { } } -impl<'a, 'tcx> Visitor<'tcx> for RefVisitor<'a, 'tcx> { +impl<'tcx> Visitor<'tcx> for RefVisitor<'_, 'tcx> { // for lifetimes as parameters of generics fn visit_lifetime(&mut self, lifetime: &'tcx Lifetime) { self.lts.push(*lifetime); diff --git a/clippy_lints/src/loops/manual_memcpy.rs b/clippy_lints/src/loops/manual_memcpy.rs index a7c1d1bd6cd..68d063ad5e5 100644 --- a/clippy_lints/src/loops/manual_memcpy.rs +++ b/clippy_lints/src/loops/manual_memcpy.rs @@ -209,7 +209,7 @@ fn build_manual_memcpy_suggestion<'tcx>( #[derive(Clone)] struct MinifyingSugg<'a>(Sugg<'a>); -impl<'a> Display for MinifyingSugg<'a> { +impl Display for MinifyingSugg<'_> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { self.0.fmt(f) } diff --git a/clippy_lints/src/loops/needless_range_loop.rs b/clippy_lints/src/loops/needless_range_loop.rs index 20dd5a311dc..745f070a577 100644 --- a/clippy_lints/src/loops/needless_range_loop.rs +++ b/clippy_lints/src/loops/needless_range_loop.rs @@ -241,7 +241,7 @@ struct VarVisitor<'a, 'tcx> { prefer_mutable: bool, } -impl<'a, 'tcx> VarVisitor<'a, 'tcx> { +impl<'tcx> VarVisitor<'_, 'tcx> { fn check(&mut self, idx: &'tcx Expr<'_>, seqexpr: &'tcx Expr<'_>, expr: &'tcx Expr<'_>) -> bool { if let ExprKind::Path(ref seqpath) = seqexpr.kind // the indexed container is referenced by a name @@ -292,7 +292,7 @@ impl<'a, 'tcx> VarVisitor<'a, 'tcx> { } } -impl<'a, 'tcx> Visitor<'tcx> for VarVisitor<'a, 'tcx> { +impl<'tcx> Visitor<'tcx> for VarVisitor<'_, 'tcx> { fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { if let ExprKind::MethodCall(meth, args_0, [args_1, ..], _) = &expr.kind // a range index op diff --git a/clippy_lints/src/loops/same_item_push.rs b/clippy_lints/src/loops/same_item_push.rs index 5662d3013e1..f8659897ffe 100644 --- a/clippy_lints/src/loops/same_item_push.rs +++ b/clippy_lints/src/loops/same_item_push.rs @@ -123,7 +123,7 @@ impl<'a, 'tcx> SameItemPushVisitor<'a, 'tcx> { } } -impl<'a, 'tcx> Visitor<'tcx> for SameItemPushVisitor<'a, 'tcx> { +impl<'tcx> Visitor<'tcx> for SameItemPushVisitor<'_, 'tcx> { fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { match &expr.kind { // Non-determinism may occur ... don't give a lint diff --git a/clippy_lints/src/loops/utils.rs b/clippy_lints/src/loops/utils.rs index 9a89a41d2b3..c4c504e1ae4 100644 --- a/clippy_lints/src/loops/utils.rs +++ b/clippy_lints/src/loops/utils.rs @@ -44,7 +44,7 @@ impl<'a, 'tcx> IncrementVisitor<'a, 'tcx> { } } -impl<'a, 'tcx> Visitor<'tcx> for IncrementVisitor<'a, 'tcx> { +impl<'tcx> Visitor<'tcx> for IncrementVisitor<'_, 'tcx> { fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { // If node is a variable if let Some(def_id) = path_to_local(expr) { @@ -138,7 +138,7 @@ impl<'a, 'tcx> InitializeVisitor<'a, 'tcx> { } } -impl<'a, 'tcx> Visitor<'tcx> for InitializeVisitor<'a, 'tcx> { +impl<'tcx> Visitor<'tcx> for InitializeVisitor<'_, 'tcx> { type NestedFilter = nested_filter::OnlyBodies; fn visit_local(&mut self, l: &'tcx LetStmt<'_>) { diff --git a/clippy_lints/src/loops/while_immutable_condition.rs b/clippy_lints/src/loops/while_immutable_condition.rs index eab096e9a22..1a1cde3c5bd 100644 --- a/clippy_lints/src/loops/while_immutable_condition.rs +++ b/clippy_lints/src/loops/while_immutable_condition.rs @@ -84,7 +84,7 @@ struct VarCollectorVisitor<'a, 'tcx> { skip: bool, } -impl<'a, 'tcx> VarCollectorVisitor<'a, 'tcx> { +impl<'tcx> VarCollectorVisitor<'_, 'tcx> { fn insert_def_id(&mut self, ex: &'tcx Expr<'_>) { if let ExprKind::Path(ref qpath) = ex.kind && let QPath::Resolved(None, _) = *qpath @@ -103,7 +103,7 @@ impl<'a, 'tcx> VarCollectorVisitor<'a, 'tcx> { } } -impl<'a, 'tcx> Visitor<'tcx> for VarCollectorVisitor<'a, 'tcx> { +impl<'tcx> Visitor<'tcx> for VarCollectorVisitor<'_, 'tcx> { fn visit_expr(&mut self, ex: &'tcx Expr<'_>) { match ex.kind { ExprKind::Path(_) => self.insert_def_id(ex), diff --git a/clippy_lints/src/loops/while_let_on_iterator.rs b/clippy_lints/src/loops/while_let_on_iterator.rs index 7d9fbaf3cea..74467522619 100644 --- a/clippy_lints/src/loops/while_let_on_iterator.rs +++ b/clippy_lints/src/loops/while_let_on_iterator.rs @@ -283,7 +283,7 @@ fn needs_mutable_borrow(cx: &LateContext<'_>, iter_expr: &IterExpr, loop_expr: & found_local: bool, used_after: bool, } - impl<'a, 'b, 'tcx> Visitor<'tcx> for NestedLoopVisitor<'a, 'b, 'tcx> { + impl<'tcx> Visitor<'tcx> for NestedLoopVisitor<'_, '_, 'tcx> { type NestedFilter = OnlyBodies; fn nested_visit_map(&mut self) -> Self::Map { self.cx.tcx.hir() diff --git a/clippy_lints/src/macro_metavars_in_unsafe.rs b/clippy_lints/src/macro_metavars_in_unsafe.rs index ccc554042d6..312bcb55a95 100644 --- a/clippy_lints/src/macro_metavars_in_unsafe.rs +++ b/clippy_lints/src/macro_metavars_in_unsafe.rs @@ -149,7 +149,7 @@ fn is_public_macro(cx: &LateContext<'_>, def_id: LocalDefId) -> bool { && !cx.tcx.is_doc_hidden(def_id) } -impl<'a, 'tcx> Visitor<'tcx> for BodyVisitor<'a, 'tcx> { +impl<'tcx> Visitor<'tcx> for BodyVisitor<'_, 'tcx> { fn visit_stmt(&mut self, s: &'tcx Stmt<'tcx>) { let from_expn = s.span.from_expansion(); if from_expn { diff --git a/clippy_lints/src/macro_use.rs b/clippy_lints/src/macro_use.rs index bd6b3f1a47b..50680331fbc 100644 --- a/clippy_lints/src/macro_use.rs +++ b/clippy_lints/src/macro_use.rs @@ -81,7 +81,7 @@ impl MacroUseImports { } } -impl<'tcx> LateLintPass<'tcx> for MacroUseImports { +impl LateLintPass<'_> for MacroUseImports { fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) { if cx.sess().opts.edition >= Edition::Edition2018 && let hir::ItemKind::Use(path, _kind) = &item.kind diff --git a/clippy_lints/src/manual_clamp.rs b/clippy_lints/src/manual_clamp.rs index 788649fd4f9..fd66cacdfe9 100644 --- a/clippy_lints/src/manual_clamp.rs +++ b/clippy_lints/src/manual_clamp.rs @@ -741,7 +741,7 @@ enum MaybeBorrowedStmtKind<'a> { Owned(StmtKind<'a>), } -impl<'a> Clone for MaybeBorrowedStmtKind<'a> { +impl Clone for MaybeBorrowedStmtKind<'_> { fn clone(&self) -> Self { match self { Self::Borrowed(t) => Self::Borrowed(t), diff --git a/clippy_lints/src/manual_strip.rs b/clippy_lints/src/manual_strip.rs index 9aceca66bf7..828c5a3f6ff 100644 --- a/clippy_lints/src/manual_strip.rs +++ b/clippy_lints/src/manual_strip.rs @@ -203,7 +203,7 @@ fn find_stripping<'tcx>( results: Vec, } - impl<'a, 'tcx> Visitor<'tcx> for StrippingFinder<'a, 'tcx> { + impl<'tcx> Visitor<'tcx> for StrippingFinder<'_, 'tcx> { fn visit_expr(&mut self, ex: &'tcx Expr<'_>) { if is_ref_str(self.cx, ex) && let unref = peel_ref(ex) diff --git a/clippy_lints/src/map_unit_fn.rs b/clippy_lints/src/map_unit_fn.rs index a97dbbbc33f..3221a04d2d0 100644 --- a/clippy_lints/src/map_unit_fn.rs +++ b/clippy_lints/src/map_unit_fn.rs @@ -251,7 +251,7 @@ fn lint_map_unit_fn( } } -impl<'tcx> LateLintPass<'tcx> for MapUnit { +impl LateLintPass<'_> for MapUnit { fn check_stmt(&mut self, cx: &LateContext<'_>, stmt: &hir::Stmt<'_>) { if let hir::StmtKind::Semi(expr) = stmt.kind && !stmt.span.from_expansion() diff --git a/clippy_lints/src/matches/match_str_case_mismatch.rs b/clippy_lints/src/matches/match_str_case_mismatch.rs index 40518ce2ca7..463aa602bc8 100644 --- a/clippy_lints/src/matches/match_str_case_mismatch.rs +++ b/clippy_lints/src/matches/match_str_case_mismatch.rs @@ -40,7 +40,7 @@ struct MatchExprVisitor<'a, 'tcx> { case_method: Option, } -impl<'a, 'tcx> Visitor<'tcx> for MatchExprVisitor<'a, 'tcx> { +impl<'tcx> Visitor<'tcx> for MatchExprVisitor<'_, 'tcx> { fn visit_expr(&mut self, ex: &'tcx Expr<'_>) { match ex.kind { ExprKind::MethodCall(segment, receiver, [], _) if self.case_altered(segment.ident.as_str(), receiver) => {}, @@ -49,7 +49,7 @@ impl<'a, 'tcx> Visitor<'tcx> for MatchExprVisitor<'a, 'tcx> { } } -impl<'a, 'tcx> MatchExprVisitor<'a, 'tcx> { +impl MatchExprVisitor<'_, '_> { fn case_altered(&mut self, segment_ident: &str, receiver: &Expr<'_>) -> bool { if let Some(case_method) = get_case_method(segment_ident) { let ty = self.cx.typeck_results().expr_ty(receiver).peel_refs(); diff --git a/clippy_lints/src/matches/overlapping_arms.rs b/clippy_lints/src/matches/overlapping_arms.rs index 6a4c553cee0..856311899f2 100644 --- a/clippy_lints/src/matches/overlapping_arms.rs +++ b/clippy_lints/src/matches/overlapping_arms.rs @@ -96,13 +96,13 @@ where #[derive(Copy, Clone, Debug, Eq, PartialEq)] struct RangeBound<'a, T>(T, BoundKind, &'a SpannedRange); - impl<'a, T: Copy + Ord> PartialOrd for RangeBound<'a, T> { + impl PartialOrd for RangeBound<'_, T> { fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } } - impl<'a, T: Copy + Ord> Ord for RangeBound<'a, T> { + impl Ord for RangeBound<'_, T> { fn cmp(&self, RangeBound(other_value, other_kind, _): &Self) -> Ordering { let RangeBound(self_value, self_kind, _) = *self; (self_value, self_kind).cmp(&(*other_value, *other_kind)) diff --git a/clippy_lints/src/matches/significant_drop_in_scrutinee.rs b/clippy_lints/src/matches/significant_drop_in_scrutinee.rs index 537f7272f7f..7372f52e1e5 100644 --- a/clippy_lints/src/matches/significant_drop_in_scrutinee.rs +++ b/clippy_lints/src/matches/significant_drop_in_scrutinee.rs @@ -424,7 +424,7 @@ fn ty_has_erased_regions(ty: Ty<'_>) -> bool { ty.visit_with(&mut V).is_break() } -impl<'a, 'tcx> Visitor<'tcx> for SigDropHelper<'a, 'tcx> { +impl<'tcx> Visitor<'tcx> for SigDropHelper<'_, 'tcx> { fn visit_expr(&mut self, ex: &'tcx Expr<'_>) { // We've emitted a lint on some neighborhood expression. That lint will suggest to move out the // _parent_ expression (not the expression itself). Since we decide to move out the parent @@ -495,7 +495,7 @@ fn has_significant_drop_in_arms<'tcx>(cx: &LateContext<'tcx>, arms: &[&'tcx Expr helper.found_sig_drop_spans } -impl<'a, 'tcx> Visitor<'tcx> for ArmSigDropHelper<'a, 'tcx> { +impl<'tcx> Visitor<'tcx> for ArmSigDropHelper<'_, 'tcx> { fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) { if self.sig_drop_checker.is_sig_drop_expr(ex) { self.found_sig_drop_spans.insert(ex.span); diff --git a/clippy_lints/src/methods/needless_collect.rs b/clippy_lints/src/methods/needless_collect.rs index 421c7a5e070..c58e27e37ad 100644 --- a/clippy_lints/src/methods/needless_collect.rs +++ b/clippy_lints/src/methods/needless_collect.rs @@ -441,7 +441,7 @@ struct UsedCountVisitor<'a, 'tcx> { count: usize, } -impl<'a, 'tcx> Visitor<'tcx> for UsedCountVisitor<'a, 'tcx> { +impl<'tcx> Visitor<'tcx> for UsedCountVisitor<'_, 'tcx> { type NestedFilter = nested_filter::OnlyBodies; fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { diff --git a/clippy_lints/src/methods/option_map_unwrap_or.rs b/clippy_lints/src/methods/option_map_unwrap_or.rs index b160ab6de8e..528e2204cf8 100644 --- a/clippy_lints/src/methods/option_map_unwrap_or.rs +++ b/clippy_lints/src/methods/option_map_unwrap_or.rs @@ -130,7 +130,7 @@ struct UnwrapVisitor<'a, 'tcx> { identifiers: FxHashSet, } -impl<'a, 'tcx> Visitor<'tcx> for UnwrapVisitor<'a, 'tcx> { +impl<'tcx> Visitor<'tcx> for UnwrapVisitor<'_, 'tcx> { type NestedFilter = nested_filter::All; fn visit_path(&mut self, path: &Path<'tcx>, _: HirId) { @@ -154,7 +154,7 @@ struct ReferenceVisitor<'a, 'tcx> { unwrap_or_span: Span, } -impl<'a, 'tcx> Visitor<'tcx> for ReferenceVisitor<'a, 'tcx> { +impl<'tcx> Visitor<'tcx> for ReferenceVisitor<'_, 'tcx> { type NestedFilter = nested_filter::All; type Result = ControlFlow<()>; fn visit_expr(&mut self, expr: &'tcx rustc_hir::Expr<'_>) -> ControlFlow<()> { diff --git a/clippy_lints/src/methods/utils.rs b/clippy_lints/src/methods/utils.rs index 4e33dc1df54..cf0ee569f13 100644 --- a/clippy_lints/src/methods/utils.rs +++ b/clippy_lints/src/methods/utils.rs @@ -86,7 +86,7 @@ struct CloneOrCopyVisitor<'cx, 'tcx> { references_to_binding: Vec<(Span, String)>, } -impl<'cx, 'tcx> Visitor<'tcx> for CloneOrCopyVisitor<'cx, 'tcx> { +impl<'tcx> Visitor<'tcx> for CloneOrCopyVisitor<'_, 'tcx> { type NestedFilter = nested_filter::OnlyBodies; fn nested_visit_map(&mut self) -> Self::Map { @@ -123,7 +123,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for CloneOrCopyVisitor<'cx, 'tcx> { } } -impl<'cx, 'tcx> CloneOrCopyVisitor<'cx, 'tcx> { +impl<'tcx> CloneOrCopyVisitor<'_, 'tcx> { fn is_binding(&self, expr: &Expr<'tcx>) -> bool { self.binding_hir_ids .iter() diff --git a/clippy_lints/src/mixed_read_write_in_expression.rs b/clippy_lints/src/mixed_read_write_in_expression.rs index d333b71edb1..a7452c8a3c8 100644 --- a/clippy_lints/src/mixed_read_write_in_expression.rs +++ b/clippy_lints/src/mixed_read_write_in_expression.rs @@ -116,7 +116,7 @@ struct DivergenceVisitor<'a, 'tcx> { cx: &'a LateContext<'tcx>, } -impl<'a, 'tcx> DivergenceVisitor<'a, 'tcx> { +impl<'tcx> DivergenceVisitor<'_, 'tcx> { fn maybe_walk_expr(&mut self, e: &'tcx Expr<'_>) { match e.kind { ExprKind::Closure(..) | ExprKind::If(..) | ExprKind::Loop(..) => {}, @@ -148,7 +148,7 @@ fn stmt_might_diverge(stmt: &Stmt<'_>) -> bool { !matches!(stmt.kind, StmtKind::Item(..)) } -impl<'a, 'tcx> Visitor<'tcx> for DivergenceVisitor<'a, 'tcx> { +impl<'tcx> Visitor<'tcx> for DivergenceVisitor<'_, 'tcx> { fn visit_expr(&mut self, e: &'tcx Expr<'_>) { match e.kind { // fix #10776 @@ -321,7 +321,7 @@ struct ReadVisitor<'a, 'tcx> { last_expr: &'tcx Expr<'tcx>, } -impl<'a, 'tcx> Visitor<'tcx> for ReadVisitor<'a, 'tcx> { +impl<'tcx> Visitor<'tcx> for ReadVisitor<'_, 'tcx> { fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { if expr.hir_id == self.last_expr.hir_id { return; diff --git a/clippy_lints/src/mut_mut.rs b/clippy_lints/src/mut_mut.rs index 60372121a7a..6cddd7ea813 100644 --- a/clippy_lints/src/mut_mut.rs +++ b/clippy_lints/src/mut_mut.rs @@ -55,7 +55,7 @@ pub struct MutVisitor<'a, 'tcx> { cx: &'a LateContext<'tcx>, } -impl<'a, 'tcx> intravisit::Visitor<'tcx> for MutVisitor<'a, 'tcx> { +impl<'tcx> intravisit::Visitor<'tcx> for MutVisitor<'_, 'tcx> { fn visit_expr(&mut self, expr: &'tcx hir::Expr<'_>) { if in_external_macro(self.cx.sess(), expr.span) { return; diff --git a/clippy_lints/src/mutable_debug_assertion.rs b/clippy_lints/src/mutable_debug_assertion.rs index 6ab811b4f2f..e589b3608b3 100644 --- a/clippy_lints/src/mutable_debug_assertion.rs +++ b/clippy_lints/src/mutable_debug_assertion.rs @@ -87,7 +87,7 @@ impl<'a, 'tcx> MutArgVisitor<'a, 'tcx> { } } -impl<'a, 'tcx> Visitor<'tcx> for MutArgVisitor<'a, 'tcx> { +impl<'tcx> Visitor<'tcx> for MutArgVisitor<'_, 'tcx> { type NestedFilter = nested_filter::OnlyBodies; fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { diff --git a/clippy_lints/src/needless_for_each.rs b/clippy_lints/src/needless_for_each.rs index b54eb164e81..93e20f37ef8 100644 --- a/clippy_lints/src/needless_for_each.rs +++ b/clippy_lints/src/needless_for_each.rs @@ -133,7 +133,7 @@ struct RetCollector { loop_depth: u16, } -impl<'tcx> Visitor<'tcx> for RetCollector { +impl Visitor<'_> for RetCollector { fn visit_expr(&mut self, expr: &Expr<'_>) { match expr.kind { ExprKind::Ret(..) => { diff --git a/clippy_lints/src/needless_pass_by_ref_mut.rs b/clippy_lints/src/needless_pass_by_ref_mut.rs index 19cbf595908..c2facb2fcf6 100644 --- a/clippy_lints/src/needless_pass_by_ref_mut.rs +++ b/clippy_lints/src/needless_pass_by_ref_mut.rs @@ -311,7 +311,7 @@ struct MutablyUsedVariablesCtxt<'tcx> { tcx: TyCtxt<'tcx>, } -impl<'tcx> MutablyUsedVariablesCtxt<'tcx> { +impl MutablyUsedVariablesCtxt<'_> { fn add_mutably_used_var(&mut self, used_id: HirId) { self.mutably_used_vars.insert(used_id); } diff --git a/clippy_lints/src/non_expressive_names.rs b/clippy_lints/src/non_expressive_names.rs index d85032e9eee..2fee1c72a91 100644 --- a/clippy_lints/src/non_expressive_names.rs +++ b/clippy_lints/src/non_expressive_names.rs @@ -104,7 +104,7 @@ struct SimilarNamesLocalVisitor<'a, 'tcx> { single_char_names: Vec>, } -impl<'a, 'tcx> SimilarNamesLocalVisitor<'a, 'tcx> { +impl SimilarNamesLocalVisitor<'_, '_> { fn check_single_char_names(&self) { if self.single_char_names.last().map(Vec::len) == Some(0) { return; @@ -152,7 +152,7 @@ fn chars_are_similar(a: char, b: char) -> bool { struct SimilarNamesNameVisitor<'a, 'tcx, 'b>(&'b mut SimilarNamesLocalVisitor<'a, 'tcx>); -impl<'a, 'tcx, 'b> Visitor<'tcx> for SimilarNamesNameVisitor<'a, 'tcx, 'b> { +impl<'tcx> Visitor<'tcx> for SimilarNamesNameVisitor<'_, 'tcx, '_> { fn visit_pat(&mut self, pat: &'tcx Pat) { match pat.kind { PatKind::Ident(_, ident, _) => { @@ -189,7 +189,7 @@ fn allowed_to_be_similar(interned_name: &str, list: &[&str]) -> bool { .any(|&name| interned_name.starts_with(name) || interned_name.ends_with(name)) } -impl<'a, 'tcx, 'b> SimilarNamesNameVisitor<'a, 'tcx, 'b> { +impl SimilarNamesNameVisitor<'_, '_, '_> { fn check_short_ident(&mut self, ident: Ident) { // Ignore shadowing if self @@ -329,7 +329,7 @@ impl<'a, 'tcx, 'b> SimilarNamesNameVisitor<'a, 'tcx, 'b> { } } -impl<'a, 'b> SimilarNamesLocalVisitor<'a, 'b> { +impl SimilarNamesLocalVisitor<'_, '_> { /// ensure scoping rules work fn apply Fn(&'c mut Self)>(&mut self, f: F) { let n = self.names.len(); @@ -340,7 +340,7 @@ impl<'a, 'b> SimilarNamesLocalVisitor<'a, 'b> { } } -impl<'a, 'tcx> Visitor<'tcx> for SimilarNamesLocalVisitor<'a, 'tcx> { +impl<'tcx> Visitor<'tcx> for SimilarNamesLocalVisitor<'_, 'tcx> { fn visit_local(&mut self, local: &'tcx Local) { if let Some((init, els)) = &local.kind.init_else_opt() { self.apply(|this| walk_expr(this, init)); diff --git a/clippy_lints/src/non_send_fields_in_send_ty.rs b/clippy_lints/src/non_send_fields_in_send_ty.rs index a60988ac5db..793eb5d9456 100644 --- a/clippy_lints/src/non_send_fields_in_send_ty.rs +++ b/clippy_lints/src/non_send_fields_in_send_ty.rs @@ -159,7 +159,7 @@ struct NonSendField<'tcx> { generic_params: Vec>, } -impl<'tcx> NonSendField<'tcx> { +impl NonSendField<'_> { fn generic_params_string(&self) -> String { self.generic_params .iter() diff --git a/clippy_lints/src/pass_by_ref_or_value.rs b/clippy_lints/src/pass_by_ref_or_value.rs index 75d8c09f2b0..1bddfab39c6 100644 --- a/clippy_lints/src/pass_by_ref_or_value.rs +++ b/clippy_lints/src/pass_by_ref_or_value.rs @@ -110,7 +110,7 @@ pub struct PassByRefOrValue { avoid_breaking_exported_api: bool, } -impl<'tcx> PassByRefOrValue { +impl PassByRefOrValue { pub fn new(tcx: TyCtxt<'_>, conf: &'static Conf) -> Self { let ref_min_size = conf.trivial_copy_size_limit.unwrap_or_else(|| { let bit_width = u64::from(tcx.sess.target.pointer_width); @@ -130,7 +130,7 @@ impl<'tcx> PassByRefOrValue { } } - fn check_poly_fn(&mut self, cx: &LateContext<'tcx>, def_id: LocalDefId, decl: &FnDecl<'_>, span: Option) { + fn check_poly_fn(&mut self, cx: &LateContext<'_>, def_id: LocalDefId, decl: &FnDecl<'_>, span: Option) { if self.avoid_breaking_exported_api && cx.effective_visibilities.is_exported(def_id) { return; } diff --git a/clippy_lints/src/pathbuf_init_then_push.rs b/clippy_lints/src/pathbuf_init_then_push.rs index 1b9a5a44382..9f84686a0b1 100644 --- a/clippy_lints/src/pathbuf_init_then_push.rs +++ b/clippy_lints/src/pathbuf_init_then_push.rs @@ -60,7 +60,7 @@ struct PathbufPushSearcher<'tcx> { err_span: Span, } -impl<'tcx> PathbufPushSearcher<'tcx> { +impl PathbufPushSearcher<'_> { /// Try to generate a suggestion with `PathBuf::from`. /// Returns `None` if the suggestion would be invalid. fn gen_pathbuf_from(&self, cx: &LateContext<'_>) -> Option { diff --git a/clippy_lints/src/redundant_closure_call.rs b/clippy_lints/src/redundant_closure_call.rs index 6930a01d48b..41a44de536b 100644 --- a/clippy_lints/src/redundant_closure_call.rs +++ b/clippy_lints/src/redundant_closure_call.rs @@ -228,7 +228,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClosureCall { path: &'tcx hir::Path<'tcx>, count: usize, } - impl<'a, 'tcx> Visitor<'tcx> for ClosureUsageCount<'a, 'tcx> { + impl<'tcx> Visitor<'tcx> for ClosureUsageCount<'_, 'tcx> { type NestedFilter = nested_filter::OnlyBodies; fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) { diff --git a/clippy_lints/src/returns.rs b/clippy_lints/src/returns.rs index 34bd9a1210c..1f223048ce5 100644 --- a/clippy_lints/src/returns.rs +++ b/clippy_lints/src/returns.rs @@ -140,7 +140,7 @@ enum RetReplacement<'tcx> { Expr(Cow<'tcx, str>, Applicability), } -impl<'tcx> RetReplacement<'tcx> { +impl RetReplacement<'_> { fn sugg_help(&self) -> &'static str { match self { Self::Empty | Self::Expr(..) => "remove `return`", @@ -158,7 +158,7 @@ impl<'tcx> RetReplacement<'tcx> { } } -impl<'tcx> Display for RetReplacement<'tcx> { +impl Display for RetReplacement<'_> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { Self::Empty => write!(f, ""), diff --git a/clippy_lints/src/significant_drop_tightening.rs b/clippy_lints/src/significant_drop_tightening.rs index d1114cb29f7..0eece922143 100644 --- a/clippy_lints/src/significant_drop_tightening.rs +++ b/clippy_lints/src/significant_drop_tightening.rs @@ -249,7 +249,7 @@ impl<'ap, 'lc, 'others, 'stmt, 'tcx> StmtsChecker<'ap, 'lc, 'others, 'stmt, 'tcx } } -impl<'ap, 'lc, 'others, 'stmt, 'tcx> Visitor<'tcx> for StmtsChecker<'ap, 'lc, 'others, 'stmt, 'tcx> { +impl<'tcx> Visitor<'tcx> for StmtsChecker<'_, '_, '_, '_, 'tcx> { fn visit_block(&mut self, block: &'tcx hir::Block<'tcx>) { self.ap.curr_block_hir_id = block.hir_id; self.ap.curr_block_span = block.span; diff --git a/clippy_lints/src/single_component_path_imports.rs b/clippy_lints/src/single_component_path_imports.rs index c986c3e8aa6..9fdee8543a8 100644 --- a/clippy_lints/src/single_component_path_imports.rs +++ b/clippy_lints/src/single_component_path_imports.rs @@ -102,7 +102,7 @@ struct ImportUsageVisitor { imports_referenced_with_self: Vec, } -impl<'tcx> Visitor<'tcx> for ImportUsageVisitor { +impl Visitor<'_> for ImportUsageVisitor { fn visit_expr(&mut self, expr: &Expr) { if let ExprKind::Path(_, path) = &expr.kind && path.segments.len() > 1 diff --git a/clippy_lints/src/slow_vector_initialization.rs b/clippy_lints/src/slow_vector_initialization.rs index 5129bbf2665..fc799cad67e 100644 --- a/clippy_lints/src/slow_vector_initialization.rs +++ b/clippy_lints/src/slow_vector_initialization.rs @@ -229,7 +229,7 @@ struct VectorInitializationVisitor<'a, 'tcx> { initialization_found: bool, } -impl<'a, 'tcx> VectorInitializationVisitor<'a, 'tcx> { +impl<'tcx> VectorInitializationVisitor<'_, 'tcx> { /// Checks if the given expression is extending a vector with `repeat(0).take(..)` fn search_slow_extend_filling(&mut self, expr: &'tcx Expr<'_>) { if self.initialization_found @@ -299,7 +299,7 @@ impl<'a, 'tcx> VectorInitializationVisitor<'a, 'tcx> { } } -impl<'a, 'tcx> Visitor<'tcx> for VectorInitializationVisitor<'a, 'tcx> { +impl<'tcx> Visitor<'tcx> for VectorInitializationVisitor<'_, 'tcx> { fn visit_stmt(&mut self, stmt: &'tcx Stmt<'_>) { if self.initialization_found { match stmt.kind { diff --git a/clippy_lints/src/swap.rs b/clippy_lints/src/swap.rs index e05fa4095b8..a3145c4647c 100644 --- a/clippy_lints/src/swap.rs +++ b/clippy_lints/src/swap.rs @@ -332,7 +332,7 @@ struct IndexBinding<'a, 'tcx> { applicability: &'a mut Applicability, } -impl<'a, 'tcx> IndexBinding<'a, 'tcx> { +impl<'tcx> IndexBinding<'_, 'tcx> { fn snippet_index_bindings(&mut self, exprs: &[&'tcx Expr<'tcx>]) -> String { let mut bindings = FxHashSet::default(); for expr in exprs { diff --git a/clippy_lints/src/unused_async.rs b/clippy_lints/src/unused_async.rs index a1f08cf6623..d6f79ae4836 100644 --- a/clippy_lints/src/unused_async.rs +++ b/clippy_lints/src/unused_async.rs @@ -67,7 +67,7 @@ struct AsyncFnVisitor<'a, 'tcx> { async_depth: usize, } -impl<'a, 'tcx> Visitor<'tcx> for AsyncFnVisitor<'a, 'tcx> { +impl<'tcx> Visitor<'tcx> for AsyncFnVisitor<'_, 'tcx> { type NestedFilter = nested_filter::OnlyBodies; fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) { diff --git a/clippy_lints/src/unwrap.rs b/clippy_lints/src/unwrap.rs index 596f0fd9c8b..6fe660b6a47 100644 --- a/clippy_lints/src/unwrap.rs +++ b/clippy_lints/src/unwrap.rs @@ -235,7 +235,7 @@ impl<'tcx> Delegate<'tcx> for MutationVisitor<'tcx> { fn fake_read(&mut self, _: &PlaceWithHirId<'tcx>, _: FakeReadCause, _: HirId) {} } -impl<'a, 'tcx> UnwrappableVariablesVisitor<'a, 'tcx> { +impl<'tcx> UnwrappableVariablesVisitor<'_, 'tcx> { fn visit_branch( &mut self, if_expr: &'tcx Expr<'_>, @@ -288,7 +288,7 @@ fn consume_option_as_ref<'tcx>(expr: &'tcx Expr<'tcx>) -> (&'tcx Expr<'tcx>, Opt } } -impl<'a, 'tcx> Visitor<'tcx> for UnwrappableVariablesVisitor<'a, 'tcx> { +impl<'tcx> Visitor<'tcx> for UnwrappableVariablesVisitor<'_, 'tcx> { type NestedFilter = nested_filter::OnlyBodies; fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { diff --git a/clippy_lints/src/use_self.rs b/clippy_lints/src/use_self.rs index e340b419bd0..08449de79b3 100644 --- a/clippy_lints/src/use_self.rs +++ b/clippy_lints/src/use_self.rs @@ -280,7 +280,7 @@ struct SkipTyCollector { types_to_skip: Vec, } -impl<'tcx> Visitor<'tcx> for SkipTyCollector { +impl Visitor<'_> for SkipTyCollector { fn visit_infer(&mut self, inf: &hir::InferArg) { self.types_to_skip.push(inf.hir_id); 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 7c45a5b2f09..dd456022212 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 @@ -270,7 +270,7 @@ struct LintCollector<'a, 'tcx> { cx: &'a LateContext<'tcx>, } -impl<'a, 'tcx> Visitor<'tcx> for LintCollector<'a, 'tcx> { +impl<'tcx> Visitor<'tcx> for LintCollector<'_, 'tcx> { type NestedFilter = nested_filter::All; fn visit_path(&mut self, path: &Path<'_>, _: HirId) { diff --git a/clippy_lints/src/zombie_processes.rs b/clippy_lints/src/zombie_processes.rs index ba2a80ee66b..58d71bee299 100644 --- a/clippy_lints/src/zombie_processes.rs +++ b/clippy_lints/src/zombie_processes.rs @@ -118,7 +118,7 @@ enum WaitFinder<'a, 'tcx> { Found(&'a LateContext<'tcx>, HirId), } -impl<'a, 'tcx> Visitor<'tcx> for WaitFinder<'a, 'tcx> { +impl<'tcx> Visitor<'tcx> for WaitFinder<'_, 'tcx> { type Result = ControlFlow; fn visit_local(&mut self, l: &'tcx LetStmt<'tcx>) -> Self::Result { @@ -300,7 +300,7 @@ struct ExitPointFinder<'a, 'tcx> { struct ExitCallFound; -impl<'a, 'tcx> Visitor<'tcx> for ExitPointFinder<'a, 'tcx> { +impl<'tcx> Visitor<'tcx> for ExitPointFinder<'_, 'tcx> { type Result = ControlFlow; fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) -> Self::Result { diff --git a/clippy_utils/src/consts.rs b/clippy_utils/src/consts.rs index bf47cf6d372..e0bc27ebe2e 100644 --- a/clippy_utils/src/consts.rs +++ b/clippy_utils/src/consts.rs @@ -118,7 +118,7 @@ impl IntTypeBounds for IntTy { } } -impl<'tcx> PartialEq for Constant<'tcx> { +impl PartialEq for Constant<'_> { fn eq(&self, other: &Self) -> bool { match (self, other) { (Self::Str(ls), Self::Str(rs)) => ls == rs, @@ -147,7 +147,7 @@ impl<'tcx> PartialEq for Constant<'tcx> { } } -impl<'tcx> Hash for Constant<'tcx> { +impl Hash for Constant<'_> { fn hash(&self, state: &mut H) where H: Hasher, @@ -203,7 +203,7 @@ impl<'tcx> Hash for Constant<'tcx> { } } -impl<'tcx> Constant<'tcx> { +impl Constant<'_> { pub fn partial_cmp(tcx: TyCtxt<'_>, cmp_type: Ty<'_>, left: &Self, right: &Self) -> Option { match (left, right) { (Self::Str(ls), Self::Str(rs)) => Some(ls.cmp(rs)), diff --git a/clippy_utils/src/eager_or_lazy.rs b/clippy_utils/src/eager_or_lazy.rs index 9420d84b959..a2e97919d04 100644 --- a/clippy_utils/src/eager_or_lazy.rs +++ b/clippy_utils/src/eager_or_lazy.rs @@ -118,7 +118,7 @@ fn expr_eagerness<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> EagernessS eagerness: EagernessSuggestion, } - impl<'cx, 'tcx> Visitor<'tcx> for V<'cx, 'tcx> { + impl<'tcx> Visitor<'tcx> for V<'_, 'tcx> { fn visit_expr(&mut self, e: &'tcx Expr<'_>) { use EagernessSuggestion::{ForceNoChange, Lazy, NoChange}; if self.eagerness == ForceNoChange { diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 2fee6473910..12e1bf9a6d6 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -1345,7 +1345,7 @@ pub struct ContainsName<'a, 'tcx> { pub result: bool, } -impl<'a, 'tcx> Visitor<'tcx> for ContainsName<'a, 'tcx> { +impl<'tcx> Visitor<'tcx> for ContainsName<'_, 'tcx> { type NestedFilter = nested_filter::OnlyBodies; fn visit_name(&mut self, name: Symbol) { @@ -3115,7 +3115,7 @@ pub fn is_never_expr<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> Option< is_never: bool, } - impl<'tcx> V<'_, 'tcx> { + impl V<'_, '_> { fn push_break_target(&mut self, id: HirId) { self.break_targets.push(BreakTarget { id, unused: true }); self.break_targets_for_result_ty += u32::from(self.in_final_expr); diff --git a/clippy_utils/src/mir/mod.rs b/clippy_utils/src/mir/mod.rs index 59bb5e35cda..3924e384c37 100644 --- a/clippy_utils/src/mir/mod.rs +++ b/clippy_utils/src/mir/mod.rs @@ -58,7 +58,7 @@ struct V<'a> { results: Vec, } -impl<'a, 'tcx> Visitor<'tcx> for V<'a> { +impl<'tcx> Visitor<'tcx> for V<'_> { fn visit_place(&mut self, place: &Place<'tcx>, ctx: PlaceContext, loc: Location) { if loc.block == self.location.block && loc.statement_index <= self.location.statement_index { return; diff --git a/clippy_utils/src/mir/possible_borrower.rs b/clippy_utils/src/mir/possible_borrower.rs index 07e6705cd3d..6bb434a466f 100644 --- a/clippy_utils/src/mir/possible_borrower.rs +++ b/clippy_utils/src/mir/possible_borrower.rs @@ -65,7 +65,7 @@ impl<'a, 'b, 'tcx> PossibleBorrowerVisitor<'a, 'b, 'tcx> { } } -impl<'a, 'b, 'tcx> mir::visit::Visitor<'tcx> for PossibleBorrowerVisitor<'a, 'b, 'tcx> { +impl<'tcx> mir::visit::Visitor<'tcx> for PossibleBorrowerVisitor<'_, '_, 'tcx> { fn visit_assign(&mut self, place: &mir::Place<'tcx>, rvalue: &mir::Rvalue<'_>, _location: mir::Location) { let lhs = place.local; match rvalue { @@ -177,8 +177,8 @@ pub struct PossibleBorrowerMap<'b, 'tcx> { pub bitset: (BitSet, BitSet), } -impl<'a, 'b, 'tcx> PossibleBorrowerMap<'b, 'tcx> { - pub fn new(cx: &'a LateContext<'tcx>, mir: &'b mir::Body<'tcx>) -> Self { +impl<'b, 'tcx> PossibleBorrowerMap<'b, 'tcx> { + pub fn new(cx: &LateContext<'tcx>, mir: &'b mir::Body<'tcx>) -> Self { let possible_origin = { let mut vis = PossibleOriginVisitor::new(mir); vis.visit_body(mir); diff --git a/clippy_utils/src/mir/possible_origin.rs b/clippy_utils/src/mir/possible_origin.rs index da04266863f..4157b3f4930 100644 --- a/clippy_utils/src/mir/possible_origin.rs +++ b/clippy_utils/src/mir/possible_origin.rs @@ -39,7 +39,7 @@ impl<'a, 'tcx> PossibleOriginVisitor<'a, 'tcx> { } } -impl<'a, 'tcx> mir::visit::Visitor<'tcx> for PossibleOriginVisitor<'a, 'tcx> { +impl<'tcx> mir::visit::Visitor<'tcx> for PossibleOriginVisitor<'_, 'tcx> { fn visit_assign(&mut self, place: &mir::Place<'tcx>, rvalue: &mir::Rvalue<'_>, _location: mir::Location) { let lhs = place.local; match rvalue { diff --git a/clippy_utils/src/ty/type_certainty/mod.rs b/clippy_utils/src/ty/type_certainty/mod.rs index e612e9c6cb6..91ec120adbf 100644 --- a/clippy_utils/src/ty/type_certainty/mod.rs +++ b/clippy_utils/src/ty/type_certainty/mod.rs @@ -108,7 +108,7 @@ impl<'cx, 'tcx> CertaintyVisitor<'cx, 'tcx> { } } -impl<'cx, 'tcx> Visitor<'cx> for CertaintyVisitor<'cx, 'tcx> { +impl<'cx> Visitor<'cx> for CertaintyVisitor<'cx, '_> { fn visit_qpath(&mut self, qpath: &'cx QPath<'_>, hir_id: HirId, _: Span) { self.certainty = self.certainty.meet(qpath_certainty(self.cx, qpath, true)); if self.certainty != Certainty::Uncertain { diff --git a/clippy_utils/src/usage.rs b/clippy_utils/src/usage.rs index 1230b60c3a6..8af3bdccaa1 100644 --- a/clippy_utils/src/usage.rs +++ b/clippy_utils/src/usage.rs @@ -46,8 +46,8 @@ struct MutVarsDelegate { skip: bool, } -impl<'tcx> MutVarsDelegate { - fn update(&mut self, cat: &PlaceWithHirId<'tcx>) { +impl MutVarsDelegate { + fn update(&mut self, cat: &PlaceWithHirId<'_>) { match cat.place.base { PlaceBase::Local(id) => { self.used_mutably.insert(id); @@ -122,7 +122,7 @@ impl<'a, 'tcx> BindingUsageFinder<'a, 'tcx> { finder.usage_found } } -impl<'a, 'tcx> Visitor<'tcx> for BindingUsageFinder<'a, 'tcx> { +impl<'tcx> Visitor<'tcx> for BindingUsageFinder<'_, 'tcx> { type NestedFilter = nested_filter::OnlyBodies; fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) { diff --git a/clippy_utils/src/visitors.rs b/clippy_utils/src/visitors.rs index 6d9a85a1181..02931306f16 100644 --- a/clippy_utils/src/visitors.rs +++ b/clippy_utils/src/visitors.rs @@ -552,7 +552,7 @@ pub fn for_each_local_use_after_expr<'tcx, B>( res: ControlFlow, f: F, } - impl<'cx, 'tcx, F: FnMut(&'tcx Expr<'tcx>) -> ControlFlow, B> Visitor<'tcx> for V<'cx, 'tcx, F, B> { + impl<'tcx, F: FnMut(&'tcx Expr<'tcx>) -> ControlFlow, B> Visitor<'tcx> for V<'_, 'tcx, F, B> { type NestedFilter = nested_filter::OnlyBodies; fn nested_visit_map(&mut self) -> Self::Map { self.cx.tcx.hir() @@ -734,7 +734,7 @@ pub fn for_each_local_assignment<'tcx, B>( res: ControlFlow, f: F, } - impl<'cx, 'tcx, F: FnMut(&'tcx Expr<'tcx>) -> ControlFlow, B> Visitor<'tcx> for V<'cx, 'tcx, F, B> { + impl<'tcx, F: FnMut(&'tcx Expr<'tcx>) -> ControlFlow, B> Visitor<'tcx> for V<'_, 'tcx, F, B> { type NestedFilter = nested_filter::OnlyBodies; fn nested_visit_map(&mut self) -> Self::Map { self.cx.tcx.hir() From 5c2f6db2892ab7abdfa7eebf96fb3600938a674a Mon Sep 17 00:00:00 2001 From: Samuel Moelius Date: Sun, 18 Aug 2024 13:42:16 -0400 Subject: [PATCH 266/683] Fix typo in `needless_lifetimes` test --- tests/ui/needless_lifetimes.fixed | 2 +- tests/ui/needless_lifetimes.rs | 2 +- tests/ui/needless_lifetimes.stderr | 10 +++++----- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/ui/needless_lifetimes.fixed b/tests/ui/needless_lifetimes.fixed index e4bb7f86d12..7ded5b4234c 100644 --- a/tests/ui/needless_lifetimes.fixed +++ b/tests/ui/needless_lifetimes.fixed @@ -384,7 +384,7 @@ mod nested_elision_sites { f() } // lint - fn where_clause_elidadable(i: &i32, f: T) -> &i32 + fn where_clause_elidable(i: &i32, f: T) -> &i32 where T: Fn(&i32) -> &i32, { diff --git a/tests/ui/needless_lifetimes.rs b/tests/ui/needless_lifetimes.rs index 03d6f201358..8b3a885f4a3 100644 --- a/tests/ui/needless_lifetimes.rs +++ b/tests/ui/needless_lifetimes.rs @@ -384,7 +384,7 @@ mod nested_elision_sites { f() } // lint - fn where_clause_elidadable<'a, T>(i: &'a i32, f: T) -> &'a i32 + fn where_clause_elidable<'a, T>(i: &'a i32, f: T) -> &'a i32 where T: Fn(&i32) -> &i32, { diff --git a/tests/ui/needless_lifetimes.stderr b/tests/ui/needless_lifetimes.stderr index 166e6d0eabf..e56c914cc86 100644 --- a/tests/ui/needless_lifetimes.stderr +++ b/tests/ui/needless_lifetimes.stderr @@ -384,15 +384,15 @@ LL + fn generics_elidable &i32>(i: &i32, f: T) -> &i32 { | error: the following explicit lifetimes could be elided: 'a - --> tests/ui/needless_lifetimes.rs:387:32 + --> tests/ui/needless_lifetimes.rs:387:30 | -LL | fn where_clause_elidadable<'a, T>(i: &'a i32, f: T) -> &'a i32 - | ^^ ^^ ^^ +LL | fn where_clause_elidable<'a, T>(i: &'a i32, f: T) -> &'a i32 + | ^^ ^^ ^^ | help: elide the lifetimes | -LL - fn where_clause_elidadable<'a, T>(i: &'a i32, f: T) -> &'a i32 -LL + fn where_clause_elidadable(i: &i32, f: T) -> &i32 +LL - fn where_clause_elidable<'a, T>(i: &'a i32, f: T) -> &'a i32 +LL + fn where_clause_elidable(i: &i32, f: T) -> &i32 | error: the following explicit lifetimes could be elided: 'a From d3e59a502be4f3cc2d90a252f0604985320599cc Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Wed, 25 Sep 2024 17:53:57 +0000 Subject: [PATCH 267/683] Revert Break into the debugger on panic (129019) --- library/std/src/panicking.rs | 18 +---- library/std/src/sys/dbg.rs | 152 ----------------------------------- library/std/src/sys/mod.rs | 1 - 3 files changed, 1 insertion(+), 170 deletions(-) delete mode 100644 library/std/src/sys/dbg.rs diff --git a/library/std/src/panicking.rs b/library/std/src/panicking.rs index 336e34d7b95..1c972d38100 100644 --- a/library/std/src/panicking.rs +++ b/library/std/src/panicking.rs @@ -23,8 +23,8 @@ use crate::mem::{self, ManuallyDrop}; use crate::panic::{BacktraceStyle, PanicHookInfo}; use crate::sync::atomic::{AtomicBool, Ordering}; use crate::sync::{PoisonError, RwLock}; +use crate::sys::backtrace; use crate::sys::stdio::panic_output; -use crate::sys::{backtrace, dbg}; use crate::{fmt, intrinsics, process, thread}; // Binary interface to the panic runtime that the standard library depends on. @@ -859,14 +859,6 @@ pub fn rust_panic_without_hook(payload: Box) -> ! { #[cfg_attr(not(test), rustc_std_internal_symbol)] #[cfg(not(feature = "panic_immediate_abort"))] fn rust_panic(msg: &mut dyn PanicPayload) -> ! { - // Break into the debugger if it is attached. - // The return value is not currently used. - // - // This function isn't used anywhere else, and - // using inside `#[panic_handler]` doesn't seem - // to count, so a warning is issued. - let _ = dbg::breakpoint_if_debugging(); - let code = unsafe { __rust_start_panic(msg) }; rtabort!("failed to initiate panic, error {code}") } @@ -874,14 +866,6 @@ fn rust_panic(msg: &mut dyn PanicPayload) -> ! { #[cfg_attr(not(test), rustc_std_internal_symbol)] #[cfg(feature = "panic_immediate_abort")] fn rust_panic(_: &mut dyn PanicPayload) -> ! { - // Break into the debugger if it is attached. - // The return value is not currently used. - // - // This function isn't used anywhere else, and - // using inside `#[panic_handler]` doesn't seem - // to count, so a warning is issued. - let _ = dbg::breakpoint_if_debugging(); - unsafe { crate::intrinsics::abort(); } diff --git a/library/std/src/sys/dbg.rs b/library/std/src/sys/dbg.rs deleted file mode 100644 index 7266a739e78..00000000000 --- a/library/std/src/sys/dbg.rs +++ /dev/null @@ -1,152 +0,0 @@ -//! Debugging aids. - -/// Presence of a debugger. The debugger being concerned -/// is expected to use the OS API to debug this process. -#[derive(Copy, Clone, Debug)] -#[allow(unused)] -pub(crate) enum DebuggerPresence { - /// The debugger is attached to this process. - Detected, - /// The debugger is not attached to this process. - NotDetected, -} - -#[cfg(target_os = "windows")] -mod os { - use super::DebuggerPresence; - - #[link(name = "kernel32")] - extern "system" { - fn IsDebuggerPresent() -> i32; - } - - pub(super) fn is_debugger_present() -> Option { - // SAFETY: No state is shared between threads. The call reads - // a field from the Thread Environment Block using the OS API - // as required by the documentation. - if unsafe { IsDebuggerPresent() } != 0 { - Some(DebuggerPresence::Detected) - } else { - Some(DebuggerPresence::NotDetected) - } - } -} - -#[cfg(any(target_vendor = "apple", target_os = "freebsd"))] -mod os { - use libc::{CTL_KERN, KERN_PROC, KERN_PROC_PID, c_int, sysctl}; - - use super::DebuggerPresence; - use crate::io::{Cursor, Read, Seek, SeekFrom}; - use crate::process; - - const P_TRACED: i32 = 0x00000800; - - // The assumption is that the kernel structures available to the - // user space may not shrink or repurpose the existing fields over - // time. The kernels normally adhere to that for the backward - // compatibility of the user space. - - // The macOS 14.5 SDK comes with a header `MacOSX14.5.sdk/usr/include/sys/sysctl.h` - // that defines `struct kinfo_proc` be of `648` bytes on the 64-bit system. That has - // not changed since macOS 10.13 (released in 2017) at least, validated by building - // a C program in XCode while changing the build target. Apple provides this example - // for reference: https://developer.apple.com/library/archive/qa/qa1361/_index.html. - #[cfg(target_vendor = "apple")] - const KINFO_PROC_SIZE: usize = if cfg!(target_pointer_width = "64") { 648 } else { 492 }; - #[cfg(target_vendor = "apple")] - const KINFO_PROC_FLAGS_OFFSET: u64 = if cfg!(target_pointer_width = "64") { 32 } else { 16 }; - - // Works for FreeBSD stable (13.3, 13.4) and current (14.0, 14.1). - // The size of the structure has stayed the same for a long time, - // at least since 2005: - // https://lists.freebsd.org/pipermail/freebsd-stable/2005-November/019899.html - #[cfg(target_os = "freebsd")] - const KINFO_PROC_SIZE: usize = if cfg!(target_pointer_width = "64") { 1088 } else { 768 }; - #[cfg(target_os = "freebsd")] - const KINFO_PROC_FLAGS_OFFSET: u64 = if cfg!(target_pointer_width = "64") { 368 } else { 296 }; - - pub(super) fn is_debugger_present() -> Option { - debug_assert_ne!(KINFO_PROC_SIZE, 0); - - let mut flags = [0u8; 4]; // `ki_flag` under FreeBSD and `p_flag` under macOS. - let mut mib = [CTL_KERN, KERN_PROC, KERN_PROC_PID, process::id() as c_int]; - let mut info_size = KINFO_PROC_SIZE; - let mut kinfo_proc = [0u8; KINFO_PROC_SIZE]; - - // SAFETY: No state is shared with other threads. The sysctl call - // is safe according to the documentation. - if unsafe { - sysctl( - mib.as_mut_ptr(), - mib.len() as u32, - kinfo_proc.as_mut_ptr().cast(), - &mut info_size, - core::ptr::null_mut(), - 0, - ) - } != 0 - { - return None; - } - debug_assert_eq!(info_size, KINFO_PROC_SIZE); - - let mut reader = Cursor::new(kinfo_proc); - reader.seek(SeekFrom::Start(KINFO_PROC_FLAGS_OFFSET)).ok()?; - reader.read_exact(&mut flags).ok()?; - // Just in case, not limiting this to the little-endian systems. - let flags = i32::from_ne_bytes(flags); - - if flags & P_TRACED != 0 { - Some(DebuggerPresence::Detected) - } else { - Some(DebuggerPresence::NotDetected) - } - } -} - -#[cfg(not(any(target_os = "windows", target_vendor = "apple", target_os = "freebsd")))] -mod os { - pub(super) fn is_debugger_present() -> Option { - None - } -} - -/// Detect the debugger presence. -/// -/// The code does not try to detect the debugger at all costs (e.g., when anti-debugger -/// tricks are at play), it relies on the interfaces provided by the OS. -/// -/// Return value: -/// * `None`: it's not possible to conclude whether the debugger is attached to this -/// process or not. When checking for the presence of the debugger, the detection logic -/// encountered an issue, such as the OS API throwing an error or the feature not being -/// implemented. -/// * `Some(DebuggerPresence::Detected)`: yes, the debugger is attached -/// to this process. -/// * `Some(DebuggerPresence::NotDetected)`: no, the debugger is not -/// attached to this process. -pub(crate) fn is_debugger_present() -> Option { - if cfg!(miri) { None } else { os::is_debugger_present() } -} - -/// Execute the breakpoint instruction if the debugger presence is detected. -/// Useful for breaking into the debugger without the need to set a breakpoint -/// in the debugger. -/// -/// Note that there is a race between attaching or detaching the debugger, and running the -/// breakpoint instruction. This is nonetheless memory-safe, like [`crate::process::abort`] -/// is. In case the debugger is attached and the function is about -/// to run the breakpoint instruction yet right before that the debugger detaches, the -/// process will crash due to running the breakpoint instruction and the debugger not -/// handling the trap exception. -pub(crate) fn breakpoint_if_debugging() -> Option { - let debugger_present = is_debugger_present(); - if let Some(DebuggerPresence::Detected) = debugger_present { - // SAFETY: Executing the breakpoint instruction. No state is shared - // or modified by this code. - unsafe { core::intrinsics::breakpoint() }; - } - - debugger_present -} diff --git a/library/std/src/sys/mod.rs b/library/std/src/sys/mod.rs index df25b84fbbe..f17dd47dece 100644 --- a/library/std/src/sys/mod.rs +++ b/library/std/src/sys/mod.rs @@ -11,7 +11,6 @@ mod personality; pub mod anonymous_pipe; pub mod backtrace; pub mod cmath; -pub mod dbg; pub mod exit_guard; pub mod os_str; pub mod path; From bc070273978b66dad4407ede21c79eee5c0f45ab Mon Sep 17 00:00:00 2001 From: VictorHugoPilled Date: Wed, 25 Sep 2024 13:12:19 -0500 Subject: [PATCH 268/683] fix(clippy_lints/matches): wildcard_in_or_patterns will no longer be triggered for types annotated with #[nonexhaustive] --- clippy_lints/src/matches/mod.rs | 2 +- clippy_lints/src/matches/wild_in_or_pats.rs | 14 ++++- tests/ui/wild_in_or_pats.rs | 68 +++++++++++++++++++++ tests/ui/wild_in_or_pats.stderr | 18 +++++- 4 files changed, 97 insertions(+), 5 deletions(-) diff --git a/clippy_lints/src/matches/mod.rs b/clippy_lints/src/matches/mod.rs index 686fc4a0fa0..28adcc2f227 100644 --- a/clippy_lints/src/matches/mod.rs +++ b/clippy_lints/src/matches/mod.rs @@ -1045,7 +1045,7 @@ impl<'tcx> LateLintPass<'tcx> for Matches { if !from_expansion { // These don't depend on a relationship between multiple arms match_wild_err_arm::check(cx, ex, arms); - wild_in_or_pats::check(cx, arms); + wild_in_or_pats::check(cx, ex, arms); } if let MatchSource::TryDesugar(_) = source { diff --git a/clippy_lints/src/matches/wild_in_or_pats.rs b/clippy_lints/src/matches/wild_in_or_pats.rs index 459513e65bf..390ba889fd2 100644 --- a/clippy_lints/src/matches/wild_in_or_pats.rs +++ b/clippy_lints/src/matches/wild_in_or_pats.rs @@ -1,11 +1,19 @@ use clippy_utils::diagnostics::span_lint_and_help; -use clippy_utils::is_wild; -use rustc_hir::{Arm, PatKind}; +use clippy_utils::{has_non_exhaustive_attr, is_wild}; +use rustc_hir::{Arm, Expr, PatKind}; use rustc_lint::LateContext; +use rustc_middle::ty; use super::WILDCARD_IN_OR_PATTERNS; -pub(crate) fn check(cx: &LateContext<'_>, arms: &[Arm<'_>]) { +pub(crate) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, arms: &[Arm<'_>]) { + // first check if we are matching on an enum that has the non_exhaustive attribute + let ty = cx.typeck_results().expr_ty(expr).peel_refs(); + if let ty::Adt(adt_def, _) = ty.kind() + && has_non_exhaustive_attr(cx.tcx, *adt_def) + { + return; + }; for arm in arms { if let PatKind::Or(fields) = arm.pat.kind { // look for multiple fields in this arm that contains at least one Wild pattern diff --git a/tests/ui/wild_in_or_pats.rs b/tests/ui/wild_in_or_pats.rs index f8bb31b83c4..bc8a1dbee71 100644 --- a/tests/ui/wild_in_or_pats.rs +++ b/tests/ui/wild_in_or_pats.rs @@ -37,4 +37,72 @@ fn main() { dbg!("matched (bar or) wild"); }, }; + + // shouldn't lint + #[non_exhaustive] + pub enum NonExhaustiveEnum<'a> { + Message(&'a str), + Quit(&'a str), + Other, + } + + match NonExhaustiveEnum::Message("Pass") { + NonExhaustiveEnum::Message(_) => dbg!("message"), + NonExhaustiveEnum::Quit(_) => dbg!("quit"), + NonExhaustiveEnum::Other | _ => dbg!("wildcard"), + }; + + // should lint + enum ExhaustiveEnum { + Quit, + Write(String), + ChangeColor(i32, i32, i32), + } + + match ExhaustiveEnum::ChangeColor(0, 160, 255) { + ExhaustiveEnum::Write(text) => { + dbg!("Write"); + }, + ExhaustiveEnum::ChangeColor(r, g, b) => { + dbg!("Change the color"); + }, + ExhaustiveEnum::Quit | _ => { + dbg!("Quit or other"); + }, + }; + + // shouldn't lint + #[non_exhaustive] + struct NonExhaustiveStruct { + a: u32, + b: u32, + c: u64, + } + + let b = NonExhaustiveStruct { a: 5, b: 42, c: 342 }; + + match b { + NonExhaustiveStruct { a: 5, b: 42, .. } => {}, + NonExhaustiveStruct { a: 0, b: 0, c: 128 } => {}, + NonExhaustiveStruct { a: 0, b: 0, c: 128, .. } | _ => {}, + } + + // should lint + struct ExhaustiveStruct { + x: i32, + y: i32, + } + + let p = ExhaustiveStruct { x: 0, y: 7 }; + match p { + ExhaustiveStruct { x: 0, y: 0 } => { + dbg!("On the x axis at {x}"); + }, + ExhaustiveStruct { x: 0, y: 1 } => { + dbg!("On the y axis at {y}"); + }, + ExhaustiveStruct { x: 1, y: 1 } | _ => { + dbg!("On neither axis: ({x}, {y})"); + }, + } } diff --git a/tests/ui/wild_in_or_pats.stderr b/tests/ui/wild_in_or_pats.stderr index 06b2415d221..5e409d6dfa6 100644 --- a/tests/ui/wild_in_or_pats.stderr +++ b/tests/ui/wild_in_or_pats.stderr @@ -32,5 +32,21 @@ LL | _ | "bar" => { | = help: consider handling `_` separately -error: aborting due to 4 previous errors +error: wildcard pattern covers any other pattern as it will match anyway + --> tests/ui/wild_in_or_pats.rs:69:9 + | +LL | ExhaustiveEnum::Quit | _ => { + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider handling `_` separately + +error: wildcard pattern covers any other pattern as it will match anyway + --> tests/ui/wild_in_or_pats.rs:104:9 + | +LL | ExhaustiveStruct { x: 1, y: 1 } | _ => { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider handling `_` separately + +error: aborting due to 6 previous errors From afb7eef79aa6bfaa9249fe2a0dc7033a44eff063 Mon Sep 17 00:00:00 2001 From: Aleksei Romanov Date: Wed, 25 Sep 2024 22:44:54 +0300 Subject: [PATCH 269/683] Pass Module Analysis Manager to Standard Instrumentations --- compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp index 165fb7aa6c3..8f0b1b81276 100644 --- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp @@ -732,12 +732,7 @@ extern "C" LLVMRustResult LLVMRustOptimize( PTO.SLPVectorization = SLPVectorize; PTO.MergeFunctions = MergeFunctions; - // FIXME: We may want to expose this as an option. - bool DebugPassManager = false; - PassInstrumentationCallbacks PIC; - StandardInstrumentations SI(TheModule->getContext(), DebugPassManager); - SI.registerCallbacks(PIC); if (LlvmSelfProfiler) { LLVMSelfProfileInitializeCallbacks(PIC, LlvmSelfProfiler, @@ -784,6 +779,12 @@ extern "C" LLVMRustResult LLVMRustOptimize( CGSCCAnalysisManager CGAM; ModuleAnalysisManager MAM; + // FIXME: We may want to expose this as an option. + bool DebugPassManager = false; + + StandardInstrumentations SI(TheModule->getContext(), DebugPassManager); + SI.registerCallbacks(PIC, &MAM); + if (LLVMPluginsLen) { auto PluginsStr = StringRef(LLVMPlugins, LLVMPluginsLen); SmallVector Plugins; From b1745c3919b57d841c15fe0bfb0dd926ab59bafa Mon Sep 17 00:00:00 2001 From: Lukas Markeffsky <@> Date: Wed, 25 Sep 2024 22:15:23 +0200 Subject: [PATCH 270/683] de-rc external traits Don't keep the `external_traits` as shared mutable data between the `DocContext` and `clean::Crate`. Instead, move the data over when necessary. This allows us to get rid of a borrowck hack in the `DocVisitor`. --- src/librustdoc/clean/inline.rs | 5 ++--- src/librustdoc/clean/types.rs | 4 +--- src/librustdoc/clean/utils.rs | 2 +- src/librustdoc/core.rs | 6 ++---- src/librustdoc/fold.rs | 11 +++++++---- src/librustdoc/formats/cache.rs | 3 ++- src/librustdoc/passes/collect_trait_impls.rs | 2 ++ src/librustdoc/visit.rs | 7 ++----- 8 files changed, 19 insertions(+), 21 deletions(-) diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index b7d6b3dda72..d3c4ef4dc90 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -837,8 +837,7 @@ pub(crate) fn record_extern_trait(cx: &mut DocContext<'_>, did: DefId) { } { - if cx.external_traits.borrow().contains_key(&did) || cx.active_extern_traits.contains(&did) - { + if cx.external_traits.contains_key(&did) || cx.active_extern_traits.contains(&did) { return; } } @@ -850,6 +849,6 @@ pub(crate) fn record_extern_trait(cx: &mut DocContext<'_>, did: DefId) { debug!("record_extern_trait: {did:?}"); let trait_ = build_external_trait(cx, did); - cx.external_traits.borrow_mut().insert(did, trait_); + cx.external_traits.insert(did, trait_); cx.active_extern_traits.remove(&did); } diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index bc6b5a7d3e3..69a414ae989 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -1,8 +1,6 @@ use std::borrow::Cow; -use std::cell::RefCell; use std::hash::Hash; use std::path::PathBuf; -use std::rc::Rc; use std::sync::{Arc, OnceLock as OnceCell}; use std::{fmt, iter}; @@ -115,7 +113,7 @@ impl From for ItemId { pub(crate) struct Crate { pub(crate) module: Item, /// Only here so that they can be filtered through the rustdoc passes. - pub(crate) external_traits: Rc>>, + pub(crate) external_traits: Box>, } impl Crate { diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index b91c1725d0c..fdf628b50fb 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -74,7 +74,7 @@ pub(crate) fn krate(cx: &mut DocContext<'_>) -> Crate { })); } - Crate { module, external_traits: cx.external_traits.clone() } + Crate { module, external_traits: Box::new(mem::take(&mut cx.external_traits)) } } pub(crate) fn clean_middle_generic_args<'tcx>( diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 8e46d93c28e..4c48c075a94 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -1,5 +1,3 @@ -use std::cell::RefCell; -use std::rc::Rc; use std::sync::atomic::AtomicBool; use std::sync::{Arc, LazyLock}; use std::{io, mem}; @@ -41,7 +39,7 @@ pub(crate) struct DocContext<'tcx> { /// Most of this logic is copied from rustc_lint::late. pub(crate) param_env: ParamEnv<'tcx>, /// Later on moved through `clean::Crate` into `cache` - pub(crate) external_traits: Rc>>, + pub(crate) external_traits: FxHashMap, /// Used while populating `external_traits` to ensure we don't process the same trait twice at /// the same time. pub(crate) active_extern_traits: DefIdSet, @@ -359,7 +357,7 @@ pub(crate) fn run_global_ctxt( // Note that in case of `#![no_core]`, the trait is not available. if let Some(sized_trait_did) = ctxt.tcx.lang_items().sized_trait() { let sized_trait = build_external_trait(&mut ctxt, sized_trait_did); - ctxt.external_traits.borrow_mut().insert(sized_trait_did, sized_trait); + ctxt.external_traits.insert(sized_trait_did, sized_trait); } debug!("crate: {:?}", tcx.hir().krate()); diff --git a/src/librustdoc/fold.rs b/src/librustdoc/fold.rs index c25a4ddb6f3..95e495205ae 100644 --- a/src/librustdoc/fold.rs +++ b/src/librustdoc/fold.rs @@ -1,3 +1,5 @@ +use std::mem; + use crate::clean::*; pub(crate) fn strip_item(mut item: Item) -> Item { @@ -116,10 +118,11 @@ pub(crate) trait DocFolder: Sized { fn fold_crate(&mut self, mut c: Crate) -> Crate { c.module = self.fold_item(c.module).unwrap(); - let external_traits = { std::mem::take(&mut *c.external_traits.borrow_mut()) }; - for (k, mut v) in external_traits { - v.items = v.items.into_iter().filter_map(|i| self.fold_item(i)).collect(); - c.external_traits.borrow_mut().insert(k, v); + for trait_ in c.external_traits.values_mut() { + trait_.items = mem::take(&mut trait_.items) + .into_iter() + .filter_map(|i| self.fold_item(i)) + .collect(); } c diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs index 8597d2e2b63..db1a0bd0af9 100644 --- a/src/librustdoc/formats/cache.rs +++ b/src/librustdoc/formats/cache.rs @@ -153,7 +153,8 @@ impl Cache { // Crawl the crate to build various caches used for the output debug!(?cx.cache.crate_version); - cx.cache.traits = krate.external_traits.take(); + assert!(cx.external_traits.is_empty()); + cx.cache.traits = mem::take(&mut krate.external_traits); // Cache where all our extern crates are located // FIXME: this part is specific to HTML so it'd be nice to remove it from the common code diff --git a/src/librustdoc/passes/collect_trait_impls.rs b/src/librustdoc/passes/collect_trait_impls.rs index a9edc485d5e..949ba548387 100644 --- a/src/librustdoc/passes/collect_trait_impls.rs +++ b/src/librustdoc/passes/collect_trait_impls.rs @@ -219,6 +219,8 @@ pub(crate) fn collect_trait_impls(mut krate: Crate, cx: &mut DocContext<'_>) -> panic!("collect-trait-impls can't run"); }; + krate.external_traits.extend(cx.external_traits.drain()); + krate } diff --git a/src/librustdoc/visit.rs b/src/librustdoc/visit.rs index 7fb0a32cc94..f1de0fe9a34 100644 --- a/src/librustdoc/visit.rs +++ b/src/librustdoc/visit.rs @@ -61,11 +61,8 @@ pub(crate) trait DocVisitor: Sized { fn visit_crate(&mut self, c: &Crate) { self.visit_item(&c.module); - // FIXME: make this a simple by-ref for loop once external_traits is cleaned up - let external_traits = { std::mem::take(&mut *c.external_traits.borrow_mut()) }; - for (k, v) in external_traits { - v.items.iter().for_each(|i| self.visit_item(i)); - c.external_traits.borrow_mut().insert(k, v); + for trait_ in c.external_traits.values() { + trait_.items.iter().for_each(|i| self.visit_item(i)); } } } From 4facc1ce41f2f98fe75129da8c2f2251e8090e26 Mon Sep 17 00:00:00 2001 From: Lukas Markeffsky <@> Date: Wed, 25 Sep 2024 22:28:28 +0200 Subject: [PATCH 271/683] rm higher-ranked lifetimes from `DocVisitor` This allows the visitor to borrow from the visitees. --- src/librustdoc/html/render/write_shared.rs | 2 +- src/librustdoc/html/sources.rs | 4 ++-- src/librustdoc/passes/calculate_doc_coverage.rs | 2 +- src/librustdoc/passes/check_doc_test_visibility.rs | 2 +- src/librustdoc/passes/collect_intra_doc_links.rs | 2 +- src/librustdoc/passes/collect_trait_impls.rs | 4 ++-- src/librustdoc/passes/lint.rs | 2 +- src/librustdoc/visit.rs | 12 ++++++------ 8 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/librustdoc/html/render/write_shared.rs b/src/librustdoc/html/render/write_shared.rs index 12246b0d416..7db70eb9dd8 100644 --- a/src/librustdoc/html/render/write_shared.rs +++ b/src/librustdoc/html/render/write_shared.rs @@ -865,7 +865,7 @@ struct AliasedTypeImpl<'cache> { type_aliases: Vec<(&'cache [Symbol], Item)>, } -impl<'cx, 'cache> DocVisitor for TypeImplCollector<'cx, 'cache> { +impl<'cx, 'cache> DocVisitor<'_> for TypeImplCollector<'cx, 'cache> { fn visit_item(&mut self, it: &Item) { self.visit_item_recur(it); let cache = self.cache; diff --git a/src/librustdoc/html/sources.rs b/src/librustdoc/html/sources.rs index 9ba0fb7b83c..7be9cc0b885 100644 --- a/src/librustdoc/html/sources.rs +++ b/src/librustdoc/html/sources.rs @@ -103,7 +103,7 @@ impl LocalSourcesCollector<'_, '_> { } } -impl DocVisitor for LocalSourcesCollector<'_, '_> { +impl DocVisitor<'_> for LocalSourcesCollector<'_, '_> { fn visit_item(&mut self, item: &clean::Item) { self.add_local_source(item); @@ -122,7 +122,7 @@ struct SourceCollector<'a, 'tcx> { crate_name: &'a str, } -impl DocVisitor for SourceCollector<'_, '_> { +impl DocVisitor<'_> for SourceCollector<'_, '_> { fn visit_item(&mut self, item: &clean::Item) { if !self.cx.include_sources { return; diff --git a/src/librustdoc/passes/calculate_doc_coverage.rs b/src/librustdoc/passes/calculate_doc_coverage.rs index 15c0d77e7ba..abea5bcbc51 100644 --- a/src/librustdoc/passes/calculate_doc_coverage.rs +++ b/src/librustdoc/passes/calculate_doc_coverage.rs @@ -187,7 +187,7 @@ impl<'a, 'b> CoverageCalculator<'a, 'b> { } } -impl<'a, 'b> DocVisitor for CoverageCalculator<'a, 'b> { +impl<'a, 'b> DocVisitor<'_> for CoverageCalculator<'a, 'b> { fn visit_item(&mut self, i: &clean::Item) { if !i.item_id.is_local() { // non-local items are skipped because they can be out of the users control, diff --git a/src/librustdoc/passes/check_doc_test_visibility.rs b/src/librustdoc/passes/check_doc_test_visibility.rs index 52b2cd7774d..1dc9af7ebe5 100644 --- a/src/librustdoc/passes/check_doc_test_visibility.rs +++ b/src/librustdoc/passes/check_doc_test_visibility.rs @@ -34,7 +34,7 @@ pub(crate) fn check_doc_test_visibility(krate: Crate, cx: &mut DocContext<'_>) - krate } -impl<'a, 'tcx> DocVisitor for DocTestVisibilityLinter<'a, 'tcx> { +impl<'a, 'tcx> DocVisitor<'_> for DocTestVisibilityLinter<'a, 'tcx> { fn visit_item(&mut self, item: &Item) { look_for_tests(self.cx, &item.doc_value(), item); diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 29342dcac59..e95e8762b1d 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -816,7 +816,7 @@ fn is_derive_trait_collision(ns: &PerNS, ResolutionFailu } } -impl<'a, 'tcx> DocVisitor for LinkCollector<'a, 'tcx> { +impl<'a, 'tcx> DocVisitor<'_> for LinkCollector<'a, 'tcx> { fn visit_item(&mut self, item: &Item) { self.resolve_links(item); self.visit_item_recur(item) diff --git a/src/librustdoc/passes/collect_trait_impls.rs b/src/librustdoc/passes/collect_trait_impls.rs index 949ba548387..b307e84e42e 100644 --- a/src/librustdoc/passes/collect_trait_impls.rs +++ b/src/librustdoc/passes/collect_trait_impls.rs @@ -229,7 +229,7 @@ struct SyntheticImplCollector<'a, 'tcx> { impls: Vec, } -impl<'a, 'tcx> DocVisitor for SyntheticImplCollector<'a, 'tcx> { +impl<'a, 'tcx> DocVisitor<'_> for SyntheticImplCollector<'a, 'tcx> { fn visit_item(&mut self, i: &Item) { if i.is_struct() || i.is_enum() || i.is_union() { // FIXME(eddyb) is this `doc(hidden)` check needed? @@ -256,7 +256,7 @@ impl<'cache> ItemAndAliasCollector<'cache> { } } -impl<'cache> DocVisitor for ItemAndAliasCollector<'cache> { +impl<'cache> DocVisitor<'_> for ItemAndAliasCollector<'cache> { fn visit_item(&mut self, i: &Item) { self.items.insert(i.item_id); diff --git a/src/librustdoc/passes/lint.rs b/src/librustdoc/passes/lint.rs index 4da5d8f0e06..593027ef7d2 100644 --- a/src/librustdoc/passes/lint.rs +++ b/src/librustdoc/passes/lint.rs @@ -25,7 +25,7 @@ pub(crate) fn run_lints(krate: Crate, cx: &mut DocContext<'_>) -> Crate { krate } -impl<'a, 'tcx> DocVisitor for Linter<'a, 'tcx> { +impl<'a, 'tcx> DocVisitor<'_> for Linter<'a, 'tcx> { fn visit_item(&mut self, item: &Item) { let Some(hir_id) = DocContext::as_local_hir_id(self.cx.tcx, item.item_id) else { // If non-local, no need to check anything. diff --git a/src/librustdoc/visit.rs b/src/librustdoc/visit.rs index f1de0fe9a34..fbc18176ed8 100644 --- a/src/librustdoc/visit.rs +++ b/src/librustdoc/visit.rs @@ -1,12 +1,12 @@ use crate::clean::*; -pub(crate) trait DocVisitor: Sized { - fn visit_item(&mut self, item: &Item) { +pub(crate) trait DocVisitor<'a>: Sized { + fn visit_item(&mut self, item: &'a Item) { self.visit_item_recur(item) } /// don't override! - fn visit_inner_recur(&mut self, kind: &ItemKind) { + fn visit_inner_recur(&mut self, kind: &'a ItemKind) { match kind { StrippedItem(..) => unreachable!(), ModuleItem(i) => { @@ -47,18 +47,18 @@ pub(crate) trait DocVisitor: Sized { } /// don't override! - fn visit_item_recur(&mut self, item: &Item) { + fn visit_item_recur(&mut self, item: &'a Item) { match &item.kind { StrippedItem(i) => self.visit_inner_recur(&*i), _ => self.visit_inner_recur(&item.kind), } } - fn visit_mod(&mut self, m: &Module) { + fn visit_mod(&mut self, m: &'a Module) { m.items.iter().for_each(|i| self.visit_item(i)) } - fn visit_crate(&mut self, c: &Crate) { + fn visit_crate(&mut self, c: &'a Crate) { self.visit_item(&c.module); for trait_ in c.external_traits.values() { From 345077af98bb0efc796536d82e4232aab10671f3 Mon Sep 17 00:00:00 2001 From: Lukas Markeffsky <@> Date: Wed, 25 Sep 2024 22:41:32 +0200 Subject: [PATCH 272/683] don't clone `clean::Item` in `TypeImplCollector` --- src/librustdoc/html/render/write_shared.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/librustdoc/html/render/write_shared.rs b/src/librustdoc/html/render/write_shared.rs index 7db70eb9dd8..af94b1042c0 100644 --- a/src/librustdoc/html/render/write_shared.rs +++ b/src/librustdoc/html/render/write_shared.rs @@ -824,9 +824,9 @@ impl Serialize for Implementor { /// this visitor works to reverse that: `aliased_types` is a map /// from target to the aliases that reference it, and each one /// will generate one file. -struct TypeImplCollector<'cx, 'cache> { +struct TypeImplCollector<'cx, 'cache, 'item> { /// Map from DefId-of-aliased-type to its data. - aliased_types: IndexMap>, + aliased_types: IndexMap>, visited_aliases: FxHashSet, cache: &'cache Cache, cx: &'cache mut Context<'cx>, @@ -847,26 +847,26 @@ struct TypeImplCollector<'cx, 'cache> { /// ] /// ) /// ``` -struct AliasedType<'cache> { +struct AliasedType<'cache, 'item> { /// This is used to generate the actual filename of this aliased type. target_fqp: &'cache [Symbol], target_type: ItemType, /// This is the data stored inside the file. /// ItemId is used to deduplicate impls. - impl_: IndexMap>, + impl_: IndexMap>, } /// The `impl_` contains data that's used to figure out if an alias will work, /// and to generate the HTML at the end. /// /// The `type_aliases` list is built up with each type alias that matches. -struct AliasedTypeImpl<'cache> { +struct AliasedTypeImpl<'cache, 'item> { impl_: &'cache Impl, - type_aliases: Vec<(&'cache [Symbol], Item)>, + type_aliases: Vec<(&'cache [Symbol], &'item Item)>, } -impl<'cx, 'cache> DocVisitor<'_> for TypeImplCollector<'cx, 'cache> { - fn visit_item(&mut self, it: &Item) { +impl<'cx, 'cache, 'item> DocVisitor<'item> for TypeImplCollector<'cx, 'cache, 'item> { + fn visit_item(&mut self, it: &'item Item) { self.visit_item_recur(it); let cache = self.cache; let ItemKind::TypeAliasItem(ref t) = it.kind else { return }; @@ -927,7 +927,7 @@ impl<'cx, 'cache> DocVisitor<'_> for TypeImplCollector<'cx, 'cache> { continue; } // This impl was not found in the set of rejected impls - aliased_type_impl.type_aliases.push((&self_fqp[..], it.clone())); + aliased_type_impl.type_aliases.push((&self_fqp[..], it)); } } } From 51b527266e9270ced4c6f1c1bd0735ce49b6ed88 Mon Sep 17 00:00:00 2001 From: Samuel Moelius Date: Wed, 25 Sep 2024 14:28:19 -0400 Subject: [PATCH 273/683] Fix bug found during review https://github.com/rust-lang/rust-clippy/pull/13286#issuecomment-2374245772 --- clippy_lints/src/lifetimes.rs | 28 ++++++++++++++-------------- tests/ui/needless_lifetimes.fixed | 19 +++++++++++++++++++ tests/ui/needless_lifetimes.rs | 19 +++++++++++++++++++ 3 files changed, 52 insertions(+), 14 deletions(-) diff --git a/clippy_lints/src/lifetimes.rs b/clippy_lints/src/lifetimes.rs index 5a3c749cab1..a4555e003c4 100644 --- a/clippy_lints/src/lifetimes.rs +++ b/clippy_lints/src/lifetimes.rs @@ -6,12 +6,12 @@ use rustc_errors::Applicability; use rustc_hir::FnRetTy::Return; use rustc_hir::intravisit::nested_filter::{self as hir_nested_filter, NestedFilter}; use rustc_hir::intravisit::{ - Visitor, walk_fn_decl, walk_generic_arg, walk_generics, walk_impl_item_ref, walk_item, walk_param_bound, + Visitor, walk_fn_decl, walk_generic_args, walk_generics, walk_impl_item_ref, walk_item, walk_param_bound, walk_poly_trait_ref, walk_trait_ref, walk_ty, walk_where_predicate, }; use rustc_hir::{ - BareFnTy, BodyId, FnDecl, FnSig, GenericArg, GenericBound, GenericParam, GenericParamKind, Generics, Impl, - ImplItem, ImplItemKind, Item, ItemKind, Lifetime, LifetimeName, LifetimeParamKind, Node, PolyTraitRef, + BareFnTy, BodyId, FnDecl, FnSig, GenericArg, GenericArgs, GenericBound, GenericParam, GenericParamKind, Generics, + Impl, ImplItem, ImplItemKind, Item, ItemKind, Lifetime, LifetimeName, LifetimeParamKind, Node, PolyTraitRef, PredicateOrigin, TraitFn, TraitItem, TraitItemKind, Ty, TyKind, WherePredicate, lang_items, }; use rustc_lint::{LateContext, LateLintPass, LintContext}; @@ -494,14 +494,14 @@ fn has_where_lifetimes<'tcx>(cx: &LateContext<'tcx>, generics: &'tcx Generics<'_ struct Usage { lifetime: Lifetime, in_where_predicate: bool, - in_generic_arg: bool, + in_generics_arg: bool, } struct LifetimeChecker<'cx, 'tcx, F> { cx: &'cx LateContext<'tcx>, map: FxHashMap>, where_predicate_depth: usize, - generic_arg_depth: usize, + generic_args_depth: usize, phantom: std::marker::PhantomData, } @@ -512,7 +512,7 @@ impl<'cx, 'tcx, F> LifetimeChecker<'cx, 'tcx, F> { cx, map, where_predicate_depth: 0, - generic_arg_depth: 0, + generic_args_depth: 0, phantom: std::marker::PhantomData, } } @@ -533,7 +533,7 @@ where usages.push(Usage { lifetime: *lifetime, in_where_predicate: self.where_predicate_depth != 0, - in_generic_arg: self.generic_arg_depth != 0, + in_generics_arg: self.generic_args_depth != 0, }); } } @@ -544,10 +544,10 @@ where self.where_predicate_depth -= 1; } - fn visit_generic_arg(&mut self, generic_arg: &'tcx GenericArg<'tcx>) -> Self::Result { - self.generic_arg_depth += 1; - walk_generic_arg(self, generic_arg); - self.generic_arg_depth -= 1; + fn visit_generic_args(&mut self, generic_args: &'tcx GenericArgs<'tcx>) -> Self::Result { + self.generic_args_depth += 1; + walk_generic_args(self, generic_args); + self.generic_args_depth -= 1; } fn nested_visit_map(&mut self) -> Self::Map { @@ -574,7 +574,7 @@ fn report_extra_lifetimes<'tcx>(cx: &LateContext<'tcx>, func: &'tcx FnDecl<'_>, for (def_id, usages) in checker.map { if usages .iter() - .all(|usage| usage.in_where_predicate && !usage.in_generic_arg) + .all(|usage| usage.in_where_predicate && !usage.in_generics_arg) { span_lint( cx, @@ -612,7 +612,7 @@ fn report_extra_impl_lifetimes<'tcx>(cx: &LateContext<'tcx>, impl_: &'tcx Impl<' for (&def_id, usages) in &checker.map { if usages .iter() - .all(|usage| usage.in_where_predicate && !usage.in_generic_arg) + .all(|usage| usage.in_where_predicate && !usage.in_generics_arg) { span_lint( cx, @@ -646,7 +646,7 @@ fn report_elidable_impl_lifetimes<'tcx>( } | Usage { lifetime, - in_generic_arg: false, + in_generics_arg: false, .. }, ] = usages.as_slice() diff --git a/tests/ui/needless_lifetimes.fixed b/tests/ui/needless_lifetimes.fixed index 7ded5b4234c..cfa4cf9da3c 100644 --- a/tests/ui/needless_lifetimes.fixed +++ b/tests/ui/needless_lifetimes.fixed @@ -543,4 +543,23 @@ mod issue5787 { } } +// https://github.com/rust-lang/rust-clippy/pull/13286#issuecomment-2374245772 +mod rayon { + trait ParallelIterator { + type Item; + } + + struct Copied { + base: I, + } + + impl<'a, T, I> ParallelIterator for Copied + where + I: ParallelIterator, + T: 'a + Copy + Send + Sync, + { + type Item = T; + } +} + fn main() {} diff --git a/tests/ui/needless_lifetimes.rs b/tests/ui/needless_lifetimes.rs index 8b3a885f4a3..5e9d5116426 100644 --- a/tests/ui/needless_lifetimes.rs +++ b/tests/ui/needless_lifetimes.rs @@ -543,4 +543,23 @@ mod issue5787 { } } +// https://github.com/rust-lang/rust-clippy/pull/13286#issuecomment-2374245772 +mod rayon { + trait ParallelIterator { + type Item; + } + + struct Copied { + base: I, + } + + impl<'a, T, I> ParallelIterator for Copied + where + I: ParallelIterator, + T: 'a + Copy + Send + Sync, + { + type Item = T; + } +} + fn main() {} From a51b0a2adf0197dbe569f1eb83dbf1caa11096ca Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Wed, 25 Sep 2024 16:40:50 -0700 Subject: [PATCH 274/683] Use `mem::offset_of!` for `sockaddr_un.sun_path` --- library/std/src/os/unix/net/addr.rs | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/library/std/src/os/unix/net/addr.rs b/library/std/src/os/unix/net/addr.rs index 79f2c365025..dcc1b5999dc 100644 --- a/library/std/src/os/unix/net/addr.rs +++ b/library/std/src/os/unix/net/addr.rs @@ -18,12 +18,7 @@ mod libc { pub struct sockaddr_un; } -fn sun_path_offset(addr: &libc::sockaddr_un) -> usize { - // Work with an actual instance of the type since using a null pointer is UB - let base = (addr as *const libc::sockaddr_un).addr(); - let path = core::ptr::addr_of!(addr.sun_path).addr(); - path - base -} +const SUN_PATH_OFFSET: usize = mem::offset_of!(libc::sockaddr_un, sun_path); pub(super) fn sockaddr_un(path: &Path) -> io::Result<(libc::sockaddr_un, libc::socklen_t)> { // SAFETY: All zeros is a valid representation for `sockaddr_un`. @@ -53,7 +48,7 @@ pub(super) fn sockaddr_un(path: &Path) -> io::Result<(libc::sockaddr_un, libc::s ptr::copy_nonoverlapping(bytes.as_ptr(), addr.sun_path.as_mut_ptr().cast(), bytes.len()) }; - let mut len = sun_path_offset(&addr) + bytes.len(); + let mut len = SUN_PATH_OFFSET + bytes.len(); match bytes.get(0) { Some(&0) | None => {} Some(_) => len += 1, @@ -114,13 +109,13 @@ impl SocketAddr { let sun_path: &[u8] = unsafe { mem::transmute::<&[libc::c_char], &[u8]>(&addr.sun_path) }; len = core::slice::memchr::memchr(0, sun_path) - .map_or(len, |new_len| (new_len + sun_path_offset(&addr)) as libc::socklen_t); + .map_or(len, |new_len| (new_len + SUN_PATH_OFFSET) as libc::socklen_t); } if len == 0 { // When there is a datagram from unnamed unix socket // linux returns zero bytes of address - len = sun_path_offset(&addr) as libc::socklen_t; // i.e., zero-length address + len = SUN_PATH_OFFSET as libc::socklen_t; // i.e., zero-length address } else if addr.sun_family != libc::AF_UNIX as libc::sa_family_t { return Err(io::const_io_error!( io::ErrorKind::InvalidInput, @@ -238,7 +233,7 @@ impl SocketAddr { } fn address(&self) -> AddressKind<'_> { - let len = self.len as usize - sun_path_offset(&self.addr); + let len = self.len as usize - SUN_PATH_OFFSET; let path = unsafe { mem::transmute::<&[libc::c_char], &[u8]>(&self.addr.sun_path) }; // macOS seems to return a len of 16 and a zeroed sun_path for unnamed addresses @@ -287,7 +282,7 @@ impl linux_ext::addr::SocketAddrExt for SocketAddr { addr.sun_path.as_mut_ptr().add(1) as *mut u8, name.len(), ); - let len = (sun_path_offset(&addr) + 1 + name.len()) as libc::socklen_t; + let len = (SUN_PATH_OFFSET + 1 + name.len()) as libc::socklen_t; SocketAddr::from_parts(addr, len) } } From f4d9d1a0eaf7e5de8c368ac5af500adf9e06f6e7 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Wed, 25 Sep 2024 17:03:20 -0700 Subject: [PATCH 275/683] Use `&raw` in the standard library Since the stabilization in #127679 has reached stage0, 1.82-beta, we can start using `&raw` freely, and even the soft-deprecated `ptr::addr_of!` and `ptr::addr_of_mut!` can stop allowing the unstable feature. I intentionally did not change any documentation or tests, but the rest of those macro uses are all now using `&raw const` or `&raw mut` in the standard library. --- library/alloc/src/boxed.rs | 10 +++--- library/alloc/src/boxed/thin.rs | 2 +- library/alloc/src/collections/btree/node.rs | 10 +++--- library/alloc/src/rc.rs | 26 ++++++-------- library/alloc/src/sync.rs | 22 ++++++------ library/alloc/src/vec/into_iter.rs | 4 +-- library/core/src/ffi/c_str.rs | 4 +-- library/core/src/iter/adapters/filter_map.rs | 3 +- library/core/src/ptr/mod.rs | 4 +-- library/core/src/slice/iter.rs | 2 +- library/core/src/slice/iter/macros.rs | 6 ++-- library/core/src/slice/mod.rs | 4 +-- library/panic_unwind/src/emcc.rs | 2 +- library/panic_unwind/src/gcc.rs | 2 +- library/panic_unwind/src/seh.rs | 33 ++++++++--------- library/std/src/ffi/os_str.rs | 3 +- library/std/src/fs/tests.rs | 2 +- library/std/src/os/unix/net/addr.rs | 2 +- library/std/src/os/unix/net/ancillary.rs | 4 +-- library/std/src/os/unix/net/datagram.rs | 12 +++---- library/std/src/os/unix/net/listener.rs | 10 ++---- library/std/src/os/unix/net/stream.rs | 4 +-- library/std/src/os/unix/net/ucred.rs | 4 +-- library/std/src/panicking.rs | 2 +- library/std/src/path.rs | 2 +- library/std/src/sync/mpmc/zero.rs | 12 ++----- library/std/src/sys/os_str/bytes.rs | 3 +- library/std/src/sys/os_str/wtf8.rs | 3 +- library/std/src/sys/pal/hermit/net.rs | 4 +-- library/std/src/sys/pal/hermit/time.rs | 6 ++-- library/std/src/sys/pal/unix/fs.rs | 8 ++--- library/std/src/sys/pal/unix/net.rs | 2 +- library/std/src/sys/pal/unix/os.rs | 2 +- .../sys/pal/unix/process/process_fuchsia.rs | 4 +-- .../src/sys/pal/unix/process/process_unix.rs | 12 +++---- .../std/src/sys/pal/unix/stack_overflow.rs | 4 +-- library/std/src/sys/pal/unix/thread.rs | 6 ++-- library/std/src/sys/pal/windows/api.rs | 3 +- library/std/src/sys/pal/windows/fs.rs | 36 +++++++++---------- library/std/src/sys/pal/windows/futex.rs | 2 +- library/std/src/sys/pal/windows/io.rs | 2 +- library/std/src/sys/pal/windows/net.rs | 2 +- library/std/src/sys/pal/windows/pipe.rs | 2 +- library/std/src/sys/pal/windows/process.rs | 6 ++-- .../src/sys/sync/thread_parking/pthread.rs | 11 +++--- .../src/sys/sync/thread_parking/windows7.rs | 2 +- .../thread_local/destructors/linux_like.rs | 2 +- library/std/src/sys_common/net.rs | 8 ++--- library/std/src/sys_common/wtf8.rs | 3 +- library/std/src/thread/mod.rs | 7 ++-- library/unwind/src/libunwind.rs | 4 +-- 51 files changed, 150 insertions(+), 185 deletions(-) diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs index f61a484499f..6421504b896 100644 --- a/library/alloc/src/boxed.rs +++ b/library/alloc/src/boxed.rs @@ -199,7 +199,7 @@ use core::ops::{ DerefPure, DispatchFromDyn, Receiver, }; use core::pin::{Pin, PinCoerceUnsized}; -use core::ptr::{self, NonNull, Unique, addr_of_mut}; +use core::ptr::{self, NonNull, Unique}; use core::task::{Context, Poll}; use core::{borrow, fmt, slice}; @@ -1277,7 +1277,7 @@ impl Box { #[inline] pub fn into_raw(b: Self) -> *mut T { // Make sure Miri realizes that we transition from a noalias pointer to a raw pointer here. - unsafe { addr_of_mut!(*&mut *Self::into_raw_with_allocator(b).0) } + unsafe { &raw mut *&mut *Self::into_raw_with_allocator(b).0 } } /// Consumes the `Box`, returning a wrapped `NonNull` pointer. @@ -1396,7 +1396,7 @@ impl Box { // want *no* aliasing requirements here! // In case `A` *is* `Global`, this does not quite have the right behavior; `into_raw` // works around that. - let ptr = addr_of_mut!(**b); + let ptr = &raw mut **b; let alloc = unsafe { ptr::read(&b.1) }; (ptr, alloc) } @@ -1506,7 +1506,7 @@ impl Box { pub fn as_mut_ptr(b: &mut Self) -> *mut T { // This is a primitive deref, not going through `DerefMut`, and therefore not materializing // any references. - ptr::addr_of_mut!(**b) + &raw mut **b } /// Returns a raw pointer to the `Box`'s contents. @@ -1554,7 +1554,7 @@ impl Box { pub fn as_ptr(b: &Self) -> *const T { // This is a primitive deref, not going through `DerefMut`, and therefore not materializing // any references. - ptr::addr_of!(**b) + &raw const **b } /// Returns a reference to the underlying allocator. diff --git a/library/alloc/src/boxed/thin.rs b/library/alloc/src/boxed/thin.rs index 9baded3a521..78e5aec09b1 100644 --- a/library/alloc/src/boxed/thin.rs +++ b/library/alloc/src/boxed/thin.rs @@ -186,7 +186,7 @@ impl ThinBox { fn with_header(&self) -> &WithHeader<::Metadata> { // SAFETY: both types are transparent to `NonNull` - unsafe { &*(core::ptr::addr_of!(self.ptr) as *const WithHeader<_>) } + unsafe { &*((&raw const self.ptr) as *const WithHeader<_>) } } } diff --git a/library/alloc/src/collections/btree/node.rs b/library/alloc/src/collections/btree/node.rs index 78ccb3af66d..5c513d34fc9 100644 --- a/library/alloc/src/collections/btree/node.rs +++ b/library/alloc/src/collections/btree/node.rs @@ -72,8 +72,8 @@ impl LeafNode { // be both slightly faster and easier to track in Valgrind. unsafe { // parent_idx, keys, and vals are all MaybeUninit - ptr::addr_of_mut!((*this).parent).write(None); - ptr::addr_of_mut!((*this).len).write(0); + (&raw mut (*this).parent).write(None); + (&raw mut (*this).len).write(0); } } @@ -114,7 +114,7 @@ impl InternalNode { unsafe { let mut node = Box::::new_uninit_in(alloc); // We only need to initialize the data; the edges are MaybeUninit. - LeafNode::init(ptr::addr_of_mut!((*node.as_mut_ptr()).data)); + LeafNode::init(&raw mut (*node.as_mut_ptr()).data); node.assume_init() } } @@ -525,8 +525,8 @@ impl<'a, K, V, Type> NodeRef, K, V, Type> { // to avoid aliasing with outstanding references to other elements, // in particular, those returned to the caller in earlier iterations. let leaf = Self::as_leaf_ptr(&mut self); - let keys = unsafe { ptr::addr_of!((*leaf).keys) }; - let vals = unsafe { ptr::addr_of_mut!((*leaf).vals) }; + let keys = unsafe { &raw const (*leaf).keys }; + let vals = unsafe { &raw mut (*leaf).vals }; // We must coerce to unsized array pointers because of Rust issue #74679. let keys: *const [_] = keys; let vals: *mut [_] = vals; diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index 54669bd310a..0e2c35845e8 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -787,7 +787,7 @@ impl Rc { let strong = unsafe { let inner = init_ptr.as_ptr(); - ptr::write(ptr::addr_of_mut!((*inner).value), data); + ptr::write(&raw mut (*inner).value, data); let prev_value = (*inner).strong.get(); debug_assert_eq!(prev_value, 0, "No prior strong references should exist"); @@ -1442,7 +1442,7 @@ impl Rc { // SAFETY: This cannot go through Deref::deref or Rc::inner because // this is required to retain raw/mut provenance such that e.g. `get_mut` can // write through the pointer after the Rc is recovered through `from_raw`. - unsafe { ptr::addr_of_mut!((*ptr).value) } + unsafe { &raw mut (*ptr).value } } /// Constructs an `Rc` from a raw pointer in the provided allocator. @@ -2042,8 +2042,8 @@ impl Rc { unsafe { debug_assert_eq!(Layout::for_value_raw(inner), layout); - ptr::addr_of_mut!((*inner).strong).write(Cell::new(1)); - ptr::addr_of_mut!((*inner).weak).write(Cell::new(1)); + (&raw mut (*inner).strong).write(Cell::new(1)); + (&raw mut (*inner).weak).write(Cell::new(1)); } Ok(inner) @@ -2072,8 +2072,8 @@ impl Rc { // Copy value as bytes ptr::copy_nonoverlapping( - core::ptr::addr_of!(*src) as *const u8, - ptr::addr_of_mut!((*ptr).value) as *mut u8, + (&raw const *src) as *const u8, + (&raw mut (*ptr).value) as *mut u8, value_size, ); @@ -2107,11 +2107,7 @@ impl Rc<[T]> { unsafe fn copy_from_slice(v: &[T]) -> Rc<[T]> { unsafe { let ptr = Self::allocate_for_slice(v.len()); - ptr::copy_nonoverlapping( - v.as_ptr(), - ptr::addr_of_mut!((*ptr).value) as *mut T, - v.len(), - ); + ptr::copy_nonoverlapping(v.as_ptr(), (&raw mut (*ptr).value) as *mut T, v.len()); Self::from_ptr(ptr) } } @@ -2149,7 +2145,7 @@ impl Rc<[T]> { let layout = Layout::for_value_raw(ptr); // Pointer to first element - let elems = ptr::addr_of_mut!((*ptr).value) as *mut T; + let elems = (&raw mut (*ptr).value) as *mut T; let mut guard = Guard { mem: NonNull::new_unchecked(mem), elems, layout, n_elems: 0 }; @@ -2577,7 +2573,7 @@ impl fmt::Debug for Rc { #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Pointer for Rc { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Pointer::fmt(&core::ptr::addr_of!(**self), f) + fmt::Pointer::fmt(&(&raw const **self), f) } } @@ -2718,7 +2714,7 @@ impl From> for Rc<[T], A> { let (vec_ptr, len, cap, alloc) = v.into_raw_parts_with_alloc(); let rc_ptr = Self::allocate_for_slice_in(len, &alloc); - ptr::copy_nonoverlapping(vec_ptr, ptr::addr_of_mut!((*rc_ptr).value) as *mut T, len); + ptr::copy_nonoverlapping(vec_ptr, (&raw mut (*rc_ptr).value) as *mut T, len); // Create a `Vec` with length 0, to deallocate the buffer // without dropping its contents or the allocator @@ -3084,7 +3080,7 @@ impl Weak { // SAFETY: if is_dangling returns false, then the pointer is dereferenceable. // The payload may be dropped at this point, and we have to maintain provenance, // so use raw pointer manipulation. - unsafe { ptr::addr_of_mut!((*ptr).value) } + unsafe { &raw mut (*ptr).value } } } diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index 50886244d58..ced789c4f92 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -797,7 +797,7 @@ impl Arc { // reference into a strong reference. let strong = unsafe { let inner = init_ptr.as_ptr(); - ptr::write(ptr::addr_of_mut!((*inner).data), data); + ptr::write(&raw mut (*inner).data, data); // The above write to the data field must be visible to any threads which // observe a non-zero strong count. Therefore we need at least "Release" ordering @@ -1583,7 +1583,7 @@ impl Arc { // SAFETY: This cannot go through Deref::deref or RcBoxPtr::inner because // this is required to retain raw/mut provenance such that e.g. `get_mut` can // write through the pointer after the Rc is recovered through `from_raw`. - unsafe { ptr::addr_of_mut!((*ptr).data) } + unsafe { &raw mut (*ptr).data } } /// Constructs an `Arc` from a raw pointer. @@ -1955,8 +1955,8 @@ impl Arc { debug_assert_eq!(unsafe { Layout::for_value_raw(inner) }, layout); unsafe { - ptr::addr_of_mut!((*inner).strong).write(atomic::AtomicUsize::new(1)); - ptr::addr_of_mut!((*inner).weak).write(atomic::AtomicUsize::new(1)); + (&raw mut (*inner).strong).write(atomic::AtomicUsize::new(1)); + (&raw mut (*inner).weak).write(atomic::AtomicUsize::new(1)); } inner @@ -1986,8 +1986,8 @@ impl Arc { // Copy value as bytes ptr::copy_nonoverlapping( - core::ptr::addr_of!(*src) as *const u8, - ptr::addr_of_mut!((*ptr).data) as *mut u8, + (&raw const *src) as *const u8, + (&raw mut (*ptr).data) as *mut u8, value_size, ); @@ -2022,7 +2022,7 @@ impl Arc<[T]> { unsafe { let ptr = Self::allocate_for_slice(v.len()); - ptr::copy_nonoverlapping(v.as_ptr(), ptr::addr_of_mut!((*ptr).data) as *mut T, v.len()); + ptr::copy_nonoverlapping(v.as_ptr(), (&raw mut (*ptr).data) as *mut T, v.len()); Self::from_ptr(ptr) } @@ -2061,7 +2061,7 @@ impl Arc<[T]> { let layout = Layout::for_value_raw(ptr); // Pointer to first element - let elems = ptr::addr_of_mut!((*ptr).data) as *mut T; + let elems = (&raw mut (*ptr).data) as *mut T; let mut guard = Guard { mem: NonNull::new_unchecked(mem), elems, layout, n_elems: 0 }; @@ -2805,7 +2805,7 @@ impl Weak { // SAFETY: if is_dangling returns false, then the pointer is dereferenceable. // The payload may be dropped at this point, and we have to maintain provenance, // so use raw pointer manipulation. - unsafe { ptr::addr_of_mut!((*ptr).data) } + unsafe { &raw mut (*ptr).data } } } @@ -3428,7 +3428,7 @@ impl fmt::Debug for Arc { #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Pointer for Arc { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Pointer::fmt(&core::ptr::addr_of!(**self), f) + fmt::Pointer::fmt(&(&raw const **self), f) } } @@ -3678,7 +3678,7 @@ impl From> for Arc<[T], A> { let (vec_ptr, len, cap, alloc) = v.into_raw_parts_with_alloc(); let rc_ptr = Self::allocate_for_slice_in(len, &alloc); - ptr::copy_nonoverlapping(vec_ptr, ptr::addr_of_mut!((*rc_ptr).data) as *mut T, len); + ptr::copy_nonoverlapping(vec_ptr, (&raw mut (*rc_ptr).data) as *mut T, len); // Create a `Vec` with length 0, to deallocate the buffer // without dropping its contents or the allocator diff --git a/library/alloc/src/vec/into_iter.rs b/library/alloc/src/vec/into_iter.rs index f7aad56695d..9a6745fdbc0 100644 --- a/library/alloc/src/vec/into_iter.rs +++ b/library/alloc/src/vec/into_iter.rs @@ -21,11 +21,11 @@ use crate::raw_vec::RawVec; macro non_null { (mut $place:expr, $t:ident) => {{ #![allow(unused_unsafe)] // we're sometimes used within an unsafe block - unsafe { &mut *(ptr::addr_of_mut!($place) as *mut NonNull<$t>) } + unsafe { &mut *((&raw mut $place) as *mut NonNull<$t>) } }}, ($place:expr, $t:ident) => {{ #![allow(unused_unsafe)] // we're sometimes used within an unsafe block - unsafe { *(ptr::addr_of!($place) as *const NonNull<$t>) } + unsafe { *((&raw const $place) as *const NonNull<$t>) } }}, } diff --git a/library/core/src/ffi/c_str.rs b/library/core/src/ffi/c_str.rs index 930f8a76620..15b00b9aa44 100644 --- a/library/core/src/ffi/c_str.rs +++ b/library/core/src/ffi/c_str.rs @@ -5,7 +5,7 @@ use crate::error::Error; use crate::ffi::c_char; use crate::iter::FusedIterator; use crate::marker::PhantomData; -use crate::ptr::{NonNull, addr_of}; +use crate::ptr::NonNull; use crate::slice::memchr; use crate::{fmt, intrinsics, ops, slice, str}; @@ -623,7 +623,7 @@ impl CStr { pub const fn to_bytes_with_nul(&self) -> &[u8] { // SAFETY: Transmuting a slice of `c_char`s to a slice of `u8`s // is safe on all supported targets. - unsafe { &*(addr_of!(self.inner) as *const [u8]) } + unsafe { &*((&raw const self.inner) as *const [u8]) } } /// Iterates over the bytes in this C string. diff --git a/library/core/src/iter/adapters/filter_map.rs b/library/core/src/iter/adapters/filter_map.rs index 914ef613177..cc64ceb13f7 100644 --- a/library/core/src/iter/adapters/filter_map.rs +++ b/library/core/src/iter/adapters/filter_map.rs @@ -3,7 +3,6 @@ use crate::iter::{FusedIterator, InPlaceIterable, TrustedFused}; use crate::mem::{ManuallyDrop, MaybeUninit}; use crate::num::NonZero; use crate::ops::{ControlFlow, Try}; -use crate::ptr::addr_of; use crate::{array, fmt}; /// An iterator that uses `f` to both filter and map elements from `iter`. @@ -101,7 +100,7 @@ where unsafe { let opt_payload_at: *const MaybeUninit = - addr_of!(val).byte_add(core::mem::offset_of!(Option, Some.0)).cast(); + (&raw const val).byte_add(core::mem::offset_of!(Option, Some.0)).cast(); let dst = guard.array.as_mut_ptr().add(idx); crate::ptr::copy_nonoverlapping(opt_payload_at, dst, 1); crate::mem::forget(val); diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs index cac33a329b9..4f97048eab1 100644 --- a/library/core/src/ptr/mod.rs +++ b/library/core/src/ptr/mod.rs @@ -1730,7 +1730,7 @@ pub const unsafe fn write_unaligned(dst: *mut T, src: T) { // `dst` cannot overlap `src` because the caller has mutable access // to `dst` while `src` is owned by this function. unsafe { - copy_nonoverlapping(addr_of!(src) as *const u8, dst as *mut u8, mem::size_of::()); + copy_nonoverlapping((&raw const src) as *const u8, dst as *mut u8, mem::size_of::()); // We are calling the intrinsic directly to avoid function calls in the generated code. intrinsics::forget(src); } @@ -2348,7 +2348,6 @@ impl fmt::Debug for F { /// no difference whether the pointer is null or dangling.) #[stable(feature = "raw_ref_macros", since = "1.51.0")] #[rustc_macro_transparency = "semitransparent"] -#[allow_internal_unstable(raw_ref_op)] pub macro addr_of($place:expr) { &raw const $place } @@ -2439,7 +2438,6 @@ pub macro addr_of($place:expr) { /// makes no difference whether the pointer is null or dangling.) #[stable(feature = "raw_ref_macros", since = "1.51.0")] #[rustc_macro_transparency = "semitransparent"] -#[allow_internal_unstable(raw_ref_op)] pub macro addr_of_mut($place:expr) { &raw mut $place } diff --git a/library/core/src/slice/iter.rs b/library/core/src/slice/iter.rs index 1168f36da15..c5746157d01 100644 --- a/library/core/src/slice/iter.rs +++ b/library/core/src/slice/iter.rs @@ -11,7 +11,7 @@ use crate::iter::{ use crate::marker::PhantomData; use crate::mem::{self, SizedTypeProperties}; use crate::num::NonZero; -use crate::ptr::{self, NonNull, without_provenance, without_provenance_mut}; +use crate::ptr::{NonNull, without_provenance, without_provenance_mut}; use crate::{cmp, fmt}; #[stable(feature = "boxed_slice_into_iter", since = "1.80.0")] diff --git a/library/core/src/slice/iter/macros.rs b/library/core/src/slice/iter/macros.rs index c2a38194644..830debe02ea 100644 --- a/library/core/src/slice/iter/macros.rs +++ b/library/core/src/slice/iter/macros.rs @@ -14,11 +14,11 @@ macro_rules! if_zst { if T::IS_ZST { // SAFETY: for ZSTs, the pointer is storing a provenance-free length, // so consuming and updating it as a `usize` is fine. - let $len = unsafe { &mut *ptr::addr_of_mut!($this.end_or_len).cast::() }; + let $len = unsafe { &mut *(&raw mut $this.end_or_len).cast::() }; $zst_body } else { // SAFETY: for non-ZSTs, the type invariant ensures it cannot be null - let $end = unsafe { &mut *ptr::addr_of_mut!($this.end_or_len).cast::>() }; + let $end = unsafe { &mut *(&raw mut $this.end_or_len).cast::>() }; $other_body } }}; @@ -30,7 +30,7 @@ macro_rules! if_zst { $zst_body } else { // SAFETY: for non-ZSTs, the type invariant ensures it cannot be null - let $end = unsafe { *ptr::addr_of!($this.end_or_len).cast::>() }; + let $end = unsafe { *(&raw const $this.end_or_len).cast::>() }; $other_body } }}; diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 11c9f483f36..dd8fa1ae343 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -883,8 +883,8 @@ impl [T] { pub const fn swap(&mut self, a: usize, b: usize) { // FIXME: use swap_unchecked here (https://github.com/rust-lang/rust/pull/88540#issuecomment-944344343) // Can't take two mutable loans from one vector, so instead use raw pointers. - let pa = ptr::addr_of_mut!(self[a]); - let pb = ptr::addr_of_mut!(self[b]); + let pa = &raw mut self[a]; + let pb = &raw mut self[b]; // SAFETY: `pa` and `pb` have been created from safe mutable references and refer // to elements in the slice and therefore are guaranteed to be valid and aligned. // Note that accessing the elements behind `a` and `b` is checked and will diff --git a/library/panic_unwind/src/emcc.rs b/library/panic_unwind/src/emcc.rs index a4cbb1875d5..b986fc1c2a8 100644 --- a/library/panic_unwind/src/emcc.rs +++ b/library/panic_unwind/src/emcc.rs @@ -78,7 +78,7 @@ pub unsafe fn cleanup(ptr: *mut u8) -> Box { super::__rust_foreign_exception(); } - let canary = ptr::addr_of!((*adjusted_ptr).canary).read(); + let canary = (&raw const (*adjusted_ptr).canary).read(); if !ptr::eq(canary, &EXCEPTION_TYPE_INFO) { super::__rust_foreign_exception(); } diff --git a/library/panic_unwind/src/gcc.rs b/library/panic_unwind/src/gcc.rs index d8c1dcaaefe..89b44338d6b 100644 --- a/library/panic_unwind/src/gcc.rs +++ b/library/panic_unwind/src/gcc.rs @@ -92,7 +92,7 @@ pub unsafe fn cleanup(ptr: *mut u8) -> Box { let exception = exception.cast::(); // Just access the canary field, avoid accessing the entire `Exception` as // it can be a foreign Rust exception. - let canary = ptr::addr_of!((*exception).canary).read(); + let canary = (&raw const (*exception).canary).read(); if !ptr::eq(canary, &CANARY) { // A foreign Rust exception, treat it slightly differently from other // foreign exceptions, because call into `_Unwind_DeleteException` will diff --git a/library/panic_unwind/src/seh.rs b/library/panic_unwind/src/seh.rs index 9e74a45a0e2..565a2b8c573 100644 --- a/library/panic_unwind/src/seh.rs +++ b/library/panic_unwind/src/seh.rs @@ -50,7 +50,6 @@ use alloc::boxed::Box; use core::any::Any; use core::ffi::{c_int, c_uint, c_void}; use core::mem::{self, ManuallyDrop}; -use core::ptr::{addr_of, addr_of_mut}; // NOTE(nbdd0121): The `canary` field is part of stable ABI. #[repr(C)] @@ -131,8 +130,6 @@ mod imp { #[cfg(not(target_arch = "x86"))] mod imp { - use core::ptr::addr_of; - // On 64-bit systems, SEH represents pointers as 32-bit offsets from `__ImageBase`. #[repr(transparent)] #[derive(Copy, Clone)] @@ -157,7 +154,7 @@ mod imp { // going to be cross-lang LTOed anyway. However, using expose is shorter and // requires less unsafe. let addr: usize = ptr.expose_provenance(); - let image_base = addr_of!(__ImageBase).addr(); + let image_base = (&raw const __ImageBase).addr(); let offset: usize = addr - image_base; Self(offset as u32) } @@ -250,7 +247,7 @@ extern "C" { // This is fine since the MSVC runtime uses string comparison on the type name // to match TypeDescriptors rather than pointer equality. static mut TYPE_DESCRIPTOR: _TypeDescriptor = _TypeDescriptor { - pVFTable: addr_of!(TYPE_INFO_VTABLE) as *const _, + pVFTable: (&raw const TYPE_INFO_VTABLE) as *const _, spare: core::ptr::null_mut(), name: TYPE_NAME, }; @@ -304,8 +301,8 @@ pub unsafe fn panic(data: Box) -> u32 { // dropped when unwinding. Instead it will be dropped by exception_cleanup // which is invoked by the C++ runtime. let mut exception = - ManuallyDrop::new(Exception { canary: addr_of!(TYPE_DESCRIPTOR), data: Some(data) }); - let throw_ptr = addr_of_mut!(exception) as *mut _; + ManuallyDrop::new(Exception { canary: (&raw const TYPE_DESCRIPTOR), data: Some(data) }); + let throw_ptr = (&raw mut exception) as *mut _; // This... may seems surprising, and justifiably so. On 32-bit MSVC the // pointers between these structure are just that, pointers. On 64-bit MSVC, @@ -328,23 +325,23 @@ pub unsafe fn panic(data: Box) -> u32 { // In any case, we basically need to do something like this until we can // express more operations in statics (and we may never be able to). atomic_store_seqcst( - addr_of_mut!(THROW_INFO.pmfnUnwind).cast(), + (&raw mut THROW_INFO.pmfnUnwind).cast(), ptr_t::new(exception_cleanup as *mut u8).raw(), ); atomic_store_seqcst( - addr_of_mut!(THROW_INFO.pCatchableTypeArray).cast(), - ptr_t::new(addr_of_mut!(CATCHABLE_TYPE_ARRAY).cast()).raw(), + (&raw mut THROW_INFO.pCatchableTypeArray).cast(), + ptr_t::new((&raw mut CATCHABLE_TYPE_ARRAY).cast()).raw(), ); atomic_store_seqcst( - addr_of_mut!(CATCHABLE_TYPE_ARRAY.arrayOfCatchableTypes[0]).cast(), - ptr_t::new(addr_of_mut!(CATCHABLE_TYPE).cast()).raw(), + (&raw mut CATCHABLE_TYPE_ARRAY.arrayOfCatchableTypes[0]).cast(), + ptr_t::new((&raw mut CATCHABLE_TYPE).cast()).raw(), ); atomic_store_seqcst( - addr_of_mut!(CATCHABLE_TYPE.pType).cast(), - ptr_t::new(addr_of_mut!(TYPE_DESCRIPTOR).cast()).raw(), + (&raw mut CATCHABLE_TYPE.pType).cast(), + ptr_t::new((&raw mut TYPE_DESCRIPTOR).cast()).raw(), ); atomic_store_seqcst( - addr_of_mut!(CATCHABLE_TYPE.copyFunction).cast(), + (&raw mut CATCHABLE_TYPE.copyFunction).cast(), ptr_t::new(exception_copy as *mut u8).raw(), ); @@ -352,7 +349,7 @@ pub unsafe fn panic(data: Box) -> u32 { fn _CxxThrowException(pExceptionObject: *mut c_void, pThrowInfo: *mut u8) -> !; } - _CxxThrowException(throw_ptr, addr_of_mut!(THROW_INFO) as *mut _); + _CxxThrowException(throw_ptr, (&raw mut THROW_INFO) as *mut _); } pub unsafe fn cleanup(payload: *mut u8) -> Box { @@ -362,8 +359,8 @@ pub unsafe fn cleanup(payload: *mut u8) -> Box { super::__rust_foreign_exception(); } let exception = payload as *mut Exception; - let canary = addr_of!((*exception).canary).read(); - if !core::ptr::eq(canary, addr_of!(TYPE_DESCRIPTOR)) { + let canary = (&raw const (*exception).canary).read(); + if !core::ptr::eq(canary, &raw const TYPE_DESCRIPTOR) { // A foreign Rust exception. super::__rust_foreign_exception(); } diff --git a/library/std/src/ffi/os_str.rs b/library/std/src/ffi/os_str.rs index 0f905803bb8..2243f100643 100644 --- a/library/std/src/ffi/os_str.rs +++ b/library/std/src/ffi/os_str.rs @@ -9,7 +9,6 @@ use crate::borrow::{Borrow, Cow}; use crate::collections::TryReserveError; use crate::hash::{Hash, Hasher}; use crate::ops::{self, Range}; -use crate::ptr::addr_of_mut; use crate::rc::Rc; use crate::str::FromStr; use crate::sync::Arc; @@ -1272,7 +1271,7 @@ unsafe impl CloneToUninit for OsStr { #[cfg_attr(debug_assertions, track_caller)] unsafe fn clone_to_uninit(&self, dst: *mut Self) { // SAFETY: we're just a wrapper around a platform-specific Slice - unsafe { self.inner.clone_to_uninit(addr_of_mut!((*dst).inner)) } + unsafe { self.inner.clone_to_uninit(&raw mut (*dst).inner) } } } diff --git a/library/std/src/fs/tests.rs b/library/std/src/fs/tests.rs index 412603ddea3..0672fe6f771 100644 --- a/library/std/src/fs/tests.rs +++ b/library/std/src/fs/tests.rs @@ -1732,7 +1732,7 @@ fn windows_unix_socket_exists() { let bytes = core::slice::from_raw_parts(bytes.as_ptr().cast::(), bytes.len()); addr.sun_path[..bytes.len()].copy_from_slice(bytes); let len = mem::size_of_val(&addr) as i32; - let result = c::bind(socket, ptr::addr_of!(addr).cast::(), len); + let result = c::bind(socket, (&raw const addr).cast::(), len); c::closesocket(socket); assert_eq!(result, 0); } diff --git a/library/std/src/os/unix/net/addr.rs b/library/std/src/os/unix/net/addr.rs index 79f2c365025..d7b87d480b7 100644 --- a/library/std/src/os/unix/net/addr.rs +++ b/library/std/src/os/unix/net/addr.rs @@ -98,7 +98,7 @@ impl SocketAddr { unsafe { let mut addr: libc::sockaddr_un = mem::zeroed(); let mut len = mem::size_of::() as libc::socklen_t; - cvt(f(core::ptr::addr_of_mut!(addr) as *mut _, &mut len))?; + cvt(f((&raw mut addr) as *mut _, &mut len))?; SocketAddr::from_parts(addr, len) } } diff --git a/library/std/src/os/unix/net/ancillary.rs b/library/std/src/os/unix/net/ancillary.rs index c34a3b4e184..36967fc3f98 100644 --- a/library/std/src/os/unix/net/ancillary.rs +++ b/library/std/src/os/unix/net/ancillary.rs @@ -37,7 +37,7 @@ pub(super) fn recv_vectored_with_ancillary_from( unsafe { let mut msg_name: libc::sockaddr_un = zeroed(); let mut msg: libc::msghdr = zeroed(); - msg.msg_name = core::ptr::addr_of_mut!(msg_name) as *mut _; + msg.msg_name = (&raw mut msg_name) as *mut _; msg.msg_namelen = size_of::() as libc::socklen_t; msg.msg_iov = bufs.as_mut_ptr().cast(); msg.msg_iovlen = bufs.len() as _; @@ -70,7 +70,7 @@ pub(super) fn send_vectored_with_ancillary_to( if let Some(path) = path { sockaddr_un(path)? } else { (zeroed(), 0) }; let mut msg: libc::msghdr = zeroed(); - msg.msg_name = core::ptr::addr_of_mut!(msg_name) as *mut _; + msg.msg_name = (&raw mut msg_name) as *mut _; msg.msg_namelen = msg_namelen; msg.msg_iov = bufs.as_ptr() as *mut _; msg.msg_iovlen = bufs.len() as _; diff --git a/library/std/src/os/unix/net/datagram.rs b/library/std/src/os/unix/net/datagram.rs index 48aaddd2d52..82446ea107f 100644 --- a/library/std/src/os/unix/net/datagram.rs +++ b/library/std/src/os/unix/net/datagram.rs @@ -100,7 +100,7 @@ impl UnixDatagram { let socket = UnixDatagram::unbound()?; let (addr, len) = sockaddr_un(path.as_ref())?; - cvt(libc::bind(socket.as_raw_fd(), core::ptr::addr_of!(addr) as *const _, len as _))?; + cvt(libc::bind(socket.as_raw_fd(), (&raw const addr) as *const _, len as _))?; Ok(socket) } @@ -133,7 +133,7 @@ impl UnixDatagram { let socket = UnixDatagram::unbound()?; cvt(libc::bind( socket.as_raw_fd(), - core::ptr::addr_of!(socket_addr.addr) as *const _, + (&raw const socket_addr.addr) as *const _, socket_addr.len as _, ))?; Ok(socket) @@ -215,7 +215,7 @@ impl UnixDatagram { unsafe { let (addr, len) = sockaddr_un(path.as_ref())?; - cvt(libc::connect(self.as_raw_fd(), core::ptr::addr_of!(addr) as *const _, len))?; + cvt(libc::connect(self.as_raw_fd(), (&raw const addr) as *const _, len))?; } Ok(()) } @@ -247,7 +247,7 @@ impl UnixDatagram { unsafe { cvt(libc::connect( self.as_raw_fd(), - core::ptr::addr_of!(socket_addr.addr) as *const _, + (&raw const socket_addr.addr) as *const _, socket_addr.len, ))?; } @@ -514,7 +514,7 @@ impl UnixDatagram { buf.as_ptr() as *const _, buf.len(), MSG_NOSIGNAL, - core::ptr::addr_of!(addr) as *const _, + (&raw const addr) as *const _, len, ))?; Ok(count as usize) @@ -549,7 +549,7 @@ impl UnixDatagram { buf.as_ptr() as *const _, buf.len(), MSG_NOSIGNAL, - core::ptr::addr_of!(socket_addr.addr) as *const _, + (&raw const socket_addr.addr) as *const _, socket_addr.len, ))?; Ok(count as usize) diff --git a/library/std/src/os/unix/net/listener.rs b/library/std/src/os/unix/net/listener.rs index 440408eb13f..be236317d04 100644 --- a/library/std/src/os/unix/net/listener.rs +++ b/library/std/src/os/unix/net/listener.rs @@ -103,11 +103,7 @@ impl UnixListener { )))] const backlog: libc::c_int = libc::SOMAXCONN; - cvt(libc::bind( - inner.as_inner().as_raw_fd(), - core::ptr::addr_of!(addr) as *const _, - len as _, - ))?; + cvt(libc::bind(inner.as_inner().as_raw_fd(), (&raw const addr) as *const _, len as _))?; cvt(libc::listen(inner.as_inner().as_raw_fd(), backlog))?; Ok(UnixListener(inner)) @@ -147,7 +143,7 @@ impl UnixListener { const backlog: core::ffi::c_int = 128; cvt(libc::bind( inner.as_raw_fd(), - core::ptr::addr_of!(socket_addr.addr) as *const _, + (&raw const socket_addr.addr) as *const _, socket_addr.len as _, ))?; cvt(libc::listen(inner.as_raw_fd(), backlog))?; @@ -182,7 +178,7 @@ impl UnixListener { pub fn accept(&self) -> io::Result<(UnixStream, SocketAddr)> { let mut storage: libc::sockaddr_un = unsafe { mem::zeroed() }; let mut len = mem::size_of_val(&storage) as libc::socklen_t; - let sock = self.0.accept(core::ptr::addr_of_mut!(storage) as *mut _, &mut len)?; + let sock = self.0.accept((&raw mut storage) as *mut _, &mut len)?; let addr = SocketAddr::from_parts(storage, len)?; Ok((UnixStream(sock), addr)) } diff --git a/library/std/src/os/unix/net/stream.rs b/library/std/src/os/unix/net/stream.rs index 4967c5b89ec..cb210b41eae 100644 --- a/library/std/src/os/unix/net/stream.rs +++ b/library/std/src/os/unix/net/stream.rs @@ -84,7 +84,7 @@ impl UnixStream { let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?; let (addr, len) = sockaddr_un(path.as_ref())?; - cvt(libc::connect(inner.as_raw_fd(), core::ptr::addr_of!(addr) as *const _, len))?; + cvt(libc::connect(inner.as_raw_fd(), (&raw const addr) as *const _, len))?; Ok(UnixStream(inner)) } } @@ -118,7 +118,7 @@ impl UnixStream { let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?; cvt(libc::connect( inner.as_raw_fd(), - core::ptr::addr_of!(socket_addr.addr) as *const _, + (&raw const socket_addr.addr) as *const _, socket_addr.len, ))?; Ok(UnixStream(inner)) diff --git a/library/std/src/os/unix/net/ucred.rs b/library/std/src/os/unix/net/ucred.rs index c818bd05858..e1014a4f296 100644 --- a/library/std/src/os/unix/net/ucred.rs +++ b/library/std/src/os/unix/net/ucred.rs @@ -60,7 +60,7 @@ mod impl_linux { socket.as_raw_fd(), SOL_SOCKET, SO_PEERCRED, - core::ptr::addr_of_mut!(ucred) as *mut c_void, + (&raw mut ucred) as *mut c_void, &mut ucred_size, ); @@ -121,7 +121,7 @@ mod impl_apple { socket.as_raw_fd(), SOL_LOCAL, LOCAL_PEERPID, - core::ptr::addr_of_mut!(pid) as *mut c_void, + (&raw mut pid) as *mut c_void, &mut pid_size, ); diff --git a/library/std/src/panicking.rs b/library/std/src/panicking.rs index 336e34d7b95..9fe05db8126 100644 --- a/library/std/src/panicking.rs +++ b/library/std/src/panicking.rs @@ -506,7 +506,7 @@ pub unsafe fn r#try R>(f: F) -> Result> // method of calling a catch panic whilst juggling ownership. let mut data = Data { f: ManuallyDrop::new(f) }; - let data_ptr = core::ptr::addr_of_mut!(data) as *mut u8; + let data_ptr = (&raw mut data) as *mut u8; // SAFETY: // // Access to the union's fields: this is `std` and we know that the `r#try` diff --git a/library/std/src/path.rs b/library/std/src/path.rs index e3ff7d199cc..63edfdb82f3 100644 --- a/library/std/src/path.rs +++ b/library/std/src/path.rs @@ -3144,7 +3144,7 @@ unsafe impl CloneToUninit for Path { #[cfg_attr(debug_assertions, track_caller)] unsafe fn clone_to_uninit(&self, dst: *mut Self) { // SAFETY: Path is just a wrapper around OsStr - unsafe { self.inner.clone_to_uninit(core::ptr::addr_of_mut!((*dst).inner)) } + unsafe { self.inner.clone_to_uninit(&raw mut (*dst).inner) } } } diff --git a/library/std/src/sync/mpmc/zero.rs b/library/std/src/sync/mpmc/zero.rs index 2451d7b79d1..446881291e6 100644 --- a/library/std/src/sync/mpmc/zero.rs +++ b/library/std/src/sync/mpmc/zero.rs @@ -185,11 +185,7 @@ impl Channel { // Prepare for blocking until a receiver wakes us up. let oper = Operation::hook(token); let mut packet = Packet::::message_on_stack(msg); - inner.senders.register_with_packet( - oper, - core::ptr::addr_of_mut!(packet) as *mut (), - cx, - ); + inner.senders.register_with_packet(oper, (&raw mut packet) as *mut (), cx); inner.receivers.notify(); drop(inner); @@ -256,11 +252,7 @@ impl Channel { // Prepare for blocking until a sender wakes us up. let oper = Operation::hook(token); let mut packet = Packet::::empty_on_stack(); - inner.receivers.register_with_packet( - oper, - core::ptr::addr_of_mut!(packet) as *mut (), - cx, - ); + inner.receivers.register_with_packet(oper, (&raw mut packet) as *mut (), cx); inner.senders.notify(); drop(inner); diff --git a/library/std/src/sys/os_str/bytes.rs b/library/std/src/sys/os_str/bytes.rs index 992767211d0..8e0609fe48c 100644 --- a/library/std/src/sys/os_str/bytes.rs +++ b/library/std/src/sys/os_str/bytes.rs @@ -2,7 +2,6 @@ //! systems: just a `Vec`/`[u8]`. use core::clone::CloneToUninit; -use core::ptr::addr_of_mut; use crate::borrow::Cow; use crate::collections::TryReserveError; @@ -355,6 +354,6 @@ unsafe impl CloneToUninit for Slice { #[cfg_attr(debug_assertions, track_caller)] unsafe fn clone_to_uninit(&self, dst: *mut Self) { // SAFETY: we're just a wrapper around [u8] - unsafe { self.inner.clone_to_uninit(addr_of_mut!((*dst).inner)) } + unsafe { self.inner.clone_to_uninit(&raw mut (*dst).inner) } } } diff --git a/library/std/src/sys/os_str/wtf8.rs b/library/std/src/sys/os_str/wtf8.rs index 6fbbec7a945..b3834388df6 100644 --- a/library/std/src/sys/os_str/wtf8.rs +++ b/library/std/src/sys/os_str/wtf8.rs @@ -1,7 +1,6 @@ //! The underlying OsString/OsStr implementation on Windows is a //! wrapper around the "WTF-8" encoding; see the `wtf8` module for more. use core::clone::CloneToUninit; -use core::ptr::addr_of_mut; use crate::borrow::Cow; use crate::collections::TryReserveError; @@ -278,6 +277,6 @@ unsafe impl CloneToUninit for Slice { #[cfg_attr(debug_assertions, track_caller)] unsafe fn clone_to_uninit(&self, dst: *mut Self) { // SAFETY: we're just a wrapper around Wtf8 - unsafe { self.inner.clone_to_uninit(addr_of_mut!((*dst).inner)) } + unsafe { self.inner.clone_to_uninit(&raw mut (*dst).inner) } } } diff --git a/library/std/src/sys/pal/hermit/net.rs b/library/std/src/sys/pal/hermit/net.rs index 416469c0037..d9baa091a23 100644 --- a/library/std/src/sys/pal/hermit/net.rs +++ b/library/std/src/sys/pal/hermit/net.rs @@ -192,7 +192,7 @@ impl Socket { buf.as_mut_ptr(), buf.len(), flags, - core::ptr::addr_of_mut!(storage) as *mut _, + (&raw mut storage) as *mut _, &mut addrlen, ) })?; @@ -298,7 +298,7 @@ impl Socket { netc::ioctl( self.as_raw_fd(), netc::FIONBIO, - core::ptr::addr_of_mut!(nonblocking) as *mut core::ffi::c_void, + (&raw mut nonblocking) as *mut core::ffi::c_void, ) }) .map(drop) diff --git a/library/std/src/sys/pal/hermit/time.rs b/library/std/src/sys/pal/hermit/time.rs index 99166b15602..e0b6eb76b03 100644 --- a/library/std/src/sys/pal/hermit/time.rs +++ b/library/std/src/sys/pal/hermit/time.rs @@ -107,8 +107,7 @@ pub struct Instant(Timespec); impl Instant { pub fn now() -> Instant { let mut time: Timespec = Timespec::zero(); - let _ = - unsafe { hermit_abi::clock_gettime(CLOCK_MONOTONIC, core::ptr::addr_of_mut!(time.t)) }; + let _ = unsafe { hermit_abi::clock_gettime(CLOCK_MONOTONIC, &raw mut time.t) }; Instant(time) } @@ -209,8 +208,7 @@ impl SystemTime { pub fn now() -> SystemTime { let mut time: Timespec = Timespec::zero(); - let _ = - unsafe { hermit_abi::clock_gettime(CLOCK_REALTIME, core::ptr::addr_of_mut!(time.t)) }; + let _ = unsafe { hermit_abi::clock_gettime(CLOCK_REALTIME, &raw mut time.t) }; SystemTime(time) } diff --git a/library/std/src/sys/pal/unix/fs.rs b/library/std/src/sys/pal/unix/fs.rs index 86342c2add0..39aabf0b2d6 100644 --- a/library/std/src/sys/pal/unix/fs.rs +++ b/library/std/src/sys/pal/unix/fs.rs @@ -740,7 +740,7 @@ impl Iterator for ReadDir { // // Like for uninitialized contents, converting entry_ptr to `&dirent64` // would not be legal. However, unique to dirent64 is that we don't even - // get to use `addr_of!((*entry_ptr).d_name)` because that operation + // get to use `&raw const (*entry_ptr).d_name` because that operation // requires the full extent of *entry_ptr to be in bounds of the same // allocation, which is not necessarily the case here. // @@ -754,7 +754,7 @@ impl Iterator for ReadDir { } else { #[allow(deref_nullptr)] { - ptr::addr_of!((*ptr::null::()).$field) + &raw const (*ptr::null::()).$field } } }}; @@ -1385,7 +1385,7 @@ impl File { } cvt(unsafe { libc::fsetattrlist( self.as_raw_fd(), - core::ptr::addr_of!(attrlist).cast::().cast_mut(), + (&raw const attrlist).cast::().cast_mut(), buf.as_ptr().cast::().cast_mut(), num_times * mem::size_of::(), 0 @@ -1944,7 +1944,7 @@ pub fn copy(from: &Path, to: &Path) -> io::Result { libc::copyfile_state_get( state.0, libc::COPYFILE_STATE_COPIED as u32, - core::ptr::addr_of_mut!(bytes_copied) as *mut libc::c_void, + (&raw mut bytes_copied) as *mut libc::c_void, ) })?; Ok(bytes_copied as u64) diff --git a/library/std/src/sys/pal/unix/net.rs b/library/std/src/sys/pal/unix/net.rs index 0f2e015bbcd..6a67bb0a101 100644 --- a/library/std/src/sys/pal/unix/net.rs +++ b/library/std/src/sys/pal/unix/net.rs @@ -329,7 +329,7 @@ impl Socket { buf.as_mut_ptr() as *mut c_void, buf.len(), flags, - core::ptr::addr_of_mut!(storage) as *mut _, + (&raw mut storage) as *mut _, &mut addrlen, ) })?; diff --git a/library/std/src/sys/pal/unix/os.rs b/library/std/src/sys/pal/unix/os.rs index d99bde2f9a5..f983d174ed6 100644 --- a/library/std/src/sys/pal/unix/os.rs +++ b/library/std/src/sys/pal/unix/os.rs @@ -612,7 +612,7 @@ pub unsafe fn environ() -> *mut *const *const c_char { extern "C" { static mut environ: *const *const c_char; } - ptr::addr_of_mut!(environ) + &raw mut environ } static ENV_LOCK: RwLock<()> = RwLock::new(()); diff --git a/library/std/src/sys/pal/unix/process/process_fuchsia.rs b/library/std/src/sys/pal/unix/process/process_fuchsia.rs index 34ff464aa37..5d0110cf55d 100644 --- a/library/std/src/sys/pal/unix/process/process_fuchsia.rs +++ b/library/std/src/sys/pal/unix/process/process_fuchsia.rs @@ -178,7 +178,7 @@ impl Process { zx_cvt(zx_object_get_info( self.handle.raw(), ZX_INFO_PROCESS, - core::ptr::addr_of_mut!(proc_info) as *mut libc::c_void, + (&raw mut proc_info) as *mut libc::c_void, mem::size_of::(), &mut actual, &mut avail, @@ -215,7 +215,7 @@ impl Process { zx_cvt(zx_object_get_info( self.handle.raw(), ZX_INFO_PROCESS, - core::ptr::addr_of_mut!(proc_info) as *mut libc::c_void, + (&raw mut proc_info) as *mut libc::c_void, mem::size_of::(), &mut actual, &mut avail, diff --git a/library/std/src/sys/pal/unix/process/process_unix.rs b/library/std/src/sys/pal/unix/process/process_unix.rs index d812aa0e02c..5d30f388da1 100644 --- a/library/std/src/sys/pal/unix/process/process_unix.rs +++ b/library/std/src/sys/pal/unix/process/process_unix.rs @@ -788,15 +788,15 @@ impl Command { let mut iov = [IoSlice::new(b"")]; let mut msg: libc::msghdr = mem::zeroed(); - msg.msg_iov = core::ptr::addr_of_mut!(iov) as *mut _; + msg.msg_iov = (&raw mut iov) as *mut _; msg.msg_iovlen = 1; // only attach cmsg if we successfully acquired the pidfd if pidfd >= 0 { msg.msg_controllen = mem::size_of_val(&cmsg.buf) as _; - msg.msg_control = core::ptr::addr_of_mut!(cmsg.buf) as *mut _; + msg.msg_control = (&raw mut cmsg.buf) as *mut _; - let hdr = CMSG_FIRSTHDR(core::ptr::addr_of_mut!(msg) as *mut _); + let hdr = CMSG_FIRSTHDR((&raw mut msg) as *mut _); (*hdr).cmsg_level = SOL_SOCKET; (*hdr).cmsg_type = SCM_RIGHTS; (*hdr).cmsg_len = CMSG_LEN(SCM_MSG_LEN as _) as _; @@ -838,17 +838,17 @@ impl Command { let mut msg: libc::msghdr = mem::zeroed(); - msg.msg_iov = core::ptr::addr_of_mut!(iov) as *mut _; + msg.msg_iov = (&raw mut iov) as *mut _; msg.msg_iovlen = 1; msg.msg_controllen = mem::size_of::() as _; - msg.msg_control = core::ptr::addr_of_mut!(cmsg) as *mut _; + msg.msg_control = (&raw mut cmsg) as *mut _; match cvt_r(|| libc::recvmsg(sock.as_raw(), &mut msg, libc::MSG_CMSG_CLOEXEC)) { Err(_) => return -1, Ok(_) => {} } - let hdr = CMSG_FIRSTHDR(core::ptr::addr_of_mut!(msg) as *mut _); + let hdr = CMSG_FIRSTHDR((&raw mut msg) as *mut _); if hdr.is_null() || (*hdr).cmsg_level != SOL_SOCKET || (*hdr).cmsg_type != SCM_RIGHTS diff --git a/library/std/src/sys/pal/unix/stack_overflow.rs b/library/std/src/sys/pal/unix/stack_overflow.rs index e0a0d0973c6..ac0858e1de8 100644 --- a/library/std/src/sys/pal/unix/stack_overflow.rs +++ b/library/std/src/sys/pal/unix/stack_overflow.rs @@ -426,8 +426,8 @@ mod imp { match sysctlbyname.get() { Some(fcn) if unsafe { fcn(oid.as_ptr(), - ptr::addr_of_mut!(guard).cast(), - ptr::addr_of_mut!(size), + (&raw mut guard).cast(), + &raw mut size, ptr::null_mut(), 0) == 0 } => guard, diff --git a/library/std/src/sys/pal/unix/thread.rs b/library/std/src/sys/pal/unix/thread.rs index cb6133274d9..2f2d6e6add3 100644 --- a/library/std/src/sys/pal/unix/thread.rs +++ b/library/std/src/sys/pal/unix/thread.rs @@ -258,7 +258,7 @@ impl Thread { tv_nsec: nsecs, }; secs -= ts.tv_sec as u64; - let ts_ptr = core::ptr::addr_of_mut!(ts); + let ts_ptr = &raw mut ts; if libc::nanosleep(ts_ptr, ts_ptr) == -1 { assert_eq!(os::errno(), libc::EINTR); secs += ts.tv_sec as u64; @@ -447,8 +447,8 @@ pub fn available_parallelism() -> io::Result> { libc::sysctl( mib.as_mut_ptr(), 2, - core::ptr::addr_of_mut!(cpus) as *mut _, - core::ptr::addr_of_mut!(cpus_size) as *mut _, + (&raw mut cpus) as *mut _, + (&raw mut cpus_size) as *mut _, ptr::null_mut(), 0, ) diff --git a/library/std/src/sys/pal/windows/api.rs b/library/std/src/sys/pal/windows/api.rs index 9e336ff2d47..ebe207fde93 100644 --- a/library/std/src/sys/pal/windows/api.rs +++ b/library/std/src/sys/pal/windows/api.rs @@ -30,7 +30,6 @@ //! should go in sys/pal/windows/mod.rs rather than here. See `IoResult` as an example. use core::ffi::c_void; -use core::ptr::addr_of; use super::c; @@ -186,7 +185,7 @@ unsafe trait SizedSetFileInformation: Sized { unsafe impl SetFileInformation for T { const CLASS: i32 = T::CLASS; fn as_ptr(&self) -> *const c_void { - addr_of!(*self).cast::() + (&raw const *self).cast::() } fn size(&self) -> u32 { win32_size_of::() diff --git a/library/std/src/sys/pal/windows/fs.rs b/library/std/src/sys/pal/windows/fs.rs index be26356bb40..aab471e28ea 100644 --- a/library/std/src/sys/pal/windows/fs.rs +++ b/library/std/src/sys/pal/windows/fs.rs @@ -1,5 +1,3 @@ -use core::ptr::addr_of; - use super::api::{self, WinError}; use super::{IoResult, to_u16s}; use crate::borrow::Cow; @@ -325,7 +323,7 @@ impl File { let result = c::SetFileInformationByHandle( handle.as_raw_handle(), c::FileEndOfFileInfo, - ptr::addr_of!(eof).cast::(), + (&raw const eof).cast::(), mem::size_of::() as u32, ); if result == 0 { @@ -364,7 +362,7 @@ impl File { cvt(c::GetFileInformationByHandleEx( self.handle.as_raw_handle(), c::FileAttributeTagInfo, - ptr::addr_of_mut!(attr_tag).cast(), + (&raw mut attr_tag).cast(), mem::size_of::().try_into().unwrap(), ))?; if attr_tag.FileAttributes & c::FILE_ATTRIBUTE_REPARSE_POINT != 0 { @@ -396,7 +394,7 @@ impl File { cvt(c::GetFileInformationByHandleEx( self.handle.as_raw_handle(), c::FileBasicInfo, - core::ptr::addr_of_mut!(info) as *mut c_void, + (&raw mut info) as *mut c_void, size as u32, ))?; let mut attr = FileAttr { @@ -428,7 +426,7 @@ impl File { cvt(c::GetFileInformationByHandleEx( self.handle.as_raw_handle(), c::FileStandardInfo, - core::ptr::addr_of_mut!(info) as *mut c_void, + (&raw mut info) as *mut c_void, size as u32, ))?; attr.file_size = info.AllocationSize as u64; @@ -438,7 +436,7 @@ impl File { cvt(c::GetFileInformationByHandleEx( self.handle.as_raw_handle(), c::FileAttributeTagInfo, - ptr::addr_of_mut!(attr_tag).cast(), + (&raw mut attr_tag).cast(), mem::size_of::().try_into().unwrap(), ))?; if attr_tag.FileAttributes & c::FILE_ATTRIBUTE_REPARSE_POINT != 0 { @@ -545,22 +543,20 @@ impl File { unsafe { let (path_buffer, subst_off, subst_len, relative) = match (*buf).ReparseTag { c::IO_REPARSE_TAG_SYMLINK => { - let info: *mut c::SYMBOLIC_LINK_REPARSE_BUFFER = - ptr::addr_of_mut!((*buf).rest).cast(); + let info: *mut c::SYMBOLIC_LINK_REPARSE_BUFFER = (&raw mut (*buf).rest).cast(); assert!(info.is_aligned()); ( - ptr::addr_of_mut!((*info).PathBuffer).cast::(), + (&raw mut (*info).PathBuffer).cast::(), (*info).SubstituteNameOffset / 2, (*info).SubstituteNameLength / 2, (*info).Flags & c::SYMLINK_FLAG_RELATIVE != 0, ) } c::IO_REPARSE_TAG_MOUNT_POINT => { - let info: *mut c::MOUNT_POINT_REPARSE_BUFFER = - ptr::addr_of_mut!((*buf).rest).cast(); + let info: *mut c::MOUNT_POINT_REPARSE_BUFFER = (&raw mut (*buf).rest).cast(); assert!(info.is_aligned()); ( - ptr::addr_of_mut!((*info).PathBuffer).cast::(), + (&raw mut (*info).PathBuffer).cast::(), (*info).SubstituteNameOffset / 2, (*info).SubstituteNameLength / 2, false, @@ -643,7 +639,7 @@ impl File { cvt(c::GetFileInformationByHandleEx( self.handle.as_raw_handle(), c::FileBasicInfo, - core::ptr::addr_of_mut!(info) as *mut c_void, + (&raw mut info) as *mut c_void, size as u32, ))?; Ok(info) @@ -790,11 +786,11 @@ impl<'a> Iterator for DirBuffIter<'a> { // it does not seem that reality is so kind, and assuming this // caused crashes in some cases (https://github.com/rust-lang/rust/issues/104530) // presumably, this can be blamed on buggy filesystem drivers, but who knows. - let next_entry = ptr::addr_of!((*info).NextEntryOffset).read_unaligned() as usize; - let length = ptr::addr_of!((*info).FileNameLength).read_unaligned() as usize; - let attrs = ptr::addr_of!((*info).FileAttributes).read_unaligned(); + let next_entry = (&raw const (*info).NextEntryOffset).read_unaligned() as usize; + let length = (&raw const (*info).FileNameLength).read_unaligned() as usize; + let attrs = (&raw const (*info).FileAttributes).read_unaligned(); let name = from_maybe_unaligned( - ptr::addr_of!((*info).FileName).cast::(), + (&raw const (*info).FileName).cast::(), length / size_of::(), ); let is_directory = (attrs & c::FILE_ATTRIBUTE_DIRECTORY) != 0; @@ -1326,7 +1322,7 @@ pub fn copy(from: &Path, to: &Path) -> io::Result { pfrom.as_ptr(), pto.as_ptr(), Some(callback), - core::ptr::addr_of_mut!(size) as *mut _, + (&raw mut size) as *mut _, ptr::null_mut(), 0, ) @@ -1405,7 +1401,7 @@ pub fn junction_point(original: &Path, link: &Path) -> io::Result<()> { cvt(c::DeviceIoControl( d.as_raw_handle(), c::FSCTL_SET_REPARSE_POINT, - addr_of!(header).cast::(), + (&raw const header).cast::(), data_len as u32 + 8, ptr::null_mut(), 0, diff --git a/library/std/src/sys/pal/windows/futex.rs b/library/std/src/sys/pal/windows/futex.rs index f16a9f534a3..4d6c4df9a5a 100644 --- a/library/std/src/sys/pal/windows/futex.rs +++ b/library/std/src/sys/pal/windows/futex.rs @@ -57,7 +57,7 @@ pub fn wait_on_address( unsafe { let addr = ptr::from_ref(address).cast::(); let size = mem::size_of::(); - let compare_addr = ptr::addr_of!(compare).cast::(); + let compare_addr = (&raw const compare).cast::(); let timeout = timeout.map(dur2timeout).unwrap_or(c::INFINITE); c::WaitOnAddress(addr, compare_addr, size, timeout) == c::TRUE } diff --git a/library/std/src/sys/pal/windows/io.rs b/library/std/src/sys/pal/windows/io.rs index 785a3f6768b..1e7d02908f6 100644 --- a/library/std/src/sys/pal/windows/io.rs +++ b/library/std/src/sys/pal/windows/io.rs @@ -122,7 +122,7 @@ fn msys_tty_on(handle: BorrowedHandle<'_>) -> bool { c::GetFileInformationByHandleEx( handle.as_raw_handle(), c::FileNameInfo, - core::ptr::addr_of_mut!(name_info) as *mut c_void, + (&raw mut name_info) as *mut c_void, size_of::() as u32, ) }; diff --git a/library/std/src/sys/pal/windows/net.rs b/library/std/src/sys/pal/windows/net.rs index 61a4504cf65..fd62d1f407c 100644 --- a/library/std/src/sys/pal/windows/net.rs +++ b/library/std/src/sys/pal/windows/net.rs @@ -390,7 +390,7 @@ impl Socket { buf.as_mut_ptr() as *mut _, length, flags, - core::ptr::addr_of_mut!(storage) as *mut _, + (&raw mut storage) as *mut _, &mut addrlen, ) }; diff --git a/library/std/src/sys/pal/windows/pipe.rs b/library/std/src/sys/pal/windows/pipe.rs index d8200ef9ca4..a8f6617c9dc 100644 --- a/library/std/src/sys/pal/windows/pipe.rs +++ b/library/std/src/sys/pal/windows/pipe.rs @@ -375,7 +375,7 @@ impl AnonPipe { let mut overlapped: c::OVERLAPPED = unsafe { crate::mem::zeroed() }; // `hEvent` is unused by `ReadFileEx` and `WriteFileEx`. // Therefore the documentation suggests using it to smuggle a pointer to the callback. - overlapped.hEvent = core::ptr::addr_of_mut!(async_result) as *mut _; + overlapped.hEvent = (&raw mut async_result) as *mut _; // Asynchronous read of the pipe. // If successful, `callback` will be called once it completes. diff --git a/library/std/src/sys/pal/windows/process.rs b/library/std/src/sys/pal/windows/process.rs index 93a6c45ce30..95b51e704f9 100644 --- a/library/std/src/sys/pal/windows/process.rs +++ b/library/std/src/sys/pal/windows/process.rs @@ -368,10 +368,10 @@ impl Command { StartupInfo: si, lpAttributeList: proc_thread_attribute_list.0.as_mut_ptr() as _, }; - si_ptr = core::ptr::addr_of_mut!(si_ex) as _; + si_ptr = (&raw mut si_ex) as _; } else { si.cb = mem::size_of::() as u32; - si_ptr = core::ptr::addr_of_mut!(si) as _; + si_ptr = (&raw mut si) as _; } unsafe { @@ -953,7 +953,7 @@ fn make_proc_thread_attribute_list( // It's theoretically possible for the attribute count to exceed a u32 value. // Therefore, we ensure that we don't add more attributes than the buffer was initialized for. for (&attribute, value) in attributes.iter().take(attribute_count as usize) { - let value_ptr = core::ptr::addr_of!(*value.data) as _; + let value_ptr = (&raw const *value.data) as _; cvt(unsafe { c::UpdateProcThreadAttribute( proc_thread_attribute_list.0.as_mut_ptr() as _, diff --git a/library/std/src/sys/sync/thread_parking/pthread.rs b/library/std/src/sys/sync/thread_parking/pthread.rs index c64600e9e29..5f195d0bb0c 100644 --- a/library/std/src/sys/sync/thread_parking/pthread.rs +++ b/library/std/src/sys/sync/thread_parking/pthread.rs @@ -3,7 +3,6 @@ use crate::cell::UnsafeCell; use crate::marker::PhantomPinned; use crate::pin::Pin; -use crate::ptr::addr_of_mut; use crate::sync::atomic::AtomicUsize; use crate::sync::atomic::Ordering::{Acquire, Relaxed, Release}; #[cfg(not(target_os = "nto"))] @@ -101,8 +100,8 @@ impl Parker { // This could lead to undefined behaviour when deadlocking. This is avoided // by not deadlocking. Note in particular the unlocking operation before any // panic, as code after the panic could try to park again. - addr_of_mut!((*parker).state).write(AtomicUsize::new(EMPTY)); - addr_of_mut!((*parker).lock).write(UnsafeCell::new(libc::PTHREAD_MUTEX_INITIALIZER)); + (&raw mut (*parker).state).write(AtomicUsize::new(EMPTY)); + (&raw mut (*parker).lock).write(UnsafeCell::new(libc::PTHREAD_MUTEX_INITIALIZER)); cfg_if::cfg_if! { if #[cfg(any( @@ -112,9 +111,9 @@ impl Parker { target_os = "vita", target_vendor = "apple", ))] { - addr_of_mut!((*parker).cvar).write(UnsafeCell::new(libc::PTHREAD_COND_INITIALIZER)); + (&raw mut (*parker).cvar).write(UnsafeCell::new(libc::PTHREAD_COND_INITIALIZER)); } else if #[cfg(any(target_os = "espidf", target_os = "horizon"))] { - let r = libc::pthread_cond_init(addr_of_mut!((*parker).cvar).cast(), crate::ptr::null()); + let r = libc::pthread_cond_init((&raw mut (*parker).cvar).cast(), crate::ptr::null()); assert_eq!(r, 0); } else { use crate::mem::MaybeUninit; @@ -123,7 +122,7 @@ impl Parker { assert_eq!(r, 0); let r = libc::pthread_condattr_setclock(attr.as_mut_ptr(), libc::CLOCK_MONOTONIC); assert_eq!(r, 0); - let r = libc::pthread_cond_init(addr_of_mut!((*parker).cvar).cast(), attr.as_ptr()); + let r = libc::pthread_cond_init((&raw mut (*parker).cvar).cast(), attr.as_ptr()); assert_eq!(r, 0); let r = libc::pthread_condattr_destroy(attr.as_mut_ptr()); assert_eq!(r, 0); diff --git a/library/std/src/sys/sync/thread_parking/windows7.rs b/library/std/src/sys/sync/thread_parking/windows7.rs index cdd59757fe2..8f7e66c46ef 100644 --- a/library/std/src/sys/sync/thread_parking/windows7.rs +++ b/library/std/src/sys/sync/thread_parking/windows7.rs @@ -178,7 +178,7 @@ impl Parker { } fn ptr(&self) -> *const c_void { - core::ptr::addr_of!(self.state).cast::() + (&raw const self.state).cast::() } } diff --git a/library/std/src/sys/thread_local/destructors/linux_like.rs b/library/std/src/sys/thread_local/destructors/linux_like.rs index c381be0bf8c..f473dc4d79d 100644 --- a/library/std/src/sys/thread_local/destructors/linux_like.rs +++ b/library/std/src/sys/thread_local/destructors/linux_like.rs @@ -47,7 +47,7 @@ pub unsafe fn register(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) { dtor, ), t.cast(), - core::ptr::addr_of!(__dso_handle) as *mut _, + (&raw const __dso_handle) as *mut _, ); } } else { diff --git a/library/std/src/sys_common/net.rs b/library/std/src/sys_common/net.rs index 57f07d05cae..5a0ad907581 100644 --- a/library/std/src/sys_common/net.rs +++ b/library/std/src/sys_common/net.rs @@ -74,7 +74,7 @@ pub fn setsockopt( sock.as_raw(), level, option_name, - core::ptr::addr_of!(option_value) as *const _, + (&raw const option_value) as *const _, mem::size_of::() as c::socklen_t, ))?; Ok(()) @@ -89,7 +89,7 @@ pub fn getsockopt(sock: &Socket, level: c_int, option_name: c_int) -> i sock.as_raw(), level, option_name, - core::ptr::addr_of_mut!(option_value) as *mut _, + (&raw mut option_value) as *mut _, &mut option_len, ))?; Ok(option_value) @@ -103,7 +103,7 @@ where unsafe { let mut storage: c::sockaddr_storage = mem::zeroed(); let mut len = mem::size_of_val(&storage) as c::socklen_t; - cvt(f(core::ptr::addr_of_mut!(storage) as *mut _, &mut len))?; + cvt(f((&raw mut storage) as *mut _, &mut len))?; sockaddr_to_addr(&storage, len as usize) } } @@ -452,7 +452,7 @@ impl TcpListener { pub fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> { let mut storage: c::sockaddr_storage = unsafe { mem::zeroed() }; let mut len = mem::size_of_val(&storage) as c::socklen_t; - let sock = self.inner.accept(core::ptr::addr_of_mut!(storage) as *mut _, &mut len)?; + let sock = self.inner.accept((&raw mut storage) as *mut _, &mut len)?; let addr = sockaddr_to_addr(&storage, len as usize)?; Ok((TcpStream { inner: sock }, addr)) } diff --git a/library/std/src/sys_common/wtf8.rs b/library/std/src/sys_common/wtf8.rs index 554e07c1e59..19d4c94f450 100644 --- a/library/std/src/sys_common/wtf8.rs +++ b/library/std/src/sys_common/wtf8.rs @@ -26,7 +26,6 @@ use crate::borrow::Cow; use crate::collections::TryReserveError; use crate::hash::{Hash, Hasher}; use crate::iter::FusedIterator; -use crate::ptr::addr_of_mut; use crate::rc::Rc; use crate::sync::Arc; use crate::sys_common::AsInner; @@ -1055,6 +1054,6 @@ unsafe impl CloneToUninit for Wtf8 { #[cfg_attr(debug_assertions, track_caller)] unsafe fn clone_to_uninit(&self, dst: *mut Self) { // SAFETY: we're just a wrapper around [u8] - unsafe { self.bytes.clone_to_uninit(addr_of_mut!((*dst).bytes)) } + unsafe { self.bytes.clone_to_uninit(&raw mut (*dst).bytes) } } } diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs index a53e3565dfe..41f02af9366 100644 --- a/library/std/src/thread/mod.rs +++ b/library/std/src/thread/mod.rs @@ -165,7 +165,6 @@ use crate::marker::PhantomData; use crate::mem::{self, ManuallyDrop, forget}; use crate::num::NonZero; use crate::pin::Pin; -use crate::ptr::addr_of_mut; use crate::sync::Arc; use crate::sync::atomic::{AtomicUsize, Ordering}; use crate::sys::sync::Parker; @@ -1386,9 +1385,9 @@ impl Thread { let inner = unsafe { let mut arc = Arc::::new_uninit(); let ptr = Arc::get_mut_unchecked(&mut arc).as_mut_ptr(); - addr_of_mut!((*ptr).name).write(name); - addr_of_mut!((*ptr).id).write(ThreadId::new()); - Parker::new_in_place(addr_of_mut!((*ptr).parker)); + (&raw mut (*ptr).name).write(name); + (&raw mut (*ptr).id).write(ThreadId::new()); + Parker::new_in_place(&raw mut (*ptr).parker); Pin::new_unchecked(arc.assume_init()) }; diff --git a/library/unwind/src/libunwind.rs b/library/unwind/src/libunwind.rs index 1d856ce1879..715f8b57876 100644 --- a/library/unwind/src/libunwind.rs +++ b/library/unwind/src/libunwind.rs @@ -222,14 +222,14 @@ if #[cfg(any(target_vendor = "apple", target_os = "netbsd", not(target_arch = "a pub unsafe fn _Unwind_GetGR(ctx: *mut _Unwind_Context, reg_index: c_int) -> _Unwind_Word { let mut val: _Unwind_Word = core::ptr::null(); _Unwind_VRS_Get(ctx, _UVRSC_CORE, reg_index as _Unwind_Word, _UVRSD_UINT32, - core::ptr::addr_of_mut!(val) as *mut c_void); + (&raw mut val) as *mut c_void); val } pub unsafe fn _Unwind_SetGR(ctx: *mut _Unwind_Context, reg_index: c_int, value: _Unwind_Word) { let mut value = value; _Unwind_VRS_Set(ctx, _UVRSC_CORE, reg_index as _Unwind_Word, _UVRSD_UINT32, - core::ptr::addr_of_mut!(value) as *mut c_void); + (&raw mut value) as *mut c_void); } pub unsafe fn _Unwind_GetIP(ctx: *mut _Unwind_Context) From fd5aa07f4f217a2f57131dfd0b17e58fb1ad3918 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Wed, 18 Sep 2024 08:11:55 -0700 Subject: [PATCH 276/683] Stabilize the `map`/`value` methods on `ControlFlow` And fix the stability attribute on the `pub use` in `core::ops`. --- compiler/rustc_borrowck/src/lib.rs | 1 - compiler/rustc_hir_analysis/src/lib.rs | 1 - compiler/rustc_hir_typeck/src/lib.rs | 1 - compiler/rustc_infer/src/lib.rs | 1 - compiler/rustc_lint/src/lib.rs | 1 - compiler/rustc_metadata/src/lib.rs | 1 - compiler/rustc_trait_selection/src/lib.rs | 1 - library/core/src/ops/control_flow.rs | 20 ++++++-------------- library/core/src/ops/mod.rs | 2 +- 9 files changed, 7 insertions(+), 22 deletions(-) diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index a11eca0b9c7..3b0b3ee1a74 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -5,7 +5,6 @@ #![doc(rust_logo)] #![feature(assert_matches)] #![feature(box_patterns)] -#![feature(control_flow_enum)] #![feature(file_buffered)] #![feature(let_chains)] #![feature(never_type)] diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index 92d85d48a42..65dbbc4aadf 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -63,7 +63,6 @@ This API is completely unstable and subject to change. #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(assert_matches)] -#![feature(control_flow_enum)] #![feature(if_let_guard)] #![feature(iter_intersperse)] #![feature(let_chains)] diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs index f8352d9d44a..6b0a897faba 100644 --- a/compiler/rustc_hir_typeck/src/lib.rs +++ b/compiler/rustc_hir_typeck/src/lib.rs @@ -3,7 +3,6 @@ #![allow(rustc::untranslatable_diagnostic)] #![feature(array_windows)] #![feature(box_patterns)] -#![feature(control_flow_enum)] #![feature(if_let_guard)] #![feature(let_chains)] #![feature(never_type)] diff --git a/compiler/rustc_infer/src/lib.rs b/compiler/rustc_infer/src/lib.rs index 051bba58518..934484bf915 100644 --- a/compiler/rustc_infer/src/lib.rs +++ b/compiler/rustc_infer/src/lib.rs @@ -20,7 +20,6 @@ #![doc(rust_logo)] #![feature(assert_matches)] #![feature(box_patterns)] -#![feature(control_flow_enum)] #![feature(extend_one)] #![feature(if_let_guard)] #![feature(iter_intersperse)] diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index c74cb866f21..e58ad23f414 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -32,7 +32,6 @@ #![feature(array_windows)] #![feature(assert_matches)] #![feature(box_patterns)] -#![feature(control_flow_enum)] #![feature(extract_if)] #![feature(if_let_guard)] #![feature(iter_order_by)] diff --git a/compiler/rustc_metadata/src/lib.rs b/compiler/rustc_metadata/src/lib.rs index 10f2087d1e6..6e2ab8c32d9 100644 --- a/compiler/rustc_metadata/src/lib.rs +++ b/compiler/rustc_metadata/src/lib.rs @@ -3,7 +3,6 @@ #![allow(rustc::potential_query_instability)] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] -#![feature(control_flow_enum)] #![feature(coroutines)] #![feature(decl_macro)] #![feature(error_iter)] diff --git a/compiler/rustc_trait_selection/src/lib.rs b/compiler/rustc_trait_selection/src/lib.rs index a17c007debd..11d72106b22 100644 --- a/compiler/rustc_trait_selection/src/lib.rs +++ b/compiler/rustc_trait_selection/src/lib.rs @@ -20,7 +20,6 @@ #![feature(associated_type_defaults)] #![feature(box_patterns)] #![feature(cfg_version)] -#![feature(control_flow_enum)] #![feature(extract_if)] #![feature(if_let_guard)] #![feature(iter_intersperse)] diff --git a/library/core/src/ops/control_flow.rs b/library/core/src/ops/control_flow.rs index ab73dc19fcc..7a8158b8231 100644 --- a/library/core/src/ops/control_flow.rs +++ b/library/core/src/ops/control_flow.rs @@ -171,14 +171,13 @@ impl ControlFlow { /// # Examples /// /// ``` - /// #![feature(control_flow_enum)] /// use std::ops::ControlFlow; /// /// assert_eq!(ControlFlow::::Break(3).break_value(), Some(3)); /// assert_eq!(ControlFlow::::Continue(3).break_value(), None); /// ``` #[inline] - #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")] + #[stable(feature = "control_flow_enum", since = "CURRENT_RUSTC_VERSION")] pub fn break_value(self) -> Option { match self { ControlFlow::Continue(..) => None, @@ -189,11 +188,8 @@ impl ControlFlow { /// Maps `ControlFlow` to `ControlFlow` by applying a function /// to the break value in case it exists. #[inline] - #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")] - pub fn map_break(self, f: F) -> ControlFlow - where - F: FnOnce(B) -> T, - { + #[stable(feature = "control_flow_enum", since = "CURRENT_RUSTC_VERSION")] + pub fn map_break(self, f: impl FnOnce(B) -> T) -> ControlFlow { match self { ControlFlow::Continue(x) => ControlFlow::Continue(x), ControlFlow::Break(x) => ControlFlow::Break(f(x)), @@ -206,14 +202,13 @@ impl ControlFlow { /// # Examples /// /// ``` - /// #![feature(control_flow_enum)] /// use std::ops::ControlFlow; /// /// assert_eq!(ControlFlow::::Break(3).continue_value(), None); /// assert_eq!(ControlFlow::::Continue(3).continue_value(), Some(3)); /// ``` #[inline] - #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")] + #[stable(feature = "control_flow_enum", since = "CURRENT_RUSTC_VERSION")] pub fn continue_value(self) -> Option { match self { ControlFlow::Continue(x) => Some(x), @@ -224,11 +219,8 @@ impl ControlFlow { /// Maps `ControlFlow` to `ControlFlow` by applying a function /// to the continue value in case it exists. #[inline] - #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")] - pub fn map_continue(self, f: F) -> ControlFlow - where - F: FnOnce(C) -> T, - { + #[stable(feature = "control_flow_enum", since = "CURRENT_RUSTC_VERSION")] + pub fn map_continue(self, f: impl FnOnce(C) -> T) -> ControlFlow { match self { ControlFlow::Continue(x) => ControlFlow::Continue(f(x)), ControlFlow::Break(x) => ControlFlow::Break(x), diff --git a/library/core/src/ops/mod.rs b/library/core/src/ops/mod.rs index 25c4b87f4e7..5464bf645d9 100644 --- a/library/core/src/ops/mod.rs +++ b/library/core/src/ops/mod.rs @@ -162,7 +162,7 @@ pub use self::async_function::{AsyncFn, AsyncFnMut, AsyncFnOnce}; pub use self::bit::{BitAnd, BitOr, BitXor, Not, Shl, Shr}; #[stable(feature = "op_assign_traits", since = "1.8.0")] pub use self::bit::{BitAndAssign, BitOrAssign, BitXorAssign, ShlAssign, ShrAssign}; -#[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")] +#[stable(feature = "control_flow_enum_type", since = "1.55.0")] pub use self::control_flow::ControlFlow; #[unstable(feature = "coroutine_trait", issue = "43122")] pub use self::coroutine::{Coroutine, CoroutineState}; From c89b873172af7e2448fc89da62948623e9e7bc47 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Wed, 18 Sep 2024 10:34:27 -0700 Subject: [PATCH 277/683] Remove the `control_flow_enum` feature from clippy --- src/tools/clippy/clippy_lints/src/lib.rs | 1 - src/tools/clippy/clippy_utils/src/lib.rs | 1 - 2 files changed, 2 deletions(-) diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs index 1d41f568f37..54c3758459c 100644 --- a/src/tools/clippy/clippy_lints/src/lib.rs +++ b/src/tools/clippy/clippy_lints/src/lib.rs @@ -1,7 +1,6 @@ #![feature(array_windows)] #![feature(binary_heap_into_iter_sorted)] #![feature(box_patterns)] -#![feature(control_flow_enum)] #![feature(f128)] #![feature(f16)] #![feature(if_let_guard)] diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index 6dbc3334157..6c0413c1808 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -1,6 +1,5 @@ #![feature(array_chunks)] #![feature(box_patterns)] -#![feature(control_flow_enum)] #![feature(f128)] #![feature(f16)] #![feature(if_let_guard)] From ddfd0c701ad60f6e31cca13d544a9abd24bc56cb Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Wed, 18 Sep 2024 11:09:41 -0700 Subject: [PATCH 278/683] Remove `feature(control_flow_enum)` in tests --- tests/mir-opt/jump_threading.rs | 1 - tests/mir-opt/separate_const_switch.rs | 1 - tests/ui-fulldeps/stable-mir/check_abi.rs | 1 - tests/ui-fulldeps/stable-mir/check_allocation.rs | 1 - tests/ui-fulldeps/stable-mir/check_attribute.rs | 1 - tests/ui-fulldeps/stable-mir/check_def_ty.rs | 1 - tests/ui-fulldeps/stable-mir/check_defs.rs | 1 - tests/ui-fulldeps/stable-mir/check_foreign.rs | 1 - tests/ui-fulldeps/stable-mir/check_instance.rs | 1 - tests/ui-fulldeps/stable-mir/check_item_kind.rs | 1 - .../stable-mir/check_trait_queries.rs | 1 - tests/ui-fulldeps/stable-mir/check_transform.rs | 1 - tests/ui-fulldeps/stable-mir/check_ty_fold.rs | 1 - tests/ui-fulldeps/stable-mir/crate-info.rs | 1 - tests/ui-fulldeps/stable-mir/projections.rs | 1 - tests/ui-fulldeps/stable-mir/smir_internal.rs | 1 - tests/ui-fulldeps/stable-mir/smir_serde.rs | 1 - tests/ui-fulldeps/stable-mir/smir_visitor.rs | 1 - tests/ui/try-trait/bad-interconversion.rs | 2 -- tests/ui/try-trait/bad-interconversion.stderr | 16 ++++++++-------- tests/ui/try-trait/try-operator-custom.rs | 1 - 21 files changed, 8 insertions(+), 29 deletions(-) diff --git a/tests/mir-opt/jump_threading.rs b/tests/mir-opt/jump_threading.rs index 9487a4e7e5f..76be3c71fab 100644 --- a/tests/mir-opt/jump_threading.rs +++ b/tests/mir-opt/jump_threading.rs @@ -2,7 +2,6 @@ //@ compile-flags: -Zmir-enable-passes=+Inline // EMIT_MIR_FOR_EACH_PANIC_STRATEGY -#![feature(control_flow_enum)] #![feature(try_trait_v2)] #![feature(custom_mir, core_intrinsics, rustc_attrs)] diff --git a/tests/mir-opt/separate_const_switch.rs b/tests/mir-opt/separate_const_switch.rs index 5e8371b3e49..05835942980 100644 --- a/tests/mir-opt/separate_const_switch.rs +++ b/tests/mir-opt/separate_const_switch.rs @@ -1,5 +1,4 @@ // skip-filecheck -#![feature(control_flow_enum)] #![feature(try_trait_v2)] //@ compile-flags: -Zunsound-mir-opts diff --git a/tests/ui-fulldeps/stable-mir/check_abi.rs b/tests/ui-fulldeps/stable-mir/check_abi.rs index 7518ea902ec..5b7da7bb129 100644 --- a/tests/ui-fulldeps/stable-mir/check_abi.rs +++ b/tests/ui-fulldeps/stable-mir/check_abi.rs @@ -8,7 +8,6 @@ #![feature(rustc_private)] #![feature(assert_matches)] -#![feature(control_flow_enum)] #![feature(ascii_char, ascii_char_variants)] extern crate rustc_hir; diff --git a/tests/ui-fulldeps/stable-mir/check_allocation.rs b/tests/ui-fulldeps/stable-mir/check_allocation.rs index 7752ff51ac8..1e2f640f39f 100644 --- a/tests/ui-fulldeps/stable-mir/check_allocation.rs +++ b/tests/ui-fulldeps/stable-mir/check_allocation.rs @@ -10,7 +10,6 @@ #![feature(rustc_private)] #![feature(assert_matches)] -#![feature(control_flow_enum)] #![feature(ascii_char, ascii_char_variants)] extern crate rustc_hir; diff --git a/tests/ui-fulldeps/stable-mir/check_attribute.rs b/tests/ui-fulldeps/stable-mir/check_attribute.rs index be52853a479..131fd99ebaa 100644 --- a/tests/ui-fulldeps/stable-mir/check_attribute.rs +++ b/tests/ui-fulldeps/stable-mir/check_attribute.rs @@ -7,7 +7,6 @@ //@ ignore-windows-gnu mingw has troubles with linking https://github.com/rust-lang/rust/pull/116837 #![feature(rustc_private)] -#![feature(control_flow_enum)] extern crate rustc_hir; #[macro_use] diff --git a/tests/ui-fulldeps/stable-mir/check_def_ty.rs b/tests/ui-fulldeps/stable-mir/check_def_ty.rs index 9f45b62d343..ec3cf1753e2 100644 --- a/tests/ui-fulldeps/stable-mir/check_def_ty.rs +++ b/tests/ui-fulldeps/stable-mir/check_def_ty.rs @@ -10,7 +10,6 @@ #![feature(rustc_private)] #![feature(assert_matches)] -#![feature(control_flow_enum)] #[macro_use] extern crate rustc_smir; diff --git a/tests/ui-fulldeps/stable-mir/check_defs.rs b/tests/ui-fulldeps/stable-mir/check_defs.rs index 5bb1053f187..3402b345818 100644 --- a/tests/ui-fulldeps/stable-mir/check_defs.rs +++ b/tests/ui-fulldeps/stable-mir/check_defs.rs @@ -9,7 +9,6 @@ #![feature(rustc_private)] #![feature(assert_matches)] -#![feature(control_flow_enum)] #[macro_use] extern crate rustc_smir; diff --git a/tests/ui-fulldeps/stable-mir/check_foreign.rs b/tests/ui-fulldeps/stable-mir/check_foreign.rs index 06d2af4ac8a..4acbabbb6be 100644 --- a/tests/ui-fulldeps/stable-mir/check_foreign.rs +++ b/tests/ui-fulldeps/stable-mir/check_foreign.rs @@ -9,7 +9,6 @@ #![feature(rustc_private)] #![feature(assert_matches)] -#![feature(control_flow_enum)] extern crate rustc_middle; #[macro_use] diff --git a/tests/ui-fulldeps/stable-mir/check_instance.rs b/tests/ui-fulldeps/stable-mir/check_instance.rs index 68eb3c54593..7d63e202fa6 100644 --- a/tests/ui-fulldeps/stable-mir/check_instance.rs +++ b/tests/ui-fulldeps/stable-mir/check_instance.rs @@ -9,7 +9,6 @@ #![feature(rustc_private)] #![feature(assert_matches)] -#![feature(control_flow_enum)] #[macro_use] extern crate rustc_smir; diff --git a/tests/ui-fulldeps/stable-mir/check_item_kind.rs b/tests/ui-fulldeps/stable-mir/check_item_kind.rs index 1d5b19304c1..91baa074c10 100644 --- a/tests/ui-fulldeps/stable-mir/check_item_kind.rs +++ b/tests/ui-fulldeps/stable-mir/check_item_kind.rs @@ -9,7 +9,6 @@ #![feature(rustc_private)] #![feature(assert_matches)] -#![feature(control_flow_enum)] #[macro_use] extern crate rustc_smir; diff --git a/tests/ui-fulldeps/stable-mir/check_trait_queries.rs b/tests/ui-fulldeps/stable-mir/check_trait_queries.rs index 5098547c2c8..8721f243587 100644 --- a/tests/ui-fulldeps/stable-mir/check_trait_queries.rs +++ b/tests/ui-fulldeps/stable-mir/check_trait_queries.rs @@ -9,7 +9,6 @@ #![feature(rustc_private)] #![feature(assert_matches)] -#![feature(control_flow_enum)] #[macro_use] extern crate rustc_smir; diff --git a/tests/ui-fulldeps/stable-mir/check_transform.rs b/tests/ui-fulldeps/stable-mir/check_transform.rs index 1d3e4c6845b..40217b9aa95 100644 --- a/tests/ui-fulldeps/stable-mir/check_transform.rs +++ b/tests/ui-fulldeps/stable-mir/check_transform.rs @@ -8,7 +8,6 @@ #![feature(rustc_private)] #![feature(assert_matches)] -#![feature(control_flow_enum)] #![feature(ascii_char, ascii_char_variants)] extern crate rustc_hir; diff --git a/tests/ui-fulldeps/stable-mir/check_ty_fold.rs b/tests/ui-fulldeps/stable-mir/check_ty_fold.rs index 0b8cfcf27fd..0715e0cfc52 100644 --- a/tests/ui-fulldeps/stable-mir/check_ty_fold.rs +++ b/tests/ui-fulldeps/stable-mir/check_ty_fold.rs @@ -10,7 +10,6 @@ #![feature(rustc_private)] #![feature(assert_matches)] -#![feature(control_flow_enum)] #[macro_use] extern crate rustc_smir; diff --git a/tests/ui-fulldeps/stable-mir/crate-info.rs b/tests/ui-fulldeps/stable-mir/crate-info.rs index 4c9a8a665b8..6b458c5d923 100644 --- a/tests/ui-fulldeps/stable-mir/crate-info.rs +++ b/tests/ui-fulldeps/stable-mir/crate-info.rs @@ -9,7 +9,6 @@ #![feature(rustc_private)] #![feature(assert_matches)] -#![feature(control_flow_enum)] extern crate rustc_hir; #[macro_use] diff --git a/tests/ui-fulldeps/stable-mir/projections.rs b/tests/ui-fulldeps/stable-mir/projections.rs index d68e7d37950..a8bf4c1d399 100644 --- a/tests/ui-fulldeps/stable-mir/projections.rs +++ b/tests/ui-fulldeps/stable-mir/projections.rs @@ -9,7 +9,6 @@ #![feature(rustc_private)] #![feature(assert_matches)] -#![feature(control_flow_enum)] extern crate rustc_hir; #[macro_use] diff --git a/tests/ui-fulldeps/stable-mir/smir_internal.rs b/tests/ui-fulldeps/stable-mir/smir_internal.rs index 07f404fd471..6f5478c08bf 100644 --- a/tests/ui-fulldeps/stable-mir/smir_internal.rs +++ b/tests/ui-fulldeps/stable-mir/smir_internal.rs @@ -10,7 +10,6 @@ #![feature(rustc_private)] #![feature(assert_matches)] -#![feature(control_flow_enum)] #[macro_use] extern crate rustc_smir; diff --git a/tests/ui-fulldeps/stable-mir/smir_serde.rs b/tests/ui-fulldeps/stable-mir/smir_serde.rs index 957d840f7a2..7dbf892f9e4 100644 --- a/tests/ui-fulldeps/stable-mir/smir_serde.rs +++ b/tests/ui-fulldeps/stable-mir/smir_serde.rs @@ -9,7 +9,6 @@ #![feature(rustc_private)] #![feature(assert_matches)] -#![feature(control_flow_enum)] #[macro_use] extern crate rustc_smir; diff --git a/tests/ui-fulldeps/stable-mir/smir_visitor.rs b/tests/ui-fulldeps/stable-mir/smir_visitor.rs index ac428c80e0f..f1bc03781b9 100644 --- a/tests/ui-fulldeps/stable-mir/smir_visitor.rs +++ b/tests/ui-fulldeps/stable-mir/smir_visitor.rs @@ -9,7 +9,6 @@ #![feature(rustc_private)] #![feature(assert_matches)] -#![feature(control_flow_enum)] #[macro_use] extern crate rustc_smir; diff --git a/tests/ui/try-trait/bad-interconversion.rs b/tests/ui/try-trait/bad-interconversion.rs index 385f5510fb4..9c45bde8898 100644 --- a/tests/ui/try-trait/bad-interconversion.rs +++ b/tests/ui/try-trait/bad-interconversion.rs @@ -1,5 +1,3 @@ -#![feature(control_flow_enum)] - use std::ops::ControlFlow; fn result_to_result() -> Result { diff --git a/tests/ui/try-trait/bad-interconversion.stderr b/tests/ui/try-trait/bad-interconversion.stderr index 9aab2cf6ab8..82877baef3e 100644 --- a/tests/ui/try-trait/bad-interconversion.stderr +++ b/tests/ui/try-trait/bad-interconversion.stderr @@ -1,5 +1,5 @@ error[E0277]: `?` couldn't convert the error to `u8` - --> $DIR/bad-interconversion.rs:6:20 + --> $DIR/bad-interconversion.rs:4:20 | LL | fn result_to_result() -> Result { | --------------- expected `u8` because of this @@ -15,7 +15,7 @@ LL | Ok(Err(123_i32)?) = note: required for `Result` to implement `FromResidual>` error[E0277]: the `?` operator can only be used on `Result`s, not `Option`s, in a function that returns `Result` - --> $DIR/bad-interconversion.rs:11:12 + --> $DIR/bad-interconversion.rs:9:12 | LL | fn option_to_result() -> Result { | -------------------------------------------- this function returns a `Result` @@ -26,7 +26,7 @@ LL | Some(3)?; = help: the trait `FromResidual>` is implemented for `Result` error[E0277]: the `?` operator can only be used on `Result`s in a function that returns `Result` - --> $DIR/bad-interconversion.rs:17:31 + --> $DIR/bad-interconversion.rs:15:31 | LL | fn control_flow_to_result() -> Result { | -------------------------------------------------- this function returns a `Result` @@ -37,7 +37,7 @@ LL | Ok(ControlFlow::Break(123)?) = help: the trait `FromResidual>` is implemented for `Result` error[E0277]: the `?` operator can only be used on `Option`s, not `Result`s, in a function that returns `Option` - --> $DIR/bad-interconversion.rs:22:22 + --> $DIR/bad-interconversion.rs:20:22 | LL | fn result_to_option() -> Option { | ------------------------------------ this function returns an `Option` @@ -48,7 +48,7 @@ LL | Some(Err("hello")?) = help: the trait `FromResidual>` is implemented for `Option` error[E0277]: the `?` operator can only be used on `Option`s in a function that returns `Option` - --> $DIR/bad-interconversion.rs:27:33 + --> $DIR/bad-interconversion.rs:25:33 | LL | fn control_flow_to_option() -> Option { | ------------------------------------------ this function returns an `Option` @@ -59,7 +59,7 @@ LL | Some(ControlFlow::Break(123)?) = help: the trait `FromResidual>` is implemented for `Option` error[E0277]: the `?` operator can only be used on `ControlFlow`s in a function that returns `ControlFlow` - --> $DIR/bad-interconversion.rs:32:39 + --> $DIR/bad-interconversion.rs:30:39 | LL | fn result_to_control_flow() -> ControlFlow { | -------------------------------------------------- this function returns a `ControlFlow` @@ -71,7 +71,7 @@ LL | ControlFlow::Continue(Err("hello")?) = help: for that trait implementation, expected `ControlFlow`, found `Result` error[E0277]: the `?` operator can only be used on `ControlFlow`s in a function that returns `ControlFlow` - --> $DIR/bad-interconversion.rs:37:12 + --> $DIR/bad-interconversion.rs:35:12 | LL | fn option_to_control_flow() -> ControlFlow { | ----------------------------------------------- this function returns a `ControlFlow` @@ -83,7 +83,7 @@ LL | Some(3)?; = help: for that trait implementation, expected `ControlFlow`, found `Option` error[E0277]: the `?` operator in a function that returns `ControlFlow` can only be used on other `ControlFlow`s (with the same Break type) - --> $DIR/bad-interconversion.rs:43:29 + --> $DIR/bad-interconversion.rs:41:29 | LL | fn control_flow_to_control_flow() -> ControlFlow { | ----------------------------------------------------- this function returns a `ControlFlow` diff --git a/tests/ui/try-trait/try-operator-custom.rs b/tests/ui/try-trait/try-operator-custom.rs index 936c0b0689a..ebeb0869f98 100644 --- a/tests/ui/try-trait/try-operator-custom.rs +++ b/tests/ui/try-trait/try-operator-custom.rs @@ -1,6 +1,5 @@ //@ run-pass -#![feature(control_flow_enum)] #![feature(try_trait_v2)] use std::ops::{ControlFlow, FromResidual, Try}; From 58921874cb2bc9ac1eb1ebcd6635d3611c0b6bb1 Mon Sep 17 00:00:00 2001 From: makai410 Date: Thu, 26 Sep 2024 10:18:18 +0800 Subject: [PATCH 279/683] Fix the misleading diagnostic for let_underscore_drop on type without Drop implementation --- compiler/rustc_lint/messages.ftl | 2 +- compiler/rustc_lint/src/let_underscore.rs | 2 +- tests/ui/lint/let_underscore/issue-119696-err-on-fn.rs | 2 +- tests/ui/lint/let_underscore/issue-119696-err-on-fn.stderr | 2 +- tests/ui/lint/let_underscore/issue-119697-extra-let.rs | 4 ++-- tests/ui/lint/let_underscore/issue-119697-extra-let.stderr | 4 ++-- tests/ui/lint/let_underscore/let_underscore_drop.rs | 2 +- tests/ui/lint/let_underscore/let_underscore_drop.stderr | 2 +- 8 files changed, 10 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index 375cfccbe9f..a286ccb22c7 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -531,7 +531,7 @@ lint_non_binding_let_multi_suggestion = consider immediately dropping the value lint_non_binding_let_on_drop_type = - non-binding let on a type that implements `Drop` + non-binding let on a type that has a destructor lint_non_binding_let_on_sync_lock = non-binding let on a synchronization lock .label = this lock is not assigned to a binding and is immediately dropped diff --git a/compiler/rustc_lint/src/let_underscore.rs b/compiler/rustc_lint/src/let_underscore.rs index a12a97ee573..abee9ee7869 100644 --- a/compiler/rustc_lint/src/let_underscore.rs +++ b/compiler/rustc_lint/src/let_underscore.rs @@ -51,7 +51,7 @@ declare_lint! { /// intent. pub LET_UNDERSCORE_DROP, Allow, - "non-binding let on a type that implements `Drop`" + "non-binding let on a type that has a destructor" } declare_lint! { diff --git a/tests/ui/lint/let_underscore/issue-119696-err-on-fn.rs b/tests/ui/lint/let_underscore/issue-119696-err-on-fn.rs index b885352dfd9..0973e2f1637 100644 --- a/tests/ui/lint/let_underscore/issue-119696-err-on-fn.rs +++ b/tests/ui/lint/let_underscore/issue-119696-err-on-fn.rs @@ -2,7 +2,7 @@ #![deny(let_underscore_drop)] fn main() { - let _ = foo(); //~ ERROR non-binding let on a type that implements `Drop` + let _ = foo(); //~ ERROR non-binding let on a type that has a destructor } async fn from_config(_: Config) {} diff --git a/tests/ui/lint/let_underscore/issue-119696-err-on-fn.stderr b/tests/ui/lint/let_underscore/issue-119696-err-on-fn.stderr index 86e521580b8..70f9979556a 100644 --- a/tests/ui/lint/let_underscore/issue-119696-err-on-fn.stderr +++ b/tests/ui/lint/let_underscore/issue-119696-err-on-fn.stderr @@ -1,4 +1,4 @@ -error: non-binding let on a type that implements `Drop` +error: non-binding let on a type that has a destructor --> $DIR/issue-119696-err-on-fn.rs:5:5 | LL | let _ = foo(); diff --git a/tests/ui/lint/let_underscore/issue-119697-extra-let.rs b/tests/ui/lint/let_underscore/issue-119697-extra-let.rs index 1dc80a123f6..84abb933911 100644 --- a/tests/ui/lint/let_underscore/issue-119697-extra-let.rs +++ b/tests/ui/lint/let_underscore/issue-119697-extra-let.rs @@ -12,9 +12,9 @@ pub fn ice_cold(beverage: Tait) { // Must destructure at least one field of `Foo` let Foo { field } = beverage; // boom - _ = field; //~ ERROR non-binding let on a type that implements `Drop` + _ = field; //~ ERROR non-binding let on a type that has a destructor - let _ = field; //~ ERROR non-binding let on a type that implements `Drop` + let _ = field; //~ ERROR non-binding let on a type that has a destructor } diff --git a/tests/ui/lint/let_underscore/issue-119697-extra-let.stderr b/tests/ui/lint/let_underscore/issue-119697-extra-let.stderr index 16df2c720ea..e4b1872bba5 100644 --- a/tests/ui/lint/let_underscore/issue-119697-extra-let.stderr +++ b/tests/ui/lint/let_underscore/issue-119697-extra-let.stderr @@ -1,4 +1,4 @@ -error: non-binding let on a type that implements `Drop` +error: non-binding let on a type that has a destructor --> $DIR/issue-119697-extra-let.rs:15:5 | LL | _ = field; @@ -18,7 +18,7 @@ help: consider immediately dropping the value LL | drop(field); | ~~~~~ + -error: non-binding let on a type that implements `Drop` +error: non-binding let on a type that has a destructor --> $DIR/issue-119697-extra-let.rs:17:5 | LL | let _ = field; diff --git a/tests/ui/lint/let_underscore/let_underscore_drop.rs b/tests/ui/lint/let_underscore/let_underscore_drop.rs index 58988ec05d7..f5a5e4299a1 100644 --- a/tests/ui/lint/let_underscore/let_underscore_drop.rs +++ b/tests/ui/lint/let_underscore/let_underscore_drop.rs @@ -10,7 +10,7 @@ impl Drop for NontrivialDrop { } fn main() { - let _ = NontrivialDrop; //~WARNING non-binding let on a type that implements `Drop` + let _ = NontrivialDrop; //~WARNING non-binding let on a type that has a destructor let (_, _) = (NontrivialDrop, NontrivialDrop); // This should be ignored. } diff --git a/tests/ui/lint/let_underscore/let_underscore_drop.stderr b/tests/ui/lint/let_underscore/let_underscore_drop.stderr index 7b7de202e46..09f2587063b 100644 --- a/tests/ui/lint/let_underscore/let_underscore_drop.stderr +++ b/tests/ui/lint/let_underscore/let_underscore_drop.stderr @@ -1,4 +1,4 @@ -warning: non-binding let on a type that implements `Drop` +warning: non-binding let on a type that has a destructor --> $DIR/let_underscore_drop.rs:13:5 | LL | let _ = NontrivialDrop; From 1bef68c4cb5e84ebcca5ed636a1a38460eb412dd Mon Sep 17 00:00:00 2001 From: Taiki Endo Date: Thu, 26 Sep 2024 12:52:35 +0900 Subject: [PATCH 280/683] Update FIXME comment in s390x_unknown_linux_*.rs --- .../rustc_target/src/spec/targets/s390x_unknown_linux_gnu.rs | 5 ++--- .../src/spec/targets/s390x_unknown_linux_musl.rs | 5 ++--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_target/src/spec/targets/s390x_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/s390x_unknown_linux_gnu.rs index a8163e228e6..3efbb464836 100644 --- a/compiler/rustc_target/src/spec/targets/s390x_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/targets/s390x_unknown_linux_gnu.rs @@ -6,9 +6,8 @@ pub(crate) fn target() -> Target { base.endian = Endian::Big; // z10 is the oldest CPU supported by LLVM base.cpu = "z10".into(); - // FIXME: The ABI implementation in cabi_s390x.rs is for now hard-coded to assume the no-vector - // ABI. Pass the -vector feature string to LLVM to respect this assumption. On LLVM < 16, we - // also strip v128 from the data_layout below to match the older LLVM's expectation. + // FIXME: The ABI implementation in abi/call/s390x.rs is for now hard-coded to assume the no-vector + // ABI. Pass the -vector feature string to LLVM to respect this assumption. base.features = "-vector".into(); base.max_atomic_width = Some(128); base.min_global_align = Some(16); diff --git a/compiler/rustc_target/src/spec/targets/s390x_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/targets/s390x_unknown_linux_musl.rs index e52bcc987f9..65b5c1167bd 100644 --- a/compiler/rustc_target/src/spec/targets/s390x_unknown_linux_musl.rs +++ b/compiler/rustc_target/src/spec/targets/s390x_unknown_linux_musl.rs @@ -6,9 +6,8 @@ pub(crate) fn target() -> Target { base.endian = Endian::Big; // z10 is the oldest CPU supported by LLVM base.cpu = "z10".into(); - // FIXME: The ABI implementation in cabi_s390x.rs is for now hard-coded to assume the no-vector - // ABI. Pass the -vector feature string to LLVM to respect this assumption. On LLVM < 16, we - // also strip v128 from the data_layout below to match the older LLVM's expectation. + // FIXME: The ABI implementation in abi/call/s390x.rs is for now hard-coded to assume the no-vector + // ABI. Pass the -vector feature string to LLVM to respect this assumption. base.features = "-vector".into(); base.max_atomic_width = Some(128); base.min_global_align = Some(16); From 824884d743c042cde47a532173b74967f10195ab Mon Sep 17 00:00:00 2001 From: The Miri Cronjob Bot Date: Thu, 26 Sep 2024 05:15:46 +0000 Subject: [PATCH 281/683] Preparing for merge from rustc --- src/tools/miri/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index 79ed6cc7d74..b05c409f823 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -1b5aa96d6016bafe50e071b45d4d2e3c90fd766f +76ed7a1fa40c3f54d3fd3f834e12bf9c932d0146 From adbaf13d32f09d134f04b3af77517500f8fd3e86 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 26 Sep 2024 09:18:14 +0200 Subject: [PATCH 282/683] bump rustc-build-sysroot version --- src/tools/miri/cargo-miri/Cargo.lock | 4 ++-- src/tools/miri/cargo-miri/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/tools/miri/cargo-miri/Cargo.lock b/src/tools/miri/cargo-miri/Cargo.lock index 7369a3fbf09..a873472fd5d 100644 --- a/src/tools/miri/cargo-miri/Cargo.lock +++ b/src/tools/miri/cargo-miri/Cargo.lock @@ -190,9 +190,9 @@ dependencies = [ [[package]] name = "rustc-build-sysroot" -version = "0.5.3" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2471f8f296262437d7e848e527b4210b44a96e53a3b4435b890227ce3e6da106" +checksum = "d6d984a9db43148467059309bd1e5ad577085162f695d9fe2cf3543aeb25cd38" dependencies = [ "anyhow", "rustc_version", diff --git a/src/tools/miri/cargo-miri/Cargo.toml b/src/tools/miri/cargo-miri/Cargo.toml index 477c60db162..ee2004278b4 100644 --- a/src/tools/miri/cargo-miri/Cargo.toml +++ b/src/tools/miri/cargo-miri/Cargo.toml @@ -18,7 +18,7 @@ directories = "5" rustc_version = "0.4" serde_json = "1.0.40" cargo_metadata = "0.18.0" -rustc-build-sysroot = "0.5.3" +rustc-build-sysroot = "0.5.4" # Enable some feature flags that dev-dependencies need but dependencies # do not. This makes `./miri install` after `./miri build` faster. From 294fdb820c16ebba2bfa442e53b659752aa48a0d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 26 Sep 2024 09:28:23 +0200 Subject: [PATCH 283/683] clippy --- src/tools/miri/cargo-miri/src/phases.rs | 2 ++ src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs | 2 +- src/tools/miri/src/shims/unix/linux/epoll.rs | 6 +++--- src/tools/miri/src/shims/unix/linux/eventfd.rs | 2 +- 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/tools/miri/cargo-miri/src/phases.rs b/src/tools/miri/cargo-miri/src/phases.rs index 3743446e276..e13ecbbe54b 100644 --- a/src/tools/miri/cargo-miri/src/phases.rs +++ b/src/tools/miri/cargo-miri/src/phases.rs @@ -666,6 +666,8 @@ pub fn phase_runner(mut binary_args: impl Iterator, phase: Runner match phase { RunnerPhase::Rustdoc => { cmd.stdin(std::process::Stdio::piped()); + // the warning is wrong, we have a `wait` inside the `scope` closure. + #[expect(clippy::zombie_processes)] let mut child = cmd.spawn().expect("failed to spawn process"); let child_stdin = child.stdin.take().unwrap(); // Write stdin in a background thread, as it may block. diff --git a/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs b/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs index f792e75ad08..7eb67730383 100644 --- a/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs +++ b/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs @@ -171,7 +171,7 @@ impl NewPermission { /// F2b: No `SharedReadWrite` or `Unique` will ever be added on top of our `SharedReadOnly`. /// F3: If an access happens with an `&` outside `UnsafeCell`, /// it requires the `SharedReadOnly` to still be in the stack. - +/// /// Core relation on `Permission` to define which accesses are allowed impl Permission { /// This defines for a given permission, whether it permits the given kind of access. diff --git a/src/tools/miri/src/shims/unix/linux/epoll.rs b/src/tools/miri/src/shims/unix/linux/epoll.rs index 3d4fe770e99..b63c29594b4 100644 --- a/src/tools/miri/src/shims/unix/linux/epoll.rs +++ b/src/tools/miri/src/shims/unix/linux/epoll.rs @@ -401,19 +401,19 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { /// list about file descriptors in the interest list that have some /// events available. Up to `maxevents` are returned by `epoll_wait()`. /// The `maxevents` argument must be greater than zero. - + /// /// The `timeout` argument specifies the number of milliseconds that /// `epoll_wait()` will block. Time is measured against the /// CLOCK_MONOTONIC clock. If the timeout is zero, the function will not block, /// while if the timeout is -1, the function will block /// until at least one event has been retrieved (or an error /// occurred). - + /// /// A call to `epoll_wait()` will block until either: /// • a file descriptor delivers an event; /// • the call is interrupted by a signal handler; or /// • the timeout expires. - + /// /// Note that the timeout interval will be rounded up to the system /// clock granularity, and kernel scheduling delays mean that the /// blocking interval may overrun by a small amount. Specifying a diff --git a/src/tools/miri/src/shims/unix/linux/eventfd.rs b/src/tools/miri/src/shims/unix/linux/eventfd.rs index d1d461daa99..9fbabbd9641 100644 --- a/src/tools/miri/src/shims/unix/linux/eventfd.rs +++ b/src/tools/miri/src/shims/unix/linux/eventfd.rs @@ -110,7 +110,7 @@ impl FileDescription for Event { /// write either blocks until a read is performed on the /// file descriptor, or fails with the error EAGAIN if the /// file descriptor has been made nonblocking. - + /// /// A write fails with the error EINVAL if the size of the /// supplied buffer is less than 8 bytes, or if an attempt is /// made to write the value 0xffffffffffffffff. From 36455c6f6b6e4e626bbcb0144dfac5ccfb30e5ba Mon Sep 17 00:00:00 2001 From: Taiki Endo Date: Thu, 26 Sep 2024 16:43:04 +0900 Subject: [PATCH 284/683] rustc_target: Add powerpc64 atomic-related features --- compiler/rustc_target/src/target_features.rs | 2 ++ tests/ui/check-cfg/mix.stderr | 2 +- tests/ui/check-cfg/well-known-values.stderr | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs index b9e86269d45..be14107baa9 100644 --- a/compiler/rustc_target/src/target_features.rs +++ b/compiler/rustc_target/src/target_features.rs @@ -352,11 +352,13 @@ const HEXAGON_ALLOWED_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ const POWERPC_ALLOWED_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ // tidy-alphabetical-start ("altivec", Unstable(sym::powerpc_target_feature), &[]), + ("partword-atomics", Unstable(sym::powerpc_target_feature), &[]), ("power10-vector", Unstable(sym::powerpc_target_feature), &["power9-vector"]), ("power8-altivec", Unstable(sym::powerpc_target_feature), &["altivec"]), ("power8-vector", Unstable(sym::powerpc_target_feature), &["vsx", "power8-altivec"]), ("power9-altivec", Unstable(sym::powerpc_target_feature), &["power8-altivec"]), ("power9-vector", Unstable(sym::powerpc_target_feature), &["power8-vector", "power9-altivec"]), + ("quadword-atomics", Unstable(sym::powerpc_target_feature), &[]), ("vsx", Unstable(sym::powerpc_target_feature), &["altivec"]), // tidy-alphabetical-end ]; diff --git a/tests/ui/check-cfg/mix.stderr b/tests/ui/check-cfg/mix.stderr index a163728b51d..653c1c983e2 100644 --- a/tests/ui/check-cfg/mix.stderr +++ b/tests/ui/check-cfg/mix.stderr @@ -251,7 +251,7 @@ warning: unexpected `cfg` condition value: `zebra` LL | cfg!(target_feature = "zebra"); | ^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: expected values for `target_feature` are: `10e60`, `2e3`, `3e3r1`, `3e3r2`, `3e3r3`, `3e7`, `7e10`, `a`, `aclass`, `adx`, `aes`, `altivec`, `alu32`, `amx-bf16`, `amx-complex`, `amx-fp16`, `amx-int8`, `amx-tile`, `atomics`, `avx`, `avx2`, `avx512bf16`, `avx512bitalg`, `avx512bw`, `avx512cd`, `avx512dq`, `avx512f`, `avx512fp16`, `avx512ifma`, `avx512vbmi`, `avx512vbmi2`, `avx512vl`, `avx512vnni`, `avx512vp2intersect`, and `avx512vpopcntdq` and 239 more + = note: expected values for `target_feature` are: `10e60`, `2e3`, `3e3r1`, `3e3r2`, `3e3r3`, `3e7`, `7e10`, `a`, `aclass`, `adx`, `aes`, `altivec`, `alu32`, `amx-bf16`, `amx-complex`, `amx-fp16`, `amx-int8`, `amx-tile`, `atomics`, `avx`, `avx2`, `avx512bf16`, `avx512bitalg`, `avx512bw`, `avx512cd`, `avx512dq`, `avx512f`, `avx512fp16`, `avx512ifma`, `avx512vbmi`, `avx512vbmi2`, `avx512vl`, `avx512vnni`, `avx512vp2intersect`, and `avx512vpopcntdq` and 241 more = note: see for more information about checking conditional configuration warning: 27 warnings emitted diff --git a/tests/ui/check-cfg/well-known-values.stderr b/tests/ui/check-cfg/well-known-values.stderr index 144a67025b3..14832e7ff43 100644 --- a/tests/ui/check-cfg/well-known-values.stderr +++ b/tests/ui/check-cfg/well-known-values.stderr @@ -174,7 +174,7 @@ warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` LL | target_feature = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: expected values for `target_feature` are: `10e60`, `2e3`, `3e3r1`, `3e3r2`, `3e3r3`, `3e7`, `7e10`, `a`, `aclass`, `adx`, `aes`, `altivec`, `alu32`, `amx-bf16`, `amx-complex`, `amx-fp16`, `amx-int8`, `amx-tile`, `atomics`, `avx`, `avx2`, `avx512bf16`, `avx512bitalg`, `avx512bw`, `avx512cd`, `avx512dq`, `avx512f`, `avx512fp16`, `avx512ifma`, `avx512vbmi`, `avx512vbmi2`, `avx512vl`, `avx512vnni`, `avx512vp2intersect`, `avx512vpopcntdq`, `avxifma`, `avxneconvert`, `avxvnni`, `avxvnniint16`, `avxvnniint8`, `backchain`, `bf16`, `bmi1`, `bmi2`, `bti`, `bulk-memory`, `c`, `cache`, `cmpxchg16b`, `crc`, `crt-static`, `cssc`, `d`, `d32`, `dit`, `doloop`, `dotprod`, `dpb`, `dpb2`, `dsp`, `dsp1e2`, `dspe60`, `e`, `e1`, `e2`, `ecv`, `edsp`, `elrw`, `ermsb`, `exception-handling`, `extended-const`, `f`, `f16c`, `f32mm`, `f64mm`, `faminmax`, `fcma`, `fdivdu`, `fhm`, `flagm`, `flagm2`, `float1e2`, `float1e3`, `float3e4`, `float7e60`, `floate1`, `fma`, `fp-armv8`, `fp16`, `fp64`, `fp8`, `fp8dot2`, `fp8dot4`, `fp8fma`, `fpuv2_df`, `fpuv2_sf`, `fpuv3_df`, `fpuv3_hf`, `fpuv3_hi`, `fpuv3_sf`, `frecipe`, `frintts`, `fxsr`, `gfni`, `hard-float`, `hard-float-abi`, `hard-tp`, `hbc`, `high-registers`, `hvx`, `hvx-length128b`, `hwdiv`, `i8mm`, `jsconv`, `lahfsahf`, `lasx`, `lbt`, `lor`, `lse`, `lse128`, `lse2`, `lsx`, `lut`, `lvz`, `lzcnt`, `m`, `mclass`, `mops`, `movbe`, `mp`, `mp1e2`, `msa`, `mte`, `multivalue`, `mutable-globals`, `neon`, `nontrapping-fptoint`, `nvic`, `paca`, `pacg`, `pan`, `pclmulqdq`, `pmuv3`, `popcnt`, `power10-vector`, `power8-altivec`, `power8-vector`, `power9-altivec`, `power9-vector`, `prfchw`, `rand`, `ras`, `rclass`, `rcpc`, `rcpc2`, `rcpc3`, `rdm`, `rdrand`, `rdseed`, `reference-types`, `relax`, `relaxed-simd`, `rtm`, `sb`, `sha`, `sha2`, `sha3`, `sha512`, `sign-ext`, `simd128`, `sm3`, `sm4`, `sme`, `sme-f16f16`, `sme-f64f64`, `sme-f8f16`, `sme-f8f32`, `sme-fa64`, `sme-i16i64`, `sme-lutv2`, `sme2`, `sme2p1`, `spe`, `ssbs`, `sse`, `sse2`, `sse3`, `sse4.1`, `sse4.2`, `sse4a`, `ssse3`, `ssve-fp8dot2`, `ssve-fp8dot4`, `ssve-fp8fma`, `sve`, `sve-b16b16`, `sve2`, `sve2-aes`, `sve2-bitperm`, `sve2-sha3`, `sve2-sm4`, `sve2p1`, `tbm`, `thumb-mode`, `thumb2`, `tme`, `trust`, `trustzone`, `ual`, `unaligned-scalar-mem`, `v`, `v5te`, `v6`, `v6k`, `v6t2`, `v7`, `v8`, `v8.1a`, `v8.2a`, `v8.3a`, `v8.4a`, `v8.5a`, `v8.6a`, `v8.7a`, `v8.8a`, `v8.9a`, `v9.1a`, `v9.2a`, `v9.3a`, `v9.4a`, `v9.5a`, `v9a`, `vaes`, `vdsp2e60f`, `vdspv1`, `vdspv2`, `vector`, `vfp2`, `vfp3`, `vfp4`, `vh`, `virt`, `virtualization`, `vpclmulqdq`, `vsx`, `wfxt`, `xop`, `xsave`, `xsavec`, `xsaveopt`, `xsaves`, `zba`, `zbb`, `zbc`, `zbkb`, `zbkc`, `zbkx`, `zbs`, `zdinx`, `zfh`, `zfhmin`, `zfinx`, `zhinx`, `zhinxmin`, `zk`, `zkn`, `zknd`, `zkne`, `zknh`, `zkr`, `zks`, `zksed`, `zksh`, and `zkt` + = note: expected values for `target_feature` are: `10e60`, `2e3`, `3e3r1`, `3e3r2`, `3e3r3`, `3e7`, `7e10`, `a`, `aclass`, `adx`, `aes`, `altivec`, `alu32`, `amx-bf16`, `amx-complex`, `amx-fp16`, `amx-int8`, `amx-tile`, `atomics`, `avx`, `avx2`, `avx512bf16`, `avx512bitalg`, `avx512bw`, `avx512cd`, `avx512dq`, `avx512f`, `avx512fp16`, `avx512ifma`, `avx512vbmi`, `avx512vbmi2`, `avx512vl`, `avx512vnni`, `avx512vp2intersect`, `avx512vpopcntdq`, `avxifma`, `avxneconvert`, `avxvnni`, `avxvnniint16`, `avxvnniint8`, `backchain`, `bf16`, `bmi1`, `bmi2`, `bti`, `bulk-memory`, `c`, `cache`, `cmpxchg16b`, `crc`, `crt-static`, `cssc`, `d`, `d32`, `dit`, `doloop`, `dotprod`, `dpb`, `dpb2`, `dsp`, `dsp1e2`, `dspe60`, `e`, `e1`, `e2`, `ecv`, `edsp`, `elrw`, `ermsb`, `exception-handling`, `extended-const`, `f`, `f16c`, `f32mm`, `f64mm`, `faminmax`, `fcma`, `fdivdu`, `fhm`, `flagm`, `flagm2`, `float1e2`, `float1e3`, `float3e4`, `float7e60`, `floate1`, `fma`, `fp-armv8`, `fp16`, `fp64`, `fp8`, `fp8dot2`, `fp8dot4`, `fp8fma`, `fpuv2_df`, `fpuv2_sf`, `fpuv3_df`, `fpuv3_hf`, `fpuv3_hi`, `fpuv3_sf`, `frecipe`, `frintts`, `fxsr`, `gfni`, `hard-float`, `hard-float-abi`, `hard-tp`, `hbc`, `high-registers`, `hvx`, `hvx-length128b`, `hwdiv`, `i8mm`, `jsconv`, `lahfsahf`, `lasx`, `lbt`, `lor`, `lse`, `lse128`, `lse2`, `lsx`, `lut`, `lvz`, `lzcnt`, `m`, `mclass`, `mops`, `movbe`, `mp`, `mp1e2`, `msa`, `mte`, `multivalue`, `mutable-globals`, `neon`, `nontrapping-fptoint`, `nvic`, `paca`, `pacg`, `pan`, `partword-atomics`, `pclmulqdq`, `pmuv3`, `popcnt`, `power10-vector`, `power8-altivec`, `power8-vector`, `power9-altivec`, `power9-vector`, `prfchw`, `quadword-atomics`, `rand`, `ras`, `rclass`, `rcpc`, `rcpc2`, `rcpc3`, `rdm`, `rdrand`, `rdseed`, `reference-types`, `relax`, `relaxed-simd`, `rtm`, `sb`, `sha`, `sha2`, `sha3`, `sha512`, `sign-ext`, `simd128`, `sm3`, `sm4`, `sme`, `sme-f16f16`, `sme-f64f64`, `sme-f8f16`, `sme-f8f32`, `sme-fa64`, `sme-i16i64`, `sme-lutv2`, `sme2`, `sme2p1`, `spe`, `ssbs`, `sse`, `sse2`, `sse3`, `sse4.1`, `sse4.2`, `sse4a`, `ssse3`, `ssve-fp8dot2`, `ssve-fp8dot4`, `ssve-fp8fma`, `sve`, `sve-b16b16`, `sve2`, `sve2-aes`, `sve2-bitperm`, `sve2-sha3`, `sve2-sm4`, `sve2p1`, `tbm`, `thumb-mode`, `thumb2`, `tme`, `trust`, `trustzone`, `ual`, `unaligned-scalar-mem`, `v`, `v5te`, `v6`, `v6k`, `v6t2`, `v7`, `v8`, `v8.1a`, `v8.2a`, `v8.3a`, `v8.4a`, `v8.5a`, `v8.6a`, `v8.7a`, `v8.8a`, `v8.9a`, `v9.1a`, `v9.2a`, `v9.3a`, `v9.4a`, `v9.5a`, `v9a`, `vaes`, `vdsp2e60f`, `vdspv1`, `vdspv2`, `vector`, `vfp2`, `vfp3`, `vfp4`, `vh`, `virt`, `virtualization`, `vpclmulqdq`, `vsx`, `wfxt`, `xop`, `xsave`, `xsavec`, `xsaveopt`, `xsaves`, `zba`, `zbb`, `zbc`, `zbkb`, `zbkc`, `zbkx`, `zbs`, `zdinx`, `zfh`, `zfhmin`, `zfinx`, `zhinx`, `zhinxmin`, `zk`, `zkn`, `zknd`, `zkne`, `zknh`, `zkr`, `zks`, `zksed`, `zksh`, and `zkt` = note: see for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` From 20c0067528a6b303fe99a753f3afa3703ebc1a68 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Fri, 13 Sep 2024 14:56:29 +0200 Subject: [PATCH 285/683] add a bootstrap variant of `naked_asm` --- library/core/src/arch.rs | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/library/core/src/arch.rs b/library/core/src/arch.rs index be734d194be..4945c045bc6 100644 --- a/library/core/src/arch.rs +++ b/library/core/src/arch.rs @@ -3,6 +3,9 @@ #[allow(unused_imports)] #[stable(feature = "simd_arch", since = "1.27.0")] pub use crate::core_arch::arch::*; +#[unstable(feature = "naked_functions", issue = "90957")] +#[cfg(bootstrap)] +pub use crate::naked_asm; /// Inline assembly. /// @@ -17,6 +20,37 @@ pub macro asm("assembly template", $(operands,)* $(options($(option),*))?) { /* compiler built-in */ } +/// Inline assembly used in combination with `#[naked]` functions. +/// +/// Refer to [Rust By Example] for a usage guide and the [reference] for +/// detailed information about the syntax and available options. +/// +/// [Rust By Example]: https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html +/// [reference]: https://doc.rust-lang.org/nightly/reference/inline-assembly.html +#[unstable(feature = "naked_functions", issue = "90957")] +#[macro_export] +#[cfg(bootstrap)] +macro_rules! naked_asm { + ([$last:expr], [$($pushed:expr),*]) => { + #[cfg(any(target_arch = "x86_64", target_arch = "x86"))] + { + core::arch::asm!($($pushed),*, options(att_syntax, noreturn)) + } + #[cfg(not(any(target_arch = "x86_64", target_arch = "x86")))] + { + core::arch::asm!($($pushed),* , $last, options(noreturn)) + } + }; + + ([$first:expr $(, $rest:expr)*], [$($pushed:expr),*]) => { + naked_asm!([$($rest),*], [$($pushed,)* $first]); + }; + + ($($expr:expr),* $(,)?) => { + naked_asm!([$($expr),*], []); + }; +} + /// Inline assembly used in combination with `#[naked]` functions. /// /// Refer to [Rust By Example] for a usage guide and the [reference] for From 42542d8cda54ade5ce5806147e787a7e48cfd3d8 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Fri, 13 Sep 2024 12:31:27 +0200 Subject: [PATCH 286/683] update `compiler_builtins` to `0.1.126` --- library/Cargo.lock | 4 ++-- library/alloc/Cargo.toml | 2 +- library/std/Cargo.toml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/library/Cargo.lock b/library/Cargo.lock index 2343b2baf83..bec34f87e9f 100644 --- a/library/Cargo.lock +++ b/library/Cargo.lock @@ -58,9 +58,9 @@ dependencies = [ [[package]] name = "compiler_builtins" -version = "0.1.125" +version = "0.1.126" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd02a01d7bc069bed818e956600fe437ee222dd1d6ad92bfb9db87b43b71fd87" +checksum = "758019257ad46e191b587d8f711022a6ac1d1fb6745d75e1d76c587fdcbca770" dependencies = [ "cc", "rustc-std-workspace-core", diff --git a/library/alloc/Cargo.toml b/library/alloc/Cargo.toml index 1da947d196f..1b76b4c4a50 100644 --- a/library/alloc/Cargo.toml +++ b/library/alloc/Cargo.toml @@ -10,7 +10,7 @@ edition = "2021" [dependencies] core = { path = "../core" } -compiler_builtins = { version = "0.1.125", features = ['rustc-dep-of-std'] } +compiler_builtins = { version = "0.1.126", features = ['rustc-dep-of-std'] } [dev-dependencies] rand = { version = "0.8.5", default-features = false, features = ["alloc"] } diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index ea11586f9a5..d55114227af 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -17,7 +17,7 @@ cfg-if = { version = "1.0", features = ['rustc-dep-of-std'] } panic_unwind = { path = "../panic_unwind", optional = true } panic_abort = { path = "../panic_abort" } core = { path = "../core", public = true } -compiler_builtins = { version = "0.1.125" } +compiler_builtins = { version = "0.1.126" } profiler_builtins = { path = "../profiler_builtins", optional = true } unwind = { path = "../unwind" } hashbrown = { version = "0.14", default-features = false, features = [ From 1e241045873cf4aebb5f6fd7ef3a91f32196dbf1 Mon Sep 17 00:00:00 2001 From: Urgau Date: Wed, 25 Sep 2024 13:23:06 +0200 Subject: [PATCH 287/683] Add `[Option; N]::transpose` --- library/core/src/option.rs | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/library/core/src/option.rs b/library/core/src/option.rs index 30c667e2494..f8c631851e7 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -2545,3 +2545,27 @@ impl Option> { } } } + +impl [Option; N] { + /// Transposes a `[Option; N]` into a `Option<[T; N]>`. + /// + /// # Examples + /// + /// ``` + /// #![feature(option_array_transpose)] + /// # use std::option::Option; + /// + /// let data = [Some(0); 1000]; + /// let data: Option<[u8; 1000]> = data.transpose(); + /// assert_eq!(data, Some([0; 1000])); + /// + /// let data = [Some(0), None]; + /// let data: Option<[u8; 2]> = data.transpose(); + /// assert_eq!(data, None); + /// ``` + #[inline] + #[unstable(feature = "option_array_transpose", issue = "130828")] + pub fn transpose(self) -> Option<[T; N]> { + self.try_map(core::convert::identity) + } +} From bf78aec5106c94fe0d490b91f6b2aaac9c4f6a9c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 26 Sep 2024 09:36:11 +0200 Subject: [PATCH 288/683] fix clippy::needless_return --- src/tools/miri/src/concurrency/sync.rs | 2 +- src/tools/miri/src/concurrency/thread.rs | 2 +- src/tools/miri/src/lib.rs | 1 - src/tools/miri/src/shims/alloc.rs | 2 +- src/tools/miri/src/shims/env.rs | 2 +- src/tools/miri/src/shims/unix/fd.rs | 4 ++-- src/tools/miri/src/shims/unix/linux/epoll.rs | 7 ++++--- src/tools/miri/src/shims/windows/foreign_items.rs | 4 ++-- src/tools/miri/src/shims/windows/sync.rs | 2 +- 9 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/tools/miri/src/concurrency/sync.rs b/src/tools/miri/src/concurrency/sync.rs index bc4d8056872..2b34db047f3 100644 --- a/src/tools/miri/src/concurrency/sync.rs +++ b/src/tools/miri/src/concurrency/sync.rs @@ -748,7 +748,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } ), ); - return Ok(()); + Ok(()) } /// Wake up some thread (if there is any) sleeping on the conditional diff --git a/src/tools/miri/src/concurrency/thread.rs b/src/tools/miri/src/concurrency/thread.rs index 4efe2beb155..681e9211246 100644 --- a/src/tools/miri/src/concurrency/thread.rs +++ b/src/tools/miri/src/concurrency/thread.rs @@ -849,7 +849,7 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> { // https://github.com/rust-lang/miri/issues/1763). In this case, // just do nothing, which effectively just returns to the // scheduler. - return Ok(()); + Ok(()) } #[inline] diff --git a/src/tools/miri/src/lib.rs b/src/tools/miri/src/lib.rs index 6e015813e77..aa0d29d38f4 100644 --- a/src/tools/miri/src/lib.rs +++ b/src/tools/miri/src/lib.rs @@ -33,7 +33,6 @@ clippy::too_many_arguments, clippy::type_complexity, clippy::single_element_loop, - clippy::needless_return, clippy::bool_to_int_with_if, clippy::box_default, clippy::needless_question_mark, diff --git a/src/tools/miri/src/shims/alloc.rs b/src/tools/miri/src/shims/alloc.rs index a33657d33a2..057d7ef5e67 100644 --- a/src/tools/miri/src/shims/alloc.rs +++ b/src/tools/miri/src/shims/alloc.rs @@ -71,7 +71,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // and not execute any Miri shim. Somewhat unintuitively doing so is done // by returning `NotSupported`, which triggers the `lookup_exported_symbol` // fallback case in `emulate_foreign_item`. - return Ok(EmulateItemResult::NotSupported); + Ok(EmulateItemResult::NotSupported) } AllocatorKind::Default => { default(this)?; diff --git a/src/tools/miri/src/shims/env.rs b/src/tools/miri/src/shims/env.rs index d12a0581b41..c465ef3d28b 100644 --- a/src/tools/miri/src/shims/env.rs +++ b/src/tools/miri/src/shims/env.rs @@ -103,7 +103,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn get_env_var(&mut self, name: &OsStr) -> InterpResult<'tcx, Option> { let this = self.eval_context_ref(); match &this.machine.env_vars { - EnvVars::Uninit => return Ok(None), + EnvVars::Uninit => Ok(None), EnvVars::Unix(vars) => vars.get(this, name), EnvVars::Windows(vars) => vars.get(name), } diff --git a/src/tools/miri/src/shims/unix/fd.rs b/src/tools/miri/src/shims/unix/fd.rs index 6b78ce7ad47..5fae746af2b 100644 --- a/src/tools/miri/src/shims/unix/fd.rs +++ b/src/tools/miri/src/shims/unix/fd.rs @@ -676,12 +676,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_bytes_ptr(buf, bytes[..read_bytes].iter().copied())?; // The actual read size is always less than what got originally requested so this cannot fail. this.write_int(u64::try_from(read_bytes).unwrap(), dest)?; - return Ok(()); + Ok(()) } Err(e) => { this.set_last_error_from_io_error(e)?; this.write_int(-1, dest)?; - return Ok(()); + Ok(()) } } } diff --git a/src/tools/miri/src/shims/unix/linux/epoll.rs b/src/tools/miri/src/shims/unix/linux/epoll.rs index b63c29594b4..675a404ae11 100644 --- a/src/tools/miri/src/shims/unix/linux/epoll.rs +++ b/src/tools/miri/src/shims/unix/linux/epoll.rs @@ -596,7 +596,7 @@ fn ready_list_next( return Some(epoll_event_instance); } } - return None; + None } /// This helper function checks whether an epoll notification should be triggered for a specific @@ -623,9 +623,10 @@ fn check_and_update_one_event_interest<'tcx>( let event_instance = EpollEventInstance::new(flags, epoll_event_interest.data); // Triggers the notification by inserting it to the ready list. ready_list.insert(epoll_key, event_instance); - return Ok(true); + Ok(true) + } else { + Ok(false) } - return Ok(false); } /// Callback function after epoll_wait unblocks diff --git a/src/tools/miri/src/shims/windows/foreign_items.rs b/src/tools/miri/src/shims/windows/foreign_items.rs index 998daddf520..cd8f3e59015 100644 --- a/src/tools/miri/src/shims/windows/foreign_items.rs +++ b/src/tools/miri/src/shims/windows/foreign_items.rs @@ -23,8 +23,8 @@ pub fn is_dyn_sym(name: &str) -> bool { #[cfg(windows)] fn win_absolute<'tcx>(path: &Path) -> InterpResult<'tcx, io::Result> { - // We are on Windows so we can simply lte the host do this. - return Ok(path::absolute(path)); + // We are on Windows so we can simply let the host do this. + Ok(path::absolute(path)) } #[cfg(unix)] diff --git a/src/tools/miri/src/shims/windows/sync.rs b/src/tools/miri/src/shims/windows/sync.rs index 51b0129356b..5786b17e50c 100644 --- a/src/tools/miri/src/shims/windows/sync.rs +++ b/src/tools/miri/src/shims/windows/sync.rs @@ -90,7 +90,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } ), ); - return Ok(()); + Ok(()) } fn InitOnceComplete( From 18aa926d0906661f7fdb2936a12fba102abbbb7d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 26 Sep 2024 09:40:57 +0200 Subject: [PATCH 289/683] remove some clippy lints from the list that we do not even trigger any more --- src/tools/miri/src/lib.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/tools/miri/src/lib.rs b/src/tools/miri/src/lib.rs index aa0d29d38f4..4d0606113f9 100644 --- a/src/tools/miri/src/lib.rs +++ b/src/tools/miri/src/lib.rs @@ -32,9 +32,7 @@ clippy::derived_hash_with_manual_eq, clippy::too_many_arguments, clippy::type_complexity, - clippy::single_element_loop, clippy::bool_to_int_with_if, - clippy::box_default, clippy::needless_question_mark, clippy::needless_lifetimes, clippy::too_long_first_doc_paragraph, From 1576a6d618a7584659be5d4d770324d5537c0d26 Mon Sep 17 00:00:00 2001 From: Ding Xiang Fei Date: Fri, 30 Aug 2024 04:48:05 +0800 Subject: [PATCH 290/683] Stabilize `const_refs_to_static` update tests fix bitwidth-sensitive stderr output use build-fail for asm tests --- .../src/check_consts/check.rs | 1 - .../rustc_const_eval/src/check_consts/ops.rs | 28 --------- .../src/error_codes/E0013.md | 2 +- compiler/rustc_feature/src/accepted.rs | 2 + compiler/rustc_feature/src/unstable.rs | 2 - src/tools/tidy/src/issues.txt | 2 - tests/ui/asm/aarch64/type-check-4.rs | 28 ++++----- tests/ui/asm/aarch64/type-check-4.stderr | 44 +++++--------- tests/ui/asm/const-refs-to-static.rs | 2 - tests/ui/asm/const-refs-to-static.stderr | 4 +- tests/ui/asm/x86_64/type-check-4.rs | 23 ++++---- tests/ui/asm/x86_64/type-check-4.stderr | 44 +++++--------- .../ui/consts/const-fn-not-safe-for-const.rs | 2 - .../consts/const-fn-not-safe-for-const.stderr | 29 +--------- .../mut_ref_in_final_dynamic_check.rs | 1 - .../mut_ref_in_final_dynamic_check.stderr | 10 ++-- .../const-ref-to-static-linux-vtable.rs | 4 +- .../consts/const_refs_to_static-ice-121413.rs | 1 - .../const_refs_to_static-ice-121413.stderr | 8 +-- tests/ui/consts/const_refs_to_static.rs | 1 - tests/ui/consts/const_refs_to_static_fail.rs | 4 +- .../consts/const_refs_to_static_fail.stderr | 6 +- .../const_refs_to_static_fail_invalid.rs | 1 - .../const_refs_to_static_fail_invalid.stderr | 12 ++-- .../ui/consts/issue-17718-const-bad-values.rs | 11 +++- .../issue-17718-const-bad-values.stderr | 23 ++++---- tests/ui/consts/issue-17718-references.rs | 11 ++-- tests/ui/consts/issue-17718-references.stderr | 39 ------------- tests/ui/consts/issue-52060.rs | 7 --- tests/ui/consts/issue-52060.stderr | 15 ----- tests/ui/consts/min_const_fn/min_const_fn.rs | 4 +- .../consts/min_const_fn/min_const_fn.stderr | 29 +--------- .../const_refers_to_static.stderr | 25 -------- .../const_refers_to_static_cross_crate.stderr | 25 +------- .../miri_unleashed/mutable_references.rs | 10 ++-- .../miri_unleashed/mutable_references.stderr | 57 +++++++------------ ...no-ice-from-static-in-const-issue-52060.rs | 9 +++ ...ce-from-static-in-const-issue-52060.stderr | 9 +++ .../feature-gate-const-refs-to-static.rs | 11 ---- .../feature-gate-const-refs-to-static.stderr | 27 --------- tests/ui/static/issue-18118-2.rs | 6 -- tests/ui/static/issue-18118-2.stderr | 15 ----- tests/ui/statics/const_generics.rs | 1 - tests/ui/statics/mutable_memory_validation.rs | 2 - .../statics/mutable_memory_validation.stderr | 2 +- 45 files changed, 157 insertions(+), 442 deletions(-) delete mode 100644 tests/ui/consts/issue-17718-references.stderr delete mode 100644 tests/ui/consts/issue-52060.rs delete mode 100644 tests/ui/consts/issue-52060.stderr create mode 100644 tests/ui/consts/no-ice-from-static-in-const-issue-52060.rs create mode 100644 tests/ui/consts/no-ice-from-static-in-const-issue-52060.stderr delete mode 100644 tests/ui/feature-gates/feature-gate-const-refs-to-static.rs delete mode 100644 tests/ui/feature-gates/feature-gate-const-refs-to-static.stderr delete mode 100644 tests/ui/static/issue-18118-2.rs delete mode 100644 tests/ui/static/issue-18118-2.stderr diff --git a/compiler/rustc_const_eval/src/check_consts/check.rs b/compiler/rustc_const_eval/src/check_consts/check.rs index e1b60597997..2cbf242fcf2 100644 --- a/compiler/rustc_const_eval/src/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/check_consts/check.rs @@ -317,7 +317,6 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> { { self.error_emitted = Some(guar); } - self.check_op_spanned(ops::StaticAccess, span) } /// Returns whether this place can possibly escape the evaluation of the current const/static diff --git a/compiler/rustc_const_eval/src/check_consts/ops.rs b/compiler/rustc_const_eval/src/check_consts/ops.rs index df8313d0e70..6eb33c29e1d 100644 --- a/compiler/rustc_const_eval/src/check_consts/ops.rs +++ b/compiler/rustc_const_eval/src/check_consts/ops.rs @@ -16,7 +16,6 @@ use rustc_middle::ty::{ suggest_constraining_type_param, }; use rustc_middle::util::{CallDesugaringKind, CallKind, call_kind}; -use rustc_session::parse::feature_err; use rustc_span::symbol::sym; use rustc_span::{BytePos, Pos, Span, Symbol}; use rustc_trait_selection::traits::SelectionContext; @@ -477,33 +476,6 @@ impl<'tcx> NonConstOp<'tcx> for RawPtrToIntCast { } } -/// An access to a (non-thread-local) `static`. -#[derive(Debug)] -pub(crate) struct StaticAccess; -impl<'tcx> NonConstOp<'tcx> for StaticAccess { - fn status_in_item(&self, ccx: &ConstCx<'_, 'tcx>) -> Status { - if let hir::ConstContext::Static(_) = ccx.const_kind() { - Status::Allowed - } else { - Status::Unstable(sym::const_refs_to_static) - } - } - - #[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable - fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> { - let mut err = feature_err( - &ccx.tcx.sess, - sym::const_refs_to_static, - span, - format!("referencing statics in {}s is unstable", ccx.const_kind(),), - ); - err - .note("`static` and `const` variables can refer to other `const` variables. A `const` variable, however, cannot refer to a `static` variable.") - .help("to fix this, the value can be extracted to a `const` and then used."); - err - } -} - /// An access to a thread-local `static`. #[derive(Debug)] pub(crate) struct ThreadLocalAccess; diff --git a/compiler/rustc_error_codes/src/error_codes/E0013.md b/compiler/rustc_error_codes/src/error_codes/E0013.md index 9f4848343ff..c4d65225ece 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0013.md +++ b/compiler/rustc_error_codes/src/error_codes/E0013.md @@ -5,7 +5,7 @@ variable cannot refer to a static variable. Erroneous code example: -```compile_fail,E0658 +``` static X: i32 = 42; const Y: i32 = X; ``` diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs index 70e92f545c6..5ff002dd7d2 100644 --- a/compiler/rustc_feature/src/accepted.rs +++ b/compiler/rustc_feature/src/accepted.rs @@ -151,6 +151,8 @@ declare_features! ( (accepted, const_raw_ptr_deref, "1.58.0", Some(51911)), /// Allows references to types with interior mutability within constants (accepted, const_refs_to_cell, "CURRENT_RUSTC_VERSION", Some(80384)), + /// Allows creating pointers and references to `static` items in constants. + (accepted, const_refs_to_static, "CURRENT_RUSTC_VERSION", Some(119618)), /// Allows implementing `Copy` for closures where possible (RFC 2132). (accepted, copy_closures, "1.26.0", Some(44490)), /// Allows `crate` in paths. diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 63b4b272f76..91b072b56db 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -407,8 +407,6 @@ declare_features! ( (unstable, const_for, "1.56.0", Some(87575)), /// Be more precise when looking for live drops in a const context. (unstable, const_precise_live_drops, "1.46.0", Some(73255)), - /// Allows creating pointers and references to `static` items in constants. - (unstable, const_refs_to_static, "1.78.0", Some(119618)), /// Allows `impl const Trait for T` syntax. (unstable, const_trait_impl, "1.42.0", Some(67792)), /// Allows the `?` operator in const contexts. diff --git a/src/tools/tidy/src/issues.txt b/src/tools/tidy/src/issues.txt index 3879f350e94..6b4c0e9c0b9 100644 --- a/src/tools/tidy/src/issues.txt +++ b/src/tools/tidy/src/issues.txt @@ -764,7 +764,6 @@ ui/consts/issue-46553.rs ui/consts/issue-47789.rs ui/consts/issue-50439.rs ui/consts/issue-52023-array-size-pointer-cast.rs -ui/consts/issue-52060.rs ui/consts/issue-54224.rs ui/consts/issue-54348.rs ui/consts/issue-54387.rs @@ -3830,7 +3829,6 @@ ui/stability-attribute/issue-28388-3.rs ui/stability-attribute/issue-99286-stable-intrinsics.rs ui/static/auxiliary/issue_24843.rs ui/static/issue-1660.rs -ui/static/issue-18118-2.rs ui/static/issue-18118.rs ui/static/issue-24446.rs ui/static/issue-24843.rs diff --git a/tests/ui/asm/aarch64/type-check-4.rs b/tests/ui/asm/aarch64/type-check-4.rs index 1169c3dcfa8..c24567bd5b0 100644 --- a/tests/ui/asm/aarch64/type-check-4.rs +++ b/tests/ui/asm/aarch64/type-check-4.rs @@ -1,31 +1,27 @@ //@ only-aarch64 -//@ compile-flags: -C target-feature=+neon +//@ build-fail -#![feature(repr_simd)] - -use std::arch::aarch64::float64x2_t; -use std::arch::{asm, global_asm}; - -#[repr(simd)] -#[derive(Copy, Clone)] -struct Simd256bit([f64; 4]); +use std::arch::global_asm; fn main() {} // Constants must be... constant -static S: i32 = 1; +static mut S: i32 = 1; const fn const_foo(x: i32) -> i32 { x } const fn const_bar(x: T) -> T { x } -global_asm!("{}", const S); -//~^ ERROR referencing statics +global_asm!("{}", const unsafe { S }); +//~^ ERROR: evaluation of constant value failed +//~| mutable global memory global_asm!("{}", const const_foo(0)); -global_asm!("{}", const const_foo(S)); -//~^ ERROR referencing statics +global_asm!("{}", const const_foo(unsafe { S })); +//~^ ERROR: evaluation of constant value failed +//~| mutable global memory global_asm!("{}", const const_bar(0)); -global_asm!("{}", const const_bar(S)); -//~^ ERROR referencing statics +global_asm!("{}", const const_bar(unsafe { S })); +//~^ ERROR: evaluation of constant value failed +//~| mutable global memory diff --git a/tests/ui/asm/aarch64/type-check-4.stderr b/tests/ui/asm/aarch64/type-check-4.stderr index 89eb8467cde..8c22dfcdb5e 100644 --- a/tests/ui/asm/aarch64/type-check-4.stderr +++ b/tests/ui/asm/aarch64/type-check-4.stderr @@ -1,39 +1,21 @@ -error[E0658]: referencing statics in constants is unstable - --> $DIR/type-check-4.rs:24:25 +error[E0080]: evaluation of constant value failed + --> $DIR/type-check-4.rs:17:34 | -LL | global_asm!("{}", const S); - | ^ - | - = note: see issue #119618 for more information - = help: add `#![feature(const_refs_to_static)]` 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: `static` and `const` variables can refer to other `const` variables. A `const` variable, however, cannot refer to a `static` variable. - = help: to fix this, the value can be extracted to a `const` and then used. +LL | global_asm!("{}", const unsafe { S }); + | ^ constant accesses mutable global memory -error[E0658]: referencing statics in constants is unstable - --> $DIR/type-check-4.rs:27:35 +error[E0080]: evaluation of constant value failed + --> $DIR/type-check-4.rs:21:44 | -LL | global_asm!("{}", const const_foo(S)); - | ^ - | - = note: see issue #119618 for more information - = help: add `#![feature(const_refs_to_static)]` 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: `static` and `const` variables can refer to other `const` variables. A `const` variable, however, cannot refer to a `static` variable. - = help: to fix this, the value can be extracted to a `const` and then used. +LL | global_asm!("{}", const const_foo(unsafe { S })); + | ^ constant accesses mutable global memory -error[E0658]: referencing statics in constants is unstable - --> $DIR/type-check-4.rs:30:35 +error[E0080]: evaluation of constant value failed + --> $DIR/type-check-4.rs:25:44 | -LL | global_asm!("{}", const const_bar(S)); - | ^ - | - = note: see issue #119618 for more information - = help: add `#![feature(const_refs_to_static)]` 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: `static` and `const` variables can refer to other `const` variables. A `const` variable, however, cannot refer to a `static` variable. - = help: to fix this, the value can be extracted to a `const` and then used. +LL | global_asm!("{}", const const_bar(unsafe { S })); + | ^ constant accesses mutable global memory error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0658`. +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/asm/const-refs-to-static.rs b/tests/ui/asm/const-refs-to-static.rs index 9fc010b5763..ce2c5b3246e 100644 --- a/tests/ui/asm/const-refs-to-static.rs +++ b/tests/ui/asm/const-refs-to-static.rs @@ -2,8 +2,6 @@ //@ ignore-nvptx64 //@ ignore-spirv -#![feature(const_refs_to_static)] - use std::arch::{asm, global_asm}; use std::ptr::addr_of; diff --git a/tests/ui/asm/const-refs-to-static.stderr b/tests/ui/asm/const-refs-to-static.stderr index 8fd69da0d1e..10e1ca5bd60 100644 --- a/tests/ui/asm/const-refs-to-static.stderr +++ b/tests/ui/asm/const-refs-to-static.stderr @@ -1,5 +1,5 @@ error: invalid type for `const` operand - --> $DIR/const-refs-to-static.rs:12:19 + --> $DIR/const-refs-to-static.rs:10:19 | LL | global_asm!("{}", const addr_of!(FOO)); | ^^^^^^------------- @@ -9,7 +9,7 @@ LL | global_asm!("{}", const addr_of!(FOO)); = help: `const` operands must be of an integer type error: invalid type for `const` operand - --> $DIR/const-refs-to-static.rs:17:25 + --> $DIR/const-refs-to-static.rs:15:25 | LL | unsafe { asm!("{}", const addr_of!(FOO)) }; | ^^^^^^------------- diff --git a/tests/ui/asm/x86_64/type-check-4.rs b/tests/ui/asm/x86_64/type-check-4.rs index 9503cd6d8ab..ebc6edc07e4 100644 --- a/tests/ui/asm/x86_64/type-check-4.rs +++ b/tests/ui/asm/x86_64/type-check-4.rs @@ -1,26 +1,27 @@ //@ only-x86_64 -//@ compile-flags: -C target-feature=+avx512f +//@ build-fail -use std::arch::{asm, global_asm}; - -use std::arch::x86_64::{_mm256_setzero_ps, _mm_setzero_ps}; +use std::arch::global_asm; fn main() {} // Constants must be... constant -static S: i32 = 1; +static mut S: i32 = 1; const fn const_foo(x: i32) -> i32 { x } const fn const_bar(x: T) -> T { x } -global_asm!("{}", const S); -//~^ ERROR referencing statics +global_asm!("{}", const unsafe { S }); +//~^ ERROR evaluation of constant value failed +//~| mutable global memory global_asm!("{}", const const_foo(0)); -global_asm!("{}", const const_foo(S)); -//~^ ERROR referencing statics +global_asm!("{}", const const_foo(unsafe { S })); +//~^ ERROR evaluation of constant value failed +//~| mutable global memory global_asm!("{}", const const_bar(0)); -global_asm!("{}", const const_bar(S)); -//~^ ERROR referencing statics +global_asm!("{}", const const_bar(unsafe { S })); +//~^ ERROR evaluation of constant value failed +//~| mutable global memory diff --git a/tests/ui/asm/x86_64/type-check-4.stderr b/tests/ui/asm/x86_64/type-check-4.stderr index f1bbc9e7d33..8c22dfcdb5e 100644 --- a/tests/ui/asm/x86_64/type-check-4.stderr +++ b/tests/ui/asm/x86_64/type-check-4.stderr @@ -1,39 +1,21 @@ -error[E0658]: referencing statics in constants is unstable - --> $DIR/type-check-4.rs:19:25 +error[E0080]: evaluation of constant value failed + --> $DIR/type-check-4.rs:17:34 | -LL | global_asm!("{}", const S); - | ^ - | - = note: see issue #119618 for more information - = help: add `#![feature(const_refs_to_static)]` 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: `static` and `const` variables can refer to other `const` variables. A `const` variable, however, cannot refer to a `static` variable. - = help: to fix this, the value can be extracted to a `const` and then used. +LL | global_asm!("{}", const unsafe { S }); + | ^ constant accesses mutable global memory -error[E0658]: referencing statics in constants is unstable - --> $DIR/type-check-4.rs:22:35 +error[E0080]: evaluation of constant value failed + --> $DIR/type-check-4.rs:21:44 | -LL | global_asm!("{}", const const_foo(S)); - | ^ - | - = note: see issue #119618 for more information - = help: add `#![feature(const_refs_to_static)]` 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: `static` and `const` variables can refer to other `const` variables. A `const` variable, however, cannot refer to a `static` variable. - = help: to fix this, the value can be extracted to a `const` and then used. +LL | global_asm!("{}", const const_foo(unsafe { S })); + | ^ constant accesses mutable global memory -error[E0658]: referencing statics in constants is unstable - --> $DIR/type-check-4.rs:25:35 +error[E0080]: evaluation of constant value failed + --> $DIR/type-check-4.rs:25:44 | -LL | global_asm!("{}", const const_bar(S)); - | ^ - | - = note: see issue #119618 for more information - = help: add `#![feature(const_refs_to_static)]` 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: `static` and `const` variables can refer to other `const` variables. A `const` variable, however, cannot refer to a `static` variable. - = help: to fix this, the value can be extracted to a `const` and then used. +LL | global_asm!("{}", const const_bar(unsafe { S })); + | ^ constant accesses mutable global memory error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0658`. +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-fn-not-safe-for-const.rs b/tests/ui/consts/const-fn-not-safe-for-const.rs index 6d8404880ca..8a0cd86819e 100644 --- a/tests/ui/consts/const-fn-not-safe-for-const.rs +++ b/tests/ui/consts/const-fn-not-safe-for-const.rs @@ -18,12 +18,10 @@ static Y: u32 = 0; const fn get_Y() -> u32 { Y - //~^ ERROR referencing statics in constant functions } const fn get_Y_addr() -> &'static u32 { &Y - //~^ ERROR referencing statics in constant functions } const fn get() -> u32 { diff --git a/tests/ui/consts/const-fn-not-safe-for-const.stderr b/tests/ui/consts/const-fn-not-safe-for-const.stderr index 7d7e94da86f..674e05a0ba9 100644 --- a/tests/ui/consts/const-fn-not-safe-for-const.stderr +++ b/tests/ui/consts/const-fn-not-safe-for-const.stderr @@ -6,31 +6,6 @@ LL | random() | = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants -error[E0658]: referencing statics in constant functions is unstable - --> $DIR/const-fn-not-safe-for-const.rs:20:5 - | -LL | Y - | ^ - | - = note: see issue #119618 for more information - = help: add `#![feature(const_refs_to_static)]` 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: `static` and `const` variables can refer to other `const` variables. A `const` variable, however, cannot refer to a `static` variable. - = help: to fix this, the value can be extracted to a `const` and then used. +error: aborting due to 1 previous error -error[E0658]: referencing statics in constant functions is unstable - --> $DIR/const-fn-not-safe-for-const.rs:25:6 - | -LL | &Y - | ^ - | - = note: see issue #119618 for more information - = help: add `#![feature(const_refs_to_static)]` 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: `static` and `const` variables can refer to other `const` variables. A `const` variable, however, cannot refer to a `static` variable. - = help: to fix this, the value can be extracted to a `const` and then used. - -error: aborting due to 3 previous errors - -Some errors have detailed explanations: E0015, E0658. -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/consts/const-mut-refs/mut_ref_in_final_dynamic_check.rs b/tests/ui/consts/const-mut-refs/mut_ref_in_final_dynamic_check.rs index 7bf178484cc..2539fcccb84 100644 --- a/tests/ui/consts/const-mut-refs/mut_ref_in_final_dynamic_check.rs +++ b/tests/ui/consts/const-mut-refs/mut_ref_in_final_dynamic_check.rs @@ -1,7 +1,6 @@ //@ normalize-stderr-test: "(the raw bytes of the constant) \(size: [0-9]*, align: [0-9]*\)" -> "$1 (size: $$SIZE, align: $$ALIGN)" //@ normalize-stderr-test: "( 0x[0-9a-f][0-9a-f] │)? ([0-9a-f][0-9a-f] |__ |╾─*ALLOC[0-9]+(\+[a-z0-9]+)?()?─*╼ )+ *│.*" -> " HEX_DUMP" //@ normalize-stderr-test: "HEX_DUMP\s*\n\s*HEX_DUMP" -> "HEX_DUMP" -#![feature(const_refs_to_static)] use std::sync::Mutex; diff --git a/tests/ui/consts/const-mut-refs/mut_ref_in_final_dynamic_check.stderr b/tests/ui/consts/const-mut-refs/mut_ref_in_final_dynamic_check.stderr index 4ea6fa62475..aebac56f8c5 100644 --- a/tests/ui/consts/const-mut-refs/mut_ref_in_final_dynamic_check.stderr +++ b/tests/ui/consts/const-mut-refs/mut_ref_in_final_dynamic_check.stderr @@ -1,5 +1,5 @@ error[E0080]: it is undefined behavior to use this value - --> $DIR/mut_ref_in_final_dynamic_check.rs:19:1 + --> $DIR/mut_ref_in_final_dynamic_check.rs:18:1 | LL | const MUT: Option<&mut i32> = helper(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at ..0: encountered reference to mutable memory in `const` @@ -10,7 +10,7 @@ LL | const MUT: Option<&mut i32> = helper(); } error[E0080]: it is undefined behavior to use this value - --> $DIR/mut_ref_in_final_dynamic_check.rs:26:1 + --> $DIR/mut_ref_in_final_dynamic_check.rs:25:1 | LL | const INT2PTR: Option<&mut i32> = helper_int2ptr(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at ..0: encountered a dangling reference (0x2a[noalloc] has no provenance) @@ -21,7 +21,7 @@ LL | const INT2PTR: Option<&mut i32> = helper_int2ptr(); } error[E0080]: it is undefined behavior to use this value - --> $DIR/mut_ref_in_final_dynamic_check.rs:28:1 + --> $DIR/mut_ref_in_final_dynamic_check.rs:27:1 | LL | static INT2PTR_STATIC: Option<&mut i32> = helper_int2ptr(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at ..0: encountered a dangling reference (0x2a[noalloc] has no provenance) @@ -32,7 +32,7 @@ LL | static INT2PTR_STATIC: Option<&mut i32> = helper_int2ptr(); } error[E0080]: it is undefined behavior to use this value - --> $DIR/mut_ref_in_final_dynamic_check.rs:35:1 + --> $DIR/mut_ref_in_final_dynamic_check.rs:34:1 | LL | const DANGLING: Option<&mut i32> = helper_dangling(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at ..0: encountered a dangling reference (use-after-free) @@ -43,7 +43,7 @@ LL | const DANGLING: Option<&mut i32> = helper_dangling(); } error[E0080]: it is undefined behavior to use this value - --> $DIR/mut_ref_in_final_dynamic_check.rs:36:1 + --> $DIR/mut_ref_in_final_dynamic_check.rs:35:1 | LL | static DANGLING_STATIC: Option<&mut i32> = helper_dangling(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at ..0: encountered a dangling reference (use-after-free) diff --git a/tests/ui/consts/const-ref-to-static-linux-vtable.rs b/tests/ui/consts/const-ref-to-static-linux-vtable.rs index b9d29d0c1f4..87af63d41ab 100644 --- a/tests/ui/consts/const-ref-to-static-linux-vtable.rs +++ b/tests/ui/consts/const-ref-to-static-linux-vtable.rs @@ -1,6 +1,6 @@ -//@check-pass +//@ check-pass //! This is the reduced version of the "Linux kernel vtable" use-case. -#![feature(const_refs_to_static)] + use std::ptr::addr_of_mut; #[repr(C)] diff --git a/tests/ui/consts/const_refs_to_static-ice-121413.rs b/tests/ui/consts/const_refs_to_static-ice-121413.rs index 8fc3912efd0..5b2d27ae853 100644 --- a/tests/ui/consts/const_refs_to_static-ice-121413.rs +++ b/tests/ui/consts/const_refs_to_static-ice-121413.rs @@ -3,7 +3,6 @@ // issue: rust-lang/rust#121413 //@ compile-flags: -Zextra-const-ub-checks // ignore-tidy-linelength -#![feature(const_refs_to_static)] const REF_INTERIOR_MUT: &usize = { //~^ HELP consider importing this struct static FOO: Sync = AtomicUsize::new(0); diff --git a/tests/ui/consts/const_refs_to_static-ice-121413.stderr b/tests/ui/consts/const_refs_to_static-ice-121413.stderr index fbe32a70293..c977c698a92 100644 --- a/tests/ui/consts/const_refs_to_static-ice-121413.stderr +++ b/tests/ui/consts/const_refs_to_static-ice-121413.stderr @@ -1,5 +1,5 @@ error[E0433]: failed to resolve: use of undeclared type `AtomicUsize` - --> $DIR/const_refs_to_static-ice-121413.rs:9:24 + --> $DIR/const_refs_to_static-ice-121413.rs:8:24 | LL | static FOO: Sync = AtomicUsize::new(0); | ^^^^^^^^^^^ use of undeclared type `AtomicUsize` @@ -10,7 +10,7 @@ LL + use std::sync::atomic::AtomicUsize; | warning: trait objects without an explicit `dyn` are deprecated - --> $DIR/const_refs_to_static-ice-121413.rs:9:17 + --> $DIR/const_refs_to_static-ice-121413.rs:8:17 | LL | static FOO: Sync = AtomicUsize::new(0); | ^^^^ @@ -24,7 +24,7 @@ LL | static FOO: dyn Sync = AtomicUsize::new(0); | +++ error[E0277]: the size for values of type `(dyn Sync + 'static)` cannot be known at compilation time - --> $DIR/const_refs_to_static-ice-121413.rs:9:17 + --> $DIR/const_refs_to_static-ice-121413.rs:8:17 | LL | static FOO: Sync = AtomicUsize::new(0); | ^^^^ doesn't have a size known at compile-time @@ -32,7 +32,7 @@ LL | static FOO: Sync = AtomicUsize::new(0); = help: the trait `Sized` is not implemented for `(dyn Sync + 'static)` error[E0277]: the size for values of type `(dyn Sync + 'static)` cannot be known at compilation time - --> $DIR/const_refs_to_static-ice-121413.rs:9:24 + --> $DIR/const_refs_to_static-ice-121413.rs:8:24 | LL | static FOO: Sync = AtomicUsize::new(0); | ^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time diff --git a/tests/ui/consts/const_refs_to_static.rs b/tests/ui/consts/const_refs_to_static.rs index f41725b786e..3c59697e8ed 100644 --- a/tests/ui/consts/const_refs_to_static.rs +++ b/tests/ui/consts/const_refs_to_static.rs @@ -1,5 +1,4 @@ //@ run-pass -#![feature(const_refs_to_static)] static S: i32 = 0; static mut S_MUT: i32 = 0; diff --git a/tests/ui/consts/const_refs_to_static_fail.rs b/tests/ui/consts/const_refs_to_static_fail.rs index a69902c3439..44e848ab637 100644 --- a/tests/ui/consts/const_refs_to_static_fail.rs +++ b/tests/ui/consts/const_refs_to_static_fail.rs @@ -1,6 +1,8 @@ //@ normalize-stderr-test: "(the raw bytes of the constant) \(size: [0-9]*, align: [0-9]*\)" -> "$1 (size: $$SIZE, align: $$ALIGN)" //@ normalize-stderr-test: "([0-9a-f][0-9a-f] |╾─*ALLOC[0-9]+(\+[a-z0-9]+)?()?─*╼ )+ *│.*" -> "HEX_DUMP" -#![feature(const_refs_to_static, sync_unsafe_cell)] + +#![feature(sync_unsafe_cell)] + use std::cell::SyncUnsafeCell; static S: SyncUnsafeCell = SyncUnsafeCell::new(0); diff --git a/tests/ui/consts/const_refs_to_static_fail.stderr b/tests/ui/consts/const_refs_to_static_fail.stderr index cdabd86b183..297561dbcf1 100644 --- a/tests/ui/consts/const_refs_to_static_fail.stderr +++ b/tests/ui/consts/const_refs_to_static_fail.stderr @@ -1,5 +1,5 @@ error[E0080]: it is undefined behavior to use this value - --> $DIR/const_refs_to_static_fail.rs:9:1 + --> $DIR/const_refs_to_static_fail.rs:11:1 | LL | const C1: &SyncUnsafeCell = &S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered reference to mutable memory in `const` @@ -10,13 +10,13 @@ LL | const C1: &SyncUnsafeCell = &S; } note: erroneous constant encountered - --> $DIR/const_refs_to_static_fail.rs:12:14 + --> $DIR/const_refs_to_static_fail.rs:14:14 | LL | assert!(*C1.get() == 0); | ^^ error[E0080]: evaluation of constant value failed - --> $DIR/const_refs_to_static_fail.rs:16:13 + --> $DIR/const_refs_to_static_fail.rs:18:13 | LL | assert!(*C2 == 0); | ^^^ constant accesses mutable global memory diff --git a/tests/ui/consts/const_refs_to_static_fail_invalid.rs b/tests/ui/consts/const_refs_to_static_fail_invalid.rs index c58606d2ebb..a160862a0fa 100644 --- a/tests/ui/consts/const_refs_to_static_fail_invalid.rs +++ b/tests/ui/consts/const_refs_to_static_fail_invalid.rs @@ -1,6 +1,5 @@ //@ normalize-stderr-test: "(the raw bytes of the constant) \(size: [0-9]*, align: [0-9]*\)" -> "$1 (size: $$SIZE, align: $$ALIGN)" //@ normalize-stderr-test: "([0-9a-f][0-9a-f] |╾─*ALLOC[0-9]+(\+[a-z0-9]+)?()?─*╼ )+ *│.*" -> "HEX_DUMP" -#![feature(const_refs_to_static)] #![allow(static_mut_refs)] fn invalid() { diff --git a/tests/ui/consts/const_refs_to_static_fail_invalid.stderr b/tests/ui/consts/const_refs_to_static_fail_invalid.stderr index d5bb4847746..0153f501174 100644 --- a/tests/ui/consts/const_refs_to_static_fail_invalid.stderr +++ b/tests/ui/consts/const_refs_to_static_fail_invalid.stderr @@ -1,5 +1,5 @@ error[E0080]: it is undefined behavior to use this value - --> $DIR/const_refs_to_static_fail_invalid.rs:9:5 + --> $DIR/const_refs_to_static_fail_invalid.rs:8:5 | LL | const C: &bool = unsafe { std::mem::transmute(&S) }; | ^^^^^^^^^^^^^^ constructing invalid value at .: encountered 0x0a, but expected a boolean @@ -10,7 +10,7 @@ LL | const C: &bool = unsafe { std::mem::transmute(&S) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/const_refs_to_static_fail_invalid.rs:25:5 + --> $DIR/const_refs_to_static_fail_invalid.rs:24:5 | LL | const C: &i8 = unsafe { &S }; | ^^^^^^^^^^^^ constructing invalid value: encountered reference to `extern` static in `const` @@ -21,7 +21,7 @@ LL | const C: &i8 = unsafe { &S }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/const_refs_to_static_fail_invalid.rs:39:5 + --> $DIR/const_refs_to_static_fail_invalid.rs:38:5 | LL | const C: &i32 = unsafe { &S_MUT }; | ^^^^^^^^^^^^^ constructing invalid value: encountered reference to mutable memory in `const` @@ -32,19 +32,19 @@ LL | const C: &i32 = unsafe { &S_MUT }; } error: could not evaluate constant pattern - --> $DIR/const_refs_to_static_fail_invalid.rs:15:9 + --> $DIR/const_refs_to_static_fail_invalid.rs:14:9 | LL | C => {} | ^ error: could not evaluate constant pattern - --> $DIR/const_refs_to_static_fail_invalid.rs:31:9 + --> $DIR/const_refs_to_static_fail_invalid.rs:30:9 | LL | C => {} | ^ error: could not evaluate constant pattern - --> $DIR/const_refs_to_static_fail_invalid.rs:46:9 + --> $DIR/const_refs_to_static_fail_invalid.rs:45:9 | LL | C => {} | ^ diff --git a/tests/ui/consts/issue-17718-const-bad-values.rs b/tests/ui/consts/issue-17718-const-bad-values.rs index 52f8c9bf149..fca6cb08537 100644 --- a/tests/ui/consts/issue-17718-const-bad-values.rs +++ b/tests/ui/consts/issue-17718-const-bad-values.rs @@ -1,10 +1,15 @@ +//@ normalize-stderr-32bit: "\(size: \d+, align: \d+\)" -> "(size: $$PTR, align: $$PTR)" +//@ normalize-stderr-64bit: "\(size: \d+, align: \d+\)" -> "(size: $$PTR, align: $$PTR)" +//@ normalize-stderr-test: "([0-9a-f][0-9a-f] |╾─*A(LLOC)?[0-9]+(\+[a-z0-9]+)?()?─*╼ )+ *│.*" -> "HEX_DUMP" + #![allow(static_mut_refs)] const C1: &'static mut [usize] = &mut []; //~^ ERROR: mutable references are not allowed -static mut S: usize = 3; -const C2: &'static mut usize = unsafe { &mut S }; -//~^ ERROR: referencing statics in constants +static mut S: i32 = 3; +const C2: &'static mut i32 = unsafe { &mut S }; +//~^ ERROR: it is undefined behavior to use this value +//~| reference to mutable memory fn main() {} diff --git a/tests/ui/consts/issue-17718-const-bad-values.stderr b/tests/ui/consts/issue-17718-const-bad-values.stderr index 57fcb1c7e9a..102491e90ba 100644 --- a/tests/ui/consts/issue-17718-const-bad-values.stderr +++ b/tests/ui/consts/issue-17718-const-bad-values.stderr @@ -1,22 +1,21 @@ error[E0764]: mutable references are not allowed in the final value of constants - --> $DIR/issue-17718-const-bad-values.rs:3:34 + --> $DIR/issue-17718-const-bad-values.rs:7:34 | LL | const C1: &'static mut [usize] = &mut []; | ^^^^^^^ -error[E0658]: referencing statics in constants is unstable - --> $DIR/issue-17718-const-bad-values.rs:7:46 +error[E0080]: it is undefined behavior to use this value + --> $DIR/issue-17718-const-bad-values.rs:11:1 | -LL | const C2: &'static mut usize = unsafe { &mut S }; - | ^ +LL | const C2: &'static mut i32 = unsafe { &mut S }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered reference to mutable memory in `const` | - = note: see issue #119618 for more information - = help: add `#![feature(const_refs_to_static)]` 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: `static` and `const` variables can refer to other `const` variables. A `const` variable, however, cannot refer to a `static` variable. - = help: to fix this, the value can be extracted to a `const` and then used. + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: $PTR, align: $PTR) { + HEX_DUMP + } error: aborting due to 2 previous errors -Some errors have detailed explanations: E0658, E0764. -For more information about an error, try `rustc --explain E0658`. +Some errors have detailed explanations: E0080, E0764. +For more information about an error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/issue-17718-references.rs b/tests/ui/consts/issue-17718-references.rs index 6a8955f4634..120ec28c404 100644 --- a/tests/ui/consts/issue-17718-references.rs +++ b/tests/ui/consts/issue-17718-references.rs @@ -1,23 +1,26 @@ +//@ check-pass #![allow(warnings)] -struct Struct { a: usize } +struct Struct { + a: usize, +} const C: usize = 1; static S: usize = 1; const T1: &'static usize = &C; -const T2: &'static usize = &S; //~ ERROR: referencing statics in constants +const T2: &'static usize = &S; static T3: &'static usize = &C; static T4: &'static usize = &S; const T5: usize = C; -const T6: usize = S; //~ ERROR: referencing statics in constants +const T6: usize = S; static T7: usize = C; static T8: usize = S; const T9: Struct = Struct { a: C }; const T10: Struct = Struct { a: S }; -//~^ ERROR: referencing statics in constants + static T11: Struct = Struct { a: C }; static T12: Struct = Struct { a: S }; diff --git a/tests/ui/consts/issue-17718-references.stderr b/tests/ui/consts/issue-17718-references.stderr deleted file mode 100644 index 8b572203781..00000000000 --- a/tests/ui/consts/issue-17718-references.stderr +++ /dev/null @@ -1,39 +0,0 @@ -error[E0658]: referencing statics in constants is unstable - --> $DIR/issue-17718-references.rs:9:29 - | -LL | const T2: &'static usize = &S; - | ^ - | - = note: see issue #119618 for more information - = help: add `#![feature(const_refs_to_static)]` 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: `static` and `const` variables can refer to other `const` variables. A `const` variable, however, cannot refer to a `static` variable. - = help: to fix this, the value can be extracted to a `const` and then used. - -error[E0658]: referencing statics in constants is unstable - --> $DIR/issue-17718-references.rs:14:19 - | -LL | const T6: usize = S; - | ^ - | - = note: see issue #119618 for more information - = help: add `#![feature(const_refs_to_static)]` 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: `static` and `const` variables can refer to other `const` variables. A `const` variable, however, cannot refer to a `static` variable. - = help: to fix this, the value can be extracted to a `const` and then used. - -error[E0658]: referencing statics in constants is unstable - --> $DIR/issue-17718-references.rs:19:33 - | -LL | const T10: Struct = Struct { a: S }; - | ^ - | - = note: see issue #119618 for more information - = help: add `#![feature(const_refs_to_static)]` 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: `static` and `const` variables can refer to other `const` variables. A `const` variable, however, cannot refer to a `static` variable. - = help: to fix this, the value can be extracted to a `const` and then used. - -error: aborting due to 3 previous errors - -For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/consts/issue-52060.rs b/tests/ui/consts/issue-52060.rs deleted file mode 100644 index 0f16ede0400..00000000000 --- a/tests/ui/consts/issue-52060.rs +++ /dev/null @@ -1,7 +0,0 @@ -// Regression test for https://github.com/rust-lang/rust/issues/52060 -// The compiler shouldn't ICE in this case -static A: &'static [u32] = &[1]; -static B: [u32; 1] = [0; A.len()]; -//~^ ERROR referencing statics in constants - -fn main() {} diff --git a/tests/ui/consts/issue-52060.stderr b/tests/ui/consts/issue-52060.stderr deleted file mode 100644 index 644a5314622..00000000000 --- a/tests/ui/consts/issue-52060.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error[E0658]: referencing statics in constants is unstable - --> $DIR/issue-52060.rs:4:26 - | -LL | static B: [u32; 1] = [0; A.len()]; - | ^ - | - = note: see issue #119618 for more information - = help: add `#![feature(const_refs_to_static)]` 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: `static` and `const` variables can refer to other `const` variables. A `const` variable, however, cannot refer to a `static` variable. - = help: to fix this, the value can be extracted to a `const` and then used. - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/consts/min_const_fn/min_const_fn.rs b/tests/ui/consts/min_const_fn/min_const_fn.rs index ed5aa40b66c..e6d9d184e04 100644 --- a/tests/ui/consts/min_const_fn/min_const_fn.rs +++ b/tests/ui/consts/min_const_fn/min_const_fn.rs @@ -74,8 +74,8 @@ const fn foo11_2(t: T) -> T { t } // not ok static BAR: u32 = 42; -const fn foo25() -> u32 { BAR } //~ ERROR referencing statics in constant functions -const fn foo26() -> &'static u32 { &BAR } //~ ERROR referencing statics in constant functions +const fn foo25() -> u32 { BAR } +const fn foo26() -> &'static u32 { &BAR } const fn foo30(x: *const u32) -> usize { x as usize } //~^ ERROR pointers cannot be cast to integers const fn foo30_with_unsafe(x: *const u32) -> usize { unsafe { x as usize } } diff --git a/tests/ui/consts/min_const_fn/min_const_fn.stderr b/tests/ui/consts/min_const_fn/min_const_fn.stderr index c02f8c76d44..0e939e5121a 100644 --- a/tests/ui/consts/min_const_fn/min_const_fn.stderr +++ b/tests/ui/consts/min_const_fn/min_const_fn.stderr @@ -22,30 +22,6 @@ LL | const fn into_inner_s(self) -> T { self.0 } | | | the destructor for this type cannot be evaluated in constant functions -error[E0658]: referencing statics in constant functions is unstable - --> $DIR/min_const_fn.rs:77:27 - | -LL | const fn foo25() -> u32 { BAR } - | ^^^ - | - = note: see issue #119618 for more information - = help: add `#![feature(const_refs_to_static)]` 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: `static` and `const` variables can refer to other `const` variables. A `const` variable, however, cannot refer to a `static` variable. - = help: to fix this, the value can be extracted to a `const` and then used. - -error[E0658]: referencing statics in constant functions is unstable - --> $DIR/min_const_fn.rs:78:37 - | -LL | const fn foo26() -> &'static u32 { &BAR } - | ^^^ - | - = note: see issue #119618 for more information - = help: add `#![feature(const_refs_to_static)]` 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: `static` and `const` variables can refer to other `const` variables. A `const` variable, however, cannot refer to a `static` variable. - = help: to fix this, the value can be extracted to a `const` and then used. - error: pointers cannot be cast to integers during const eval --> $DIR/min_const_fn.rs:79:42 | @@ -98,7 +74,6 @@ LL | const fn no_apit(_x: impl std::fmt::Debug) {} | | | the destructor for this type cannot be evaluated in constant functions -error: aborting due to 11 previous errors +error: aborting due to 9 previous errors -Some errors have detailed explanations: E0493, E0658. -For more information about an error, try `rustc --explain E0493`. +For more information about this error, try `rustc --explain E0493`. diff --git a/tests/ui/consts/miri_unleashed/const_refers_to_static.stderr b/tests/ui/consts/miri_unleashed/const_refers_to_static.stderr index df910546d11..f8e0606fbd7 100644 --- a/tests/ui/consts/miri_unleashed/const_refers_to_static.stderr +++ b/tests/ui/consts/miri_unleashed/const_refers_to_static.stderr @@ -29,36 +29,11 @@ LL | const REF_INTERIOR_MUT: &usize = { warning: skipping const checks | -help: skipping check for `const_refs_to_static` feature - --> $DIR/const_refers_to_static.rs:10:5 - | -LL | FOO.fetch_add(1, Ordering::Relaxed) - | ^^^ help: skipping check that does not even have a feature gate --> $DIR/const_refers_to_static.rs:10:5 | LL | FOO.fetch_add(1, Ordering::Relaxed) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -help: skipping check for `const_refs_to_static` feature - --> $DIR/const_refers_to_static.rs:15:17 - | -LL | unsafe { *(&FOO as *const _ as *const usize) } - | ^^^ -help: skipping check for `const_refs_to_static` feature - --> $DIR/const_refers_to_static.rs:19:32 - | -LL | const READ_MUT: u32 = unsafe { MUTABLE }; - | ^^^^^^^ -help: skipping check for `const_refs_to_static` feature - --> $DIR/const_refers_to_static.rs:25:18 - | -LL | unsafe { &*(&FOO as *const _ as *const usize) } - | ^^^ -help: skipping check for `const_refs_to_static` feature - --> $DIR/const_refers_to_static.rs:30:25 - | -LL | const REF_IMMUT: &u8 = &MY_STATIC; - | ^^^^^^^^^ error: aborting due to 4 previous errors; 1 warning emitted diff --git a/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.stderr b/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.stderr index 7a7b7bc57da..147d3f238f7 100644 --- a/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.stderr +++ b/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.stderr @@ -61,29 +61,6 @@ error: could not evaluate constant pattern LL | U8_MUT3 => true, | ^^^^^^^ -warning: skipping const checks - | -help: skipping check for `const_refs_to_static` feature - --> $DIR/const_refers_to_static_cross_crate.rs:14:15 - | -LL | unsafe { &static_cross_crate::ZERO } - | ^^^^^^^^^^^^^^^^^^^^^^^^ -help: skipping check for `const_refs_to_static` feature - --> $DIR/const_refers_to_static_cross_crate.rs:19:15 - | -LL | unsafe { &static_cross_crate::ZERO[0] } - | ^^^^^^^^^^^^^^^^^^^^^^^^ -help: skipping check for `const_refs_to_static` feature - --> $DIR/const_refers_to_static_cross_crate.rs:25:17 - | -LL | unsafe { &(*static_cross_crate::ZERO_REF)[0] } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -help: skipping check for `const_refs_to_static` feature - --> $DIR/const_refers_to_static_cross_crate.rs:29:15 - | -LL | match static_cross_crate::OPT_ZERO { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 8 previous errors; 1 warning emitted +error: aborting due to 8 previous errors For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/miri_unleashed/mutable_references.rs b/tests/ui/consts/miri_unleashed/mutable_references.rs index 6ac61e67001..a60058cc5c0 100644 --- a/tests/ui/consts/miri_unleashed/mutable_references.rs +++ b/tests/ui/consts/miri_unleashed/mutable_references.rs @@ -27,9 +27,12 @@ const BLUNT: &mut i32 = &mut 42; //~^ ERROR: it is undefined behavior to use this value //~| pointing to read-only memory -const SUBTLE: &mut i32 = unsafe { static mut STATIC: i32 = 0; &mut STATIC }; -//~^ ERROR: it is undefined behavior to use this value -//~| static +const SUBTLE: &mut i32 = unsafe { + //~^ ERROR: it is undefined behavior to use this value + //~| constructing invalid value: encountered reference to mutable memory in `const` + static mut STATIC: i32 = 0; + &mut STATIC +}; // # Interior mutability @@ -105,7 +108,6 @@ const RAW_MUT_CAST: SyncPtr = SyncPtr { x: &mut 42 as *mut _ as *const _ }; const RAW_MUT_COERCE: SyncPtr = SyncPtr { x: &mut 0 }; //~^ ERROR mutable pointer in final value - fn main() { unsafe { *MEH.x.get() = 99; diff --git a/tests/ui/consts/miri_unleashed/mutable_references.stderr b/tests/ui/consts/miri_unleashed/mutable_references.stderr index 874dd0389d4..ce5cedac8bc 100644 --- a/tests/ui/consts/miri_unleashed/mutable_references.stderr +++ b/tests/ui/consts/miri_unleashed/mutable_references.stderr @@ -46,7 +46,7 @@ LL | const BLUNT: &mut i32 = &mut 42; error[E0080]: it is undefined behavior to use this value --> $DIR/mutable_references.rs:30:1 | -LL | const SUBTLE: &mut i32 = unsafe { static mut STATIC: i32 = 0; &mut STATIC }; +LL | const SUBTLE: &mut i32 = unsafe { | ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered reference to mutable memory in `const` | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. @@ -55,7 +55,7 @@ LL | const SUBTLE: &mut i32 = unsafe { static mut STATIC: i32 = 0; &mut STATIC } } error[E0080]: it is undefined behavior to use this value - --> $DIR/mutable_references.rs:40:1 + --> $DIR/mutable_references.rs:43:1 | LL | static MEH: Meh = Meh { x: &UnsafeCell::new(42) }; | ^^^^^^^^^^^^^^^ constructing invalid value at .x.: encountered `UnsafeCell` in read-only memory @@ -66,7 +66,7 @@ LL | static MEH: Meh = Meh { x: &UnsafeCell::new(42) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/mutable_references.rs:46:1 + --> $DIR/mutable_references.rs:49:1 | LL | const MUH: Meh = Meh { | ^^^^^^^^^^^^^^ constructing invalid value at .x.: encountered `UnsafeCell` in read-only memory @@ -77,7 +77,7 @@ LL | const MUH: Meh = Meh { } error[E0080]: it is undefined behavior to use this value - --> $DIR/mutable_references.rs:58:1 + --> $DIR/mutable_references.rs:61:1 | LL | const SNEAKY: &dyn Sync = &Synced { x: UnsafeCell::new(42) }; | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at ...x: encountered `UnsafeCell` in read-only memory @@ -88,7 +88,7 @@ LL | const SNEAKY: &dyn Sync = &Synced { x: UnsafeCell::new(42) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/mutable_references.rs:65:1 + --> $DIR/mutable_references.rs:68:1 | LL | static mut MUT_TO_READONLY: &mut i32 = unsafe { &mut *(&READONLY as *const _ as *mut _) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered mutable reference or box pointing to read-only memory @@ -99,7 +99,7 @@ LL | static mut MUT_TO_READONLY: &mut i32 = unsafe { &mut *(&READONLY as *const } error[E0080]: it is undefined behavior to use this value - --> $DIR/mutable_references.rs:72:1 + --> $DIR/mutable_references.rs:75:1 | LL | const POINTS_TO_MUTABLE: &i32 = unsafe { &MUTABLE }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered reference to mutable memory in `const` @@ -110,37 +110,37 @@ LL | const POINTS_TO_MUTABLE: &i32 = unsafe { &MUTABLE }; } error[E0080]: evaluation of constant value failed - --> $DIR/mutable_references.rs:75:43 + --> $DIR/mutable_references.rs:78:43 | LL | const POINTS_TO_MUTABLE2: &i32 = unsafe { &*MUTABLE_REF }; | ^^^^^^^^^^^^^ constant accesses mutable global memory error: encountered mutable pointer in final value of constant - --> $DIR/mutable_references.rs:79:1 + --> $DIR/mutable_references.rs:82:1 | LL | const POINTS_TO_MUTABLE_INNER: *const i32 = &mut 42 as *mut _ as *const _; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: encountered mutable pointer in final value of constant - --> $DIR/mutable_references.rs:82:1 + --> $DIR/mutable_references.rs:85:1 | LL | const POINTS_TO_MUTABLE_INNER2: *const i32 = &mut 42 as *const _; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: encountered mutable pointer in final value of constant - --> $DIR/mutable_references.rs:102:1 + --> $DIR/mutable_references.rs:105:1 | LL | const RAW_MUT_CAST: SyncPtr = SyncPtr { x: &mut 42 as *mut _ as *const _ }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: encountered mutable pointer in final value of constant - --> $DIR/mutable_references.rs:105:1 + --> $DIR/mutable_references.rs:108:1 | LL | const RAW_MUT_COERCE: SyncPtr = SyncPtr { x: &mut 0 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0594]: cannot assign to `*OH_YES`, as `OH_YES` is an immutable static item - --> $DIR/mutable_references.rs:113:5 + --> $DIR/mutable_references.rs:115:5 | LL | *OH_YES = 99; | ^^^^^^^^^^^^ cannot assign @@ -172,63 +172,48 @@ help: skipping check that does not even have a feature gate | LL | const BLUNT: &mut i32 = &mut 42; | ^^^^^^^ -help: skipping check for `const_refs_to_static` feature - --> $DIR/mutable_references.rs:30:68 - | -LL | const SUBTLE: &mut i32 = unsafe { static mut STATIC: i32 = 0; &mut STATIC }; - | ^^^^^^ help: skipping check that does not even have a feature gate - --> $DIR/mutable_references.rs:40:28 + --> $DIR/mutable_references.rs:43:28 | LL | static MEH: Meh = Meh { x: &UnsafeCell::new(42) }; | ^^^^^^^^^^^^^^^^^^^^ help: skipping check that does not even have a feature gate - --> $DIR/mutable_references.rs:49:8 + --> $DIR/mutable_references.rs:52:8 | LL | x: &UnsafeCell::new(42), | ^^^^^^^^^^^^^^^^^^^^ help: skipping check that does not even have a feature gate - --> $DIR/mutable_references.rs:58:27 + --> $DIR/mutable_references.rs:61:27 | LL | const SNEAKY: &dyn Sync = &Synced { x: UnsafeCell::new(42) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -help: skipping check for `const_refs_to_static` feature - --> $DIR/mutable_references.rs:72:43 - | -LL | const POINTS_TO_MUTABLE: &i32 = unsafe { &MUTABLE }; - | ^^^^^^^ -help: skipping check for `const_refs_to_static` feature - --> $DIR/mutable_references.rs:75:45 - | -LL | const POINTS_TO_MUTABLE2: &i32 = unsafe { &*MUTABLE_REF }; - | ^^^^^^^^^^^ help: skipping check that does not even have a feature gate - --> $DIR/mutable_references.rs:79:45 + --> $DIR/mutable_references.rs:82:45 | LL | const POINTS_TO_MUTABLE_INNER: *const i32 = &mut 42 as *mut _ as *const _; | ^^^^^^^ help: skipping check that does not even have a feature gate - --> $DIR/mutable_references.rs:82:46 + --> $DIR/mutable_references.rs:85:46 | LL | const POINTS_TO_MUTABLE_INNER2: *const i32 = &mut 42 as *const _; | ^^^^^^^ help: skipping check that does not even have a feature gate - --> $DIR/mutable_references.rs:87:47 + --> $DIR/mutable_references.rs:90:47 | LL | const INTERIOR_MUTABLE_BEHIND_RAW: *mut i32 = &UnsafeCell::new(42) as *const _ as *mut _; | ^^^^^^^^^^^^^^^^^^^^ help: skipping check that does not even have a feature gate - --> $DIR/mutable_references.rs:99:51 + --> $DIR/mutable_references.rs:102:51 | LL | const RAW_SYNC: SyncPtr = SyncPtr { x: &AtomicI32::new(42) }; | ^^^^^^^^^^^^^^^^^^^ help: skipping check that does not even have a feature gate - --> $DIR/mutable_references.rs:102:49 + --> $DIR/mutable_references.rs:105:49 | LL | const RAW_MUT_CAST: SyncPtr = SyncPtr { x: &mut 42 as *mut _ as *const _ }; | ^^^^^^^ help: skipping check that does not even have a feature gate - --> $DIR/mutable_references.rs:105:51 + --> $DIR/mutable_references.rs:108:51 | LL | const RAW_MUT_COERCE: SyncPtr = SyncPtr { x: &mut 0 }; | ^^^^^^ diff --git a/tests/ui/consts/no-ice-from-static-in-const-issue-52060.rs b/tests/ui/consts/no-ice-from-static-in-const-issue-52060.rs new file mode 100644 index 00000000000..e0f9e462d32 --- /dev/null +++ b/tests/ui/consts/no-ice-from-static-in-const-issue-52060.rs @@ -0,0 +1,9 @@ +// Regression test for https://github.com/rust-lang/rust/issues/52060 +// The compiler shouldn't ICE in this case + +static mut A: &'static [u32] = &[1]; +static B: [u32; 1] = [0; unsafe { A.len() }]; +//~^ ERROR: evaluation of constant value failed +//~| mutable global memory + +fn main() {} diff --git a/tests/ui/consts/no-ice-from-static-in-const-issue-52060.stderr b/tests/ui/consts/no-ice-from-static-in-const-issue-52060.stderr new file mode 100644 index 00000000000..ca4d3224ec7 --- /dev/null +++ b/tests/ui/consts/no-ice-from-static-in-const-issue-52060.stderr @@ -0,0 +1,9 @@ +error[E0080]: evaluation of constant value failed + --> $DIR/no-ice-from-static-in-const-issue-52060.rs:5:35 + | +LL | static B: [u32; 1] = [0; unsafe { A.len() }]; + | ^ constant accesses mutable global memory + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/feature-gates/feature-gate-const-refs-to-static.rs b/tests/ui/feature-gates/feature-gate-const-refs-to-static.rs deleted file mode 100644 index 008b754dc6c..00000000000 --- a/tests/ui/feature-gates/feature-gate-const-refs-to-static.rs +++ /dev/null @@ -1,11 +0,0 @@ -static S: i32 = 0; -static mut S_MUT: i32 = 0; - -const C1: &i32 = &S; //~ERROR: referencing statics in constants is unstable -const C1_READ: () = { - assert!(*C1 == 0); -}; -const C2: *const i32 = unsafe { std::ptr::addr_of!(S_MUT) }; //~ERROR: referencing statics in constants is unstable - -fn main() { -} diff --git a/tests/ui/feature-gates/feature-gate-const-refs-to-static.stderr b/tests/ui/feature-gates/feature-gate-const-refs-to-static.stderr deleted file mode 100644 index 5af48471250..00000000000 --- a/tests/ui/feature-gates/feature-gate-const-refs-to-static.stderr +++ /dev/null @@ -1,27 +0,0 @@ -error[E0658]: referencing statics in constants is unstable - --> $DIR/feature-gate-const-refs-to-static.rs:4:19 - | -LL | const C1: &i32 = &S; - | ^ - | - = note: see issue #119618 for more information - = help: add `#![feature(const_refs_to_static)]` 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: `static` and `const` variables can refer to other `const` variables. A `const` variable, however, cannot refer to a `static` variable. - = help: to fix this, the value can be extracted to a `const` and then used. - -error[E0658]: referencing statics in constants is unstable - --> $DIR/feature-gate-const-refs-to-static.rs:8:52 - | -LL | const C2: *const i32 = unsafe { std::ptr::addr_of!(S_MUT) }; - | ^^^^^ - | - = note: see issue #119618 for more information - = help: add `#![feature(const_refs_to_static)]` 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: `static` and `const` variables can refer to other `const` variables. A `const` variable, however, cannot refer to a `static` variable. - = help: to fix this, the value can be extracted to a `const` and then used. - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/static/issue-18118-2.rs b/tests/ui/static/issue-18118-2.rs deleted file mode 100644 index 6c81eec7d7e..00000000000 --- a/tests/ui/static/issue-18118-2.rs +++ /dev/null @@ -1,6 +0,0 @@ -pub fn main() { - const z: &'static isize = { - static p: isize = 3; - &p //~ ERROR referencing statics - }; -} diff --git a/tests/ui/static/issue-18118-2.stderr b/tests/ui/static/issue-18118-2.stderr deleted file mode 100644 index f084f2b9fdf..00000000000 --- a/tests/ui/static/issue-18118-2.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error[E0658]: referencing statics in constants is unstable - --> $DIR/issue-18118-2.rs:4:10 - | -LL | &p - | ^ - | - = note: see issue #119618 for more information - = help: add `#![feature(const_refs_to_static)]` 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: `static` and `const` variables can refer to other `const` variables. A `const` variable, however, cannot refer to a `static` variable. - = help: to fix this, the value can be extracted to a `const` and then used. - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/statics/const_generics.rs b/tests/ui/statics/const_generics.rs index 7f64f6995a4..6cc0a65f77d 100644 --- a/tests/ui/statics/const_generics.rs +++ b/tests/ui/statics/const_generics.rs @@ -10,7 +10,6 @@ //@[noopt] compile-flags: -Copt-level=0 //@[opt] compile-flags: -O -#![feature(const_refs_to_static)] #![feature(adt_const_params, unsized_const_params)] #![allow(incomplete_features)] diff --git a/tests/ui/statics/mutable_memory_validation.rs b/tests/ui/statics/mutable_memory_validation.rs index d16b787fef8..032b903f64e 100644 --- a/tests/ui/statics/mutable_memory_validation.rs +++ b/tests/ui/statics/mutable_memory_validation.rs @@ -4,8 +4,6 @@ //@ normalize-stderr-test: "(the raw bytes of the constant) \(size: [0-9]*, align: [0-9]*\)" -> "$1 (size: $$SIZE, align: $$ALIGN)" //@ normalize-stderr-test: "([0-9a-f][0-9a-f] |╾─*A(LLOC)?[0-9]+(\+[a-z0-9]+)?()?─*╼ )+ *│.*" -> "HEX_DUMP" -#![feature(const_refs_to_static)] - use std::cell::UnsafeCell; struct Meh { diff --git a/tests/ui/statics/mutable_memory_validation.stderr b/tests/ui/statics/mutable_memory_validation.stderr index 60d13564679..76e1827ea12 100644 --- a/tests/ui/statics/mutable_memory_validation.stderr +++ b/tests/ui/statics/mutable_memory_validation.stderr @@ -1,5 +1,5 @@ error[E0080]: it is undefined behavior to use this value - --> $DIR/mutable_memory_validation.rs:15:1 + --> $DIR/mutable_memory_validation.rs:13:1 | LL | const MUH: Meh = Meh { x: unsafe { &mut *(&READONLY as *const _ as *mut _) } }; | ^^^^^^^^^^^^^^ constructing invalid value at .x.: encountered `UnsafeCell` in read-only memory From cdd3371bb4fceb9931be48700f5a70de7819df7c Mon Sep 17 00:00:00 2001 From: zopsicle <50083900+zopsicle@users.noreply.github.com> Date: Thu, 26 Sep 2024 01:44:06 +0200 Subject: [PATCH 291/683] rustdoc: do not animate when user prefers reduced motion This accessibility improvement gates the target flashing and tooltip fade-out behind an inverted prefers-reduced-motion media query. --- src/librustdoc/html/static/css/rustdoc.css | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index ae9727a4d4f..61e32aa5d30 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -1687,7 +1687,12 @@ instead, we check that it's not a "finger" cursor. padding-right: 3px; background-color: var(--target-background-color); border-right: 3px solid var(--target-border-color); - animation: 0.65s cubic-bezier(0, 0, 0.1, 1.0) 0.1s targetfadein; +} + +@media not (prefers-reduced-motion) { + :target { + animation: 0.65s cubic-bezier(0, 0, 0.1, 1.0) 0.1s targetfadein; + } } .code-header a.tooltip { @@ -1712,12 +1717,14 @@ a.tooltip:hover::after { content: "\00a0"; } -/* This animation is layered onto the mistake-proofing delay for dismissing - a hovered tooltip, to ensure it feels responsive even with the delay. - */ -.fade-out { - opacity: 0; - transition: opacity 0.45s cubic-bezier(0, 0, 0.1, 1.0); +@media not (prefers-reduced-motion) { + /* This animation is layered onto the mistake-proofing delay for dismissing + a hovered tooltip, to ensure it feels responsive even with the delay. + */ + .fade-out { + opacity: 0; + transition: opacity 0.45s cubic-bezier(0, 0, 0.1, 1.0); + } } .popover.tooltip .content { From ef87a7f663826b67cf47e147546ada7e1d081c46 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 26 Sep 2024 15:42:37 +0200 Subject: [PATCH 292/683] add missing FIXME(const-hack) --- library/core/src/ptr/alignment.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/ptr/alignment.rs b/library/core/src/ptr/alignment.rs index ceb5906d226..50706fca5b0 100644 --- a/library/core/src/ptr/alignment.rs +++ b/library/core/src/ptr/alignment.rs @@ -155,7 +155,7 @@ impl Alignment { !(unsafe { self.as_usize().unchecked_sub(1) }) } - // Remove me once `Ord::max` is usable in const + // FIXME(const-hack) Remove me once `Ord::max` is usable in const pub(crate) const fn max(a: Self, b: Self) -> Self { if a.as_usize() > b.as_usize() { a } else { b } } From fb10eeb42b0389961d12c432f476b63ea23851a9 Mon Sep 17 00:00:00 2001 From: Mads Marquart Date: Sat, 14 Sep 2024 21:17:50 +0200 Subject: [PATCH 293/683] Move Apple linker args from `rustc_target` to `rustc_codegen_ssa` They are dependent on the deployment target and SDK version, but having these in `rustc_target` makes it hard to introduce that dependency. --- compiler/rustc_codegen_ssa/src/back/link.rs | 133 +++++++++++++++++- .../rustc_target/src/spec/base/apple/mod.rs | 122 +--------------- 2 files changed, 134 insertions(+), 121 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 69693230ce0..80e8111516e 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -40,7 +40,7 @@ use rustc_target::spec::crt_objects::CrtObjects; use rustc_target::spec::{ Cc, LinkOutputKind, LinkSelfContainedComponents, LinkSelfContainedDefault, LinkerFeatures, LinkerFlavor, LinkerFlavorCli, Lld, PanicStrategy, RelocModel, RelroLevel, SanitizerSet, - SplitDebuginfo, + SplitDebuginfo, current_apple_deployment_target, }; use tempfile::Builder as TempFileBuilder; use tracing::{debug, info, warn}; @@ -2405,6 +2405,8 @@ fn add_order_independent_options( // Take care of the flavors and CLI options requesting the `lld` linker. add_lld_args(cmd, sess, flavor, self_contained_components); + add_apple_link_args(cmd, sess, flavor); + let apple_sdk_root = add_apple_sdk(cmd, sess, flavor); add_link_script(cmd, sess, tmpdir, crate_type); @@ -2957,6 +2959,135 @@ pub(crate) fn are_upstream_rust_objects_already_included(sess: &Session) -> bool } } +/// We need to communicate four things to the linker on Apple/Darwin targets: +/// - The architecture. +/// - The operating system (and that it's an Apple platform). +/// - The deployment target. +/// - The environment / ABI. +fn add_apple_link_args(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) { + if !sess.target.is_like_osx { + return; + } + let LinkerFlavor::Darwin(cc, _) = flavor else { + return; + }; + + // `sess.target.arch` (`target_arch`) is not detailed enough. + let llvm_arch = sess.target.llvm_target.split_once('-').expect("LLVM target must have arch").0; + let target_os = &*sess.target.os; + let target_abi = &*sess.target.abi; + + // The architecture name to forward to the linker. + // + // Supported architecture names can be found in the source: + // https://github.com/apple-oss-distributions/ld64/blob/ld64-951.9/src/abstraction/MachOFileAbstraction.hpp#L578-L648 + // + // Intentially verbose to ensure that the list always matches correctly + // with the list in the source above. + let ld64_arch = match llvm_arch { + "armv7k" => "armv7k", + "armv7s" => "armv7s", + "arm64" => "arm64", + "arm64e" => "arm64e", + "arm64_32" => "arm64_32", + // ld64 doesn't understand i686, so fall back to i386 instead. + // + // Same story when linking with cc, since that ends up invoking ld64. + "i386" | "i686" => "i386", + "x86_64" => "x86_64", + "x86_64h" => "x86_64h", + _ => bug!("unsupported architecture in Apple target: {}", sess.target.llvm_target), + }; + + if cc == Cc::No { + // From the man page for ld64 (`man ld`): + // > The linker accepts universal (multiple-architecture) input files, + // > but always creates a "thin" (single-architecture), standard + // > Mach-O output file. The architecture for the output file is + // > specified using the -arch option. + // + // The linker has heuristics to determine the desired architecture, + // but to be safe, and to avoid a warning, we set the architecture + // explicitly. + cmd.link_args(&["-arch", ld64_arch]); + + // Man page says that ld64 supports the following platform names: + // > - macos + // > - ios + // > - tvos + // > - watchos + // > - bridgeos + // > - visionos + // > - xros + // > - mac-catalyst + // > - ios-simulator + // > - tvos-simulator + // > - watchos-simulator + // > - visionos-simulator + // > - xros-simulator + // > - driverkit + let platform_name = match (target_os, target_abi) { + (os, "") => os, + ("ios", "macabi") => "mac-catalyst", + ("ios", "sim") => "ios-simulator", + ("tvos", "sim") => "tvos-simulator", + ("watchos", "sim") => "watchos-simulator", + ("visionos", "sim") => "visionos-simulator", + _ => bug!("invalid OS/ABI combination for Apple target: {target_os}, {target_abi}"), + }; + + let (major, minor, patch) = current_apple_deployment_target(&sess.target); + let min_version = format!("{major}.{minor}.{patch}"); + + // Lie about the SDK version, we don't know it here + let sdk_version = &*min_version; + + // From the man page for ld64 (`man ld`): + // > This is set to indicate the platform, oldest supported version of + // > that platform that output is to be used on, and the SDK that the + // > output was built against. + // + // Like with `-arch`, the linker can figure out the platform versions + // itself from the binaries being linked, but to be safe, we specify + // the desired versions here explicitly. + cmd.link_args(&["-platform_version", platform_name, &*min_version, sdk_version]); + } else { + // cc == Cc::Yes + // We'd _like_ to use `-target` everywhere, since that can uniquely + // communicate all the required details, but that doesn't work on GCC, + // and since we don't know whether the `cc` compiler is Clang, GCC, or + // something else, we fall back to other options that also work on GCC + // when compiling for macOS. + // + // Targets other than macOS are ill-supported by GCC (it doesn't even + // support e.g. `-miphoneos-version-min`), so in those cases we can + // fairly safely use `-target`. See also the following, where it is + // made explicit that the recommendation by LLVM developers is to use + // `-target`: + if target_os == "macos" { + // `-arch` communicates the architecture. + // + // CC forwards the `-arch` to the linker, so we use the same value + // here intentionally. + cmd.cc_args(&["-arch", ld64_arch]); + + // The presence of `-mmacosx-version-min` makes CC default to + // macOS, and it sets the deployment target. + let (major, minor, patch) = current_apple_deployment_target(&sess.target); + // Intentionally pass this as a single argument, Clang doesn't + // seem to like it otherwise. + cmd.cc_arg(&format!("-mmacosx-version-min={major}.{minor}.{patch}")); + + // macOS has no environment, so with these two, we've told CC the + // four desired parameters. + // + // We avoid `-m32`/`-m64`, as this is already encoded by `-arch`. + } else { + cmd.cc_args(&["-target", &sess.target.llvm_target]); + } + } +} + fn add_apple_sdk(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) -> Option { let arch = &sess.target.arch; let os = &sess.target.os; diff --git a/compiler/rustc_target/src/spec/base/apple/mod.rs b/compiler/rustc_target/src/spec/base/apple/mod.rs index fdecd330c2d..81b5a936d35 100644 --- a/compiler/rustc_target/src/spec/base/apple/mod.rs +++ b/compiler/rustc_target/src/spec/base/apple/mod.rs @@ -3,8 +3,8 @@ use std::env; use std::num::ParseIntError; use crate::spec::{ - Cc, DebuginfoKind, FramePointer, LinkArgs, LinkerFlavor, Lld, SplitDebuginfo, StackProbeType, - StaticCow, Target, TargetOptions, add_link_args, add_link_args_iter, cvs, + Cc, DebuginfoKind, FramePointer, LinkerFlavor, Lld, SplitDebuginfo, StackProbeType, StaticCow, + Target, TargetOptions, cvs, }; #[cfg(test)] @@ -40,25 +40,6 @@ impl Arch { } } - /// The architecture name to forward to the linker. - fn ld_arch(self) -> &'static str { - // Supported architecture names can be found in the source: - // https://github.com/apple-oss-distributions/ld64/blob/ld64-951.9/src/abstraction/MachOFileAbstraction.hpp#L578-L648 - match self { - Armv7k => "armv7k", - Armv7s => "armv7s", - Arm64 => "arm64", - Arm64e => "arm64e", - Arm64_32 => "arm64_32", - // ld64 doesn't understand i686, so fall back to i386 instead - // - // Same story when linking with cc, since that ends up invoking ld64. - I386 | I686 => "i386", - X86_64 => "x86_64", - X86_64h => "x86_64h", - } - } - pub(crate) fn target_arch(self) -> Cow<'static, str> { Cow::Borrowed(match self { Armv7k | Armv7s => "arm", @@ -116,104 +97,6 @@ impl TargetAbi { } } -fn pre_link_args(os: &'static str, arch: Arch, abi: TargetAbi) -> LinkArgs { - // From the man page for ld64 (`man ld`): - // > The linker accepts universal (multiple-architecture) input files, - // > but always creates a "thin" (single-architecture), standard Mach-O - // > output file. The architecture for the output file is specified using - // > the -arch option. - // - // The linker has heuristics to determine the desired architecture, but to - // be safe, and to avoid a warning, we set the architecture explicitly. - let mut args = - TargetOptions::link_args(LinkerFlavor::Darwin(Cc::No, Lld::No), &["-arch", arch.ld_arch()]); - - // From the man page for ld64 (`man ld`): - // > This is set to indicate the platform, oldest supported version of - // > that platform that output is to be used on, and the SDK that the - // > output was built against. platform [...] may be one of the following - // > strings: - // > - macos - // > - ios - // > - tvos - // > - watchos - // > - bridgeos - // > - visionos - // > - xros - // > - mac-catalyst - // > - ios-simulator - // > - tvos-simulator - // > - watchos-simulator - // > - visionos-simulator - // > - xros-simulator - // > - driverkit - // - // Like with `-arch`, the linker can figure out the platform versions - // itself from the binaries being linked, but to be safe, we specify the - // desired versions here explicitly. - let platform_name: StaticCow = match abi { - TargetAbi::Normal => os.into(), - TargetAbi::Simulator => format!("{os}-simulator").into(), - TargetAbi::MacCatalyst => "mac-catalyst".into(), - }; - let min_version: StaticCow = { - let (major, minor, patch) = deployment_target(os, arch, abi); - format!("{major}.{minor}.{patch}").into() - }; - // Lie about the SDK version, we don't know it here - let sdk_version = min_version.clone(); - add_link_args_iter( - &mut args, - LinkerFlavor::Darwin(Cc::No, Lld::No), - ["-platform_version".into(), platform_name, min_version, sdk_version].into_iter(), - ); - - // We need to communicate four things to the C compiler to be able to link: - // - The architecture. - // - The operating system (and that it's an Apple platform). - // - The deployment target. - // - The environment / ABI. - // - // We'd like to use `-target` everywhere, since that can uniquely - // communicate all of these, but that doesn't work on GCC, and since we - // don't know whether the `cc` compiler is Clang, GCC, or something else, - // we fall back to other options that also work on GCC when compiling for - // macOS. - // - // Targets other than macOS are ill-supported by GCC (it doesn't even - // support e.g. `-miphoneos-version-min`), so in those cases we can fairly - // safely use `-target`. See also the following, where it is made explicit - // that the recommendation by LLVM developers is to use `-target`: - // - if os == "macos" { - // `-arch` communicates the architecture. - // - // CC forwards the `-arch` to the linker, so we use the same value - // here intentionally. - add_link_args(&mut args, LinkerFlavor::Darwin(Cc::Yes, Lld::No), &[ - "-arch", - arch.ld_arch(), - ]); - // The presence of `-mmacosx-version-min` makes CC default to macOS, - // and it sets the deployment target. - let (major, minor, patch) = deployment_target(os, arch, abi); - let opt = format!("-mmacosx-version-min={major}.{minor}.{patch}").into(); - add_link_args_iter(&mut args, LinkerFlavor::Darwin(Cc::Yes, Lld::No), [opt].into_iter()); - // macOS has no environment, so with these two, we've told CC all the - // desired parameters. - // - // We avoid `-m32`/`-m64`, as this is already encoded by `-arch`. - } else { - add_link_args_iter( - &mut args, - LinkerFlavor::Darwin(Cc::Yes, Lld::No), - ["-target".into(), llvm_target(os, arch, abi)].into_iter(), - ); - } - - args -} - /// Get the base target options, LLVM target and `target_arch` from the three /// things that uniquely identify Rust's Apple targets: The OS, the /// architecture, and the ABI. @@ -232,7 +115,6 @@ pub(crate) fn base( // macOS has -dead_strip, which doesn't rely on function_sections function_sections: false, dynamic_linking: true, - pre_link_args: pre_link_args(os, arch, abi), families: cvs!["unix"], is_like_osx: true, // LLVM notes that macOS 10.11+ and iOS 9+ default From 9431d1ab4e7613a21790d7e95616e52f3b679957 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Thu, 26 Sep 2024 09:33:30 -0700 Subject: [PATCH 294/683] Add `sun_path` to the fake doc `sockaddr_un` --- library/std/src/os/unix/net/addr.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/library/std/src/os/unix/net/addr.rs b/library/std/src/os/unix/net/addr.rs index dcc1b5999dc..e0f3aea42b6 100644 --- a/library/std/src/os/unix/net/addr.rs +++ b/library/std/src/os/unix/net/addr.rs @@ -15,7 +15,9 @@ mod libc { pub type socklen_t = u32; pub struct sockaddr; #[derive(Clone)] - pub struct sockaddr_un; + pub struct sockaddr_un { + pub sun_path: [u8; 1], + } } const SUN_PATH_OFFSET: usize = mem::offset_of!(libc::sockaddr_un, sun_path); From fb095cc3ff6054d7f6a2d793455210abe0a1ae63 Mon Sep 17 00:00:00 2001 From: github-actions Date: Sun, 22 Sep 2024 00:22:12 +0000 Subject: [PATCH 295/683] cargo update: rustbook rustbook dependencies: Locking 70 packages to latest compatible versions Removing adler v1.0.2 Adding adler2 v2.0.0 Updating anstream v0.6.14 -> v0.6.15 Updating anstyle v1.0.7 -> v1.0.8 Updating anstyle-parse v0.2.4 -> v0.2.5 Updating anstyle-query v1.1.0 -> v1.1.1 Updating anstyle-wincon v3.0.3 -> v3.0.4 Updating anyhow v1.0.86 -> v1.0.89 Removing base64 v0.22.1 Updating bstr v1.9.1 -> v1.10.0 Adding byteorder v1.5.0 Updating cc v1.1.5 -> v1.1.21 Updating clap v4.5.9 -> v4.5.18 Updating clap_builder v4.5.9 -> v4.5.18 Updating clap_complete v4.5.8 -> v4.5.29 Updating clap_derive v4.5.8 -> v4.5.18 Updating clap_lex v0.7.1 -> v0.7.2 Updating colorchoice v1.0.1 -> v1.0.2 Updating core-foundation-sys v0.8.6 -> v0.8.7 Updating cpufeatures v0.2.12 -> v0.2.14 Adding dateparser v0.2.1 Removing deranged v0.3.11 Updating env_filter v0.1.0 -> v0.1.2 Updating env_logger v0.11.3 -> v0.11.5 Updating fastrand v2.1.0 -> v2.1.1 Updating flate2 v1.0.30 -> v1.0.33 Updating iana-time-zone v0.1.60 -> v0.1.61 Updating indexmap v2.2.6 -> v2.5.0 Updating is_terminal_polyfill v1.70.0 -> v1.70.1 Updating js-sys v0.3.69 -> v0.3.70 Adding lazy_static v1.5.0 Updating libc v0.2.155 -> v0.2.158 Removing linked-hash-map v0.5.6 Updating mdbook-i18n-helpers v0.3.4 -> v0.3.5 Updating miniz_oxide v0.7.4 -> v0.8.0 Updating normpath v1.2.0 -> v1.3.0 Removing num-conv v0.1.0 Updating opener v0.7.1 -> v0.7.2 Updating pest v2.7.11 -> v2.7.13 Updating pest_derive v2.7.11 -> v2.7.13 Updating pest_generator v2.7.11 -> v2.7.13 Updating pest_meta v2.7.11 -> v2.7.13 Removing plist v1.7.0 Removing powerfmt v0.2.0 Updating ppv-lite86 v0.2.17 -> v0.2.20 Adding pulldown-cmark v0.11.3 (latest: v0.12.1) Adding pulldown-cmark-escape v0.11.0 Adding pulldown-cmark-to-cmark v15.0.1 (latest: v17.0.0) Removing quick-xml v0.32.0 Updating quote v1.0.36 -> v1.0.37 Updating redox_syscall v0.5.3 -> v0.5.4 Updating regex v1.10.5 -> v1.10.6 Updating rustix v0.38.34 -> v0.38.37 Updating serde v1.0.204 -> v1.0.210 Updating serde_derive v1.0.204 -> v1.0.210 Updating serde_json v1.0.120 -> v1.0.128 Updating serde_spanned v0.6.6 -> v0.6.7 Updating syn v2.0.71 -> v2.0.77 Updating tempfile v3.10.1 -> v3.12.0 Updating thiserror v1.0.62 -> v1.0.63 Updating thiserror-impl v1.0.62 -> v1.0.63 Removing time v0.3.36 Removing time-core v0.1.2 Removing time-macros v0.2.18 Updating toml v0.8.14 -> v0.8.19 Updating toml_datetime v0.6.6 -> v0.6.8 Updating toml_edit v0.22.15 -> v0.22.21 Updating unicode-ident v1.0.12 -> v1.0.13 Updating unicode-normalization v0.1.23 -> v0.1.24 Updating unicode-width v0.1.13 -> v0.1.14 (latest: v0.2.0) Updating version_check v0.9.4 -> v0.9.5 Updating wasm-bindgen v0.2.92 -> v0.2.93 Updating wasm-bindgen-backend v0.2.92 -> v0.2.93 Updating wasm-bindgen-macro v0.2.92 -> v0.2.93 Updating wasm-bindgen-macro-support v0.2.92 -> v0.2.93 Updating wasm-bindgen-shared v0.2.92 -> v0.2.93 Updating winapi-util v0.1.8 -> v0.1.9 Adding windows-sys v0.59.0 Updating winnow v0.6.13 -> v0.6.18 Removing yaml-rust v0.4.5 Adding zerocopy v0.7.35 Adding zerocopy-derive v0.7.35 note: pass `--verbose` to see 26 unchanged dependencies behind latest [ extracted from rust-lang/rust#129538 - Trevor ] Co-authored-by: Trevor Gross --- src/tools/rustbook/Cargo.lock | 452 +++++++++++++++++----------------- 1 file changed, 224 insertions(+), 228 deletions(-) diff --git a/src/tools/rustbook/Cargo.lock b/src/tools/rustbook/Cargo.lock index 1394675a9dc..e5f0aabbf7c 100644 --- a/src/tools/rustbook/Cargo.lock +++ b/src/tools/rustbook/Cargo.lock @@ -3,10 +3,10 @@ version = 3 [[package]] -name = "adler" -version = "1.0.2" +name = "adler2" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" [[package]] name = "aho-corasick" @@ -47,9 +47,9 @@ dependencies = [ [[package]] name = "anstream" -version = "0.6.14" +version = "0.6.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "418c75fa768af9c03be99d17643f93f79bbba589895012a80e3452a19ddda15b" +checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526" dependencies = [ "anstyle", "anstyle-parse", @@ -62,33 +62,33 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.7" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b" +checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1" [[package]] name = "anstyle-parse" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c03a11a9034d92058ceb6ee011ce58af4a9bf61491aa7e1e59ecd24bd40d22d4" +checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.1.0" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad186efb764318d35165f1758e7dcef3b10628e26d41a44bc5550652e6804391" +checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a" dependencies = [ "windows-sys 0.52.0", ] [[package]] name = "anstyle-wincon" -version = "3.0.3" +version = "3.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19" +checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8" dependencies = [ "anstyle", "windows-sys 0.52.0", @@ -96,9 +96,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.86" +version = "1.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" +checksum = "86fdf8605db99b54d3cd748a44c6d04df638eb5dafb219b135d0149bd0db01f6" [[package]] name = "autocfg" @@ -106,12 +106,6 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" -[[package]] -name = "base64" -version = "0.22.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" - [[package]] name = "bincode" version = "1.3.3" @@ -144,9 +138,9 @@ dependencies = [ [[package]] name = "bstr" -version = "1.9.1" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05efc5cfd9110c8416e471df0e96702d58690178e206e61b7173706673c93706" +checksum = "40723b8fb387abc38f4f4a37c09073622e41dd12327033091ef8950659e6dc0c" dependencies = [ "memchr", "regex-automata", @@ -160,10 +154,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" [[package]] -name = "cc" -version = "1.1.5" +name = "byteorder" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "324c74f2155653c90b04f25b2a47a8a631360cb908f92a772695f430c7e31052" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "cc" +version = "1.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07b1695e2c7e8fc85310cde85aeaab7e3097f593c91d209d3f9df76c928100f0" +dependencies = [ + "shlex", +] [[package]] name = "cfg-if" @@ -179,15 +182,17 @@ checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" dependencies = [ "android-tzdata", "iana-time-zone", + "js-sys", "num-traits", + "wasm-bindgen", "windows-targets 0.52.6", ] [[package]] name = "clap" -version = "4.5.9" +version = "4.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64acc1846d54c1fe936a78dc189c34e28d3f5afc348403f28ecf53660b9b8462" +checksum = "b0956a43b323ac1afaffc053ed5c4b7c1f1800bacd1683c353aabbb752515dd3" dependencies = [ "clap_builder", "clap_derive", @@ -195,9 +200,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.9" +version = "4.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fb8393d67ba2e7bfaf28a23458e4e2b543cc73a99595511eb207fdb8aede942" +checksum = "4d72166dd41634086d5803a47eb71ae740e61d84709c36f3c34110173db3961b" dependencies = [ "anstream", "anstyle", @@ -208,18 +213,18 @@ dependencies = [ [[package]] name = "clap_complete" -version = "4.5.8" +version = "4.5.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b4be9c4c4b1f30b78d8a750e0822b6a6102d97e62061c583a6c1dea2dfb33ae" +checksum = "8937760c3f4c60871870b8c3ee5f9b30771f792a7045c48bcbba999d7d6b3b8e" dependencies = [ "clap", ] [[package]] name = "clap_derive" -version = "4.5.8" +version = "4.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bac35c6dafb060fd4d275d9a4ffae97917c13a6327903a8be2153cd964f7085" +checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab" dependencies = [ "heck", "proc-macro2", @@ -229,27 +234,27 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.7.1" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b82cf0babdbd58558212896d1a4272303a57bdb245c2bf1147185fb45640e70" +checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" [[package]] name = "colorchoice" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422" +checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0" [[package]] name = "core-foundation-sys" -version = "0.8.6" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "cpufeatures" -version = "0.2.12" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" +checksum = "608697df725056feaccfa42cffdaeeec3fccc4ffc38358ecd19b243e716a78e0" dependencies = [ "libc", ] @@ -273,6 +278,18 @@ dependencies = [ "typenum", ] +[[package]] +name = "dateparser" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2ef451feee09ae5ecd8a02e738bd9adee9266b8fa9b44e22d3ce968d8694238" +dependencies = [ + "anyhow", + "chrono", + "lazy_static", + "regex", +] + [[package]] name = "dbus" version = "0.9.7" @@ -284,15 +301,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "deranged" -version = "0.3.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" -dependencies = [ - "powerfmt", -] - [[package]] name = "digest" version = "0.10.7" @@ -323,9 +331,9 @@ dependencies = [ [[package]] name = "env_filter" -version = "0.1.0" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a009aa4810eb158359dda09d0c87378e4bbb89b5a801f016885a4707ba24f7ea" +checksum = "4f2c92ceda6ceec50f43169f9ee8424fe2db276791afde7b2cd8bc084cb376ab" dependencies = [ "log", "regex", @@ -333,9 +341,9 @@ dependencies = [ [[package]] name = "env_logger" -version = "0.11.3" +version = "0.11.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38b35839ba51819680ba087cd351788c9a3c476841207e0b8cee0b04722343b9" +checksum = "e13fa619b91fb2381732789fc5de83b45675e882f66623b7d8cb4f643017018d" dependencies = [ "anstream", "anstyle", @@ -362,15 +370,15 @@ dependencies = [ [[package]] name = "fastrand" -version = "2.1.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" +checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6" [[package]] name = "flate2" -version = "1.0.30" +version = "1.0.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f54427cfd1c7829e2a139fcefea601bf088ebca651d2bf53ebc600eac295dae" +checksum = "324a1be68054ef05ad64b861cc9eaf1d623d2d8cb25b4bf2cb9cdd902b4bf253" dependencies = [ "crc32fast", "miniz_oxide", @@ -494,9 +502,9 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "iana-time-zone" -version = "0.1.60" +version = "0.1.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" +checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" dependencies = [ "android_system_properties", "core-foundation-sys", @@ -527,9 +535,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.2.6" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" +checksum = "68b900aa2f7301e21c36462b170ee99994de34dff39a4a6a528e80e7376d07e5" dependencies = [ "equivalent", "hashbrown", @@ -537,9 +545,9 @@ dependencies = [ [[package]] name = "is_terminal_polyfill" -version = "1.70.0" +version = "1.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" [[package]] name = "itoa" @@ -549,18 +557,24 @@ checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" [[package]] name = "js-sys" -version = "0.3.69" +version = "0.3.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" +checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a" dependencies = [ "wasm-bindgen", ] [[package]] -name = "libc" -version = "0.2.155" +name = "lazy_static" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "libc" +version = "0.2.158" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" [[package]] name = "libdbus-sys" @@ -581,12 +595,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "linked-hash-map" -version = "0.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" - [[package]] name = "linux-raw-sys" version = "0.4.14" @@ -653,7 +661,7 @@ dependencies = [ "memchr", "once_cell", "opener", - "pulldown-cmark", + "pulldown-cmark 0.10.3", "regex", "serde", "serde_json", @@ -665,16 +673,17 @@ dependencies = [ [[package]] name = "mdbook-i18n-helpers" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c8f972ab672d366c3dad77ea5aa7bae68db2d25fbeb889849f97469d7b658e4" +checksum = "7cac78e4f518f326e5fc1ff95e79e7e0e58330cb8ac6e4b559d9659cf69bb1ab" dependencies = [ "anyhow", "chrono", + "dateparser", "mdbook", "polib", - "pulldown-cmark", - "pulldown-cmark-to-cmark", + "pulldown-cmark 0.11.3", + "pulldown-cmark-to-cmark 15.0.1", "regex", "semver", "serde_json", @@ -690,7 +699,7 @@ dependencies = [ "mdbook", "once_cell", "pathdiff", - "pulldown-cmark", + "pulldown-cmark 0.10.3", "regex", "semver", "serde_json", @@ -704,11 +713,11 @@ dependencies = [ "clap", "html_parser", "mdbook", - "pulldown-cmark", - "pulldown-cmark-to-cmark", + "pulldown-cmark 0.10.3", + "pulldown-cmark-to-cmark 13.0.0", "serde_json", "thiserror", - "toml 0.8.14", + "toml 0.8.19", ] [[package]] @@ -717,8 +726,8 @@ version = "1.0.0" dependencies = [ "clap", "mdbook", - "pulldown-cmark", - "pulldown-cmark-to-cmark", + "pulldown-cmark 0.10.3", + "pulldown-cmark-to-cmark 13.0.0", "serde_json", ] @@ -730,11 +739,11 @@ checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "miniz_oxide" -version = "0.7.4" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" +checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" dependencies = [ - "adler", + "adler2", ] [[package]] @@ -745,19 +754,13 @@ checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" [[package]] name = "normpath" -version = "1.2.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5831952a9476f2fed74b77d74182fa5ddc4d21c72ec45a333b250e3ed0272804" +checksum = "c8911957c4b1549ac0dc74e30db9c8b0e66ddcd6d7acc33098f4c63a64a6d7ed" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] -[[package]] -name = "num-conv" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" - [[package]] name = "num-traits" version = "0.2.19" @@ -797,14 +800,14 @@ dependencies = [ [[package]] name = "opener" -version = "0.7.1" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8df34be653210fbe9ffaff41d3b92721c56ce82dfee58ee684f9afb5e3a90c0" +checksum = "d0812e5e4df08da354c851a3376fead46db31c2214f849d3de356d774d057681" dependencies = [ "bstr", "dbus", "normpath", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -844,9 +847,9 @@ checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "pest" -version = "2.7.11" +version = "2.7.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd53dff83f26735fdc1ca837098ccf133605d794cdae66acfc2bfac3ec809d95" +checksum = "fdbef9d1d47087a895abd220ed25eb4ad973a5e26f6a4367b038c25e28dfc2d9" dependencies = [ "memchr", "thiserror", @@ -855,9 +858,9 @@ dependencies = [ [[package]] name = "pest_derive" -version = "2.7.11" +version = "2.7.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a548d2beca6773b1c244554d36fcf8548a8a58e74156968211567250e48e49a" +checksum = "4d3a6e3394ec80feb3b6393c725571754c6188490265c61aaf260810d6b95aa0" dependencies = [ "pest", "pest_generator", @@ -865,9 +868,9 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.7.11" +version = "2.7.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c93a82e8d145725dcbaf44e5ea887c8a869efdcc28706df2d08c69e17077183" +checksum = "94429506bde1ca69d1b5601962c73f4172ab4726571a59ea95931218cb0e930e" dependencies = [ "pest", "pest_meta", @@ -878,9 +881,9 @@ dependencies = [ [[package]] name = "pest_meta" -version = "2.7.11" +version = "2.7.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a941429fea7e08bedec25e4f6785b6ffaacc6b755da98df5ef3e7dcf4a124c4f" +checksum = "ac8a071862e93690b6e34e9a5fb8e33ff3734473ac0245b27232222c4906a33f" dependencies = [ "once_cell", "pest", @@ -950,19 +953,6 @@ version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" -[[package]] -name = "plist" -version = "1.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42cf17e9a1800f5f396bc67d193dc9411b59012a5876445ef450d449881e1016" -dependencies = [ - "base64", - "indexmap", - "quick-xml", - "serde", - "time", -] - [[package]] name = "polib" version = "0.2.0" @@ -972,17 +962,14 @@ dependencies = [ "linereader", ] -[[package]] -name = "powerfmt" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" - [[package]] name = "ppv-lite86" -version = "0.2.17" +version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +dependencies = [ + "zerocopy", +] [[package]] name = "precomputed-hash" @@ -1008,7 +995,19 @@ dependencies = [ "bitflags 2.6.0", "getopts", "memchr", - "pulldown-cmark-escape", + "pulldown-cmark-escape 0.10.1", + "unicase", +] + +[[package]] +name = "pulldown-cmark" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "679341d22c78c6c649893cbd6c3278dcbe9fc4faa62fea3a9296ae2b50c14625" +dependencies = [ + "bitflags 2.6.0", + "memchr", + "pulldown-cmark-escape 0.11.0", "unicase", ] @@ -1018,29 +1017,35 @@ version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd348ff538bc9caeda7ee8cad2d1d48236a1f443c1fa3913c6a02fe0043b1dd3" +[[package]] +name = "pulldown-cmark-escape" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "007d8adb5ddab6f8e3f491ac63566a7d5002cc7ed73901f72057943fa71ae1ae" + [[package]] name = "pulldown-cmark-to-cmark" version = "13.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f609795c8d835f79dcfcf768415b9fb57ef1b74891e99f86e73f43a7a257163b" dependencies = [ - "pulldown-cmark", + "pulldown-cmark 0.10.3", ] [[package]] -name = "quick-xml" -version = "0.32.0" +name = "pulldown-cmark-to-cmark" +version = "15.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d3a6e5838b60e0e8fa7a43f22ade549a37d61f8bdbe636d0d7816191de969c2" +checksum = "b9c77db841443d89a57ae94f22d29c022f6d9f41b00bddbf1f4024dbaf4bdce1" dependencies = [ - "memchr", + "pulldown-cmark 0.11.3", ] [[package]] name = "quote" -version = "1.0.36" +version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" dependencies = [ "proc-macro2", ] @@ -1077,18 +1082,18 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.3" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4" +checksum = "0884ad60e090bf1345b93da0a5de8923c93884cd03f40dfcfddd3b4bee661853" dependencies = [ "bitflags 2.6.0", ] [[package]] name = "regex" -version = "1.10.5" +version = "1.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b91213439dad192326a0d7c6ee3955910425f441d7038e0d6933b0aec5c4517f" +checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" dependencies = [ "aho-corasick", "memchr", @@ -1128,9 +1133,9 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.34" +version = "0.38.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" +checksum = "8acb788b847c24f28525660c4d7758620a7210875711f79e7f663cc152726811" dependencies = [ "bitflags 2.6.0", "errno", @@ -1168,18 +1173,18 @@ checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" [[package]] name = "serde" -version = "1.0.204" +version = "1.0.210" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc76f558e0cbb2a839d37354c575f1dc3fdc6546b5be373ba43d95f231bf7c12" +checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.204" +version = "1.0.210" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222" +checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" dependencies = [ "proc-macro2", "quote", @@ -1188,20 +1193,21 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.120" +version = "1.0.128" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e0d21c9a8cae1235ad58a00c11cb40d4b1e5c784f1ef2c537876ed6ffd8b7c5" +checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8" dependencies = [ "itoa", + "memchr", "ryu", "serde", ] [[package]] name = "serde_spanned" -version = "0.6.6" +version = "0.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79e674e01f999af37c49f70a6ede167a8a60b2503e56c5599532a65baa5969a0" +checksum = "eb5b1b31579f3811bf615c144393417496f152e12ac8b7663bf664f4a815306d" dependencies = [ "serde", ] @@ -1269,9 +1275,9 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "syn" -version = "2.0.71" +version = "2.0.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b146dcf730474b4bcd16c311627b31ede9ab149045db4d6088b3becaea046462" +checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed" dependencies = [ "proc-macro2", "quote", @@ -1290,26 +1296,25 @@ dependencies = [ "fnv", "once_cell", "onig", - "plist", "regex-syntax", "serde", "serde_derive", "serde_json", "thiserror", "walkdir", - "yaml-rust", ] [[package]] name = "tempfile" -version = "3.10.1" +version = "3.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" +checksum = "04cbcdd0c794ebb0d4cf35e88edd2f7d2c4c3e9a5a6dab322839b321c6a87a64" dependencies = [ "cfg-if", "fastrand", + "once_cell", "rustix", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -1341,55 +1346,24 @@ checksum = "23d434d3f8967a09480fb04132ebe0a3e088c173e6d0ee7897abbdf4eab0f8b9" [[package]] name = "thiserror" -version = "1.0.62" +version = "1.0.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2675633b1499176c2dff06b0856a27976a8f9d436737b4cf4f312d4d91d8bbb" +checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.62" +version = "1.0.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d20468752b09f49e909e55a5d338caa8bedf615594e9d80bc4c565d30faf798c" +checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" dependencies = [ "proc-macro2", "quote", "syn", ] -[[package]] -name = "time" -version = "0.3.36" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" -dependencies = [ - "deranged", - "itoa", - "num-conv", - "powerfmt", - "serde", - "time-core", - "time-macros", -] - -[[package]] -name = "time-core" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" - -[[package]] -name = "time-macros" -version = "0.2.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf" -dependencies = [ - "num-conv", - "time-core", -] - [[package]] name = "tinyvec" version = "1.8.0" @@ -1416,9 +1390,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.14" +version = "0.8.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f49eb2ab21d2f26bd6db7bf383edc527a7ebaee412d17af4d40fdccd442f335" +checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e" dependencies = [ "serde", "serde_spanned", @@ -1428,18 +1402,18 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.6.6" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4badfd56924ae69bcc9039335b2e017639ce3f9b001c393c1b2d1ef846ce2cbf" +checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" dependencies = [ "serde", ] [[package]] name = "toml_edit" -version = "0.22.15" +version = "0.22.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d59a3a72298453f564e2b111fa896f8d07fabb36f51f06d7e875fc5e0b5a3ef1" +checksum = "3b072cee73c449a636ffd6f32bd8de3a9f7119139aff882f44943ce2986dc5cf" dependencies = [ "indexmap", "serde", @@ -1483,24 +1457,24 @@ checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" [[package]] name = "unicode-ident" -version = "1.0.12" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" [[package]] name = "unicode-normalization" -version = "0.1.23" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" +checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956" dependencies = [ "tinyvec", ] [[package]] name = "unicode-width" -version = "0.1.13" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d" +checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" [[package]] name = "url" @@ -1527,9 +1501,9 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "version_check" -version = "0.9.4" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] name = "walkdir" @@ -1549,19 +1523,20 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.92" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" +checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5" dependencies = [ "cfg-if", + "once_cell", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.92" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" +checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b" dependencies = [ "bumpalo", "log", @@ -1574,9 +1549,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.92" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" +checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -1584,9 +1559,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.92" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" +checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836" dependencies = [ "proc-macro2", "quote", @@ -1597,9 +1572,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.92" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" +checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484" [[package]] name = "winapi" @@ -1619,11 +1594,11 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b" +checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -1659,6 +1634,15 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", +] + [[package]] name = "windows-targets" version = "0.48.5" @@ -1782,18 +1766,30 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winnow" -version = "0.6.13" +version = "0.6.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59b5e5f6c299a3c7890b876a2a587f3115162487e704907d9b6cd29473052ba1" +checksum = "68a9bda4691f099d435ad181000724da8e5899daa10713c2d432552b9ccd3a6f" dependencies = [ "memchr", ] [[package]] -name = "yaml-rust" -version = "0.4.5" +name = "zerocopy" +version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" dependencies = [ - "linked-hash-map", + "byteorder", + "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", ] From fa64fb1de6048d7c15d0ccb805b99b11e29c1c3f Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 26 Sep 2024 13:18:46 -0400 Subject: [PATCH 296/683] Partially update `library/Cargo.lock` Run `cargo update` in library but exclude updates to `cc` and to `compiler_builtins`. Exclusions were done because `cc` seems to have some issues updating [1], and `compiler_builtins` needs to be updated on its own. [1]: https://github.com/rust-lang/rust/pull/130720 --- library/Cargo.lock | 64 +++++++++++++++++++++++----------------------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/library/Cargo.lock b/library/Cargo.lock index 2343b2baf83..e0cedb14820 100644 --- a/library/Cargo.lock +++ b/library/Cargo.lock @@ -110,9 +110,9 @@ dependencies = [ [[package]] name = "gimli" -version = "0.28.1" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" +checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" dependencies = [ "compiler_builtins", "rustc-std-workspace-alloc", @@ -121,9 +121,9 @@ dependencies = [ [[package]] name = "gimli" -version = "0.29.0" +version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" +checksum = "e2e1d97fbe9722ba9bbd0c97051c2956e726562b61f86a25a4360398a40edfc9" dependencies = [ "compiler_builtins", "rustc-std-workspace-alloc", @@ -155,9 +155,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.158" +version = "0.2.159" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" +checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5" dependencies = [ "rustc-std-workspace-core", ] @@ -186,9 +186,9 @@ dependencies = [ [[package]] name = "object" -version = "0.36.2" +version = "0.36.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f203fa8daa7bb185f760ae12bd8e097f63d17041dcdcaf675ac54cdf863170e" +checksum = "084f1a5821ac4c651660a94a7153d27ac9d8a53736203f58b31945ded098070a" dependencies = [ "compiler_builtins", "memchr", @@ -375,9 +375,9 @@ dependencies = [ [[package]] name = "unicode-width" -version = "0.1.13" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d" +checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" dependencies = [ "compiler_builtins", "rustc-std-workspace-core", @@ -397,12 +397,12 @@ dependencies = [ [[package]] name = "unwinding" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37a19a21a537f635c16c7576f22d0f2f7d63353c1337ad4ce0d8001c7952a25b" +checksum = "dc55842d0db6329a669d55a623c674b02d677b16bfb2d24857d4089d41eba882" dependencies = [ "compiler_builtins", - "gimli 0.28.1", + "gimli 0.30.0", "rustc-std-workspace-core", ] @@ -423,7 +423,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.5", + "windows-targets 0.52.6", ] [[package]] @@ -432,9 +432,9 @@ version = "0.0.0" [[package]] name = "windows-targets" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ "windows_aarch64_gnullvm", "windows_aarch64_msvc", @@ -448,48 +448,48 @@ dependencies = [ [[package]] name = "windows_aarch64_gnullvm" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_msvc" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_i686_gnu" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" [[package]] name = "windows_i686_gnullvm" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_msvc" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_x86_64_gnu" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_msvc" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" From e29ff8c058d3bca10ae810de924417e96ed51b04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Thu, 26 Sep 2024 13:25:52 +0200 Subject: [PATCH 297/683] Pass correct HirId to late_bound_vars in diagnostic code --- .../src/fn_ctxt/suggestions.rs | 3 ++- tests/crashes/125655.rs | 8 ------ .../binder/closure-return-type-mismatch.rs | 15 +++++++++++ .../closure-return-type-mismatch.stderr | 25 +++++++++++++++++++ .../closures/closure-return-type-mismatch.rs | 4 +++ .../closure-return-type-mismatch.stderr | 10 +++++++- 6 files changed, 55 insertions(+), 10 deletions(-) delete mode 100644 tests/crashes/125655.rs create mode 100644 tests/ui/closures/binder/closure-return-type-mismatch.rs create mode 100644 tests/ui/closures/binder/closure-return-type-mismatch.stderr diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index 5f89f7dedc2..487cc7e55cd 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -882,7 +882,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let ty = self.lowerer().lower_ty(hir_ty); debug!(?ty, "return type (lowered)"); debug!(?expected, "expected type"); - let bound_vars = self.tcx.late_bound_vars(hir_ty.hir_id.owner.into()); + let bound_vars = + self.tcx.late_bound_vars(self.tcx.local_def_id_to_hir_id(fn_id)); let ty = Binder::bind_with_vars(ty, bound_vars); let ty = self.normalize(hir_ty.span, ty); let ty = self.tcx.instantiate_bound_regions_with_erased(ty); diff --git a/tests/crashes/125655.rs b/tests/crashes/125655.rs deleted file mode 100644 index fbf92ca22be..00000000000 --- a/tests/crashes/125655.rs +++ /dev/null @@ -1,8 +0,0 @@ -//@ known-bug: rust-lang/rust#125655 - -fn main() { - static foo: dyn Fn() -> u32 = || -> u32 { - ... - 0 - }; -} diff --git a/tests/ui/closures/binder/closure-return-type-mismatch.rs b/tests/ui/closures/binder/closure-return-type-mismatch.rs new file mode 100644 index 00000000000..398a4c43ee2 --- /dev/null +++ b/tests/ui/closures/binder/closure-return-type-mismatch.rs @@ -0,0 +1,15 @@ +// We used to bind the closure return type `&'a ()` with the late-bound vars of +// the owner (here `main` & `env` resp.) instead of the ones of the enclosing +// function-like / closure inside diagnostic code which was incorrect. + +#![feature(closure_lifetime_binder)] + +// issue: rust-lang/rust#130391 +fn main() { + let _ = for<'a> |x: &'a u8| -> &'a () { x }; //~ ERROR mismatched types +} + +// issue: rust-lang/rust#130663 +fn env<'r>() { + let _ = for<'a> |x: &'a u8| -> &'a () { x }; //~ ERROR mismatched types +} diff --git a/tests/ui/closures/binder/closure-return-type-mismatch.stderr b/tests/ui/closures/binder/closure-return-type-mismatch.stderr new file mode 100644 index 00000000000..67045654f99 --- /dev/null +++ b/tests/ui/closures/binder/closure-return-type-mismatch.stderr @@ -0,0 +1,25 @@ +error[E0308]: mismatched types + --> $DIR/closure-return-type-mismatch.rs:9:45 + | +LL | let _ = for<'a> |x: &'a u8| -> &'a () { x }; + | ------ ^ expected `&()`, found `&u8` + | | + | expected `&'a ()` because of return type + | + = note: expected reference `&'a ()` + found reference `&'a u8` + +error[E0308]: mismatched types + --> $DIR/closure-return-type-mismatch.rs:14:45 + | +LL | let _ = for<'a> |x: &'a u8| -> &'a () { x }; + | ------ ^ expected `&()`, found `&u8` + | | + | expected `&'a ()` because of return type + | + = note: expected reference `&'a ()` + found reference `&'a u8` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/closures/closure-return-type-mismatch.rs b/tests/ui/closures/closure-return-type-mismatch.rs index 1631bb303e5..e5cda1659de 100644 --- a/tests/ui/closures/closure-return-type-mismatch.rs +++ b/tests/ui/closures/closure-return-type-mismatch.rs @@ -15,3 +15,7 @@ fn main() { b }; } + +// issue: rust-lang/rust#130858 rust-lang/rust#125655 +static FOO: fn() -> bool = || -> bool { 1 }; +//~^ ERROR mismatched types diff --git a/tests/ui/closures/closure-return-type-mismatch.stderr b/tests/ui/closures/closure-return-type-mismatch.stderr index 3a2f098d1ef..052bbbb5ed5 100644 --- a/tests/ui/closures/closure-return-type-mismatch.stderr +++ b/tests/ui/closures/closure-return-type-mismatch.stderr @@ -1,3 +1,11 @@ +error[E0308]: mismatched types + --> $DIR/closure-return-type-mismatch.rs:20:41 + | +LL | static FOO: fn() -> bool = || -> bool { 1 }; + | ---- ^ expected `bool`, found integer + | | + | expected `bool` because of return type + error[E0308]: mismatched types --> $DIR/closure-return-type-mismatch.rs:7:9 | @@ -19,6 +27,6 @@ LL | if false { LL | return "hello" | ^^^^^^^ expected `bool`, found `&str` -error: aborting due to 2 previous errors +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0308`. From 4a515bdf7b2d4ca38f848b181977d04d460fabc4 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 26 Aug 2024 16:02:54 -0400 Subject: [PATCH 298/683] Run `cargo update` in the project root --- Cargo.lock | 462 +++++++++++++++++++++++++++++------------------------ 1 file changed, 251 insertions(+), 211 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5e9808c8068..0d2ae4ee15f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,6 +17,12 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +[[package]] +name = "adler2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" + [[package]] name = "aes" version = "0.8.4" @@ -177,9 +183,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.86" +version = "1.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" +checksum = "86fdf8605db99b54d3cd748a44c6d04df638eb5dafb219b135d0149bd0db01f6" dependencies = [ "backtrace", ] @@ -215,7 +221,7 @@ dependencies = [ "cc", "cfg-if", "libc", - "miniz_oxide", + "miniz_oxide 0.7.4", "object 0.32.2", "rustc-demangle", ] @@ -267,12 +273,12 @@ dependencies = [ [[package]] name = "bstr" -version = "1.6.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6798148dccfbff0fae41c7574d2fa8f1ef3492fba0face179de5d8d447d67b05" +checksum = "40723b8fb387abc38f4f4a37c09073622e41dd12327033091ef8950659e6dc0c" dependencies = [ "memchr", - "regex-automata 0.3.9", + "regex-automata 0.4.7", "serde", ] @@ -332,9 +338,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.7.1" +version = "1.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50" +checksum = "428d9aa8fbc0670b7b8d6030a7fadd0f86151cae55e4dbbece15f3780a3dfaf3" [[package]] name = "camino" @@ -464,9 +470,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.16" +version = "4.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed6719fffa43d0d87e5fd8caeab59be1554fb028cd30edc88fc4369b17971019" +checksum = "b0956a43b323ac1afaffc053ed5c4b7c1f1800bacd1683c353aabbb752515dd3" dependencies = [ "clap_builder", "clap_derive", @@ -484,9 +490,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.15" +version = "4.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "216aec2b177652e3846684cbfe25c9964d18ec45234f0f5da5157b207ed1aab6" +checksum = "4d72166dd41634086d5803a47eb71ae740e61d84709c36f3c34110173db3961b" dependencies = [ "anstream", "anstyle", @@ -497,23 +503,23 @@ dependencies = [ [[package]] name = "clap_complete" -version = "4.5.18" +version = "4.5.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ee158892bd7ce77aa15c208abbdb73e155d191c287a659b57abd5adb92feb03" +checksum = "8937760c3f4c60871870b8c3ee5f9b30771f792a7045c48bcbba999d7d6b3b8e" dependencies = [ "clap", ] [[package]] name = "clap_derive" -version = "4.5.13" +version = "4.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "501d359d5f3dcaf6ecdeee48833ae73ec6e42723a1e52419c79abf9507eec0a0" +checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab" dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.77", ] [[package]] @@ -542,7 +548,7 @@ dependencies = [ "rustc_tools_util", "serde", "serde_json", - "syn 2.0.75", + "syn 2.0.77", "tempfile", "termize", "tokio", @@ -651,7 +657,7 @@ dependencies = [ "nom", "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.77", ] [[package]] @@ -741,16 +747,16 @@ dependencies = [ "anyhow", "leb128", "md-5", - "miniz_oxide", + "miniz_oxide 0.7.4", "regex", "rustc-demangle", ] [[package]] name = "cpufeatures" -version = "0.2.13" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51e852e6dc9a5bed1fae92dd2375037bf2b768725bf3be87811edee3249d09ad" +checksum = "608697df725056feaccfa42cffdaeeec3fccc4ffc38358ecd19b243e716a78e0" dependencies = [ "libc", ] @@ -835,9 +841,9 @@ dependencies = [ [[package]] name = "curl-sys" -version = "0.4.74+curl-8.9.0" +version = "0.4.76+curl-8.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8af10b986114528fcdc4b63b6f5f021b7057618411046a4de2ba0f0149a097bf" +checksum = "00462dbe9cbb9344e1b2be34d9094d74e3b8aac59a883495b335eafd02e25120" dependencies = [ "cc", "libc", @@ -869,7 +875,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.75", + "syn 2.0.77", ] [[package]] @@ -880,7 +886,7 @@ checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" dependencies = [ "darling_core", "quote", - "syn 2.0.75", + "syn 2.0.77", ] [[package]] @@ -906,7 +912,7 @@ version = "0.1.83" dependencies = [ "itertools", "quote", - "syn 2.0.75", + "syn 2.0.77", ] [[package]] @@ -926,38 +932,38 @@ checksum = "62d671cc41a825ebabc75757b62d3d168c577f9149b2d49ece1dad1f72119d25" dependencies = [ "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.77", ] [[package]] name = "derive_builder" -version = "0.20.0" +version = "0.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0350b5cb0331628a5916d6c5c0b72e97393b8b6b03b47a9284f4e7f5a405ffd7" +checksum = "cd33f37ee6a119146a1781d3356a7c26028f83d779b2e04ecd45fdc75c76877b" dependencies = [ "derive_builder_macro", ] [[package]] name = "derive_builder_core" -version = "0.20.0" +version = "0.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d48cda787f839151732d396ac69e3473923d54312c070ee21e9effcaa8ca0b1d" +checksum = "7431fa049613920234f22c47fdc33e6cf3ee83067091ea4277a3f8c4587aae38" dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.77", ] [[package]] name = "derive_builder_macro" -version = "0.20.0" +version = "0.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "206868b8242f27cecce124c19fd88157fbd0dd334df2587f36417bafbc85097b" +checksum = "4abae7035bf79b9877b779505d8cf3749285b80c43941eda66604841889451dc" dependencies = [ "derive_builder_core", - "syn 2.0.75", + "syn 2.0.77", ] [[package]] @@ -968,7 +974,7 @@ checksum = "5f33878137e4dafd7fa914ad4e259e18a4e8e532b9617a2d0150262bf53abfce" dependencies = [ "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.77", ] [[package]] @@ -980,7 +986,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.77", ] [[package]] @@ -1058,7 +1064,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.77", ] [[package]] @@ -1183,9 +1189,9 @@ checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649" [[package]] name = "fastrand" -version = "2.1.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" +checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6" [[package]] name = "field-offset" @@ -1199,9 +1205,9 @@ dependencies = [ [[package]] name = "filetime" -version = "0.2.24" +version = "0.2.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf401df4a4e3872c4fe8151134cf483738e74b67fc934d6532c882b3d24a4550" +checksum = "35c0522e981e68cbfa8c3f978441a5f34b30b96e146b33cd3359176b50fe8586" dependencies = [ "cfg-if", "libc", @@ -1211,12 +1217,12 @@ dependencies = [ [[package]] name = "flate2" -version = "1.0.31" +version = "1.0.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f211bbe8e69bbd0cfdea405084f128ae8b4aaa6b0b522fc8f2b009084797920" +checksum = "324a1be68054ef05ad64b861cc9eaf1d623d2d8cb25b4bf2cb9cdd902b4bf253" dependencies = [ "crc32fast", - "miniz_oxide", + "miniz_oxide 0.8.0", ] [[package]] @@ -1229,7 +1235,7 @@ dependencies = [ "fluent-syntax", "intl-memoizer", "intl_pluralrules", - "rustc-hash", + "rustc-hash 1.1.0", "self_cell 0.10.3", "smallvec", "unic-langid", @@ -1349,7 +1355,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.77", ] [[package]] @@ -1461,15 +1467,15 @@ checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" [[package]] name = "globset" -version = "0.4.13" +version = "0.4.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "759c97c1e17c55525b57192c06a267cda0ac5210b222d6b82189a2338fa1c13d" +checksum = "15f1ce686646e7f1e19bf7d5533fe443a45dbfb990e00629110797578b42fb19" dependencies = [ "aho-corasick", "bstr", - "fnv", "log", - "regex", + "regex-automata 0.4.7", + "regex-syntax 0.8.4", ] [[package]] @@ -1567,7 +1573,7 @@ dependencies = [ "markup5ever", "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.77", ] [[package]] @@ -1587,9 +1593,9 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "iana-time-zone" -version = "0.1.60" +version = "0.1.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" +checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" dependencies = [ "android_system_properties", "core-foundation-sys", @@ -1699,7 +1705,7 @@ checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.77", ] [[package]] @@ -1732,17 +1738,16 @@ checksum = "cb56e1aa765b4b4f3aadfab769793b7087bb03a4ea4920644a6d238e2df5b9ed" [[package]] name = "ignore" -version = "0.4.20" +version = "0.4.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbe7873dab538a9a44ad79ede1faf5f30d49f9a5c883ddbab48bce81b64b7492" +checksum = "6d89fd380afde86567dfba715db065673989d6253f42b88179abd3eae47bda4b" dependencies = [ + "crossbeam-deque", "globset", - "lazy_static", "log", "memchr", - "regex", + "regex-automata 0.4.7", "same-file", - "thread_local", "walkdir", "winapi-util", ] @@ -1755,9 +1760,9 @@ checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683" [[package]] name = "indexmap" -version = "2.4.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93ead53efc7ea8ed3cfb0c79fc8023fbb782a5432b52830b6518941cebe6505c" +checksum = "68b900aa2f7301e21c36462b170ee99994de34dff39a4a6a528e80e7376d07e5" dependencies = [ "equivalent", "hashbrown", @@ -1902,7 +1907,7 @@ dependencies = [ "anyhow", "clap", "fs-err", - "rustc-hash", + "rustc-hash 1.1.0", "rustdoc-json-types", "serde", "serde_json", @@ -1945,9 +1950,9 @@ checksum = "baff4b617f7df3d896f97fe922b64817f6cd9a756bb81d40f8883f2f66dcb401" [[package]] name = "libc" -version = "0.2.157" +version = "0.2.159" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "374af5f94e54fa97cf75e945cce8a6b201e88a1a07e688b47dfd2a59c66dbd86" +checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5" [[package]] name = "libdbus-sys" @@ -2007,9 +2012,9 @@ dependencies = [ [[package]] name = "libz-sys" -version = "1.1.19" +version = "1.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdc53a7799a7496ebc9fd29f31f7df80e83c9bda5299768af5f9e59eeea74647" +checksum = "d2d16453e800a8cf6dd2fc3eb4bc99b786a9b90c663b8559a5b1a041bf89e472" dependencies = [ "cc", "libc", @@ -2171,7 +2176,7 @@ dependencies = [ "memmap2", "parking_lot", "perf-event-open-sys", - "rustc-hash", + "rustc-hash 1.1.0", "smallvec", ] @@ -2239,6 +2244,15 @@ dependencies = [ "adler", ] +[[package]] +name = "miniz_oxide" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" +dependencies = [ + "adler2", +] + [[package]] name = "miow" version = "0.6.0" @@ -2453,8 +2467,8 @@ dependencies = [ "hashbrown", "indexmap", "memchr", - "ruzstd 0.7.0", - "wasmparser", + "ruzstd 0.7.2", + "wasmparser 0.216.0", ] [[package]] @@ -2474,9 +2488,9 @@ checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "once_map" -version = "0.4.18" +version = "0.4.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa7085055bbe9c8edbd982048dbcf8181794d4a81cb04a11931673e63cc18dc6" +checksum = "30c7f82d6d446dd295845094f3a76bcdc5e6183b66667334e169f019cd05e5a0" dependencies = [ "ahash", "hashbrown", @@ -2642,9 +2656,9 @@ dependencies = [ [[package]] name = "pest" -version = "2.7.11" +version = "2.7.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd53dff83f26735fdc1ca837098ccf133605d794cdae66acfc2bfac3ec809d95" +checksum = "fdbef9d1d47087a895abd220ed25eb4ad973a5e26f6a4367b038c25e28dfc2d9" dependencies = [ "memchr", "thiserror", @@ -2653,9 +2667,9 @@ dependencies = [ [[package]] name = "pest_derive" -version = "2.7.11" +version = "2.7.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a548d2beca6773b1c244554d36fcf8548a8a58e74156968211567250e48e49a" +checksum = "4d3a6e3394ec80feb3b6393c725571754c6188490265c61aaf260810d6b95aa0" dependencies = [ "pest", "pest_generator", @@ -2663,22 +2677,22 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.7.11" +version = "2.7.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c93a82e8d145725dcbaf44e5ea887c8a869efdcc28706df2d08c69e17077183" +checksum = "94429506bde1ca69d1b5601962c73f4172ab4726571a59ea95931218cb0e930e" dependencies = [ "pest", "pest_meta", "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.77", ] [[package]] name = "pest_meta" -version = "2.7.11" +version = "2.7.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a941429fea7e08bedec25e4f6785b6ffaacc6b755da98df5ef3e7dcf4a124c4f" +checksum = "ac8a071862e93690b6e34e9a5fb8e33ff3734473ac0245b27232222c4906a33f" dependencies = [ "once_cell", "pest", @@ -2756,9 +2770,9 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "pkg-config" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" +checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" [[package]] name = "polonius-engine" @@ -2768,14 +2782,14 @@ checksum = "c4e8e505342045d397d0b6674dcb82d6faf5cf40484d30eeb88fc82ef14e903f" dependencies = [ "datafrog", "log", - "rustc-hash", + "rustc-hash 1.1.0", ] [[package]] name = "portable-atomic" -version = "1.7.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da544ee218f0d287a911e9c99a39a8c9bc8fcad3cb8db5959940044ecfc67265" +checksum = "d30538d42559de6b034bc76fd6dd4c38961b1ee5c6c56e3808c50128fdbc22ce" [[package]] name = "powerfmt" @@ -2825,9 +2839,9 @@ dependencies = [ [[package]] name = "psm" -version = "0.1.21" +version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5787f7cda34e3033a72192c018bc5883100330f362ef279a8cbccfce8bb4e874" +checksum = "aa37f80ca58604976033fae9515a8a2989fc13797d953f7c04fb8fa36a11f205" dependencies = [ "cc", ] @@ -2857,9 +2871,9 @@ dependencies = [ [[package]] name = "pulldown-cmark" -version = "0.11.2" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb4e75767fbc9d92b90e4d0c011f61358cde9513b31ef07ea3631b15ffc3b4fd" +checksum = "679341d22c78c6c649893cbd6c3278dcbe9fc4faa62fea3a9296ae2b50c14625" dependencies = [ "bitflags 2.6.0", "memchr", @@ -2893,9 +2907,9 @@ checksum = "07589615d719a60c8dd8a4622e7946465dfef20d1a428f969e3443e7386d5f45" [[package]] name = "quote" -version = "1.0.36" +version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" dependencies = [ "proc-macro2", ] @@ -2961,18 +2975,18 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.3" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4" +checksum = "355ae415ccd3a04315d3f8246e86d67689ea74d88d915576e1589a351062a13b" dependencies = [ "bitflags 2.6.0", ] [[package]] name = "redox_users" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd283d9651eeda4b2a83a43c1c91b266c40fd76ecd39a50a8c630ae69dc72891" +checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" dependencies = [ "getrandom", "libredox", @@ -2981,13 +2995,14 @@ dependencies = [ [[package]] name = "regex" -version = "1.8.4" +version = "1.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0ab3ca65655bb1e41f2a8c8cd662eb4fb035e67c3f78da1d61dffe89d07300f" +checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.7.5", + "regex-automata 0.4.7", + "regex-syntax 0.8.4", ] [[package]] @@ -3010,9 +3025,14 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.3.9" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59b23e92ee4318893fa3fe3e6fb365258efbfe6ac6ab30f090cdcbb7aa37efa9" +checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax 0.8.4", +] [[package]] name = "regex-lite" @@ -3026,12 +3046,6 @@ version = "0.6.29" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" -[[package]] -name = "regex-syntax" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da" - [[package]] name = "regex-syntax" version = "0.8.4" @@ -3056,9 +3070,9 @@ dependencies = [ [[package]] name = "rinja" -version = "0.3.0" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d3762e3740cdbf2fd2be465cc2c26d643ad17353cc2e0223d211c1b096118bd" +checksum = "f28580fecce391f3c0e65a692e5f2b5db258ba2346ee04f355ae56473ab973dc" dependencies = [ "humansize", "itoa", @@ -3069,9 +3083,9 @@ dependencies = [ [[package]] name = "rinja_derive" -version = "0.3.0" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd01fd8e15e7d19c8b8052c1d428325131e02ff1633cdcf695190c2e56ab682c" +checksum = "1f1ae91455a4c82892d9513fcfa1ac8faff6c523602d0041536341882714aede" dependencies = [ "basic-toml", "memchr", @@ -3081,18 +3095,20 @@ dependencies = [ "proc-macro2", "quote", "rinja_parser", + "rustc-hash 2.0.0", "serde", - "syn 2.0.75", + "syn 2.0.77", ] [[package]] name = "rinja_parser" -version = "0.3.0" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2f6bf7cef118c6de21206edf0b3f19f5ede60006be674a58ca21b6e003a1b57" +checksum = "06ea17639e1f35032e1c67539856e498c04cd65fe2a45f55ec437ec55e4be941" dependencies = [ "memchr", "nom", + "serde", ] [[package]] @@ -3114,14 +3130,14 @@ dependencies = [ "regex", "serde_json", "similar", - "wasmparser", + "wasmparser 0.216.0", ] [[package]] name = "rustc-build-sysroot" -version = "0.5.3" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2471f8f296262437d7e848e527b4210b44a96e53a3b4435b890227ce3e6da106" +checksum = "d6d984a9db43148467059309bd1e5ad577085162f695d9fe2cf3543aeb25cd38" dependencies = [ "anyhow", "rustc_version", @@ -3141,6 +3157,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" +[[package]] +name = "rustc-hash" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "583034fd73374156e66797ed8e5b0d5690409c9226b22d87cb7f19821c05d152" + [[package]] name = "rustc-main" version = "0.0.0" @@ -3458,7 +3480,7 @@ dependencies = [ "thin-vec", "thorin-dwp", "tracing", - "wasm-encoder", + "wasm-encoder 0.216.0", "windows 0.52.0", ] @@ -3503,7 +3525,7 @@ dependencies = [ "memmap2", "parking_lot", "portable-atomic", - "rustc-hash", + "rustc-hash 1.1.0", "rustc-rayon", "rustc-stable-hash", "rustc_arena", @@ -3673,7 +3695,7 @@ dependencies = [ "fluent-syntax", "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.77", "unic-langid", ] @@ -3807,7 +3829,7 @@ version = "0.0.0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.77", ] [[package]] @@ -3956,7 +3978,7 @@ version = "0.0.0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.77", "synstructure", ] @@ -4197,7 +4219,7 @@ dependencies = [ name = "rustc_pattern_analysis" version = "0.0.0" dependencies = [ - "rustc-hash", + "rustc-hash 1.1.0", "rustc_apfloat", "rustc_arena", "rustc_data_structures", @@ -4281,7 +4303,7 @@ name = "rustc_resolve" version = "0.0.0" dependencies = [ "bitflags 2.6.0", - "pulldown-cmark 0.11.2", + "pulldown-cmark 0.11.3", "rustc_arena", "rustc_ast", "rustc_ast_pretty", @@ -4519,7 +4541,7 @@ dependencies = [ "bitflags 2.6.0", "derive-where", "indexmap", - "rustc-hash", + "rustc-hash 1.1.0", "rustc_ast_ir", "rustc_data_structures", "rustc_index", @@ -4537,15 +4559,15 @@ version = "0.0.0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.77", "synstructure", ] [[package]] name = "rustc_version" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" dependencies = [ "semver", ] @@ -4590,7 +4612,7 @@ name = "rustdoc-json-types" version = "0.1.0" dependencies = [ "bincode", - "rustc-hash", + "rustc-hash 1.1.0", "serde", "serde_json", ] @@ -4625,7 +4647,7 @@ dependencies = [ "proc-macro2", "quote", "serde", - "syn 2.0.75", + "syn 2.0.77", ] [[package]] @@ -4659,9 +4681,9 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.34" +version = "0.38.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" +checksum = "8acb788b847c24f28525660c4d7758620a7210875711f79e7f663cc152726811" dependencies = [ "bitflags 2.6.0", "errno", @@ -4689,11 +4711,10 @@ dependencies = [ [[package]] name = "ruzstd" -version = "0.7.0" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5022b253619b1ba797f243056276bed8ed1a73b0f5a7ce7225d524067644bf8f" +checksum = "99c3938e133aac070997ddc684d4b393777d293ba170f2988c8fd5ea2ad4ce21" dependencies = [ - "byteorder", "twox-hash", ] @@ -4714,11 +4735,11 @@ dependencies = [ [[package]] name = "schannel" -version = "0.1.23" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534" +checksum = "e9aaafd5a2b6e3d657ff009d82fbd630b6bd54dd4eb06f21693925cdf80f9b8b" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -4759,29 +4780,29 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.208" +version = "1.0.210" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cff085d2cb684faa248efb494c39b68e522822ac0de72ccf08109abde717cfb2" +checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.208" +version = "1.0.210" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24008e81ff7613ed8e5ba0cfaf24e2c2f1e5b8a0495711e44fcd4882fca62bcf" +checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.77", ] [[package]] name = "serde_json" -version = "1.0.125" +version = "1.0.128" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83c8e735a073ccf5be70aa8066aa984eaf2fa000db6c8d0100ae605b366d31ed" +checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8" dependencies = [ "indexmap", "itoa", @@ -4792,9 +4813,9 @@ dependencies = [ [[package]] name = "serde_spanned" -version = "0.6.7" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb5b1b31579f3811bf615c144393417496f152e12ac8b7663bf664f4a815306d" +checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" dependencies = [ "serde", ] @@ -5038,9 +5059,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.75" +version = "2.0.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6af063034fc1935ede7be0122941bafa9bacb949334d090b77ca98b5817c7d9" +checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed" dependencies = [ "proc-macro2", "quote", @@ -5055,14 +5076,14 @@ checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" dependencies = [ "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.77", ] [[package]] name = "sysinfo" -version = "0.31.2" +version = "0.31.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4115055da5f572fff541dd0c4e61b0262977f453cc9fe04be83aba25a89bdab" +checksum = "355dbe4f8799b304b05e1b0f05fc59b2a18d36645cf169607da45bde2f69a1be" dependencies = [ "core-foundation-sys", "libc", @@ -5081,9 +5102,9 @@ dependencies = [ [[package]] name = "tar" -version = "0.4.41" +version = "0.4.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb797dad5fb5b76fcf519e702f4a589483b5ef06567f160c392832c1f5e44909" +checksum = "4ff6c40d3aedb5e06b57c6f669ad17ab063dd1e63d977c6a88e7f4dfa4f04020" dependencies = [ "filetime", "libc", @@ -5173,22 +5194,22 @@ checksum = "a38c90d48152c236a3ab59271da4f4ae63d678c5d7ad6b7714d7cb9760be5e4b" [[package]] name = "thiserror" -version = "1.0.63" +version = "1.0.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724" +checksum = "d50af8abc119fb8bb6dbabcfa89656f46f84aa0ac7688088608076ad2b459a84" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.63" +version = "1.0.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" +checksum = "08904e7672f5eb876eaaf87e0ce17857500934f4981c4a0ab2b4aa98baac7fc3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.77", ] [[package]] @@ -5232,7 +5253,7 @@ dependencies = [ "ignore", "miropt-test-tools", "regex", - "rustc-hash", + "rustc-hash 1.1.0", "semver", "similar", "termcolor", @@ -5301,9 +5322,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.39.3" +version = "1.40.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9babc99b9923bfa4804bd74722ff02c0381021eafa4db9949217e3be8e84fff5" +checksum = "e2b070231665d27ad9ec9b8df639893f46727666c6767db40317fbe920a5d998" dependencies = [ "backtrace", "bytes", @@ -5379,7 +5400,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.77", ] [[package]] @@ -5461,7 +5482,7 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "deb68604048ff8fa93347f02441e4487594adc20bb8a084f9e564d2b827a0a9f" dependencies = [ - "rustc-hash", + "rustc-hash 1.1.0", ] [[package]] @@ -5550,7 +5571,7 @@ checksum = "1ed7f4237ba393424195053097c1516bd4590dc82b84f2f97c5c69e12704555b" dependencies = [ "proc-macro-hack", "quote", - "syn 2.0.75", + "syn 2.0.77", "unic-langid-impl", ] @@ -5578,36 +5599,36 @@ checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" [[package]] name = "unicode-ident" -version = "1.0.12" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" [[package]] name = "unicode-normalization" -version = "0.1.23" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" +checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956" dependencies = [ "tinyvec", ] [[package]] name = "unicode-properties" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4259d9d4425d9f0661581b804cb85fe66a4c631cadd8f490d1c13a35d5d9291" +checksum = "52ea75f83c0137a9b98608359a5f1af8144876eb67bcb1ce837368e906a9f524" [[package]] name = "unicode-script" -version = "0.5.6" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad8d71f5726e5f285a935e9fe8edfd53f0491eb6e9a5774097fdabee7cd8c9cd" +checksum = "9fb421b350c9aff471779e262955939f565ec18b86c15364e6bdf0d662ca7c1f" [[package]] name = "unicode-security" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee9e13753df674873f3c4693b240ae5c03245ddc157dfccf7c26db9329af3a11" +checksum = "2e4ddba1535dd35ed8b61c52166b7155d7f4e4b8847cec6f48e71dc66d8b5e50" dependencies = [ "unicode-normalization", "unicode-script", @@ -5615,21 +5636,21 @@ dependencies = [ [[package]] name = "unicode-segmentation" -version = "1.11.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" +checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" [[package]] name = "unicode-width" -version = "0.1.13" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d" +checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" [[package]] name = "unicode-xid" -version = "0.2.4" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" [[package]] name = "unified-diff" @@ -5748,7 +5769,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.77", "wasm-bindgen-shared", ] @@ -5770,7 +5791,7 @@ checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836" dependencies = [ "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.77", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -5783,16 +5804,16 @@ checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484" [[package]] name = "wasm-component-ld" -version = "0.5.7" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13261270d3ac58ffae0219ae34f297a7e24f9ee3b13b29be579132c588a83519" +checksum = "cb17cdbc91766d4ea0bcd6026c36ba77a21b5c8199aeb1f0993461fe6a6bec2b" dependencies = [ "anyhow", "clap", "lexopt", "tempfile", "wasi-preview1-component-adapter-provider", - "wasmparser", + "wasmparser 0.217.0", "wat", "wit-component", "wit-parser", @@ -5812,14 +5833,23 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04c23aebea22c8a75833ae08ed31ccc020835b12a41999e58c31464271b94a88" dependencies = [ "leb128", - "wasmparser", +] + +[[package]] +name = "wasm-encoder" +version = "0.217.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b88b0814c9a2b323a9b46c687e726996c255ac8b64aa237dd11c81ed4854760" +dependencies = [ + "leb128", + "wasmparser 0.217.0", ] [[package]] name = "wasm-metadata" -version = "0.216.0" +version = "0.217.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47c8154d703a6b0e45acf6bd172fa002fc3c7058a9f7615e517220aeca27c638" +checksum = "65a146bf9a60e9264f0548a2599aa9656dba9a641eff9ab88299dc2a637e483c" dependencies = [ "anyhow", "indexmap", @@ -5827,8 +5857,8 @@ dependencies = [ "serde_derive", "serde_json", "spdx", - "wasm-encoder", - "wasmparser", + "wasm-encoder 0.217.0", + "wasmparser 0.217.0", ] [[package]] @@ -5836,6 +5866,16 @@ name = "wasmparser" version = "0.216.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bcdee6bea3619d311fb4b299721e89a986c3470f804b6d534340e412589028e3" +dependencies = [ + "bitflags 2.6.0", + "indexmap", +] + +[[package]] +name = "wasmparser" +version = "0.217.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca917a21307d3adf2b9857b94dd05ebf8496bdcff4437a9b9fb3899d3e6c74e7" dependencies = [ "ahash", "bitflags 2.6.0", @@ -5847,22 +5887,22 @@ dependencies = [ [[package]] name = "wast" -version = "216.0.0" +version = "217.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7eb1f2eecd913fdde0dc6c3439d0f24530a98ac6db6cb3d14d92a5328554a08" +checksum = "79004ecebded92d3c710d4841383368c7f04b63d0992ddd6b0c7d5029b7629b7" dependencies = [ "bumpalo", "leb128", "memchr", "unicode-width", - "wasm-encoder", + "wasm-encoder 0.217.0", ] [[package]] name = "wat" -version = "1.216.0" +version = "1.217.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac0409090fb5154f95fb5ba3235675fd9e579e731524d63b6a2f653e1280c82a" +checksum = "c126271c3d92ca0f7c63e4e462e40c69cca52fd4245fcda730d1cf558fb55088" dependencies = [ "wast", ] @@ -5928,7 +5968,7 @@ dependencies = [ "rayon", "serde", "serde_json", - "syn 2.0.75", + "syn 2.0.77", "windows-metadata", ] @@ -5961,7 +6001,7 @@ checksum = "9107ddc059d5b6fbfbffdfa7a7fe3e22a226def0b2608f72e9d552763d3e1ad7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.77", ] [[package]] @@ -5972,7 +6012,7 @@ checksum = "29bee4b38ea3cde66011baa44dba677c432a78593e202392d1e9070cf2a7fca7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.77", ] [[package]] @@ -6149,9 +6189,9 @@ dependencies = [ [[package]] name = "wit-component" -version = "0.216.0" +version = "0.217.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e2ca3ece38ea2447a9069b43074ba73d96dde1944cba276c54e41371745f9dc" +checksum = "d7117809905e49db716d81e794f79590c052bf2fdbbcda1731ca0fb28f6f3ddf" dependencies = [ "anyhow", "bitflags 2.6.0", @@ -6160,17 +6200,17 @@ dependencies = [ "serde", "serde_derive", "serde_json", - "wasm-encoder", + "wasm-encoder 0.217.0", "wasm-metadata", - "wasmparser", + "wasmparser 0.217.0", "wit-parser", ] [[package]] name = "wit-parser" -version = "0.216.0" +version = "0.217.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4d108165c1167a4ccc8a803dcf5c28e0a51d6739fd228cc7adce768632c764c" +checksum = "fb893dcd6d370cfdf19a0d9adfcd403efb8e544e1a0ea3a8b81a21fe392eaa78" dependencies = [ "anyhow", "id-arena", @@ -6181,7 +6221,7 @@ dependencies = [ "serde_derive", "serde_json", "unicode-xid", - "wasmparser", + "wasmparser 0.217.0", ] [[package]] @@ -6239,7 +6279,7 @@ checksum = "28cc31741b18cb6f1d5ff12f5b7523e3d6eb0852bbbad19d73905511d9849b95" dependencies = [ "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.77", "synstructure", ] @@ -6261,7 +6301,7 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.77", ] [[package]] @@ -6281,7 +6321,7 @@ checksum = "0ea7b4a3637ea8669cedf0f1fd5c286a17f3de97b8dd5a70a6c167a1730e63a5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.77", "synstructure", ] @@ -6304,5 +6344,5 @@ checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.77", ] From 1760d3914f04a187286f337d081a983615e67789 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 26 Aug 2024 16:19:28 -0400 Subject: [PATCH 299/683] Adjust allowed dependencies from the latest `cargo update` --- src/tools/tidy/src/deps.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index 28367f25267..b880f312715 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -242,7 +242,7 @@ const PERMITTED_DEPS_LOCATION: &str = concat!(file!(), ":", line!()); /// rustc. Please check with the compiler team before adding an entry. const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[ // tidy-alphabetical-start - "adler", + "adler2", "ahash", "aho-corasick", "allocator-api2", // FIXME: only appears in Cargo.lock due to https://github.com/rust-lang/cargo/issues/10801 From f21f4cd60e764f4e6a37cb9d7cc1b1445ad3044f Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Thu, 26 Sep 2024 11:33:12 -0700 Subject: [PATCH 300/683] library: Compute `RUST_EXCEPTION_CLASS` from native-endian bytes This makes it appear correctly in hexdumps on both LE and BE platforms. --- library/panic_unwind/src/gcc.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/panic_unwind/src/gcc.rs b/library/panic_unwind/src/gcc.rs index 89b44338d6b..925af6c0832 100644 --- a/library/panic_unwind/src/gcc.rs +++ b/library/panic_unwind/src/gcc.rs @@ -107,4 +107,4 @@ pub unsafe fn cleanup(ptr: *mut u8) -> Box { // Rust's exception class identifier. This is used by personality routines to // determine whether the exception was thrown by their own runtime. -const RUST_EXCEPTION_CLASS: uw::_Unwind_Exception_Class = u64::from_be_bytes(*b"MOZ\0RUST"); +const RUST_EXCEPTION_CLASS: uw::_Unwind_Exception_Class = u64::from_ne_bytes(*b"MOZ\0RUST"); From 6414d9f52dd8c9e31ce0c923a4327583b794bb43 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 26 Sep 2024 19:51:14 +0000 Subject: [PATCH 301/683] Couple of changes to make it easier to compile rustc for wasm This is a subset of the patches I have on my rust fork to compile rustc for wasm32-wasip1. --- compiler/rustc_fs_util/src/lib.rs | 6 +++++- src/bootstrap/src/utils/shared_helpers.rs | 2 ++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_fs_util/src/lib.rs b/compiler/rustc_fs_util/src/lib.rs index 80813af3864..4e9d21c900d 100644 --- a/compiler/rustc_fs_util/src/lib.rs +++ b/compiler/rustc_fs_util/src/lib.rs @@ -76,10 +76,14 @@ pub fn link_or_copy, Q: AsRef>(p: P, q: Q) -> io::Result
  • CString { use std::ffi::OsStr; + #[cfg(unix)] use std::os::unix::ffi::OsStrExt; + #[cfg(all(target_os = "wasi", target_env = "p1"))] + use std::os::wasi::ffi::OsStrExt; + let p: &OsStr = p.as_ref(); CString::new(p.as_bytes()).unwrap() } diff --git a/src/bootstrap/src/utils/shared_helpers.rs b/src/bootstrap/src/utils/shared_helpers.rs index 7150c84313c..6d3c276cc05 100644 --- a/src/bootstrap/src/utils/shared_helpers.rs +++ b/src/bootstrap/src/utils/shared_helpers.rs @@ -49,6 +49,8 @@ pub fn exe(name: &str, target: &str) -> String { format!("{name}.exe") } else if target.contains("uefi") { format!("{name}.efi") + } else if target.contains("wasm") { + format!("{name}.wasm") } else { name.to_string() } From 5b5848188d4b3e0652267d56d8e0ec8de34eaa89 Mon Sep 17 00:00:00 2001 From: zopsicle Date: Thu, 26 Sep 2024 23:59:13 +0200 Subject: [PATCH 302/683] rustdoc: consolidate prefers-reduced-motion-gated rulesets --- src/librustdoc/html/static/css/rustdoc.css | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index 61e32aa5d30..40391b1b4df 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -1689,12 +1689,6 @@ instead, we check that it's not a "finger" cursor. border-right: 3px solid var(--target-border-color); } -@media not (prefers-reduced-motion) { - :target { - animation: 0.65s cubic-bezier(0, 0, 0.1, 1.0) 0.1s targetfadein; - } -} - .code-header a.tooltip { color: inherit; margin-right: 15px; @@ -1718,6 +1712,10 @@ a.tooltip:hover::after { } @media not (prefers-reduced-motion) { + :target { + animation: 0.65s cubic-bezier(0, 0, 0.1, 1.0) 0.1s targetfadein; + } + /* This animation is layered onto the mistake-proofing delay for dismissing a hovered tooltip, to ensure it feels responsive even with the delay. */ From 69150396bf145ab19488263f2a111ef48338dced Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sun, 22 Sep 2024 17:06:00 +0200 Subject: [PATCH 303/683] Extend rustdoc template check to detect unneeded comments --- src/tools/tidy/src/rustdoc_templates.rs | 34 ++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/src/tools/tidy/src/rustdoc_templates.rs b/src/tools/tidy/src/rustdoc_templates.rs index 6c8530e6366..2173dbf7e74 100644 --- a/src/tools/tidy/src/rustdoc_templates.rs +++ b/src/tools/tidy/src/rustdoc_templates.rs @@ -20,7 +20,39 @@ pub fn check(librustdoc_path: &Path, bad: &mut bool) { while let Some((pos, line)) = lines.next() { let line = line.trim(); - if TAGS.iter().any(|(_, tag)| line.ends_with(tag)) { + if let Some(need_next_line_check) = TAGS.iter().find_map(|(tag, end_tag)| { + // We first check if the line ends with a jinja tag. + if !line.ends_with(end_tag) { + return None; + // Then we check if this a comment tag. + } else if *tag != "{#" { + return Some(false); + // And finally we check if the comment is empty (ie, only there to strip + // extra whitespace characters). + } else if let Some(start_pos) = line.rfind(tag) { + Some(line[start_pos + 2..].trim() == "#}") + } else { + Some(false) + } + }) { + // All good, the line is ending is a jinja tag. But maybe this tag is useless + // if the next line starts with a jinja tag as well! + // + // However, only (empty) comment jinja tags are concerned about it. + if need_next_line_check + && lines.peek().is_some_and(|(_, next_line)| { + let next_line = next_line.trim_start(); + TAGS.iter().any(|(tag, _)| next_line.starts_with(tag)) + }) + { + // It seems like ending this line with a jinja tag is not needed after all. + tidy_error!( + bad, + "`{}` at line {}: unneeded `{{# #}}` tag at the end of the line", + path.path().display(), + pos + 1, + ); + } continue; } let Some(next_line) = lines.peek().map(|(_, next_line)| next_line.trim()) else { From 575df06a8b48f567ed1c53edc61facfee6f42e9c Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sun, 22 Sep 2024 17:06:19 +0200 Subject: [PATCH 304/683] Remove unneeded jinja comments in templates --- src/librustdoc/html/templates/item_info.html | 2 +- src/librustdoc/html/templates/page.html | 62 +++++++++---------- src/librustdoc/html/templates/print_item.html | 2 +- .../html/templates/short_item_info.html | 10 +-- src/librustdoc/html/templates/sidebar.html | 2 +- src/librustdoc/html/templates/source.html | 2 +- .../html/templates/type_layout.html | 20 +++--- 7 files changed, 50 insertions(+), 50 deletions(-) diff --git a/src/librustdoc/html/templates/item_info.html b/src/librustdoc/html/templates/item_info.html index 9e65ae95e15..9fee268622e 100644 --- a/src/librustdoc/html/templates/item_info.html +++ b/src/librustdoc/html/templates/item_info.html @@ -1,7 +1,7 @@ {% if !items.is_empty() %} {% for item in items %} - {{item|safe}} {# #} + {{item|safe}} {% endfor %} {% endif %} diff --git a/src/librustdoc/html/templates/page.html b/src/librustdoc/html/templates/page.html index 65c4304e202..a05d6ca8313 100644 --- a/src/librustdoc/html/templates/page.html +++ b/src/librustdoc/html/templates/page.html @@ -12,13 +12,13 @@ {# #} {# #} + href="{{static_root_path|safe}}{{files.rustdoc_css}}"> {% if !layout.default_settings.is_empty() %} {# #} + > {% endif %} {# #} - {# #} + {% if page.css_class.contains("crate") %} - {# #} + {% else if page.css_class == "src" %} {# #} - {# #} + {% else if !page.css_class.contains("mod") %} - {# #} + {% else if !page.css_class.contains("sys") %} - {# #} + {% endif %} - {# #} + {% if layout.scrape_examples_extension %} - {# #} + {% endif %} {# #} + {% if layout.css_file_extension.is_some() %} {# #} + href="{{page.root_path|safe}}theme{{page.resource_suffix}}.css"> {% endif %} {% if !layout.favicon.is_empty() %} - {# #} + {% else %} {# #} {# #} + href="{{static_root_path|safe}}{{files.rust_favicon_svg}}"> {% endif %} {{ layout.external_html.in_header|safe }} {# #} @@ -69,60 +69,60 @@
    {# #} This old browser is unsupported and will most likely display funky things. {# #}
    {# #} - {# #} + {{ layout.external_html.before_content|safe }} {% if page.css_class != "src" %}
    {% endif %} -
  • {% if !display_krate_version_extra.is_empty() %} -
    {{+ display_krate_version_extra}}
    {# #} +
    {{+ display_krate_version_extra}}
    {% endif %} {% else %}
    {# #}

    Files

    {# #} -
    {# #} +
    {% endif %} {{ sidebar|safe }} {# #} {# #} -
    {# #} +
    {% if page.css_class != "src" %}
    {% endif %} {# defined in storage.js to avoid duplicating complex UI across every page #} {# and because the search form only works if JS is enabled anyway #} {# #} -
    {{ content|safe }}
    {# #} +
    {{ content|safe }}
    {% if page.css_class != "src" %}
    {% endif %} -
    {# #} +
    {{ layout.external_html.after_content|safe }} {# #} {# #} diff --git a/src/librustdoc/html/templates/print_item.html b/src/librustdoc/html/templates/print_item.html index 32ded1fbe42..f60720b67c6 100644 --- a/src/librustdoc/html/templates/print_item.html +++ b/src/librustdoc/html/templates/print_item.html @@ -1,4 +1,4 @@ -
    {# #} +
    {% if !path_components.is_empty() %} {% for (i, component) in path_components.iter().enumerate() %} diff --git a/src/librustdoc/html/templates/short_item_info.html b/src/librustdoc/html/templates/short_item_info.html index 75d155e91c2..e76b98541cf 100644 --- a/src/librustdoc/html/templates/short_item_info.html +++ b/src/librustdoc/html/templates/short_item_info.html @@ -3,21 +3,21 @@
    {# #} 👎 {# #} {{message|safe}} {# #} -
    {# #} +
    {% when Self::Unstable with { feature, tracking } %}
    {# #} 🔬 {# #} {# #} This is a nightly-only experimental API. ({# #} - {{feature}} {# #} + {{feature}} {% match tracking %} {% when Some with ((url, num)) %} -  #{{num}} {# #} +  #{{num}} {% when None %} {% endmatch %} ) {# #} {# #} -
    {# #} +
    {% when Self::Portability with { message } %} -
    {{message|safe}}
    {# #} +
    {{message|safe}}
    {% endmatch %} diff --git a/src/librustdoc/html/templates/sidebar.html b/src/librustdoc/html/templates/sidebar.html index fccf65cbefc..7f852b489fa 100644 --- a/src/librustdoc/html/templates/sidebar.html +++ b/src/librustdoc/html/templates/sidebar.html @@ -30,7 +30,7 @@ {% else %} {{link.name}} {% endmatch %} - {# #} + {% if !link.children.is_empty() %}
      {% for child in link.children %} diff --git a/src/librustdoc/html/templates/source.html b/src/librustdoc/html/templates/source.html index 9daa0cf8ff6..ea530087e6f 100644 --- a/src/librustdoc/html/templates/source.html +++ b/src/librustdoc/html/templates/source.html @@ -9,7 +9,7 @@
    {% else %} {% endmatch %} -
    {# #} +
    {# https://developers.google.com/search/docs/crawling-indexing/robots-meta-tag#data-nosnippet-attr Do not show "1 2 3 4 5 ..." in web search results. #}
    diff --git a/src/librustdoc/html/templates/type_layout.html b/src/librustdoc/html/templates/type_layout.html
    index e0516bb42fe..aee96fb8c41 100644
    --- a/src/librustdoc/html/templates/type_layout.html
    +++ b/src/librustdoc/html/templates/type_layout.html
    @@ -1,7 +1,7 @@
     

    {# #} Layout§ {# #}

    {# #} -
    {# #} +
    {% match type_layout_size %} {% when Ok(type_layout_size) %}
    {# #} @@ -14,19 +14,19 @@ chapter for details on type layout guarantees. {# #}

    {# #}
    {# #} -

    Size: {{+ type_layout_size|safe }}

    {# #} +

    Size: {{+ type_layout_size|safe }}

    {% if !variants.is_empty() %}

    {# #} Size for each variant: {# #}

    {# #} -
      {# #} +
        {% for (name, layout_size) in variants %}
      • {# #} {{ name }}: {#+ #} {{ layout_size|safe }} -
      • {# #} + {% endfor %} -
      {# #} +
    {% endif %} {# This kind of layout error can occur with valid code, e.g. if you try to get the layout of a generic type such as `Vec`. #} @@ -35,7 +35,7 @@ Note: Unable to compute type layout, {#+ #} possibly due to this type having generic parameters. {#+ #} Layout can only be computed for concrete, fully-instantiated types. {# #} -

    {# #} +

    {# This kind of error probably can't happen with valid code, but we don't want to panic and prevent the docs from building, so we just let the user know that we couldn't compute the layout. #} @@ -43,21 +43,21 @@

    {# #} Note: Encountered an error during type layout; {#+ #} the type was too big. {# #} -

    {# #} +

    {% when Err(LayoutError::ReferencesError(_)) %}

    {# #} Note: Encountered an error during type layout; {#+ #} the type references errors. {# #} -

    {# #} +

    {% when Err(LayoutError::NormalizationFailure(_, _)) %}

    {# #} Note: Encountered an error during type layout; {#+ #} the type failed to be normalized. {# #} -

    {# #} +

    {% when Err(LayoutError::Cycle(_)) %}

    {# #} Note: Encountered an error during type layout; {#+ #} the type's layout depended on the type's layout itself. {# #} -

    {# #} +

    {% endmatch %}
    {# #} From c7d171d7714e1645c35c81b0631c6aadc969c086 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Fri, 27 Sep 2024 00:45:02 +0000 Subject: [PATCH 305/683] On implicit `Sized` bound on fn argument, point at type instead of pattern Instead of ``` error[E0277]: the size for values of type `(dyn ThriftService<(), AssocType = _> + 'static)` cannot be known at compilation time --> $DIR/issue-59324.rs:23:20 | LL | fn with_factory(factory: dyn ThriftService<()>) {} | ^^^^^^^ doesn't have a size known at compile-time ``` output ``` error[E0277]: the size for values of type `(dyn ThriftService<(), AssocType = _> + 'static)` cannot be known at compilation time --> $DIR/issue-59324.rs:23:29 | LL | fn with_factory(factory: dyn ThriftService<()>) {} | ^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time ``` --- compiler/rustc_hir_typeck/src/check.rs | 2 +- .../rustc_hir_typeck/src/gather_locals.rs | 2 +- .../clippy/tests/ui/crashes/ice-6251.stderr | 4 +- tests/ui/associated-types/issue-59324.stderr | 4 +- .../occurs-check/opaques.next.stderr | 4 +- .../replace-impl-infer-ty-from-trait.stderr | 4 +- tests/ui/error-codes/E0277.stderr | 4 +- .../feature-gate-unsized_fn_params.stderr | 12 ++--- .../feature-gate-unsized_locals.stderr | 4 +- ...r-var-leaked-out-of-rollback-122098.stderr | 4 +- tests/ui/issues/issue-38954.stderr | 4 +- tests/ui/issues/issue-41229-ref-str.stderr | 4 +- tests/ui/issues/issue-42312.stderr | 8 +-- tests/ui/issues/issue-5883.stderr | 4 +- tests/ui/issues/issue-66706.stderr | 4 +- .../avoid-ice-on-warning-2.new.stderr | 4 +- .../avoid-ice-on-warning-2.old.stderr | 4 +- tests/ui/resolve/issue-3907-2.stderr | 4 +- tests/ui/resolve/issue-5035-2.stderr | 4 +- ...object-unsafe-trait-references-self.stderr | 4 +- tests/ui/suggestions/path-by-value.stderr | 4 +- .../unsized-function-parameter.stderr | 12 ++--- tests/ui/trait-bounds/apit-unsized.stderr | 18 ++++--- ...f-for-repeated-unsized-bound-127441.stderr | 52 ++++++++++--------- .../alias/dont-elaborate-non-self.stderr | 4 +- .../bound/not-on-bare-trait-2021.stderr | 8 +-- .../ui/traits/bound/not-on-bare-trait.stderr | 8 +-- .../unknown_type_for_closure.stderr | 4 +- .../typeck_type_placeholder_item.stderr | 4 +- tests/ui/unsized/unsized-fn-arg.stderr | 4 +- tests/ui/unsized/unsized6.stderr | 8 +-- 31 files changed, 110 insertions(+), 104 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/check.rs b/compiler/rustc_hir_typeck/src/check.rs index f2d3a3b509a..2d8943c6159 100644 --- a/compiler/rustc_hir_typeck/src/check.rs +++ b/compiler/rustc_hir_typeck/src/check.rs @@ -99,7 +99,7 @@ pub(super) fn check_fn<'a, 'tcx>( if !params_can_be_unsized { fcx.require_type_is_sized( param_ty, - param.pat.span, + param.ty_span, // ty.span == binding_span iff this is a closure parameter with no type ascription, // or if it's an implicit `self` parameter ObligationCauseCode::SizedArgumentType( diff --git a/compiler/rustc_hir_typeck/src/gather_locals.rs b/compiler/rustc_hir_typeck/src/gather_locals.rs index 83c9a4878d2..5ae8d2230f8 100644 --- a/compiler/rustc_hir_typeck/src/gather_locals.rs +++ b/compiler/rustc_hir_typeck/src/gather_locals.rs @@ -144,7 +144,7 @@ impl<'a, 'tcx> Visitor<'tcx> for GatherLocalsVisitor<'a, 'tcx> { if !self.fcx.tcx.features().unsized_fn_params { self.fcx.require_type_is_sized( var_ty, - p.span, + ty_span, // ty_span == ident.span iff this is a closure parameter with no type // ascription, or if it's an implicit `self` parameter ObligationCauseCode::SizedArgumentType( diff --git a/src/tools/clippy/tests/ui/crashes/ice-6251.stderr b/src/tools/clippy/tests/ui/crashes/ice-6251.stderr index 82e7d723586..77c3e6288ce 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-6251.stderr +++ b/src/tools/clippy/tests/ui/crashes/ice-6251.stderr @@ -1,8 +1,8 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation time - --> tests/ui/crashes/ice-6251.rs:4:45 + --> tests/ui/crashes/ice-6251.rs:4:48 | LL | fn bug() -> impl Iterator { - | ^ doesn't have a size known at compile-time + | ^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `[u8]` = help: unsized fn params are gated as an unstable feature diff --git a/tests/ui/associated-types/issue-59324.stderr b/tests/ui/associated-types/issue-59324.stderr index f50d86580f8..6c77ee6044f 100644 --- a/tests/ui/associated-types/issue-59324.stderr +++ b/tests/ui/associated-types/issue-59324.stderr @@ -79,10 +79,10 @@ LL | pub trait Foo: NotFoo { | ^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the size for values of type `(dyn ThriftService<(), AssocType = _> + 'static)` cannot be known at compilation time - --> $DIR/issue-59324.rs:23:20 + --> $DIR/issue-59324.rs:23:29 | LL | fn with_factory(factory: dyn ThriftService<()>) {} - | ^^^^^^^ doesn't have a size known at compile-time + | ^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `(dyn ThriftService<(), AssocType = _> + 'static)` = help: unsized fn params are gated as an unstable feature diff --git a/tests/ui/coherence/occurs-check/opaques.next.stderr b/tests/ui/coherence/occurs-check/opaques.next.stderr index 11d1edcca2f..757219398f1 100644 --- a/tests/ui/coherence/occurs-check/opaques.next.stderr +++ b/tests/ui/coherence/occurs-check/opaques.next.stderr @@ -8,10 +8,10 @@ LL | impl Trait for defining_scope::Alias { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation error[E0282]: type annotations needed - --> $DIR/opaques.rs:13:20 + --> $DIR/opaques.rs:13:23 | LL | pub fn cast(x: Container, T>) -> Container { - | ^ cannot infer type + | ^^^^^^^^^^^^^^^^^^^^^^ cannot infer type error: aborting due to 2 previous errors diff --git a/tests/ui/did_you_mean/replace-impl-infer-ty-from-trait.stderr b/tests/ui/did_you_mean/replace-impl-infer-ty-from-trait.stderr index 6f38def6998..96742f8bf47 100644 --- a/tests/ui/did_you_mean/replace-impl-infer-ty-from-trait.stderr +++ b/tests/ui/did_you_mean/replace-impl-infer-ty-from-trait.stderr @@ -14,10 +14,10 @@ LL | fn bar(i: i32, t: usize, s: &()) -> (usize, i32) { | ~~~ ~~~~~ ~~~ ~~~~~~~~~~~~ error[E0282]: type annotations needed - --> $DIR/replace-impl-infer-ty-from-trait.rs:9:12 + --> $DIR/replace-impl-infer-ty-from-trait.rs:9:15 | LL | fn bar(i: _, t: _, s: _) -> _ { - | ^ cannot infer type + | ^ cannot infer type error: aborting due to 2 previous errors diff --git a/tests/ui/error-codes/E0277.stderr b/tests/ui/error-codes/E0277.stderr index aeb97290cf8..52ada36574e 100644 --- a/tests/ui/error-codes/E0277.stderr +++ b/tests/ui/error-codes/E0277.stderr @@ -1,8 +1,8 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation time - --> $DIR/E0277.rs:11:6 + --> $DIR/E0277.rs:11:9 | LL | fn f(p: Path) { } - | ^ doesn't have a size known at compile-time + | ^^^^ doesn't have a size known at compile-time | = help: within `Path`, the trait `Sized` is not implemented for `[u8]`, which is required by `Path: Sized` note: required because it appears within the type `Path` diff --git a/tests/ui/feature-gates/feature-gate-unsized_fn_params.stderr b/tests/ui/feature-gates/feature-gate-unsized_fn_params.stderr index b11c30eaad4..360c73ae2d7 100644 --- a/tests/ui/feature-gates/feature-gate-unsized_fn_params.stderr +++ b/tests/ui/feature-gates/feature-gate-unsized_fn_params.stderr @@ -1,8 +1,8 @@ error[E0277]: the size for values of type `(dyn Foo + 'static)` cannot be known at compilation time - --> $DIR/feature-gate-unsized_fn_params.rs:17:8 + --> $DIR/feature-gate-unsized_fn_params.rs:17:11 | LL | fn foo(x: dyn Foo) { - | ^ doesn't have a size known at compile-time + | ^^^^^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `(dyn Foo + 'static)` = help: unsized fn params are gated as an unstable feature @@ -16,10 +16,10 @@ LL | fn foo(x: &dyn Foo) { | + error[E0277]: the size for values of type `(dyn Foo + 'static)` cannot be known at compilation time - --> $DIR/feature-gate-unsized_fn_params.rs:21:8 + --> $DIR/feature-gate-unsized_fn_params.rs:21:11 | LL | fn bar(x: Foo) { - | ^ doesn't have a size known at compile-time + | ^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `(dyn Foo + 'static)` = help: unsized fn params are gated as an unstable feature @@ -33,10 +33,10 @@ LL | fn bar(x: &dyn Foo) { | ++++ error[E0277]: the size for values of type `[()]` cannot be known at compilation time - --> $DIR/feature-gate-unsized_fn_params.rs:25:8 + --> $DIR/feature-gate-unsized_fn_params.rs:25:11 | LL | fn qux(_: [()]) {} - | ^ doesn't have a size known at compile-time + | ^^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `[()]` = help: unsized fn params are gated as an unstable feature diff --git a/tests/ui/feature-gates/feature-gate-unsized_locals.stderr b/tests/ui/feature-gates/feature-gate-unsized_locals.stderr index f1595e034be..f48565b922b 100644 --- a/tests/ui/feature-gates/feature-gate-unsized_locals.stderr +++ b/tests/ui/feature-gates/feature-gate-unsized_locals.stderr @@ -1,8 +1,8 @@ error[E0277]: the size for values of type `(dyn FnOnce() + 'static)` cannot be known at compilation time - --> $DIR/feature-gate-unsized_locals.rs:1:6 + --> $DIR/feature-gate-unsized_locals.rs:1:9 | LL | fn f(f: dyn FnOnce()) {} - | ^ doesn't have a size known at compile-time + | ^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `(dyn FnOnce() + 'static)` = help: unsized fn params are gated as an unstable feature diff --git a/tests/ui/inference/ice-ifer-var-leaked-out-of-rollback-122098.stderr b/tests/ui/inference/ice-ifer-var-leaked-out-of-rollback-122098.stderr index a5cd057e284..ce01e24770d 100644 --- a/tests/ui/inference/ice-ifer-var-leaked-out-of-rollback-122098.stderr +++ b/tests/ui/inference/ice-ifer-var-leaked-out-of-rollback-122098.stderr @@ -36,10 +36,10 @@ LL | struct Query<'q> {} = help: consider removing `'q`, referring to it in a field, or using a marker such as `PhantomData` error[E0277]: the size for values of type `Self` cannot be known at compilation time - --> $DIR/ice-ifer-var-leaked-out-of-rollback-122098.rs:7:17 + --> $DIR/ice-ifer-var-leaked-out-of-rollback-122098.rs:7:21 | LL | fn for_each(mut self, mut f: Box) + 'static>) {} - | ^^^^^^^^ doesn't have a size known at compile-time + | ^^^^ doesn't have a size known at compile-time | = help: unsized fn params are gated as an unstable feature help: consider further restricting `Self` diff --git a/tests/ui/issues/issue-38954.stderr b/tests/ui/issues/issue-38954.stderr index 4dd83ddf32d..bd9c5e4197b 100644 --- a/tests/ui/issues/issue-38954.stderr +++ b/tests/ui/issues/issue-38954.stderr @@ -1,8 +1,8 @@ error[E0277]: the size for values of type `str` cannot be known at compilation time - --> $DIR/issue-38954.rs:1:10 + --> $DIR/issue-38954.rs:1:18 | LL | fn _test(ref _p: str) {} - | ^^^^^^ doesn't have a size known at compile-time + | ^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `str` = help: unsized fn params are gated as an unstable feature diff --git a/tests/ui/issues/issue-41229-ref-str.stderr b/tests/ui/issues/issue-41229-ref-str.stderr index afc2cac7343..d4ef2a77725 100644 --- a/tests/ui/issues/issue-41229-ref-str.stderr +++ b/tests/ui/issues/issue-41229-ref-str.stderr @@ -1,8 +1,8 @@ error[E0277]: the size for values of type `str` cannot be known at compilation time - --> $DIR/issue-41229-ref-str.rs:1:16 + --> $DIR/issue-41229-ref-str.rs:1:23 | LL | pub fn example(ref s: str) {} - | ^^^^^ doesn't have a size known at compile-time + | ^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `str` = help: unsized fn params are gated as an unstable feature diff --git a/tests/ui/issues/issue-42312.stderr b/tests/ui/issues/issue-42312.stderr index 3ca6a2957e1..cbdc9ce0f83 100644 --- a/tests/ui/issues/issue-42312.stderr +++ b/tests/ui/issues/issue-42312.stderr @@ -1,8 +1,8 @@ error[E0277]: the size for values of type `::Target` cannot be known at compilation time - --> $DIR/issue-42312.rs:4:12 + --> $DIR/issue-42312.rs:4:15 | LL | fn baz(_: Self::Target) where Self: Deref {} - | ^ doesn't have a size known at compile-time + | ^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `::Target` = help: unsized fn params are gated as an unstable feature @@ -16,10 +16,10 @@ LL | fn baz(_: &Self::Target) where Self: Deref {} | + error[E0277]: the size for values of type `(dyn ToString + 'static)` cannot be known at compilation time - --> $DIR/issue-42312.rs:8:10 + --> $DIR/issue-42312.rs:8:13 | LL | pub fn f(_: dyn ToString) {} - | ^ doesn't have a size known at compile-time + | ^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `(dyn ToString + 'static)` = help: unsized fn params are gated as an unstable feature diff --git a/tests/ui/issues/issue-5883.stderr b/tests/ui/issues/issue-5883.stderr index 51d9708e0fa..d481d0ef94e 100644 --- a/tests/ui/issues/issue-5883.stderr +++ b/tests/ui/issues/issue-5883.stderr @@ -1,8 +1,8 @@ error[E0277]: the size for values of type `(dyn A + 'static)` cannot be known at compilation time - --> $DIR/issue-5883.rs:8:5 + --> $DIR/issue-5883.rs:8:8 | LL | r: dyn A + 'static - | ^ doesn't have a size known at compile-time + | ^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `(dyn A + 'static)` = help: unsized fn params are gated as an unstable feature diff --git a/tests/ui/issues/issue-66706.stderr b/tests/ui/issues/issue-66706.stderr index dd1e07589f5..cfe85764000 100644 --- a/tests/ui/issues/issue-66706.stderr +++ b/tests/ui/issues/issue-66706.stderr @@ -29,10 +29,10 @@ LL | [0; match [|f @ &ref _| () ] {} ] | while parsing this `match` expression error[E0282]: type annotations needed - --> $DIR/issue-66706.rs:2:11 + --> $DIR/issue-66706.rs:2:14 | LL | [0; [|_: _ &_| ()].len()] - | ^ cannot infer type + | ^ cannot infer type error[E0282]: type annotations needed --> $DIR/issue-66706.rs:13:11 diff --git a/tests/ui/object-safety/avoid-ice-on-warning-2.new.stderr b/tests/ui/object-safety/avoid-ice-on-warning-2.new.stderr index 0bc396390d7..811b9ac187b 100644 --- a/tests/ui/object-safety/avoid-ice-on-warning-2.new.stderr +++ b/tests/ui/object-safety/avoid-ice-on-warning-2.new.stderr @@ -19,10 +19,10 @@ LL | f() | call expression requires function error[E0277]: the size for values of type `(dyn Copy + 'static)` cannot be known at compilation time - --> $DIR/avoid-ice-on-warning-2.rs:4:10 + --> $DIR/avoid-ice-on-warning-2.rs:4:13 | LL | fn id(f: Copy) -> usize { - | ^ doesn't have a size known at compile-time + | ^^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `(dyn Copy + 'static)` = help: unsized fn params are gated as an unstable feature diff --git a/tests/ui/object-safety/avoid-ice-on-warning-2.old.stderr b/tests/ui/object-safety/avoid-ice-on-warning-2.old.stderr index f1f33a6c6d6..dd4c7647e24 100644 --- a/tests/ui/object-safety/avoid-ice-on-warning-2.old.stderr +++ b/tests/ui/object-safety/avoid-ice-on-warning-2.old.stderr @@ -47,10 +47,10 @@ LL | f() | call expression requires function error[E0277]: the size for values of type `(dyn Copy + 'static)` cannot be known at compilation time - --> $DIR/avoid-ice-on-warning-2.rs:4:10 + --> $DIR/avoid-ice-on-warning-2.rs:4:13 | LL | fn id(f: Copy) -> usize { - | ^ doesn't have a size known at compile-time + | ^^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `(dyn Copy + 'static)` = help: unsized fn params are gated as an unstable feature diff --git a/tests/ui/resolve/issue-3907-2.stderr b/tests/ui/resolve/issue-3907-2.stderr index 364edb788c6..b252e45e6b2 100644 --- a/tests/ui/resolve/issue-3907-2.stderr +++ b/tests/ui/resolve/issue-3907-2.stderr @@ -11,10 +11,10 @@ LL | fn bar(); | ^^^ the trait cannot be made into an object because associated function `bar` has no `self` parameter error[E0277]: the size for values of type `(dyn issue_3907::Foo + 'static)` cannot be known at compilation time - --> $DIR/issue-3907-2.rs:11:8 + --> $DIR/issue-3907-2.rs:11:12 | LL | fn bar(_x: Foo) {} - | ^^ doesn't have a size known at compile-time + | ^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `(dyn issue_3907::Foo + 'static)` = help: unsized fn params are gated as an unstable feature diff --git a/tests/ui/resolve/issue-5035-2.stderr b/tests/ui/resolve/issue-5035-2.stderr index 30721c0a206..ade0d6b4a35 100644 --- a/tests/ui/resolve/issue-5035-2.stderr +++ b/tests/ui/resolve/issue-5035-2.stderr @@ -1,8 +1,8 @@ error[E0277]: the size for values of type `(dyn I + 'static)` cannot be known at compilation time - --> $DIR/issue-5035-2.rs:4:8 + --> $DIR/issue-5035-2.rs:4:12 | LL | fn foo(_x: K) {} - | ^^ doesn't have a size known at compile-time + | ^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `(dyn I + 'static)` = help: unsized fn params are gated as an unstable feature diff --git a/tests/ui/suggestions/object-unsafe-trait-references-self.stderr b/tests/ui/suggestions/object-unsafe-trait-references-self.stderr index 64270068471..f6530200d22 100644 --- a/tests/ui/suggestions/object-unsafe-trait-references-self.stderr +++ b/tests/ui/suggestions/object-unsafe-trait-references-self.stderr @@ -32,10 +32,10 @@ LL | trait Other: Sized {} | this trait cannot be made into an object... error[E0277]: the size for values of type `Self` cannot be known at compilation time - --> $DIR/object-unsafe-trait-references-self.rs:2:19 + --> $DIR/object-unsafe-trait-references-self.rs:2:22 | LL | fn baz(&self, _: Self) {} - | ^ doesn't have a size known at compile-time + | ^^^^ doesn't have a size known at compile-time | = help: unsized fn params are gated as an unstable feature help: consider further restricting `Self` diff --git a/tests/ui/suggestions/path-by-value.stderr b/tests/ui/suggestions/path-by-value.stderr index 46002d4e257..62feafe534d 100644 --- a/tests/ui/suggestions/path-by-value.stderr +++ b/tests/ui/suggestions/path-by-value.stderr @@ -1,8 +1,8 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation time - --> $DIR/path-by-value.rs:3:6 + --> $DIR/path-by-value.rs:3:9 | LL | fn f(p: Path) { } - | ^ doesn't have a size known at compile-time + | ^^^^ doesn't have a size known at compile-time | = help: within `Path`, the trait `Sized` is not implemented for `[u8]`, which is required by `Path: Sized` note: required because it appears within the type `Path` diff --git a/tests/ui/suggestions/unsized-function-parameter.stderr b/tests/ui/suggestions/unsized-function-parameter.stderr index 55d8d1ab1bc..4513a22bf15 100644 --- a/tests/ui/suggestions/unsized-function-parameter.stderr +++ b/tests/ui/suggestions/unsized-function-parameter.stderr @@ -1,8 +1,8 @@ error[E0277]: the size for values of type `str` cannot be known at compilation time - --> $DIR/unsized-function-parameter.rs:5:9 + --> $DIR/unsized-function-parameter.rs:5:14 | LL | fn foo1(bar: str) {} - | ^^^ doesn't have a size known at compile-time + | ^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `str` = help: unsized fn params are gated as an unstable feature @@ -12,10 +12,10 @@ LL | fn foo1(bar: &str) {} | + error[E0277]: the size for values of type `str` cannot be known at compilation time - --> $DIR/unsized-function-parameter.rs:11:9 + --> $DIR/unsized-function-parameter.rs:11:15 | LL | fn foo2(_bar: str) {} - | ^^^^ doesn't have a size known at compile-time + | ^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `str` = help: unsized fn params are gated as an unstable feature @@ -25,10 +25,10 @@ LL | fn foo2(_bar: &str) {} | + error[E0277]: the size for values of type `str` cannot be known at compilation time - --> $DIR/unsized-function-parameter.rs:17:9 + --> $DIR/unsized-function-parameter.rs:17:12 | LL | fn foo3(_: str) {} - | ^ doesn't have a size known at compile-time + | ^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `str` = help: unsized fn params are gated as an unstable feature diff --git a/tests/ui/trait-bounds/apit-unsized.stderr b/tests/ui/trait-bounds/apit-unsized.stderr index 0f2dc52599f..6b68178757b 100644 --- a/tests/ui/trait-bounds/apit-unsized.stderr +++ b/tests/ui/trait-bounds/apit-unsized.stderr @@ -1,10 +1,11 @@ error[E0277]: the size for values of type `impl Iterator + ?Sized` cannot be known at compilation time - --> $DIR/apit-unsized.rs:1:8 + --> $DIR/apit-unsized.rs:1:11 | LL | fn foo(_: impl Iterator + ?Sized) {} - | ^ ---------------------------------- this type parameter needs to be `Sized` - | | - | doesn't have a size known at compile-time + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | doesn't have a size known at compile-time + | this type parameter needs to be `Sized` | = help: unsized fn params are gated as an unstable feature help: consider removing the `?Sized` bound to make the type parameter `Sized` @@ -18,12 +19,13 @@ LL | fn foo(_: &impl Iterator + ?Sized) {} | + error[E0277]: the size for values of type `impl ?Sized` cannot be known at compilation time - --> $DIR/apit-unsized.rs:2:8 + --> $DIR/apit-unsized.rs:2:11 | LL | fn bar(_: impl ?Sized) {} - | ^ ----------- this type parameter needs to be `Sized` - | | - | doesn't have a size known at compile-time + | ^^^^^^^^^^^ + | | + | doesn't have a size known at compile-time + | this type parameter needs to be `Sized` | = help: unsized fn params are gated as an unstable feature help: consider replacing `?Sized` with `Sized` diff --git a/tests/ui/trait-bounds/bad-suggestionf-for-repeated-unsized-bound-127441.stderr b/tests/ui/trait-bounds/bad-suggestionf-for-repeated-unsized-bound-127441.stderr index 3e8f45ee9fc..363f52d6df8 100644 --- a/tests/ui/trait-bounds/bad-suggestionf-for-repeated-unsized-bound-127441.stderr +++ b/tests/ui/trait-bounds/bad-suggestionf-for-repeated-unsized-bound-127441.stderr @@ -35,10 +35,10 @@ LL | fn foo8(_: impl ?Sized + Debug + ?Sized ) {} | ^^^^^^ ^^^^^^ error[E0277]: the size for values of type `T` cannot be known at compilation time - --> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:9:20 + --> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:9:23 | LL | fn foo1(a: T) {} - | - ^ doesn't have a size known at compile-time + | - ^ doesn't have a size known at compile-time | | | this type parameter needs to be `Sized` | @@ -54,10 +54,10 @@ LL | fn foo1(a: &T) {} | + error[E0277]: the size for values of type `T` cannot be known at compilation time - --> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:12:29 + --> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:12:32 | LL | fn foo2(a: T) {} - | - ^ doesn't have a size known at compile-time + | - ^ doesn't have a size known at compile-time | | | this type parameter needs to be `Sized` | @@ -73,10 +73,10 @@ LL | fn foo2(a: &T) {} | + error[E0277]: the size for values of type `T` cannot be known at compilation time - --> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:16:37 + --> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:16:40 | LL | fn foo3(a: T) {} - | - ^ doesn't have a size known at compile-time + | - ^ doesn't have a size known at compile-time | | | this type parameter needs to be `Sized` | @@ -92,10 +92,10 @@ LL | fn foo3(a: &T) {} | + error[E0277]: the size for values of type `T` cannot be known at compilation time - --> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:20:38 + --> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:20:41 | LL | fn foo4(a: T) {} - | - ^ doesn't have a size known at compile-time + | - ^ doesn't have a size known at compile-time | | | this type parameter needs to be `Sized` | @@ -111,12 +111,13 @@ LL | fn foo4(a: &T) {} | + error[E0277]: the size for values of type `impl ?Sized` cannot be known at compilation time - --> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:24:9 + --> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:24:12 | LL | fn foo5(_: impl ?Sized) {} - | ^ ----------- this type parameter needs to be `Sized` - | | - | doesn't have a size known at compile-time + | ^^^^^^^^^^^ + | | + | doesn't have a size known at compile-time + | this type parameter needs to be `Sized` | = help: unsized fn params are gated as an unstable feature help: consider replacing `?Sized` with `Sized` @@ -130,12 +131,13 @@ LL | fn foo5(_: &impl ?Sized) {} | + error[E0277]: the size for values of type `impl ?Sized + ?Sized` cannot be known at compilation time - --> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:27:9 + --> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:27:12 | LL | fn foo6(_: impl ?Sized + ?Sized) {} - | ^ -------------------- this type parameter needs to be `Sized` - | | - | doesn't have a size known at compile-time + | ^^^^^^^^^^^^^^^^^^^^ + | | + | doesn't have a size known at compile-time + | this type parameter needs to be `Sized` | = help: unsized fn params are gated as an unstable feature help: consider restricting type parameters @@ -149,12 +151,13 @@ LL | fn foo6(_: &impl ?Sized + ?Sized) {} | + error[E0277]: the size for values of type `impl ?Sized + ?Sized + Debug` cannot be known at compilation time - --> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:31:9 + --> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:31:12 | LL | fn foo7(_: impl ?Sized + ?Sized + Debug) {} - | ^ ---------------------------- this type parameter needs to be `Sized` - | | - | doesn't have a size known at compile-time + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | doesn't have a size known at compile-time + | this type parameter needs to be `Sized` | = help: unsized fn params are gated as an unstable feature help: consider restricting type parameters @@ -168,12 +171,13 @@ LL | fn foo7(_: &impl ?Sized + ?Sized + Debug) {} | + error[E0277]: the size for values of type `impl ?Sized + Debug + ?Sized` cannot be known at compilation time - --> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:35:9 + --> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:35:12 | LL | fn foo8(_: impl ?Sized + Debug + ?Sized ) {} - | ^ ---------------------------- this type parameter needs to be `Sized` - | | - | doesn't have a size known at compile-time + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | doesn't have a size known at compile-time + | this type parameter needs to be `Sized` | = help: unsized fn params are gated as an unstable feature help: consider restricting type parameters diff --git a/tests/ui/traits/alias/dont-elaborate-non-self.stderr b/tests/ui/traits/alias/dont-elaborate-non-self.stderr index 4e2edb474c0..952f78dd3da 100644 --- a/tests/ui/traits/alias/dont-elaborate-non-self.stderr +++ b/tests/ui/traits/alias/dont-elaborate-non-self.stderr @@ -1,8 +1,8 @@ error[E0277]: the size for values of type `(dyn Fn() -> Fut + 'static)` cannot be known at compilation time - --> $DIR/dont-elaborate-non-self.rs:7:11 + --> $DIR/dont-elaborate-non-self.rs:7:14 | LL | fn f(a: dyn F) {} - | ^ doesn't have a size known at compile-time + | ^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `(dyn Fn() -> Fut + 'static)` = help: unsized fn params are gated as an unstable feature diff --git a/tests/ui/traits/bound/not-on-bare-trait-2021.stderr b/tests/ui/traits/bound/not-on-bare-trait-2021.stderr index 57d3bc8f109..e05ae8e5267 100644 --- a/tests/ui/traits/bound/not-on-bare-trait-2021.stderr +++ b/tests/ui/traits/bound/not-on-bare-trait-2021.stderr @@ -1,8 +1,8 @@ error[E0277]: the size for values of type `(dyn Foo + Send + 'static)` cannot be known at compilation time - --> $DIR/not-on-bare-trait-2021.rs:8:8 + --> $DIR/not-on-bare-trait-2021.rs:8:12 | LL | fn foo(_x: Foo + Send) { - | ^^ doesn't have a size known at compile-time + | ^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `(dyn Foo + Send + 'static)` = help: unsized fn params are gated as an unstable feature @@ -16,10 +16,10 @@ LL | fn foo(_x: &(dyn Foo + Send)) { | +++++ + error[E0277]: the size for values of type `(dyn Foo + 'static)` cannot be known at compilation time - --> $DIR/not-on-bare-trait-2021.rs:12:8 + --> $DIR/not-on-bare-trait-2021.rs:12:11 | LL | fn bar(x: Foo) -> Foo { - | ^ doesn't have a size known at compile-time + | ^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `(dyn Foo + 'static)` = help: unsized fn params are gated as an unstable feature diff --git a/tests/ui/traits/bound/not-on-bare-trait.stderr b/tests/ui/traits/bound/not-on-bare-trait.stderr index f1e7a28654a..3c9b1413d64 100644 --- a/tests/ui/traits/bound/not-on-bare-trait.stderr +++ b/tests/ui/traits/bound/not-on-bare-trait.stderr @@ -13,10 +13,10 @@ LL | fn foo(_x: dyn Foo + Send) { | +++ error[E0277]: the size for values of type `(dyn Foo + Send + 'static)` cannot be known at compilation time - --> $DIR/not-on-bare-trait.rs:7:8 + --> $DIR/not-on-bare-trait.rs:7:12 | LL | fn foo(_x: Foo + Send) { - | ^^ doesn't have a size known at compile-time + | ^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `(dyn Foo + Send + 'static)` = help: unsized fn params are gated as an unstable feature @@ -30,10 +30,10 @@ LL | fn foo(_x: &(dyn Foo + Send)) { | +++++ + error[E0277]: the size for values of type `(dyn Foo + Send + 'static)` cannot be known at compilation time - --> $DIR/not-on-bare-trait.rs:12:8 + --> $DIR/not-on-bare-trait.rs:12:12 | LL | fn bar(_x: (dyn Foo + Send)) { - | ^^ doesn't have a size known at compile-time + | ^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `(dyn Foo + Send + 'static)` = help: unsized fn params are gated as an unstable feature diff --git a/tests/ui/type/type-check/unknown_type_for_closure.stderr b/tests/ui/type/type-check/unknown_type_for_closure.stderr index 960c0eff8ea..387ba4db9d3 100644 --- a/tests/ui/type/type-check/unknown_type_for_closure.stderr +++ b/tests/ui/type/type-check/unknown_type_for_closure.stderr @@ -16,10 +16,10 @@ LL | let x = |_: /* Type */| {}; | ++++++++++++ error[E0282]: type annotations needed - --> $DIR/unknown_type_for_closure.rs:10:14 + --> $DIR/unknown_type_for_closure.rs:10:17 | LL | let x = |k: _| {}; - | ^ cannot infer type + | ^ cannot infer type error[E0282]: type annotations needed --> $DIR/unknown_type_for_closure.rs:14:28 diff --git a/tests/ui/typeck/typeck_type_placeholder_item.stderr b/tests/ui/typeck/typeck_type_placeholder_item.stderr index 9d295f88da5..2c064fbb19f 100644 --- a/tests/ui/typeck/typeck_type_placeholder_item.stderr +++ b/tests/ui/typeck/typeck_type_placeholder_item.stderr @@ -358,10 +358,10 @@ LL ~ b: (T, T), | error[E0282]: type annotations needed - --> $DIR/typeck_type_placeholder_item.rs:128:18 + --> $DIR/typeck_type_placeholder_item.rs:128:21 | LL | fn fn_test11(_: _) -> (_, _) { panic!() } - | ^ cannot infer type + | ^ cannot infer type error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types --> $DIR/typeck_type_placeholder_item.rs:128:28 diff --git a/tests/ui/unsized/unsized-fn-arg.stderr b/tests/ui/unsized/unsized-fn-arg.stderr index c8a6622b809..3c582e8d93a 100644 --- a/tests/ui/unsized/unsized-fn-arg.stderr +++ b/tests/ui/unsized/unsized-fn-arg.stderr @@ -1,8 +1,8 @@ error[E0277]: the size for values of type `T` cannot be known at compilation time - --> $DIR/unsized-fn-arg.rs:5:17 + --> $DIR/unsized-fn-arg.rs:5:20 | LL | fn f(t: T) {} - | - ^ doesn't have a size known at compile-time + | - ^ doesn't have a size known at compile-time | | | this type parameter needs to be `Sized` | diff --git a/tests/ui/unsized/unsized6.stderr b/tests/ui/unsized/unsized6.stderr index d406120efc5..de921709865 100644 --- a/tests/ui/unsized/unsized6.stderr +++ b/tests/ui/unsized/unsized6.stderr @@ -206,10 +206,10 @@ LL + fn f4(x1: Box, x2: Box, x3: Box) { | error[E0277]: the size for values of type `X` cannot be known at compilation time - --> $DIR/unsized6.rs:38:18 + --> $DIR/unsized6.rs:38:21 | LL | fn g1(x: X) {} - | - ^ doesn't have a size known at compile-time + | - ^ doesn't have a size known at compile-time | | | this type parameter needs to be `Sized` | @@ -225,10 +225,10 @@ LL | fn g1(x: &X) {} | + error[E0277]: the size for values of type `X` cannot be known at compilation time - --> $DIR/unsized6.rs:40:22 + --> $DIR/unsized6.rs:40:25 | LL | fn g2(x: X) {} - | - ^ doesn't have a size known at compile-time + | - ^ doesn't have a size known at compile-time | | | this type parameter needs to be `Sized` | From eff6d414c05411a0f83d74eb745e951e8bdc9408 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Fri, 27 Sep 2024 00:45:02 +0000 Subject: [PATCH 306/683] On implicit `Sized` bound on fn argument, point at type instead of pattern Instead of ``` error[E0277]: the size for values of type `(dyn ThriftService<(), AssocType = _> + 'static)` cannot be known at compilation time --> $DIR/issue-59324.rs:23:20 | LL | fn with_factory(factory: dyn ThriftService<()>) {} | ^^^^^^^ doesn't have a size known at compile-time ``` output ``` error[E0277]: the size for values of type `(dyn ThriftService<(), AssocType = _> + 'static)` cannot be known at compilation time --> $DIR/issue-59324.rs:23:29 | LL | fn with_factory(factory: dyn ThriftService<()>) {} | ^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time ``` --- tests/ui/crashes/ice-6251.stderr | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/ui/crashes/ice-6251.stderr b/tests/ui/crashes/ice-6251.stderr index 82e7d723586..77c3e6288ce 100644 --- a/tests/ui/crashes/ice-6251.stderr +++ b/tests/ui/crashes/ice-6251.stderr @@ -1,8 +1,8 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation time - --> tests/ui/crashes/ice-6251.rs:4:45 + --> tests/ui/crashes/ice-6251.rs:4:48 | LL | fn bug() -> impl Iterator { - | ^ doesn't have a size known at compile-time + | ^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `[u8]` = help: unsized fn params are gated as an unstable feature From c48b0d4eb404f856f8bf1d305818ce21cc125fc5 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Thu, 26 Sep 2024 17:26:05 -0700 Subject: [PATCH 307/683] diagnostics: wrap fn cast suggestions in parens Fixes #121632 --- .../traits/fulfillment_errors.rs | 29 ++++++++++++++++--- src/tools/tidy/src/issues.txt | 1 - .../bare-fn-no-impl-fn-ptr-99875.rs} | 0 .../bare-fn-no-impl-fn-ptr-99875.stderr} | 12 ++++---- .../fn-trait-cast-diagnostic.rs | 0 .../fn-trait-cast-diagnostic.stderr | 0 .../suggest-wrap-parens-method.fixed | 15 ++++++++++ .../fn-pointer/suggest-wrap-parens-method.rs | 15 ++++++++++ .../suggest-wrap-parens-method.stderr | 19 ++++++++++++ .../fn-pointer/suggest-wrap-parens.fixed | 10 +++++++ .../traits/fn-pointer/suggest-wrap-parens.rs | 10 +++++++ .../fn-pointer/suggest-wrap-parens.stderr | 15 ++++++++++ 12 files changed, 115 insertions(+), 11 deletions(-) rename tests/ui/traits/{issue-99875.rs => fn-pointer/bare-fn-no-impl-fn-ptr-99875.rs} (100%) rename tests/ui/traits/{issue-99875.stderr => fn-pointer/bare-fn-no-impl-fn-ptr-99875.stderr} (74%) rename tests/ui/traits/{ => fn-pointer}/fn-trait-cast-diagnostic.rs (100%) rename tests/ui/traits/{ => fn-pointer}/fn-trait-cast-diagnostic.stderr (100%) create mode 100644 tests/ui/traits/fn-pointer/suggest-wrap-parens-method.fixed create mode 100644 tests/ui/traits/fn-pointer/suggest-wrap-parens-method.rs create mode 100644 tests/ui/traits/fn-pointer/suggest-wrap-parens-method.stderr create mode 100644 tests/ui/traits/fn-pointer/suggest-wrap-parens.fixed create mode 100644 tests/ui/traits/fn-pointer/suggest-wrap-parens.rs create mode 100644 tests/ui/traits/fn-pointer/suggest-wrap-parens.stderr 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 19e2679ae4d..de95e32de10 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 @@ -33,7 +33,8 @@ use tracing::{debug, instrument}; use super::on_unimplemented::{AppendConstMessage, OnUnimplementedNote}; use super::suggestions::get_explanation_based_on_obligation; use super::{ - ArgKind, CandidateSimilarity, GetSafeTransmuteErrorAndReason, ImplCandidate, UnsatisfiedConst, + ArgKind, CandidateSimilarity, FindExprBySpan, GetSafeTransmuteErrorAndReason, ImplCandidate, + UnsatisfiedConst, }; use crate::error_reporting::TypeErrCtxt; use crate::error_reporting::infer::TyCategory; @@ -378,14 +379,34 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { if let (ty::FnPtr(..), ty::FnDef(..)) = (cand.self_ty().kind(), main_trait_ref.self_ty().skip_binder().kind()) { - err.span_suggestion( - span.shrink_to_hi(), + // Wrap method receivers and `&`-references in parens + let suggestion = if self.tcx.sess.source_map().span_look_ahead(span, ".", Some(50)).is_some() { + vec![ + (span.shrink_to_lo(), format!("(")), + (span.shrink_to_hi(), format!(" as {})", cand.self_ty())), + ] + } else if let Some(body) = self.tcx.hir().maybe_body_owned_by(obligation.cause.body_id) { + let mut expr_finder = FindExprBySpan::new(span, self.tcx); + expr_finder.visit_expr(body.value); + if let Some(expr) = expr_finder.result && + let hir::ExprKind::AddrOf(_, _, expr) = expr.kind { + vec![ + (expr.span.shrink_to_lo(), format!("(")), + (expr.span.shrink_to_hi(), format!(" as {})", cand.self_ty())), + ] + } else { + vec![(span.shrink_to_hi(), format!(" as {}", cand.self_ty()))] + } + } else { + vec![(span.shrink_to_hi(), format!(" as {}", cand.self_ty()))] + }; + err.multipart_suggestion( format!( "the trait `{}` is implemented for fn pointer `{}`, try casting using `as`", cand.print_trait_sugared(), cand.self_ty(), ), - format!(" as {}", cand.self_ty()), + suggestion, Applicability::MaybeIncorrect, ); true diff --git a/src/tools/tidy/src/issues.txt b/src/tools/tidy/src/issues.txt index 6b4c0e9c0b9..2071abefbe1 100644 --- a/src/tools/tidy/src/issues.txt +++ b/src/tools/tidy/src/issues.txt @@ -4076,7 +4076,6 @@ ui/traits/issue-96664.rs ui/traits/issue-96665.rs ui/traits/issue-97576.rs ui/traits/issue-97695-double-trivial-bound.rs -ui/traits/issue-99875.rs ui/traits/next-solver/coherence/issue-102048.rs ui/traits/next-solver/issue-118950-root-region.rs ui/traits/object/issue-33140-traitobject-crate.rs diff --git a/tests/ui/traits/issue-99875.rs b/tests/ui/traits/fn-pointer/bare-fn-no-impl-fn-ptr-99875.rs similarity index 100% rename from tests/ui/traits/issue-99875.rs rename to tests/ui/traits/fn-pointer/bare-fn-no-impl-fn-ptr-99875.rs diff --git a/tests/ui/traits/issue-99875.stderr b/tests/ui/traits/fn-pointer/bare-fn-no-impl-fn-ptr-99875.stderr similarity index 74% rename from tests/ui/traits/issue-99875.stderr rename to tests/ui/traits/fn-pointer/bare-fn-no-impl-fn-ptr-99875.stderr index 29e87571561..0666da4c707 100644 --- a/tests/ui/traits/issue-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/issue-99875.rs:12:11 + --> $DIR/bare-fn-no-impl-fn-ptr-99875.rs:12: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/issue-99875.rs:9:18 + --> $DIR/bare-fn-no-impl-fn-ptr-99875.rs:9:18 | LL | fn takes(_: impl Trait) {} | ^^^^^ required by this bound in `takes` @@ -16,17 +16,17 @@ 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/issue-99875.rs:14:11: 14:34}: Trait` is not satisfied - --> $DIR/issue-99875.rs:14:11 +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 | LL | takes(|_: Argument| -> Return { todo!() }); - | ----- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for closure `{closure@$DIR/issue-99875.rs:14:11: 14:34}` + | ----- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for closure `{closure@$DIR/bare-fn-no-impl-fn-ptr-99875.rs:14:11: 14:34}` | | | required by a bound introduced by this call | = help: the trait `Trait` is implemented for fn pointer `fn(Argument) -> Return` note: required by a bound in `takes` - --> $DIR/issue-99875.rs:9:18 + --> $DIR/bare-fn-no-impl-fn-ptr-99875.rs:9:18 | LL | fn takes(_: impl Trait) {} | ^^^^^ required by this bound in `takes` diff --git a/tests/ui/traits/fn-trait-cast-diagnostic.rs b/tests/ui/traits/fn-pointer/fn-trait-cast-diagnostic.rs similarity index 100% rename from tests/ui/traits/fn-trait-cast-diagnostic.rs rename to tests/ui/traits/fn-pointer/fn-trait-cast-diagnostic.rs diff --git a/tests/ui/traits/fn-trait-cast-diagnostic.stderr b/tests/ui/traits/fn-pointer/fn-trait-cast-diagnostic.stderr similarity index 100% rename from tests/ui/traits/fn-trait-cast-diagnostic.stderr rename to tests/ui/traits/fn-pointer/fn-trait-cast-diagnostic.stderr diff --git a/tests/ui/traits/fn-pointer/suggest-wrap-parens-method.fixed b/tests/ui/traits/fn-pointer/suggest-wrap-parens-method.fixed new file mode 100644 index 00000000000..e54963d01e8 --- /dev/null +++ b/tests/ui/traits/fn-pointer/suggest-wrap-parens-method.fixed @@ -0,0 +1,15 @@ +//@ run-rustfix + +trait Foo {} + +impl Foo for fn() {} + +trait Bar { + fn do_stuff(&self) where Self: Foo {} +} +impl Bar for T {} + +fn main() { + (main as fn()).do_stuff(); + //~^ ERROR the trait bound +} diff --git a/tests/ui/traits/fn-pointer/suggest-wrap-parens-method.rs b/tests/ui/traits/fn-pointer/suggest-wrap-parens-method.rs new file mode 100644 index 00000000000..89c1295613c --- /dev/null +++ b/tests/ui/traits/fn-pointer/suggest-wrap-parens-method.rs @@ -0,0 +1,15 @@ +//@ run-rustfix + +trait Foo {} + +impl Foo for fn() {} + +trait Bar { + fn do_stuff(&self) where Self: Foo {} +} +impl Bar for T {} + +fn main() { + main.do_stuff(); + //~^ ERROR the trait bound +} diff --git a/tests/ui/traits/fn-pointer/suggest-wrap-parens-method.stderr b/tests/ui/traits/fn-pointer/suggest-wrap-parens-method.stderr new file mode 100644 index 00000000000..2fc1523a193 --- /dev/null +++ b/tests/ui/traits/fn-pointer/suggest-wrap-parens-method.stderr @@ -0,0 +1,19 @@ +error[E0277]: the trait bound `fn() {main}: Foo` is not satisfied + --> $DIR/suggest-wrap-parens-method.rs:13:10 + | +LL | main.do_stuff(); + | ^^^^^^^^ the trait `Foo` is not implemented for fn item `fn() {main}` + | +note: required by a bound in `Bar::do_stuff` + --> $DIR/suggest-wrap-parens-method.rs:8:36 + | +LL | fn do_stuff(&self) where Self: Foo {} + | ^^^ required by this bound in `Bar::do_stuff` +help: the trait `Foo` is implemented for fn pointer `fn()`, try casting using `as` + | +LL | (main as fn()).do_stuff(); + | + ++++++++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/fn-pointer/suggest-wrap-parens.fixed b/tests/ui/traits/fn-pointer/suggest-wrap-parens.fixed new file mode 100644 index 00000000000..0bc8792b04e --- /dev/null +++ b/tests/ui/traits/fn-pointer/suggest-wrap-parens.fixed @@ -0,0 +1,10 @@ +//@ run-rustfix + +trait Foo {} + +impl Foo for fn() {} + +fn main() { + let _x: &dyn Foo = &(main as fn()); + //~^ ERROR the trait bound +} diff --git a/tests/ui/traits/fn-pointer/suggest-wrap-parens.rs b/tests/ui/traits/fn-pointer/suggest-wrap-parens.rs new file mode 100644 index 00000000000..ffe0826c035 --- /dev/null +++ b/tests/ui/traits/fn-pointer/suggest-wrap-parens.rs @@ -0,0 +1,10 @@ +//@ run-rustfix + +trait Foo {} + +impl Foo for fn() {} + +fn main() { + let _x: &dyn Foo = &main; + //~^ ERROR the trait bound +} diff --git a/tests/ui/traits/fn-pointer/suggest-wrap-parens.stderr b/tests/ui/traits/fn-pointer/suggest-wrap-parens.stderr new file mode 100644 index 00000000000..b71debac715 --- /dev/null +++ b/tests/ui/traits/fn-pointer/suggest-wrap-parens.stderr @@ -0,0 +1,15 @@ +error[E0277]: the trait bound `fn() {main}: Foo` is not satisfied + --> $DIR/suggest-wrap-parens.rs:8:24 + | +LL | let _x: &dyn Foo = &main; + | ^^^^^ the trait `Foo` is not implemented for fn item `fn() {main}` + | + = note: required for the cast from `&fn() {main}` to `&dyn Foo` +help: the trait `Foo` is implemented for fn pointer `fn()`, try casting using `as` + | +LL | let _x: &dyn Foo = &(main as fn()); + | + ++++++++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. From d4ee408afc59b36ff59b6fd12d47c1beeba8e985 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 25 Sep 2024 19:19:22 -0400 Subject: [PATCH 308/683] Check allow instantiating object trait binder when upcasting and in new solver --- .../src/solve/trait_goals.rs | 6 ++--- .../src/traits/select/mod.rs | 6 ++--- tests/ui/coercion/sub-principals.rs | 27 +++++++++++++++++++ .../higher-ranked-upcasting-ok.current.stderr | 22 --------------- .../higher-ranked-upcasting-ok.next.stderr | 14 ---------- .../higher-ranked-upcasting-ok.rs | 12 +++++---- .../higher-ranked-upcasting-ub.current.stderr | 8 +++--- tests/ui/traits/trait-upcasting/sub.rs | 26 ++++++++++++++++++ 8 files changed, 70 insertions(+), 51 deletions(-) create mode 100644 tests/ui/coercion/sub-principals.rs delete mode 100644 tests/ui/traits/trait-upcasting/higher-ranked-upcasting-ok.current.stderr delete mode 100644 tests/ui/traits/trait-upcasting/higher-ranked-upcasting-ok.next.stderr create mode 100644 tests/ui/traits/trait-upcasting/sub.rs diff --git a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs index 781ca127e15..0befe7f5e8a 100644 --- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs @@ -896,7 +896,7 @@ where && ecx .probe(|_| ProbeKind::UpcastProjectionCompatibility) .enter(|ecx| -> Result<(), NoSolution> { - ecx.eq(param_env, source_projection, target_projection)?; + ecx.sub(param_env, source_projection, target_projection)?; let _ = ecx.try_evaluate_added_goals()?; Ok(()) }) @@ -909,7 +909,7 @@ where // Check that a's supertrait (upcast_principal) is compatible // with the target (b_ty). ty::ExistentialPredicate::Trait(target_principal) => { - ecx.eq( + ecx.sub( param_env, upcast_principal.unwrap(), bound.rebind(target_principal), @@ -934,7 +934,7 @@ where Certainty::AMBIGUOUS, ); } - ecx.eq(param_env, source_projection, target_projection)?; + ecx.sub(param_env, source_projection, target_projection)?; } // Check that b_ty's auto traits are present in a_ty's bounds. ty::ExistentialPredicate::AutoTrait(def_id) => { diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index cbc17a058f6..2922a4898e9 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -2582,12 +2582,12 @@ impl<'tcx> SelectionContext<'_, 'tcx> { nested.extend( self.infcx .at(&obligation.cause, obligation.param_env) - .eq( + .sup( DefineOpaqueTypes::Yes, + bound.rebind(target_principal), upcast_principal.map_bound(|trait_ref| { ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref) }), - bound.rebind(target_principal), ) .map_err(|_| SelectionError::Unimplemented)? .into_obligations(), @@ -2620,7 +2620,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> { nested.extend( self.infcx .at(&obligation.cause, obligation.param_env) - .eq(DefineOpaqueTypes::Yes, source_projection, target_projection) + .sup(DefineOpaqueTypes::Yes, target_projection, source_projection) .map_err(|_| SelectionError::Unimplemented)? .into_obligations(), ); diff --git a/tests/ui/coercion/sub-principals.rs b/tests/ui/coercion/sub-principals.rs new file mode 100644 index 00000000000..c38769f0d09 --- /dev/null +++ b/tests/ui/coercion/sub-principals.rs @@ -0,0 +1,27 @@ +//@ check-pass +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver + +// Verify that the unsize goal can cast a higher-ranked trait goal to +// a non-higer-ranked instantiation. + +#![feature(unsize)] + +use std::marker::Unsize; + +fn test() +where + T: Unsize, +{ +} + +fn main() { + test:: Fn(&'a ()) -> &'a (), dyn Fn(&'static ()) -> &'static ()>(); + + trait Foo<'a, 'b> {} + test:: Foo<'a, 'b>, dyn for<'a> Foo<'a, 'a>>(); + + trait Bar<'a> {} + test:: Bar<'a>, dyn Bar<'_>>(); +} diff --git a/tests/ui/traits/trait-upcasting/higher-ranked-upcasting-ok.current.stderr b/tests/ui/traits/trait-upcasting/higher-ranked-upcasting-ok.current.stderr deleted file mode 100644 index 098ab71e946..00000000000 --- a/tests/ui/traits/trait-upcasting/higher-ranked-upcasting-ok.current.stderr +++ /dev/null @@ -1,22 +0,0 @@ -error[E0308]: mismatched types - --> $DIR/higher-ranked-upcasting-ok.rs:17:5 - | -LL | x - | ^ one type is more general than the other - | - = note: expected existential trait ref `for<'a, 'b> Supertrait<'a, 'b>` - found existential trait ref `for<'a> Supertrait<'a, 'a>` - -error[E0308]: mismatched types - --> $DIR/higher-ranked-upcasting-ok.rs:17:5 - | -LL | x - | ^ one type is more general than the other - | - = note: expected existential trait ref `for<'a, 'b> Supertrait<'a, 'b>` - found existential trait ref `for<'a> Supertrait<'a, 'a>` - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/traits/trait-upcasting/higher-ranked-upcasting-ok.next.stderr b/tests/ui/traits/trait-upcasting/higher-ranked-upcasting-ok.next.stderr deleted file mode 100644 index ac516fd6975..00000000000 --- a/tests/ui/traits/trait-upcasting/higher-ranked-upcasting-ok.next.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error[E0308]: mismatched types - --> $DIR/higher-ranked-upcasting-ok.rs:17:5 - | -LL | fn ok(x: &dyn for<'a, 'b> Subtrait<'a, 'b>) -> &dyn for<'a> Supertrait<'a, 'a> { - | ------------------------------- expected `&dyn for<'a> Supertrait<'a, 'a>` because of return type -LL | x - | ^ expected trait `Supertrait`, found trait `Subtrait` - | - = note: expected reference `&dyn for<'a> Supertrait<'a, 'a>` - found reference `&dyn for<'a, 'b> Subtrait<'a, 'b>` - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/traits/trait-upcasting/higher-ranked-upcasting-ok.rs b/tests/ui/traits/trait-upcasting/higher-ranked-upcasting-ok.rs index 00743203179..7f793e1269f 100644 --- a/tests/ui/traits/trait-upcasting/higher-ranked-upcasting-ok.rs +++ b/tests/ui/traits/trait-upcasting/higher-ranked-upcasting-ok.rs @@ -1,19 +1,21 @@ //@ revisions: current next //@ ignore-compare-mode-next-solver (explicit revisions) //@[next] compile-flags: -Znext-solver +//@ check-pass // We should be able to instantiate a binder during trait upcasting. // This test could be `check-pass`, but we should make sure that we // do so in both trait solvers. -#![feature(trait_upcasting)] -#![crate_type = "rlib"] -trait Supertrait<'a, 'b> {} +#![feature(trait_upcasting)] + +trait Supertrait<'a, 'b> {} trait Subtrait<'a, 'b>: Supertrait<'a, 'b> {} impl<'a> Supertrait<'a, 'a> for () {} impl<'a> Subtrait<'a, 'a> for () {} fn ok(x: &dyn for<'a, 'b> Subtrait<'a, 'b>) -> &dyn for<'a> Supertrait<'a, 'a> { - x //~ ERROR mismatched types - //[current]~^ ERROR mismatched types + x } + +fn main() {} diff --git a/tests/ui/traits/trait-upcasting/higher-ranked-upcasting-ub.current.stderr b/tests/ui/traits/trait-upcasting/higher-ranked-upcasting-ub.current.stderr index bac82983268..e5885ea35a7 100644 --- a/tests/ui/traits/trait-upcasting/higher-ranked-upcasting-ub.current.stderr +++ b/tests/ui/traits/trait-upcasting/higher-ranked-upcasting-ub.current.stderr @@ -4,8 +4,8 @@ error[E0308]: mismatched types LL | x | ^ one type is more general than the other | - = note: expected existential trait ref `for<'a> Supertrait<'a, 'a>` - found existential trait ref `for<'a, 'b> Supertrait<'a, 'b>` + = note: expected existential trait ref `for<'a, 'b> Supertrait<'a, 'b>` + found existential trait ref `for<'a> Supertrait<'a, 'a>` error[E0308]: mismatched types --> $DIR/higher-ranked-upcasting-ub.rs:22:5 @@ -13,8 +13,8 @@ error[E0308]: mismatched types LL | x | ^ one type is more general than the other | - = note: expected existential trait ref `for<'a> Supertrait<'a, 'a>` - found existential trait ref `for<'a, 'b> Supertrait<'a, 'b>` + = note: expected existential trait ref `for<'a, 'b> Supertrait<'a, 'b>` + found existential trait ref `for<'a> Supertrait<'a, 'a>` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: aborting due to 2 previous errors diff --git a/tests/ui/traits/trait-upcasting/sub.rs b/tests/ui/traits/trait-upcasting/sub.rs new file mode 100644 index 00000000000..255c4895b7f --- /dev/null +++ b/tests/ui/traits/trait-upcasting/sub.rs @@ -0,0 +1,26 @@ +//@ check-pass +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver + +// Verify that the unsize goal can cast a higher-ranked trait goal to +// a non-higer-ranked instantiation. + +#![feature(unsize)] + +use std::marker::Unsize; + +fn test() +where + T: Unsize, +{ +} + +fn main() { + test:: Fn(&'a ()) -> &'a (), dyn FnOnce(&'static ()) -> &'static ()>(); + + trait Foo: for<'a> Bar<'a> {} + trait Bar<'a> {} + test::>(); + test::>(); +} From 4160a54dc5751d08dd23c7e5b0dc6cbc0889ce32 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Thu, 26 Sep 2024 20:33:26 -0700 Subject: [PATCH 309/683] Use `&raw` in the compiler Like #130865 did for the standard library, we can use `&raw` in the compiler now that stage0 supports it. Also like the other issue, I did not make any doc or test changes at this time. --- compiler/rustc_codegen_llvm/src/back/archive.rs | 2 +- compiler/rustc_codegen_llvm/src/lib.rs | 4 ++-- compiler/rustc_codegen_llvm/src/llvm_util.rs | 2 +- compiler/rustc_data_structures/src/sync.rs | 2 +- compiler/rustc_middle/src/query/on_disk_cache.rs | 4 ++-- compiler/rustc_middle/src/ty/list.rs | 10 +++++----- compiler/stable_mir/src/compiler_interface.rs | 2 +- 7 files changed, 13 insertions(+), 13 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/back/archive.rs b/compiler/rustc_codegen_llvm/src/back/archive.rs index 1b4f6682af0..33a956e552f 100644 --- a/compiler/rustc_codegen_llvm/src/back/archive.rs +++ b/compiler/rustc_codegen_llvm/src/back/archive.rs @@ -123,7 +123,7 @@ fn get_llvm_object_symbols( llvm::LLVMRustGetSymbols( buf.as_ptr(), buf.len(), - std::ptr::addr_of_mut!(*state) as *mut c_void, + (&raw mut *state) as *mut c_void, callback, error_callback, ) diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index bdfc0f626f8..b85d28a2f1f 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -167,7 +167,7 @@ impl WriteBackendMethods for LlvmCodegenBackend { fn print_pass_timings(&self) { unsafe { let mut size = 0; - let cstr = llvm::LLVMRustPrintPassTimings(std::ptr::addr_of_mut!(size)); + let cstr = llvm::LLVMRustPrintPassTimings(&raw mut size); if cstr.is_null() { println!("failed to get pass timings"); } else { @@ -180,7 +180,7 @@ impl WriteBackendMethods for LlvmCodegenBackend { fn print_statistics(&self) { unsafe { let mut size = 0; - let cstr = llvm::LLVMRustPrintStatistics(std::ptr::addr_of_mut!(size)); + let cstr = llvm::LLVMRustPrintStatistics(&raw mut size); if cstr.is_null() { println!("failed to get pass stats"); } else { diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index 71fd7afb148..a2a5499597c 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -478,7 +478,7 @@ pub(crate) fn print(req: &PrintRequest, mut out: &mut String, sess: &Session) { &tm, cpu_cstring.as_ptr(), callback, - std::ptr::addr_of_mut!(out) as *mut c_void, + (&raw mut out) as *mut c_void, ); } } diff --git a/compiler/rustc_data_structures/src/sync.rs b/compiler/rustc_data_structures/src/sync.rs index 6df94bc0e94..a3491dbfec7 100644 --- a/compiler/rustc_data_structures/src/sync.rs +++ b/compiler/rustc_data_structures/src/sync.rs @@ -437,7 +437,7 @@ impl RwLock { #[inline(always)] pub fn leak(&self) -> &T { let guard = self.read(); - let ret = unsafe { &*std::ptr::addr_of!(*guard) }; + let ret = unsafe { &*(&raw const *guard) }; std::mem::forget(guard); ret } diff --git a/compiler/rustc_middle/src/query/on_disk_cache.rs b/compiler/rustc_middle/src/query/on_disk_cache.rs index 06c9ebc87b5..35a16684615 100644 --- a/compiler/rustc_middle/src/query/on_disk_cache.rs +++ b/compiler/rustc_middle/src/query/on_disk_cache.rs @@ -233,7 +233,7 @@ impl<'sess> OnDiskCache<'sess> { for (index, file) in files.iter().enumerate() { let index = SourceFileIndex(index as u32); - let file_ptr: *const SourceFile = std::ptr::addr_of!(**file); + let file_ptr: *const SourceFile = &raw const **file; file_to_file_index.insert(file_ptr, index); let source_file_id = EncodedSourceFileId::new(tcx, file); file_index_to_stable_id.insert(index, source_file_id); @@ -827,7 +827,7 @@ pub struct CacheEncoder<'a, 'tcx> { impl<'a, 'tcx> CacheEncoder<'a, 'tcx> { #[inline] fn source_file_index(&mut self, source_file: Lrc) -> SourceFileIndex { - self.file_to_file_index[&std::ptr::addr_of!(*source_file)] + self.file_to_file_index[&(&raw const *source_file)] } /// Encode something with additional information that allows to do some diff --git a/compiler/rustc_middle/src/ty/list.rs b/compiler/rustc_middle/src/ty/list.rs index ec9ca65dbda..ea07cd3a1b9 100644 --- a/compiler/rustc_middle/src/ty/list.rs +++ b/compiler/rustc_middle/src/ty/list.rs @@ -103,13 +103,13 @@ impl RawList { let mem = arena.dropless.alloc_raw(layout) as *mut RawList; unsafe { // Write the header - ptr::addr_of_mut!((*mem).skel.header).write(header); + (&raw mut (*mem).skel.header).write(header); // Write the length - ptr::addr_of_mut!((*mem).skel.len).write(slice.len()); + (&raw mut (*mem).skel.len).write(slice.len()); // Write the elements - ptr::addr_of_mut!((*mem).skel.data) + (&raw mut (*mem).skel.data) .cast::() .copy_from_nonoverlapping(slice.as_ptr(), slice.len()); @@ -160,7 +160,7 @@ macro_rules! impl_list_empty { // SAFETY: `EMPTY` is sufficiently aligned to be an empty list for all // types with `align_of(T) <= align_of(MaxAlign)`, which we checked above. - unsafe { &*(std::ptr::addr_of!(EMPTY) as *const RawList<$header_ty, T>) } + unsafe { &*((&raw const EMPTY) as *const RawList<$header_ty, T>) } } } }; @@ -238,7 +238,7 @@ impl Deref for RawList { impl AsRef<[T]> for RawList { #[inline(always)] fn as_ref(&self) -> &[T] { - let data_ptr = ptr::addr_of!(self.skel.data).cast::(); + let data_ptr = (&raw const self.skel.data).cast::(); // SAFETY: `data_ptr` has the same provenance as `self` and can therefore // access the `self.skel.len` elements stored at `self.skel.data`. // Note that we specifically don't reborrow `&self.skel.data`, because that diff --git a/compiler/stable_mir/src/compiler_interface.rs b/compiler/stable_mir/src/compiler_interface.rs index 9060a869f7f..4b7707ebccf 100644 --- a/compiler/stable_mir/src/compiler_interface.rs +++ b/compiler/stable_mir/src/compiler_interface.rs @@ -255,7 +255,7 @@ where if TLV.is_set() { Err(Error::from("StableMIR already running")) } else { - let ptr: *const () = std::ptr::addr_of!(context) as _; + let ptr: *const () = (&raw const context) as _; TLV.set(&Cell::new(ptr), || Ok(f())) } } From 8ba2c7d42b37497802499540b8a4cc4b3506fc64 Mon Sep 17 00:00:00 2001 From: naskya Date: Fri, 27 Sep 2024 12:58:16 +0900 Subject: [PATCH 310/683] fix minor typo in triagebot config --- triagebot.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/triagebot.toml b/triagebot.toml index 5d80b9e656e..aba36692828 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -823,7 +823,7 @@ If appropriate, please update `CONFIG_CHANGE_HISTORY` in `src/bootstrap/src/util message = "This PR changes how LLVM is built. Consider updating src/bootstrap/download-ci-llvm-stamp." [mentions."test/crashes"] -message = "This PR changes a file inside `tests/crashes`. If a crash was fixed, please move into the correspondig `ui` subdir and add 'Fixes #' to the pr description to autoclose the issue upon merge." +message = "This PR changes a file inside `tests/crashes`. If a crash was fixed, please move into the corresponding `ui` subdir and add 'Fixes #' to the PR description to autoclose the issue upon merge." [mentions."tests/ui/deriving/deriving-all-codegen.stdout"] message = "Changes to the code generated for builtin derived traits." From 3dd583d5407c1d459c6539a4673e6d329903da66 Mon Sep 17 00:00:00 2001 From: Gurinder Singh Date: Fri, 27 Sep 2024 09:49:15 +0530 Subject: [PATCH 311/683] Fix error span when arg to asm!() is a macro call When the template string passed to asm!() is produced by a macro call like concat!() we were producing wrong error spans. Now in the case of a macro call we just use the entire arg to asm!(), macro call and all, as the error span. --- compiler/rustc_builtin_macros/src/asm.rs | 10 ++++++- tests/crashes/129503.rs | 7 ----- .../ice-bad-err-span-in-template-129503.rs | 26 +++++++++++++++++ ...ice-bad-err-span-in-template-129503.stderr | 28 +++++++++++++++++++ 4 files changed, 63 insertions(+), 8 deletions(-) delete mode 100644 tests/crashes/129503.rs create mode 100644 tests/ui/asm/ice-bad-err-span-in-template-129503.rs create mode 100644 tests/ui/asm/ice-bad-err-span-in-template-129503.stderr diff --git a/compiler/rustc_builtin_macros/src/asm.rs b/compiler/rustc_builtin_macros/src/asm.rs index 0e1ec3b3cad..486d1dada84 100644 --- a/compiler/rustc_builtin_macros/src/asm.rs +++ b/compiler/rustc_builtin_macros/src/asm.rs @@ -507,6 +507,7 @@ fn expand_preparsed_asm( let msg = "asm template must be a string literal"; let template_sp = template_expr.span; + let template_is_mac_call = matches!(template_expr.kind, ast::ExprKind::MacCall(_)); let (template_str, template_style, template_span) = { let ExpandResult::Ready(mac) = expr_to_spanned_string(ecx, template_expr, msg) else { return ExpandResult::Retry(()); @@ -596,7 +597,14 @@ fn expand_preparsed_asm( if !parser.errors.is_empty() { let err = parser.errors.remove(0); - let err_sp = template_span.from_inner(InnerSpan::new(err.span.start, err.span.end)); + let err_sp = if template_is_mac_call { + // If the template is a macro call we can't reliably point to the error's + // span so just use the template's span as the error span (fixes #129503) + template_span + } else { + template_span.from_inner(InnerSpan::new(err.span.start, err.span.end)) + }; + let msg = format!("invalid asm template string: {}", err.description); let mut e = ecx.dcx().struct_span_err(err_sp, msg); e.span_label(err_sp, err.label + " in asm template string"); diff --git a/tests/crashes/129503.rs b/tests/crashes/129503.rs deleted file mode 100644 index c1ed46e5955..00000000000 --- a/tests/crashes/129503.rs +++ /dev/null @@ -1,7 +0,0 @@ -//@ known-bug: rust-lang/rust#129503 - -use std::arch::asm; - -unsafe fn f6() { - asm!(concat!(r#"lJ𐏿Æ�.𐏿�"#, "r} {}")); -} diff --git a/tests/ui/asm/ice-bad-err-span-in-template-129503.rs b/tests/ui/asm/ice-bad-err-span-in-template-129503.rs new file mode 100644 index 00000000000..3b4390f881a --- /dev/null +++ b/tests/ui/asm/ice-bad-err-span-in-template-129503.rs @@ -0,0 +1,26 @@ +// Regression test for ICE #129503 + + +// Tests that we come up with decent error spans +// when the template fed to `asm!()` is itself a +// macro call like `concat!()` and should not ICE + +use std::arch::asm; + +fn main() { + // Should not ICE + asm!(concat!(r#"lJ𐏿Æ�.𐏿�"#, "r} {}")); + //~^ ERROR invalid asm template string: unmatched `}` found + + + // Macro call template: should point to + // everything within `asm!()` as error span + asm!(concat!("abc", "r} {}")); + //~^ ERROR invalid asm template string: unmatched `}` found + + + // Literal template: should point precisely to + // just the `}` as error span + asm!("abc", "r} {}"); + //~^ ERROR invalid asm template string: unmatched `}` found +} diff --git a/tests/ui/asm/ice-bad-err-span-in-template-129503.stderr b/tests/ui/asm/ice-bad-err-span-in-template-129503.stderr new file mode 100644 index 00000000000..ffa9362ed95 --- /dev/null +++ b/tests/ui/asm/ice-bad-err-span-in-template-129503.stderr @@ -0,0 +1,28 @@ +error: invalid asm template string: unmatched `}` found + --> $DIR/ice-bad-err-span-in-template-129503.rs:12:10 + | +LL | asm!(concat!(r#"lJ𐏿Æ�.𐏿�"#, "r} {}")); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unmatched `}` in asm template string + | + = note: if you intended to print `}`, you can escape it using `}}` + = note: this error originates in the macro `concat` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: invalid asm template string: unmatched `}` found + --> $DIR/ice-bad-err-span-in-template-129503.rs:18:10 + | +LL | asm!(concat!("abc", "r} {}")); + | ^^^^^^^^^^^^^^^^^^^^^^^ unmatched `}` in asm template string + | + = note: if you intended to print `}`, you can escape it using `}}` + = note: this error originates in the macro `concat` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: invalid asm template string: unmatched `}` found + --> $DIR/ice-bad-err-span-in-template-129503.rs:24:19 + | +LL | asm!("abc", "r} {}"); + | ^ unmatched `}` in asm template string + | + = note: if you intended to print `}`, you can escape it using `}}` + +error: aborting due to 3 previous errors + From 26c09b6553733a0849c30845909a52a6d210b8da Mon Sep 17 00:00:00 2001 From: klensy Date: Tue, 24 Sep 2024 16:14:49 +0300 Subject: [PATCH 312/683] bump few deps cargo_metadata, thorin-dwp, windows --- Cargo.lock | 95 ++++++----------------- compiler/rustc_codegen_ssa/Cargo.toml | 4 +- compiler/rustc_data_structures/Cargo.toml | 2 +- compiler/rustc_driver_impl/Cargo.toml | 2 +- compiler/rustc_errors/Cargo.toml | 2 +- compiler/rustc_session/Cargo.toml | 2 +- src/tools/compiletest/Cargo.toml | 2 +- src/tools/tidy/Cargo.toml | 2 +- 8 files changed, 33 insertions(+), 78 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0d2ae4ee15f..ebb8d114f2a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -355,7 +355,7 @@ dependencies = [ name = "cargo-miri" version = "0.1.0" dependencies = [ - "cargo_metadata 0.18.1", + "cargo_metadata", "directories", "rustc-build-sysroot", "rustc_tools_util", @@ -373,20 +373,6 @@ dependencies = [ "serde", ] -[[package]] -name = "cargo_metadata" -version = "0.15.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eee4243f1f26fc7a42710e7439c149e2b10b05472f88090acce52632f231a73a" -dependencies = [ - "camino", - "cargo-platform", - "semver", - "serde", - "serde_json", - "thiserror", -] - [[package]] name = "cargo_metadata" version = "0.18.1" @@ -533,7 +519,7 @@ name = "clippy" version = "0.1.83" dependencies = [ "anstream", - "cargo_metadata 0.18.1", + "cargo_metadata", "clippy_config", "clippy_lints", "clippy_utils", @@ -585,7 +571,7 @@ name = "clippy_lints" version = "0.1.83" dependencies = [ "arrayvec", - "cargo_metadata 0.18.1", + "cargo_metadata", "clippy_config", "clippy_utils", "declare_clippy_lint", @@ -718,7 +704,7 @@ dependencies = [ "tracing-subscriber", "unified-diff", "walkdir", - "windows 0.52.0", + "windows", ] [[package]] @@ -966,17 +952,6 @@ dependencies = [ "syn 2.0.77", ] -[[package]] -name = "derive_more" -version = "0.99.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f33878137e4dafd7fa914ad4e259e18a4e8e532b9617a2d0150262bf53abfce" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.77", -] - [[package]] name = "derive_setters" version = "0.1.6" @@ -1393,7 +1368,7 @@ name = "generate-copyright" version = "0.1.0" dependencies = [ "anyhow", - "cargo_metadata 0.18.1", + "cargo_metadata", "rinja", "serde", "serde_json", @@ -1442,6 +1417,12 @@ name = "gimli" version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" + +[[package]] +name = "gimli" +version = "0.30.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2e1d97fbe9722ba9bbd0c97051c2956e726562b61f86a25a4360398a40edfc9" dependencies = [ "fallible-iterator", "indexmap", @@ -2448,12 +2429,7 @@ version = "0.32.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" dependencies = [ - "crc32fast", - "flate2", - "hashbrown", - "indexmap", "memchr", - "ruzstd 0.5.0", ] [[package]] @@ -2467,7 +2443,7 @@ dependencies = [ "hashbrown", "indexmap", "memchr", - "ruzstd 0.7.2", + "ruzstd", "wasmparser 0.216.0", ] @@ -3481,7 +3457,7 @@ dependencies = [ "thorin-dwp", "tracing", "wasm-encoder 0.216.0", - "windows 0.52.0", + "windows", ] [[package]] @@ -3538,7 +3514,7 @@ dependencies = [ "tempfile", "thin-vec", "tracing", - "windows 0.52.0", + "windows", ] [[package]] @@ -3600,7 +3576,7 @@ dependencies = [ "shlex", "time", "tracing", - "windows 0.52.0", + "windows", ] [[package]] @@ -3651,7 +3627,7 @@ dependencies = [ "termcolor", "termize", "tracing", - "windows 0.52.0", + "windows", ] [[package]] @@ -4374,7 +4350,7 @@ dependencies = [ "smallvec", "termize", "tracing", - "windows 0.52.0", + "windows", ] [[package]] @@ -4657,7 +4633,7 @@ dependencies = [ "annotate-snippets 0.9.2", "anyhow", "bytecount", - "cargo_metadata 0.18.1", + "cargo_metadata", "clap", "clap-cargo", "diff", @@ -4698,17 +4674,6 @@ version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" -[[package]] -name = "ruzstd" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58c4eb8a81997cf040a091d1f7e1938aeab6749d3a0dfa73af43cdc32393483d" -dependencies = [ - "byteorder", - "derive_more", - "twox-hash", -] - [[package]] name = "ruzstd" version = "0.7.2" @@ -5087,7 +5052,7 @@ checksum = "355dbe4f8799b304b05e1b0f05fc59b2a18d36645cf169607da45bde2f69a1be" dependencies = [ "core-foundation-sys", "libc", - "windows 0.57.0", + "windows", ] [[package]] @@ -5214,13 +5179,13 @@ dependencies = [ [[package]] name = "thorin-dwp" -version = "0.7.0" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4db52ee8fec06e119b692ef3dd2c4cf621a99204c1b8c47407870ed050305b9b" +checksum = "813ba76597db32dc4f6992fd8bf8f394715b88d352fd97401da67dab6283b4c6" dependencies = [ - "gimli 0.28.1", + "gimli 0.30.0", "hashbrown", - "object 0.32.2", + "object 0.36.4", "tracing", ] @@ -5248,7 +5213,7 @@ name = "tidy" version = "0.1.0" dependencies = [ "build_helper", - "cargo_metadata 0.15.4", + "cargo_metadata", "fluent-syntax", "ignore", "miropt-test-tools", @@ -5516,7 +5481,7 @@ dependencies = [ "anyhow", "bstr", "cargo-platform", - "cargo_metadata 0.18.1", + "cargo_metadata", "color-eyre", "colored", "comma", @@ -5938,16 +5903,6 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" -[[package]] -name = "windows" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be" -dependencies = [ - "windows-core 0.52.0", - "windows-targets 0.52.6", -] - [[package]] name = "windows" version = "0.57.0" diff --git a/compiler/rustc_codegen_ssa/Cargo.toml b/compiler/rustc_codegen_ssa/Cargo.toml index 3ab4cd0a0f5..81590674ec7 100644 --- a/compiler/rustc_codegen_ssa/Cargo.toml +++ b/compiler/rustc_codegen_ssa/Cargo.toml @@ -39,7 +39,7 @@ serde_json = "1.0.59" smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } tempfile = "3.2" thin-vec = "0.2.12" -thorin-dwp = "0.7" +thorin-dwp = "0.8" tracing = "0.1" wasm-encoder = "0.216.0" # tidy-alphabetical-end @@ -55,5 +55,5 @@ default-features = false features = ["read_core", "elf", "macho", "pe", "xcoff", "unaligned", "archive", "write", "wasm"] [target.'cfg(windows)'.dependencies.windows] -version = "0.52.0" +version = "0.57.0" features = ["Win32_Globalization"] diff --git a/compiler/rustc_data_structures/Cargo.toml b/compiler/rustc_data_structures/Cargo.toml index 38c6c8a8d11..d73cf11ee64 100644 --- a/compiler/rustc_data_structures/Cargo.toml +++ b/compiler/rustc_data_structures/Cargo.toml @@ -32,7 +32,7 @@ tracing = "0.1" version = "0.12" [target.'cfg(windows)'.dependencies.windows] -version = "0.52.0" +version = "0.57.0" features = [ "Win32_Foundation", "Win32_Storage_FileSystem", diff --git a/compiler/rustc_driver_impl/Cargo.toml b/compiler/rustc_driver_impl/Cargo.toml index 6d6d3f35a4b..ef577c03218 100644 --- a/compiler/rustc_driver_impl/Cargo.toml +++ b/compiler/rustc_driver_impl/Cargo.toml @@ -59,7 +59,7 @@ libc = "0.2" # tidy-alphabetical-end [target.'cfg(windows)'.dependencies.windows] -version = "0.52.0" +version = "0.57.0" features = [ "Win32_System_Diagnostics_Debug", ] diff --git a/compiler/rustc_errors/Cargo.toml b/compiler/rustc_errors/Cargo.toml index 59cf4e5f210..00eaf4d5a86 100644 --- a/compiler/rustc_errors/Cargo.toml +++ b/compiler/rustc_errors/Cargo.toml @@ -29,7 +29,7 @@ tracing = "0.1" # tidy-alphabetical-end [target.'cfg(windows)'.dependencies.windows] -version = "0.52.0" +version = "0.57.0" features = [ "Win32_Foundation", "Win32_Security", diff --git a/compiler/rustc_session/Cargo.toml b/compiler/rustc_session/Cargo.toml index 721a9275d01..75cc8f18a54 100644 --- a/compiler/rustc_session/Cargo.toml +++ b/compiler/rustc_session/Cargo.toml @@ -30,7 +30,7 @@ libc = "0.2" # tidy-alphabetical-end [target.'cfg(windows)'.dependencies.windows] -version = "0.52.0" +version = "0.57.0" features = [ "Win32_Foundation", "Win32_System_LibraryLoader", diff --git a/src/tools/compiletest/Cargo.toml b/src/tools/compiletest/Cargo.toml index 52beb4c8b3d..b6a89dd49e6 100644 --- a/src/tools/compiletest/Cargo.toml +++ b/src/tools/compiletest/Cargo.toml @@ -33,7 +33,7 @@ libc = "0.2" miow = "0.6" [target.'cfg(windows)'.dependencies.windows] -version = "0.52.0" +version = "0.57.0" features = [ "Win32_Foundation", "Win32_System_Diagnostics_Debug", diff --git a/src/tools/tidy/Cargo.toml b/src/tools/tidy/Cargo.toml index 1acdf9fbc7f..928867be64f 100644 --- a/src/tools/tidy/Cargo.toml +++ b/src/tools/tidy/Cargo.toml @@ -6,7 +6,7 @@ autobins = false [dependencies] build_helper = { path = "../build_helper" } -cargo_metadata = "0.15" +cargo_metadata = "0.18" regex = "1" miropt-test-tools = { path = "../miropt-test-tools" } walkdir = "2" From 62d92e651ecf70d55842c0253ff6e440cd9b640b Mon Sep 17 00:00:00 2001 From: klensy Date: Thu, 26 Sep 2024 11:28:35 +0300 Subject: [PATCH 313/683] bless tidy --- src/tools/tidy/src/deps.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index b880f312715..ca6f9346d25 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -271,7 +271,6 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[ "datafrog", "deranged", "derive-where", - "derive_more", "derive_setters", "digest", "displaydoc", @@ -435,6 +434,9 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[ "winapi-x86_64-pc-windows-gnu", "windows", "windows-core", + "windows-implement", + "windows-interface", + "windows-result", "windows-sys", "windows-targets", "windows_aarch64_gnullvm", From fa3215daad3f845acbbf31222b84f13d6d4d56e3 Mon Sep 17 00:00:00 2001 From: Asger Hautop Drewsen Date: Fri, 27 Sep 2024 10:05:52 +0200 Subject: [PATCH 314/683] Reference UNSPECIFIED instead of INADDR_ANY in join_multicast_v4 --- library/std/src/net/udp.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/std/src/net/udp.rs b/library/std/src/net/udp.rs index d4252cb87ac..8c9e31f9c15 100644 --- a/library/std/src/net/udp.rs +++ b/library/std/src/net/udp.rs @@ -579,8 +579,8 @@ impl UdpSocket { /// This function specifies a new multicast group for this socket to join. /// The address must be a valid multicast address, and `interface` is the /// address of the local interface with which the system should join the - /// multicast group. If it's equal to `INADDR_ANY` then an appropriate - /// interface is chosen by the system. + /// multicast group. If it's equal to [`UNSPECIFIED`](Ipv4Addr::UNSPECIFIED) + /// then an appropriate interface is chosen by the system. #[stable(feature = "net2_mutators", since = "1.9.0")] pub fn join_multicast_v4(&self, multiaddr: &Ipv4Addr, interface: &Ipv4Addr) -> io::Result<()> { self.0.join_multicast_v4(multiaddr, interface) From 0bf928968bf442ba0e4d50e8d716edf2dd43cbbc Mon Sep 17 00:00:00 2001 From: surechen Date: Fri, 27 Sep 2024 16:37:43 +0800 Subject: [PATCH 315/683] Make clashing_extern_declarations considering generic args for ADT field fixes #130851 --- compiler/rustc_lint/src/foreign_modules.rs | 6 +-- .../lint/clashing-extern-fn-issue-130851.rs | 42 +++++++++++++++++++ .../clashing-extern-fn-issue-130851.stderr | 31 ++++++++++++++ 3 files changed, 76 insertions(+), 3 deletions(-) create mode 100644 tests/ui/lint/clashing-extern-fn-issue-130851.rs create mode 100644 tests/ui/lint/clashing-extern-fn-issue-130851.stderr diff --git a/compiler/rustc_lint/src/foreign_modules.rs b/compiler/rustc_lint/src/foreign_modules.rs index 1ead377607f..816882962be 100644 --- a/compiler/rustc_lint/src/foreign_modules.rs +++ b/compiler/rustc_lint/src/foreign_modules.rs @@ -280,7 +280,7 @@ fn structurally_same_type_impl<'tcx>( ensure_sufficient_stack(|| { match (a.kind(), b.kind()) { - (&Adt(a_def, _), &Adt(b_def, _)) => { + (&Adt(a_def, a_gen_args), &Adt(b_def, b_gen_args)) => { // Only `repr(C)` types can be compared structurally. if !(a_def.repr().c() && b_def.repr().c()) { return false; @@ -304,8 +304,8 @@ fn structurally_same_type_impl<'tcx>( seen_types, tcx, param_env, - tcx.type_of(a_did).instantiate_identity(), - tcx.type_of(b_did).instantiate_identity(), + tcx.type_of(a_did).instantiate(tcx, a_gen_args), + tcx.type_of(b_did).instantiate(tcx, b_gen_args), ckind, ) }, diff --git a/tests/ui/lint/clashing-extern-fn-issue-130851.rs b/tests/ui/lint/clashing-extern-fn-issue-130851.rs new file mode 100644 index 00000000000..1b2fdf1d3fc --- /dev/null +++ b/tests/ui/lint/clashing-extern-fn-issue-130851.rs @@ -0,0 +1,42 @@ +//@ build-pass +#![warn(clashing_extern_declarations)] + +#[repr(C)] +pub struct A { + a: [u16; 4], +} +#[repr(C)] +pub struct B { + b: [u32; 4], +} + +pub mod a { + extern "C" { + pub fn foo(_: super::A); + } +} +pub mod b { + extern "C" { + pub fn foo(_: super::B); + //~^ WARN `foo` redeclared with a different signature + } +} + +#[repr(C)] +pub struct G { + g: [T; 4], +} + +pub mod x { + extern "C" { + pub fn bar(_: super::G); + } +} +pub mod y { + extern "C" { + pub fn bar(_: super::G); + //~^ WARN `bar` redeclared with a different signature + } +} + +fn main() {} diff --git a/tests/ui/lint/clashing-extern-fn-issue-130851.stderr b/tests/ui/lint/clashing-extern-fn-issue-130851.stderr new file mode 100644 index 00000000000..c38ec404047 --- /dev/null +++ b/tests/ui/lint/clashing-extern-fn-issue-130851.stderr @@ -0,0 +1,31 @@ +warning: `foo` redeclared with a different signature + --> $DIR/clashing-extern-fn-issue-130851.rs:20:9 + | +LL | pub fn foo(_: super::A); + | ------------------------ `foo` previously declared here +... +LL | pub fn foo(_: super::B); + | ^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration + | + = note: expected `unsafe extern "C" fn(A)` + found `unsafe extern "C" fn(B)` +note: the lint level is defined here + --> $DIR/clashing-extern-fn-issue-130851.rs:2:9 + | +LL | #![warn(clashing_extern_declarations)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: `bar` redeclared with a different signature + --> $DIR/clashing-extern-fn-issue-130851.rs:37:9 + | +LL | pub fn bar(_: super::G); + | ----------------------------- `bar` previously declared here +... +LL | pub fn bar(_: super::G); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration + | + = note: expected `unsafe extern "C" fn(G)` + found `unsafe extern "C" fn(G)` + +warning: 2 warnings emitted + From a2c82f9b2b2272794e3482aae4152d5e7d976647 Mon Sep 17 00:00:00 2001 From: Lukas Bergdoll Date: Thu, 1 Aug 2024 17:11:29 +0200 Subject: [PATCH 316/683] Improve Ord docs - Makes wording more clear and re-structures some sections that can be overwhelming for some not already in the know. - Adds examples of how *not* to implement Ord, inspired by various anti-patterns found in real world code. --- library/core/src/cmp.rs | 358 +++++++++++++++++++++++++++++----------- 1 file changed, 263 insertions(+), 95 deletions(-) diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs index 818a36002e7..ce897b9638d 100644 --- a/library/core/src/cmp.rs +++ b/library/core/src/cmp.rs @@ -275,49 +275,57 @@ pub macro PartialEq($item:item) { /// Trait for comparisons corresponding to [equivalence relations]( /// https://en.wikipedia.org/wiki/Equivalence_relation). /// -/// This means, that in addition to `a == b` and `a != b` being strict inverses, -/// the relation must be (for all `a`, `b` and `c`): +/// The primary difference to [`PartialEq`] is the additional requirement for reflexivity. A type +/// that implements [`PartialEq`] guarantees that for all `a`, `b` and `c`: /// -/// - reflexive: `a == a`; -/// - symmetric: `a == b` implies `b == a` (required by `PartialEq` as well); and -/// - transitive: `a == b` and `b == c` implies `a == c` (required by `PartialEq` as well). +/// - symmetric: `a == b` implies `b == a` +/// - transitive: `a == b` and `b == c` implies `a == c` /// -/// This property cannot be checked by the compiler, and therefore `Eq` implies -/// [`PartialEq`], and has no extra methods. +/// `Eq` which builds on top of [`PartialEq`] also implies: +/// +/// - reflexive: `a == a` +/// +/// This property cannot be checked by the compiler, and therefore `Eq` is a marker trait without +/// methods. /// /// Violating this property is a logic error. The behavior resulting from a logic error is not /// specified, but users of the trait must ensure that such logic errors do *not* result in /// undefined behavior. This means that `unsafe` code **must not** rely on the correctness of these /// methods. /// -/// Implement `Eq` in addition to `PartialEq` if it's guaranteed that -/// `PartialEq::eq(a, a)` always returns `true` (reflexivity), in addition to -/// the symmetric and transitive properties already required by `PartialEq`. +/// Floating point types such as [`f32`] and [`f64`] implement only [`PartialEq`] but *not* `Eq` +/// because `NaN` != `NaN`. /// /// ## Derivable /// -/// This trait can be used with `#[derive]`. When `derive`d, because `Eq` has -/// no extra methods, it is only informing the compiler that this is an -/// equivalence relation rather than a partial equivalence relation. Note that -/// the `derive` strategy requires all fields are `Eq`, which isn't +/// This trait can be used with `#[derive]`. When `derive`d, because `Eq` has no extra methods, it +/// is only informing the compiler that this is an equivalence relation rather than a partial +/// equivalence relation. Note that the `derive` strategy requires all fields are `Eq`, which isn't /// always desired. /// /// ## How can I implement `Eq`? /// -/// If you cannot use the `derive` strategy, specify that your type implements -/// `Eq`, which has no methods: +/// If you cannot use the `derive` strategy, specify that your type implements `Eq`, which has no +/// extra methods: /// /// ``` -/// enum BookFormat { Paperback, Hardback, Ebook } +/// enum BookFormat { +/// Paperback, +/// Hardback, +/// Ebook, +/// } +/// /// struct Book { /// isbn: i32, /// format: BookFormat, /// } +/// /// impl PartialEq for Book { /// fn eq(&self, other: &Self) -> bool { /// self.isbn == other.isbn /// } /// } +/// /// impl Eq for Book {} /// ``` #[doc(alias = "==")] @@ -693,17 +701,14 @@ impl Clone for Reverse { /// Trait for types that form a [total order](https://en.wikipedia.org/wiki/Total_order). /// -/// Implementations must be consistent with the [`PartialOrd`] implementation, and ensure -/// `max`, `min`, and `clamp` are consistent with `cmp`: +/// Implementations must be consistent with the [`PartialOrd`] implementation, and ensure `max`, +/// `min`, and `clamp` are consistent with `cmp`: /// /// - `partial_cmp(a, b) == Some(cmp(a, b))`. /// - `max(a, b) == max_by(a, b, cmp)` (ensured by the default implementation). /// - `min(a, b) == min_by(a, b, cmp)` (ensured by the default implementation). -/// - For `a.clamp(min, max)`, see the [method docs](#method.clamp) -/// (ensured by the default implementation). -/// -/// It's easy to accidentally make `cmp` and `partial_cmp` disagree by -/// deriving some of the traits and manually implementing others. +/// - For `a.clamp(min, max)`, see the [method docs](#method.clamp) (ensured by the default +/// implementation). /// /// Violating these requirements is a logic error. The behavior resulting from a logic error is not /// specified, but users of the trait must ensure that such logic errors do *not* result in @@ -712,15 +717,14 @@ impl Clone for Reverse { /// /// ## Corollaries /// -/// From the above and the requirements of `PartialOrd`, it follows that for -/// all `a`, `b` and `c`: +/// From the above and the requirements of `PartialOrd`, it follows that for all `a`, `b` and `c`: /// /// - exactly one of `a < b`, `a == b` or `a > b` is true; and -/// - `<` is transitive: `a < b` and `b < c` implies `a < c`. The same must hold for both `==` and `>`. +/// - `<` is transitive: `a < b` and `b < c` implies `a < c`. The same must hold for both `==` and +/// `>`. /// -/// Mathematically speaking, the `<` operator defines a strict [weak order]. In -/// cases where `==` conforms to mathematical equality, it also defines a -/// strict [total order]. +/// Mathematically speaking, the `<` operator defines a strict [weak order]. In cases where `==` +/// conforms to mathematical equality, it also defines a strict [total order]. /// /// [weak order]: https://en.wikipedia.org/wiki/Weak_ordering /// [total order]: https://en.wikipedia.org/wiki/Total_order @@ -730,13 +734,12 @@ impl Clone for Reverse { /// This trait can be used with `#[derive]`. /// /// When `derive`d on structs, it will produce a -/// [lexicographic](https://en.wikipedia.org/wiki/Lexicographic_order) ordering -/// based on the top-to-bottom declaration order of the struct's members. +/// [lexicographic](https://en.wikipedia.org/wiki/Lexicographic_order) ordering based on the +/// top-to-bottom declaration order of the struct's members. /// -/// When `derive`d on enums, variants are ordered primarily by their discriminants. -/// Secondarily, they are ordered by their fields. -/// By default, the discriminant is smallest for variants at the top, and -/// largest for variants at the bottom. Here's an example: +/// When `derive`d on enums, variants are ordered primarily by their discriminants. Secondarily, +/// they are ordered by their fields. By default, the discriminant is smallest for variants at the +/// top, and largest for variants at the bottom. Here's an example: /// /// ``` /// #[derive(PartialEq, Eq, PartialOrd, Ord)] @@ -748,8 +751,7 @@ impl Clone for Reverse { /// assert!(E::Top < E::Bottom); /// ``` /// -/// However, manually setting the discriminants can override this default -/// behavior: +/// However, manually setting the discriminants can override this default behavior: /// /// ``` /// #[derive(PartialEq, Eq, PartialOrd, Ord)] @@ -765,51 +767,187 @@ impl Clone for Reverse { /// /// Lexicographical comparison is an operation with the following properties: /// - Two sequences are compared element by element. -/// - The first mismatching element defines which sequence is lexicographically less or greater than the other. -/// - If one sequence is a prefix of another, the shorter sequence is lexicographically less than the other. -/// - If two sequences have equivalent elements and are of the same length, then the sequences are lexicographically equal. +/// - The first mismatching element defines which sequence is lexicographically less or greater +/// than the other. +/// - If one sequence is a prefix of another, the shorter sequence is lexicographically less than +/// the other. +/// - If two sequences have equivalent elements and are of the same length, then the sequences are +/// lexicographically equal. /// - An empty sequence is lexicographically less than any non-empty sequence. /// - Two empty sequences are lexicographically equal. /// /// ## How can I implement `Ord`? /// -/// `Ord` requires that the type also be [`PartialOrd`] and [`Eq`] (which requires [`PartialEq`]). +/// `Ord` requires that the type also be [`PartialOrd`] and [`Eq`] which itself requires +/// [`PartialEq`]. /// -/// Then you must define an implementation for [`cmp`]. You may find it useful to use -/// [`cmp`] on your type's fields. +/// Non `derive`d implementations of `Ord` require that the [`cmp`] function is implemented +/// manually. It's a logic error to have [`PartialOrd`] and `Ord` disagree, so it's best practice to +/// have the logic in `Ord` and implement [`PartialOrd`] as `Some(self.cmp(other))`. /// -/// Here's an example where you want to sort people by height only, disregarding `id` -/// and `name`: +/// Conceptually [`PartialOrd`] and `Ord` form a similar relationship to [`PartialEq`] and [`Eq`]. +/// [`PartialEq`] implements and implies an equality relationship between types, and [`Eq`] implies +/// an additional property on top of the properties implied by [`PartialOrd`], namely reflexivity. +/// In a similar fashion `Ord` builds on top of [`PartialOrd`] and implies further properties, such +/// as totality, which means all values must be comparable. +/// +/// Because of different signatures, `Ord` cannot be a simple marker trait like `Eq`. So it can't be +/// `derive`d automatically when `PartialOrd` is implemented. The recommended best practice for a +/// type that manually implements `Ord` is to implement the equality comparison logic in `PartialEq` +/// and implement the ordering comparison logic in `Ord`. From there one should implement +/// `PartialOrd` as `Some(self.cmp(other))`. +/// +/// Here's an example where you want to define the `Character` comparison by `health` and +/// `experience` only, disregarding the field `mana`: /// /// ``` /// use std::cmp::Ordering; /// -/// #[derive(Eq)] -/// struct Person { -/// id: u32, -/// name: String, -/// height: u32, +/// struct Character { +/// health: u32, +/// experience: u32, +/// mana: f32, /// } /// -/// impl Ord for Person { -/// fn cmp(&self, other: &Self) -> Ordering { -/// self.height.cmp(&other.height) +/// impl Ord for Character { +/// fn cmp(&self, other: &Self) -> std::cmp::Ordering { +/// self.health +/// .cmp(&other.health) +/// .then(self.experience.cmp(&other.experience)) /// } /// } /// -/// impl PartialOrd for Person { +/// impl PartialOrd for Character { /// fn partial_cmp(&self, other: &Self) -> Option { /// Some(self.cmp(other)) /// } /// } /// -/// impl PartialEq for Person { +/// impl PartialEq for Character { /// fn eq(&self, other: &Self) -> bool { -/// self.height == other.height +/// self.health == other.health && self.experience == other.experience /// } /// } +/// +/// impl Eq for Character {} /// ``` /// +/// If all you need is to `slice::sort` a type by a field value, it can be simpler to use +/// `slice::sort_by_key`. +/// +/// ## Examples of incorrect `Ord` implementations +/// +/// ``` +/// use std::cmp::Ordering; +/// +/// #[derive(Debug)] +/// struct Character { +/// health: f32, +/// } +/// +/// impl Ord for Character { +/// fn cmp(&self, other: &Self) -> std::cmp::Ordering { +/// if self.health < other.health { +/// Ordering::Less +/// } else if self.health > other.health { +/// Ordering::Greater +/// } else { +/// Ordering::Equal +/// } +/// } +/// } +/// +/// impl PartialOrd for Character { +/// fn partial_cmp(&self, other: &Self) -> Option { +/// Some(self.cmp(other)) +/// } +/// } +/// +/// impl PartialEq for Character { +/// fn eq(&self, other: &Self) -> bool { +/// self.health == other.health +/// } +/// } +/// +/// impl Eq for Character {} +/// +/// let a = Character { health: 4.5 }; +/// let b = Character { health: f32::NAN }; +/// +/// // Mistake: floating-point values do not form a total order and using the built-in comparison +/// // operands to implement `Ord` irregardless of that reality does not change it. Use +/// // `f32::total_cmp` if you need a total order for floating-point values. +/// +/// // Reflexivity requirement of `Ord` is not given. +/// assert!(a == a); +/// assert!(b != b); +/// +/// // Antisymmetry requirement of `Ord` is not given. Only one of a < c and c < a is allowed to be +/// // true, not both or neither. +/// assert_eq!((a < b) as u8 + (b < a) as u8, 0); +/// ``` +/// +/// ``` +/// use std::cmp::Ordering; +/// +/// #[derive(Eq, Debug)] +/// struct Character { +/// health: u32, +/// experience: u32, +/// } +/// +/// impl PartialOrd for Character { +/// fn partial_cmp(&self, other: &Self) -> Option { +/// Some(self.cmp(other)) +/// } +/// } +/// +/// impl Ord for Character { +/// fn cmp(&self, other: &Self) -> std::cmp::Ordering { +/// if self.health < 50 { +/// self.health.cmp(&other.health) +/// } else { +/// self.experience.cmp(&other.experience) +/// } +/// } +/// } +/// +/// // For performance reasons implementing `PartialEq` this way is not the idiomatic way, but it +/// // ensures consistent behavior between `PartialEq`, `PartialOrd` and `Ord` in this example. +/// impl PartialEq for Character { +/// fn eq(&self, other: &Self) -> bool { +/// self.cmp(other) == Ordering::Equal +/// } +/// } +/// +/// let a = Character { +/// health: 3, +/// experience: 5, +/// }; +/// let b = Character { +/// health: 10, +/// experience: 77, +/// }; +/// let c = Character { +/// health: 143, +/// experience: 2, +/// }; +/// +/// // Mistake: The implementation of `Ord` compares different fields depending on the value of +/// // `self.health`, the resulting order is not total. +/// +/// // Transitivity requirement of `Ord` is not given. If a is smaller than b and b is smaller than +/// // c, by transitive property a must also be smaller than c. +/// assert!(a < b && b < c && c < a); +/// +/// // Antisymmetry requirement of `Ord` is not given. Only one of a < c and c < a is allowed to be +/// // true, not both or neither. +/// assert_eq!((a < c) as u8 + (b < c) as u8, 2); +/// ``` +/// +/// The documentation of [`PartialOrd`] contains further examples, for example it's wrong for +/// [`PartialOrd`] and [`PartialEq`] to disagree. +/// /// [`cmp`]: Ord::cmp #[doc(alias = "<")] #[doc(alias = ">")] @@ -924,8 +1062,12 @@ pub macro Ord($item:item) { /// Trait for types that form a [partial order](https://en.wikipedia.org/wiki/Partial_order). /// -/// The `lt`, `le`, `gt`, and `ge` methods of this trait can be called using -/// the `<`, `<=`, `>`, and `>=` operators, respectively. +/// The `lt`, `le`, `gt`, and `ge` methods of this trait can be called using the `<`, `<=`, `>`, and +/// `>=` operators, respectively. +/// +/// This trait should **only** contain the comparison logic for a type **if one plans on only +/// implementing `PartialOrd` but not [`Ord`]**. Otherwise the comparison logic should be in [`Ord`] +/// and this trait implemented with `Some(self.cmp(other))`. /// /// The methods of this trait must be consistent with each other and with those of [`PartialEq`]. /// The following conditions must hold: @@ -933,30 +1075,28 @@ pub macro Ord($item:item) { /// 1. `a == b` if and only if `partial_cmp(a, b) == Some(Equal)`. /// 2. `a < b` if and only if `partial_cmp(a, b) == Some(Less)` /// 3. `a > b` if and only if `partial_cmp(a, b) == Some(Greater)` -/// 4. `a <= b` if and only if `a < b || a == b` -/// 5. `a >= b` if and only if `a > b || a == b` +/// 4. `a <= b` if and only if `a < b || a == b` 5. `a >= b` if and only if `a > b || a == b` /// 6. `a != b` if and only if `!(a == b)`. /// -/// Conditions 2–5 above are ensured by the default implementation. -/// Condition 6 is already ensured by [`PartialEq`]. +/// Conditions 2–5 above are ensured by the default implementation. Condition 6 is already ensured +/// by [`PartialEq`]. /// /// If [`Ord`] is also implemented for `Self` and `Rhs`, it must also be consistent with -/// `partial_cmp` (see the documentation of that trait for the exact requirements). It's -/// easy to accidentally make them disagree by deriving some of the traits and manually -/// implementing others. +/// `partial_cmp` (see the documentation of that trait for the exact requirements). It's easy to +/// accidentally make them disagree by deriving some of the traits and manually implementing others. /// -/// The comparison relations must satisfy the following conditions -/// (for all `a`, `b`, `c` of type `A`, `B`, `C`): +/// The comparison relations must satisfy the following conditions (for all `a`, `b`, `c` of type +/// `A`, `B`, `C`): /// -/// - **Transitivity**: if `A: PartialOrd` and `B: PartialOrd` and `A: -/// PartialOrd`, then `a < b` and `b < c` implies `a < c`. The same must hold for both `==` and `>`. -/// This must also work for longer chains, such as when `A: PartialOrd`, `B: PartialOrd`, -/// `C: PartialOrd`, and `A: PartialOrd` all exist. -/// - **Duality**: if `A: PartialOrd` and `B: PartialOrd`, then `a < b` if and only if `b > a`. +/// - **Transitivity**: if `A: PartialOrd` and `B: PartialOrd` and `A: PartialOrd`, then `a +/// < b` and `b < c` implies `a < c`. The same must hold for both `==` and `>`. This must also +/// work for longer chains, such as when `A: PartialOrd`, `B: PartialOrd`, `C: +/// PartialOrd`, and `A: PartialOrd` all exist. +/// - **Duality**: if `A: PartialOrd` and `B: PartialOrd`, then `a < b` if and only if `b > +/// a`. /// -/// Note that the `B: PartialOrd` (dual) and `A: PartialOrd` -/// (transitive) impls are not forced to exist, but these requirements apply -/// whenever they do exist. +/// Note that the `B: PartialOrd` (dual) and `A: PartialOrd` (transitive) impls are not forced +/// to exist, but these requirements apply whenever they do exist. /// /// Violating these requirements is a logic error. The behavior resulting from a logic error is not /// specified, but users of the trait must ensure that such logic errors do *not* result in @@ -992,12 +1132,10 @@ pub macro Ord($item:item) { /// /// ## Strict and non-strict partial orders /// -/// The `<` and `>` operators behave according to a *strict* partial order. -/// However, `<=` and `>=` do **not** behave according to a *non-strict* -/// partial order. -/// That is because mathematically, a non-strict partial order would require -/// reflexivity, i.e. `a <= a` would need to be true for every `a`. This isn't -/// always the case for types that implement `PartialOrd`, for example: +/// The `<` and `>` operators behave according to a *strict* partial order. However, `<=` and `>=` +/// do **not** behave according to a *non-strict* partial order. That is because mathematically, a +/// non-strict partial order would require reflexivity, i.e. `a <= a` would need to be true for +/// every `a`. This isn't always the case for types that implement `PartialOrd`, for example: /// /// ``` /// let a = f64::sqrt(-1.0); @@ -1009,13 +1147,12 @@ pub macro Ord($item:item) { /// This trait can be used with `#[derive]`. /// /// When `derive`d on structs, it will produce a -/// [lexicographic](https://en.wikipedia.org/wiki/Lexicographic_order) ordering -/// based on the top-to-bottom declaration order of the struct's members. +/// [lexicographic](https://en.wikipedia.org/wiki/Lexicographic_order) ordering based on the +/// top-to-bottom declaration order of the struct's members. /// -/// When `derive`d on enums, variants are primarily ordered by their discriminants. -/// Secondarily, they are ordered by their fields. -/// By default, the discriminant is smallest for variants at the top, and -/// largest for variants at the bottom. Here's an example: +/// When `derive`d on enums, variants are primarily ordered by their discriminants. Secondarily, +/// they are ordered by their fields. By default, the discriminant is smallest for variants at the +/// top, and largest for variants at the bottom. Here's an example: /// /// ``` /// #[derive(PartialEq, PartialOrd)] @@ -1027,8 +1164,7 @@ pub macro Ord($item:item) { /// assert!(E::Top < E::Bottom); /// ``` /// -/// However, manually setting the discriminants can override this default -/// behavior: +/// However, manually setting the discriminants can override this default behavior: /// /// ``` /// #[derive(PartialEq, PartialOrd)] @@ -1046,8 +1182,8 @@ pub macro Ord($item:item) { /// generated from default implementations. /// /// However it remains possible to implement the others separately for types which do not have a -/// total order. For example, for floating point numbers, `NaN < 0 == false` and `NaN >= 0 == -/// false` (cf. IEEE 754-2008 section 5.11). +/// total order. For example, for floating point numbers, `NaN < 0 == false` and `NaN >= 0 == false` +/// (cf. IEEE 754-2008 section 5.11). /// /// `PartialOrd` requires your type to be [`PartialEq`]. /// @@ -1082,9 +1218,9 @@ pub macro Ord($item:item) { /// } /// ``` /// -/// You may also find it useful to use [`partial_cmp`] on your type's fields. Here -/// is an example of `Person` types who have a floating-point `height` field that -/// is the only field to be used for sorting: +/// You may also find it useful to use [`partial_cmp`] on your type's fields. Here is an example of +/// `Person` types who have a floating-point `height` field that is the only field to be used for +/// sorting: /// /// ``` /// use std::cmp::Ordering; @@ -1108,6 +1244,38 @@ pub macro Ord($item:item) { /// } /// ``` /// +/// ## Examples of incorrect `PartialOrd` implementations +/// +/// ``` +/// use std::cmp::Ordering; +/// +/// #[derive(PartialEq, Debug)] +/// struct Character { +/// health: u32, +/// experience: u32, +/// } +/// +/// impl PartialOrd for Character { +/// fn partial_cmp(&self, other: &Self) -> Option { +/// Some(self.health.cmp(&other.health)) +/// } +/// } +/// +/// let a = Character { +/// health: 10, +/// experience: 5, +/// }; +/// let b = Character { +/// health: 10, +/// experience: 77, +/// }; +/// +/// // Mistake: `PartialEq` and `PartialOrd` disagree with each other. +/// +/// assert_eq!(a.partial_cmp(&b).unwrap(), Ordering::Equal); // a == b according to `PartialOrd`. +/// assert_ne!(a, b); // a != b according to `PartialEq`. +/// ``` +/// /// # Examples /// /// ``` From d9449315ad5461a8cb9b2ca0b53ac6712d04d1b4 Mon Sep 17 00:00:00 2001 From: Lukas Bergdoll Date: Mon, 12 Aug 2024 14:46:11 +0200 Subject: [PATCH 317/683] Fix mistake in example --- library/core/src/cmp.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs index ce897b9638d..1015542cc33 100644 --- a/library/core/src/cmp.rs +++ b/library/core/src/cmp.rs @@ -942,7 +942,7 @@ impl Clone for Reverse { /// /// // Antisymmetry requirement of `Ord` is not given. Only one of a < c and c < a is allowed to be /// // true, not both or neither. -/// assert_eq!((a < c) as u8 + (b < c) as u8, 2); +/// assert_eq!((a < c) as u8 + (c < a) as u8, 2); /// ``` /// /// The documentation of [`PartialOrd`] contains further examples, for example it's wrong for From 5559ebe0949f63f52f906f841dbb088892e4c872 Mon Sep 17 00:00:00 2001 From: Lukas Bergdoll Date: Mon, 26 Aug 2024 11:59:00 +0200 Subject: [PATCH 318/683] Apply round 1 of review comments --- library/core/src/cmp.rs | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs index 1015542cc33..185b0fb9de7 100644 --- a/library/core/src/cmp.rs +++ b/library/core/src/cmp.rs @@ -281,12 +281,11 @@ pub macro PartialEq($item:item) { /// - symmetric: `a == b` implies `b == a` /// - transitive: `a == b` and `b == c` implies `a == c` /// -/// `Eq` which builds on top of [`PartialEq`] also implies: +/// `Eq`, which builds on top of [`PartialEq`] also implies: /// /// - reflexive: `a == a` /// -/// This property cannot be checked by the compiler, and therefore `Eq` is a marker trait without -/// methods. +/// This property cannot be checked by the compiler, and therefore `Eq` is a trait without methods. /// /// Violating this property is a logic error. The behavior resulting from a logic error is not /// specified, but users of the trait must ensure that such logic errors do *not* result in @@ -778,18 +777,17 @@ impl Clone for Reverse { /// /// ## How can I implement `Ord`? /// -/// `Ord` requires that the type also be [`PartialOrd`] and [`Eq`] which itself requires -/// [`PartialEq`]. +/// `Ord` requires that the type also be [`PartialOrd`], [`PartialEq`] and [`Eq`]. /// -/// Non `derive`d implementations of `Ord` require that the [`cmp`] function is implemented -/// manually. It's a logic error to have [`PartialOrd`] and `Ord` disagree, so it's best practice to -/// have the logic in `Ord` and implement [`PartialOrd`] as `Some(self.cmp(other))`. +/// If you manually implement `Ord`, you should also implement [`PartialOrd`]. It is a logic error +/// to have [`PartialOrd`] and `Ord` disagree, so it is best to have the logic in `Ord` and +/// implement [`PartialOrd`] as `Some(self.cmp(other))`. /// /// Conceptually [`PartialOrd`] and `Ord` form a similar relationship to [`PartialEq`] and [`Eq`]. -/// [`PartialEq`] implements and implies an equality relationship between types, and [`Eq`] implies -/// an additional property on top of the properties implied by [`PartialOrd`], namely reflexivity. -/// In a similar fashion `Ord` builds on top of [`PartialOrd`] and implies further properties, such -/// as totality, which means all values must be comparable. +/// [`PartialEq`] defines an equality relationship between types, and [`Eq`] defines an additional +/// property on top of the properties implied by [`PartialEq`], namely reflexivity. In a similar +/// fashion `Ord` builds on top of [`PartialOrd`] and adds further properties, such as totality, +/// which means all values must be comparable. /// /// Because of different signatures, `Ord` cannot be a simple marker trait like `Eq`. So it can't be /// `derive`d automatically when `PartialOrd` is implemented. The recommended best practice for a @@ -811,9 +809,9 @@ impl Clone for Reverse { /// /// impl Ord for Character { /// fn cmp(&self, other: &Self) -> std::cmp::Ordering { -/// self.health -/// .cmp(&other.health) -/// .then(self.experience.cmp(&other.experience)) +/// self.experience +/// .cmp(&other.experience) +/// .then(self.health.cmp(&other.health)) /// } /// } /// @@ -1075,7 +1073,8 @@ pub macro Ord($item:item) { /// 1. `a == b` if and only if `partial_cmp(a, b) == Some(Equal)`. /// 2. `a < b` if and only if `partial_cmp(a, b) == Some(Less)` /// 3. `a > b` if and only if `partial_cmp(a, b) == Some(Greater)` -/// 4. `a <= b` if and only if `a < b || a == b` 5. `a >= b` if and only if `a > b || a == b` +/// 4. `a <= b` if and only if `a < b || a == b` +/// 5. `a >= b` if and only if `a > b || a == b` /// 6. `a != b` if and only if `!(a == b)`. /// /// Conditions 2–5 above are ensured by the default implementation. Condition 6 is already ensured From d17ba5d5c8c16f374a923c384263f2c7bf19496d Mon Sep 17 00:00:00 2001 From: Lukas Bergdoll Date: Fri, 27 Sep 2024 10:26:02 +0200 Subject: [PATCH 319/683] Apply review feedback --- library/core/src/cmp.rs | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs index 185b0fb9de7..7a3f40fdf1e 100644 --- a/library/core/src/cmp.rs +++ b/library/core/src/cmp.rs @@ -278,7 +278,7 @@ pub macro PartialEq($item:item) { /// The primary difference to [`PartialEq`] is the additional requirement for reflexivity. A type /// that implements [`PartialEq`] guarantees that for all `a`, `b` and `c`: /// -/// - symmetric: `a == b` implies `b == a` +/// - symmetric: `a == b` implies `b == a` and `a != b` implies `!(a == b)` /// - transitive: `a == b` and `b == c` implies `a == c` /// /// `Eq`, which builds on top of [`PartialEq`] also implies: @@ -332,11 +332,9 @@ pub macro PartialEq($item:item) { #[stable(feature = "rust1", since = "1.0.0")] #[rustc_diagnostic_item = "Eq"] pub trait Eq: PartialEq { - // this method is used solely by #[derive(Eq)] to assert - // that every component of a type implements `Eq` - // itself. The current deriving infrastructure means doing this - // assertion without using a method on this trait is nearly - // impossible. + // this method is used solely by `impl Eq or #[derive(Eq)]` to assert that every component of a + // type implements `Eq` itself. The current deriving infrastructure means doing this assertion + // without using a method on this trait is nearly impossible. // // This should never be implemented by hand. #[doc(hidden)] @@ -789,11 +787,13 @@ impl Clone for Reverse { /// fashion `Ord` builds on top of [`PartialOrd`] and adds further properties, such as totality, /// which means all values must be comparable. /// -/// Because of different signatures, `Ord` cannot be a simple marker trait like `Eq`. So it can't be -/// `derive`d automatically when `PartialOrd` is implemented. The recommended best practice for a -/// type that manually implements `Ord` is to implement the equality comparison logic in `PartialEq` -/// and implement the ordering comparison logic in `Ord`. From there one should implement -/// `PartialOrd` as `Some(self.cmp(other))`. +/// `Ord` requires that the type also be PartialOrd, PartialEq, and Eq. +/// +/// Because `Ord` implies a stronger ordering relationship than [`PartialOrd`], and both `Ord` and +/// [`PartialOrd`] must agree, you must choose how to implement `Ord` **first**. You can choose to +/// derive it, or implement it manually. If you derive it, you should derive all four traits. If you +/// implement it manually, you should manually implement all four traits, based on the +/// implementation of `Ord`. /// /// Here's an example where you want to define the `Character` comparison by `health` and /// `experience` only, disregarding the field `mana`: @@ -888,7 +888,7 @@ impl Clone for Reverse { /// ``` /// use std::cmp::Ordering; /// -/// #[derive(Eq, Debug)] +/// #[derive(Debug)] /// struct Character { /// health: u32, /// experience: u32, @@ -918,6 +918,8 @@ impl Clone for Reverse { /// } /// } /// +/// impl Eq for Character {} +/// /// let a = Character { /// health: 3, /// experience: 5, @@ -1191,7 +1193,6 @@ pub macro Ord($item:item) { /// ``` /// use std::cmp::Ordering; /// -/// #[derive(Eq)] /// struct Person { /// id: u32, /// name: String, @@ -1215,6 +1216,8 @@ pub macro Ord($item:item) { /// self.height == other.height /// } /// } +/// +/// impl Eq for Person {} /// ``` /// /// You may also find it useful to use [`partial_cmp`] on your type's fields. Here is an example of From c1c0bd7a251865e82b1e8d0292451f78f19f22a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Thu, 26 Sep 2024 13:44:06 +0200 Subject: [PATCH 320/683] Upload average CPU consumption of CI jobs to DataDog --- .github/workflows/ci.yml | 10 ++++ src/ci/scripts/upload-artifacts.sh | 2 +- src/ci/scripts/upload-build-metrics.py | 81 ++++++++++++++++++++++++++ 3 files changed, 92 insertions(+), 1 deletion(-) create mode 100644 src/ci/scripts/upload-build-metrics.py diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8032154a736..b6dc27f1234 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -212,6 +212,16 @@ jobs: # erroring about invalid credentials instead. if: github.event_name == 'push' || env.DEPLOY == '1' || env.DEPLOY_ALT == '1' + - name: upload job metrics to DataDog + if: needs.calculate_matrix.outputs.run_type != 'pr' + env: + DATADOG_SITE: datadoghq.com + DATADOG_API_KEY: ${{ secrets.DATADOG_API_KEY }} + DD_GITHUB_JOB_NAME: ${{ matrix.name }} + run: | + npm install -g @datadog/datadog-ci@^2.x.x + python3 src/ci/scripts/upload-build-metrics.py build/cpu-usage.csv + # This job isused to tell bors the final status of the build, as there is no practical way to detect # when a workflow is successful listening to webhooks only in our current bors implementation (homu). outcome: diff --git a/src/ci/scripts/upload-artifacts.sh b/src/ci/scripts/upload-artifacts.sh index 61c187fa77c..129ede636f3 100755 --- a/src/ci/scripts/upload-artifacts.sh +++ b/src/ci/scripts/upload-artifacts.sh @@ -23,7 +23,7 @@ if [[ "${DEPLOY-0}" -eq "1" ]] || [[ "${DEPLOY_ALT-0}" -eq "1" ]]; then fi # CPU usage statistics. -mv build/cpu-usage.csv "${upload_dir}/cpu-${CI_JOB_NAME}.csv" +cp build/cpu-usage.csv "${upload_dir}/cpu-${CI_JOB_NAME}.csv" # Build metrics generated by x.py. mv "${build_dir}/metrics.json" "${upload_dir}/metrics-${CI_JOB_NAME}.json" diff --git a/src/ci/scripts/upload-build-metrics.py b/src/ci/scripts/upload-build-metrics.py new file mode 100644 index 00000000000..a95e0949d70 --- /dev/null +++ b/src/ci/scripts/upload-build-metrics.py @@ -0,0 +1,81 @@ +""" +This script postprocesses data gathered during a CI run, computes certain metrics +from them, and uploads these metrics to DataDog. + +This script is expected to be executed from within a GitHub Actions job. + +It expects the following environment variables: +- DATADOG_SITE: path to the DataDog API endpoint +- DATADOG_API_KEY: DataDog API token +- DD_GITHUB_JOB_NAME: Name of the current GitHub Actions job + +And it also expects the presence of a binary called `datadog-ci` to be in PATH. +It can be installed with `npm install -g @datadog/datadog-ci`. + +Usage: +```bash +$ python3 upload-build-metrics.py +``` + +`path-to-CPU-usage-CSV` is a path to a CSV generated by the `src/ci/cpu-usage-over-time.py` script. +""" +import argparse +import csv +import os +import subprocess +import sys +from pathlib import Path +from typing import List + + +def load_cpu_usage(path: Path) -> List[float]: + usage = [] + with open(path) as f: + reader = csv.reader(f, delimiter=',') + for row in reader: + # The log might contain incomplete rows or some Python exception + if len(row) == 2: + try: + idle = float(row[1]) + usage.append(100.0 - idle) + except ValueError: + pass + return usage + + +def upload_datadog_measure(name: str, value: float): + """ + Uploads a single numeric metric for the current GitHub Actions job to DataDog. + """ + print(f"Metric {name}: {value:.4f}") + + datadog_cmd = "datadog-ci" + if os.getenv("GITHUB_ACTIONS") is not None and sys.platform.lower().startswith("win"): + # Due to weird interaction of MSYS2 and Python, we need to use an absolute path, + # and also specify the ".cmd" at the end. See https://github.com/rust-lang/rust/pull/125771. + datadog_cmd = "C:\\npm\\prefix\\datadog-ci.cmd" + + subprocess.run([ + datadog_cmd, + "measure", + "--level", "job", + "--measures", f"{name}:{value}" + ], + check=False + ) + + +if __name__ == "__main__": + parser = argparse.ArgumentParser( + prog="DataDog metric uploader" + ) + parser.add_argument("cpu-usage-history-csv") + args = parser.parse_args() + + build_usage_csv = vars(args)["cpu-usage-history-csv"] + usage_timeseries = load_cpu_usage(Path(build_usage_csv)) + if len(usage_timeseries) > 0: + avg_cpu_usage = sum(usage_timeseries) / len(usage_timeseries) + else: + avg_cpu_usage = 0 + upload_datadog_measure("avg-cpu-usage", avg_cpu_usage) From 892d192b157a4289599a1fe3e8e02589fe8dbf42 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Fri, 27 Sep 2024 09:41:56 +0000 Subject: [PATCH 321/683] Update Cargo.lock --- library/Cargo.lock | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/library/Cargo.lock b/library/Cargo.lock index 2343b2baf83..913b75d5d3e 100644 --- a/library/Cargo.lock +++ b/library/Cargo.lock @@ -42,9 +42,12 @@ checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" [[package]] name = "cc" -version = "1.0.99" +version = "1.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96c51067fd44124faa7f870b4b1c969379ad32b2ba805aa959430ceaa384f695" +checksum = "9540e661f81799159abee814118cc139a2004b3a3aa3ea37724a1b66530b90e0" +dependencies = [ + "shlex", +] [[package]] name = "cfg-if" @@ -312,6 +315,12 @@ dependencies = [ "std", ] +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + [[package]] name = "std" version = "0.0.0" From 6c852d3ec40f72f9f84ffa36578410b1068ffa07 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Fri, 27 Sep 2024 10:06:48 +0000 Subject: [PATCH 322/683] Allow shlex stdlib dependency --- src/tools/tidy/src/deps.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index b880f312715..698fb42180f 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -481,6 +481,7 @@ const PERMITTED_STDLIB_DEPENDENCIES: &[&str] = &[ "rand_core", "rand_xorshift", "rustc-demangle", + "shlex", "unicode-width", "unwinding", "wasi", From 8075ddb98e594f75df45c0103838c61b4d6d747d Mon Sep 17 00:00:00 2001 From: Urgau Date: Wed, 21 Aug 2024 18:56:03 +0200 Subject: [PATCH 323/683] Implement RFC3137 trim-paths sysroot changes --- compiler/rustc_metadata/src/rmeta/decoder.rs | 99 ++++++++++--------- src/tools/compiletest/src/header.rs | 10 ++ src/tools/compiletest/src/runtest.rs | 12 ++- tests/ui/errors/remap-path-prefix-sysroot.rs | 23 +++++ ...emap-path-prefix-sysroot.with-remap.stderr | 17 ++++ ...p-path-prefix-sysroot.without-remap.stderr | 17 ++++ 6 files changed, 129 insertions(+), 49 deletions(-) create mode 100644 tests/ui/errors/remap-path-prefix-sysroot.rs create mode 100644 tests/ui/errors/remap-path-prefix-sysroot.with-remap.stderr create mode 100644 tests/ui/errors/remap-path-prefix-sysroot.without-remap.stderr diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index 4425c93211a..2157324d5cc 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -1622,56 +1622,63 @@ impl<'a> CrateMetadataRef<'a> { ); for virtual_dir in virtual_rust_source_base_dir.iter().flatten() { - if let Some(real_dir) = &sess.opts.real_rust_source_base_dir { - if let rustc_span::FileName::Real(old_name) = name { - if let rustc_span::RealFileName::Remapped { local_path: _, virtual_name } = - old_name - { - if let Ok(rest) = virtual_name.strip_prefix(virtual_dir) { - let virtual_name = virtual_name.clone(); + if let Some(real_dir) = &sess.opts.real_rust_source_base_dir + && let rustc_span::FileName::Real(old_name) = name + && let rustc_span::RealFileName::Remapped { local_path: _, virtual_name } = + old_name + && let Ok(rest) = virtual_name.strip_prefix(virtual_dir) + { + // The std library crates are in + // `$sysroot/lib/rustlib/src/rust/library`, whereas other crates + // may be in `$sysroot/lib/rustlib/src/rust/` directly. So we + // detect crates from the std libs and handle them specially. + const STD_LIBS: &[&str] = &[ + "core", + "alloc", + "std", + "test", + "term", + "unwind", + "proc_macro", + "panic_abort", + "panic_unwind", + "profiler_builtins", + "rtstartup", + "rustc-std-workspace-core", + "rustc-std-workspace-alloc", + "rustc-std-workspace-std", + "backtrace", + ]; + let is_std_lib = STD_LIBS.iter().any(|l| rest.starts_with(l)); - // The std library crates are in - // `$sysroot/lib/rustlib/src/rust/library`, whereas other crates - // may be in `$sysroot/lib/rustlib/src/rust/` directly. So we - // detect crates from the std libs and handle them specially. - const STD_LIBS: &[&str] = &[ - "core", - "alloc", - "std", - "test", - "term", - "unwind", - "proc_macro", - "panic_abort", - "panic_unwind", - "profiler_builtins", - "rtstartup", - "rustc-std-workspace-core", - "rustc-std-workspace-alloc", - "rustc-std-workspace-std", - "backtrace", - ]; - let is_std_lib = STD_LIBS.iter().any(|l| rest.starts_with(l)); + let new_path = if is_std_lib { + real_dir.join("library").join(rest) + } else { + real_dir.join(rest) + }; - let new_path = if is_std_lib { - real_dir.join("library").join(rest) - } else { - real_dir.join(rest) - }; + debug!( + "try_to_translate_virtual_to_real: `{}` -> `{}`", + virtual_name.display(), + new_path.display(), + ); - debug!( - "try_to_translate_virtual_to_real: `{}` -> `{}`", - virtual_name.display(), - new_path.display(), - ); - let new_name = rustc_span::RealFileName::Remapped { - local_path: Some(new_path), - virtual_name, - }; - *old_name = new_name; - } + // Check if the translated real path is affected by any user-requested + // remaps via --remap-path-prefix. Apply them if so. + // Note that this is a special case for imported rust-src paths specified by + // https://rust-lang.github.io/rfcs/3127-trim-paths.html#handling-sysroot-paths. + // Other imported paths are not currently remapped (see #66251). + let (user_remapped, applied) = + sess.source_map().path_mapping().map_prefix(&new_path); + let new_name = if applied { + rustc_span::RealFileName::Remapped { + local_path: Some(new_path.clone()), + virtual_name: user_remapped.to_path_buf(), } - } + } else { + rustc_span::RealFileName::LocalPath(new_path) + }; + *old_name = new_name; } } }; diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index a291ff37112..1fa31181fd5 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -1115,6 +1115,7 @@ fn expand_variables(mut value: String, config: &Config) -> String { const CWD: &str = "{{cwd}}"; const SRC_BASE: &str = "{{src-base}}"; const BUILD_BASE: &str = "{{build-base}}"; + const RUST_SRC_BASE: &str = "{{rust-src-base}}"; const SYSROOT_BASE: &str = "{{sysroot-base}}"; const TARGET_LINKER: &str = "{{target-linker}}"; const TARGET: &str = "{{target}}"; @@ -1144,6 +1145,15 @@ fn expand_variables(mut value: String, config: &Config) -> String { value = value.replace(TARGET, &config.target); } + if value.contains(RUST_SRC_BASE) { + let src_base = config + .sysroot_base + .join("lib/rustlib/src/rust") + .read_link() + .expect("lib/rustlib/src/rust in target is a symlink to checkout root"); + value = value.replace(RUST_SRC_BASE, &src_base.to_string_lossy()); + } + value } diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 25a135aa320..1a1cc86e2de 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -2294,7 +2294,7 @@ impl<'test> TestCx<'test> { } let base_dir = Path::new("/rustc/FAKE_PREFIX"); - // Paths into the libstd/libcore + // Fake paths into the libstd/libcore normalize_path(&base_dir.join("library"), "$SRC_DIR"); // `ui-fulldeps` tests can show paths to the compiler source when testing macros from // `rustc_macros` @@ -2310,8 +2310,14 @@ impl<'test> TestCx<'test> { // eg. /home/user/rust/build normalize_path(parent_build_dir, "$BUILD_DIR"); - // Paths into lib directory. - normalize_path(&parent_build_dir.parent().unwrap().join("lib"), "$LIB_DIR"); + // Real paths into the libstd/libcore + let rust_src_dir = &self + .config + .sysroot_base + .join("lib/rustlib/src/rust") + .read_link() + .expect("lib/rustlib/src/rust in target is a symlink to checkout root"); + normalize_path(&rust_src_dir.join("library"), "$SRC_DIR_REAL"); if json { // escaped newlines in json strings should be readable diff --git a/tests/ui/errors/remap-path-prefix-sysroot.rs b/tests/ui/errors/remap-path-prefix-sysroot.rs new file mode 100644 index 00000000000..66cafbf43b6 --- /dev/null +++ b/tests/ui/errors/remap-path-prefix-sysroot.rs @@ -0,0 +1,23 @@ +//@ revisions: with-remap without-remap +//@ compile-flags: -g -Ztranslate-remapped-path-to-local-path=yes +//@ [with-remap]compile-flags: --remap-path-prefix={{rust-src-base}}=remapped +//@ [without-remap]compile-flags: +//@ error-pattern: E0507 + +// The $SRC_DIR*.rs:LL:COL normalisation doesn't kick in automatically +// as the remapped revision will not begin with $SRC_DIR_REAL, +// so we have to do it ourselves. +//@ normalize-stderr-test: ".rs:\d+:\d+" -> ".rs:LL:COL" + +use std::thread; +struct Worker { + thread: thread::JoinHandle<()>, +} + +impl Drop for Worker { + fn drop(&mut self) { + self.thread.join().unwrap(); + } +} + +pub fn main(){} diff --git a/tests/ui/errors/remap-path-prefix-sysroot.with-remap.stderr b/tests/ui/errors/remap-path-prefix-sysroot.with-remap.stderr new file mode 100644 index 00000000000..bdb882e2df5 --- /dev/null +++ b/tests/ui/errors/remap-path-prefix-sysroot.with-remap.stderr @@ -0,0 +1,17 @@ +error[E0507]: cannot move out of `self.thread` which is behind a mutable reference + --> remapped/tests/ui/errors/remap-path-prefix-sysroot.rs:LL:COL + | +LL | self.thread.join().unwrap(); + | ^^^^^^^^^^^ ------ `self.thread` moved due to this method call + | | + | move occurs because `self.thread` has type `JoinHandle<()>`, which does not implement the `Copy` trait + | +note: `JoinHandle::::join` takes ownership of the receiver `self`, which moves `self.thread` + --> remapped/library/std/src/thread/mod.rs:LL:COL + | +LL | pub fn join(self) -> Result { + | ^^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0507`. diff --git a/tests/ui/errors/remap-path-prefix-sysroot.without-remap.stderr b/tests/ui/errors/remap-path-prefix-sysroot.without-remap.stderr new file mode 100644 index 00000000000..9b337699c32 --- /dev/null +++ b/tests/ui/errors/remap-path-prefix-sysroot.without-remap.stderr @@ -0,0 +1,17 @@ +error[E0507]: cannot move out of `self.thread` which is behind a mutable reference + --> $DIR/remap-path-prefix-sysroot.rs:LL:COL + | +LL | self.thread.join().unwrap(); + | ^^^^^^^^^^^ ------ `self.thread` moved due to this method call + | | + | move occurs because `self.thread` has type `JoinHandle<()>`, which does not implement the `Copy` trait + | +note: `JoinHandle::::join` takes ownership of the receiver `self`, which moves `self.thread` + --> $SRC_DIR_REAL/std/src/thread/mod.rs:LL:COL + | +LL | pub fn join(self) -> Result { + | ^^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0507`. From 9766192545190027b3c087f78cdc7dc5a51f0204 Mon Sep 17 00:00:00 2001 From: lcnr Date: Fri, 27 Sep 2024 13:48:11 +0200 Subject: [PATCH 324/683] update outdated comments --- compiler/rustc_type_ir/src/predicate.rs | 4 ++-- compiler/rustc_type_ir/src/predicate_kind.rs | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_type_ir/src/predicate.rs b/compiler/rustc_type_ir/src/predicate.rs index 7e300fe02dc..76065c10d19 100644 --- a/compiler/rustc_type_ir/src/predicate.rs +++ b/compiler/rustc_type_ir/src/predicate.rs @@ -668,8 +668,8 @@ impl fmt::Debug for ProjectionPredicate { } } -/// Used by the new solver. Unlike a `ProjectionPredicate` this can only be -/// proven by actually normalizing `alias`. +/// Used by the new solver to normalize an alias. This always expects the `term` to +/// be an unconstrained inference variable which is used as the output. #[derive_where(Clone, Copy, Hash, PartialEq, Eq; I: Interner)] #[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)] #[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))] diff --git a/compiler/rustc_type_ir/src/predicate_kind.rs b/compiler/rustc_type_ir/src/predicate_kind.rs index c8a21028588..55015e6e202 100644 --- a/compiler/rustc_type_ir/src/predicate_kind.rs +++ b/compiler/rustc_type_ir/src/predicate_kind.rs @@ -74,13 +74,13 @@ pub enum PredicateKind { Ambiguous, /// This should only be used inside of the new solver for `AliasRelate` and expects - /// the `term` to be an unconstrained inference variable. + /// the `term` to be always be an unconstrained inference variable. It is used to + /// normalize `alias` as much as possible. In case the alias is rigid - i.e. it cannot + /// be normalized in the current environment - this constrains `term` to be equal to + /// the alias itself. /// - /// The alias normalizes to `term`. Unlike `Projection`, this always fails if the - /// alias cannot be normalized in the current context. For the rigid alias - /// `T as Trait>::Assoc`, `Projection(::Assoc, ?x)` constrains `?x` - /// to `::Assoc` while `NormalizesTo(::Assoc, ?x)` - /// results in `NoSolution`. + /// It is likely more useful to think of this as a function `normalizes_to(alias)`, + /// whose return value is written into `term`. NormalizesTo(ty::NormalizesTo), /// Separate from `ClauseKind::Projection` which is used for normalization in new solver. From 61ef9838dfb5045d00aa5563065a31210dab9460 Mon Sep 17 00:00:00 2001 From: Urgau Date: Fri, 27 Sep 2024 14:05:24 +0200 Subject: [PATCH 325/683] compiletest: fallback to the original path if it's not a symlink --- src/tools/compiletest/src/header.rs | 8 +++----- src/tools/compiletest/src/runtest.rs | 9 +++------ 2 files changed, 6 insertions(+), 11 deletions(-) diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index 1fa31181fd5..6a889d27793 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -1146,11 +1146,9 @@ fn expand_variables(mut value: String, config: &Config) -> String { } if value.contains(RUST_SRC_BASE) { - let src_base = config - .sysroot_base - .join("lib/rustlib/src/rust") - .read_link() - .expect("lib/rustlib/src/rust in target is a symlink to checkout root"); + let src_base = config.sysroot_base.join("lib/rustlib/src/rust"); + src_base.try_exists().expect(&*format!("{} should exists", src_base.display())); + let src_base = src_base.read_link().unwrap_or(src_base); value = value.replace(RUST_SRC_BASE, &src_base.to_string_lossy()); } diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 1a1cc86e2de..922492e451f 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -2311,12 +2311,9 @@ impl<'test> TestCx<'test> { normalize_path(parent_build_dir, "$BUILD_DIR"); // Real paths into the libstd/libcore - let rust_src_dir = &self - .config - .sysroot_base - .join("lib/rustlib/src/rust") - .read_link() - .expect("lib/rustlib/src/rust in target is a symlink to checkout root"); + let rust_src_dir = &self.config.sysroot_base.join("lib/rustlib/src/rust"); + rust_src_dir.try_exists().expect(&*format!("{} should exists", rust_src_dir.display())); + let rust_src_dir = rust_src_dir.read_link().unwrap_or(rust_src_dir.to_path_buf()); normalize_path(&rust_src_dir.join("library"), "$SRC_DIR_REAL"); if json { From cd1b245c99c6422ffe2f63846558b436da16b34d Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Fri, 27 Sep 2024 15:00:49 +0300 Subject: [PATCH 326/683] improve LLVM submodule handling logic in `llvm::prebuilt_llvm_config` Signed-off-by: onur-ozkan --- src/bootstrap/src/core/build_steps/compile.rs | 3 ++- src/bootstrap/src/core/build_steps/dist.rs | 2 +- src/bootstrap/src/core/build_steps/llvm.rs | 21 ++++++++++++------- src/bootstrap/src/core/builder.rs | 4 +++- 4 files changed, 19 insertions(+), 11 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index 0e596f0da0e..eaa982d4e2b 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -1205,7 +1205,8 @@ pub fn rustc_cargo_env( // busting caches (e.g. like #71152). if builder.config.llvm_enabled(target) { let building_is_expensive = - crate::core::build_steps::llvm::prebuilt_llvm_config(builder, target).should_build(); + crate::core::build_steps::llvm::prebuilt_llvm_config(builder, target, false) + .should_build(); // `top_stage == stage` might be false for `check --stage 1`, if we are building the stage 1 compiler let can_skip_build = builder.kind == Kind::Check && builder.top_stage == stage; let should_skip_build = building_is_expensive && can_skip_build; diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs index 4c557366297..90e6a10d9d6 100644 --- a/src/bootstrap/src/core/build_steps/dist.rs +++ b/src/bootstrap/src/core/build_steps/dist.rs @@ -2036,7 +2036,7 @@ fn maybe_install_llvm( } !builder.config.dry_run() } else if let llvm::LlvmBuildStatus::AlreadyBuilt(llvm::LlvmResult { llvm_config, .. }) = - llvm::prebuilt_llvm_config(builder, target) + llvm::prebuilt_llvm_config(builder, target, true) { let mut cmd = command(llvm_config); cmd.arg("--libfiles"); diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs index b3bc6df1f87..bae7642cffd 100644 --- a/src/bootstrap/src/core/build_steps/llvm.rs +++ b/src/bootstrap/src/core/build_steps/llvm.rs @@ -87,10 +87,14 @@ impl LdFlags { /// /// This will return the llvm-config if it can get it (but it will not build it /// if not). -pub fn prebuilt_llvm_config(builder: &Builder<'_>, target: TargetSelection) -> LlvmBuildStatus { - // If we have llvm submodule initialized already, sync it. - builder.update_existing_submodule("src/llvm-project"); - +pub fn prebuilt_llvm_config( + builder: &Builder<'_>, + target: TargetSelection, + // Certain commands (like `x test mir-opt --bless`) may call this function with different targets, + // which could bypass the CI LLVM early-return even if `builder.config.llvm_from_ci` is true. + // This flag should be `true` only if the caller needs the LLVM sources (e.g., if it will build LLVM). + handle_submodule_when_needed: bool, +) -> LlvmBuildStatus { builder.config.maybe_download_ci_llvm(); // If we're using a custom LLVM bail out here, but we can only use a @@ -109,9 +113,10 @@ pub fn prebuilt_llvm_config(builder: &Builder<'_>, target: TargetSelection) -> L } } - // Initialize the llvm submodule if not initialized already. - // If submodules are disabled, this does nothing. - builder.config.update_submodule("src/llvm-project"); + if handle_submodule_when_needed { + // If submodules are disabled, this does nothing. + builder.config.update_submodule("src/llvm-project"); + } let root = "src/llvm-project/llvm"; let out_dir = builder.llvm_out(target); @@ -284,7 +289,7 @@ impl Step for Llvm { }; // If LLVM has already been built or been downloaded through download-ci-llvm, we avoid building it again. - let Meta { stamp, res, out_dir, root } = match prebuilt_llvm_config(builder, target) { + let Meta { stamp, res, out_dir, root } = match prebuilt_llvm_config(builder, target, true) { LlvmBuildStatus::AlreadyBuilt(p) => return p, LlvmBuildStatus::ShouldBuild(m) => m, }; diff --git a/src/bootstrap/src/core/builder.rs b/src/bootstrap/src/core/builder.rs index 47420f8fe72..6ba669f3b10 100644 --- a/src/bootstrap/src/core/builder.rs +++ b/src/bootstrap/src/core/builder.rs @@ -1537,7 +1537,9 @@ impl<'a> Builder<'a> { // rustc_llvm. But if LLVM is stale, that'll be a tiny amount // of work comparatively, and we'd likely need to rebuild it anyway, // so that's okay. - if crate::core::build_steps::llvm::prebuilt_llvm_config(self, target).should_build() { + if crate::core::build_steps::llvm::prebuilt_llvm_config(self, target, false) + .should_build() + { cargo.env("RUST_CHECK", "1"); } } From 1e8354a461486bb543741d9343ce170af554e7eb Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Wed, 25 Sep 2024 19:54:16 -0400 Subject: [PATCH 327/683] Fix mapping --- src/builder.rs | 2 ++ src/intrinsic/llvm.rs | 24 +++++++++++++++++------- 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/src/builder.rs b/src/builder.rs index 408b7bc3caa..e001e59177d 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -285,6 +285,8 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { ); // TODO(antoyo): perhaps use __builtin_convertvector for vector casting. // TODO: remove bitcast now that vector types can be compared? + // ==> We use bitcast to avoid having to do many manual casts from e.g. __m256i to __v32qi (in + // the case of _mm256_aesenc_epi128). self.bitcast(actual_val, expected_ty) } } else { diff --git a/src/intrinsic/llvm.rs b/src/intrinsic/llvm.rs index cc6bed1fc9a..4aed955627d 100644 --- a/src/intrinsic/llvm.rs +++ b/src/intrinsic/llvm.rs @@ -466,12 +466,12 @@ pub fn adjust_intrinsic_arguments<'a, 'b, 'gcc, 'tcx>( let arg1_type = gcc_func.get_param_type(0); let arg2_type = gcc_func.get_param_type(1); let arg3_type = gcc_func.get_param_type(2); - let arg5_type = gcc_func.get_param_type(4); + let arg4_type = gcc_func.get_param_type(3); let a = builder.context.new_rvalue_from_vector(None, arg1_type, &[new_args[0]; 8]); let b = builder.context.new_rvalue_from_vector(None, arg2_type, &[new_args[1]; 8]); let c = builder.context.new_rvalue_from_vector(None, arg3_type, &[new_args[2]; 8]); - let arg5 = builder.context.new_rvalue_from_int(arg5_type, 4); - args = vec![a, b, c, new_args[3], arg5].into(); + let arg4 = builder.context.new_rvalue_from_int(arg4_type, -1); + args = vec![a, b, c, arg4, new_args[3]].into(); } _ => (), } @@ -604,7 +604,13 @@ pub fn adjust_intrinsic_arguments<'a, 'b, 'gcc, 'tcx>( new_args[2] = builder.context.new_cast(None, new_args[2], builder.double_type); args = new_args.into(); } - "__builtin_ia32_sqrtsh_mask_round" => { + "__builtin_ia32_sqrtsh_mask_round" + | "__builtin_ia32_vcvtss2sh_mask_round" + | "__builtin_ia32_vcvtsd2sh_mask_round" + | "__builtin_ia32_vcvtsh2ss_mask_round" + | "__builtin_ia32_vcvtsh2sd_mask_round" + | "__builtin_ia32_rcpsh_mask" + | "__builtin_ia32_rsqrtsh_mask" => { // The first two arguments are inverted, so swap them. let mut new_args = args.to_vec(); new_args.swap(0, 1); @@ -1192,11 +1198,11 @@ pub fn intrinsic<'gcc, 'tcx>(name: &str, cx: &CodegenCx<'gcc, 'tcx>) -> Function "llvm.x86.avx512fp16.mask.vfcmul.csh" => "__builtin_ia32_vfcmulcsh_mask_round", "llvm.x86.avx512fp16.mask.vfmadd.cph.512" => "__builtin_ia32_vfmaddcph512_mask3_round", "llvm.x86.avx512fp16.maskz.vfmadd.cph.512" => "__builtin_ia32_vfmaddcph512_maskz_round", - "llvm.x86.avx512fp16.mask.vfmadd.csh" => "__builtin_ia32_vfmaddcsh_mask3_round", + "llvm.x86.avx512fp16.mask.vfmadd.csh" => "__builtin_ia32_vfmaddcsh_mask_round", "llvm.x86.avx512fp16.maskz.vfmadd.csh" => "__builtin_ia32_vfmaddcsh_maskz_round", "llvm.x86.avx512fp16.mask.vfcmadd.cph.512" => "__builtin_ia32_vfcmaddcph512_mask3_round", "llvm.x86.avx512fp16.maskz.vfcmadd.cph.512" => "__builtin_ia32_vfcmaddcph512_maskz_round", - "llvm.x86.avx512fp16.mask.vfcmadd.csh" => "__builtin_ia32_vfcmaddcsh_mask_round", + "llvm.x86.avx512fp16.mask.vfcmadd.csh" => "__builtin_ia32_vfcmaddcsh_mask3_round", "llvm.x86.avx512fp16.maskz.vfcmadd.csh" => "__builtin_ia32_vfcmaddcsh_maskz_round", "llvm.x86.avx512fp16.vfmadd.ph.512" => "__builtin_ia32_vfmaddph512_mask", "llvm.x86.avx512fp16.vcvtsi642sh" => "__builtin_ia32_vcvtsi2sh64_round", @@ -1209,7 +1215,7 @@ pub fn intrinsic<'gcc, 'tcx>(name: &str, cx: &CodegenCx<'gcc, 'tcx>) -> Function "llvm.x86.avx512.mask.load.pd.256" => "__builtin_ia32_loadapd256_mask", "llvm.x86.avx512.mask.load.d.128" => "__builtin_ia32_movdqa32load128_mask", "llvm.x86.avx512.mask.load.q.128" => "__builtin_ia32_movdqa64load128_mask", - "llvm.x86.avx512.mask.load.ps.128" => "__builtin_ia32_movdqa64load128_mask", + "llvm.x86.avx512.mask.load.ps.128" => "__builtin_ia32_loadaps128_mask", "llvm.x86.avx512.mask.load.pd.128" => "__builtin_ia32_loadapd128_mask", "llvm.x86.avx512.mask.storeu.d.256" => "__builtin_ia32_storedqusi256_mask", "llvm.x86.avx512.mask.storeu.q.256" => "__builtin_ia32_storedqudi256_mask", @@ -1283,6 +1289,10 @@ pub fn intrinsic<'gcc, 'tcx>(name: &str, cx: &CodegenCx<'gcc, 'tcx>) -> Function "llvm.x86.avx512fp16.mask.vcvttph2uqq.512" => "__builtin_ia32_vcvttph2uqq512_mask_round", "llvm.x86.avx512fp16.mask.vcvtph2psx.512" => "__builtin_ia32_vcvtph2psx512_mask_round", "llvm.x86.avx512fp16.mask.vcvtph2pd.512" => "__builtin_ia32_vcvtph2pd512_mask_round", + "llvm.x86.avx512fp16.mask.vfcmadd.cph.256" => "__builtin_ia32_vfcmaddcph256_mask3", + "llvm.x86.avx512fp16.mask.vfmadd.cph.256" => "__builtin_ia32_vfmaddcph256_mask3", + "llvm.x86.avx512fp16.mask.vfcmadd.cph.128" => "__builtin_ia32_vfcmaddcph128_mask3", + "llvm.x86.avx512fp16.mask.vfmadd.cph.128" => "__builtin_ia32_vfmaddcph128_mask3", // TODO: support the tile builtins: "llvm.x86.ldtilecfg" => "__builtin_trap", From 7c2a24b50c48c9716a88e3053064a7d4470b011f Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Sat, 24 Aug 2024 14:01:00 +0800 Subject: [PATCH 328/683] properly elaborate effects implied bounds for super traits --- compiler/rustc_hir_analysis/src/bounds.rs | 44 +++++++++++-- .../src/collect/item_bounds.rs | 29 +-------- compiler/rustc_middle/src/ty/context.rs | 2 + compiler/rustc_type_ir/src/elaborate.rs | 65 +++++++++++++++++++ compiler/rustc_type_ir/src/lang_items.rs | 2 + .../super-traits-fail-3.rs | 2 +- .../super-traits-fail-3.yy.stderr | 22 ------- .../super-traits-fail.rs | 2 +- .../super-traits-fail.stderr | 23 +++++-- .../rfc-2632-const-trait-impl/super-traits.rs | 3 +- .../super-traits.stderr | 22 ------- 11 files changed, 132 insertions(+), 84 deletions(-) delete mode 100644 tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.yy.stderr delete mode 100644 tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits.stderr diff --git a/compiler/rustc_hir_analysis/src/bounds.rs b/compiler/rustc_hir_analysis/src/bounds.rs index caf9960741d..8947e7a2216 100644 --- a/compiler/rustc_hir_analysis/src/bounds.rs +++ b/compiler/rustc_hir_analysis/src/bounds.rs @@ -91,12 +91,46 @@ impl<'tcx> Bounds<'tcx> { } tcx.consts.true_ } + (DefKind::Trait, ty::BoundConstness::ConstIfConst) => { + // we are in a trait, where `bound_trait_ref` could be: + // (1) a super trait `trait Foo: ~const Bar`. + // - This generates `::Effects: TyCompat<::Effects>` + // + // (2) a where clause `where for<..> Something: ~const Bar`. + // - This generates `for<..> ::Effects: TyCompat<::Effects>` + let Some(own_fx) = tcx.associated_type_for_effects(defining_def_id) else { + tcx.dcx().span_delayed_bug(span, "should not have allowed `~const` on a trait that doesn't have `#[const_trait]`"); + return; + }; + let own_fx_ty = Ty::new_projection( + tcx, + own_fx, + ty::GenericArgs::identity_for_item(tcx, own_fx), + ); + let Some(their_fx) = tcx.associated_type_for_effects(bound_trait_ref.def_id()) + else { + tcx.dcx().span_delayed_bug(span, "`~const` on trait without Effects assoc"); + return; + }; + let their_fx_ty = + Ty::new_projection(tcx, their_fx, bound_trait_ref.skip_binder().args); + let compat = tcx.require_lang_item(LangItem::EffectsTyCompat, Some(span)); + let clause = bound_trait_ref + .map_bound(|_| { + let trait_ref = ty::TraitRef::new(tcx, compat, [own_fx_ty, their_fx_ty]); + ty::ClauseKind::Trait(ty::TraitPredicate { + trait_ref, + polarity: ty::PredicatePolarity::Positive, + }) + }) + .upcast(tcx); - ( - DefKind::Trait | DefKind::Impl { of_trait: true }, - ty::BoundConstness::ConstIfConst, - ) => { - // this is either a where clause on an impl/trait header or on a trait. + self.clauses.push((clause, span)); + return; + } + + (DefKind::Impl { of_trait: true }, ty::BoundConstness::ConstIfConst) => { + // this is a where clause on an impl header. // push `::Effects` into the set for the `Min` bound. let Some(assoc) = tcx.associated_type_for_effects(bound_trait_ref.def_id()) else { tcx.dcx().span_delayed_bug(span, "`~const` on trait without Effects assoc"); diff --git a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs index 7557219aaa6..f44b4728ad5 100644 --- a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs +++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs @@ -360,33 +360,10 @@ pub(super) fn explicit_item_bounds_with_filter( None => {} } - if tcx.is_effects_desugared_assoc_ty(def_id.to_def_id()) { - let mut predicates = Vec::new(); - - let parent = tcx.local_parent(def_id); - - let preds = tcx.explicit_predicates_of(parent); - - if let ty::AssocItemContainer::TraitContainer = tcx.associated_item(def_id).container { - // for traits, emit `type Effects: TyCompat<<(T1::Effects, ..) as Min>::Output>` - let tup = Ty::new(tcx, ty::Tuple(preds.effects_min_tys)); - // FIXME(effects) span - let span = tcx.def_span(def_id); - let assoc = tcx.require_lang_item(hir::LangItem::EffectsIntersectionOutput, Some(span)); - let proj = Ty::new_projection(tcx, assoc, [tup]); - let self_proj = Ty::new_projection( - tcx, - def_id.to_def_id(), - ty::GenericArgs::identity_for_item(tcx, def_id), - ); - let trait_ = tcx.require_lang_item(hir::LangItem::EffectsTyCompat, Some(span)); - let trait_ref = ty::TraitRef::new(tcx, trait_, [self_proj, proj]); - predicates.push((ty::Binder::dummy(trait_ref).upcast(tcx), span)); - } - return ty::EarlyBinder::bind(tcx.arena.alloc_from_iter(predicates)); - } - let bounds = match tcx.hir_node_by_def_id(def_id) { + _ if tcx.is_effects_desugared_assoc_ty(def_id.to_def_id()) => { + associated_type_bounds(tcx, def_id, &[], tcx.def_span(def_id), filter) + } hir::Node::TraitItem(hir::TraitItem { kind: hir::TraitItemKind::Type(bounds, _), span, diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index f017216489d..f1732e4859d 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -622,11 +622,13 @@ bidirectional_lang_item_map! { Destruct, DiscriminantKind, DynMetadata, + EffectsCompat, EffectsIntersection, EffectsIntersectionOutput, EffectsMaybe, EffectsNoRuntime, EffectsRuntime, + EffectsTyCompat, Fn, FnMut, FnOnce, diff --git a/compiler/rustc_type_ir/src/elaborate.rs b/compiler/rustc_type_ir/src/elaborate.rs index 3db9b8b0661..61736633cfa 100644 --- a/compiler/rustc_type_ir/src/elaborate.rs +++ b/compiler/rustc_type_ir/src/elaborate.rs @@ -4,6 +4,7 @@ use smallvec::smallvec; use crate::data_structures::HashSet; use crate::inherent::*; +use crate::lang_items::TraitSolverLangItem; use crate::outlives::{Component, push_outlives_components}; use crate::{self as ty, Interner, Upcast as _}; @@ -89,6 +90,70 @@ impl> Elaborator { return; } + // HACK(effects): The following code is required to get implied bounds for effects associated + // types to work with super traits. + // + // Suppose `data` is a trait predicate with the form `::Fx: EffectsCompat` + // and we know that `trait Tr: ~const SuperTr`, we need to elaborate this predicate into + // `::Fx: EffectsCompat`. + // + // Since the semantics for elaborating bounds about effects is equivalent to elaborating + // bounds about super traits (elaborate `T: Tr` into `T: SuperTr`), we place effects elaboration + // next to super trait elaboration. + if cx.is_lang_item(data.def_id(), TraitSolverLangItem::EffectsCompat) + && matches!(self.mode, Filter::All) + { + // first, ensure that the predicate we've got looks like a `::Fx: EffectsCompat`. + if let ty::Alias(ty::AliasTyKind::Projection, alias_ty) = data.self_ty().kind() + { + // look for effects-level bounds that look like `::Fx: TyCompat<::Fx>` + // on the trait, which is proof to us that `Tr: ~const SuperTr`. We're looking for bounds on the + // associated trait, so we use `explicit_implied_predicates_of` since it gives us more than just + // `Self: SuperTr` bounds. + let bounds = cx.explicit_implied_predicates_of(cx.parent(alias_ty.def_id)); + + // instantiate the implied bounds, so we get `::Fx` and not `::Fx`. + let elaborated = bounds.iter_instantiated(cx, alias_ty.args).filter_map( + |(clause, _)| { + let ty::ClauseKind::Trait(tycompat_bound) = + clause.kind().skip_binder() + else { + return None; + }; + if !cx.is_lang_item( + tycompat_bound.def_id(), + TraitSolverLangItem::EffectsTyCompat, + ) { + return None; + } + + // extract `::Fx` from the `TyCompat` bound. + let supertrait_effects_ty = + tycompat_bound.trait_ref.args.type_at(1); + let ty::Alias(ty::AliasTyKind::Projection, supertrait_alias_ty) = + supertrait_effects_ty.kind() + else { + return None; + }; + + // The self types (`T`) must be equal for `::Fx` and `::Fx`. + if supertrait_alias_ty.self_ty() != alias_ty.self_ty() { + return None; + }; + + // replace the self type in the original bound `::Fx: EffectsCompat` + // to the effects type of the super trait. (`::Fx`) + let elaborated_bound = data.with_self_ty(cx, supertrait_effects_ty); + Some( + elaboratable + .child(bound_clause.rebind(elaborated_bound).upcast(cx)), + ) + }, + ); + self.extend_deduped(elaborated); + } + } + let map_to_child_clause = |(index, (clause, span)): (usize, (I::Clause, I::Span))| { elaboratable.child_with_derived_cause( diff --git a/compiler/rustc_type_ir/src/lang_items.rs b/compiler/rustc_type_ir/src/lang_items.rs index 265a4118827..c680c844746 100644 --- a/compiler/rustc_type_ir/src/lang_items.rs +++ b/compiler/rustc_type_ir/src/lang_items.rs @@ -20,11 +20,13 @@ pub enum TraitSolverLangItem { Destruct, DiscriminantKind, DynMetadata, + EffectsCompat, EffectsIntersection, EffectsIntersectionOutput, EffectsMaybe, EffectsNoRuntime, EffectsRuntime, + EffectsTyCompat, Fn, FnMut, FnOnce, diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.rs index 66943512650..c7e224dcce0 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.rs @@ -3,7 +3,7 @@ #![feature(const_trait_impl, effects)] //@ revisions: yy yn ny nn -//@[yy] known-bug: #110395 +//@[yy] check-pass #[cfg_attr(any(yy, yn), const_trait)] trait Foo { diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.yy.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.yy.stderr deleted file mode 100644 index ea0e6c690b7..00000000000 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.yy.stderr +++ /dev/null @@ -1,22 +0,0 @@ -error[E0277]: the trait bound `Foo::{synthetic#0}: ~const Compat` is not satisfied - --> $DIR/super-traits-fail-3.rs:22:7 - | -LL | x.a(); - | ^ the trait `~const Compat` is not implemented for `Foo::{synthetic#0}` - | -note: required by a bound in `Foo::a` - --> $DIR/super-traits-fail-3.rs:8:25 - | -LL | #[cfg_attr(any(yy, yn), const_trait)] - | ^^^^^^^^^^^ required by this bound in `Foo::a` -LL | trait Foo { -LL | fn a(&self); - | - required by a bound in this associated function -help: consider further restricting the associated type - | -LL | const fn foo(x: &T) where Foo::{synthetic#0}: ~const Compat { - | +++++++++++++++++++++++++++++++++++++++ - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail.rs index 6c320c0462e..da41d7fcc72 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail.rs @@ -17,6 +17,6 @@ impl Foo for S { } impl const Bar for S {} -// FIXME(effects) bad span +//~^ ERROR the trait bound fn main() {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail.stderr index 9a907bbee0a..3870f0f722f 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail.stderr @@ -1,11 +1,24 @@ -error[E0277]: the trait bound `Maybe: TyCompat<<(Foo::{synthetic#0},) as std::marker::effects::Intersection>::Output>` is not satisfied +error[E0277]: the trait bound `Bar::{synthetic#0}: TyCompat` is not satisfied + --> $DIR/super-traits-fail.rs:19:12 + | +LL | impl const Bar for S {} + | ^^^ the trait `TyCompat` is not implemented for `Bar::{synthetic#0}`, which is required by `S: Bar` + | + = help: the trait `Bar` is implemented for `S` +note: required for `S` to implement `Bar` + --> $DIR/super-traits-fail.rs:12:7 + | +LL | trait Bar: ~const Foo {} + | ^^^ + +error[E0277]: the trait bound `Maybe: TyCompat` is not satisfied | note: required by a bound in `Bar::{synthetic#0}` - --> $DIR/super-traits-fail.rs:11:1 + --> $DIR/super-traits-fail.rs:12:12 | -LL | #[const_trait] - | ^^^^^^^^^^^^^^ required by this bound in `Bar::{synthetic#0}` +LL | trait Bar: ~const Foo {} + | ^^^^^^^^^^ required by this bound in `Bar::{synthetic#0}` -error: aborting due to 1 previous error +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits.rs index fbe89b00b97..ff7349bba3c 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits.rs @@ -1,5 +1,4 @@ -// FIXME(effects) check-pass -//@ known-bug: #110395 +//@ check-pass //@ compile-flags: -Znext-solver #![allow(incomplete_features)] #![feature(const_trait_impl, effects)] diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits.stderr deleted file mode 100644 index 5b6b39ee05e..00000000000 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits.stderr +++ /dev/null @@ -1,22 +0,0 @@ -error[E0277]: the trait bound `Foo::{synthetic#0}: ~const Compat` is not satisfied - --> $DIR/super-traits.rs:23:7 - | -LL | t.a(); - | ^ the trait `~const Compat` is not implemented for `Foo::{synthetic#0}` - | -note: required by a bound in `Foo::a` - --> $DIR/super-traits.rs:7:1 - | -LL | #[const_trait] - | ^^^^^^^^^^^^^^ required by this bound in `Foo::a` -LL | trait Foo { -LL | fn a(&self); - | - required by a bound in this associated function -help: consider further restricting the associated type - | -LL | const fn foo(t: &T) where Foo::{synthetic#0}: ~const Compat { - | +++++++++++++++++++++++++++++++++++++++ - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0277`. From 7033468a67c0e39b2e34de2b43f78a29d101861d Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 26 Sep 2024 22:10:04 -0400 Subject: [PATCH 329/683] Mark some more types as having insignificant dtor --- library/alloc/src/ffi/c_str.rs | 1 + library/std/src/io/error/repr_bitpacked.rs | 1 + 2 files changed, 2 insertions(+) diff --git a/library/alloc/src/ffi/c_str.rs b/library/alloc/src/ffi/c_str.rs index 797d591a8b5..d496899e72b 100644 --- a/library/alloc/src/ffi/c_str.rs +++ b/library/alloc/src/ffi/c_str.rs @@ -696,6 +696,7 @@ impl CString { // memory-unsafe code from working by accident. Inline // to prevent LLVM from optimizing it away in debug builds. #[stable(feature = "cstring_drop", since = "1.13.0")] +#[rustc_insignificant_dtor] impl Drop for CString { #[inline] fn drop(&mut self) { diff --git a/library/std/src/io/error/repr_bitpacked.rs b/library/std/src/io/error/repr_bitpacked.rs index 80ba8455df3..a839a2fbac1 100644 --- a/library/std/src/io/error/repr_bitpacked.rs +++ b/library/std/src/io/error/repr_bitpacked.rs @@ -124,6 +124,7 @@ const TAG_SIMPLE: usize = 0b11; /// is_unwind_safe::(); /// ``` #[repr(transparent)] +#[rustc_insignificant_dtor] pub(super) struct Repr(NonNull<()>, PhantomData>>); // All the types `Repr` stores internally are Send + Sync, and so is it. From 24290efafffb83514da4e37f5f42a962d0e9bb1f Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 27 Sep 2024 11:59:35 -0400 Subject: [PATCH 330/683] Mark some more smart pointers as insignificant --- library/alloc/src/boxed.rs | 1 + library/alloc/src/sync.rs | 1 + 2 files changed, 2 insertions(+) diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs index 6421504b896..5f207295683 100644 --- a/library/alloc/src/boxed.rs +++ b/library/alloc/src/boxed.rs @@ -228,6 +228,7 @@ mod thin; #[lang = "owned_box"] #[fundamental] #[stable(feature = "rust1", since = "1.0.0")] +#[rustc_insignificant_dtor] // The declaration of the `Box` struct must be kept in sync with the // compiler or ICEs will happen. pub struct Box< diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index ced789c4f92..5d099a49854 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -237,6 +237,7 @@ macro_rules! acquire { /// [rc_examples]: crate::rc#examples #[cfg_attr(not(test), rustc_diagnostic_item = "Arc")] #[stable(feature = "rust1", since = "1.0.0")] +#[rustc_insignificant_dtor] pub struct Arc< T: ?Sized, #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, From 11f4f160d3a10d2c4e6f49c173f0344f9b9f09ae Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Fri, 27 Sep 2024 12:07:24 -0400 Subject: [PATCH 331/683] Implement a hack for an intrinsic mapping where we need to output a different builtin based on an argument --- src/builder.rs | 1 + src/intrinsic/llvm.rs | 34 ++++++++++++++++++++++++++++++++-- 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/src/builder.rs b/src/builder.rs index e001e59177d..9936bc1f5f2 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -370,6 +370,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { let args = { let function_address_names = self.function_address_names.borrow(); let original_function_name = function_address_names.get(&func_ptr); + func_ptr = llvm::adjust_function(self.context, &func_name, func_ptr, args); llvm::adjust_intrinsic_arguments( self, gcc_func, diff --git a/src/intrinsic/llvm.rs b/src/intrinsic/llvm.rs index 4aed955627d..b1fed82507d 100644 --- a/src/intrinsic/llvm.rs +++ b/src/intrinsic/llvm.rs @@ -1,12 +1,42 @@ use std::borrow::Cow; -use gccjit::CType; +use gccjit::{CType, Context}; use gccjit::{Function, FunctionPtrType, RValue, ToRValue, UnaryOp}; use rustc_codegen_ssa::traits::BuilderMethods; use crate::builder::Builder; use crate::context::CodegenCx; +pub fn adjust_function<'gcc>( + context: &'gcc Context<'gcc>, + func_name: &str, + func_ptr: RValue<'gcc>, + args: &[RValue<'gcc>], +) -> RValue<'gcc> { + // FIXME: we should not need this hack: this is required because both _mm_fcmadd_sch + // and _mm_mask3_fcmadd_round_sch calls llvm.x86.avx512fp16.mask.vfcmadd.csh and we + // seem to need to map this one LLVM intrinsic to 2 different GCC builtins. + match func_name { + "__builtin_ia32_vfcmaddcsh_mask3_round" => { + if format!("{:?}", args[3]).ends_with("255") { + return context + .get_target_builtin_function("__builtin_ia32_vfcmaddcsh_mask_round") + .get_address(None); + } + } + "__builtin_ia32_vfmaddcsh_mask3_round" => { + if format!("{:?}", args[3]).ends_with("255") { + return context + .get_target_builtin_function("__builtin_ia32_vfmaddcsh_mask_round") + .get_address(None); + } + } + _ => (), + } + + func_ptr +} + pub fn adjust_intrinsic_arguments<'a, 'b, 'gcc, 'tcx>( builder: &Builder<'a, 'gcc, 'tcx>, gcc_func: FunctionPtrType<'gcc>, @@ -1198,7 +1228,7 @@ pub fn intrinsic<'gcc, 'tcx>(name: &str, cx: &CodegenCx<'gcc, 'tcx>) -> Function "llvm.x86.avx512fp16.mask.vfcmul.csh" => "__builtin_ia32_vfcmulcsh_mask_round", "llvm.x86.avx512fp16.mask.vfmadd.cph.512" => "__builtin_ia32_vfmaddcph512_mask3_round", "llvm.x86.avx512fp16.maskz.vfmadd.cph.512" => "__builtin_ia32_vfmaddcph512_maskz_round", - "llvm.x86.avx512fp16.mask.vfmadd.csh" => "__builtin_ia32_vfmaddcsh_mask_round", + "llvm.x86.avx512fp16.mask.vfmadd.csh" => "__builtin_ia32_vfmaddcsh_mask3_round", "llvm.x86.avx512fp16.maskz.vfmadd.csh" => "__builtin_ia32_vfmaddcsh_maskz_round", "llvm.x86.avx512fp16.mask.vfcmadd.cph.512" => "__builtin_ia32_vfcmaddcph512_mask3_round", "llvm.x86.avx512fp16.maskz.vfcmadd.cph.512" => "__builtin_ia32_vfcmaddcph512_maskz_round", From 117cf3e3cd292c6c18454dcab3eec73ef090b323 Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Fri, 27 Sep 2024 12:12:24 -0400 Subject: [PATCH 332/683] Fix for libgccjit 12 --- src/context.rs | 1 + src/intrinsic/llvm.rs | 2 ++ 2 files changed, 3 insertions(+) diff --git a/src/context.rs b/src/context.rs index d4ac4f26b03..9756f0faae2 100644 --- a/src/context.rs +++ b/src/context.rs @@ -25,6 +25,7 @@ use rustc_target::spec::{HasTargetSpec, HasWasmCAbiOpt, Target, TlsModel, WasmCA use crate::callee::get_fn; use crate::common::SignType; +#[cfg_attr(not(feature = "master"), allow(dead_code))] pub struct CodegenCx<'gcc, 'tcx> { pub codegen_unit: &'tcx CodegenUnit<'tcx>, pub context: &'gcc Context<'gcc>, diff --git a/src/intrinsic/llvm.rs b/src/intrinsic/llvm.rs index b1fed82507d..7a8fe134cfc 100644 --- a/src/intrinsic/llvm.rs +++ b/src/intrinsic/llvm.rs @@ -7,6 +7,7 @@ use rustc_codegen_ssa::traits::BuilderMethods; use crate::builder::Builder; use crate::context::CodegenCx; +#[cfg_attr(not(feature = "master"), allow(unused_variables))] pub fn adjust_function<'gcc>( context: &'gcc Context<'gcc>, func_name: &str, @@ -16,6 +17,7 @@ pub fn adjust_function<'gcc>( // FIXME: we should not need this hack: this is required because both _mm_fcmadd_sch // and _mm_mask3_fcmadd_round_sch calls llvm.x86.avx512fp16.mask.vfcmadd.csh and we // seem to need to map this one LLVM intrinsic to 2 different GCC builtins. + #[cfg(feature = "master")] match func_name { "__builtin_ia32_vfcmaddcsh_mask3_round" => { if format!("{:?}", args[3]).ends_with("255") { From 6453f7e51463c7e94081bd135219c44e15bc174a Mon Sep 17 00:00:00 2001 From: Kajetan Puchalski Date: Tue, 24 Sep 2024 01:45:56 +0100 Subject: [PATCH 333/683] etc: Add rust-analyzer configs for eglot & helix LSP configuration in editors like Emacs (eglot) and helix does not use the same JSON format as vscode and vim do. It is not obvious how to set up LSP for rustc in those editors and the dev guide currently does not cover them. Adding sample configuration files for those editors alongside the currently existing JSON one would be helpful. --- src/etc/rust_analyzer_eglot.el | 29 +++++++++++++++++++ src/etc/rust_analyzer_helix.toml | 49 ++++++++++++++++++++++++++++++++ 2 files changed, 78 insertions(+) create mode 100644 src/etc/rust_analyzer_eglot.el create mode 100644 src/etc/rust_analyzer_helix.toml diff --git a/src/etc/rust_analyzer_eglot.el b/src/etc/rust_analyzer_eglot.el new file mode 100644 index 00000000000..e55d80d98de --- /dev/null +++ b/src/etc/rust_analyzer_eglot.el @@ -0,0 +1,29 @@ +((rustic-mode + .((eglot-workspace-configuration + . (:rust-analyzer + ( :check ( :invocationLocation "root" + :invocationStrategy "once" + :overrideCommand ["python3" + "x.py" + "check" + "--json-output"]) + :linkedProjects ["Cargo.toml" + "src/tools/x/Cargo.toml" + "src/bootstrap/Cargo.toml" + "src/tools/rust-analyzer/Cargo.toml" + "compiler/rustc_codegen_cranelift/Cargo.toml" + "compiler/rustc_codegen_gcc/Cargo.toml"] + :rustfmt ( :overrideCommand ["build/host/rustfmt/bin/rustfmt" + "--edition=2021"]) + :procMacro ( :server "build/host/stage0/libexec/rust-analyzer-proc-macro-srv" + :enable t) + :cargo ( :buildScripts ( :enable t + :invocationLocation "root" + :invocationStrategy "once" + :overrideCommand ["python3" + "x.py" + "check" + "--json-output"]) + :sysrootSrc "./library" + :extraEnv (:RUSTC_BOOTSTRAP "1")) + :rustc ( :source "./Cargo.toml" ))))))) diff --git a/src/etc/rust_analyzer_helix.toml b/src/etc/rust_analyzer_helix.toml new file mode 100644 index 00000000000..642350cad34 --- /dev/null +++ b/src/etc/rust_analyzer_helix.toml @@ -0,0 +1,49 @@ +[language-server.rust-analyzer.config] +linkedProjects = [ + "Cargo.toml", + "src/tools/x/Cargo.toml", + "src/bootstrap/Cargo.toml", + "src/tools/rust-analyzer/Cargo.toml", + "compiler/rustc_codegen_cranelift/Cargo.toml", + "compiler/rustc_codegen_gcc/Cargo.toml" +] + +[language-server.rust-analyzer.config.check] +invocationLocation = "root" +invocationStrategy = "once" +overrideCommand = [ + "python3", + "x.py", + "check", + "--json-output", +] + +[language-server.rust-analyzer.config.rustfmt] +overrideCommand = [ + "build-rust-analyzer/host/rustfmt/bin/rustfmt", + "--edition=2021" +] + +[language-server.rust-analyzer.config.procMacro] +server = "build-rust-analyzer/host/stage0/libexec/rust-analyzer-proc-macro-srv" +enable = true + +[language-server.rust-analyzer.config.rustc] +source = "./Cargo.toml" + +[language-server.rust-analyzer.config.cargo] +sysrootSrc = "./library" + +[language-server.rust-analyzer.config.cargo.extraEnv] +RUSTC_BOOTSTRAP = "1" + +[language-server.rust-analyzer.config.cargo.buildScripts] +enable = true +invocationLocation = "root" +invocationStrategy = "once" +overrideCommand = [ + "python3", + "x.py", + "check", + "--json-output", +] From a1846ec22f33748aca79b2106fa85c3576e5db68 Mon Sep 17 00:00:00 2001 From: Kajetan Puchalski Date: Fri, 27 Sep 2024 17:29:31 +0100 Subject: [PATCH 334/683] gitignore: Add eglot LSP config file --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 2e6499081a6..d6d8b99f602 100644 --- a/.gitignore +++ b/.gitignore @@ -25,6 +25,7 @@ Session.vim .favorites.json .settings/ .vs/ +.dir-locals.el ## Tool .valgrindrc From 94a3f96f71e78e74c1fdf76ed6dad5b042accfaf Mon Sep 17 00:00:00 2001 From: binarycat Date: Fri, 27 Sep 2024 12:43:34 -0400 Subject: [PATCH 335/683] rustdoc: lists items that contain multiple paragraphs are more clear fixes https://github.com/rust-lang/rust/issues/130622 --- src/librustdoc/html/static/css/rustdoc.css | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index 40391b1b4df..67d74399a1f 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -958,6 +958,13 @@ pre, .rustdoc.src .example-wrap, .example-wrap .src-line-numbers { display: inline-block; } +.docblock li { + margin-bottom: .8em; +} +.docblock li p { + margin-bottom: .1em; +} + /* "where ..." clauses with block display are also smaller */ div.where { white-space: pre-wrap; From 605f88aab80de3e8f02d919456323702abba9f81 Mon Sep 17 00:00:00 2001 From: Alex Macleod Date: Fri, 27 Sep 2024 16:56:04 +0000 Subject: [PATCH 336/683] Ignore `--print`/`-Vv` requests in `clippy-driver` --- src/driver.rs | 47 +++++++++++++++++++++++++++++------------------ 1 file changed, 29 insertions(+), 18 deletions(-) diff --git a/src/driver.rs b/src/driver.rs index 324f754e615..afd9df6c0fc 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -22,7 +22,6 @@ use rustc_span::symbol::Symbol; use std::env; use std::fs::read_to_string; -use std::ops::Deref; use std::path::Path; use std::process::exit; @@ -30,12 +29,8 @@ use anstream::println; /// If a command-line option matches `find_arg`, then apply the predicate `pred` on its value. If /// true, then return it. The parameter is assumed to be either `--arg=value` or `--arg value`. -fn arg_value<'a, T: Deref>( - args: &'a [T], - find_arg: &str, - pred: impl Fn(&str) -> bool, -) -> Option<&'a str> { - let mut args = args.iter().map(Deref::deref); +fn arg_value<'a>(args: &'a [String], find_arg: &str, pred: impl Fn(&str) -> bool) -> Option<&'a str> { + let mut args = args.iter().map(String::as_str); while let Some(arg) = args.next() { let mut arg = arg.splitn(2, '='); if arg.next() != Some(find_arg) { @@ -50,11 +45,15 @@ fn arg_value<'a, T: Deref>( None } +fn has_arg(args: &[String], find_arg: &str) -> bool { + args.iter().any(|arg| find_arg == arg.split('=').next().unwrap()) +} + #[test] fn test_arg_value() { - let args = &["--bar=bar", "--foobar", "123", "--foo"]; + let args = &["--bar=bar", "--foobar", "123", "--foo"].map(String::from); - assert_eq!(arg_value(&[] as &[&str], "--foobar", |_| true), None); + assert_eq!(arg_value(&[], "--foobar", |_| true), None); assert_eq!(arg_value(args, "--bar", |_| false), None); assert_eq!(arg_value(args, "--bar", |_| true), Some("bar")); assert_eq!(arg_value(args, "--bar", |p| p == "bar"), Some("bar")); @@ -65,6 +64,16 @@ fn test_arg_value() { assert_eq!(arg_value(args, "--foo", |_| true), None); } +#[test] +fn test_has_arg() { + let args = &["--foo=bar", "-vV", "--baz"].map(String::from); + assert!(has_arg(args, "--foo")); + assert!(has_arg(args, "--baz")); + assert!(has_arg(args, "-vV")); + + assert!(!has_arg(args, "--bar")); +} + fn track_clippy_args(psess: &mut ParseSess, args_env_var: &Option) { psess.env_depinfo.get_mut().insert(( Symbol::intern("CLIPPY_ARGS"), @@ -189,7 +198,7 @@ pub fn main() { let mut orig_args = rustc_driver::args::raw_args(&early_dcx)?; let has_sysroot_arg = |args: &mut [String]| -> bool { - if arg_value(args, "--sysroot", |_| true).is_some() { + if has_arg(args, "--sysroot") { return true; } // https://doc.rust-lang.org/rustc/command-line-arguments.html#path-load-command-line-flags-from-a-path @@ -199,7 +208,7 @@ pub fn main() { if let Some(arg_file_path) = arg.strip_prefix('@') { if let Ok(arg_file) = read_to_string(arg_file_path) { let split_arg_file: Vec = arg_file.lines().map(ToString::to_string).collect(); - if arg_value(&split_arg_file, "--sysroot", |_| true).is_some() { + if has_arg(&split_arg_file, "--sysroot") { return true; } } @@ -271,16 +280,18 @@ pub fn main() { .chain(vec!["--cfg".into(), "clippy".into()]) .collect::>(); - // We enable Clippy if one of the following conditions is met - // - IF Clippy is run on its test suite OR - // - IF Clippy is run on the main crate, not on deps (`!cap_lints_allow`) THEN - // - IF `--no-deps` is not set (`!no_deps`) OR - // - IF `--no-deps` is set and Clippy is run on the specified primary package + // If no Clippy lints will be run we do not need to run Clippy 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(); - let in_primary_package = env::var("CARGO_PRIMARY_PACKAGE").is_ok(); - let clippy_enabled = !cap_lints_allow && (!no_deps || in_primary_package); + // If `--no-deps` is enabled only lint the primary pacakge + 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 + // https://github.com/rust-lang/cargo/issues/14385 + let info_query = has_arg(&orig_args, "-vV") || has_arg(&orig_args, "--print"); + + let clippy_enabled = !cap_lints_allow && relevant_package && !info_query; if clippy_enabled { args.extend(clippy_args); rustc_driver::RunCompiler::new(&args, &mut ClippyCallbacks { clippy_args_var }) From 74d7b226ee511700de42e70a34ca47b6e181e031 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Fri, 27 Sep 2024 17:09:23 +0000 Subject: [PATCH 337/683] Update cc to 1.1.22 --- src/tools/miri/Cargo.lock | 13 +++++++++++-- .../miri/bench-cargo-miri/backtraces/Cargo.lock | 13 +++++++++++-- src/tools/miri/test_dependencies/Cargo.lock | 13 +++++++++++-- 3 files changed, 33 insertions(+), 6 deletions(-) diff --git a/src/tools/miri/Cargo.lock b/src/tools/miri/Cargo.lock index 002c44b0cc5..14b719300a8 100644 --- a/src/tools/miri/Cargo.lock +++ b/src/tools/miri/Cargo.lock @@ -137,9 +137,12 @@ dependencies = [ [[package]] name = "cc" -version = "1.1.7" +version = "1.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26a5c3fd7bfa1ce3897a3a3501d362b2d87b7f2583ebcb4a949ec25911025cbc" +checksum = "9540e661f81799159abee814118cc139a2004b3a3aa3ea37724a1b66530b90e0" +dependencies = [ + "shlex", +] [[package]] name = "cfg-if" @@ -947,6 +950,12 @@ dependencies = [ "lazy_static", ] +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + [[package]] name = "siphasher" version = "0.3.11" diff --git a/src/tools/miri/bench-cargo-miri/backtraces/Cargo.lock b/src/tools/miri/bench-cargo-miri/backtraces/Cargo.lock index 375b129a7e5..848864ea1f3 100644 --- a/src/tools/miri/bench-cargo-miri/backtraces/Cargo.lock +++ b/src/tools/miri/bench-cargo-miri/backtraces/Cargo.lock @@ -41,9 +41,12 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.73" +version = "1.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" +checksum = "9540e661f81799159abee814118cc139a2004b3a3aa3ea37724a1b66530b90e0" +dependencies = [ + "shlex", +] [[package]] name = "cfg-if" @@ -92,3 +95,9 @@ name = "rustc-demangle" version = "0.1.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342" + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" diff --git a/src/tools/miri/test_dependencies/Cargo.lock b/src/tools/miri/test_dependencies/Cargo.lock index 9a4431eb704..64bfc84ef20 100644 --- a/src/tools/miri/test_dependencies/Cargo.lock +++ b/src/tools/miri/test_dependencies/Cargo.lock @@ -52,9 +52,12 @@ checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50" [[package]] name = "cc" -version = "1.1.7" +version = "1.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26a5c3fd7bfa1ce3897a3a3501d362b2d87b7f2583ebcb4a949ec25911025cbc" +checksum = "9540e661f81799159abee814118cc139a2004b3a3aa3ea37724a1b66530b90e0" +dependencies = [ + "shlex", +] [[package]] name = "cfg-if" @@ -261,6 +264,12 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + [[package]] name = "signal-hook-registry" version = "1.4.2" From 12575df6ba2d897f7d8a91c252ca0af4451f5024 Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Fri, 27 Sep 2024 12:37:56 -0400 Subject: [PATCH 338/683] Cleanup --- Cargo.lock | 10 ++++++---- Cargo.toml | 4 ++-- build_system/src/build.rs | 10 +--------- src/base.rs | 4 ---- src/declare.rs | 14 +++----------- 5 files changed, 12 insertions(+), 30 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 42528419a25..f2a368395b2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -79,16 +79,18 @@ dependencies = [ [[package]] name = "gccjit" -version = "2.1.0" -source = "git+https://github.com/rust-lang/gccjit.rs#4fbe2023250357378fb2faf6f484b34cb8f8ebc3" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bb376e98c82d9284c3a17fc1d6bf9bc921055418950238d7a553c27a7e1f6ab" dependencies = [ "gccjit_sys", ] [[package]] name = "gccjit_sys" -version = "0.2.0" -source = "git+https://github.com/rust-lang/gccjit.rs#4fbe2023250357378fb2faf6f484b34cb8f8ebc3" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93b4b1be553b5df790bf25ca2a1d6add81727dc29f8d5c8742468ed306d621d1" dependencies = [ "libc", ] diff --git a/Cargo.toml b/Cargo.toml index 67a90cc34ee..22b953cd2d1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,8 +22,8 @@ master = ["gccjit/master"] default = ["master"] [dependencies] -#gccjit = "2.1" -gccjit = { git = "https://github.com/rust-lang/gccjit.rs" } +gccjit = "2.2" +#gccjit = { git = "https://github.com/rust-lang/gccjit.rs" } # Local copy. #gccjit = { path = "../gccjit.rs" } diff --git a/build_system/src/build.rs b/build_system/src/build.rs index d5d099fb14c..d0ced211a61 100644 --- a/build_system/src/build.rs +++ b/build_system/src/build.rs @@ -131,15 +131,7 @@ pub fn build_sysroot(env: &HashMap, config: &ConfigInfo) -> Resu rustflags.push_str(" -Csymbol-mangling-version=v0"); } - let mut args: Vec<&dyn AsRef> = vec![ - &"cargo", - &"build", - &"--target", - &config.target, - // TODO: remove this feature? - &"--features", - &"std/compiler-builtins-no-f16-f128", - ]; + let mut args: Vec<&dyn AsRef> = vec![&"cargo", &"build", &"--target", &config.target]; for feature in &config.features { args.push(&"--features"); args.push(feature); diff --git a/src/base.rs b/src/base.rs index b8f511b73a0..2eaab3ed00c 100644 --- a/src/base.rs +++ b/src/base.rs @@ -116,10 +116,6 @@ pub fn compile_codegen_unit( context.add_command_line_option("-mavx"); } - /*for feature in tcx.sess.opts.cg.target_feature.split(',') { - println!("Feature: {}", feature); - }*/ - for arg in &tcx.sess.opts.cg.llvm_args { context.add_command_line_option(arg); } diff --git a/src/declare.rs b/src/declare.rs index cbf82918a9c..aa7709488e6 100644 --- a/src/declare.rs +++ b/src/declare.rs @@ -170,17 +170,9 @@ fn declare_raw_fn<'gcc>( if name.starts_with("llvm.") { let intrinsic = match name { "llvm.fma.f16" => { - let param1 = cx.context.new_parameter(None, cx.double_type, "x"); - let param2 = cx.context.new_parameter(None, cx.double_type, "y"); - let param3 = cx.context.new_parameter(None, cx.double_type, "z"); - cx.context.new_function( - None, - FunctionType::Extern, - cx.double_type, - &[param1, param2, param3], - "fma", - false, - ) + // fma is not a target builtin, but a normal builtin, so we handle it differently + // here. + cx.context.get_builtin_function("fma") } _ => llvm::intrinsic(name, cx), }; From e5e1fadc2b9b6395a29a76396d20827ca5405809 Mon Sep 17 00:00:00 2001 From: Jack Huey <31162821+jackh726@users.noreply.github.com> Date: Sun, 22 Sep 2024 15:42:55 -0400 Subject: [PATCH 339/683] Cleanup some known-bug issues --- .../in-trait/async-generics-and-bounds.rs | 3 +-- .../in-trait/async-generics-and-bounds.stderr | 4 +-- .../ui/async-await/in-trait/async-generics.rs | 3 +-- .../in-trait/async-generics.stderr | 4 +-- .../coherence/auxiliary/parametrized-trait.rs | 3 +++ .../coherence/occurs-check/associated-type.rs | 2 +- .../orphan-check-alias.classic.stderr | 15 +++++++++++ .../coherence/orphan-check-alias.next.stderr | 15 +++++++++++ tests/ui/coherence/orphan-check-alias.rs | 25 +++++++++++++++++++ .../bugs/issue-100013.rs | 2 +- .../bugs/issue-87735.rs | 2 +- .../bugs/issue-91762.rs | 2 +- tests/ui/never_type/exhaustive_patterns.rs | 4 ++- .../ui/never_type/exhaustive_patterns.stderr | 4 +-- ...102048.stderr => issue-102048.next.stderr} | 2 +- .../next-solver/coherence/issue-102048.rs | 9 +++++-- .../implied_lifetime_wf_check.error.stderr | 12 +++++++++ .../implied_lifetime_wf_check.rs | 12 +++++---- 18 files changed, 100 insertions(+), 23 deletions(-) create mode 100644 tests/ui/coherence/orphan-check-alias.classic.stderr create mode 100644 tests/ui/coherence/orphan-check-alias.next.stderr create mode 100644 tests/ui/coherence/orphan-check-alias.rs rename tests/ui/traits/next-solver/coherence/{issue-102048.stderr => issue-102048.next.stderr} (96%) create mode 100644 tests/ui/type-alias-impl-trait/implied_lifetime_wf_check.error.stderr diff --git a/tests/ui/async-await/in-trait/async-generics-and-bounds.rs b/tests/ui/async-await/in-trait/async-generics-and-bounds.rs index aede820f6fd..89f6e057aaa 100644 --- a/tests/ui/async-await/in-trait/async-generics-and-bounds.rs +++ b/tests/ui/async-await/in-trait/async-generics-and-bounds.rs @@ -1,5 +1,4 @@ -//@ check-fail -//@ known-bug: #102682 +//@ known-bug: #130935 //@ edition: 2021 use std::fmt::Debug; diff --git a/tests/ui/async-await/in-trait/async-generics-and-bounds.stderr b/tests/ui/async-await/in-trait/async-generics-and-bounds.stderr index b547da7126a..183b0fa152a 100644 --- a/tests/ui/async-await/in-trait/async-generics-and-bounds.stderr +++ b/tests/ui/async-await/in-trait/async-generics-and-bounds.stderr @@ -1,5 +1,5 @@ error[E0311]: the parameter type `T` may not live long enough - --> $DIR/async-generics-and-bounds.rs:9:5 + --> $DIR/async-generics-and-bounds.rs:8:5 | LL | async fn foo(&self) -> &(T, U) where T: Debug + Sized, U: Hash; | ^^^^^^^^^^^^^-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -13,7 +13,7 @@ LL | async fn foo<'a>(&'a self) -> &'a (T, U) where T: Debug + Sized, U: Has | ++++ ++ ++ +++++++ error[E0311]: the parameter type `U` may not live long enough - --> $DIR/async-generics-and-bounds.rs:9:5 + --> $DIR/async-generics-and-bounds.rs:8:5 | LL | async fn foo(&self) -> &(T, U) where T: Debug + Sized, U: Hash; | ^^^^^^^^^^^^^-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/async-await/in-trait/async-generics.rs b/tests/ui/async-await/in-trait/async-generics.rs index eedc63fa24c..2302407e1eb 100644 --- a/tests/ui/async-await/in-trait/async-generics.rs +++ b/tests/ui/async-await/in-trait/async-generics.rs @@ -1,5 +1,4 @@ -//@ check-fail -//@ known-bug: #102682 +//@ known-bug: #130935 //@ edition: 2021 trait MyTrait { diff --git a/tests/ui/async-await/in-trait/async-generics.stderr b/tests/ui/async-await/in-trait/async-generics.stderr index 2e29a9bcc77..8916ef5ab68 100644 --- a/tests/ui/async-await/in-trait/async-generics.stderr +++ b/tests/ui/async-await/in-trait/async-generics.stderr @@ -1,5 +1,5 @@ error[E0311]: the parameter type `T` may not live long enough - --> $DIR/async-generics.rs:6:5 + --> $DIR/async-generics.rs:5:5 | LL | async fn foo(&self) -> &(T, U); | ^^^^^^^^^^^^^-^^^^^^^^^^^^^^^^^ @@ -13,7 +13,7 @@ LL | async fn foo<'a>(&'a self) -> &'a (T, U) where T: 'a; | ++++ ++ ++ +++++++++++ error[E0311]: the parameter type `U` may not live long enough - --> $DIR/async-generics.rs:6:5 + --> $DIR/async-generics.rs:5:5 | LL | async fn foo(&self) -> &(T, U); | ^^^^^^^^^^^^^-^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/coherence/auxiliary/parametrized-trait.rs b/tests/ui/coherence/auxiliary/parametrized-trait.rs index 88a3d5cd52d..f9dbdd4ff18 100644 --- a/tests/ui/coherence/auxiliary/parametrized-trait.rs +++ b/tests/ui/coherence/auxiliary/parametrized-trait.rs @@ -1,2 +1,5 @@ pub trait Trait0 {} pub trait Trait1 {} +pub trait Trait2 { + type Assoc; +} diff --git a/tests/ui/coherence/occurs-check/associated-type.rs b/tests/ui/coherence/occurs-check/associated-type.rs index df03d5f60a0..4441c38ba6d 100644 --- a/tests/ui/coherence/occurs-check/associated-type.rs +++ b/tests/ui/coherence/occurs-check/associated-type.rs @@ -1,7 +1,7 @@ //@ revisions: old next //@[next] compile-flags: -Znext-solver -// A regression test for #105787 +// A (partial) regression test for #105787 // Using the higher ranked projection hack to prevent us from replacing the projection // with an inference variable. diff --git a/tests/ui/coherence/orphan-check-alias.classic.stderr b/tests/ui/coherence/orphan-check-alias.classic.stderr new file mode 100644 index 00000000000..3fd62b05b4d --- /dev/null +++ b/tests/ui/coherence/orphan-check-alias.classic.stderr @@ -0,0 +1,15 @@ +warning[E0210]: type parameter `T` must be covered by another type when it appears before the first local type (`B`) + --> $DIR/orphan-check-alias.rs:21:6 + | +LL | impl foreign::Trait2 for ::Assoc { + | ^ type parameter `T` must be covered by another type when it appears before the first local type (`B`) + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #124559 + = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local, and no uncovered type parameters appear before that first local type + = note: in this case, 'before' refers to the following order: `impl<..> ForeignTrait for T0`, where `T0` is the first and `Tn` is the last + = note: `#[warn(uncovered_param_in_projection)]` on by default + +warning: 1 warning emitted + +For more information about this error, try `rustc --explain E0210`. diff --git a/tests/ui/coherence/orphan-check-alias.next.stderr b/tests/ui/coherence/orphan-check-alias.next.stderr new file mode 100644 index 00000000000..3fd62b05b4d --- /dev/null +++ b/tests/ui/coherence/orphan-check-alias.next.stderr @@ -0,0 +1,15 @@ +warning[E0210]: type parameter `T` must be covered by another type when it appears before the first local type (`B`) + --> $DIR/orphan-check-alias.rs:21:6 + | +LL | impl foreign::Trait2 for ::Assoc { + | ^ type parameter `T` must be covered by another type when it appears before the first local type (`B`) + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #124559 + = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local, and no uncovered type parameters appear before that first local type + = note: in this case, 'before' refers to the following order: `impl<..> ForeignTrait for T0`, where `T0` is the first and `Tn` is the last + = note: `#[warn(uncovered_param_in_projection)]` on by default + +warning: 1 warning emitted + +For more information about this error, try `rustc --explain E0210`. diff --git a/tests/ui/coherence/orphan-check-alias.rs b/tests/ui/coherence/orphan-check-alias.rs new file mode 100644 index 00000000000..d6c9d0aa8be --- /dev/null +++ b/tests/ui/coherence/orphan-check-alias.rs @@ -0,0 +1,25 @@ +// Alias might not cover type parameters. + +//@ revisions: classic next +//@[next] compile-flags: -Znext-solver + +//@ aux-crate:foreign=parametrized-trait.rs +//@ edition:2021 + +//@ known-bug: #99554 +//@ check-pass + +trait Id { + type Assoc; +} + +impl Id for T { + type Assoc = T; +} + +pub struct B; +impl foreign::Trait2 for ::Assoc { + type Assoc = usize; +} + +fn main() {} diff --git a/tests/ui/generic-associated-types/bugs/issue-100013.rs b/tests/ui/generic-associated-types/bugs/issue-100013.rs index 994f41e9f86..ac72c29c03b 100644 --- a/tests/ui/generic-associated-types/bugs/issue-100013.rs +++ b/tests/ui/generic-associated-types/bugs/issue-100013.rs @@ -1,5 +1,5 @@ //@ check-fail -//@ known-bug: unknown +//@ known-bug: #100013 //@ edition: 2021 // We really should accept this, but we need implied bounds between the regions diff --git a/tests/ui/generic-associated-types/bugs/issue-87735.rs b/tests/ui/generic-associated-types/bugs/issue-87735.rs index e864ad7c815..0a24151cda7 100644 --- a/tests/ui/generic-associated-types/bugs/issue-87735.rs +++ b/tests/ui/generic-associated-types/bugs/issue-87735.rs @@ -1,5 +1,5 @@ //@ check-fail -//@ known-bug: #87735, #88526 +//@ known-bug: unknown // This should pass, but we need an extension of implied bounds (probably). diff --git a/tests/ui/generic-associated-types/bugs/issue-91762.rs b/tests/ui/generic-associated-types/bugs/issue-91762.rs index b4799eb12f4..77bd275fa88 100644 --- a/tests/ui/generic-associated-types/bugs/issue-91762.rs +++ b/tests/ui/generic-associated-types/bugs/issue-91762.rs @@ -1,5 +1,5 @@ //@ check-fail -//@ known-bug: unknown +//@ known-bug: #91762 // We almost certainly want this to pass, but // it's particularly difficult currently, because we need a way of specifying diff --git a/tests/ui/never_type/exhaustive_patterns.rs b/tests/ui/never_type/exhaustive_patterns.rs index 3c53ac319b4..b56eab6cb9d 100644 --- a/tests/ui/never_type/exhaustive_patterns.rs +++ b/tests/ui/never_type/exhaustive_patterns.rs @@ -1,5 +1,4 @@ //@ check-fail -//@ known-bug: #104034 #![feature(exhaustive_patterns, never_type)] @@ -17,5 +16,8 @@ fn foo() -> Either<(), !> { } fn main() { + // We can't treat this a irrefutable, because `Either::B` could become + // inhabited in the future because it's private. let Either::A(()) = foo(); + //~^ error refutable pattern in local binding } diff --git a/tests/ui/never_type/exhaustive_patterns.stderr b/tests/ui/never_type/exhaustive_patterns.stderr index ee7d9070cd3..1314cbc52f8 100644 --- a/tests/ui/never_type/exhaustive_patterns.stderr +++ b/tests/ui/never_type/exhaustive_patterns.stderr @@ -1,5 +1,5 @@ error[E0005]: refutable pattern in local binding - --> $DIR/exhaustive_patterns.rs:20:9 + --> $DIR/exhaustive_patterns.rs:21:9 | LL | let Either::A(()) = foo(); | ^^^^^^^^^^^^^ pattern `Either::B(_)` not covered @@ -7,7 +7,7 @@ LL | let Either::A(()) = foo(); = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html note: `Either<(), !>` defined here - --> $DIR/exhaustive_patterns.rs:10:6 + --> $DIR/exhaustive_patterns.rs:9:6 | LL | enum Either { | ^^^^^^ diff --git a/tests/ui/traits/next-solver/coherence/issue-102048.stderr b/tests/ui/traits/next-solver/coherence/issue-102048.next.stderr similarity index 96% rename from tests/ui/traits/next-solver/coherence/issue-102048.stderr rename to tests/ui/traits/next-solver/coherence/issue-102048.next.stderr index 4e93ae28496..39fde307f23 100644 --- a/tests/ui/traits/next-solver/coherence/issue-102048.stderr +++ b/tests/ui/traits/next-solver/coherence/issue-102048.next.stderr @@ -1,5 +1,5 @@ error[E0119]: conflicting implementations of trait `Trait fn(<_ as WithAssoc1<'a>>::Assoc, <_ as WithAssoc2<'a>>::Assoc)>` for type `(_, _)` - --> $DIR/issue-102048.rs:39:1 + --> $DIR/issue-102048.rs:44:1 | LL | / impl Trait fn(>::Assoc, >::Assoc)> for (T, U) LL | | where diff --git a/tests/ui/traits/next-solver/coherence/issue-102048.rs b/tests/ui/traits/next-solver/coherence/issue-102048.rs index 64b223822c6..16ae5d98488 100644 --- a/tests/ui/traits/next-solver/coherence/issue-102048.rs +++ b/tests/ui/traits/next-solver/coherence/issue-102048.rs @@ -17,7 +17,12 @@ // that to `i32`. We then try to unify `i32` from `impl1` with `u32` from `impl2` which fails, // causing coherence to consider these two impls distinct. -//@ compile-flags: -Znext-solver +//@ revisions: classic next +//@[next] compile-flags: -Znext-solver + +//@[classic] known-bug: #102048 +//@[classic] check-pass + pub trait Trait {} pub trait WithAssoc1<'a> { @@ -37,7 +42,7 @@ where // impl 2 impl Trait fn(>::Assoc, u32)> for (T, U) where - U: for<'a> WithAssoc1<'a> //~^ ERROR conflicting implementations of trait + U: for<'a> WithAssoc1<'a> //[next]~^ ERROR conflicting implementations of trait { } diff --git a/tests/ui/type-alias-impl-trait/implied_lifetime_wf_check.error.stderr b/tests/ui/type-alias-impl-trait/implied_lifetime_wf_check.error.stderr new file mode 100644 index 00000000000..a97227e481e --- /dev/null +++ b/tests/ui/type-alias-impl-trait/implied_lifetime_wf_check.error.stderr @@ -0,0 +1,12 @@ +error[E0119]: conflicting implementations of trait `Yay` for type `Alias` + --> $DIR/implied_lifetime_wf_check.rs:26:1 + | +LL | impl Yay for <() as HideIt>::Assoc {} + | ---------------------------------- first implementation here +LL | #[cfg(error)] +LL | impl Yay for i32 {} + | ^^^^^^^^^^^^^^^^ conflicting implementation for `Alias` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0119`. diff --git a/tests/ui/type-alias-impl-trait/implied_lifetime_wf_check.rs b/tests/ui/type-alias-impl-trait/implied_lifetime_wf_check.rs index bc9d760cd29..d85c7f60023 100644 --- a/tests/ui/type-alias-impl-trait/implied_lifetime_wf_check.rs +++ b/tests/ui/type-alias-impl-trait/implied_lifetime_wf_check.rs @@ -1,8 +1,9 @@ #![feature(type_alias_impl_trait)] -//@ known-bug: #99840 -// this should not compile -//@ check-pass +//@ revisions: pass error + +//@[pass] check-pass +//@[error] check-fail type Alias = impl Sized; @@ -21,7 +22,8 @@ impl HideIt for () { pub trait Yay {} impl Yay for <() as HideIt>::Assoc {} -// impl Yay for i32 {} // this already errors -// impl Yay for u32 {} // this also already errors +#[cfg(error)] +impl Yay for i32 {} +//[error]~^ error conflicting implementations fn main() {} From 3b9db47f07e2b609dc2acf45b0eaa7239ef76f49 Mon Sep 17 00:00:00 2001 From: Predrag Gruevski <2348618+obi1kenobi@users.noreply.github.com> Date: Fri, 27 Sep 2024 14:34:48 -0400 Subject: [PATCH 340/683] rustdoc: update `ProcMacro` docs section on helper attributes I believe the mention of attribute macros in the section on proc macro helper attributes is erroneous. As far as I can tell, attribute macros cannot define helper attributes. The following attribute macro is not valid (fails to build), no matter how I try to define (or skip defining) the helpers: ```rust #[proc_macro_attribute(attributes(helper))] pub fn attribute_helpers(_attr: TokenStream, item: TokenStream) -> TokenStream { item } ``` The [language reference](https://doc.rust-lang.org/reference/procedural-macros.html#attribute-macros) also doesn't seem to mention attribute macro helpers. The helpers subsection is inside the section on derive macros. --- src/rustdoc-json-types/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rustdoc-json-types/lib.rs b/src/rustdoc-json-types/lib.rs index ef21779b099..b3707cf6157 100644 --- a/src/rustdoc-json-types/lib.rs +++ b/src/rustdoc-json-types/lib.rs @@ -1168,7 +1168,7 @@ pub struct ProcMacro { pub kind: MacroKind, /// Helper attributes defined by a macro to be used inside it. /// - /// Defined only for attribute & derive macros. + /// Defined only for derive macros. /// /// E.g. the [`Default`] derive macro defines a `#[default]` helper attribute so that one can /// do: From 282d04489adefc09286160719676a309e26ddd07 Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Fri, 27 Sep 2024 11:45:59 -0700 Subject: [PATCH 341/683] Revert "ci: Try to remove unused Xcode dirs" This reverts commit 06f49f6d5326440192b8d31d69fa490dbfe01cfe. --- src/ci/scripts/select-xcode.sh | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/src/ci/scripts/select-xcode.sh b/src/ci/scripts/select-xcode.sh index d635d438472..569c4a4136d 100755 --- a/src/ci/scripts/select-xcode.sh +++ b/src/ci/scripts/select-xcode.sh @@ -1,6 +1,5 @@ #!/bin/bash # This script selects the Xcode instance to use. -# It also tries to do some cleanup in CI jobs of unused Xcodes. set -euo pipefail IFS=$'\n\t' @@ -8,21 +7,5 @@ IFS=$'\n\t' source "$(cd "$(dirname "$0")" && pwd)/../shared.sh" if isMacOS; then - # This additional step is to try to remove an Xcode we aren't using because each one is HUGE - old_xcode="$(xcode-select --print-path)" - old_xcode="${old_xcode%/*}" # pop a dir - old_xcode="${old_xcode%/*}" # twice - if [[ $old_xcode =~ $SELECT_XCODE ]]; then - echo "xcode-select.sh's brutal hack may not be necessary?" - exit 1 - elif [[ $SELECT_XCODE =~ "16" ]]; then - echo "Using Xcode 16? Please fix xcode-select.sh" - exit 1 - fi - if [ $CI ]; then # just in case someone sources this on their real computer - sudo rm -rf "${old_xcode}" - xcode_16="${old_xcode%/*}/Xcode-16.0.0.app" - sudo rm -rf "${xcode_16}" - fi sudo xcode-select -s "${SELECT_XCODE}" fi From a2a4ea0850b7324fcf0bb1779d3b1f288835b2f4 Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Fri, 27 Sep 2024 11:47:07 -0700 Subject: [PATCH 342/683] Partially revert "ci: Use mv instead of cp in upload step" This partially reverts commit fe7c97c2e732de8dfc93ef21ee84ccfbc04c7d0c. I kept a mv, not a cp, for the one that shuffles major artifacts around, because the size of those artifacts are big enough to matter, sometimes. I don't think the diagnostic info will be that heavy, by comparison. --- src/ci/scripts/upload-artifacts.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ci/scripts/upload-artifacts.sh b/src/ci/scripts/upload-artifacts.sh index 61c187fa77c..0bc91f6ba71 100755 --- a/src/ci/scripts/upload-artifacts.sh +++ b/src/ci/scripts/upload-artifacts.sh @@ -23,14 +23,14 @@ if [[ "${DEPLOY-0}" -eq "1" ]] || [[ "${DEPLOY_ALT-0}" -eq "1" ]]; then fi # CPU usage statistics. -mv build/cpu-usage.csv "${upload_dir}/cpu-${CI_JOB_NAME}.csv" +cp build/cpu-usage.csv "${upload_dir}/cpu-${CI_JOB_NAME}.csv" # Build metrics generated by x.py. -mv "${build_dir}/metrics.json" "${upload_dir}/metrics-${CI_JOB_NAME}.json" +cp "${build_dir}/metrics.json" "${upload_dir}/metrics-${CI_JOB_NAME}.json" # Toolstate data. if [[ -n "${DEPLOY_TOOLSTATES_JSON+x}" ]]; then - mv /tmp/toolstate/toolstates.json "${upload_dir}/${DEPLOY_TOOLSTATES_JSON}" + cp /tmp/toolstate/toolstates.json "${upload_dir}/${DEPLOY_TOOLSTATES_JSON}" fi echo "Files that will be uploaded:" From 8302f2e35fe7d9fc4cafbe2d5057775e82fc9690 Mon Sep 17 00:00:00 2001 From: Lukas Markeffsky <@> Date: Fri, 27 Sep 2024 19:27:48 +0200 Subject: [PATCH 343/683] add even more tests for ptr-to-ptr casts on trait objects --- ...ptr-to-trait-obj-different-regions-misc.rs | 6 ++++ ...to-trait-obj-different-regions-misc.stderr | 35 +++++++++++++++---- tests/ui/cast/ptr-to-trait-obj-ok.rs | 34 +++++++++++++++++- tests/ui/cast/ptr-to-trait-obj-ok.stderr | 24 +++++++++++++ 4 files changed, 92 insertions(+), 7 deletions(-) create mode 100644 tests/ui/cast/ptr-to-trait-obj-ok.stderr 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 d7c6c50d8be..18566acc07f 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 @@ -15,6 +15,12 @@ fn change_lt_ba<'a, 'b: 'a>(x: *mut dyn Trait<'a>) -> *mut dyn Trait<'b> { x as _ //~ error: lifetime may not live long enough } +fn change_lt_hr<'a>(x: *mut dyn Trait<'a>) -> *mut dyn for<'b> Trait<'b> { + x as _ //~ error: lifetime may not live long enough + //~^ error: mismatched types + //~| one type is more general than the other +} + trait Assocked { type Assoc: ?Sized; } 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 6069f4f3b55..6f590585c4a 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 @@ -61,7 +61,29 @@ LL | x as _ = help: see for more information about variance error: lifetime may not live long enough - --> $DIR/ptr-to-trait-obj-different-regions-misc.rs:25:5 + --> $DIR/ptr-to-trait-obj-different-regions-misc.rs:19:5 + | +LL | fn change_lt_hr<'a>(x: *mut dyn Trait<'a>) -> *mut dyn for<'b> Trait<'b> { + | -- lifetime `'a` defined here +LL | x as _ + | ^^^^^^ cast requires that `'a` must outlive `'static` + | +help: to declare that the trait object captures data from argument `x`, you can add an explicit `'a` lifetime bound + | +LL | fn change_lt_hr<'a>(x: *mut dyn Trait<'a>) -> *mut dyn for<'b> Trait<'b> + 'a { + | ++++ + +error[E0308]: mismatched types + --> $DIR/ptr-to-trait-obj-different-regions-misc.rs:19:5 + | +LL | x as _ + | ^^^^^^ one type is more general than the other + | + = note: expected trait object `dyn for<'b> Trait<'b>` + found trait object `dyn Trait<'_>` + +error: lifetime may not live long enough + --> $DIR/ptr-to-trait-obj-different-regions-misc.rs:31:5 | LL | fn change_assoc_0<'a, 'b>( | -- -- lifetime `'b` defined here @@ -77,7 +99,7 @@ LL | x as _ = help: see for more information about variance error: lifetime may not live long enough - --> $DIR/ptr-to-trait-obj-different-regions-misc.rs:25:5 + --> $DIR/ptr-to-trait-obj-different-regions-misc.rs:31:5 | LL | fn change_assoc_0<'a, 'b>( | -- -- lifetime `'b` defined here @@ -97,7 +119,7 @@ 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:32:5 + --> $DIR/ptr-to-trait-obj-different-regions-misc.rs:38:5 | LL | fn change_assoc_1<'a, 'b>( | -- -- lifetime `'b` defined here @@ -113,7 +135,7 @@ LL | x as _ = help: see for more information about variance error: lifetime may not live long enough - --> $DIR/ptr-to-trait-obj-different-regions-misc.rs:32:5 + --> $DIR/ptr-to-trait-obj-different-regions-misc.rs:38:5 | LL | fn change_assoc_1<'a, 'b>( | -- -- lifetime `'b` defined here @@ -133,12 +155,13 @@ 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:39:20 + --> $DIR/ptr-to-trait-obj-different-regions-misc.rs:45:20 | LL | fn extend_to_static<'a>(ptr: *const dyn Trait<'a>) { | -- lifetime `'a` defined here LL | require_static(ptr as _) | ^^^^^^^^ cast requires that `'a` must outlive `'static` -error: aborting due to 9 previous errors +error: aborting due to 11 previous errors +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/cast/ptr-to-trait-obj-ok.rs b/tests/ui/cast/ptr-to-trait-obj-ok.rs index 656c99c58dc..f30472667b7 100644 --- a/tests/ui/cast/ptr-to-trait-obj-ok.rs +++ b/tests/ui/cast/ptr-to-trait-obj-ok.rs @@ -1,4 +1,4 @@ -//@ check-pass +//@ check-fail trait Trait<'a> {} @@ -10,8 +10,40 @@ fn cast_inherent_lt<'a, 'b>(x: *mut (dyn Trait<'static> + 'a)) -> *mut (dyn Trai x as _ } +fn cast_away_higher_ranked<'a>(x: *mut dyn for<'b> Trait<'b>) -> *mut dyn Trait<'a> { + x as _ +} + fn unprincipled<'a, 'b>(x: *mut (dyn Send + 'a)) -> *mut (dyn Sync + 'b) { x as _ } +// If it is possible to coerce from the source to the target type modulo +// regions, then we skip the HIR checks for ptr-to-ptr casts and possibly +// insert an unsizing coercion into the MIR before the ptr-to-ptr cast. +// By wrapping the target type, we ensure that no coercion happens +// and also test the non-coercion cast behavior. +struct Wrapper(T); + +fn remove_auto_wrap<'a>(x: *mut (dyn Trait<'a> + Send)) -> *mut Wrapper> { + x as _ +} + +fn cast_inherent_lt_wrap<'a, 'b>( + x: *mut (dyn Trait<'static> + 'a), +) -> *mut Wrapper + 'b> { + x as _ +} + +fn cast_away_higher_ranked_wrap<'a>(x: *mut dyn for<'b> Trait<'b>) -> *mut Wrapper> { + x as _ + //~^ error: lifetime may not live long enough + //~| error: mismatched types + //~| one type is more general than the other +} + +fn unprincipled_wrap<'a, 'b>(x: *mut (dyn Send + 'a)) -> *mut Wrapper { + x as _ +} + fn main() {} diff --git a/tests/ui/cast/ptr-to-trait-obj-ok.stderr b/tests/ui/cast/ptr-to-trait-obj-ok.stderr new file mode 100644 index 00000000000..8de07691c21 --- /dev/null +++ b/tests/ui/cast/ptr-to-trait-obj-ok.stderr @@ -0,0 +1,24 @@ +error: lifetime may not live long enough + --> $DIR/ptr-to-trait-obj-ok.rs:39:5 + | +LL | fn cast_away_higher_ranked_wrap<'a>(x: *mut dyn for<'b> Trait<'b>) -> *mut Wrapper> { + | -- lifetime `'a` defined here +LL | x as _ + | ^^^^^^ returning this value requires that `'a` must outlive `'static` + | + = note: requirement occurs because of a mutable pointer to `Wrapper>` + = note: mutable pointers are invariant over their type parameter + = help: see for more information about variance + +error[E0308]: mismatched types + --> $DIR/ptr-to-trait-obj-ok.rs:39:5 + | +LL | x as _ + | ^^^^^^ one type is more general than the other + | + = note: expected trait object `dyn for<'b> Trait<'b>` + found trait object `dyn Trait<'_>` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`. From 53f45c4332fa3703bc6866699a40df5fba2fd8ca Mon Sep 17 00:00:00 2001 From: Lukas Markeffsky <@> Date: Fri, 27 Sep 2024 20:02:43 +0200 Subject: [PATCH 344/683] borrowck: use subtyping instead of equality for ptr-to-ptr casts --- compiler/rustc_borrowck/src/type_check/mod.rs | 2 +- tests/ui/cast/ptr-to-trait-obj-ok.rs | 5 +--- tests/ui/cast/ptr-to-trait-obj-ok.stderr | 24 ------------------- 3 files changed, 2 insertions(+), 29 deletions(-) delete mode 100644 tests/ui/cast/ptr-to-trait-obj-ok.stderr diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 16e51e82f85..6b17879de26 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -2437,7 +2437,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { debug!(?src_tty, ?dst_tty, ?src_obj, ?dst_obj); - self.eq_types( + self.sub_types( src_obj, dst_obj, location.to_locations(), diff --git a/tests/ui/cast/ptr-to-trait-obj-ok.rs b/tests/ui/cast/ptr-to-trait-obj-ok.rs index f30472667b7..dbeee9d2944 100644 --- a/tests/ui/cast/ptr-to-trait-obj-ok.rs +++ b/tests/ui/cast/ptr-to-trait-obj-ok.rs @@ -1,4 +1,4 @@ -//@ check-fail +//@ check-pass trait Trait<'a> {} @@ -37,9 +37,6 @@ fn cast_inherent_lt_wrap<'a, 'b>( fn cast_away_higher_ranked_wrap<'a>(x: *mut dyn for<'b> Trait<'b>) -> *mut Wrapper> { x as _ - //~^ error: lifetime may not live long enough - //~| error: mismatched types - //~| one type is more general than the other } fn unprincipled_wrap<'a, 'b>(x: *mut (dyn Send + 'a)) -> *mut Wrapper { diff --git a/tests/ui/cast/ptr-to-trait-obj-ok.stderr b/tests/ui/cast/ptr-to-trait-obj-ok.stderr deleted file mode 100644 index 8de07691c21..00000000000 --- a/tests/ui/cast/ptr-to-trait-obj-ok.stderr +++ /dev/null @@ -1,24 +0,0 @@ -error: lifetime may not live long enough - --> $DIR/ptr-to-trait-obj-ok.rs:39:5 - | -LL | fn cast_away_higher_ranked_wrap<'a>(x: *mut dyn for<'b> Trait<'b>) -> *mut Wrapper> { - | -- lifetime `'a` defined here -LL | x as _ - | ^^^^^^ returning this value requires that `'a` must outlive `'static` - | - = note: requirement occurs because of a mutable pointer to `Wrapper>` - = note: mutable pointers are invariant over their type parameter - = help: see for more information about variance - -error[E0308]: mismatched types - --> $DIR/ptr-to-trait-obj-ok.rs:39:5 - | -LL | x as _ - | ^^^^^^ one type is more general than the other - | - = note: expected trait object `dyn for<'b> Trait<'b>` - found trait object `dyn Trait<'_>` - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0308`. From 4fb097a5de14399b86dda519e1e597104a15b3b2 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 26 Sep 2024 23:20:59 -0400 Subject: [PATCH 345/683] Instantiate binders when checking supertrait upcasting --- compiler/rustc_infer/src/infer/at.rs | 19 +++- .../src/solve/eval_ctxt/mod.rs | 16 ++-- .../src/solve/trait_goals.rs | 49 ++++++---- .../src/traits/select/mod.rs | 96 +++++++++++++++---- 4 files changed, 132 insertions(+), 48 deletions(-) diff --git a/compiler/rustc_infer/src/infer/at.rs b/compiler/rustc_infer/src/infer/at.rs index 9f6a1763866..37f7f04db3f 100644 --- a/compiler/rustc_infer/src/infer/at.rs +++ b/compiler/rustc_infer/src/infer/at.rs @@ -159,7 +159,24 @@ impl<'a, 'tcx> At<'a, 'tcx> { ToTrace::to_trace(self.cause, true, expected, actual), self.param_env, define_opaque_types, - ); + ToTrace::to_trace(self.cause, expected, actual), + expected, + actual, + ) + } + + /// Makes `expected == actual`. + pub fn eq_trace( + self, + define_opaque_types: DefineOpaqueTypes, + trace: TypeTrace<'tcx>, + expected: T, + actual: T, + ) -> InferResult<'tcx, ()> + where + T: Relate>, + { + let mut fields = CombineFields::new(self.infcx, trace, self.param_env, define_opaque_types); fields.equate(StructurallyRelateAliases::No).relate(expected, actual)?; Ok(InferOk { value: (), diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs index 12ad0724b5c..932875b759f 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs @@ -448,10 +448,10 @@ where } } } else { - self.delegate.enter_forall(kind, |kind| { - let goal = goal.with(self.cx(), ty::Binder::dummy(kind)); - self.add_goal(GoalSource::InstantiateHigherRanked, goal); - self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + self.enter_forall(kind, |ecx, kind| { + let goal = goal.with(ecx.cx(), ty::Binder::dummy(kind)); + ecx.add_goal(GoalSource::InstantiateHigherRanked, goal); + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) }) } } @@ -840,12 +840,14 @@ where self.delegate.instantiate_binder_with_infer(value) } + /// `enter_forall`, but takes `&mut self` and passes it back through the + /// callback since it can't be aliased during the call. pub(super) fn enter_forall + Copy, U>( - &self, + &mut self, value: ty::Binder, - f: impl FnOnce(T) -> U, + f: impl FnOnce(&mut Self, T) -> U, ) -> U { - self.delegate.enter_forall(value, f) + self.delegate.enter_forall(value, |value| f(self, value)) } pub(super) fn resolve_vars_if_possible(&self, value: T) -> T diff --git a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs index 0befe7f5e8a..493bbf1e665 100644 --- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs @@ -895,10 +895,13 @@ where source_projection.item_def_id() == target_projection.item_def_id() && ecx .probe(|_| ProbeKind::UpcastProjectionCompatibility) - .enter(|ecx| -> Result<(), NoSolution> { - ecx.sub(param_env, source_projection, target_projection)?; - let _ = ecx.try_evaluate_added_goals()?; - Ok(()) + .enter(|ecx| -> Result<_, NoSolution> { + ecx.enter_forall(target_projection, |ecx, target_projection| { + let source_projection = + ecx.instantiate_binder_with_infer(source_projection); + ecx.eq(param_env, source_projection, target_projection)?; + ecx.try_evaluate_added_goals() + }) }) .is_ok() }; @@ -909,11 +912,14 @@ where // Check that a's supertrait (upcast_principal) is compatible // with the target (b_ty). ty::ExistentialPredicate::Trait(target_principal) => { - ecx.sub( - param_env, - upcast_principal.unwrap(), - bound.rebind(target_principal), - )?; + let source_principal = upcast_principal.unwrap(); + let target_principal = bound.rebind(target_principal); + ecx.enter_forall(target_principal, |ecx, target_principal| { + let source_principal = + ecx.instantiate_binder_with_infer(source_principal); + ecx.eq(param_env, source_principal, target_principal)?; + ecx.try_evaluate_added_goals() + })?; } // Check that b_ty's projection is satisfied by exactly one of // a_ty's projections. First, we look through the list to see if @@ -934,7 +940,12 @@ where Certainty::AMBIGUOUS, ); } - ecx.sub(param_env, source_projection, target_projection)?; + ecx.enter_forall(target_projection, |ecx, target_projection| { + let source_projection = + ecx.instantiate_binder_with_infer(source_projection); + ecx.eq(param_env, source_projection, target_projection)?; + ecx.try_evaluate_added_goals() + })?; } // Check that b_ty's auto traits are present in a_ty's bounds. ty::ExistentialPredicate::AutoTrait(def_id) => { @@ -1187,17 +1198,15 @@ where ) -> Result>, NoSolution>, ) -> Result, NoSolution> { self.probe_trait_candidate(source).enter(|ecx| { - ecx.add_goals( - GoalSource::ImplWhereBound, - constituent_tys(ecx, goal.predicate.self_ty())? - .into_iter() - .map(|ty| { - ecx.enter_forall(ty, |ty| { - goal.with(ecx.cx(), goal.predicate.with_self_ty(ecx.cx(), ty)) - }) + let goals = constituent_tys(ecx, goal.predicate.self_ty())? + .into_iter() + .map(|ty| { + ecx.enter_forall(ty, |ecx, ty| { + goal.with(ecx.cx(), goal.predicate.with_self_ty(ecx.cx(), ty)) }) - .collect::>(), - ); + }) + .collect::>(); + ecx.add_goals(GoalSource::ImplWhereBound, goals); ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) }) } diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 2922a4898e9..c3042ab9636 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -16,6 +16,7 @@ use rustc_hir::LangItem; use rustc_hir::def_id::DefId; use rustc_infer::infer::BoundRegionConversionTime::{self, HigherRankedType}; use rustc_infer::infer::DefineOpaqueTypes; +use rustc_infer::infer::at::ToTrace; use rustc_infer::infer::relate::TypeRelation; use rustc_infer::traits::TraitObligation; use rustc_middle::bug; @@ -44,7 +45,7 @@ use super::{ TraitQueryMode, const_evaluatable, project, util, wf, }; use crate::error_reporting::InferCtxtErrorExt; -use crate::infer::{InferCtxt, InferCtxtExt, InferOk, TypeFreshener}; +use crate::infer::{InferCtxt, InferOk, TypeFreshener}; use crate::solve::InferCtxtSelectExt as _; use crate::traits::normalize::{normalize_with_depth, normalize_with_depth_to}; use crate::traits::project::{ProjectAndUnifyResult, ProjectionCacheKeyExt}; @@ -2579,16 +2580,32 @@ impl<'tcx> SelectionContext<'_, 'tcx> { // Check that a_ty's supertrait (upcast_principal) is compatible // with the target (b_ty). ty::ExistentialPredicate::Trait(target_principal) => { + let hr_source_principal = upcast_principal.map_bound(|trait_ref| { + ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref) + }); + let hr_target_principal = bound.rebind(target_principal); + nested.extend( self.infcx - .at(&obligation.cause, obligation.param_env) - .sup( - DefineOpaqueTypes::Yes, - bound.rebind(target_principal), - upcast_principal.map_bound(|trait_ref| { - ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref) - }), - ) + .enter_forall(hr_target_principal, |target_principal| { + let source_principal = + self.infcx.instantiate_binder_with_fresh_vars( + obligation.cause.span, + HigherRankedType, + hr_source_principal, + ); + self.infcx.at(&obligation.cause, obligation.param_env).eq_trace( + DefineOpaqueTypes::Yes, + ToTrace::to_trace( + &obligation.cause, + true, + hr_target_principal, + hr_source_principal, + ), + target_principal, + source_principal, + ) + }) .map_err(|_| SelectionError::Unimplemented)? .into_obligations(), ); @@ -2599,19 +2616,41 @@ impl<'tcx> SelectionContext<'_, 'tcx> { // return ambiguity. Otherwise, if exactly one matches, equate // it with b_ty's projection. ty::ExistentialPredicate::Projection(target_projection) => { - let target_projection = bound.rebind(target_projection); + let hr_target_projection = bound.rebind(target_projection); + let mut matching_projections = - a_data.projection_bounds().filter(|source_projection| { + a_data.projection_bounds().filter(|&hr_source_projection| { // Eager normalization means that we can just use can_eq // here instead of equating and processing obligations. - source_projection.item_def_id() == target_projection.item_def_id() - && self.infcx.can_eq( - obligation.param_env, - *source_projection, - target_projection, - ) + hr_source_projection.item_def_id() == hr_target_projection.item_def_id() + && self.infcx.probe(|_| { + self.infcx + .enter_forall(hr_target_projection, |target_projection| { + let source_projection = + self.infcx.instantiate_binder_with_fresh_vars( + obligation.cause.span, + HigherRankedType, + hr_source_projection, + ); + self.infcx + .at(&obligation.cause, obligation.param_env) + .eq_trace( + DefineOpaqueTypes::Yes, + ToTrace::to_trace( + &obligation.cause, + true, + hr_target_projection, + hr_source_projection, + ), + target_projection, + source_projection, + ) + }) + .is_ok() + }) }); - let Some(source_projection) = matching_projections.next() else { + + let Some(hr_source_projection) = matching_projections.next() else { return Err(SelectionError::Unimplemented); }; if matching_projections.next().is_some() { @@ -2619,8 +2658,25 @@ impl<'tcx> SelectionContext<'_, 'tcx> { } nested.extend( self.infcx - .at(&obligation.cause, obligation.param_env) - .sup(DefineOpaqueTypes::Yes, target_projection, source_projection) + .enter_forall(hr_target_projection, |target_projection| { + let source_projection = + self.infcx.instantiate_binder_with_fresh_vars( + obligation.cause.span, + HigherRankedType, + hr_source_projection, + ); + self.infcx.at(&obligation.cause, obligation.param_env).eq_trace( + DefineOpaqueTypes::Yes, + ToTrace::to_trace( + &obligation.cause, + true, + hr_target_projection, + hr_source_projection, + ), + target_projection, + source_projection, + ) + }) .map_err(|_| SelectionError::Unimplemented)? .into_obligations(), ); From d753aba3b342a286fbaa198b43154cf7fbe68692 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 26 Sep 2024 23:22:48 -0400 Subject: [PATCH 346/683] Get rid of a_is_expected from ToTrace --- compiler/rustc_infer/src/infer/at.rs | 145 +++++------------- .../src/traits/select/mod.rs | 3 - 2 files changed, 36 insertions(+), 112 deletions(-) diff --git a/compiler/rustc_infer/src/infer/at.rs b/compiler/rustc_infer/src/infer/at.rs index 37f7f04db3f..6ce47db8b9b 100644 --- a/compiler/rustc_infer/src/infer/at.rs +++ b/compiler/rustc_infer/src/infer/at.rs @@ -92,12 +92,7 @@ impl<'tcx> InferCtxt<'tcx> { } pub trait ToTrace<'tcx>: Relate> + Copy { - fn to_trace( - cause: &ObligationCause<'tcx>, - a_is_expected: bool, - a: Self, - b: Self, - ) -> TypeTrace<'tcx>; + fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx>; } impl<'a, 'tcx> At<'a, 'tcx> { @@ -116,7 +111,7 @@ impl<'a, 'tcx> At<'a, 'tcx> { { let mut fields = CombineFields::new( self.infcx, - ToTrace::to_trace(self.cause, true, expected, actual), + ToTrace::to_trace(self.cause, expected, actual), self.param_env, define_opaque_types, ); @@ -136,7 +131,7 @@ impl<'a, 'tcx> At<'a, 'tcx> { { let mut fields = CombineFields::new( self.infcx, - ToTrace::to_trace(self.cause, true, expected, actual), + ToTrace::to_trace(self.cause, expected, actual), self.param_env, define_opaque_types, ); @@ -154,10 +149,7 @@ impl<'a, 'tcx> At<'a, 'tcx> { where T: ToTrace<'tcx>, { - let mut fields = CombineFields::new( - self.infcx, - ToTrace::to_trace(self.cause, true, expected, actual), - self.param_env, + self.eq_trace( define_opaque_types, ToTrace::to_trace(self.cause, expected, actual), expected, @@ -209,7 +201,7 @@ impl<'a, 'tcx> At<'a, 'tcx> { assert!(self.infcx.next_trait_solver()); let mut fields = CombineFields::new( self.infcx, - ToTrace::to_trace(self.cause, true, expected, actual), + ToTrace::to_trace(self.cause, expected, actual), self.param_env, DefineOpaqueTypes::Yes, ); @@ -301,7 +293,7 @@ impl<'a, 'tcx> At<'a, 'tcx> { { let mut fields = CombineFields::new( self.infcx, - ToTrace::to_trace(self.cause, true, expected, actual), + ToTrace::to_trace(self.cause, expected, actual), self.param_env, define_opaque_types, ); @@ -323,7 +315,7 @@ impl<'a, 'tcx> At<'a, 'tcx> { { let mut fields = CombineFields::new( self.infcx, - ToTrace::to_trace(self.cause, true, expected, actual), + ToTrace::to_trace(self.cause, expected, actual), self.param_env, define_opaque_types, ); @@ -333,18 +325,13 @@ impl<'a, 'tcx> At<'a, 'tcx> { } impl<'tcx> ToTrace<'tcx> for ImplSubject<'tcx> { - fn to_trace( - cause: &ObligationCause<'tcx>, - a_is_expected: bool, - a: Self, - b: Self, - ) -> TypeTrace<'tcx> { + fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> { match (a, b) { (ImplSubject::Trait(trait_ref_a), ImplSubject::Trait(trait_ref_b)) => { - ToTrace::to_trace(cause, a_is_expected, trait_ref_a, trait_ref_b) + ToTrace::to_trace(cause, trait_ref_a, trait_ref_b) } (ImplSubject::Inherent(ty_a), ImplSubject::Inherent(ty_b)) => { - ToTrace::to_trace(cause, a_is_expected, ty_a, ty_b) + ToTrace::to_trace(cause, ty_a, ty_b) } (ImplSubject::Trait(_), ImplSubject::Inherent(_)) | (ImplSubject::Inherent(_), ImplSubject::Trait(_)) => { @@ -355,65 +342,45 @@ impl<'tcx> ToTrace<'tcx> for ImplSubject<'tcx> { } impl<'tcx> ToTrace<'tcx> for Ty<'tcx> { - fn to_trace( - cause: &ObligationCause<'tcx>, - a_is_expected: bool, - a: Self, - b: Self, - ) -> TypeTrace<'tcx> { + fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> { TypeTrace { cause: cause.clone(), - values: ValuePairs::Terms(ExpectedFound::new(a_is_expected, a.into(), b.into())), + values: ValuePairs::Terms(ExpectedFound::new(true, a.into(), b.into())), } } } impl<'tcx> ToTrace<'tcx> for ty::Region<'tcx> { - fn to_trace( - cause: &ObligationCause<'tcx>, - a_is_expected: bool, - a: Self, - b: Self, - ) -> TypeTrace<'tcx> { + fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> { TypeTrace { cause: cause.clone(), - values: ValuePairs::Regions(ExpectedFound::new(a_is_expected, a, b)), + values: ValuePairs::Regions(ExpectedFound::new(true, a, b)), } } } impl<'tcx> ToTrace<'tcx> for Const<'tcx> { - fn to_trace( - cause: &ObligationCause<'tcx>, - a_is_expected: bool, - a: Self, - b: Self, - ) -> TypeTrace<'tcx> { + fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> { TypeTrace { cause: cause.clone(), - values: ValuePairs::Terms(ExpectedFound::new(a_is_expected, a.into(), b.into())), + values: ValuePairs::Terms(ExpectedFound::new(true, a.into(), b.into())), } } } impl<'tcx> ToTrace<'tcx> for ty::GenericArg<'tcx> { - fn to_trace( - cause: &ObligationCause<'tcx>, - a_is_expected: bool, - a: Self, - b: Self, - ) -> TypeTrace<'tcx> { + fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> { TypeTrace { cause: cause.clone(), values: match (a.unpack(), b.unpack()) { (GenericArgKind::Lifetime(a), GenericArgKind::Lifetime(b)) => { - ValuePairs::Regions(ExpectedFound::new(a_is_expected, a, b)) + ValuePairs::Regions(ExpectedFound::new(true, a, b)) } (GenericArgKind::Type(a), GenericArgKind::Type(b)) => { - ValuePairs::Terms(ExpectedFound::new(a_is_expected, a.into(), b.into())) + ValuePairs::Terms(ExpectedFound::new(true, a.into(), b.into())) } (GenericArgKind::Const(a), GenericArgKind::Const(b)) => { - ValuePairs::Terms(ExpectedFound::new(a_is_expected, a.into(), b.into())) + ValuePairs::Terms(ExpectedFound::new(true, a.into(), b.into())) } ( @@ -436,72 +403,47 @@ impl<'tcx> ToTrace<'tcx> for ty::GenericArg<'tcx> { } impl<'tcx> ToTrace<'tcx> for ty::Term<'tcx> { - fn to_trace( - cause: &ObligationCause<'tcx>, - a_is_expected: bool, - a: Self, - b: Self, - ) -> TypeTrace<'tcx> { + fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> { TypeTrace { cause: cause.clone(), - values: ValuePairs::Terms(ExpectedFound::new(a_is_expected, a, b)), + values: ValuePairs::Terms(ExpectedFound::new(true, a, b)), } } } impl<'tcx> ToTrace<'tcx> for ty::TraitRef<'tcx> { - fn to_trace( - cause: &ObligationCause<'tcx>, - a_is_expected: bool, - a: Self, - b: Self, - ) -> TypeTrace<'tcx> { + fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> { TypeTrace { cause: cause.clone(), - values: ValuePairs::TraitRefs(ExpectedFound::new(a_is_expected, a, b)), + values: ValuePairs::TraitRefs(ExpectedFound::new(true, a, b)), } } } impl<'tcx> ToTrace<'tcx> for ty::AliasTy<'tcx> { - fn to_trace( - cause: &ObligationCause<'tcx>, - a_is_expected: bool, - a: Self, - b: Self, - ) -> TypeTrace<'tcx> { + fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> { TypeTrace { cause: cause.clone(), - values: ValuePairs::Aliases(ExpectedFound::new(a_is_expected, a.into(), b.into())), + values: ValuePairs::Aliases(ExpectedFound::new(true, a.into(), b.into())), } } } impl<'tcx> ToTrace<'tcx> for ty::AliasTerm<'tcx> { - fn to_trace( - cause: &ObligationCause<'tcx>, - a_is_expected: bool, - a: Self, - b: Self, - ) -> TypeTrace<'tcx> { + fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> { TypeTrace { cause: cause.clone(), - values: ValuePairs::Aliases(ExpectedFound::new(a_is_expected, a, b)), + values: ValuePairs::Aliases(ExpectedFound::new(true, a, b)), } } } impl<'tcx> ToTrace<'tcx> for ty::FnSig<'tcx> { - fn to_trace( - cause: &ObligationCause<'tcx>, - a_is_expected: bool, - a: Self, - b: Self, - ) -> TypeTrace<'tcx> { + fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> { TypeTrace { cause: cause.clone(), values: ValuePairs::PolySigs(ExpectedFound::new( - a_is_expected, + true, ty::Binder::dummy(a), ty::Binder::dummy(b), )), @@ -510,43 +452,28 @@ impl<'tcx> ToTrace<'tcx> for ty::FnSig<'tcx> { } impl<'tcx> ToTrace<'tcx> for ty::PolyFnSig<'tcx> { - fn to_trace( - cause: &ObligationCause<'tcx>, - a_is_expected: bool, - a: Self, - b: Self, - ) -> TypeTrace<'tcx> { + fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> { TypeTrace { cause: cause.clone(), - values: ValuePairs::PolySigs(ExpectedFound::new(a_is_expected, a, b)), + values: ValuePairs::PolySigs(ExpectedFound::new(true, a, b)), } } } impl<'tcx> ToTrace<'tcx> for ty::PolyExistentialTraitRef<'tcx> { - fn to_trace( - cause: &ObligationCause<'tcx>, - a_is_expected: bool, - a: Self, - b: Self, - ) -> TypeTrace<'tcx> { + fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> { TypeTrace { cause: cause.clone(), - values: ValuePairs::ExistentialTraitRef(ExpectedFound::new(a_is_expected, a, b)), + values: ValuePairs::ExistentialTraitRef(ExpectedFound::new(true, a, b)), } } } impl<'tcx> ToTrace<'tcx> for ty::PolyExistentialProjection<'tcx> { - fn to_trace( - cause: &ObligationCause<'tcx>, - a_is_expected: bool, - a: Self, - b: Self, - ) -> TypeTrace<'tcx> { + fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> { TypeTrace { cause: cause.clone(), - values: ValuePairs::ExistentialProjection(ExpectedFound::new(a_is_expected, a, b)), + values: ValuePairs::ExistentialProjection(ExpectedFound::new(true, a, b)), } } } diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index c3042ab9636..dbe05a33328 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -2598,7 +2598,6 @@ impl<'tcx> SelectionContext<'_, 'tcx> { DefineOpaqueTypes::Yes, ToTrace::to_trace( &obligation.cause, - true, hr_target_principal, hr_source_principal, ), @@ -2638,7 +2637,6 @@ impl<'tcx> SelectionContext<'_, 'tcx> { DefineOpaqueTypes::Yes, ToTrace::to_trace( &obligation.cause, - true, hr_target_projection, hr_source_projection, ), @@ -2669,7 +2667,6 @@ impl<'tcx> SelectionContext<'_, 'tcx> { DefineOpaqueTypes::Yes, ToTrace::to_trace( &obligation.cause, - true, hr_target_projection, hr_source_projection, ), From f0677e7d39f7a2792681fff72e1e8747a1b34669 Mon Sep 17 00:00:00 2001 From: Weihang Lo Date: Fri, 27 Sep 2024 15:45:11 -0400 Subject: [PATCH 347/683] Update cargo --- src/tools/cargo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/cargo b/src/tools/cargo index eaee77dc158..80d82ca22ab 160000 --- a/src/tools/cargo +++ b/src/tools/cargo @@ -1 +1 @@ -Subproject commit eaee77dc1584be45949b75e4c4c9a841605e3a4b +Subproject commit 80d82ca22abbee5fb7b51fa1abeb1ae34e99e88a From 7cde7db1fcb201defa76ac40b0e5d6d3b790755b Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 27 Sep 2024 22:09:18 +0200 Subject: [PATCH 348/683] Fmt --- compiler/rustc_codegen_gcc/src/int.rs | 2 +- compiler/rustc_codegen_gcc/src/intrinsic/llvm.rs | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_codegen_gcc/src/int.rs b/compiler/rustc_codegen_gcc/src/int.rs index c23bb52754a..5ca440f4c9b 100644 --- a/compiler/rustc_codegen_gcc/src/int.rs +++ b/compiler/rustc_codegen_gcc/src/int.rs @@ -6,8 +6,8 @@ use gccjit::{BinaryOp, ComparisonOp, FunctionType, Location, RValue, ToRValue, T use rustc_codegen_ssa::common::{IntPredicate, TypeKind}; use rustc_codegen_ssa::traits::{BackendTypes, BaseTypeCodegenMethods, BuilderMethods, OverflowOp}; use rustc_middle::ty::{ParamEnv, Ty}; -use rustc_target::abi::call::{ArgAbi, ArgAttributes, Conv, FnAbi, PassMode}; use rustc_target::abi::Endian; +use rustc_target::abi::call::{ArgAbi, ArgAttributes, Conv, FnAbi, PassMode}; use rustc_target::spec; use crate::builder::{Builder, ToGccComp}; diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/llvm.rs b/compiler/rustc_codegen_gcc/src/intrinsic/llvm.rs index 83ba6c76c6a..0a448ded6b1 100644 --- a/compiler/rustc_codegen_gcc/src/intrinsic/llvm.rs +++ b/compiler/rustc_codegen_gcc/src/intrinsic/llvm.rs @@ -1,7 +1,6 @@ use std::borrow::Cow; -use gccjit::{CType, Context}; -use gccjit::{Function, FunctionPtrType, RValue, ToRValue, UnaryOp}; +use gccjit::{CType, Context, Function, FunctionPtrType, RValue, ToRValue, UnaryOp}; use rustc_codegen_ssa::traits::BuilderMethods; use crate::builder::Builder; From 3fb21f38fdc6371228c78c425efc42ff004cded1 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 27 Sep 2024 16:21:03 -0400 Subject: [PATCH 349/683] Bump `cc` and run `cargo update` for bootstrap Bump `cc` to 1.1.22, which includes a caching fix. Also run `cargo update` which does a minor increment on a few dependencies. --- src/bootstrap/Cargo.lock | 100 +++++++++++++++++++-------------------- src/bootstrap/Cargo.toml | 2 +- 2 files changed, 51 insertions(+), 51 deletions(-) diff --git a/src/bootstrap/Cargo.lock b/src/bootstrap/Cargo.lock index 952db063636..efcac4f0953 100644 --- a/src/bootstrap/Cargo.lock +++ b/src/bootstrap/Cargo.lock @@ -84,9 +84,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.1.19" +version = "1.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d74707dde2ba56f86ae90effb3b43ddd369504387e718014de010cec7959800" +checksum = "9540e661f81799159abee814118cc139a2004b3a3aa3ea37724a1b66530b90e0" dependencies = [ "shlex", ] @@ -99,9 +99,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "clap" -version = "4.5.16" +version = "4.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed6719fffa43d0d87e5fd8caeab59be1554fb028cd30edc88fc4369b17971019" +checksum = "b0956a43b323ac1afaffc053ed5c4b7c1f1800bacd1683c353aabbb752515dd3" dependencies = [ "clap_builder", "clap_derive", @@ -109,9 +109,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.15" +version = "4.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "216aec2b177652e3846684cbfe25c9964d18ec45234f0f5da5157b207ed1aab6" +checksum = "4d72166dd41634086d5803a47eb71ae740e61d84709c36f3c34110173db3961b" dependencies = [ "anstyle", "clap_lex", @@ -119,18 +119,18 @@ dependencies = [ [[package]] name = "clap_complete" -version = "4.5.18" +version = "4.5.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ee158892bd7ce77aa15c208abbdb73e155d191c287a659b57abd5adb92feb03" +checksum = "8937760c3f4c60871870b8c3ee5f9b30771f792a7045c48bcbba999d7d6b3b8e" dependencies = [ "clap", ] [[package]] name = "clap_derive" -version = "4.5.13" +version = "4.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "501d359d5f3dcaf6ecdeee48833ae73ec6e42723a1e52419c79abf9507eec0a0" +checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab" dependencies = [ "heck", "proc-macro2", @@ -161,9 +161,9 @@ checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "cpufeatures" -version = "0.2.13" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51e852e6dc9a5bed1fae92dd2375037bf2b768725bf3be87811edee3249d09ad" +checksum = "608697df725056feaccfa42cffdaeeec3fccc4ffc38358ecd19b243e716a78e0" dependencies = [ "libc", ] @@ -242,9 +242,9 @@ dependencies = [ [[package]] name = "filetime" -version = "0.2.24" +version = "0.2.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf401df4a4e3872c4fe8151134cf483738e74b67fc934d6532c882b3d24a4550" +checksum = "35c0522e981e68cbfa8c3f978441a5f34b30b96e146b33cd3359176b50fe8586" dependencies = [ "cfg-if", "libc", @@ -264,9 +264,9 @@ dependencies = [ [[package]] name = "globset" -version = "0.4.14" +version = "0.4.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57da3b9b5b85bd66f31093f8c408b90a74431672542466497dcbdfdc02034be1" +checksum = "15f1ce686646e7f1e19bf7d5533fe443a45dbfb990e00629110797578b42fb19" dependencies = [ "aho-corasick", "bstr", @@ -292,9 +292,9 @@ dependencies = [ [[package]] name = "ignore" -version = "0.4.22" +version = "0.4.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b46810df39e66e925525d6e38ce1e7f6e1d208f72dc39757880fcb66e2c58af1" +checksum = "6d89fd380afde86567dfba715db065673989d6253f42b88179abd3eae47bda4b" dependencies = [ "crossbeam-deque", "globset", @@ -314,9 +314,9 @@ checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" [[package]] name = "junction" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c9c415a9b7b1e86cd5738f39d34c9e78c765da7fb1756dbd7d31b3b0d2e7afa" +checksum = "72bbdfd737a243da3dfc1f99ee8d6e166480f17ab4ac84d7c34aacd73fc7bd16" dependencies = [ "scopeguard", "windows-sys 0.52.0", @@ -324,9 +324,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.157" +version = "0.2.159" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "374af5f94e54fa97cf75e945cce8a6b201e88a1a07e688b47dfd2a59c66dbd86" +checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5" [[package]] name = "libredox" @@ -379,9 +379,9 @@ dependencies = [ [[package]] name = "object" -version = "0.36.3" +version = "0.36.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27b64972346851a39438c60b341ebc01bba47464ae329e55cf343eb93964efd9" +checksum = "084f1a5821ac4c651660a94a7153d27ac9d8a53736203f58b31945ded098070a" dependencies = [ "memchr", ] @@ -398,15 +398,15 @@ dependencies = [ [[package]] name = "pkg-config" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" +checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" [[package]] name = "pretty_assertions" -version = "1.4.0" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af7cee1a6c8a5b9208b3cb1061f10c0cb689087b3d8ce85fb9d2dd7a29b6ba66" +checksum = "3ae130e2f271fbc2ac3a40fb1d07180839cdbbe443c7a27e1e3c13c5cac0116d" dependencies = [ "diff", "yansi", @@ -423,18 +423,18 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.36" +version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" dependencies = [ "proc-macro2", ] [[package]] name = "redox_syscall" -version = "0.5.3" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4" +checksum = "355ae415ccd3a04315d3f8246e86d67689ea74d88d915576e1589a351062a13b" dependencies = [ "bitflags", ] @@ -458,9 +458,9 @@ checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" [[package]] name = "rustix" -version = "0.38.34" +version = "0.38.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" +checksum = "8acb788b847c24f28525660c4d7758620a7210875711f79e7f663cc152726811" dependencies = [ "bitflags", "errno", @@ -498,18 +498,18 @@ checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" [[package]] name = "serde" -version = "1.0.208" +version = "1.0.210" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cff085d2cb684faa248efb494c39b68e522822ac0de72ccf08109abde717cfb2" +checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.208" +version = "1.0.210" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24008e81ff7613ed8e5ba0cfaf24e2c2f1e5b8a0495711e44fcd4882fca62bcf" +checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" dependencies = [ "proc-macro2", "quote", @@ -518,9 +518,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.125" +version = "1.0.128" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83c8e735a073ccf5be70aa8066aa984eaf2fa000db6c8d0100ae605b366d31ed" +checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8" dependencies = [ "itoa", "memchr", @@ -547,9 +547,9 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "syn" -version = "2.0.75" +version = "2.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6af063034fc1935ede7be0122941bafa9bacb949334d090b77ca98b5817c7d9" +checksum = "89132cd0bf050864e1d38dc3bbc07a0eb8e7530af26344d3d2bbbef83499f590" dependencies = [ "proc-macro2", "quote", @@ -558,9 +558,9 @@ dependencies = [ [[package]] name = "sysinfo" -version = "0.31.2" +version = "0.31.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4115055da5f572fff541dd0c4e61b0262977f453cc9fe04be83aba25a89bdab" +checksum = "355dbe4f8799b304b05e1b0f05fc59b2a18d36645cf169607da45bde2f69a1be" dependencies = [ "core-foundation-sys", "libc", @@ -571,9 +571,9 @@ dependencies = [ [[package]] name = "tar" -version = "0.4.41" +version = "0.4.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb797dad5fb5b76fcf519e702f4a589483b5ef06567f160c392832c1f5e44909" +checksum = "4ff6c40d3aedb5e06b57c6f669ad17ab063dd1e63d977c6a88e7f4dfa4f04020" dependencies = [ "filetime", "libc", @@ -606,9 +606,9 @@ checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" [[package]] name = "unicode-ident" -version = "1.0.12" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" [[package]] name = "version_check" @@ -833,6 +833,6 @@ dependencies = [ [[package]] name = "yansi" -version = "0.5.1" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" +checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049" diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml index 1959d0a9662..ba505089a00 100644 --- a/src/bootstrap/Cargo.toml +++ b/src/bootstrap/Cargo.toml @@ -37,7 +37,7 @@ test = false # Most of the time updating these dependencies requires modifications to the # bootstrap codebase(e.g., https://github.com/rust-lang/rust/issues/124565); # otherwise, some targets will fail. That's why these dependencies are explicitly pinned. -cc = "=1.1.19" +cc = "=1.1.22" cmake = "=0.1.48" build_helper = { path = "../tools/build_helper" } From d0102fdd0fe298adc1a64bb0b9cf3da20b0f1bb2 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 27 Sep 2024 23:05:29 +0200 Subject: [PATCH 350/683] Update libgccjit version used in CI --- src/ci/docker/host-x86_64/dist-x86_64-linux/build-gccjit.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ci/docker/host-x86_64/dist-x86_64-linux/build-gccjit.sh b/src/ci/docker/host-x86_64/dist-x86_64-linux/build-gccjit.sh index 4c80e895fd2..c565922dcd1 100755 --- a/src/ci/docker/host-x86_64/dist-x86_64-linux/build-gccjit.sh +++ b/src/ci/docker/host-x86_64/dist-x86_64-linux/build-gccjit.sh @@ -3,7 +3,7 @@ GIT_REPO="https://github.com/rust-lang/gcc" # This commit hash needs to be updated to use a more recent gcc fork version. -GIT_COMMIT="341be3b7d7ac6976cfed8ed59da3573c040d0776" +GIT_COMMIT="e744a9459d33864067214741daf5c5bc2a7b88c6" set -ex From bcf8cf29433ed2d74dbe5598ccd7db1d1c20ed2e Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Thu, 26 Sep 2024 10:34:08 -0700 Subject: [PATCH 351/683] tests: issue-69488.rs => load-preserves-partial-init-issue-69488.rs --- src/tools/tidy/src/issues.txt | 1 - .../consts/{issue-69488.rs => load-preserves-partial-init.rs} | 3 +++ 2 files changed, 3 insertions(+), 1 deletion(-) rename tests/ui/consts/{issue-69488.rs => load-preserves-partial-init.rs} (80%) diff --git a/src/tools/tidy/src/issues.txt b/src/tools/tidy/src/issues.txt index 2071abefbe1..9d3b090abb6 100644 --- a/src/tools/tidy/src/issues.txt +++ b/src/tools/tidy/src/issues.txt @@ -795,7 +795,6 @@ ui/consts/issue-68684.rs ui/consts/issue-69191-ice-on-uninhabited-enum-field.rs ui/consts/issue-69310-array-size-lit-wrong-ty.rs ui/consts/issue-69312.rs -ui/consts/issue-69488.rs ui/consts/issue-69532.rs ui/consts/issue-6991.rs ui/consts/issue-70773-mir-typeck-lt-norm.rs diff --git a/tests/ui/consts/issue-69488.rs b/tests/ui/consts/load-preserves-partial-init.rs similarity index 80% rename from tests/ui/consts/issue-69488.rs rename to tests/ui/consts/load-preserves-partial-init.rs index d528d6a88de..d97e9cb3d9d 100644 --- a/tests/ui/consts/issue-69488.rs +++ b/tests/ui/consts/load-preserves-partial-init.rs @@ -1,6 +1,9 @@ //@ run-pass #![feature(const_ptr_write)] +// issue: https://github.com/rust-lang/rust/issues/69488 +// Loads of partially-initialized data could produce completely-uninitialized results. +// Test to make sure that we no longer do such a "deinitializing" load. // Or, equivalently: `MaybeUninit`. pub union BagOfBits { From a1fbf251b81b165016d4f29ea9a9e08647275957 Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Fri, 27 Sep 2024 14:04:42 -0700 Subject: [PATCH 352/683] tests: issue-14309.* => repr-rust-is-undefined.* --- src/tools/tidy/src/issues.txt | 1 - .../repr-rust-is-undefined.rs} | 4 ++++ .../repr-rust-is-undefined.stderr} | 22 +++++++++---------- 3 files changed, 15 insertions(+), 12 deletions(-) rename tests/ui/lint/{issue-14309.rs => improper_ctypes/repr-rust-is-undefined.rs} (70%) rename tests/ui/lint/{issue-14309.stderr => improper_ctypes/repr-rust-is-undefined.stderr} (79%) diff --git a/src/tools/tidy/src/issues.txt b/src/tools/tidy/src/issues.txt index 9d3b090abb6..89535079772 100644 --- a/src/tools/tidy/src/issues.txt +++ b/src/tools/tidy/src/issues.txt @@ -2744,7 +2744,6 @@ ui/lint/issue-111359.rs ui/lint/issue-112489.rs ui/lint/issue-117949.rs ui/lint/issue-121070-let-range.rs -ui/lint/issue-14309.rs ui/lint/issue-14837.rs ui/lint/issue-17718-const-naming.rs ui/lint/issue-1866.rs diff --git a/tests/ui/lint/issue-14309.rs b/tests/ui/lint/improper_ctypes/repr-rust-is-undefined.rs similarity index 70% rename from tests/ui/lint/issue-14309.rs rename to tests/ui/lint/improper_ctypes/repr-rust-is-undefined.rs index 328a4c982b8..379c4132404 100644 --- a/tests/ui/lint/issue-14309.rs +++ b/tests/ui/lint/improper_ctypes/repr-rust-is-undefined.rs @@ -1,6 +1,10 @@ #![deny(improper_ctypes)] #![allow(dead_code)] +// issue https://github.com/rust-lang/rust/issues/14309 +// Validates we lint on repr(Rust) structs and not repr(C) structs in FFI, to implement RFC 79: +// https://rust-lang.github.io/rfcs/0079-undefined-struct-layout.html + struct A { x: i32 } diff --git a/tests/ui/lint/issue-14309.stderr b/tests/ui/lint/improper_ctypes/repr-rust-is-undefined.stderr similarity index 79% rename from tests/ui/lint/issue-14309.stderr rename to tests/ui/lint/improper_ctypes/repr-rust-is-undefined.stderr index 9ce62a6b804..5f0465bcf00 100644 --- a/tests/ui/lint/issue-14309.stderr +++ b/tests/ui/lint/improper_ctypes/repr-rust-is-undefined.stderr @@ -1,5 +1,5 @@ error: `extern` block uses type `A`, which is not FFI-safe - --> $DIR/issue-14309.rs:30:15 + --> $DIR/repr-rust-is-undefined.rs:34:15 | LL | fn foo(x: A); | ^ not FFI-safe @@ -7,18 +7,18 @@ LL | fn foo(x: A); = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct = note: this struct has unspecified layout note: the type is defined here - --> $DIR/issue-14309.rs:4:1 + --> $DIR/repr-rust-is-undefined.rs:8:1 | LL | struct A { | ^^^^^^^^ note: the lint level is defined here - --> $DIR/issue-14309.rs:1:9 + --> $DIR/repr-rust-is-undefined.rs:1:9 | LL | #![deny(improper_ctypes)] | ^^^^^^^^^^^^^^^ error: `extern` block uses type `A`, which is not FFI-safe - --> $DIR/issue-14309.rs:31:15 + --> $DIR/repr-rust-is-undefined.rs:35:15 | LL | fn bar(x: B); | ^ not FFI-safe @@ -26,13 +26,13 @@ LL | fn bar(x: B); = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct = note: this struct has unspecified layout note: the type is defined here - --> $DIR/issue-14309.rs:4:1 + --> $DIR/repr-rust-is-undefined.rs:8:1 | LL | struct A { | ^^^^^^^^ error: `extern` block uses type `A`, which is not FFI-safe - --> $DIR/issue-14309.rs:33:15 + --> $DIR/repr-rust-is-undefined.rs:37:15 | LL | fn qux(x: A2); | ^^ not FFI-safe @@ -40,13 +40,13 @@ LL | fn qux(x: A2); = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct = note: this struct has unspecified layout note: the type is defined here - --> $DIR/issue-14309.rs:4:1 + --> $DIR/repr-rust-is-undefined.rs:8:1 | LL | struct A { | ^^^^^^^^ error: `extern` block uses type `A`, which is not FFI-safe - --> $DIR/issue-14309.rs:34:16 + --> $DIR/repr-rust-is-undefined.rs:38:16 | LL | fn quux(x: B2); | ^^ not FFI-safe @@ -54,13 +54,13 @@ LL | fn quux(x: B2); = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct = note: this struct has unspecified layout note: the type is defined here - --> $DIR/issue-14309.rs:4:1 + --> $DIR/repr-rust-is-undefined.rs:8:1 | LL | struct A { | ^^^^^^^^ error: `extern` block uses type `A`, which is not FFI-safe - --> $DIR/issue-14309.rs:36:16 + --> $DIR/repr-rust-is-undefined.rs:40:16 | LL | fn fred(x: D); | ^ not FFI-safe @@ -68,7 +68,7 @@ LL | fn fred(x: D); = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct = note: this struct has unspecified layout note: the type is defined here - --> $DIR/issue-14309.rs:4:1 + --> $DIR/repr-rust-is-undefined.rs:8:1 | LL | struct A { | ^^^^^^^^ From 19d5568ad3a83d48b152f5c7182c364005ee969e Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Fri, 27 Sep 2024 14:12:57 -0700 Subject: [PATCH 353/683] tests: issue-34798.rs => allow-phantomdata-in-ffi.rs --- src/tools/tidy/src/issues.txt | 1 - .../allow-phantomdata-in-ffi.rs} | 2 ++ 2 files changed, 2 insertions(+), 1 deletion(-) rename tests/ui/lint/{issue-34798.rs => improper_ctypes/allow-phantomdata-in-ffi.rs} (71%) diff --git a/src/tools/tidy/src/issues.txt b/src/tools/tidy/src/issues.txt index 89535079772..86cae849b97 100644 --- a/src/tools/tidy/src/issues.txt +++ b/src/tools/tidy/src/issues.txt @@ -2750,7 +2750,6 @@ ui/lint/issue-1866.rs ui/lint/issue-19102.rs ui/lint/issue-20343.rs ui/lint/issue-30302.rs -ui/lint/issue-34798.rs ui/lint/issue-35075.rs ui/lint/issue-47775-nested-macro-unnecessary-parens-arg.rs ui/lint/issue-49588-non-shorthand-field-patterns-in-pattern-macro.rs diff --git a/tests/ui/lint/issue-34798.rs b/tests/ui/lint/improper_ctypes/allow-phantomdata-in-ffi.rs similarity index 71% rename from tests/ui/lint/issue-34798.rs rename to tests/ui/lint/improper_ctypes/allow-phantomdata-in-ffi.rs index 064fc7c4ad6..a90159d2b58 100644 --- a/tests/ui/lint/issue-34798.rs +++ b/tests/ui/lint/improper_ctypes/allow-phantomdata-in-ffi.rs @@ -1,6 +1,8 @@ //@ run-pass #![forbid(improper_ctypes)] #![allow(dead_code)] +// issue https://github.com/rust-lang/rust/issues/34798 +// We allow PhantomData in FFI so bindgen can bind templated C++ structs with "unused generic args" #[repr(C)] pub struct Foo { From d24a63199a5ad140fd52f6feb2e279e2a51cc201 Mon Sep 17 00:00:00 2001 From: y21 <30553356+y21@users.noreply.github.com> Date: Fri, 27 Sep 2024 21:38:38 +0000 Subject: [PATCH 354/683] remove method call receiver special casing in `unused_async` lint --- clippy_lints/src/unused_async.rs | 23 ++++++++++------------- tests/ui/unused_async.rs | 16 ++++++++++++++++ tests/ui/unused_async.stderr | 4 ++-- 3 files changed, 28 insertions(+), 15 deletions(-) diff --git a/clippy_lints/src/unused_async.rs b/clippy_lints/src/unused_async.rs index a1f08cf6623..0ed64fd1f8e 100644 --- a/clippy_lints/src/unused_async.rs +++ b/clippy_lints/src/unused_async.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_hir_and_then; use clippy_utils::is_def_id_trait_method; use rustc_hir::def::DefKind; use rustc_hir::intravisit::{FnKind, Visitor, walk_expr, walk_fn}; -use rustc_hir::{Body, Expr, ExprKind, FnDecl, Node, YieldSource}; +use rustc_hir::{Body, Expr, ExprKind, FnDecl, HirId, Node, YieldSource}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::nested_filter; use rustc_session::impl_lint_pass; @@ -137,17 +137,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedAsync { } } - fn check_path(&mut self, cx: &LateContext<'tcx>, path: &rustc_hir::Path<'tcx>, hir_id: rustc_hir::HirId) { - fn is_node_func_call(node: Node<'_>, expected_receiver: Span) -> bool { - matches!( - node, - Node::Expr(Expr { - kind: ExprKind::Call(Expr { span, .. }, _) | ExprKind::MethodCall(_, Expr { span, .. }, ..), - .. - }) if *span == expected_receiver - ) - } - + fn check_path(&mut self, cx: &LateContext<'tcx>, path: &rustc_hir::Path<'tcx>, hir_id: HirId) { // Find paths to local async functions that aren't immediately called. // E.g. `async fn f() {}; let x = f;` // Depending on how `x` is used, f's asyncness might be required despite not having any `await` @@ -156,7 +146,14 @@ impl<'tcx> LateLintPass<'tcx> for UnusedAsync { && let Some(local_def_id) = def_id.as_local() && cx.tcx.def_kind(def_id) == DefKind::Fn && cx.tcx.asyncness(def_id).is_async() - && !is_node_func_call(cx.tcx.parent_hir_node(hir_id), path.span) + && let parent = cx.tcx.parent_hir_node(hir_id) + && !matches!( + parent, + Node::Expr(Expr { + kind: ExprKind::Call(Expr { span, .. }, _), + .. + }) if *span == path.span + ) { self.async_fns_as_value.insert(local_def_id); } diff --git a/tests/ui/unused_async.rs b/tests/ui/unused_async.rs index 7ec8a3adb4c..838d6f0aa97 100644 --- a/tests/ui/unused_async.rs +++ b/tests/ui/unused_async.rs @@ -55,6 +55,22 @@ mod issue9695 { } } +mod issue13466 { + use std::future::Future; + + struct Wrap(F); + impl From for Wrap { + fn from(f: F) -> Self { + Self(f) + } + } + fn takes_fut Fut, Fut: Future>(_: Wrap) {} + async fn unused_async() {} + fn fp() { + takes_fut(unused_async.into()); + } +} + async fn foo() -> i32 { //~^ ERROR: unused `async` for function with no await statements 4 diff --git a/tests/ui/unused_async.stderr b/tests/ui/unused_async.stderr index 337c650e029..4811df63658 100644 --- a/tests/ui/unused_async.stderr +++ b/tests/ui/unused_async.stderr @@ -27,7 +27,7 @@ LL | async fn f3() {} = help: consider removing the `async` from this function error: unused `async` for function with no await statements - --> tests/ui/unused_async.rs:58:1 + --> tests/ui/unused_async.rs:74:1 | LL | / async fn foo() -> i32 { LL | | @@ -38,7 +38,7 @@ LL | | } = help: consider removing the `async` from this function error: unused `async` for function with no await statements - --> tests/ui/unused_async.rs:70:5 + --> tests/ui/unused_async.rs:86:5 | LL | / async fn unused(&self) -> i32 { LL | | From 404c5d26c9aa37899fe00a5e66fdc5178fc9e0ea Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 21 Aug 2024 19:58:44 -0500 Subject: [PATCH 355/683] Enable `f16` on platforms that were missing conversion symbols The only requirement for `f16` support, aside from LLVM not crashing and no ABI issues, is that symbols to convert to and from `f32` are available. Since the update to compiler-builtins in [1], we now provide these on all platforms. This also enables `f16` math since there are no further requirements. Still excluded are platforms for which LLVM emits infinitely-recursing code. [1]: https://github.com/rust-lang/rust/pull/125016 --- library/std/build.rs | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/library/std/build.rs b/library/std/build.rs index 359ae4f20ee..c5d0af469a8 100644 --- a/library/std/build.rs +++ b/library/std/build.rs @@ -96,9 +96,6 @@ fn main() { let has_reliable_f16 = match (target_arch.as_str(), target_os.as_str()) { // We can always enable these in Miri as that is not affected by codegen bugs. _ if is_miri => true, - // Selection failure until recent LLVM - // FIXME(llvm19): can probably be removed at the version bump - ("loongarch64", _) => false, // Selection failure ("s390x", _) => false, // Unsupported @@ -108,18 +105,18 @@ fn main() { // Apple has a special ABI for `f16` that we do not yet support // FIXME(builtins): fixed by ("x86" | "x86_64", _) if target_vendor == "apple" => false, - // Missing `__gnu_h2f_ieee` and `__gnu_f2h_ieee` + // Infinite recursion + ("csky", _) => false, + ("hexagon", _) => false, + ("loongarch64", _) => false, + ("mips" | "mips64" | "mips32r6" | "mips64r6", _) => false, ("powerpc" | "powerpc64", _) => false, - // Missing `__gnu_h2f_ieee` and `__gnu_f2h_ieee` - ("mips" | "mips32r6" | "mips64" | "mips64r6", _) => false, - // Missing `__extendhfsf` and `__truncsfhf` - ("riscv32" | "riscv64", _) => false, - // Most OSs are missing `__extendhfsf` and `__truncsfhf` - (_, "linux" | "macos") => true, - // Almost all OSs besides Linux and MacOS are missing symbols until compiler-builtins can - // be updated. will get some of these, the - // next CB update should get the rest. - _ => false, + ("sparc" | "sparc64", _) => false, + ("wasm32" | "wasm64", _) => false, + // `f16` support only requires that symbols converting to and from `f32` are available. We + // provide these in `compiler-builtins`, so `f16` should be available on all platforms that + // do not have other ABI issues or LLVM crashes. + _ => true, }; let has_reliable_f128 = match (target_arch.as_str(), target_os.as_str()) { From f46057bf1cc0dc24a0ecd7d87c9c93872e685253 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Fri, 27 Sep 2024 15:53:26 -0700 Subject: [PATCH 356/683] Only add an automatic SONAME for Rust dylibs --- compiler/rustc_codegen_ssa/src/back/link.rs | 2 +- compiler/rustc_codegen_ssa/src/back/linker.rs | 83 +++++++++++++++---- tests/run-make/dylib-soname/rmake.rs | 16 ++-- 3 files changed, 80 insertions(+), 21 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 80e8111516e..a23cc512926 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -2490,7 +2490,7 @@ fn add_order_independent_options( } } - cmd.set_output_kind(link_output_kind, out_filename); + cmd.set_output_kind(link_output_kind, crate_type, out_filename); add_relro_args(cmd, sess); diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs index a73ec83ee62..3f3d305da01 100644 --- a/compiler/rustc_codegen_ssa/src/back/linker.rs +++ b/compiler/rustc_codegen_ssa/src/back/linker.rs @@ -275,7 +275,12 @@ pub(crate) trait Linker { fn is_cc(&self) -> bool { false } - fn set_output_kind(&mut self, output_kind: LinkOutputKind, out_filename: &Path); + fn set_output_kind( + &mut self, + output_kind: LinkOutputKind, + crate_type: CrateType, + out_filename: &Path, + ); fn link_dylib_by_name(&mut self, _name: &str, _verbatim: bool, _as_needed: bool) { bug!("dylib linked with unsupported linker") } @@ -396,7 +401,7 @@ impl<'a> GccLinker<'a> { ]); } - fn build_dylib(&mut self, out_filename: &Path) { + fn build_dylib(&mut self, crate_type: CrateType, out_filename: &Path) { // On mac we need to tell the linker to let this library be rpathed if self.sess.target.is_like_osx { if !self.is_ld { @@ -427,7 +432,7 @@ impl<'a> GccLinker<'a> { let mut out_implib = OsString::from("--out-implib="); out_implib.push(out_filename.with_file_name(implib_name)); self.link_arg(out_implib); - } else { + } else if crate_type == CrateType::Dylib { // When dylibs are linked by a full path this value will get into `DT_NEEDED` // instead of the full path, so the library can be later found in some other // location than that specific path. @@ -474,7 +479,12 @@ impl<'a> Linker for GccLinker<'a> { !self.is_ld } - fn set_output_kind(&mut self, output_kind: LinkOutputKind, out_filename: &Path) { + fn set_output_kind( + &mut self, + output_kind: LinkOutputKind, + crate_type: CrateType, + out_filename: &Path, + ) { match output_kind { LinkOutputKind::DynamicNoPicExe => { if !self.is_ld && self.is_gnu { @@ -509,10 +519,10 @@ impl<'a> Linker for GccLinker<'a> { self.link_args(&["-static", "-pie", "--no-dynamic-linker", "-z", "text"]); } } - LinkOutputKind::DynamicDylib => self.build_dylib(out_filename), + LinkOutputKind::DynamicDylib => self.build_dylib(crate_type, out_filename), LinkOutputKind::StaticDylib => { self.link_or_cc_arg("-static"); - self.build_dylib(out_filename); + self.build_dylib(crate_type, out_filename); } LinkOutputKind::WasiReactorExe => { self.link_args(&["--entry", "_initialize"]); @@ -866,7 +876,12 @@ impl<'a> Linker for MsvcLinker<'a> { &mut self.cmd } - fn set_output_kind(&mut self, output_kind: LinkOutputKind, out_filename: &Path) { + fn set_output_kind( + &mut self, + output_kind: LinkOutputKind, + _crate_type: CrateType, + out_filename: &Path, + ) { match output_kind { LinkOutputKind::DynamicNoPicExe | LinkOutputKind::DynamicPicExe @@ -1124,7 +1139,13 @@ impl<'a> Linker for EmLinker<'a> { true } - fn set_output_kind(&mut self, _output_kind: LinkOutputKind, _out_filename: &Path) {} + fn set_output_kind( + &mut self, + _output_kind: LinkOutputKind, + _crate_type: CrateType, + _out_filename: &Path, + ) { + } fn link_dylib_by_name(&mut self, name: &str, _verbatim: bool, _as_needed: bool) { // Emscripten always links statically @@ -1273,7 +1294,12 @@ impl<'a> Linker for WasmLd<'a> { &mut self.cmd } - fn set_output_kind(&mut self, output_kind: LinkOutputKind, _out_filename: &Path) { + fn set_output_kind( + &mut self, + output_kind: LinkOutputKind, + _crate_type: CrateType, + _out_filename: &Path, + ) { match output_kind { LinkOutputKind::DynamicNoPicExe | LinkOutputKind::DynamicPicExe @@ -1422,7 +1448,13 @@ impl<'a> Linker for L4Bender<'a> { &mut self.cmd } - fn set_output_kind(&mut self, _output_kind: LinkOutputKind, _out_filename: &Path) {} + fn set_output_kind( + &mut self, + _output_kind: LinkOutputKind, + _crate_type: CrateType, + _out_filename: &Path, + ) { + } fn link_staticlib_by_name(&mut self, name: &str, _verbatim: bool, whole_archive: bool) { self.hint_static(); @@ -1568,7 +1600,12 @@ impl<'a> Linker for AixLinker<'a> { &mut self.cmd } - fn set_output_kind(&mut self, output_kind: LinkOutputKind, out_filename: &Path) { + fn set_output_kind( + &mut self, + output_kind: LinkOutputKind, + _crate_type: CrateType, + out_filename: &Path, + ) { match output_kind { LinkOutputKind::DynamicDylib => { self.hint_dynamic(); @@ -1775,7 +1812,13 @@ impl<'a> Linker for PtxLinker<'a> { &mut self.cmd } - fn set_output_kind(&mut self, _output_kind: LinkOutputKind, _out_filename: &Path) {} + fn set_output_kind( + &mut self, + _output_kind: LinkOutputKind, + _crate_type: CrateType, + _out_filename: &Path, + ) { + } fn link_staticlib_by_name(&mut self, _name: &str, _verbatim: bool, _whole_archive: bool) { panic!("staticlibs not supported") @@ -1841,7 +1884,13 @@ impl<'a> Linker for LlbcLinker<'a> { &mut self.cmd } - fn set_output_kind(&mut self, _output_kind: LinkOutputKind, _out_filename: &Path) {} + fn set_output_kind( + &mut self, + _output_kind: LinkOutputKind, + _crate_type: CrateType, + _out_filename: &Path, + ) { + } fn link_staticlib_by_name(&mut self, _name: &str, _verbatim: bool, _whole_archive: bool) { panic!("staticlibs not supported") @@ -1912,7 +1961,13 @@ impl<'a> Linker for BpfLinker<'a> { &mut self.cmd } - fn set_output_kind(&mut self, _output_kind: LinkOutputKind, _out_filename: &Path) {} + fn set_output_kind( + &mut self, + _output_kind: LinkOutputKind, + _crate_type: CrateType, + _out_filename: &Path, + ) { + } fn link_staticlib_by_name(&mut self, _name: &str, _verbatim: bool, _whole_archive: bool) { panic!("staticlibs not supported") diff --git a/tests/run-make/dylib-soname/rmake.rs b/tests/run-make/dylib-soname/rmake.rs index cec0d463842..714997cbc1a 100644 --- a/tests/run-make/dylib-soname/rmake.rs +++ b/tests/run-make/dylib-soname/rmake.rs @@ -7,12 +7,16 @@ use run_make_support::{cmd, run_in_tmpdir, rustc}; fn main() { + let check = |ty: &str| { + rustc().crate_name("foo").crate_type(ty).input("foo.rs").run(); + cmd("readelf").arg("-d").arg("libfoo.so").run() + }; run_in_tmpdir(|| { - rustc().crate_name("foo").crate_type("dylib").input("foo.rs").run(); - cmd("readelf") - .arg("-d") - .arg("libfoo.so") - .run() - .assert_stdout_contains("Library soname: [libfoo.so]"); + // Rust dylibs should get a relative SONAME + check("dylib").assert_stdout_contains("Library soname: [libfoo.so]"); + }); + run_in_tmpdir(|| { + // C dylibs should not implicitly get any SONAME + check("cdylib").assert_stdout_not_contains("Library soname:"); }); } From 62612af37223d21374741cb81d91c23d2f49076e Mon Sep 17 00:00:00 2001 From: Taiki Endo Date: Fri, 27 Sep 2024 10:44:04 +0900 Subject: [PATCH 357/683] rustc_target: Add RISC-V atomic-related features --- compiler/rustc_codegen_llvm/src/llvm_util.rs | 4 ++++ compiler/rustc_target/src/target_features.rs | 5 ++++- tests/ui/check-cfg/mix.stderr | 2 +- tests/ui/check-cfg/well-known-values.stderr | 2 +- 4 files changed, 10 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index a2a5499597c..3ed9d39b38b 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -264,6 +264,10 @@ pub(crate) fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> Option { Some(LLVMFeature::new("fast-unaligned-access")) } + // Filter out features that are not supported by the current LLVM version + ("riscv32" | "riscv64", "zaamo") if get_version().0 < 19 => None, + ("riscv32" | "riscv64", "zabha") if get_version().0 < 19 => None, + ("riscv32" | "riscv64", "zalrsc") if get_version().0 < 19 => None, // Enable the evex512 target feature if an avx512 target feature is enabled. ("x86", s) if s.starts_with("avx512") => { Some(LLVMFeature::with_dependency(s, TargetFeatureFoldStrength::EnableOnly("evex512"))) diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs index be14107baa9..0a98b363b1a 100644 --- a/compiler/rustc_target/src/target_features.rs +++ b/compiler/rustc_target/src/target_features.rs @@ -373,7 +373,7 @@ const MIPS_ALLOWED_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ const RISCV_ALLOWED_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ // tidy-alphabetical-start - ("a", Stable, &[]), + ("a", Stable, &["zaamo", "zalrsc"]), ("c", Stable, &[]), ("d", Unstable(sym::riscv_target_feature), &["f"]), ("e", Unstable(sym::riscv_target_feature), &[]), @@ -382,6 +382,9 @@ const RISCV_ALLOWED_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ ("relax", Unstable(sym::riscv_target_feature), &[]), ("unaligned-scalar-mem", Unstable(sym::riscv_target_feature), &[]), ("v", Unstable(sym::riscv_target_feature), &[]), + ("zaamo", Unstable(sym::riscv_target_feature), &[]), + ("zabha", Unstable(sym::riscv_target_feature), &["zaamo"]), + ("zalrsc", Unstable(sym::riscv_target_feature), &[]), ("zba", Stable, &[]), ("zbb", Stable, &[]), ("zbc", Stable, &[]), diff --git a/tests/ui/check-cfg/mix.stderr b/tests/ui/check-cfg/mix.stderr index 653c1c983e2..7726c2d52f5 100644 --- a/tests/ui/check-cfg/mix.stderr +++ b/tests/ui/check-cfg/mix.stderr @@ -251,7 +251,7 @@ warning: unexpected `cfg` condition value: `zebra` LL | cfg!(target_feature = "zebra"); | ^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: expected values for `target_feature` are: `10e60`, `2e3`, `3e3r1`, `3e3r2`, `3e3r3`, `3e7`, `7e10`, `a`, `aclass`, `adx`, `aes`, `altivec`, `alu32`, `amx-bf16`, `amx-complex`, `amx-fp16`, `amx-int8`, `amx-tile`, `atomics`, `avx`, `avx2`, `avx512bf16`, `avx512bitalg`, `avx512bw`, `avx512cd`, `avx512dq`, `avx512f`, `avx512fp16`, `avx512ifma`, `avx512vbmi`, `avx512vbmi2`, `avx512vl`, `avx512vnni`, `avx512vp2intersect`, and `avx512vpopcntdq` and 241 more + = note: expected values for `target_feature` are: `10e60`, `2e3`, `3e3r1`, `3e3r2`, `3e3r3`, `3e7`, `7e10`, `a`, `aclass`, `adx`, `aes`, `altivec`, `alu32`, `amx-bf16`, `amx-complex`, `amx-fp16`, `amx-int8`, `amx-tile`, `atomics`, `avx`, `avx2`, `avx512bf16`, `avx512bitalg`, `avx512bw`, `avx512cd`, `avx512dq`, `avx512f`, `avx512fp16`, `avx512ifma`, `avx512vbmi`, `avx512vbmi2`, `avx512vl`, `avx512vnni`, `avx512vp2intersect`, and `avx512vpopcntdq` and 244 more = note: see for more information about checking conditional configuration warning: 27 warnings emitted diff --git a/tests/ui/check-cfg/well-known-values.stderr b/tests/ui/check-cfg/well-known-values.stderr index 14832e7ff43..3c99fdd3821 100644 --- a/tests/ui/check-cfg/well-known-values.stderr +++ b/tests/ui/check-cfg/well-known-values.stderr @@ -174,7 +174,7 @@ warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` LL | target_feature = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: expected values for `target_feature` are: `10e60`, `2e3`, `3e3r1`, `3e3r2`, `3e3r3`, `3e7`, `7e10`, `a`, `aclass`, `adx`, `aes`, `altivec`, `alu32`, `amx-bf16`, `amx-complex`, `amx-fp16`, `amx-int8`, `amx-tile`, `atomics`, `avx`, `avx2`, `avx512bf16`, `avx512bitalg`, `avx512bw`, `avx512cd`, `avx512dq`, `avx512f`, `avx512fp16`, `avx512ifma`, `avx512vbmi`, `avx512vbmi2`, `avx512vl`, `avx512vnni`, `avx512vp2intersect`, `avx512vpopcntdq`, `avxifma`, `avxneconvert`, `avxvnni`, `avxvnniint16`, `avxvnniint8`, `backchain`, `bf16`, `bmi1`, `bmi2`, `bti`, `bulk-memory`, `c`, `cache`, `cmpxchg16b`, `crc`, `crt-static`, `cssc`, `d`, `d32`, `dit`, `doloop`, `dotprod`, `dpb`, `dpb2`, `dsp`, `dsp1e2`, `dspe60`, `e`, `e1`, `e2`, `ecv`, `edsp`, `elrw`, `ermsb`, `exception-handling`, `extended-const`, `f`, `f16c`, `f32mm`, `f64mm`, `faminmax`, `fcma`, `fdivdu`, `fhm`, `flagm`, `flagm2`, `float1e2`, `float1e3`, `float3e4`, `float7e60`, `floate1`, `fma`, `fp-armv8`, `fp16`, `fp64`, `fp8`, `fp8dot2`, `fp8dot4`, `fp8fma`, `fpuv2_df`, `fpuv2_sf`, `fpuv3_df`, `fpuv3_hf`, `fpuv3_hi`, `fpuv3_sf`, `frecipe`, `frintts`, `fxsr`, `gfni`, `hard-float`, `hard-float-abi`, `hard-tp`, `hbc`, `high-registers`, `hvx`, `hvx-length128b`, `hwdiv`, `i8mm`, `jsconv`, `lahfsahf`, `lasx`, `lbt`, `lor`, `lse`, `lse128`, `lse2`, `lsx`, `lut`, `lvz`, `lzcnt`, `m`, `mclass`, `mops`, `movbe`, `mp`, `mp1e2`, `msa`, `mte`, `multivalue`, `mutable-globals`, `neon`, `nontrapping-fptoint`, `nvic`, `paca`, `pacg`, `pan`, `partword-atomics`, `pclmulqdq`, `pmuv3`, `popcnt`, `power10-vector`, `power8-altivec`, `power8-vector`, `power9-altivec`, `power9-vector`, `prfchw`, `quadword-atomics`, `rand`, `ras`, `rclass`, `rcpc`, `rcpc2`, `rcpc3`, `rdm`, `rdrand`, `rdseed`, `reference-types`, `relax`, `relaxed-simd`, `rtm`, `sb`, `sha`, `sha2`, `sha3`, `sha512`, `sign-ext`, `simd128`, `sm3`, `sm4`, `sme`, `sme-f16f16`, `sme-f64f64`, `sme-f8f16`, `sme-f8f32`, `sme-fa64`, `sme-i16i64`, `sme-lutv2`, `sme2`, `sme2p1`, `spe`, `ssbs`, `sse`, `sse2`, `sse3`, `sse4.1`, `sse4.2`, `sse4a`, `ssse3`, `ssve-fp8dot2`, `ssve-fp8dot4`, `ssve-fp8fma`, `sve`, `sve-b16b16`, `sve2`, `sve2-aes`, `sve2-bitperm`, `sve2-sha3`, `sve2-sm4`, `sve2p1`, `tbm`, `thumb-mode`, `thumb2`, `tme`, `trust`, `trustzone`, `ual`, `unaligned-scalar-mem`, `v`, `v5te`, `v6`, `v6k`, `v6t2`, `v7`, `v8`, `v8.1a`, `v8.2a`, `v8.3a`, `v8.4a`, `v8.5a`, `v8.6a`, `v8.7a`, `v8.8a`, `v8.9a`, `v9.1a`, `v9.2a`, `v9.3a`, `v9.4a`, `v9.5a`, `v9a`, `vaes`, `vdsp2e60f`, `vdspv1`, `vdspv2`, `vector`, `vfp2`, `vfp3`, `vfp4`, `vh`, `virt`, `virtualization`, `vpclmulqdq`, `vsx`, `wfxt`, `xop`, `xsave`, `xsavec`, `xsaveopt`, `xsaves`, `zba`, `zbb`, `zbc`, `zbkb`, `zbkc`, `zbkx`, `zbs`, `zdinx`, `zfh`, `zfhmin`, `zfinx`, `zhinx`, `zhinxmin`, `zk`, `zkn`, `zknd`, `zkne`, `zknh`, `zkr`, `zks`, `zksed`, `zksh`, and `zkt` + = note: expected values for `target_feature` are: `10e60`, `2e3`, `3e3r1`, `3e3r2`, `3e3r3`, `3e7`, `7e10`, `a`, `aclass`, `adx`, `aes`, `altivec`, `alu32`, `amx-bf16`, `amx-complex`, `amx-fp16`, `amx-int8`, `amx-tile`, `atomics`, `avx`, `avx2`, `avx512bf16`, `avx512bitalg`, `avx512bw`, `avx512cd`, `avx512dq`, `avx512f`, `avx512fp16`, `avx512ifma`, `avx512vbmi`, `avx512vbmi2`, `avx512vl`, `avx512vnni`, `avx512vp2intersect`, `avx512vpopcntdq`, `avxifma`, `avxneconvert`, `avxvnni`, `avxvnniint16`, `avxvnniint8`, `backchain`, `bf16`, `bmi1`, `bmi2`, `bti`, `bulk-memory`, `c`, `cache`, `cmpxchg16b`, `crc`, `crt-static`, `cssc`, `d`, `d32`, `dit`, `doloop`, `dotprod`, `dpb`, `dpb2`, `dsp`, `dsp1e2`, `dspe60`, `e`, `e1`, `e2`, `ecv`, `edsp`, `elrw`, `ermsb`, `exception-handling`, `extended-const`, `f`, `f16c`, `f32mm`, `f64mm`, `faminmax`, `fcma`, `fdivdu`, `fhm`, `flagm`, `flagm2`, `float1e2`, `float1e3`, `float3e4`, `float7e60`, `floate1`, `fma`, `fp-armv8`, `fp16`, `fp64`, `fp8`, `fp8dot2`, `fp8dot4`, `fp8fma`, `fpuv2_df`, `fpuv2_sf`, `fpuv3_df`, `fpuv3_hf`, `fpuv3_hi`, `fpuv3_sf`, `frecipe`, `frintts`, `fxsr`, `gfni`, `hard-float`, `hard-float-abi`, `hard-tp`, `hbc`, `high-registers`, `hvx`, `hvx-length128b`, `hwdiv`, `i8mm`, `jsconv`, `lahfsahf`, `lasx`, `lbt`, `lor`, `lse`, `lse128`, `lse2`, `lsx`, `lut`, `lvz`, `lzcnt`, `m`, `mclass`, `mops`, `movbe`, `mp`, `mp1e2`, `msa`, `mte`, `multivalue`, `mutable-globals`, `neon`, `nontrapping-fptoint`, `nvic`, `paca`, `pacg`, `pan`, `partword-atomics`, `pclmulqdq`, `pmuv3`, `popcnt`, `power10-vector`, `power8-altivec`, `power8-vector`, `power9-altivec`, `power9-vector`, `prfchw`, `quadword-atomics`, `rand`, `ras`, `rclass`, `rcpc`, `rcpc2`, `rcpc3`, `rdm`, `rdrand`, `rdseed`, `reference-types`, `relax`, `relaxed-simd`, `rtm`, `sb`, `sha`, `sha2`, `sha3`, `sha512`, `sign-ext`, `simd128`, `sm3`, `sm4`, `sme`, `sme-f16f16`, `sme-f64f64`, `sme-f8f16`, `sme-f8f32`, `sme-fa64`, `sme-i16i64`, `sme-lutv2`, `sme2`, `sme2p1`, `spe`, `ssbs`, `sse`, `sse2`, `sse3`, `sse4.1`, `sse4.2`, `sse4a`, `ssse3`, `ssve-fp8dot2`, `ssve-fp8dot4`, `ssve-fp8fma`, `sve`, `sve-b16b16`, `sve2`, `sve2-aes`, `sve2-bitperm`, `sve2-sha3`, `sve2-sm4`, `sve2p1`, `tbm`, `thumb-mode`, `thumb2`, `tme`, `trust`, `trustzone`, `ual`, `unaligned-scalar-mem`, `v`, `v5te`, `v6`, `v6k`, `v6t2`, `v7`, `v8`, `v8.1a`, `v8.2a`, `v8.3a`, `v8.4a`, `v8.5a`, `v8.6a`, `v8.7a`, `v8.8a`, `v8.9a`, `v9.1a`, `v9.2a`, `v9.3a`, `v9.4a`, `v9.5a`, `v9a`, `vaes`, `vdsp2e60f`, `vdspv1`, `vdspv2`, `vector`, `vfp2`, `vfp3`, `vfp4`, `vh`, `virt`, `virtualization`, `vpclmulqdq`, `vsx`, `wfxt`, `xop`, `xsave`, `xsavec`, `xsaveopt`, `xsaves`, `zaamo`, `zabha`, `zalrsc`, `zba`, `zbb`, `zbc`, `zbkb`, `zbkc`, `zbkx`, `zbs`, `zdinx`, `zfh`, `zfhmin`, `zfinx`, `zhinx`, `zhinxmin`, `zk`, `zkn`, `zknd`, `zkne`, `zknh`, `zkr`, `zks`, `zksed`, `zksh`, and `zkt` = note: see for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` From 5efb3ef2da9348d23c26171dce78ec02fe888653 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Bj=C3=B8rnager=20Jensen?= Date: Sat, 28 Sep 2024 08:31:51 +0200 Subject: [PATCH 358/683] Update Unicode escapes; --- library/core/src/char/methods.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/library/core/src/char/methods.rs b/library/core/src/char/methods.rs index 3dcaab6a12b..3f11e4fe21c 100644 --- a/library/core/src/char/methods.rs +++ b/library/core/src/char/methods.rs @@ -69,7 +69,7 @@ impl char { /// assert_eq!(char::from_u32(value_at_max + 1), None); /// ``` #[stable(feature = "assoc_char_consts", since = "1.52.0")] - pub const MAX: char = '\u{10ffff}'; + pub const MAX: char = '\u{10FFFF}'; /// `U+FFFD REPLACEMENT CHARACTER` (�) is used in Unicode to represent a /// decoding error. @@ -1837,7 +1837,6 @@ pub const fn encode_utf16_raw(mut code: u32, dst: &mut [u16]) -> &mut [u16] { } (2, [a, b, ..]) => { code -= 0x1_0000; - *a = (code >> 10) as u16 | 0xD800; *b = (code & 0x3FF) as u16 | 0xDC00; } From 5c3ceb3bd90c2ae082e381d72964a8306d05c15e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 28 Sep 2024 10:19:13 +0200 Subject: [PATCH 359/683] make ptr metadata functions callable from stable const fn --- library/core/src/intrinsics.rs | 4 ++-- library/core/src/ptr/const_ptr.rs | 10 +--------- library/core/src/ptr/metadata.rs | 6 +++--- library/core/src/ptr/mod.rs | 3 --- library/core/src/ptr/mut_ptr.rs | 10 +--------- library/core/src/ptr/non_null.rs | 2 -- library/core/src/slice/mod.rs | 1 - 7 files changed, 7 insertions(+), 29 deletions(-) diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index 881a89f4d10..548cb0912a0 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -3160,7 +3160,7 @@ pub const fn type_id() -> u128 { /// change the possible layouts of pointers. #[rustc_nounwind] #[unstable(feature = "core_intrinsics", issue = "none")] -#[rustc_const_unstable(feature = "ptr_metadata", issue = "81513")] +#[rustc_const_stable(feature = "ptr_metadata_const", since = "CURRENT_RUSTC_VERSION")] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] pub const fn aggregate_raw_ptr, D, M>(_data: D, _meta: M) -> P { @@ -3185,7 +3185,7 @@ impl AggregateRawPtr<*mut T> for *mut P { /// This is used to implement functions like `ptr::metadata`. #[rustc_nounwind] #[unstable(feature = "core_intrinsics", issue = "none")] -#[rustc_const_unstable(feature = "ptr_metadata", issue = "81513")] +#[rustc_const_stable(feature = "ptr_metadata_const", since = "CURRENT_RUSTC_VERSION")] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] pub const fn ptr_metadata + ?Sized, M>(_ptr: *const P) -> M { diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs index 1146ca6ef43..73f0538a49d 100644 --- a/library/core/src/ptr/const_ptr.rs +++ b/library/core/src/ptr/const_ptr.rs @@ -92,7 +92,7 @@ impl *const T { /// } /// ``` #[unstable(feature = "set_ptr_value", issue = "75091")] - #[rustc_const_unstable(feature = "set_ptr_value", issue = "75091")] + #[rustc_const_stable(feature = "ptr_metadata_const", since = "CURRENT_RUSTC_VERSION")] #[must_use = "returns a new pointer rather than modifying its argument"] #[inline] pub const fn with_metadata_of(self, meta: *const U) -> *const U @@ -412,7 +412,6 @@ impl *const T { #[inline(always)] #[stable(feature = "pointer_byte_offsets", since = "1.75.0")] #[rustc_const_stable(feature = "const_pointer_byte_offsets", since = "1.75.0")] - #[rustc_allow_const_fn_unstable(set_ptr_value)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn byte_offset(self, count: isize) -> Self { // SAFETY: the caller must uphold the safety contract for `offset`. @@ -495,7 +494,6 @@ impl *const T { #[inline(always)] #[stable(feature = "pointer_byte_offsets", since = "1.75.0")] #[rustc_const_stable(feature = "const_pointer_byte_offsets", since = "1.75.0")] - #[rustc_allow_const_fn_unstable(set_ptr_value)] pub const fn wrapping_byte_offset(self, count: isize) -> Self { self.cast::().wrapping_offset(count).with_metadata_of(self) } @@ -645,7 +643,6 @@ impl *const T { #[inline(always)] #[stable(feature = "pointer_byte_offsets", since = "1.75.0")] #[rustc_const_stable(feature = "const_pointer_byte_offsets", since = "1.75.0")] - #[rustc_allow_const_fn_unstable(set_ptr_value)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn byte_offset_from(self, origin: *const U) -> isize { // SAFETY: the caller must uphold the safety contract for `offset_from`. @@ -873,7 +870,6 @@ impl *const T { #[inline(always)] #[stable(feature = "pointer_byte_offsets", since = "1.75.0")] #[rustc_const_stable(feature = "const_pointer_byte_offsets", since = "1.75.0")] - #[rustc_allow_const_fn_unstable(set_ptr_value)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn byte_add(self, count: usize) -> Self { // SAFETY: the caller must uphold the safety contract for `add`. @@ -956,7 +952,6 @@ impl *const T { #[inline(always)] #[stable(feature = "pointer_byte_offsets", since = "1.75.0")] #[rustc_const_stable(feature = "const_pointer_byte_offsets", since = "1.75.0")] - #[rustc_allow_const_fn_unstable(set_ptr_value)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn byte_sub(self, count: usize) -> Self { // SAFETY: the caller must uphold the safety contract for `sub`. @@ -1039,7 +1034,6 @@ impl *const T { #[inline(always)] #[stable(feature = "pointer_byte_offsets", since = "1.75.0")] #[rustc_const_stable(feature = "const_pointer_byte_offsets", since = "1.75.0")] - #[rustc_allow_const_fn_unstable(set_ptr_value)] pub const fn wrapping_byte_add(self, count: usize) -> Self { self.cast::().wrapping_add(count).with_metadata_of(self) } @@ -1120,7 +1114,6 @@ impl *const T { #[inline(always)] #[stable(feature = "pointer_byte_offsets", since = "1.75.0")] #[rustc_const_stable(feature = "const_pointer_byte_offsets", since = "1.75.0")] - #[rustc_allow_const_fn_unstable(set_ptr_value)] pub const fn wrapping_byte_sub(self, count: usize) -> Self { self.cast::().wrapping_sub(count).with_metadata_of(self) } @@ -1554,7 +1547,6 @@ impl *const [T] { #[inline] #[stable(feature = "slice_ptr_len", since = "1.79.0")] #[rustc_const_stable(feature = "const_slice_ptr_len", since = "1.79.0")] - #[rustc_allow_const_fn_unstable(ptr_metadata)] pub const fn len(self) -> usize { metadata(self) } diff --git a/library/core/src/ptr/metadata.rs b/library/core/src/ptr/metadata.rs index 76a0e2ba774..feeaf78d3e7 100644 --- a/library/core/src/ptr/metadata.rs +++ b/library/core/src/ptr/metadata.rs @@ -92,7 +92,7 @@ pub trait Thin = Pointee; /// /// assert_eq!(std::ptr::metadata("foo"), 3_usize); /// ``` -#[rustc_const_unstable(feature = "ptr_metadata", issue = "81513")] +#[rustc_const_stable(feature = "ptr_metadata_const", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const fn metadata(ptr: *const T) -> ::Metadata { ptr_metadata(ptr) @@ -106,7 +106,7 @@ pub const fn metadata(ptr: *const T) -> ::Metadata { /// /// [`slice::from_raw_parts`]: crate::slice::from_raw_parts #[unstable(feature = "ptr_metadata", issue = "81513")] -#[rustc_const_unstable(feature = "ptr_metadata", issue = "81513")] +#[rustc_const_stable(feature = "ptr_metadata_const", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const fn from_raw_parts( data_pointer: *const impl Thin, @@ -120,7 +120,7 @@ pub const fn from_raw_parts( /// /// See the documentation of [`from_raw_parts`] for more details. #[unstable(feature = "ptr_metadata", issue = "81513")] -#[rustc_const_unstable(feature = "ptr_metadata", issue = "81513")] +#[rustc_const_stable(feature = "ptr_metadata_const", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const fn from_raw_parts_mut( data_pointer: *mut impl Thin, diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs index 4f97048eab1..b6df780fe2f 100644 --- a/library/core/src/ptr/mod.rs +++ b/library/core/src/ptr/mod.rs @@ -599,7 +599,6 @@ pub unsafe fn drop_in_place(to_drop: *mut T) { #[stable(feature = "rust1", since = "1.0.0")] #[rustc_promotable] #[rustc_const_stable(feature = "const_ptr_null", since = "1.24.0")] -#[rustc_allow_const_fn_unstable(ptr_metadata)] #[rustc_diagnostic_item = "ptr_null"] pub const fn null() -> *const T { from_raw_parts(without_provenance::<()>(0), ()) @@ -625,7 +624,6 @@ pub const fn null() -> *const T { #[stable(feature = "rust1", since = "1.0.0")] #[rustc_promotable] #[rustc_const_stable(feature = "const_ptr_null", since = "1.24.0")] -#[rustc_allow_const_fn_unstable(ptr_metadata)] #[rustc_diagnostic_item = "ptr_null_mut"] pub const fn null_mut() -> *mut T { from_raw_parts_mut(without_provenance_mut::<()>(0), ()) @@ -949,7 +947,6 @@ pub const fn from_mut(r: &mut T) -> *mut T { #[inline] #[stable(feature = "slice_from_raw_parts", since = "1.42.0")] #[rustc_const_stable(feature = "const_slice_from_raw_parts", since = "1.64.0")] -#[rustc_allow_const_fn_unstable(ptr_metadata)] #[rustc_diagnostic_item = "ptr_slice_from_raw_parts"] pub const fn slice_from_raw_parts(data: *const T, len: usize) -> *const [T] { from_raw_parts(data, len) diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index 8e33cf081ba..b737c5fdc40 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -74,7 +74,7 @@ impl *mut T { /// } /// ``` #[unstable(feature = "set_ptr_value", issue = "75091")] - #[rustc_const_unstable(feature = "set_ptr_value", issue = "75091")] + #[rustc_const_stable(feature = "ptr_metadata_const", since = "CURRENT_RUSTC_VERSION")] #[must_use = "returns a new pointer rather than modifying its argument"] #[inline] pub const fn with_metadata_of(self, meta: *const U) -> *mut U @@ -412,7 +412,6 @@ impl *mut T { #[inline(always)] #[stable(feature = "pointer_byte_offsets", since = "1.75.0")] #[rustc_const_stable(feature = "const_pointer_byte_offsets", since = "1.75.0")] - #[rustc_allow_const_fn_unstable(set_ptr_value)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn byte_offset(self, count: isize) -> Self { // SAFETY: the caller must uphold the safety contract for `offset`. @@ -492,7 +491,6 @@ impl *mut T { #[inline(always)] #[stable(feature = "pointer_byte_offsets", since = "1.75.0")] #[rustc_const_stable(feature = "const_pointer_byte_offsets", since = "1.75.0")] - #[rustc_allow_const_fn_unstable(set_ptr_value)] pub const fn wrapping_byte_offset(self, count: isize) -> Self { self.cast::().wrapping_offset(count).with_metadata_of(self) } @@ -808,7 +806,6 @@ impl *mut T { #[inline(always)] #[stable(feature = "pointer_byte_offsets", since = "1.75.0")] #[rustc_const_stable(feature = "const_pointer_byte_offsets", since = "1.75.0")] - #[rustc_allow_const_fn_unstable(set_ptr_value)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn byte_offset_from(self, origin: *const U) -> isize { // SAFETY: the caller must uphold the safety contract for `offset_from`. @@ -954,7 +951,6 @@ impl *mut T { #[inline(always)] #[stable(feature = "pointer_byte_offsets", since = "1.75.0")] #[rustc_const_stable(feature = "const_pointer_byte_offsets", since = "1.75.0")] - #[rustc_allow_const_fn_unstable(set_ptr_value)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn byte_add(self, count: usize) -> Self { // SAFETY: the caller must uphold the safety contract for `add`. @@ -1037,7 +1033,6 @@ impl *mut T { #[inline(always)] #[stable(feature = "pointer_byte_offsets", since = "1.75.0")] #[rustc_const_stable(feature = "const_pointer_byte_offsets", since = "1.75.0")] - #[rustc_allow_const_fn_unstable(set_ptr_value)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn byte_sub(self, count: usize) -> Self { // SAFETY: the caller must uphold the safety contract for `sub`. @@ -1118,7 +1113,6 @@ impl *mut T { #[inline(always)] #[stable(feature = "pointer_byte_offsets", since = "1.75.0")] #[rustc_const_stable(feature = "const_pointer_byte_offsets", since = "1.75.0")] - #[rustc_allow_const_fn_unstable(set_ptr_value)] pub const fn wrapping_byte_add(self, count: usize) -> Self { self.cast::().wrapping_add(count).with_metadata_of(self) } @@ -1197,7 +1191,6 @@ impl *mut T { #[inline(always)] #[stable(feature = "pointer_byte_offsets", since = "1.75.0")] #[rustc_const_stable(feature = "const_pointer_byte_offsets", since = "1.75.0")] - #[rustc_allow_const_fn_unstable(set_ptr_value)] pub const fn wrapping_byte_sub(self, count: usize) -> Self { self.cast::().wrapping_sub(count).with_metadata_of(self) } @@ -1804,7 +1797,6 @@ impl *mut [T] { #[inline(always)] #[stable(feature = "slice_ptr_len", since = "1.79.0")] #[rustc_const_stable(feature = "const_slice_ptr_len", since = "1.79.0")] - #[rustc_allow_const_fn_unstable(ptr_metadata)] pub const fn len(self) -> usize { metadata(self) } diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs index daa40b3c9d2..e7a265f7e2b 100644 --- a/library/core/src/ptr/non_null.rs +++ b/library/core/src/ptr/non_null.rs @@ -567,7 +567,6 @@ impl NonNull { #[must_use] #[inline(always)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces - #[rustc_allow_const_fn_unstable(set_ptr_value)] #[stable(feature = "non_null_convenience", since = "1.80.0")] #[rustc_const_stable(feature = "non_null_convenience", since = "1.80.0")] pub const unsafe fn byte_add(self, count: usize) -> Self { @@ -651,7 +650,6 @@ impl NonNull { #[must_use] #[inline(always)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces - #[rustc_allow_const_fn_unstable(set_ptr_value)] #[stable(feature = "non_null_convenience", since = "1.80.0")] #[rustc_const_stable(feature = "non_null_convenience", since = "1.80.0")] pub const unsafe fn byte_sub(self, count: usize) -> Self { diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index dd8fa1ae343..922168b9e8e 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -111,7 +111,6 @@ impl [T] { #[lang = "slice_len_fn"] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_slice_len", since = "1.39.0")] - #[rustc_allow_const_fn_unstable(ptr_metadata)] #[inline] #[must_use] pub const fn len(&self) -> usize { From ac488a2c3fc77462926d4db1031decc0ac142ad2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 28 Sep 2024 11:29:02 +0200 Subject: [PATCH 360/683] stabilize const_cell_into_inner --- library/core/src/cell.rs | 51 ++++----------------------------- library/core/src/cell/once.rs | 3 +- library/core/src/lib.rs | 1 - library/core/src/sync/atomic.rs | 6 ++-- library/core/tests/lib.rs | 1 - 5 files changed, 11 insertions(+), 51 deletions(-) diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs index a3e91bc0670..d7620c07635 100644 --- a/library/core/src/cell.rs +++ b/library/core/src/cell.rs @@ -514,7 +514,8 @@ impl Cell { /// assert_eq!(five, 5); /// ``` #[stable(feature = "move_cell", since = "1.17.0")] - #[rustc_const_unstable(feature = "const_cell_into_inner", issue = "78729")] + #[rustc_const_stable(feature = "const_cell_into_inner", since = "CURRENT_RUSTC_VERSION")] + #[rustc_allow_const_fn_unstable(const_precise_live_drops)] pub const fn into_inner(self) -> T { self.value.into_inner() } @@ -857,7 +858,8 @@ impl RefCell { /// let five = c.into_inner(); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_cell_into_inner", issue = "78729")] + #[rustc_const_stable(feature = "const_cell_into_inner", since = "CURRENT_RUSTC_VERSION")] + #[rustc_allow_const_fn_unstable(const_precise_live_drops)] #[inline] pub const fn into_inner(self) -> T { // Since this function takes `self` (the `RefCell`) by value, the @@ -2098,8 +2100,8 @@ impl UnsafeCell { /// ``` #[inline(always)] #[stable(feature = "rust1", since = "1.0.0")] - // When this is const stabilized, please remove `primitive_into_inner` below. - #[rustc_const_unstable(feature = "const_cell_into_inner", issue = "78729")] + #[rustc_const_stable(feature = "const_cell_into_inner", since = "CURRENT_RUSTC_VERSION")] + #[rustc_allow_const_fn_unstable(const_precise_live_drops)] pub const fn into_inner(self) -> T { self.value } @@ -2245,47 +2247,6 @@ impl, U> CoerceUnsized> for UnsafeCell {} #[unstable(feature = "dispatch_from_dyn", issue = "none")] impl, U> DispatchFromDyn> for UnsafeCell {} -// Special cases of UnsafeCell::into_inner where T is a primitive. These are -// used by Atomic*::into_inner. -// -// The real UnsafeCell::into_inner cannot be used yet in a stable const function. -// That is blocked on a "precise drop analysis" unstable const feature. -// https://github.com/rust-lang/rust/issues/73255 -macro_rules! unsafe_cell_primitive_into_inner { - ($($primitive:ident $atomic:literal)*) => { - $( - #[cfg(target_has_atomic_load_store = $atomic)] - impl UnsafeCell<$primitive> { - pub(crate) const fn primitive_into_inner(self) -> $primitive { - self.value - } - } - )* - }; -} - -unsafe_cell_primitive_into_inner! { - i8 "8" - u8 "8" - i16 "16" - u16 "16" - i32 "32" - u32 "32" - i64 "64" - u64 "64" - i128 "128" - u128 "128" - isize "ptr" - usize "ptr" -} - -#[cfg(target_has_atomic_load_store = "ptr")] -impl UnsafeCell<*mut T> { - pub(crate) const fn primitive_into_inner(self) -> *mut T { - self.value - } -} - /// [`UnsafeCell`], but [`Sync`]. /// /// This is just an `UnsafeCell`, except it implements `Sync` diff --git a/library/core/src/cell/once.rs b/library/core/src/cell/once.rs index 87df8a4e272..14c587e0c48 100644 --- a/library/core/src/cell/once.rs +++ b/library/core/src/cell/once.rs @@ -309,7 +309,8 @@ impl OnceCell { /// ``` #[inline] #[stable(feature = "once_cell", since = "1.70.0")] - #[rustc_const_unstable(feature = "const_cell_into_inner", issue = "78729")] + #[rustc_const_stable(feature = "const_cell_into_inner", since = "CURRENT_RUSTC_VERSION")] + #[rustc_allow_const_fn_unstable(const_precise_live_drops)] pub const fn into_inner(self) -> Option { // Because `into_inner` takes `self` by value, the compiler statically verifies // that it is not currently borrowed. So it is safe to move out `Option`. diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 01cadd78cc0..817d9e3b962 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -118,7 +118,6 @@ #![feature(const_array_into_iter_constructors)] #![feature(const_bigint_helper_methods)] #![feature(const_black_box)] -#![feature(const_cell_into_inner)] #![feature(const_char_encode_utf16)] #![feature(const_char_encode_utf8)] #![feature(const_eval_select)] diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs index b06a3bd4487..f6d29183204 100644 --- a/library/core/src/sync/atomic.rs +++ b/library/core/src/sync/atomic.rs @@ -577,7 +577,7 @@ impl AtomicBool { #[stable(feature = "atomic_access", since = "1.15.0")] #[rustc_const_stable(feature = "const_atomic_into_inner", since = "1.79.0")] pub const fn into_inner(self) -> bool { - self.v.primitive_into_inner() != 0 + self.v.into_inner() != 0 } /// Loads a value from the bool. @@ -1394,7 +1394,7 @@ impl AtomicPtr { #[stable(feature = "atomic_access", since = "1.15.0")] #[rustc_const_stable(feature = "const_atomic_into_inner", since = "1.79.0")] pub const fn into_inner(self) -> *mut T { - self.p.primitive_into_inner() + self.p.into_inner() } /// Loads a value from the pointer. @@ -2389,7 +2389,7 @@ macro_rules! atomic_int { #[$stable_access] #[rustc_const_stable(feature = "const_atomic_into_inner", since = "1.79.0")] pub const fn into_inner(self) -> $int_type { - self.v.primitive_into_inner() + self.v.into_inner() } /// Loads a value from the atomic integer. diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index 604c0d48743..4f2190f78bf 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -18,7 +18,6 @@ #![feature(const_align_offset)] #![feature(const_array_from_ref)] #![feature(const_black_box)] -#![feature(const_cell_into_inner)] #![feature(const_hash)] #![feature(const_heap)] #![feature(const_ip)] From 76bce58b7ae52890d83edc5486c1427c3ab3c546 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 7 Aug 2024 14:30:26 +0200 Subject: [PATCH 361/683] atomics: allow atomic and non-atomic reads to race --- library/core/src/sync/atomic.rs | 62 ++++++++++++++++++++------------- 1 file changed, 38 insertions(+), 24 deletions(-) diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs index b06a3bd4487..b3fe99f7f1a 100644 --- a/library/core/src/sync/atomic.rs +++ b/library/core/src/sync/atomic.rs @@ -24,26 +24,37 @@ //! //! ## Memory model for atomic accesses //! -//! Rust atomics currently follow the same rules as [C++20 atomics][cpp], specifically `atomic_ref`. -//! Basically, creating a *shared reference* to one of the Rust atomic types corresponds to creating -//! an `atomic_ref` in C++; the `atomic_ref` is destroyed when the lifetime of the shared reference -//! ends. A Rust atomic type that is exclusively owned or behind a mutable reference does *not* -//! correspond to an “atomic object” in C++, since the underlying primitive can be mutably accessed, -//! for example with `get_mut`, to perform non-atomic operations. +//! Rust atomics currently follow the same rules as [C++20 atomics][cpp], specifically the rules +//! from the [`intro.races`][cpp-intro.races] section, without the "consume" memory ordering. Since +//! C++ uses an object-based memory model whereas Rust is access-based, a bit of translation work +//! has to be done to apply the C++ rules to Rust: whenever C++ talks about "the value of an +//! object", we understand that to mean the resulting bytes obtained when doing a read. When the C++ +//! standard talks about "the value of an atomic object", this refers to the result of doing an +//! atomic load (via the operations provided in this module). A "modification of an atomic object" +//! refers to an atomic store. +//! +//! The end result is *almost* equivalent to saying that creating a *shared reference* to one of the +//! Rust atomic types corresponds to creating an `atomic_ref` in C++, with the `atomic_ref` being +//! destroyed when the lifetime of the shared reference ends. The main difference is that Rust +//! permits concurrent atomic and non-atomic reads to the same memory as those cause no issue in the +//! C++ memory model, they are just forbidden in C++ because memory is partitioned into "atomic +//! objects" and "non-atomic objects" (with `atomic_ref` temporarily converting a non-atomic object +//! into an atomic object). +//! +//! That said, Rust *does* inherit the C++ limitation that non-synchronized atomic accesses may not +//! partially overlap: they must be either disjoint or access the exact same memory. This in +//! particular rules out non-synchronized differently-sized accesses to the same data. //! //! [cpp]: https://en.cppreference.com/w/cpp/atomic +//! [cpp-intro.races]: https://timsong-cpp.github.io/cppwp/n4868/intro.multithread#intro.races //! //! Each method takes an [`Ordering`] which represents the strength of -//! the memory barrier for that operation. These orderings are the -//! same as the [C++20 atomic orderings][1]. For more information see the [nomicon][2]. +//! the memory barrier for that operation. These orderings behave the +//! same as the corresponding [C++20 atomic orderings][1]. For more information see the [nomicon][2]. //! //! [1]: https://en.cppreference.com/w/cpp/atomic/memory_order //! [2]: ../../../nomicon/atomics.html //! -//! Since C++ does not support mixing atomic and non-atomic accesses, or non-synchronized -//! different-sized accesses to the same data, Rust does not support those operations either. -//! Note that both of those restrictions only apply if the accesses are non-synchronized. -//! //! ```rust,no_run undefined_behavior //! use std::sync::atomic::{AtomicU16, AtomicU8, Ordering}; //! use std::mem::transmute; @@ -52,27 +63,30 @@ //! let atomic = AtomicU16::new(0); //! //! thread::scope(|s| { -//! // This is UB: mixing atomic and non-atomic accesses -//! s.spawn(|| atomic.store(1, Ordering::Relaxed)); -//! s.spawn(|| unsafe { atomic.as_ptr().write(2) }); +//! // This is UB: conflicting concurrent accesses. +//! s.spawn(|| atomic.store(1, Ordering::Relaxed)); // atomic store +//! s.spawn(|| unsafe { atomic.as_ptr().write(2) }); // non-atomic write //! }); //! //! thread::scope(|s| { -//! // This is UB: even reads are not allowed to be mixed -//! s.spawn(|| atomic.load(Ordering::Relaxed)); -//! s.spawn(|| unsafe { atomic.as_ptr().read() }); +//! // This is fine: the accesses do not conflict (as none of them performs any modification). +//! // In C++ this would be disallowed since creating an `atomic_ref` precludes +//! // further non-atomic accesses, but Rust does not have that limitation. +//! s.spawn(|| atomic.load(Ordering::Relaxed)); // atomic load +//! s.spawn(|| unsafe { atomic.as_ptr().read() }); // non-atomic read //! }); //! //! thread::scope(|s| { //! // This is fine, `join` synchronizes the code in a way such that atomic -//! // and non-atomic accesses can't happen "at the same time" -//! let handle = s.spawn(|| atomic.store(1, Ordering::Relaxed)); -//! handle.join().unwrap(); -//! s.spawn(|| unsafe { atomic.as_ptr().write(2) }); +//! // and non-atomic accesses can't happen "at the same time". +//! let handle = s.spawn(|| atomic.store(1, Ordering::Relaxed)); // atomic store +//! handle.join().unwrap(); // synchronize +//! s.spawn(|| unsafe { atomic.as_ptr().write(2) }); // non-atomic write //! }); //! //! thread::scope(|s| { -//! // This is UB: using different-sized atomic accesses to the same data +//! // This is UB: using differently-sized atomic accesses to the same data. +//! // (It would be UB even if these are both loads.) //! s.spawn(|| atomic.store(1, Ordering::Relaxed)); //! s.spawn(|| unsafe { //! let differently_sized = transmute::<&AtomicU16, &AtomicU8>(&atomic); @@ -82,7 +96,7 @@ //! //! thread::scope(|s| { //! // This is fine, `join` synchronizes the code in a way such that -//! // differently-sized accesses can't happen "at the same time" +//! // differently-sized accesses can't happen "at the same time". //! let handle = s.spawn(|| atomic.store(1, Ordering::Relaxed)); //! handle.join().unwrap(); //! s.spawn(|| unsafe { From ed417f44f81f7096bfe135e7d84092f2a7fecaa6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 7 Aug 2024 14:50:34 +0200 Subject: [PATCH 362/683] miri: no longer complain about read-read races --- src/tools/miri/src/concurrency/data_race.rs | 23 +++-------- .../tests/fail/data_race/read_read_race1.rs | 30 --------------- .../fail/data_race/read_read_race1.stderr | 22 ----------- .../tests/fail/data_race/read_read_race2.rs | 30 --------------- .../fail/data_race/read_read_race2.stderr | 22 ----------- .../miri/tests/pass/concurrency/data_race.rs | 38 ++++++++++++++++++- 6 files changed, 43 insertions(+), 122 deletions(-) delete mode 100644 src/tools/miri/tests/fail/data_race/read_read_race1.rs delete mode 100644 src/tools/miri/tests/fail/data_race/read_read_race1.stderr delete mode 100644 src/tools/miri/tests/fail/data_race/read_read_race2.rs delete mode 100644 src/tools/miri/tests/fail/data_race/read_read_race2.stderr diff --git a/src/tools/miri/src/concurrency/data_race.rs b/src/tools/miri/src/concurrency/data_race.rs index b5b43f589f6..558a032d0bc 100644 --- a/src/tools/miri/src/concurrency/data_race.rs +++ b/src/tools/miri/src/concurrency/data_race.rs @@ -499,7 +499,7 @@ impl MemoryCellClocks { Ok(()) } - /// Detect data-races with an atomic read, caused by a non-atomic access that does + /// Detect data-races with an atomic read, caused by a non-atomic write that does /// not happen-before the atomic-read. fn atomic_read_detect( &mut self, @@ -510,12 +510,8 @@ impl MemoryCellClocks { trace!("Atomic read with vectors: {:#?} :: {:#?}", self, thread_clocks); let atomic = self.atomic_access(thread_clocks, access_size)?; atomic.read_vector.set_at_index(&thread_clocks.clock, index); - // Make sure the last non-atomic write and all non-atomic reads were before this access. - if self.write_was_before(&thread_clocks.clock) && self.read <= thread_clocks.clock { - Ok(()) - } else { - Err(DataRace) - } + // Make sure the last non-atomic write was before this access. + if self.write_was_before(&thread_clocks.clock) { Ok(()) } else { Err(DataRace) } } /// Detect data-races with an atomic write, either with a non-atomic read or with @@ -552,11 +548,9 @@ impl MemoryCellClocks { } thread_clocks.clock.index_mut(index).set_read_type(read_type); if self.write_was_before(&thread_clocks.clock) { + // We must be ordered-after all atomic writes. let race_free = if let Some(atomic) = self.atomic() { - // We must be ordered-after all atomic accesses, reads and writes. - // This ensures we don't mix atomic and non-atomic accesses. atomic.write_vector <= thread_clocks.clock - && atomic.read_vector <= thread_clocks.clock } else { true }; @@ -957,9 +951,7 @@ impl VClockAlloc { let mut other_size = None; // if `Some`, this was a size-mismatch race let write_clock; let (other_access, other_thread, other_clock) = - // First check the atomic-nonatomic cases. If it looks like multiple - // cases apply, this one should take precedence, else it might look like - // we are reporting races between two non-atomic reads. + // First check the atomic-nonatomic cases. if !access.is_atomic() && let Some(atomic) = mem_clocks.atomic() && let Some(idx) = Self::find_gt_index(&atomic.write_vector, &active_clocks.clock) @@ -1007,10 +999,7 @@ impl VClockAlloc { assert!(!involves_non_atomic); Some("overlapping unsynchronized atomic accesses must use the same access size") } else if access.is_read() && other_access.is_read() { - assert!(involves_non_atomic); - Some( - "overlapping atomic and non-atomic accesses must be synchronized, even if both are read-only", - ) + panic!("there should be no same-size read-read races") } else { None }; diff --git a/src/tools/miri/tests/fail/data_race/read_read_race1.rs b/src/tools/miri/tests/fail/data_race/read_read_race1.rs deleted file mode 100644 index 02aa4e4b716..00000000000 --- a/src/tools/miri/tests/fail/data_race/read_read_race1.rs +++ /dev/null @@ -1,30 +0,0 @@ -//@compile-flags: -Zmiri-preemption-rate=0.0 -// Avoid accidental synchronization via address reuse inside `thread::spawn`. -//@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0 - -use std::sync::atomic::{AtomicU16, Ordering}; -use std::thread; - -// Make sure races between atomic and non-atomic reads are detected. -// This seems harmless but C++ does not allow them, so we can't allow them for now either. -// This test coverse the case where the non-atomic access come first. -fn main() { - let a = AtomicU16::new(0); - - thread::scope(|s| { - s.spawn(|| { - let ptr = &a as *const AtomicU16 as *mut u16; - unsafe { ptr.read() }; - }); - s.spawn(|| { - thread::yield_now(); - - // We also put a non-atomic access here, but that should *not* be reported. - let ptr = &a as *const AtomicU16 as *mut u16; - unsafe { ptr.read() }; - // Then do the atomic access. - a.load(Ordering::SeqCst); - //~^ ERROR: Data race detected between (1) non-atomic read on thread `unnamed-1` and (2) atomic load on thread `unnamed-2` - }); - }); -} diff --git a/src/tools/miri/tests/fail/data_race/read_read_race1.stderr b/src/tools/miri/tests/fail/data_race/read_read_race1.stderr deleted file mode 100644 index e97c4a4fdcb..00000000000 --- a/src/tools/miri/tests/fail/data_race/read_read_race1.stderr +++ /dev/null @@ -1,22 +0,0 @@ -error: Undefined Behavior: Data race detected between (1) non-atomic read on thread `unnamed-ID` and (2) atomic load on thread `unnamed-ID` at ALLOC. (2) just happened here - --> tests/fail/data_race/read_read_race1.rs:LL:CC - | -LL | a.load(Ordering::SeqCst); - | ^^^^^^^^^^^^^^^^^^^^^^^^ Data race detected between (1) non-atomic read on thread `unnamed-ID` and (2) atomic load on thread `unnamed-ID` at ALLOC. (2) just happened here - | -help: and (1) occurred earlier here - --> tests/fail/data_race/read_read_race1.rs:LL:CC - | -LL | unsafe { ptr.read() }; - | ^^^^^^^^^^ - = help: overlapping atomic and non-atomic accesses must be synchronized, even if both are read-only - = help: see https://doc.rust-lang.org/nightly/std/sync/atomic/index.html#memory-model-for-atomic-accesses for more information about the Rust memory model - = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior - = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: BACKTRACE (of the first span) on thread `unnamed-ID`: - = note: inside closure at tests/fail/data_race/read_read_race1.rs:LL:CC - -note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace - -error: aborting due to 1 previous error - diff --git a/src/tools/miri/tests/fail/data_race/read_read_race2.rs b/src/tools/miri/tests/fail/data_race/read_read_race2.rs deleted file mode 100644 index 3b94c9143f3..00000000000 --- a/src/tools/miri/tests/fail/data_race/read_read_race2.rs +++ /dev/null @@ -1,30 +0,0 @@ -//@compile-flags: -Zmiri-preemption-rate=0.0 -// Avoid accidental synchronization via address reuse inside `thread::spawn`. -//@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0 - -use std::sync::atomic::{AtomicU16, Ordering}; -use std::thread; - -// Make sure races between atomic and non-atomic reads are detected. -// This seems harmless but C++ does not allow them, so we can't allow them for now either. -// This test coverse the case where the atomic access come first. -fn main() { - let a = AtomicU16::new(0); - - thread::scope(|s| { - s.spawn(|| { - // We also put a non-atomic access here, but that should *not* be reported. - let ptr = &a as *const AtomicU16 as *mut u16; - unsafe { ptr.read() }; - // Then do the atomic access. - a.load(Ordering::SeqCst); - }); - s.spawn(|| { - thread::yield_now(); - - let ptr = &a as *const AtomicU16 as *mut u16; - unsafe { ptr.read() }; - //~^ ERROR: Data race detected between (1) atomic load on thread `unnamed-1` and (2) non-atomic read on thread `unnamed-2` - }); - }); -} diff --git a/src/tools/miri/tests/fail/data_race/read_read_race2.stderr b/src/tools/miri/tests/fail/data_race/read_read_race2.stderr deleted file mode 100644 index d64032db7b3..00000000000 --- a/src/tools/miri/tests/fail/data_race/read_read_race2.stderr +++ /dev/null @@ -1,22 +0,0 @@ -error: Undefined Behavior: Data race detected between (1) atomic load on thread `unnamed-ID` and (2) non-atomic read on thread `unnamed-ID` at ALLOC. (2) just happened here - --> tests/fail/data_race/read_read_race2.rs:LL:CC - | -LL | unsafe { ptr.read() }; - | ^^^^^^^^^^ Data race detected between (1) atomic load on thread `unnamed-ID` and (2) non-atomic read on thread `unnamed-ID` at ALLOC. (2) just happened here - | -help: and (1) occurred earlier here - --> tests/fail/data_race/read_read_race2.rs:LL:CC - | -LL | a.load(Ordering::SeqCst); - | ^^^^^^^^^^^^^^^^^^^^^^^^ - = help: overlapping atomic and non-atomic accesses must be synchronized, even if both are read-only - = help: see https://doc.rust-lang.org/nightly/std/sync/atomic/index.html#memory-model-for-atomic-accesses for more information about the Rust memory model - = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior - = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: BACKTRACE (of the first span) on thread `unnamed-ID`: - = note: inside closure at tests/fail/data_race/read_read_race2.rs:LL:CC - -note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace - -error: aborting due to 1 previous error - diff --git a/src/tools/miri/tests/pass/concurrency/data_race.rs b/src/tools/miri/tests/pass/concurrency/data_race.rs index 34380dfa504..adf5a37891f 100644 --- a/src/tools/miri/tests/pass/concurrency/data_race.rs +++ b/src/tools/miri/tests/pass/concurrency/data_race.rs @@ -1,7 +1,7 @@ //@compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 use std::sync::atomic::*; -use std::thread::spawn; +use std::thread::{self, spawn}; #[derive(Copy, Clone)] struct EvilSend(pub T); @@ -143,10 +143,46 @@ fn test_local_variable_lazy_write() { assert_eq!(val, 127); } +// This test coverse the case where the non-atomic access come first. +fn test_read_read_race1() { + let a = AtomicU16::new(0); + + thread::scope(|s| { + s.spawn(|| { + let ptr = &a as *const AtomicU16 as *mut u16; + unsafe { ptr.read() }; + }); + s.spawn(|| { + thread::yield_now(); + + a.load(Ordering::SeqCst); + }); + }); +} + +// This test coverse the case where the atomic access come first. +fn test_read_read_race2() { + let a = AtomicU16::new(0); + + thread::scope(|s| { + s.spawn(|| { + a.load(Ordering::SeqCst); + }); + s.spawn(|| { + thread::yield_now(); + + let ptr = &a as *const AtomicU16 as *mut u16; + unsafe { ptr.read() }; + }); + }); +} + pub fn main() { test_fence_sync(); test_multiple_reads(); test_rmw_no_block(); test_simple_release(); test_local_variable_lazy_write(); + test_read_read_race1(); + test_read_read_race2(); } From 6ca5e29e49811ccee4e8843c419ec45d7656aff6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 10 Aug 2024 19:47:22 +0200 Subject: [PATCH 363/683] allow mixed-size atomic reads --- library/core/src/sync/atomic.rs | 26 +++++++----- src/tools/miri/src/concurrency/data_race.rs | 40 ++++++++++++------ .../tests/fail/data_race/mixed_size_read.rs | 28 ------------- ...ze_read_read_write.match_first_load.stderr | 22 ++++++++++ ...e_read_read_write.match_second_load.stderr | 22 ++++++++++ .../data_race/mixed_size_read_read_write.rs | 39 ++++++++++++++++++ .../mixed_size_read_write.read_write.stderr | 22 ++++++++++ .../fail/data_race/mixed_size_read_write.rs | 39 ++++++++++++++++++ ...> mixed_size_read_write.write_read.stderr} | 14 +++---- ...ize_write.rs => mixed_size_write_write.rs} | 0 ...e.stderr => mixed_size_write_write.stderr} | 6 +-- .../fail/weak_memory/racing_mixed_size.rs | 41 ------------------- .../weak_memory/racing_mixed_size_read.rs | 39 ------------------ .../weak_memory/racing_mixed_size_read.stderr | 22 ---------- .../miri/tests/pass/concurrency/data_race.rs | 21 ++++++++++ 15 files changed, 218 insertions(+), 163 deletions(-) delete mode 100644 src/tools/miri/tests/fail/data_race/mixed_size_read.rs create mode 100644 src/tools/miri/tests/fail/data_race/mixed_size_read_read_write.match_first_load.stderr create mode 100644 src/tools/miri/tests/fail/data_race/mixed_size_read_read_write.match_second_load.stderr create mode 100644 src/tools/miri/tests/fail/data_race/mixed_size_read_read_write.rs create mode 100644 src/tools/miri/tests/fail/data_race/mixed_size_read_write.read_write.stderr create mode 100644 src/tools/miri/tests/fail/data_race/mixed_size_read_write.rs rename src/tools/miri/tests/fail/data_race/{mixed_size_read.stderr => mixed_size_read_write.write_read.stderr} (66%) rename src/tools/miri/tests/fail/data_race/{mixed_size_write.rs => mixed_size_write_write.rs} (100%) rename src/tools/miri/tests/fail/data_race/{mixed_size_write.stderr => mixed_size_write_write.stderr} (90%) delete mode 100644 src/tools/miri/tests/fail/weak_memory/racing_mixed_size.rs delete mode 100644 src/tools/miri/tests/fail/weak_memory/racing_mixed_size_read.rs delete mode 100644 src/tools/miri/tests/fail/weak_memory/racing_mixed_size_read.stderr diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs index b3fe99f7f1a..2357fb932b4 100644 --- a/library/core/src/sync/atomic.rs +++ b/library/core/src/sync/atomic.rs @@ -33,6 +33,12 @@ //! atomic load (via the operations provided in this module). A "modification of an atomic object" //! refers to an atomic store. //! +//! The most important aspect of this model is that conflicting non-synchronized accesses are +//! Undefined Behavior unless both accesses are atomic. Here, accesses are *conflicting* if they +//! affect overlapping regions of memory and at least one of them is a write. They are +//! *non-synchronized* if neither of them *happens-before* the other, according to the +//! happens-before order of the memory model. +//! //! The end result is *almost* equivalent to saying that creating a *shared reference* to one of the //! Rust atomic types corresponds to creating an `atomic_ref` in C++, with the `atomic_ref` being //! destroyed when the lifetime of the shared reference ends. The main difference is that Rust @@ -41,9 +47,10 @@ //! objects" and "non-atomic objects" (with `atomic_ref` temporarily converting a non-atomic object //! into an atomic object). //! -//! That said, Rust *does* inherit the C++ limitation that non-synchronized atomic accesses may not -//! partially overlap: they must be either disjoint or access the exact same memory. This in -//! particular rules out non-synchronized differently-sized accesses to the same data. +//! That said, Rust *does* inherit the C++ limitation that non-synchronized conflicting atomic +//! accesses may not partially overlap: they must be either disjoint or access the exact same +//! memory. This in particular rules out non-synchronized differently-sized atomic accesses to the +//! same data unless all accesses are reads. //! //! [cpp]: https://en.cppreference.com/w/cpp/atomic //! [cpp-intro.races]: https://timsong-cpp.github.io/cppwp/n4868/intro.multithread#intro.races @@ -63,7 +70,7 @@ //! let atomic = AtomicU16::new(0); //! //! thread::scope(|s| { -//! // This is UB: conflicting concurrent accesses. +//! // This is UB: conflicting non-synchronized accesses, at least one of which is non-atomic. //! s.spawn(|| atomic.store(1, Ordering::Relaxed)); // atomic store //! s.spawn(|| unsafe { atomic.as_ptr().write(2) }); // non-atomic write //! }); @@ -77,16 +84,15 @@ //! }); //! //! thread::scope(|s| { -//! // This is fine, `join` synchronizes the code in a way such that atomic -//! // and non-atomic accesses can't happen "at the same time". +//! // This is fine: `join` synchronizes the code in a way such that the atomic +//! // store happens-before the non-atomic write. //! let handle = s.spawn(|| atomic.store(1, Ordering::Relaxed)); // atomic store //! handle.join().unwrap(); // synchronize //! s.spawn(|| unsafe { atomic.as_ptr().write(2) }); // non-atomic write //! }); //! //! thread::scope(|s| { -//! // This is UB: using differently-sized atomic accesses to the same data. -//! // (It would be UB even if these are both loads.) +//! // This is UB: non-synchronized conflicting differently-sized atomic accesses. //! s.spawn(|| atomic.store(1, Ordering::Relaxed)); //! s.spawn(|| unsafe { //! let differently_sized = transmute::<&AtomicU16, &AtomicU8>(&atomic); @@ -95,8 +101,8 @@ //! }); //! //! thread::scope(|s| { -//! // This is fine, `join` synchronizes the code in a way such that -//! // differently-sized accesses can't happen "at the same time". +//! // This is fine: `join` synchronizes the code in a way such that +//! // the 1-byte store happens-before the 2-byte store. //! let handle = s.spawn(|| atomic.store(1, Ordering::Relaxed)); //! handle.join().unwrap(); //! s.spawn(|| unsafe { diff --git a/src/tools/miri/src/concurrency/data_race.rs b/src/tools/miri/src/concurrency/data_race.rs index 558a032d0bc..812602c3980 100644 --- a/src/tools/miri/src/concurrency/data_race.rs +++ b/src/tools/miri/src/concurrency/data_race.rs @@ -191,7 +191,8 @@ struct AtomicMemoryCellClocks { /// The size of accesses to this atomic location. /// We use this to detect non-synchronized mixed-size accesses. Since all accesses must be /// aligned to their size, this is sufficient to detect imperfectly overlapping accesses. - size: Size, + /// `None` indicates that we saw multiple different sizes, which is okay as long as all accesses are reads. + size: Option, } #[derive(Copy, Clone, PartialEq, Eq, Debug)] @@ -265,6 +266,14 @@ impl AccessType { let mut msg = String::new(); if let Some(size) = size { + if size == Size::ZERO { + // In this case there were multiple read accesss with different sizes and then a write. + // We will be reporting *one* of the other reads, but we don't have enough information + // to determine which one had which size. + assert!(self == AccessType::AtomicLoad); + assert!(ty.is_none()); + return format!("multiple differently-sized atomic loads, including one load"); + } msg.push_str(&format!("{}-byte {}", size.bytes(), msg)) } @@ -305,8 +314,7 @@ impl AccessType { } } -/// Memory Cell vector clock metadata -/// for data-race detection. +/// Per-byte vector clock metadata for data-race detection. #[derive(Clone, PartialEq, Eq, Debug)] struct MemoryCellClocks { /// The vector-clock timestamp and the thread that did the last non-atomic write. We don't need @@ -325,8 +333,8 @@ struct MemoryCellClocks { read: VClock, /// Atomic access, acquire, release sequence tracking clocks. - /// For non-atomic memory in the common case this - /// value is set to None. + /// For non-atomic memory this value is set to None. + /// For atomic memory, each byte carries this information. atomic_ops: Option>, } @@ -336,7 +344,7 @@ impl AtomicMemoryCellClocks { read_vector: Default::default(), write_vector: Default::default(), sync_vector: Default::default(), - size, + size: Some(size), } } } @@ -383,17 +391,23 @@ impl MemoryCellClocks { &mut self, thread_clocks: &ThreadClockSet, size: Size, + write: bool, ) -> Result<&mut AtomicMemoryCellClocks, DataRace> { match self.atomic_ops { Some(ref mut atomic) => { // We are good if the size is the same or all atomic accesses are before our current time. - if atomic.size == size { + if atomic.size == Some(size) { Ok(atomic) } else if atomic.read_vector <= thread_clocks.clock && atomic.write_vector <= thread_clocks.clock { - // This is now the new size that must be used for accesses here. - atomic.size = size; + // We are fully ordered after all previous accesses, so we can change the size. + atomic.size = Some(size); + Ok(atomic) + } else if !write && atomic.write_vector <= thread_clocks.clock { + // This is a read, and it is ordered after the last write. It's okay for the + // sizes to mismatch, as long as no writes with a different size occur later. + atomic.size = None; Ok(atomic) } else { Err(DataRace) @@ -508,7 +522,7 @@ impl MemoryCellClocks { access_size: Size, ) -> Result<(), DataRace> { trace!("Atomic read with vectors: {:#?} :: {:#?}", self, thread_clocks); - let atomic = self.atomic_access(thread_clocks, access_size)?; + let atomic = self.atomic_access(thread_clocks, access_size, /*write*/ false)?; atomic.read_vector.set_at_index(&thread_clocks.clock, index); // Make sure the last non-atomic write was before this access. if self.write_was_before(&thread_clocks.clock) { Ok(()) } else { Err(DataRace) } @@ -523,7 +537,7 @@ impl MemoryCellClocks { access_size: Size, ) -> Result<(), DataRace> { trace!("Atomic write with vectors: {:#?} :: {:#?}", self, thread_clocks); - let atomic = self.atomic_access(thread_clocks, access_size)?; + let atomic = self.atomic_access(thread_clocks, access_size, /*write*/ true)?; atomic.write_vector.set_at_index(&thread_clocks.clock, index); // Make sure the last non-atomic write and all non-atomic reads were before this access. if self.write_was_before(&thread_clocks.clock) && self.read <= thread_clocks.clock { @@ -969,10 +983,10 @@ impl VClockAlloc { } else if let Some(idx) = Self::find_gt_index(&mem_clocks.read, &active_clocks.clock) { (AccessType::NaRead(mem_clocks.read[idx].read_type()), idx, &mem_clocks.read) // Finally, mixed-size races. - } else if access.is_atomic() && let Some(atomic) = mem_clocks.atomic() && atomic.size != access_size { + } else if access.is_atomic() && let Some(atomic) = mem_clocks.atomic() && atomic.size != Some(access_size) { // This is only a race if we are not synchronized with all atomic accesses, so find // the one we are not synchronized with. - other_size = Some(atomic.size); + other_size = Some(atomic.size.unwrap_or(Size::ZERO)); if let Some(idx) = Self::find_gt_index(&atomic.write_vector, &active_clocks.clock) { (AccessType::AtomicStore, idx, &atomic.write_vector) diff --git a/src/tools/miri/tests/fail/data_race/mixed_size_read.rs b/src/tools/miri/tests/fail/data_race/mixed_size_read.rs deleted file mode 100644 index 828b47f0a65..00000000000 --- a/src/tools/miri/tests/fail/data_race/mixed_size_read.rs +++ /dev/null @@ -1,28 +0,0 @@ -//@compile-flags: -Zmiri-preemption-rate=0.0 -Zmiri-disable-weak-memory-emulation -// Avoid accidental synchronization via address reuse inside `thread::spawn`. -//@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0 - -use std::sync::atomic::{AtomicU8, AtomicU16, Ordering}; -use std::thread; - -fn convert(a: &AtomicU16) -> &[AtomicU8; 2] { - unsafe { std::mem::transmute(a) } -} - -// We can't allow mixed-size accesses; they are not possible in C++ and even -// Intel says you shouldn't do it. -fn main() { - let a = AtomicU16::new(0); - let a16 = &a; - let a8 = convert(a16); - - thread::scope(|s| { - s.spawn(|| { - a16.load(Ordering::SeqCst); - }); - s.spawn(|| { - a8[0].load(Ordering::SeqCst); - //~^ ERROR: Race condition detected between (1) 2-byte atomic load on thread `unnamed-1` and (2) 1-byte atomic load on thread `unnamed-2` - }); - }); -} diff --git a/src/tools/miri/tests/fail/data_race/mixed_size_read_read_write.match_first_load.stderr b/src/tools/miri/tests/fail/data_race/mixed_size_read_read_write.match_first_load.stderr new file mode 100644 index 00000000000..b829627c00a --- /dev/null +++ b/src/tools/miri/tests/fail/data_race/mixed_size_read_read_write.match_first_load.stderr @@ -0,0 +1,22 @@ +error: Undefined Behavior: Race condition detected between (1) multiple differently-sized atomic loads, including one load on thread `unnamed-ID` and (2) 2-byte atomic store on thread `unnamed-ID` at ALLOC. (2) just happened here + --> tests/fail/data_race/mixed_size_read_read_write.rs:LL:CC + | +LL | a16.store(0, Ordering::SeqCst); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Race condition detected between (1) multiple differently-sized atomic loads, including one load on thread `unnamed-ID` and (2) 2-byte atomic store on thread `unnamed-ID` at ALLOC. (2) just happened here + | +help: and (1) occurred earlier here + --> tests/fail/data_race/mixed_size_read_read_write.rs:LL:CC + | +LL | a16.load(Ordering::SeqCst); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + = help: overlapping unsynchronized atomic accesses must use the same access size + = help: see https://doc.rust-lang.org/nightly/std/sync/atomic/index.html#memory-model-for-atomic-accesses for more information about the Rust memory model + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: BACKTRACE (of the first span) on thread `unnamed-ID`: + = note: inside closure at tests/fail/data_race/mixed_size_read_read_write.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + diff --git a/src/tools/miri/tests/fail/data_race/mixed_size_read_read_write.match_second_load.stderr b/src/tools/miri/tests/fail/data_race/mixed_size_read_read_write.match_second_load.stderr new file mode 100644 index 00000000000..6bc38b14cb2 --- /dev/null +++ b/src/tools/miri/tests/fail/data_race/mixed_size_read_read_write.match_second_load.stderr @@ -0,0 +1,22 @@ +error: Undefined Behavior: Race condition detected between (1) multiple differently-sized atomic loads, including one load on thread `unnamed-ID` and (2) 1-byte atomic store on thread `unnamed-ID` at ALLOC. (2) just happened here + --> tests/fail/data_race/mixed_size_read_read_write.rs:LL:CC + | +LL | a8[0].store(0, Ordering::SeqCst); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Race condition detected between (1) multiple differently-sized atomic loads, including one load on thread `unnamed-ID` and (2) 1-byte atomic store on thread `unnamed-ID` at ALLOC. (2) just happened here + | +help: and (1) occurred earlier here + --> tests/fail/data_race/mixed_size_read_read_write.rs:LL:CC + | +LL | a16.load(Ordering::SeqCst); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + = help: overlapping unsynchronized atomic accesses must use the same access size + = help: see https://doc.rust-lang.org/nightly/std/sync/atomic/index.html#memory-model-for-atomic-accesses for more information about the Rust memory model + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: BACKTRACE (of the first span) on thread `unnamed-ID`: + = note: inside closure at tests/fail/data_race/mixed_size_read_read_write.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + diff --git a/src/tools/miri/tests/fail/data_race/mixed_size_read_read_write.rs b/src/tools/miri/tests/fail/data_race/mixed_size_read_read_write.rs new file mode 100644 index 00000000000..ece5bd31274 --- /dev/null +++ b/src/tools/miri/tests/fail/data_race/mixed_size_read_read_write.rs @@ -0,0 +1,39 @@ +//@compile-flags: -Zmiri-preemption-rate=0.0 -Zmiri-disable-weak-memory-emulation +// Avoid accidental synchronization via address reuse inside `thread::spawn`. +//@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0 +// Two variants: the atomic store matches the size of the first or second atomic load. +//@revisions: match_first_load match_second_load + +use std::sync::atomic::{AtomicU16, AtomicU8, Ordering}; +use std::thread; + +fn convert(a: &AtomicU16) -> &[AtomicU8; 2] { + unsafe { std::mem::transmute(a) } +} + +// We can't allow mixed-size accesses; they are not possible in C++ and even +// Intel says you shouldn't do it. +fn main() { + let a = AtomicU16::new(0); + let a16 = &a; + let a8 = convert(a16); + + thread::scope(|s| { + s.spawn(|| { + a16.load(Ordering::SeqCst); + }); + s.spawn(|| { + a8[0].load(Ordering::SeqCst); + }); + s.spawn(|| { + thread::yield_now(); // make sure this happens last + if cfg!(match_first_load) { + a16.store(0, Ordering::SeqCst); + //~[match_first_load]^ ERROR: Race condition detected between (1) multiple differently-sized atomic loads, including one load on thread `unnamed-1` and (2) 2-byte atomic store on thread `unnamed-3` + } else { + a8[0].store(0, Ordering::SeqCst); + //~[match_second_load]^ ERROR: Race condition detected between (1) multiple differently-sized atomic loads, including one load on thread `unnamed-1` and (2) 1-byte atomic store on thread `unnamed-3` + } + }); + }); +} diff --git a/src/tools/miri/tests/fail/data_race/mixed_size_read_write.read_write.stderr b/src/tools/miri/tests/fail/data_race/mixed_size_read_write.read_write.stderr new file mode 100644 index 00000000000..6f8dbd38ca8 --- /dev/null +++ b/src/tools/miri/tests/fail/data_race/mixed_size_read_write.read_write.stderr @@ -0,0 +1,22 @@ +error: Undefined Behavior: Race condition detected between (1) 1-byte atomic load on thread `unnamed-ID` and (2) 2-byte atomic store on thread `unnamed-ID` at ALLOC. (2) just happened here + --> tests/fail/data_race/mixed_size_read_write.rs:LL:CC + | +LL | a16.store(1, Ordering::SeqCst); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Race condition detected between (1) 1-byte atomic load on thread `unnamed-ID` and (2) 2-byte atomic store on thread `unnamed-ID` at ALLOC. (2) just happened here + | +help: and (1) occurred earlier here + --> tests/fail/data_race/mixed_size_read_write.rs:LL:CC + | +LL | a8[0].load(Ordering::SeqCst); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = help: overlapping unsynchronized atomic accesses must use the same access size + = help: see https://doc.rust-lang.org/nightly/std/sync/atomic/index.html#memory-model-for-atomic-accesses for more information about the Rust memory model + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: BACKTRACE (of the first span) on thread `unnamed-ID`: + = note: inside closure at tests/fail/data_race/mixed_size_read_write.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + diff --git a/src/tools/miri/tests/fail/data_race/mixed_size_read_write.rs b/src/tools/miri/tests/fail/data_race/mixed_size_read_write.rs new file mode 100644 index 00000000000..acc12427b3f --- /dev/null +++ b/src/tools/miri/tests/fail/data_race/mixed_size_read_write.rs @@ -0,0 +1,39 @@ +//@compile-flags: -Zmiri-preemption-rate=0.0 -Zmiri-disable-weak-memory-emulation +// Avoid accidental synchronization via address reuse inside `thread::spawn`. +//@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0 +// Two revisions, depending on which access goes first. +//@revisions: read_write write_read + +use std::sync::atomic::{AtomicU16, AtomicU8, Ordering}; +use std::thread; + +fn convert(a: &AtomicU16) -> &[AtomicU8; 2] { + unsafe { std::mem::transmute(a) } +} + +// We can't allow mixed-size accesses; they are not possible in C++ and even +// Intel says you shouldn't do it. +fn main() { + let a = AtomicU16::new(0); + let a16 = &a; + let a8 = convert(a16); + + thread::scope(|s| { + s.spawn(|| { + if cfg!(read_write) { + // Let the other one go first. + thread::yield_now(); + } + a16.store(1, Ordering::SeqCst); + //~[read_write]^ ERROR: Race condition detected between (1) 1-byte atomic load on thread `unnamed-2` and (2) 2-byte atomic store on thread `unnamed-1` + }); + s.spawn(|| { + if cfg!(write_read) { + // Let the other one go first. + thread::yield_now(); + } + a8[0].load(Ordering::SeqCst); + //~[write_read]^ ERROR: Race condition detected between (1) 2-byte atomic store on thread `unnamed-1` and (2) 1-byte atomic load on thread `unnamed-2` + }); + }); +} diff --git a/src/tools/miri/tests/fail/data_race/mixed_size_read.stderr b/src/tools/miri/tests/fail/data_race/mixed_size_read_write.write_read.stderr similarity index 66% rename from src/tools/miri/tests/fail/data_race/mixed_size_read.stderr rename to src/tools/miri/tests/fail/data_race/mixed_size_read_write.write_read.stderr index 31a798a89b1..990d2058bca 100644 --- a/src/tools/miri/tests/fail/data_race/mixed_size_read.stderr +++ b/src/tools/miri/tests/fail/data_race/mixed_size_read_write.write_read.stderr @@ -1,20 +1,20 @@ -error: Undefined Behavior: Race condition detected between (1) 2-byte atomic load on thread `unnamed-ID` and (2) 1-byte atomic load on thread `unnamed-ID` at ALLOC. (2) just happened here - --> tests/fail/data_race/mixed_size_read.rs:LL:CC +error: Undefined Behavior: Race condition detected between (1) 2-byte atomic store on thread `unnamed-ID` and (2) 1-byte atomic load on thread `unnamed-ID` at ALLOC. (2) just happened here + --> tests/fail/data_race/mixed_size_read_write.rs:LL:CC | LL | a8[0].load(Ordering::SeqCst); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Race condition detected between (1) 2-byte atomic load on thread `unnamed-ID` and (2) 1-byte atomic load on thread `unnamed-ID` at ALLOC. (2) just happened here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Race condition detected between (1) 2-byte atomic store on thread `unnamed-ID` and (2) 1-byte atomic load on thread `unnamed-ID` at ALLOC. (2) just happened here | help: and (1) occurred earlier here - --> tests/fail/data_race/mixed_size_read.rs:LL:CC + --> tests/fail/data_race/mixed_size_read_write.rs:LL:CC | -LL | a16.load(Ordering::SeqCst); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | a16.store(1, Ordering::SeqCst); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = help: overlapping unsynchronized atomic accesses must use the same access size = help: see https://doc.rust-lang.org/nightly/std/sync/atomic/index.html#memory-model-for-atomic-accesses for more information about the Rust memory model = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE (of the first span) on thread `unnamed-ID`: - = note: inside closure at tests/fail/data_race/mixed_size_read.rs:LL:CC + = note: inside closure at tests/fail/data_race/mixed_size_read_write.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/data_race/mixed_size_write.rs b/src/tools/miri/tests/fail/data_race/mixed_size_write_write.rs similarity index 100% rename from src/tools/miri/tests/fail/data_race/mixed_size_write.rs rename to src/tools/miri/tests/fail/data_race/mixed_size_write_write.rs diff --git a/src/tools/miri/tests/fail/data_race/mixed_size_write.stderr b/src/tools/miri/tests/fail/data_race/mixed_size_write_write.stderr similarity index 90% rename from src/tools/miri/tests/fail/data_race/mixed_size_write.stderr rename to src/tools/miri/tests/fail/data_race/mixed_size_write_write.stderr index c30b48c1f32..1f22413bc5f 100644 --- a/src/tools/miri/tests/fail/data_race/mixed_size_write.stderr +++ b/src/tools/miri/tests/fail/data_race/mixed_size_write_write.stderr @@ -1,11 +1,11 @@ error: Undefined Behavior: Race condition detected between (1) 2-byte atomic store on thread `unnamed-ID` and (2) 1-byte atomic store on thread `unnamed-ID` at ALLOC. (2) just happened here - --> tests/fail/data_race/mixed_size_write.rs:LL:CC + --> tests/fail/data_race/mixed_size_write_write.rs:LL:CC | LL | a8[0].store(1, Ordering::SeqCst); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Race condition detected between (1) 2-byte atomic store on thread `unnamed-ID` and (2) 1-byte atomic store on thread `unnamed-ID` at ALLOC. (2) just happened here | help: and (1) occurred earlier here - --> tests/fail/data_race/mixed_size_write.rs:LL:CC + --> tests/fail/data_race/mixed_size_write_write.rs:LL:CC | LL | a16.store(1, Ordering::SeqCst); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -14,7 +14,7 @@ LL | a16.store(1, Ordering::SeqCst); = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE (of the first span) on thread `unnamed-ID`: - = note: inside closure at tests/fail/data_race/mixed_size_write.rs:LL:CC + = note: inside closure at tests/fail/data_race/mixed_size_write_write.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/weak_memory/racing_mixed_size.rs b/src/tools/miri/tests/fail/weak_memory/racing_mixed_size.rs deleted file mode 100644 index 1193dddc577..00000000000 --- a/src/tools/miri/tests/fail/weak_memory/racing_mixed_size.rs +++ /dev/null @@ -1,41 +0,0 @@ -// We want to control preemption here. -// Avoid accidental synchronization via address reuse. -//@compile-flags: -Zmiri-preemption-rate=0 -Zmiri-address-reuse-cross-thread-rate=0 - -#![feature(core_intrinsics)] - -use std::ptr; -use std::sync::atomic::AtomicU32; -use std::sync::atomic::Ordering::*; -use std::thread::spawn; - -fn static_atomic_u32(val: u32) -> &'static AtomicU32 { - let ret = Box::leak(Box::new(AtomicU32::new(val))); - ret -} - -fn split_u32_ptr(dword: *const u32) -> *const [u16; 2] { - unsafe { std::mem::transmute::<*const u32, *const [u16; 2]>(dword) } -} - -// Wine's SRWLock implementation does this, which is definitely undefined in C++ memory model -// https://github.com/wine-mirror/wine/blob/303f8042f9db508adaca02ef21f8de4992cb9c03/dlls/ntdll/sync.c#L543-L566 -// It probably works just fine on x86, but Intel does document this as "don't do it!" -pub fn main() { - let x = static_atomic_u32(0); - let j1 = spawn(move || { - x.store(1, Relaxed); - }); - - let j2 = spawn(move || { - let x_ptr = x as *const AtomicU32 as *const u32; - let x_split = split_u32_ptr(x_ptr); - unsafe { - let hi = ptr::addr_of!((*x_split)[0]); - std::intrinsics::atomic_load_relaxed(hi); //~ ERROR: (1) 4-byte atomic store on thread `unnamed-1` and (2) 2-byte atomic load - } - }); - - j1.join().unwrap(); - j2.join().unwrap(); -} diff --git a/src/tools/miri/tests/fail/weak_memory/racing_mixed_size_read.rs b/src/tools/miri/tests/fail/weak_memory/racing_mixed_size_read.rs deleted file mode 100644 index 0a0e372f1f3..00000000000 --- a/src/tools/miri/tests/fail/weak_memory/racing_mixed_size_read.rs +++ /dev/null @@ -1,39 +0,0 @@ -// We want to control preemption here. -// Avoid accidental synchronization via address reuse. -//@compile-flags: -Zmiri-preemption-rate=0 -Zmiri-address-reuse-cross-thread-rate=0 - -use std::sync::atomic::Ordering::*; -use std::sync::atomic::{AtomicU16, AtomicU32}; -use std::thread::spawn; - -fn static_atomic(val: u32) -> &'static AtomicU32 { - let ret = Box::leak(Box::new(AtomicU32::new(val))); - ret -} - -fn split_u32_ptr(dword: *const u32) -> *const [u16; 2] { - unsafe { std::mem::transmute::<*const u32, *const [u16; 2]>(dword) } -} - -// Racing mixed size reads may cause two loads to read-from -// the same store but observe different values, which doesn't make -// sense under the formal model so we forbid this. -pub fn main() { - let x = static_atomic(0); - - let j1 = spawn(move || { - x.load(Relaxed); - }); - - let j2 = spawn(move || { - let x_ptr = x as *const AtomicU32 as *const u32; - let x_split = split_u32_ptr(x_ptr); - unsafe { - let hi = x_split as *const u16 as *const AtomicU16; - (*hi).load(Relaxed); //~ ERROR: (1) 4-byte atomic load on thread `unnamed-1` and (2) 2-byte atomic load - } - }); - - j1.join().unwrap(); - j2.join().unwrap(); -} diff --git a/src/tools/miri/tests/fail/weak_memory/racing_mixed_size_read.stderr b/src/tools/miri/tests/fail/weak_memory/racing_mixed_size_read.stderr deleted file mode 100644 index 9e6a6e80418..00000000000 --- a/src/tools/miri/tests/fail/weak_memory/racing_mixed_size_read.stderr +++ /dev/null @@ -1,22 +0,0 @@ -error: Undefined Behavior: Race condition detected between (1) 4-byte atomic load on thread `unnamed-ID` and (2) 2-byte atomic load on thread `unnamed-ID` at ALLOC. (2) just happened here - --> tests/fail/weak_memory/racing_mixed_size_read.rs:LL:CC - | -LL | (*hi).load(Relaxed); - | ^^^^^^^^^^^^^^^^^^^ Race condition detected between (1) 4-byte atomic load on thread `unnamed-ID` and (2) 2-byte atomic load on thread `unnamed-ID` at ALLOC. (2) just happened here - | -help: and (1) occurred earlier here - --> tests/fail/weak_memory/racing_mixed_size_read.rs:LL:CC - | -LL | x.load(Relaxed); - | ^^^^^^^^^^^^^^^ - = help: overlapping unsynchronized atomic accesses must use the same access size - = help: see https://doc.rust-lang.org/nightly/std/sync/atomic/index.html#memory-model-for-atomic-accesses for more information about the Rust memory model - = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior - = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: BACKTRACE (of the first span) on thread `unnamed-ID`: - = note: inside closure at tests/fail/weak_memory/racing_mixed_size_read.rs:LL:CC - -note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace - -error: aborting due to 1 previous error - diff --git a/src/tools/miri/tests/pass/concurrency/data_race.rs b/src/tools/miri/tests/pass/concurrency/data_race.rs index adf5a37891f..0918b94ed31 100644 --- a/src/tools/miri/tests/pass/concurrency/data_race.rs +++ b/src/tools/miri/tests/pass/concurrency/data_race.rs @@ -177,6 +177,26 @@ fn test_read_read_race2() { }); } +fn mixed_size_read_read() { + fn convert(a: &AtomicU16) -> &[AtomicU8; 2] { + unsafe { std::mem::transmute(a) } + } + + let a = AtomicU16::new(0); + let a16 = &a; + let a8 = convert(a16); + + // Just two different-sized atomic reads without any writes are fine. + thread::scope(|s| { + s.spawn(|| { + a16.load(Ordering::SeqCst); + }); + s.spawn(|| { + a8[0].load(Ordering::SeqCst); + }); + }); +} + pub fn main() { test_fence_sync(); test_multiple_reads(); @@ -185,4 +205,5 @@ pub fn main() { test_local_variable_lazy_write(); test_read_read_race1(); test_read_read_race2(); + mixed_size_read_read(); } From 96be76bf53b2a9472f03786ccc3b291196e5a77d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 12 Aug 2024 10:34:05 +0200 Subject: [PATCH 364/683] Further clarificarion for atomic and UnsafeCell docs: - UnsafeCell: mention the term "data race", and reference the data race definition - atomic: failing RMWs are just reads, reorder and reword docs --- library/core/src/cell.rs | 10 +++-- library/core/src/sync/atomic.rs | 37 +++++++++---------- .../miri/tests/pass/concurrency/data_race.rs | 17 +++++++++ 3 files changed, 41 insertions(+), 23 deletions(-) diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs index a3e91bc0670..c99f1aece4f 100644 --- a/library/core/src/cell.rs +++ b/library/core/src/cell.rs @@ -1895,11 +1895,17 @@ impl fmt::Display for RefMut<'_, T> { /// uniqueness guarantee for mutable references is unaffected. There is *no* legal way to obtain /// aliasing `&mut`, not even with `UnsafeCell`. /// +/// `UnsafeCell` does nothing to avoid data races; they are still undefined behavior. If multiple +/// threads have access to the same `UnsafeCell`, they must follow the usual rules of the +/// [concurrent memory model]: conflicting non-synchronized accesses must be done via the APIs in +/// [`core::sync::atomic`]. +/// /// The `UnsafeCell` API itself is technically very simple: [`.get()`] gives you a raw pointer /// `*mut T` to its contents. It is up to _you_ as the abstraction designer to use that raw pointer /// correctly. /// /// [`.get()`]: `UnsafeCell::get` +/// [concurrent memory model]: ../sync/atomic/index.html#memory-model-for-atomic-accesses /// /// The precise Rust aliasing rules are somewhat in flux, but the main points are not contentious: /// @@ -1922,10 +1928,6 @@ impl fmt::Display for RefMut<'_, T> { /// live memory and the compiler is allowed to insert spurious reads if it can prove that this /// memory has not yet been deallocated. /// -/// - At all times, you must avoid data races. If multiple threads have access to -/// the same `UnsafeCell`, then any writes must have a proper happens-before relation to all other -/// accesses (or use atomics). -/// /// To assist with proper design, the following scenarios are explicitly declared legal /// for single-threaded code: /// diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs index 2357fb932b4..be85f507129 100644 --- a/library/core/src/sync/atomic.rs +++ b/library/core/src/sync/atomic.rs @@ -33,12 +33,6 @@ //! atomic load (via the operations provided in this module). A "modification of an atomic object" //! refers to an atomic store. //! -//! The most important aspect of this model is that conflicting non-synchronized accesses are -//! Undefined Behavior unless both accesses are atomic. Here, accesses are *conflicting* if they -//! affect overlapping regions of memory and at least one of them is a write. They are -//! *non-synchronized* if neither of them *happens-before* the other, according to the -//! happens-before order of the memory model. -//! //! The end result is *almost* equivalent to saying that creating a *shared reference* to one of the //! Rust atomic types corresponds to creating an `atomic_ref` in C++, with the `atomic_ref` being //! destroyed when the lifetime of the shared reference ends. The main difference is that Rust @@ -47,20 +41,25 @@ //! objects" and "non-atomic objects" (with `atomic_ref` temporarily converting a non-atomic object //! into an atomic object). //! -//! That said, Rust *does* inherit the C++ limitation that non-synchronized conflicting atomic -//! accesses may not partially overlap: they must be either disjoint or access the exact same -//! memory. This in particular rules out non-synchronized differently-sized atomic accesses to the -//! same data unless all accesses are reads. +//! The most important aspect of this model is that *data races* are undefined behavior. A data race +//! is defined as conflicting non-synchronized accesses where at least one of the accesses is +//! non-atomic. Here, accesses are *conflicting* if they affect overlapping regions of memory and at +//! least one of them is a write. They are *non-synchronized* if neither of them *happens-before* +//! the other, according to the happens-before order of the memory model. +//! +//! The other possible cause of undefined behavior in the memory model are mixed-size accesses: Rust +//! inherits the C++ limitation that non-synchronized conflicting atomic accesses may not partially +//! overlap. In other words, every pair of non-synchronized atomic accesses must be either disjoint, +//! access the exact same memory (including using the same access size), or both be reads. +//! +//! Each atomic access takes an [`Ordering`] which defines how the operation interacts with the +//! happens-before order. These orderings behave the same as the corresponding [C++20 atomic +//! orderings][cpp_memory_order]. For more information, see the [nomicon]. //! //! [cpp]: https://en.cppreference.com/w/cpp/atomic //! [cpp-intro.races]: https://timsong-cpp.github.io/cppwp/n4868/intro.multithread#intro.races -//! -//! Each method takes an [`Ordering`] which represents the strength of -//! the memory barrier for that operation. These orderings behave the -//! same as the corresponding [C++20 atomic orderings][1]. For more information see the [nomicon][2]. -//! -//! [1]: https://en.cppreference.com/w/cpp/atomic/memory_order -//! [2]: ../../../nomicon/atomics.html +//! [cpp_memory_order]: https://en.cppreference.com/w/cpp/atomic/memory_order +//! [nomicon]: ../../../nomicon/atomics.html //! //! ```rust,no_run undefined_behavior //! use std::sync::atomic::{AtomicU16, AtomicU8, Ordering}; @@ -157,7 +156,7 @@ //! //! # Atomic accesses to read-only memory //! -//! In general, *all* atomic accesses on read-only memory are Undefined Behavior. For instance, attempting +//! In general, *all* atomic accesses on read-only memory are undefined behavior. For instance, attempting //! to do a `compare_exchange` that will definitely fail (making it conceptually a read-only //! operation) can still cause a segmentation fault if the underlying memory page is mapped read-only. Since //! atomic `load`s might be implemented using compare-exchange operations, even a `load` can fault @@ -173,7 +172,7 @@ //! //! As an exception from the general rule stated above, "sufficiently small" atomic loads with //! `Ordering::Relaxed` are implemented in a way that works on read-only memory, and are hence not -//! Undefined Behavior. The exact size limit for what makes a load "sufficiently small" varies +//! undefined behavior. The exact size limit for what makes a load "sufficiently small" varies //! depending on the target: //! //! | `target_arch` | Size limit | diff --git a/src/tools/miri/tests/pass/concurrency/data_race.rs b/src/tools/miri/tests/pass/concurrency/data_race.rs index 0918b94ed31..d16de0ae8e2 100644 --- a/src/tools/miri/tests/pass/concurrency/data_race.rs +++ b/src/tools/miri/tests/pass/concurrency/data_race.rs @@ -197,6 +197,22 @@ fn mixed_size_read_read() { }); } +fn failing_rmw_is_read() { + let a = AtomicUsize::new(0); + thread::scope(|s| { + s.spawn(|| unsafe { + // Non-atomic read. + let _val = *(&a as *const AtomicUsize).cast::(); + }); + + s.spawn(|| { + // RMW that will fail. + // This is not considered a write, so there is no data race here. + a.compare_exchange(1, 2, Ordering::SeqCst, Ordering::SeqCst).unwrap_err(); + }); + }); +} + pub fn main() { test_fence_sync(); test_multiple_reads(); @@ -206,4 +222,5 @@ pub fn main() { test_read_read_race1(); test_read_read_race2(); mixed_size_read_read(); + failing_rmw_is_read(); } From 84c944c6fffea5dd84e770f3a6adf80cc4554a76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Sat, 28 Sep 2024 12:45:13 +0200 Subject: [PATCH 365/683] compiletest: rename "runtest/crash.rs" to "runtest/crashes.rs" to be in line with the test directory r? jieyouxu --- src/tools/compiletest/src/runtest.rs | 2 +- src/tools/compiletest/src/runtest/{crash.rs => crashes.rs} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename src/tools/compiletest/src/runtest/{crash.rs => crashes.rs} (100%) diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 25a135aa320..c2e74dffdca 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -39,7 +39,7 @@ mod assembly; mod codegen; mod codegen_units; mod coverage; -mod crash; +mod crashes; mod debuginfo; mod incremental; mod js_doc; diff --git a/src/tools/compiletest/src/runtest/crash.rs b/src/tools/compiletest/src/runtest/crashes.rs similarity index 100% rename from src/tools/compiletest/src/runtest/crash.rs rename to src/tools/compiletest/src/runtest/crashes.rs From e174b92cb45138dcea93727e64f2255ae39cd5bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Sat, 28 Sep 2024 13:42:37 +0200 Subject: [PATCH 366/683] remove couple redundant clones --- compiler/rustc_builtin_macros/src/deriving/smart_ptr.rs | 2 +- compiler/rustc_pattern_analysis/src/rustc.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_builtin_macros/src/deriving/smart_ptr.rs b/compiler/rustc_builtin_macros/src/deriving/smart_ptr.rs index 12749e87dcb..78028df2aa0 100644 --- a/compiler/rustc_builtin_macros/src/deriving/smart_ptr.rs +++ b/compiler/rustc_builtin_macros/src/deriving/smart_ptr.rs @@ -310,7 +310,7 @@ pub(crate) fn expand_deriving_smart_ptr( // Add the impl blocks for `DispatchFromDyn` and `CoerceUnsized`. let gen_args = vec![GenericArg::Type(alt_self_type.clone())]; add_impl_block(impl_generics.clone(), sym::DispatchFromDyn, gen_args.clone()); - add_impl_block(impl_generics.clone(), sym::CoerceUnsized, gen_args.clone()); + add_impl_block(impl_generics.clone(), sym::CoerceUnsized, gen_args); } fn contains_maybe_sized_bound_on_pointee(predicates: &[WherePredicate], pointee: Symbol) -> bool { diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs index 72737fb98cb..70a9319d666 100644 --- a/compiler/rustc_pattern_analysis/src/rustc.rs +++ b/compiler/rustc_pattern_analysis/src/rustc.rs @@ -1027,7 +1027,7 @@ impl<'p, 'tcx: 'p> PatCx for RustcPatCtxt<'p, 'tcx> { // Point at this range. first_range: thir_pat.span, // That's the gap that isn't covered. - max: gap_as_pat.to_string(), + max: gap_as_pat, // Suggest `lo..=max` instead. suggestion: suggested_range, }, From c1401daf3ff4c70bda523b5d2c46ffe09732d5cc Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 28 Sep 2024 13:41:58 +0200 Subject: [PATCH 367/683] add tests for validity of Box with custom allocator --- .../validity/box-custom-alloc-dangling-ptr.rs | 32 ++++++++++++++++ .../box-custom-alloc-dangling-ptr.stderr | 15 ++++++++ .../box-custom-alloc-invalid-alloc.rs | 37 +++++++++++++++++++ .../box-custom-alloc-invalid-alloc.stderr | 15 ++++++++ 4 files changed, 99 insertions(+) create mode 100644 src/tools/miri/tests/fail/validity/box-custom-alloc-dangling-ptr.rs create mode 100644 src/tools/miri/tests/fail/validity/box-custom-alloc-dangling-ptr.stderr create mode 100644 src/tools/miri/tests/fail/validity/box-custom-alloc-invalid-alloc.rs create mode 100644 src/tools/miri/tests/fail/validity/box-custom-alloc-invalid-alloc.stderr diff --git a/src/tools/miri/tests/fail/validity/box-custom-alloc-dangling-ptr.rs b/src/tools/miri/tests/fail/validity/box-custom-alloc-dangling-ptr.rs new file mode 100644 index 00000000000..5fb81296494 --- /dev/null +++ b/src/tools/miri/tests/fail/validity/box-custom-alloc-dangling-ptr.rs @@ -0,0 +1,32 @@ +//! Ensure that a box with a custom allocator detects when the pointer is dangling. +#![feature(allocator_api)] +// This should not need the aliasing model. +//@compile-flags: -Zmiri-disable-stacked-borrows +use std::alloc::Layout; +use std::ptr::NonNull; + +#[allow(unused)] +struct MyAlloc(usize, usize); // make sure `Box` is an `Aggregate` + +unsafe impl std::alloc::Allocator for MyAlloc { + fn allocate(&self, _layout: Layout) -> Result, std::alloc::AllocError> { + unimplemented!() + } + + unsafe fn deallocate(&self, _ptr: NonNull, _layout: Layout) { + unimplemented!() + } +} + +#[repr(C)] +struct MyBox { + ptr: NonNull, + alloc: MyAlloc, +} + +fn main() { + let b = MyBox { ptr: NonNull::::dangling(), alloc: MyAlloc(0, 0) }; + let _b: Box = unsafe { + std::mem::transmute(b) //~ERROR: dangling box + }; +} diff --git a/src/tools/miri/tests/fail/validity/box-custom-alloc-dangling-ptr.stderr b/src/tools/miri/tests/fail/validity/box-custom-alloc-dangling-ptr.stderr new file mode 100644 index 00000000000..76d7e66cfc5 --- /dev/null +++ b/src/tools/miri/tests/fail/validity/box-custom-alloc-dangling-ptr.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: constructing invalid value: encountered a dangling box (0x4[noalloc] has no provenance) + --> tests/fail/validity/box-custom-alloc-dangling-ptr.rs:LL:CC + | +LL | std::mem::transmute(b) + | ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling box (0x4[noalloc] has no provenance) + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: BACKTRACE: + = note: inside `main` at tests/fail/validity/box-custom-alloc-dangling-ptr.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + diff --git a/src/tools/miri/tests/fail/validity/box-custom-alloc-invalid-alloc.rs b/src/tools/miri/tests/fail/validity/box-custom-alloc-invalid-alloc.rs new file mode 100644 index 00000000000..101a550593f --- /dev/null +++ b/src/tools/miri/tests/fail/validity/box-custom-alloc-invalid-alloc.rs @@ -0,0 +1,37 @@ +//! Ensure that a box with a custom allocator detects when the allocator itself is invalid. +#![feature(allocator_api)] +// This should not need the aliasing model. +//@compile-flags: -Zmiri-disable-stacked-borrows +use std::alloc::Layout; +use std::mem::MaybeUninit; +use std::ptr::NonNull; + +// make sure `Box` is an `Aggregate` +#[allow(unused)] +struct MyAlloc { + my_alloc_field1: usize, + my_alloc_field2: usize, +} + +unsafe impl std::alloc::Allocator for MyAlloc { + fn allocate(&self, _layout: Layout) -> Result, std::alloc::AllocError> { + unimplemented!() + } + + unsafe fn deallocate(&self, _ptr: NonNull, _layout: Layout) { + unimplemented!() + } +} + +#[repr(C)] +struct MyBox { + ptr: NonNull, + alloc: MaybeUninit, +} + +fn main() { + let b = MyBox { ptr: NonNull::from(&42), alloc: MaybeUninit::uninit() }; + let _b: Box = unsafe { + std::mem::transmute(b) //~ERROR: uninitialized memory + }; +} diff --git a/src/tools/miri/tests/fail/validity/box-custom-alloc-invalid-alloc.stderr b/src/tools/miri/tests/fail/validity/box-custom-alloc-invalid-alloc.stderr new file mode 100644 index 00000000000..e151f80dde3 --- /dev/null +++ b/src/tools/miri/tests/fail/validity/box-custom-alloc-invalid-alloc.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: constructing invalid value at .1.my_alloc_field1: encountered uninitialized memory, but expected an integer + --> tests/fail/validity/box-custom-alloc-invalid-alloc.rs:LL:CC + | +LL | std::mem::transmute(b) + | ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .1.my_alloc_field1: encountered uninitialized memory, but expected an integer + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: BACKTRACE: + = note: inside `main` at tests/fail/validity/box-custom-alloc-invalid-alloc.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + From fd36e8b0ec314afa794d61512b5bdfc6146a7027 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 24 Sep 2024 18:53:33 +0200 Subject: [PATCH 368/683] Update compiler_builtins to 0.1.130 This includes the following which add `__divtf3` and `__powtf2`, and do some feature cleanup: - https://github.com/rust-lang/compiler-builtins/pull/622 - https://github.com/rust-lang/compiler-builtins/pull/692 - https://github.com/rust-lang/compiler-builtins/pull/614 - https://github.com/rust-lang/compiler-builtins/pull/694 The `cc` bump [1] was previously included but was reverted due to problems updating. [1]: https://github.com/rust-lang/compiler-builtins/pull/690 --- library/Cargo.lock | 4 ++-- library/alloc/Cargo.toml | 2 +- library/std/Cargo.toml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/library/Cargo.lock b/library/Cargo.lock index e883749730c..877ae0cc1cc 100644 --- a/library/Cargo.lock +++ b/library/Cargo.lock @@ -61,9 +61,9 @@ dependencies = [ [[package]] name = "compiler_builtins" -version = "0.1.126" +version = "0.1.130" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "758019257ad46e191b587d8f711022a6ac1d1fb6745d75e1d76c587fdcbca770" +checksum = "e64c30475571756801eff60a811520c3d18e0ceb9c56c97bad2047ae601f6709" dependencies = [ "cc", "rustc-std-workspace-core", diff --git a/library/alloc/Cargo.toml b/library/alloc/Cargo.toml index 1b76b4c4a50..11db50a0fdf 100644 --- a/library/alloc/Cargo.toml +++ b/library/alloc/Cargo.toml @@ -10,7 +10,7 @@ edition = "2021" [dependencies] core = { path = "../core" } -compiler_builtins = { version = "0.1.126", features = ['rustc-dep-of-std'] } +compiler_builtins = { version = "0.1.130", features = ['rustc-dep-of-std'] } [dev-dependencies] rand = { version = "0.8.5", default-features = false, features = ["alloc"] } diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index d55114227af..7d860b49e87 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -17,7 +17,7 @@ cfg-if = { version = "1.0", features = ['rustc-dep-of-std'] } panic_unwind = { path = "../panic_unwind", optional = true } panic_abort = { path = "../panic_abort" } core = { path = "../core", public = true } -compiler_builtins = { version = "0.1.126" } +compiler_builtins = { version = "0.1.130" } profiler_builtins = { path = "../profiler_builtins", optional = true } unwind = { path = "../unwind" } hashbrown = { version = "0.14", default-features = false, features = [ From 73a16c10dba19efbd5b3363be5f1d37a60d6436c Mon Sep 17 00:00:00 2001 From: Yuri Astrakhan Date: Tue, 3 Sep 2024 00:21:02 -0400 Subject: [PATCH 369/683] Suggest `Option<&T>` instead of `&Option` --- CHANGELOG.md | 1 + book/src/lint_configuration.md | 1 + clippy_config/src/conf.rs | 1 + clippy_lints/src/declared_lints.rs | 1 + clippy_lints/src/functions/mod.rs | 57 ++++++ clippy_lints/src/functions/ref_option.rs | 122 +++++++++++++ tests/ui/ref_option/all/clippy.toml | 1 + tests/ui/ref_option/private/clippy.toml | 1 + tests/ui/ref_option/ref_option.all.fixed | 62 +++++++ tests/ui/ref_option/ref_option.all.stderr | 162 ++++++++++++++++++ tests/ui/ref_option/ref_option.private.fixed | 62 +++++++ tests/ui/ref_option/ref_option.private.stderr | 108 ++++++++++++ tests/ui/ref_option/ref_option.rs | 62 +++++++ .../ref_option/ref_option_traits.all.stderr | 37 ++++ .../ref_option_traits.private.stderr | 21 +++ tests/ui/ref_option/ref_option_traits.rs | 37 ++++ 16 files changed, 736 insertions(+) create mode 100644 clippy_lints/src/functions/ref_option.rs create mode 100644 tests/ui/ref_option/all/clippy.toml create mode 100644 tests/ui/ref_option/private/clippy.toml create mode 100644 tests/ui/ref_option/ref_option.all.fixed create mode 100644 tests/ui/ref_option/ref_option.all.stderr create mode 100644 tests/ui/ref_option/ref_option.private.fixed create mode 100644 tests/ui/ref_option/ref_option.private.stderr create mode 100644 tests/ui/ref_option/ref_option.rs create mode 100644 tests/ui/ref_option/ref_option_traits.all.stderr create mode 100644 tests/ui/ref_option/ref_option_traits.private.stderr create mode 100644 tests/ui/ref_option/ref_option_traits.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index 41a86e8ce51..5d253d52531 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5871,6 +5871,7 @@ Released 2018-09-13 [`ref_as_ptr`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_as_ptr [`ref_binding_to_reference`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_binding_to_reference [`ref_in_deref`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_in_deref +[`ref_option`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_option [`ref_option_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_option_ref [`ref_patterns`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_patterns [`regex_macro`]: https://rust-lang.github.io/rust-clippy/master/index.html#regex_macro diff --git a/book/src/lint_configuration.md b/book/src/lint_configuration.md index 91159bc79c5..07a56fb33df 100644 --- a/book/src/lint_configuration.md +++ b/book/src/lint_configuration.md @@ -353,6 +353,7 @@ Suppress lints whenever the suggested change would cause breakage for other crat * [`rc_buffer`](https://rust-lang.github.io/rust-clippy/master/index.html#rc_buffer) * [`rc_mutex`](https://rust-lang.github.io/rust-clippy/master/index.html#rc_mutex) * [`redundant_allocation`](https://rust-lang.github.io/rust-clippy/master/index.html#redundant_allocation) +* [`ref_option`](https://rust-lang.github.io/rust-clippy/master/index.html#ref_option) * [`single_call_fn`](https://rust-lang.github.io/rust-clippy/master/index.html#single_call_fn) * [`trivially_copy_pass_by_ref`](https://rust-lang.github.io/rust-clippy/master/index.html#trivially_copy_pass_by_ref) * [`unnecessary_box_returns`](https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_box_returns) diff --git a/clippy_config/src/conf.rs b/clippy_config/src/conf.rs index 757620341cc..e4e2c97fdc1 100644 --- a/clippy_config/src/conf.rs +++ b/clippy_config/src/conf.rs @@ -378,6 +378,7 @@ define_Conf! { rc_buffer, rc_mutex, redundant_allocation, + ref_option, single_call_fn, trivially_copy_pass_by_ref, unnecessary_box_returns, diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index 2b229d2fe6a..9cec672beb0 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -202,6 +202,7 @@ pub static LINTS: &[&crate::LintInfo] = &[ crate::functions::MUST_USE_CANDIDATE_INFO, crate::functions::MUST_USE_UNIT_INFO, crate::functions::NOT_UNSAFE_PTR_ARG_DEREF_INFO, + crate::functions::REF_OPTION_INFO, crate::functions::RENAMED_FUNCTION_PARAMS_INFO, crate::functions::RESULT_LARGE_ERR_INFO, crate::functions::RESULT_UNIT_ERR_INFO, diff --git a/clippy_lints/src/functions/mod.rs b/clippy_lints/src/functions/mod.rs index ba8a459c917..cfa63d3befc 100644 --- a/clippy_lints/src/functions/mod.rs +++ b/clippy_lints/src/functions/mod.rs @@ -2,6 +2,7 @@ mod impl_trait_in_params; mod misnamed_getters; mod must_use; mod not_unsafe_ptr_arg_deref; +mod ref_option; mod renamed_function_params; mod result; mod too_many_arguments; @@ -399,6 +400,50 @@ declare_clippy_lint! { "renamed function parameters in trait implementation" } +declare_clippy_lint! { + /// ### What it does + /// Warns when a function signature uses `&Option` instead of `Option<&T>`. + /// + /// ### Why is this bad? + /// More flexibility, better memory optimization, and more idiomatic Rust code. + /// + /// `&Option` in a function signature breaks encapsulation because the caller must own T + /// and move it into an Option to call with it. When returned, the owner must internally store + /// it as `Option` in order to return it. + /// At a lower level `&Option` points to memory that has `presence` bit flag + value, + /// whereas `Option<&T>` is always optimized to a single pointer. + /// + /// See this [YouTube video](https://www.youtube.com/watch?v=6c7pZYP_iIE) by + /// Logan Smith for an in-depth explanation of why this is important. + /// + /// ### Known problems + /// This lint recommends changing the function signatures, but it cannot + /// automatically change the function calls or the function implementations. + /// + /// ### Example + /// ```no_run + /// // caller uses foo(&opt) + /// fn foo(a: &Option) {} + /// # struct Unit {} + /// # impl Unit { + /// fn bar(&self) -> &Option { &None } + /// # } + /// ``` + /// Use instead: + /// ```no_run + /// // caller should use foo(opt.as_ref()) + /// fn foo(a: Option<&String>) {} + /// # struct Unit {} + /// # impl Unit { + /// fn bar(&self) -> Option<&String> { None } + /// # } + /// ``` + #[clippy::version = "1.82.0"] + pub REF_OPTION, + nursery, + "function signature uses `&Option` instead of `Option<&T>`" +} + pub struct Functions { too_many_arguments_threshold: u64, too_many_lines_threshold: u64, @@ -437,6 +482,7 @@ impl_lint_pass!(Functions => [ MISNAMED_GETTERS, IMPL_TRAIT_IN_PARAMS, RENAMED_FUNCTION_PARAMS, + REF_OPTION, ]); impl<'tcx> LateLintPass<'tcx> for Functions { @@ -455,6 +501,16 @@ impl<'tcx> LateLintPass<'tcx> for Functions { not_unsafe_ptr_arg_deref::check_fn(cx, kind, decl, body, def_id); misnamed_getters::check_fn(cx, kind, decl, body, span); impl_trait_in_params::check_fn(cx, &kind, body, hir_id); + ref_option::check_fn( + cx, + kind, + decl, + span, + hir_id, + def_id, + body, + self.avoid_breaking_exported_api, + ); } fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) { @@ -475,5 +531,6 @@ impl<'tcx> LateLintPass<'tcx> for Functions { must_use::check_trait_item(cx, item); result::check_trait_item(cx, item, self.large_error_threshold); 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); } } diff --git a/clippy_lints/src/functions/ref_option.rs b/clippy_lints/src/functions/ref_option.rs new file mode 100644 index 00000000000..373ecd74cb3 --- /dev/null +++ b/clippy_lints/src/functions/ref_option.rs @@ -0,0 +1,122 @@ +use crate::functions::REF_OPTION; +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::is_trait_impl_item; +use clippy_utils::source::snippet; +use clippy_utils::ty::is_type_diagnostic_item; +use rustc_errors::Applicability; +use rustc_hir as hir; +use rustc_hir::intravisit::FnKind; +use rustc_hir::{FnDecl, HirId}; +use rustc_lint::LateContext; +use rustc_middle::ty::{self, GenericArgKind, Mutability, Ty}; +use rustc_span::def_id::LocalDefId; +use rustc_span::{Span, sym}; + +fn check_ty<'a>(cx: &LateContext<'a>, param: &rustc_hir::Ty<'a>, param_ty: Ty<'a>, fixes: &mut Vec<(Span, String)>) { + if let ty::Ref(_, opt_ty, Mutability::Not) = param_ty.kind() + && is_type_diagnostic_item(cx, *opt_ty, sym::Option) + && let ty::Adt(_, opt_gen) = opt_ty.kind() + && let [gen] = opt_gen.as_slice() + && let GenericArgKind::Type(gen_ty) = gen.unpack() + && !gen_ty.is_ref() + // Need to gen the original spans, so first parsing mid, and hir parsing afterward + && let hir::TyKind::Ref(lifetime, hir::MutTy { ty, .. }) = param.kind + && let hir::TyKind::Path(hir::QPath::Resolved(_, path)) = ty.kind + && let (Some(first), Some(last)) = (path.segments.first(), path.segments.last()) + && let Some(hir::GenericArgs { + args: [hir::GenericArg::Type(opt_ty)], + .. + }) = last.args + { + let lifetime = snippet(cx, lifetime.ident.span, ".."); + fixes.push(( + param.span, + format!( + "{}<&{lifetime}{}{}>", + snippet(cx, first.ident.span.to(last.ident.span), ".."), + if lifetime.is_empty() { "" } else { " " }, + snippet(cx, opt_ty.span, "..") + ), + )); + } +} + +fn check_fn_sig<'a>(cx: &LateContext<'a>, decl: &FnDecl<'a>, span: Span, sig: ty::FnSig<'a>) { + let mut fixes = Vec::new(); + // Check function arguments' types + for (param, param_ty) in decl.inputs.iter().zip(sig.inputs()) { + check_ty(cx, param, *param_ty, &mut fixes); + } + // Check return type + if let hir::FnRetTy::Return(ty) = &decl.output { + check_ty(cx, ty, sig.output(), &mut fixes); + } + if !fixes.is_empty() { + span_lint_and_then( + cx, + REF_OPTION, + span, + "it is more idiomatic to use `Option<&T>` instead of `&Option`", + |diag| { + diag.multipart_suggestion("change this to", fixes, Applicability::Unspecified); + }, + ); + } +} + +#[allow(clippy::too_many_arguments)] +pub(crate) fn check_fn<'a>( + cx: &LateContext<'a>, + kind: FnKind<'_>, + decl: &FnDecl<'a>, + span: Span, + hir_id: HirId, + def_id: LocalDefId, + body: &hir::Body<'_>, + avoid_breaking_exported_api: bool, +) { + if avoid_breaking_exported_api && cx.effective_visibilities.is_exported(def_id) { + return; + } + + if let FnKind::Closure = kind { + // Compute the span of the closure parameters + return type if set + let span = if let hir::FnRetTy::Return(out_ty) = &decl.output { + if decl.inputs.is_empty() { + out_ty.span + } else { + span.with_hi(out_ty.span.hi()) + } + } else if let (Some(first), Some(last)) = (decl.inputs.first(), decl.inputs.last()) { + first.span.to(last.span) + } else { + // No parameters - no point in checking + return; + }; + + // Figure out the signature of the closure + let ty::Closure(_, args) = cx.typeck_results().expr_ty(body.value).kind() else { + return; + }; + let sig = args.as_closure().sig().skip_binder(); + + check_fn_sig(cx, decl, span, sig); + } else if !is_trait_impl_item(cx, hir_id) { + let sig = cx.tcx.fn_sig(def_id).instantiate_identity().skip_binder(); + check_fn_sig(cx, decl, span, sig); + } +} + +pub(super) fn check_trait_item<'a>( + cx: &LateContext<'a>, + trait_item: &hir::TraitItem<'a>, + avoid_breaking_exported_api: bool, +) { + if let hir::TraitItemKind::Fn(ref sig, _) = trait_item.kind + && !(avoid_breaking_exported_api && cx.effective_visibilities.is_exported(trait_item.owner_id.def_id)) + { + let def_id = trait_item.owner_id.def_id; + let ty_sig = cx.tcx.fn_sig(def_id).instantiate_identity().skip_binder(); + check_fn_sig(cx, sig.decl, sig.span, ty_sig); + } +} diff --git a/tests/ui/ref_option/all/clippy.toml b/tests/ui/ref_option/all/clippy.toml new file mode 100644 index 00000000000..cda8d17eed4 --- /dev/null +++ b/tests/ui/ref_option/all/clippy.toml @@ -0,0 +1 @@ +avoid-breaking-exported-api = false diff --git a/tests/ui/ref_option/private/clippy.toml b/tests/ui/ref_option/private/clippy.toml new file mode 100644 index 00000000000..5f304987aa9 --- /dev/null +++ b/tests/ui/ref_option/private/clippy.toml @@ -0,0 +1 @@ +avoid-breaking-exported-api = true diff --git a/tests/ui/ref_option/ref_option.all.fixed b/tests/ui/ref_option/ref_option.all.fixed new file mode 100644 index 00000000000..47781a97c98 --- /dev/null +++ b/tests/ui/ref_option/ref_option.all.fixed @@ -0,0 +1,62 @@ +//@revisions: private all +//@[private] rustc-env:CLIPPY_CONF_DIR=tests/ui/ref_option/private +//@[all] rustc-env:CLIPPY_CONF_DIR=tests/ui/ref_option/all + +#![allow(unused, clippy::needless_lifetimes, clippy::borrowed_box)] +#![warn(clippy::ref_option)] + +fn opt_u8(a: Option<&u8>) {} +fn opt_gen(a: Option<&T>) {} +fn opt_string(a: std::option::Option<&String>) {} +fn ret_string<'a>(p: &'a str) -> Option<&'a u8> { + panic!() +} +fn ret_string_static() -> Option<&'static u8> { + panic!() +} +fn mult_string(a: Option<&String>, b: Option<&Vec>) {} +fn ret_box<'a>() -> Option<&'a Box> { + panic!() +} + +pub fn pub_opt_string(a: Option<&String>) {} +pub fn pub_mult_string(a: Option<&String>, b: Option<&Vec>) {} + +pub trait PubTrait { + fn pub_trait_opt(&self, a: Option<&Vec>); + fn pub_trait_ret(&self) -> Option<&Vec>; +} + +trait PrivateTrait { + fn trait_opt(&self, a: Option<&String>); + fn trait_ret(&self) -> Option<&String>; +} + +pub struct PubStruct; + +impl PubStruct { + pub fn pub_opt_params(&self, a: Option<&()>) {} + pub fn pub_opt_ret(&self) -> Option<&String> { + panic!() + } + + fn private_opt_params(&self, a: Option<&()>) {} + fn private_opt_ret(&self) -> Option<&String> { + panic!() + } +} + +// valid, don't change +fn mut_u8(a: &mut Option) {} +pub fn pub_mut_u8(a: &mut Option) {} + +// might be good to catch in the future +fn mut_u8_ref(a: &mut &Option) {} +pub fn pub_mut_u8_ref(a: &mut &Option) {} +fn lambdas() { + // Not handled for now, not sure if we should + let x = |a: &Option| {}; + let x = |a: &Option| -> &Option { panic!() }; +} + +fn main() {} diff --git a/tests/ui/ref_option/ref_option.all.stderr b/tests/ui/ref_option/ref_option.all.stderr new file mode 100644 index 00000000000..b4c69ac6296 --- /dev/null +++ b/tests/ui/ref_option/ref_option.all.stderr @@ -0,0 +1,162 @@ +error: it is more idiomatic to use `Option<&T>` instead of `&Option` + --> tests/ui/ref_option/ref_option.rs:8:1 + | +LL | fn opt_u8(a: &Option) {} + | ^^^^^^^^^^^^^-----------^^^^ + | | + | help: change this to: `Option<&u8>` + | + = note: `-D clippy::ref-option` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::ref_option)]` + +error: it is more idiomatic to use `Option<&T>` instead of `&Option` + --> tests/ui/ref_option/ref_option.rs:9:1 + | +LL | fn opt_gen(a: &Option) {} + | ^^^^^^^^^^^^^^^^^----------^^^^ + | | + | help: change this to: `Option<&T>` + +error: it is more idiomatic to use `Option<&T>` instead of `&Option` + --> tests/ui/ref_option/ref_option.rs:10:1 + | +LL | fn opt_string(a: &std::option::Option) {} + | ^^^^^^^^^^^^^^^^^----------------------------^^^^ + | | + | help: change this to: `std::option::Option<&String>` + +error: it is more idiomatic to use `Option<&T>` instead of `&Option` + --> tests/ui/ref_option/ref_option.rs:11:1 + | +LL | fn ret_string<'a>(p: &'a str) -> &'a Option { + | ^ -------------- help: change this to: `Option<&'a u8>` + | _| + | | +LL | | panic!() +LL | | } + | |_^ + +error: it is more idiomatic to use `Option<&T>` instead of `&Option` + --> tests/ui/ref_option/ref_option.rs:14:1 + | +LL | fn ret_string_static() -> &'static Option { + | ^ ------------------- help: change this to: `Option<&'static u8>` + | _| + | | +LL | | panic!() +LL | | } + | |_^ + +error: it is more idiomatic to use `Option<&T>` instead of `&Option` + --> tests/ui/ref_option/ref_option.rs:17:1 + | +LL | fn mult_string(a: &Option, b: &Option>) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: change this to + | +LL | fn mult_string(a: Option<&String>, b: Option<&Vec>) {} + | ~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~ + +error: it is more idiomatic to use `Option<&T>` instead of `&Option` + --> tests/ui/ref_option/ref_option.rs:18:1 + | +LL | fn ret_box<'a>() -> &'a Option> { + | ^ ------------------- help: change this to: `Option<&'a Box>` + | _| + | | +LL | | panic!() +LL | | } + | |_^ + +error: it is more idiomatic to use `Option<&T>` instead of `&Option` + --> tests/ui/ref_option/ref_option.rs:22:1 + | +LL | pub fn pub_opt_string(a: &Option) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^---------------^^^^ + | | + | help: change this to: `Option<&String>` + +error: it is more idiomatic to use `Option<&T>` instead of `&Option` + --> tests/ui/ref_option/ref_option.rs:23:1 + | +LL | pub fn pub_mult_string(a: &Option, b: &Option>) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: change this to + | +LL | pub fn pub_mult_string(a: Option<&String>, b: Option<&Vec>) {} + | ~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~ + +error: it is more idiomatic to use `Option<&T>` instead of `&Option` + --> tests/ui/ref_option/ref_option.rs:26:5 + | +LL | fn pub_trait_opt(&self, a: &Option>); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^----------------^^ + | | + | help: change this to: `Option<&Vec>` + +error: it is more idiomatic to use `Option<&T>` instead of `&Option` + --> tests/ui/ref_option/ref_option.rs:27:5 + | +LL | fn pub_trait_ret(&self) -> &Option>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^----------------^ + | | + | help: change this to: `Option<&Vec>` + +error: it is more idiomatic to use `Option<&T>` instead of `&Option` + --> tests/ui/ref_option/ref_option.rs:31:5 + | +LL | fn trait_opt(&self, a: &Option); + | ^^^^^^^^^^^^^^^^^^^^^^^---------------^^ + | | + | help: change this to: `Option<&String>` + +error: it is more idiomatic to use `Option<&T>` instead of `&Option` + --> tests/ui/ref_option/ref_option.rs:32:5 + | +LL | fn trait_ret(&self) -> &Option; + | ^^^^^^^^^^^^^^^^^^^^^^^---------------^ + | | + | help: change this to: `Option<&String>` + +error: it is more idiomatic to use `Option<&T>` instead of `&Option` + --> tests/ui/ref_option/ref_option.rs:38:5 + | +LL | pub fn pub_opt_params(&self, a: &Option<()>) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-----------^^^^ + | | + | help: change this to: `Option<&()>` + +error: it is more idiomatic to use `Option<&T>` instead of `&Option` + --> tests/ui/ref_option/ref_option.rs:39:5 + | +LL | pub fn pub_opt_ret(&self) -> &Option { + | ^ --------------- help: change this to: `Option<&String>` + | _____| + | | +LL | | panic!() +LL | | } + | |_____^ + +error: it is more idiomatic to use `Option<&T>` instead of `&Option` + --> tests/ui/ref_option/ref_option.rs:43:5 + | +LL | fn private_opt_params(&self, a: &Option<()>) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-----------^^^^ + | | + | help: change this to: `Option<&()>` + +error: it is more idiomatic to use `Option<&T>` instead of `&Option` + --> tests/ui/ref_option/ref_option.rs:44:5 + | +LL | fn private_opt_ret(&self) -> &Option { + | ^ --------------- help: change this to: `Option<&String>` + | _____| + | | +LL | | panic!() +LL | | } + | |_____^ + +error: aborting due to 17 previous errors + diff --git a/tests/ui/ref_option/ref_option.private.fixed b/tests/ui/ref_option/ref_option.private.fixed new file mode 100644 index 00000000000..8c42556e9b0 --- /dev/null +++ b/tests/ui/ref_option/ref_option.private.fixed @@ -0,0 +1,62 @@ +//@revisions: private all +//@[private] rustc-env:CLIPPY_CONF_DIR=tests/ui/ref_option/private +//@[all] rustc-env:CLIPPY_CONF_DIR=tests/ui/ref_option/all + +#![allow(unused, clippy::needless_lifetimes, clippy::borrowed_box)] +#![warn(clippy::ref_option)] + +fn opt_u8(a: Option<&u8>) {} +fn opt_gen(a: Option<&T>) {} +fn opt_string(a: std::option::Option<&String>) {} +fn ret_string<'a>(p: &'a str) -> Option<&'a u8> { + panic!() +} +fn ret_string_static() -> Option<&'static u8> { + panic!() +} +fn mult_string(a: Option<&String>, b: Option<&Vec>) {} +fn ret_box<'a>() -> Option<&'a Box> { + panic!() +} + +pub fn pub_opt_string(a: &Option) {} +pub fn pub_mult_string(a: &Option, b: &Option>) {} + +pub trait PubTrait { + fn pub_trait_opt(&self, a: &Option>); + fn pub_trait_ret(&self) -> &Option>; +} + +trait PrivateTrait { + fn trait_opt(&self, a: Option<&String>); + fn trait_ret(&self) -> Option<&String>; +} + +pub struct PubStruct; + +impl PubStruct { + pub fn pub_opt_params(&self, a: &Option<()>) {} + pub fn pub_opt_ret(&self) -> &Option { + panic!() + } + + fn private_opt_params(&self, a: Option<&()>) {} + fn private_opt_ret(&self) -> Option<&String> { + panic!() + } +} + +// valid, don't change +fn mut_u8(a: &mut Option) {} +pub fn pub_mut_u8(a: &mut Option) {} + +// might be good to catch in the future +fn mut_u8_ref(a: &mut &Option) {} +pub fn pub_mut_u8_ref(a: &mut &Option) {} +fn lambdas() { + // Not handled for now, not sure if we should + let x = |a: &Option| {}; + let x = |a: &Option| -> &Option { panic!() }; +} + +fn main() {} diff --git a/tests/ui/ref_option/ref_option.private.stderr b/tests/ui/ref_option/ref_option.private.stderr new file mode 100644 index 00000000000..17c90536da3 --- /dev/null +++ b/tests/ui/ref_option/ref_option.private.stderr @@ -0,0 +1,108 @@ +error: it is more idiomatic to use `Option<&T>` instead of `&Option` + --> tests/ui/ref_option/ref_option.rs:8:1 + | +LL | fn opt_u8(a: &Option) {} + | ^^^^^^^^^^^^^-----------^^^^ + | | + | help: change this to: `Option<&u8>` + | + = note: `-D clippy::ref-option` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::ref_option)]` + +error: it is more idiomatic to use `Option<&T>` instead of `&Option` + --> tests/ui/ref_option/ref_option.rs:9:1 + | +LL | fn opt_gen(a: &Option) {} + | ^^^^^^^^^^^^^^^^^----------^^^^ + | | + | help: change this to: `Option<&T>` + +error: it is more idiomatic to use `Option<&T>` instead of `&Option` + --> tests/ui/ref_option/ref_option.rs:10:1 + | +LL | fn opt_string(a: &std::option::Option) {} + | ^^^^^^^^^^^^^^^^^----------------------------^^^^ + | | + | help: change this to: `std::option::Option<&String>` + +error: it is more idiomatic to use `Option<&T>` instead of `&Option` + --> tests/ui/ref_option/ref_option.rs:11:1 + | +LL | fn ret_string<'a>(p: &'a str) -> &'a Option { + | ^ -------------- help: change this to: `Option<&'a u8>` + | _| + | | +LL | | panic!() +LL | | } + | |_^ + +error: it is more idiomatic to use `Option<&T>` instead of `&Option` + --> tests/ui/ref_option/ref_option.rs:14:1 + | +LL | fn ret_string_static() -> &'static Option { + | ^ ------------------- help: change this to: `Option<&'static u8>` + | _| + | | +LL | | panic!() +LL | | } + | |_^ + +error: it is more idiomatic to use `Option<&T>` instead of `&Option` + --> tests/ui/ref_option/ref_option.rs:17:1 + | +LL | fn mult_string(a: &Option, b: &Option>) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: change this to + | +LL | fn mult_string(a: Option<&String>, b: Option<&Vec>) {} + | ~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~ + +error: it is more idiomatic to use `Option<&T>` instead of `&Option` + --> tests/ui/ref_option/ref_option.rs:18:1 + | +LL | fn ret_box<'a>() -> &'a Option> { + | ^ ------------------- help: change this to: `Option<&'a Box>` + | _| + | | +LL | | panic!() +LL | | } + | |_^ + +error: it is more idiomatic to use `Option<&T>` instead of `&Option` + --> tests/ui/ref_option/ref_option.rs:31:5 + | +LL | fn trait_opt(&self, a: &Option); + | ^^^^^^^^^^^^^^^^^^^^^^^---------------^^ + | | + | help: change this to: `Option<&String>` + +error: it is more idiomatic to use `Option<&T>` instead of `&Option` + --> tests/ui/ref_option/ref_option.rs:32:5 + | +LL | fn trait_ret(&self) -> &Option; + | ^^^^^^^^^^^^^^^^^^^^^^^---------------^ + | | + | help: change this to: `Option<&String>` + +error: it is more idiomatic to use `Option<&T>` instead of `&Option` + --> tests/ui/ref_option/ref_option.rs:43:5 + | +LL | fn private_opt_params(&self, a: &Option<()>) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-----------^^^^ + | | + | help: change this to: `Option<&()>` + +error: it is more idiomatic to use `Option<&T>` instead of `&Option` + --> tests/ui/ref_option/ref_option.rs:44:5 + | +LL | fn private_opt_ret(&self) -> &Option { + | ^ --------------- help: change this to: `Option<&String>` + | _____| + | | +LL | | panic!() +LL | | } + | |_____^ + +error: aborting due to 11 previous errors + diff --git a/tests/ui/ref_option/ref_option.rs b/tests/ui/ref_option/ref_option.rs new file mode 100644 index 00000000000..05251bcf12c --- /dev/null +++ b/tests/ui/ref_option/ref_option.rs @@ -0,0 +1,62 @@ +//@revisions: private all +//@[private] rustc-env:CLIPPY_CONF_DIR=tests/ui/ref_option/private +//@[all] rustc-env:CLIPPY_CONF_DIR=tests/ui/ref_option/all + +#![allow(unused, clippy::needless_lifetimes, clippy::borrowed_box)] +#![warn(clippy::ref_option)] + +fn opt_u8(a: &Option) {} +fn opt_gen(a: &Option) {} +fn opt_string(a: &std::option::Option) {} +fn ret_string<'a>(p: &'a str) -> &'a Option { + panic!() +} +fn ret_string_static() -> &'static Option { + panic!() +} +fn mult_string(a: &Option, b: &Option>) {} +fn ret_box<'a>() -> &'a Option> { + panic!() +} + +pub fn pub_opt_string(a: &Option) {} +pub fn pub_mult_string(a: &Option, b: &Option>) {} + +pub trait PubTrait { + fn pub_trait_opt(&self, a: &Option>); + fn pub_trait_ret(&self) -> &Option>; +} + +trait PrivateTrait { + fn trait_opt(&self, a: &Option); + fn trait_ret(&self) -> &Option; +} + +pub struct PubStruct; + +impl PubStruct { + pub fn pub_opt_params(&self, a: &Option<()>) {} + pub fn pub_opt_ret(&self) -> &Option { + panic!() + } + + fn private_opt_params(&self, a: &Option<()>) {} + fn private_opt_ret(&self) -> &Option { + panic!() + } +} + +// valid, don't change +fn mut_u8(a: &mut Option) {} +pub fn pub_mut_u8(a: &mut Option) {} + +// might be good to catch in the future +fn mut_u8_ref(a: &mut &Option) {} +pub fn pub_mut_u8_ref(a: &mut &Option) {} +fn lambdas() { + // Not handled for now, not sure if we should + let x = |a: &Option| {}; + let x = |a: &Option| -> &Option { panic!() }; +} + +fn main() {} diff --git a/tests/ui/ref_option/ref_option_traits.all.stderr b/tests/ui/ref_option/ref_option_traits.all.stderr new file mode 100644 index 00000000000..a9967168c12 --- /dev/null +++ b/tests/ui/ref_option/ref_option_traits.all.stderr @@ -0,0 +1,37 @@ +error: it is more idiomatic to use `Option<&T>` instead of `&Option` + --> tests/ui/ref_option/ref_option_traits.rs:10:5 + | +LL | fn pub_trait_opt(&self, a: &Option>); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^----------------^^ + | | + | help: change this to: `Option<&Vec>` + | + = note: `-D clippy::ref-option` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::ref_option)]` + +error: it is more idiomatic to use `Option<&T>` instead of `&Option` + --> tests/ui/ref_option/ref_option_traits.rs:11:5 + | +LL | fn pub_trait_ret(&self) -> &Option>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^----------------^ + | | + | help: change this to: `Option<&Vec>` + +error: it is more idiomatic to use `Option<&T>` instead of `&Option` + --> tests/ui/ref_option/ref_option_traits.rs:15:5 + | +LL | fn trait_opt(&self, a: &Option); + | ^^^^^^^^^^^^^^^^^^^^^^^---------------^^ + | | + | help: change this to: `Option<&String>` + +error: it is more idiomatic to use `Option<&T>` instead of `&Option` + --> tests/ui/ref_option/ref_option_traits.rs:16:5 + | +LL | fn trait_ret(&self) -> &Option; + | ^^^^^^^^^^^^^^^^^^^^^^^---------------^ + | | + | help: change this to: `Option<&String>` + +error: aborting due to 4 previous errors + diff --git a/tests/ui/ref_option/ref_option_traits.private.stderr b/tests/ui/ref_option/ref_option_traits.private.stderr new file mode 100644 index 00000000000..36d0833af8a --- /dev/null +++ b/tests/ui/ref_option/ref_option_traits.private.stderr @@ -0,0 +1,21 @@ +error: it is more idiomatic to use `Option<&T>` instead of `&Option` + --> tests/ui/ref_option/ref_option_traits.rs:15:5 + | +LL | fn trait_opt(&self, a: &Option); + | ^^^^^^^^^^^^^^^^^^^^^^^---------------^^ + | | + | help: change this to: `Option<&String>` + | + = note: `-D clippy::ref-option` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::ref_option)]` + +error: it is more idiomatic to use `Option<&T>` instead of `&Option` + --> tests/ui/ref_option/ref_option_traits.rs:16:5 + | +LL | fn trait_ret(&self) -> &Option; + | ^^^^^^^^^^^^^^^^^^^^^^^---------------^ + | | + | help: change this to: `Option<&String>` + +error: aborting due to 2 previous errors + diff --git a/tests/ui/ref_option/ref_option_traits.rs b/tests/ui/ref_option/ref_option_traits.rs new file mode 100644 index 00000000000..5d5f113c83d --- /dev/null +++ b/tests/ui/ref_option/ref_option_traits.rs @@ -0,0 +1,37 @@ +//@no-rustfix: fixes are only done to traits, not the impls +//@revisions: private all +//@[private] rustc-env:CLIPPY_CONF_DIR=tests/ui/ref_option/private +//@[all] rustc-env:CLIPPY_CONF_DIR=tests/ui/ref_option/all + +#![allow(unused, clippy::all)] +#![warn(clippy::ref_option)] + +pub trait PubTrait { + fn pub_trait_opt(&self, a: &Option>); + fn pub_trait_ret(&self) -> &Option>; +} + +trait PrivateTrait { + fn trait_opt(&self, a: &Option); + fn trait_ret(&self) -> &Option; +} + +pub struct PubStruct; + +impl PubTrait for PubStruct { + fn pub_trait_opt(&self, a: &Option>) {} + fn pub_trait_ret(&self) -> &Option> { + panic!() + } +} + +struct PrivateStruct; + +impl PrivateTrait for PrivateStruct { + fn trait_opt(&self, a: &Option) {} + fn trait_ret(&self) -> &Option { + panic!() + } +} + +fn main() {} From 62cbd2b7bd7e49c6eaa9a057465c470140b572e9 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 28 Sep 2024 18:03:47 +0200 Subject: [PATCH 370/683] Update `browser-ui-test` version to `0.18.1` --- .../docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version b/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version index 47d04a52883..6b2d58c8ef3 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version +++ b/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version @@ -1 +1 @@ -0.18.0 \ No newline at end of file +0.18.1 \ No newline at end of file From 2f16ff7b37fb8425df36434513c026b9696d16ea Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 28 Sep 2024 18:04:00 +0200 Subject: [PATCH 371/683] Make use of `wait-for*-false` commands --- .../docblock-code-block-line-number.goml | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/tests/rustdoc-gui/docblock-code-block-line-number.goml b/tests/rustdoc-gui/docblock-code-block-line-number.goml index 53f756dfcd6..3c16626336e 100644 --- a/tests/rustdoc-gui/docblock-code-block-line-number.goml +++ b/tests/rustdoc-gui/docblock-code-block-line-number.goml @@ -87,8 +87,7 @@ assert-css: ("#settings", {"display": "block"}) // Then, click the toggle button. click: "input#line-numbers" -wait-for: 100 // FIXME: `wait-for-false` does not exist -assert-false: "pre.example-line-numbers" +wait-for-false: "pre.example-line-numbers" assert-local-storage: {"rustdoc-line-numbers": "false" } // Check that the rounded corners are back. @@ -107,8 +106,7 @@ assert-css: ( click: "input#line-numbers" wait-for: "pre.example-line-numbers" assert-local-storage: {"rustdoc-line-numbers": "true" } -wait-for: 100 // FIXME: `wait-for-false` does not exist -assert: "pre.example-line-numbers" +wait-for: "pre.example-line-numbers" // Same check with scraped examples line numbers. go-to: "file://" + |DOC_PATH| + "/scrape_examples/fn.test_many.html" @@ -195,15 +193,13 @@ define-function: ("check-line-numbers-existence", [], block { // Then, click the toggle button. click: "input#line-numbers" - wait-for: 100 // FIXME: `wait-for-false` does not exist - assert-local-storage-false: {"rustdoc-line-numbers": "true" } + wait-for-local-storage-false: {"rustdoc-line-numbers": "true" } assert-false: ".example-line-numbers" // Line numbers should still be there. assert: ".src-line-numbers" // Now disabling the setting. click: "input#line-numbers" - wait-for: 100 // FIXME: `wait-for-false` does not exist - assert-local-storage: {"rustdoc-line-numbers": "true" } + wait-for-local-storage: {"rustdoc-line-numbers": "true" } assert-false: ".example-line-numbers" // Line numbers should still be there. assert: ".src-line-numbers" @@ -246,12 +242,10 @@ wait-for: "#settings" // Then, click the toggle button. click: "input#line-numbers" -wait-for: 100 // FIXME: `wait-for-false` does not exist +wait-for-count: (".example-wrap > pre.example-line-numbers", 0) assert-local-storage-false: {"rustdoc-line-numbers": "true" } -assert-count: (".example-wrap > pre.example-line-numbers", 0) // Now turning off the setting. click: "input#line-numbers" -wait-for: 100 // FIXME: `wait-for-false` does not exist +wait-for-count: (".example-wrap > pre.example-line-numbers", 2) assert-local-storage: {"rustdoc-line-numbers": "true" } -assert-count: (".example-wrap > pre.example-line-numbers", 2) From cdf2a8ffc5f8af31529b44964457a7a7e9979680 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 27 Sep 2024 18:03:54 +0200 Subject: [PATCH 372/683] Rename `standalone` doctest attribute into `standalone-crate` --- library/core/src/panic/location.rs | 2 +- .../src/write-documentation/documentation-tests.md | 4 ++-- src/librustdoc/doctest.rs | 2 +- src/librustdoc/doctest/make.rs | 2 +- src/librustdoc/html/markdown.rs | 8 ++++---- tests/run-make/doctests-merge/doctest-standalone.rs | 4 ++-- 6 files changed, 11 insertions(+), 11 deletions(-) diff --git a/library/core/src/panic/location.rs b/library/core/src/panic/location.rs index e2a842046a9..97408a4ac18 100644 --- a/library/core/src/panic/location.rs +++ b/library/core/src/panic/location.rs @@ -44,7 +44,7 @@ impl<'a> Location<'a> { /// /// # Examples /// - /// ```standalone + /// ```standalone-crate /// use std::panic::Location; /// /// /// Returns the [`Location`] at which it is called. diff --git a/src/doc/rustdoc/src/write-documentation/documentation-tests.md b/src/doc/rustdoc/src/write-documentation/documentation-tests.md index 7ed2e9720fe..94ef34ea5a5 100644 --- a/src/doc/rustdoc/src/write-documentation/documentation-tests.md +++ b/src/doc/rustdoc/src/write-documentation/documentation-tests.md @@ -414,11 +414,11 @@ In some cases, doctests cannot be merged. For example, if you have: The problem with this code is that, if you change any other doctests, it'll likely break when runing `rustdoc --test`, making it tricky to maintain. -This is where the `standalone` attribute comes in: it tells `rustdoc` that a doctest +This is where the `standalone-crate` attribute comes in: it tells `rustdoc` that a doctest should not be merged with the others. So the previous code should use it: ```rust -//! ```standalone +//! ```standalone-crate //! let location = std::panic::Location::caller(); //! assert_eq!(location.line(), 4); //! ``` diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index 3ee6b24ac92..bdd6fbe8c0c 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -837,7 +837,7 @@ impl CreateRunnableDocTests { let is_standalone = !doctest.can_be_merged || scraped_test.langstr.compile_fail || scraped_test.langstr.test_harness - || scraped_test.langstr.standalone + || scraped_test.langstr.standalone_crate || self.rustdoc_options.nocapture || self.rustdoc_options.test_args.iter().any(|arg| arg == "--show-output"); if is_standalone { diff --git a/src/librustdoc/doctest/make.rs b/src/librustdoc/doctest/make.rs index d560e3a476b..efbb332d12d 100644 --- a/src/librustdoc/doctest/make.rs +++ b/src/librustdoc/doctest/make.rs @@ -48,7 +48,7 @@ impl DocTestBuilder { ) -> Self { let can_merge_doctests = can_merge_doctests && lang_str.is_some_and(|lang_str| { - !lang_str.compile_fail && !lang_str.test_harness && !lang_str.standalone + !lang_str.compile_fail && !lang_str.test_harness && !lang_str.standalone_crate }); let SourceInfo { crate_attrs, maybe_crate_attrs, crates, everything_else } = diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index b18d621478c..fbba63f9445 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -871,7 +871,7 @@ pub(crate) struct LangString { pub(crate) rust: bool, pub(crate) test_harness: bool, pub(crate) compile_fail: bool, - pub(crate) standalone: bool, + pub(crate) standalone_crate: bool, pub(crate) error_codes: Vec, pub(crate) edition: Option, pub(crate) added_classes: Vec, @@ -1194,7 +1194,7 @@ impl Default for LangString { rust: true, test_harness: false, compile_fail: false, - standalone: false, + standalone_crate: false, error_codes: Vec::new(), edition: None, added_classes: Vec::new(), @@ -1264,8 +1264,8 @@ impl LangString { seen_rust_tags = !seen_other_tags || seen_rust_tags; data.no_run = true; } - LangStringToken::LangToken("standalone") => { - data.standalone = true; + LangStringToken::LangToken("standalone-crate") => { + data.standalone_crate = true; seen_rust_tags = !seen_other_tags || seen_rust_tags; } LangStringToken::LangToken(x) if x.starts_with("edition") => { diff --git a/tests/run-make/doctests-merge/doctest-standalone.rs b/tests/run-make/doctests-merge/doctest-standalone.rs index 134ffb58285..4b6a1c6ab61 100644 --- a/tests/run-make/doctests-merge/doctest-standalone.rs +++ b/tests/run-make/doctests-merge/doctest-standalone.rs @@ -1,11 +1,11 @@ #![crate_name = "foo"] #![crate_type = "lib"] -//! ```standalone +//! ```standalone-crate //! foo::init(); //! ``` -/// ```standalone +/// ```standalone-crate /// foo::init(); /// ``` pub fn init() { From 35f24d0d14f66ddd59088af7f5f1582d21b6ea11 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 27 Sep 2024 21:28:15 +0200 Subject: [PATCH 373/683] Improve code for codeblock invalid attributes --- src/librustdoc/html/markdown.rs | 43 ++++++++++++++------------------- 1 file changed, 18 insertions(+), 25 deletions(-) diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index fbba63f9445..a9befefa118 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -1298,35 +1298,28 @@ impl LangString { } LangStringToken::LangToken(x) if extra.is_some() => { let s = x.to_lowercase(); - if let Some((flag, help)) = if s == "compile-fail" - || s == "compile_fail" - || s == "compilefail" - { - Some(( + if let Some((flag, help)) = match s.as_str() { + "compile-fail" | "compile_fail" | "compilefail" => Some(( "compile_fail", - "the code block will either not be tested if not marked as a rust one \ - or won't fail if it compiles successfully", - )) - } else if s == "should-panic" || s == "should_panic" || s == "shouldpanic" { - Some(( + "the code block will either not be tested if not marked as a rust \ + one or won't fail if it compiles successfully", + )), + "should-panic" | "should_panic" | "shouldpanic" => Some(( "should_panic", - "the code block will either not be tested if not marked as a rust one \ - or won't fail if it doesn't panic when running", - )) - } else if s == "no-run" || s == "no_run" || s == "norun" { - Some(( + "the code block will either not be tested if not marked as a rust \ + one or won't fail if it doesn't panic when running", + )), + "no-run" | "no_run" | "norun" => Some(( "no_run", - "the code block will either not be tested if not marked as a rust one \ - or will be run (which you might not want)", - )) - } else if s == "test-harness" || s == "test_harness" || s == "testharness" { - Some(( + "the code block will either not be tested if not marked as a rust \ + one or will be run (which you might not want)", + )), + "test-harness" | "test_harness" | "testharness" => Some(( "test_harness", - "the code block will either not be tested if not marked as a rust one \ - or the code will be wrapped inside a main function", - )) - } else { - None + "the code block will either not be tested if not marked as a rust \ + one or the code will be wrapped inside a main function", + )), + _ => None, } { if let Some(extra) = extra { extra.error_invalid_codeblock_attr_with_help( From 0956f69cafb4132023b9974f0a4a091bcac76618 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 27 Sep 2024 21:39:52 +0200 Subject: [PATCH 374/683] Add warning if `standalone-crate` is mistyped --- src/librustdoc/html/markdown.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index a9befefa118..c487138152d 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -1319,6 +1319,20 @@ impl LangString { "the code block will either not be tested if not marked as a rust \ one or the code will be wrapped inside a main function", )), + "standalone" | "standalone_crate" => { + if let Some(extra) = extra + && extra.sp.at_least_rust_2024() + { + Some(( + "standalone-crate", + "the code block will either not be tested if not marked as \ + a rust one or the code will be run as part of the merged \ + doctests if compatible", + )) + } else { + None + } + } _ => None, } { if let Some(extra) = extra { From 84d41e2fc19570e553dc6704e747062373ce4270 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 27 Sep 2024 21:40:11 +0200 Subject: [PATCH 375/683] Add regression tests for mistyped `standalone-crate` attribute --- .../doctest/standalone-warning-2024.rs | 16 ++++++++ .../doctest/standalone-warning-2024.stderr | 38 +++++++++++++++++++ .../rustdoc-ui/doctest/standalone-warning.rs | 10 +++++ 3 files changed, 64 insertions(+) create mode 100644 tests/rustdoc-ui/doctest/standalone-warning-2024.rs create mode 100644 tests/rustdoc-ui/doctest/standalone-warning-2024.stderr create mode 100644 tests/rustdoc-ui/doctest/standalone-warning.rs diff --git a/tests/rustdoc-ui/doctest/standalone-warning-2024.rs b/tests/rustdoc-ui/doctest/standalone-warning-2024.rs new file mode 100644 index 00000000000..33ed16a87fa --- /dev/null +++ b/tests/rustdoc-ui/doctest/standalone-warning-2024.rs @@ -0,0 +1,16 @@ +// This test checks that it will output warnings for usage of `standalone` or `standalone_crate`. + +//@ compile-flags:--test -Zunstable-options --edition 2024 +//@ normalize-stdout-test: "tests/rustdoc-ui/doctest" -> "$$DIR" +//@ normalize-stdout-test: "finished in \d+\.\d+s" -> "finished in $$TIME" +//@ normalize-stdout-test: ".rs:\d+:\d+" -> ".rs:$$LINE:$$COL" + +#![deny(warnings)] + +//! ```standalone +//! bla +//! ``` +//! +//! ```standalone_crate +//! bla +//! ``` diff --git a/tests/rustdoc-ui/doctest/standalone-warning-2024.stderr b/tests/rustdoc-ui/doctest/standalone-warning-2024.stderr new file mode 100644 index 00000000000..ec9d17bb073 --- /dev/null +++ b/tests/rustdoc-ui/doctest/standalone-warning-2024.stderr @@ -0,0 +1,38 @@ +error: unknown attribute `standalone` + --> $DIR/standalone-warning-2024.rs:10:1 + | +10 | / //! ```standalone +11 | | //! bla +12 | | //! ``` +13 | | //! +14 | | //! ```standalone_crate +15 | | //! bla +16 | | //! ``` + | |_______^ + | + = help: there is an attribute with a similar name: `standalone-crate` + = help: the code block will either not be tested if not marked as a rust one or the code will be run as part of the merged doctests if compatible +note: the lint level is defined here + --> $DIR/standalone-warning-2024.rs:8:9 + | +8 | #![deny(warnings)] + | ^^^^^^^^ + = note: `#[deny(rustdoc::invalid_codeblock_attributes)]` implied by `#[deny(warnings)]` + +error: unknown attribute `standalone_crate` + --> $DIR/standalone-warning-2024.rs:10:1 + | +10 | / //! ```standalone +11 | | //! bla +12 | | //! ``` +13 | | //! +14 | | //! ```standalone_crate +15 | | //! bla +16 | | //! ``` + | |_______^ + | + = help: there is an attribute with a similar name: `standalone-crate` + = help: the code block will either not be tested if not marked as a rust one or the code will be run as part of the merged doctests if compatible + +error: aborting due to 2 previous errors + diff --git a/tests/rustdoc-ui/doctest/standalone-warning.rs b/tests/rustdoc-ui/doctest/standalone-warning.rs new file mode 100644 index 00000000000..323d8f5f580 --- /dev/null +++ b/tests/rustdoc-ui/doctest/standalone-warning.rs @@ -0,0 +1,10 @@ +// This test checks that it will not output warning for usage of `standalone` or `standalone_crate`. +//@ check-pass + +//! ```standalone +//! bla +//! ``` +//! +//! ```standalone_crate +//! bla +//! ``` From 632fed891df4850e579b2c796de7e18b53d80daa Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 28 Sep 2024 01:32:09 +0200 Subject: [PATCH 376/683] Improve mistyped docblock attribute warning messages --- src/librustdoc/html/markdown.rs | 58 +++++++++---------- .../rustdoc-ui/doctest/check-attr-test.stderr | 48 +++++++-------- .../doctest/standalone-warning-2024.stderr | 8 +-- tests/rustdoc-ui/lints/check-attr.stderr | 52 ++++++++--------- tests/rustdoc-ui/lints/check-fail.stderr | 8 +-- 5 files changed, 85 insertions(+), 89 deletions(-) diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index c487138152d..e1a8dc6e50c 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -1298,37 +1298,31 @@ impl LangString { } LangStringToken::LangToken(x) if extra.is_some() => { let s = x.to_lowercase(); - if let Some((flag, help)) = match s.as_str() { - "compile-fail" | "compile_fail" | "compilefail" => Some(( - "compile_fail", - "the code block will either not be tested if not marked as a rust \ - one or won't fail if it compiles successfully", - )), - "should-panic" | "should_panic" | "shouldpanic" => Some(( - "should_panic", - "the code block will either not be tested if not marked as a rust \ - one or won't fail if it doesn't panic when running", - )), - "no-run" | "no_run" | "norun" => Some(( - "no_run", - "the code block will either not be tested if not marked as a rust \ - one or will be run (which you might not want)", - )), - "test-harness" | "test_harness" | "testharness" => Some(( - "test_harness", - "the code block will either not be tested if not marked as a rust \ - one or the code will be wrapped inside a main function", - )), + if let Some(help) = match s.as_str() { + "compile-fail" | "compile_fail" | "compilefail" => Some( + "use `compile_fail` to invert the results of this test, so that it \ + passes if it cannot be compiled and fails if it can", + ), + "should-panic" | "should_panic" | "shouldpanic" => Some( + "use `should_panic` to invert the results of this test, so that if \ + passes if it panics and fails if it does not", + ), + "no-run" | "no_run" | "norun" => Some( + "use `no_run` to compile, but not run, the code sample during \ + testing", + ), + "test-harness" | "test_harness" | "testharness" => Some( + "use `test_harness` to run functions marked `#[test]` instead of a \ + potentially-implicit `main` function", + ), "standalone" | "standalone_crate" => { if let Some(extra) = extra && extra.sp.at_least_rust_2024() { - Some(( - "standalone-crate", - "the code block will either not be tested if not marked as \ - a rust one or the code will be run as part of the merged \ - doctests if compatible", - )) + Some( + "use `standalone-crate` to compile this code block \ + separately", + ) } else { None } @@ -1339,10 +1333,12 @@ impl LangString { extra.error_invalid_codeblock_attr_with_help( format!("unknown attribute `{x}`"), |lint| { - lint.help(format!( - "there is an attribute with a similar name: `{flag}`" - )) - .help(help); + lint.help(help).help( + "this code block may be skipped during testing, \ + because unknown attributes are treated as markers for \ + code samples written in other programming languages, \ + unless it is also explicitly marked as `rust`", + ); }, ); } diff --git a/tests/rustdoc-ui/doctest/check-attr-test.stderr b/tests/rustdoc-ui/doctest/check-attr-test.stderr index 10f763a6f9d..257136d1633 100644 --- a/tests/rustdoc-ui/doctest/check-attr-test.stderr +++ b/tests/rustdoc-ui/doctest/check-attr-test.stderr @@ -8,8 +8,8 @@ error: unknown attribute `compile-fail` 9 | | /// ``` | |_______^ | - = help: there is an attribute with a similar name: `compile_fail` - = help: the code block will either not be tested if not marked as a rust one or won't fail if it compiles successfully + = help: use `compile_fail` to invert the results of this test, so that it passes if it cannot be compiled and fails if it can + = help: this code block may be skipped during testing, because unknown attributes are treated as markers for code samples written in other programming languages, unless it is also explicitly marked as `rust` note: the lint level is defined here --> $DIR/check-attr-test.rs:3:9 | @@ -26,8 +26,8 @@ error: unknown attribute `compilefail` 9 | | /// ``` | |_______^ | - = help: there is an attribute with a similar name: `compile_fail` - = help: the code block will either not be tested if not marked as a rust one or won't fail if it compiles successfully + = help: use `compile_fail` to invert the results of this test, so that it passes if it cannot be compiled and fails if it can + = help: this code block may be skipped during testing, because unknown attributes are treated as markers for code samples written in other programming languages, unless it is also explicitly marked as `rust` error: unknown attribute `comPile_fail` --> $DIR/check-attr-test.rs:5:1 @@ -39,8 +39,8 @@ error: unknown attribute `comPile_fail` 9 | | /// ``` | |_______^ | - = help: there is an attribute with a similar name: `compile_fail` - = help: the code block will either not be tested if not marked as a rust one or won't fail if it compiles successfully + = help: use `compile_fail` to invert the results of this test, so that it passes if it cannot be compiled and fails if it can + = help: this code block may be skipped during testing, because unknown attributes are treated as markers for code samples written in other programming languages, unless it is also explicitly marked as `rust` error: unknown attribute `should-panic` --> $DIR/check-attr-test.rs:12:1 @@ -52,8 +52,8 @@ error: unknown attribute `should-panic` 16 | | /// ``` | |_______^ | - = help: there is an attribute with a similar name: `should_panic` - = help: the code block will either not be tested if not marked as a rust one or won't fail if it doesn't panic when running + = help: use `should_panic` to invert the results of this test, so that if passes if it panics and fails if it does not + = help: this code block may be skipped during testing, because unknown attributes are treated as markers for code samples written in other programming languages, unless it is also explicitly marked as `rust` error: unknown attribute `shouldpanic` --> $DIR/check-attr-test.rs:12:1 @@ -65,8 +65,8 @@ error: unknown attribute `shouldpanic` 16 | | /// ``` | |_______^ | - = help: there is an attribute with a similar name: `should_panic` - = help: the code block will either not be tested if not marked as a rust one or won't fail if it doesn't panic when running + = help: use `should_panic` to invert the results of this test, so that if passes if it panics and fails if it does not + = help: this code block may be skipped during testing, because unknown attributes are treated as markers for code samples written in other programming languages, unless it is also explicitly marked as `rust` error: unknown attribute `shOuld_panic` --> $DIR/check-attr-test.rs:12:1 @@ -78,8 +78,8 @@ error: unknown attribute `shOuld_panic` 16 | | /// ``` | |_______^ | - = help: there is an attribute with a similar name: `should_panic` - = help: the code block will either not be tested if not marked as a rust one or won't fail if it doesn't panic when running + = help: use `should_panic` to invert the results of this test, so that if passes if it panics and fails if it does not + = help: this code block may be skipped during testing, because unknown attributes are treated as markers for code samples written in other programming languages, unless it is also explicitly marked as `rust` error: unknown attribute `no-run` --> $DIR/check-attr-test.rs:19:1 @@ -91,8 +91,8 @@ error: unknown attribute `no-run` 23 | | /// ``` | |_______^ | - = help: there is an attribute with a similar name: `no_run` - = help: the code block will either not be tested if not marked as a rust one or will be run (which you might not want) + = help: use `no_run` to compile, but not run, the code sample during testing + = help: this code block may be skipped during testing, because unknown attributes are treated as markers for code samples written in other programming languages, unless it is also explicitly marked as `rust` error: unknown attribute `norun` --> $DIR/check-attr-test.rs:19:1 @@ -104,8 +104,8 @@ error: unknown attribute `norun` 23 | | /// ``` | |_______^ | - = help: there is an attribute with a similar name: `no_run` - = help: the code block will either not be tested if not marked as a rust one or will be run (which you might not want) + = help: use `no_run` to compile, but not run, the code sample during testing + = help: this code block may be skipped during testing, because unknown attributes are treated as markers for code samples written in other programming languages, unless it is also explicitly marked as `rust` error: unknown attribute `nO_run` --> $DIR/check-attr-test.rs:19:1 @@ -117,8 +117,8 @@ error: unknown attribute `nO_run` 23 | | /// ``` | |_______^ | - = help: there is an attribute with a similar name: `no_run` - = help: the code block will either not be tested if not marked as a rust one or will be run (which you might not want) + = help: use `no_run` to compile, but not run, the code sample during testing + = help: this code block may be skipped during testing, because unknown attributes are treated as markers for code samples written in other programming languages, unless it is also explicitly marked as `rust` error: unknown attribute `test-harness` --> $DIR/check-attr-test.rs:26:1 @@ -130,8 +130,8 @@ error: unknown attribute `test-harness` 30 | | /// ``` | |_______^ | - = help: there is an attribute with a similar name: `test_harness` - = help: the code block will either not be tested if not marked as a rust one or the code will be wrapped inside a main function + = help: use `test_harness` to run functions marked `#[test]` instead of a potentially-implicit `main` function + = help: this code block may be skipped during testing, because unknown attributes are treated as markers for code samples written in other programming languages, unless it is also explicitly marked as `rust` error: unknown attribute `testharness` --> $DIR/check-attr-test.rs:26:1 @@ -143,8 +143,8 @@ error: unknown attribute `testharness` 30 | | /// ``` | |_______^ | - = help: there is an attribute with a similar name: `test_harness` - = help: the code block will either not be tested if not marked as a rust one or the code will be wrapped inside a main function + = help: use `test_harness` to run functions marked `#[test]` instead of a potentially-implicit `main` function + = help: this code block may be skipped during testing, because unknown attributes are treated as markers for code samples written in other programming languages, unless it is also explicitly marked as `rust` error: unknown attribute `tesT_harness` --> $DIR/check-attr-test.rs:26:1 @@ -156,8 +156,8 @@ error: unknown attribute `tesT_harness` 30 | | /// ``` | |_______^ | - = help: there is an attribute with a similar name: `test_harness` - = help: the code block will either not be tested if not marked as a rust one or the code will be wrapped inside a main function + = help: use `test_harness` to run functions marked `#[test]` instead of a potentially-implicit `main` function + = help: this code block may be skipped during testing, because unknown attributes are treated as markers for code samples written in other programming languages, unless it is also explicitly marked as `rust` error: aborting due to 12 previous errors diff --git a/tests/rustdoc-ui/doctest/standalone-warning-2024.stderr b/tests/rustdoc-ui/doctest/standalone-warning-2024.stderr index ec9d17bb073..ef2e2364319 100644 --- a/tests/rustdoc-ui/doctest/standalone-warning-2024.stderr +++ b/tests/rustdoc-ui/doctest/standalone-warning-2024.stderr @@ -10,8 +10,8 @@ error: unknown attribute `standalone` 16 | | //! ``` | |_______^ | - = help: there is an attribute with a similar name: `standalone-crate` - = help: the code block will either not be tested if not marked as a rust one or the code will be run as part of the merged doctests if compatible + = help: use `standalone-crate` to compile this code block separately + = help: this code block may be skipped during testing, because unknown attributes are treated as markers for code samples written in other programming languages, unless it is also explicitly marked as `rust` note: the lint level is defined here --> $DIR/standalone-warning-2024.rs:8:9 | @@ -31,8 +31,8 @@ error: unknown attribute `standalone_crate` 16 | | //! ``` | |_______^ | - = help: there is an attribute with a similar name: `standalone-crate` - = help: the code block will either not be tested if not marked as a rust one or the code will be run as part of the merged doctests if compatible + = help: use `standalone-crate` to compile this code block separately + = help: this code block may be skipped during testing, because unknown attributes are treated as markers for code samples written in other programming languages, unless it is also explicitly marked as `rust` error: aborting due to 2 previous errors diff --git a/tests/rustdoc-ui/lints/check-attr.stderr b/tests/rustdoc-ui/lints/check-attr.stderr index d640125ab51..e23806e0bab 100644 --- a/tests/rustdoc-ui/lints/check-attr.stderr +++ b/tests/rustdoc-ui/lints/check-attr.stderr @@ -10,8 +10,8 @@ LL | | /// boo LL | | /// ``` | |_______^ | - = help: there is an attribute with a similar name: `compile_fail` - = help: the code block will either not be tested if not marked as a rust one or won't fail if it compiles successfully + = help: use `compile_fail` to invert the results of this test, so that it passes if it cannot be compiled and fails if it can + = help: this code block may be skipped during testing, because unknown attributes are treated as markers for code samples written in other programming languages, unless it is also explicitly marked as `rust` note: the lint level is defined here --> $DIR/check-attr.rs:1:9 | @@ -30,8 +30,8 @@ LL | | /// boo LL | | /// ``` | |_______^ | - = help: there is an attribute with a similar name: `compile_fail` - = help: the code block will either not be tested if not marked as a rust one or won't fail if it compiles successfully + = help: use `compile_fail` to invert the results of this test, so that it passes if it cannot be compiled and fails if it can + = help: this code block may be skipped during testing, because unknown attributes are treated as markers for code samples written in other programming languages, unless it is also explicitly marked as `rust` error: unknown attribute `comPile_fail` --> $DIR/check-attr.rs:3:1 @@ -45,8 +45,8 @@ LL | | /// boo LL | | /// ``` | |_______^ | - = help: there is an attribute with a similar name: `compile_fail` - = help: the code block will either not be tested if not marked as a rust one or won't fail if it compiles successfully + = help: use `compile_fail` to invert the results of this test, so that it passes if it cannot be compiled and fails if it can + = help: this code block may be skipped during testing, because unknown attributes are treated as markers for code samples written in other programming languages, unless it is also explicitly marked as `rust` error: unknown attribute `should-panic` --> $DIR/check-attr.rs:13:1 @@ -60,8 +60,8 @@ LL | | /// boo LL | | /// ``` | |_______^ | - = help: there is an attribute with a similar name: `should_panic` - = help: the code block will either not be tested if not marked as a rust one or won't fail if it doesn't panic when running + = help: use `should_panic` to invert the results of this test, so that if passes if it panics and fails if it does not + = help: this code block may be skipped during testing, because unknown attributes are treated as markers for code samples written in other programming languages, unless it is also explicitly marked as `rust` error: unknown attribute `shouldpanic` --> $DIR/check-attr.rs:13:1 @@ -75,8 +75,8 @@ LL | | /// boo LL | | /// ``` | |_______^ | - = help: there is an attribute with a similar name: `should_panic` - = help: the code block will either not be tested if not marked as a rust one or won't fail if it doesn't panic when running + = help: use `should_panic` to invert the results of this test, so that if passes if it panics and fails if it does not + = help: this code block may be skipped during testing, because unknown attributes are treated as markers for code samples written in other programming languages, unless it is also explicitly marked as `rust` error: unknown attribute `sHould_panic` --> $DIR/check-attr.rs:13:1 @@ -90,8 +90,8 @@ LL | | /// boo LL | | /// ``` | |_______^ | - = help: there is an attribute with a similar name: `should_panic` - = help: the code block will either not be tested if not marked as a rust one or won't fail if it doesn't panic when running + = help: use `should_panic` to invert the results of this test, so that if passes if it panics and fails if it does not + = help: this code block may be skipped during testing, because unknown attributes are treated as markers for code samples written in other programming languages, unless it is also explicitly marked as `rust` error: unknown attribute `no-run` --> $DIR/check-attr.rs:23:1 @@ -105,8 +105,8 @@ LL | | /// boo LL | | /// ``` | |_______^ | - = help: there is an attribute with a similar name: `no_run` - = help: the code block will either not be tested if not marked as a rust one or will be run (which you might not want) + = help: use `no_run` to compile, but not run, the code sample during testing + = help: this code block may be skipped during testing, because unknown attributes are treated as markers for code samples written in other programming languages, unless it is also explicitly marked as `rust` error: unknown attribute `norun` --> $DIR/check-attr.rs:23:1 @@ -120,8 +120,8 @@ LL | | /// boo LL | | /// ``` | |_______^ | - = help: there is an attribute with a similar name: `no_run` - = help: the code block will either not be tested if not marked as a rust one or will be run (which you might not want) + = help: use `no_run` to compile, but not run, the code sample during testing + = help: this code block may be skipped during testing, because unknown attributes are treated as markers for code samples written in other programming languages, unless it is also explicitly marked as `rust` error: unknown attribute `no_Run` --> $DIR/check-attr.rs:23:1 @@ -135,8 +135,8 @@ LL | | /// boo LL | | /// ``` | |_______^ | - = help: there is an attribute with a similar name: `no_run` - = help: the code block will either not be tested if not marked as a rust one or will be run (which you might not want) + = help: use `no_run` to compile, but not run, the code sample during testing + = help: this code block may be skipped during testing, because unknown attributes are treated as markers for code samples written in other programming languages, unless it is also explicitly marked as `rust` error: unknown attribute `test-harness` --> $DIR/check-attr.rs:33:1 @@ -150,8 +150,8 @@ LL | | /// boo LL | | /// ``` | |_______^ | - = help: there is an attribute with a similar name: `test_harness` - = help: the code block will either not be tested if not marked as a rust one or the code will be wrapped inside a main function + = help: use `test_harness` to run functions marked `#[test]` instead of a potentially-implicit `main` function + = help: this code block may be skipped during testing, because unknown attributes are treated as markers for code samples written in other programming languages, unless it is also explicitly marked as `rust` error: unknown attribute `testharness` --> $DIR/check-attr.rs:33:1 @@ -165,8 +165,8 @@ LL | | /// boo LL | | /// ``` | |_______^ | - = help: there is an attribute with a similar name: `test_harness` - = help: the code block will either not be tested if not marked as a rust one or the code will be wrapped inside a main function + = help: use `test_harness` to run functions marked `#[test]` instead of a potentially-implicit `main` function + = help: this code block may be skipped during testing, because unknown attributes are treated as markers for code samples written in other programming languages, unless it is also explicitly marked as `rust` error: unknown attribute `teSt_harness` --> $DIR/check-attr.rs:33:1 @@ -180,8 +180,8 @@ LL | | /// boo LL | | /// ``` | |_______^ | - = help: there is an attribute with a similar name: `test_harness` - = help: the code block will either not be tested if not marked as a rust one or the code will be wrapped inside a main function + = help: use `test_harness` to run functions marked `#[test]` instead of a potentially-implicit `main` function + = help: this code block may be skipped during testing, because unknown attributes are treated as markers for code samples written in other programming languages, unless it is also explicitly marked as `rust` error: unknown attribute `rust2018` --> $DIR/check-attr.rs:43:1 @@ -222,8 +222,8 @@ LL | | /// boo LL | | /// ``` | |_______^ | - = help: there is an attribute with a similar name: `should_panic` - = help: the code block will either not be tested if not marked as a rust one or won't fail if it doesn't panic when running + = help: use `should_panic` to invert the results of this test, so that if passes if it panics and fails if it does not + = help: this code block may be skipped during testing, because unknown attributes are treated as markers for code samples written in other programming languages, unless it is also explicitly marked as `rust` error: aborting due to 15 previous errors diff --git a/tests/rustdoc-ui/lints/check-fail.stderr b/tests/rustdoc-ui/lints/check-fail.stderr index 99b01bac598..2eb9496e5dc 100644 --- a/tests/rustdoc-ui/lints/check-fail.stderr +++ b/tests/rustdoc-ui/lints/check-fail.stderr @@ -31,8 +31,8 @@ LL | | //! let x = 12; LL | | //! ``` | |_______^ | - = help: there is an attribute with a similar name: `test_harness` - = help: the code block will either not be tested if not marked as a rust one or the code will be wrapped inside a main function + = help: use `test_harness` to run functions marked `#[test]` instead of a potentially-implicit `main` function + = help: this code block may be skipped during testing, because unknown attributes are treated as markers for code samples written in other programming languages, unless it is also explicitly marked as `rust` note: the lint level is defined here --> $DIR/check-fail.rs:6:9 | @@ -51,8 +51,8 @@ LL | | /// let x = 12; LL | | /// ``` | |_______^ | - = help: there is an attribute with a similar name: `test_harness` - = help: the code block will either not be tested if not marked as a rust one or the code will be wrapped inside a main function + = help: use `test_harness` to run functions marked `#[test]` instead of a potentially-implicit `main` function + = help: this code block may be skipped during testing, because unknown attributes are treated as markers for code samples written in other programming languages, unless it is also explicitly marked as `rust` error: aborting due to 4 previous errors From 38295a0d8acf04a55567cbc1bfa3eddd45e5e702 Mon Sep 17 00:00:00 2001 From: Yuri Astrakhan Date: Sat, 28 Sep 2024 13:01:51 -0400 Subject: [PATCH 377/683] update docs --- clippy_lints/src/functions/mod.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/functions/mod.rs b/clippy_lints/src/functions/mod.rs index cfa63d3befc..50b3d039ed3 100644 --- a/clippy_lints/src/functions/mod.rs +++ b/clippy_lints/src/functions/mod.rs @@ -410,8 +410,9 @@ declare_clippy_lint! { /// `&Option` in a function signature breaks encapsulation because the caller must own T /// and move it into an Option to call with it. When returned, the owner must internally store /// it as `Option` in order to return it. - /// At a lower level `&Option` points to memory that has `presence` bit flag + value, - /// whereas `Option<&T>` is always optimized to a single pointer. + /// At a lower level, `&Option` points to memory with the `presence` bit flag plus the `T` value, + /// whereas `Option<&T>` is usually [optimized](https://doc.rust-lang.org/1.81.0/std/option/index.html#representation) + /// to a single pointer, so it may be more optimal. /// /// See this [YouTube video](https://www.youtube.com/watch?v=6c7pZYP_iIE) by /// Logan Smith for an in-depth explanation of why this is important. From 10e02cf8e3e8b46d3bc7f8194c9224755604eac4 Mon Sep 17 00:00:00 2001 From: Yuri Astrakhan Date: Sat, 28 Sep 2024 13:17:29 -0400 Subject: [PATCH 378/683] suggest &str --- clippy_lints/src/functions/mod.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/functions/mod.rs b/clippy_lints/src/functions/mod.rs index 50b3d039ed3..203c3ce9eec 100644 --- a/clippy_lints/src/functions/mod.rs +++ b/clippy_lints/src/functions/mod.rs @@ -432,8 +432,10 @@ declare_clippy_lint! { /// ``` /// Use instead: /// ```no_run - /// // caller should use foo(opt.as_ref()) - /// fn foo(a: Option<&String>) {} + /// // caller should use `foo1(opt.as_ref())` + /// fn foo1(a: Option<&String>) {} + /// // better yet, use string slice `foo2(opt.as_deref())` + /// fn foo2(a: Option<&str>) {} /// # struct Unit {} /// # impl Unit { /// fn bar(&self) -> Option<&String> { None } From f14f72eb34243ea13b0c6a1750a999352abe47fe Mon Sep 17 00:00:00 2001 From: David Carlier Date: Thu, 26 Sep 2024 19:32:36 +0100 Subject: [PATCH 379/683] implements arc4random_buf shim for freebsd/solarish platforms. close #3914 --- src/tools/miri/src/shims/unix/foreign_items.rs | 14 ++++++++++++++ src/tools/miri/tests/pass-dep/libc/libc-random.rs | 13 +++++++++++++ 2 files changed, 27 insertions(+) diff --git a/src/tools/miri/src/shims/unix/foreign_items.rs b/src/tools/miri/src/shims/unix/foreign_items.rs index c06ce57e610..470f13442f9 100644 --- a/src/tools/miri/src/shims/unix/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/foreign_items.rs @@ -792,6 +792,20 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.gen_random(ptr, len)?; this.write_scalar(Scalar::from_target_usize(len, this), dest)?; } + "arc4random_buf" => { + // This function is non-standard but exists with the same signature and + // same behavior (eg never fails) on FreeBSD and Solaris/Illumos. + if !matches!(&*this.tcx.sess.target.os, "freebsd" | "illumos" | "solaris") { + throw_unsup_format!( + "`arc4random_buf` is not supported on {}", + this.tcx.sess.target.os + ); + } + let [ptr, len] = this.check_shim(abi, Abi::C { unwind: false}, link_name, args)?; + let ptr = this.read_pointer(ptr)?; + let len = this.read_target_usize(len)?; + this.gen_random(ptr, len)?; + } "_Unwind_RaiseException" => { // This is not formally part of POSIX, but it is very wide-spread on POSIX systems. // It was originally specified as part of the Itanium C++ ABI: diff --git a/src/tools/miri/tests/pass-dep/libc/libc-random.rs b/src/tools/miri/tests/pass-dep/libc/libc-random.rs index e951603639c..8f4398cbd8f 100644 --- a/src/tools/miri/tests/pass-dep/libc/libc-random.rs +++ b/src/tools/miri/tests/pass-dep/libc/libc-random.rs @@ -6,6 +6,8 @@ fn main() { test_getentropy(); #[cfg(not(target_os = "macos"))] test_getrandom(); + #[cfg(any(target_os = "freebsd", target_os = "illumos", target_os = "solaris"))] + test_arc4random_buf(); } fn test_getentropy() { @@ -61,3 +63,14 @@ fn test_getrandom() { ); } } + +#[cfg(any(target_os = "freebsd", target_os = "illumos", target_os = "solaris"))] +fn test_arc4random_buf() { + // FIXME: Use declaration from libc once lands. + extern "C" { + fn arc4random_buf(buf: *mut libc::c_void, size: libc::size_t); + } + let mut buf = [0u8; 5]; + unsafe { arc4random_buf(buf.as_mut_ptr() as _, buf.len()) }; + assert!(buf != [0u8; 5]); +} From 921a5ef6d7d2f965dab5b1f8b896dfe042db231b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 28 Sep 2024 21:15:18 +0200 Subject: [PATCH 380/683] try to get rid of mir::Const::normalize --- compiler/rustc_middle/src/mir/consts.rs | 12 ------------ compiler/rustc_mir_build/src/thir/cx/expr.rs | 6 ++---- compiler/rustc_mir_transform/src/jump_threading.rs | 4 +--- 3 files changed, 3 insertions(+), 19 deletions(-) diff --git a/compiler/rustc_middle/src/mir/consts.rs b/compiler/rustc_middle/src/mir/consts.rs index 89d4c460160..4e5d11831a4 100644 --- a/compiler/rustc_middle/src/mir/consts.rs +++ b/compiler/rustc_middle/src/mir/consts.rs @@ -329,18 +329,6 @@ impl<'tcx> Const<'tcx> { } } - /// Normalizes the constant to a value or an error if possible. - #[inline] - pub fn normalize(self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Self { - match self.eval(tcx, param_env, DUMMY_SP) { - Ok(val) => Self::Val(val, self.ty()), - Err(ErrorHandled::Reported(guar, _span)) => { - Self::Ty(Ty::new_error(tcx, guar.into()), ty::Const::new_error(tcx, guar.into())) - } - Err(ErrorHandled::TooGeneric(_span)) => self, - } - } - #[inline] pub fn try_eval_scalar( self, diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index fbd45f59a4f..f83c7852568 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -703,8 +703,7 @@ impl<'tcx> Cx<'tcx> { tcx, anon_const.def_id.to_def_id(), ) - .instantiate_identity() - .normalize(tcx, self.param_env); + .instantiate_identity(); let span = tcx.def_span(anon_const.def_id); InlineAsmOperand::Const { value, span } @@ -714,8 +713,7 @@ impl<'tcx> Cx<'tcx> { tcx, anon_const.def_id.to_def_id(), ) - .instantiate_identity() - .normalize(tcx, self.param_env); + .instantiate_identity(); let span = tcx.def_span(anon_const.def_id); InlineAsmOperand::SymFn { value, span } diff --git a/compiler/rustc_mir_transform/src/jump_threading.rs b/compiler/rustc_mir_transform/src/jump_threading.rs index 9d85b5ba5a7..91fbc91e1e7 100644 --- a/compiler/rustc_mir_transform/src/jump_threading.rs +++ b/compiler/rustc_mir_transform/src/jump_threading.rs @@ -516,9 +516,7 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> { // Avoid handling them, though this could be extended in the future. return; } - let Some(value) = - value.const_.normalize(self.tcx, self.param_env).try_to_scalar_int() - else { + let Some(value) = value.const_.try_eval_scalar_int(self.tcx, self.param_env) else { return; }; let conds = conditions.map(self.arena, |c| Condition { From c55c4c9f9de86034a942909d657e75ffb5674a73 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 28 Sep 2024 21:28:03 +0200 Subject: [PATCH 381/683] tweak Const::identity_unevaluated name and docs --- compiler/rustc_middle/src/mir/consts.rs | 4 +++- compiler/rustc_mir_build/src/thir/cx/expr.rs | 16 ++++++---------- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_middle/src/mir/consts.rs b/compiler/rustc_middle/src/mir/consts.rs index 4e5d11831a4..b34f5b48b78 100644 --- a/compiler/rustc_middle/src/mir/consts.rs +++ b/compiler/rustc_middle/src/mir/consts.rs @@ -221,7 +221,9 @@ pub enum Const<'tcx> { } impl<'tcx> Const<'tcx> { - pub fn identity_unevaluated( + /// Creates an unevaluated const from a `DefId` for a const item. + /// The binders of the const item still need to be instantiated. + pub fn from_unevaluated( tcx: TyCtxt<'tcx>, def_id: DefId, ) -> ty::EarlyBinder<'tcx, Const<'tcx>> { diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index f83c7852568..2ffad0b4834 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -699,21 +699,17 @@ impl<'tcx> Cx<'tcx> { } } hir::InlineAsmOperand::Const { ref anon_const } => { - let value = mir::Const::identity_unevaluated( - tcx, - anon_const.def_id.to_def_id(), - ) - .instantiate_identity(); + let value = + mir::Const::from_unevaluated(tcx, anon_const.def_id.to_def_id()) + .instantiate_identity(); let span = tcx.def_span(anon_const.def_id); InlineAsmOperand::Const { value, span } } hir::InlineAsmOperand::SymFn { ref anon_const } => { - let value = mir::Const::identity_unevaluated( - tcx, - anon_const.def_id.to_def_id(), - ) - .instantiate_identity(); + let value = + mir::Const::from_unevaluated(tcx, anon_const.def_id.to_def_id()) + .instantiate_identity(); let span = tcx.def_span(anon_const.def_id); InlineAsmOperand::SymFn { value, span } From 7cb5a799af4058306a989ee3d891abec2fbd5fc9 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 28 Sep 2024 21:05:30 +0200 Subject: [PATCH 382/683] make sure the new function is tested --- src/tools/miri/ci/ci.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/tools/miri/ci/ci.sh b/src/tools/miri/ci/ci.sh index 97f06dd9330..5725d6609cc 100755 --- a/src/tools/miri/ci/ci.sh +++ b/src/tools/miri/ci/ci.sh @@ -150,10 +150,10 @@ case $HOST_TARGET in # Partially supported targets (tier 2) BASIC="empty_main integer heap_alloc libc-mem vec string btreemap" # ensures we have the basics: pre-main code, system allocator UNIX="hello panic/panic panic/unwind concurrency/simple atomic libc-mem libc-misc libc-random env num_cpus" # the things that are very similar across all Unixes, and hence easily supported there - TEST_TARGET=x86_64-unknown-freebsd run_tests_minimal $BASIC $UNIX threadname pthread time fs - TEST_TARGET=i686-unknown-freebsd run_tests_minimal $BASIC $UNIX threadname pthread time fs - TEST_TARGET=x86_64-unknown-illumos run_tests_minimal $BASIC $UNIX thread sync available-parallelism time tls - TEST_TARGET=x86_64-pc-solaris run_tests_minimal $BASIC $UNIX thread sync available-parallelism time tls + TEST_TARGET=x86_64-unknown-freebsd run_tests_minimal $BASIC $UNIX hashmap random threadname pthread time fs + TEST_TARGET=i686-unknown-freebsd run_tests_minimal $BASIC $UNIX hashmap random threadname pthread time fs + TEST_TARGET=x86_64-unknown-illumos run_tests_minimal $BASIC $UNIX hashmap thread sync available-parallelism time tls + TEST_TARGET=x86_64-pc-solaris run_tests_minimal $BASIC $UNIX hashmap thread sync available-parallelism time tls TEST_TARGET=aarch64-linux-android run_tests_minimal $BASIC $UNIX hashmap pthread time --skip threadname TEST_TARGET=wasm32-wasip2 run_tests_minimal $BASIC wasm TEST_TARGET=wasm32-unknown-unknown run_tests_minimal no_std empty_main wasm # this target doesn't really have std From 37ea27c741f3d04c23033b0c7ec343584b3e7502 Mon Sep 17 00:00:00 2001 From: Urgau Date: Sat, 28 Sep 2024 21:44:44 +0200 Subject: [PATCH 383/683] compiletest: normalize to `$SRC_DIR_REAL` before `$TEST_BUILD_DIR` in case the real paths into the libstd/libcore are located inside the the build directory, maybe because it's coming from an extracted dist component in the build dir (cc opt-dist) --- src/tools/compiletest/src/runtest.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 922492e451f..456528da21a 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -2301,6 +2301,12 @@ impl<'test> TestCx<'test> { // eg. /home/user/rust/compiler normalize_path(&base_dir.join("compiler"), "$COMPILER_DIR"); + // Real paths into the libstd/libcore + let rust_src_dir = &self.config.sysroot_base.join("lib/rustlib/src/rust"); + rust_src_dir.try_exists().expect(&*format!("{} should exists", rust_src_dir.display())); + let rust_src_dir = rust_src_dir.read_link().unwrap_or(rust_src_dir.to_path_buf()); + normalize_path(&rust_src_dir.join("library"), "$SRC_DIR_REAL"); + // Paths into the build directory let test_build_dir = &self.config.build_base; let parent_build_dir = test_build_dir.parent().unwrap().parent().unwrap().parent().unwrap(); @@ -2310,12 +2316,6 @@ impl<'test> TestCx<'test> { // eg. /home/user/rust/build normalize_path(parent_build_dir, "$BUILD_DIR"); - // Real paths into the libstd/libcore - let rust_src_dir = &self.config.sysroot_base.join("lib/rustlib/src/rust"); - rust_src_dir.try_exists().expect(&*format!("{} should exists", rust_src_dir.display())); - let rust_src_dir = rust_src_dir.read_link().unwrap_or(rust_src_dir.to_path_buf()); - normalize_path(&rust_src_dir.join("library"), "$SRC_DIR_REAL"); - if json { // escaped newlines in json strings should be readable // in the stderr files. There's no point int being correct, From 3a6c6ee3d3a3ea3ddc60f450704c2f9d2421bc3c Mon Sep 17 00:00:00 2001 From: Urgau Date: Sat, 28 Sep 2024 21:50:23 +0200 Subject: [PATCH 384/683] remap-path-prefix-sysroot: remap {{src-base}} as well This is done to cover the path of the test it-self as it may not live on the same root directory as {{rust-src-base}}, which can be the case if {{rust-src-base}} is coming from a extracted dist build (cc opt-dist) --- tests/ui/errors/remap-path-prefix-sysroot.rs | 1 + tests/ui/errors/remap-path-prefix-sysroot.with-remap.stderr | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/ui/errors/remap-path-prefix-sysroot.rs b/tests/ui/errors/remap-path-prefix-sysroot.rs index 66cafbf43b6..4cbb38709be 100644 --- a/tests/ui/errors/remap-path-prefix-sysroot.rs +++ b/tests/ui/errors/remap-path-prefix-sysroot.rs @@ -1,6 +1,7 @@ //@ revisions: with-remap without-remap //@ compile-flags: -g -Ztranslate-remapped-path-to-local-path=yes //@ [with-remap]compile-flags: --remap-path-prefix={{rust-src-base}}=remapped +//@ [with-remap]compile-flags: --remap-path-prefix={{src-base}}=remapped-tests-ui //@ [without-remap]compile-flags: //@ error-pattern: E0507 diff --git a/tests/ui/errors/remap-path-prefix-sysroot.with-remap.stderr b/tests/ui/errors/remap-path-prefix-sysroot.with-remap.stderr index bdb882e2df5..88d713d2b04 100644 --- a/tests/ui/errors/remap-path-prefix-sysroot.with-remap.stderr +++ b/tests/ui/errors/remap-path-prefix-sysroot.with-remap.stderr @@ -1,5 +1,5 @@ error[E0507]: cannot move out of `self.thread` which is behind a mutable reference - --> remapped/tests/ui/errors/remap-path-prefix-sysroot.rs:LL:COL + --> remapped-tests-ui/errors/remap-path-prefix-sysroot.rs:LL:COL | LL | self.thread.join().unwrap(); | ^^^^^^^^^^^ ------ `self.thread` moved due to this method call From b3cf448761eb016a5c20470a757f0d5358e30e35 Mon Sep 17 00:00:00 2001 From: Samuel Moelius Date: Sat, 28 Sep 2024 16:30:31 -0400 Subject: [PATCH 385/683] Adjust comment --- clippy_lints/src/lifetimes.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/lifetimes.rs b/clippy_lints/src/lifetimes.rs index a4555e003c4..37d244ff53d 100644 --- a/clippy_lints/src/lifetimes.rs +++ b/clippy_lints/src/lifetimes.rs @@ -628,8 +628,8 @@ 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 `GenericArg` in a `WherePredicate`. (Note that a `GenericArg` is -// different from a `GenericParam`.) +// - That single use is not in `GenericArgs` in a `WherePredicate`. (Note that `GenericArgs` are +// different from `GenericParam`s.) fn report_elidable_impl_lifetimes<'tcx>( cx: &LateContext<'tcx>, impl_: &'tcx Impl<'_>, From 5ef63ec3b4cacfa21a3e7666e955cf1e7efa34d1 Mon Sep 17 00:00:00 2001 From: binarycat Date: Wed, 18 Sep 2024 18:15:42 -0400 Subject: [PATCH 386/683] rustdoc: add doc comment to DocVisitor --- src/librustdoc/visit.rs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/librustdoc/visit.rs b/src/librustdoc/visit.rs index fbc18176ed8..bfa285c57fa 100644 --- a/src/librustdoc/visit.rs +++ b/src/librustdoc/visit.rs @@ -1,11 +1,17 @@ use crate::clean::*; +/// Allows a type to traverse the cleaned ast of a crate. +/// +/// Note that like [`rustc_ast::visit::Visitor`], but +/// unlike [`rustc_lint::EarlyLintPass`], if you override a +/// `visit_*` method, you will need to manually recurse into +/// its contents. pub(crate) trait DocVisitor<'a>: Sized { fn visit_item(&mut self, item: &'a Item) { self.visit_item_recur(item) } - /// don't override! + /// Don't override! fn visit_inner_recur(&mut self, kind: &'a ItemKind) { match kind { StrippedItem(..) => unreachable!(), @@ -46,7 +52,7 @@ pub(crate) trait DocVisitor<'a>: Sized { } } - /// don't override! + /// Don't override! fn visit_item_recur(&mut self, item: &'a Item) { match &item.kind { StrippedItem(i) => self.visit_inner_recur(&*i), @@ -58,6 +64,7 @@ pub(crate) trait DocVisitor<'a>: Sized { m.items.iter().for_each(|i| self.visit_item(i)) } + /// This is the main entrypoint of [`DocVisitor`]. fn visit_crate(&mut self, c: &'a Crate) { self.visit_item(&c.module); From 2511cc1d153323712906ac318519220920920fba Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 27 Sep 2024 19:04:35 -0400 Subject: [PATCH 387/683] Enable `f16` tests on x86 Apple platforms These were disabled because Apple uses a special ABI for `f16`. `compiler-builtins` merged a fix for this in [1], which has since propagated to rust-lang/rust. Enable tests since there should be no remaining issues on these platforms. [1]: https://github.com/rust-lang/compiler-builtins/pull/675 --- library/std/build.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/library/std/build.rs b/library/std/build.rs index c5d0af469a8..5da470c6462 100644 --- a/library/std/build.rs +++ b/library/std/build.rs @@ -102,9 +102,6 @@ fn main() { ("arm64ec", _) => false, // MinGW ABI bugs ("x86_64", "windows") => false, - // Apple has a special ABI for `f16` that we do not yet support - // FIXME(builtins): fixed by - ("x86" | "x86_64", _) if target_vendor == "apple" => false, // Infinite recursion ("csky", _) => false, ("hexagon", _) => false, From f7d5d9d892ea8affb3e3fb4e30241300ba7b63f7 Mon Sep 17 00:00:00 2001 From: Yuri Astrakhan Date: Fri, 27 Sep 2024 23:48:00 -0400 Subject: [PATCH 388/683] Convert `&Option` to `Option<&T>` --- clippy_lints/src/cargo/common_metadata.rs | 16 ++-- clippy_lints/src/functions/mod.rs | 2 +- clippy_lints/src/unnested_or_patterns.rs | 11 ++- clippy_utils/src/ast_utils.rs | 109 +++++++++++++--------- clippy_utils/src/hir_utils.rs | 49 ++++++---- lintcheck/src/main.rs | 4 +- src/driver.rs | 14 +-- 7 files changed, 122 insertions(+), 83 deletions(-) diff --git a/clippy_lints/src/cargo/common_metadata.rs b/clippy_lints/src/cargo/common_metadata.rs index fed0aa8b275..6714c053913 100644 --- a/clippy_lints/src/cargo/common_metadata.rs +++ b/clippy_lints/src/cargo/common_metadata.rs @@ -10,27 +10,27 @@ pub(super) fn check(cx: &LateContext<'_>, metadata: &Metadata, ignore_publish: b // only run the lint if publish is `None` (`publish = true` or skipped entirely) // or if the vector isn't empty (`publish = ["something"]`) if package.publish.as_ref().filter(|publish| publish.is_empty()).is_none() || ignore_publish { - if is_empty_str(&package.description) { + if is_empty_str(package.description.as_ref()) { missing_warning(cx, package, "package.description"); } - if is_empty_str(&package.license) && is_empty_str(&package.license_file) { + if is_empty_str(package.license.as_ref()) && is_empty_str(package.license_file.as_ref()) { missing_warning(cx, package, "either package.license or package.license_file"); } - if is_empty_str(&package.repository) { + if is_empty_str(package.repository.as_ref()) { missing_warning(cx, package, "package.repository"); } - if is_empty_str(&package.readme) { + if is_empty_str(package.readme.as_ref()) { missing_warning(cx, package, "package.readme"); } - if is_empty_vec(&package.keywords) { + if is_empty_vec(package.keywords.as_ref()) { missing_warning(cx, package, "package.keywords"); } - if is_empty_vec(&package.categories) { + if is_empty_vec(package.categories.as_ref()) { missing_warning(cx, package, "package.categories"); } } @@ -42,8 +42,8 @@ fn missing_warning(cx: &LateContext<'_>, package: &cargo_metadata::Package, fiel span_lint(cx, CARGO_COMMON_METADATA, DUMMY_SP, message); } -fn is_empty_str>(value: &Option) -> bool { - value.as_ref().map_or(true, |s| s.as_ref().is_empty()) +fn is_empty_str>(value: Option<&T>) -> bool { + value.map_or(true, |s| s.as_ref().is_empty()) } fn is_empty_vec(value: &[String]) -> bool { diff --git a/clippy_lints/src/functions/mod.rs b/clippy_lints/src/functions/mod.rs index 203c3ce9eec..91d73c2a9c9 100644 --- a/clippy_lints/src/functions/mod.rs +++ b/clippy_lints/src/functions/mod.rs @@ -443,7 +443,7 @@ declare_clippy_lint! { /// ``` #[clippy::version = "1.82.0"] pub REF_OPTION, - nursery, + pedantic, "function signature uses `&Option` instead of `Option<&T>`" } diff --git a/clippy_lints/src/unnested_or_patterns.rs b/clippy_lints/src/unnested_or_patterns.rs index 104be63bb15..c7c837de505 100644 --- a/clippy_lints/src/unnested_or_patterns.rs +++ b/clippy_lints/src/unnested_or_patterns.rs @@ -275,12 +275,15 @@ fn transform_with_focus_on_idx(alternatives: &mut ThinVec>, focus_idx: us |k, ps1, idx| matches!( k, TupleStruct(qself2, path2, ps2) - if eq_maybe_qself(qself1, qself2) && eq_path(path1, path2) && eq_pre_post(ps1, ps2, idx) + if eq_maybe_qself(qself1.as_ref(), qself2.as_ref()) + && eq_path(path1, path2) && eq_pre_post(ps1, ps2, idx) ), |k| always_pat!(k, TupleStruct(_, _, ps) => ps), ), // Transform a record pattern `S { fp_0, ..., fp_n }`. - Struct(qself1, path1, fps1, rest1) => extend_with_struct_pat(qself1, path1, fps1, *rest1, start, alternatives), + Struct(qself1, path1, fps1, rest1) => { + extend_with_struct_pat(qself1.as_ref(), path1, fps1, *rest1, start, alternatives) + }, }; alternatives[focus_idx].kind = focus_kind; @@ -292,7 +295,7 @@ fn transform_with_focus_on_idx(alternatives: &mut ThinVec>, focus_idx: us /// So when we fixate on some `ident_k: pat_k`, we try to find `ident_k` in the other pattern /// and check that all `fp_i` where `i ∈ ((0...n) \ k)` between two patterns are equal. fn extend_with_struct_pat( - qself1: &Option>, + qself1: Option<&P>, path1: &ast::Path, fps1: &mut [ast::PatField], rest1: ast::PatFieldsRest, @@ -307,7 +310,7 @@ fn extend_with_struct_pat( |k| { matches!(k, Struct(qself2, path2, fps2, rest2) if rest1 == *rest2 // If one struct pattern has `..` so must the other. - && eq_maybe_qself(qself1, qself2) + && eq_maybe_qself(qself1, qself2.as_ref()) && eq_path(path1, path2) && fps1.len() == fps2.len() && fps1.iter().enumerate().all(|(idx_1, fp1)| { diff --git a/clippy_utils/src/ast_utils.rs b/clippy_utils/src/ast_utils.rs index 49323492e12..68f74e52ed7 100644 --- a/clippy_utils/src/ast_utils.rs +++ b/clippy_utils/src/ast_utils.rs @@ -37,20 +37,27 @@ pub fn eq_pat(l: &Pat, r: &Pat) -> bool { (_, Paren(r)) => eq_pat(l, r), (Wild, Wild) | (Rest, Rest) => true, (Lit(l), Lit(r)) => eq_expr(l, r), - (Ident(b1, i1, s1), Ident(b2, i2, s2)) => b1 == b2 && eq_id(*i1, *i2) && both(s1, s2, |l, r| eq_pat(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) + }, (Range(lf, lt, le), Range(rf, rt, re)) => { - eq_expr_opt(lf, rf) && eq_expr_opt(lt, rt) && eq_range_end(&le.node, &re.node) + eq_expr_opt(lf.as_ref(), rf.as_ref()) + && eq_expr_opt(lt.as_ref(), rt.as_ref()) + && eq_range_end(&le.node, &re.node) }, (Box(l), Box(r)) | (Ref(l, Mutability::Not), Ref(r, Mutability::Not)) | (Ref(l, Mutability::Mut), Ref(r, Mutability::Mut)) => eq_pat(l, r), (Tuple(l), Tuple(r)) | (Slice(l), Slice(r)) => over(l, r, |l, r| eq_pat(l, r)), - (Path(lq, lp), Path(rq, rp)) => both(lq, rq, eq_qself) && eq_path(lp, rp), + (Path(lq, lp), Path(rq, rp)) => both(lq.as_ref(), rq.as_ref(), eq_qself) && eq_path(lp, rp), (TupleStruct(lqself, lp, lfs), TupleStruct(rqself, rp, rfs)) => { - eq_maybe_qself(lqself, rqself) && eq_path(lp, rp) && over(lfs, rfs, |l, r| eq_pat(l, r)) + eq_maybe_qself(lqself.as_ref(), rqself.as_ref()) && eq_path(lp, rp) && over(lfs, rfs, |l, r| eq_pat(l, r)) }, (Struct(lqself, lp, lfs, lr), Struct(rqself, rp, rfs, rr)) => { - lr == rr && eq_maybe_qself(lqself, rqself) && eq_path(lp, rp) && unordered_over(lfs, rfs, eq_field_pat) + lr == rr + && eq_maybe_qself(lqself.as_ref(), rqself.as_ref()) + && eq_path(lp, rp) + && unordered_over(lfs, rfs, eq_field_pat) }, (Or(ls), Or(rs)) => unordered_over(ls, rs, |l, r| eq_pat(l, r)), (MacCall(l), MacCall(r)) => eq_mac_call(l, r), @@ -79,7 +86,7 @@ pub fn eq_qself(l: &P, r: &P) -> bool { l.position == r.position && eq_ty(&l.ty, &r.ty) } -pub fn eq_maybe_qself(l: &Option>, r: &Option>) -> bool { +pub fn eq_maybe_qself(l: Option<&P>, r: Option<&P>) -> bool { match (l, r) { (Some(l), Some(r)) => eq_qself(l, r), (None, None) => true, @@ -92,7 +99,7 @@ pub fn eq_path(l: &Path, r: &Path) -> bool { } pub fn eq_path_seg(l: &PathSegment, r: &PathSegment) -> bool { - eq_id(l.ident, r.ident) && both(&l.args, &r.args, |l, r| eq_generic_args(l, r)) + eq_id(l.ident, r.ident) && both(l.args.as_ref(), r.args.as_ref(), |l, r| eq_generic_args(l, r)) } pub fn eq_generic_args(l: &GenericArgs, r: &GenericArgs) -> bool { @@ -122,7 +129,7 @@ pub fn eq_generic_arg(l: &GenericArg, r: &GenericArg) -> bool { } } -pub fn eq_expr_opt(l: &Option>, r: &Option>) -> bool { +pub fn eq_expr_opt(l: Option<&P>, r: Option<&P>) -> bool { both(l, r, |l, r| eq_expr(l, r)) } @@ -169,8 +176,12 @@ pub fn eq_expr(l: &Expr, r: &Expr) -> bool { (Lit(l), Lit(r)) => l == r, (Cast(l, lt), Cast(r, rt)) | (Type(l, lt), Type(r, rt)) => eq_expr(l, r) && eq_ty(lt, rt), (Let(lp, le, _, _), Let(rp, re, _, _)) => eq_pat(lp, rp) && eq_expr(le, re), - (If(lc, lt, le), If(rc, rt, re)) => eq_expr(lc, rc) && eq_block(lt, rt) && eq_expr_opt(le, re), - (While(lc, lt, ll), While(rc, rt, rl)) => eq_label(ll, rl) && eq_expr(lc, rc) && eq_block(lt, rt), + (If(lc, lt, le), If(rc, rt, re)) => { + eq_expr(lc, rc) && eq_block(lt, rt) && eq_expr_opt(le.as_ref(), re.as_ref()) + }, + (While(lc, lt, ll), While(rc, rt, rl)) => { + eq_label(ll.as_ref(), rl.as_ref()) && eq_expr(lc, rc) && eq_block(lt, rt) + }, ( ForLoop { pat: lp, @@ -186,13 +197,13 @@ pub fn eq_expr(l: &Expr, r: &Expr) -> bool { label: rl, kind: rk, }, - ) => eq_label(ll, rl) && eq_pat(lp, rp) && eq_expr(li, ri) && eq_block(lt, rt) && lk == rk, - (Loop(lt, ll, _), Loop(rt, rl, _)) => eq_label(ll, rl) && eq_block(lt, rt), - (Block(lb, ll), Block(rb, rl)) => eq_label(ll, rl) && eq_block(lb, rb), + ) => eq_label(ll.as_ref(), rl.as_ref()) && eq_pat(lp, rp) && eq_expr(li, ri) && eq_block(lt, rt) && lk == rk, + (Loop(lt, ll, _), Loop(rt, rl, _)) => eq_label(ll.as_ref(), rl.as_ref()) && eq_block(lt, rt), + (Block(lb, ll), Block(rb, rl)) => eq_label(ll.as_ref(), rl.as_ref()) && eq_block(lb, rb), (TryBlock(l), TryBlock(r)) => eq_block(l, r), - (Yield(l), Yield(r)) | (Ret(l), Ret(r)) => eq_expr_opt(l, r), - (Break(ll, le), Break(rl, re)) => eq_label(ll, rl) && eq_expr_opt(le, re), - (Continue(ll), Continue(rl)) => eq_label(ll, rl), + (Yield(l), Yield(r)) | (Ret(l), Ret(r)) => eq_expr_opt(l.as_ref(), r.as_ref()), + (Break(ll, le), Break(rl, re)) => eq_label(ll.as_ref(), rl.as_ref()) && eq_expr_opt(le.as_ref(), re.as_ref()), + (Continue(ll), Continue(rl)) => eq_label(ll.as_ref(), rl.as_ref()), (Assign(l1, l2, _), Assign(r1, r2, _)) | (Index(l1, l2, _), Index(r1, r2, _)) => { eq_expr(l1, r1) && eq_expr(l2, r2) }, @@ -227,12 +238,14 @@ pub fn eq_expr(l: &Expr, r: &Expr) -> bool { && eq_expr(le, re) }, (Gen(lc, lb, lk, _), Gen(rc, rb, rk, _)) => lc == rc && eq_block(lb, rb) && lk == rk, - (Range(lf, lt, ll), Range(rf, rt, rl)) => ll == rl && eq_expr_opt(lf, rf) && eq_expr_opt(lt, rt), + (Range(lf, lt, ll), Range(rf, rt, rl)) => { + ll == rl && eq_expr_opt(lf.as_ref(), rf.as_ref()) && eq_expr_opt(lt.as_ref(), rt.as_ref()) + }, (AddrOf(lbk, lm, le), AddrOf(rbk, rm, re)) => lbk == rbk && lm == rm && eq_expr(le, re), - (Path(lq, lp), Path(rq, rp)) => both(lq, rq, eq_qself) && eq_path(lp, rp), + (Path(lq, lp), Path(rq, rp)) => both(lq.as_ref(), rq.as_ref(), eq_qself) && eq_path(lp, rp), (MacCall(l), MacCall(r)) => eq_mac_call(l, r), (Struct(lse), Struct(rse)) => { - eq_maybe_qself(&lse.qself, &rse.qself) + eq_maybe_qself(lse.qself.as_ref(), rse.qself.as_ref()) && eq_path(&lse.path, &rse.path) && eq_struct_rest(&lse.rest, &rse.rest) && unordered_over(&lse.fields, &rse.fields, eq_field) @@ -264,12 +277,12 @@ pub fn eq_field(l: &ExprField, r: &ExprField) -> bool { pub fn eq_arm(l: &Arm, r: &Arm) -> bool { l.is_placeholder == r.is_placeholder && eq_pat(&l.pat, &r.pat) - && eq_expr_opt(&l.body, &r.body) - && eq_expr_opt(&l.guard, &r.guard) + && eq_expr_opt(l.body.as_ref(), r.body.as_ref()) + && eq_expr_opt(l.guard.as_ref(), r.guard.as_ref()) && over(&l.attrs, &r.attrs, eq_attr) } -pub fn eq_label(l: &Option

    ` (where P is one of the previous types except `Self`) + error[E0038]: the trait `Foo` cannot be made into an object --> $DIR/inference_var_self_argument.rs:5:5 | @@ -13,15 +22,6 @@ LL | async fn foo(self: &dyn Foo) { | ^^^ ...because method `foo` is `async` = help: consider moving `foo` to another trait -error[E0307]: invalid `self` parameter type: `&dyn Foo` - --> $DIR/inference_var_self_argument.rs:5:24 - | -LL | async fn foo(self: &dyn Foo) { - | ^^^^^^^^ - | - = note: type of `self` must be `Self` or a type that dereferences to it - = help: consider changing to `self`, `&self`, `&mut self`, `self: Box`, `self: Rc`, `self: Arc`, or `self: Pin

    ` (where P is one of the previous types except `Self`) - error: aborting due to 2 previous errors Some errors have detailed explanations: E0038, E0307. diff --git a/tests/ui/async-await/issue-66312.stderr b/tests/ui/async-await/issue-66312.stderr index 702e0b375e5..c95ae1147df 100644 --- a/tests/ui/async-await/issue-66312.stderr +++ b/tests/ui/async-await/issue-66312.stderr @@ -1,9 +1,3 @@ -error[E0308]: mismatched types - --> $DIR/issue-66312.rs:9:8 - | -LL | if x.is_some() { - | ^^^^^^^^^^^ expected `bool`, found `()` - error[E0307]: invalid `self` parameter type: `T` --> $DIR/issue-66312.rs:4:22 | @@ -13,6 +7,12 @@ LL | fn is_some(self: T); = note: type of `self` must be `Self` or a type that dereferences to it = help: consider changing to `self`, `&self`, `&mut self`, `self: Box`, `self: Rc`, `self: Arc`, or `self: Pin

    ` (where P is one of the previous types except `Self`) +error[E0308]: mismatched types + --> $DIR/issue-66312.rs:9:8 + | +LL | if x.is_some() { + | ^^^^^^^^^^^ expected `bool`, found `()` + error: aborting due to 2 previous errors Some errors have detailed explanations: E0307, E0308. diff --git a/tests/ui/const-generics/opaque_types.stderr b/tests/ui/const-generics/opaque_types.stderr index 847f1da16f6..a060488b328 100644 --- a/tests/ui/const-generics/opaque_types.stderr +++ b/tests/ui/const-generics/opaque_types.stderr @@ -1,3 +1,11 @@ +error: `Foo` is forbidden as the type of a const generic parameter + --> $DIR/opaque_types.rs:7:17 + | +LL | fn foo() {} + | ^^^ + | + = note: the only supported types are integers, `bool`, and `char` + error: item does not constrain `Foo::{opaque#0}`, but has it in its signature --> $DIR/opaque_types.rs:7:4 | @@ -68,14 +76,6 @@ LL | type Foo = impl Sized; | ^^^^^^^^^^ = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information -error: `Foo` is forbidden as the type of a const generic parameter - --> $DIR/opaque_types.rs:7:17 - | -LL | fn foo() {} - | ^^^ - | - = note: the only supported types are integers, `bool`, and `char` - error[E0391]: cycle detected when computing type of opaque `Foo::{opaque#0}` --> $DIR/opaque_types.rs:3:12 | diff --git a/tests/ui/delegation/unsupported.stderr b/tests/ui/delegation/unsupported.stderr index 03ded300bb4..6a627be3b64 100644 --- a/tests/ui/delegation/unsupported.stderr +++ b/tests/ui/delegation/unsupported.stderr @@ -3,22 +3,6 @@ error: using `#![feature(effects)]` without enabling next trait solver globally = note: the next trait solver must be enabled globally for the effects feature to work correctly = help: use `-Znext-solver` to enable -warning: this function depends on never type fallback being `()` - --> $DIR/unsupported.rs:20:9 - | -LL | fn opaque_ret() -> impl Trait { unimplemented!() } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #123748 - = help: specify the types explicitly -note: in edition 2024, the requirement `!: opaque::Trait` will fail - --> $DIR/unsupported.rs:20:28 - | -LL | fn opaque_ret() -> impl Trait { unimplemented!() } - | ^^^^^^^^^^ - = note: `#[warn(dependency_on_unit_never_type_fallback)]` on by default - error[E0391]: cycle detected when computing type of `opaque::::{synthetic#0}` --> $DIR/unsupported.rs:27:25 | @@ -52,6 +36,22 @@ note: in edition 2024, the requirement `!: opaque::Trait` will fail | LL | pub fn opaque_ret() -> impl Trait { unimplemented!() } | ^^^^^^^^^^ + = note: `#[warn(dependency_on_unit_never_type_fallback)]` on by default + +warning: this function depends on never type fallback being `()` + --> $DIR/unsupported.rs:20:9 + | +LL | fn opaque_ret() -> impl Trait { unimplemented!() } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #123748 + = help: specify the types explicitly +note: in edition 2024, the requirement `!: opaque::Trait` will fail + --> $DIR/unsupported.rs:20:28 + | +LL | fn opaque_ret() -> impl Trait { unimplemented!() } + | ^^^^^^^^^^ error[E0391]: cycle detected when computing type of `opaque::::{synthetic#0}` --> $DIR/unsupported.rs:30:24 diff --git a/tests/ui/feature-gates/feature-gate-impl_trait_in_assoc_type.stderr b/tests/ui/feature-gates/feature-gate-impl_trait_in_assoc_type.stderr index d8a85c8838d..7dfd79c7286 100644 --- a/tests/ui/feature-gates/feature-gate-impl_trait_in_assoc_type.stderr +++ b/tests/ui/feature-gates/feature-gate-impl_trait_in_assoc_type.stderr @@ -18,14 +18,6 @@ LL | type Bop = impl std::fmt::Debug; = help: add `#![feature(impl_trait_in_assoc_type)]` 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: unconstrained opaque type - --> $DIR/feature-gate-impl_trait_in_assoc_type.rs:6:16 - | -LL | type Bar = impl std::fmt::Debug; - | ^^^^^^^^^^^^^^^^^^^^ - | - = note: `Bar` must be used in combination with a concrete type within the same impl - error[E0658]: inherent associated types are unstable --> $DIR/feature-gate-impl_trait_in_assoc_type.rs:14:5 | @@ -36,6 +28,14 @@ LL | type Bop = impl std::fmt::Debug; = help: add `#![feature(inherent_associated_types)]` 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: unconstrained opaque type + --> $DIR/feature-gate-impl_trait_in_assoc_type.rs:6:16 + | +LL | type Bar = impl std::fmt::Debug; + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: `Bar` must be used in combination with a concrete type within the same impl + error: unconstrained opaque type --> $DIR/feature-gate-impl_trait_in_assoc_type.rs:14:16 | diff --git a/tests/ui/impl-trait/impl-fn-predefined-lifetimes.stderr b/tests/ui/impl-trait/impl-fn-predefined-lifetimes.stderr index 50a9f3ebeab..91550f0e284 100644 --- a/tests/ui/impl-trait/impl-fn-predefined-lifetimes.stderr +++ b/tests/ui/impl-trait/impl-fn-predefined-lifetimes.stderr @@ -19,7 +19,10 @@ error[E0720]: cannot resolve opaque type --> $DIR/impl-fn-predefined-lifetimes.rs:4:35 | LL | fn a<'a>() -> impl Fn(&'a u8) -> (impl Debug + '_) { - | ^^^^^^^^^^^^^^^ cannot resolve opaque type + | ^^^^^^^^^^^^^^^ recursive opaque type +... +LL | |x| x + | ----- returning here with type `{closure@$DIR/impl-fn-predefined-lifetimes.rs:7:5: 7:8}` error: aborting due to 2 previous errors; 1 warning emitted diff --git a/tests/ui/impl-trait/issues/issue-78722-2.stderr b/tests/ui/impl-trait/issues/issue-78722-2.stderr index dc5579c1c82..2cf6b94dd9d 100644 --- a/tests/ui/impl-trait/issues/issue-78722-2.stderr +++ b/tests/ui/impl-trait/issues/issue-78722-2.stderr @@ -1,9 +1,3 @@ -error[E0271]: expected `{async block@$DIR/issue-78722-2.rs:13:13: 13:18}` to be a future that resolves to `u8`, but it resolves to `()` - --> $DIR/issue-78722-2.rs:11:30 - | -LL | fn concrete_use() -> F { - | ^ expected `()`, found `u8` - error[E0308]: mismatched types --> $DIR/issue-78722-2.rs:16:20 | @@ -18,6 +12,12 @@ LL | let f: F = async { 1 }; = note: expected opaque type `F` found `async` block `{async block@$DIR/issue-78722-2.rs:16:20: 16:25}` +error[E0271]: expected `{async block@$DIR/issue-78722-2.rs:13:13: 13:18}` to be a future that resolves to `u8`, but it resolves to `()` + --> $DIR/issue-78722-2.rs:11:30 + | +LL | fn concrete_use() -> F { + | ^ expected `()`, found `u8` + error: aborting due to 2 previous errors Some errors have detailed explanations: E0271, E0308. diff --git a/tests/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle.stderr b/tests/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle.stderr index 3692cc77b0f..6485aa20710 100644 --- a/tests/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle.stderr +++ b/tests/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle.stderr @@ -1,24 +1,3 @@ -error: item does not constrain `a::Foo::{opaque#0}`, but has it in its signature - --> $DIR/recursive-type-alias-impl-trait-declaration-too-subtle.rs:10:12 - | -LL | fn eq(&self, _other: &(Foo, i32)) -> bool { - | ^^ - | - = note: consider moving the opaque type's declaration and defining uses into a separate module -note: this opaque type is in the signature - --> $DIR/recursive-type-alias-impl-trait-declaration-too-subtle.rs:4:16 - | -LL | type Foo = impl PartialEq<(Foo, i32)>; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: unconstrained opaque type - --> $DIR/recursive-type-alias-impl-trait-declaration-too-subtle.rs:4:16 - | -LL | type Foo = impl PartialEq<(Foo, i32)>; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: `Foo` must be used in combination with a concrete type within the same module - error[E0053]: method `eq` has an incompatible type for trait --> $DIR/recursive-type-alias-impl-trait-declaration-too-subtle.rs:10:30 | @@ -35,8 +14,21 @@ help: change the parameter type to match the trait LL | fn eq(&self, _other: &(a::Bar, i32)) -> bool { | ~~~~~~~~~~~~~~ +error: item does not constrain `a::Foo::{opaque#0}`, but has it in its signature + --> $DIR/recursive-type-alias-impl-trait-declaration-too-subtle.rs:10:12 + | +LL | fn eq(&self, _other: &(Foo, i32)) -> bool { + | ^^ + | + = note: consider moving the opaque type's declaration and defining uses into a separate module +note: this opaque type is in the signature + --> $DIR/recursive-type-alias-impl-trait-declaration-too-subtle.rs:4:16 + | +LL | type Foo = impl PartialEq<(Foo, i32)>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + error: unconstrained opaque type - --> $DIR/recursive-type-alias-impl-trait-declaration-too-subtle.rs:19:16 + --> $DIR/recursive-type-alias-impl-trait-declaration-too-subtle.rs:4:16 | LL | type Foo = impl PartialEq<(Foo, i32)>; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -64,6 +56,14 @@ help: change the parameter type to match the trait LL | fn eq(&self, _other: &(b::Foo, i32)) -> bool { | ~~~~~~~~~~~~~~ +error: unconstrained opaque type + --> $DIR/recursive-type-alias-impl-trait-declaration-too-subtle.rs:19:16 + | +LL | type Foo = impl PartialEq<(Foo, i32)>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `Foo` must be used in combination with a concrete type within the same module + error: aborting due to 5 previous errors For more information about this error, try `rustc --explain E0053`. diff --git a/tests/ui/impl-trait/where-allowed.stderr b/tests/ui/impl-trait/where-allowed.stderr index 2770a6cc40e..13f50fcea7b 100644 --- a/tests/ui/impl-trait/where-allowed.stderr +++ b/tests/ui/impl-trait/where-allowed.stderr @@ -342,44 +342,6 @@ LL | let _in_return_in_local_variable = || -> impl Fn() { || {} }; | = note: `impl Trait` is only allowed in arguments and return types of functions and methods -error[E0283]: type annotations needed - --> $DIR/where-allowed.rs:46:57 - | -LL | fn in_dyn_Fn_return_in_return() -> &'static dyn Fn() -> impl Debug { panic!() } - | ^^^^^^^^^^ cannot infer type - | - = note: cannot satisfy `_: Debug` - -error[E0283]: type annotations needed - --> $DIR/where-allowed.rs:64:46 - | -LL | fn in_impl_Fn_return_in_return() -> &'static impl Fn() -> impl Debug { panic!() } - | ^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type - | - = note: multiple `impl`s satisfying `_: Fn()` found in the following crates: `alloc`, `core`: - - impl Fn for &F - where A: Tuple, F: Fn, F: ?Sized; - - impl Fn for Box - where Args: Tuple, F: Fn, A: Allocator, F: ?Sized; - -error: defaults for type parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions - --> $DIR/where-allowed.rs:238:7 - | -LL | impl T {} - | ^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #36887 - = note: `#[deny(invalid_type_param_default)]` on by default - -error[E0118]: no nominal type found for inherent implementation - --> $DIR/where-allowed.rs:238:1 - | -LL | impl T {} - | ^^^^^^^^^^^^^^^^^^^^^^^ impl requires a nominal type - | - = note: either implement a trait on it or create a newtype to wrap it instead - error[E0053]: method `in_trait_impl_return` has an incompatible type for trait --> $DIR/where-allowed.rs:128:34 | @@ -402,14 +364,6 @@ help: change the output type to match the trait LL | fn in_trait_impl_return() -> <() as DummyTrait>::Out { () } | ~~~~~~~~~~~~~~~~~~~~~~~ -error: unconstrained opaque type - --> $DIR/where-allowed.rs:121:16 - | -LL | type Out = impl Debug; - | ^^^^^^^^^^ - | - = note: `Out` must be used in combination with a concrete type within the same impl - error: defaults for type parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions --> $DIR/where-allowed.rs:245:36 | @@ -418,12 +372,69 @@ LL | fn in_method_generic_param_default(_: T) {} | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #36887 + = note: `#[deny(invalid_type_param_default)]` on by default + +error: defaults for type parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions + --> $DIR/where-allowed.rs:238:7 + | +LL | impl T {} + | ^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #36887 + +error[E0283]: type annotations needed + --> $DIR/where-allowed.rs:46:57 + | +LL | fn in_dyn_Fn_return_in_return() -> &'static dyn Fn() -> impl Debug { panic!() } + | ^^^^^^^^^^ cannot infer type + | + = note: cannot satisfy `_: Debug` + +error[E0283]: type annotations needed + --> $DIR/where-allowed.rs:64:46 + | +LL | fn in_impl_Fn_return_in_return() -> &'static impl Fn() -> impl Debug { panic!() } + | ^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type + | + = note: multiple `impl`s satisfying `_: Fn()` found in the following crates: `alloc`, `core`: + - impl Fn for &F + where A: Tuple, F: Fn, F: ?Sized; + - impl Fn for Box + where Args: Tuple, F: Fn, A: Allocator, F: ?Sized; + +error[E0118]: no nominal type found for inherent implementation + --> $DIR/where-allowed.rs:238:1 + | +LL | impl T {} + | ^^^^^^^^^^^^^^^^^^^^^^^ impl requires a nominal type + | + = note: either implement a trait on it or create a newtype to wrap it instead + +error: unconstrained opaque type + --> $DIR/where-allowed.rs:121:16 + | +LL | type Out = impl Debug; + | ^^^^^^^^^^ + | + = note: `Out` must be used in combination with a concrete type within the same impl error: aborting due to 49 previous errors Some errors have detailed explanations: E0053, E0118, E0283, E0562, E0658, E0666. For more information about an error, try `rustc --explain E0053`. Future incompatibility report: Future breakage diagnostic: +error: defaults for type parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions + --> $DIR/where-allowed.rs:245:36 + | +LL | fn in_method_generic_param_default(_: T) {} + | ^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #36887 + = note: `#[deny(invalid_type_param_default)]` on by default + +Future breakage diagnostic: error: defaults for type parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions --> $DIR/where-allowed.rs:238:7 | @@ -434,14 +445,3 @@ LL | impl T {} = note: for more information, see issue #36887 = note: `#[deny(invalid_type_param_default)]` on by default -Future breakage diagnostic: -error: defaults for type parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions - --> $DIR/where-allowed.rs:245:36 - | -LL | fn in_method_generic_param_default(_: T) {} - | ^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #36887 - = note: `#[deny(invalid_type_param_default)]` on by default - diff --git a/tests/ui/privacy/private-type-in-interface.rs b/tests/ui/privacy/private-type-in-interface.rs index 2e8be28d76e..9eadd09867d 100644 --- a/tests/ui/privacy/private-type-in-interface.rs +++ b/tests/ui/privacy/private-type-in-interface.rs @@ -26,7 +26,5 @@ type A = ::X; //~ ERROR type `Priv` is private trait Tr2 {} impl Tr2 for u8 {} fn g() -> impl Tr2 { 0 } //~ ERROR type `Priv` is private - //~| ERROR type `Priv` is private fn g_ext() -> impl Tr2 { 0 } //~ ERROR type `ext::Priv` is private - //~| ERROR type `ext::Priv` is private fn main() {} diff --git a/tests/ui/privacy/private-type-in-interface.stderr b/tests/ui/privacy/private-type-in-interface.stderr index 091cae42dea..03225d84fdb 100644 --- a/tests/ui/privacy/private-type-in-interface.stderr +++ b/tests/ui/privacy/private-type-in-interface.stderr @@ -46,23 +46,11 @@ error: type `Priv` is private LL | fn g() -> impl Tr2 { 0 } | ^^^^^^^^^^^^^^^^^^ private type -error: type `Priv` is private - --> $DIR/private-type-in-interface.rs:28:11 - | -LL | fn g() -> impl Tr2 { 0 } - | ^^^^^^^^^^^^^^^^^^ private type - error: type `ext::Priv` is private - --> $DIR/private-type-in-interface.rs:30:15 + --> $DIR/private-type-in-interface.rs:29:15 | LL | fn g_ext() -> impl Tr2 { 0 } | ^^^^^^^^^^^^^^^^^^^^ private type -error: type `ext::Priv` is private - --> $DIR/private-type-in-interface.rs:30:15 - | -LL | fn g_ext() -> impl Tr2 { 0 } - | ^^^^^^^^^^^^^^^^^^^^ private type - -error: aborting due to 11 previous errors +error: aborting due to 9 previous errors diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-impl-trait.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-impl-trait.stderr index b59c6d1eed8..1040af7541c 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-impl-trait.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-impl-trait.stderr @@ -67,38 +67,6 @@ error: `~const` can only be applied to `#[const_trait]` traits LL | fn huh() -> impl ~const PartialEq + ~const Destruct + Copy; | ^^^^^^^^ -error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/const-impl-trait.rs:25:29 - | -LL | fn huh() -> impl ~const PartialEq + ~const Destruct + Copy; - | ^^^^^^^^^ - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/const-impl-trait.rs:25:48 - | -LL | fn huh() -> impl ~const PartialEq + ~const Destruct + Copy; - | ^^^^^^^^ - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/const-impl-trait.rs:25:29 - | -LL | fn huh() -> impl ~const PartialEq + ~const Destruct + Copy; - | ^^^^^^^^^ - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/const-impl-trait.rs:25:48 - | -LL | fn huh() -> impl ~const PartialEq + ~const Destruct + Copy; - | ^^^^^^^^ - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/const-impl-trait.rs:29:29 | @@ -155,6 +123,38 @@ LL | fn huh() -> impl ~const PartialEq + ~const Destruct + Copy; | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/const-impl-trait.rs:25:29 + | +LL | fn huh() -> impl ~const PartialEq + ~const Destruct + Copy; + | ^^^^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/const-impl-trait.rs:25:48 + | +LL | fn huh() -> impl ~const PartialEq + ~const Destruct + Copy; + | ^^^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/const-impl-trait.rs:25:29 + | +LL | fn huh() -> impl ~const PartialEq + ~const Destruct + Copy; + | ^^^^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/const-impl-trait.rs:25:48 + | +LL | fn huh() -> impl ~const PartialEq + ~const Destruct + Copy; + | ^^^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + error[E0493]: destructor of `impl PartialEq + Destruct` cannot be evaluated at compile-time --> $DIR/const-impl-trait.rs:37:26 | diff --git a/tests/ui/self/arbitrary-self-opaque.stderr b/tests/ui/self/arbitrary-self-opaque.stderr index 5ccc076bfaf..5634b3d6e64 100644 --- a/tests/ui/self/arbitrary-self-opaque.stderr +++ b/tests/ui/self/arbitrary-self-opaque.stderr @@ -1,3 +1,12 @@ +error[E0307]: invalid `self` parameter type: `Bar` + --> $DIR/arbitrary-self-opaque.rs:8:18 + | +LL | fn foo(self: Bar) {} + | ^^^ + | + = note: type of `self` must be `Self` or a type that dereferences to it + = help: consider changing to `self`, `&self`, `&mut self`, `self: Box`, `self: Rc`, `self: Arc`, or `self: Pin

    ` (where P is one of the previous types except `Self`) + error: item does not constrain `Bar::{opaque#0}`, but has it in its signature --> $DIR/arbitrary-self-opaque.rs:8:8 | @@ -19,15 +28,6 @@ LL | type Bar = impl Sized; | = note: `Bar` must be used in combination with a concrete type within the same module -error[E0307]: invalid `self` parameter type: `Bar` - --> $DIR/arbitrary-self-opaque.rs:8:18 - | -LL | fn foo(self: Bar) {} - | ^^^ - | - = note: type of `self` must be `Self` or a type that dereferences to it - = help: consider changing to `self`, `&self`, `&mut self`, `self: Box`, `self: Rc`, `self: Arc`, or `self: Pin

    ` (where P is one of the previous types except `Self`) - error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0307`. diff --git a/tests/ui/self/arbitrary_self_types_pin_lifetime_mismatch-async.stderr b/tests/ui/self/arbitrary_self_types_pin_lifetime_mismatch-async.stderr index b00260fa0ef..f3393830eeb 100644 --- a/tests/ui/self/arbitrary_self_types_pin_lifetime_mismatch-async.stderr +++ b/tests/ui/self/arbitrary_self_types_pin_lifetime_mismatch-async.stderr @@ -9,8 +9,8 @@ LL | async fn a(self: Pin<&Foo>, f: &Foo) -> &Foo { f } | help: consider introducing a named lifetime parameter and update trait if needed | -LL | async fn a<'a>(self: Pin<&'a Foo>, f: &'a Foo) -> &Foo { f } - | ++++ ++ ++ +LL | async fn a<'a>(self: Pin<&Foo>, f: &'a Foo) -> &'a Foo { f } + | ++++ ++ ++ error: lifetime may not live long enough --> $DIR/arbitrary_self_types_pin_lifetime_mismatch-async.rs:11:75 @@ -23,8 +23,8 @@ LL | async fn c(self: Pin<&Self>, f: &Foo, g: &Foo) -> (Pin<&Foo>, &Foo) { ( | help: consider introducing a named lifetime parameter and update trait if needed | -LL | async fn c<'a>(self: Pin<&'a Self>, f: &'a Foo, g: &Foo) -> (Pin<&Foo>, &Foo) { (self, f) } - | ++++ ++ ++ +LL | async fn c<'a>(self: Pin<&Self>, f: &'a Foo, g: &Foo) -> (Pin<&'a Foo>, &'a Foo) { (self, f) } + | ++++ ++ ++ ++ error: lifetime may not live long enough --> $DIR/arbitrary_self_types_pin_lifetime_mismatch-async.rs:17:64 @@ -37,8 +37,8 @@ LL | async fn bar<'a>(self: Alias<&Self>, arg: &'a ()) -> &() { arg } | help: consider reusing a named lifetime parameter and update trait if needed | -LL | async fn bar<'a>(self: Alias<&'a Self>, arg: &'a ()) -> &() { arg } - | ++ +LL | async fn bar<'a>(self: Alias<&Self>, arg: &'a ()) -> &'a () { arg } + | ++ error: aborting due to 3 previous errors diff --git a/tests/ui/self/elision/lt-ref-self-async.fixed b/tests/ui/self/elision/lt-ref-self-async.fixed index 914511641b8..aae94f7a6cc 100644 --- a/tests/ui/self/elision/lt-ref-self-async.fixed +++ b/tests/ui/self/elision/lt-ref-self-async.fixed @@ -11,34 +11,34 @@ struct Struct<'a> { impl<'a> Struct<'a> { // Test using `&self` sugar: - async fn ref_self<'b>(&'b self, f: &'b u32) -> &u32 { + async fn ref_self<'b>(&self, f: &'b u32) -> &'b u32 { f //~^ ERROR lifetime may not live long enough } // Test using `&Self` explicitly: - async fn ref_Self<'b>(self: &'b Self, f: &'b u32) -> &u32 { + async fn ref_Self<'b>(self: &Self, f: &'b u32) -> &'b u32 { f //~^ ERROR lifetime may not live long enough } - async fn box_ref_Self<'b>(self: Box<&'b Self>, f: &'b u32) -> &u32 { + async fn box_ref_Self<'b>(self: Box<&Self>, f: &'b u32) -> &'b u32 { f //~^ ERROR lifetime may not live long enough } - async fn pin_ref_Self<'b>(self: Pin<&'b Self>, f: &'b u32) -> &u32 { + async fn pin_ref_Self<'b>(self: Pin<&Self>, f: &'b u32) -> &'b u32 { f //~^ ERROR lifetime may not live long enough } - async fn box_box_ref_Self<'b>(self: Box>, f: &'b u32) -> &u32 { + async fn box_box_ref_Self<'b>(self: Box>, f: &'b u32) -> &'b u32 { f //~^ ERROR lifetime may not live long enough } - async fn box_pin_Self<'b>(self: Box>, f: &'b u32) -> &u32 { + async fn box_pin_Self<'b>(self: Box>, f: &'b u32) -> &'b u32 { f //~^ ERROR lifetime may not live long enough } diff --git a/tests/ui/self/elision/lt-ref-self-async.stderr b/tests/ui/self/elision/lt-ref-self-async.stderr index b84044f7548..c43ff49d508 100644 --- a/tests/ui/self/elision/lt-ref-self-async.stderr +++ b/tests/ui/self/elision/lt-ref-self-async.stderr @@ -10,8 +10,8 @@ LL | f | help: consider introducing a named lifetime parameter and update trait if needed | -LL | async fn ref_self<'b>(&'b self, f: &'b u32) -> &u32 { - | ++++ ++ ++ +LL | async fn ref_self<'b>(&self, f: &'b u32) -> &'b u32 { + | ++++ ++ ++ error: lifetime may not live long enough --> $DIR/lt-ref-self-async.rs:22:9 @@ -25,8 +25,8 @@ LL | f | help: consider introducing a named lifetime parameter and update trait if needed | -LL | async fn ref_Self<'b>(self: &'b Self, f: &'b u32) -> &u32 { - | ++++ ++ ++ +LL | async fn ref_Self<'b>(self: &Self, f: &'b u32) -> &'b u32 { + | ++++ ++ ++ error: lifetime may not live long enough --> $DIR/lt-ref-self-async.rs:27:9 @@ -40,8 +40,8 @@ LL | f | help: consider introducing a named lifetime parameter and update trait if needed | -LL | async fn box_ref_Self<'b>(self: Box<&'b Self>, f: &'b u32) -> &u32 { - | ++++ ++ ++ +LL | async fn box_ref_Self<'b>(self: Box<&Self>, f: &'b u32) -> &'b u32 { + | ++++ ++ ++ error: lifetime may not live long enough --> $DIR/lt-ref-self-async.rs:32:9 @@ -55,8 +55,8 @@ LL | f | help: consider introducing a named lifetime parameter and update trait if needed | -LL | async fn pin_ref_Self<'b>(self: Pin<&'b Self>, f: &'b u32) -> &u32 { - | ++++ ++ ++ +LL | async fn pin_ref_Self<'b>(self: Pin<&Self>, f: &'b u32) -> &'b u32 { + | ++++ ++ ++ error: lifetime may not live long enough --> $DIR/lt-ref-self-async.rs:37:9 @@ -70,8 +70,8 @@ LL | f | help: consider introducing a named lifetime parameter and update trait if needed | -LL | async fn box_box_ref_Self<'b>(self: Box>, f: &'b u32) -> &u32 { - | ++++ ++ ++ +LL | async fn box_box_ref_Self<'b>(self: Box>, f: &'b u32) -> &'b u32 { + | ++++ ++ ++ error: lifetime may not live long enough --> $DIR/lt-ref-self-async.rs:42:9 @@ -85,8 +85,8 @@ LL | f | help: consider introducing a named lifetime parameter and update trait if needed | -LL | async fn box_pin_Self<'b>(self: Box>, f: &'b u32) -> &u32 { - | ++++ ++ ++ +LL | async fn box_pin_Self<'b>(self: Box>, f: &'b u32) -> &'b u32 { + | ++++ ++ ++ error: aborting due to 6 previous errors diff --git a/tests/ui/self/elision/ref-assoc-async.stderr b/tests/ui/self/elision/ref-assoc-async.stderr index cf54a86b45f..9f2768d5e69 100644 --- a/tests/ui/self/elision/ref-assoc-async.stderr +++ b/tests/ui/self/elision/ref-assoc-async.stderr @@ -10,8 +10,8 @@ LL | f | help: consider introducing a named lifetime parameter and update trait if needed | -LL | async fn ref_AssocType<'a>(self: &'a ::AssocType, f: &'a u32) -> &u32 { - | ++++ ++ ++ +LL | async fn ref_AssocType<'a>(self: &::AssocType, f: &'a u32) -> &'a u32 { + | ++++ ++ ++ error: lifetime may not live long enough --> $DIR/ref-assoc-async.rs:24:9 @@ -25,8 +25,8 @@ LL | f | help: consider introducing a named lifetime parameter and update trait if needed | -LL | async fn box_ref_AssocType<'a>(self: Box<&'a ::AssocType>, f: &'a u32) -> &u32 { - | ++++ ++ ++ +LL | async fn box_ref_AssocType<'a>(self: Box<&::AssocType>, f: &'a u32) -> &'a u32 { + | ++++ ++ ++ error: lifetime may not live long enough --> $DIR/ref-assoc-async.rs:29:9 @@ -40,8 +40,8 @@ LL | f | help: consider introducing a named lifetime parameter and update trait if needed | -LL | async fn pin_ref_AssocType<'a>(self: Pin<&'a ::AssocType>, f: &'a u32) -> &u32 { - | ++++ ++ ++ +LL | async fn pin_ref_AssocType<'a>(self: Pin<&::AssocType>, f: &'a u32) -> &'a u32 { + | ++++ ++ ++ error: lifetime may not live long enough --> $DIR/ref-assoc-async.rs:34:9 @@ -55,8 +55,8 @@ LL | f | help: consider introducing a named lifetime parameter and update trait if needed | -LL | async fn box_box_ref_AssocType<'a>(self: Box::AssocType>>, f: &'a u32) -> &u32 { - | ++++ ++ ++ +LL | async fn box_box_ref_AssocType<'a>(self: Box::AssocType>>, f: &'a u32) -> &'a u32 { + | ++++ ++ ++ error: lifetime may not live long enough --> $DIR/ref-assoc-async.rs:39:9 @@ -70,8 +70,8 @@ LL | f | help: consider introducing a named lifetime parameter and update trait if needed | -LL | async fn box_pin_ref_AssocType<'a>(self: Box::AssocType>>, f: &'a u32) -> &u32 { - | ++++ ++ ++ +LL | async fn box_pin_ref_AssocType<'a>(self: Box::AssocType>>, f: &'a u32) -> &'a u32 { + | ++++ ++ ++ error: aborting due to 5 previous errors diff --git a/tests/ui/self/elision/ref-mut-self-async.stderr b/tests/ui/self/elision/ref-mut-self-async.stderr index 62543ba5339..945fb5e0282 100644 --- a/tests/ui/self/elision/ref-mut-self-async.stderr +++ b/tests/ui/self/elision/ref-mut-self-async.stderr @@ -10,8 +10,8 @@ LL | f | help: consider introducing a named lifetime parameter and update trait if needed | -LL | async fn ref_self<'a>(&'a mut self, f: &'a u32) -> &u32 { - | ++++ ++ ++ +LL | async fn ref_self<'a>(&mut self, f: &'a u32) -> &'a u32 { + | ++++ ++ ++ error: lifetime may not live long enough --> $DIR/ref-mut-self-async.rs:20:9 @@ -25,8 +25,8 @@ LL | f | help: consider introducing a named lifetime parameter and update trait if needed | -LL | async fn ref_Self<'a>(self: &'a mut Self, f: &'a u32) -> &u32 { - | ++++ ++ ++ +LL | async fn ref_Self<'a>(self: &mut Self, f: &'a u32) -> &'a u32 { + | ++++ ++ ++ error: lifetime may not live long enough --> $DIR/ref-mut-self-async.rs:25:9 @@ -40,8 +40,8 @@ LL | f | help: consider introducing a named lifetime parameter and update trait if needed | -LL | async fn box_ref_Self<'a>(self: Box<&'a mut Self>, f: &'a u32) -> &u32 { - | ++++ ++ ++ +LL | async fn box_ref_Self<'a>(self: Box<&mut Self>, f: &'a u32) -> &'a u32 { + | ++++ ++ ++ error: lifetime may not live long enough --> $DIR/ref-mut-self-async.rs:30:9 @@ -55,8 +55,8 @@ LL | f | help: consider introducing a named lifetime parameter and update trait if needed | -LL | async fn pin_ref_Self<'a>(self: Pin<&'a mut Self>, f: &'a u32) -> &u32 { - | ++++ ++ ++ +LL | async fn pin_ref_Self<'a>(self: Pin<&mut Self>, f: &'a u32) -> &'a u32 { + | ++++ ++ ++ error: lifetime may not live long enough --> $DIR/ref-mut-self-async.rs:35:9 @@ -70,8 +70,8 @@ LL | f | help: consider introducing a named lifetime parameter and update trait if needed | -LL | async fn box_box_ref_Self<'a>(self: Box>, f: &'a u32) -> &u32 { - | ++++ ++ ++ +LL | async fn box_box_ref_Self<'a>(self: Box>, f: &'a u32) -> &'a u32 { + | ++++ ++ ++ error: lifetime may not live long enough --> $DIR/ref-mut-self-async.rs:40:9 @@ -85,8 +85,8 @@ LL | f | help: consider introducing a named lifetime parameter and update trait if needed | -LL | async fn box_pin_ref_Self<'a>(self: Box>, f: &'a u32) -> &u32 { - | ++++ ++ ++ +LL | async fn box_pin_ref_Self<'a>(self: Box>, f: &'a u32) -> &'a u32 { + | ++++ ++ ++ error: aborting due to 6 previous errors diff --git a/tests/ui/self/elision/ref-mut-struct-async.stderr b/tests/ui/self/elision/ref-mut-struct-async.stderr index f8fb2e4a138..149ab01045c 100644 --- a/tests/ui/self/elision/ref-mut-struct-async.stderr +++ b/tests/ui/self/elision/ref-mut-struct-async.stderr @@ -10,8 +10,8 @@ LL | f | help: consider introducing a named lifetime parameter and update trait if needed | -LL | async fn ref_Struct<'a>(self: &'a mut Struct, f: &'a u32) -> &u32 { - | ++++ ++ ++ +LL | async fn ref_Struct<'a>(self: &mut Struct, f: &'a u32) -> &'a u32 { + | ++++ ++ ++ error: lifetime may not live long enough --> $DIR/ref-mut-struct-async.rs:18:9 @@ -25,8 +25,8 @@ LL | f | help: consider introducing a named lifetime parameter and update trait if needed | -LL | async fn box_ref_Struct<'a>(self: Box<&'a mut Struct>, f: &'a u32) -> &u32 { - | ++++ ++ ++ +LL | async fn box_ref_Struct<'a>(self: Box<&mut Struct>, f: &'a u32) -> &'a u32 { + | ++++ ++ ++ error: lifetime may not live long enough --> $DIR/ref-mut-struct-async.rs:23:9 @@ -40,8 +40,8 @@ LL | f | help: consider introducing a named lifetime parameter and update trait if needed | -LL | async fn pin_ref_Struct<'a>(self: Pin<&'a mut Struct>, f: &'a u32) -> &u32 { - | ++++ ++ ++ +LL | async fn pin_ref_Struct<'a>(self: Pin<&mut Struct>, f: &'a u32) -> &'a u32 { + | ++++ ++ ++ error: lifetime may not live long enough --> $DIR/ref-mut-struct-async.rs:28:9 @@ -55,8 +55,8 @@ LL | f | help: consider introducing a named lifetime parameter and update trait if needed | -LL | async fn box_box_ref_Struct<'a>(self: Box>, f: &'a u32) -> &u32 { - | ++++ ++ ++ +LL | async fn box_box_ref_Struct<'a>(self: Box>, f: &'a u32) -> &'a u32 { + | ++++ ++ ++ error: lifetime may not live long enough --> $DIR/ref-mut-struct-async.rs:33:9 @@ -70,8 +70,8 @@ LL | f | help: consider introducing a named lifetime parameter and update trait if needed | -LL | async fn box_pin_ref_Struct<'a>(self: Box>, f: &'a u32) -> &u32 { - | ++++ ++ ++ +LL | async fn box_pin_ref_Struct<'a>(self: Box>, f: &'a u32) -> &'a u32 { + | ++++ ++ ++ error: aborting due to 5 previous errors diff --git a/tests/ui/self/elision/ref-self-async.stderr b/tests/ui/self/elision/ref-self-async.stderr index 010d281b002..a75ece5f2c7 100644 --- a/tests/ui/self/elision/ref-self-async.stderr +++ b/tests/ui/self/elision/ref-self-async.stderr @@ -10,8 +10,8 @@ LL | f | help: consider introducing a named lifetime parameter and update trait if needed | -LL | async fn ref_self<'a>(&'a self, f: &'a u32) -> &u32 { - | ++++ ++ ++ +LL | async fn ref_self<'a>(&self, f: &'a u32) -> &'a u32 { + | ++++ ++ ++ error: lifetime may not live long enough --> $DIR/ref-self-async.rs:30:9 @@ -25,8 +25,8 @@ LL | f | help: consider introducing a named lifetime parameter and update trait if needed | -LL | async fn ref_Self<'a>(self: &'a Self, f: &'a u32) -> &u32 { - | ++++ ++ ++ +LL | async fn ref_Self<'a>(self: &Self, f: &'a u32) -> &'a u32 { + | ++++ ++ ++ error: lifetime may not live long enough --> $DIR/ref-self-async.rs:35:9 @@ -40,8 +40,8 @@ LL | f | help: consider introducing a named lifetime parameter and update trait if needed | -LL | async fn box_ref_Self<'a>(self: Box<&'a Self>, f: &'a u32) -> &u32 { - | ++++ ++ ++ +LL | async fn box_ref_Self<'a>(self: Box<&Self>, f: &'a u32) -> &'a u32 { + | ++++ ++ ++ error: lifetime may not live long enough --> $DIR/ref-self-async.rs:40:9 @@ -55,8 +55,8 @@ LL | f | help: consider introducing a named lifetime parameter and update trait if needed | -LL | async fn pin_ref_Self<'a>(self: Pin<&'a Self>, f: &'a u32) -> &u32 { - | ++++ ++ ++ +LL | async fn pin_ref_Self<'a>(self: Pin<&Self>, f: &'a u32) -> &'a u32 { + | ++++ ++ ++ error: lifetime may not live long enough --> $DIR/ref-self-async.rs:45:9 @@ -70,8 +70,8 @@ LL | f | help: consider introducing a named lifetime parameter and update trait if needed | -LL | async fn box_box_ref_Self<'a>(self: Box>, f: &'a u32) -> &u32 { - | ++++ ++ ++ +LL | async fn box_box_ref_Self<'a>(self: Box>, f: &'a u32) -> &'a u32 { + | ++++ ++ ++ error: lifetime may not live long enough --> $DIR/ref-self-async.rs:50:9 @@ -85,8 +85,8 @@ LL | f | help: consider introducing a named lifetime parameter and update trait if needed | -LL | async fn box_pin_ref_Self<'a>(self: Box>, f: &'a u32) -> &u32 { - | ++++ ++ ++ +LL | async fn box_pin_ref_Self<'a>(self: Box>, f: &'a u32) -> &'a u32 { + | ++++ ++ ++ error: lifetime may not live long enough --> $DIR/ref-self-async.rs:55:9 @@ -100,8 +100,8 @@ LL | f | help: consider introducing a named lifetime parameter and update trait if needed | -LL | async fn wrap_ref_Self_Self<'a>(self: Wrap<&'a Self, Self>, f: &'a u8) -> &u8 { - | ++++ ++ ++ +LL | async fn wrap_ref_Self_Self<'a>(self: Wrap<&Self, Self>, f: &'a u8) -> &'a u8 { + | ++++ ++ ++ error: aborting due to 7 previous errors diff --git a/tests/ui/self/elision/ref-struct-async.stderr b/tests/ui/self/elision/ref-struct-async.stderr index c9376d58f90..6bdc145223a 100644 --- a/tests/ui/self/elision/ref-struct-async.stderr +++ b/tests/ui/self/elision/ref-struct-async.stderr @@ -10,8 +10,8 @@ LL | f | help: consider introducing a named lifetime parameter and update trait if needed | -LL | async fn ref_Struct<'a>(self: &'a Struct, f: &'a u32) -> &u32 { - | ++++ ++ ++ +LL | async fn ref_Struct<'a>(self: &Struct, f: &'a u32) -> &'a u32 { + | ++++ ++ ++ error: lifetime may not live long enough --> $DIR/ref-struct-async.rs:18:9 @@ -25,8 +25,8 @@ LL | f | help: consider introducing a named lifetime parameter and update trait if needed | -LL | async fn box_ref_Struct<'a>(self: Box<&'a Struct>, f: &'a u32) -> &u32 { - | ++++ ++ ++ +LL | async fn box_ref_Struct<'a>(self: Box<&Struct>, f: &'a u32) -> &'a u32 { + | ++++ ++ ++ error: lifetime may not live long enough --> $DIR/ref-struct-async.rs:23:9 @@ -40,8 +40,8 @@ LL | f | help: consider introducing a named lifetime parameter and update trait if needed | -LL | async fn pin_ref_Struct<'a>(self: Pin<&'a Struct>, f: &'a u32) -> &u32 { - | ++++ ++ ++ +LL | async fn pin_ref_Struct<'a>(self: Pin<&Struct>, f: &'a u32) -> &'a u32 { + | ++++ ++ ++ error: lifetime may not live long enough --> $DIR/ref-struct-async.rs:28:9 @@ -55,8 +55,8 @@ LL | f | help: consider introducing a named lifetime parameter and update trait if needed | -LL | async fn box_box_ref_Struct<'a>(self: Box>, f: &'a u32) -> &u32 { - | ++++ ++ ++ +LL | async fn box_box_ref_Struct<'a>(self: Box>, f: &'a u32) -> &'a u32 { + | ++++ ++ ++ error: lifetime may not live long enough --> $DIR/ref-struct-async.rs:33:9 @@ -70,8 +70,8 @@ LL | f | help: consider introducing a named lifetime parameter and update trait if needed | -LL | async fn box_pin_Struct<'a>(self: Box>, f: &'a u32) -> &u32 { - | ++++ ++ ++ +LL | async fn box_pin_Struct<'a>(self: Box>, f: &'a u32) -> &'a u32 { + | ++++ ++ ++ error: aborting due to 5 previous errors diff --git a/tests/ui/type-alias-impl-trait/const_generic_type.no_infer.stderr b/tests/ui/type-alias-impl-trait/const_generic_type.no_infer.stderr index b526ab49d8d..ec8a51b0818 100644 --- a/tests/ui/type-alias-impl-trait/const_generic_type.no_infer.stderr +++ b/tests/ui/type-alias-impl-trait/const_generic_type.no_infer.stderr @@ -1,3 +1,11 @@ +error: `Bar` is forbidden as the type of a const generic parameter + --> $DIR/const_generic_type.rs:8:24 + | +LL | async fn test() { + | ^^^^^^^^^^ + | + = note: the only supported types are integers, `bool`, and `char` + error: item does not constrain `Bar::{opaque#0}`, but has it in its signature --> $DIR/const_generic_type.rs:8:10 | @@ -39,13 +47,5 @@ LL | type Bar = impl std::fmt::Display; | = note: `Bar` must be used in combination with a concrete type within the same module -error: `Bar` is forbidden as the type of a const generic parameter - --> $DIR/const_generic_type.rs:8:24 - | -LL | async fn test() { - | ^^^^^^^^^^ - | - = note: the only supported types are integers, `bool`, and `char` - error: aborting due to 4 previous errors diff --git a/tests/ui/type-alias-impl-trait/constrain_inputs.stderr b/tests/ui/type-alias-impl-trait/constrain_inputs.stderr index 2468fb7480b..436326e66c3 100644 --- a/tests/ui/type-alias-impl-trait/constrain_inputs.stderr +++ b/tests/ui/type-alias-impl-trait/constrain_inputs.stderr @@ -7,19 +7,6 @@ LL | fn execute(ty: Ty<'_>) -> &str { todo!() } = note: lifetimes appearing in an associated or opaque type are not considered constrained = note: consider introducing a named lifetime parameter -error: item does not constrain `lifetime_params::Ty::{opaque#0}`, but has it in its signature - --> $DIR/constrain_inputs.rs:6:8 - | -LL | fn execute(ty: Ty<'_>) -> &str { todo!() } - | ^^^^^^^ - | - = note: consider moving the opaque type's declaration and defining uses into a separate module -note: this opaque type is in the signature - --> $DIR/constrain_inputs.rs:4:19 - | -LL | type Ty<'a> = impl Sized; - | ^^^^^^^^^^ - error[E0581]: return type references an anonymous lifetime, which is not constrained by the fn input types --> $DIR/constrain_inputs.rs:10:35 | @@ -38,6 +25,19 @@ LL | type BadTraitRef = dyn Fn(Ty<'_>) -> &str; = note: lifetimes appearing in an associated or opaque type are not considered constrained = note: consider introducing a named lifetime parameter +error: item does not constrain `lifetime_params::Ty::{opaque#0}`, but has it in its signature + --> $DIR/constrain_inputs.rs:6:8 + | +LL | fn execute(ty: Ty<'_>) -> &str { todo!() } + | ^^^^^^^ + | + = note: consider moving the opaque type's declaration and defining uses into a separate module +note: this opaque type is in the signature + --> $DIR/constrain_inputs.rs:4:19 + | +LL | type Ty<'a> = impl Sized; + | ^^^^^^^^^^ + error[E0581]: return type references an anonymous lifetime, which is not constrained by the fn input types --> $DIR/constrain_inputs.rs:19:31 | diff --git a/tests/ui/type-alias-impl-trait/generic_underconstrained.stderr b/tests/ui/type-alias-impl-trait/generic_underconstrained.stderr index be9b07823ae..88529b370f1 100644 --- a/tests/ui/type-alias-impl-trait/generic_underconstrained.stderr +++ b/tests/ui/type-alias-impl-trait/generic_underconstrained.stderr @@ -1,3 +1,19 @@ +error[E0277]: the trait bound `T: Trait` is not satisfied + --> $DIR/generic_underconstrained.rs:9:31 + | +LL | fn underconstrain(_: T) -> Underconstrained { + | ^^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `T` + | +note: required by a bound on the type alias `Underconstrained` + --> $DIR/generic_underconstrained.rs:6:26 + | +LL | type Underconstrained = impl Send; + | ^^^^^ required by this bound +help: consider restricting type parameter `T` + | +LL | fn underconstrain(_: T) -> Underconstrained { + | +++++++ + error[E0277]: the trait bound `T: Trait` is not satisfied --> $DIR/generic_underconstrained.rs:9:51 | @@ -19,22 +35,6 @@ help: consider restricting type parameter `T` LL | fn underconstrain(_: T) -> Underconstrained { | +++++++ -error[E0277]: the trait bound `T: Trait` is not satisfied - --> $DIR/generic_underconstrained.rs:9:31 - | -LL | fn underconstrain(_: T) -> Underconstrained { - | ^^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `T` - | -note: required by a bound on the type alias `Underconstrained` - --> $DIR/generic_underconstrained.rs:6:26 - | -LL | type Underconstrained = impl Send; - | ^^^^^ required by this bound -help: consider restricting type parameter `T` - | -LL | fn underconstrain(_: T) -> Underconstrained { - | +++++++ - error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/type-alias-impl-trait/generic_underconstrained2.stderr b/tests/ui/type-alias-impl-trait/generic_underconstrained2.stderr index 15d96191ba9..b3b9cbca968 100644 --- a/tests/ui/type-alias-impl-trait/generic_underconstrained2.stderr +++ b/tests/ui/type-alias-impl-trait/generic_underconstrained2.stderr @@ -1,3 +1,35 @@ +error[E0277]: `U` doesn't implement `Debug` + --> $DIR/generic_underconstrained2.rs:8:33 + | +LL | fn underconstrained(_: U) -> Underconstrained { + | ^^^^^^^^^^^^^^^^^^^ `U` cannot be formatted using `{:?}` because it doesn't implement `Debug` + | +note: required by a bound on the type alias `Underconstrained` + --> $DIR/generic_underconstrained2.rs:5:26 + | +LL | type Underconstrained = impl Send; + | ^^^^^^^^^^^^^^^ required by this bound +help: consider restricting type parameter `U` + | +LL | fn underconstrained(_: U) -> Underconstrained { + | +++++++++++++++++ + +error[E0277]: `V` doesn't implement `Debug` + --> $DIR/generic_underconstrained2.rs:17:43 + | +LL | fn underconstrained2(_: U, _: V) -> Underconstrained2 { + | ^^^^^^^^^^^^^^^^^^^^ `V` cannot be formatted using `{:?}` because it doesn't implement `Debug` + | +note: required by a bound on the type alias `Underconstrained2` + --> $DIR/generic_underconstrained2.rs:14:27 + | +LL | type Underconstrained2 = impl Send; + | ^^^^^^^^^^^^^^^ required by this bound +help: consider restricting type parameter `V` + | +LL | fn underconstrained2(_: U, _: V) -> Underconstrained2 { + | +++++++++++++++++ + error[E0277]: `U` doesn't implement `Debug` --> $DIR/generic_underconstrained2.rs:8:53 | @@ -40,38 +72,6 @@ help: consider restricting type parameter `V` LL | fn underconstrained2(_: U, _: V) -> Underconstrained2 { | +++++++++++++++++ -error[E0277]: `U` doesn't implement `Debug` - --> $DIR/generic_underconstrained2.rs:8:33 - | -LL | fn underconstrained(_: U) -> Underconstrained { - | ^^^^^^^^^^^^^^^^^^^ `U` cannot be formatted using `{:?}` because it doesn't implement `Debug` - | -note: required by a bound on the type alias `Underconstrained` - --> $DIR/generic_underconstrained2.rs:5:26 - | -LL | type Underconstrained = impl Send; - | ^^^^^^^^^^^^^^^ required by this bound -help: consider restricting type parameter `U` - | -LL | fn underconstrained(_: U) -> Underconstrained { - | +++++++++++++++++ - -error[E0277]: `V` doesn't implement `Debug` - --> $DIR/generic_underconstrained2.rs:17:43 - | -LL | fn underconstrained2(_: U, _: V) -> Underconstrained2 { - | ^^^^^^^^^^^^^^^^^^^^ `V` cannot be formatted using `{:?}` because it doesn't implement `Debug` - | -note: required by a bound on the type alias `Underconstrained2` - --> $DIR/generic_underconstrained2.rs:14:27 - | -LL | type Underconstrained2 = impl Send; - | ^^^^^^^^^^^^^^^ required by this bound -help: consider restricting type parameter `V` - | -LL | fn underconstrained2(_: U, _: V) -> Underconstrained2 { - | +++++++++++++++++ - error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/type-alias-impl-trait/ice-failed-to-resolve-instance-for-110696.stderr b/tests/ui/type-alias-impl-trait/ice-failed-to-resolve-instance-for-110696.stderr index 22c776e171c..eace96317dc 100644 --- a/tests/ui/type-alias-impl-trait/ice-failed-to-resolve-instance-for-110696.stderr +++ b/tests/ui/type-alias-impl-trait/ice-failed-to-resolve-instance-for-110696.stderr @@ -1,3 +1,9 @@ +error[E0207]: the type parameter `T` is not constrained by the impl trait, self type, or predicates + --> $DIR/ice-failed-to-resolve-instance-for-110696.rs:41:6 + | +LL | impl>>, U> MyIndex> for Scope { + | ^ unconstrained type parameter + error: item does not constrain `DummyT::{opaque#0}`, but has it in its signature --> $DIR/ice-failed-to-resolve-instance-for-110696.rs:28:8 | @@ -24,12 +30,6 @@ note: this opaque type is in the signature LL | type DummyT = impl F; | ^^^^^^ -error[E0207]: the type parameter `T` is not constrained by the impl trait, self type, or predicates - --> $DIR/ice-failed-to-resolve-instance-for-110696.rs:41:6 - | -LL | impl>>, U> MyIndex> for Scope { - | ^ unconstrained type parameter - error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0207`. diff --git a/tests/ui/type-alias-impl-trait/in-where-clause.stderr b/tests/ui/type-alias-impl-trait/in-where-clause.stderr index f1361b47c56..5ac09e20b02 100644 --- a/tests/ui/type-alias-impl-trait/in-where-clause.stderr +++ b/tests/ui/type-alias-impl-trait/in-where-clause.stderr @@ -1,30 +1,3 @@ -error[E0391]: cycle detected when computing type of `Bar::{opaque#0}` - --> $DIR/in-where-clause.rs:5:12 - | -LL | type Bar = impl Sized; - | ^^^^^^^^^^ - | -note: ...which requires computing type of opaque `Bar::{opaque#0}`... - --> $DIR/in-where-clause.rs:5:12 - | -LL | type Bar = impl Sized; - | ^^^^^^^^^^ -note: ...which requires type-checking `foo`... - --> $DIR/in-where-clause.rs:8:1 - | -LL | / fn foo() -> Bar -LL | | where -LL | | Bar: Send, - | |______________^ - = note: ...which requires revealing opaque types in `[Binder { value: TraitPredicate(, polarity:Positive), bound_vars: [] }]`... - = note: ...which again requires computing type of `Bar::{opaque#0}`, completing the cycle -note: cycle used when checking that `Bar::{opaque#0}` is well-formed - --> $DIR/in-where-clause.rs:5:12 - | -LL | type Bar = impl Sized; - | ^^^^^^^^^^ - = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information - error[E0283]: type annotations needed: cannot satisfy `Bar: Send` --> $DIR/in-where-clause.rs:12:9 | @@ -41,6 +14,29 @@ LL | where LL | Bar: Send, | ^^^^ required by this bound in `foo` +error[E0391]: cycle detected when computing type of opaque `Bar::{opaque#0}` + --> $DIR/in-where-clause.rs:5:12 + | +LL | type Bar = impl Sized; + | ^^^^^^^^^^ + | +note: ...which requires type-checking `foo`... + --> $DIR/in-where-clause.rs:8:1 + | +LL | / fn foo() -> Bar +LL | | where +LL | | Bar: Send, + | |______________^ + = note: ...which requires revealing opaque types in `[Binder { value: TraitPredicate(, polarity:Positive), bound_vars: [] }]`... +note: ...which requires computing type of `Bar::{opaque#0}`... + --> $DIR/in-where-clause.rs:5:12 + | +LL | type Bar = impl Sized; + | ^^^^^^^^^^ + = note: ...which again requires computing type of opaque `Bar::{opaque#0}`, completing the cycle + = note: cycle used when evaluating trait selection obligation `Bar: core::marker::Send` + = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information + error: aborting due to 2 previous errors Some errors have detailed explanations: E0283, E0391. diff --git a/tests/ui/type-alias-impl-trait/issue-53092-2.rs b/tests/ui/type-alias-impl-trait/issue-53092-2.rs index 2adfad4fc5b..2383008d042 100644 --- a/tests/ui/type-alias-impl-trait/issue-53092-2.rs +++ b/tests/ui/type-alias-impl-trait/issue-53092-2.rs @@ -1,15 +1,14 @@ #![feature(type_alias_impl_trait)] #![allow(dead_code)] -type Bug = impl Fn(T) -> U + Copy; //~ ERROR cycle detected +type Bug = impl Fn(T) -> U + Copy; const CONST_BUG: Bug = unsafe { std::mem::transmute(|_: u8| ()) }; -//~^ ERROR: non-defining opaque type use -//~| ERROR: item does not constrain -//~| ERROR: item does not constrain +//~^ ERROR cycle detected +//~| ERROR: non-defining opaque type use fn make_bug>() -> Bug { - |x| x.into() //~ ERROR the trait bound `U: From` is not satisfied + |x| x.into() } fn main() { diff --git a/tests/ui/type-alias-impl-trait/issue-53092-2.stderr b/tests/ui/type-alias-impl-trait/issue-53092-2.stderr index 121f765e667..ac580866704 100644 --- a/tests/ui/type-alias-impl-trait/issue-53092-2.stderr +++ b/tests/ui/type-alias-impl-trait/issue-53092-2.stderr @@ -10,75 +10,33 @@ note: for this opaque type LL | type Bug = impl Fn(T) -> U + Copy; | ^^^^^^^^^^^^^^^^^^^^^^ -error[E0391]: cycle detected when computing type of `Bug::{opaque#0}` +error[E0391]: cycle detected when type-checking `CONST_BUG` + --> $DIR/issue-53092-2.rs:6:1 + | +LL | const CONST_BUG: Bug = unsafe { std::mem::transmute(|_: u8| ()) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: ...which requires computing layout of `Bug`... + = note: ...which requires normalizing `Bug`... +note: ...which requires computing type of `Bug::{opaque#0}`... --> $DIR/issue-53092-2.rs:4:18 | LL | type Bug = impl Fn(T) -> U + Copy; | ^^^^^^^^^^^^^^^^^^^^^^ - | note: ...which requires computing type of opaque `Bug::{opaque#0}`... --> $DIR/issue-53092-2.rs:4:18 | LL | type Bug = impl Fn(T) -> U + Copy; | ^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires type-checking `CONST_BUG`... + = note: ...which again requires type-checking `CONST_BUG`, completing the cycle +note: cycle used when checking that `CONST_BUG` is well-formed --> $DIR/issue-53092-2.rs:6:1 | LL | const CONST_BUG: Bug = unsafe { std::mem::transmute(|_: u8| ()) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: ...which requires computing layout of `Bug`... - = note: ...which requires normalizing `Bug`... - = note: ...which again requires computing type of `Bug::{opaque#0}`, completing the cycle -note: cycle used when checking that `Bug::{opaque#0}` is well-formed - --> $DIR/issue-53092-2.rs:4:18 - | -LL | type Bug = impl Fn(T) -> U + Copy; - | ^^^^^^^^^^^^^^^^^^^^^^ = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information -error: item does not constrain `Bug::{opaque#0}`, but has it in its signature - --> $DIR/issue-53092-2.rs:6:7 - | -LL | const CONST_BUG: Bug = unsafe { std::mem::transmute(|_: u8| ()) }; - | ^^^^^^^^^ - | - = note: consider moving the opaque type's declaration and defining uses into a separate module -note: this opaque type is in the signature - --> $DIR/issue-53092-2.rs:4:18 - | -LL | type Bug = impl Fn(T) -> U + Copy; - | ^^^^^^^^^^^^^^^^^^^^^^ +error: aborting due to 2 previous errors -error: item does not constrain `Bug::{opaque#0}`, but has it in its signature - --> $DIR/issue-53092-2.rs:6:61 - | -LL | const CONST_BUG: Bug = unsafe { std::mem::transmute(|_: u8| ()) }; - | ^^^^^^^ - | - = note: consider moving the opaque type's declaration and defining uses into a separate module -note: this opaque type is in the signature - --> $DIR/issue-53092-2.rs:4:18 - | -LL | type Bug = impl Fn(T) -> U + Copy; - | ^^^^^^^^^^^^^^^^^^^^^^ - -error[E0277]: the trait bound `U: From` is not satisfied - --> $DIR/issue-53092-2.rs:12:5 - | -LL | |x| x.into() - | ^^^^^^^^^^^^ the trait `From` is not implemented for `U` - | -note: required by a bound in `make_bug` - --> $DIR/issue-53092-2.rs:11:19 - | -LL | fn make_bug>() -> Bug { - | ^^^^^^^ required by this bound in `make_bug` -help: consider restricting type parameter `U` - | -LL | type Bug> = impl Fn(T) -> U + Copy; - | +++++++++++++++++++++++ - -error: aborting due to 5 previous errors - -Some errors have detailed explanations: E0277, E0391, E0792. -For more information about an error, try `rustc --explain E0277`. +Some errors have detailed explanations: E0391, E0792. +For more information about an error, try `rustc --explain E0391`. diff --git a/tests/ui/type-alias-impl-trait/issue-84660-unsoundness.current.stderr b/tests/ui/type-alias-impl-trait/issue-84660-unsoundness.current.stderr index 2b064dcfc31..ec7b9e0e12b 100644 --- a/tests/ui/type-alias-impl-trait/issue-84660-unsoundness.current.stderr +++ b/tests/ui/type-alias-impl-trait/issue-84660-unsoundness.current.stderr @@ -1,3 +1,12 @@ +error[E0119]: conflicting implementations of trait `Trait` + --> $DIR/issue-84660-unsoundness.rs:29:1 + | +LL | impl Trait for Out { + | ------------------------------------ first implementation here +... +LL | impl Trait<(), In> for Out { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation + error: item does not constrain `Bar::{opaque#0}`, but has it in its signature --> $DIR/issue-84660-unsoundness.rs:22:8 | @@ -11,15 +20,6 @@ note: this opaque type is in the signature LL | type Bar = impl Foo; | ^^^^^^^^ -error[E0119]: conflicting implementations of trait `Trait` - --> $DIR/issue-84660-unsoundness.rs:29:1 - | -LL | impl Trait for Out { - | ------------------------------------ first implementation here -... -LL | impl Trait<(), In> for Out { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation - error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0119`. diff --git a/tests/ui/type-alias-impl-trait/issue-84660-unsoundness.next.stderr b/tests/ui/type-alias-impl-trait/issue-84660-unsoundness.next.stderr index 5a728a00138..e33102f687c 100644 --- a/tests/ui/type-alias-impl-trait/issue-84660-unsoundness.next.stderr +++ b/tests/ui/type-alias-impl-trait/issue-84660-unsoundness.next.stderr @@ -1,3 +1,12 @@ +error[E0119]: conflicting implementations of trait `Trait` + --> $DIR/issue-84660-unsoundness.rs:29:1 + | +LL | impl Trait for Out { + | ------------------------------------ first implementation here +... +LL | impl Trait<(), In> for Out { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation + error[E0284]: type annotations needed: cannot satisfy `Bar == _` --> $DIR/issue-84660-unsoundness.rs:22:37 | @@ -9,15 +18,6 @@ LL | | unreachable!(); LL | | } | |_____^ cannot satisfy `Bar == _` -error[E0119]: conflicting implementations of trait `Trait` - --> $DIR/issue-84660-unsoundness.rs:29:1 - | -LL | impl Trait for Out { - | ------------------------------------ first implementation here -... -LL | impl Trait<(), In> for Out { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation - error: aborting due to 2 previous errors Some errors have detailed explanations: E0119, E0284. diff --git a/tests/ui/type-alias-impl-trait/nested-in-anon-const.stderr b/tests/ui/type-alias-impl-trait/nested-in-anon-const.stderr index d0fe920b35f..aa0c1076117 100644 --- a/tests/ui/type-alias-impl-trait/nested-in-anon-const.stderr +++ b/tests/ui/type-alias-impl-trait/nested-in-anon-const.stderr @@ -1,11 +1,3 @@ -error: unconstrained opaque type - --> $DIR/nested-in-anon-const.rs:13:33 - | -LL | type B = impl Sized; - | ^^^^^^^^^^ - | - = note: `B` must be used in combination with a concrete type within the same item - error[E0308]: mismatched types --> $DIR/nested-in-anon-const.rs:12:17 | @@ -15,6 +7,14 @@ LL | | LL | | }, | |_________________^ expected `usize`, found `()` +error: unconstrained opaque type + --> $DIR/nested-in-anon-const.rs:13:33 + | +LL | type B = impl Sized; + | ^^^^^^^^^^ + | + = note: `B` must be used in combination with a concrete type within the same item + error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error-4.stderr b/tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error-4.stderr index aedb78bf5e7..99646aa4d1b 100644 --- a/tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error-4.stderr +++ b/tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error-4.stderr @@ -10,18 +10,6 @@ note: required by a bound on the type alias `Ty` LL | Ty: Id, | ^^^^^^^^^^^^^^ required by this bound -error[E0275]: overflow evaluating the requirement `Ty: Id` - --> $DIR/type-alias-impl-trait-with-cycle-error-4.rs:15:19 - | -LL | fn define() -> Ty {} - | ^^ - | -note: required by a bound on the type alias `Ty` - --> $DIR/type-alias-impl-trait-with-cycle-error-4.rs:13:9 - | -LL | Ty: Id, - | ^^^^^^^^^^^^^^ required by this bound - error[E0275]: overflow evaluating the requirement `Ty: Id` --> $DIR/type-alias-impl-trait-with-cycle-error-4.rs:15:16 | @@ -34,6 +22,6 @@ note: required by a bound on the type alias `Ty` LL | Ty: Id, | ^^^^^^^^^^^^^^ required by this bound -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0275`. diff --git a/tests/ui/typeck/typeck_type_placeholder_item.rs b/tests/ui/typeck/typeck_type_placeholder_item.rs index 29a21a1f45f..437a1aed403 100644 --- a/tests/ui/typeck/typeck_type_placeholder_item.rs +++ b/tests/ui/typeck/typeck_type_placeholder_item.rs @@ -160,7 +160,7 @@ impl BadTrait<_> for BadStruct<_> {} //~^ ERROR the placeholder `_` is not allowed within types on item signatures for implementations fn impl_trait() -> impl BadTrait<_> { -//~^ ERROR the placeholder `_` is not allowed within types on item signatures for opaque types +//~^ ERROR the placeholder `_` is not allowed within types on item signatures for functions unimplemented!() } @@ -180,7 +180,7 @@ struct Struct; trait Trait {} impl Trait for Struct {} type Y = impl Trait<_>; -//~^ ERROR the placeholder `_` is not allowed within types on item signatures for opaque types +//~^ ERROR the placeholder `_` is not allowed within types on item signatures for type aliases fn foo() -> Y { Struct } diff --git a/tests/ui/typeck/typeck_type_placeholder_item.stderr b/tests/ui/typeck/typeck_type_placeholder_item.stderr index 2c064fbb19f..8a765c21624 100644 --- a/tests/ui/typeck/typeck_type_placeholder_item.stderr +++ b/tests/ui/typeck/typeck_type_placeholder_item.stderr @@ -484,11 +484,16 @@ help: use type parameters instead LL | impl BadTrait for BadStruct {} | +++ ~ ~ -error[E0121]: the placeholder `_` is not allowed within types on item signatures for opaque types +error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions --> $DIR/typeck_type_placeholder_item.rs:162:34 | LL | fn impl_trait() -> impl BadTrait<_> { | ^ not allowed in type signatures + | +help: use type parameters instead + | +LL | fn impl_trait() -> impl BadTrait { + | +++ ~ error[E0121]: the placeholder `_` is not allowed within types on item signatures for structs --> $DIR/typeck_type_placeholder_item.rs:167:25 @@ -518,33 +523,17 @@ error[E0121]: the placeholder `_` is not allowed within types on item signatures LL | type X = Box<_>; | ^ not allowed in type signatures -error[E0121]: the placeholder `_` is not allowed within types on item signatures for opaque types +error[E0121]: the placeholder `_` is not allowed within types on item signatures for type aliases --> $DIR/typeck_type_placeholder_item.rs:182:21 | LL | type Y = impl Trait<_>; | ^ not allowed in type signatures -error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions - --> $DIR/typeck_type_placeholder_item.rs:44:27 +error[E0121]: the placeholder `_` is not allowed within types on item signatures for associated constants + --> $DIR/typeck_type_placeholder_item.rs:206:14 | -LL | fn test10(&self, _x : _) { } - | ^ not allowed in type signatures - | -help: use type parameters instead - | -LL | fn test10(&self, _x : T) { } - | +++ ~ - -error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions - --> $DIR/typeck_type_placeholder_item.rs:110:34 - | -LL | fn fn_test10(&self, _x : _) { } - | ^ not allowed in type signatures - | -help: use type parameters instead - | -LL | fn fn_test10(&self, _x : T) { } - | +++ ~ +LL | const C: _; + | ^ not allowed in type signatures error[E0121]: the placeholder `_` is not allowed within types on item signatures for associated constants --> $DIR/typeck_type_placeholder_item.rs:194:14 @@ -555,6 +544,21 @@ LL | const D: _ = 42; | not allowed in type signatures | help: replace with the correct type: `i32` +error[E0121]: the placeholder `_` is not allowed within types on item signatures for associated constants + --> $DIR/typeck_type_placeholder_item.rs:209:14 + | +LL | const D: _ = 42; + | ^ not allowed in type signatures + +error[E0046]: not all trait items implemented, missing: `F` + --> $DIR/typeck_type_placeholder_item.rs:200:1 + | +LL | type F: std::ops::Fn(_); + | ----------------------- `F` from trait +... +LL | impl Qux for Struct { + | ^^^^^^^^^^^^^^^^^^^ missing `F` in implementation + error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types --> $DIR/typeck_type_placeholder_item.rs:217:31 | @@ -573,27 +577,6 @@ LL | const _: Option<_> = map(value); | not allowed in type signatures | help: replace with the correct type: `Option` -error[E0121]: the placeholder `_` is not allowed within types on item signatures for associated constants - --> $DIR/typeck_type_placeholder_item.rs:206:14 - | -LL | const C: _; - | ^ not allowed in type signatures - -error[E0121]: the placeholder `_` is not allowed within types on item signatures for associated constants - --> $DIR/typeck_type_placeholder_item.rs:209:14 - | -LL | const D: _ = 42; - | ^ not allowed in type signatures - -error[E0046]: not all trait items implemented, missing: `F` - --> $DIR/typeck_type_placeholder_item.rs:200:1 - | -LL | type F: std::ops::Fn(_); - | ----------------------- `F` from trait -... -LL | impl Qux for Struct { - | ^^^^^^^^^^^^^^^^^^^ missing `F` in implementation - error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types --> $DIR/typeck_type_placeholder_item.rs:225:31 | @@ -624,6 +607,17 @@ LL | fn test9(&self) -> _ { () } | not allowed in type signatures | help: replace with the correct return type: `()` +error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions + --> $DIR/typeck_type_placeholder_item.rs:44:27 + | +LL | fn test10(&self, _x : _) { } + | ^ not allowed in type signatures + | +help: use type parameters instead + | +LL | fn test10(&self, _x : T) { } + | +++ ~ + error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types --> $DIR/typeck_type_placeholder_item.rs:107:31 | @@ -633,6 +627,17 @@ LL | fn fn_test9(&self) -> _ { () } | not allowed in type signatures | help: replace with the correct return type: `()` +error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions + --> $DIR/typeck_type_placeholder_item.rs:110:34 + | +LL | fn fn_test10(&self, _x : _) { } + | ^ not allowed in type signatures + | +help: use type parameters instead + | +LL | fn fn_test10(&self, _x : T) { } + | +++ ~ + error[E0121]: the placeholder `_` is not allowed within types on item signatures for associated types --> $DIR/typeck_type_placeholder_item.rs:202:14 | From c7cb45a791b0a3191b68a3cfaf5883e1958466ec Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Thu, 22 Aug 2024 00:55:23 +0000 Subject: [PATCH 576/683] Remove stray fixmes. --- compiler/rustc_hir_analysis/src/collect.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 02ad5355d25..640907c3e4a 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -260,7 +260,6 @@ fn reject_placeholder_type_signatures_in_item<'tcx>( | hir::ItemKind::Trait(_, _, generics, ..) | hir::ItemKind::Impl(hir::Impl { generics, .. }) | hir::ItemKind::Struct(_, generics) => (generics, true), - // FIXME: how to handle opaque types since no longer items hir::ItemKind::TyAlias(_, generics) => (generics, false), // `static`, `fn` and `const` are handled elsewhere to suggest appropriate type. _ => return, @@ -744,8 +743,6 @@ fn lower_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) { } } - // FIXME: ok to ignore opaque tys in collection? - // hir::ItemKind::TyAlias(..) => { tcx.ensure().generics_of(def_id); tcx.ensure().type_of(def_id); From 6ec58a44e20fa3c0a5c957ab3c31f2d039e9a24a Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sun, 18 Aug 2024 16:10:54 +0000 Subject: [PATCH 577/683] Simplify bound var resolution. --- .../src/collect/resolve_bound_vars.rs | 56 +++++++++---------- .../src/middle/resolve_bound_vars.rs | 10 ++-- compiler/rustc_middle/src/query/mod.rs | 6 +- compiler/rustc_middle/src/ty/context.rs | 11 ++-- 4 files changed, 39 insertions(+), 44 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs index 513d4e9b4a5..c8852a3a369 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -11,10 +11,13 @@ use std::fmt; use rustc_ast::visit::walk_list; use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; +use rustc_data_structures::sorted_map::SortedMap; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::intravisit::{self, Visitor}; -use rustc_hir::{GenericArg, GenericParam, GenericParamKind, HirId, HirIdMap, LifetimeName, Node}; +use rustc_hir::{ + GenericArg, GenericParam, GenericParamKind, HirId, ItemLocalMap, LifetimeName, Node, +}; use rustc_macros::extension; use rustc_middle::hir::nested_filter; use rustc_middle::middle::resolve_bound_vars::*; @@ -74,7 +77,7 @@ impl ResolvedArg { struct NamedVarMap { // maps from every use of a named (not anonymous) bound var to a // `ResolvedArg` describing how that variable is bound - defs: HirIdMap, + defs: ItemLocalMap, // Maps relevant hir items to the bound vars on them. These include: // - function defs @@ -82,7 +85,7 @@ struct NamedVarMap { // - closures // - trait refs // - bound types (like `T` in `for<'a> T<'a>: Foo`) - late_bound_vars: HirIdMap>, + late_bound_vars: ItemLocalMap>, } struct BoundVarContext<'a, 'tcx> { @@ -225,10 +228,10 @@ pub(crate) fn provide(providers: &mut Providers) { *providers = Providers { resolve_bound_vars, - named_variable_map: |tcx, id| tcx.resolve_bound_vars(id).defs.get(&id), + named_variable_map: |tcx, id| &tcx.resolve_bound_vars(id).defs, is_late_bound_map, object_lifetime_default, - late_bound_vars_map: |tcx, id| tcx.resolve_bound_vars(id).late_bound_vars.get(&id), + late_bound_vars_map: |tcx, id| &tcx.resolve_bound_vars(id).late_bound_vars, ..*providers }; @@ -265,16 +268,12 @@ fn resolve_bound_vars(tcx: TyCtxt<'_>, local_def_id: hir::OwnerId) -> ResolveBou hir::OwnerNode::Synthetic => unreachable!(), } - let mut rl = ResolveBoundVars::default(); - - for (hir_id, v) in named_variable_map.defs { - let map = rl.defs.entry(hir_id.owner).or_default(); - map.insert(hir_id.local_id, v); - } - for (hir_id, v) in named_variable_map.late_bound_vars { - let map = rl.late_bound_vars.entry(hir_id.owner).or_default(); - map.insert(hir_id.local_id, v); - } + let defs = named_variable_map.defs.into_sorted_stable_ord(); + let late_bound_vars = named_variable_map.late_bound_vars.into_sorted_stable_ord(); + let rl = ResolveBoundVars { + defs: SortedMap::from_presorted_elements(defs), + late_bound_vars: SortedMap::from_presorted_elements(late_bound_vars), + }; debug!(?rl.defs); debug!(?rl.late_bound_vars); @@ -340,7 +339,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { Scope::Binder { hir_id, .. } => { // Nested poly trait refs have the binders concatenated let mut full_binders = - self.map.late_bound_vars.entry(*hir_id).or_default().clone(); + self.map.late_bound_vars.entry(hir_id.local_id).or_default().clone(); full_binders.extend(supertrait_bound_vars); break (full_binders, BinderScopeType::Concatenating); } @@ -677,7 +676,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { hir::TyKind::Ref(lifetime_ref, ref mt) => { self.visit_lifetime(lifetime_ref); let scope = Scope::ObjectLifetimeDefault { - lifetime: self.map.defs.get(&lifetime_ref.hir_id).cloned(), + lifetime: self.map.defs.get(&lifetime_ref.hir_id.local_id).cloned(), s: self.scope, }; self.with(scope, |this| this.visit_ty(mt.ty)); @@ -704,7 +703,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { // and ban them. Type variables instantiated inside binders aren't // well-supported at the moment, so this doesn't work. // In the future, this should be fixed and this error should be removed. - let def = self.map.defs.get(&lifetime.hir_id).copied(); + let def = self.map.defs.get(&lifetime.hir_id.local_id).copied(); let Some(ResolvedArg::LateBound(_, _, lifetime_def_id)) = def else { continue }; let lifetime_hir_id = self.tcx.local_def_id_to_hir_id(lifetime_def_id); @@ -841,7 +840,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { let bound_vars: Vec<_> = self.tcx.fn_sig(sig_id).skip_binder().bound_vars().iter().collect(); let hir_id = self.tcx.local_def_id_to_hir_id(def_id); - self.map.late_bound_vars.insert(hir_id, bound_vars); + self.map.late_bound_vars.insert(hir_id.local_id, bound_vars); } self.visit_fn_like_elision(fd.inputs, output, matches!(fk, intravisit::FnKind::Closure)); intravisit::walk_fn_kind(self, fk); @@ -1019,10 +1018,10 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { } fn record_late_bound_vars(&mut self, hir_id: HirId, binder: Vec) { - if let Some(old) = self.map.late_bound_vars.insert(hir_id, binder) { + if let Some(old) = self.map.late_bound_vars.insert(hir_id.local_id, binder) { bug!( "overwrote bound vars for {hir_id:?}:\nold={old:?}\nnew={:?}", - self.map.late_bound_vars[&hir_id] + self.map.late_bound_vars[&hir_id.local_id] ) } } @@ -1381,9 +1380,9 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { kind.descr(param_def_id.to_def_id()) ), }; - self.map.defs.insert(hir_id, ResolvedArg::Error(guar)); + self.map.defs.insert(hir_id.local_id, ResolvedArg::Error(guar)); } else { - self.map.defs.insert(hir_id, def); + self.map.defs.insert(hir_id.local_id, def); } return; } @@ -1416,7 +1415,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { bug!("unexpected def-kind: {}", kind.descr(param_def_id.to_def_id())) } }); - self.map.defs.insert(hir_id, ResolvedArg::Error(guar)); + self.map.defs.insert(hir_id.local_id, ResolvedArg::Error(guar)); return; } Scope::Root { .. } => break, @@ -1526,7 +1525,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { // This index can be used with `generic_args` since `parent_count == 0`. let index = generics.param_def_id_to_index[¶m_def_id] as usize; generic_args.args.get(index).and_then(|arg| match arg { - GenericArg::Lifetime(lt) => map.defs.get(<.hir_id).copied(), + GenericArg::Lifetime(lt) => map.defs.get(<.hir_id.local_id).copied(), _ => None, }) } @@ -1816,7 +1815,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { #[instrument(level = "debug", skip(self))] fn insert_lifetime(&mut self, lifetime_ref: &'tcx hir::Lifetime, def: ResolvedArg) { debug!(span = ?lifetime_ref.ident.span); - self.map.defs.insert(lifetime_ref.hir_id, def); + self.map.defs.insert(lifetime_ref.hir_id.local_id, def); } /// Sometimes we resolve a lifetime, but later find that it is an @@ -1827,8 +1826,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { lifetime_ref: &'tcx hir::Lifetime, bad_def: ResolvedArg, ) { - // FIXME(#120456) - is `swap_remove` correct? - let old_value = self.map.defs.swap_remove(&lifetime_ref.hir_id); + let old_value = self.map.defs.remove(&lifetime_ref.hir_id.local_id); assert_eq!(old_value, Some(bad_def)); } @@ -1998,7 +1996,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { // See where these vars are used in `HirTyLowerer::lower_ty_maybe_return_type_notation`. // And this is exercised in: // `tests/ui/associated-type-bounds/return-type-notation/higher-ranked-bound-works.rs`. - let existing_bound_vars = self.map.late_bound_vars.get_mut(&hir_id).unwrap(); + let existing_bound_vars = self.map.late_bound_vars.get_mut(&hir_id.local_id).unwrap(); let existing_bound_vars_saved = existing_bound_vars.clone(); existing_bound_vars.extend(bound_vars); self.record_late_bound_vars(item_segment.hir_id, existing_bound_vars_saved); diff --git a/compiler/rustc_middle/src/middle/resolve_bound_vars.rs b/compiler/rustc_middle/src/middle/resolve_bound_vars.rs index 32e2f3b4b16..13e35cd0909 100644 --- a/compiler/rustc_middle/src/middle/resolve_bound_vars.rs +++ b/compiler/rustc_middle/src/middle/resolve_bound_vars.rs @@ -1,9 +1,9 @@ //! Name resolution for lifetimes and late-bound type and const variables: type declarations. -use rustc_data_structures::fx::FxIndexMap; +use rustc_data_structures::sorted_map::SortedMap; use rustc_errors::ErrorGuaranteed; +use rustc_hir::ItemLocalId; use rustc_hir::def_id::{DefId, LocalDefId}; -use rustc_hir::{ItemLocalId, OwnerId}; use rustc_macros::{Decodable, Encodable, HashStable, TyDecodable, TyEncodable}; use crate::ty; @@ -47,11 +47,11 @@ pub enum ObjectLifetimeDefault { /// Maps the id of each lifetime reference to the lifetime decl /// that it corresponds to. -#[derive(Default, HashStable, Debug)] +#[derive(HashStable, Debug)] pub struct ResolveBoundVars { /// Maps from every use of a named (not anonymous) lifetime to a /// `Region` describing how that region is bound - pub defs: FxIndexMap>, + pub defs: SortedMap, - pub late_bound_vars: FxIndexMap>>, + pub late_bound_vars: SortedMap>, } diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index bd6a7578a68..f0be70e00df 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -16,6 +16,7 @@ use rustc_ast::expand::StrippedCfgItem; use rustc_ast::expand::allocator::AllocatorKind; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; +use rustc_data_structures::sorted_map::SortedMap; use rustc_data_structures::steal::Steal; use rustc_data_structures::svh::Svh; use rustc_data_structures::sync::Lrc; @@ -1742,8 +1743,7 @@ rustc_queries! { arena_cache desc { |tcx| "resolving lifetimes for `{}`", tcx.def_path_str(owner_id) } } - query named_variable_map(owner_id: hir::OwnerId) -> - Option<&'tcx FxIndexMap> { + query named_variable_map(owner_id: hir::OwnerId) -> &'tcx SortedMap { desc { |tcx| "looking up a named region inside `{}`", tcx.def_path_str(owner_id) } } query is_late_bound_map(owner_id: hir::OwnerId) -> Option<&'tcx FxIndexSet> { @@ -1759,7 +1759,7 @@ rustc_queries! { separate_provide_extern } query late_bound_vars_map(owner_id: hir::OwnerId) - -> Option<&'tcx FxIndexMap>> { + -> &'tcx SortedMap> { desc { |tcx| "looking up late bound vars inside `{}`", tcx.def_path_str(owner_id) } } diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index d6547b51186..27c1b88f93f 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -2996,7 +2996,7 @@ impl<'tcx> TyCtxt<'tcx> { pub fn named_bound_var(self, id: HirId) -> Option { debug!(?id, "named_region"); - self.named_variable_map(id.owner).and_then(|map| map.get(&id.local_id).cloned()) + self.named_variable_map(id.owner).get(&id.local_id).cloned() } pub fn is_late_bound(self, id: HirId) -> bool { @@ -3005,12 +3005,9 @@ impl<'tcx> TyCtxt<'tcx> { pub fn late_bound_vars(self, id: HirId) -> &'tcx List { self.mk_bound_variable_kinds( - &self - .late_bound_vars_map(id.owner) - .and_then(|map| map.get(&id.local_id).cloned()) - .unwrap_or_else(|| { - bug!("No bound vars found for {}", self.hir().node_to_string(id)) - }), + &self.late_bound_vars_map(id.owner).get(&id.local_id).cloned().unwrap_or_else(|| { + bug!("No bound vars found for {}", self.hir().node_to_string(id)) + }), ) } From 6278e0f50745bafb8563c5765ef6a1622e3718c4 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sun, 18 Aug 2024 16:35:03 +0000 Subject: [PATCH 578/683] Promote crash tests to ui. --- tests/crashes/119716-2.rs | 4 --- tests/crashes/119716.rs | 4 --- tests/crashes/121422.rs | 8 ----- tests/crashes/125843.rs | 4 --- tests/crashes/129099.rs | 15 ---------- .../bound-lifetime-through-dyn-trait.rs | 18 +++++++++++ .../bound-lifetime-through-dyn-trait.stderr | 28 +++++++++++++++++ .../non-lifetime-binder-in-constraint.rs | 13 ++++++++ .../non-lifetime-binder-in-constraint.stderr | 30 +++++++++++++++++++ .../non-lifetime-binder.rs | 10 +++++++ .../non-lifetime-binder.stderr | 25 ++++++++++++++++ 11 files changed, 124 insertions(+), 35 deletions(-) delete mode 100644 tests/crashes/119716-2.rs delete mode 100644 tests/crashes/119716.rs delete mode 100644 tests/crashes/121422.rs delete mode 100644 tests/crashes/125843.rs delete mode 100644 tests/crashes/129099.rs create mode 100644 tests/ui/type-alias-impl-trait/bound-lifetime-through-dyn-trait.rs create mode 100644 tests/ui/type-alias-impl-trait/bound-lifetime-through-dyn-trait.stderr create mode 100644 tests/ui/type-alias-impl-trait/non-lifetime-binder-in-constraint.rs create mode 100644 tests/ui/type-alias-impl-trait/non-lifetime-binder-in-constraint.stderr create mode 100644 tests/ui/type-alias-impl-trait/non-lifetime-binder.rs create mode 100644 tests/ui/type-alias-impl-trait/non-lifetime-binder.stderr diff --git a/tests/crashes/119716-2.rs b/tests/crashes/119716-2.rs deleted file mode 100644 index 47bffb5c1de..00000000000 --- a/tests/crashes/119716-2.rs +++ /dev/null @@ -1,4 +0,0 @@ -//@ known-bug: #119716 -#![feature(non_lifetime_binders)] -trait Trait {} -fn f() -> impl for Trait> {} diff --git a/tests/crashes/119716.rs b/tests/crashes/119716.rs deleted file mode 100644 index d7cba0f51c4..00000000000 --- a/tests/crashes/119716.rs +++ /dev/null @@ -1,4 +0,0 @@ -//@ known-bug: #119716 -#![feature(non_lifetime_binders)] -trait v0 {} -fn kind :(v3main impl for v0<'_, v2 = impl v0 + '_>) {} diff --git a/tests/crashes/121422.rs b/tests/crashes/121422.rs deleted file mode 100644 index 5d7ef6e8ce9..00000000000 --- a/tests/crashes/121422.rs +++ /dev/null @@ -1,8 +0,0 @@ -//@ known-bug: #121422 -#![feature(non_lifetime_binders)] - -trait Trait {} - -fn produce() -> impl for Trait<(), Assoc = impl Trait> { - 16 -} diff --git a/tests/crashes/125843.rs b/tests/crashes/125843.rs deleted file mode 100644 index 8b9a3913c7e..00000000000 --- a/tests/crashes/125843.rs +++ /dev/null @@ -1,4 +0,0 @@ -//@ known-bug: rust-lang/rust#125843 -#![feature(non_lifetime_binders)] -trait v0<> {} -fn kind :(v3main impl for v0<'_, v2 = impl v0 + '_>) {} diff --git a/tests/crashes/129099.rs b/tests/crashes/129099.rs deleted file mode 100644 index 9aaab756b5b..00000000000 --- a/tests/crashes/129099.rs +++ /dev/null @@ -1,15 +0,0 @@ -//@ known-bug: rust-lang/rust#129099 - -#![feature(type_alias_impl_trait)] - -fn dyn_hoops() -> dyn for<'a> Iterator> { - loop {} -} - -pub fn main() { - type Opaque = impl Sized; - fn define() -> Opaque { - let x: Opaque = dyn_hoops::<()>(0); - x - } -} diff --git a/tests/ui/type-alias-impl-trait/bound-lifetime-through-dyn-trait.rs b/tests/ui/type-alias-impl-trait/bound-lifetime-through-dyn-trait.rs new file mode 100644 index 00000000000..df589473a84 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/bound-lifetime-through-dyn-trait.rs @@ -0,0 +1,18 @@ +#![feature(type_alias_impl_trait)] + +trait Captures<'a> {} +impl Captures<'_> for T {} + +fn dyn_hoops() -> dyn for<'a> Iterator> { + //~^ ERROR `impl Trait` cannot capture higher-ranked lifetime from `dyn` type + loop {} +} + +pub fn main() { + //~^ ERROR item does not constrain `Opaque::{opaque#0}`, but has it in its signature + type Opaque = impl Sized; + fn define() -> Opaque { + let x: Opaque = dyn_hoops::<()>(); + x + } +} diff --git a/tests/ui/type-alias-impl-trait/bound-lifetime-through-dyn-trait.stderr b/tests/ui/type-alias-impl-trait/bound-lifetime-through-dyn-trait.stderr new file mode 100644 index 00000000000..59d9ff86c6e --- /dev/null +++ b/tests/ui/type-alias-impl-trait/bound-lifetime-through-dyn-trait.stderr @@ -0,0 +1,28 @@ +error[E0657]: `impl Trait` cannot capture higher-ranked lifetime from `dyn` type + --> $DIR/bound-lifetime-through-dyn-trait.rs:6:71 + | +LL | fn dyn_hoops() -> dyn for<'a> Iterator> { + | ^^ + | +note: lifetime declared here + --> $DIR/bound-lifetime-through-dyn-trait.rs:6:37 + | +LL | fn dyn_hoops() -> dyn for<'a> Iterator> { + | ^^ + +error: item does not constrain `Opaque::{opaque#0}`, but has it in its signature + --> $DIR/bound-lifetime-through-dyn-trait.rs:11:8 + | +LL | pub fn main() { + | ^^^^ + | + = note: consider moving the opaque type's declaration and defining uses into a separate module +note: this opaque type is in the signature + --> $DIR/bound-lifetime-through-dyn-trait.rs:13:19 + | +LL | type Opaque = impl Sized; + | ^^^^^^^^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0657`. diff --git a/tests/ui/type-alias-impl-trait/non-lifetime-binder-in-constraint.rs b/tests/ui/type-alias-impl-trait/non-lifetime-binder-in-constraint.rs new file mode 100644 index 00000000000..dda42580e0f --- /dev/null +++ b/tests/ui/type-alias-impl-trait/non-lifetime-binder-in-constraint.rs @@ -0,0 +1,13 @@ +#![allow(incomplete_features)] +#![feature(non_lifetime_binders)] + +trait Trait {} + +fn produce() -> impl for Trait<(), Assoc = impl Trait> { + //~^ ERROR associated type `Assoc` not found for `Trait` + //~| ERROR associated type `Assoc` not found for `Trait` + //~| the trait bound `{integer}: Trait<()>` is not satisfied + 16 +} + +fn main() {} diff --git a/tests/ui/type-alias-impl-trait/non-lifetime-binder-in-constraint.stderr b/tests/ui/type-alias-impl-trait/non-lifetime-binder-in-constraint.stderr new file mode 100644 index 00000000000..fa3306ff11f --- /dev/null +++ b/tests/ui/type-alias-impl-trait/non-lifetime-binder-in-constraint.stderr @@ -0,0 +1,30 @@ +error[E0220]: associated type `Assoc` not found for `Trait` + --> $DIR/non-lifetime-binder-in-constraint.rs:6:39 + | +LL | fn produce() -> impl for Trait<(), Assoc = impl Trait> { + | ^^^^^ associated type `Assoc` not found + +error[E0220]: associated type `Assoc` not found for `Trait` + --> $DIR/non-lifetime-binder-in-constraint.rs:6:39 + | +LL | fn produce() -> impl for Trait<(), Assoc = impl Trait> { + | ^^^^^ associated type `Assoc` not found + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error[E0277]: the trait bound `{integer}: Trait<()>` is not satisfied + --> $DIR/non-lifetime-binder-in-constraint.rs:6:17 + | +LL | fn produce() -> impl for Trait<(), Assoc = impl Trait> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait<()>` is not implemented for `{integer}` + | +help: this trait has no implementations, consider adding one + --> $DIR/non-lifetime-binder-in-constraint.rs:4:1 + | +LL | trait Trait {} + | ^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0220, E0277. +For more information about an error, try `rustc --explain E0220`. diff --git a/tests/ui/type-alias-impl-trait/non-lifetime-binder.rs b/tests/ui/type-alias-impl-trait/non-lifetime-binder.rs new file mode 100644 index 00000000000..23951c34270 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/non-lifetime-binder.rs @@ -0,0 +1,10 @@ +#![allow(incomplete_features)] +#![feature(non_lifetime_binders)] + +trait Trait {} + +fn f() -> impl for Trait> {} +//~^ ERROR nested `impl Trait` is not allowed +//~| ERROR the trait bound `(): Trait>` is not satisfied + +fn main() {} diff --git a/tests/ui/type-alias-impl-trait/non-lifetime-binder.stderr b/tests/ui/type-alias-impl-trait/non-lifetime-binder.stderr new file mode 100644 index 00000000000..5859d952b75 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/non-lifetime-binder.stderr @@ -0,0 +1,25 @@ +error[E0666]: nested `impl Trait` is not allowed + --> $DIR/non-lifetime-binder.rs:6:29 + | +LL | fn f() -> impl for Trait> {} + | ------------------^^^^^^^^^^^^^- + | | | + | | nested `impl Trait` here + | outer `impl Trait` + +error[E0277]: the trait bound `(): Trait>` is not satisfied + --> $DIR/non-lifetime-binder.rs:6:11 + | +LL | fn f() -> impl for Trait> {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait>` is not implemented for `()` + | +help: this trait has no implementations, consider adding one + --> $DIR/non-lifetime-binder.rs:4:1 + | +LL | trait Trait {} + | ^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0277, E0666. +For more information about an error, try `rustc --explain E0277`. From 98941f76ff5cd166d9c88177cae1e06db08bbe5f Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sun, 18 Aug 2024 16:54:02 +0000 Subject: [PATCH 579/683] Bless incremental tests. --- tests/incremental/hashes/function_interfaces.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/incremental/hashes/function_interfaces.rs b/tests/incremental/hashes/function_interfaces.rs index ab4d578458d..016a1813bab 100644 --- a/tests/incremental/hashes/function_interfaces.rs +++ b/tests/incremental/hashes/function_interfaces.rs @@ -318,9 +318,9 @@ pub fn change_return_impl_trait() -> impl Clone { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg = "cfail2")] +#[rustc_clean(cfg = "cfail2", except = "opt_hir_owner_nodes")] #[rustc_clean(cfg = "cfail3")] -#[rustc_clean(cfg = "cfail5", except = "typeck")] +#[rustc_clean(cfg = "cfail5", except = "opt_hir_owner_nodes, typeck")] #[rustc_clean(cfg = "cfail6")] pub fn change_return_impl_trait() -> impl Copy { 0u32 From ef17eb79bbc5c7f5b303e203c1095e2eb216f84b Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sun, 18 Aug 2024 16:43:39 +0000 Subject: [PATCH 580/683] Adapt clippy. --- .../clippy_lints/src/extra_unused_type_parameters.rs | 8 +------- .../clippy/clippy_lints/src/implied_bounds_in_impls.rs | 9 +++------ src/tools/clippy/clippy_lints/src/len_zero.rs | 6 +----- src/tools/clippy/clippy_lints/src/lifetimes.rs | 8 +++----- src/tools/clippy/clippy_lints/src/manual_async_fn.rs | 6 ++---- src/tools/clippy/clippy_lints/src/missing_doc.rs | 3 +-- src/tools/clippy/clippy_lints/src/missing_inline.rs | 1 - src/tools/clippy/clippy_lints/src/use_self.rs | 10 ++-------- 8 files changed, 13 insertions(+), 38 deletions(-) diff --git a/src/tools/clippy/clippy_lints/src/extra_unused_type_parameters.rs b/src/tools/clippy/clippy_lints/src/extra_unused_type_parameters.rs index 796af851bac..6ad879b9fe7 100644 --- a/src/tools/clippy/clippy_lints/src/extra_unused_type_parameters.rs +++ b/src/tools/clippy/clippy_lints/src/extra_unused_type_parameters.rs @@ -6,7 +6,7 @@ use rustc_errors::Applicability; use rustc_hir::intravisit::{Visitor, walk_impl_item, walk_item, walk_param_bound, walk_ty}; use rustc_hir::{ BodyId, ExprKind, GenericBound, GenericParam, GenericParamKind, Generics, ImplItem, ImplItemKind, Item, ItemKind, - PredicateOrigin, Ty, TyKind, WherePredicate, + PredicateOrigin, Ty, WherePredicate, }; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::hir::nested_filter; @@ -199,12 +199,6 @@ impl<'tcx> Visitor<'tcx> for TypeWalker<'_, 'tcx> { fn visit_ty(&mut self, t: &'tcx Ty<'tcx>) { if let Some((def_id, _)) = t.peel_refs().as_generic_param() { self.ty_params.remove(&def_id); - } else if let TyKind::OpaqueDef(id, _) = t.kind { - // Explicitly walk OpaqueDef. Normally `walk_ty` would do the job, but it calls - // `visit_nested_item`, which checks that `Self::NestedFilter::INTER` is set. We're - // using `OnlyBodies`, so the check ends up failing and the type isn't fully walked. - let item = self.nested_visit_map().item(id); - walk_item(self, item); } else { walk_ty(self, t); } diff --git a/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs b/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs index 6794c6cabfe..5f349d78053 100644 --- a/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs +++ b/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs @@ -3,7 +3,7 @@ use clippy_utils::source::snippet; use rustc_errors::{Applicability, SuggestionStyle}; use rustc_hir::def_id::DefId; use rustc_hir::{ - AssocItemConstraint, GenericArg, GenericBound, GenericBounds, ItemKind, PredicateOrigin, TraitBoundModifier, + AssocItemConstraint, GenericArg, GenericBound, GenericBounds, PredicateOrigin, TraitBoundModifier, TyKind, WherePredicate, }; use rustc_hir_analysis::lower_ty; @@ -342,11 +342,8 @@ impl<'tcx> LateLintPass<'tcx> for ImpliedBoundsInImpls { } } - fn check_ty(&mut self, cx: &LateContext<'_>, ty: &rustc_hir::Ty<'_>) { - if let TyKind::OpaqueDef(item_id, ..) = ty.kind - && let item = cx.tcx.hir().item(item_id) - && let ItemKind::OpaqueTy(opaque_ty) = item.kind - { + fn check_ty(&mut self, cx: &LateContext<'tcx>, ty: &rustc_hir::Ty<'tcx>) { + if let TyKind::OpaqueDef(opaque_ty, ..) = ty.kind { check(cx, opaque_ty.bounds); } } diff --git a/src/tools/clippy/clippy_lints/src/len_zero.rs b/src/tools/clippy/clippy_lints/src/len_zero.rs index 45346cd18a6..311bbce14bd 100644 --- a/src/tools/clippy/clippy_lints/src/len_zero.rs +++ b/src/tools/clippy/clippy_lints/src/len_zero.rs @@ -308,11 +308,7 @@ enum LenOutput { fn extract_future_output<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<&'tcx PathSegment<'tcx>> { if let ty::Alias(_, alias_ty) = ty.kind() - && let Some(Node::Item(item)) = cx.tcx.hir().get_if_local(alias_ty.def_id) - && let Item { - kind: ItemKind::OpaqueTy(opaque), - .. - } = item + && let Some(Node::OpaqueTy(opaque)) = cx.tcx.hir().get_if_local(alias_ty.def_id) && let OpaqueTyOrigin::AsyncFn { .. } = opaque.origin && let [GenericBound::Trait(trait_ref, _)] = &opaque.bounds && let Some(segment) = trait_ref.trait_ref.path.segments.last() diff --git a/src/tools/clippy/clippy_lints/src/lifetimes.rs b/src/tools/clippy/clippy_lints/src/lifetimes.rs index 5c37e735445..7c3ef98fd74 100644 --- a/src/tools/clippy/clippy_lints/src/lifetimes.rs +++ b/src/tools/clippy/clippy_lints/src/lifetimes.rs @@ -6,7 +6,7 @@ use rustc_errors::Applicability; use rustc_hir::FnRetTy::Return; use rustc_hir::intravisit::nested_filter::{self as hir_nested_filter, NestedFilter}; use rustc_hir::intravisit::{ - Visitor, walk_fn_decl, walk_generic_args, walk_generics, walk_impl_item_ref, walk_item, walk_param_bound, + Visitor, walk_fn_decl, walk_generic_args, walk_generics, walk_impl_item_ref, walk_param_bound, walk_poly_trait_ref, walk_trait_ref, walk_ty, walk_where_predicate, }; use rustc_hir::{ @@ -420,11 +420,9 @@ impl<'tcx> Visitor<'tcx> for RefVisitor<'_, 'tcx> { fn visit_ty(&mut self, ty: &'tcx Ty<'_>) { match ty.kind { - TyKind::OpaqueDef(item, bounds) => { - let map = self.cx.tcx.hir(); - let item = map.item(item); + TyKind::OpaqueDef(opaque, bounds) => { let len = self.lts.len(); - walk_item(self, item); + self.visit_opaque_ty(opaque); self.lts.truncate(len); self.lts.extend(bounds.iter().filter_map(|bound| match bound { GenericArg::Lifetime(&l) => Some(l), diff --git a/src/tools/clippy/clippy_lints/src/manual_async_fn.rs b/src/tools/clippy/clippy_lints/src/manual_async_fn.rs index 7097c85156c..81115cffdca 100644 --- a/src/tools/clippy/clippy_lints/src/manual_async_fn.rs +++ b/src/tools/clippy/clippy_lints/src/manual_async_fn.rs @@ -4,7 +4,7 @@ use rustc_errors::Applicability; use rustc_hir::intravisit::FnKind; use rustc_hir::{ Block, Body, Closure, ClosureKind, CoroutineDesugaring, CoroutineKind, CoroutineSource, Expr, ExprKind, FnDecl, - FnRetTy, GenericArg, GenericBound, ImplItem, Item, ItemKind, LifetimeName, Node, TraitRef, Ty, TyKind, + FnRetTy, GenericArg, GenericBound, ImplItem, Item, LifetimeName, Node, TraitRef, Ty, TyKind, }; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; @@ -105,9 +105,7 @@ fn future_trait_ref<'tcx>( cx: &LateContext<'tcx>, ty: &'tcx Ty<'tcx>, ) -> Option<(&'tcx TraitRef<'tcx>, Vec)> { - if let TyKind::OpaqueDef(item_id, bounds) = ty.kind - && let item = cx.tcx.hir().item(item_id) - && let ItemKind::OpaqueTy(opaque) = &item.kind + if let TyKind::OpaqueDef(opaque, bounds) = ty.kind && let Some(trait_ref) = opaque.bounds.iter().find_map(|bound| { if let GenericBound::Trait(poly, _) = bound { Some(&poly.trait_ref) diff --git a/src/tools/clippy/clippy_lints/src/missing_doc.rs b/src/tools/clippy/clippy_lints/src/missing_doc.rs index 64fc1a8a1a5..007bcebdff6 100644 --- a/src/tools/clippy/clippy_lints/src/missing_doc.rs +++ b/src/tools/clippy/clippy_lints/src/missing_doc.rs @@ -193,8 +193,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc { | hir::ItemKind::Trait(..) | hir::ItemKind::TraitAlias(..) | hir::ItemKind::TyAlias(..) - | hir::ItemKind::Union(..) - | hir::ItemKind::OpaqueTy(..) => {}, + | hir::ItemKind::Union(..) => {} hir::ItemKind::ExternCrate(..) | hir::ItemKind::ForeignMod { .. } | hir::ItemKind::GlobalAsm(..) diff --git a/src/tools/clippy/clippy_lints/src/missing_inline.rs b/src/tools/clippy/clippy_lints/src/missing_inline.rs index d342be4545c..f95a0f63fab 100644 --- a/src/tools/clippy/clippy_lints/src/missing_inline.rs +++ b/src/tools/clippy/clippy_lints/src/missing_inline.rs @@ -130,7 +130,6 @@ impl<'tcx> LateLintPass<'tcx> for MissingInline { | hir::ItemKind::GlobalAsm(..) | hir::ItemKind::TyAlias(..) | hir::ItemKind::Union(..) - | hir::ItemKind::OpaqueTy(..) | hir::ItemKind::ExternCrate(..) | hir::ItemKind::ForeignMod { .. } | hir::ItemKind::Impl { .. } diff --git a/src/tools/clippy/clippy_lints/src/use_self.rs b/src/tools/clippy/clippy_lints/src/use_self.rs index 08449de79b3..f5cf4a586fd 100644 --- a/src/tools/clippy/clippy_lints/src/use_self.rs +++ b/src/tools/clippy/clippy_lints/src/use_self.rs @@ -85,10 +85,6 @@ const SEGMENTS_MSG: &str = "segments should be composed of at least 1 element"; impl<'tcx> LateLintPass<'tcx> for UseSelf { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &Item<'tcx>) { - if matches!(item.kind, ItemKind::OpaqueTy(_)) { - // skip over `ItemKind::OpaqueTy` in order to lint `foo() -> impl <..>` - return; - } // We push the self types of `impl`s on a stack here. Only the top type on the stack is // relevant for linting, since this is the self type of the `impl` we're currently in. To // avoid linting on nested items, we push `StackItem::NoCheck` on the stack to signal, that @@ -130,10 +126,8 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf { self.stack.push(stack_item); } - fn check_item_post(&mut self, _: &LateContext<'_>, item: &Item<'_>) { - if !matches!(item.kind, ItemKind::OpaqueTy(_)) { - self.stack.pop(); - } + fn check_item_post(&mut self, _: &LateContext<'_>, _: &Item<'_>) { + self.stack.pop(); } fn check_impl_item(&mut self, cx: &LateContext<'_>, impl_item: &hir::ImplItem<'_>) { From 6b67c46a253d453674401fad70c515d8fd439e35 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sat, 24 Aug 2024 18:19:38 +0000 Subject: [PATCH 581/683] Compute array length from type for unconditional panic. --- .../rustc_mir_transform/src/known_panics_lint.rs | 16 +++++++++------- tests/ui/lint/unconditional_panic_promoted.rs | 8 ++++++++ .../ui/lint/unconditional_panic_promoted.stderr | 10 ++++++++++ 3 files changed, 27 insertions(+), 7 deletions(-) create mode 100644 tests/ui/lint/unconditional_panic_promoted.rs create mode 100644 tests/ui/lint/unconditional_panic_promoted.stderr diff --git a/compiler/rustc_mir_transform/src/known_panics_lint.rs b/compiler/rustc_mir_transform/src/known_panics_lint.rs index ccc029b1e28..8f490094d60 100644 --- a/compiler/rustc_mir_transform/src/known_panics_lint.rs +++ b/compiler/rustc_mir_transform/src/known_panics_lint.rs @@ -600,13 +600,15 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { } Len(place) => { - let len = match self.get_const(place)? { - Value::Immediate(src) => src.len(&self.ecx).discard_err()?, - Value::Aggregate { fields, .. } => fields.len() as u64, - Value::Uninit => match place.ty(self.local_decls(), self.tcx).ty.kind() { - ty::Array(_, n) => n.try_eval_target_usize(self.tcx, self.param_env)?, - _ => return None, - }, + let len = if let ty::Array(_, n) = place.ty(self.local_decls(), self.tcx).ty.kind() + { + n.try_eval_target_usize(self.tcx, self.param_env)? + } else { + match self.get_const(place)? { + Value::Immediate(src) => src.len(&self.ecx).discard_err()?, + Value::Aggregate { fields, .. } => fields.len() as u64, + Value::Uninit => return None, + } }; ImmTy::from_scalar(Scalar::from_target_usize(len, self), layout).into() } diff --git a/tests/ui/lint/unconditional_panic_promoted.rs b/tests/ui/lint/unconditional_panic_promoted.rs new file mode 100644 index 00000000000..37bcf046513 --- /dev/null +++ b/tests/ui/lint/unconditional_panic_promoted.rs @@ -0,0 +1,8 @@ +//@ build-fail + +fn main() { + // MIR encodes this as a reborrow from a promoted constant. + // But the array lenth can still be gotten from the type. + let slice = &[0, 1]; + let _ = slice[2]; //~ ERROR: this operation will panic at runtime [unconditional_panic] +} diff --git a/tests/ui/lint/unconditional_panic_promoted.stderr b/tests/ui/lint/unconditional_panic_promoted.stderr new file mode 100644 index 00000000000..647a84a55fd --- /dev/null +++ b/tests/ui/lint/unconditional_panic_promoted.stderr @@ -0,0 +1,10 @@ +error: this operation will panic at runtime + --> $DIR/unconditional_panic_promoted.rs:7:13 + | +LL | let _ = slice[2]; + | ^^^^^^^^ index out of bounds: the length is 2 but the index is 2 + | + = note: `#[deny(unconditional_panic)]` on by default + +error: aborting due to 1 previous error + From 479779d6a90cc228fc45b5126c558ca52539b2c2 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sun, 25 Aug 2024 12:13:15 +0000 Subject: [PATCH 582/683] Bless clippy. --- .../clippy/tests/ui-toml/unwrap_used/unwrap_used.fixed | 1 + src/tools/clippy/tests/ui-toml/unwrap_used/unwrap_used.rs | 1 + .../clippy/tests/ui-toml/unwrap_used/unwrap_used.stderr | 2 +- src/tools/clippy/tests/ui/get_unwrap.fixed | 1 + src/tools/clippy/tests/ui/get_unwrap.rs | 1 + src/tools/clippy/tests/ui/get_unwrap.stderr | 8 ++++---- 6 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/tools/clippy/tests/ui-toml/unwrap_used/unwrap_used.fixed b/src/tools/clippy/tests/ui-toml/unwrap_used/unwrap_used.fixed index baf939af24e..cdb8fa0454c 100644 --- a/src/tools/clippy/tests/ui-toml/unwrap_used/unwrap_used.fixed +++ b/src/tools/clippy/tests/ui-toml/unwrap_used/unwrap_used.fixed @@ -86,6 +86,7 @@ mod issue9612 { util(); } + #[allow(unconditional_panic)] fn util() { let _a: u8 = 4.try_into().unwrap(); let _a: u8 = 5.try_into().expect(""); diff --git a/src/tools/clippy/tests/ui-toml/unwrap_used/unwrap_used.rs b/src/tools/clippy/tests/ui-toml/unwrap_used/unwrap_used.rs index e300ba18c33..e53d53db5f7 100644 --- a/src/tools/clippy/tests/ui-toml/unwrap_used/unwrap_used.rs +++ b/src/tools/clippy/tests/ui-toml/unwrap_used/unwrap_used.rs @@ -86,6 +86,7 @@ mod issue9612 { util(); } + #[allow(unconditional_panic)] fn util() { let _a: u8 = 4.try_into().unwrap(); let _a: u8 = 5.try_into().expect(""); diff --git a/src/tools/clippy/tests/ui-toml/unwrap_used/unwrap_used.stderr b/src/tools/clippy/tests/ui-toml/unwrap_used/unwrap_used.stderr index 320578bfabc..b58ce9b8af3 100644 --- a/src/tools/clippy/tests/ui-toml/unwrap_used/unwrap_used.stderr +++ b/src/tools/clippy/tests/ui-toml/unwrap_used/unwrap_used.stderr @@ -274,7 +274,7 @@ LL | let _ = &boxed_slice[1]; | ~~~~~~~~~~~~~~~ error: called `.get().unwrap()` on a slice - --> tests/ui-toml/unwrap_used/unwrap_used.rs:93:17 + --> tests/ui-toml/unwrap_used/unwrap_used.rs:94:17 | LL | let _ = Box::new([0]).get(1).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/get_unwrap.fixed b/src/tools/clippy/tests/ui/get_unwrap.fixed index 62beb195939..2dd3c30a4e2 100644 --- a/src/tools/clippy/tests/ui/get_unwrap.fixed +++ b/src/tools/clippy/tests/ui/get_unwrap.fixed @@ -70,6 +70,7 @@ fn main() { mod issue9909 { #![allow(clippy::identity_op, clippy::unwrap_used, dead_code)] + #[allow(unconditional_panic)] fn reduced() { let f = &[1, 2, 3]; diff --git a/src/tools/clippy/tests/ui/get_unwrap.rs b/src/tools/clippy/tests/ui/get_unwrap.rs index 1e09ff5c67e..94226564cac 100644 --- a/src/tools/clippy/tests/ui/get_unwrap.rs +++ b/src/tools/clippy/tests/ui/get_unwrap.rs @@ -70,6 +70,7 @@ fn main() { mod issue9909 { #![allow(clippy::identity_op, clippy::unwrap_used, dead_code)] + #[allow(unconditional_panic)] fn reduced() { let f = &[1, 2, 3]; diff --git a/src/tools/clippy/tests/ui/get_unwrap.stderr b/src/tools/clippy/tests/ui/get_unwrap.stderr index 0f8b279da1e..8eacb249c60 100644 --- a/src/tools/clippy/tests/ui/get_unwrap.stderr +++ b/src/tools/clippy/tests/ui/get_unwrap.stderr @@ -266,7 +266,7 @@ LL | let _ = some_vec.get_mut(0..1).unwrap().to_vec(); = help: consider using `expect()` to provide a better panic message error: called `.get().unwrap()` on a slice - --> tests/ui/get_unwrap.rs:77:24 + --> tests/ui/get_unwrap.rs:78:24 | LL | let _x: &i32 = f.get(1 + 2).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^ @@ -277,7 +277,7 @@ LL | let _x: &i32 = &f[1 + 2]; | ~~~~~~~~~ error: called `.get().unwrap()` on a slice - --> tests/ui/get_unwrap.rs:80:18 + --> tests/ui/get_unwrap.rs:81:18 | LL | let _x = f.get(1 + 2).unwrap().to_string(); | ^^^^^^^^^^^^^^^^^^^^^ @@ -288,7 +288,7 @@ LL | let _x = f[1 + 2].to_string(); | ~~~~~~~~ error: called `.get().unwrap()` on a slice - --> tests/ui/get_unwrap.rs:83:18 + --> tests/ui/get_unwrap.rs:84:18 | LL | let _x = f.get(1 + 2).unwrap().abs(); | ^^^^^^^^^^^^^^^^^^^^^ @@ -299,7 +299,7 @@ LL | let _x = f[1 + 2].abs(); | ~~~~~~~~ error: called `.get_mut().unwrap()` on a slice - --> tests/ui/get_unwrap.rs:100:33 + --> tests/ui/get_unwrap.rs:101:33 | LL | let b = rest.get_mut(linidx(j, k) - linidx(i, k) - 1).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ From 00ed47b8496bacb9da0196127508e07ba5d14bb4 Mon Sep 17 00:00:00 2001 From: est31 Date: Wed, 28 Aug 2024 00:00:08 +0200 Subject: [PATCH 583/683] Make deprecated_cfg_attr_crate_type_name a hard error --- compiler/rustc_expand/messages.ftl | 6 +++ compiler/rustc_expand/src/config.rs | 19 +++------ compiler/rustc_expand/src/errors.rs | 14 +++++++ compiler/rustc_lint/messages.ftl | 6 --- .../rustc_lint/src/context/diagnostics.rs | 6 --- compiler/rustc_lint/src/lib.rs | 5 +++ compiler/rustc_lint/src/lints.rs | 8 ---- compiler/rustc_lint_defs/src/builtin.rs | 37 ----------------- compiler/rustc_lint_defs/src/lib.rs | 2 - ....rs => crate-attributes-using-cfg_attr.rs} | 4 -- .../crate-attributes-using-cfg_attr.stderr | 30 ++++++++++++++ ...pat-crate-attributes-using-cfg_attr.stderr | 41 ------------------- 12 files changed, 60 insertions(+), 118 deletions(-) rename tests/ui/cfg/{future-compat-crate-attributes-using-cfg_attr.rs => crate-attributes-using-cfg_attr.rs} (63%) create mode 100644 tests/ui/cfg/crate-attributes-using-cfg_attr.stderr delete mode 100644 tests/ui/cfg/future-compat-crate-attributes-using-cfg_attr.stderr diff --git a/compiler/rustc_expand/messages.ftl b/compiler/rustc_expand/messages.ftl index 766d96e268f..57bac9d09d5 100644 --- a/compiler/rustc_expand/messages.ftl +++ b/compiler/rustc_expand/messages.ftl @@ -27,6 +27,12 @@ expand_collapse_debuginfo_illegal = expand_count_repetition_misplaced = `count` can not be placed inside the inner-most repetition +expand_crate_name_in_cfg_attr = + `crate_name` within an `#![cfg_attr]` attribute is forbidden + +expand_crate_type_in_cfg_attr = + `crate_type` within an `#![cfg_attr]` attribute is forbidden + expand_custom_attribute_panicked = custom attribute panicked .help = message: {$message} diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs index 32088374277..7bd4372d186 100644 --- a/compiler/rustc_expand/src/config.rs +++ b/compiler/rustc_expand/src/config.rs @@ -21,8 +21,9 @@ use thin_vec::ThinVec; use tracing::instrument; use crate::errors::{ - FeatureNotAllowed, FeatureRemoved, FeatureRemovedReason, InvalidCfg, MalformedFeatureAttribute, - MalformedFeatureAttributeHelp, RemoveExprNotSupported, + CrateNameInCfgAttr, CrateTypeInCfgAttr, FeatureNotAllowed, FeatureRemoved, + FeatureRemovedReason, InvalidCfg, MalformedFeatureAttribute, MalformedFeatureAttributeHelp, + RemoveExprNotSupported, }; /// A folder that strips out items that do not belong in the current configuration. @@ -358,20 +359,10 @@ impl<'a> StripUnconfigured<'a> { item_span, ); if attr.has_name(sym::crate_type) { - self.sess.psess.buffer_lint( - rustc_lint_defs::builtin::DEPRECATED_CFG_ATTR_CRATE_TYPE_NAME, - attr.span, - ast::CRATE_NODE_ID, - BuiltinLintDiag::CrateTypeInCfgAttr, - ); + self.sess.dcx().emit_err(CrateTypeInCfgAttr { span: attr.span }); } if attr.has_name(sym::crate_name) { - self.sess.psess.buffer_lint( - rustc_lint_defs::builtin::DEPRECATED_CFG_ATTR_CRATE_TYPE_NAME, - attr.span, - ast::CRATE_NODE_ID, - BuiltinLintDiag::CrateNameInCfgAttr, - ); + self.sess.dcx().emit_err(CrateNameInCfgAttr { span: attr.span }); } attr } diff --git a/compiler/rustc_expand/src/errors.rs b/compiler/rustc_expand/src/errors.rs index 0fdccb08918..5682c574552 100644 --- a/compiler/rustc_expand/src/errors.rs +++ b/compiler/rustc_expand/src/errors.rs @@ -467,6 +467,20 @@ pub(crate) struct GlobDelegationOutsideImpls { pub span: Span, } +#[derive(Diagnostic)] +#[diag(expand_crate_name_in_cfg_attr)] +pub(crate) struct CrateNameInCfgAttr { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(expand_crate_type_in_cfg_attr)] +pub(crate) struct CrateTypeInCfgAttr { + #[primary_span] + pub span: Span, +} + #[derive(Diagnostic)] #[diag(expand_glob_delegation_traitless_qpath)] pub(crate) struct GlobDelegationTraitlessQpath { diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index 375cfccbe9f..3b360bdef2f 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -203,12 +203,6 @@ lint_confusable_identifier_pair = found both `{$existing_sym}` and `{$sym}` as i .current_use = this identifier can be confused with `{$existing_sym}` .other_use = other identifier used here -lint_crate_name_in_cfg_attr_deprecated = - `crate_name` within an `#![cfg_attr]` attribute is deprecated - -lint_crate_type_in_cfg_attr_deprecated = - `crate_type` within an `#![cfg_attr]` attribute is deprecated - lint_cstring_ptr = getting the inner pointer of a temporary `CString` .as_ptr_label = this pointer will be invalid .unwrap_label = this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime diff --git a/compiler/rustc_lint/src/context/diagnostics.rs b/compiler/rustc_lint/src/context/diagnostics.rs index 168e3a8e92c..b5ab56912cb 100644 --- a/compiler/rustc_lint/src/context/diagnostics.rs +++ b/compiler/rustc_lint/src/context/diagnostics.rs @@ -400,12 +400,6 @@ pub(super) fn decorate_lint(sess: &Session, diagnostic: BuiltinLintDiag, diag: & BuiltinLintDiag::CfgAttrNoAttributes => { lints::CfgAttrNoAttributes.decorate_lint(diag); } - BuiltinLintDiag::CrateTypeInCfgAttr => { - lints::CrateTypeInCfgAttr.decorate_lint(diag); - } - BuiltinLintDiag::CrateNameInCfgAttr => { - lints::CrateNameInCfgAttr.decorate_lint(diag); - } BuiltinLintDiag::MissingFragmentSpecifier => { lints::MissingFragmentSpecifier.decorate_lint(diag); } diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index c74cb866f21..38a9fb8abfc 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -570,6 +570,11 @@ fn register_builtins(store: &mut LintStore) { "converted into hard error, see RFC #3535 \ for more information", ); + store.register_removed( + "deprecated_cfg_attr_crate_type_name", + "converted into hard error, see issue #91632 \ + for more information", + ); store.register_removed( "pointer_structural_match", "converted into hard error, see RFC #3535 \ diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 0045cfcaa56..5187a13bd41 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -2441,14 +2441,6 @@ pub(crate) struct DuplicateMacroAttribute; #[diag(lint_cfg_attr_no_attributes)] pub(crate) struct CfgAttrNoAttributes; -#[derive(LintDiagnostic)] -#[diag(lint_crate_type_in_cfg_attr_deprecated)] -pub(crate) struct CrateTypeInCfgAttr; - -#[derive(LintDiagnostic)] -#[diag(lint_crate_name_in_cfg_attr_deprecated)] -pub(crate) struct CrateNameInCfgAttr; - #[derive(LintDiagnostic)] #[diag(lint_missing_fragment_specifier)] pub(crate) struct MissingFragmentSpecifier; diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 549dc64a562..3cc9cb901a6 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -34,7 +34,6 @@ declare_lint_pass! { DEAD_CODE, DEPENDENCY_ON_UNIT_NEVER_TYPE_FALLBACK, DEPRECATED, - DEPRECATED_CFG_ATTR_CRATE_TYPE_NAME, DEPRECATED_IN_FUTURE, DEPRECATED_SAFE_2024, DEPRECATED_WHERE_CLAUSE_LOCATION, @@ -3143,42 +3142,6 @@ declare_lint! { "detects large moves or copies", } -declare_lint! { - /// The `deprecated_cfg_attr_crate_type_name` lint detects uses of the - /// `#![cfg_attr(..., crate_type = "...")]` and - /// `#![cfg_attr(..., crate_name = "...")]` attributes to conditionally - /// specify the crate type and name in the source code. - /// - /// ### Example - /// - /// ```rust,compile_fail - /// #![cfg_attr(debug_assertions, crate_type = "lib")] - /// ``` - /// - /// {{produces}} - /// - /// - /// ### Explanation - /// - /// The `#![crate_type]` and `#![crate_name]` attributes require a hack in - /// the compiler to be able to change the used crate type and crate name - /// after macros have been expanded. Neither attribute works in combination - /// with Cargo as it explicitly passes `--crate-type` and `--crate-name` on - /// the commandline. These values must match the value used in the source - /// code to prevent an error. - /// - /// To fix the warning use `--crate-type` on the commandline when running - /// rustc instead of `#![cfg_attr(..., crate_type = "...")]` and - /// `--crate-name` instead of `#![cfg_attr(..., crate_name = "...")]`. - pub DEPRECATED_CFG_ATTR_CRATE_TYPE_NAME, - Deny, - "detects usage of `#![cfg_attr(..., crate_type/crate_name = \"...\")]`", - @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps, - reference: "issue #91632 ", - }; -} - declare_lint! { /// The `unexpected_cfgs` lint detects unexpected conditional compilation conditions. /// diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index 734e7069c90..386918a5c41 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -720,8 +720,6 @@ pub enum BuiltinLintDiag { UnnameableTestItems, DuplicateMacroAttribute, CfgAttrNoAttributes, - CrateTypeInCfgAttr, - CrateNameInCfgAttr, MissingFragmentSpecifier, MetaVariableStillRepeating(MacroRulesNormalizedIdent), MetaVariableWrongOperator, diff --git a/tests/ui/cfg/future-compat-crate-attributes-using-cfg_attr.rs b/tests/ui/cfg/crate-attributes-using-cfg_attr.rs similarity index 63% rename from tests/ui/cfg/future-compat-crate-attributes-using-cfg_attr.rs rename to tests/ui/cfg/crate-attributes-using-cfg_attr.rs index 3ced3a630e3..f99fad881f2 100644 --- a/tests/ui/cfg/future-compat-crate-attributes-using-cfg_attr.rs +++ b/tests/ui/cfg/crate-attributes-using-cfg_attr.rs @@ -3,13 +3,9 @@ #![cfg_attr(foo, crate_type="bin")] //~^ERROR `crate_type` within -//~| WARN this was previously accepted //~|ERROR `crate_type` within -//~| WARN this was previously accepted #![cfg_attr(foo, crate_name="bar")] //~^ERROR `crate_name` within -//~| WARN this was previously accepted //~|ERROR `crate_name` within -//~| WARN this was previously accepted fn main() {} diff --git a/tests/ui/cfg/crate-attributes-using-cfg_attr.stderr b/tests/ui/cfg/crate-attributes-using-cfg_attr.stderr new file mode 100644 index 00000000000..1dfca2b88d0 --- /dev/null +++ b/tests/ui/cfg/crate-attributes-using-cfg_attr.stderr @@ -0,0 +1,30 @@ +error: `crate_type` within an `#![cfg_attr]` attribute is forbidden + --> $DIR/crate-attributes-using-cfg_attr.rs:4:18 + | +LL | #![cfg_attr(foo, crate_type="bin")] + | ^^^^^^^^^^^^^^^^ + +error: `crate_name` within an `#![cfg_attr]` attribute is forbidden + --> $DIR/crate-attributes-using-cfg_attr.rs:7:18 + | +LL | #![cfg_attr(foo, crate_name="bar")] + | ^^^^^^^^^^^^^^^^ + +error: `crate_type` within an `#![cfg_attr]` attribute is forbidden + --> $DIR/crate-attributes-using-cfg_attr.rs:4:18 + | +LL | #![cfg_attr(foo, crate_type="bin")] + | ^^^^^^^^^^^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: `crate_name` within an `#![cfg_attr]` attribute is forbidden + --> $DIR/crate-attributes-using-cfg_attr.rs:7:18 + | +LL | #![cfg_attr(foo, crate_name="bar")] + | ^^^^^^^^^^^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: aborting due to 4 previous errors + diff --git a/tests/ui/cfg/future-compat-crate-attributes-using-cfg_attr.stderr b/tests/ui/cfg/future-compat-crate-attributes-using-cfg_attr.stderr deleted file mode 100644 index 82b2d7d1b1d..00000000000 --- a/tests/ui/cfg/future-compat-crate-attributes-using-cfg_attr.stderr +++ /dev/null @@ -1,41 +0,0 @@ -error: `crate_type` within an `#![cfg_attr]` attribute is deprecated - --> $DIR/future-compat-crate-attributes-using-cfg_attr.rs:4:18 - | -LL | #![cfg_attr(foo, crate_type="bin")] - | ^^^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #91632 - = note: `#[deny(deprecated_cfg_attr_crate_type_name)]` on by default - -error: `crate_name` within an `#![cfg_attr]` attribute is deprecated - --> $DIR/future-compat-crate-attributes-using-cfg_attr.rs:9:18 - | -LL | #![cfg_attr(foo, crate_name="bar")] - | ^^^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #91632 - -error: `crate_type` within an `#![cfg_attr]` attribute is deprecated - --> $DIR/future-compat-crate-attributes-using-cfg_attr.rs:4:18 - | -LL | #![cfg_attr(foo, crate_type="bin")] - | ^^^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #91632 - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: `crate_name` within an `#![cfg_attr]` attribute is deprecated - --> $DIR/future-compat-crate-attributes-using-cfg_attr.rs:9:18 - | -LL | #![cfg_attr(foo, crate_name="bar")] - | ^^^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #91632 - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: aborting due to 4 previous errors - From 05f7b092a484c1bd0132ab645800e53be3709aef Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Sat, 5 Oct 2024 08:07:26 +0300 Subject: [PATCH 584/683] remove outdated contribution direction Signed-off-by: onur-ozkan --- src/bootstrap/README.md | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/bootstrap/README.md b/src/bootstrap/README.md index 0ac58645d2d..f036603ee70 100644 --- a/src/bootstrap/README.md +++ b/src/bootstrap/README.md @@ -182,10 +182,8 @@ Some general areas that you may be interested in modifying are: `Config` struct. * Adding a sanity check? Take a look at `bootstrap/src/core/sanity.rs`. -If you make a major change on bootstrap configuration, please remember to: - -+ Update `CONFIG_CHANGE_HISTORY` in `src/bootstrap/src/utils/change_tracker.rs`. -* Update `change-id = {pull-request-id}` in `config.example.toml`. +If you make a major change on bootstrap configuration, please add a new entry to +`CONFIG_CHANGE_HISTORY` in `src/bootstrap/src/utils/change_tracker.rs`. A 'major change' includes From 2feed6279655d6febce04a0efd167c2aea56facf Mon Sep 17 00:00:00 2001 From: ismailarilik Date: Sat, 5 Oct 2024 10:01:27 +0300 Subject: [PATCH 585/683] Handle `rustc_interface` cases of `rustc::potential_query_instability` lint --- compiler/rustc_interface/src/passes.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 204ae437a3e..fd850d2f39a 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -470,7 +470,6 @@ fn write_out_deps(tcx: TyCtxt<'_>, outputs: &OutputFilenames, out_filenames: &[P }) } - #[allow(rustc::potential_query_instability)] let extra_tracked_files = hash_iter_files( file_depinfo.iter().map(|path_sym| normalize_path(PathBuf::from(path_sym.as_str()))), checksum_hash_algo, From d0e67586774530fa8fd70e563768067c0b2ca99d Mon Sep 17 00:00:00 2001 From: onestacked Date: Sun, 29 Sep 2024 23:51:18 +0200 Subject: [PATCH 586/683] Stabilize `const_slice_split_at_mut` and `const_slice_first_last_chunk` --- library/core/src/lib.rs | 1 - library/core/src/slice/mod.rs | 21 ++++++++++++++------- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index b1dbcc744ac..380140601a5 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -146,7 +146,6 @@ #![feature(const_size_of_val)] #![feature(const_size_of_val_raw)] #![feature(const_slice_from_ref)] -#![feature(const_slice_split_at_mut)] #![feature(const_strict_overflow_ops)] #![feature(const_swap)] #![feature(const_try)] diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 754a736b15b..90ddc9c1d85 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -356,7 +356,8 @@ impl [T] { /// ``` #[inline] #[stable(feature = "slice_first_last_chunk", since = "1.77.0")] - #[rustc_const_unstable(feature = "const_slice_first_last_chunk", issue = "111774")] + #[rustc_const_stable(feature = "const_slice_first_last_chunk", since = "CURRENT_RUSTC_VERSION")] + #[cfg_attr(bootstrap, rustc_allow_const_fn_unstable(const_mut_refs))] pub const fn first_chunk_mut(&mut self) -> Option<&mut [T; N]> { if self.len() < N { None @@ -421,7 +422,8 @@ impl [T] { /// ``` #[inline] #[stable(feature = "slice_first_last_chunk", since = "1.77.0")] - #[rustc_const_unstable(feature = "const_slice_first_last_chunk", issue = "111774")] + #[rustc_const_stable(feature = "const_slice_first_last_chunk", since = "CURRENT_RUSTC_VERSION")] + #[cfg_attr(bootstrap, rustc_allow_const_fn_unstable(const_mut_refs))] pub const fn split_first_chunk_mut( &mut self, ) -> Option<(&mut [T; N], &mut [T])> { @@ -491,7 +493,8 @@ impl [T] { /// ``` #[inline] #[stable(feature = "slice_first_last_chunk", since = "1.77.0")] - #[rustc_const_unstable(feature = "const_slice_first_last_chunk", issue = "111774")] + #[rustc_const_stable(feature = "const_slice_first_last_chunk", since = "CURRENT_RUSTC_VERSION")] + #[cfg_attr(bootstrap, rustc_allow_const_fn_unstable(const_mut_refs))] pub const fn split_last_chunk_mut( &mut self, ) -> Option<(&mut [T], &mut [T; N])> { @@ -560,7 +563,8 @@ impl [T] { /// ``` #[inline] #[stable(feature = "slice_first_last_chunk", since = "1.77.0")] - #[rustc_const_unstable(feature = "const_slice_first_last_chunk", issue = "111774")] + #[rustc_const_stable(feature = "const_slice_first_last_chunk", since = "CURRENT_RUSTC_VERSION")] + #[cfg_attr(bootstrap, rustc_allow_const_fn_unstable(const_mut_refs))] pub const fn last_chunk_mut(&mut self) -> Option<&mut [T; N]> { if self.len() < N { None @@ -1903,7 +1907,8 @@ impl [T] { #[inline] #[track_caller] #[must_use] - #[rustc_const_unstable(feature = "const_slice_split_at_mut", issue = "101804")] + #[rustc_const_stable(feature = "const_slice_split_at_mut", since = "CURRENT_RUSTC_VERSION")] + #[cfg_attr(bootstrap, rustc_allow_const_fn_unstable(const_mut_refs))] pub const fn split_at_mut(&mut self, mid: usize) -> (&mut [T], &mut [T]) { match self.split_at_mut_checked(mid) { Some(pair) => pair, @@ -2005,7 +2010,8 @@ impl [T] { /// assert_eq!(v, [1, 2, 3, 4, 5, 6]); /// ``` #[stable(feature = "slice_split_at_unchecked", since = "1.79.0")] - #[rustc_const_unstable(feature = "const_slice_split_at_mut", issue = "101804")] + #[rustc_const_stable(feature = "const_slice_split_at_mut", since = "CURRENT_RUSTC_VERSION")] + #[cfg_attr(bootstrap, rustc_allow_const_fn_unstable(const_mut_refs))] #[inline] #[must_use] pub const unsafe fn split_at_mut_unchecked(&mut self, mid: usize) -> (&mut [T], &mut [T]) { @@ -2105,7 +2111,8 @@ impl [T] { /// assert_eq!(None, v.split_at_mut_checked(7)); /// ``` #[stable(feature = "split_at_checked", since = "1.80.0")] - #[rustc_const_unstable(feature = "const_slice_split_at_mut", issue = "101804")] + #[rustc_const_stable(feature = "const_slice_split_at_mut", since = "CURRENT_RUSTC_VERSION")] + #[cfg_attr(bootstrap, rustc_allow_const_fn_unstable(const_mut_refs))] #[inline] #[must_use] pub const fn split_at_mut_checked(&mut self, mid: usize) -> Option<(&mut [T], &mut [T])> { From 0cd0f7ceef442f2767024df261d3898db23402d8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 4 Oct 2024 17:43:27 +0200 Subject: [PATCH 587/683] move f16/f128 const fn under f16/f128 feature gate --- library/core/src/lib.rs | 2 -- library/core/src/num/f128.rs | 16 ++++++++-------- library/core/src/num/f16.rs | 16 ++++++++-------- .../clippy/tests/ui/transmute_float_to_int.fixed | 4 ++-- .../clippy/tests/ui/transmute_float_to_int.rs | 4 ++-- tests/ui/float/classify-runtime-const.rs | 4 ++-- tests/ui/float/conv-bits-runtime-const.rs | 2 -- 7 files changed, 22 insertions(+), 26 deletions(-) diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index b1dbcc744ac..577ce124251 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -158,8 +158,6 @@ #![feature(coverage_attribute)] #![feature(do_not_recommend)] #![feature(duration_consts_float)] -#![feature(f128_const)] -#![feature(f16_const)] #![feature(internal_impls_macro)] #![feature(ip)] #![feature(is_ascii_octdigit)] diff --git a/library/core/src/num/f128.rs b/library/core/src/num/f128.rs index 133d6e3fc9a..764df4fe4b0 100644 --- a/library/core/src/num/f128.rs +++ b/library/core/src/num/f128.rs @@ -910,7 +910,7 @@ impl f128 { /// ``` #[inline] #[unstable(feature = "f128", issue = "116909")] - #[rustc_const_unstable(feature = "f128_const", issue = "116909")] + #[rustc_const_unstable(feature = "f128", issue = "116909")] #[must_use = "this returns the result of the operation, without modifying the original"] pub const fn to_bits(self) -> u128 { // SAFETY: `u128` is a plain old datatype so we can always transmute to it. @@ -959,7 +959,7 @@ impl f128 { #[inline] #[must_use] #[unstable(feature = "f128", issue = "116909")] - #[rustc_const_unstable(feature = "f128_const", issue = "116909")] + #[rustc_const_unstable(feature = "f128", issue = "116909")] pub const fn from_bits(v: u128) -> Self { // It turns out the safety issues with sNaN were overblown! Hooray! // SAFETY: `u128` is a plain old datatype so we can always transmute from it. @@ -986,7 +986,7 @@ impl f128 { /// ``` #[inline] #[unstable(feature = "f128", issue = "116909")] - #[rustc_const_unstable(feature = "f128_const", issue = "116909")] + #[rustc_const_unstable(feature = "f128", issue = "116909")] #[must_use = "this returns the result of the operation, without modifying the original"] pub const fn to_be_bytes(self) -> [u8; 16] { self.to_bits().to_be_bytes() @@ -1012,7 +1012,7 @@ impl f128 { /// ``` #[inline] #[unstable(feature = "f128", issue = "116909")] - #[rustc_const_unstable(feature = "f128_const", issue = "116909")] + #[rustc_const_unstable(feature = "f128", issue = "116909")] #[must_use = "this returns the result of the operation, without modifying the original"] pub const fn to_le_bytes(self) -> [u8; 16] { self.to_bits().to_le_bytes() @@ -1049,7 +1049,7 @@ impl f128 { /// ``` #[inline] #[unstable(feature = "f128", issue = "116909")] - #[rustc_const_unstable(feature = "f128_const", issue = "116909")] + #[rustc_const_unstable(feature = "f128", issue = "116909")] #[must_use = "this returns the result of the operation, without modifying the original"] pub const fn to_ne_bytes(self) -> [u8; 16] { self.to_bits().to_ne_bytes() @@ -1077,7 +1077,7 @@ impl f128 { #[inline] #[must_use] #[unstable(feature = "f128", issue = "116909")] - #[rustc_const_unstable(feature = "f128_const", issue = "116909")] + #[rustc_const_unstable(feature = "f128", issue = "116909")] pub const fn from_be_bytes(bytes: [u8; 16]) -> Self { Self::from_bits(u128::from_be_bytes(bytes)) } @@ -1104,7 +1104,7 @@ impl f128 { #[inline] #[must_use] #[unstable(feature = "f128", issue = "116909")] - #[rustc_const_unstable(feature = "f128_const", issue = "116909")] + #[rustc_const_unstable(feature = "f128", issue = "116909")] pub const fn from_le_bytes(bytes: [u8; 16]) -> Self { Self::from_bits(u128::from_le_bytes(bytes)) } @@ -1141,7 +1141,7 @@ impl f128 { #[inline] #[must_use] #[unstable(feature = "f128", issue = "116909")] - #[rustc_const_unstable(feature = "f128_const", issue = "116909")] + #[rustc_const_unstable(feature = "f128", issue = "116909")] pub const fn from_ne_bytes(bytes: [u8; 16]) -> Self { Self::from_bits(u128::from_ne_bytes(bytes)) } diff --git a/library/core/src/num/f16.rs b/library/core/src/num/f16.rs index e50f5e7e8fb..897fc8c105d 100644 --- a/library/core/src/num/f16.rs +++ b/library/core/src/num/f16.rs @@ -896,7 +896,7 @@ impl f16 { /// ``` #[inline] #[unstable(feature = "f16", issue = "116909")] - #[rustc_const_unstable(feature = "f16_const", issue = "116909")] + #[rustc_const_unstable(feature = "f16", issue = "116909")] #[must_use = "this returns the result of the operation, without modifying the original"] pub const fn to_bits(self) -> u16 { // SAFETY: `u16` is a plain old datatype so we can always transmute to it. @@ -944,7 +944,7 @@ impl f16 { #[inline] #[must_use] #[unstable(feature = "f16", issue = "116909")] - #[rustc_const_unstable(feature = "f16_const", issue = "116909")] + #[rustc_const_unstable(feature = "f16", issue = "116909")] pub const fn from_bits(v: u16) -> Self { // It turns out the safety issues with sNaN were overblown! Hooray! // SAFETY: `u16` is a plain old datatype so we can always transmute from it. @@ -970,7 +970,7 @@ impl f16 { /// ``` #[inline] #[unstable(feature = "f16", issue = "116909")] - #[rustc_const_unstable(feature = "f16_const", issue = "116909")] + #[rustc_const_unstable(feature = "f16", issue = "116909")] #[must_use = "this returns the result of the operation, without modifying the original"] pub const fn to_be_bytes(self) -> [u8; 2] { self.to_bits().to_be_bytes() @@ -995,7 +995,7 @@ impl f16 { /// ``` #[inline] #[unstable(feature = "f16", issue = "116909")] - #[rustc_const_unstable(feature = "f16_const", issue = "116909")] + #[rustc_const_unstable(feature = "f16", issue = "116909")] #[must_use = "this returns the result of the operation, without modifying the original"] pub const fn to_le_bytes(self) -> [u8; 2] { self.to_bits().to_le_bytes() @@ -1033,7 +1033,7 @@ impl f16 { /// ``` #[inline] #[unstable(feature = "f16", issue = "116909")] - #[rustc_const_unstable(feature = "f16_const", issue = "116909")] + #[rustc_const_unstable(feature = "f16", issue = "116909")] #[must_use = "this returns the result of the operation, without modifying the original"] pub const fn to_ne_bytes(self) -> [u8; 2] { self.to_bits().to_ne_bytes() @@ -1057,7 +1057,7 @@ impl f16 { #[inline] #[must_use] #[unstable(feature = "f16", issue = "116909")] - #[rustc_const_unstable(feature = "f16_const", issue = "116909")] + #[rustc_const_unstable(feature = "f16", issue = "116909")] pub const fn from_be_bytes(bytes: [u8; 2]) -> Self { Self::from_bits(u16::from_be_bytes(bytes)) } @@ -1080,7 +1080,7 @@ impl f16 { #[inline] #[must_use] #[unstable(feature = "f16", issue = "116909")] - #[rustc_const_unstable(feature = "f16_const", issue = "116909")] + #[rustc_const_unstable(feature = "f16", issue = "116909")] pub const fn from_le_bytes(bytes: [u8; 2]) -> Self { Self::from_bits(u16::from_le_bytes(bytes)) } @@ -1114,7 +1114,7 @@ impl f16 { #[inline] #[must_use] #[unstable(feature = "f16", issue = "116909")] - #[rustc_const_unstable(feature = "f16_const", issue = "116909")] + #[rustc_const_unstable(feature = "f16", issue = "116909")] pub const fn from_ne_bytes(bytes: [u8; 2]) -> Self { Self::from_bits(u16::from_ne_bytes(bytes)) } diff --git a/src/tools/clippy/tests/ui/transmute_float_to_int.fixed b/src/tools/clippy/tests/ui/transmute_float_to_int.fixed index 83814ca43b9..075a198918a 100644 --- a/src/tools/clippy/tests/ui/transmute_float_to_int.fixed +++ b/src/tools/clippy/tests/ui/transmute_float_to_int.fixed @@ -1,7 +1,7 @@ #![warn(clippy::transmute_float_to_int)] #![allow(clippy::missing_transmute_annotations)] -#![feature(f128, f128_const)] -#![feature(f16, f16_const)] +#![feature(f128)] +#![feature(f16)] fn float_to_int() { let _: u32 = unsafe { 1f32.to_bits() }; diff --git a/src/tools/clippy/tests/ui/transmute_float_to_int.rs b/src/tools/clippy/tests/ui/transmute_float_to_int.rs index 64d6e917203..12541b2f7cf 100644 --- a/src/tools/clippy/tests/ui/transmute_float_to_int.rs +++ b/src/tools/clippy/tests/ui/transmute_float_to_int.rs @@ -1,7 +1,7 @@ #![warn(clippy::transmute_float_to_int)] #![allow(clippy::missing_transmute_annotations)] -#![feature(f128, f128_const)] -#![feature(f16, f16_const)] +#![feature(f128)] +#![feature(f16)] fn float_to_int() { let _: u32 = unsafe { std::mem::transmute(1f32) }; diff --git a/tests/ui/float/classify-runtime-const.rs b/tests/ui/float/classify-runtime-const.rs index 2a24e51cabb..ca852ea2468 100644 --- a/tests/ui/float/classify-runtime-const.rs +++ b/tests/ui/float/classify-runtime-const.rs @@ -6,8 +6,8 @@ // This tests the float classification functions, for regular runtime code and for const evaluation. -#![feature(f16_const)] -#![feature(f128_const)] +#![feature(f16)] +#![feature(f128)] use std::num::FpCategory::*; diff --git a/tests/ui/float/conv-bits-runtime-const.rs b/tests/ui/float/conv-bits-runtime-const.rs index 60c45cc4cc1..3046728fe66 100644 --- a/tests/ui/float/conv-bits-runtime-const.rs +++ b/tests/ui/float/conv-bits-runtime-const.rs @@ -5,8 +5,6 @@ #![feature(f16)] #![feature(f128)] -#![feature(f16_const)] -#![feature(f128_const)] #![allow(unused_macro_rules)] use std::hint::black_box; From 155380523c1fe0381255556d2b0588f9a0fdcacd Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 5 Oct 2024 10:40:38 +0200 Subject: [PATCH 588/683] pthread mutex: better error in reentrant-locking-UB, also test PTHREAD_MUTEX_INITIALIZER --- src/tools/miri/src/shims/unix/sync.rs | 4 +++- ...ck.rs => libc_pthread_mutex_NULL_reentrant.rs} | 4 ++-- ...r => libc_pthread_mutex_NULL_reentrant.stderr} | 8 ++++---- ...rs => libc_pthread_mutex_default_reentrant.rs} | 9 +++++++-- ...> libc_pthread_mutex_default_reentrant.stderr} | 8 ++++---- ....rs => libc_pthread_mutex_normal_reentrant.rs} | 2 ++ ...=> libc_pthread_mutex_normal_reentrant.stderr} | 4 ++-- .../libc_pthread_mutex_staticinit_reentrant.rs | 12 ++++++++++++ ...libc_pthread_mutex_staticinit_reentrant.stderr | 15 +++++++++++++++ 9 files changed, 51 insertions(+), 15 deletions(-) rename src/tools/miri/tests/fail-dep/concurrency/{libc_pthread_mutex_NULL_deadlock.rs => libc_pthread_mutex_NULL_reentrant.rs} (72%) rename src/tools/miri/tests/fail-dep/concurrency/{libc_pthread_mutex_NULL_deadlock.stderr => libc_pthread_mutex_NULL_reentrant.stderr} (68%) rename src/tools/miri/tests/fail-dep/concurrency/{libc_pthread_mutex_default_deadlock.rs => libc_pthread_mutex_default_reentrant.rs} (52%) rename src/tools/miri/tests/fail-dep/concurrency/{libc_pthread_mutex_default_deadlock.stderr => libc_pthread_mutex_default_reentrant.stderr} (68%) rename src/tools/miri/tests/fail-dep/concurrency/{libc_pthread_mutex_normal_deadlock.rs => libc_pthread_mutex_normal_reentrant.rs} (81%) rename src/tools/miri/tests/fail-dep/concurrency/{libc_pthread_mutex_normal_deadlock.stderr => libc_pthread_mutex_normal_reentrant.stderr} (79%) create mode 100644 src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_staticinit_reentrant.rs create mode 100644 src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_staticinit_reentrant.stderr diff --git a/src/tools/miri/src/shims/unix/sync.rs b/src/tools/miri/src/shims/unix/sync.rs index 017291f81a2..b05f340861e 100644 --- a/src/tools/miri/src/shims/unix/sync.rs +++ b/src/tools/miri/src/shims/unix/sync.rs @@ -483,7 +483,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Trying to acquire the same mutex again. match kind { MutexKind::Default => - throw_ub_format!("trying to acquire already locked default mutex"), + throw_ub_format!( + "trying to acquire default mutex already locked by the current thread" + ), MutexKind::Normal => throw_machine_stop!(TerminationInfo::Deadlock), MutexKind::ErrorCheck => this.eval_libc_i32("EDEADLK"), MutexKind::Recursive => { diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_NULL_deadlock.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_NULL_reentrant.rs similarity index 72% rename from src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_NULL_deadlock.rs rename to src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_NULL_reentrant.rs index a79abe65328..f2df8bdca12 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_NULL_deadlock.rs +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_NULL_reentrant.rs @@ -1,12 +1,12 @@ //@ignore-target: windows # No pthreads on Windows // -// Check that if we pass NULL attribute, then we get the default mutex type. +// Check that if we pass NULL attribute, then reentrant locking is UB. fn main() { unsafe { let mut mutex: libc::pthread_mutex_t = std::mem::zeroed(); assert_eq!(libc::pthread_mutex_init(&mut mutex as *mut _, std::ptr::null() as *const _), 0); assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), 0); - libc::pthread_mutex_lock(&mut mutex as *mut _); //~ ERROR: Undefined Behavior: trying to acquire already locked default mutex + libc::pthread_mutex_lock(&mut mutex as *mut _); //~ ERROR: already locked by the current thread } } diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_NULL_deadlock.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_NULL_reentrant.stderr similarity index 68% rename from src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_NULL_deadlock.stderr rename to src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_NULL_reentrant.stderr index e9961ed413d..9455e704376 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_NULL_deadlock.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_NULL_reentrant.stderr @@ -1,13 +1,13 @@ -error: Undefined Behavior: trying to acquire already locked default mutex - --> tests/fail-dep/concurrency/libc_pthread_mutex_NULL_deadlock.rs:LL:CC +error: Undefined Behavior: trying to acquire default mutex already locked by the current thread + --> tests/fail-dep/concurrency/libc_pthread_mutex_NULL_reentrant.rs:LL:CC | LL | libc::pthread_mutex_lock(&mut mutex as *mut _); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trying to acquire already locked default mutex + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trying to acquire default mutex already locked by the current thread | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at tests/fail-dep/concurrency/libc_pthread_mutex_NULL_deadlock.rs:LL:CC + = note: inside `main` at tests/fail-dep/concurrency/libc_pthread_mutex_NULL_reentrant.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_default_deadlock.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_default_reentrant.rs similarity index 52% rename from src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_default_deadlock.rs rename to src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_default_reentrant.rs index d9293f938b6..d2d0ffff07a 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_default_deadlock.rs +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_default_reentrant.rs @@ -1,6 +1,11 @@ //@ignore-target: windows # No pthreads on Windows // -// Check that if we do not set the mutex type, it is the default. +// Check that if we do not set the mutex type, it is UB to do reentrant locking. glibc apparently +// actually exploits this, see +// : +// one must actively call pthread_mutexattr_settype to disable lock elision. This means a call to +// pthread_mutexattr_settype(PTHREAD_MUTEX_NORMAL) makes a difference even if +// PTHREAD_MUTEX_NORMAL == PTHREAD_MUTEX_DEFAULT! fn main() { unsafe { @@ -9,6 +14,6 @@ fn main() { let mut mutex: libc::pthread_mutex_t = std::mem::zeroed(); assert_eq!(libc::pthread_mutex_init(&mut mutex as *mut _, &mutexattr as *const _), 0); assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), 0); - libc::pthread_mutex_lock(&mut mutex as *mut _); //~ ERROR: Undefined Behavior: trying to acquire already locked default mutex + libc::pthread_mutex_lock(&mut mutex as *mut _); //~ ERROR: already locked by the current thread } } diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_default_deadlock.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_default_reentrant.stderr similarity index 68% rename from src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_default_deadlock.stderr rename to src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_default_reentrant.stderr index a57d10753d9..a9ffbde1b65 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_default_deadlock.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_default_reentrant.stderr @@ -1,13 +1,13 @@ -error: Undefined Behavior: trying to acquire already locked default mutex - --> tests/fail-dep/concurrency/libc_pthread_mutex_default_deadlock.rs:LL:CC +error: Undefined Behavior: trying to acquire default mutex already locked by the current thread + --> tests/fail-dep/concurrency/libc_pthread_mutex_default_reentrant.rs:LL:CC | LL | libc::pthread_mutex_lock(&mut mutex as *mut _); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trying to acquire already locked default mutex + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trying to acquire default mutex already locked by the current thread | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at tests/fail-dep/concurrency/libc_pthread_mutex_default_deadlock.rs:LL:CC + = note: inside `main` at tests/fail-dep/concurrency/libc_pthread_mutex_default_reentrant.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_normal_deadlock.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_normal_reentrant.rs similarity index 81% rename from src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_normal_deadlock.rs rename to src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_normal_reentrant.rs index b38582482b8..9a88639edf7 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_normal_deadlock.rs +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_normal_reentrant.rs @@ -10,6 +10,8 @@ fn main() { let mut mutex: libc::pthread_mutex_t = std::mem::zeroed(); assert_eq!(libc::pthread_mutex_init(&mut mutex as *mut _, &mutexattr as *const _), 0); assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), 0); + // A "normal" mutex properly tries to acquire the lock even if its is already held + // by the current thread -- and then we deadlock. libc::pthread_mutex_lock(&mut mutex as *mut _); //~ ERROR: deadlock: the evaluated program deadlocked } } diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_normal_deadlock.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_normal_reentrant.stderr similarity index 79% rename from src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_normal_deadlock.stderr rename to src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_normal_reentrant.stderr index 4337475963e..f20b26297e2 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_normal_deadlock.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_normal_reentrant.stderr @@ -1,11 +1,11 @@ error: deadlock: the evaluated program deadlocked - --> tests/fail-dep/concurrency/libc_pthread_mutex_normal_deadlock.rs:LL:CC + --> tests/fail-dep/concurrency/libc_pthread_mutex_normal_reentrant.rs:LL:CC | LL | libc::pthread_mutex_lock(&mut mutex as *mut _); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the evaluated program deadlocked | = note: BACKTRACE: - = note: inside `main` at tests/fail-dep/concurrency/libc_pthread_mutex_normal_deadlock.rs:LL:CC + = note: inside `main` at tests/fail-dep/concurrency/libc_pthread_mutex_normal_reentrant.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_staticinit_reentrant.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_staticinit_reentrant.rs new file mode 100644 index 00000000000..bd8aef787e6 --- /dev/null +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_staticinit_reentrant.rs @@ -0,0 +1,12 @@ +//@ignore-target: windows # No pthreads on Windows +// +// Check that if we use PTHREAD_MUTEX_INITIALIZER, then reentrant locking is UB. +// glibc apparently actually exploits this so we better catch it! + +fn main() { + unsafe { + let mut mutex: libc::pthread_mutex_t = libc::PTHREAD_MUTEX_INITIALIZER; + assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), 0); + libc::pthread_mutex_lock(&mut mutex as *mut _); //~ ERROR: already locked by the current thread + } +} diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_staticinit_reentrant.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_staticinit_reentrant.stderr new file mode 100644 index 00000000000..984bb07b728 --- /dev/null +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_staticinit_reentrant.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: trying to acquire default mutex already locked by the current thread + --> tests/fail-dep/concurrency/libc_pthread_mutex_staticinit_reentrant.rs:LL:CC + | +LL | libc::pthread_mutex_lock(&mut mutex as *mut _); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trying to acquire default mutex already locked by the current thread + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: BACKTRACE: + = note: inside `main` at tests/fail-dep/concurrency/libc_pthread_mutex_staticinit_reentrant.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + From 98aa3d96e2d93eefa50374f1ea6057377bcec17b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 5 Oct 2024 11:08:33 +0200 Subject: [PATCH 589/683] make Cell unstably const --- library/core/src/cell.rs | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs index 690d4395137..95cf55a923e 100644 --- a/library/core/src/cell.rs +++ b/library/core/src/cell.rs @@ -494,8 +494,9 @@ impl Cell { /// ``` #[inline] #[stable(feature = "move_cell", since = "1.17.0")] + #[rustc_const_unstable(feature = "const_cell", issue = "131283")] #[rustc_confusables("swap")] - pub fn replace(&self, val: T) -> T { + pub const fn replace(&self, val: T) -> T { // SAFETY: This can cause data races if called from a separate thread, // but `Cell` is `!Sync` so this won't happen. mem::replace(unsafe { &mut *self.value.get() }, val) @@ -535,7 +536,8 @@ impl Cell { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - pub fn get(&self) -> T { + #[rustc_const_unstable(feature = "const_cell", issue = "131283")] + pub const fn get(&self) -> T { // SAFETY: This can cause data races if called from a separate thread, // but `Cell` is `!Sync` so this won't happen. unsafe { *self.value.get() } @@ -613,7 +615,8 @@ impl Cell { /// ``` #[inline] #[stable(feature = "cell_get_mut", since = "1.11.0")] - pub fn get_mut(&mut self) -> &mut T { + #[rustc_const_unstable(feature = "const_cell", issue = "131283")] + pub const fn get_mut(&mut self) -> &mut T { self.value.get_mut() } @@ -632,7 +635,8 @@ impl Cell { /// ``` #[inline] #[stable(feature = "as_cell", since = "1.37.0")] - pub fn from_mut(t: &mut T) -> &Cell { + #[rustc_const_unstable(feature = "const_cell", issue = "131283")] + pub const fn from_mut(t: &mut T) -> &Cell { // SAFETY: `&mut` ensures unique access. unsafe { &*(t as *mut T as *const Cell) } } @@ -686,7 +690,8 @@ impl Cell<[T]> { /// assert_eq!(slice_cell.len(), 3); /// ``` #[stable(feature = "as_cell", since = "1.37.0")] - pub fn as_slice_of_cells(&self) -> &[Cell] { + #[rustc_const_unstable(feature = "const_cell", issue = "131283")] + pub const fn as_slice_of_cells(&self) -> &[Cell] { // SAFETY: `Cell` has the same memory layout as `T`. unsafe { &*(self as *const Cell<[T]> as *const [Cell]) } } @@ -706,7 +711,8 @@ impl Cell<[T; N]> { /// let array_cell: &[Cell; 3] = cell_array.as_array_of_cells(); /// ``` #[unstable(feature = "as_array_of_cells", issue = "88248")] - pub fn as_array_of_cells(&self) -> &[Cell; N] { + #[rustc_const_unstable(feature = "as_array_of_cells", issue = "88248")] + pub const fn as_array_of_cells(&self) -> &[Cell; N] { // SAFETY: `Cell` has the same memory layout as `T`. unsafe { &*(self as *const Cell<[T; N]> as *const [Cell; N]) } } From b22b348e0d0334c42521aed90955cb39bd0d278c Mon Sep 17 00:00:00 2001 From: Henri Lunnikivi Date: Thu, 19 Sep 2024 13:14:52 +0300 Subject: [PATCH 590/683] Add targets: riscv32{e|em|emc} - Based on riscv32{i|im|imc} - Set data_layout stack alignment: S32 (bits) - Set llvm_abiname = ilp32e --- compiler/rustc_target/src/spec/mod.rs | 4 +++ .../spec/targets/riscv32e_unknown_none_elf.rs | 25 +++++++++++++++++++ .../targets/riscv32em_unknown_none_elf.rs | 25 +++++++++++++++++++ .../targets/riscv32emc_unknown_none_elf.rs | 25 +++++++++++++++++++ 4 files changed, 79 insertions(+) create mode 100644 compiler/rustc_target/src/spec/targets/riscv32e_unknown_none_elf.rs create mode 100644 compiler/rustc_target/src/spec/targets/riscv32em_unknown_none_elf.rs create mode 100644 compiler/rustc_target/src/spec/targets/riscv32emc_unknown_none_elf.rs diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 18ec8ee9476..82e11a3afce 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -1841,6 +1841,10 @@ supported_targets! { ("riscv32imac-esp-espidf", riscv32imac_esp_espidf), ("riscv32imafc-esp-espidf", riscv32imafc_esp_espidf), + ("riscv32e-unknown-none-elf", riscv32e_unknown_none_elf), + ("riscv32em-unknown-none-elf", riscv32em_unknown_none_elf), + ("riscv32emc-unknown-none-elf", riscv32emc_unknown_none_elf), + ("riscv32imac-unknown-none-elf", riscv32imac_unknown_none_elf), ("riscv32imafc-unknown-none-elf", riscv32imafc_unknown_none_elf), ("riscv32imac-unknown-xous-elf", riscv32imac_unknown_xous_elf), diff --git a/compiler/rustc_target/src/spec/targets/riscv32e_unknown_none_elf.rs b/compiler/rustc_target/src/spec/targets/riscv32e_unknown_none_elf.rs new file mode 100644 index 00000000000..71a5607f927 --- /dev/null +++ b/compiler/rustc_target/src/spec/targets/riscv32e_unknown_none_elf.rs @@ -0,0 +1,25 @@ +use crate::spec::{Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetOptions}; + +pub fn target() -> Target { + Target { + data_layout: "e-m:e-p:32:32-i64:64-n32-S32".into(), + llvm_target: "riscv32".into(), + pointer_width: 32, + arch: "riscv32".into(), + + options: TargetOptions { + linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes), + linker: Some("rust-lld".into()), + cpu: "generic-rv32".into(), + llvm_abiname: "ilp32e".into(), + max_atomic_width: Some(32), + atomic_cas: false, + features: "+e,+forced-atomics".into(), + panic_strategy: PanicStrategy::Abort, + relocation_model: RelocModel::Static, + emit_debug_gdb_scripts: false, + eh_frame_header: false, + ..Default::default() + }, + } +} diff --git a/compiler/rustc_target/src/spec/targets/riscv32em_unknown_none_elf.rs b/compiler/rustc_target/src/spec/targets/riscv32em_unknown_none_elf.rs new file mode 100644 index 00000000000..ed7a006963d --- /dev/null +++ b/compiler/rustc_target/src/spec/targets/riscv32em_unknown_none_elf.rs @@ -0,0 +1,25 @@ +use crate::spec::{Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetOptions}; + +pub fn target() -> Target { + Target { + data_layout: "e-m:e-p:32:32-i64:64-n32-S32".into(), + llvm_target: "riscv32".into(), + pointer_width: 32, + arch: "riscv32".into(), + + options: TargetOptions { + linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes), + linker: Some("rust-lld".into()), + cpu: "generic-rv32".into(), + llvm_abiname: "ilp32e".into(), + max_atomic_width: Some(32), + atomic_cas: false, + features: "+e,+m,+forced-atomics".into(), + panic_strategy: PanicStrategy::Abort, + relocation_model: RelocModel::Static, + emit_debug_gdb_scripts: false, + eh_frame_header: false, + ..Default::default() + }, + } +} diff --git a/compiler/rustc_target/src/spec/targets/riscv32emc_unknown_none_elf.rs b/compiler/rustc_target/src/spec/targets/riscv32emc_unknown_none_elf.rs new file mode 100644 index 00000000000..cba19c28be3 --- /dev/null +++ b/compiler/rustc_target/src/spec/targets/riscv32emc_unknown_none_elf.rs @@ -0,0 +1,25 @@ +use crate::spec::{Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetOptions}; + +pub fn target() -> Target { + Target { + data_layout: "e-m:e-p:32:32-i64:64-n32-S32".into(), + llvm_target: "riscv32".into(), + pointer_width: 32, + arch: "riscv32".into(), + + options: TargetOptions { + linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes), + linker: Some("rust-lld".into()), + cpu: "generic-rv32".into(), + llvm_abiname: "ilp32e".into(), + max_atomic_width: Some(32), + atomic_cas: false, + features: "+e,+m,+c,+forced-atomics".into(), + panic_strategy: PanicStrategy::Abort, + relocation_model: RelocModel::Static, + emit_debug_gdb_scripts: false, + eh_frame_header: false, + ..Default::default() + }, + } +} From 7a0bac49c8bbdd06869aad64d2ea25e41b24cb9d Mon Sep 17 00:00:00 2001 From: Henri Lunnikivi Date: Fri, 4 Oct 2024 19:18:25 +0300 Subject: [PATCH 591/683] Add comment: data_layout --- .../rustc_target/src/spec/targets/riscv32e_unknown_none_elf.rs | 3 +++ .../src/spec/targets/riscv32em_unknown_none_elf.rs | 3 +++ .../src/spec/targets/riscv32emc_unknown_none_elf.rs | 3 +++ 3 files changed, 9 insertions(+) diff --git a/compiler/rustc_target/src/spec/targets/riscv32e_unknown_none_elf.rs b/compiler/rustc_target/src/spec/targets/riscv32e_unknown_none_elf.rs index 71a5607f927..9aeb591cb57 100644 --- a/compiler/rustc_target/src/spec/targets/riscv32e_unknown_none_elf.rs +++ b/compiler/rustc_target/src/spec/targets/riscv32e_unknown_none_elf.rs @@ -2,6 +2,8 @@ use crate::spec::{Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, Targ pub fn target() -> Target { Target { + // The below `data_layout` is explicitly specified by the ilp32e ABI in LLVM. See also + // `options.llvm_abiname`. data_layout: "e-m:e-p:32:32-i64:64-n32-S32".into(), llvm_target: "riscv32".into(), pointer_width: 32, @@ -11,6 +13,7 @@ pub fn target() -> Target { linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes), linker: Some("rust-lld".into()), cpu: "generic-rv32".into(), + // The ilp32e ABI specifies the `data_layout` llvm_abiname: "ilp32e".into(), max_atomic_width: Some(32), atomic_cas: false, diff --git a/compiler/rustc_target/src/spec/targets/riscv32em_unknown_none_elf.rs b/compiler/rustc_target/src/spec/targets/riscv32em_unknown_none_elf.rs index ed7a006963d..07b1a0228a2 100644 --- a/compiler/rustc_target/src/spec/targets/riscv32em_unknown_none_elf.rs +++ b/compiler/rustc_target/src/spec/targets/riscv32em_unknown_none_elf.rs @@ -2,6 +2,8 @@ use crate::spec::{Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, Targ pub fn target() -> Target { Target { + // The below `data_layout` is explicitly specified by the ilp32e ABI in LLVM. See also + // `options.llvm_abiname`. data_layout: "e-m:e-p:32:32-i64:64-n32-S32".into(), llvm_target: "riscv32".into(), pointer_width: 32, @@ -11,6 +13,7 @@ pub fn target() -> Target { linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes), linker: Some("rust-lld".into()), cpu: "generic-rv32".into(), + // The ilp32e ABI specifies the `data_layout` llvm_abiname: "ilp32e".into(), max_atomic_width: Some(32), atomic_cas: false, diff --git a/compiler/rustc_target/src/spec/targets/riscv32emc_unknown_none_elf.rs b/compiler/rustc_target/src/spec/targets/riscv32emc_unknown_none_elf.rs index cba19c28be3..18da14a00d4 100644 --- a/compiler/rustc_target/src/spec/targets/riscv32emc_unknown_none_elf.rs +++ b/compiler/rustc_target/src/spec/targets/riscv32emc_unknown_none_elf.rs @@ -2,6 +2,8 @@ use crate::spec::{Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, Targ pub fn target() -> Target { Target { + // The below `data_layout` is explicitly specified by the ilp32e ABI in LLVM. See also + // `options.llvm_abiname`. data_layout: "e-m:e-p:32:32-i64:64-n32-S32".into(), llvm_target: "riscv32".into(), pointer_width: 32, @@ -11,6 +13,7 @@ pub fn target() -> Target { linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes), linker: Some("rust-lld".into()), cpu: "generic-rv32".into(), + // The ilp32e ABI specifies the `data_layout` llvm_abiname: "ilp32e".into(), max_atomic_width: Some(32), atomic_cas: false, From 04099b663c1ee252be058f27147d2e6cfec9ec5f Mon Sep 17 00:00:00 2001 From: Henri Lunnikivi Date: Thu, 19 Sep 2024 13:24:21 +0300 Subject: [PATCH 592/683] Update target fns to latest main --- .../src/spec/targets/riscv32e_unknown_none_elf.rs | 8 +++++++- .../src/spec/targets/riscv32em_unknown_none_elf.rs | 8 +++++++- .../src/spec/targets/riscv32emc_unknown_none_elf.rs | 8 +++++++- 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_target/src/spec/targets/riscv32e_unknown_none_elf.rs b/compiler/rustc_target/src/spec/targets/riscv32e_unknown_none_elf.rs index 9aeb591cb57..b1f52973c10 100644 --- a/compiler/rustc_target/src/spec/targets/riscv32e_unknown_none_elf.rs +++ b/compiler/rustc_target/src/spec/targets/riscv32e_unknown_none_elf.rs @@ -1,11 +1,17 @@ use crate::spec::{Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetOptions}; -pub fn target() -> Target { +pub(crate) fn target() -> Target { Target { // The below `data_layout` is explicitly specified by the ilp32e ABI in LLVM. See also // `options.llvm_abiname`. data_layout: "e-m:e-p:32:32-i64:64-n32-S32".into(), llvm_target: "riscv32".into(), + metadata: crate::spec::TargetMetadata { + description: Some("Bare RISC-V (RV32E ISA)".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(false), + }, pointer_width: 32, arch: "riscv32".into(), diff --git a/compiler/rustc_target/src/spec/targets/riscv32em_unknown_none_elf.rs b/compiler/rustc_target/src/spec/targets/riscv32em_unknown_none_elf.rs index 07b1a0228a2..feeaa48778d 100644 --- a/compiler/rustc_target/src/spec/targets/riscv32em_unknown_none_elf.rs +++ b/compiler/rustc_target/src/spec/targets/riscv32em_unknown_none_elf.rs @@ -1,11 +1,17 @@ use crate::spec::{Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetOptions}; -pub fn target() -> Target { +pub(crate) fn target() -> Target { Target { // The below `data_layout` is explicitly specified by the ilp32e ABI in LLVM. See also // `options.llvm_abiname`. data_layout: "e-m:e-p:32:32-i64:64-n32-S32".into(), llvm_target: "riscv32".into(), + metadata: crate::spec::TargetMetadata { + description: Some("Bare RISC-V (RV32EM ISA)".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(false), + }, pointer_width: 32, arch: "riscv32".into(), diff --git a/compiler/rustc_target/src/spec/targets/riscv32emc_unknown_none_elf.rs b/compiler/rustc_target/src/spec/targets/riscv32emc_unknown_none_elf.rs index 18da14a00d4..45d73c13233 100644 --- a/compiler/rustc_target/src/spec/targets/riscv32emc_unknown_none_elf.rs +++ b/compiler/rustc_target/src/spec/targets/riscv32emc_unknown_none_elf.rs @@ -1,11 +1,17 @@ use crate::spec::{Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetOptions}; -pub fn target() -> Target { +pub(crate) fn target() -> Target { Target { // The below `data_layout` is explicitly specified by the ilp32e ABI in LLVM. See also // `options.llvm_abiname`. data_layout: "e-m:e-p:32:32-i64:64-n32-S32".into(), llvm_target: "riscv32".into(), + metadata: crate::spec::TargetMetadata { + description: Some("Bare RISC-V (RV32EMC ISA)".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(false), + }, pointer_width: 32, arch: "riscv32".into(), From f3037823de584ea94cf2b1c275d4c1dd8a769507 Mon Sep 17 00:00:00 2001 From: Henri Lunnikivi Date: Fri, 27 Sep 2024 22:01:44 +0300 Subject: [PATCH 593/683] doc: platform-support.md: Document port --- src/doc/rustc/src/platform-support.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index 9d2efc0f6de..0ef95ba64a1 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -413,5 +413,8 @@ target | std | host | notes [`riscv32imafc-unknown-nuttx-elf`](platform-support/nuttx.md) | * | | RISC-V 32bit with NuttX [`riscv64imac-unknown-nuttx-elf`](platform-support/nuttx.md) | * | | RISC-V 64bit with NuttX [`riscv64gc-unknown-nuttx-elf`](platform-support/nuttx.md) | * | | RISC-V 64bit with NuttX +[`riscv32e-unknown-none-elf`](platform-support/riscv32-unknown-none-elf.md) | * | | Bare RISC-V (RV32E ISA) +[`riscv32em-unknown-none-elf`](platform-support/riscv32-unknown-none-elf.md) | * | | Bare RISC-V (RV32EM ISA) +[`riscv32emc-unknown-none-elf`](platform-support/riscv32-unknown-none-elf.md) | * | | Bare RISC-V (RV32EMC ISA) [runs on NVIDIA GPUs]: https://github.com/japaric-archived/nvptx#targets From 66b3d0b36ad48400e83ae2692799b42a252ae023 Mon Sep 17 00:00:00 2001 From: Henri Lunnikivi Date: Thu, 19 Sep 2024 13:54:11 +0300 Subject: [PATCH 594/683] Work around the stage0 sanity check Add rv32e-targets to 'stage0 missing targets'. This prevents the error "no such target exists in the target list". --- src/bootstrap/src/core/sanity.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/bootstrap/src/core/sanity.rs b/src/bootstrap/src/core/sanity.rs index 888ba8e2a3f..11260f87d00 100644 --- a/src/bootstrap/src/core/sanity.rs +++ b/src/bootstrap/src/core/sanity.rs @@ -37,6 +37,9 @@ pub struct Finder { const STAGE0_MISSING_TARGETS: &[&str] = &[ // just a dummy comment so the list doesn't get onelined "armv7-rtems-eabihf", + "riscv32e-unknown-none-elf", + "riscv32em-unknown-none-elf", + "riscv32emc-unknown-none-elf", ]; /// Minimum version threshold for libstdc++ required when using prebuilt LLVM From fe658e1fe4d44e2eeeffc079acd7481b2d67b7d9 Mon Sep 17 00:00:00 2001 From: Henri Lunnikivi Date: Thu, 19 Sep 2024 16:43:33 +0300 Subject: [PATCH 595/683] Add assembly tests to satisfy 'tidy' --- tests/assembly/targets/targets-elf.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/assembly/targets/targets-elf.rs b/tests/assembly/targets/targets-elf.rs index e08e6a8b174..f26d06a0ecb 100644 --- a/tests/assembly/targets/targets-elf.rs +++ b/tests/assembly/targets/targets-elf.rs @@ -375,6 +375,15 @@ //@ revisions: riscv32_wrs_vxworks //@ [riscv32_wrs_vxworks] compile-flags: --target riscv32-wrs-vxworks //@ [riscv32_wrs_vxworks] needs-llvm-components: riscv +//@ revisions: riscv32e_unknown_none_elf +//@ [riscv32e_unknown_none_elf] compile-flags: --target riscv32e-unknown-none-elf +//@ [riscv32e_unknown_none_elf] needs-llvm-components: riscv +//@ revisions: riscv32em_unknown_none_elf +//@ [riscv32em_unknown_none_elf] compile-flags: --target riscv32em-unknown-none-elf +//@ [riscv32em_unknown_none_elf] needs-llvm-components: riscv +//@ revisions: riscv32emc_unknown_none_elf +//@ [riscv32emc_unknown_none_elf] compile-flags: --target riscv32emc-unknown-none-elf +//@ [riscv32emc_unknown_none_elf] needs-llvm-components: riscv //@ revisions: riscv32gc_unknown_linux_gnu //@ [riscv32gc_unknown_linux_gnu] compile-flags: --target riscv32gc-unknown-linux-gnu //@ [riscv32gc_unknown_linux_gnu] needs-llvm-components: riscv From 346afc7017fc9b4475fbbe8984f41d7467c6065a Mon Sep 17 00:00:00 2001 From: Henri Lunnikivi Date: Fri, 4 Oct 2024 18:20:53 +0300 Subject: [PATCH 596/683] Add UI test to verify invalid loads are not generated --- .../ui/abi/riscv32e-registers.riscv32e.stderr | 194 ++++++++++++++++++ .../abi/riscv32e-registers.riscv32em.stderr | 194 ++++++++++++++++++ .../abi/riscv32e-registers.riscv32emc.stderr | 194 ++++++++++++++++++ tests/ui/abi/riscv32e-registers.rs | 91 ++++++++ 4 files changed, 673 insertions(+) create mode 100644 tests/ui/abi/riscv32e-registers.riscv32e.stderr create mode 100644 tests/ui/abi/riscv32e-registers.riscv32em.stderr create mode 100644 tests/ui/abi/riscv32e-registers.riscv32emc.stderr create mode 100644 tests/ui/abi/riscv32e-registers.rs diff --git a/tests/ui/abi/riscv32e-registers.riscv32e.stderr b/tests/ui/abi/riscv32e-registers.riscv32e.stderr new file mode 100644 index 00000000000..e3894431eb4 --- /dev/null +++ b/tests/ui/abi/riscv32e-registers.riscv32e.stderr @@ -0,0 +1,194 @@ +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:43:11 + | +LL | asm!("li x16, 0"); + | ^ + | +note: instantiated into assembly here + --> :1:5 + | +LL | li x16, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:46:11 + | +LL | asm!("li x17, 0"); + | ^ + | +note: instantiated into assembly here + --> :1:5 + | +LL | li x17, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:49:11 + | +LL | asm!("li x18, 0"); + | ^ + | +note: instantiated into assembly here + --> :1:5 + | +LL | li x18, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:52:11 + | +LL | asm!("li x19, 0"); + | ^ + | +note: instantiated into assembly here + --> :1:5 + | +LL | li x19, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:55:11 + | +LL | asm!("li x20, 0"); + | ^ + | +note: instantiated into assembly here + --> :1:5 + | +LL | li x20, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:58:11 + | +LL | asm!("li x21, 0"); + | ^ + | +note: instantiated into assembly here + --> :1:5 + | +LL | li x21, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:61:11 + | +LL | asm!("li x22, 0"); + | ^ + | +note: instantiated into assembly here + --> :1:5 + | +LL | li x22, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:64:11 + | +LL | asm!("li x23, 0"); + | ^ + | +note: instantiated into assembly here + --> :1:5 + | +LL | li x23, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:67:11 + | +LL | asm!("li x24, 0"); + | ^ + | +note: instantiated into assembly here + --> :1:5 + | +LL | li x24, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:70:11 + | +LL | asm!("li x25, 0"); + | ^ + | +note: instantiated into assembly here + --> :1:5 + | +LL | li x25, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:73:11 + | +LL | asm!("li x26, 0"); + | ^ + | +note: instantiated into assembly here + --> :1:5 + | +LL | li x26, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:76:11 + | +LL | asm!("li x27, 0"); + | ^ + | +note: instantiated into assembly here + --> :1:5 + | +LL | li x27, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:79:11 + | +LL | asm!("li x28, 0"); + | ^ + | +note: instantiated into assembly here + --> :1:5 + | +LL | li x28, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:82:11 + | +LL | asm!("li x29, 0"); + | ^ + | +note: instantiated into assembly here + --> :1:5 + | +LL | li x29, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:85:11 + | +LL | asm!("li x30, 0"); + | ^ + | +note: instantiated into assembly here + --> :1:5 + | +LL | li x30, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:88:11 + | +LL | asm!("li x31, 0"); + | ^ + | +note: instantiated into assembly here + --> :1:5 + | +LL | li x31, 0 + | ^ + +error: aborting due to 16 previous errors + diff --git a/tests/ui/abi/riscv32e-registers.riscv32em.stderr b/tests/ui/abi/riscv32e-registers.riscv32em.stderr new file mode 100644 index 00000000000..e3894431eb4 --- /dev/null +++ b/tests/ui/abi/riscv32e-registers.riscv32em.stderr @@ -0,0 +1,194 @@ +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:43:11 + | +LL | asm!("li x16, 0"); + | ^ + | +note: instantiated into assembly here + --> :1:5 + | +LL | li x16, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:46:11 + | +LL | asm!("li x17, 0"); + | ^ + | +note: instantiated into assembly here + --> :1:5 + | +LL | li x17, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:49:11 + | +LL | asm!("li x18, 0"); + | ^ + | +note: instantiated into assembly here + --> :1:5 + | +LL | li x18, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:52:11 + | +LL | asm!("li x19, 0"); + | ^ + | +note: instantiated into assembly here + --> :1:5 + | +LL | li x19, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:55:11 + | +LL | asm!("li x20, 0"); + | ^ + | +note: instantiated into assembly here + --> :1:5 + | +LL | li x20, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:58:11 + | +LL | asm!("li x21, 0"); + | ^ + | +note: instantiated into assembly here + --> :1:5 + | +LL | li x21, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:61:11 + | +LL | asm!("li x22, 0"); + | ^ + | +note: instantiated into assembly here + --> :1:5 + | +LL | li x22, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:64:11 + | +LL | asm!("li x23, 0"); + | ^ + | +note: instantiated into assembly here + --> :1:5 + | +LL | li x23, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:67:11 + | +LL | asm!("li x24, 0"); + | ^ + | +note: instantiated into assembly here + --> :1:5 + | +LL | li x24, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:70:11 + | +LL | asm!("li x25, 0"); + | ^ + | +note: instantiated into assembly here + --> :1:5 + | +LL | li x25, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:73:11 + | +LL | asm!("li x26, 0"); + | ^ + | +note: instantiated into assembly here + --> :1:5 + | +LL | li x26, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:76:11 + | +LL | asm!("li x27, 0"); + | ^ + | +note: instantiated into assembly here + --> :1:5 + | +LL | li x27, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:79:11 + | +LL | asm!("li x28, 0"); + | ^ + | +note: instantiated into assembly here + --> :1:5 + | +LL | li x28, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:82:11 + | +LL | asm!("li x29, 0"); + | ^ + | +note: instantiated into assembly here + --> :1:5 + | +LL | li x29, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:85:11 + | +LL | asm!("li x30, 0"); + | ^ + | +note: instantiated into assembly here + --> :1:5 + | +LL | li x30, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:88:11 + | +LL | asm!("li x31, 0"); + | ^ + | +note: instantiated into assembly here + --> :1:5 + | +LL | li x31, 0 + | ^ + +error: aborting due to 16 previous errors + diff --git a/tests/ui/abi/riscv32e-registers.riscv32emc.stderr b/tests/ui/abi/riscv32e-registers.riscv32emc.stderr new file mode 100644 index 00000000000..e3894431eb4 --- /dev/null +++ b/tests/ui/abi/riscv32e-registers.riscv32emc.stderr @@ -0,0 +1,194 @@ +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:43:11 + | +LL | asm!("li x16, 0"); + | ^ + | +note: instantiated into assembly here + --> :1:5 + | +LL | li x16, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:46:11 + | +LL | asm!("li x17, 0"); + | ^ + | +note: instantiated into assembly here + --> :1:5 + | +LL | li x17, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:49:11 + | +LL | asm!("li x18, 0"); + | ^ + | +note: instantiated into assembly here + --> :1:5 + | +LL | li x18, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:52:11 + | +LL | asm!("li x19, 0"); + | ^ + | +note: instantiated into assembly here + --> :1:5 + | +LL | li x19, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:55:11 + | +LL | asm!("li x20, 0"); + | ^ + | +note: instantiated into assembly here + --> :1:5 + | +LL | li x20, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:58:11 + | +LL | asm!("li x21, 0"); + | ^ + | +note: instantiated into assembly here + --> :1:5 + | +LL | li x21, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:61:11 + | +LL | asm!("li x22, 0"); + | ^ + | +note: instantiated into assembly here + --> :1:5 + | +LL | li x22, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:64:11 + | +LL | asm!("li x23, 0"); + | ^ + | +note: instantiated into assembly here + --> :1:5 + | +LL | li x23, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:67:11 + | +LL | asm!("li x24, 0"); + | ^ + | +note: instantiated into assembly here + --> :1:5 + | +LL | li x24, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:70:11 + | +LL | asm!("li x25, 0"); + | ^ + | +note: instantiated into assembly here + --> :1:5 + | +LL | li x25, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:73:11 + | +LL | asm!("li x26, 0"); + | ^ + | +note: instantiated into assembly here + --> :1:5 + | +LL | li x26, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:76:11 + | +LL | asm!("li x27, 0"); + | ^ + | +note: instantiated into assembly here + --> :1:5 + | +LL | li x27, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:79:11 + | +LL | asm!("li x28, 0"); + | ^ + | +note: instantiated into assembly here + --> :1:5 + | +LL | li x28, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:82:11 + | +LL | asm!("li x29, 0"); + | ^ + | +note: instantiated into assembly here + --> :1:5 + | +LL | li x29, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:85:11 + | +LL | asm!("li x30, 0"); + | ^ + | +note: instantiated into assembly here + --> :1:5 + | +LL | li x30, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:88:11 + | +LL | asm!("li x31, 0"); + | ^ + | +note: instantiated into assembly here + --> :1:5 + | +LL | li x31, 0 + | ^ + +error: aborting due to 16 previous errors + diff --git a/tests/ui/abi/riscv32e-registers.rs b/tests/ui/abi/riscv32e-registers.rs new file mode 100644 index 00000000000..714b0ee4633 --- /dev/null +++ b/tests/ui/abi/riscv32e-registers.rs @@ -0,0 +1,91 @@ +// Test that loads into registers x16..=x31 are never generated for riscv32{e,em,emc} targets +// +//@ build-fail +//@ revisions: riscv32e riscv32em riscv32emc +// +//@ compile-flags: --crate-type=rlib +//@ [riscv32e] needs-llvm-components: riscv +//@ [riscv32e] compile-flags: --target=riscv32e-unknown-none-elf +//@ [riscv32em] needs-llvm-components: riscv +//@ [riscv32em] compile-flags: --target=riscv32em-unknown-none-elf +//@ [riscv32emc] needs-llvm-components: riscv +//@ [riscv32emc] compile-flags: --target=riscv32emc-unknown-none-elf + +#![no_core] +#![feature(no_core, lang_items, rustc_attrs)] + +#[rustc_builtin_macro] +macro_rules! asm { + () => {}; +} + +#[lang = "sized"] +trait Sized {} + +// Verify registers x1..=x15 are addressable on riscv32e, but registers x16..=x31 are not +#[no_mangle] +pub unsafe fn registers() { + asm!("li x1, 0"); + asm!("li x2, 0"); + asm!("li x3, 0"); + asm!("li x4, 0"); + asm!("li x5, 0"); + asm!("li x6, 0"); + asm!("li x7, 0"); + asm!("li x8, 0"); + asm!("li x9, 0"); + asm!("li x10, 0"); + asm!("li x11, 0"); + asm!("li x12, 0"); + asm!("li x13, 0"); + asm!("li x14, 0"); + asm!("li x15, 0"); + asm!("li x16, 0"); + //~^ ERROR invalid operand for instruction + //~| NOTE instantiated into assembly here + asm!("li x17, 0"); + //~^ ERROR invalid operand for instruction + //~| NOTE instantiated into assembly here + asm!("li x18, 0"); + //~^ ERROR invalid operand for instruction + //~| NOTE instantiated into assembly here + asm!("li x19, 0"); + //~^ ERROR invalid operand for instruction + //~| NOTE instantiated into assembly here + asm!("li x20, 0"); + //~^ ERROR invalid operand for instruction + //~| NOTE instantiated into assembly here + asm!("li x21, 0"); + //~^ ERROR invalid operand for instruction + //~| NOTE instantiated into assembly here + asm!("li x22, 0"); + //~^ ERROR invalid operand for instruction + //~| NOTE instantiated into assembly here + asm!("li x23, 0"); + //~^ ERROR invalid operand for instruction + //~| NOTE instantiated into assembly here + asm!("li x24, 0"); + //~^ ERROR invalid operand for instruction + //~| NOTE instantiated into assembly here + asm!("li x25, 0"); + //~^ ERROR invalid operand for instruction + //~| NOTE instantiated into assembly here + asm!("li x26, 0"); + //~^ ERROR invalid operand for instruction + //~| NOTE instantiated into assembly here + asm!("li x27, 0"); + //~^ ERROR invalid operand for instruction + //~| NOTE instantiated into assembly here + asm!("li x28, 0"); + //~^ ERROR invalid operand for instruction + //~| NOTE instantiated into assembly here + asm!("li x29, 0"); + //~^ ERROR invalid operand for instruction + //~| NOTE instantiated into assembly here + asm!("li x30, 0"); + //~^ ERROR invalid operand for instruction + //~| NOTE instantiated into assembly here + asm!("li x31, 0"); + //~^ ERROR invalid operand for instruction + //~| NOTE instantiated into assembly here +} From 6edd0b356fac7585b27b14b4b9e6cd2b29537726 Mon Sep 17 00:00:00 2001 From: Henri Lunnikivi Date: Fri, 4 Oct 2024 20:58:39 +0300 Subject: [PATCH 597/683] Add platform support doc for rv32e --- .../riscv32-unknown-none-elf.md | 2 +- .../riscv32e-unknown-none-elf.md | 30 +++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 src/doc/rustc/src/platform-support/riscv32e-unknown-none-elf.md diff --git a/src/doc/rustc/src/platform-support/riscv32-unknown-none-elf.md b/src/doc/rustc/src/platform-support/riscv32-unknown-none-elf.md index 9a27a568b57..38742143c4b 100644 --- a/src/doc/rustc/src/platform-support/riscv32-unknown-none-elf.md +++ b/src/doc/rustc/src/platform-support/riscv32-unknown-none-elf.md @@ -35,4 +35,4 @@ Rust test-suite on this target. ## Cross-compilation toolchains and C code This target supports C code. If interlinking with C or C++, you may need to use -`riscv64-unknown-elf-gcc` as a linker instead of `rust-lld`. +`riscv32-unknown-elf-gcc` as a linker instead of `rust-lld`. diff --git a/src/doc/rustc/src/platform-support/riscv32e-unknown-none-elf.md b/src/doc/rustc/src/platform-support/riscv32e-unknown-none-elf.md new file mode 100644 index 00000000000..69f08774f83 --- /dev/null +++ b/src/doc/rustc/src/platform-support/riscv32e-unknown-none-elf.md @@ -0,0 +1,30 @@ +# `riscv32{e,em,emc}-unknown-none-elf` + +**Tier: 3** + +Bare-metal target for RISC-V CPUs with the RV32E, RV32EM and RV32EMC ISAs. + +## Target maintainers + +* Henri Lunnikivi, , [@hegza](https://github.com/hegza) + +## Requirements + +The target is cross-compiled, and uses static linking. No external toolchain is +required and the default `rust-lld` linker works, but you must specify a linker +script. + +## Building the target + +This target is included in Rust and can be installed via `rustup`. + +## Testing + +This is a cross-compiled `no-std` target, which must be run either in a +simulator or by programming them onto suitable hardware. It is not possible to +run the Rust test-suite on this target. + +## Cross-compilation toolchains and C code + +This target supports C code. If interlinking with C or C++, you may need to use +`riscv32-unknown-elf-gcc` as a linker instead of `rust-lld`. From f0ddc7b472a6ea84f2224364e2b71c688b7b285e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 5 Oct 2024 12:19:14 +0200 Subject: [PATCH 598/683] clarify semantics of ConstantIndex MIR projection --- compiler/rustc_middle/src/mir/syntax.rs | 6 ++++-- compiler/stable_mir/src/mir/body.rs | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs index ae75f2d4187..1722a7a1f35 100644 --- a/compiler/rustc_middle/src/mir/syntax.rs +++ b/compiler/rustc_middle/src/mir/syntax.rs @@ -1135,8 +1135,10 @@ pub enum ProjectionElem { ConstantIndex { /// index or -index (in Python terms), depending on from_end offset: u64, - /// The thing being indexed must be at least this long. For arrays this - /// is always the exact length. + /// The thing being indexed must be at least this long -- otherwise, the + /// projection is UB. + /// + /// For arrays this is always the exact length. min_length: u64, /// Counting backwards from end? This is always false when indexing an /// array. diff --git a/compiler/stable_mir/src/mir/body.rs b/compiler/stable_mir/src/mir/body.rs index 9f4db7e4833..742469a1c93 100644 --- a/compiler/stable_mir/src/mir/body.rs +++ b/compiler/stable_mir/src/mir/body.rs @@ -768,8 +768,10 @@ pub enum ProjectionElem { ConstantIndex { /// index or -index (in Python terms), depending on from_end offset: u64, - /// The thing being indexed must be at least this long. For arrays this - /// is always the exact length. + /// The thing being indexed must be at least this long -- otherwise, the + /// projection is UB. + /// + /// For arrays this is always the exact length. min_length: u64, /// Counting backwards from end? This is always false when indexing an /// array. From ab8673501ce13573c06b5989b179f5cfed85c771 Mon Sep 17 00:00:00 2001 From: Veera Date: Sun, 22 Sep 2024 19:32:56 -0400 Subject: [PATCH 599/683] Add a Lint for Pointer to Integer Transmutes in Consts --- compiler/rustc_lint_defs/src/builtin.rs | 35 +++++++++ compiler/rustc_mir_transform/messages.ftl | 5 ++ .../src/check_undefined_transmutes.rs | 77 +++++++++++++++++++ compiler/rustc_mir_transform/src/errors.rs | 7 ++ compiler/rustc_mir_transform/src/lib.rs | 2 + library/core/src/ptr/mod.rs | 1 + .../transmutes_expressible_as_ptr_casts.fixed | 9 ++- .../ui/transmutes_expressible_as_ptr_casts.rs | 9 ++- ...-to-int-transmute-in-consts-issue-87525.rs | 22 +++--- ...int-transmute-in-consts-issue-87525.stderr | 43 ++++++++++- 10 files changed, 192 insertions(+), 18 deletions(-) create mode 100644 compiler/rustc_mir_transform/src/check_undefined_transmutes.rs diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 25d33126754..a618bd77301 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -82,6 +82,7 @@ declare_lint_pass! { PRIVATE_INTERFACES, PROC_MACRO_DERIVE_RESOLUTION_FALLBACK, PTR_CAST_ADD_AUTO_TO_OBJECT, + PTR_TO_INTEGER_TRANSMUTE_IN_CONSTS, PUB_USE_OF_PRIVATE_EXTERN_CRATE, REDUNDANT_IMPORTS, REDUNDANT_LIFETIMES, @@ -5095,3 +5096,37 @@ declare_lint! { reference: "issue #124535 ", }; } + +declare_lint! { + /// The `ptr_to_integer_transmute_in_consts` lint detects pointer to integer + /// transmute in const functions and associated constants. + /// + /// ### Example + /// + /// ```rust + /// const fn foo(ptr: *const u8) -> usize { + /// unsafe { + /// std::mem::transmute::<*const u8, usize>(ptr) + /// } + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Transmuting pointers to integers in a `const` context is undefined behavior. + /// Any attempt to use the resulting integer will abort const-evaluation. + /// + /// But sometimes the compiler might not emit an error for pointer to integer transmutes + /// inside const functions and associated consts because they are evaluated only when referenced. + /// Therefore, this lint serves as an extra layer of defense to prevent any undefined behavior + /// from compiling without any warnings or errors. + /// + /// See [std::mem::transmute] in the reference for more details. + /// + /// [std::mem::transmute]: https://doc.rust-lang.org/std/mem/fn.transmute.html + pub PTR_TO_INTEGER_TRANSMUTE_IN_CONSTS, + Warn, + "detects pointer to integer transmutes in const functions and associated constants", +} diff --git a/compiler/rustc_mir_transform/messages.ftl b/compiler/rustc_mir_transform/messages.ftl index f9b79d72b05..b81c0906734 100644 --- a/compiler/rustc_mir_transform/messages.ftl +++ b/compiler/rustc_mir_transform/messages.ftl @@ -27,3 +27,8 @@ mir_transform_unaligned_packed_ref = reference to packed field is unaligned .note = packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses .note_ub = creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) .help = copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers) + +mir_transform_undefined_transmute = pointers cannot be transmuted to integers during const eval + .note = at compile-time, pointers do not have an integer value + .note2 = avoiding this restriction via `union` or raw pointers leads to compile-time undefined behavior + .help = for more information, see https://doc.rust-lang.org/std/mem/fn.transmute.html diff --git a/compiler/rustc_mir_transform/src/check_undefined_transmutes.rs b/compiler/rustc_mir_transform/src/check_undefined_transmutes.rs new file mode 100644 index 00000000000..8ba14a1158e --- /dev/null +++ b/compiler/rustc_mir_transform/src/check_undefined_transmutes.rs @@ -0,0 +1,77 @@ +use rustc_middle::mir::visit::Visitor; +use rustc_middle::mir::{Body, Location, Operand, Terminator, TerminatorKind}; +use rustc_middle::ty::{AssocItem, AssocKind, TyCtxt}; +use rustc_session::lint::builtin::PTR_TO_INTEGER_TRANSMUTE_IN_CONSTS; +use rustc_span::sym; + +use crate::errors; + +/// Check for transmutes that exhibit undefined behavior. +/// For example, transmuting pointers to integers in a const context. +pub(super) struct CheckUndefinedTransmutes; + +impl<'tcx> crate::MirLint<'tcx> for CheckUndefinedTransmutes { + fn run_lint(&self, tcx: TyCtxt<'tcx>, body: &Body<'tcx>) { + let mut checker = UndefinedTransmutesChecker { body, tcx }; + checker.visit_body(body); + } +} + +struct UndefinedTransmutesChecker<'a, 'tcx> { + body: &'a Body<'tcx>, + tcx: TyCtxt<'tcx>, +} + +impl<'a, 'tcx> UndefinedTransmutesChecker<'a, 'tcx> { + // This functions checks two things: + // 1. `function` takes a raw pointer as input and returns an integer as output. + // 2. `function` is called from a const function or an associated constant. + // + // Why do we consider const functions and associated constants only? + // + // Generally, undefined behavior in const items are handled by the evaluator. + // But, const functions and associated constants are evaluated only when referenced. + // This can result in undefined behavior in a library going unnoticed until + // the function or constant is actually used. + // + // Therefore, we only consider const functions and associated constants here and leave + // other const items to be handled by the evaluator. + fn is_ptr_to_int_in_const(&self, function: &Operand<'tcx>) -> bool { + let def_id = self.body.source.def_id(); + + if self.tcx.is_const_fn(def_id) + || matches!( + self.tcx.opt_associated_item(def_id), + Some(AssocItem { kind: AssocKind::Const, .. }) + ) + { + let fn_sig = function.ty(self.body, self.tcx).fn_sig(self.tcx).skip_binder(); + if let [input] = fn_sig.inputs() { + return input.is_unsafe_ptr() && fn_sig.output().is_integral(); + } + } + false + } +} + +impl<'tcx> Visitor<'tcx> for UndefinedTransmutesChecker<'_, 'tcx> { + // Check each block's terminator for calls to pointer to integer transmutes + // in const functions or associated constants and emit a lint. + fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) { + if let TerminatorKind::Call { func, .. } = &terminator.kind + && let Some((func_def_id, _)) = func.const_fn_def() + && self.tcx.is_intrinsic(func_def_id, sym::transmute) + && self.is_ptr_to_int_in_const(func) + && let Some(call_id) = self.body.source.def_id().as_local() + { + let hir_id = self.tcx.local_def_id_to_hir_id(call_id); + let span = self.body.source_info(location).span; + self.tcx.emit_node_span_lint( + PTR_TO_INTEGER_TRANSMUTE_IN_CONSTS, + hir_id, + span, + errors::UndefinedTransmute, + ); + } + } +} diff --git a/compiler/rustc_mir_transform/src/errors.rs b/compiler/rustc_mir_transform/src/errors.rs index 9a93c3a72b1..e480537402d 100644 --- a/compiler/rustc_mir_transform/src/errors.rs +++ b/compiler/rustc_mir_transform/src/errors.rs @@ -121,3 +121,10 @@ pub(crate) struct MustNotSuspendReason { pub span: Span, pub reason: String, } + +#[derive(LintDiagnostic)] +#[diag(mir_transform_undefined_transmute)] +#[note] +#[note(mir_transform_note2)] +#[help] +pub(crate) struct UndefinedTransmute; diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index 84d07d38330..626b4584fb2 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -51,6 +51,7 @@ mod add_subtyping_projections; mod check_alignment; mod check_const_item_mutation; mod check_packed_ref; +mod check_undefined_transmutes; // This pass is public to allow external drivers to perform MIR cleanup pub mod cleanup_post_borrowck; mod copy_prop; @@ -293,6 +294,7 @@ fn mir_built(tcx: TyCtxt<'_>, def: LocalDefId) -> &Steal> { &Lint(check_packed_ref::CheckPackedRef), &Lint(check_const_item_mutation::CheckConstItemMutation), &Lint(function_item_references::FunctionItemReferences), + &Lint(check_undefined_transmutes::CheckUndefinedTransmutes), // What we need to do constant evaluation. &simplify::SimplifyCfg::Initial, &Lint(sanity_check::SanityCheck), diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs index 08d06cad55d..8d6560111da 100644 --- a/library/core/src/ptr/mod.rs +++ b/library/core/src/ptr/mod.rs @@ -1916,6 +1916,7 @@ pub unsafe fn write_volatile(dst: *mut T, src: T) { /// than trying to adapt this to accommodate that change. /// /// Any questions go to @nagisa. +#[cfg_attr(not(bootstrap), allow(ptr_to_integer_transmute_in_consts))] #[lang = "align_offset"] pub(crate) const unsafe fn align_offset(p: *const T, a: usize) -> usize { // FIXME(#75598): Direct use of these intrinsics improves codegen significantly at opt-level <= diff --git a/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.fixed b/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.fixed index e95054a7ccb..617d32d1fa7 100644 --- a/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.fixed +++ b/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.fixed @@ -84,8 +84,11 @@ fn issue_10449() { } // Pointers cannot be cast to integers in const contexts +#[allow(ptr_to_integer_transmute_in_consts, reason = "This is tested in the compiler test suite")] const fn issue_12402

    (ptr: *const P) { - unsafe { transmute::<*const i32, usize>(&42i32) }; - unsafe { transmute::(issue_12402) }; - let _ = unsafe { transmute::<_, usize>(ptr) }; + // This test exists even though the compiler lints against it + // to test that clippy's transmute lints do not trigger on this. + unsafe { std::mem::transmute::<*const i32, usize>(&42i32) }; + unsafe { std::mem::transmute::(issue_12402) }; + let _ = unsafe { std::mem::transmute::<_, usize>(ptr) }; } diff --git a/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.rs b/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.rs index e5fcdef7a1c..d68db3c2deb 100644 --- a/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.rs +++ b/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.rs @@ -84,8 +84,11 @@ fn issue_10449() { } // Pointers cannot be cast to integers in const contexts +#[allow(ptr_to_integer_transmute_in_consts, reason = "This is tested in the compiler test suite")] const fn issue_12402

    (ptr: *const P) { - unsafe { transmute::<*const i32, usize>(&42i32) }; - unsafe { transmute::(issue_12402) }; - let _ = unsafe { transmute::<_, usize>(ptr) }; + // This test exists even though the compiler lints against it + // to test that clippy's transmute lints do not trigger on this. + unsafe { std::mem::transmute::<*const i32, usize>(&42i32) }; + unsafe { std::mem::transmute::(issue_12402) }; + let _ = unsafe { std::mem::transmute::<_, usize>(ptr) }; } diff --git a/tests/ui/consts/const-eval/ptr-to-int-transmute-in-consts-issue-87525.rs b/tests/ui/consts/const-eval/ptr-to-int-transmute-in-consts-issue-87525.rs index f8e97904e9e..19c78f019aa 100644 --- a/tests/ui/consts/const-eval/ptr-to-int-transmute-in-consts-issue-87525.rs +++ b/tests/ui/consts/const-eval/ptr-to-int-transmute-in-consts-issue-87525.rs @@ -1,21 +1,21 @@ const fn foo(ptr: *const u8) -> usize { unsafe { std::mem::transmute(ptr) - //~^ ERROR pointers cannot be transmuted to integers + //~^ WARN pointers cannot be transmuted to integers } } trait Human { - const ID: u64 = { + const ID: usize = { let value = 10; - let ptr: *const i32 = &value; + let ptr: *const usize = &value; unsafe { std::mem::transmute(ptr) - //~^ ERROR pointers cannot be transmuted to integers + //~^ WARN pointers cannot be transmuted to integers } }; - fn id_plus_one() -> u64 { + fn id_plus_one() -> usize { Self::ID + 1 } } @@ -23,16 +23,16 @@ trait Human { struct Type(T); impl Type { - const ID: u64 = { + const ID: usize = { let value = 10; - let ptr: *const i32 = &value; + let ptr: *const usize = &value; unsafe { std::mem::transmute(ptr) - //~^ ERROR pointers cannot be transmuted to integers + //~^ WARN pointers cannot be transmuted to integers } }; - fn id_plus_one() -> u64 { + fn id_plus_one() -> usize { Self::ID + 1 } } @@ -59,10 +59,10 @@ impl ControlStruct { const fn zoom(ptr: *const u8) -> usize { unsafe { std::mem::transmute(ptr) - //~^ ERROR pointers cannot be transmuted to integers + //~^ WARN pointers cannot be transmuted to integers } } - + fn main() { const a: u8 = 10; const value: usize = zoom(&a); diff --git a/tests/ui/consts/const-eval/ptr-to-int-transmute-in-consts-issue-87525.stderr b/tests/ui/consts/const-eval/ptr-to-int-transmute-in-consts-issue-87525.stderr index a57bc8e1e70..ca6ad9408ab 100644 --- a/tests/ui/consts/const-eval/ptr-to-int-transmute-in-consts-issue-87525.stderr +++ b/tests/ui/consts/const-eval/ptr-to-int-transmute-in-consts-issue-87525.stderr @@ -1,3 +1,14 @@ +warning: pointers cannot be transmuted to integers during const eval + --> $DIR/ptr-to-int-transmute-in-consts-issue-87525.rs:61:9 + | +LL | std::mem::transmute(ptr) + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: at compile-time, pointers do not have an integer value + = note: avoiding this restriction via `union` or raw pointers leads to compile-time undefined behavior + = help: for more information, see https://doc.rust-lang.org/std/mem/fn.transmute.html + = note: `#[warn(ptr_to_integer_transmute_in_consts)]` on by default + error[E0080]: evaluation of constant value failed --> $DIR/ptr-to-int-transmute-in-consts-issue-87525.rs:68:26 | @@ -7,6 +18,36 @@ LL | const value: usize = zoom(&a); = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported -error: aborting due to 1 previous error +warning: pointers cannot be transmuted to integers during const eval + --> $DIR/ptr-to-int-transmute-in-consts-issue-87525.rs:3:9 + | +LL | std::mem::transmute(ptr) + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: at compile-time, pointers do not have an integer value + = note: avoiding this restriction via `union` or raw pointers leads to compile-time undefined behavior + = help: for more information, see https://doc.rust-lang.org/std/mem/fn.transmute.html + +warning: pointers cannot be transmuted to integers during const eval + --> $DIR/ptr-to-int-transmute-in-consts-issue-87525.rs:13:13 + | +LL | std::mem::transmute(ptr) + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: at compile-time, pointers do not have an integer value + = note: avoiding this restriction via `union` or raw pointers leads to compile-time undefined behavior + = help: for more information, see https://doc.rust-lang.org/std/mem/fn.transmute.html + +warning: pointers cannot be transmuted to integers during const eval + --> $DIR/ptr-to-int-transmute-in-consts-issue-87525.rs:30:13 + | +LL | std::mem::transmute(ptr) + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: at compile-time, pointers do not have an integer value + = note: avoiding this restriction via `union` or raw pointers leads to compile-time undefined behavior + = help: for more information, see https://doc.rust-lang.org/std/mem/fn.transmute.html + +error: aborting due to 1 previous error; 4 warnings emitted For more information about this error, try `rustc --explain E0080`. From 70260dbeca3303e4d62d2ff4c136501ddac7491d Mon Sep 17 00:00:00 2001 From: DianQK Date: Sat, 5 Oct 2024 21:10:04 +0800 Subject: [PATCH 600/683] Update to LLVM 19.1.1 --- src/llvm-project | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/llvm-project b/src/llvm-project index 56997739365..dd46457da78 160000 --- a/src/llvm-project +++ b/src/llvm-project @@ -1 +1 @@ -Subproject commit 56997739365e8132cc817e00899480746c09d7d9 +Subproject commit dd46457da782554454106d48ecd4f6b4c2f9af73 From 8faf3722ac963a637265c3fb087fce08f9ceb163 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 5 Oct 2024 17:12:46 +0200 Subject: [PATCH 601/683] fix typo in 'lang item with track_caller' message --- compiler/rustc_passes/messages.ftl | 2 +- tests/ui/panic-handler/panic-handler-with-track-caller.stderr | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index 5369f54afb9..f2682acf8aa 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -391,7 +391,7 @@ passes_lang_item_fn_with_target_feature = passes_lang_item_fn_with_track_caller = {passes_lang_item_fn} is not allowed to have `#[track_caller]` - .label = {passes_lang_item_fn} is not allowed to have `#[target_feature]` + .label = {passes_lang_item_fn} is not allowed to have `#[track_caller]` passes_lang_item_on_incorrect_target = `{$name}` lang item must be applied to a {$expected_target} diff --git a/tests/ui/panic-handler/panic-handler-with-track-caller.stderr b/tests/ui/panic-handler/panic-handler-with-track-caller.stderr index 9ed387fc8d1..605567acdb5 100644 --- a/tests/ui/panic-handler/panic-handler-with-track-caller.stderr +++ b/tests/ui/panic-handler/panic-handler-with-track-caller.stderr @@ -5,7 +5,7 @@ LL | #[track_caller] | ^^^^^^^^^^^^^^^ LL | LL | fn panic(info: &PanicInfo) -> ! { - | ------------------------------- `#[panic_handler]` function is not allowed to have `#[target_feature]` + | ------------------------------- `#[panic_handler]` function is not allowed to have `#[track_caller]` error: aborting due to 1 previous error From 7d63efdb8c2d3b9ea25fa2bbb8703168d21483c8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 5 Oct 2024 17:05:47 +0200 Subject: [PATCH 602/683] fix GVN trying to transmute pointers to integers --- compiler/rustc_mir_transform/src/gvn.rs | 30 +++++++++++++++++----- tests/coverage/closure_macro.cov-map | 8 +++--- tests/coverage/closure_macro_async.cov-map | 8 +++--- 3 files changed, 31 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index 50c9702cb9b..7707d0d51f1 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -103,7 +103,7 @@ use rustc_middle::ty::layout::{HasParamEnv, LayoutOf}; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_span::DUMMY_SP; use rustc_span::def_id::DefId; -use rustc_target::abi::{self, Abi, FIRST_VARIANT, FieldIdx, Size, VariantIdx}; +use rustc_target::abi::{self, Abi, FIRST_VARIANT, FieldIdx, Primitive, Size, VariantIdx}; use smallvec::SmallVec; use tracing::{debug, instrument, trace}; @@ -568,13 +568,29 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { CastKind::Transmute => { let value = self.evaluated[value].as_ref()?; let to = self.ecx.layout_of(to).ok()?; - // `offset` for immediates only supports scalar/scalar-pair ABIs, - // so bail out if the target is not one. + // `offset` for immediates generally only supports projections that match the + // type of the immediate. However, as a HACK, we exploit that it can also do + // limited transmutes: it only works between types with the same layout, and + // cannot transmute pointers to integers. if value.as_mplace_or_imm().is_right() { - match (value.layout.abi, to.abi) { - (Abi::Scalar(..), Abi::Scalar(..)) => {} - (Abi::ScalarPair(..), Abi::ScalarPair(..)) => {} - _ => return None, + let can_transmute = match (value.layout.abi, to.abi) { + (Abi::Scalar(s1), Abi::Scalar(s2)) => { + s1.size(&self.ecx) == s2.size(&self.ecx) + && !matches!(s1.primitive(), Primitive::Pointer(..)) + } + (Abi::ScalarPair(a1, b1), Abi::ScalarPair(a2, b2)) => { + a1.size(&self.ecx) == a2.size(&self.ecx) && + b1.size(&self.ecx) == b2.size(&self.ecx) && + // The alignment of the second component determines its offset, so that also needs to match. + b1.align(&self.ecx) == b2.align(&self.ecx) && + // None of the inputs may be a pointer. + !matches!(a1.primitive(), Primitive::Pointer(..)) + && !matches!(b1.primitive(), Primitive::Pointer(..)) + } + _ => false, + }; + if !can_transmute { + return None; } } value.offset(Size::ZERO, to, &self.ecx).discard_err()? diff --git a/tests/coverage/closure_macro.cov-map b/tests/coverage/closure_macro.cov-map index eb5f94d1080..fb4a137d4c8 100644 --- a/tests/coverage/closure_macro.cov-map +++ b/tests/coverage/closure_macro.cov-map @@ -23,19 +23,19 @@ Number of file 0 mappings: 6 - Code(Counter(0)) at (prev + 3, 1) to (start + 0, 2) Function name: closure_macro::main::{closure#0} -Raw bytes (35): 0x[01, 01, 03, 01, 05, 05, 0b, 09, 00, 05, 01, 10, 1c, 03, 21, 05, 04, 11, 01, 27, 02, 03, 11, 00, 16, 00, 00, 17, 00, 1e, 07, 02, 09, 00, 0a] +Raw bytes (35): 0x[01, 01, 03, 01, 05, 05, 0b, 09, 0d, 05, 01, 10, 1c, 03, 21, 05, 04, 11, 01, 27, 02, 03, 11, 00, 16, 0d, 00, 17, 00, 1e, 07, 02, 09, 00, 0a] Number of files: 1 - file 0 => global file 1 Number of expressions: 3 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(1), rhs = Expression(2, Add) -- expression 2 operands: lhs = Counter(2), rhs = Zero +- expression 2 operands: lhs = Counter(2), rhs = Counter(3) Number of file 0 mappings: 5 - Code(Counter(0)) at (prev + 16, 28) to (start + 3, 33) - Code(Counter(1)) at (prev + 4, 17) to (start + 1, 39) - Code(Expression(0, Sub)) at (prev + 3, 17) to (start + 0, 22) = (c0 - c1) -- Code(Zero) at (prev + 0, 23) to (start + 0, 30) +- Code(Counter(3)) at (prev + 0, 23) to (start + 0, 30) - Code(Expression(1, Add)) at (prev + 2, 9) to (start + 0, 10) - = (c1 + (c2 + Zero)) + = (c1 + (c2 + c3)) diff --git a/tests/coverage/closure_macro_async.cov-map b/tests/coverage/closure_macro_async.cov-map index 4d0597f58bf..091e87909f9 100644 --- a/tests/coverage/closure_macro_async.cov-map +++ b/tests/coverage/closure_macro_async.cov-map @@ -31,19 +31,19 @@ Number of file 0 mappings: 6 - Code(Counter(0)) at (prev + 3, 1) to (start + 0, 2) Function name: closure_macro_async::test::{closure#0}::{closure#0} -Raw bytes (35): 0x[01, 01, 03, 01, 05, 05, 0b, 09, 00, 05, 01, 15, 1c, 03, 21, 05, 04, 11, 01, 27, 02, 03, 11, 00, 16, 00, 00, 17, 00, 1e, 07, 02, 09, 00, 0a] +Raw bytes (35): 0x[01, 01, 03, 01, 05, 05, 0b, 09, 0d, 05, 01, 15, 1c, 03, 21, 05, 04, 11, 01, 27, 02, 03, 11, 00, 16, 0d, 00, 17, 00, 1e, 07, 02, 09, 00, 0a] Number of files: 1 - file 0 => global file 1 Number of expressions: 3 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(1), rhs = Expression(2, Add) -- expression 2 operands: lhs = Counter(2), rhs = Zero +- expression 2 operands: lhs = Counter(2), rhs = Counter(3) Number of file 0 mappings: 5 - Code(Counter(0)) at (prev + 21, 28) to (start + 3, 33) - Code(Counter(1)) at (prev + 4, 17) to (start + 1, 39) - Code(Expression(0, Sub)) at (prev + 3, 17) to (start + 0, 22) = (c0 - c1) -- Code(Zero) at (prev + 0, 23) to (start + 0, 30) +- Code(Counter(3)) at (prev + 0, 23) to (start + 0, 30) - Code(Expression(1, Add)) at (prev + 2, 9) to (start + 0, 10) - = (c1 + (c2 + Zero)) + = (c1 + (c2 + c3)) From 2223328d166a16cde864a17a5cb96de0853c9981 Mon Sep 17 00:00:00 2001 From: Yoh Deadfall Date: Sat, 5 Oct 2024 21:29:40 +0300 Subject: [PATCH 603/683] Android: Debug assertion after setting thread name --- library/std/src/sys/pal/unix/thread.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/library/std/src/sys/pal/unix/thread.rs b/library/std/src/sys/pal/unix/thread.rs index 2f2d6e6add3..04024661836 100644 --- a/library/std/src/sys/pal/unix/thread.rs +++ b/library/std/src/sys/pal/unix/thread.rs @@ -117,13 +117,15 @@ impl Thread { pub fn set_name(name: &CStr) { const PR_SET_NAME: libc::c_int = 15; unsafe { - libc::prctl( + let res = libc::prctl( PR_SET_NAME, name.as_ptr(), 0 as libc::c_ulong, 0 as libc::c_ulong, 0 as libc::c_ulong, ); + // 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); } } From 4f50efd1329f430998231f018c2cf61bfe0db449 Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Sat, 5 Oct 2024 22:48:55 +0300 Subject: [PATCH 604/683] update "build/host" symlink comment Signed-off-by: onur-ozkan --- src/bootstrap/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs index 75659f46431..bcd6b07f2a2 100644 --- a/src/bootstrap/src/lib.rs +++ b/src/bootstrap/src/lib.rs @@ -470,7 +470,7 @@ impl Build { crate::core::metadata::build(&mut build); } - // Make a symbolic link so we can use a consistent directory in the documentation. + // Create symbolic link to use host sysroot from a consistent path (e.g., in the rust-analyzer config file). let build_triple = build.out.join(build.build); t!(fs::create_dir_all(&build_triple)); let host = build.out.join("host"); From 9d2495db60312472506939fdde49bb852b75b414 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Miku=C5=82a?= Date: Sun, 29 Sep 2024 22:28:08 +0200 Subject: [PATCH 605/683] enable f16 and f128 on windows-gnullvm targets --- library/std/build.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/library/std/build.rs b/library/std/build.rs index 7d37d4e9d7d..032326556bd 100644 --- a/library/std/build.rs +++ b/library/std/build.rs @@ -7,6 +7,7 @@ fn main() { let target_vendor = env::var("CARGO_CFG_TARGET_VENDOR").expect("CARGO_CFG_TARGET_VENDOR was not set"); let target_env = env::var("CARGO_CFG_TARGET_ENV").expect("CARGO_CFG_TARGET_ENV was not set"); + let target_abi = env::var("CARGO_CFG_TARGET_ABI").expect("CARGO_CFG_TARGET_ABI was not set"); let target_pointer_width: u32 = env::var("CARGO_CFG_TARGET_POINTER_WIDTH") .expect("CARGO_CFG_TARGET_POINTER_WIDTH was not set") .parse() @@ -101,7 +102,7 @@ fn main() { // Unsupported ("arm64ec", _) => false, // MinGW ABI bugs - ("x86_64", "windows") if target_env == "gnu" => false, + ("x86_64", "windows") if target_env == "gnu" && target_abi != "llvm" => false, // Infinite recursion ("csky", _) => false, ("hexagon", _) => false, @@ -129,7 +130,7 @@ fn main() { // ABI unsupported ("sparc", _) => false, // MinGW ABI bugs - ("x86_64", "windows") if target_env == "gnu" => false, + ("x86_64", "windows") if target_env == "gnu" && target_abi != "llvm" => false, // 64-bit Linux is about the only platform to have f128 symbols by default (_, "linux") if target_pointer_width == 64 => true, // Almost all OSs are missing symbol. compiler-builtins will have to add them. From 6371ef6e964a72ca3b4c7557312d8808e98f4ff3 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 5 Sep 2024 07:02:26 -0400 Subject: [PATCH 606/683] Evaluating place expr that is never read from does not diverge --- compiler/rustc_hir_typeck/src/expr.rs | 67 ++++++++++++++++++- compiler/rustc_hir_typeck/src/pat.rs | 7 ++ ...ocess_never.SimplifyLocals-final.after.mir | 5 +- tests/mir-opt/uninhabited_enum.rs | 2 - tests/ui/never_type/diverging-place-match.rs | 13 ++++ .../never_type/diverging-place-match.stderr | 20 ++++++ .../raw-ref-op/never-place-isnt-diverging.rs | 13 ++++ .../never-place-isnt-diverging.stderr | 20 ++++++ tests/ui/reachable/expr_assign.stderr | 9 +-- .../reachable/unwarned-match-on-never.stderr | 2 +- 10 files changed, 146 insertions(+), 12 deletions(-) create mode 100644 tests/ui/never_type/diverging-place-match.rs create mode 100644 tests/ui/never_type/diverging-place-match.stderr create mode 100644 tests/ui/raw-ref-op/never-place-isnt-diverging.rs create mode 100644 tests/ui/raw-ref-op/never-place-isnt-diverging.stderr diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index e3c7dded0ca..870a260c9fe 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -238,8 +238,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { _ => self.warn_if_unreachable(expr.hir_id, expr.span, "expression"), } - // Any expression that produces a value of type `!` must have diverged - if ty.is_never() { + // Any expression that produces a value of type `!` must have diverged, + // unless it's a place expression that isn't being read from, in which case + // diverging would be unsound since we may never actually read the `!`. + // e.g. `let _ = *never_ptr;` with `never_ptr: *const !`. + if ty.is_never() && self.expr_constitutes_read(expr) { self.diverges.set(self.diverges.get() | Diverges::always(expr.span)); } @@ -257,6 +260,66 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty } + pub(super) fn expr_constitutes_read(&self, expr: &'tcx hir::Expr<'tcx>) -> bool { + // We only care about place exprs. Anything else returns an immediate + // which would constitute a read. We don't care about distinguishing + // "syntactic" place exprs since if the base of a field projection is + // not a place then it would've been UB to read from it anyways since + // that constitutes a read. + if !expr.is_syntactic_place_expr() { + return true; + } + + // If this expression has any adjustments applied after the place expression, + // they may constitute reads. + if !self.typeck_results.borrow().expr_adjustments(expr).is_empty() { + return true; + } + + fn pat_does_read(pat: &hir::Pat<'_>) -> bool { + let mut does_read = false; + pat.walk(|pat| { + if matches!( + pat.kind, + hir::PatKind::Wild | hir::PatKind::Never | hir::PatKind::Or(_) + ) { + true + } else { + does_read = true; + // No need to continue. + false + } + }); + does_read + } + + match self.tcx.parent_hir_node(expr.hir_id) { + // Addr-of, field projections, and LHS of assignment don't constitute reads. + // Assignment does call `drop_in_place`, though, but its safety + // requirements are not the same. + hir::Node::Expr(hir::Expr { kind: hir::ExprKind::AddrOf(..), .. }) => false, + hir::Node::Expr(hir::Expr { + kind: hir::ExprKind::Assign(target, _, _) | hir::ExprKind::Field(target, _), + .. + }) if expr.hir_id == target.hir_id => false, + + // If we have a subpattern that performs a read, we want to consider this + // to diverge for compatibility to support something like `let x: () = *never_ptr;`. + hir::Node::LetStmt(hir::LetStmt { init: Some(target), pat, .. }) + | hir::Node::Expr(hir::Expr { + kind: hir::ExprKind::Let(hir::LetExpr { init: target, pat, .. }), + .. + }) if expr.hir_id == target.hir_id && !pat_does_read(*pat) => false, + hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Match(target, arms, _), .. }) + if expr.hir_id == target.hir_id + && !arms.iter().any(|arm| pat_does_read(arm.pat)) => + { + false + } + _ => true, + } + } + #[instrument(skip(self, expr), level = "debug")] fn check_expr_kind( &self, diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index 49c5a7d8a65..824918d1fa2 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -27,6 +27,7 @@ use tracing::{debug, instrument, trace}; use ty::VariantDef; use super::report_unexpected_variant_res; +use crate::diverges::Diverges; use crate::gather_locals::DeclOrigin; use crate::{FnCtxt, LoweredTy, errors}; @@ -276,6 +277,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } }; + // All other patterns constitute a read, which causes us to diverge + // if the type is never. + if ty.is_never() && !matches!(pat.kind, PatKind::Wild | PatKind::Never | PatKind::Or(_)) { + self.diverges.set(self.diverges.get() | Diverges::always(pat.span)); + } + self.write_ty(pat.hir_id, ty); // (note_1): In most of the cases where (note_1) is referenced diff --git a/tests/mir-opt/uninhabited_enum.process_never.SimplifyLocals-final.after.mir b/tests/mir-opt/uninhabited_enum.process_never.SimplifyLocals-final.after.mir index 240f409817d..64fc81e2989 100644 --- a/tests/mir-opt/uninhabited_enum.process_never.SimplifyLocals-final.after.mir +++ b/tests/mir-opt/uninhabited_enum.process_never.SimplifyLocals-final.after.mir @@ -3,12 +3,11 @@ fn process_never(_1: *const !) -> () { debug input => _1; let mut _0: (); - let _2: &!; scope 1 { - debug _input => _2; + debug _input => _1; } bb0: { - unreachable; + return; } } diff --git a/tests/mir-opt/uninhabited_enum.rs b/tests/mir-opt/uninhabited_enum.rs index 859535852cf..9d845e34fbd 100644 --- a/tests/mir-opt/uninhabited_enum.rs +++ b/tests/mir-opt/uninhabited_enum.rs @@ -13,8 +13,6 @@ pub fn process_never(input: *const !) { #[no_mangle] pub fn process_void(input: *const Void) { let _input = unsafe { &*input }; - // In the future, this should end with `unreachable`, but we currently only do - // unreachability analysis for `!`. } fn main() {} diff --git a/tests/ui/never_type/diverging-place-match.rs b/tests/ui/never_type/diverging-place-match.rs new file mode 100644 index 00000000000..7bc00773c0b --- /dev/null +++ b/tests/ui/never_type/diverging-place-match.rs @@ -0,0 +1,13 @@ +#![feature(never_type)] + +fn make_up_a_value() -> T { + unsafe { + //~^ ERROR mismatched types + let x: *const ! = 0 as _; + let _: ! = *x; + // Since `*x` "diverges" in HIR, but doesn't count as a read in MIR, this + // is unsound since we act as if it diverges but it doesn't. + } +} + +fn main() {} diff --git a/tests/ui/never_type/diverging-place-match.stderr b/tests/ui/never_type/diverging-place-match.stderr new file mode 100644 index 00000000000..e86c634d591 --- /dev/null +++ b/tests/ui/never_type/diverging-place-match.stderr @@ -0,0 +1,20 @@ +error[E0308]: mismatched types + --> $DIR/diverging-place-match.rs:4:5 + | +LL | fn make_up_a_value() -> T { + | - expected this type parameter +LL | / unsafe { +LL | | +LL | | let x: *const ! = 0 as _; +LL | | let _: ! = *x; +LL | | // Since `*x` "diverges" in HIR, but doesn't count as a read in MIR, this +LL | | // is unsound since we act as if it diverges but it doesn't. +LL | | } + | |_____^ expected type parameter `T`, found `()` + | + = note: expected type parameter `T` + found unit type `()` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/raw-ref-op/never-place-isnt-diverging.rs b/tests/ui/raw-ref-op/never-place-isnt-diverging.rs new file mode 100644 index 00000000000..52f4158dbc9 --- /dev/null +++ b/tests/ui/raw-ref-op/never-place-isnt-diverging.rs @@ -0,0 +1,13 @@ +#![feature(never_type)] + +fn make_up_a_value() -> T { + unsafe { + //~^ ERROR mismatched types + let x: *const ! = 0 as _; + &raw const *x; + // Since `*x` is `!`, HIR typeck used to think that it diverges + // and allowed the block to coerce to any value, leading to UB. + } +} + +fn main() {} diff --git a/tests/ui/raw-ref-op/never-place-isnt-diverging.stderr b/tests/ui/raw-ref-op/never-place-isnt-diverging.stderr new file mode 100644 index 00000000000..9eba57dde8f --- /dev/null +++ b/tests/ui/raw-ref-op/never-place-isnt-diverging.stderr @@ -0,0 +1,20 @@ +error[E0308]: mismatched types + --> $DIR/never-place-isnt-diverging.rs:4:5 + | +LL | fn make_up_a_value() -> T { + | - expected this type parameter +LL | / unsafe { +LL | | +LL | | let x: *const ! = 0 as _; +LL | | &raw const *x; +LL | | // Since `*x` is `!`, HIR typeck used to think that it diverges +LL | | // and allowed the block to coerce to any value, leading to UB. +LL | | } + | |_____^ expected type parameter `T`, found `()` + | + = note: expected type parameter `T` + found unit type `()` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/reachable/expr_assign.stderr b/tests/ui/reachable/expr_assign.stderr index c51156b3f40..cfbbe04db76 100644 --- a/tests/ui/reachable/expr_assign.stderr +++ b/tests/ui/reachable/expr_assign.stderr @@ -14,12 +14,13 @@ LL | #![deny(unreachable_code)] | ^^^^^^^^^^^^^^^^ error: unreachable expression - --> $DIR/expr_assign.rs:20:14 + --> $DIR/expr_assign.rs:20:9 | LL | *p = return; - | -- ^^^^^^ unreachable expression - | | - | any code following this expression is unreachable + | ^^^^^------ + | | | + | | any code following this expression is unreachable + | unreachable expression error: unreachable expression --> $DIR/expr_assign.rs:26:15 diff --git a/tests/ui/reachable/unwarned-match-on-never.stderr b/tests/ui/reachable/unwarned-match-on-never.stderr index a296d2a055e..c1ad3511b4e 100644 --- a/tests/ui/reachable/unwarned-match-on-never.stderr +++ b/tests/ui/reachable/unwarned-match-on-never.stderr @@ -2,7 +2,7 @@ error: unreachable expression --> $DIR/unwarned-match-on-never.rs:10:5 | LL | match x {} - | - any code following this expression is unreachable + | ---------- any code following this expression is unreachable LL | // But matches in unreachable code are warned. LL | match x {} | ^^^^^^^^^^ unreachable expression From 5193c211ea594ad9918372868bdb5d4dfafaea87 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 5 Sep 2024 07:21:52 -0400 Subject: [PATCH 607/683] Do not coerce places if they do not constitute reads --- compiler/rustc_hir_typeck/src/coercion.rs | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index fb462eec1b9..6a1018883c9 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -82,6 +82,7 @@ struct Coerce<'a, 'tcx> { /// See #47489 and #48598 /// See docs on the "AllowTwoPhase" type for a more detailed discussion allow_two_phase: AllowTwoPhase, + coerce_never: bool, } impl<'a, 'tcx> Deref for Coerce<'a, 'tcx> { @@ -125,8 +126,9 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { fcx: &'f FnCtxt<'f, 'tcx>, cause: ObligationCause<'tcx>, allow_two_phase: AllowTwoPhase, + coerce_never: bool, ) -> Self { - Coerce { fcx, cause, allow_two_phase, use_lub: false } + Coerce { fcx, cause, allow_two_phase, use_lub: false, coerce_never } } fn unify(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> InferResult<'tcx, Ty<'tcx>> { @@ -177,7 +179,11 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { // Coercing from `!` to any type is allowed: if a.is_never() { - return success(simple(Adjust::NeverToAny)(b), b, vec![]); + if self.coerce_never { + return success(simple(Adjust::NeverToAny)(b), b, vec![]); + } else { + return self.unify_and(a, b, identity); + } } // Coercing *from* an unresolved inference variable means that @@ -1038,7 +1044,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// The expressions *must not* have any preexisting adjustments. pub(crate) fn coerce( &self, - expr: &hir::Expr<'_>, + expr: &'tcx hir::Expr<'tcx>, expr_ty: Ty<'tcx>, mut target: Ty<'tcx>, allow_two_phase: AllowTwoPhase, @@ -1055,7 +1061,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let cause = cause.unwrap_or_else(|| self.cause(expr.span, ObligationCauseCode::ExprAssignable)); - let coerce = Coerce::new(self, cause, allow_two_phase); + let coerce = Coerce::new(self, cause, allow_two_phase, self.expr_constitutes_read(expr)); let ok = self.commit_if_ok(|_| coerce.coerce(source, target))?; let (adjustments, _) = self.register_infer_ok_obligations(ok); @@ -1078,7 +1084,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let cause = self.cause(DUMMY_SP, ObligationCauseCode::ExprAssignable); // We don't ever need two-phase here since we throw out the result of the coercion - let coerce = Coerce::new(self, cause, AllowTwoPhase::No); + let coerce = Coerce::new(self, cause, AllowTwoPhase::No, true); self.probe(|_| { let Ok(ok) = coerce.coerce(source, target) else { return false; @@ -1095,7 +1101,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub(crate) fn deref_steps(&self, expr_ty: Ty<'tcx>, target: Ty<'tcx>) -> Option { let cause = self.cause(DUMMY_SP, ObligationCauseCode::ExprAssignable); // We don't ever need two-phase here since we throw out the result of the coercion - let coerce = Coerce::new(self, cause, AllowTwoPhase::No); + let coerce = Coerce::new(self, cause, AllowTwoPhase::No, true); coerce .autoderef(DUMMY_SP, expr_ty) .find_map(|(ty, steps)| self.probe(|_| coerce.unify(ty, target)).ok().map(|_| steps)) @@ -1252,7 +1258,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // probably aren't processing function arguments here and even if we were, // they're going to get autorefed again anyway and we can apply 2-phase borrows // at that time. - let mut coerce = Coerce::new(self, cause.clone(), AllowTwoPhase::No); + let mut coerce = Coerce::new(self, cause.clone(), AllowTwoPhase::No, true); coerce.use_lub = true; // First try to coerce the new expression to the type of the previous ones, From 73d49f8c697da34ee1372b51540bfb0f1ae0c712 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 5 Sep 2024 07:49:38 -0400 Subject: [PATCH 608/683] Fix up tests --- compiler/rustc_hir_typeck/src/coercion.rs | 17 ++++- .../src/fn_ctxt/suggestions.rs | 6 +- .../miri/tests/pass/underscore_pattern.rs | 51 ++++++++++++- ...t_read.main.SimplifyLocals-final.after.mir | 49 ++++++++++++ tests/mir-opt/uninhabited_not_read.rs | 27 +++++++ tests/ui/never_type/diverging-place-match.rs | 36 ++++++++- .../never_type/diverging-place-match.stderr | 75 +++++++++++++++++-- 7 files changed, 245 insertions(+), 16 deletions(-) create mode 100644 tests/mir-opt/uninhabited_not_read.main.SimplifyLocals-final.after.mir create mode 100644 tests/mir-opt/uninhabited_not_read.rs diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index 6a1018883c9..1705421c2f4 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -82,6 +82,10 @@ struct Coerce<'a, 'tcx> { /// See #47489 and #48598 /// See docs on the "AllowTwoPhase" type for a more detailed discussion allow_two_phase: AllowTwoPhase, + /// Whether we allow `NeverToAny` coercions. This is unsound if we're + /// coercing a place expression without it counting as a read in the MIR. + /// This is a side-effect of HIR not really having a great distinction + /// between places and values. coerce_never: bool, } @@ -1083,7 +1087,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { debug!("coercion::can_with_predicates({:?} -> {:?})", source, target); let cause = self.cause(DUMMY_SP, ObligationCauseCode::ExprAssignable); - // We don't ever need two-phase here since we throw out the result of the coercion + // We don't ever need two-phase here since we throw out the result of the coercion. + // We also just always set `coerce_never` to true, since this is a heuristic. let coerce = Coerce::new(self, cause, AllowTwoPhase::No, true); self.probe(|_| { let Ok(ok) = coerce.coerce(source, target) else { @@ -1096,11 +1101,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } /// Given a type and a target type, this function will calculate and return - /// how many dereference steps needed to achieve `expr_ty <: target`. If + /// how many dereference steps needed to coerce `expr_ty` to `target`. If /// it's not possible, return `None`. - pub(crate) fn deref_steps(&self, expr_ty: Ty<'tcx>, target: Ty<'tcx>) -> Option { + pub(crate) fn deref_steps_for_suggestion( + &self, + expr_ty: Ty<'tcx>, + target: Ty<'tcx>, + ) -> Option { let cause = self.cause(DUMMY_SP, ObligationCauseCode::ExprAssignable); - // We don't ever need two-phase here since we throw out the result of the coercion + // We don't ever need two-phase here since we throw out the result of the coercion. let coerce = Coerce::new(self, cause, AllowTwoPhase::No, true); coerce .autoderef(DUMMY_SP, expr_ty) diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index 435b7d0f39a..1df4d32f3cb 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -2608,7 +2608,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } if let hir::ExprKind::Unary(hir::UnOp::Deref, inner) = expr.kind - && let Some(1) = self.deref_steps(expected, checked_ty) + && let Some(1) = self.deref_steps_for_suggestion(expected, checked_ty) { // We have `*&T`, check if what was expected was `&T`. // If so, we may want to suggest removing a `*`. @@ -2738,7 +2738,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } (_, &ty::RawPtr(ty_b, mutbl_b), &ty::Ref(_, ty_a, mutbl_a)) => { - if let Some(steps) = self.deref_steps(ty_a, ty_b) + if let Some(steps) = self.deref_steps_for_suggestion(ty_a, ty_b) // Only suggest valid if dereferencing needed. && steps > 0 // The pointer type implements `Copy` trait so the suggestion is always valid. @@ -2782,7 +2782,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } _ if sp == expr.span => { - if let Some(mut steps) = self.deref_steps(checked_ty, expected) { + if let Some(mut steps) = self.deref_steps_for_suggestion(checked_ty, expected) { let mut expr = expr.peel_blocks(); let mut prefix_span = expr.span.shrink_to_lo(); let mut remove = String::new(); diff --git a/src/tools/miri/tests/pass/underscore_pattern.rs b/src/tools/miri/tests/pass/underscore_pattern.rs index f0afe558954..f59bb9f5c82 100644 --- a/src/tools/miri/tests/pass/underscore_pattern.rs +++ b/src/tools/miri/tests/pass/underscore_pattern.rs @@ -1,5 +1,7 @@ // Various tests ensuring that underscore patterns really just construct the place, but don't check its contents. #![feature(strict_provenance)] +#![feature(never_type)] + use std::ptr; fn main() { @@ -9,6 +11,7 @@ fn main() { invalid_let(); dangling_let_type_annotation(); invalid_let_type_annotation(); + never(); } fn dangling_match() { @@ -34,6 +37,13 @@ fn invalid_match() { _ => {} } } + + unsafe { + let x: Uninit = Uninit { uninit: () }; + match x.value { + _ => {} + } + } } fn dangling_let() { @@ -41,6 +51,11 @@ fn dangling_let() { let ptr = ptr::without_provenance::(0x40); let _ = *ptr; } + + unsafe { + let ptr = ptr::without_provenance::(0x40); + let _ = *ptr; + } } fn invalid_let() { @@ -49,6 +64,12 @@ fn invalid_let() { let ptr = ptr::addr_of!(val).cast::(); let _ = *ptr; } + + unsafe { + let val = 3u8; + let ptr = ptr::addr_of!(val).cast::(); + let _ = *ptr; + } } // Adding a type annotation used to change how MIR is generated, make sure we cover both cases. @@ -57,6 +78,11 @@ fn dangling_let_type_annotation() { let ptr = ptr::without_provenance::(0x40); let _: bool = *ptr; } + + unsafe { + let ptr = ptr::without_provenance::(0x40); + let _: ! = *ptr; + } } fn invalid_let_type_annotation() { @@ -65,7 +91,28 @@ fn invalid_let_type_annotation() { let ptr = ptr::addr_of!(val).cast::(); let _: bool = *ptr; } + + unsafe { + let val = 3u8; + let ptr = ptr::addr_of!(val).cast::(); + let _: ! = *ptr; + } } -// FIXME: we should also test `!`, not just `bool` -- but that s currently buggy: -// https://github.com/rust-lang/rust/issues/117288 +// Regression test from . +fn never() { + unsafe { + let x = 3u8; + let x: *const ! = &x as *const u8 as *const _; + let _: ! = *x; + } + + // Without a type annotation, make sure we don't implicitly coerce `!` to `()` + // when we do the noop `*x` (as that would require a `!` *value*, creating + // which is UB). + unsafe { + let x = 3u8; + let x: *const ! = &x as *const u8 as *const _; + let _ = *x; + } +} diff --git a/tests/mir-opt/uninhabited_not_read.main.SimplifyLocals-final.after.mir b/tests/mir-opt/uninhabited_not_read.main.SimplifyLocals-final.after.mir new file mode 100644 index 00000000000..6bf4be652be --- /dev/null +++ b/tests/mir-opt/uninhabited_not_read.main.SimplifyLocals-final.after.mir @@ -0,0 +1,49 @@ +// MIR for `main` after SimplifyLocals-final + +fn main() -> () { + let mut _0: (); + let _1: u8; + let mut _2: *const !; + let mut _3: *const u8; + let _4: u8; + let mut _5: *const !; + let mut _6: *const u8; + scope 1 { + debug x => _1; + scope 2 { + debug x => _2; + scope 3 { + } + } + } + scope 4 { + debug x => _4; + scope 5 { + debug x => _5; + scope 6 { + } + } + } + + bb0: { + StorageLive(_1); + _1 = const 3_u8; + StorageLive(_2); + StorageLive(_3); + _3 = &raw const _1; + _2 = move _3 as *const ! (PtrToPtr); + StorageDead(_3); + StorageDead(_2); + StorageDead(_1); + StorageLive(_4); + _4 = const 3_u8; + StorageLive(_5); + StorageLive(_6); + _6 = &raw const _4; + _5 = move _6 as *const ! (PtrToPtr); + StorageDead(_6); + StorageDead(_5); + StorageDead(_4); + return; + } +} diff --git a/tests/mir-opt/uninhabited_not_read.rs b/tests/mir-opt/uninhabited_not_read.rs new file mode 100644 index 00000000000..39ffdbdbb33 --- /dev/null +++ b/tests/mir-opt/uninhabited_not_read.rs @@ -0,0 +1,27 @@ +// skip-filecheck + +//@ edition: 2021 +// In ed 2021 and below, we don't fallback `!` to `()`. +// This would introduce a `! -> ()` coercion which would +// be UB if we didn't disallow this explicitly. + +#![feature(never_type)] + +// EMIT_MIR uninhabited_not_read.main.SimplifyLocals-final.after.mir +fn main() { + // With a type annotation + unsafe { + let x = 3u8; + let x: *const ! = &x as *const u8 as *const _; + let _: ! = *x; + } + + // Without a type annotation, make sure we don't implicitly coerce `!` to `()` + // when we do the noop `*x`. + unsafe { + let x = 3u8; + let x: *const ! = &x as *const u8 as *const _; + let _ = *x; + } +} + diff --git a/tests/ui/never_type/diverging-place-match.rs b/tests/ui/never_type/diverging-place-match.rs index 7bc00773c0b..185e17c05a7 100644 --- a/tests/ui/never_type/diverging-place-match.rs +++ b/tests/ui/never_type/diverging-place-match.rs @@ -1,6 +1,6 @@ #![feature(never_type)] -fn make_up_a_value() -> T { +fn not_a_read() -> ! { unsafe { //~^ ERROR mismatched types let x: *const ! = 0 as _; @@ -10,4 +10,38 @@ fn make_up_a_value() -> T { } } +fn not_a_read_implicit() -> ! { + unsafe { + //~^ ERROR mismatched types + let x: *const ! = 0 as _; + let _ = *x; + } +} + +fn not_a_read_guide_coercion() -> ! { + unsafe { + //~^ ERROR mismatched types + let x: *const ! = 0 as _; + let _: () = *x; + //~^ ERROR mismatched types + } +} + +fn empty_match() -> ! { + unsafe { + //~^ ERROR mismatched types + let x: *const ! = 0 as _; + match *x { _ => {} }; + } +} + +fn field_projection() -> ! { + unsafe { + //~^ ERROR mismatched types + let x: *const (!, ()) = 0 as _; + let _ = (*x).0; + // ^ I think this is still UB, but because of the inbounds projection. + } +} + fn main() {} diff --git a/tests/ui/never_type/diverging-place-match.stderr b/tests/ui/never_type/diverging-place-match.stderr index e86c634d591..14b14f42701 100644 --- a/tests/ui/never_type/diverging-place-match.stderr +++ b/tests/ui/never_type/diverging-place-match.stderr @@ -1,8 +1,6 @@ error[E0308]: mismatched types --> $DIR/diverging-place-match.rs:4:5 | -LL | fn make_up_a_value() -> T { - | - expected this type parameter LL | / unsafe { LL | | LL | | let x: *const ! = 0 as _; @@ -10,11 +8,76 @@ LL | | let _: ! = *x; LL | | // Since `*x` "diverges" in HIR, but doesn't count as a read in MIR, this LL | | // is unsound since we act as if it diverges but it doesn't. LL | | } - | |_____^ expected type parameter `T`, found `()` + | |_____^ expected `!`, found `()` | - = note: expected type parameter `T` - found unit type `()` + = note: expected type `!` + found unit type `()` -error: aborting due to 1 previous error +error[E0308]: mismatched types + --> $DIR/diverging-place-match.rs:14:5 + | +LL | / unsafe { +LL | | +LL | | let x: *const ! = 0 as _; +LL | | let _ = *x; +LL | | } + | |_____^ expected `!`, found `()` + | + = note: expected type `!` + found unit type `()` + +error[E0308]: mismatched types + --> $DIR/diverging-place-match.rs:25:21 + | +LL | let _: () = *x; + | -- ^^ expected `()`, found `!` + | | + | expected due to this + | + = note: expected unit type `()` + found type `!` + +error[E0308]: mismatched types + --> $DIR/diverging-place-match.rs:22:5 + | +LL | / unsafe { +LL | | +LL | | let x: *const ! = 0 as _; +LL | | let _: () = *x; +LL | | +LL | | } + | |_____^ expected `!`, found `()` + | + = note: expected type `!` + found unit type `()` + +error[E0308]: mismatched types + --> $DIR/diverging-place-match.rs:31:5 + | +LL | / unsafe { +LL | | +LL | | let x: *const ! = 0 as _; +LL | | match *x { _ => {} }; +LL | | } + | |_____^ expected `!`, found `()` + | + = note: expected type `!` + found unit type `()` + +error[E0308]: mismatched types + --> $DIR/diverging-place-match.rs:39:5 + | +LL | / unsafe { +LL | | +LL | | let x: *const (!, ()) = 0 as _; +LL | | let _ = (*x).0; +LL | | // ^ I think this is still UB, but because of the inbounds projection. +LL | | } + | |_____^ expected `!`, found `()` + | + = note: expected type `!` + found unit type `()` + +error: aborting due to 6 previous errors For more information about this error, try `rustc --explain E0308`. From 515b93297ff6b96e6368070f3eb3f3a833112bc0 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 5 Sep 2024 07:53:49 -0400 Subject: [PATCH 609/683] Document things a bit more carefully, also account for coercion in check_expr_has_type_or_error --- compiler/rustc_hir_typeck/src/coercion.rs | 1 + compiler/rustc_hir_typeck/src/expr.rs | 16 +++++++++++++++- tests/mir-opt/uninhabited_not_read.rs | 1 - .../match/pattern-matching-should-fail.stderr | 6 ++---- 4 files changed, 18 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index 1705421c2f4..96bff04dbc7 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -186,6 +186,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { if self.coerce_never { return success(simple(Adjust::NeverToAny)(b), b, vec![]); } else { + // Otherwise the only coercion we can do is unification. return self.unify_and(a, b, identity); } } diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 870a260c9fe..604bec95701 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -62,7 +62,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // While we don't allow *arbitrary* coercions here, we *do* allow // coercions from ! to `expected`. - if ty.is_never() { + if ty.is_never() && self.expr_constitutes_read(expr) { if let Some(_) = self.typeck_results.borrow().adjustments().get(expr.hir_id) { let reported = self.dcx().span_delayed_bug( expr.span, @@ -260,6 +260,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty } + /// Whether this expression constitutes a read of value of the type that + /// it evaluates to. + /// + /// This is used to determine if we should consider the block to diverge + /// if the expression evaluates to `!`, and if we should insert a `NeverToAny` + /// coercion for values of type `!`. + /// + /// This function generally returns `false` if the expression is a place + /// expression and the *parent* expression is the scrutinee of a match or + /// the pointee of an `&` addr-of expression, since both of those parent + /// expressions take a *place* and not a value. + /// + /// This function is unfortunately a bit heuristical, though it is certainly + /// far sounder than the prior status quo: . pub(super) fn expr_constitutes_read(&self, expr: &'tcx hir::Expr<'tcx>) -> bool { // We only care about place exprs. Anything else returns an immediate // which would constitute a read. We don't care about distinguishing diff --git a/tests/mir-opt/uninhabited_not_read.rs b/tests/mir-opt/uninhabited_not_read.rs index 39ffdbdbb33..15769cdd75b 100644 --- a/tests/mir-opt/uninhabited_not_read.rs +++ b/tests/mir-opt/uninhabited_not_read.rs @@ -24,4 +24,3 @@ fn main() { let _ = *x; } } - diff --git a/tests/ui/closures/2229_closure_analysis/match/pattern-matching-should-fail.stderr b/tests/ui/closures/2229_closure_analysis/match/pattern-matching-should-fail.stderr index f8ed792e3c6..e0d900a1eb5 100644 --- a/tests/ui/closures/2229_closure_analysis/match/pattern-matching-should-fail.stderr +++ b/tests/ui/closures/2229_closure_analysis/match/pattern-matching-should-fail.stderr @@ -7,14 +7,12 @@ LL | let c1 = || match x { }; | ^ `x` used here but it isn't initialized error[E0381]: used binding `x` isn't initialized - --> $DIR/pattern-matching-should-fail.rs:15:14 + --> $DIR/pattern-matching-should-fail.rs:15:23 | LL | let x: !; | - binding declared here but left uninitialized LL | let c2 = || match x { _ => () }; - | ^^ - borrow occurs due to use in closure - | | - | `x` used here but it isn't initialized + | ^ `x` used here but it isn't initialized error[E0381]: used binding `variant` isn't initialized --> $DIR/pattern-matching-should-fail.rs:27:13 From d2bd018dadc98442a15f52d962aaf3c5d102f034 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 5 Sep 2024 09:42:44 -0400 Subject: [PATCH 610/683] Be more thorough in expr_constitutes_read --- compiler/rustc_hir_typeck/src/expr.rs | 181 ++++++++++++++++++++------ compiler/rustc_hir_typeck/src/pat.rs | 2 +- 2 files changed, 141 insertions(+), 42 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 604bec95701..cef00cf8ce8 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -1,3 +1,6 @@ +// ignore-tidy-filelength +// FIXME: we should move the field error reporting code somewhere else. + //! Type checking expressions. //! //! See [`rustc_hir_analysis::check`] for more context on type checking in general. @@ -284,54 +287,150 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return true; } - // If this expression has any adjustments applied after the place expression, - // they may constitute reads. - if !self.typeck_results.borrow().expr_adjustments(expr).is_empty() { - return true; - } + let parent_node = self.tcx.parent_hir_node(expr.hir_id); + match parent_node { + hir::Node::Expr(parent_expr) => { + match parent_expr.kind { + // Addr-of, field projections, and LHS of assignment don't constitute reads. + // Assignment does call `drop_in_place`, though, but its safety + // requirements are not the same. + ExprKind::AddrOf(..) | hir::ExprKind::Field(..) => false, + ExprKind::Assign(lhs, _, _) => { + // Only the LHS does not constitute a read + expr.hir_id != lhs.hir_id + } - fn pat_does_read(pat: &hir::Pat<'_>) -> bool { - let mut does_read = false; - pat.walk(|pat| { - if matches!( - pat.kind, - hir::PatKind::Wild | hir::PatKind::Never | hir::PatKind::Or(_) - ) { + // If we have a subpattern that performs a read, we want to consider this + // to diverge for compatibility to support something like `let x: () = *never_ptr;`. + ExprKind::Match(scrutinee, arms, _) => { + assert_eq!(scrutinee.hir_id, expr.hir_id); + arms.iter().any(|arm| self.pat_constitutes_read(arm.pat)) + } + ExprKind::Let(hir::LetExpr { init, pat, .. }) => { + assert_eq!(init.hir_id, expr.hir_id); + self.pat_constitutes_read(*pat) + } + + // Any expression child of these expressions constitute reads. + ExprKind::Array(_) + | ExprKind::Call(_, _) + | ExprKind::MethodCall(_, _, _, _) + | ExprKind::Tup(_) + | ExprKind::Binary(_, _, _) + | ExprKind::Unary(_, _) + | ExprKind::Cast(_, _) + | ExprKind::Type(_, _) + | ExprKind::DropTemps(_) + | ExprKind::If(_, _, _) + | ExprKind::Closure(_) + | ExprKind::Block(_, _) + | ExprKind::AssignOp(_, _, _) + | ExprKind::Index(_, _, _) + | ExprKind::Break(_, _) + | ExprKind::Ret(_) + | ExprKind::Become(_) + | ExprKind::InlineAsm(_) + | ExprKind::Struct(_, _, _) + | ExprKind::Repeat(_, _) + | ExprKind::Yield(_, _) => true, + + // These expressions have no (direct) sub-exprs. + ExprKind::ConstBlock(_) + | ExprKind::Loop(_, _, _, _) + | ExprKind::Lit(_) + | ExprKind::Path(_) + | ExprKind::Continue(_) + | ExprKind::OffsetOf(_, _) + | ExprKind::Err(_) => unreachable!("no sub-expr expected for {:?}", expr.kind), + } + } + + // If we have a subpattern that performs a read, we want to consider this + // to diverge for compatibility to support something like `let x: () = *never_ptr;`. + hir::Node::LetStmt(hir::LetStmt { init: Some(target), pat, .. }) => { + assert_eq!(target.hir_id, expr.hir_id); + self.pat_constitutes_read(*pat) + } + + // These nodes (if they have a sub-expr) do constitute a read. + hir::Node::Block(_) + | hir::Node::Arm(_) + | hir::Node::ExprField(_) + | hir::Node::AnonConst(_) + | hir::Node::ConstBlock(_) + | hir::Node::ConstArg(_) + | hir::Node::Stmt(_) + | hir::Node::Item(hir::Item { + kind: hir::ItemKind::Const(..) | hir::ItemKind::Static(..), + .. + }) + | hir::Node::TraitItem(hir::TraitItem { + kind: hir::TraitItemKind::Const(..), .. + }) + | hir::Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Const(..), .. }) => true, + + // These nodes do not have direct sub-exprs. + hir::Node::Param(_) + | hir::Node::Item(_) + | hir::Node::ForeignItem(_) + | hir::Node::TraitItem(_) + | hir::Node::ImplItem(_) + | hir::Node::Variant(_) + | hir::Node::Field(_) + | hir::Node::PathSegment(_) + | hir::Node::Ty(_) + | hir::Node::AssocItemConstraint(_) + | hir::Node::TraitRef(_) + | hir::Node::Pat(_) + | hir::Node::PatField(_) + | hir::Node::LetStmt(_) + | hir::Node::Synthetic + | hir::Node::Err(_) + | hir::Node::Ctor(_) + | hir::Node::Lifetime(_) + | hir::Node::GenericParam(_) + | hir::Node::Crate(_) + | hir::Node::Infer(_) + | hir::Node::WhereBoundPredicate(_) + | hir::Node::ArrayLenInfer(_) + | hir::Node::PreciseCapturingNonLifetimeArg(_) + | hir::Node::OpaqueTy(_) => { + unreachable!("no sub-expr expected for {parent_node:?}") + } + } + } + + /// Whether this pattern constitutes a read of value of the scrutinee that + /// it is matching against. + /// + /// See above for the nuances of what happens when this returns true. + pub(super) fn pat_constitutes_read(&self, pat: &hir::Pat<'_>) -> bool { + let mut does_read = false; + pat.walk(|pat| { + match pat.kind { + hir::PatKind::Wild | hir::PatKind::Never | hir::PatKind::Or(_) => { + // Recurse true - } else { + } + hir::PatKind::Binding(_, _, _, _) + | hir::PatKind::Struct(_, _, _) + | hir::PatKind::TupleStruct(_, _, _) + | hir::PatKind::Path(_) + | hir::PatKind::Tuple(_, _) + | hir::PatKind::Box(_) + | hir::PatKind::Ref(_, _) + | hir::PatKind::Deref(_) + | hir::PatKind::Lit(_) + | hir::PatKind::Range(_, _, _) + | hir::PatKind::Slice(_, _, _) + | hir::PatKind::Err(_) => { does_read = true; // No need to continue. false } - }); - does_read - } - - match self.tcx.parent_hir_node(expr.hir_id) { - // Addr-of, field projections, and LHS of assignment don't constitute reads. - // Assignment does call `drop_in_place`, though, but its safety - // requirements are not the same. - hir::Node::Expr(hir::Expr { kind: hir::ExprKind::AddrOf(..), .. }) => false, - hir::Node::Expr(hir::Expr { - kind: hir::ExprKind::Assign(target, _, _) | hir::ExprKind::Field(target, _), - .. - }) if expr.hir_id == target.hir_id => false, - - // If we have a subpattern that performs a read, we want to consider this - // to diverge for compatibility to support something like `let x: () = *never_ptr;`. - hir::Node::LetStmt(hir::LetStmt { init: Some(target), pat, .. }) - | hir::Node::Expr(hir::Expr { - kind: hir::ExprKind::Let(hir::LetExpr { init: target, pat, .. }), - .. - }) if expr.hir_id == target.hir_id && !pat_does_read(*pat) => false, - hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Match(target, arms, _), .. }) - if expr.hir_id == target.hir_id - && !arms.iter().any(|arm| pat_does_read(arm.pat)) => - { - false } - _ => true, - } + }); + does_read } #[instrument(skip(self, expr), level = "debug")] diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index 824918d1fa2..c2e25d259c5 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> { // All other patterns constitute a read, which causes us to diverge // if the type is never. - if ty.is_never() && !matches!(pat.kind, PatKind::Wild | PatKind::Never | PatKind::Or(_)) { + if ty.is_never() && self.pat_constitutes_read(pat) { self.diverges.set(self.diverges.get() | Diverges::always(pat.span)); } From e8d5eb2a2b6cdddd6725501e1b54a33c278d9697 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 6 Sep 2024 10:19:07 -0400 Subject: [PATCH 611/683] Be far more strict about what we consider to be a read of never --- compiler/rustc_hir_typeck/src/coercion.rs | 10 ++- compiler/rustc_hir_typeck/src/expr.rs | 85 ++++++++++--------- compiler/rustc_hir_typeck/src/pat.rs | 7 -- ...ocess_never.SimplifyLocals-final.after.mir | 4 +- ...rocess_void.SimplifyLocals-final.after.mir | 2 +- tests/mir-opt/uninhabited_enum.rs | 7 +- tests/ui/never_type/diverging-place-match.rs | 27 ++++++ .../never_type/diverging-place-match.stderr | 61 ++++++++++++- .../raw-ref-op/never-place-isnt-diverging.rs | 9 ++ .../never-place-isnt-diverging.stderr | 16 +++- .../reachable/unwarned-match-on-never.stderr | 2 +- 11 files changed, 176 insertions(+), 54 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index 96bff04dbc7..642db3f36b5 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -1066,7 +1066,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let cause = cause.unwrap_or_else(|| self.cause(expr.span, ObligationCauseCode::ExprAssignable)); - let coerce = Coerce::new(self, cause, allow_two_phase, self.expr_constitutes_read(expr)); + let coerce = Coerce::new( + self, + cause, + allow_two_phase, + self.expr_guaranteed_to_constitute_read_for_never(expr), + ); let ok = self.commit_if_ok(|_| coerce.coerce(source, target))?; let (adjustments, _) = self.register_infer_ok_obligations(ok); @@ -1268,6 +1273,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // probably aren't processing function arguments here and even if we were, // they're going to get autorefed again anyway and we can apply 2-phase borrows // at that time. + // + // NOTE: we set `coerce_never` to `true` here because coercion LUBs only + // operate on values and not places, so a never coercion is valid. let mut coerce = Coerce::new(self, cause.clone(), AllowTwoPhase::No, true); coerce.use_lub = true; diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index cef00cf8ce8..2d718295374 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -65,7 +65,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // While we don't allow *arbitrary* coercions here, we *do* allow // coercions from ! to `expected`. - if ty.is_never() && self.expr_constitutes_read(expr) { + if ty.is_never() && self.expr_guaranteed_to_constitute_read_for_never(expr) { if let Some(_) = self.typeck_results.borrow().adjustments().get(expr.hir_id) { let reported = self.dcx().span_delayed_bug( expr.span, @@ -245,7 +245,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // unless it's a place expression that isn't being read from, in which case // diverging would be unsound since we may never actually read the `!`. // e.g. `let _ = *never_ptr;` with `never_ptr: *const !`. - if ty.is_never() && self.expr_constitutes_read(expr) { + if ty.is_never() && self.expr_guaranteed_to_constitute_read_for_never(expr) { self.diverges.set(self.diverges.get() | Diverges::always(expr.span)); } @@ -274,10 +274,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// expression and the *parent* expression is the scrutinee of a match or /// the pointee of an `&` addr-of expression, since both of those parent /// expressions take a *place* and not a value. - /// - /// This function is unfortunately a bit heuristical, though it is certainly - /// far sounder than the prior status quo: . - pub(super) fn expr_constitutes_read(&self, expr: &'tcx hir::Expr<'tcx>) -> bool { + pub(super) fn expr_guaranteed_to_constitute_read_for_never( + &self, + expr: &'tcx hir::Expr<'tcx>, + ) -> bool { // We only care about place exprs. Anything else returns an immediate // which would constitute a read. We don't care about distinguishing // "syntactic" place exprs since if the base of a field projection is @@ -300,15 +300,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expr.hir_id != lhs.hir_id } - // If we have a subpattern that performs a read, we want to consider this - // to diverge for compatibility to support something like `let x: () = *never_ptr;`. + // See note on `PatKind::Or` below for why this is `all`. ExprKind::Match(scrutinee, arms, _) => { assert_eq!(scrutinee.hir_id, expr.hir_id); - arms.iter().any(|arm| self.pat_constitutes_read(arm.pat)) + arms.iter() + .all(|arm| self.pat_guaranteed_to_constitute_read_for_never(arm.pat)) } ExprKind::Let(hir::LetExpr { init, pat, .. }) => { assert_eq!(init.hir_id, expr.hir_id); - self.pat_constitutes_read(*pat) + self.pat_guaranteed_to_constitute_read_for_never(*pat) } // Any expression child of these expressions constitute reads. @@ -349,7 +349,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // to diverge for compatibility to support something like `let x: () = *never_ptr;`. hir::Node::LetStmt(hir::LetStmt { init: Some(target), pat, .. }) => { assert_eq!(target.hir_id, expr.hir_id); - self.pat_constitutes_read(*pat) + self.pat_guaranteed_to_constitute_read_for_never(*pat) } // These nodes (if they have a sub-expr) do constitute a read. @@ -401,36 +401,45 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } /// Whether this pattern constitutes a read of value of the scrutinee that - /// it is matching against. + /// it is matching against. This is used to determine whether we should + /// perform `NeverToAny` coercions. /// /// See above for the nuances of what happens when this returns true. - pub(super) fn pat_constitutes_read(&self, pat: &hir::Pat<'_>) -> bool { - let mut does_read = false; - pat.walk(|pat| { - match pat.kind { - hir::PatKind::Wild | hir::PatKind::Never | hir::PatKind::Or(_) => { - // Recurse - true - } - hir::PatKind::Binding(_, _, _, _) - | hir::PatKind::Struct(_, _, _) - | hir::PatKind::TupleStruct(_, _, _) - | hir::PatKind::Path(_) - | hir::PatKind::Tuple(_, _) - | hir::PatKind::Box(_) - | hir::PatKind::Ref(_, _) - | hir::PatKind::Deref(_) - | hir::PatKind::Lit(_) - | hir::PatKind::Range(_, _, _) - | hir::PatKind::Slice(_, _, _) - | hir::PatKind::Err(_) => { - does_read = true; - // No need to continue. - false - } + pub(super) fn pat_guaranteed_to_constitute_read_for_never(&self, pat: &hir::Pat<'_>) -> bool { + match pat.kind { + // Does not constitute a read. + hir::PatKind::Wild => false, + + // This is unnecessarily restrictive when the pattern that doesn't + // constitute a read is unreachable. + // + // For example `match *never_ptr { value => {}, _ => {} }` or + // `match *never_ptr { _ if false => {}, value => {} }`. + // + // It is however fine to be restrictive here; only returning `true` + // can lead to unsoundness. + hir::PatKind::Or(subpats) => { + subpats.iter().all(|pat| self.pat_guaranteed_to_constitute_read_for_never(pat)) } - }); - does_read + + // Does constitute a read, since it is equivalent to a discriminant read. + hir::PatKind::Never => true, + + // All of these constitute a read, or match on something that isn't `!`, + // which would require a `NeverToAny` coercion. + hir::PatKind::Binding(_, _, _, _) + | hir::PatKind::Struct(_, _, _) + | hir::PatKind::TupleStruct(_, _, _) + | hir::PatKind::Path(_) + | hir::PatKind::Tuple(_, _) + | hir::PatKind::Box(_) + | hir::PatKind::Ref(_, _) + | hir::PatKind::Deref(_) + | hir::PatKind::Lit(_) + | hir::PatKind::Range(_, _, _) + | hir::PatKind::Slice(_, _, _) + | hir::PatKind::Err(_) => true, + } } #[instrument(skip(self, expr), level = "debug")] diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index c2e25d259c5..49c5a7d8a65 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -27,7 +27,6 @@ use tracing::{debug, instrument, trace}; use ty::VariantDef; use super::report_unexpected_variant_res; -use crate::diverges::Diverges; use crate::gather_locals::DeclOrigin; use crate::{FnCtxt, LoweredTy, errors}; @@ -277,12 +276,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } }; - // All other patterns constitute a read, which causes us to diverge - // if the type is never. - if ty.is_never() && self.pat_constitutes_read(pat) { - self.diverges.set(self.diverges.get() | Diverges::always(pat.span)); - } - self.write_ty(pat.hir_id, ty); // (note_1): In most of the cases where (note_1) is referenced diff --git a/tests/mir-opt/uninhabited_enum.process_never.SimplifyLocals-final.after.mir b/tests/mir-opt/uninhabited_enum.process_never.SimplifyLocals-final.after.mir index 64fc81e2989..02e1f4be15e 100644 --- a/tests/mir-opt/uninhabited_enum.process_never.SimplifyLocals-final.after.mir +++ b/tests/mir-opt/uninhabited_enum.process_never.SimplifyLocals-final.after.mir @@ -4,10 +4,10 @@ fn process_never(_1: *const !) -> () { debug input => _1; let mut _0: (); scope 1 { - debug _input => _1; + debug _input => const (); } bb0: { - return; + unreachable; } } diff --git a/tests/mir-opt/uninhabited_enum.process_void.SimplifyLocals-final.after.mir b/tests/mir-opt/uninhabited_enum.process_void.SimplifyLocals-final.after.mir index 51514ba5e5d..64711755f73 100644 --- a/tests/mir-opt/uninhabited_enum.process_void.SimplifyLocals-final.after.mir +++ b/tests/mir-opt/uninhabited_enum.process_void.SimplifyLocals-final.after.mir @@ -4,7 +4,7 @@ fn process_void(_1: *const Void) -> () { debug input => _1; let mut _0: (); scope 1 { - debug _input => _1; + debug _input => const ZeroSized: Void; } bb0: { diff --git a/tests/mir-opt/uninhabited_enum.rs b/tests/mir-opt/uninhabited_enum.rs index 9d845e34fbd..90b5353f291 100644 --- a/tests/mir-opt/uninhabited_enum.rs +++ b/tests/mir-opt/uninhabited_enum.rs @@ -1,18 +1,21 @@ // skip-filecheck #![feature(never_type)] +#[derive(Copy, Clone)] pub enum Void {} // EMIT_MIR uninhabited_enum.process_never.SimplifyLocals-final.after.mir #[no_mangle] pub fn process_never(input: *const !) { - let _input = unsafe { &*input }; + let _input = unsafe { *input }; } // EMIT_MIR uninhabited_enum.process_void.SimplifyLocals-final.after.mir #[no_mangle] pub fn process_void(input: *const Void) { - let _input = unsafe { &*input }; + let _input = unsafe { *input }; + // In the future, this should end with `unreachable`, but we currently only do + // unreachability analysis for `!`. } fn main() {} diff --git a/tests/ui/never_type/diverging-place-match.rs b/tests/ui/never_type/diverging-place-match.rs index 185e17c05a7..b9bc29a218c 100644 --- a/tests/ui/never_type/diverging-place-match.rs +++ b/tests/ui/never_type/diverging-place-match.rs @@ -44,4 +44,31 @@ fn field_projection() -> ! { } } +fn covered_arm() -> ! { + unsafe { + //~^ ERROR mismatched types + let x: *const ! = 0 as _; + let (_ | 1i32) = *x; + //~^ ERROR mismatched types + } +} + +// FIXME: This *could* be considered a read of `!`, but we're not that sophisticated.. +fn uncovered_arm() -> ! { + unsafe { + //~^ ERROR mismatched types + let x: *const ! = 0 as _; + let (1i32 | _) = *x; + //~^ ERROR mismatched types + } +} + +fn coerce_ref_binding() -> ! { + unsafe { + let x: *const ! = 0 as _; + let ref _x: () = *x; + //~^ ERROR mismatched types + } +} + fn main() {} diff --git a/tests/ui/never_type/diverging-place-match.stderr b/tests/ui/never_type/diverging-place-match.stderr index 14b14f42701..74e1bfa0a6b 100644 --- a/tests/ui/never_type/diverging-place-match.stderr +++ b/tests/ui/never_type/diverging-place-match.stderr @@ -78,6 +78,65 @@ LL | | } = note: expected type `!` found unit type `()` -error: aborting due to 6 previous errors +error[E0308]: mismatched types + --> $DIR/diverging-place-match.rs:51:18 + | +LL | let (_ | 1i32) = *x; + | ^^^^ -- this expression has type `!` + | | + | expected `!`, found `i32` + | + = note: expected type `!` + found type `i32` + +error[E0308]: mismatched types + --> $DIR/diverging-place-match.rs:48:5 + | +LL | / unsafe { +LL | | +LL | | let x: *const ! = 0 as _; +LL | | let (_ | 1i32) = *x; +LL | | +LL | | } + | |_____^ expected `!`, found `()` + | + = note: expected type `!` + found unit type `()` + +error[E0308]: mismatched types + --> $DIR/diverging-place-match.rs:61:14 + | +LL | let (1i32 | _) = *x; + | ^^^^ -- this expression has type `!` + | | + | expected `!`, found `i32` + | + = note: expected type `!` + found type `i32` + +error[E0308]: mismatched types + --> $DIR/diverging-place-match.rs:58:5 + | +LL | / unsafe { +LL | | +LL | | let x: *const ! = 0 as _; +LL | | let (1i32 | _) = *x; +LL | | +LL | | } + | |_____^ expected `!`, found `()` + | + = note: expected type `!` + found unit type `()` + +error[E0308]: mismatched types + --> $DIR/diverging-place-match.rs:69:26 + | +LL | let ref _x: () = *x; + | ^^ expected `()`, found `!` + | + = note: expected unit type `()` + found type `!` + +error: aborting due to 11 previous errors For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/raw-ref-op/never-place-isnt-diverging.rs b/tests/ui/raw-ref-op/never-place-isnt-diverging.rs index 52f4158dbc9..80d441729f7 100644 --- a/tests/ui/raw-ref-op/never-place-isnt-diverging.rs +++ b/tests/ui/raw-ref-op/never-place-isnt-diverging.rs @@ -10,4 +10,13 @@ fn make_up_a_value() -> T { } } + +fn make_up_a_pointer() -> *const T { + unsafe { + let x: *const ! = 0 as _; + &raw const *x + //~^ ERROR mismatched types + } +} + fn main() {} diff --git a/tests/ui/raw-ref-op/never-place-isnt-diverging.stderr b/tests/ui/raw-ref-op/never-place-isnt-diverging.stderr index 9eba57dde8f..af9e7889821 100644 --- a/tests/ui/raw-ref-op/never-place-isnt-diverging.stderr +++ b/tests/ui/raw-ref-op/never-place-isnt-diverging.stderr @@ -15,6 +15,20 @@ LL | | } = note: expected type parameter `T` found unit type `()` -error: aborting due to 1 previous error +error[E0308]: mismatched types + --> $DIR/never-place-isnt-diverging.rs:17:9 + | +LL | fn make_up_a_pointer() -> *const T { + | - -------- expected `*const T` because of return type + | | + | expected this type parameter +... +LL | &raw const *x + | ^^^^^^^^^^^^^ expected `*const T`, found `*const !` + | + = note: expected raw pointer `*const T` + found raw pointer `*const !` + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/reachable/unwarned-match-on-never.stderr b/tests/ui/reachable/unwarned-match-on-never.stderr index c1ad3511b4e..a296d2a055e 100644 --- a/tests/ui/reachable/unwarned-match-on-never.stderr +++ b/tests/ui/reachable/unwarned-match-on-never.stderr @@ -2,7 +2,7 @@ error: unreachable expression --> $DIR/unwarned-match-on-never.rs:10:5 | LL | match x {} - | ---------- any code following this expression is unreachable + | - any code following this expression is unreachable LL | // But matches in unreachable code are warned. LL | match x {} | ^^^^^^^^^^ unreachable expression From 7f5548fa8b22bccdadb3cbe7cf4d566a970eeb25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sun, 6 Oct 2024 01:44:59 +0000 Subject: [PATCH 612/683] On function and method calls in patterns, link to the book ``` error: expected a pattern, found an expression --> f889.rs:3:13 | 3 | let (x, y.drop()) = (1, 2); //~ ERROR | ^^^^^^^^ not a pattern | = note: arbitrary expressions are not allowed in patterns: error[E0532]: expected a pattern, found a function call --> f889.rs:2:13 | 2 | let (x, drop(y)) = (1, 2); //~ ERROR | ^^^^ not a tuple struct or tuple variant | = note: function calls are not allowed in patterns: ``` Fix #97200. --- compiler/rustc_parse/messages.ftl | 3 +- compiler/rustc_parse/src/errors.rs | 1 + .../rustc_resolve/src/late/diagnostics.rs | 13 +++ .../range_pat_interactions1.stderr | 3 +- .../range_pat_interactions2.stderr | 3 +- tests/ui/parser/bad-name.stderr | 4 +- tests/ui/parser/issues/issue-24197.stderr | 4 +- tests/ui/parser/issues/issue-24375.stderr | 3 +- tests/ui/parser/pat-lt-bracket-5.stderr | 4 +- tests/ui/parser/pat-lt-bracket-6.stderr | 4 +- tests/ui/parser/pat-ranges-3.stderr | 8 +- .../parser/recover/recover-pat-exprs.stderr | 103 ++++++++++++------ .../parser/recover/recover-pat-issues.stderr | 18 ++- .../ui/parser/recover/recover-pat-lets.stderr | 18 ++- .../parser/recover/recover-pat-ranges.stderr | 18 ++- .../recover/recover-pat-wildcards.stderr | 3 +- tests/ui/resolve/issue-10200.rs | 2 +- tests/ui/resolve/issue-10200.stderr | 4 +- ...s-in-pattern-with-ty-err-doesnt-ice.stderr | 4 +- 19 files changed, 156 insertions(+), 64 deletions(-) diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index 5d1c300b453..948199fd55c 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -812,7 +812,8 @@ parse_unexpected_expr_in_pat = *[false] a pattern }, found an expression - .label = arbitrary expressions are not allowed in patterns + .label = not a pattern + .note = arbitrary expressions are not allowed in patterns: parse_unexpected_expr_in_pat_const_sugg = consider extracting the expression into a `const` diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 40502158469..dade3912751 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -2608,6 +2608,7 @@ pub(crate) struct ExpectedCommaAfterPatternField { #[derive(Diagnostic)] #[diag(parse_unexpected_expr_in_pat)] +#[note] pub(crate) struct UnexpectedExpressionInPattern { /// The unexpected expr's span. #[primary_span] diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 35d166e8b4a..fce5ec36c66 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -443,6 +443,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { self.suggest_bare_struct_literal(&mut err); self.suggest_changing_type_to_const_param(&mut err, res, source, span); + self.explain_functions_in_pattern(&mut err, res, source); if self.suggest_pattern_match_with_let(&mut err, source, span) { // Fallback label. @@ -1166,6 +1167,18 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { } } + fn explain_functions_in_pattern( + &mut self, + err: &mut Diag<'_>, + res: Option, + source: PathSource<'_>, + ) { + let PathSource::TupleStruct(_, _) = source else { return }; + let Some(Res::Def(DefKind::Fn, _)) = res else { return }; + err.primary_message("expected a pattern, found a function call"); + err.note("function calls are not allowed in patterns: "); + } + fn suggest_changing_type_to_const_param( &mut self, err: &mut Diag<'_>, diff --git a/tests/ui/half-open-range-patterns/range_pat_interactions1.stderr b/tests/ui/half-open-range-patterns/range_pat_interactions1.stderr index 9831348de75..e2916725fbd 100644 --- a/tests/ui/half-open-range-patterns/range_pat_interactions1.stderr +++ b/tests/ui/half-open-range-patterns/range_pat_interactions1.stderr @@ -2,8 +2,9 @@ error: expected a pattern range bound, found an expression --> $DIR/range_pat_interactions1.rs:17:16 | LL | 0..5+1 => errors_only.push(x), - | ^^^ arbitrary expressions are not allowed in patterns + | ^^^ not a pattern | + = note: arbitrary expressions are not allowed in patterns: help: consider extracting the expression into a `const` | LL + const VAL: /* Type */ = 5+1; diff --git a/tests/ui/half-open-range-patterns/range_pat_interactions2.stderr b/tests/ui/half-open-range-patterns/range_pat_interactions2.stderr index 1b5e875cccb..f54e07c3a63 100644 --- a/tests/ui/half-open-range-patterns/range_pat_interactions2.stderr +++ b/tests/ui/half-open-range-patterns/range_pat_interactions2.stderr @@ -14,8 +14,9 @@ error: expected a pattern range bound, found an expression --> $DIR/range_pat_interactions2.rs:10:18 | LL | 0..=(5+1) => errors_only.push(x), - | ^^^ arbitrary expressions are not allowed in patterns + | ^^^ not a pattern | + = note: arbitrary expressions are not allowed in patterns: help: consider extracting the expression into a `const` | LL + const VAL: /* Type */ = 5+1; diff --git a/tests/ui/parser/bad-name.stderr b/tests/ui/parser/bad-name.stderr index 3fc416dd531..5ca248380ee 100644 --- a/tests/ui/parser/bad-name.stderr +++ b/tests/ui/parser/bad-name.stderr @@ -8,7 +8,9 @@ error: expected a pattern, found an expression --> $DIR/bad-name.rs:2:7 | LL | let x.y::.z foo; - | ^^^^^^^^^^^^^^ arbitrary expressions are not allowed in patterns + | ^^^^^^^^^^^^^^ not a pattern + | + = note: arbitrary expressions are not allowed in patterns: error: expected one of `(`, `.`, `::`, `:`, `;`, `=`, `?`, `|`, or an operator, found `foo` --> $DIR/bad-name.rs:2:22 diff --git a/tests/ui/parser/issues/issue-24197.stderr b/tests/ui/parser/issues/issue-24197.stderr index 7ebbf4ac370..c92e165b23b 100644 --- a/tests/ui/parser/issues/issue-24197.stderr +++ b/tests/ui/parser/issues/issue-24197.stderr @@ -2,7 +2,9 @@ error: expected a pattern, found an expression --> $DIR/issue-24197.rs:2:9 | LL | let buf[0] = 0; - | ^^^^^^ arbitrary expressions are not allowed in patterns + | ^^^^^^ not a pattern + | + = note: arbitrary expressions are not allowed in patterns: error: aborting due to 1 previous error diff --git a/tests/ui/parser/issues/issue-24375.stderr b/tests/ui/parser/issues/issue-24375.stderr index a25c277d78a..fef3fcde7b7 100644 --- a/tests/ui/parser/issues/issue-24375.stderr +++ b/tests/ui/parser/issues/issue-24375.stderr @@ -2,8 +2,9 @@ error: expected a pattern, found an expression --> $DIR/issue-24375.rs:6:9 | LL | tmp[0] => {} - | ^^^^^^ arbitrary expressions are not allowed in patterns + | ^^^^^^ not a pattern | + = note: arbitrary expressions are not allowed in patterns: help: consider moving the expression to a match arm guard | LL | val if val == tmp[0] => {} diff --git a/tests/ui/parser/pat-lt-bracket-5.stderr b/tests/ui/parser/pat-lt-bracket-5.stderr index 18cf2df0282..a2a972652d1 100644 --- a/tests/ui/parser/pat-lt-bracket-5.stderr +++ b/tests/ui/parser/pat-lt-bracket-5.stderr @@ -2,7 +2,9 @@ error: expected a pattern, found an expression --> $DIR/pat-lt-bracket-5.rs:2:9 | LL | let v[0] = v[1]; - | ^^^^ arbitrary expressions are not allowed in patterns + | ^^^^ not a pattern + | + = note: arbitrary expressions are not allowed in patterns: error[E0425]: cannot find value `v` in this scope --> $DIR/pat-lt-bracket-5.rs:2:16 diff --git a/tests/ui/parser/pat-lt-bracket-6.stderr b/tests/ui/parser/pat-lt-bracket-6.stderr index 892883c4aed..14ae602fedf 100644 --- a/tests/ui/parser/pat-lt-bracket-6.stderr +++ b/tests/ui/parser/pat-lt-bracket-6.stderr @@ -2,7 +2,9 @@ error: expected a pattern, found an expression --> $DIR/pat-lt-bracket-6.rs:5:14 | LL | let Test(&desc[..]) = x; - | ^^^^^^^^^ arbitrary expressions are not allowed in patterns + | ^^^^^^^^^ not a pattern + | + = note: arbitrary expressions are not allowed in patterns: error[E0308]: mismatched types --> $DIR/pat-lt-bracket-6.rs:10:30 diff --git a/tests/ui/parser/pat-ranges-3.stderr b/tests/ui/parser/pat-ranges-3.stderr index 5e1f35d1b6f..ef080368e19 100644 --- a/tests/ui/parser/pat-ranges-3.stderr +++ b/tests/ui/parser/pat-ranges-3.stderr @@ -2,13 +2,17 @@ error: expected a pattern range bound, found an expression --> $DIR/pat-ranges-3.rs:4:16 | LL | let 10 ..= 10 + 3 = 12; - | ^^^^^^ arbitrary expressions are not allowed in patterns + | ^^^^^^ not a pattern + | + = note: arbitrary expressions are not allowed in patterns: error: expected a pattern range bound, found an expression --> $DIR/pat-ranges-3.rs:7:9 | LL | let 10 - 3 ..= 10 = 8; - | ^^^^^^ arbitrary expressions are not allowed in patterns + | ^^^^^^ not a pattern + | + = note: arbitrary expressions are not allowed in patterns: error: aborting due to 2 previous errors diff --git a/tests/ui/parser/recover/recover-pat-exprs.stderr b/tests/ui/parser/recover/recover-pat-exprs.stderr index 63956f35c07..6cb3753de8d 100644 --- a/tests/ui/parser/recover/recover-pat-exprs.stderr +++ b/tests/ui/parser/recover/recover-pat-exprs.stderr @@ -2,8 +2,9 @@ error: expected a pattern, found an expression --> $DIR/recover-pat-exprs.rs:5:9 | LL | x.y => (), - | ^^^ arbitrary expressions are not allowed in patterns + | ^^^ not a pattern | + = note: arbitrary expressions are not allowed in patterns: help: consider moving the expression to a match arm guard | LL | val if val == x.y => (), @@ -24,8 +25,9 @@ error: expected a pattern, found an expression --> $DIR/recover-pat-exprs.rs:6:9 | LL | x.0 => (), - | ^^^ arbitrary expressions are not allowed in patterns + | ^^^ not a pattern | + = note: arbitrary expressions are not allowed in patterns: help: consider moving the expression to a match arm guard | LL | val if val == x.0 => (), @@ -47,8 +49,9 @@ error: expected a pattern, found an expression --> $DIR/recover-pat-exprs.rs:7:9 | LL | x._0 => (), - | ^^^^ arbitrary expressions are not allowed in patterns + | ^^^^ not a pattern | + = note: arbitrary expressions are not allowed in patterns: help: consider moving the expression to a match arm guard | LL | val if val == x._0 => (), @@ -71,8 +74,9 @@ error: expected a pattern, found an expression --> $DIR/recover-pat-exprs.rs:8:9 | LL | x.0.1 => (), - | ^^^^^ arbitrary expressions are not allowed in patterns + | ^^^^^ not a pattern | + = note: arbitrary expressions are not allowed in patterns: help: consider moving the expression to a match arm guard | LL | val if val == x.0.1 => (), @@ -95,8 +99,9 @@ error: expected a pattern, found an expression --> $DIR/recover-pat-exprs.rs:9:9 | LL | x.4.y.17.__z => (), - | ^^^^^^^^^^^^ arbitrary expressions are not allowed in patterns + | ^^^^^^^^^^^^ not a pattern | + = note: arbitrary expressions are not allowed in patterns: help: consider moving the expression to a match arm guard | LL | val if val == x.4.y.17.__z => (), @@ -149,8 +154,9 @@ error: expected a pattern, found an expression --> $DIR/recover-pat-exprs.rs:23:9 | LL | x[0] => (), - | ^^^^ arbitrary expressions are not allowed in patterns + | ^^^^ not a pattern | + = note: arbitrary expressions are not allowed in patterns: help: consider moving the expression to a match arm guard | LL | val if val == x[0] => (), @@ -170,8 +176,9 @@ error: expected a pattern, found an expression --> $DIR/recover-pat-exprs.rs:24:9 | LL | x[..] => (), - | ^^^^^ arbitrary expressions are not allowed in patterns + | ^^^^^ not a pattern | + = note: arbitrary expressions are not allowed in patterns: help: consider moving the expression to a match arm guard | LL | val if val == x[..] => (), @@ -219,8 +226,9 @@ error: expected a pattern, found an expression --> $DIR/recover-pat-exprs.rs:37:9 | LL | x.f() => (), - | ^^^^^ arbitrary expressions are not allowed in patterns + | ^^^^^ not a pattern | + = note: arbitrary expressions are not allowed in patterns: help: consider moving the expression to a match arm guard | LL | val if val == x.f() => (), @@ -240,8 +248,9 @@ error: expected a pattern, found an expression --> $DIR/recover-pat-exprs.rs:38:9 | LL | x._f() => (), - | ^^^^^^ arbitrary expressions are not allowed in patterns + | ^^^^^^ not a pattern | + = note: arbitrary expressions are not allowed in patterns: help: consider moving the expression to a match arm guard | LL | val if val == x._f() => (), @@ -262,8 +271,9 @@ error: expected a pattern, found an expression --> $DIR/recover-pat-exprs.rs:39:9 | LL | x? => (), - | ^^ arbitrary expressions are not allowed in patterns + | ^^ not a pattern | + = note: arbitrary expressions are not allowed in patterns: help: consider moving the expression to a match arm guard | LL | val if val == x? => (), @@ -285,8 +295,9 @@ error: expected a pattern, found an expression --> $DIR/recover-pat-exprs.rs:40:9 | LL | ().f() => (), - | ^^^^^^ arbitrary expressions are not allowed in patterns + | ^^^^^^ not a pattern | + = note: arbitrary expressions are not allowed in patterns: help: consider moving the expression to a match arm guard | LL | val if val == ().f() => (), @@ -309,8 +320,9 @@ error: expected a pattern, found an expression --> $DIR/recover-pat-exprs.rs:41:9 | LL | (0, x)?.f() => (), - | ^^^^^^^^^^^ arbitrary expressions are not allowed in patterns + | ^^^^^^^^^^^ not a pattern | + = note: arbitrary expressions are not allowed in patterns: help: consider moving the expression to a match arm guard | LL | val if val == (0, x)?.f() => (), @@ -333,8 +345,9 @@ error: expected a pattern, found an expression --> $DIR/recover-pat-exprs.rs:42:9 | LL | x.f().g() => (), - | ^^^^^^^^^ arbitrary expressions are not allowed in patterns + | ^^^^^^^^^ not a pattern | + = note: arbitrary expressions are not allowed in patterns: help: consider moving the expression to a match arm guard | LL | val if val == x.f().g() => (), @@ -357,8 +370,9 @@ error: expected a pattern, found an expression --> $DIR/recover-pat-exprs.rs:43:9 | LL | 0.f()?.g()?? => (), - | ^^^^^^^^^^^^ arbitrary expressions are not allowed in patterns + | ^^^^^^^^^^^^ not a pattern | + = note: arbitrary expressions are not allowed in patterns: help: consider moving the expression to a match arm guard | LL | val if val == 0.f()?.g()?? => (), @@ -381,8 +395,9 @@ error: expected a pattern, found an expression --> $DIR/recover-pat-exprs.rs:50:9 | LL | x as usize => (), - | ^^^^^^^^^^ arbitrary expressions are not allowed in patterns + | ^^^^^^^^^^ not a pattern | + = note: arbitrary expressions are not allowed in patterns: help: consider moving the expression to a match arm guard | LL | val if val == x as usize => (), @@ -402,8 +417,9 @@ error: expected a pattern, found an expression --> $DIR/recover-pat-exprs.rs:51:9 | LL | 0 as usize => (), - | ^^^^^^^^^^ arbitrary expressions are not allowed in patterns + | ^^^^^^^^^^ not a pattern | + = note: arbitrary expressions are not allowed in patterns: help: consider moving the expression to a match arm guard | LL | val if val == 0 as usize => (), @@ -424,8 +440,9 @@ error: expected a pattern, found an expression --> $DIR/recover-pat-exprs.rs:52:9 | LL | x.f().0.4 as f32 => (), - | ^^^^^^^^^^^^^^^^ arbitrary expressions are not allowed in patterns + | ^^^^^^^^^^^^^^^^ not a pattern | + = note: arbitrary expressions are not allowed in patterns: help: consider moving the expression to a match arm guard | LL | val if val == x.f().0.4 as f32 => (), @@ -447,8 +464,9 @@ error: expected a pattern, found an expression --> $DIR/recover-pat-exprs.rs:59:9 | LL | 1 + 1 => (), - | ^^^^^ arbitrary expressions are not allowed in patterns + | ^^^^^ not a pattern | + = note: arbitrary expressions are not allowed in patterns: help: consider moving the expression to a match arm guard | LL | val if val == 1 + 1 => (), @@ -468,8 +486,9 @@ error: expected a pattern, found an expression --> $DIR/recover-pat-exprs.rs:60:9 | LL | (1 + 2) * 3 => (), - | ^^^^^^^^^^^ arbitrary expressions are not allowed in patterns + | ^^^^^^^^^^^ not a pattern | + = note: arbitrary expressions are not allowed in patterns: help: consider moving the expression to a match arm guard | LL | val if val == (1 + 2) * 3 => (), @@ -490,8 +509,9 @@ error: expected a pattern, found an expression --> $DIR/recover-pat-exprs.rs:63:9 | LL | x.0 > 2 => (), - | ^^^^^^^ arbitrary expressions are not allowed in patterns + | ^^^^^^^ not a pattern | + = note: arbitrary expressions are not allowed in patterns: help: consider moving the expression to a match arm guard | LL | val if val == (x.0 > 2) => (), @@ -514,8 +534,9 @@ error: expected a pattern, found an expression --> $DIR/recover-pat-exprs.rs:64:9 | LL | x.0 == 2 => (), - | ^^^^^^^^ arbitrary expressions are not allowed in patterns + | ^^^^^^^^ not a pattern | + = note: arbitrary expressions are not allowed in patterns: help: consider moving the expression to a match arm guard | LL | val if val == (x.0 == 2) => (), @@ -538,8 +559,9 @@ error: expected a pattern, found an expression --> $DIR/recover-pat-exprs.rs:69:13 | LL | (x, y.0 > 2) if x != 0 => (), - | ^^^^^^^ arbitrary expressions are not allowed in patterns + | ^^^^^^^ not a pattern | + = note: arbitrary expressions are not allowed in patterns: help: consider moving the expression to the match arm guard | LL | (x, val) if x != 0 && val == (y.0 > 2) => (), @@ -559,8 +581,9 @@ error: expected a pattern, found an expression --> $DIR/recover-pat-exprs.rs:70:13 | LL | (x, y.0 > 2) if x != 0 || x != 1 => (), - | ^^^^^^^ arbitrary expressions are not allowed in patterns + | ^^^^^^^ not a pattern | + = note: arbitrary expressions are not allowed in patterns: help: consider moving the expression to the match arm guard | LL | (x, val) if (x != 0 || x != 1) && val == (y.0 > 2) => (), @@ -598,8 +621,9 @@ error: expected a pattern, found an expression --> $DIR/recover-pat-exprs.rs:81:9 | LL | u8::MAX.abs() => (), - | ^^^^^^^^^^^^^ arbitrary expressions are not allowed in patterns + | ^^^^^^^^^^^^^ not a pattern | + = note: arbitrary expressions are not allowed in patterns: help: consider moving the expression to a match arm guard | LL | val if val == u8::MAX.abs() => (), @@ -619,8 +643,9 @@ error: expected a pattern, found an expression --> $DIR/recover-pat-exprs.rs:86:17 | LL | z @ w @ v.u() => (), - | ^^^^^ arbitrary expressions are not allowed in patterns + | ^^^^^ not a pattern | + = note: arbitrary expressions are not allowed in patterns: help: consider moving the expression to a match arm guard | LL | z @ w @ val if val == v.u() => (), @@ -643,8 +668,9 @@ error: expected a pattern, found an expression --> $DIR/recover-pat-exprs.rs:88:9 | LL | y.ilog(3) => (), - | ^^^^^^^^^ arbitrary expressions are not allowed in patterns + | ^^^^^^^^^ not a pattern | + = note: arbitrary expressions are not allowed in patterns: help: consider moving the expression to a match arm guard | LL | val if val == y.ilog(3) => (), @@ -667,8 +693,9 @@ error: expected a pattern, found an expression --> $DIR/recover-pat-exprs.rs:90:9 | LL | n + 1 => (), - | ^^^^^ arbitrary expressions are not allowed in patterns + | ^^^^^ not a pattern | + = note: arbitrary expressions are not allowed in patterns: help: consider moving the expression to a match arm guard | LL | val if val == n + 1 => (), @@ -691,8 +718,9 @@ error: expected a pattern, found an expression --> $DIR/recover-pat-exprs.rs:92:10 | LL | ("".f() + 14 * 8) => (), - | ^^^^^^^^^^^^^^^ arbitrary expressions are not allowed in patterns + | ^^^^^^^^^^^^^^^ not a pattern | + = note: arbitrary expressions are not allowed in patterns: help: consider moving the expression to a match arm guard | LL | (val) if val == "".f() + 14 * 8 => (), @@ -715,8 +743,9 @@ error: expected a pattern, found an expression --> $DIR/recover-pat-exprs.rs:95:9 | LL | f?() => (), - | ^^^^ arbitrary expressions are not allowed in patterns + | ^^^^ not a pattern | + = note: arbitrary expressions are not allowed in patterns: help: consider moving the expression to a match arm guard | LL | val if val == f?() => (), @@ -739,7 +768,9 @@ error: expected a pattern, found an expression --> $DIR/recover-pat-exprs.rs:101:9 | LL | let 1 + 1 = 2; - | ^^^^^ arbitrary expressions are not allowed in patterns + | ^^^^^ not a pattern + | + = note: arbitrary expressions are not allowed in patterns: error: expected one of `)`, `,`, `@`, or `|`, found `*` --> $DIR/recover-pat-exprs.rs:104:28 @@ -754,19 +785,25 @@ error: expected a pattern, found an expression --> $DIR/recover-pat-exprs.rs:60:10 | LL | (1 + 2) * 3 => (), - | ^^^^^ arbitrary expressions are not allowed in patterns + | ^^^^^ not a pattern + | + = note: arbitrary expressions are not allowed in patterns: error: expected a pattern, found an expression --> $DIR/recover-pat-exprs.rs:75:5 | LL | 1 + 2 * PI.cos() => 2, - | ^^^^^^^^^^^^^^^^ arbitrary expressions are not allowed in patterns + | ^^^^^^^^^^^^^^^^ not a pattern + | + = note: arbitrary expressions are not allowed in patterns: error: expected a pattern, found an expression --> $DIR/recover-pat-exprs.rs:83:9 | LL | x.sqrt() @ .. => (), - | ^^^^^^^^ arbitrary expressions are not allowed in patterns + | ^^^^^^^^ not a pattern + | + = note: arbitrary expressions are not allowed in patterns: error: aborting due to 45 previous errors diff --git a/tests/ui/parser/recover/recover-pat-issues.stderr b/tests/ui/parser/recover/recover-pat-issues.stderr index 596bff21395..17cb7b4aead 100644 --- a/tests/ui/parser/recover/recover-pat-issues.stderr +++ b/tests/ui/parser/recover/recover-pat-issues.stderr @@ -2,8 +2,9 @@ error: expected a pattern, found an expression --> $DIR/recover-pat-issues.rs:6:13 | LL | Foo("hi".to_owned()) => true, - | ^^^^^^^^^^^^^^^ arbitrary expressions are not allowed in patterns + | ^^^^^^^^^^^^^^^ not a pattern | + = note: arbitrary expressions are not allowed in patterns: help: consider moving the expression to a match arm guard | LL | Foo(val) if val == "hi".to_owned() => true, @@ -23,8 +24,9 @@ error: expected a pattern, found an expression --> $DIR/recover-pat-issues.rs:14:20 | LL | Bar { baz: "hi".to_owned() } => true, - | ^^^^^^^^^^^^^^^ arbitrary expressions are not allowed in patterns + | ^^^^^^^^^^^^^^^ not a pattern | + = note: arbitrary expressions are not allowed in patterns: help: consider moving the expression to a match arm guard | LL | Bar { baz } if baz == "hi".to_owned() => true, @@ -44,8 +46,9 @@ error: expected a pattern, found an expression --> $DIR/recover-pat-issues.rs:25:11 | LL | &["foo".to_string()] => {} - | ^^^^^^^^^^^^^^^^^ arbitrary expressions are not allowed in patterns + | ^^^^^^^^^^^^^^^^^ not a pattern | + = note: arbitrary expressions are not allowed in patterns: help: consider moving the expression to a match arm guard | LL | &[val] if val == "foo".to_string() => {} @@ -65,8 +68,9 @@ error: expected a pattern, found an expression --> $DIR/recover-pat-issues.rs:36:17 | LL | if let Some(MAGIC.0 as usize) = None:: {} - | ^^^^^^^^^^^^^^^^ arbitrary expressions are not allowed in patterns + | ^^^^^^^^^^^^^^^^ not a pattern | + = note: arbitrary expressions are not allowed in patterns: help: consider extracting the expression into a `const` | LL + const VAL: /* Type */ = MAGIC.0 as usize; @@ -81,8 +85,9 @@ error: expected a pattern, found an expression --> $DIR/recover-pat-issues.rs:41:13 | LL | if let (-1.some(4)) = (0, Some(4)) {} - | ^^^^^^^^^^ arbitrary expressions are not allowed in patterns + | ^^^^^^^^^^ not a pattern | + = note: arbitrary expressions are not allowed in patterns: help: consider extracting the expression into a `const` | LL + const VAL: /* Type */ = -1.some(4); @@ -97,8 +102,9 @@ error: expected a pattern, found an expression --> $DIR/recover-pat-issues.rs:44:13 | LL | if let (-1.Some(4)) = (0, Some(4)) {} - | ^^^^^^^^^^ arbitrary expressions are not allowed in patterns + | ^^^^^^^^^^ not a pattern | + = note: arbitrary expressions are not allowed in patterns: help: consider extracting the expression into a `const` | LL + const VAL: /* Type */ = -1.Some(4); diff --git a/tests/ui/parser/recover/recover-pat-lets.stderr b/tests/ui/parser/recover/recover-pat-lets.stderr index e54586b0924..b481813b246 100644 --- a/tests/ui/parser/recover/recover-pat-lets.stderr +++ b/tests/ui/parser/recover/recover-pat-lets.stderr @@ -2,26 +2,33 @@ error: expected a pattern, found an expression --> $DIR/recover-pat-lets.rs:4:9 | LL | let x.expect("foo"); - | ^^^^^^^^^^^^^^^ arbitrary expressions are not allowed in patterns + | ^^^^^^^^^^^^^^^ not a pattern + | + = note: arbitrary expressions are not allowed in patterns: error: expected a pattern, found an expression --> $DIR/recover-pat-lets.rs:7:9 | LL | let x.unwrap(): u32; - | ^^^^^^^^^^ arbitrary expressions are not allowed in patterns + | ^^^^^^^^^^ not a pattern + | + = note: arbitrary expressions are not allowed in patterns: error: expected a pattern, found an expression --> $DIR/recover-pat-lets.rs:10:9 | LL | let x[0] = 1; - | ^^^^ arbitrary expressions are not allowed in patterns + | ^^^^ not a pattern + | + = note: arbitrary expressions are not allowed in patterns: error: expected a pattern, found an expression --> $DIR/recover-pat-lets.rs:13:14 | LL | let Some(1 + 1) = x else { - | ^^^^^ arbitrary expressions are not allowed in patterns + | ^^^^^ not a pattern | + = note: arbitrary expressions are not allowed in patterns: help: consider extracting the expression into a `const` | LL + const VAL: /* Type */ = 1 + 1; @@ -36,8 +43,9 @@ error: expected a pattern, found an expression --> $DIR/recover-pat-lets.rs:17:17 | LL | if let Some(1 + 1) = x { - | ^^^^^ arbitrary expressions are not allowed in patterns + | ^^^^^ not a pattern | + = note: arbitrary expressions are not allowed in patterns: help: consider extracting the expression into a `const` | LL + const VAL: /* Type */ = 1 + 1; diff --git a/tests/ui/parser/recover/recover-pat-ranges.stderr b/tests/ui/parser/recover/recover-pat-ranges.stderr index 088f83b0ccb..0a9b5447468 100644 --- a/tests/ui/parser/recover/recover-pat-ranges.stderr +++ b/tests/ui/parser/recover/recover-pat-ranges.stderr @@ -86,8 +86,9 @@ error: expected a pattern range bound, found an expression --> $DIR/recover-pat-ranges.rs:11:12 | LL | ..=1 + 2 => (), - | ^^^^^ arbitrary expressions are not allowed in patterns + | ^^^^^ not a pattern | + = note: arbitrary expressions are not allowed in patterns: help: consider extracting the expression into a `const` | LL + const VAL: /* Type */ = 1 + 2; @@ -106,8 +107,9 @@ error: expected a pattern range bound, found an expression --> $DIR/recover-pat-ranges.rs:15:10 | LL | (-4 + 0).. => (), - | ^^^^^^ arbitrary expressions are not allowed in patterns + | ^^^^^^ not a pattern | + = note: arbitrary expressions are not allowed in patterns: help: consider extracting the expression into a `const` | LL + const VAL: /* Type */ = -4 + 0; @@ -126,8 +128,9 @@ error: expected a pattern range bound, found an expression --> $DIR/recover-pat-ranges.rs:18:10 | LL | (1 + 4)...1 * 2 => (), - | ^^^^^ arbitrary expressions are not allowed in patterns + | ^^^^^ not a pattern | + = note: arbitrary expressions are not allowed in patterns: help: consider extracting the expression into a `const` | LL + const VAL: /* Type */ = 1 + 4; @@ -146,8 +149,9 @@ error: expected a pattern range bound, found an expression --> $DIR/recover-pat-ranges.rs:18:19 | LL | (1 + 4)...1 * 2 => (), - | ^^^^^ arbitrary expressions are not allowed in patterns + | ^^^^^ not a pattern | + = note: arbitrary expressions are not allowed in patterns: help: consider extracting the expression into a `const` | LL + const VAL: /* Type */ = 1 * 2; @@ -166,8 +170,9 @@ error: expected a pattern range bound, found an expression --> $DIR/recover-pat-ranges.rs:24:9 | LL | 0.x()..="y".z() => (), - | ^^^^^ arbitrary expressions are not allowed in patterns + | ^^^^^ not a pattern | + = note: arbitrary expressions are not allowed in patterns: help: consider extracting the expression into a `const` | LL + const VAL: /* Type */ = 0.x(); @@ -186,8 +191,9 @@ error: expected a pattern range bound, found an expression --> $DIR/recover-pat-ranges.rs:24:17 | LL | 0.x()..="y".z() => (), - | ^^^^^^^ arbitrary expressions are not allowed in patterns + | ^^^^^^^ not a pattern | + = note: arbitrary expressions are not allowed in patterns: help: consider extracting the expression into a `const` | LL + const VAL: /* Type */ = "y".z(); diff --git a/tests/ui/parser/recover/recover-pat-wildcards.stderr b/tests/ui/parser/recover/recover-pat-wildcards.stderr index 30307726a97..8d4212ed389 100644 --- a/tests/ui/parser/recover/recover-pat-wildcards.stderr +++ b/tests/ui/parser/recover/recover-pat-wildcards.stderr @@ -75,8 +75,9 @@ error: expected a pattern range bound, found an expression --> $DIR/recover-pat-wildcards.rs:55:14 | LL | 4..=(2 + _) => () - | ^^^^^ arbitrary expressions are not allowed in patterns + | ^^^^^ not a pattern | + = note: arbitrary expressions are not allowed in patterns: help: consider extracting the expression into a `const` | LL + const VAL: /* Type */ = 2 + _; diff --git a/tests/ui/resolve/issue-10200.rs b/tests/ui/resolve/issue-10200.rs index fe36a7e00bf..d529536b952 100644 --- a/tests/ui/resolve/issue-10200.rs +++ b/tests/ui/resolve/issue-10200.rs @@ -3,7 +3,7 @@ fn foo(_: usize) -> Foo { Foo(false) } fn main() { match Foo(true) { - foo(x) //~ ERROR expected tuple struct or tuple variant, found function `foo` + foo(x) //~ ERROR expected a pattern, found a function call => () } } diff --git a/tests/ui/resolve/issue-10200.stderr b/tests/ui/resolve/issue-10200.stderr index 7b218694b26..172d016c6e6 100644 --- a/tests/ui/resolve/issue-10200.stderr +++ b/tests/ui/resolve/issue-10200.stderr @@ -1,4 +1,4 @@ -error[E0532]: expected tuple struct or tuple variant, found function `foo` +error[E0532]: expected a pattern, found a function call --> $DIR/issue-10200.rs:6:9 | LL | struct Foo(bool); @@ -6,6 +6,8 @@ LL | struct Foo(bool); ... LL | foo(x) | ^^^ help: a tuple struct with a similar name exists (notice the capitalization): `Foo` + | + = note: function calls are not allowed in patterns: error: aborting due to 1 previous error diff --git a/tests/ui/sized/ensure-overriding-bindings-in-pattern-with-ty-err-doesnt-ice.stderr b/tests/ui/sized/ensure-overriding-bindings-in-pattern-with-ty-err-doesnt-ice.stderr index fc431eb1412..d40e9822435 100644 --- a/tests/ui/sized/ensure-overriding-bindings-in-pattern-with-ty-err-doesnt-ice.stderr +++ b/tests/ui/sized/ensure-overriding-bindings-in-pattern-with-ty-err-doesnt-ice.stderr @@ -2,7 +2,9 @@ error: expected a pattern, found an expression --> $DIR/ensure-overriding-bindings-in-pattern-with-ty-err-doesnt-ice.rs:2:31 | LL | let str::<{fn str() { let str::T>>::as_bytes; }}, T>::as_bytes; - | ^^^^^^^^^^^^^^^^^^ arbitrary expressions are not allowed in patterns + | ^^^^^^^^^^^^^^^^^^ not a pattern + | + = note: arbitrary expressions are not allowed in patterns: error[E0412]: cannot find type `T` in this scope --> $DIR/ensure-overriding-bindings-in-pattern-with-ty-err-doesnt-ice.rs:2:55 From 7c0c51193327fcf7f09d6450bd4dcc744adf6fe3 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 5 Oct 2024 21:34:51 -0500 Subject: [PATCH 613/683] Update `compiler-builtins` to 0.1.133 This includes [1], which should help resolve an infinite recusion issue on WASM and SPARC (possibly other platforms). See [2] and [3] for further details. [1]: https://github.com/rust-lang/compiler-builtins/pull/708 [2]: https://rust-lang.zulipchat.com/#narrow/stream/131828-t-compiler/topic/sparc-unknown-none-elf.20regresssion.20between.20compiler-built.2E.2E.2E [3]: https://rust-lang.zulipchat.com/#narrow/stream/131828-t-compiler/topic/.5Bwasm32.5D.20Infinite.20recursion.20.60compiler-builtins.60.20.60__multi3.60 --- library/Cargo.lock | 4 ++-- library/alloc/Cargo.toml | 2 +- library/std/Cargo.toml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/library/Cargo.lock b/library/Cargo.lock index 66ded59ae36..59b76d8d442 100644 --- a/library/Cargo.lock +++ b/library/Cargo.lock @@ -61,9 +61,9 @@ dependencies = [ [[package]] name = "compiler_builtins" -version = "0.1.132" +version = "0.1.133" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88f58330b127df19326d19e9debbb722578589cb1b9c061b5cdc4036d038b54b" +checksum = "ab10bf45b2ed1b4f4c25401527a61684142c042b3c86ace7da7ea6881e26741b" dependencies = [ "cc", "rustc-std-workspace-core", diff --git a/library/alloc/Cargo.toml b/library/alloc/Cargo.toml index fa18c7aec74..259a3ed2beb 100644 --- a/library/alloc/Cargo.toml +++ b/library/alloc/Cargo.toml @@ -10,7 +10,7 @@ edition = "2021" [dependencies] core = { path = "../core" } -compiler_builtins = { version = "0.1.132", features = ['rustc-dep-of-std'] } +compiler_builtins = { version = "0.1.133", features = ['rustc-dep-of-std'] } [dev-dependencies] rand = { version = "0.8.5", default-features = false, features = ["alloc"] } diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index 6bf70e1d82a..f2669326065 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -17,7 +17,7 @@ cfg-if = { version = "1.0", features = ['rustc-dep-of-std'] } panic_unwind = { path = "../panic_unwind", optional = true } panic_abort = { path = "../panic_abort" } core = { path = "../core", public = true } -compiler_builtins = { version = "0.1.132" } +compiler_builtins = { version = "0.1.133" } profiler_builtins = { path = "../profiler_builtins", optional = true } unwind = { path = "../unwind" } hashbrown = { version = "0.15", default-features = false, features = [ From 8b968764f15ea84b389b2af98297b9d30fb9952e Mon Sep 17 00:00:00 2001 From: Shriram Balaji Date: Thu, 12 Sep 2024 00:56:52 +0530 Subject: [PATCH 614/683] bootstrap: add `std_features` config MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit bootstrap: add std_features to config.example fix: use BTreeSet for std-features; add unit tests * fix formatting of string in front of std_features * rename `std_features` to `std-features` in config.toml fix: remove space before std-features in config.toml fix: remove explicit .into_iter conversion bootstrap: add details for rust.std-features in config.example.toml Co-authored-by: Onur Özkan fix: remove `Option` from `rust_std_features` fix: move default rust_std_features to config fix: make std_features CI rustc incompatible --- config.example.toml | 10 +++++++++ src/bootstrap/src/core/config/config.rs | 12 ++++++++++- src/bootstrap/src/core/config/tests.rs | 22 ++++++++++++++++++++ src/bootstrap/src/lib.rs | 27 ++++++++++++++----------- 4 files changed, 58 insertions(+), 13 deletions(-) diff --git a/config.example.toml b/config.example.toml index 47ebb20d8fa..4b591b949b3 100644 --- a/config.example.toml +++ b/config.example.toml @@ -759,6 +759,16 @@ # Build compiler with the optimization enabled and -Zvalidate-mir, currently only for `std` #validate-mir-opts = 3 +# Configure `std` features used during bootstrap. +# Default features will be expanded in the following cases: +# - If `rust.llvm-libunwind` or `target.llvm-libunwind` is enabled: +# - "llvm-libunwind" will be added for in-tree LLVM builds. +# - "system-llvm-libunwind" will be added for system LLVM builds. +# - If `rust.backtrace` is enabled, "backtrace" will be added. +# - If `rust.profiler` or `target.profiler` is enabled, "profiler" will be added. +# - If building for a zkvm target, "compiler-builtins-mem" will be added. +#std-features = ["panic_unwind"] + # ============================================================================= # Options for specific targets # diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index 07460b81412..7dc3b7b081a 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -4,7 +4,7 @@ //! how the build runs. use std::cell::{Cell, RefCell}; -use std::collections::{HashMap, HashSet}; +use std::collections::{BTreeSet, HashMap, HashSet}; use std::fmt::{self, Display}; use std::io::IsTerminal; use std::path::{Path, PathBuf, absolute}; @@ -287,6 +287,7 @@ pub struct Config { pub rust_profile_generate: Option, pub rust_lto: RustcLto, pub rust_validate_mir_opts: Option, + pub rust_std_features: BTreeSet, pub llvm_profile_use: Option, pub llvm_profile_generate: bool, pub llvm_libunwind_default: Option, @@ -1152,6 +1153,7 @@ define_config! { download_rustc: Option = "download-rustc", lto: Option = "lto", validate_mir_opts: Option = "validate-mir-opts", + std_features: Option> = "std-features", } } @@ -1645,6 +1647,7 @@ impl Config { let mut optimize = None; let mut omit_git_hash = None; let mut lld_enabled = None; + let mut std_features = None; let mut is_user_configured_rust_channel = false; @@ -1703,6 +1706,7 @@ impl Config { stack_protector, strip, lld_mode, + std_features: std_features_toml, } = rust; is_user_configured_rust_channel = channel.is_some(); @@ -1722,6 +1726,7 @@ impl Config { debuginfo_level_tools = debuginfo_level_tools_toml; debuginfo_level_tests = debuginfo_level_tests_toml; lld_enabled = lld_enabled_toml; + std_features = std_features_toml; optimize = optimize_toml; omit_git_hash = omit_git_hash_toml; @@ -2118,6 +2123,9 @@ impl Config { ); } + let default_std_features = BTreeSet::from([String::from("panic-unwind")]); + config.rust_std_features = std_features.unwrap_or(default_std_features); + let default = debug == Some(true); config.rust_debug_assertions = debug_assertions.unwrap_or(default); config.rust_debug_assertions_std = @@ -3016,6 +3024,7 @@ fn check_incompatible_options_for_ci_rustc( description, incremental, default_linker, + std_features, // Rest of the options can simply be ignored. debug: _, @@ -3077,6 +3086,7 @@ fn check_incompatible_options_for_ci_rustc( err!(current_rust_config.default_linker, default_linker); err!(current_rust_config.stack_protector, stack_protector); err!(current_rust_config.lto, lto); + err!(current_rust_config.std_features, std_features); warn!(current_rust_config.channel, channel); warn!(current_rust_config.description, description); diff --git a/src/bootstrap/src/core/config/tests.rs b/src/bootstrap/src/core/config/tests.rs index e38d4eac051..278becdcbc7 100644 --- a/src/bootstrap/src/core/config/tests.rs +++ b/src/bootstrap/src/core/config/tests.rs @@ -1,3 +1,4 @@ +use std::collections::BTreeSet; use std::env; use std::fs::{File, remove_file}; use std::io::Write; @@ -326,3 +327,24 @@ fn verbose_tests_default_value() { let config = Config::parse(Flags::parse(&["build".into(), "compiler".into(), "-v".into()])); assert_eq!(config.verbose_tests, true); } + +#[test] +fn parse_rust_std_features() { + let config = parse("rust.std-features = [\"panic-unwind\", \"backtrace\"]"); + let expected_features: BTreeSet = + ["panic-unwind", "backtrace"].into_iter().map(|s| s.to_string()).collect(); + assert_eq!(config.rust_std_features, expected_features); +} + +#[test] +fn parse_rust_std_features_empty() { + let config = parse("rust.std-features = []"); + let expected_features: BTreeSet = BTreeSet::new(); + assert_eq!(config.rust_std_features, expected_features); +} + +#[test] +#[should_panic] +fn parse_rust_std_features_invalid() { + parse("rust.std-features = \"backtrace\""); +} diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs index 75659f46431..313b49346bc 100644 --- a/src/bootstrap/src/lib.rs +++ b/src/bootstrap/src/lib.rs @@ -17,7 +17,7 @@ //! also check out the `src/bootstrap/README.md` file for more information. use std::cell::{Cell, RefCell}; -use std::collections::{HashMap, HashSet}; +use std::collections::{BTreeSet, HashMap, HashSet}; use std::fmt::Display; use std::fs::{self, File}; use std::path::{Path, PathBuf}; @@ -645,28 +645,31 @@ impl Build { &self.config.rust_info } - /// Gets the space-separated set of activated features for the standard - /// library. + /// Gets the space-separated set of activated features for the standard library. + /// This can be configured with the `std-features` key in config.toml. fn std_features(&self, target: TargetSelection) -> String { - let mut features = " panic-unwind".to_string(); + let mut features: BTreeSet<&str> = + self.config.rust_std_features.iter().map(|s| s.as_str()).collect(); match self.config.llvm_libunwind(target) { - LlvmLibunwind::InTree => features.push_str(" llvm-libunwind"), - LlvmLibunwind::System => features.push_str(" system-llvm-libunwind"), - LlvmLibunwind::No => {} - } + LlvmLibunwind::InTree => features.insert("llvm-libunwind"), + LlvmLibunwind::System => features.insert("system-llvm-libunwind"), + LlvmLibunwind::No => false, + }; + if self.config.backtrace { - features.push_str(" backtrace"); + features.insert("backtrace"); } if self.config.profiler_enabled(target) { - features.push_str(" profiler"); + features.insert("profiler"); } // Generate memcpy, etc. FIXME: Remove this once compiler-builtins // automatically detects this target. if target.contains("zkvm") { - features.push_str(" compiler-builtins-mem"); + features.insert("compiler-builtins-mem"); } - features + + features.into_iter().collect::>().join(" ") } /// Gets the space-separated set of activated features for the compiler. From 002afd1ae9c646d4120cc8e078bb329de8b3ecac Mon Sep 17 00:00:00 2001 From: Jacob Lifshay Date: Sat, 5 Oct 2024 22:01:02 -0700 Subject: [PATCH 615/683] Fix typo in primitive_docs.rs --- library/core/src/primitive_docs.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/primitive_docs.rs b/library/core/src/primitive_docs.rs index 962da6643dd..c25501f1200 100644 --- a/library/core/src/primitive_docs.rs +++ b/library/core/src/primitive_docs.rs @@ -1251,7 +1251,7 @@ mod prim_f16 {} /// - **Unchanged NaN propagation**: The quiet bit and payload are copied from any input operand /// that is a NaN. If the inputs and outputs do not have the same size (i.e., for `as` casts), the /// same rules as for "quieting NaN propagation" apply, with one caveat: if the output is smaller -/// than the input, droppig the low-order bits may result in a payload of 0; a payload of 0 is not +/// than the input, dropping the low-order bits may result in a payload of 0; a payload of 0 is not /// possible with a signaling NaN (the all-0 significand encodes an infinity) so unchanged NaN /// propagation cannot occur with some inputs. /// - **Target-specific NaN**: The quiet bit is set and the payload is picked from a target-specific From e0a20b484d0b88183ddd46b82aa47d7bbfe48468 Mon Sep 17 00:00:00 2001 From: ismailarilik Date: Sun, 6 Oct 2024 10:39:03 +0300 Subject: [PATCH 616/683] Handle `librustdoc` cases of `rustc::potential_query_instability` lint --- compiler/rustc_resolve/src/rustdoc.rs | 6 +-- src/librustdoc/clean/types.rs | 16 ++++---- src/librustdoc/config.rs | 4 +- src/librustdoc/core.rs | 4 +- src/librustdoc/doctest.rs | 15 ++++---- src/librustdoc/doctest/runner.rs | 6 +-- src/librustdoc/formats/cache.rs | 16 ++++---- src/librustdoc/html/highlight.rs | 4 +- src/librustdoc/html/highlight/tests.rs | 4 +- src/librustdoc/html/layout.rs | 4 +- src/librustdoc/html/markdown.rs | 8 ++-- src/librustdoc/html/render/context.rs | 14 +++---- src/librustdoc/html/render/mod.rs | 38 +++++++++---------- src/librustdoc/html/render/print_item.rs | 4 +- src/librustdoc/html/render/search_index.rs | 10 ++--- src/librustdoc/html/render/span_map.rs | 4 +- src/librustdoc/html/render/write_shared.rs | 10 ++--- src/librustdoc/html/sources.rs | 8 ++-- src/librustdoc/lib.rs | 3 +- .../passes/collect_intra_doc_links.rs | 6 +-- src/librustdoc/passes/collect_trait_impls.rs | 2 +- src/librustdoc/scrape_examples.rs | 10 ++--- src/librustdoc/theme.rs | 33 ++++++++-------- 23 files changed, 114 insertions(+), 115 deletions(-) diff --git a/compiler/rustc_resolve/src/rustdoc.rs b/compiler/rustc_resolve/src/rustdoc.rs index d1c1b6c882e..02e255d7726 100644 --- a/compiler/rustc_resolve/src/rustdoc.rs +++ b/compiler/rustc_resolve/src/rustdoc.rs @@ -6,7 +6,7 @@ use pulldown_cmark::{ }; use rustc_ast as ast; use rustc_ast::util::comments::beautify_doc_string; -use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::fx::FxIndexMap; use rustc_middle::ty::TyCtxt; use rustc_span::def_id::DefId; use rustc_span::symbol::{Symbol, kw, sym}; @@ -235,8 +235,8 @@ fn span_for_value(attr: &ast::Attribute) -> Span { /// early and late doc link resolution regardless of their position. pub fn prepare_to_doc_link_resolution( doc_fragments: &[DocFragment], -) -> FxHashMap, String> { - let mut res = FxHashMap::default(); +) -> FxIndexMap, String> { + let mut res = FxIndexMap::default(); for fragment in doc_fragments { let out_str = res.entry(fragment.item_id).or_default(); add_doc_fragment(out_str, fragment); diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index ec31a51a81e..ea4388b305b 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -9,7 +9,7 @@ use rustc_ast::NestedMetaItem; use rustc_ast_pretty::pprust; use rustc_attr::{ConstStability, Deprecation, Stability, StableSince}; use rustc_const_eval::const_eval::is_unstable_const_fn; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; use rustc_hir::def::{CtorKind, DefKind, Res}; use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE, LocalDefId}; use rustc_hir::lang_items::LangItem; @@ -114,7 +114,7 @@ impl From for ItemId { pub(crate) struct Crate { pub(crate) module: Item, /// Only here so that they can be filtered through the rustdoc passes. - pub(crate) external_traits: Box>, + pub(crate) external_traits: Box>, } impl Crate { @@ -1223,7 +1223,7 @@ impl Attributes { } pub(crate) fn get_doc_aliases(&self) -> Box<[Symbol]> { - let mut aliases = FxHashSet::default(); + let mut aliases = FxIndexSet::default(); for attr in self.other_attrs.lists(sym::doc).filter(|a| a.has_name(sym::alias)) { if let Some(values) = attr.meta_item_list() { @@ -1759,7 +1759,7 @@ pub(crate) enum PrimitiveType { Never, } -type SimplifiedTypes = FxHashMap>; +type SimplifiedTypes = FxIndexMap>; impl PrimitiveType { pub(crate) fn from_hir(prim: hir::PrimTy) -> PrimitiveType { use ast::{FloatTy, IntTy, UintTy}; @@ -1927,10 +1927,10 @@ impl PrimitiveType { /// In particular, if a crate depends on both `std` and another crate that also defines /// `rustc_doc_primitive`, then it's entirely random whether `std` or the other crate is picked. /// (no_std crates are usually fine unless multiple dependencies define a primitive.) - pub(crate) fn primitive_locations(tcx: TyCtxt<'_>) -> &FxHashMap { - static PRIMITIVE_LOCATIONS: OnceCell> = OnceCell::new(); + pub(crate) fn primitive_locations(tcx: TyCtxt<'_>) -> &FxIndexMap { + static PRIMITIVE_LOCATIONS: OnceCell> = OnceCell::new(); PRIMITIVE_LOCATIONS.get_or_init(|| { - let mut primitive_locations = FxHashMap::default(); + let mut primitive_locations = FxIndexMap::default(); // NOTE: technically this misses crates that are only passed with `--extern` and not loaded when checking the crate. // This is a degenerate case that I don't plan to support. for &crate_num in tcx.crates(()) { @@ -2460,7 +2460,7 @@ pub(crate) struct Impl { } impl Impl { - pub(crate) fn provided_trait_methods(&self, tcx: TyCtxt<'_>) -> FxHashSet { + pub(crate) fn provided_trait_methods(&self, tcx: TyCtxt<'_>) -> FxIndexSet { self.trait_ .as_ref() .map(|t| t.def_id()) diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs index 7a37f5c70a5..2cd69474b1c 100644 --- a/src/librustdoc/config.rs +++ b/src/librustdoc/config.rs @@ -5,7 +5,7 @@ use std::path::{Path, PathBuf}; use std::str::FromStr; use std::{fmt, io}; -use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::fx::FxIndexMap; use rustc_errors::DiagCtxtHandle; use rustc_session::config::{ self, CodegenOptions, CrateType, ErrorOutputType, Externs, Input, JsonUnusedExterns, @@ -249,7 +249,7 @@ pub(crate) struct RenderOptions { pub(crate) extern_html_root_takes_precedence: bool, /// A map of the default settings (values are as for DOM storage API). Keys should lack the /// `rustdoc-` prefix. - pub(crate) default_settings: FxHashMap, + pub(crate) default_settings: FxIndexMap, /// If present, suffix added to CSS/JavaScript files when referencing them in generated pages. pub(crate) resource_suffix: String, /// Whether to create an index page in the root of the output directory. If this is true but diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 4c48c075a94..aaf4c80f997 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -2,7 +2,7 @@ use std::sync::atomic::AtomicBool; use std::sync::{Arc, LazyLock}; use std::{io, mem}; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap}; use rustc_data_structures::sync::Lrc; use rustc_data_structures::unord::UnordSet; use rustc_errors::codes::*; @@ -39,7 +39,7 @@ pub(crate) struct DocContext<'tcx> { /// Most of this logic is copied from rustc_lint::late. pub(crate) param_env: ParamEnv<'tcx>, /// Later on moved through `clean::Crate` into `cache` - pub(crate) external_traits: FxHashMap, + pub(crate) external_traits: FxIndexMap, /// Used while populating `external_traits` to ensure we don't process the same trait twice at /// the same time. pub(crate) active_extern_traits: DefIdSet, diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index 4e7571a4803..d5bc2a93fa8 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -14,7 +14,7 @@ use std::{panic, str}; pub(crate) use make::DocTestBuilder; pub(crate) use markdown::test as test_markdown; use rustc_ast as ast; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::fx::{FxHashMap, FxIndexMap, FxIndexSet}; use rustc_errors::{ColorConfig, DiagCtxtHandle, ErrorGuaranteed, FatalError}; use rustc_hir::CRATE_HIR_ID; use rustc_hir::def_id::LOCAL_CRATE; @@ -213,12 +213,13 @@ pub(crate) fn run( let unused_extern_reports: Vec<_> = std::mem::take(&mut unused_extern_reports.lock().unwrap()); if unused_extern_reports.len() == compiling_test_count { - let extern_names = externs.iter().map(|(name, _)| name).collect::>(); + let extern_names = + externs.iter().map(|(name, _)| name).collect::>(); let mut unused_extern_names = unused_extern_reports .iter() - .map(|uexts| uexts.unused_extern_names.iter().collect::>()) + .map(|uexts| uexts.unused_extern_names.iter().collect::>()) .fold(extern_names, |uextsa, uextsb| { - uextsa.intersection(&uextsb).copied().collect::>() + uextsa.intersection(&uextsb).copied().collect::>() }) .iter() .map(|v| (*v).clone()) @@ -253,7 +254,7 @@ pub(crate) fn run_tests( rustdoc_options: &Arc, unused_extern_reports: &Arc>>, mut standalone_tests: Vec, - mergeable_tests: FxHashMap>, + mergeable_tests: FxIndexMap>, ) { let mut test_args = Vec::with_capacity(rustdoc_options.test_args.len() + 1); test_args.insert(0, "rustdoctest".to_string()); @@ -775,7 +776,7 @@ pub(crate) trait DocTestVisitor { struct CreateRunnableDocTests { standalone_tests: Vec, - mergeable_tests: FxHashMap>, + mergeable_tests: FxIndexMap>, rustdoc_options: Arc, opts: GlobalTestOptions, @@ -790,7 +791,7 @@ impl CreateRunnableDocTests { let can_merge_doctests = rustdoc_options.edition >= Edition::Edition2024; CreateRunnableDocTests { standalone_tests: Vec::new(), - mergeable_tests: FxHashMap::default(), + mergeable_tests: FxIndexMap::default(), rustdoc_options: Arc::new(rustdoc_options), opts, visited_tests: FxHashMap::default(), diff --git a/src/librustdoc/doctest/runner.rs b/src/librustdoc/doctest/runner.rs index 326ca4ee1e6..942ec8d9936 100644 --- a/src/librustdoc/doctest/runner.rs +++ b/src/librustdoc/doctest/runner.rs @@ -1,6 +1,6 @@ use std::fmt::Write; -use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::fx::FxIndexSet; use rustc_span::edition::Edition; use crate::doctest::{ @@ -11,7 +11,7 @@ use crate::html::markdown::{Ignore, LangString}; /// Convenient type to merge compatible doctests into one. pub(crate) struct DocTestRunner { - crate_attrs: FxHashSet, + crate_attrs: FxIndexSet, ids: String, output: String, supports_color: bool, @@ -21,7 +21,7 @@ pub(crate) struct DocTestRunner { impl DocTestRunner { pub(crate) fn new() -> Self { Self { - crate_attrs: FxHashSet::default(), + crate_attrs: FxIndexSet::default(), ids: String::new(), output: String::new(), supports_color: true, diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs index db1a0bd0af9..ff0d537b19f 100644 --- a/src/librustdoc/formats/cache.rs +++ b/src/librustdoc/formats/cache.rs @@ -1,6 +1,6 @@ use std::mem; -use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet}; +use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet}; use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, DefIdSet}; use rustc_middle::ty::{self, TyCtxt}; use rustc_span::Symbol; @@ -42,7 +42,7 @@ pub(crate) struct Cache { /// URLs when a type is being linked to. External paths are not located in /// this map because the `External` type itself has all the information /// necessary. - pub(crate) paths: FxHashMap, ItemType)>, + pub(crate) paths: FxIndexMap, ItemType)>, /// Similar to `paths`, but only holds external paths. This is only used for /// generating explicit hyperlinks to other crates. @@ -64,18 +64,18 @@ pub(crate) struct Cache { /// Implementations of a crate should inherit the documentation of the /// parent trait if no extra documentation is specified, and default methods /// should show up in documentation about trait implementations. - pub(crate) traits: FxHashMap, + pub(crate) traits: FxIndexMap, /// When rendering traits, it's often useful to be able to list all /// implementors of the trait, and this mapping is exactly, that: a mapping /// of trait ids to the list of known implementors of the trait - pub(crate) implementors: FxHashMap>, + pub(crate) implementors: FxIndexMap>, /// Cache of where external crate documentation can be found. - pub(crate) extern_locations: FxHashMap, + pub(crate) extern_locations: FxIndexMap, /// Cache of where documentation for primitives can be found. - pub(crate) primitive_locations: FxHashMap, + pub(crate) primitive_locations: FxIndexMap, // Note that external items for which `doc(hidden)` applies to are shown as // non-reachable while local items aren't. This is because we're reusing @@ -118,7 +118,7 @@ pub(crate) struct Cache { // crawl. In order to prevent crashes when looking for notable traits or // when gathering trait documentation on a type, hold impls here while // folding and add them to the cache later on if we find the trait. - orphan_trait_impls: Vec<(DefId, FxHashSet, Impl)>, + orphan_trait_impls: Vec<(DefId, FxIndexSet, Impl)>, /// All intra-doc links resolved so far. /// @@ -376,7 +376,7 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> { // Figure out the id of this impl. This may map to a // primitive rather than always to a struct/enum. // Note: matching twice to restrict the lifetime of the `i` borrow. - let mut dids = FxHashSet::default(); + let mut dids = FxIndexSet::default(); match i.for_ { clean::Type::Path { ref path } | clean::BorrowedRef { type_: box clean::Type::Path { ref path }, .. } => { diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs index 69b3421f888..e7ddd4b73b4 100644 --- a/src/librustdoc/html/highlight.rs +++ b/src/librustdoc/html/highlight.rs @@ -8,7 +8,7 @@ use std::collections::VecDeque; use std::fmt::{Display, Write}; -use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::fx::FxIndexMap; use rustc_lexer::{Cursor, LiteralKind, TokenKind}; use rustc_span::edition::Edition; use rustc_span::symbol::Symbol; @@ -34,7 +34,7 @@ pub(crate) struct HrefContext<'a, 'tcx> { /// Decorations are represented as a map from CSS class to vector of character ranges. /// Each range will be wrapped in a span with that class. #[derive(Default)] -pub(crate) struct DecorationInfo(pub(crate) FxHashMap<&'static str, Vec<(u32, u32)>>); +pub(crate) struct DecorationInfo(pub(crate) FxIndexMap<&'static str, Vec<(u32, u32)>>); #[derive(Eq, PartialEq, Clone, Copy)] pub(crate) enum Tooltip { diff --git a/src/librustdoc/html/highlight/tests.rs b/src/librustdoc/html/highlight/tests.rs index 75328e724fe..fd5275189d6 100644 --- a/src/librustdoc/html/highlight/tests.rs +++ b/src/librustdoc/html/highlight/tests.rs @@ -1,5 +1,5 @@ use expect_test::expect_file; -use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::fx::FxIndexMap; use rustc_span::create_default_session_globals_then; use super::{DecorationInfo, write_code}; @@ -73,7 +73,7 @@ fn test_decorations() { let y = 2; let z = 3; let a = 4;"; - let mut decorations = FxHashMap::default(); + let mut decorations = FxIndexMap::default(); decorations.insert("example", vec![(0, 10), (11, 21)]); decorations.insert("example2", vec![(22, 32)]); diff --git a/src/librustdoc/html/layout.rs b/src/librustdoc/html/layout.rs index 3684dc42ac7..31ccfeb3873 100644 --- a/src/librustdoc/html/layout.rs +++ b/src/librustdoc/html/layout.rs @@ -1,7 +1,7 @@ use std::path::PathBuf; use rinja::Template; -use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::fx::FxIndexMap; use super::static_files::{STATIC_FILES, StaticFiles}; use crate::externalfiles::ExternalHtml; @@ -13,7 +13,7 @@ pub(crate) struct Layout { pub(crate) logo: String, pub(crate) favicon: String, pub(crate) external_html: ExternalHtml, - pub(crate) default_settings: FxHashMap, + pub(crate) default_settings: FxIndexMap, pub(crate) krate: String, pub(crate) krate_version: String, /// The given user css file which allow to customize the generated diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 8ae5484feda..6c5c58754a8 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -38,7 +38,7 @@ use pulldown_cmark::{ BrokenLink, BrokenLinkCallback, CodeBlockKind, CowStr, Event, LinkType, OffsetIter, Options, Parser, Tag, TagEnd, html, }; -use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; use rustc_errors::{Diag, DiagMessage}; use rustc_hir::def_id::LocalDefId; use rustc_middle::ty::TyCtxt; @@ -651,12 +651,12 @@ impl<'a, I: Iterator>> Iterator for SummaryLine<'a, I> { /// references. struct Footnotes<'a, I> { inner: I, - footnotes: FxHashMap>, u16)>, + footnotes: FxIndexMap>, u16)>, } impl<'a, I> Footnotes<'a, I> { fn new(iter: I) -> Self { - Footnotes { inner: iter, footnotes: FxHashMap::default() } + Footnotes { inner: iter, footnotes: FxIndexMap::default() } } fn get_entry(&mut self, key: &str) -> &mut (Vec>, u16) { @@ -694,7 +694,7 @@ impl<'a, I: Iterator>> Iterator for Footnotes<'a, I> { Some(e) => return Some(e), None => { if !self.footnotes.is_empty() { - let mut v: Vec<_> = self.footnotes.drain().map(|(_, x)| x).collect(); + let mut v: Vec<_> = self.footnotes.drain(..).map(|(_, x)| x).collect(); v.sort_by(|a, b| a.1.cmp(&b.1)); let mut ret = String::from("


      "); for (mut content, id) in v { diff --git a/src/librustdoc/html/render/context.rs b/src/librustdoc/html/render/context.rs index bce3f218908..dc4d45e592e 100644 --- a/src/librustdoc/html/render/context.rs +++ b/src/librustdoc/html/render/context.rs @@ -6,7 +6,7 @@ use std::rc::Rc; use std::sync::mpsc::{Receiver, channel}; use rinja::Template; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet}; use rustc_hir::def_id::{DefIdMap, LOCAL_CRATE}; use rustc_middle::ty::TyCtxt; use rustc_session::Session; @@ -69,16 +69,16 @@ pub(crate) struct Context<'tcx> { /// `true`. pub(crate) include_sources: bool, /// Collection of all types with notable traits referenced in the current module. - pub(crate) types_with_notable_traits: FxHashSet, + pub(crate) types_with_notable_traits: FxIndexSet, /// Field used during rendering, to know if we're inside an inlined item. pub(crate) is_inside_inlined_module: bool, } // `Context` is cloned a lot, so we don't want the size to grow unexpectedly. #[cfg(all(not(windows), target_pointer_width = "64"))] -rustc_data_structures::static_assert_size!(Context<'_>, 160); +rustc_data_structures::static_assert_size!(Context<'_>, 184); #[cfg(all(windows, target_pointer_width = "64"))] -rustc_data_structures::static_assert_size!(Context<'_>, 168); +rustc_data_structures::static_assert_size!(Context<'_>, 192); /// Shared mutable state used in [`Context`] and elsewhere. pub(crate) struct SharedContext<'tcx> { @@ -90,7 +90,7 @@ pub(crate) struct SharedContext<'tcx> { /// creation of the context (contains info like the favicon and added html). pub(crate) layout: layout::Layout, /// The local file sources we've emitted and their respective url-paths. - pub(crate) local_sources: FxHashMap, + pub(crate) local_sources: FxIndexMap, /// Show the memory layout of types in the docs. pub(super) show_type_layout: bool, /// The base-URL of the issue tracker for when an item has been tagged with @@ -567,7 +567,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { deref_id_map: Default::default(), shared: Rc::new(scx), include_sources, - types_with_notable_traits: FxHashSet::default(), + types_with_notable_traits: FxIndexSet::default(), is_inside_inlined_module: false, }; @@ -591,7 +591,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { id_map: IdMap::new(), shared: Rc::clone(&self.shared), include_sources: self.include_sources, - types_with_notable_traits: FxHashSet::default(), + types_with_notable_traits: FxIndexSet::default(), is_inside_inlined_module: self.is_inside_inlined_module, } } diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 227df0c5f39..399730a01c8 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -47,7 +47,7 @@ use std::{fs, str}; use rinja::Template; use rustc_attr::{ConstStability, DeprecatedSince, Deprecation, StabilityLevel, StableSince}; use rustc_data_structures::captures::Captures; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; use rustc_hir::Mutability; use rustc_hir::def_id::{DefId, DefIdSet}; use rustc_middle::ty::print::PrintTraitRefExt; @@ -328,24 +328,24 @@ impl Ord for ItemEntry { #[derive(Debug)] struct AllTypes { - structs: FxHashSet, - enums: FxHashSet, - unions: FxHashSet, - primitives: FxHashSet, - traits: FxHashSet, - macros: FxHashSet, - functions: FxHashSet, - type_aliases: FxHashSet, - statics: FxHashSet, - constants: FxHashSet, - attribute_macros: FxHashSet, - derive_macros: FxHashSet, - trait_aliases: FxHashSet, + structs: FxIndexSet, + enums: FxIndexSet, + unions: FxIndexSet, + primitives: FxIndexSet, + traits: FxIndexSet, + macros: FxIndexSet, + functions: FxIndexSet, + type_aliases: FxIndexSet, + statics: FxIndexSet, + constants: FxIndexSet, + attribute_macros: FxIndexSet, + derive_macros: FxIndexSet, + trait_aliases: FxIndexSet, } impl AllTypes { fn new() -> AllTypes { - let new_set = |cap| FxHashSet::with_capacity_and_hasher(cap, Default::default()); + let new_set = |cap| FxIndexSet::with_capacity_and_hasher(cap, Default::default()); AllTypes { structs: new_set(100), enums: new_set(100), @@ -437,7 +437,7 @@ impl AllTypes { } fn print(self, f: &mut Buffer) { - fn print_entries(f: &mut Buffer, e: &FxHashSet, kind: ItemSection) { + fn print_entries(f: &mut Buffer, e: &FxIndexSet, kind: ItemSection) { if !e.is_empty() { let mut e: Vec<&ItemEntry> = e.iter().collect(); e.sort(); @@ -1151,7 +1151,7 @@ fn render_attributes_in_code(w: &mut impl fmt::Write, it: &clean::Item, cx: &Con #[derive(Copy, Clone)] enum AssocItemLink<'a> { Anchor(Option<&'a str>), - GotoSource(ItemId, &'a FxHashSet), + GotoSource(ItemId, &'a FxIndexSet), } impl<'a> AssocItemLink<'a> { @@ -1494,7 +1494,7 @@ fn notable_traits_decl(ty: &clean::Type, cx: &Context<'_>) -> (String, String) { for it in &impl_.items { if let clean::AssocTypeItem(ref tydef, ref _bounds) = it.kind { out.push_str("
      "); - let empty_set = FxHashSet::default(); + let empty_set = FxIndexSet::default(); let src_link = AssocItemLink::GotoSource(trait_did.into(), &empty_set); assoc_type( &mut out, @@ -2526,7 +2526,7 @@ fn render_call_locations(mut w: W, cx: &mut Context<'_>, item: &c })() .unwrap_or(DUMMY_SP); - let mut decoration_info = FxHashMap::default(); + let mut decoration_info = FxIndexMap::default(); decoration_info.insert("highlight focus", vec![byte_ranges.remove(0)]); decoration_info.insert("highlight", byte_ranges); diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index 38276e4d20c..3c96f873681 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -6,7 +6,7 @@ use std::rc::Rc; use itertools::Itertools; use rinja::Template; use rustc_data_structures::captures::Captures; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::fx::{FxHashMap, FxIndexSet}; use rustc_hir as hir; use rustc_hir::def::CtorKind; use rustc_hir::def_id::DefId; @@ -932,7 +932,7 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean: let cloned_shared = Rc::clone(&cx.shared); let cache = &cloned_shared.cache; - let mut extern_crates = FxHashSet::default(); + let mut extern_crates = FxIndexSet::default(); if !t.is_object_safe(cx.tcx()) { write_section_heading( diff --git a/src/librustdoc/html/render/search_index.rs b/src/librustdoc/html/render/search_index.rs index 660ca3b2594..c958458b662 100644 --- a/src/librustdoc/html/render/search_index.rs +++ b/src/librustdoc/html/render/search_index.rs @@ -774,7 +774,7 @@ pub(crate) fn get_function_type_for_search<'tcx>( fn get_index_type( clean_type: &clean::Type, generics: Vec, - rgen: &mut FxHashMap)>, + rgen: &mut FxIndexMap)>, ) -> RenderType { RenderType { id: get_index_type_id(clean_type, rgen), @@ -785,7 +785,7 @@ fn get_index_type( fn get_index_type_id( clean_type: &clean::Type, - rgen: &mut FxHashMap)>, + rgen: &mut FxIndexMap)>, ) -> Option { use rustc_hir::def::{DefKind, Res}; match *clean_type { @@ -854,7 +854,7 @@ fn simplify_fn_type<'a, 'tcx>( tcx: TyCtxt<'tcx>, recurse: usize, res: &mut Vec, - rgen: &mut FxHashMap)>, + rgen: &mut FxIndexMap)>, is_return: bool, cache: &Cache, ) { @@ -1198,7 +1198,7 @@ fn simplify_fn_constraint<'a, 'tcx>( tcx: TyCtxt<'tcx>, recurse: usize, res: &mut Vec<(RenderTypeId, Vec)>, - rgen: &mut FxHashMap)>, + rgen: &mut FxIndexMap)>, is_return: bool, cache: &Cache, ) { @@ -1285,7 +1285,7 @@ fn get_fn_inputs_and_outputs<'tcx>( ) -> (Vec, Vec, Vec>) { let decl = &func.decl; - let mut rgen: FxHashMap)> = Default::default(); + let mut rgen: FxIndexMap)> = Default::default(); let combined_generics; let (self_, generics) = if let Some((impl_self, impl_generics)) = impl_or_trait_generics { diff --git a/src/librustdoc/html/render/span_map.rs b/src/librustdoc/html/render/span_map.rs index 7e1ea5cde83..b314b060368 100644 --- a/src/librustdoc/html/render/span_map.rs +++ b/src/librustdoc/html/render/span_map.rs @@ -1,6 +1,6 @@ use std::path::{Path, PathBuf}; -use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, LOCAL_CRATE}; use rustc_hir::intravisit::{self, Visitor}; @@ -44,7 +44,7 @@ pub(crate) fn collect_spans_and_sources( src_root: &Path, include_sources: bool, generate_link_to_definition: bool, -) -> (FxHashMap, FxHashMap) { +) -> (FxIndexMap, FxHashMap) { let mut visitor = SpanMapVisitor { tcx, matches: FxHashMap::default() }; if include_sources { diff --git a/src/librustdoc/html/render/write_shared.rs b/src/librustdoc/html/render/write_shared.rs index af94b1042c0..12b63460056 100644 --- a/src/librustdoc/html/render/write_shared.rs +++ b/src/librustdoc/html/render/write_shared.rs @@ -28,7 +28,7 @@ use indexmap::IndexMap; use itertools::Itertools; use regex::Regex; use rustc_data_structures::flock; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; use rustc_middle::ty::TyCtxt; use rustc_middle::ty::fast_reject::DeepRejectCtxt; use rustc_span::Symbol; @@ -505,8 +505,8 @@ createSrcSidebar();", struct Hierarchy { parent: Weak, elem: OsString, - children: RefCell>>, - elems: RefCell>, + children: RefCell>>, + elems: RefCell>, } impl Hierarchy { @@ -961,8 +961,8 @@ impl Serialize for AliasSerializableImpl { fn get_path_parts( dst: &Path, crates_info: &[CrateInfo], -) -> FxHashMap> { - let mut templates: FxHashMap> = FxHashMap::default(); +) -> FxIndexMap> { + let mut templates: FxIndexMap> = FxIndexMap::default(); crates_info .iter() .map(|crate_info| T::from_crate_info(crate_info).parts.iter()) diff --git a/src/librustdoc/html/sources.rs b/src/librustdoc/html/sources.rs index 7be9cc0b885..f4a0ef01c25 100644 --- a/src/librustdoc/html/sources.rs +++ b/src/librustdoc/html/sources.rs @@ -6,7 +6,7 @@ use std::rc::Rc; use std::{fmt, fs}; use rinja::Template; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; use rustc_hir::def_id::LOCAL_CRATE; use rustc_middle::ty::TyCtxt; use rustc_session::Session; @@ -39,15 +39,15 @@ pub(crate) fn collect_local_sources<'tcx>( tcx: TyCtxt<'tcx>, src_root: &Path, krate: &clean::Crate, -) -> FxHashMap { - let mut lsc = LocalSourcesCollector { tcx, local_sources: FxHashMap::default(), src_root }; +) -> FxIndexMap { + let mut lsc = LocalSourcesCollector { tcx, local_sources: FxIndexMap::default(), src_root }; lsc.visit_crate(krate); lsc.local_sources } struct LocalSourcesCollector<'a, 'tcx> { tcx: TyCtxt<'tcx>, - local_sources: FxHashMap, + local_sources: FxIndexMap, src_root: &'a Path, } diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 2be415e2e0e..10fc0ea9990 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -20,7 +20,6 @@ #![warn(rustc::internal)] #![allow(clippy::collapsible_if, clippy::collapsible_else_if)] #![allow(rustc::diagnostic_outside_of_impl)] -#![allow(rustc::potential_query_instability)] #![allow(rustc::untranslatable_diagnostic)] extern crate thin_vec; @@ -99,7 +98,7 @@ use crate::clean::utils::DOC_RUST_LANG_ORG_CHANNEL; /// Commas between elements are required (even if the expression is a block). macro_rules! map { ($( $key: expr => $val: expr ),* $(,)*) => {{ - let mut map = ::rustc_data_structures::fx::FxHashMap::default(); + let mut map = ::rustc_data_structures::fx::FxIndexMap::default(); $( map.insert($key, $val); )* map }} diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index def9ac3ce4b..2eb0e32b831 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -9,7 +9,7 @@ use std::ops::Range; use pulldown_cmark::LinkType; use rustc_ast::util::comments::may_have_doc_links; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet}; use rustc_data_structures::intern::Interned; use rustc_errors::{Applicability, Diag, DiagMessage}; use rustc_hir::def::Namespace::*; @@ -778,9 +778,9 @@ fn trait_impls_for<'a>( cx: &mut DocContext<'a>, ty: Ty<'a>, module: DefId, -) -> FxHashSet<(DefId, DefId)> { +) -> FxIndexSet<(DefId, DefId)> { let tcx = cx.tcx; - let mut impls = FxHashSet::default(); + let mut impls = FxIndexSet::default(); for &trait_ in tcx.doc_link_traits_in_scope(module) { tcx.for_each_relevant_impl(trait_, ty, |impl_| { diff --git a/src/librustdoc/passes/collect_trait_impls.rs b/src/librustdoc/passes/collect_trait_impls.rs index b307e84e42e..d1a1f0df3e7 100644 --- a/src/librustdoc/passes/collect_trait_impls.rs +++ b/src/librustdoc/passes/collect_trait_impls.rs @@ -219,7 +219,7 @@ pub(crate) fn collect_trait_impls(mut krate: Crate, cx: &mut DocContext<'_>) -> panic!("collect-trait-impls can't run"); }; - krate.external_traits.extend(cx.external_traits.drain()); + krate.external_traits.extend(cx.external_traits.drain(..)); krate } diff --git a/src/librustdoc/scrape_examples.rs b/src/librustdoc/scrape_examples.rs index 9d4d203562c..a59c43bfbf9 100644 --- a/src/librustdoc/scrape_examples.rs +++ b/src/librustdoc/scrape_examples.rs @@ -3,7 +3,7 @@ use std::fs; use std::path::PathBuf; -use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::fx::FxIndexMap; use rustc_errors::DiagCtxtHandle; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{self as hir}; @@ -102,8 +102,8 @@ pub(crate) struct CallData { pub(crate) is_bin: bool, } -pub(crate) type FnCallLocations = FxHashMap; -pub(crate) type AllCallLocations = FxHashMap; +pub(crate) type FnCallLocations = FxIndexMap; +pub(crate) type AllCallLocations = FxIndexMap; /// Visitor for traversing a crate and finding instances of function calls. struct FindCalls<'a, 'tcx> { @@ -293,7 +293,7 @@ pub(crate) fn run( debug!("Scrape examples target_crates: {target_crates:?}"); // Run call-finder on all items - let mut calls = FxHashMap::default(); + let mut calls = FxIndexMap::default(); let mut finder = FindCalls { calls: &mut calls, tcx, map: tcx.hir(), cx, target_crates, bin_crate }; tcx.hir().visit_all_item_likes_in_crate(&mut finder); @@ -332,7 +332,7 @@ pub(crate) fn load_call_locations( with_examples: Vec, dcx: DiagCtxtHandle<'_>, ) -> AllCallLocations { - let mut all_calls: AllCallLocations = FxHashMap::default(); + let mut all_calls: AllCallLocations = FxIndexMap::default(); for path in with_examples { let bytes = match fs::read(&path) { Ok(bytes) => bytes, diff --git a/src/librustdoc/theme.rs b/src/librustdoc/theme.rs index 409728a8e86..2c00bb7e132 100644 --- a/src/librustdoc/theme.rs +++ b/src/librustdoc/theme.rs @@ -1,10 +1,9 @@ -use std::collections::hash_map::Entry; use std::fs; use std::iter::Peekable; use std::path::Path; use std::str::Chars; -use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::fx::{FxIndexMap, IndexEntry}; use rustc_errors::DiagCtxtHandle; #[cfg(test)] @@ -12,8 +11,8 @@ mod tests; #[derive(Debug)] pub(crate) struct CssPath { - pub(crate) rules: FxHashMap, - pub(crate) children: FxHashMap, + pub(crate) rules: FxIndexMap, + pub(crate) children: FxIndexMap, } /// When encountering a `"` or a `'`, returns the whole string, including the quote characters. @@ -120,10 +119,10 @@ fn parse_rules( content: &str, selector: String, iter: &mut Peekable>, - paths: &mut FxHashMap, + paths: &mut FxIndexMap, ) -> Result<(), String> { - let mut rules = FxHashMap::default(); - let mut children = FxHashMap::default(); + let mut rules = FxIndexMap::default(); + let mut children = FxIndexMap::default(); loop { // If the parent isn't a "normal" CSS selector, we only expect sub-selectors and not CSS @@ -146,10 +145,10 @@ fn parse_rules( return Err(format!("Found empty value for rule `{rule}` in selector `{selector}`")); } match rules.entry(rule) { - Entry::Occupied(mut o) => { + IndexEntry::Occupied(mut o) => { *o.get_mut() = value; } - Entry::Vacant(v) => { + IndexEntry::Vacant(v) => { v.insert(value); } } @@ -159,7 +158,7 @@ fn parse_rules( } match paths.entry(selector) { - Entry::Occupied(mut o) => { + IndexEntry::Occupied(mut o) => { let v = o.get_mut(); for (key, value) in rules.into_iter() { v.rules.insert(key, value); @@ -168,7 +167,7 @@ fn parse_rules( v.children.insert(sel, child); } } - Entry::Vacant(v) => { + IndexEntry::Vacant(v) => { v.insert(CssPath { rules, children }); } } @@ -178,7 +177,7 @@ fn parse_rules( pub(crate) fn parse_selectors( content: &str, iter: &mut Peekable>, - paths: &mut FxHashMap, + paths: &mut FxIndexMap, ) -> Result<(), String> { let mut selector = String::new(); @@ -202,17 +201,17 @@ pub(crate) fn parse_selectors( /// The entry point to parse the CSS rules. Every time we encounter a `{`, we then parse the rules /// inside it. -pub(crate) fn load_css_paths(content: &str) -> Result, String> { +pub(crate) fn load_css_paths(content: &str) -> Result, String> { let mut iter = content.chars().peekable(); - let mut paths = FxHashMap::default(); + let mut paths = FxIndexMap::default(); parse_selectors(content, &mut iter, &mut paths)?; Ok(paths) } pub(crate) fn get_differences( - origin: &FxHashMap, - against: &FxHashMap, + origin: &FxIndexMap, + against: &FxIndexMap, v: &mut Vec, ) { for (selector, entry) in origin.iter() { @@ -235,7 +234,7 @@ pub(crate) fn get_differences( pub(crate) fn test_theme_against>( f: &P, - origin: &FxHashMap, + origin: &FxIndexMap, dcx: DiagCtxtHandle<'_>, ) -> (bool, Vec) { let against = match fs::read_to_string(f) From aa75b5f686945b0d2c4927ae3f277cd2216a1350 Mon Sep 17 00:00:00 2001 From: mu001999 Date: Sun, 6 Oct 2024 18:08:28 +0800 Subject: [PATCH 617/683] Update out-dated link --- compiler/rustc_driver_impl/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_driver_impl/README.md b/compiler/rustc_driver_impl/README.md index 6d7fba36fb3..9fa4242de3c 100644 --- a/compiler/rustc_driver_impl/README.md +++ b/compiler/rustc_driver_impl/README.md @@ -7,4 +7,4 @@ options). For more information about how the driver works, see the [rustc dev guide]. -[rustc dev guide]: https://rustc-dev-guide.rust-lang.org/rustc-driver.html +[rustc dev guide]: https://rustc-dev-guide.rust-lang.org/rustc-driver/intro.html From 3f90bb15ed1672984c826b38d93e6d771c320701 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Sun, 6 Oct 2024 20:59:24 +1100 Subject: [PATCH 618/683] coverage: Make `BcbCounter` module-private --- compiler/rustc_mir_transform/src/coverage/counters.rs | 8 ++++---- compiler/rustc_mir_transform/src/coverage/mod.rs | 8 ++------ 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_mir_transform/src/coverage/counters.rs b/compiler/rustc_mir_transform/src/coverage/counters.rs index ef4031c5c03..a954ca35985 100644 --- a/compiler/rustc_mir_transform/src/coverage/counters.rs +++ b/compiler/rustc_mir_transform/src/coverage/counters.rs @@ -13,13 +13,13 @@ use crate::coverage::graph::{BasicCoverageBlock, CoverageGraph, TraverseCoverage /// The coverage counter or counter expression associated with a particular /// BCB node or BCB edge. #[derive(Clone, Copy, PartialEq, Eq, Hash)] -pub(super) enum BcbCounter { +enum BcbCounter { Counter { id: CounterId }, Expression { id: ExpressionId }, } impl BcbCounter { - pub(super) fn as_term(&self) -> CovTerm { + fn as_term(&self) -> CovTerm { match *self { BcbCounter::Counter { id, .. } => CovTerm::Counter(id), BcbCounter::Expression { id, .. } => CovTerm::Expression(id), @@ -218,8 +218,8 @@ impl CoverageCounters { } } - pub(super) fn bcb_counter(&self, bcb: BasicCoverageBlock) -> Option { - self.bcb_counters[bcb] + pub(super) fn term_for_bcb(&self, bcb: BasicCoverageBlock) -> Option { + self.bcb_counters[bcb].map(|counter| counter.as_term()) } /// Returns an iterator over all the nodes/edges in the coverage graph that diff --git a/compiler/rustc_mir_transform/src/coverage/mod.rs b/compiler/rustc_mir_transform/src/coverage/mod.rs index 104f340c8d6..97684d796b7 100644 --- a/compiler/rustc_mir_transform/src/coverage/mod.rs +++ b/compiler/rustc_mir_transform/src/coverage/mod.rs @@ -153,12 +153,8 @@ fn create_mappings<'tcx>( &source_file.name.for_scope(tcx.sess, RemapPathScopeComponents::MACRO).to_string_lossy(), ); - let term_for_bcb = |bcb| { - coverage_counters - .bcb_counter(bcb) - .expect("all BCBs with spans were given counters") - .as_term() - }; + let term_for_bcb = + |bcb| coverage_counters.term_for_bcb(bcb).expect("all BCBs with spans were given counters"); let region_for_span = |span: Span| make_source_region(source_map, file_name, span, body_span); // Fully destructure the mappings struct to make sure we don't miss any kinds. From c6e4fcd4faaa57fa059165a5c24b119d1e8f0f7f Mon Sep 17 00:00:00 2001 From: Zalathar Date: Sat, 5 Oct 2024 17:08:07 +1000 Subject: [PATCH 619/683] coverage: Have MakeBcbCounters own its CoverageCounters --- .../src/coverage/counters.rs | 27 ++++++++++--------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/compiler/rustc_mir_transform/src/coverage/counters.rs b/compiler/rustc_mir_transform/src/coverage/counters.rs index a954ca35985..95c4d9f88fb 100644 --- a/compiler/rustc_mir_transform/src/coverage/counters.rs +++ b/compiler/rustc_mir_transform/src/coverage/counters.rs @@ -80,19 +80,20 @@ impl CoverageCounters { basic_coverage_blocks: &CoverageGraph, bcb_needs_counter: impl Fn(BasicCoverageBlock) -> bool, ) -> Self { - let num_bcbs = basic_coverage_blocks.num_nodes(); + let mut counters = MakeBcbCounters::new(basic_coverage_blocks); + counters.make_bcb_counters(bcb_needs_counter); - let mut this = Self { + counters.coverage_counters + } + + fn with_num_bcbs(num_bcbs: usize) -> Self { + Self { counter_increment_sites: IndexVec::new(), bcb_counters: IndexVec::from_elem_n(None, num_bcbs), bcb_edge_counters: FxHashMap::default(), expressions: IndexVec::new(), expressions_memo: FxHashMap::default(), - }; - - MakeBcbCounters::new(&mut this, basic_coverage_blocks).make_bcb_counters(bcb_needs_counter); - - this + } } /// Shared helper used by [`Self::make_phys_node_counter`] and @@ -265,16 +266,16 @@ impl CoverageCounters { /// Helper struct that allows counter creation to inspect the BCB graph. struct MakeBcbCounters<'a> { - coverage_counters: &'a mut CoverageCounters, + coverage_counters: CoverageCounters, basic_coverage_blocks: &'a CoverageGraph, } impl<'a> MakeBcbCounters<'a> { - fn new( - coverage_counters: &'a mut CoverageCounters, - basic_coverage_blocks: &'a CoverageGraph, - ) -> Self { - Self { coverage_counters, basic_coverage_blocks } + fn new(basic_coverage_blocks: &'a CoverageGraph) -> Self { + Self { + coverage_counters: CoverageCounters::with_num_bcbs(basic_coverage_blocks.num_nodes()), + basic_coverage_blocks, + } } fn make_bcb_counters(&mut self, bcb_needs_counter: impl Fn(BasicCoverageBlock) -> bool) { From ab154e69993f15c4f37842dd2c2dfc6750af6a8a Mon Sep 17 00:00:00 2001 From: Zalathar Date: Sun, 6 Oct 2024 22:44:14 +1100 Subject: [PATCH 620/683] coverage: Store `bcb_needs_counter` in a field as a bitset This makes it possible for other parts of counter-assignment to check whether a node is guaranteed to end up with some kind of counter. Switching from `impl Fn` to a concrete `&BitSet` just avoids the hassle of trying to store a closure in a struct field, and currently there's no foreseeable need for this information to not be a bitset. --- .../src/coverage/counters.rs | 19 +++++++++++++------ .../rustc_mir_transform/src/coverage/mod.rs | 3 +-- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_mir_transform/src/coverage/counters.rs b/compiler/rustc_mir_transform/src/coverage/counters.rs index 95c4d9f88fb..94088156756 100644 --- a/compiler/rustc_mir_transform/src/coverage/counters.rs +++ b/compiler/rustc_mir_transform/src/coverage/counters.rs @@ -4,6 +4,7 @@ use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::graph::DirectedGraph; use rustc_index::IndexVec; +use rustc_index::bit_set::BitSet; use rustc_middle::bug; use rustc_middle::mir::coverage::{CounterId, CovTerm, Expression, ExpressionId, Op}; use tracing::{debug, debug_span, instrument}; @@ -78,10 +79,10 @@ impl CoverageCounters { /// counters or counter expressions for nodes and edges as required. pub(super) fn make_bcb_counters( basic_coverage_blocks: &CoverageGraph, - bcb_needs_counter: impl Fn(BasicCoverageBlock) -> bool, + bcb_needs_counter: &BitSet, ) -> Self { - let mut counters = MakeBcbCounters::new(basic_coverage_blocks); - counters.make_bcb_counters(bcb_needs_counter); + let mut counters = MakeBcbCounters::new(basic_coverage_blocks, bcb_needs_counter); + counters.make_bcb_counters(); counters.coverage_counters } @@ -268,17 +269,23 @@ impl CoverageCounters { struct MakeBcbCounters<'a> { coverage_counters: CoverageCounters, basic_coverage_blocks: &'a CoverageGraph, + bcb_needs_counter: &'a BitSet, } impl<'a> MakeBcbCounters<'a> { - fn new(basic_coverage_blocks: &'a CoverageGraph) -> Self { + fn new( + basic_coverage_blocks: &'a CoverageGraph, + bcb_needs_counter: &'a BitSet, + ) -> Self { + assert_eq!(basic_coverage_blocks.num_nodes(), bcb_needs_counter.domain_size()); Self { coverage_counters: CoverageCounters::with_num_bcbs(basic_coverage_blocks.num_nodes()), basic_coverage_blocks, + bcb_needs_counter, } } - fn make_bcb_counters(&mut self, bcb_needs_counter: impl Fn(BasicCoverageBlock) -> bool) { + fn make_bcb_counters(&mut self) { debug!("make_bcb_counters(): adding a counter or expression to each BasicCoverageBlock"); // Traverse the coverage graph, ensuring that every node that needs a @@ -291,7 +298,7 @@ impl<'a> MakeBcbCounters<'a> { let mut traversal = TraverseCoverageGraphWithLoops::new(self.basic_coverage_blocks); while let Some(bcb) = traversal.next() { let _span = debug_span!("traversal", ?bcb).entered(); - if bcb_needs_counter(bcb) { + if self.bcb_needs_counter.contains(bcb) { self.make_node_counter_and_out_edge_counters(&traversal, bcb); } } diff --git a/compiler/rustc_mir_transform/src/coverage/mod.rs b/compiler/rustc_mir_transform/src/coverage/mod.rs index 97684d796b7..79482ba3919 100644 --- a/compiler/rustc_mir_transform/src/coverage/mod.rs +++ b/compiler/rustc_mir_transform/src/coverage/mod.rs @@ -94,9 +94,8 @@ fn instrument_function_for_coverage<'tcx>(tcx: TyCtxt<'tcx>, mir_body: &mut mir: return; } - let bcb_has_counter_mappings = |bcb| bcbs_with_counter_mappings.contains(bcb); let coverage_counters = - CoverageCounters::make_bcb_counters(&basic_coverage_blocks, bcb_has_counter_mappings); + CoverageCounters::make_bcb_counters(&basic_coverage_blocks, &bcbs_with_counter_mappings); let mappings = create_mappings(tcx, &hir_info, &extracted_mappings, &coverage_counters); if mappings.is_empty() { From 0df736c2a9a7b5ceddd90bfdd6aa991801145a54 Mon Sep 17 00:00:00 2001 From: "Naveen R. Iyer" Date: Sat, 28 Sep 2024 20:27:51 -0500 Subject: [PATCH 621/683] add clarity for custom path installation install.sysconfdir is another value, in addition to install.prefix, that could be set for custom path installation. Signed-off-by: Naveen R. Iyer --- INSTALL.md | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/INSTALL.md b/INSTALL.md index ded0b59fc6c..74fcc58348b 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -79,9 +79,23 @@ See [the rustc-dev-guide for more info][sysllvm]. ./configure ``` - If you plan to use `x.py install` to create an installation, it is - recommended that you set the `prefix` value in the `[install]` section to a - directory: `./configure --set install.prefix=` + If you plan to use `x.py install` to create an installation, you can either + set `DESTDIR` environment variable to your custom directory path: + + ```bash + export DESTDIR= + ``` + + or set `prefix` and `sysconfdir` in the `[install]` section to your custom + directory path: + + ```sh + ./configure --set install.prefix= --set install.sysconfdir= + ``` + + When the `DESTDIR` environment variable is present, the `prefix` and + `sysconfdir` values are combined with the path from the `DESTDIR` + environment variable. 3. Build and install: From 6dfc4a0473ed0901b9c0d09f5189c41f3882d5fc Mon Sep 17 00:00:00 2001 From: codemountains <4kz12zz@gmail.com> Date: Fri, 4 Oct 2024 21:59:04 +0900 Subject: [PATCH 622/683] Rename NestedMetaItem to MetaItemInner --- compiler/rustc_ast/src/ast.rs | 4 +- compiler/rustc_ast/src/attr/mod.rs | 48 +++++++++---------- compiler/rustc_ast/src/mut_visit.rs | 8 ++-- compiler/rustc_ast_pretty/src/pprust/mod.rs | 2 +- compiler/rustc_ast_pretty/src/pprust/state.rs | 8 ++-- compiler/rustc_attr/src/builtin.rs | 24 +++++----- compiler/rustc_builtin_macros/src/cfg.rs | 2 +- compiler/rustc_builtin_macros/src/derive.rs | 6 +-- .../rustc_codegen_ssa/src/codegen_attrs.rs | 4 +- compiler/rustc_codegen_ssa/src/lib.rs | 2 +- compiler/rustc_expand/src/base.rs | 4 +- compiler/rustc_expand/src/config.rs | 6 +-- compiler/rustc_expand/src/expand.rs | 4 +- .../src/persist/dirty_clean.rs | 6 +-- compiler/rustc_lint/src/levels.rs | 2 +- compiler/rustc_middle/src/ty/context.rs | 5 +- .../src/framework/engine.rs | 2 +- compiler/rustc_parse/src/lib.rs | 4 +- compiler/rustc_parse/src/parser/attr.rs | 10 ++-- compiler/rustc_parse/src/validate_attr.rs | 6 +-- compiler/rustc_passes/src/check_attr.rs | 29 ++++++----- compiler/rustc_resolve/src/diagnostics.rs | 5 +- compiler/rustc_session/src/cstore.rs | 2 +- .../traits/on_unimplemented.rs | 6 +-- src/librustdoc/clean/cfg.rs | 14 +++--- src/librustdoc/clean/cfg/tests.rs | 18 +++---- src/librustdoc/clean/types.rs | 18 +++---- .../attrs/allow_attributes_without_reason.rs | 6 +-- .../attrs/blanket_clippy_restriction_lints.rs | 4 +- .../clippy/clippy_lints/src/attrs/mod.rs | 4 +- .../clippy_lints/src/attrs/non_minimal_cfg.rs | 6 +-- .../src/attrs/useless_attribute.rs | 4 +- .../clippy/clippy_lints/src/attrs/utils.rs | 8 ++-- .../clippy/clippy_lints/src/cfg_not_test.rs | 4 +- src/tools/clippy/clippy_lints/src/returns.rs | 4 +- src/tools/rustfmt/src/attr.rs | 16 +++---- src/tools/rustfmt/src/overflow.rs | 25 +++++----- src/tools/rustfmt/src/spanned.rs | 2 +- src/tools/rustfmt/src/utils.rs | 8 ++-- 39 files changed, 167 insertions(+), 173 deletions(-) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 37f429cce44..18d27167ec9 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -511,7 +511,7 @@ pub enum MetaItemKind { /// List meta item. /// /// E.g., `#[derive(..)]`, where the field represents the `..`. - List(ThinVec), + List(ThinVec), /// Name value meta item. /// @@ -523,7 +523,7 @@ pub enum MetaItemKind { /// /// E.g., each of `Clone`, `Copy` in `#[derive(Clone, Copy)]`. #[derive(Clone, Encodable, Decodable, Debug, HashStable_Generic)] -pub enum NestedMetaItem { +pub enum MetaItemInner { /// A full MetaItem, for recursive meta items. MetaItem(MetaItem), diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs index 338d50cb394..b73412a4b1d 100644 --- a/compiler/rustc_ast/src/attr/mod.rs +++ b/compiler/rustc_ast/src/attr/mod.rs @@ -11,7 +11,7 @@ use thin_vec::{ThinVec, thin_vec}; use crate::ast::{ AttrArgs, AttrArgsEq, AttrId, AttrItem, AttrKind, AttrStyle, AttrVec, Attribute, DUMMY_NODE_ID, - DelimArgs, Expr, ExprKind, LitKind, MetaItem, MetaItemKind, MetaItemLit, NestedMetaItem, + DelimArgs, Expr, ExprKind, LitKind, MetaItem, MetaItemInner, MetaItemKind, MetaItemLit, NormalAttr, Path, PathSegment, Safety, }; use crate::ptr::P; @@ -136,7 +136,7 @@ impl Attribute { } } - pub fn meta_item_list(&self) -> Option> { + pub fn meta_item_list(&self) -> Option> { match &self.kind { AttrKind::Normal(normal) => normal.item.meta_item_list(), AttrKind::DocComment(..) => None, @@ -223,7 +223,7 @@ impl AttrItem { self.args.span().map_or(self.path.span, |args_span| self.path.span.to(args_span)) } - fn meta_item_list(&self) -> Option> { + fn meta_item_list(&self) -> Option> { match &self.args { AttrArgs::Delimited(args) if args.delim == Delimiter::Parenthesis => { MetaItemKind::list_from_tokens(args.tokens.clone()) @@ -285,7 +285,7 @@ impl MetaItem { matches!(self.kind, MetaItemKind::Word) } - pub fn meta_item_list(&self) -> Option<&[NestedMetaItem]> { + pub fn meta_item_list(&self) -> Option<&[MetaItemInner]> { match &self.kind { MetaItemKind::List(l) => Some(&**l), _ => None, @@ -393,11 +393,11 @@ impl MetaItem { } impl MetaItemKind { - fn list_from_tokens(tokens: TokenStream) -> Option> { + fn list_from_tokens(tokens: TokenStream) -> Option> { let mut tokens = tokens.trees().peekable(); let mut result = ThinVec::new(); while tokens.peek().is_some() { - let item = NestedMetaItem::from_tokens(&mut tokens)?; + let item = MetaItemInner::from_tokens(&mut tokens)?; result.push(item); match tokens.next() { None | Some(TokenTree::Token(Token { kind: token::Comma, .. }, _)) => {} @@ -460,11 +460,11 @@ impl MetaItemKind { } } -impl NestedMetaItem { +impl MetaItemInner { pub fn span(&self) -> Span { match self { - NestedMetaItem::MetaItem(item) => item.span, - NestedMetaItem::Lit(lit) => lit.span, + MetaItemInner::MetaItem(item) => item.span, + MetaItemInner::Lit(lit) => lit.span, } } @@ -488,7 +488,7 @@ impl NestedMetaItem { } /// Gets a list of inner meta items from a list `MetaItem` type. - pub fn meta_item_list(&self) -> Option<&[NestedMetaItem]> { + pub fn meta_item_list(&self) -> Option<&[MetaItemInner]> { self.meta_item().and_then(|meta_item| meta_item.meta_item_list()) } @@ -519,28 +519,28 @@ impl NestedMetaItem { self.meta_item().and_then(|meta_item| meta_item.value_str()) } - /// Returns the `MetaItemLit` if `self` is a `NestedMetaItem::Literal`s. + /// Returns the `MetaItemLit` if `self` is a `MetaItemInner::Literal`s. pub fn lit(&self) -> Option<&MetaItemLit> { match self { - NestedMetaItem::Lit(lit) => Some(lit), + MetaItemInner::Lit(lit) => Some(lit), _ => None, } } - /// Returns the `MetaItem` if `self` is a `NestedMetaItem::MetaItem` or if it's - /// `NestedMetaItem::Lit(MetaItemLit { kind: LitKind::Bool(_), .. })`. - pub fn meta_item_or_bool(&self) -> Option<&NestedMetaItem> { + /// Returns the `MetaItem` if `self` is a `MetaItemInner::MetaItem` or if it's + /// `MetaItemInner::Lit(MetaItemLit { kind: LitKind::Bool(_), .. })`. + pub fn meta_item_or_bool(&self) -> Option<&MetaItemInner> { match self { - NestedMetaItem::MetaItem(_item) => Some(self), - NestedMetaItem::Lit(MetaItemLit { kind: LitKind::Bool(_), .. }) => Some(self), + MetaItemInner::MetaItem(_item) => Some(self), + MetaItemInner::Lit(MetaItemLit { kind: LitKind::Bool(_), .. }) => Some(self), _ => None, } } - /// Returns the `MetaItem` if `self` is a `NestedMetaItem::MetaItem`. + /// Returns the `MetaItem` if `self` is a `MetaItemInner::MetaItem`. pub fn meta_item(&self) -> Option<&MetaItem> { match self { - NestedMetaItem::MetaItem(item) => Some(item), + MetaItemInner::MetaItem(item) => Some(item), _ => None, } } @@ -550,22 +550,22 @@ impl NestedMetaItem { self.meta_item().is_some() } - fn from_tokens<'a, I>(tokens: &mut iter::Peekable) -> Option + fn from_tokens<'a, I>(tokens: &mut iter::Peekable) -> Option where I: Iterator, { match tokens.peek() { Some(TokenTree::Token(token, _)) if let Some(lit) = MetaItemLit::from_token(token) => { tokens.next(); - return Some(NestedMetaItem::Lit(lit)); + return Some(MetaItemInner::Lit(lit)); } Some(TokenTree::Delimited(.., Delimiter::Invisible, inner_tokens)) => { tokens.next(); - return NestedMetaItem::from_tokens(&mut inner_tokens.trees().peekable()); + return MetaItemInner::from_tokens(&mut inner_tokens.trees().peekable()); } _ => {} } - MetaItem::from_tokens(tokens).map(NestedMetaItem::MetaItem) + MetaItem::from_tokens(tokens).map(MetaItemInner::MetaItem) } } @@ -676,6 +676,6 @@ pub fn contains_name(attrs: &[Attribute], name: Symbol) -> bool { find_by_name(attrs, name).is_some() } -pub fn list_contains_name(items: &[NestedMetaItem], name: Symbol) -> bool { +pub fn list_contains_name(items: &[MetaItemInner], name: Symbol) -> bool { items.iter().any(|item| item.has_name(name)) } diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index 104f84f26e0..6ce23a1479d 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -83,7 +83,7 @@ pub trait MutVisitor: Sized { walk_crate(self, c) } - fn visit_meta_list_item(&mut self, list_item: &mut NestedMetaItem) { + fn visit_meta_list_item(&mut self, list_item: &mut MetaItemInner) { walk_meta_list_item(self, list_item); } @@ -659,10 +659,10 @@ fn walk_macro_def(vis: &mut T, macro_def: &mut MacroDef) { visit_delim_args(vis, body); } -fn walk_meta_list_item(vis: &mut T, li: &mut NestedMetaItem) { +fn walk_meta_list_item(vis: &mut T, li: &mut MetaItemInner) { match li { - NestedMetaItem::MetaItem(mi) => vis.visit_meta_item(mi), - NestedMetaItem::Lit(_lit) => {} + MetaItemInner::MetaItem(mi) => vis.visit_meta_item(mi), + MetaItemInner::Lit(_lit) => {} } } diff --git a/compiler/rustc_ast_pretty/src/pprust/mod.rs b/compiler/rustc_ast_pretty/src/pprust/mod.rs index 726ceebe3c5..97cb6e52d56 100644 --- a/compiler/rustc_ast_pretty/src/pprust/mod.rs +++ b/compiler/rustc_ast_pretty/src/pprust/mod.rs @@ -67,7 +67,7 @@ pub fn vis_to_string(v: &ast::Visibility) -> String { State::new().vis_to_string(v) } -pub fn meta_list_item_to_string(li: &ast::NestedMetaItem) -> String { +pub fn meta_list_item_to_string(li: &ast::MetaItemInner) -> String { State::new().meta_list_item_to_string(li) } diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index 7e07ccf28a0..884cc413bd5 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -2006,10 +2006,10 @@ impl<'a> State<'a> { self.print_attribute_inline(attr, false) } - fn print_meta_list_item(&mut self, item: &ast::NestedMetaItem) { + fn print_meta_list_item(&mut self, item: &ast::MetaItemInner) { match item { - ast::NestedMetaItem::MetaItem(mi) => self.print_meta_item(mi), - ast::NestedMetaItem::Lit(lit) => self.print_meta_item_lit(lit), + ast::MetaItemInner::MetaItem(mi) => self.print_meta_item(mi), + ast::MetaItemInner::Lit(lit) => self.print_meta_item_lit(lit), } } @@ -2054,7 +2054,7 @@ impl<'a> State<'a> { Self::to_string(|s| s.print_path_segment(p, false)) } - pub(crate) fn meta_list_item_to_string(&self, li: &ast::NestedMetaItem) -> String { + pub(crate) fn meta_list_item_to_string(&self, li: &ast::MetaItemInner) -> String { Self::to_string(|s| s.print_meta_list_item(li)) } diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs index d6a7dbad12d..c1db4d07dfc 100644 --- a/compiler/rustc_attr/src/builtin.rs +++ b/compiler/rustc_attr/src/builtin.rs @@ -4,7 +4,7 @@ use std::num::NonZero; use rustc_abi::Align; use rustc_ast::{ - self as ast, Attribute, LitKind, MetaItem, MetaItemKind, MetaItemLit, NestedMetaItem, NodeId, + self as ast, Attribute, LitKind, MetaItem, MetaItemInner, MetaItemKind, MetaItemLit, NodeId, attr, }; use rustc_ast_pretty::pprust; @@ -534,7 +534,7 @@ pub struct Condition { /// Tests if a cfg-pattern matches the cfg set pub fn cfg_matches( - cfg: &ast::NestedMetaItem, + cfg: &ast::MetaItemInner, sess: &Session, lint_node_id: NodeId, features: Option<&Features>, @@ -605,7 +605,7 @@ pub fn parse_version(s: Symbol) -> Option { /// Evaluate a cfg-like condition (with `any` and `all`), using `eval` to /// evaluate individual items. pub fn eval_condition( - cfg: &ast::NestedMetaItem, + cfg: &ast::MetaItemInner, sess: &Session, features: Option<&Features>, eval: &mut impl FnMut(Condition) -> bool, @@ -613,8 +613,8 @@ pub fn eval_condition( let dcx = sess.dcx(); let cfg = match cfg { - ast::NestedMetaItem::MetaItem(meta_item) => meta_item, - ast::NestedMetaItem::Lit(MetaItemLit { kind: LitKind::Bool(b), .. }) => { + ast::MetaItemInner::MetaItem(meta_item) => meta_item, + ast::MetaItemInner::Lit(MetaItemLit { kind: LitKind::Bool(b), .. }) => { if let Some(features) = features { // we can't use `try_gate_cfg` as symbols don't differentiate between `r#true` // and `true`, and we want to keep the former working without feature gate @@ -646,12 +646,12 @@ pub fn eval_condition( ast::MetaItemKind::List(mis) if cfg.name_or_empty() == sym::version => { try_gate_cfg(sym::version, cfg.span, sess, features); let (min_version, span) = match &mis[..] { - [NestedMetaItem::Lit(MetaItemLit { kind: LitKind::Str(sym, ..), span, .. })] => { + [MetaItemInner::Lit(MetaItemLit { kind: LitKind::Str(sym, ..), span, .. })] => { (sym, span) } [ - NestedMetaItem::Lit(MetaItemLit { span, .. }) - | NestedMetaItem::MetaItem(MetaItem { span, .. }), + MetaItemInner::Lit(MetaItemLit { span, .. }) + | MetaItemInner::MetaItem(MetaItem { span, .. }), ] => { dcx.emit_err(session_diagnostics::ExpectedVersionLiteral { span: *span }); return false; @@ -729,7 +729,7 @@ pub fn eval_condition( } res & eval_condition( - &ast::NestedMetaItem::MetaItem(mi), + &ast::MetaItemInner::MetaItem(mi), sess, features, eval, @@ -873,7 +873,7 @@ pub fn find_deprecation( for meta in list { match meta { - NestedMetaItem::MetaItem(mi) => match mi.name_or_empty() { + MetaItemInner::MetaItem(mi) => match mi.name_or_empty() { sym::since => { if !get(mi, &mut since) { continue 'outer; @@ -912,7 +912,7 @@ pub fn find_deprecation( continue 'outer; } }, - NestedMetaItem::Lit(lit) => { + MetaItemInner::Lit(lit) => { sess.dcx().emit_err(session_diagnostics::UnsupportedLiteral { span: lit.span, reason: UnsupportedLiteralReason::DeprecatedKvPair, @@ -1277,7 +1277,7 @@ pub fn parse_confusables(attr: &Attribute) -> Option> { let mut candidates = Vec::new(); for meta in metas { - let NestedMetaItem::Lit(meta_lit) = meta else { + let MetaItemInner::Lit(meta_lit) = meta else { return None; }; candidates.push(meta_lit.symbol); diff --git a/compiler/rustc_builtin_macros/src/cfg.rs b/compiler/rustc_builtin_macros/src/cfg.rs index 940c94b1cfc..15993dbf5ec 100644 --- a/compiler/rustc_builtin_macros/src/cfg.rs +++ b/compiler/rustc_builtin_macros/src/cfg.rs @@ -39,7 +39,7 @@ fn parse_cfg<'a>( cx: &ExtCtxt<'a>, span: Span, tts: TokenStream, -) -> PResult<'a, ast::NestedMetaItem> { +) -> PResult<'a, ast::MetaItemInner> { let mut p = cx.new_parser_from_tts(tts); if p.token == token::Eof { diff --git a/compiler/rustc_builtin_macros/src/derive.rs b/compiler/rustc_builtin_macros/src/derive.rs index 4be2d209ae7..361fcaa8534 100644 --- a/compiler/rustc_builtin_macros/src/derive.rs +++ b/compiler/rustc_builtin_macros/src/derive.rs @@ -1,5 +1,5 @@ use rustc_ast as ast; -use rustc_ast::{GenericParamKind, ItemKind, MetaItemKind, NestedMetaItem, StmtKind}; +use rustc_ast::{GenericParamKind, ItemKind, MetaItemInner, MetaItemKind, StmtKind}; use rustc_expand::base::{ Annotatable, DeriveResolution, ExpandResult, ExtCtxt, Indeterminate, MultiItemModifier, }; @@ -50,8 +50,8 @@ impl MultiItemModifier for Expander { MetaItemKind::List(list) => { list.iter() .filter_map(|nested_meta| match nested_meta { - NestedMetaItem::MetaItem(meta) => Some(meta), - NestedMetaItem::Lit(lit) => { + MetaItemInner::MetaItem(meta) => Some(meta), + MetaItemInner::Lit(lit) => { // Reject `#[derive("Debug")]`. report_unexpected_meta_item_lit(sess, lit); None diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index e99c3a46271..8d634ca4655 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -1,4 +1,4 @@ -use rustc_ast::{MetaItemKind, NestedMetaItem, ast, attr}; +use rustc_ast::{MetaItemInner, MetaItemKind, ast, attr}; use rustc_attr::{InlineAttr, InstructionSetAttr, OptimizeAttr, list_contains_name}; use rustc_errors::codes::*; use rustc_errors::{DiagMessage, SubdiagMessage, struct_span_code_err}; @@ -357,7 +357,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { sym::instruction_set => { codegen_fn_attrs.instruction_set = attr.meta_item_list().and_then(|l| match &l[..] { - [NestedMetaItem::MetaItem(set)] => { + [MetaItemInner::MetaItem(set)] => { let segments = set.path.segments.iter().map(|x| x.ident.name).collect::>(); match segments.as_slice() { diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs index 3129b9ac203..cbd95146294 100644 --- a/compiler/rustc_codegen_ssa/src/lib.rs +++ b/compiler/rustc_codegen_ssa/src/lib.rs @@ -156,7 +156,7 @@ pub struct NativeLib { pub kind: NativeLibKind, pub name: Symbol, pub filename: Option, - pub cfg: Option, + pub cfg: Option, pub verbatim: bool, pub dll_imports: Vec, } diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index d0552a754fe..f0cfe133a49 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -29,7 +29,7 @@ use rustc_span::{DUMMY_SP, FileName, Span}; use smallvec::{SmallVec, smallvec}; use thin_vec::ThinVec; -use crate::base::ast::NestedMetaItem; +use crate::base::ast::MetaItemInner; use crate::errors; use crate::expand::{self, AstFragment, Invocation}; use crate::module::DirOwnership; @@ -783,7 +783,7 @@ impl SyntaxExtension { fn collapse_debuginfo_by_name(attr: &Attribute) -> Result { let list = attr.meta_item_list(); - let Some([NestedMetaItem::MetaItem(item)]) = list.as_deref() else { + let Some([MetaItemInner::MetaItem(item)]) = list.as_deref() else { return Err(attr.span); }; if !item.is_word() { diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs index af56169fd60..db5a98878e8 100644 --- a/compiler/rustc_expand/src/config.rs +++ b/compiler/rustc_expand/src/config.rs @@ -6,7 +6,7 @@ use rustc_ast::tokenstream::{ AttrTokenStream, AttrTokenTree, LazyAttrTokenStream, Spacing, TokenTree, }; use rustc_ast::{ - self as ast, AttrStyle, Attribute, HasAttrs, HasTokens, MetaItem, NestedMetaItem, NodeId, + self as ast, AttrStyle, Attribute, HasAttrs, HasTokens, MetaItem, MetaItemInner, NodeId, }; use rustc_attr as attr; use rustc_data_structures::flat_map_in_place::FlatMapInPlace; @@ -39,7 +39,7 @@ pub struct StripUnconfigured<'a> { } pub fn features(sess: &Session, krate_attrs: &[Attribute], crate_name: Symbol) -> Features { - fn feature_list(attr: &Attribute) -> ThinVec { + fn feature_list(attr: &Attribute) -> ThinVec { if attr.has_name(sym::feature) && let Some(list) = attr.meta_item_list() { @@ -451,7 +451,7 @@ impl<'a> StripUnconfigured<'a> { } } -pub fn parse_cfg<'a>(meta_item: &'a MetaItem, sess: &Session) -> Option<&'a NestedMetaItem> { +pub fn parse_cfg<'a>(meta_item: &'a MetaItem, sess: &Session) -> Option<&'a MetaItemInner> { let span = meta_item.span; match meta_item.meta_item_list() { None => { diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 079dcee99d3..5347381c3c3 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -11,7 +11,7 @@ use rustc_ast::tokenstream::TokenStream; use rustc_ast::visit::{self, AssocCtxt, Visitor, VisitorResult, try_visit, walk_list}; use rustc_ast::{ AssocItemKind, AstNodeWrapper, AttrArgs, AttrStyle, AttrVec, ExprKind, ForeignItemKind, - HasAttrs, HasNodeId, Inline, ItemKind, MacStmtStyle, MetaItemKind, ModKind, NestedMetaItem, + HasAttrs, HasNodeId, Inline, ItemKind, MacStmtStyle, MetaItemInner, MetaItemKind, ModKind, NodeId, PatKind, StmtKind, TyKind, }; use rustc_ast_pretty::pprust; @@ -1864,7 +1864,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { .filter(|a| a.has_name(sym::derive)) .flat_map(|a| a.meta_item_list().unwrap_or_default()) .filter_map(|nested_meta| match nested_meta { - NestedMetaItem::MetaItem(ast::MetaItem { + MetaItemInner::MetaItem(ast::MetaItem { kind: MetaItemKind::Word, path, .. diff --git a/compiler/rustc_incremental/src/persist/dirty_clean.rs b/compiler/rustc_incremental/src/persist/dirty_clean.rs index 9dc5cbaafce..d25fe4219b5 100644 --- a/compiler/rustc_incremental/src/persist/dirty_clean.rs +++ b/compiler/rustc_incremental/src/persist/dirty_clean.rs @@ -19,7 +19,7 @@ //! Errors are reported if we are in the suitable configuration but //! the required condition is not met. -use rustc_ast::{self as ast, Attribute, NestedMetaItem}; +use rustc_ast::{self as ast, Attribute, MetaItemInner}; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::unord::UnordSet; use rustc_hir::def_id::LocalDefId; @@ -307,7 +307,7 @@ impl<'tcx> DirtyCleanVisitor<'tcx> { (name, labels) } - fn resolve_labels(&self, item: &NestedMetaItem, value: Symbol) -> Labels { + fn resolve_labels(&self, item: &MetaItemInner, value: Symbol) -> Labels { let mut out = Labels::default(); for label in value.as_str().split(',') { let label = label.trim(); @@ -415,7 +415,7 @@ fn check_config(tcx: TyCtxt<'_>, attr: &Attribute) -> bool { } } -fn expect_associated_value(tcx: TyCtxt<'_>, item: &NestedMetaItem) -> Symbol { +fn expect_associated_value(tcx: TyCtxt<'_>, item: &MetaItemInner) -> Symbol { if let Some(value) = item.value_str() { value } else if let Some(ident) = item.ident() { diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs index 007e86ae0d2..89a67fc0d89 100644 --- a/compiler/rustc_lint/src/levels.rs +++ b/compiler/rustc_lint/src/levels.rs @@ -669,7 +669,7 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> { let sp = li.span(); let meta_item = match li { - ast::NestedMetaItem::MetaItem(meta_item) if meta_item.is_word() => meta_item, + ast::MetaItemInner::MetaItem(meta_item) if meta_item.is_word() => meta_item, _ => { let sub = if let Some(item) = li.meta_item() && let ast::MetaItemKind::NameValue(_) = item.kind diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 27c1b88f93f..4a02fce5e7d 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -1451,9 +1451,8 @@ impl<'tcx> TyCtxt<'tcx> { debug!("layout_scalar_valid_range: attr={:?}", attr); if let Some( &[ - ast::NestedMetaItem::Lit(ast::MetaItemLit { - kind: ast::LitKind::Int(a, _), - .. + ast::MetaItemInner::Lit(ast::MetaItemLit { + kind: ast::LitKind::Int(a, _), .. }), ], ) = attr.meta_item_list().as_deref() diff --git a/compiler/rustc_mir_dataflow/src/framework/engine.rs b/compiler/rustc_mir_dataflow/src/framework/engine.rs index faf5c610a0c..9d50e57d668 100644 --- a/compiler/rustc_mir_dataflow/src/framework/engine.rs +++ b/compiler/rustc_mir_dataflow/src/framework/engine.rs @@ -367,7 +367,7 @@ impl RustcMirAttrs { fn set_field( field: &mut Option, tcx: TyCtxt<'_>, - attr: &ast::NestedMetaItem, + attr: &ast::MetaItemInner, mapper: impl FnOnce(Symbol) -> Result, ) -> Result<(), ()> { if field.is_some() { diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs index da02f98d0e5..2792050a0b3 100644 --- a/compiler/rustc_parse/src/lib.rs +++ b/compiler/rustc_parse/src/lib.rs @@ -18,7 +18,7 @@ use std::path::Path; use rustc_ast as ast; use rustc_ast::tokenstream::TokenStream; -use rustc_ast::{AttrItem, Attribute, NestedMetaItem, token}; +use rustc_ast::{AttrItem, Attribute, MetaItemInner, token}; use rustc_ast_pretty::pprust; use rustc_data_structures::sync::Lrc; use rustc_errors::{Diag, FatalError, PResult}; @@ -160,7 +160,7 @@ pub fn fake_token_stream_for_crate(psess: &ParseSess, krate: &ast::Crate) -> Tok pub fn parse_cfg_attr( cfg_attr: &Attribute, psess: &ParseSess, -) -> Option<(NestedMetaItem, Vec<(AttrItem, Span)>)> { +) -> Option<(MetaItemInner, Vec<(AttrItem, Span)>)> { const CFG_ATTR_GRAMMAR_HELP: &str = "#[cfg_attr(condition, attribute, other_attribute, ...)]"; const CFG_ATTR_NOTE_REF: &str = "for more information, visit \ "; diff --git a/compiler/rustc_parse/src/parser/attr.rs b/compiler/rustc_parse/src/parser/attr.rs index 4aa56cb7624..b6fa2099588 100644 --- a/compiler/rustc_parse/src/parser/attr.rs +++ b/compiler/rustc_parse/src/parser/attr.rs @@ -358,7 +358,7 @@ impl<'a> Parser<'a> { /// Parses `cfg_attr(pred, attr_item_list)` where `attr_item_list` is comma-delimited. pub fn parse_cfg_attr( &mut self, - ) -> PResult<'a, (ast::NestedMetaItem, Vec<(ast::AttrItem, Span)>)> { + ) -> PResult<'a, (ast::MetaItemInner, Vec<(ast::AttrItem, Span)>)> { let cfg_predicate = self.parse_meta_item_inner()?; self.expect(&token::Comma)?; @@ -377,7 +377,7 @@ impl<'a> Parser<'a> { } /// Matches `COMMASEP(meta_item_inner)`. - pub(crate) fn parse_meta_seq_top(&mut self) -> PResult<'a, ThinVec> { + pub(crate) fn parse_meta_seq_top(&mut self) -> PResult<'a, ThinVec> { // Presumably, the majority of the time there will only be one attr. let mut nmis = ThinVec::with_capacity(1); while self.token != token::Eof { @@ -454,14 +454,14 @@ impl<'a> Parser<'a> { /// ```ebnf /// MetaItemInner = UNSUFFIXED_LIT | MetaItem ; /// ``` - pub fn parse_meta_item_inner(&mut self) -> PResult<'a, ast::NestedMetaItem> { + pub fn parse_meta_item_inner(&mut self) -> PResult<'a, ast::MetaItemInner> { match self.parse_unsuffixed_meta_item_lit() { - Ok(lit) => return Ok(ast::NestedMetaItem::Lit(lit)), + Ok(lit) => return Ok(ast::MetaItemInner::Lit(lit)), Err(err) => err.cancel(), // we provide a better error below } match self.parse_meta_item(AllowLeadingUnsafe::No) { - Ok(mi) => return Ok(ast::NestedMetaItem::MetaItem(mi)), + Ok(mi) => return Ok(ast::MetaItemInner::MetaItem(mi)), Err(err) => err.cancel(), // we provide a better error below } diff --git a/compiler/rustc_parse/src/validate_attr.rs b/compiler/rustc_parse/src/validate_attr.rs index b15d1edf79c..f3174e7dea2 100644 --- a/compiler/rustc_parse/src/validate_attr.rs +++ b/compiler/rustc_parse/src/validate_attr.rs @@ -3,8 +3,8 @@ use rustc_ast::token::Delimiter; use rustc_ast::tokenstream::DelimSpan; use rustc_ast::{ - self as ast, AttrArgs, AttrArgsEq, Attribute, DelimArgs, MetaItem, MetaItemKind, - NestedMetaItem, Safety, + self as ast, AttrArgs, AttrArgsEq, Attribute, DelimArgs, MetaItem, MetaItemInner, MetaItemKind, + Safety, }; use rustc_errors::{Applicability, FatalError, PResult}; use rustc_feature::{AttributeSafety, AttributeTemplate, BUILTIN_ATTRIBUTE_MAP, BuiltinAttribute}; @@ -143,7 +143,7 @@ pub(super) fn check_cfg_attr_bad_delim(psess: &ParseSess, span: DelimSpan, delim /// Checks that the given meta-item is compatible with this `AttributeTemplate`. fn is_attr_template_compatible(template: &AttributeTemplate, meta: &ast::MetaItemKind) -> bool { - let is_one_allowed_subword = |items: &[NestedMetaItem]| match items { + let is_one_allowed_subword = |items: &[MetaItemInner]| match items { [item] => item.is_word() && template.one_of.iter().any(|&word| item.has_name(word)), _ => false, }; diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index b3334bb70aa..44a62383e6e 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -8,7 +8,7 @@ use std::cell::Cell; use std::collections::hash_map::Entry; use rustc_ast::{ - AttrKind, AttrStyle, Attribute, LitKind, MetaItemKind, MetaItemLit, NestedMetaItem, ast, + AttrKind, AttrStyle, Attribute, LitKind, MetaItemInner, MetaItemKind, MetaItemLit, ast, }; use rustc_data_structures::fx::FxHashMap; use rustc_errors::{Applicability, DiagCtxtHandle, IntoDiagArg, MultiSpan, StashKey}; @@ -742,13 +742,13 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } - fn doc_attr_str_error(&self, meta: &NestedMetaItem, attr_name: &str) { + fn doc_attr_str_error(&self, meta: &MetaItemInner, attr_name: &str) { self.dcx().emit_err(errors::DocExpectStr { attr_span: meta.span(), attr_name }); } fn check_doc_alias_value( &self, - meta: &NestedMetaItem, + meta: &MetaItemInner, doc_alias: Symbol, hir_id: HirId, target: Target, @@ -850,7 +850,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { fn check_doc_alias( &self, - meta: &NestedMetaItem, + meta: &MetaItemInner, hir_id: HirId, target: Target, aliases: &mut FxHashMap, @@ -882,7 +882,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } - fn check_doc_keyword(&self, meta: &NestedMetaItem, hir_id: HirId) { + fn check_doc_keyword(&self, meta: &MetaItemInner, hir_id: HirId) { let doc_keyword = meta.value_str().unwrap_or(kw::Empty); if doc_keyword == kw::Empty { self.doc_attr_str_error(meta, "keyword"); @@ -912,7 +912,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } - fn check_doc_fake_variadic(&self, meta: &NestedMetaItem, hir_id: HirId) { + fn check_doc_fake_variadic(&self, meta: &MetaItemInner, hir_id: HirId) { let item_kind = match self.tcx.hir_node(hir_id) { hir::Node::Item(item) => Some(&item.kind), _ => None, @@ -957,7 +957,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { fn check_doc_inline( &self, attr: &Attribute, - meta: &NestedMetaItem, + meta: &MetaItemInner, hir_id: HirId, target: Target, specified_inline: &mut Option<(bool, Span)>, @@ -997,7 +997,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { fn check_doc_masked( &self, attr: &Attribute, - meta: &NestedMetaItem, + meta: &MetaItemInner, hir_id: HirId, target: Target, ) { @@ -1032,7 +1032,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { /// Checks that an attribute is *not* used at the crate level. Returns `true` if valid. fn check_attr_not_crate_level( &self, - meta: &NestedMetaItem, + meta: &MetaItemInner, hir_id: HirId, attr_name: &str, ) -> bool { @@ -1047,7 +1047,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { fn check_attr_crate_level( &self, attr: &Attribute, - meta: &NestedMetaItem, + meta: &MetaItemInner, hir_id: HirId, ) -> bool { if hir_id != CRATE_HIR_ID { @@ -1071,7 +1071,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { /// Checks that `doc(test(...))` attribute contains only valid attributes. Returns `true` if /// valid. - fn check_test_attr(&self, meta: &NestedMetaItem, hir_id: HirId) { + fn check_test_attr(&self, meta: &MetaItemInner, hir_id: HirId) { if let Some(metas) = meta.meta_item_list() { for i_meta in metas { match (i_meta.name_or_empty(), i_meta.meta_item()) { @@ -1108,7 +1108,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { /// Check that the `#![doc(cfg_hide(...))]` attribute only contains a list of attributes. /// - fn check_doc_cfg_hide(&self, meta: &NestedMetaItem, hir_id: HirId) { + fn check_doc_cfg_hide(&self, meta: &MetaItemInner, hir_id: HirId) { if meta.meta_item_list().is_none() { self.tcx.emit_node_span_lint( INVALID_DOC_ATTRIBUTES, @@ -1499,8 +1499,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { return; }; - if !matches!(&list[..], &[NestedMetaItem::Lit(MetaItemLit { kind: LitKind::Int(..), .. })]) - { + if !matches!(&list[..], &[MetaItemInner::Lit(MetaItemLit { kind: LitKind::Int(..), .. })]) { self.tcx .dcx() .emit_err(errors::RustcLayoutScalarValidRangeArg { attr_span: attr.span }); @@ -2073,7 +2072,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { let mut candidates = Vec::new(); for meta in metas { - let NestedMetaItem::Lit(meta_lit) = meta else { + let MetaItemInner::Lit(meta_lit) = meta else { self.dcx().emit_err(errors::IncorrectMetaItem { span: meta.span(), suggestion: errors::IncorrectMetaItemSuggestion { diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 582db97e1ce..5437ca65935 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -2,8 +2,7 @@ use rustc_ast::expand::StrippedCfgItem; use rustc_ast::ptr::P; use rustc_ast::visit::{self, Visitor}; use rustc_ast::{ - self as ast, CRATE_NODE_ID, Crate, ItemKind, MetaItemKind, ModKind, NestedMetaItem, NodeId, - Path, + self as ast, CRATE_NODE_ID, Crate, ItemKind, MetaItemInner, MetaItemKind, ModKind, NodeId, Path, }; use rustc_ast_pretty::pprust; use rustc_data_structures::fx::FxHashSet; @@ -2541,7 +2540,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { err.subdiagnostic(note); if let MetaItemKind::List(nested) = &cfg.kind - && let NestedMetaItem::MetaItem(meta_item) = &nested[0] + && let MetaItemInner::MetaItem(meta_item) = &nested[0] && let MetaItemKind::NameValue(feature_name) = &meta_item.kind { let note = errors::ItemWasBehindFeature { diff --git a/compiler/rustc_session/src/cstore.rs b/compiler/rustc_session/src/cstore.rs index b936a299b09..041a10475ea 100644 --- a/compiler/rustc_session/src/cstore.rs +++ b/compiler/rustc_session/src/cstore.rs @@ -72,7 +72,7 @@ pub struct NativeLib { pub name: Symbol, /// If packed_bundled_libs enabled, actual filename of library is stored. pub filename: Option, - pub cfg: Option, + pub cfg: Option, pub foreign_module: Option, pub verbatim: Option, pub dll_imports: Vec, diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs index e9a2c5b8d8e..c3100c48b0a 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs @@ -1,7 +1,7 @@ use std::iter; use std::path::PathBuf; -use rustc_ast::{AttrArgs, AttrArgsEq, AttrKind, Attribute, NestedMetaItem}; +use rustc_ast::{AttrArgs, AttrArgsEq, AttrKind, Attribute, MetaItemInner}; use rustc_data_structures::fx::FxHashMap; use rustc_errors::codes::*; use rustc_errors::{ErrorGuaranteed, struct_span_code_err}; @@ -282,7 +282,7 @@ pub struct OnUnimplementedFormatString { #[derive(Debug)] pub struct OnUnimplementedDirective { - pub condition: Option, + pub condition: Option, pub subcommands: Vec, pub message: Option, pub label: Option, @@ -389,7 +389,7 @@ impl<'tcx> OnUnimplementedDirective { fn parse( tcx: TyCtxt<'tcx>, item_def_id: DefId, - items: &[NestedMetaItem], + items: &[MetaItemInner], span: Span, is_root: bool, is_diagnostic_namespace_variant: bool, diff --git a/src/librustdoc/clean/cfg.rs b/src/librustdoc/clean/cfg.rs index 53830016a80..9255242611a 100644 --- a/src/librustdoc/clean/cfg.rs +++ b/src/librustdoc/clean/cfg.rs @@ -6,7 +6,7 @@ use std::fmt::{self, Write}; use std::{mem, ops}; -use rustc_ast::{LitKind, MetaItem, MetaItemKind, MetaItemLit, NestedMetaItem}; +use rustc_ast::{LitKind, MetaItem, MetaItemInner, MetaItemKind, MetaItemLit}; use rustc_data_structures::fx::FxHashSet; use rustc_feature::Features; use rustc_session::parse::ParseSess; @@ -41,18 +41,18 @@ pub(crate) struct InvalidCfgError { } impl Cfg { - /// Parses a `NestedMetaItem` into a `Cfg`. + /// Parses a `MetaItemInner` into a `Cfg`. fn parse_nested( - nested_cfg: &NestedMetaItem, + nested_cfg: &MetaItemInner, exclude: &FxHashSet, ) -> Result, InvalidCfgError> { match nested_cfg { - NestedMetaItem::MetaItem(ref cfg) => Cfg::parse_without(cfg, exclude), - NestedMetaItem::Lit(MetaItemLit { kind: LitKind::Bool(b), .. }) => match *b { + MetaItemInner::MetaItem(ref cfg) => Cfg::parse_without(cfg, exclude), + MetaItemInner::Lit(MetaItemLit { kind: LitKind::Bool(b), .. }) => match *b { true => Ok(Some(Cfg::True)), false => Ok(Some(Cfg::False)), }, - NestedMetaItem::Lit(ref lit) => { + MetaItemInner::Lit(ref lit) => { Err(InvalidCfgError { msg: "unexpected literal", span: lit.span }) } } @@ -124,7 +124,7 @@ impl Cfg { /// /// If the content is not properly formatted, it will return an error indicating what and where /// the error is. - pub(crate) fn parse(cfg: &NestedMetaItem) -> Result { + pub(crate) fn parse(cfg: &MetaItemInner) -> Result { Self::parse_nested(cfg, &FxHashSet::default()).map(|ret| ret.unwrap()) } diff --git a/src/librustdoc/clean/cfg/tests.rs b/src/librustdoc/clean/cfg/tests.rs index d4b11451c89..2c62e12c96d 100644 --- a/src/librustdoc/clean/cfg/tests.rs +++ b/src/librustdoc/clean/cfg/tests.rs @@ -1,5 +1,5 @@ use rustc_ast::ast::LitIntType; -use rustc_ast::{MetaItemLit, NestedMetaItem, Path, Safety, StrStyle}; +use rustc_ast::{MetaItemInner, MetaItemLit, Path, Safety, StrStyle}; use rustc_span::symbol::{Ident, kw}; use rustc_span::{DUMMY_SP, create_default_session_globals_then}; use thin_vec::thin_vec; @@ -14,12 +14,12 @@ fn name_value_cfg(name: &str, value: &str) -> Cfg { Cfg::Cfg(Symbol::intern(name), Some(Symbol::intern(value))) } -fn dummy_lit(symbol: Symbol, kind: LitKind) -> NestedMetaItem { - NestedMetaItem::Lit(MetaItemLit { symbol, suffix: None, kind, span: DUMMY_SP }) +fn dummy_lit(symbol: Symbol, kind: LitKind) -> MetaItemInner { + MetaItemInner::Lit(MetaItemLit { symbol, suffix: None, kind, span: DUMMY_SP }) } -fn dummy_meta_item_word(name: &str) -> NestedMetaItem { - NestedMetaItem::MetaItem(MetaItem { +fn dummy_meta_item_word(name: &str) -> MetaItemInner { + MetaItemInner::MetaItem(MetaItem { unsafety: Safety::Default, path: Path::from_ident(Ident::from_str(name)), kind: MetaItemKind::Word, @@ -27,9 +27,9 @@ fn dummy_meta_item_word(name: &str) -> NestedMetaItem { }) } -fn dummy_meta_item_name_value(name: &str, symbol: Symbol, kind: LitKind) -> NestedMetaItem { +fn dummy_meta_item_name_value(name: &str, symbol: Symbol, kind: LitKind) -> MetaItemInner { let lit = MetaItemLit { symbol, suffix: None, kind, span: DUMMY_SP }; - NestedMetaItem::MetaItem(MetaItem { + MetaItemInner::MetaItem(MetaItem { unsafety: Safety::Default, path: Path::from_ident(Ident::from_str(name)), kind: MetaItemKind::NameValue(lit), @@ -39,7 +39,7 @@ fn dummy_meta_item_name_value(name: &str, symbol: Symbol, kind: LitKind) -> Nest macro_rules! dummy_meta_item_list { ($name:ident, [$($list:ident),* $(,)?]) => { - NestedMetaItem::MetaItem(MetaItem { + MetaItemInner::MetaItem(MetaItem { unsafety: Safety::Default, path: Path::from_ident(Ident::from_str(stringify!($name))), kind: MetaItemKind::List(thin_vec![ @@ -52,7 +52,7 @@ macro_rules! dummy_meta_item_list { }; ($name:ident, [$($list:expr),* $(,)?]) => { - NestedMetaItem::MetaItem(MetaItem { + MetaItemInner::MetaItem(MetaItem { unsafety: Safety::Default, path: Path::from_ident(Ident::from_str(stringify!($name))), kind: MetaItemKind::List(thin_vec![ diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index ec31a51a81e..5e43dfc7bcc 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -5,7 +5,7 @@ use std::sync::{Arc, OnceLock as OnceCell}; use std::{fmt, iter}; use arrayvec::ArrayVec; -use rustc_ast::NestedMetaItem; +use rustc_ast::MetaItemInner; use rustc_ast_pretty::pprust; use rustc_attr::{ConstStability, Deprecation, Stability, StableSince}; use rustc_const_eval::const_eval::is_unstable_const_fn; @@ -953,7 +953,7 @@ pub(crate) struct Module { } pub(crate) trait AttributesExt { - type AttributeIterator<'a>: Iterator + type AttributeIterator<'a>: Iterator where Self: 'a; type Attributes<'a>: Iterator @@ -1043,7 +1043,7 @@ pub(crate) trait AttributesExt { let mut meta = attr.meta_item().unwrap().clone(); meta.path = ast::Path::from_ident(Ident::with_dummy_span(sym::target_feature)); - if let Ok(feat_cfg) = Cfg::parse(&NestedMetaItem::MetaItem(meta)) { + if let Ok(feat_cfg) = Cfg::parse(&MetaItemInner::MetaItem(meta)) { cfg &= feat_cfg; } } @@ -1055,7 +1055,7 @@ pub(crate) trait AttributesExt { } impl AttributesExt for [ast::Attribute] { - type AttributeIterator<'a> = impl Iterator + 'a; + type AttributeIterator<'a> = impl Iterator + 'a; type Attributes<'a> = impl Iterator + 'a; fn lists(&self, name: Symbol) -> Self::AttributeIterator<'_> { @@ -1072,7 +1072,7 @@ impl AttributesExt for [ast::Attribute] { impl AttributesExt for [(Cow<'_, ast::Attribute>, Option)] { type AttributeIterator<'a> - = impl Iterator + 'a + = impl Iterator + 'a where Self: 'a; type Attributes<'a> @@ -1106,11 +1106,11 @@ pub(crate) trait NestedAttributesExt { /// Returns `Some(attr)` if the attribute list contains 'attr' /// corresponding to a specific `word` - fn get_word_attr(self, word: Symbol) -> Option; + fn get_word_attr(self, word: Symbol) -> Option; } -impl> NestedAttributesExt for I { - fn get_word_attr(mut self, word: Symbol) -> Option { +impl> NestedAttributesExt for I { + fn get_word_attr(mut self, word: Symbol) -> Option { self.find(|attr| attr.is_word() && attr.has_name(word)) } } @@ -1157,7 +1157,7 @@ pub(crate) struct Attributes { } impl Attributes { - pub(crate) fn lists(&self, name: Symbol) -> impl Iterator + '_ { + pub(crate) fn lists(&self, name: Symbol) -> impl Iterator + '_ { self.other_attrs.lists(name) } diff --git a/src/tools/clippy/clippy_lints/src/attrs/allow_attributes_without_reason.rs b/src/tools/clippy/clippy_lints/src/attrs/allow_attributes_without_reason.rs index 40959eccd3a..5d4e864b9b0 100644 --- a/src/tools/clippy/clippy_lints/src/attrs/allow_attributes_without_reason.rs +++ b/src/tools/clippy/clippy_lints/src/attrs/allow_attributes_without_reason.rs @@ -1,15 +1,15 @@ use super::{ALLOW_ATTRIBUTES_WITHOUT_REASON, Attribute}; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::is_from_proc_macro; -use rustc_ast::{MetaItemKind, NestedMetaItem}; +use rustc_ast::{MetaItemInner, MetaItemKind}; use rustc_lint::{LateContext, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_span::sym; use rustc_span::symbol::Symbol; -pub(super) fn check<'cx>(cx: &LateContext<'cx>, name: Symbol, items: &[NestedMetaItem], attr: &'cx Attribute) { +pub(super) fn check<'cx>(cx: &LateContext<'cx>, name: Symbol, items: &[MetaItemInner], attr: &'cx Attribute) { // Check if the reason is present - if let Some(item) = items.last().and_then(NestedMetaItem::meta_item) + if let Some(item) = items.last().and_then(MetaItemInner::meta_item) && let MetaItemKind::NameValue(_) = &item.kind && item.path == sym::reason { diff --git a/src/tools/clippy/clippy_lints/src/attrs/blanket_clippy_restriction_lints.rs b/src/tools/clippy/clippy_lints/src/attrs/blanket_clippy_restriction_lints.rs index 508963a20ea..0baf889faa0 100644 --- a/src/tools/clippy/clippy_lints/src/attrs/blanket_clippy_restriction_lints.rs +++ b/src/tools/clippy/clippy_lints/src/attrs/blanket_clippy_restriction_lints.rs @@ -1,12 +1,12 @@ use super::BLANKET_CLIPPY_RESTRICTION_LINTS; use super::utils::extract_clippy_lint; use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_then}; -use rustc_ast::NestedMetaItem; +use rustc_ast::MetaItemInner; use rustc_lint::{LateContext, Level, LintContext}; use rustc_span::symbol::Symbol; use rustc_span::{DUMMY_SP, sym}; -pub(super) fn check(cx: &LateContext<'_>, name: Symbol, items: &[NestedMetaItem]) { +pub(super) fn check(cx: &LateContext<'_>, name: Symbol, items: &[MetaItemInner]) { for lint in items { if let Some(lint_name) = extract_clippy_lint(lint) { if lint_name.as_str() == "restriction" && name != sym::allow { diff --git a/src/tools/clippy/clippy_lints/src/attrs/mod.rs b/src/tools/clippy/clippy_lints/src/attrs/mod.rs index 888f28fa225..1a34ca99fc2 100644 --- a/src/tools/clippy/clippy_lints/src/attrs/mod.rs +++ b/src/tools/clippy/clippy_lints/src/attrs/mod.rs @@ -14,7 +14,7 @@ mod utils; use clippy_config::Conf; use clippy_config::msrvs::{self, Msrv}; -use rustc_ast::{Attribute, MetaItemKind, NestedMetaItem}; +use rustc_ast::{Attribute, MetaItemInner, MetaItemKind}; use rustc_hir::{ImplItem, Item, ItemKind, TraitItem}; use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass}; use rustc_session::impl_lint_pass; @@ -456,7 +456,7 @@ impl<'tcx> LateLintPass<'tcx> for Attributes { return; } for item in items { - if let NestedMetaItem::MetaItem(mi) = &item + if let MetaItemInner::MetaItem(mi) = &item && let MetaItemKind::NameValue(lit) = &mi.kind && mi.has_name(sym::since) { diff --git a/src/tools/clippy/clippy_lints/src/attrs/non_minimal_cfg.rs b/src/tools/clippy/clippy_lints/src/attrs/non_minimal_cfg.rs index 877025cce4c..7eff5eccfa1 100644 --- a/src/tools/clippy/clippy_lints/src/attrs/non_minimal_cfg.rs +++ b/src/tools/clippy/clippy_lints/src/attrs/non_minimal_cfg.rs @@ -1,7 +1,7 @@ use super::{Attribute, NON_MINIMAL_CFG}; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::SpanRangeExt; -use rustc_ast::{MetaItemKind, NestedMetaItem}; +use rustc_ast::{MetaItemInner, MetaItemKind}; use rustc_errors::Applicability; use rustc_lint::EarlyContext; use rustc_span::sym; @@ -14,9 +14,9 @@ pub(super) fn check(cx: &EarlyContext<'_>, attr: &Attribute) { } } -fn check_nested_cfg(cx: &EarlyContext<'_>, items: &[NestedMetaItem]) { +fn check_nested_cfg(cx: &EarlyContext<'_>, items: &[MetaItemInner]) { for item in items { - if let NestedMetaItem::MetaItem(meta) = item { + if let MetaItemInner::MetaItem(meta) = item { if !meta.has_name(sym::any) && !meta.has_name(sym::all) { continue; } diff --git a/src/tools/clippy/clippy_lints/src/attrs/useless_attribute.rs b/src/tools/clippy/clippy_lints/src/attrs/useless_attribute.rs index 12668c616c1..72e6ce59d59 100644 --- a/src/tools/clippy/clippy_lints/src/attrs/useless_attribute.rs +++ b/src/tools/clippy/clippy_lints/src/attrs/useless_attribute.rs @@ -2,7 +2,7 @@ use super::utils::{extract_clippy_lint, is_lint_level, is_word}; use super::{Attribute, USELESS_ATTRIBUTE}; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::{SpanRangeExt, first_line_of_span}; -use rustc_ast::NestedMetaItem; +use rustc_ast::MetaItemInner; use rustc_errors::Applicability; use rustc_hir::{Item, ItemKind}; use rustc_lint::{LateContext, LintContext}; @@ -21,7 +21,7 @@ pub(super) fn check(cx: &LateContext<'_>, item: &Item<'_>, attrs: &[Attribute]) for lint in lint_list { match item.kind { ItemKind::Use(..) => { - if let NestedMetaItem::MetaItem(meta_item) = lint + if let MetaItemInner::MetaItem(meta_item) = lint && meta_item.is_word() && let Some(ident) = meta_item.ident() && matches!( diff --git a/src/tools/clippy/clippy_lints/src/attrs/utils.rs b/src/tools/clippy/clippy_lints/src/attrs/utils.rs index 91ae19acbf7..9b10ae83651 100644 --- a/src/tools/clippy/clippy_lints/src/attrs/utils.rs +++ b/src/tools/clippy/clippy_lints/src/attrs/utils.rs @@ -1,5 +1,5 @@ use clippy_utils::macros::{is_panic, macro_backtrace}; -use rustc_ast::{AttrId, NestedMetaItem}; +use rustc_ast::{AttrId, MetaItemInner}; use rustc_hir::{ Block, Expr, ExprKind, ImplItem, ImplItemKind, Item, ItemKind, StmtKind, TraitFn, TraitItem, TraitItemKind, }; @@ -8,8 +8,8 @@ use rustc_middle::ty; use rustc_span::sym; use rustc_span::symbol::Symbol; -pub(super) fn is_word(nmi: &NestedMetaItem, expected: Symbol) -> bool { - if let NestedMetaItem::MetaItem(mi) = &nmi { +pub(super) fn is_word(nmi: &MetaItemInner, expected: Symbol) -> bool { + if let MetaItemInner::MetaItem(mi) = &nmi { mi.is_word() && mi.has_name(expected) } else { false @@ -74,7 +74,7 @@ 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: &NestedMetaItem) -> Option { +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 diff --git a/src/tools/clippy/clippy_lints/src/cfg_not_test.rs b/src/tools/clippy/clippy_lints/src/cfg_not_test.rs index 884d15cabff..84136a2e6c2 100644 --- a/src/tools/clippy/clippy_lints/src/cfg_not_test.rs +++ b/src/tools/clippy/clippy_lints/src/cfg_not_test.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_then; -use rustc_ast::NestedMetaItem; +use rustc_ast::MetaItemInner; use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_session::declare_lint_pass; @@ -47,7 +47,7 @@ impl EarlyLintPass for CfgNotTest { } } -fn contains_not_test(list: Option<&[NestedMetaItem]>, not: bool) -> bool { +fn contains_not_test(list: Option<&[MetaItemInner]>, not: bool) -> bool { list.is_some_and(|list| { list.iter().any(|item| { item.ident().is_some_and(|ident| match ident.name { diff --git a/src/tools/clippy/clippy_lints/src/returns.rs b/src/tools/clippy/clippy_lints/src/returns.rs index 1f223048ce5..f6f75d8c798 100644 --- a/src/tools/clippy/clippy_lints/src/returns.rs +++ b/src/tools/clippy/clippy_lints/src/returns.rs @@ -7,7 +7,7 @@ use clippy_utils::{ path_to_local_id, span_contains_cfg, span_find_starting_semi, }; use core::ops::ControlFlow; -use rustc_ast::NestedMetaItem; +use rustc_ast::MetaItemInner; use rustc_errors::Applicability; use rustc_hir::LangItem::ResultErr; use rustc_hir::intravisit::FnKind; @@ -421,7 +421,7 @@ fn check_final_expr<'tcx>( if matches!(Level::from_attr(attr), Some(Level::Expect(_))) && let metas = attr.meta_item_list() && let Some(lst) = metas - && let [NestedMetaItem::MetaItem(meta_item), ..] = lst.as_slice() + && let [MetaItemInner::MetaItem(meta_item), ..] = lst.as_slice() && let [tool, lint_name] = meta_item.path.segments.as_slice() && tool.ident.name == sym::clippy && matches!( diff --git a/src/tools/rustfmt/src/attr.rs b/src/tools/rustfmt/src/attr.rs index 5c2068b6a22..ad425d0bff7 100644 --- a/src/tools/rustfmt/src/attr.rs +++ b/src/tools/rustfmt/src/attr.rs @@ -243,17 +243,15 @@ fn rewrite_initial_doc_comments( Ok((0, None)) } -impl Rewrite for ast::NestedMetaItem { +impl Rewrite for ast::MetaItemInner { fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option { self.rewrite_result(context, shape).ok() } fn rewrite_result(&self, context: &RewriteContext<'_>, shape: Shape) -> RewriteResult { match self { - ast::NestedMetaItem::MetaItem(ref meta_item) => { - meta_item.rewrite_result(context, shape) - } - ast::NestedMetaItem::Lit(ref l) => { + ast::MetaItemInner::MetaItem(ref meta_item) => meta_item.rewrite_result(context, shape), + ast::MetaItemInner::Lit(ref l) => { rewrite_literal(context, l.as_token_lit(), l.span, shape) } } @@ -535,7 +533,7 @@ pub(crate) trait MetaVisitor<'ast> { fn visit_meta_list( &mut self, _meta_item: &'ast ast::MetaItem, - list: &'ast [ast::NestedMetaItem], + list: &'ast [ast::MetaItemInner], ) { for nm in list { self.visit_nested_meta_item(nm); @@ -551,10 +549,10 @@ pub(crate) trait MetaVisitor<'ast> { ) { } - fn visit_nested_meta_item(&mut self, nm: &'ast ast::NestedMetaItem) { + fn visit_nested_meta_item(&mut self, nm: &'ast ast::MetaItemInner) { match nm { - ast::NestedMetaItem::MetaItem(ref meta_item) => self.visit_meta_item(meta_item), - ast::NestedMetaItem::Lit(ref lit) => self.visit_meta_item_lit(lit), + ast::MetaItemInner::MetaItem(ref meta_item) => self.visit_meta_item(meta_item), + ast::MetaItemInner::Lit(ref lit) => self.visit_meta_item_lit(lit), } } diff --git a/src/tools/rustfmt/src/overflow.rs b/src/tools/rustfmt/src/overflow.rs index fdc8e23e72b..3f44789bafd 100644 --- a/src/tools/rustfmt/src/overflow.rs +++ b/src/tools/rustfmt/src/overflow.rs @@ -78,7 +78,7 @@ pub(crate) enum OverflowableItem<'a> { Expr(&'a ast::Expr), GenericParam(&'a ast::GenericParam), MacroArg(&'a MacroArg), - NestedMetaItem(&'a ast::NestedMetaItem), + MetaItemInner(&'a ast::MetaItemInner), SegmentParam(&'a SegmentParam<'a>), FieldDef(&'a ast::FieldDef), TuplePatField(&'a TuplePatField<'a>), @@ -123,7 +123,7 @@ impl<'a> OverflowableItem<'a> { OverflowableItem::Expr(expr) => f(*expr), OverflowableItem::GenericParam(gp) => f(*gp), OverflowableItem::MacroArg(macro_arg) => f(*macro_arg), - OverflowableItem::NestedMetaItem(nmi) => f(*nmi), + OverflowableItem::MetaItemInner(nmi) => f(*nmi), OverflowableItem::SegmentParam(sp) => f(*sp), OverflowableItem::FieldDef(sf) => f(*sf), OverflowableItem::TuplePatField(pat) => f(*pat), @@ -138,9 +138,9 @@ impl<'a> OverflowableItem<'a> { OverflowableItem::Expr(expr) => is_simple_expr(expr), OverflowableItem::MacroArg(MacroArg::Keyword(..)) => true, OverflowableItem::MacroArg(MacroArg::Expr(expr)) => is_simple_expr(expr), - OverflowableItem::NestedMetaItem(nested_meta_item) => match nested_meta_item { - ast::NestedMetaItem::Lit(..) => true, - ast::NestedMetaItem::MetaItem(ref meta_item) => { + OverflowableItem::MetaItemInner(nested_meta_item) => match nested_meta_item { + ast::MetaItemInner::Lit(..) => true, + ast::MetaItemInner::MetaItem(ref meta_item) => { matches!(meta_item.kind, ast::MetaItemKind::Word) } }, @@ -184,12 +184,11 @@ impl<'a> OverflowableItem<'a> { MacroArg::Item(..) => len == 1, MacroArg::Keyword(..) => false, }, - OverflowableItem::NestedMetaItem(nested_meta_item) if len == 1 => { - match nested_meta_item { - ast::NestedMetaItem::Lit(..) => false, - ast::NestedMetaItem::MetaItem(..) => true, - } - } + OverflowableItem::MetaItemInner(nested_meta_item) if len == 1 => match nested_meta_item + { + ast::MetaItemInner::Lit(..) => false, + ast::MetaItemInner::MetaItem(..) => true, + }, OverflowableItem::SegmentParam(SegmentParam::Type(ty)) => { can_be_overflowed_type(context, ty, len) } @@ -202,7 +201,7 @@ impl<'a> OverflowableItem<'a> { fn special_cases(&self, config: &Config) -> impl Iterator { let base_cases = match self { OverflowableItem::MacroArg(..) => SPECIAL_CASE_MACROS, - OverflowableItem::NestedMetaItem(..) => SPECIAL_CASE_ATTR, + OverflowableItem::MetaItemInner(..) => SPECIAL_CASE_ATTR, _ => &[], }; let additional_cases = match self { @@ -261,7 +260,7 @@ macro_rules! impl_into_overflowable_item_for_rustfmt_types { impl_into_overflowable_item_for_ast_node!( Expr, GenericParam, - NestedMetaItem, + MetaItemInner, FieldDef, Ty, Pat, diff --git a/src/tools/rustfmt/src/spanned.rs b/src/tools/rustfmt/src/spanned.rs index b4424e476ee..555a9240798 100644 --- a/src/tools/rustfmt/src/spanned.rs +++ b/src/tools/rustfmt/src/spanned.rs @@ -199,7 +199,7 @@ impl Spanned for MacroArg { } } -impl Spanned for ast::NestedMetaItem { +impl Spanned for ast::MetaItemInner { fn span(&self) -> Span { self.span() } diff --git a/src/tools/rustfmt/src/utils.rs b/src/tools/rustfmt/src/utils.rs index d1cfc6acc49..0ca34a79491 100644 --- a/src/tools/rustfmt/src/utils.rs +++ b/src/tools/rustfmt/src/utils.rs @@ -1,7 +1,7 @@ use std::borrow::Cow; use rustc_ast::ast::{ - self, Attribute, MetaItem, MetaItemKind, NestedMetaItem, NodeId, Path, Visibility, + self, Attribute, MetaItem, MetaItemInner, MetaItemKind, NodeId, Path, Visibility, VisibilityKind, }; use rustc_ast::ptr; @@ -257,10 +257,10 @@ fn is_skip(meta_item: &MetaItem) -> bool { } #[inline] -fn is_skip_nested(meta_item: &NestedMetaItem) -> bool { +fn is_skip_nested(meta_item: &MetaItemInner) -> bool { match meta_item { - NestedMetaItem::MetaItem(ref mi) => is_skip(mi), - NestedMetaItem::Lit(_) => false, + MetaItemInner::MetaItem(ref mi) => is_skip(mi), + MetaItemInner::Lit(_) => false, } } From dd0bcf5185c540508b318079cde03aa67e205f32 Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Sun, 6 Oct 2024 18:59:40 +0300 Subject: [PATCH 623/683] Revert "Auto merge of #130121 - lolbinarycat:bootstrap-warn-old-upstream-worktree, r=albertlarsan68" This reverts commit 507c05bead4026ed8841512095b4218119eb479f, reversing changes made to 0609062a91c8f445c3e9a0de57e402f9b1b8b0a7. --- src/bootstrap/src/core/sanity.rs | 10 ++++- src/tools/build_helper/src/git.rs | 62 ++++++++----------------------- 2 files changed, 25 insertions(+), 47 deletions(-) diff --git a/src/bootstrap/src/core/sanity.rs b/src/bootstrap/src/core/sanity.rs index 11260f87d00..e9f03352ff3 100644 --- a/src/bootstrap/src/core/sanity.rs +++ b/src/bootstrap/src/core/sanity.rs @@ -383,5 +383,13 @@ $ pacman -R cmake && pacman -S mingw-w64-x86_64-cmake cmd_finder.must_have(s); } - warn_old_master_branch(&build.config.git_config(), &build.config.src); + // this warning is useless in CI, + // and CI probably won't have the right branches anyway. + if !build_helper::ci::CiEnv::is_ci() { + if let Err(e) = warn_old_master_branch(&build.config.git_config(), &build.config.src) + .map_err(|e| e.to_string()) + { + eprintln!("unable to check if upstream branch is old: {e}"); + } + } } diff --git a/src/tools/build_helper/src/git.rs b/src/tools/build_helper/src/git.rs index 10c5476cd8f..15d863caf0c 100644 --- a/src/tools/build_helper/src/git.rs +++ b/src/tools/build_helper/src/git.rs @@ -204,20 +204,21 @@ pub fn get_git_untracked_files( /// /// This can result in formatting thousands of files instead of a dozen, /// so we should warn the user something is wrong. -pub fn warn_old_master_branch(config: &GitConfig<'_>, git_dir: &Path) { - if crate::ci::CiEnv::is_ci() { - // this warning is useless in CI, - // and CI probably won't have the right branches anyway. - return; - } - // this will be overwritten by the actual name, if possible - let mut updated_master = "the upstream master branch".to_string(); - match warn_old_master_branch_(config, git_dir, &mut updated_master) { - Ok(branch_is_old) => { - if !branch_is_old { - return; +pub fn warn_old_master_branch( + config: &GitConfig<'_>, + git_dir: &Path, +) -> Result<(), Box> { + use std::time::Duration; + const WARN_AFTER: Duration = Duration::from_secs(60 * 60 * 24 * 10); + let updated_master = updated_master_branch(config, Some(git_dir))?; + let branch_path = git_dir.join(".git/refs/remotes").join(&updated_master); + match std::fs::metadata(branch_path) { + Ok(meta) => { + if meta.modified()?.elapsed()? > WARN_AFTER { + eprintln!("warning: {updated_master} has not been updated in 10 days"); + } else { + return Ok(()); } - // otherwise fall through and print the rest of the warning } Err(err) => { eprintln!("warning: unable to check if {updated_master} is old due to error: {err}") @@ -225,38 +226,7 @@ pub fn warn_old_master_branch(config: &GitConfig<'_>, git_dir: &Path) { } eprintln!( "warning: {updated_master} is used to determine if files have been modified\n\ - warning: if it is not updated, this may cause files to be needlessly reformatted" + warning: if it is not updated, this may cause files to be needlessly reformatted" ); -} - -pub fn warn_old_master_branch_( - config: &GitConfig<'_>, - git_dir: &Path, - updated_master: &mut String, -) -> Result> { - use std::time::Duration; - *updated_master = updated_master_branch(config, Some(git_dir))?; - let branch_path = git_dir.join(".git/refs/remotes").join(&updated_master); - const WARN_AFTER: Duration = Duration::from_secs(60 * 60 * 24 * 10); - let meta = match std::fs::metadata(&branch_path) { - Ok(meta) => meta, - Err(err) => { - let gcd = git_common_dir(&git_dir)?; - if branch_path.starts_with(&gcd) { - return Err(Box::new(err)); - } - std::fs::metadata(Path::new(&gcd).join("refs/remotes").join(&updated_master))? - } - }; - if meta.modified()?.elapsed()? > WARN_AFTER { - eprintln!("warning: {updated_master} has not been updated in 10 days"); - Ok(true) - } else { - Ok(false) - } -} - -fn git_common_dir(dir: &Path) -> Result { - output_result(Command::new("git").arg("-C").arg(dir).arg("rev-parse").arg("--git-common-dir")) - .map(|x| x.trim().to_string()) + Ok(()) } From 1e5c4cb0a2a4ef588598eb63f7d56b6dfe9296d4 Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Sun, 6 Oct 2024 19:01:12 +0300 Subject: [PATCH 624/683] Revert "Rollup merge of #129584 - lolbinarycat:old-upstream-warning, r=albertlarsan68" This reverts commit 776187d2c9a42dc07452ae36a8b765d66bd8e2ca, reversing changes made to 7d015575ada1de8a4627fcdea416194a57a175c2. --- src/bootstrap/src/core/build_steps/format.rs | 1 + src/bootstrap/src/core/sanity.rs | 12 ------- src/tools/build_helper/src/git.rs | 34 -------------------- 3 files changed, 1 insertion(+), 46 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/format.rs b/src/bootstrap/src/core/build_steps/format.rs index 952d8d73328..5ca4321d855 100644 --- a/src/bootstrap/src/core/build_steps/format.rs +++ b/src/bootstrap/src/core/build_steps/format.rs @@ -93,6 +93,7 @@ fn get_modified_rs_files(build: &Builder<'_>) -> Result>, Str if !verify_rustfmt_version(build) { return Ok(None); } + get_git_modified_files(&build.config.git_config(), Some(&build.config.src), &["rs"]) } diff --git a/src/bootstrap/src/core/sanity.rs b/src/bootstrap/src/core/sanity.rs index e9f03352ff3..6fbdd76ed5b 100644 --- a/src/bootstrap/src/core/sanity.rs +++ b/src/bootstrap/src/core/sanity.rs @@ -13,8 +13,6 @@ use std::ffi::{OsStr, OsString}; use std::path::PathBuf; use std::{env, fs}; -use build_helper::git::warn_old_master_branch; - use crate::Build; #[cfg(not(feature = "bootstrap-self-test"))] use crate::builder::Builder; @@ -382,14 +380,4 @@ $ pacman -R cmake && pacman -S mingw-w64-x86_64-cmake if let Some(ref s) = build.config.ccache { cmd_finder.must_have(s); } - - // this warning is useless in CI, - // and CI probably won't have the right branches anyway. - if !build_helper::ci::CiEnv::is_ci() { - if let Err(e) = warn_old_master_branch(&build.config.git_config(), &build.config.src) - .map_err(|e| e.to_string()) - { - eprintln!("unable to check if upstream branch is old: {e}"); - } - } } diff --git a/src/tools/build_helper/src/git.rs b/src/tools/build_helper/src/git.rs index 15d863caf0c..1e28d552fe6 100644 --- a/src/tools/build_helper/src/git.rs +++ b/src/tools/build_helper/src/git.rs @@ -196,37 +196,3 @@ pub fn get_git_untracked_files( .collect(); Ok(Some(files)) } - -/// Print a warning if the branch returned from `updated_master_branch` is old -/// -/// For certain configurations of git repository, this remote will not be -/// updated when running `git pull`. -/// -/// This can result in formatting thousands of files instead of a dozen, -/// so we should warn the user something is wrong. -pub fn warn_old_master_branch( - config: &GitConfig<'_>, - git_dir: &Path, -) -> Result<(), Box> { - use std::time::Duration; - const WARN_AFTER: Duration = Duration::from_secs(60 * 60 * 24 * 10); - let updated_master = updated_master_branch(config, Some(git_dir))?; - let branch_path = git_dir.join(".git/refs/remotes").join(&updated_master); - match std::fs::metadata(branch_path) { - Ok(meta) => { - if meta.modified()?.elapsed()? > WARN_AFTER { - eprintln!("warning: {updated_master} has not been updated in 10 days"); - } else { - return Ok(()); - } - } - Err(err) => { - eprintln!("warning: unable to check if {updated_master} is old due to error: {err}") - } - } - eprintln!( - "warning: {updated_master} is used to determine if files have been modified\n\ - warning: if it is not updated, this may cause files to be needlessly reformatted" - ); - Ok(()) -} From aa5bbf05f424ae7bfb2bd859141c7e8553120d87 Mon Sep 17 00:00:00 2001 From: Folkert Date: Sun, 4 Aug 2024 16:42:37 +0200 Subject: [PATCH 625/683] implement `naked_asm` macro --- compiler/rustc_builtin_macros/messages.ftl | 24 +-- compiler/rustc_builtin_macros/src/asm.rs | 159 ++++++++++++++------ compiler/rustc_builtin_macros/src/errors.rs | 27 ++-- library/core/src/arch.rs | 14 ++ src/tools/rustfmt/src/parse/macros/asm.rs | 4 +- 5 files changed, 160 insertions(+), 68 deletions(-) diff --git a/compiler/rustc_builtin_macros/messages.ftl b/compiler/rustc_builtin_macros/messages.ftl index 9695df9c87e..b25892242b5 100644 --- a/compiler/rustc_builtin_macros/messages.ftl +++ b/compiler/rustc_builtin_macros/messages.ftl @@ -12,9 +12,9 @@ builtin_macros_asm_duplicate_arg = duplicate argument named `{$name}` builtin_macros_asm_expected_comma = expected token: `,` .label = expected `,` -builtin_macros_asm_expected_other = expected operand, {$is_global_asm -> - [true] options - *[false] clobber_abi, options +builtin_macros_asm_expected_other = expected operand, {$is_inline_asm -> + [false] options + *[true] clobber_abi, options }, or additional template string builtin_macros_asm_expected_string_literal = expected string literal @@ -51,6 +51,15 @@ builtin_macros_asm_sym_no_path = expected a path for argument to `sym` builtin_macros_asm_underscore_input = _ cannot be used for input operands +builtin_macros_asm_unsupported_clobber_abi = `clobber_abi` cannot be used with `{$macro_name}!` + +builtin_macros_asm_unsupported_operand = the `{$symbol}` operand cannot be used with `{$macro_name}!` + .label = the `{$symbol}` operand is not meaningful for global-scoped inline assembly, remove it + +builtin_macros_asm_unsupported_option = the `{$symbol}` option cannot be used with `{$macro_name}!` + .label = the `{$symbol}` option is not meaningful for global-scoped inline assembly + .suggestion = remove this option + builtin_macros_assert_missing_comma = unexpected string literal .suggestion = try adding a comma @@ -194,15 +203,6 @@ builtin_macros_format_unused_args = multiple unused formatting arguments builtin_macros_format_use_positional = consider using a positional formatting argument instead -builtin_macros_global_asm_clobber_abi = `clobber_abi` cannot be used with `global_asm!` - -builtin_macros_global_asm_unsupported_operand = the `{$symbol}` operand cannot be used with `global_asm!` - .label = the `{$symbol}` operand is not meaningful for global-scoped inline assembly, remove it - -builtin_macros_global_asm_unsupported_option = the `{$symbol}` option cannot be used with `global_asm!` - .label = the `{$symbol}` option is not meaningful for global-scoped inline assembly - .suggestion = remove this option - builtin_macros_invalid_crate_attribute = invalid crate attribute builtin_macros_multiple_default_attrs = multiple `#[default]` attributes diff --git a/compiler/rustc_builtin_macros/src/asm.rs b/compiler/rustc_builtin_macros/src/asm.rs index 75dbb3d8e6a..2019c42e296 100644 --- a/compiler/rustc_builtin_macros/src/asm.rs +++ b/compiler/rustc_builtin_macros/src/asm.rs @@ -37,29 +37,66 @@ pub struct AsmArgs { /// - `Ok(true)` if the current token matches the keyword, and was expected /// - `Ok(false)` if the current token does not match the keyword /// - `Err(_)` if the current token matches the keyword, but was not expected -fn eat_operand_keyword<'a>(p: &mut Parser<'a>, symbol: Symbol, expect: bool) -> PResult<'a, bool> { - if expect { +fn eat_operand_keyword<'a>( + p: &mut Parser<'a>, + symbol: Symbol, + asm_macro: AsmMacro, +) -> PResult<'a, bool> { + if matches!(asm_macro, AsmMacro::Asm) { Ok(p.eat_keyword(symbol)) } else { let span = p.token.span; if p.eat_keyword_noexpect(symbol) { // in gets printed as `r#in` otherwise let symbol = if symbol == kw::In { "in" } else { symbol.as_str() }; - Err(p.dcx().create_err(errors::GlobalAsmUnsupportedOperand { span, symbol })) + Err(p.dcx().create_err(errors::AsmUnsupportedOperand { + span, + symbol, + macro_name: asm_macro.macro_name(), + })) } else { Ok(false) } } } +// Public for rustfmt consumption. +#[derive(Copy, Clone)] +pub enum AsmMacro { + /// The `asm!` macro + Asm, + /// The `global_asm!` macro + GlobalAsm, + /// The `naked_asm!` macro + NakedAsm, +} + +impl AsmMacro { + const fn macro_name(&self) -> &'static str { + match self { + AsmMacro::Asm => "asm", + AsmMacro::GlobalAsm => "global_asm", + AsmMacro::NakedAsm => "naked_asm", + } + } + + const fn is_supported_option(&self, option: ast::InlineAsmOptions) -> bool { + match self { + AsmMacro::Asm => true, + AsmMacro::GlobalAsm => ast::InlineAsmOptions::GLOBAL_OPTIONS.contains(option), + AsmMacro::NakedAsm => ast::InlineAsmOptions::NAKED_OPTIONS.contains(option), + } + } +} + fn parse_args<'a>( ecx: &ExtCtxt<'a>, sp: Span, tts: TokenStream, - is_global_asm: bool, + asm_macro: AsmMacro, ) -> PResult<'a, AsmArgs> { let mut p = ecx.new_parser_from_tts(tts); - parse_asm_args(&mut p, sp, is_global_asm) + parse_asm_args(&mut p, sp, asm_macro) } // Primarily public for rustfmt consumption. @@ -67,7 +104,7 @@ fn parse_args<'a>( pub fn parse_asm_args<'a>( p: &mut Parser<'a>, sp: Span, - is_global_asm: bool, + asm_macro: AsmMacro, ) -> PResult<'a, AsmArgs> { let dcx = p.dcx(); @@ -110,7 +147,7 @@ pub fn parse_asm_args<'a>( // Parse options if p.eat_keyword(sym::options) { - parse_options(p, &mut args, is_global_asm)?; + parse_options(p, &mut args, asm_macro)?; allow_templates = false; continue; } @@ -129,7 +166,7 @@ pub fn parse_asm_args<'a>( }; let mut explicit_reg = false; - let op = if eat_operand_keyword(p, kw::In, !is_global_asm)? { + let op = if eat_operand_keyword(p, kw::In, asm_macro)? { let reg = parse_reg(p, &mut explicit_reg)?; if p.eat_keyword(kw::Underscore) { let err = dcx.create_err(errors::AsmUnderscoreInput { span: p.token.span }); @@ -137,15 +174,15 @@ pub fn parse_asm_args<'a>( } let expr = p.parse_expr()?; ast::InlineAsmOperand::In { reg, expr } - } else if eat_operand_keyword(p, sym::out, !is_global_asm)? { + } else if eat_operand_keyword(p, sym::out, asm_macro)? { let reg = parse_reg(p, &mut explicit_reg)?; let expr = if p.eat_keyword(kw::Underscore) { None } else { Some(p.parse_expr()?) }; ast::InlineAsmOperand::Out { reg, expr, late: false } - } else if eat_operand_keyword(p, sym::lateout, !is_global_asm)? { + } else if eat_operand_keyword(p, sym::lateout, asm_macro)? { let reg = parse_reg(p, &mut explicit_reg)?; let expr = if p.eat_keyword(kw::Underscore) { None } else { Some(p.parse_expr()?) }; ast::InlineAsmOperand::Out { reg, expr, late: true } - } else if eat_operand_keyword(p, sym::inout, !is_global_asm)? { + } else if eat_operand_keyword(p, sym::inout, asm_macro)? { let reg = parse_reg(p, &mut explicit_reg)?; if p.eat_keyword(kw::Underscore) { let err = dcx.create_err(errors::AsmUnderscoreInput { span: p.token.span }); @@ -159,7 +196,7 @@ pub fn parse_asm_args<'a>( } else { ast::InlineAsmOperand::InOut { reg, expr, late: false } } - } else if eat_operand_keyword(p, sym::inlateout, !is_global_asm)? { + } else if eat_operand_keyword(p, sym::inlateout, asm_macro)? { let reg = parse_reg(p, &mut explicit_reg)?; if p.eat_keyword(kw::Underscore) { let err = dcx.create_err(errors::AsmUnderscoreInput { span: p.token.span }); @@ -173,7 +210,7 @@ pub fn parse_asm_args<'a>( } else { ast::InlineAsmOperand::InOut { reg, expr, late: true } } - } else if eat_operand_keyword(p, sym::label, !is_global_asm)? { + } else if eat_operand_keyword(p, sym::label, asm_macro)? { let block = p.parse_block()?; ast::InlineAsmOperand::Label { block } } else if p.eat_keyword(kw::Const) { @@ -205,7 +242,7 @@ pub fn parse_asm_args<'a>( _ => { let err = dcx.create_err(errors::AsmExpectedOther { span: template.span, - is_global_asm, + is_inline_asm: matches!(asm_macro, AsmMacro::Asm), }); return Err(err); } @@ -301,20 +338,25 @@ pub fn parse_asm_args<'a>( dcx.emit_err(errors::AsmMayUnwind { labels_sp }); } - if args.clobber_abis.len() > 0 { - if is_global_asm { - let err = dcx.create_err(errors::GlobalAsmClobberAbi { - spans: args.clobber_abis.iter().map(|(_, span)| *span).collect(), - }); + if !args.clobber_abis.is_empty() { + match asm_macro { + AsmMacro::GlobalAsm | AsmMacro::NakedAsm => { + let err = dcx.create_err(errors::AsmUnsupportedClobberAbi { + spans: args.clobber_abis.iter().map(|(_, span)| *span).collect(), + macro_name: asm_macro.macro_name(), + }); - // Bail out now since this is likely to confuse later stages - return Err(err); - } - if !regclass_outputs.is_empty() { - dcx.emit_err(errors::AsmClobberNoReg { - spans: regclass_outputs, - clobbers: args.clobber_abis.iter().map(|(_, span)| *span).collect(), - }); + // Bail out now since this is likely to confuse later stages + return Err(err); + } + AsmMacro::Asm => { + if !regclass_outputs.is_empty() { + dcx.emit_err(errors::AsmClobberNoReg { + spans: regclass_outputs, + clobbers: args.clobber_abis.iter().map(|(_, span)| *span).collect(), + }); + } + } } } @@ -335,10 +377,15 @@ fn err_duplicate_option(p: &Parser<'_>, symbol: Symbol, span: Span) { /// /// This function must be called immediately after the option token is parsed. /// Otherwise, the suggestion will be incorrect. -fn err_unsupported_option(p: &Parser<'_>, symbol: Symbol, span: Span) { +fn err_unsupported_option(p: &Parser<'_>, asm_macro: AsmMacro, symbol: Symbol, span: Span) { // Tool-only output let full_span = if p.token == token::Comma { span.to(p.token.span) } else { span }; - p.dcx().emit_err(errors::GlobalAsmUnsupportedOption { span, symbol, full_span }); + p.dcx().emit_err(errors::AsmUnsupportedOption { + span, + symbol, + full_span, + macro_name: asm_macro.macro_name(), + }); } /// Try to set the provided option in the provided `AsmArgs`. @@ -349,12 +396,12 @@ fn err_unsupported_option(p: &Parser<'_>, symbol: Symbol, span: Span) { fn try_set_option<'a>( p: &Parser<'a>, args: &mut AsmArgs, - is_global_asm: bool, + asm_macro: AsmMacro, symbol: Symbol, option: ast::InlineAsmOptions, ) { - if is_global_asm && !ast::InlineAsmOptions::GLOBAL_OPTIONS.contains(option) { - err_unsupported_option(p, symbol, p.prev_token.span); + if !asm_macro.is_supported_option(option) { + err_unsupported_option(p, asm_macro, symbol, p.prev_token.span); } else if args.options.contains(option) { err_duplicate_option(p, symbol, p.prev_token.span); } else { @@ -365,7 +412,7 @@ fn try_set_option<'a>( fn parse_options<'a>( p: &mut Parser<'a>, args: &mut AsmArgs, - is_global_asm: bool, + asm_macro: AsmMacro, ) -> PResult<'a, ()> { let span_start = p.prev_token.span; @@ -386,15 +433,14 @@ fn parse_options<'a>( 'blk: { for (symbol, option) in OPTIONS { - let kw_matched = - if !is_global_asm || ast::InlineAsmOptions::GLOBAL_OPTIONS.contains(option) { - p.eat_keyword(symbol) - } else { - p.eat_keyword_noexpect(symbol) - }; + let kw_matched = if asm_macro.is_supported_option(option) { + p.eat_keyword(symbol) + } else { + p.eat_keyword_noexpect(symbol) + }; if kw_matched { - try_set_option(p, args, is_global_asm, symbol, option); + try_set_option(p, args, asm_macro, symbol, option); break 'blk; } } @@ -797,7 +843,7 @@ pub(super) fn expand_asm<'cx>( sp: Span, tts: TokenStream, ) -> MacroExpanderResult<'cx> { - ExpandResult::Ready(match parse_args(ecx, sp, tts, false) { + ExpandResult::Ready(match parse_args(ecx, sp, tts, AsmMacro::Asm) { Ok(args) => { let ExpandResult::Ready(mac) = expand_preparsed_asm(ecx, AsmMacro::Asm, args) else { return ExpandResult::Retry(()); @@ -865,7 +911,7 @@ pub(super) fn expand_global_asm<'cx>( sp: Span, tts: TokenStream, ) -> MacroExpanderResult<'cx> { - ExpandResult::Ready(match parse_args(ecx, sp, tts, true) { + ExpandResult::Ready(match parse_args(ecx, sp, tts, AsmMacro::GlobalAsm) { Ok(args) => { let ExpandResult::Ready(mac) = expand_preparsed_asm(ecx, AsmMacro::GlobalAsm, args) else { @@ -894,3 +940,32 @@ pub(super) fn expand_global_asm<'cx>( } }) } + +pub(super) fn expand_naked_asm<'cx>( + ecx: &'cx mut ExtCtxt<'_>, + sp: Span, + tts: TokenStream, +) -> MacroExpanderResult<'cx> { + ExpandResult::Ready(match parse_args(ecx, sp, tts, AsmMacro::NakedAsm) { + Ok(args) => { + let ExpandResult::Ready(mac) = expand_preparsed_asm(ecx, args) else { + return ExpandResult::Retry(()); + }; + let expr = match mac { + Ok(inline_asm) => P(ast::Expr { + id: ast::DUMMY_NODE_ID, + kind: ast::ExprKind::InlineAsm(P(inline_asm)), + span: sp, + attrs: ast::AttrVec::new(), + tokens: None, + }), + Err(guar) => DummyResult::raw_expr(sp, Some(guar)), + }; + MacEager::expr(expr) + } + Err(err) => { + let guar = err.emit(); + DummyResult::any(sp, guar) + } + }) +} diff --git a/compiler/rustc_builtin_macros/src/errors.rs b/compiler/rustc_builtin_macros/src/errors.rs index 4fffffb91c8..f13ca224a45 100644 --- a/compiler/rustc_builtin_macros/src/errors.rs +++ b/compiler/rustc_builtin_macros/src/errors.rs @@ -751,7 +751,7 @@ pub(crate) struct AsmExpectedOther { #[primary_span] #[label(builtin_macros_asm_expected_other)] pub(crate) span: Span, - pub(crate) is_global_asm: bool, + pub(crate) is_inline_asm: bool, } #[derive(Diagnostic)] @@ -799,13 +799,6 @@ pub(crate) struct AsmMayUnwind { pub(crate) labels_sp: Vec, } -#[derive(Diagnostic)] -#[diag(builtin_macros_global_asm_clobber_abi)] -pub(crate) struct GlobalAsmClobberAbi { - #[primary_span] - pub(crate) spans: Vec, -} - pub(crate) struct AsmClobberNoReg { pub(crate) spans: Vec, pub(crate) clobbers: Vec, @@ -841,23 +834,33 @@ pub(crate) struct AsmOptAlreadyprovided { } #[derive(Diagnostic)] -#[diag(builtin_macros_global_asm_unsupported_option)] -pub(crate) struct GlobalAsmUnsupportedOption { +#[diag(builtin_macros_asm_unsupported_option)] +pub(crate) struct AsmUnsupportedOption { #[primary_span] #[label] pub(crate) span: Span, pub(crate) symbol: Symbol, #[suggestion(code = "", applicability = "machine-applicable", style = "tool-only")] pub(crate) full_span: Span, + pub(crate) macro_name: &'static str, } #[derive(Diagnostic)] -#[diag(builtin_macros_global_asm_unsupported_operand)] -pub(crate) struct GlobalAsmUnsupportedOperand<'a> { +#[diag(builtin_macros_asm_unsupported_operand)] +pub(crate) struct AsmUnsupportedOperand<'a> { #[primary_span] #[label] pub(crate) span: Span, pub(crate) symbol: &'a str, + pub(crate) macro_name: &'static str, +} + +#[derive(Diagnostic)] +#[diag(builtin_macros_asm_unsupported_clobber_abi)] +pub(crate) struct AsmUnsupportedClobberAbi { + #[primary_span] + pub(crate) spans: Vec, + pub(crate) macro_name: &'static str, } #[derive(Diagnostic)] diff --git a/library/core/src/arch.rs b/library/core/src/arch.rs index 4945c045bc6..f1a0739128c 100644 --- a/library/core/src/arch.rs +++ b/library/core/src/arch.rs @@ -77,3 +77,17 @@ pub macro naked_asm("assembly template", $(operands,)* $(options($(option),*))?) pub macro global_asm("assembly template", $(operands,)* $(options($(option),*))?) { /* compiler built-in */ } + +/// Inline assembly used in combination with `#[naked]` functions. +/// +/// Refer to [Rust By Example] for a usage guide and the [reference] for +/// detailed information about the syntax and available options. +/// +/// [Rust By Example]: https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html +/// [reference]: https://doc.rust-lang.org/nightly/reference/inline-assembly.html +#[unstable(feature = "naked_functions", issue = "90957")] +#[rustc_builtin_macro] +#[cfg(not(bootstrap))] +pub macro naked_asm("assembly template", $(operands,)* $(options($(option),*))?) { + /* compiler built-in */ +} diff --git a/src/tools/rustfmt/src/parse/macros/asm.rs b/src/tools/rustfmt/src/parse/macros/asm.rs index 5ee083da539..5d30171e295 100644 --- a/src/tools/rustfmt/src/parse/macros/asm.rs +++ b/src/tools/rustfmt/src/parse/macros/asm.rs @@ -1,5 +1,5 @@ use rustc_ast::ast; -use rustc_builtin_macros::asm::{AsmArgs, parse_asm_args}; +use rustc_builtin_macros::asm::{parse_asm_args, AsmArgs, AsmMacro}; use crate::rewrite::RewriteContext; @@ -7,5 +7,5 @@ use crate::rewrite::RewriteContext; pub(crate) fn parse_asm(context: &RewriteContext<'_>, mac: &ast::MacCall) -> Option { let ts = mac.args.tokens.clone(); let mut parser = super::build_parser(context, ts); - parse_asm_args(&mut parser, mac.span(), false).ok() + parse_asm_args(&mut parser, mac.span(), AsmMacro::Asm).ok() } From 0aec55504cf188d99b2047e49aad9027604df89e Mon Sep 17 00:00:00 2001 From: Folkert Date: Sun, 4 Aug 2024 16:43:12 +0200 Subject: [PATCH 626/683] use `naked_asm!` in `tests/ui/asm/naked-functions.rs` --- tests/ui/asm/naked-functions.rs | 72 +++++------ tests/ui/asm/naked-functions.stderr | 194 ++++++++++++---------------- 2 files changed, 122 insertions(+), 144 deletions(-) diff --git a/tests/ui/asm/naked-functions.rs b/tests/ui/asm/naked-functions.rs index 116a84506c5..86c89ea1262 100644 --- a/tests/ui/asm/naked-functions.rs +++ b/tests/ui/asm/naked-functions.rs @@ -6,7 +6,7 @@ #![feature(asm_unwind, linkage)] #![crate_type = "lib"] -use std::arch::asm; +use std::arch::naked_asm; #[repr(C)] pub struct P { @@ -25,7 +25,7 @@ pub unsafe extern "C" fn patterns( P { x, y }: P, //~^ ERROR patterns not allowed in naked function parameters ) { - asm!("", options(noreturn)) + naked_asm!("", options(noreturn)) } #[naked] @@ -38,9 +38,8 @@ pub unsafe extern "C" fn inc(a: u32) -> u32 { #[naked] #[allow(asm_sub_register)] pub unsafe extern "C" fn inc_asm(a: u32) -> u32 { - asm!("/* {0} */", in(reg) a, options(noreturn)); - //~^ ERROR referencing function parameters is not allowed in naked functions - //~| ERROR only `const` and `sym` operands are supported in naked functions + naked_asm!("/* {0} */", in(reg) a, options(noreturn)) + //~^ ERROR the `in` operand cannot be used with `naked_asm!` } #[naked] @@ -59,10 +58,9 @@ pub unsafe extern "C" fn unsupported_operands() { let mut e = 0usize; const F: usize = 0usize; static G: usize = 0usize; - asm!("/* {0} {1} {2} {3} {4} {5} {6} */", - //~^ ERROR asm in naked functions must use `noreturn` option + naked_asm!("/* {0} {1} {2} {3} {4} {5} {6} */", in(reg) a, - //~^ ERROR only `const` and `sym` operands are supported in naked functions + //~^ ERROR the `in` operand cannot be used with `naked_asm!` inlateout(reg) b, inout(reg) c, lateout(reg) d, @@ -81,13 +79,13 @@ pub extern "C" fn missing_assembly() { pub extern "C" fn too_many_asm_blocks() { //~^ ERROR naked functions must contain a single asm block unsafe { - asm!(""); + naked_asm!(""); //~^ ERROR asm in naked functions must use `noreturn` option - asm!(""); + naked_asm!(""); //~^ ERROR asm in naked functions must use `noreturn` option - asm!(""); + naked_asm!(""); //~^ ERROR asm in naked functions must use `noreturn` option - asm!("", options(noreturn)); + naked_asm!("", options(noreturn)); } } @@ -103,40 +101,42 @@ pub fn outer(x: u32) -> extern "C" fn(usize) -> usize { #[naked] unsafe extern "C" fn invalid_options() { - asm!("", options(nomem, preserves_flags, noreturn)); - //~^ ERROR asm options unsupported in naked functions: `nomem`, `preserves_flags` + naked_asm!("", options(nomem, preserves_flags, noreturn)); + //~^ ERROR the `nomem` option cannot be used with `naked_asm!` + //~| ERROR the `preserves_flags` option cannot be used with `naked_asm!` } #[naked] unsafe extern "C" fn invalid_options_continued() { - asm!("", options(readonly, nostack), options(pure)); - //~^ ERROR asm with the `pure` option must have at least one output - //~| ERROR asm options unsupported in naked functions: `pure`, `readonly`, `nostack` + naked_asm!("", options(readonly, nostack), options(pure)); + //~^ ERROR the `readonly` option cannot be used with `naked_asm!` + //~| ERROR the `nostack` option cannot be used with `naked_asm!` + //~| ERROR the `pure` option cannot be used with `naked_asm!` //~| ERROR asm in naked functions must use `noreturn` option } #[naked] unsafe extern "C" fn invalid_may_unwind() { - asm!("", options(noreturn, may_unwind)); - //~^ ERROR asm options unsupported in naked functions: `may_unwind` + naked_asm!("", options(noreturn, may_unwind)); + //~^ ERROR the `may_unwind` option cannot be used with `naked_asm!` } #[naked] pub unsafe fn default_abi() { //~^ WARN Rust ABI is unsupported in naked functions - asm!("", options(noreturn)); + naked_asm!("", options(noreturn)); } #[naked] pub unsafe fn rust_abi() { //~^ WARN Rust ABI is unsupported in naked functions - asm!("", options(noreturn)); + naked_asm!("", options(noreturn)); } #[naked] pub extern "C" fn valid_a() -> T { unsafe { - asm!("", options(noreturn)); + naked_asm!("", options(noreturn)); } } @@ -145,7 +145,7 @@ pub extern "C" fn valid_b() { unsafe { { { - asm!("", options(noreturn)); + naked_asm!("", options(noreturn)); }; }; } @@ -153,13 +153,13 @@ pub extern "C" fn valid_b() { #[naked] pub unsafe extern "C" fn valid_c() { - asm!("", options(noreturn)); + naked_asm!("", options(noreturn)); } #[cfg(target_arch = "x86_64")] #[naked] pub unsafe extern "C" fn valid_att_syntax() { - asm!("", options(noreturn, att_syntax)); + naked_asm!("", options(noreturn, att_syntax)); } #[naked] @@ -173,12 +173,12 @@ pub unsafe extern "C" fn allow_compile_error(a: u32) -> u32 { pub unsafe extern "C" fn allow_compile_error_and_asm(a: u32) -> u32 { compile_error!("this is a user specified error"); //~^ ERROR this is a user specified error - asm!("", options(noreturn)) + naked_asm!("", options(noreturn)) } #[naked] pub unsafe extern "C" fn invalid_asm_syntax(a: u32) -> u32 { - asm!(invalid_syntax) + naked_asm!(invalid_syntax) //~^ ERROR asm template must be a string literal } @@ -186,7 +186,7 @@ pub unsafe extern "C" fn invalid_asm_syntax(a: u32) -> u32 { #[cfg_attr(target_pointer_width = "64", no_mangle)] #[naked] pub unsafe extern "C" fn compatible_cfg_attributes() { - asm!("", options(noreturn, att_syntax)); + naked_asm!("", options(noreturn, att_syntax)); } #[allow(dead_code)] @@ -195,20 +195,20 @@ pub unsafe extern "C" fn compatible_cfg_attributes() { #[forbid(dead_code)] #[naked] pub unsafe extern "C" fn compatible_diagnostic_attributes() { - asm!("", options(noreturn, raw)); + naked_asm!("", options(noreturn, raw)); } #[deprecated = "test"] #[naked] pub unsafe extern "C" fn compatible_deprecated_attributes() { - asm!("", options(noreturn, raw)); + naked_asm!("", options(noreturn, raw)); } #[cfg(target_arch = "x86_64")] #[must_use] #[naked] pub unsafe extern "C" fn compatible_must_use_attributes() -> u64 { - asm!( + naked_asm!( " mov rax, 42 ret @@ -222,20 +222,20 @@ pub unsafe extern "C" fn compatible_must_use_attributes() -> u64 { #[no_mangle] #[naked] pub unsafe extern "C" fn compatible_ffi_attributes_1() { - asm!("", options(noreturn, raw)); + naked_asm!("", options(noreturn, raw)); } #[cold] #[naked] pub unsafe extern "C" fn compatible_codegen_attributes() { - asm!("", options(noreturn, raw)); + naked_asm!("", options(noreturn, raw)); } #[cfg(target_arch = "x86_64")] #[target_feature(enable = "sse2")] #[naked] pub unsafe extern "C" fn compatible_target_feature() { - asm!("", options(noreturn)); + naked_asm!("", options(noreturn)); } #[doc = "foo bar baz"] @@ -244,11 +244,11 @@ pub unsafe extern "C" fn compatible_target_feature() { #[doc(alias = "ADocAlias")] #[naked] pub unsafe extern "C" fn compatible_doc_attributes() { - asm!("", options(noreturn, raw)); + naked_asm!("", options(noreturn, raw)); } #[linkage = "external"] #[naked] pub unsafe extern "C" fn compatible_linkage() { - asm!("", options(noreturn, raw)); + naked_asm!("", options(noreturn, raw)); } diff --git a/tests/ui/asm/naked-functions.stderr b/tests/ui/asm/naked-functions.stderr index 93c02e2fbef..22c1946a960 100644 --- a/tests/ui/asm/naked-functions.stderr +++ b/tests/ui/asm/naked-functions.stderr @@ -1,8 +1,50 @@ -error: asm with the `pure` option must have at least one output - --> $DIR/naked-functions.rs:112:14 +error: the `in` operand cannot be used with `naked_asm!` + --> $DIR/naked-functions.rs:41:29 | -LL | asm!("", options(readonly, nostack), options(pure)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^ +LL | naked_asm!("/* {0} */", in(reg) a, options(noreturn)) + | ^^ the `in` operand is not meaningful for global-scoped inline assembly, remove it + +error: the `in` operand cannot be used with `naked_asm!` + --> $DIR/naked-functions.rs:62:10 + | +LL | in(reg) a, + | ^^ the `in` operand is not meaningful for global-scoped inline assembly, remove it + +error: the `nomem` option cannot be used with `naked_asm!` + --> $DIR/naked-functions.rs:104:28 + | +LL | naked_asm!("", options(nomem, preserves_flags, noreturn)); + | ^^^^^ the `nomem` option is not meaningful for global-scoped inline assembly + +error: the `preserves_flags` option cannot be used with `naked_asm!` + --> $DIR/naked-functions.rs:104:35 + | +LL | naked_asm!("", options(nomem, preserves_flags, noreturn)); + | ^^^^^^^^^^^^^^^ the `preserves_flags` option is not meaningful for global-scoped inline assembly + +error: the `readonly` option cannot be used with `naked_asm!` + --> $DIR/naked-functions.rs:111:28 + | +LL | naked_asm!("", options(readonly, nostack), options(pure)); + | ^^^^^^^^ the `readonly` option is not meaningful for global-scoped inline assembly + +error: the `nostack` option cannot be used with `naked_asm!` + --> $DIR/naked-functions.rs:111:38 + | +LL | naked_asm!("", options(readonly, nostack), options(pure)); + | ^^^^^^^ the `nostack` option is not meaningful for global-scoped inline assembly + +error: the `pure` option cannot be used with `naked_asm!` + --> $DIR/naked-functions.rs:111:56 + | +LL | naked_asm!("", options(readonly, nostack), options(pure)); + | ^^^^ the `pure` option is not meaningful for global-scoped inline assembly + +error: the `may_unwind` option cannot be used with `naked_asm!` + --> $DIR/naked-functions.rs:120:38 + | +LL | naked_asm!("", options(noreturn, may_unwind)); + | ^^^^^^^^^^ the `may_unwind` option is not meaningful for global-scoped inline assembly error: this is a user specified error --> $DIR/naked-functions.rs:168:5 @@ -17,10 +59,10 @@ LL | compile_error!("this is a user specified error"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: asm template must be a string literal - --> $DIR/naked-functions.rs:181:10 + --> $DIR/naked-functions.rs:181:16 | -LL | asm!(invalid_syntax) - | ^^^^^^^^^^^^^^ +LL | naked_asm!(invalid_syntax) + | ^^^^^^^^^^^^^^ error: patterns not allowed in naked function parameters --> $DIR/naked-functions.rs:19:5 @@ -63,22 +105,8 @@ LL | LL | a + 1 | ----- non-asm is unsupported in naked functions -error: referencing function parameters is not allowed in naked functions - --> $DIR/naked-functions.rs:41:31 - | -LL | asm!("/* {0} */", in(reg) a, options(noreturn)); - | ^ - | - = help: follow the calling convention in asm block to use parameters - -error[E0787]: only `const` and `sym` operands are supported in naked functions - --> $DIR/naked-functions.rs:41:23 - | -LL | asm!("/* {0} */", in(reg) a, options(noreturn)); - | ^^^^^^^^^ - error[E0787]: naked functions must contain a single asm block - --> $DIR/naked-functions.rs:47:1 + --> $DIR/naked-functions.rs:46:1 | LL | pub unsafe extern "C" fn inc_closure(a: u32) -> u32 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -86,40 +114,8 @@ LL | LL | (|| a + 1)() | ------------ non-asm is unsupported in naked functions -error[E0787]: only `const` and `sym` operands are supported in naked functions - --> $DIR/naked-functions.rs:64:10 - | -LL | in(reg) a, - | ^^^^^^^^^ -LL | -LL | inlateout(reg) b, - | ^^^^^^^^^^^^^^^^ -LL | inout(reg) c, - | ^^^^^^^^^^^^ -LL | lateout(reg) d, - | ^^^^^^^^^^^^^^ -LL | out(reg) e, - | ^^^^^^^^^^ - -error[E0787]: asm in naked functions must use `noreturn` option - --> $DIR/naked-functions.rs:62:5 - | -LL | / asm!("/* {0} {1} {2} {3} {4} {5} {6} */", -LL | | -LL | | in(reg) a, -LL | | -... | -LL | | sym G, -LL | | ); - | |_____^ - | -help: consider specifying that the asm block is responsible for returning from the function - | -LL | sym G, options(noreturn), - | +++++++++++++++++++ - error[E0787]: naked functions must contain a single asm block - --> $DIR/naked-functions.rs:53:1 + --> $DIR/naked-functions.rs:52:1 | LL | pub unsafe extern "C" fn unsupported_operands() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -136,61 +132,61 @@ LL | let mut e = 0usize; | ------------------- non-asm is unsupported in naked functions error[E0787]: naked functions must contain a single asm block - --> $DIR/naked-functions.rs:76:1 + --> $DIR/naked-functions.rs:74:1 | LL | pub extern "C" fn missing_assembly() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0787]: asm in naked functions must use `noreturn` option - --> $DIR/naked-functions.rs:84:9 + --> $DIR/naked-functions.rs:82:9 | -LL | asm!(""); - | ^^^^^^^^ +LL | naked_asm!(""); + | ^^^^^^^^^^^^^^ | help: consider specifying that the asm block is responsible for returning from the function | -LL | asm!("", options(noreturn)); - | +++++++++++++++++++ +LL | naked_asm!("", options(noreturn)); + | +++++++++++++++++++ + +error[E0787]: asm in naked functions must use `noreturn` option + --> $DIR/naked-functions.rs:84:9 + | +LL | naked_asm!(""); + | ^^^^^^^^^^^^^^ + | +help: consider specifying that the asm block is responsible for returning from the function + | +LL | naked_asm!("", options(noreturn)); + | +++++++++++++++++++ error[E0787]: asm in naked functions must use `noreturn` option --> $DIR/naked-functions.rs:86:9 | -LL | asm!(""); - | ^^^^^^^^ +LL | naked_asm!(""); + | ^^^^^^^^^^^^^^ | help: consider specifying that the asm block is responsible for returning from the function | -LL | asm!("", options(noreturn)); - | +++++++++++++++++++ - -error[E0787]: asm in naked functions must use `noreturn` option - --> $DIR/naked-functions.rs:88:9 - | -LL | asm!(""); - | ^^^^^^^^ - | -help: consider specifying that the asm block is responsible for returning from the function - | -LL | asm!("", options(noreturn)); - | +++++++++++++++++++ +LL | naked_asm!("", options(noreturn)); + | +++++++++++++++++++ error[E0787]: naked functions must contain a single asm block - --> $DIR/naked-functions.rs:81:1 + --> $DIR/naked-functions.rs:79:1 | LL | pub extern "C" fn too_many_asm_blocks() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ... -LL | asm!(""); - | -------- multiple asm blocks are unsupported in naked functions +LL | naked_asm!(""); + | -------------- multiple asm blocks are unsupported in naked functions LL | -LL | asm!(""); - | -------- multiple asm blocks are unsupported in naked functions +LL | naked_asm!(""); + | -------------- multiple asm blocks are unsupported in naked functions LL | -LL | asm!("", options(noreturn)); - | --------------------------- multiple asm blocks are unsupported in naked functions +LL | naked_asm!("", options(noreturn)); + | --------------------------------- multiple asm blocks are unsupported in naked functions error: referencing function parameters is not allowed in naked functions - --> $DIR/naked-functions.rs:98:11 + --> $DIR/naked-functions.rs:96:11 | LL | *&y | ^ @@ -198,7 +194,7 @@ LL | *&y = help: follow the calling convention in asm block to use parameters error[E0787]: naked functions must contain a single asm block - --> $DIR/naked-functions.rs:96:5 + --> $DIR/naked-functions.rs:94:5 | LL | pub extern "C" fn inner(y: usize) -> usize { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -206,34 +202,16 @@ LL | LL | *&y | --- non-asm is unsupported in naked functions -error[E0787]: asm options unsupported in naked functions: `nomem`, `preserves_flags` - --> $DIR/naked-functions.rs:106:5 - | -LL | asm!("", options(nomem, preserves_flags, noreturn)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0787]: asm options unsupported in naked functions: `pure`, `readonly`, `nostack` - --> $DIR/naked-functions.rs:112:5 - | -LL | asm!("", options(readonly, nostack), options(pure)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - error[E0787]: asm in naked functions must use `noreturn` option - --> $DIR/naked-functions.rs:112:5 + --> $DIR/naked-functions.rs:111:5 | -LL | asm!("", options(readonly, nostack), options(pure)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | naked_asm!("", options(readonly, nostack), options(pure)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: consider specifying that the asm block is responsible for returning from the function | -LL | asm!("", options(noreturn), options(readonly, nostack), options(pure)); - | +++++++++++++++++++ - -error[E0787]: asm options unsupported in naked functions: `may_unwind` - --> $DIR/naked-functions.rs:120:5 - | -LL | asm!("", options(noreturn, may_unwind)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | naked_asm!("", options(noreturn), options(readonly, nostack), options(pure)); + | +++++++++++++++++++ warning: Rust ABI is unsupported in naked functions --> $DIR/naked-functions.rs:125:1 From 47b42bef3226bb71506988572c73ec1b6f99a730 Mon Sep 17 00:00:00 2001 From: Folkert Date: Sun, 4 Aug 2024 16:45:48 +0200 Subject: [PATCH 627/683] use `naked_asm!` in naked-function tests --- tests/codegen/naked-fn/naked-functions.rs | 6 +-- tests/ui/asm/naked-functions-ffi.rs | 4 +- tests/ui/asm/naked-functions-inline.rs | 2 +- .../ui/asm/naked-functions-instruction-set.rs | 6 +-- tests/ui/asm/naked-functions-testattrs.rs | 10 ++--- .../asm/naked-functions-unused.aarch64.stderr | 16 +++---- tests/ui/asm/naked-functions-unused.rs | 42 ++++++++++++++----- .../asm/naked-functions-unused.x86_64.stderr | 16 +++---- .../feature-gate-naked_functions.rs | 4 +- 9 files changed, 63 insertions(+), 43 deletions(-) diff --git a/tests/codegen/naked-fn/naked-functions.rs b/tests/codegen/naked-fn/naked-functions.rs index 307745a921c..2b2625429f8 100644 --- a/tests/codegen/naked-fn/naked-functions.rs +++ b/tests/codegen/naked-fn/naked-functions.rs @@ -4,7 +4,7 @@ #![crate_type = "lib"] #![feature(naked_functions)] -use std::arch::asm; +use std::arch::naked_asm; // CHECK: Function Attrs: naked // CHECK-NEXT: define{{.*}}void @naked_empty() @@ -14,7 +14,7 @@ pub unsafe extern "C" fn naked_empty() { // CHECK-NEXT: {{.+}}: // CHECK-NEXT: call void asm // CHECK-NEXT: unreachable - asm!("ret", options(noreturn)); + naked_asm!("ret", options(noreturn)); } // CHECK: Function Attrs: naked @@ -25,5 +25,5 @@ pub unsafe extern "C" fn naked_with_args_and_return(a: isize, b: isize) -> isize // CHECK-NEXT: {{.+}}: // CHECK-NEXT: call void asm // CHECK-NEXT: unreachable - asm!("lea rax, [rdi + rsi]", "ret", options(noreturn)); + naked_asm!("lea rax, [rdi + rsi]", "ret", options(noreturn)); } diff --git a/tests/ui/asm/naked-functions-ffi.rs b/tests/ui/asm/naked-functions-ffi.rs index 93d23885b13..6b32290905d 100644 --- a/tests/ui/asm/naked-functions-ffi.rs +++ b/tests/ui/asm/naked-functions-ffi.rs @@ -3,13 +3,13 @@ #![feature(naked_functions)] #![crate_type = "lib"] -use std::arch::asm; +use std::arch::naked_asm; #[naked] pub extern "C" fn naked(p: char) -> u128 { //~^ WARN uses type `char` //~| WARN uses type `u128` unsafe { - asm!("", options(noreturn)); + naked_asm!("", options(noreturn)); } } diff --git a/tests/ui/asm/naked-functions-inline.rs b/tests/ui/asm/naked-functions-inline.rs index 74049e8ecbc..a4df38e3347 100644 --- a/tests/ui/asm/naked-functions-inline.rs +++ b/tests/ui/asm/naked-functions-inline.rs @@ -19,7 +19,7 @@ pub unsafe extern "C" fn inline_hint() { #[naked] #[inline(always)] //~^ ERROR [E0736] -pub unsafe extern "C" fn inline_always() { +<<<<<<< HEAD naked_asm!(""); } diff --git a/tests/ui/asm/naked-functions-instruction-set.rs b/tests/ui/asm/naked-functions-instruction-set.rs index b81b65cff74..6c6dcdf0087 100644 --- a/tests/ui/asm/naked-functions-instruction-set.rs +++ b/tests/ui/asm/naked-functions-instruction-set.rs @@ -8,7 +8,7 @@ #![no_core] #[rustc_builtin_macro] -macro_rules! asm { +macro_rules! naked_asm { () => {}; } @@ -19,12 +19,12 @@ trait Sized {} #[naked] #[instruction_set(arm::t32)] unsafe extern "C" fn test_thumb() { - asm!("bx lr", options(noreturn)); + naked_asm!("bx lr", options(noreturn)); } #[no_mangle] #[naked] #[instruction_set(arm::t32)] unsafe extern "C" fn test_arm() { - asm!("bx lr", options(noreturn)); + naked_asm!("bx lr", options(noreturn)); } diff --git a/tests/ui/asm/naked-functions-testattrs.rs b/tests/ui/asm/naked-functions-testattrs.rs index 12943ac0378..2532e6e86d6 100644 --- a/tests/ui/asm/naked-functions-testattrs.rs +++ b/tests/ui/asm/naked-functions-testattrs.rs @@ -6,13 +6,13 @@ #![feature(test)] #![crate_type = "lib"] -use std::arch::asm; +use std::arch::naked_asm; #[test] #[naked] //~^ ERROR [E0736] fn test_naked() { - unsafe { asm!("", options(noreturn)) }; + unsafe { naked_asm!("", options(noreturn)) }; } #[should_panic] @@ -20,7 +20,7 @@ fn test_naked() { #[naked] //~^ ERROR [E0736] fn test_naked_should_panic() { - unsafe { asm!("", options(noreturn)) }; + unsafe { naked_asm!("", options(noreturn)) }; } #[ignore] @@ -28,12 +28,12 @@ fn test_naked_should_panic() { #[naked] //~^ ERROR [E0736] fn test_naked_ignore() { - unsafe { asm!("", options(noreturn)) }; + unsafe { naked_asm!("", options(noreturn)) }; } #[bench] #[naked] //~^ ERROR [E0736] fn bench_naked() { - unsafe { asm!("", options(noreturn)) }; + unsafe { naked_asm!("", options(noreturn)) }; } diff --git a/tests/ui/asm/naked-functions-unused.aarch64.stderr b/tests/ui/asm/naked-functions-unused.aarch64.stderr index 8d3c300e058..ea63ced1aab 100644 --- a/tests/ui/asm/naked-functions-unused.aarch64.stderr +++ b/tests/ui/asm/naked-functions-unused.aarch64.stderr @@ -18,49 +18,49 @@ LL | pub extern "C" fn function(a: usize, b: usize) -> usize { | ^ help: if this is intentional, prefix it with an underscore: `_b` error: unused variable: `a` - --> $DIR/naked-functions-unused.rs:26:38 + --> $DIR/naked-functions-unused.rs:28:38 | LL | pub extern "C" fn associated(a: usize, b: usize) -> usize { | ^ help: if this is intentional, prefix it with an underscore: `_a` error: unused variable: `b` - --> $DIR/naked-functions-unused.rs:26:48 + --> $DIR/naked-functions-unused.rs:28:48 | LL | pub extern "C" fn associated(a: usize, b: usize) -> usize { | ^ help: if this is intentional, prefix it with an underscore: `_b` error: unused variable: `a` - --> $DIR/naked-functions-unused.rs:32:41 + --> $DIR/naked-functions-unused.rs:36:41 | LL | pub extern "C" fn method(&self, a: usize, b: usize) -> usize { | ^ help: if this is intentional, prefix it with an underscore: `_a` error: unused variable: `b` - --> $DIR/naked-functions-unused.rs:32:51 + --> $DIR/naked-functions-unused.rs:36:51 | LL | pub extern "C" fn method(&self, a: usize, b: usize) -> usize { | ^ help: if this is intentional, prefix it with an underscore: `_b` error: unused variable: `a` - --> $DIR/naked-functions-unused.rs:40:40 + --> $DIR/naked-functions-unused.rs:46:40 | LL | extern "C" fn trait_associated(a: usize, b: usize) -> usize { | ^ help: if this is intentional, prefix it with an underscore: `_a` error: unused variable: `b` - --> $DIR/naked-functions-unused.rs:40:50 + --> $DIR/naked-functions-unused.rs:46:50 | LL | extern "C" fn trait_associated(a: usize, b: usize) -> usize { | ^ help: if this is intentional, prefix it with an underscore: `_b` error: unused variable: `a` - --> $DIR/naked-functions-unused.rs:46:43 + --> $DIR/naked-functions-unused.rs:54:43 | LL | extern "C" fn trait_method(&self, a: usize, b: usize) -> usize { | ^ help: if this is intentional, prefix it with an underscore: `_a` error: unused variable: `b` - --> $DIR/naked-functions-unused.rs:46:53 + --> $DIR/naked-functions-unused.rs:54:53 | LL | extern "C" fn trait_method(&self, a: usize, b: usize) -> usize { | ^ help: if this is intentional, prefix it with an underscore: `_b` diff --git a/tests/ui/asm/naked-functions-unused.rs b/tests/ui/asm/naked-functions-unused.rs index 745d30e6a84..6d3cc0afed8 100644 --- a/tests/ui/asm/naked-functions-unused.rs +++ b/tests/ui/asm/naked-functions-unused.rs @@ -17,7 +17,9 @@ pub mod normal { pub extern "C" fn function(a: usize, b: usize) -> usize { //~^ ERROR unused variable: `a` //~| ERROR unused variable: `b` - unsafe { asm!("", options(noreturn)); } + unsafe { + asm!("", options(noreturn)); + } } pub struct Normal; @@ -26,13 +28,17 @@ pub mod normal { pub extern "C" fn associated(a: usize, b: usize) -> usize { //~^ ERROR unused variable: `a` //~| ERROR unused variable: `b` - unsafe { asm!("", options(noreturn)); } + unsafe { + asm!("", options(noreturn)); + } } pub extern "C" fn method(&self, a: usize, b: usize) -> usize { //~^ ERROR unused variable: `a` //~| ERROR unused variable: `b` - unsafe { asm!("", options(noreturn)); } + unsafe { + asm!("", options(noreturn)); + } } } @@ -40,23 +46,29 @@ pub mod normal { extern "C" fn trait_associated(a: usize, b: usize) -> usize { //~^ ERROR unused variable: `a` //~| ERROR unused variable: `b` - unsafe { asm!("", options(noreturn)); } + unsafe { + asm!("", options(noreturn)); + } } extern "C" fn trait_method(&self, a: usize, b: usize) -> usize { //~^ ERROR unused variable: `a` //~| ERROR unused variable: `b` - unsafe { asm!("", options(noreturn)); } + unsafe { + asm!("", options(noreturn)); + } } } } pub mod naked { - use std::arch::asm; + use std::arch::naked_asm; #[naked] pub extern "C" fn function(a: usize, b: usize) -> usize { - unsafe { asm!("", options(noreturn)); } + unsafe { + naked_asm!("", options(noreturn)); + } } pub struct Naked; @@ -64,24 +76,32 @@ pub mod naked { impl Naked { #[naked] pub extern "C" fn associated(a: usize, b: usize) -> usize { - unsafe { asm!("", options(noreturn)); } + unsafe { + naked_asm!("", options(noreturn)); + } } #[naked] pub extern "C" fn method(&self, a: usize, b: usize) -> usize { - unsafe { asm!("", options(noreturn)); } + unsafe { + naked_asm!("", options(noreturn)); + } } } impl super::Trait for Naked { #[naked] extern "C" fn trait_associated(a: usize, b: usize) -> usize { - unsafe { asm!("", options(noreturn)); } + unsafe { + naked_asm!("", options(noreturn)); + } } #[naked] extern "C" fn trait_method(&self, a: usize, b: usize) -> usize { - unsafe { asm!("", options(noreturn)); } + unsafe { + naked_asm!("", options(noreturn)); + } } } } diff --git a/tests/ui/asm/naked-functions-unused.x86_64.stderr b/tests/ui/asm/naked-functions-unused.x86_64.stderr index 8d3c300e058..ea63ced1aab 100644 --- a/tests/ui/asm/naked-functions-unused.x86_64.stderr +++ b/tests/ui/asm/naked-functions-unused.x86_64.stderr @@ -18,49 +18,49 @@ LL | pub extern "C" fn function(a: usize, b: usize) -> usize { | ^ help: if this is intentional, prefix it with an underscore: `_b` error: unused variable: `a` - --> $DIR/naked-functions-unused.rs:26:38 + --> $DIR/naked-functions-unused.rs:28:38 | LL | pub extern "C" fn associated(a: usize, b: usize) -> usize { | ^ help: if this is intentional, prefix it with an underscore: `_a` error: unused variable: `b` - --> $DIR/naked-functions-unused.rs:26:48 + --> $DIR/naked-functions-unused.rs:28:48 | LL | pub extern "C" fn associated(a: usize, b: usize) -> usize { | ^ help: if this is intentional, prefix it with an underscore: `_b` error: unused variable: `a` - --> $DIR/naked-functions-unused.rs:32:41 + --> $DIR/naked-functions-unused.rs:36:41 | LL | pub extern "C" fn method(&self, a: usize, b: usize) -> usize { | ^ help: if this is intentional, prefix it with an underscore: `_a` error: unused variable: `b` - --> $DIR/naked-functions-unused.rs:32:51 + --> $DIR/naked-functions-unused.rs:36:51 | LL | pub extern "C" fn method(&self, a: usize, b: usize) -> usize { | ^ help: if this is intentional, prefix it with an underscore: `_b` error: unused variable: `a` - --> $DIR/naked-functions-unused.rs:40:40 + --> $DIR/naked-functions-unused.rs:46:40 | LL | extern "C" fn trait_associated(a: usize, b: usize) -> usize { | ^ help: if this is intentional, prefix it with an underscore: `_a` error: unused variable: `b` - --> $DIR/naked-functions-unused.rs:40:50 + --> $DIR/naked-functions-unused.rs:46:50 | LL | extern "C" fn trait_associated(a: usize, b: usize) -> usize { | ^ help: if this is intentional, prefix it with an underscore: `_b` error: unused variable: `a` - --> $DIR/naked-functions-unused.rs:46:43 + --> $DIR/naked-functions-unused.rs:54:43 | LL | extern "C" fn trait_method(&self, a: usize, b: usize) -> usize { | ^ help: if this is intentional, prefix it with an underscore: `_a` error: unused variable: `b` - --> $DIR/naked-functions-unused.rs:46:53 + --> $DIR/naked-functions-unused.rs:54:53 | LL | extern "C" fn trait_method(&self, a: usize, b: usize) -> usize { | ^ help: if this is intentional, prefix it with an underscore: `_b` diff --git a/tests/ui/feature-gates/feature-gate-naked_functions.rs b/tests/ui/feature-gates/feature-gate-naked_functions.rs index 36980fd74c2..298b687e4f2 100644 --- a/tests/ui/feature-gates/feature-gate-naked_functions.rs +++ b/tests/ui/feature-gates/feature-gate-naked_functions.rs @@ -5,14 +5,14 @@ use std::arch::asm; #[naked] //~^ the `#[naked]` attribute is an experimental feature extern "C" fn naked() { - asm!("", options(noreturn)) + naked_asm!("", options(noreturn)) //~^ ERROR: requires unsafe } #[naked] //~^ the `#[naked]` attribute is an experimental feature extern "C" fn naked_2() -> isize { - asm!("", options(noreturn)) + naked_asm!("", options(noreturn)) //~^ ERROR: requires unsafe } From 1a9c1cbf367fb2b6f04a0a81d7fae56485e29e7f Mon Sep 17 00:00:00 2001 From: Folkert Date: Sun, 4 Aug 2024 17:19:08 +0200 Subject: [PATCH 628/683] use `naked_asm!` in feature-gate-naked_functions test --- .../feature-gate-naked_functions.rs | 9 ++-- .../feature-gate-naked_functions.stderr | 50 +++++++++++++++---- 2 files changed, 46 insertions(+), 13 deletions(-) diff --git a/tests/ui/feature-gates/feature-gate-naked_functions.rs b/tests/ui/feature-gates/feature-gate-naked_functions.rs index 298b687e4f2..c8802ea4c31 100644 --- a/tests/ui/feature-gates/feature-gate-naked_functions.rs +++ b/tests/ui/feature-gates/feature-gate-naked_functions.rs @@ -1,19 +1,22 @@ //@ needs-asm-support -use std::arch::asm; +use std::arch::naked_asm; +//~^ ERROR use of unstable library feature 'naked_functions' #[naked] //~^ the `#[naked]` attribute is an experimental feature extern "C" fn naked() { naked_asm!("", options(noreturn)) - //~^ ERROR: requires unsafe + //~^ ERROR use of unstable library feature 'naked_functions' + //~| ERROR: requires unsafe } #[naked] //~^ the `#[naked]` attribute is an experimental feature extern "C" fn naked_2() -> isize { naked_asm!("", options(noreturn)) - //~^ ERROR: requires unsafe + //~^ ERROR use of unstable library feature 'naked_functions' + //~| ERROR: requires unsafe } fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-naked_functions.stderr b/tests/ui/feature-gates/feature-gate-naked_functions.stderr index ffdf31e147a..5fecc218a16 100644 --- a/tests/ui/feature-gates/feature-gate-naked_functions.stderr +++ b/tests/ui/feature-gates/feature-gate-naked_functions.stderr @@ -1,5 +1,25 @@ +error[E0658]: use of unstable library feature 'naked_functions' + --> $DIR/feature-gate-naked_functions.rs:9:5 + | +LL | naked_asm!("", options(noreturn)) + | ^^^^^^^^^ + | + = note: see issue #90957 for more information + = help: add `#![feature(naked_functions)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: use of unstable library feature 'naked_functions' + --> $DIR/feature-gate-naked_functions.rs:17:5 + | +LL | naked_asm!("", options(noreturn)) + | ^^^^^^^^^ + | + = note: see issue #90957 for more information + = help: add `#![feature(naked_functions)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + error[E0658]: the `#[naked]` attribute is an experimental feature - --> $DIR/feature-gate-naked_functions.rs:5:1 + --> $DIR/feature-gate-naked_functions.rs:6:1 | LL | #[naked] | ^^^^^^^^ @@ -9,7 +29,7 @@ LL | #[naked] = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: the `#[naked]` attribute is an experimental feature - --> $DIR/feature-gate-naked_functions.rs:12:1 + --> $DIR/feature-gate-naked_functions.rs:14:1 | LL | #[naked] | ^^^^^^^^ @@ -18,23 +38,33 @@ LL | #[naked] = help: add `#![feature(naked_functions)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error[E0133]: use of inline assembly is unsafe and requires unsafe function or block - --> $DIR/feature-gate-naked_functions.rs:8:5 +error[E0658]: use of unstable library feature 'naked_functions' + --> $DIR/feature-gate-naked_functions.rs:3:5 | -LL | asm!("", options(noreturn)) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ use of inline assembly +LL | use std::arch::naked_asm; + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #90957 for more information + = help: add `#![feature(naked_functions)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0133]: use of inline assembly is unsafe and requires unsafe function or block + --> $DIR/feature-gate-naked_functions.rs:9:5 + | +LL | naked_asm!("", options(noreturn)) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ use of inline assembly | = note: inline assembly is entirely unchecked and can cause undefined behavior error[E0133]: use of inline assembly is unsafe and requires unsafe function or block - --> $DIR/feature-gate-naked_functions.rs:15:5 + --> $DIR/feature-gate-naked_functions.rs:17:5 | -LL | asm!("", options(noreturn)) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ use of inline assembly +LL | naked_asm!("", options(noreturn)) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ use of inline assembly | = note: inline assembly is entirely unchecked and can cause undefined behavior -error: aborting due to 4 previous errors +error: aborting due to 7 previous errors Some errors have detailed explanations: E0133, E0658. For more information about an error, try `rustc --explain E0133`. From 562ec5a6fb469a360b72aa8ba0ce149598cc7975 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Thu, 5 Sep 2024 13:45:26 +0200 Subject: [PATCH 629/683] disallow `asm!` in `#[naked]` functions also disallow the `noreturn` option, and infer `naked_asm!` as `!` --- compiler/rustc_ast/src/ast.rs | 20 ++- compiler/rustc_builtin_macros/src/asm.rs | 62 +------ .../src/error_codes/E0787.md | 5 +- compiler/rustc_hir_typeck/src/expr.rs | 6 +- compiler/rustc_passes/messages.ftl | 12 +- compiler/rustc_passes/src/errors.rs | 8 +- compiler/rustc_passes/src/naked_functions.rs | 47 +++--- library/core/src/arch.rs | 14 -- src/tools/rustfmt/src/parse/macros/asm.rs | 4 +- tests/codegen/naked-fn/aligned.rs | 4 +- tests/codegen/naked-fn/naked-functions.rs | 4 +- tests/codegen/naked-fn/naked-nocoverage.rs | 4 +- tests/codegen/naked-fn/naked-noinline.rs | 4 +- tests/ui/asm/naked-functions-ffi.rs | 2 +- tests/ui/asm/naked-functions-inline.rs | 2 +- .../ui/asm/naked-functions-instruction-set.rs | 4 +- tests/ui/asm/naked-functions-testattrs.rs | 8 +- tests/ui/asm/naked-functions-unused.rs | 10 +- tests/ui/asm/naked-functions.rs | 68 ++++---- tests/ui/asm/naked-functions.stderr | 158 +++++++----------- tests/ui/asm/naked-invalid-attr.rs | 13 +- tests/ui/asm/naked-invalid-attr.stderr | 6 +- tests/ui/asm/naked-with-invalid-repr-attr.rs | 12 +- .../asm/naked-with-invalid-repr-attr.stderr | 12 +- tests/ui/asm/named-asm-labels.rs | 10 +- tests/ui/asm/named-asm-labels.stderr | 18 +- .../feature-gate-naked_functions.rs | 4 +- 27 files changed, 223 insertions(+), 298 deletions(-) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 37f429cce44..cb715213176 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -2278,7 +2278,7 @@ impl InlineAsmOptions { pub const COUNT: usize = Self::all().bits().count_ones() as usize; pub const GLOBAL_OPTIONS: Self = Self::ATT_SYNTAX.union(Self::RAW); - pub const NAKED_OPTIONS: Self = Self::ATT_SYNTAX.union(Self::RAW).union(Self::NORETURN); + pub const NAKED_OPTIONS: Self = Self::ATT_SYNTAX.union(Self::RAW); pub fn human_readable_names(&self) -> Vec<&'static str> { let mut options = vec![]; @@ -2434,6 +2434,24 @@ pub enum AsmMacro { NakedAsm, } +impl AsmMacro { + pub const fn macro_name(&self) -> &'static str { + match self { + AsmMacro::Asm => "asm", + AsmMacro::GlobalAsm => "global_asm", + AsmMacro::NakedAsm => "naked_asm", + } + } + + pub const fn is_supported_option(&self, option: InlineAsmOptions) -> bool { + match self { + AsmMacro::Asm => true, + AsmMacro::GlobalAsm => InlineAsmOptions::GLOBAL_OPTIONS.contains(option), + AsmMacro::NakedAsm => InlineAsmOptions::NAKED_OPTIONS.contains(option), + } + } +} + /// Inline assembly. /// /// E.g., `asm!("NOP");`. diff --git a/compiler/rustc_builtin_macros/src/asm.rs b/compiler/rustc_builtin_macros/src/asm.rs index 2019c42e296..515ac17f70a 100644 --- a/compiler/rustc_builtin_macros/src/asm.rs +++ b/compiler/rustc_builtin_macros/src/asm.rs @@ -60,35 +60,6 @@ fn eat_operand_keyword<'a>( } } -// Public for rustfmt consumption. -#[derive(Copy, Clone)] -pub enum AsmMacro { - /// The `asm!` macro - Asm, - /// The `global_asm!` macro - GlobalAsm, - /// The `naked_asm!` macro - NakedAsm, -} - -impl AsmMacro { - const fn macro_name(&self) -> &'static str { - match self { - AsmMacro::Asm => "asm", - AsmMacro::GlobalAsm => "global_asm", - AsmMacro::NakedAsm => "naked_asm", - } - } - - const fn is_supported_option(&self, option: ast::InlineAsmOptions) -> bool { - match self { - AsmMacro::Asm => true, - AsmMacro::GlobalAsm => ast::InlineAsmOptions::GLOBAL_OPTIONS.contains(option), - AsmMacro::NakedAsm => ast::InlineAsmOptions::NAKED_OPTIONS.contains(option), - } - } -} - fn parse_args<'a>( ecx: &ExtCtxt<'a>, sp: Span, @@ -529,7 +500,7 @@ fn parse_reg<'a>( fn expand_preparsed_asm( ecx: &mut ExtCtxt<'_>, - asm_macro: ast::AsmMacro, + asm_macro: AsmMacro, args: AsmArgs, ) -> ExpandResult, ()> { let mut template = vec![]; @@ -872,7 +843,7 @@ pub(super) fn expand_naked_asm<'cx>( sp: Span, tts: TokenStream, ) -> MacroExpanderResult<'cx> { - ExpandResult::Ready(match parse_args(ecx, sp, tts, false) { + ExpandResult::Ready(match parse_args(ecx, sp, tts, AsmMacro::NakedAsm) { Ok(args) => { let ExpandResult::Ready(mac) = expand_preparsed_asm(ecx, AsmMacro::NakedAsm, args) else { @@ -940,32 +911,3 @@ pub(super) fn expand_global_asm<'cx>( } }) } - -pub(super) fn expand_naked_asm<'cx>( - ecx: &'cx mut ExtCtxt<'_>, - sp: Span, - tts: TokenStream, -) -> MacroExpanderResult<'cx> { - ExpandResult::Ready(match parse_args(ecx, sp, tts, AsmMacro::NakedAsm) { - Ok(args) => { - let ExpandResult::Ready(mac) = expand_preparsed_asm(ecx, args) else { - return ExpandResult::Retry(()); - }; - let expr = match mac { - Ok(inline_asm) => P(ast::Expr { - id: ast::DUMMY_NODE_ID, - kind: ast::ExprKind::InlineAsm(P(inline_asm)), - span: sp, - attrs: ast::AttrVec::new(), - tokens: None, - }), - Err(guar) => DummyResult::raw_expr(sp, Some(guar)), - }; - MacEager::expr(expr) - } - Err(err) => { - let guar = err.emit(); - DummyResult::any(sp, guar) - } - }) -} diff --git a/compiler/rustc_error_codes/src/error_codes/E0787.md b/compiler/rustc_error_codes/src/error_codes/E0787.md index cee50829270..f5c5faa066b 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0787.md +++ b/compiler/rustc_error_codes/src/error_codes/E0787.md @@ -11,11 +11,10 @@ pub extern "C" fn f() -> u32 { } ``` -The naked functions must be defined using a single inline assembly -block. +The naked function must be defined using a single `naked_asm!` assembly block. The execution must never fall through past the end of the assembly -code so the block must use `noreturn` option. The asm block can also +code, so it must either return or diverge. The asm block can also use `att_syntax` and `raw` options, but others options are not allowed. The asm block must not contain any operands other than `const` and diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 2d718295374..5c2f39f879c 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -3507,7 +3507,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } fn check_expr_asm(&self, asm: &'tcx hir::InlineAsm<'tcx>) -> Ty<'tcx> { - let mut diverge = asm.options.contains(ast::InlineAsmOptions::NORETURN); + let mut diverge = match asm.asm_macro { + rustc_ast::AsmMacro::Asm => asm.options.contains(ast::InlineAsmOptions::NORETURN), + rustc_ast::AsmMacro::GlobalAsm => true, + rustc_ast::AsmMacro::NakedAsm => true, + }; for (op, _op_sp) in asm.operands { match op { diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index f2682acf8aa..1b1d1b1fb72 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -488,9 +488,9 @@ passes_naked_asm_outside_naked_fn = the `naked_asm!` macro can only be used in functions marked with `#[naked]` passes_naked_functions_asm_block = - naked functions must contain a single asm block - .label_multiple_asm = multiple asm blocks are unsupported in naked functions - .label_non_asm = non-asm is unsupported in naked functions + naked functions must contain a single `naked_asm!` invocation + .label_multiple_asm = multiple `naked_asm!` invocations are not allowed in naked functions + .label_non_asm = not allowed in naked functions passes_naked_functions_asm_options = asm options unsupported in naked functions: {$unsupported_options} @@ -500,9 +500,9 @@ passes_naked_functions_incompatible_attribute = .label = the `{$attr}` attribute is incompatible with `#[naked]` .naked_attribute = function marked with `#[naked]` here -passes_naked_functions_must_use_noreturn = - asm in naked functions must use `noreturn` option - .suggestion = consider specifying that the asm block is responsible for returning from the function +passes_naked_functions_must_naked_asm = + the `asm!` macro is not allowed in naked functions + .suggestion = consider using the `naked_asm!` macro instead passes_naked_functions_operands = only `const` and `sym` operands are supported in naked functions diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index 29a087bf759..c46768ace53 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -1202,12 +1202,12 @@ pub(crate) struct NakedFunctionsAsmOptions { } #[derive(Diagnostic)] -#[diag(passes_naked_functions_must_use_noreturn, code = E0787)] -pub(crate) struct NakedFunctionsMustUseNoreturn { +#[diag(passes_naked_functions_must_naked_asm, code = E0787)] +pub(crate) struct NakedFunctionsMustNakedAsm { #[primary_span] pub span: Span, - #[suggestion(code = ", options(noreturn)", applicability = "machine-applicable")] - pub last_span: Span, + #[suggestion(code = "naked_asm!", applicability = "machine-applicable")] + pub macro_span: Span, } #[derive(Diagnostic)] diff --git a/compiler/rustc_passes/src/naked_functions.rs b/compiler/rustc_passes/src/naked_functions.rs index 8d3f7e0231f..6046c728430 100644 --- a/compiler/rustc_passes/src/naked_functions.rs +++ b/compiler/rustc_passes/src/naked_functions.rs @@ -10,13 +10,13 @@ use rustc_middle::hir::nested_filter::OnlyBodies; use rustc_middle::query::Providers; use rustc_middle::ty::TyCtxt; use rustc_session::lint::builtin::UNDEFINED_NAKED_FUNCTION_ABI; -use rustc_span::Span; use rustc_span::symbol::sym; +use rustc_span::{BytePos, Span}; use rustc_target::spec::abi::Abi; use crate::errors::{ NakedAsmOutsideNakedFn, NakedFunctionsAsmBlock, NakedFunctionsAsmOptions, - NakedFunctionsMustUseNoreturn, NakedFunctionsOperands, NoPatterns, ParamsNotAllowed, + NakedFunctionsMustNakedAsm, NakedFunctionsOperands, NoPatterns, ParamsNotAllowed, UndefinedNakedFunctionAbi, }; @@ -121,21 +121,29 @@ impl<'tcx> Visitor<'tcx> for CheckParameters<'tcx> { fn check_asm<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId, body: &'tcx hir::Body<'tcx>) { let mut this = CheckInlineAssembly { tcx, items: Vec::new() }; this.visit_body(body); - if let [(ItemKind::Asm | ItemKind::Err, _)] = this.items[..] { + if let [(ItemKind::NakedAsm | ItemKind::Err, _)] = this.items[..] { // Ok. } else { let mut must_show_error = false; - let mut has_asm = false; + let mut has_naked_asm = false; let mut has_err = false; let mut multiple_asms = vec![]; let mut non_asms = vec![]; for &(kind, span) in &this.items { match kind { - ItemKind::Asm if has_asm => { + ItemKind::NakedAsm if has_naked_asm => { must_show_error = true; multiple_asms.push(span); } - ItemKind::Asm => has_asm = true, + ItemKind::NakedAsm => has_naked_asm = true, + ItemKind::InlineAsm => { + has_err = true; + + // the span that contains the `asm!` call, + // so tooling can replace it with `naked_asm!` + let macro_span = span.with_hi(span.lo() + BytePos("asm!".len() as u32)); + tcx.dcx().emit_err(NakedFunctionsMustNakedAsm { span, macro_span }); + } ItemKind::NonAsm => { must_show_error = true; non_asms.push(span); @@ -164,7 +172,8 @@ struct CheckInlineAssembly<'tcx> { #[derive(Copy, Clone)] enum ItemKind { - Asm, + NakedAsm, + InlineAsm, NonAsm, Err, } @@ -205,8 +214,18 @@ impl<'tcx> CheckInlineAssembly<'tcx> { } ExprKind::InlineAsm(asm) => { - self.items.push((ItemKind::Asm, span)); - self.check_inline_asm(asm, span); + match asm.asm_macro { + rustc_ast::AsmMacro::Asm => { + self.items.push((ItemKind::InlineAsm, span)); + } + rustc_ast::AsmMacro::NakedAsm => { + self.items.push((ItemKind::NakedAsm, span)); + self.check_inline_asm(asm, span); + } + rustc_ast::AsmMacro::GlobalAsm => { + // not allowed in this position + } + } } ExprKind::DropTemps(..) | ExprKind::Block(..) => { @@ -250,16 +269,6 @@ impl<'tcx> CheckInlineAssembly<'tcx> { .join(", "), }); } - - if !asm.options.contains(InlineAsmOptions::NORETURN) { - let last_span = asm - .operands - .last() - .map_or_else(|| asm.template_strs.last().unwrap().2, |op| op.1) - .shrink_to_hi(); - - self.tcx.dcx().emit_err(NakedFunctionsMustUseNoreturn { span, last_span }); - } } } diff --git a/library/core/src/arch.rs b/library/core/src/arch.rs index f1a0739128c..4945c045bc6 100644 --- a/library/core/src/arch.rs +++ b/library/core/src/arch.rs @@ -77,17 +77,3 @@ pub macro naked_asm("assembly template", $(operands,)* $(options($(option),*))?) pub macro global_asm("assembly template", $(operands,)* $(options($(option),*))?) { /* compiler built-in */ } - -/// Inline assembly used in combination with `#[naked]` functions. -/// -/// Refer to [Rust By Example] for a usage guide and the [reference] for -/// detailed information about the syntax and available options. -/// -/// [Rust By Example]: https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html -/// [reference]: https://doc.rust-lang.org/nightly/reference/inline-assembly.html -#[unstable(feature = "naked_functions", issue = "90957")] -#[rustc_builtin_macro] -#[cfg(not(bootstrap))] -pub macro naked_asm("assembly template", $(operands,)* $(options($(option),*))?) { - /* compiler built-in */ -} diff --git a/src/tools/rustfmt/src/parse/macros/asm.rs b/src/tools/rustfmt/src/parse/macros/asm.rs index 5d30171e295..0c37d12490e 100644 --- a/src/tools/rustfmt/src/parse/macros/asm.rs +++ b/src/tools/rustfmt/src/parse/macros/asm.rs @@ -1,5 +1,5 @@ use rustc_ast::ast; -use rustc_builtin_macros::asm::{parse_asm_args, AsmArgs, AsmMacro}; +use rustc_builtin_macros::asm::{parse_asm_args, AsmArgs}; use crate::rewrite::RewriteContext; @@ -7,5 +7,5 @@ use crate::rewrite::RewriteContext; pub(crate) fn parse_asm(context: &RewriteContext<'_>, mac: &ast::MacCall) -> Option { let ts = mac.args.tokens.clone(); let mut parser = super::build_parser(context, ts); - parse_asm_args(&mut parser, mac.span(), AsmMacro::Asm).ok() + parse_asm_args(&mut parser, mac.span(), ast::AsmMacro::Asm).ok() } diff --git a/tests/codegen/naked-fn/aligned.rs b/tests/codegen/naked-fn/aligned.rs index d5faac44836..3bbd67981e5 100644 --- a/tests/codegen/naked-fn/aligned.rs +++ b/tests/codegen/naked-fn/aligned.rs @@ -4,7 +4,7 @@ #![crate_type = "lib"] #![feature(naked_functions, fn_align)] -use std::arch::asm; +use std::arch::naked_asm; // CHECK: Function Attrs: naked // CHECK-NEXT: define{{.*}}void @naked_empty() @@ -16,5 +16,5 @@ pub unsafe extern "C" fn naked_empty() { // CHECK-NEXT: start: // CHECK-NEXT: call void asm // CHECK-NEXT: unreachable - asm!("ret", options(noreturn)); + naked_asm!("ret"); } diff --git a/tests/codegen/naked-fn/naked-functions.rs b/tests/codegen/naked-fn/naked-functions.rs index 2b2625429f8..3f7447af599 100644 --- a/tests/codegen/naked-fn/naked-functions.rs +++ b/tests/codegen/naked-fn/naked-functions.rs @@ -14,7 +14,7 @@ pub unsafe extern "C" fn naked_empty() { // CHECK-NEXT: {{.+}}: // CHECK-NEXT: call void asm // CHECK-NEXT: unreachable - naked_asm!("ret", options(noreturn)); + naked_asm!("ret"); } // CHECK: Function Attrs: naked @@ -25,5 +25,5 @@ pub unsafe extern "C" fn naked_with_args_and_return(a: isize, b: isize) -> isize // CHECK-NEXT: {{.+}}: // CHECK-NEXT: call void asm // CHECK-NEXT: unreachable - naked_asm!("lea rax, [rdi + rsi]", "ret", options(noreturn)); + naked_asm!("lea rax, [rdi + rsi]", "ret"); } diff --git a/tests/codegen/naked-fn/naked-nocoverage.rs b/tests/codegen/naked-fn/naked-nocoverage.rs index d73c5b7fd26..f63661bcd3a 100644 --- a/tests/codegen/naked-fn/naked-nocoverage.rs +++ b/tests/codegen/naked-fn/naked-nocoverage.rs @@ -6,7 +6,7 @@ //@ compile-flags: -Cinstrument-coverage #![crate_type = "lib"] #![feature(naked_functions)] -use std::arch::asm; +use std::arch::naked_asm; #[naked] #[no_mangle] @@ -15,5 +15,5 @@ pub unsafe extern "C" fn f() { // CHECK-NEXT: start: // CHECK-NEXT: call void asm // CHECK-NEXT: unreachable - asm!("", options(noreturn)); + naked_asm!(""); } diff --git a/tests/codegen/naked-fn/naked-noinline.rs b/tests/codegen/naked-fn/naked-noinline.rs index c1e8f368249..6ea36d96783 100644 --- a/tests/codegen/naked-fn/naked-noinline.rs +++ b/tests/codegen/naked-fn/naked-noinline.rs @@ -5,7 +5,7 @@ #![crate_type = "lib"] #![feature(naked_functions)] -use std::arch::asm; +use std::arch::naked_asm; #[naked] #[no_mangle] @@ -15,7 +15,7 @@ pub unsafe extern "C" fn f() { // CHECK: define {{(dso_local )?}}void @f() unnamed_addr [[ATTR:#[0-9]+]] // CHECK-NEXT: start: // CHECK-NEXT: call void asm - asm!("", options(noreturn)); + naked_asm!(""); } #[no_mangle] diff --git a/tests/ui/asm/naked-functions-ffi.rs b/tests/ui/asm/naked-functions-ffi.rs index 6b32290905d..b78d1e6a0d1 100644 --- a/tests/ui/asm/naked-functions-ffi.rs +++ b/tests/ui/asm/naked-functions-ffi.rs @@ -10,6 +10,6 @@ pub extern "C" fn naked(p: char) -> u128 { //~^ WARN uses type `char` //~| WARN uses type `u128` unsafe { - naked_asm!("", options(noreturn)); + naked_asm!(""); } } diff --git a/tests/ui/asm/naked-functions-inline.rs b/tests/ui/asm/naked-functions-inline.rs index a4df38e3347..74049e8ecbc 100644 --- a/tests/ui/asm/naked-functions-inline.rs +++ b/tests/ui/asm/naked-functions-inline.rs @@ -19,7 +19,7 @@ pub unsafe extern "C" fn inline_hint() { #[naked] #[inline(always)] //~^ ERROR [E0736] -<<<<<<< HEAD +pub unsafe extern "C" fn inline_always() { naked_asm!(""); } diff --git a/tests/ui/asm/naked-functions-instruction-set.rs b/tests/ui/asm/naked-functions-instruction-set.rs index 6c6dcdf0087..37c7b52c191 100644 --- a/tests/ui/asm/naked-functions-instruction-set.rs +++ b/tests/ui/asm/naked-functions-instruction-set.rs @@ -19,12 +19,12 @@ trait Sized {} #[naked] #[instruction_set(arm::t32)] unsafe extern "C" fn test_thumb() { - naked_asm!("bx lr", options(noreturn)); + naked_asm!("bx lr"); } #[no_mangle] #[naked] #[instruction_set(arm::t32)] unsafe extern "C" fn test_arm() { - naked_asm!("bx lr", options(noreturn)); + naked_asm!("bx lr"); } diff --git a/tests/ui/asm/naked-functions-testattrs.rs b/tests/ui/asm/naked-functions-testattrs.rs index 2532e6e86d6..7e373270e9f 100644 --- a/tests/ui/asm/naked-functions-testattrs.rs +++ b/tests/ui/asm/naked-functions-testattrs.rs @@ -12,7 +12,7 @@ use std::arch::naked_asm; #[naked] //~^ ERROR [E0736] fn test_naked() { - unsafe { naked_asm!("", options(noreturn)) }; + unsafe { naked_asm!("") }; } #[should_panic] @@ -20,7 +20,7 @@ fn test_naked() { #[naked] //~^ ERROR [E0736] fn test_naked_should_panic() { - unsafe { naked_asm!("", options(noreturn)) }; + unsafe { naked_asm!("") }; } #[ignore] @@ -28,12 +28,12 @@ fn test_naked_should_panic() { #[naked] //~^ ERROR [E0736] fn test_naked_ignore() { - unsafe { naked_asm!("", options(noreturn)) }; + unsafe { naked_asm!("") }; } #[bench] #[naked] //~^ ERROR [E0736] fn bench_naked() { - unsafe { naked_asm!("", options(noreturn)) }; + unsafe { naked_asm!("") }; } diff --git a/tests/ui/asm/naked-functions-unused.rs b/tests/ui/asm/naked-functions-unused.rs index 6d3cc0afed8..c27037819a4 100644 --- a/tests/ui/asm/naked-functions-unused.rs +++ b/tests/ui/asm/naked-functions-unused.rs @@ -67,7 +67,7 @@ pub mod naked { #[naked] pub extern "C" fn function(a: usize, b: usize) -> usize { unsafe { - naked_asm!("", options(noreturn)); + naked_asm!(""); } } @@ -77,14 +77,14 @@ pub mod naked { #[naked] pub extern "C" fn associated(a: usize, b: usize) -> usize { unsafe { - naked_asm!("", options(noreturn)); + naked_asm!(""); } } #[naked] pub extern "C" fn method(&self, a: usize, b: usize) -> usize { unsafe { - naked_asm!("", options(noreturn)); + naked_asm!(""); } } } @@ -93,14 +93,14 @@ pub mod naked { #[naked] extern "C" fn trait_associated(a: usize, b: usize) -> usize { unsafe { - naked_asm!("", options(noreturn)); + naked_asm!(""); } } #[naked] extern "C" fn trait_method(&self, a: usize, b: usize) -> usize { unsafe { - naked_asm!("", options(noreturn)); + naked_asm!(""); } } } diff --git a/tests/ui/asm/naked-functions.rs b/tests/ui/asm/naked-functions.rs index 86c89ea1262..5c58f1498cc 100644 --- a/tests/ui/asm/naked-functions.rs +++ b/tests/ui/asm/naked-functions.rs @@ -6,7 +6,13 @@ #![feature(asm_unwind, linkage)] #![crate_type = "lib"] -use std::arch::naked_asm; +use std::arch::{asm, naked_asm}; + +#[naked] +pub unsafe extern "C" fn inline_asm_macro() { + asm!("", options(raw)); + //~^ERROR the `asm!` macro is not allowed in naked functions +} #[repr(C)] pub struct P { @@ -25,12 +31,12 @@ pub unsafe extern "C" fn patterns( P { x, y }: P, //~^ ERROR patterns not allowed in naked function parameters ) { - naked_asm!("", options(noreturn)) + naked_asm!("") } #[naked] pub unsafe extern "C" fn inc(a: u32) -> u32 { - //~^ ERROR naked functions must contain a single asm block + //~^ ERROR naked functions must contain a single `naked_asm!` invocation a + 1 //~^ ERROR referencing function parameters is not allowed in naked functions } @@ -38,19 +44,19 @@ pub unsafe extern "C" fn inc(a: u32) -> u32 { #[naked] #[allow(asm_sub_register)] pub unsafe extern "C" fn inc_asm(a: u32) -> u32 { - naked_asm!("/* {0} */", in(reg) a, options(noreturn)) + naked_asm!("/* {0} */", in(reg) a) //~^ ERROR the `in` operand cannot be used with `naked_asm!` } #[naked] pub unsafe extern "C" fn inc_closure(a: u32) -> u32 { - //~^ ERROR naked functions must contain a single asm block + //~^ ERROR naked functions must contain a single `naked_asm!` invocation (|| a + 1)() } #[naked] pub unsafe extern "C" fn unsupported_operands() { - //~^ ERROR naked functions must contain a single asm block + //~^ ERROR naked functions must contain a single `naked_asm!` invocation let mut a = 0usize; let mut b = 0usize; let mut c = 0usize; @@ -72,27 +78,23 @@ pub unsafe extern "C" fn unsupported_operands() { #[naked] pub extern "C" fn missing_assembly() { - //~^ ERROR naked functions must contain a single asm block + //~^ ERROR naked functions must contain a single `naked_asm!` invocation } #[naked] pub extern "C" fn too_many_asm_blocks() { - //~^ ERROR naked functions must contain a single asm block + //~^ ERROR naked functions must contain a single `naked_asm!` invocation unsafe { - naked_asm!(""); - //~^ ERROR asm in naked functions must use `noreturn` option - naked_asm!(""); - //~^ ERROR asm in naked functions must use `noreturn` option - naked_asm!(""); - //~^ ERROR asm in naked functions must use `noreturn` option naked_asm!("", options(noreturn)); + //~^ ERROR the `noreturn` option cannot be used with `naked_asm!` + naked_asm!(""); } } pub fn outer(x: u32) -> extern "C" fn(usize) -> usize { #[naked] pub extern "C" fn inner(y: usize) -> usize { - //~^ ERROR naked functions must contain a single asm block + //~^ ERROR naked functions must contain a single `naked_asm!` invocation *&y //~^ ERROR referencing function parameters is not allowed in naked functions } @@ -101,7 +103,7 @@ pub fn outer(x: u32) -> extern "C" fn(usize) -> usize { #[naked] unsafe extern "C" fn invalid_options() { - naked_asm!("", options(nomem, preserves_flags, noreturn)); + naked_asm!("", options(nomem, preserves_flags)); //~^ ERROR the `nomem` option cannot be used with `naked_asm!` //~| ERROR the `preserves_flags` option cannot be used with `naked_asm!` } @@ -112,31 +114,30 @@ unsafe extern "C" fn invalid_options_continued() { //~^ ERROR the `readonly` option cannot be used with `naked_asm!` //~| ERROR the `nostack` option cannot be used with `naked_asm!` //~| ERROR the `pure` option cannot be used with `naked_asm!` - //~| ERROR asm in naked functions must use `noreturn` option } #[naked] unsafe extern "C" fn invalid_may_unwind() { - naked_asm!("", options(noreturn, may_unwind)); + naked_asm!("", options(may_unwind)); //~^ ERROR the `may_unwind` option cannot be used with `naked_asm!` } #[naked] pub unsafe fn default_abi() { //~^ WARN Rust ABI is unsupported in naked functions - naked_asm!("", options(noreturn)); + naked_asm!(""); } #[naked] pub unsafe fn rust_abi() { //~^ WARN Rust ABI is unsupported in naked functions - naked_asm!("", options(noreturn)); + naked_asm!(""); } #[naked] pub extern "C" fn valid_a() -> T { unsafe { - naked_asm!("", options(noreturn)); + naked_asm!(""); } } @@ -145,7 +146,7 @@ pub extern "C" fn valid_b() { unsafe { { { - naked_asm!("", options(noreturn)); + naked_asm!(""); }; }; } @@ -153,13 +154,13 @@ pub extern "C" fn valid_b() { #[naked] pub unsafe extern "C" fn valid_c() { - naked_asm!("", options(noreturn)); + naked_asm!(""); } #[cfg(target_arch = "x86_64")] #[naked] pub unsafe extern "C" fn valid_att_syntax() { - naked_asm!("", options(noreturn, att_syntax)); + naked_asm!("", options(att_syntax)); } #[naked] @@ -173,7 +174,7 @@ pub unsafe extern "C" fn allow_compile_error(a: u32) -> u32 { pub unsafe extern "C" fn allow_compile_error_and_asm(a: u32) -> u32 { compile_error!("this is a user specified error"); //~^ ERROR this is a user specified error - naked_asm!("", options(noreturn)) + naked_asm!("") } #[naked] @@ -186,7 +187,7 @@ pub unsafe extern "C" fn invalid_asm_syntax(a: u32) -> u32 { #[cfg_attr(target_pointer_width = "64", no_mangle)] #[naked] pub unsafe extern "C" fn compatible_cfg_attributes() { - naked_asm!("", options(noreturn, att_syntax)); + naked_asm!("", options(att_syntax)); } #[allow(dead_code)] @@ -195,13 +196,13 @@ pub unsafe extern "C" fn compatible_cfg_attributes() { #[forbid(dead_code)] #[naked] pub unsafe extern "C" fn compatible_diagnostic_attributes() { - naked_asm!("", options(noreturn, raw)); + naked_asm!("", options(raw)); } #[deprecated = "test"] #[naked] pub unsafe extern "C" fn compatible_deprecated_attributes() { - naked_asm!("", options(noreturn, raw)); + naked_asm!("", options(raw)); } #[cfg(target_arch = "x86_64")] @@ -213,7 +214,6 @@ pub unsafe extern "C" fn compatible_must_use_attributes() -> u64 { mov rax, 42 ret ", - options(noreturn) ) } @@ -222,20 +222,20 @@ pub unsafe extern "C" fn compatible_must_use_attributes() -> u64 { #[no_mangle] #[naked] pub unsafe extern "C" fn compatible_ffi_attributes_1() { - naked_asm!("", options(noreturn, raw)); + naked_asm!("", options(raw)); } #[cold] #[naked] pub unsafe extern "C" fn compatible_codegen_attributes() { - naked_asm!("", options(noreturn, raw)); + naked_asm!("", options(raw)); } #[cfg(target_arch = "x86_64")] #[target_feature(enable = "sse2")] #[naked] pub unsafe extern "C" fn compatible_target_feature() { - naked_asm!("", options(noreturn)); + naked_asm!(""); } #[doc = "foo bar baz"] @@ -244,11 +244,11 @@ pub unsafe extern "C" fn compatible_target_feature() { #[doc(alias = "ADocAlias")] #[naked] pub unsafe extern "C" fn compatible_doc_attributes() { - naked_asm!("", options(noreturn, raw)); + naked_asm!("", options(raw)); } #[linkage = "external"] #[naked] pub unsafe extern "C" fn compatible_linkage() { - naked_asm!("", options(noreturn, raw)); + naked_asm!("", options(raw)); } diff --git a/tests/ui/asm/naked-functions.stderr b/tests/ui/asm/naked-functions.stderr index 22c1946a960..1ceeafffd90 100644 --- a/tests/ui/asm/naked-functions.stderr +++ b/tests/ui/asm/naked-functions.stderr @@ -1,220 +1,184 @@ error: the `in` operand cannot be used with `naked_asm!` - --> $DIR/naked-functions.rs:41:29 + --> $DIR/naked-functions.rs:47:29 | -LL | naked_asm!("/* {0} */", in(reg) a, options(noreturn)) +LL | naked_asm!("/* {0} */", in(reg) a) | ^^ the `in` operand is not meaningful for global-scoped inline assembly, remove it error: the `in` operand cannot be used with `naked_asm!` - --> $DIR/naked-functions.rs:62:10 + --> $DIR/naked-functions.rs:68:10 | LL | in(reg) a, | ^^ the `in` operand is not meaningful for global-scoped inline assembly, remove it -error: the `nomem` option cannot be used with `naked_asm!` - --> $DIR/naked-functions.rs:104:28 +error: the `noreturn` option cannot be used with `naked_asm!` + --> $DIR/naked-functions.rs:88:32 | -LL | naked_asm!("", options(nomem, preserves_flags, noreturn)); +LL | naked_asm!("", options(noreturn)); + | ^^^^^^^^ the `noreturn` option is not meaningful for global-scoped inline assembly + +error: the `nomem` option cannot be used with `naked_asm!` + --> $DIR/naked-functions.rs:106:28 + | +LL | naked_asm!("", options(nomem, preserves_flags)); | ^^^^^ the `nomem` option is not meaningful for global-scoped inline assembly error: the `preserves_flags` option cannot be used with `naked_asm!` - --> $DIR/naked-functions.rs:104:35 + --> $DIR/naked-functions.rs:106:35 | -LL | naked_asm!("", options(nomem, preserves_flags, noreturn)); +LL | naked_asm!("", options(nomem, preserves_flags)); | ^^^^^^^^^^^^^^^ the `preserves_flags` option is not meaningful for global-scoped inline assembly error: the `readonly` option cannot be used with `naked_asm!` - --> $DIR/naked-functions.rs:111:28 + --> $DIR/naked-functions.rs:113:28 | LL | naked_asm!("", options(readonly, nostack), options(pure)); | ^^^^^^^^ the `readonly` option is not meaningful for global-scoped inline assembly error: the `nostack` option cannot be used with `naked_asm!` - --> $DIR/naked-functions.rs:111:38 + --> $DIR/naked-functions.rs:113:38 | LL | naked_asm!("", options(readonly, nostack), options(pure)); | ^^^^^^^ the `nostack` option is not meaningful for global-scoped inline assembly error: the `pure` option cannot be used with `naked_asm!` - --> $DIR/naked-functions.rs:111:56 + --> $DIR/naked-functions.rs:113:56 | LL | naked_asm!("", options(readonly, nostack), options(pure)); | ^^^^ the `pure` option is not meaningful for global-scoped inline assembly error: the `may_unwind` option cannot be used with `naked_asm!` - --> $DIR/naked-functions.rs:120:38 + --> $DIR/naked-functions.rs:121:28 | -LL | naked_asm!("", options(noreturn, may_unwind)); - | ^^^^^^^^^^ the `may_unwind` option is not meaningful for global-scoped inline assembly +LL | naked_asm!("", options(may_unwind)); + | ^^^^^^^^^^ the `may_unwind` option is not meaningful for global-scoped inline assembly error: this is a user specified error - --> $DIR/naked-functions.rs:168:5 + --> $DIR/naked-functions.rs:169:5 | LL | compile_error!("this is a user specified error") | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this is a user specified error - --> $DIR/naked-functions.rs:174:5 + --> $DIR/naked-functions.rs:175:5 | LL | compile_error!("this is a user specified error"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: asm template must be a string literal - --> $DIR/naked-functions.rs:181:16 + --> $DIR/naked-functions.rs:182:16 | LL | naked_asm!(invalid_syntax) | ^^^^^^^^^^^^^^ +error[E0787]: the `asm!` macro is not allowed in naked functions + --> $DIR/naked-functions.rs:13:5 + | +LL | asm!("", options(raw)); + | ----^^^^^^^^^^^^^^^^^^ + | | + | help: consider using the `naked_asm!` macro instead: `naked_asm!` + error: patterns not allowed in naked function parameters - --> $DIR/naked-functions.rs:19:5 + --> $DIR/naked-functions.rs:25:5 | LL | mut a: u32, | ^^^^^ error: patterns not allowed in naked function parameters - --> $DIR/naked-functions.rs:21:5 + --> $DIR/naked-functions.rs:27:5 | LL | &b: &i32, | ^^ error: patterns not allowed in naked function parameters - --> $DIR/naked-functions.rs:23:6 + --> $DIR/naked-functions.rs:29:6 | LL | (None | Some(_)): Option>, | ^^^^^^^^^^^^^^ error: patterns not allowed in naked function parameters - --> $DIR/naked-functions.rs:25:5 + --> $DIR/naked-functions.rs:31:5 | LL | P { x, y }: P, | ^^^^^^^^^^ error: referencing function parameters is not allowed in naked functions - --> $DIR/naked-functions.rs:34:5 + --> $DIR/naked-functions.rs:40:5 | LL | a + 1 | ^ | = help: follow the calling convention in asm block to use parameters -error[E0787]: naked functions must contain a single asm block - --> $DIR/naked-functions.rs:32:1 +error[E0787]: naked functions must contain a single `naked_asm!` invocation + --> $DIR/naked-functions.rs:38:1 | LL | pub unsafe extern "C" fn inc(a: u32) -> u32 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ LL | LL | a + 1 - | ----- non-asm is unsupported in naked functions + | ----- not allowed in naked functions -error[E0787]: naked functions must contain a single asm block - --> $DIR/naked-functions.rs:46:1 +error[E0787]: naked functions must contain a single `naked_asm!` invocation + --> $DIR/naked-functions.rs:52:1 | LL | pub unsafe extern "C" fn inc_closure(a: u32) -> u32 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ LL | LL | (|| a + 1)() - | ------------ non-asm is unsupported in naked functions + | ------------ not allowed in naked functions -error[E0787]: naked functions must contain a single asm block - --> $DIR/naked-functions.rs:52:1 +error[E0787]: naked functions must contain a single `naked_asm!` invocation + --> $DIR/naked-functions.rs:58:1 | LL | pub unsafe extern "C" fn unsupported_operands() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ LL | LL | let mut a = 0usize; - | ------------------- non-asm is unsupported in naked functions + | ------------------- not allowed in naked functions LL | let mut b = 0usize; - | ------------------- non-asm is unsupported in naked functions + | ------------------- not allowed in naked functions LL | let mut c = 0usize; - | ------------------- non-asm is unsupported in naked functions + | ------------------- not allowed in naked functions LL | let mut d = 0usize; - | ------------------- non-asm is unsupported in naked functions + | ------------------- not allowed in naked functions LL | let mut e = 0usize; - | ------------------- non-asm is unsupported in naked functions + | ------------------- not allowed in naked functions -error[E0787]: naked functions must contain a single asm block - --> $DIR/naked-functions.rs:74:1 +error[E0787]: naked functions must contain a single `naked_asm!` invocation + --> $DIR/naked-functions.rs:80:1 | LL | pub extern "C" fn missing_assembly() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0787]: asm in naked functions must use `noreturn` option - --> $DIR/naked-functions.rs:82:9 - | -LL | naked_asm!(""); - | ^^^^^^^^^^^^^^ - | -help: consider specifying that the asm block is responsible for returning from the function - | -LL | naked_asm!("", options(noreturn)); - | +++++++++++++++++++ - -error[E0787]: asm in naked functions must use `noreturn` option - --> $DIR/naked-functions.rs:84:9 - | -LL | naked_asm!(""); - | ^^^^^^^^^^^^^^ - | -help: consider specifying that the asm block is responsible for returning from the function - | -LL | naked_asm!("", options(noreturn)); - | +++++++++++++++++++ - -error[E0787]: asm in naked functions must use `noreturn` option - --> $DIR/naked-functions.rs:86:9 - | -LL | naked_asm!(""); - | ^^^^^^^^^^^^^^ - | -help: consider specifying that the asm block is responsible for returning from the function - | -LL | naked_asm!("", options(noreturn)); - | +++++++++++++++++++ - -error[E0787]: naked functions must contain a single asm block - --> $DIR/naked-functions.rs:79:1 +error[E0787]: naked functions must contain a single `naked_asm!` invocation + --> $DIR/naked-functions.rs:85:1 | LL | pub extern "C" fn too_many_asm_blocks() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ... LL | naked_asm!(""); - | -------------- multiple asm blocks are unsupported in naked functions -LL | -LL | naked_asm!(""); - | -------------- multiple asm blocks are unsupported in naked functions -LL | -LL | naked_asm!("", options(noreturn)); - | --------------------------------- multiple asm blocks are unsupported in naked functions + | -------------- multiple `naked_asm!` invocations are not allowed in naked functions error: referencing function parameters is not allowed in naked functions - --> $DIR/naked-functions.rs:96:11 + --> $DIR/naked-functions.rs:98:11 | LL | *&y | ^ | = help: follow the calling convention in asm block to use parameters -error[E0787]: naked functions must contain a single asm block - --> $DIR/naked-functions.rs:94:5 +error[E0787]: naked functions must contain a single `naked_asm!` invocation + --> $DIR/naked-functions.rs:96:5 | LL | pub extern "C" fn inner(y: usize) -> usize { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ LL | LL | *&y - | --- non-asm is unsupported in naked functions - -error[E0787]: asm in naked functions must use `noreturn` option - --> $DIR/naked-functions.rs:111:5 - | -LL | naked_asm!("", options(readonly, nostack), options(pure)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -help: consider specifying that the asm block is responsible for returning from the function - | -LL | naked_asm!("", options(noreturn), options(readonly, nostack), options(pure)); - | +++++++++++++++++++ + | --- not allowed in naked functions warning: Rust ABI is unsupported in naked functions - --> $DIR/naked-functions.rs:125:1 + --> $DIR/naked-functions.rs:126:1 | LL | pub unsafe fn default_abi() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -222,11 +186,11 @@ LL | pub unsafe fn default_abi() { = note: `#[warn(undefined_naked_function_abi)]` on by default warning: Rust ABI is unsupported in naked functions - --> $DIR/naked-functions.rs:131:1 + --> $DIR/naked-functions.rs:132:1 | LL | pub unsafe fn rust_abi() { | ^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 27 previous errors; 2 warnings emitted +error: aborting due to 25 previous errors; 2 warnings emitted For more information about this error, try `rustc --explain E0787`. diff --git a/tests/ui/asm/naked-invalid-attr.rs b/tests/ui/asm/naked-invalid-attr.rs index 57edd57de99..4053c58fb51 100644 --- a/tests/ui/asm/naked-invalid-attr.rs +++ b/tests/ui/asm/naked-invalid-attr.rs @@ -4,7 +4,7 @@ #![feature(naked_functions)] #![naked] //~ ERROR should be applied to a function definition -use std::arch::asm; +use std::arch::naked_asm; extern "C" { #[naked] //~ ERROR should be applied to a function definition @@ -26,27 +26,28 @@ trait Invoke { impl Invoke for S { #[naked] extern "C" fn invoke(&self) { - unsafe { asm!("", options(noreturn)) } + unsafe { naked_asm!("") } } } #[naked] extern "C" fn ok() { - unsafe { asm!("", options(noreturn)) } + unsafe { naked_asm!("") } } impl S { #[naked] extern "C" fn g() { - unsafe { asm!("", options(noreturn)) } + unsafe { naked_asm!("") } } #[naked] extern "C" fn h(&self) { - unsafe { asm!("", options(noreturn)) } + unsafe { naked_asm!("") } } } fn main() { - #[naked] || {}; //~ ERROR should be applied to a function definition + #[naked] //~ ERROR should be applied to a function definition + || {}; } diff --git a/tests/ui/asm/naked-invalid-attr.stderr b/tests/ui/asm/naked-invalid-attr.stderr index e8ddccc854a..640f9d9510d 100644 --- a/tests/ui/asm/naked-invalid-attr.stderr +++ b/tests/ui/asm/naked-invalid-attr.stderr @@ -13,8 +13,10 @@ LL | | } error: attribute should be applied to a function definition --> $DIR/naked-invalid-attr.rs:51:5 | -LL | #[naked] || {}; - | ^^^^^^^^ ----- not a function definition +LL | #[naked] + | ^^^^^^^^ +LL | || {}; + | ----- not a function definition error: attribute should be applied to a function definition --> $DIR/naked-invalid-attr.rs:22:5 diff --git a/tests/ui/asm/naked-with-invalid-repr-attr.rs b/tests/ui/asm/naked-with-invalid-repr-attr.rs index 687fe1ad73d..18b9c1014c3 100644 --- a/tests/ui/asm/naked-with-invalid-repr-attr.rs +++ b/tests/ui/asm/naked-with-invalid-repr-attr.rs @@ -2,14 +2,14 @@ #![feature(naked_functions)] #![feature(fn_align)] #![crate_type = "lib"] -use std::arch::asm; +use std::arch::naked_asm; #[repr(C)] //~^ ERROR attribute should be applied to a struct, enum, or union [E0517] #[naked] extern "C" fn example1() { //~^ NOTE not a struct, enum, or union - unsafe { asm!("", options(noreturn)) } + unsafe { naked_asm!("") } } #[repr(transparent)] @@ -17,7 +17,7 @@ extern "C" fn example1() { #[naked] extern "C" fn example2() { //~^ NOTE not a struct, enum, or union - unsafe { asm!("", options(noreturn)) } + unsafe { naked_asm!("") } } #[repr(align(16), C)] @@ -25,7 +25,7 @@ extern "C" fn example2() { #[naked] extern "C" fn example3() { //~^ NOTE not a struct, enum, or union - unsafe { asm!("", options(noreturn)) } + unsafe { naked_asm!("") } } // note: two errors because of packed and C @@ -36,7 +36,7 @@ extern "C" fn example3() { extern "C" fn example4() { //~^ NOTE not a struct, enum, or union //~| NOTE not a struct or union - unsafe { asm!("", options(noreturn)) } + unsafe { naked_asm!("") } } #[repr(u8)] @@ -44,5 +44,5 @@ extern "C" fn example4() { #[naked] extern "C" fn example5() { //~^ NOTE not an enum - unsafe { asm!("", options(noreturn)) } + unsafe { naked_asm!("") } } diff --git a/tests/ui/asm/naked-with-invalid-repr-attr.stderr b/tests/ui/asm/naked-with-invalid-repr-attr.stderr index 3740f17a9dc..8248a8c1657 100644 --- a/tests/ui/asm/naked-with-invalid-repr-attr.stderr +++ b/tests/ui/asm/naked-with-invalid-repr-attr.stderr @@ -6,7 +6,7 @@ LL | #[repr(C)] ... LL | / extern "C" fn example1() { LL | | -LL | | unsafe { asm!("", options(noreturn)) } +LL | | unsafe { naked_asm!("") } LL | | } | |_- not a struct, enum, or union @@ -18,7 +18,7 @@ LL | #[repr(transparent)] ... LL | / extern "C" fn example2() { LL | | -LL | | unsafe { asm!("", options(noreturn)) } +LL | | unsafe { naked_asm!("") } LL | | } | |_- not a struct, enum, or union @@ -30,7 +30,7 @@ LL | #[repr(align(16), C)] ... LL | / extern "C" fn example3() { LL | | -LL | | unsafe { asm!("", options(noreturn)) } +LL | | unsafe { naked_asm!("") } LL | | } | |_- not a struct, enum, or union @@ -43,7 +43,7 @@ LL | #[repr(C, packed)] LL | / extern "C" fn example4() { LL | | LL | | -LL | | unsafe { asm!("", options(noreturn)) } +LL | | unsafe { naked_asm!("") } LL | | } | |_- not a struct, enum, or union @@ -56,7 +56,7 @@ LL | #[repr(C, packed)] LL | / extern "C" fn example4() { LL | | LL | | -LL | | unsafe { asm!("", options(noreturn)) } +LL | | unsafe { naked_asm!("") } LL | | } | |_- not a struct or union @@ -68,7 +68,7 @@ LL | #[repr(u8)] ... LL | / extern "C" fn example5() { LL | | -LL | | unsafe { asm!("", options(noreturn)) } +LL | | unsafe { naked_asm!("") } LL | | } | |_- not an enum diff --git a/tests/ui/asm/named-asm-labels.rs b/tests/ui/asm/named-asm-labels.rs index 043aab9029d..77831e679ed 100644 --- a/tests/ui/asm/named-asm-labels.rs +++ b/tests/ui/asm/named-asm-labels.rs @@ -12,7 +12,7 @@ #![feature(naked_functions)] -use std::arch::{asm, global_asm}; +use std::arch::{asm, global_asm, naked_asm}; #[no_mangle] pub static FOO: usize = 42; @@ -177,7 +177,7 @@ fn main() { // label or LTO can cause labels to break #[naked] pub extern "C" fn foo() -> i32 { - unsafe { asm!(".Lfoo: mov rax, {}; ret;", "nop", const 1, options(noreturn)) } + unsafe { naked_asm!(".Lfoo: mov rax, {}; ret;", "nop", const 1) } //~^ ERROR avoid using named labels } @@ -192,7 +192,7 @@ pub extern "C" fn bar() { pub extern "C" fn aaa() { fn _local() {} - unsafe { asm!(".Laaa: nop; ret;", options(noreturn)) } //~ ERROR avoid using named labels + unsafe { naked_asm!(".Laaa: nop; ret;") } //~ ERROR avoid using named labels } pub fn normal() { @@ -202,7 +202,7 @@ pub fn normal() { pub extern "C" fn bbb() { fn _very_local() {} - unsafe { asm!(".Lbbb: nop; ret;", options(noreturn)) } //~ ERROR avoid using named labels + unsafe { naked_asm!(".Lbbb: nop; ret;") } //~ ERROR avoid using named labels } fn _local2() {} @@ -221,7 +221,7 @@ fn closures() { || { #[naked] unsafe extern "C" fn _nested() { - asm!("ret;", options(noreturn)); + naked_asm!("ret;"); } unsafe { diff --git a/tests/ui/asm/named-asm-labels.stderr b/tests/ui/asm/named-asm-labels.stderr index e5e177fb8b8..44ce358c62b 100644 --- a/tests/ui/asm/named-asm-labels.stderr +++ b/tests/ui/asm/named-asm-labels.stderr @@ -475,10 +475,10 @@ LL | #[warn(named_asm_labels)] | ^^^^^^^^^^^^^^^^ error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:180:20 + --> $DIR/named-asm-labels.rs:180:26 | -LL | unsafe { asm!(".Lfoo: mov rax, {}; ret;", "nop", const 1, options(noreturn)) } - | ^^^^^ +LL | unsafe { naked_asm!(".Lfoo: mov rax, {}; ret;", "nop", const 1) } + | ^^^^^ | = help: only local labels of the form `:` should be used in inline asm = note: see the asm section of Rust By Example for more information @@ -493,19 +493,19 @@ LL | unsafe { asm!(".Lbar: mov rax, {}; ret;", "nop", const 1, options(noret = note: see the asm section of Rust By Example for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:195:20 + --> $DIR/named-asm-labels.rs:195:26 | -LL | unsafe { asm!(".Laaa: nop; ret;", options(noreturn)) } - | ^^^^^ +LL | unsafe { naked_asm!(".Laaa: nop; ret;") } + | ^^^^^ | = help: only local labels of the form `:` should be used in inline asm = note: see the asm section of Rust By Example for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:205:24 + --> $DIR/named-asm-labels.rs:205:30 | -LL | unsafe { asm!(".Lbbb: nop; ret;", options(noreturn)) } - | ^^^^^ +LL | unsafe { naked_asm!(".Lbbb: nop; ret;") } + | ^^^^^ | = help: only local labels of the form `:` should be used in inline asm = note: see the asm section of Rust By Example for more information diff --git a/tests/ui/feature-gates/feature-gate-naked_functions.rs b/tests/ui/feature-gates/feature-gate-naked_functions.rs index c8802ea4c31..5fe0bbdc774 100644 --- a/tests/ui/feature-gates/feature-gate-naked_functions.rs +++ b/tests/ui/feature-gates/feature-gate-naked_functions.rs @@ -6,7 +6,7 @@ use std::arch::naked_asm; #[naked] //~^ the `#[naked]` attribute is an experimental feature extern "C" fn naked() { - naked_asm!("", options(noreturn)) + naked_asm!("") //~^ ERROR use of unstable library feature 'naked_functions' //~| ERROR: requires unsafe } @@ -14,7 +14,7 @@ extern "C" fn naked() { #[naked] //~^ the `#[naked]` attribute is an experimental feature extern "C" fn naked_2() -> isize { - naked_asm!("", options(noreturn)) + naked_asm!("") //~^ ERROR use of unstable library feature 'naked_functions' //~| ERROR: requires unsafe } From bc0a9543a3e8843a908d3e256e70b75441ef2743 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Thu, 5 Sep 2024 17:48:13 +0200 Subject: [PATCH 630/683] more `asm!` -> `naked_asm!` in tests --- tests/assembly/aarch64-naked-fn-no-bti-prolog.rs | 4 ++-- tests/assembly/x86_64-naked-fn-no-cet-prolog.rs | 4 ++-- tests/codegen/cffi/c-variadic-naked.rs | 3 +-- tests/crashes/124375.rs | 4 ++-- .../run-make/naked-symbol-visibility/a_rust_dylib.rs | 12 ++++++------ .../feature-gate-naked_functions.stderr | 12 ++++++------ .../rfcs/rfc-2091-track-caller/error-with-naked.rs | 6 +++--- 7 files changed, 22 insertions(+), 23 deletions(-) diff --git a/tests/assembly/aarch64-naked-fn-no-bti-prolog.rs b/tests/assembly/aarch64-naked-fn-no-bti-prolog.rs index 8ee6f6792e9..46e627eaa00 100644 --- a/tests/assembly/aarch64-naked-fn-no-bti-prolog.rs +++ b/tests/assembly/aarch64-naked-fn-no-bti-prolog.rs @@ -5,7 +5,7 @@ #![crate_type = "lib"] #![feature(naked_functions)] -use std::arch::asm; +use std::arch::naked_asm; // The problem at hand: Rust has adopted a fairly strict meaning for "naked functions", // meaning "no prologue whatsoever, no, really, not one instruction." @@ -17,5 +17,5 @@ use std::arch::asm; pub unsafe extern "C" fn _hlt() -> ! { // CHECK-NOT: hint #34 // CHECK: hlt #0x1 - asm!("hlt #1", options(noreturn)) + naked_asm!("hlt #1") } diff --git a/tests/assembly/x86_64-naked-fn-no-cet-prolog.rs b/tests/assembly/x86_64-naked-fn-no-cet-prolog.rs index a5683874182..54e1d93c68b 100644 --- a/tests/assembly/x86_64-naked-fn-no-cet-prolog.rs +++ b/tests/assembly/x86_64-naked-fn-no-cet-prolog.rs @@ -5,7 +5,7 @@ #![crate_type = "lib"] #![feature(naked_functions)] -use std::arch::asm; +use std::arch::naked_asm; // The problem at hand: Rust has adopted a fairly strict meaning for "naked functions", // meaning "no prologue whatsoever, no, really, not one instruction." @@ -17,7 +17,7 @@ use std::arch::asm; pub unsafe extern "sysv64" fn will_halt() -> ! { // CHECK-NOT: endbr{{32|64}} // CHECK: hlt - asm!("hlt", options(noreturn)) + naked_asm!("hlt") } // what about aarch64? diff --git a/tests/codegen/cffi/c-variadic-naked.rs b/tests/codegen/cffi/c-variadic-naked.rs index 807873ea368..24b69c5f59e 100644 --- a/tests/codegen/cffi/c-variadic-naked.rs +++ b/tests/codegen/cffi/c-variadic-naked.rs @@ -12,8 +12,7 @@ pub unsafe extern "C" fn c_variadic(_: usize, _: ...) { // CHECK-NOT: va_start // CHECK-NOT: alloca - core::arch::asm! { + core::arch::naked_asm! { "ret", - options(noreturn), } } diff --git a/tests/crashes/124375.rs b/tests/crashes/124375.rs index 7165655178d..1d877caeb8b 100644 --- a/tests/crashes/124375.rs +++ b/tests/crashes/124375.rs @@ -3,9 +3,9 @@ //@ only-x86_64 #![crate_type = "lib"] #![feature(naked_functions)] -use std::arch::asm; +use std::arch::naked_asm; #[naked] pub unsafe extern "C" fn naked_with_args_and_return(a: isize, b: isize) -> isize { - asm!("lea rax, [rdi + rsi]", "ret", options(noreturn)); + naked_asm!("lea rax, [rdi + rsi]", "ret"); } diff --git a/tests/run-make/naked-symbol-visibility/a_rust_dylib.rs b/tests/run-make/naked-symbol-visibility/a_rust_dylib.rs index f00123f006b..517c8da656a 100644 --- a/tests/run-make/naked-symbol-visibility/a_rust_dylib.rs +++ b/tests/run-make/naked-symbol-visibility/a_rust_dylib.rs @@ -1,7 +1,7 @@ #![feature(naked_functions, asm_const, linkage)] #![crate_type = "dylib"] -use std::arch::asm; +use std::arch::naked_asm; pub trait TraitWithConst { const COUNT: u32; @@ -28,7 +28,7 @@ extern "C" fn private_vanilla() -> u32 { #[naked] extern "C" fn private_naked() -> u32 { - unsafe { asm!("mov rax, 42", "ret", options(noreturn)) } + unsafe { naked_asm!("mov rax, 42", "ret") } } #[no_mangle] @@ -39,7 +39,7 @@ pub extern "C" fn public_vanilla() -> u32 { #[naked] #[no_mangle] pub extern "C" fn public_naked() -> u32 { - unsafe { asm!("mov rax, 42", "ret", options(noreturn)) } + unsafe { naked_asm!("mov rax, 42", "ret") } } pub extern "C" fn public_vanilla_generic() -> u32 { @@ -48,7 +48,7 @@ pub extern "C" fn public_vanilla_generic() -> u32 { #[naked] pub extern "C" fn public_naked_generic() -> u32 { - unsafe { asm!("mov rax, {}", "ret", const T::COUNT, options(noreturn)) } + unsafe { naked_asm!("mov rax, {}", "ret", const T::COUNT) } } #[linkage = "external"] @@ -59,7 +59,7 @@ extern "C" fn vanilla_external_linkage() -> u32 { #[naked] #[linkage = "external"] extern "C" fn naked_external_linkage() -> u32 { - unsafe { asm!("mov rax, 42", "ret", options(noreturn)) } + unsafe { naked_asm!("mov rax, 42", "ret") } } #[cfg(not(windows))] @@ -72,7 +72,7 @@ extern "C" fn vanilla_weak_linkage() -> u32 { #[cfg(not(windows))] #[linkage = "weak"] extern "C" fn naked_weak_linkage() -> u32 { - unsafe { asm!("mov rax, 42", "ret", options(noreturn)) } + unsafe { naked_asm!("mov rax, 42", "ret", options(noreturn)) } } // functions that are declared in an `extern "C"` block are currently not exported diff --git a/tests/ui/feature-gates/feature-gate-naked_functions.stderr b/tests/ui/feature-gates/feature-gate-naked_functions.stderr index 5fecc218a16..709234eb023 100644 --- a/tests/ui/feature-gates/feature-gate-naked_functions.stderr +++ b/tests/ui/feature-gates/feature-gate-naked_functions.stderr @@ -1,7 +1,7 @@ error[E0658]: use of unstable library feature 'naked_functions' --> $DIR/feature-gate-naked_functions.rs:9:5 | -LL | naked_asm!("", options(noreturn)) +LL | naked_asm!("") | ^^^^^^^^^ | = note: see issue #90957 for more information @@ -11,7 +11,7 @@ LL | naked_asm!("", options(noreturn)) error[E0658]: use of unstable library feature 'naked_functions' --> $DIR/feature-gate-naked_functions.rs:17:5 | -LL | naked_asm!("", options(noreturn)) +LL | naked_asm!("") | ^^^^^^^^^ | = note: see issue #90957 for more information @@ -51,16 +51,16 @@ LL | use std::arch::naked_asm; error[E0133]: use of inline assembly is unsafe and requires unsafe function or block --> $DIR/feature-gate-naked_functions.rs:9:5 | -LL | naked_asm!("", options(noreturn)) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ use of inline assembly +LL | naked_asm!("") + | ^^^^^^^^^^^^^^ use of inline assembly | = note: inline assembly is entirely unchecked and can cause undefined behavior error[E0133]: use of inline assembly is unsafe and requires unsafe function or block --> $DIR/feature-gate-naked_functions.rs:17:5 | -LL | naked_asm!("", options(noreturn)) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ use of inline assembly +LL | naked_asm!("") + | ^^^^^^^^^^^^^^ use of inline assembly | = note: inline assembly is entirely unchecked and can cause undefined behavior diff --git a/tests/ui/rfcs/rfc-2091-track-caller/error-with-naked.rs b/tests/ui/rfcs/rfc-2091-track-caller/error-with-naked.rs index 0c73b9abf35..0e85515fd10 100644 --- a/tests/ui/rfcs/rfc-2091-track-caller/error-with-naked.rs +++ b/tests/ui/rfcs/rfc-2091-track-caller/error-with-naked.rs @@ -1,14 +1,14 @@ //@ needs-asm-support #![feature(naked_functions)] -use std::arch::asm; +use std::arch::naked_asm; #[track_caller] //~ ERROR [E0736] //~^ ERROR `#[track_caller]` requires Rust ABI #[naked] extern "C" fn f() { unsafe { - asm!("", options(noreturn)); + naked_asm!(""); } } @@ -20,7 +20,7 @@ impl S { #[naked] extern "C" fn g() { unsafe { - asm!("", options(noreturn)); + naked_asm!(""); } } } From 10fa482906ab1f2fba07b32b70457ad9444e8f63 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Thu, 5 Sep 2024 18:56:38 +0200 Subject: [PATCH 631/683] remove checks that are now performed during macro expansion of `naked_asm!` --- compiler/rustc_passes/messages.ftl | 6 --- compiler/rustc_passes/src/errors.rs | 15 ------ compiler/rustc_passes/src/naked_functions.rs | 53 +++----------------- 3 files changed, 8 insertions(+), 66 deletions(-) diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index 1b1d1b1fb72..414a9c6e3b9 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -492,9 +492,6 @@ passes_naked_functions_asm_block = .label_multiple_asm = multiple `naked_asm!` invocations are not allowed in naked functions .label_non_asm = not allowed in naked functions -passes_naked_functions_asm_options = - asm options unsupported in naked functions: {$unsupported_options} - passes_naked_functions_incompatible_attribute = attribute incompatible with `#[naked]` .label = the `{$attr}` attribute is incompatible with `#[naked]` @@ -504,9 +501,6 @@ passes_naked_functions_must_naked_asm = the `asm!` macro is not allowed in naked functions .suggestion = consider using the `naked_asm!` macro instead -passes_naked_functions_operands = - only `const` and `sym` operands are supported in naked functions - passes_no_link = attribute should be applied to an `extern crate` item .label = not an `extern crate` item diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index c46768ace53..fb471377022 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -1186,21 +1186,6 @@ impl Diagnostic<'_, G> for NakedFunctionsAsmBlock { } } -#[derive(Diagnostic)] -#[diag(passes_naked_functions_operands, code = E0787)] -pub(crate) struct NakedFunctionsOperands { - #[primary_span] - pub unsupported_operands: Vec, -} - -#[derive(Diagnostic)] -#[diag(passes_naked_functions_asm_options, code = E0787)] -pub(crate) struct NakedFunctionsAsmOptions { - #[primary_span] - pub span: Span, - pub unsupported_options: String, -} - #[derive(Diagnostic)] #[diag(passes_naked_functions_must_naked_asm, code = E0787)] pub(crate) struct NakedFunctionsMustNakedAsm { diff --git a/compiler/rustc_passes/src/naked_functions.rs b/compiler/rustc_passes/src/naked_functions.rs index 6046c728430..fa4971cd2cc 100644 --- a/compiler/rustc_passes/src/naked_functions.rs +++ b/compiler/rustc_passes/src/naked_functions.rs @@ -1,11 +1,10 @@ //! Checks validity of naked functions. -use rustc_ast::InlineAsmOptions; use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::{LocalDefId, LocalModDefId}; use rustc_hir::intravisit::Visitor; -use rustc_hir::{ExprKind, HirIdSet, InlineAsmOperand, StmtKind}; +use rustc_hir::{ExprKind, HirIdSet, StmtKind}; use rustc_middle::hir::nested_filter::OnlyBodies; use rustc_middle::query::Providers; use rustc_middle::ty::TyCtxt; @@ -15,9 +14,8 @@ use rustc_span::{BytePos, Span}; use rustc_target::spec::abi::Abi; use crate::errors::{ - NakedAsmOutsideNakedFn, NakedFunctionsAsmBlock, NakedFunctionsAsmOptions, - NakedFunctionsMustNakedAsm, NakedFunctionsOperands, NoPatterns, ParamsNotAllowed, - UndefinedNakedFunctionAbi, + NakedAsmOutsideNakedFn, NakedFunctionsAsmBlock, NakedFunctionsMustNakedAsm, NoPatterns, + ParamsNotAllowed, UndefinedNakedFunctionAbi, }; pub(crate) fn provide(providers: &mut Providers) { @@ -119,7 +117,7 @@ impl<'tcx> Visitor<'tcx> for CheckParameters<'tcx> { /// Checks that function body contains a single inline assembly block. fn check_asm<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId, body: &'tcx hir::Body<'tcx>) { - let mut this = CheckInlineAssembly { tcx, items: Vec::new() }; + let mut this = CheckInlineAssembly { items: Vec::new() }; this.visit_body(body); if let [(ItemKind::NakedAsm | ItemKind::Err, _)] = this.items[..] { // Ok. @@ -165,8 +163,7 @@ fn check_asm<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId, body: &'tcx hir::Body< } } -struct CheckInlineAssembly<'tcx> { - tcx: TyCtxt<'tcx>, +struct CheckInlineAssembly { items: Vec<(ItemKind, Span)>, } @@ -178,8 +175,8 @@ enum ItemKind { Err, } -impl<'tcx> CheckInlineAssembly<'tcx> { - fn check_expr(&mut self, expr: &'tcx hir::Expr<'tcx>, span: Span) { +impl CheckInlineAssembly { + fn check_expr<'tcx>(&mut self, expr: &'tcx hir::Expr<'tcx>, span: Span) { match expr.kind { ExprKind::ConstBlock(..) | ExprKind::Array(..) @@ -220,7 +217,6 @@ impl<'tcx> CheckInlineAssembly<'tcx> { } rustc_ast::AsmMacro::NakedAsm => { self.items.push((ItemKind::NakedAsm, span)); - self.check_inline_asm(asm, span); } rustc_ast::AsmMacro::GlobalAsm => { // not allowed in this position @@ -237,42 +233,9 @@ impl<'tcx> CheckInlineAssembly<'tcx> { } } } - - fn check_inline_asm(&self, asm: &'tcx hir::InlineAsm<'tcx>, span: Span) { - let unsupported_operands: Vec = asm - .operands - .iter() - .filter_map(|&(ref op, op_sp)| match op { - InlineAsmOperand::Const { .. } - | InlineAsmOperand::SymFn { .. } - | InlineAsmOperand::SymStatic { .. } => None, - InlineAsmOperand::In { .. } - | InlineAsmOperand::Out { .. } - | InlineAsmOperand::InOut { .. } - | InlineAsmOperand::SplitInOut { .. } - | InlineAsmOperand::Label { .. } => Some(op_sp), - }) - .collect(); - if !unsupported_operands.is_empty() { - self.tcx.dcx().emit_err(NakedFunctionsOperands { unsupported_operands }); - } - - let unsupported_options = asm.options.difference(InlineAsmOptions::NAKED_OPTIONS); - if !unsupported_options.is_empty() { - self.tcx.dcx().emit_err(NakedFunctionsAsmOptions { - span, - unsupported_options: unsupported_options - .human_readable_names() - .into_iter() - .map(|name| format!("`{name}`")) - .collect::>() - .join(", "), - }); - } - } } -impl<'tcx> Visitor<'tcx> for CheckInlineAssembly<'tcx> { +impl<'tcx> Visitor<'tcx> for CheckInlineAssembly { fn visit_stmt(&mut self, stmt: &'tcx hir::Stmt<'tcx>) { match stmt.kind { StmtKind::Item(..) => {} From 5fc60d1e52ea12f53d2c8d22fee94592860739ad Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Thu, 5 Sep 2024 19:45:40 +0200 Subject: [PATCH 632/683] various fixes for `naked_asm!` implementation - fix for divergence - fix error message - fix another cranelift test - fix some cranelift things - don't set the NORETURN option for naked asm - fix use of naked_asm! in doc comment - fix use of naked_asm! in run-make test - use `span_bug` in unreachable branch --- compiler/rustc_ast/src/ast.rs | 12 ++++++-- compiler/rustc_borrowck/src/lib.rs | 1 + .../src/polonius/loan_invalidations.rs | 1 + compiler/rustc_builtin_macros/src/asm.rs | 23 +++++--------- .../example/mini_core.rs | 6 ++++ .../example/mini_core_hello_world.rs | 2 +- compiler/rustc_codegen_cranelift/src/base.rs | 3 ++ compiler/rustc_codegen_ssa/src/mir/block.rs | 13 ++++---- .../rustc_const_eval/src/interpret/machine.rs | 2 +- compiler/rustc_hir_typeck/src/expr.rs | 6 +--- compiler/rustc_lint_defs/src/builtin.rs | 6 ++-- compiler/rustc_middle/src/mir/pretty.rs | 6 ++-- compiler/rustc_middle/src/mir/syntax.rs | 24 ++++++++++++++- compiler/rustc_middle/src/mir/terminator.rs | 1 + compiler/rustc_middle/src/mir/visit.rs | 1 + compiler/rustc_middle/src/thir.rs | 3 +- compiler/rustc_middle/src/thir/visit.rs | 8 ++++- .../rustc_mir_build/src/build/expr/into.rs | 19 ++++++++---- compiler/rustc_mir_build/src/thir/cx/expr.rs | 1 + compiler/rustc_mir_build/src/thir/print.rs | 4 ++- .../src/move_paths/builder.rs | 1 + compiler/rustc_passes/messages.ftl | 2 +- compiler/rustc_passes/src/errors.rs | 3 +- compiler/rustc_passes/src/naked_functions.rs | 30 ++++++++----------- .../rustc_smir/src/rustc_smir/convert/mir.rs | 1 + src/tools/rustfmt/src/parse/macros/asm.rs | 2 +- tests/codegen/naked-asan.rs | 2 +- .../naked-symbol-visibility/a_rust_dylib.rs | 2 +- tests/ui/asm/naked-functions.stderr | 4 +-- 29 files changed, 116 insertions(+), 73 deletions(-) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index cb715213176..733c2d93114 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -2435,7 +2435,7 @@ pub enum AsmMacro { } impl AsmMacro { - pub const fn macro_name(&self) -> &'static str { + pub const fn macro_name(self) -> &'static str { match self { AsmMacro::Asm => "asm", AsmMacro::GlobalAsm => "global_asm", @@ -2443,13 +2443,21 @@ impl AsmMacro { } } - pub const fn is_supported_option(&self, option: InlineAsmOptions) -> bool { + pub const fn is_supported_option(self, option: InlineAsmOptions) -> bool { match self { AsmMacro::Asm => true, AsmMacro::GlobalAsm => InlineAsmOptions::GLOBAL_OPTIONS.contains(option), AsmMacro::NakedAsm => InlineAsmOptions::NAKED_OPTIONS.contains(option), } } + + pub const fn diverges(self, options: InlineAsmOptions) -> bool { + match self { + AsmMacro::Asm => options.contains(InlineAsmOptions::NORETURN), + AsmMacro::GlobalAsm => true, + AsmMacro::NakedAsm => true, + } + } } /// Inline assembly. diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 3b0b3ee1a74..fad4d790be4 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -742,6 +742,7 @@ impl<'a, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'a, 'tcx, R> } TerminatorKind::InlineAsm { + asm_macro: _, template: _, operands, options: _, diff --git a/compiler/rustc_borrowck/src/polonius/loan_invalidations.rs b/compiler/rustc_borrowck/src/polonius/loan_invalidations.rs index afd811a0efb..d1b65943199 100644 --- a/compiler/rustc_borrowck/src/polonius/loan_invalidations.rs +++ b/compiler/rustc_borrowck/src/polonius/loan_invalidations.rs @@ -169,6 +169,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LoanInvalidationsGenerator<'a, 'tcx> { } } TerminatorKind::InlineAsm { + asm_macro: _, template: _, operands, options: _, diff --git a/compiler/rustc_builtin_macros/src/asm.rs b/compiler/rustc_builtin_macros/src/asm.rs index 515ac17f70a..9ae48024f44 100644 --- a/compiler/rustc_builtin_macros/src/asm.rs +++ b/compiler/rustc_builtin_macros/src/asm.rs @@ -850,22 +850,13 @@ pub(super) fn expand_naked_asm<'cx>( return ExpandResult::Retry(()); }; let expr = match mac { - Ok(mut inline_asm) => { - // for future compatibility, we always set the NORETURN option. - // - // When we turn `asm!` into `naked_asm!` with this implementation, we can drop - // the `options(noreturn)`, which makes the upgrade smooth when `naked_asm!` - // starts disallowing the `noreturn` option in the future - inline_asm.options |= ast::InlineAsmOptions::NORETURN; - - P(ast::Expr { - id: ast::DUMMY_NODE_ID, - kind: ast::ExprKind::InlineAsm(P(inline_asm)), - span: sp, - attrs: ast::AttrVec::new(), - tokens: None, - }) - } + Ok(inline_asm) => P(ast::Expr { + id: ast::DUMMY_NODE_ID, + kind: ast::ExprKind::InlineAsm(P(inline_asm)), + span: sp, + attrs: ast::AttrVec::new(), + tokens: None, + }), Err(guar) => DummyResult::raw_expr(sp, Some(guar)), }; MacEager::expr(expr) diff --git a/compiler/rustc_codegen_cranelift/example/mini_core.rs b/compiler/rustc_codegen_cranelift/example/mini_core.rs index 5e535ff62e1..9fc0318df5d 100644 --- a/compiler/rustc_codegen_cranelift/example/mini_core.rs +++ b/compiler/rustc_codegen_cranelift/example/mini_core.rs @@ -726,6 +726,12 @@ pub macro global_asm() { /* compiler built-in */ } +#[rustc_builtin_macro] +#[rustc_macro_transparency = "semitransparent"] +pub macro naked_asm() { + /* compiler built-in */ +} + pub static A_STATIC: u8 = 42; #[lang = "panic_location"] diff --git a/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs b/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs index ccbd5a78485..e47431e0f87 100644 --- a/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs +++ b/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs @@ -390,7 +390,7 @@ global_asm! { #[naked] extern "C" fn naked_test() { unsafe { - asm!("ret", options(noreturn)); + naked_asm!("ret"); } } diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs index 09680622069..a681e6d9f3c 100644 --- a/compiler/rustc_codegen_cranelift/src/base.rs +++ b/compiler/rustc_codegen_cranelift/src/base.rs @@ -8,6 +8,7 @@ use rustc_ast::InlineAsmOptions; use rustc_codegen_ssa::base::is_call_from_compiler_builtins_to_upstream_monomorphization; use rustc_index::IndexVec; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; +use rustc_middle::mir::InlineAsmMacro; use rustc_middle::ty::TypeVisitableExt; use rustc_middle::ty::adjustment::PointerCoercion; use rustc_middle::ty::layout::FnAbiOf; @@ -57,6 +58,7 @@ pub(crate) fn codegen_fn<'tcx>( match &mir.basic_blocks[START_BLOCK].terminator().kind { TerminatorKind::InlineAsm { + asm_macro: InlineAsmMacro::NakedAsm, template, operands, options, @@ -498,6 +500,7 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) { "tail calls are not yet supported in `rustc_codegen_cranelift` backend" ), TerminatorKind::InlineAsm { + asm_macro: _, template, operands, options, diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index 125d3b908c7..be9a6d9a90e 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -3,7 +3,9 @@ use std::cmp; use rustc_ast as ast; use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece}; use rustc_hir::lang_items::LangItem; -use rustc_middle::mir::{self, AssertKind, BasicBlock, SwitchTargets, UnwindTerminateReason}; +use rustc_middle::mir::{ + self, AssertKind, BasicBlock, InlineAsmMacro, SwitchTargets, UnwindTerminateReason, +}; use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, ValidityRequirement}; use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths}; use rustc_middle::ty::{self, Instance, Ty}; @@ -1133,6 +1135,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { &mut self, helper: TerminatorCodegenHelper<'tcx>, bx: &mut Bx, + asm_macro: InlineAsmMacro, terminator: &mir::Terminator<'tcx>, template: &[ast::InlineAsmTemplatePiece], operands: &[mir::InlineAsmOperand<'tcx>], @@ -1203,11 +1206,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { &operands, options, line_spans, - if options.contains(InlineAsmOptions::NORETURN) { - None - } else { - targets.get(0).copied() - }, + if asm_macro.diverges(options) { None } else { targets.get(0).copied() }, unwind, instance, mergeable_succ, @@ -1381,6 +1380,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } mir::TerminatorKind::InlineAsm { + asm_macro, template, ref operands, options, @@ -1390,6 +1390,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } => self.codegen_asm_terminator( helper, bx, + asm_macro, terminator, template, operands, diff --git a/compiler/rustc_const_eval/src/interpret/machine.rs b/compiler/rustc_const_eval/src/interpret/machine.rs index 0f796c31222..89d49ba046e 100644 --- a/compiler/rustc_const_eval/src/interpret/machine.rs +++ b/compiler/rustc_const_eval/src/interpret/machine.rs @@ -395,7 +395,7 @@ pub trait Machine<'tcx>: Sized { /// /// This should take care of jumping to the next block (one of `targets`) when asm goto /// is triggered, `targets[0]` when the assembly falls through, or diverge in case of - /// `InlineAsmOptions::NORETURN` being set. + /// naked_asm! or `InlineAsmOptions::NORETURN` being set. fn eval_inline_asm( _ecx: &mut InterpCx<'tcx, Self>, _template: &'tcx [InlineAsmTemplatePiece], diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 5c2f39f879c..95ca3e66472 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -3507,11 +3507,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } fn check_expr_asm(&self, asm: &'tcx hir::InlineAsm<'tcx>) -> Ty<'tcx> { - let mut diverge = match asm.asm_macro { - rustc_ast::AsmMacro::Asm => asm.options.contains(ast::InlineAsmOptions::NORETURN), - rustc_ast::AsmMacro::GlobalAsm => true, - rustc_ast::AsmMacro::NakedAsm => true, - }; + let mut diverge = asm.asm_macro.diverges(asm.options); for (op, _op_sp) in asm.operands { match op { diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index bd87019508b..a439514e16f 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -2926,16 +2926,16 @@ declare_lint! { /// ```rust /// #![feature(asm_experimental_arch, naked_functions)] /// - /// use std::arch::asm; + /// use std::arch::naked_asm; /// /// #[naked] /// pub fn default_abi() -> u32 { - /// unsafe { asm!("", options(noreturn)); } + /// unsafe { naked_asm!(""); } /// } /// /// #[naked] /// pub extern "Rust" fn rust_abi() -> u32 { - /// unsafe { asm!("", options(noreturn)); } + /// unsafe { naked_asm!(""); } /// } /// ``` /// diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index 48789565218..9cafe804a8e 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -4,7 +4,7 @@ use std::fs; use std::io::{self, Write as _}; use std::path::{Path, PathBuf}; -use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece}; +use rustc_ast::InlineAsmTemplatePiece; use rustc_middle::mir::interpret::{ AllocBytes, AllocId, Allocation, GlobalAlloc, Pointer, Provenance, alloc_range, read_target_uint, @@ -1024,9 +1024,9 @@ impl<'tcx> TerminatorKind<'tcx> { vec!["real".into(), "unwind".into()] } FalseUnwind { unwind: _, .. } => vec!["real".into()], - InlineAsm { options, ref targets, unwind, .. } => { + InlineAsm { asm_macro, options, ref targets, unwind, .. } => { let mut vec = Vec::with_capacity(targets.len() + 1); - if !options.contains(InlineAsmOptions::NORETURN) { + if !asm_macro.diverges(options) { vec.push("return".into()); } vec.resize(targets.len(), "label".into()); diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs index 1722a7a1f35..c610fac80f6 100644 --- a/compiler/rustc_middle/src/mir/syntax.rs +++ b/compiler/rustc_middle/src/mir/syntax.rs @@ -605,6 +605,25 @@ impl CallSource { } } +#[derive(Clone, Copy, Debug, TyEncodable, TyDecodable, Hash, HashStable, PartialEq)] +#[derive(TypeFoldable, TypeVisitable)] +/// The macro that an inline assembly block was created by +pub enum InlineAsmMacro { + /// The `asm!` macro + Asm, + /// The `naked_asm!` macro + NakedAsm, +} + +impl InlineAsmMacro { + pub const fn diverges(self, options: InlineAsmOptions) -> bool { + match self { + InlineAsmMacro::Asm => options.contains(InlineAsmOptions::NORETURN), + InlineAsmMacro::NakedAsm => true, + } + } +} + /////////////////////////////////////////////////////////////////////////// // Terminators @@ -859,6 +878,9 @@ pub enum TerminatorKind<'tcx> { /// Block ends with an inline assembly block. This is a terminator since /// inline assembly is allowed to diverge. InlineAsm { + /// Macro used to create this inline asm: one of `asm!` or `naked_asm!` + asm_macro: InlineAsmMacro, + /// The template for the inline assembly, with placeholders. template: &'tcx [InlineAsmTemplatePiece], @@ -874,7 +896,7 @@ pub enum TerminatorKind<'tcx> { /// Valid targets for the inline assembly. /// The first element is the fallthrough destination, unless - /// InlineAsmOptions::NORETURN is set. + /// asm_macro == InlineAsmMacro::NakedAsm or InlineAsmOptions::NORETURN is set. targets: Box<[BasicBlock]>, /// Action to be taken if the inline assembly unwinds. This is present diff --git a/compiler/rustc_middle/src/mir/terminator.rs b/compiler/rustc_middle/src/mir/terminator.rs index 783952fb9cb..b919f5726db 100644 --- a/compiler/rustc_middle/src/mir/terminator.rs +++ b/compiler/rustc_middle/src/mir/terminator.rs @@ -666,6 +666,7 @@ impl<'tcx> TerminatorKind<'tcx> { }, InlineAsm { + asm_macro: _, template: _, ref operands, options: _, diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index 64898a8495e..9f9ee8497b6 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -576,6 +576,7 @@ macro_rules! make_mir_visitor { } TerminatorKind::InlineAsm { + asm_macro: _, template: _, operands, options: _, diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index e614d41899a..fe865b8a515 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -12,7 +12,7 @@ use std::cmp::Ordering; use std::fmt; use std::ops::Index; -use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece}; +use rustc_ast::{AsmMacro, InlineAsmOptions, InlineAsmTemplatePiece}; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_hir::{BindingMode, ByRef, HirId, MatchSource, RangeEnd}; @@ -173,6 +173,7 @@ pub struct ClosureExpr<'tcx> { #[derive(Clone, Debug, HashStable)] pub struct InlineAsmExpr<'tcx> { + pub asm_macro: AsmMacro, pub template: &'tcx [InlineAsmTemplatePiece], pub operands: Box<[InlineAsmOperand<'tcx>]>, pub options: InlineAsmOptions, diff --git a/compiler/rustc_middle/src/thir/visit.rs b/compiler/rustc_middle/src/thir/visit.rs index 58e2ebaeaf8..36f0e3d890c 100644 --- a/compiler/rustc_middle/src/thir/visit.rs +++ b/compiler/rustc_middle/src/thir/visit.rs @@ -148,7 +148,13 @@ pub fn walk_expr<'thir, 'tcx: 'thir, V: Visitor<'thir, 'tcx>>( NamedConst { def_id: _, args: _, user_ty: _ } => {} ConstParam { param: _, def_id: _ } => {} StaticRef { alloc_id: _, ty: _, def_id: _ } => {} - InlineAsm(box InlineAsmExpr { ref operands, template: _, options: _, line_spans: _ }) => { + InlineAsm(box InlineAsmExpr { + asm_macro: _, + ref operands, + template: _, + options: _, + line_spans: _, + }) => { for op in &**operands { use InlineAsmOperand::*; match op { diff --git a/compiler/rustc_mir_build/src/build/expr/into.rs b/compiler/rustc_mir_build/src/build/expr/into.rs index 86fe447f399..dc317feb20c 100644 --- a/compiler/rustc_mir_build/src/build/expr/into.rs +++ b/compiler/rustc_mir_build/src/build/expr/into.rs @@ -2,7 +2,7 @@ use std::iter; -use rustc_ast::InlineAsmOptions; +use rustc_ast::{AsmMacro, InlineAsmOptions}; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_hir as hir; @@ -384,6 +384,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { block.unit() } ExprKind::InlineAsm(box InlineAsmExpr { + asm_macro, template, ref operands, options, @@ -392,11 +393,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { use rustc_middle::{mir, thir}; let destination_block = this.cfg.start_new_block(); - let mut targets = if options.contains(InlineAsmOptions::NORETURN) { - vec![] - } else { - vec![destination_block] - }; + let mut targets = + if asm_macro.diverges(options) { vec![] } else { vec![destination_block] }; let operands = operands .into_iter() @@ -474,7 +472,16 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { this.cfg.push_assign_unit(block, source_info, destination, this.tcx); } + let asm_macro = match asm_macro { + AsmMacro::Asm => InlineAsmMacro::Asm, + AsmMacro::GlobalAsm => { + span_bug!(expr_span, "unexpected global_asm! in inline asm") + } + AsmMacro::NakedAsm => InlineAsmMacro::NakedAsm, + }; + this.cfg.terminate(block, source_info, TerminatorKind::InlineAsm { + asm_macro, template, operands, options, diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index 2ffad0b4834..abf486af962 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -672,6 +672,7 @@ impl<'tcx> Cx<'tcx> { } hir::ExprKind::InlineAsm(asm) => ExprKind::InlineAsm(Box::new(InlineAsmExpr { + asm_macro: asm.asm_macro, template: asm.template, operands: asm .operands diff --git a/compiler/rustc_mir_build/src/thir/print.rs b/compiler/rustc_mir_build/src/thir/print.rs index 61317925d09..dae13df4054 100644 --- a/compiler/rustc_mir_build/src/thir/print.rs +++ b/compiler/rustc_mir_build/src/thir/print.rs @@ -818,10 +818,12 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> { } fn print_inline_asm_expr(&mut self, expr: &InlineAsmExpr<'tcx>, depth_lvl: usize) { - let InlineAsmExpr { template, operands, options, line_spans } = expr; + let InlineAsmExpr { asm_macro, template, operands, options, line_spans } = expr; print_indented!(self, "InlineAsmExpr {", depth_lvl); + print_indented!(self, format!("asm_macro: {:?}", asm_macro), depth_lvl + 1); + print_indented!(self, "template: [", depth_lvl + 1); for template_piece in template.iter() { print_indented!(self, format!("{:?}", template_piece), depth_lvl + 2); diff --git a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs index 3c8be2f73e1..162245cb950 100644 --- a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs +++ b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs @@ -481,6 +481,7 @@ impl<'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> MoveDataBuilder<'a, 'tcx, F> { } } TerminatorKind::InlineAsm { + asm_macro: _, template: _, ref operands, options: _, diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index 414a9c6e3b9..be76d6cef2b 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -499,7 +499,7 @@ passes_naked_functions_incompatible_attribute = passes_naked_functions_must_naked_asm = the `asm!` macro is not allowed in naked functions - .suggestion = consider using the `naked_asm!` macro instead + .label = consider using the `naked_asm!` macro instead passes_no_link = attribute should be applied to an `extern crate` item diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index fb471377022..4f00c90fa3b 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -1190,9 +1190,8 @@ impl Diagnostic<'_, G> for NakedFunctionsAsmBlock { #[diag(passes_naked_functions_must_naked_asm, code = E0787)] pub(crate) struct NakedFunctionsMustNakedAsm { #[primary_span] + #[label] pub span: Span, - #[suggestion(code = "naked_asm!", applicability = "machine-applicable")] - pub macro_span: Span, } #[derive(Diagnostic)] diff --git a/compiler/rustc_passes/src/naked_functions.rs b/compiler/rustc_passes/src/naked_functions.rs index fa4971cd2cc..b2f8d7dadff 100644 --- a/compiler/rustc_passes/src/naked_functions.rs +++ b/compiler/rustc_passes/src/naked_functions.rs @@ -7,10 +7,11 @@ use rustc_hir::intravisit::Visitor; use rustc_hir::{ExprKind, HirIdSet, StmtKind}; use rustc_middle::hir::nested_filter::OnlyBodies; use rustc_middle::query::Providers; +use rustc_middle::span_bug; use rustc_middle::ty::TyCtxt; use rustc_session::lint::builtin::UNDEFINED_NAKED_FUNCTION_ABI; +use rustc_span::Span; use rustc_span::symbol::sym; -use rustc_span::{BytePos, Span}; use rustc_target::spec::abi::Abi; use crate::errors::{ @@ -137,10 +138,7 @@ fn check_asm<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId, body: &'tcx hir::Body< ItemKind::InlineAsm => { has_err = true; - // the span that contains the `asm!` call, - // so tooling can replace it with `naked_asm!` - let macro_span = span.with_hi(span.lo() + BytePos("asm!".len() as u32)); - tcx.dcx().emit_err(NakedFunctionsMustNakedAsm { span, macro_span }); + tcx.dcx().emit_err(NakedFunctionsMustNakedAsm { span }); } ItemKind::NonAsm => { must_show_error = true; @@ -210,19 +208,17 @@ impl CheckInlineAssembly { self.items.push((ItemKind::NonAsm, span)); } - ExprKind::InlineAsm(asm) => { - match asm.asm_macro { - rustc_ast::AsmMacro::Asm => { - self.items.push((ItemKind::InlineAsm, span)); - } - rustc_ast::AsmMacro::NakedAsm => { - self.items.push((ItemKind::NakedAsm, span)); - } - rustc_ast::AsmMacro::GlobalAsm => { - // not allowed in this position - } + ExprKind::InlineAsm(asm) => match asm.asm_macro { + rustc_ast::AsmMacro::Asm => { + self.items.push((ItemKind::InlineAsm, span)); } - } + rustc_ast::AsmMacro::NakedAsm => { + self.items.push((ItemKind::NakedAsm, span)); + } + rustc_ast::AsmMacro::GlobalAsm => { + span_bug!(span, "`global_asm!` is not allowed in this position") + } + }, ExprKind::DropTemps(..) | ExprKind::Block(..) => { hir::intravisit::walk_expr(self, expr); diff --git a/compiler/rustc_smir/src/rustc_smir/convert/mir.rs b/compiler/rustc_smir/src/rustc_smir/convert/mir.rs index 0dbbc338e73..dbae4b7e719 100644 --- a/compiler/rustc_smir/src/rustc_smir/convert/mir.rs +++ b/compiler/rustc_smir/src/rustc_smir/convert/mir.rs @@ -655,6 +655,7 @@ impl<'tcx> Stable<'tcx> for mir::TerminatorKind<'tcx> { } } mir::TerminatorKind::InlineAsm { + asm_macro: _, template, operands, options, diff --git a/src/tools/rustfmt/src/parse/macros/asm.rs b/src/tools/rustfmt/src/parse/macros/asm.rs index 0c37d12490e..58c8d21bd7a 100644 --- a/src/tools/rustfmt/src/parse/macros/asm.rs +++ b/src/tools/rustfmt/src/parse/macros/asm.rs @@ -1,5 +1,5 @@ use rustc_ast::ast; -use rustc_builtin_macros::asm::{parse_asm_args, AsmArgs}; +use rustc_builtin_macros::asm::{AsmArgs, parse_asm_args}; use crate::rewrite::RewriteContext; diff --git a/tests/codegen/naked-asan.rs b/tests/codegen/naked-asan.rs index ac36018eed3..bcaa60baeff 100644 --- a/tests/codegen/naked-asan.rs +++ b/tests/codegen/naked-asan.rs @@ -14,7 +14,7 @@ #[no_mangle] pub extern "x86-interrupt" fn page_fault_handler(_: u64, _: u64) { unsafe { - core::arch::asm!("ud2", options(noreturn)); + core::arch::naked_asm!("ud2"); } } diff --git a/tests/run-make/naked-symbol-visibility/a_rust_dylib.rs b/tests/run-make/naked-symbol-visibility/a_rust_dylib.rs index 517c8da656a..8dd19e613bf 100644 --- a/tests/run-make/naked-symbol-visibility/a_rust_dylib.rs +++ b/tests/run-make/naked-symbol-visibility/a_rust_dylib.rs @@ -72,7 +72,7 @@ extern "C" fn vanilla_weak_linkage() -> u32 { #[cfg(not(windows))] #[linkage = "weak"] extern "C" fn naked_weak_linkage() -> u32 { - unsafe { naked_asm!("mov rax, 42", "ret", options(noreturn)) } + unsafe { naked_asm!("mov rax, 42", "ret") } } // functions that are declared in an `extern "C"` block are currently not exported diff --git a/tests/ui/asm/naked-functions.stderr b/tests/ui/asm/naked-functions.stderr index 1ceeafffd90..0898f3620f2 100644 --- a/tests/ui/asm/naked-functions.stderr +++ b/tests/ui/asm/naked-functions.stderr @@ -74,9 +74,7 @@ error[E0787]: the `asm!` macro is not allowed in naked functions --> $DIR/naked-functions.rs:13:5 | LL | asm!("", options(raw)); - | ----^^^^^^^^^^^^^^^^^^ - | | - | help: consider using the `naked_asm!` macro instead: `naked_asm!` + | ^^^^^^^^^^^^^^^^^^^^^^ consider using the `naked_asm!` macro instead error: patterns not allowed in naked function parameters --> $DIR/naked-functions.rs:25:5 From 3b2be4457da8521ab0a8a9cd7e11b1c24b0de191 Mon Sep 17 00:00:00 2001 From: dacian Date: Sun, 6 Oct 2024 20:37:10 +0300 Subject: [PATCH 633/683] grammar fix --- library/core/src/intrinsics/mir.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/intrinsics/mir.rs b/library/core/src/intrinsics/mir.rs index fb0aa5398a5..a2ab39caade 100644 --- a/library/core/src/intrinsics/mir.rs +++ b/library/core/src/intrinsics/mir.rs @@ -213,7 +213,7 @@ //! - All other locals need to be declared with `let` somewhere and then can be accessed by name. //! //! #### Places -//! - Locals implicit convert to places. +//! - Locals implicitly convert to places. //! - Field accesses, derefs, and indexing work normally. //! - Fields in variants can be accessed via the [`Variant`] and [`Field`] associated functions, //! see their documentation for details. From aa4f16a6e71fa63a366ffa0981a422eec73f66ca Mon Sep 17 00:00:00 2001 From: Brezak Date: Tue, 20 Aug 2024 20:53:49 +0200 Subject: [PATCH 634/683] Check that `#[pointee]` is applied only to generic arguments --- compiler/rustc_builtin_macros/messages.ftl | 2 + .../src/deriving/smart_ptr.rs | 64 +++++++++++++++++++ compiler/rustc_builtin_macros/src/errors.rs | 7 ++ .../ui/deriving/deriving-smart-pointer-neg.rs | 33 ++++++++++ .../deriving-smart-pointer-neg.stderr | 26 +++++++- 5 files changed, 131 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_builtin_macros/messages.ftl b/compiler/rustc_builtin_macros/messages.ftl index 9695df9c87e..8bd07027da4 100644 --- a/compiler/rustc_builtin_macros/messages.ftl +++ b/compiler/rustc_builtin_macros/messages.ftl @@ -235,6 +235,8 @@ builtin_macros_non_exhaustive_default = default variant must be exhaustive .label = declared `#[non_exhaustive]` here .help = consider a manual implementation of `Default` +builtin_macros_non_generic_pointee = the `#[pointee]` attribute may only be used on generic parameters + builtin_macros_non_unit_default = the `#[default]` attribute may only be used on unit enum variants .help = consider a manual implementation of `Default` diff --git a/compiler/rustc_builtin_macros/src/deriving/smart_ptr.rs b/compiler/rustc_builtin_macros/src/deriving/smart_ptr.rs index 78028df2aa0..fab1906eecd 100644 --- a/compiler/rustc_builtin_macros/src/deriving/smart_ptr.rs +++ b/compiler/rustc_builtin_macros/src/deriving/smart_ptr.rs @@ -13,6 +13,8 @@ use rustc_span::symbol::{Ident, sym}; use rustc_span::{Span, Symbol}; use thin_vec::{ThinVec, thin_vec}; +use crate::errors; + macro_rules! path { ($span:expr, $($part:ident)::*) => { vec![$(Ident::new(sym::$part, $span),)*] } } @@ -25,6 +27,8 @@ pub(crate) fn expand_deriving_smart_ptr( push: &mut dyn FnMut(Annotatable), _is_const: bool, ) { + item.visit_with(&mut DetectNonGenericPointeeAttr { cx }); + let (name_ident, generics) = if let Annotatable::Item(aitem) = item && let ItemKind::Struct(struct_data, g) = &aitem.kind { @@ -396,3 +400,63 @@ impl<'a> ast::mut_visit::MutVisitor for TypeSubstitution<'a> { } } } + +struct DetectNonGenericPointeeAttr<'a, 'b> { + cx: &'a ExtCtxt<'b>, +} + +impl<'a, 'b> rustc_ast::visit::Visitor<'a> for DetectNonGenericPointeeAttr<'a, 'b> { + fn visit_attribute(&mut self, attr: &'a rustc_ast::Attribute) -> Self::Result { + if attr.has_name(sym::pointee) { + self.cx.dcx().emit_err(errors::NonGenericPointee { span: attr.span }); + } + } + + fn visit_generic_param(&mut self, param: &'a rustc_ast::GenericParam) -> Self::Result { + let mut error_on_pointee = AlwaysErrorOnGenericParam { cx: self.cx }; + + match ¶m.kind { + GenericParamKind::Type { default } => { + // The `default` may end up containing a block expression. + // The problem is block expressions may define structs with generics. + // A user may attach a #[pointee] attribute to one of these generics + // We want to catch that. The simple solution is to just + // always raise a `NonGenericPointee` error when this happens. + // + // This solution does reject valid rust programs but, + // such a code would have to, in order: + // - Define a smart pointer struct. + // - Somewhere in this struct definition use a type with a const generic argument. + // - Calculate this const generic in a expression block. + // - Define a new smart pointer type in this block. + // - Have this smart pointer type have more than 1 generic type. + // In this case, the inner smart pointer derive would be complaining that it + // needs a pointer attribute. Meanwhile, the outer macro would be complaining + // that we attached a #[pointee] to a generic type argument while helpfully + // informing the user that #[pointee] can only be attached to generic pointer arguments + rustc_ast::visit::visit_opt!(error_on_pointee, visit_ty, default); + } + + GenericParamKind::Const { .. } | GenericParamKind::Lifetime => { + rustc_ast::visit::walk_generic_param(&mut error_on_pointee, param); + } + } + } + + fn visit_ty(&mut self, t: &'a rustc_ast::Ty) -> Self::Result { + let mut error_on_pointee = AlwaysErrorOnGenericParam { cx: self.cx }; + error_on_pointee.visit_ty(t) + } +} + +struct AlwaysErrorOnGenericParam<'a, 'b> { + cx: &'a ExtCtxt<'b>, +} + +impl<'a, 'b> rustc_ast::visit::Visitor<'a> for AlwaysErrorOnGenericParam<'a, 'b> { + fn visit_attribute(&mut self, attr: &'a rustc_ast::Attribute) -> Self::Result { + if attr.has_name(sym::pointee) { + self.cx.dcx().emit_err(errors::NonGenericPointee { span: attr.span }); + } + } +} diff --git a/compiler/rustc_builtin_macros/src/errors.rs b/compiler/rustc_builtin_macros/src/errors.rs index 4fffffb91c8..625aa4f2b75 100644 --- a/compiler/rustc_builtin_macros/src/errors.rs +++ b/compiler/rustc_builtin_macros/src/errors.rs @@ -937,3 +937,10 @@ pub(crate) struct NakedFunctionTestingAttribute { #[label] pub testing_span: Span, } + +#[derive(Diagnostic)] +#[diag(builtin_macros_non_generic_pointee)] +pub(crate) struct NonGenericPointee { + #[primary_span] + pub span: Span, +} diff --git a/tests/ui/deriving/deriving-smart-pointer-neg.rs b/tests/ui/deriving/deriving-smart-pointer-neg.rs index f02fb56130f..41d3039236f 100644 --- a/tests/ui/deriving/deriving-smart-pointer-neg.rs +++ b/tests/ui/deriving/deriving-smart-pointer-neg.rs @@ -53,6 +53,39 @@ struct NoMaybeSized<'a, #[pointee] T> { ptr: &'a T, } +#[derive(SmartPointer)] +#[repr(transparent)] +struct PointeeOnField<'a, #[pointee] T: ?Sized> { + #[pointee] + //~^ ERROR: the `#[pointee]` attribute may only be used on generic parameters + ptr: &'a T +} + +#[derive(SmartPointer)] +#[repr(transparent)] +struct PointeeInTypeConstBlock<'a, T: ?Sized = [u32; const { struct UhOh<#[pointee] T>(T); 10 }]> { + //~^ ERROR: the `#[pointee]` attribute may only be used on generic parameters + ptr: &'a T, +} + +#[derive(SmartPointer)] +#[repr(transparent)] +struct PointeeInConstConstBlock< + 'a, + T: ?Sized, + const V: u32 = { struct UhOh<#[pointee] T>(T); 10 }> + //~^ ERROR: the `#[pointee]` attribute may only be used on generic parameters +{ + ptr: &'a T, +} + +#[derive(SmartPointer)] +#[repr(transparent)] +struct PointeeInAnotherTypeConstBlock<'a, #[pointee] T: ?Sized> { + ptr: PointeeInConstConstBlock<'a, T, { struct UhOh<#[pointee] T>(T); 0 }> + //~^ ERROR: the `#[pointee]` attribute may only be used on generic parameters +} + // However, reordering attributes should work nevertheless. #[repr(transparent)] #[derive(SmartPointer)] diff --git a/tests/ui/deriving/deriving-smart-pointer-neg.stderr b/tests/ui/deriving/deriving-smart-pointer-neg.stderr index e7c2afc8b00..9ab117698c7 100644 --- a/tests/ui/deriving/deriving-smart-pointer-neg.stderr +++ b/tests/ui/deriving/deriving-smart-pointer-neg.stderr @@ -58,6 +58,30 @@ error: `derive(SmartPointer)` requires T to be marked `?Sized` LL | struct NoMaybeSized<'a, #[pointee] T> { | ^ +error: the `#[pointee]` attribute may only be used on generic parameters + --> $DIR/deriving-smart-pointer-neg.rs:59:5 + | +LL | #[pointee] + | ^^^^^^^^^^ + +error: the `#[pointee]` attribute may only be used on generic parameters + --> $DIR/deriving-smart-pointer-neg.rs:66:74 + | +LL | struct PointeeInTypeConstBlock<'a, T: ?Sized = [u32; const { struct UhOh<#[pointee] T>(T); 10 }]> { + | ^^^^^^^^^^ + +error: the `#[pointee]` attribute may only be used on generic parameters + --> $DIR/deriving-smart-pointer-neg.rs:76:34 + | +LL | const V: u32 = { struct UhOh<#[pointee] T>(T); 10 }> + | ^^^^^^^^^^ + +error: the `#[pointee]` attribute may only be used on generic parameters + --> $DIR/deriving-smart-pointer-neg.rs:85:56 + | +LL | ptr: PointeeInConstConstBlock<'a, T, { struct UhOh<#[pointee] T>(T); 0 }> + | ^^^^^^^^^^ + error[E0392]: lifetime parameter `'a` is never used --> $DIR/deriving-smart-pointer-neg.rs:15:16 | @@ -90,6 +114,6 @@ LL | struct NoFieldUnit<'a, #[pointee] T: ?Sized>(); | = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData` -error: aborting due to 12 previous errors +error: aborting due to 16 previous errors For more information about this error, try `rustc --explain E0392`. From cfeee7bcbf182a6c22083c7dfb56c6034a65d0a0 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 1 Oct 2024 16:08:09 +1000 Subject: [PATCH 635/683] Remove unused features. --- compiler/rustc_infer/src/lib.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/compiler/rustc_infer/src/lib.rs b/compiler/rustc_infer/src/lib.rs index 934484bf915..a04b2bb2b08 100644 --- a/compiler/rustc_infer/src/lib.rs +++ b/compiler/rustc_infer/src/lib.rs @@ -19,10 +19,7 @@ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(assert_matches)] -#![feature(box_patterns)] #![feature(extend_one)] -#![feature(if_let_guard)] -#![feature(iter_intersperse)] #![feature(iterator_try_collect)] #![feature(let_chains)] #![feature(rustdoc_internals)] From 7a9bbd05c42f1c6b0d920a4e741ea28452916c99 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 1 Oct 2024 16:11:48 +1000 Subject: [PATCH 636/683] Rename `errors/mod.rs` as `errors.rs`. It's simpler, for this tiny module. --- compiler/rustc_infer/src/{errors/mod.rs => errors.rs} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename compiler/rustc_infer/src/{errors/mod.rs => errors.rs} (100%) diff --git a/compiler/rustc_infer/src/errors/mod.rs b/compiler/rustc_infer/src/errors.rs similarity index 100% rename from compiler/rustc_infer/src/errors/mod.rs rename to compiler/rustc_infer/src/errors.rs From 5486d72e7783271f457649e4e865a821becf27a2 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 1 Oct 2024 16:18:34 +1000 Subject: [PATCH 637/683] Reduce visibilities. Three of the modules don't need to be `pub`, and then `warn(unreachable_pub)` identifies a bunch more things that also shouldn't be `pub`, plus a couple of things that are unused. --- compiler/rustc_infer/src/infer/mod.rs | 6 +-- .../rustc_infer/src/infer/opaque_types/mod.rs | 24 +++------- .../src/infer/opaque_types/table.rs | 2 +- .../rustc_infer/src/infer/type_variable.rs | 45 +++++++------------ 4 files changed, 25 insertions(+), 52 deletions(-) diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 5fa1bf51634..87dae0c1e09 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -56,17 +56,17 @@ use crate::traits::{self, ObligationCause, ObligationInspector, PredicateObligat pub mod at; pub mod canonical; mod context; -pub mod free_regions; +mod free_regions; mod freshen; mod lexical_region_resolve; -pub mod opaque_types; +mod opaque_types; pub mod outlives; mod projection; pub mod region_constraints; pub mod relate; pub mod resolve; pub(crate) mod snapshot; -pub mod type_variable; +mod type_variable; #[must_use] #[derive(Debug)] diff --git a/compiler/rustc_infer/src/infer/opaque_types/mod.rs b/compiler/rustc_infer/src/infer/opaque_types/mod.rs index 55c51bc856f..0c5eca6ebdf 100644 --- a/compiler/rustc_infer/src/infer/opaque_types/mod.rs +++ b/compiler/rustc_infer/src/infer/opaque_types/mod.rs @@ -19,8 +19,8 @@ use crate::traits::{self, Obligation}; mod table; -pub type OpaqueTypeMap<'tcx> = FxIndexMap, OpaqueTypeDecl<'tcx>>; -pub use table::{OpaqueTypeStorage, OpaqueTypeTable}; +pub(crate) type OpaqueTypeMap<'tcx> = FxIndexMap, OpaqueTypeDecl<'tcx>>; +pub(crate) use table::{OpaqueTypeStorage, OpaqueTypeTable}; use super::DefineOpaqueTypes; @@ -377,9 +377,9 @@ impl<'tcx> InferCtxt<'tcx> { /// /// We ignore any type parameters because impl trait values are assumed to /// capture all the in-scope type parameters. -pub struct ConstrainOpaqueTypeRegionVisitor<'tcx, OP: FnMut(ty::Region<'tcx>)> { - pub tcx: TyCtxt<'tcx>, - pub op: OP, +struct ConstrainOpaqueTypeRegionVisitor<'tcx, OP: FnMut(ty::Region<'tcx>)> { + tcx: TyCtxt<'tcx>, + op: OP, } impl<'tcx, OP> TypeVisitor> for ConstrainOpaqueTypeRegionVisitor<'tcx, OP> @@ -455,20 +455,6 @@ where } } -pub enum UseKind { - DefiningUse, - OpaqueUse, -} - -impl UseKind { - pub fn is_defining(self) -> bool { - match self { - UseKind::DefiningUse => true, - UseKind::OpaqueUse => false, - } - } -} - impl<'tcx> InferCtxt<'tcx> { #[instrument(skip(self), level = "debug")] fn register_hidden_type( diff --git a/compiler/rustc_infer/src/infer/opaque_types/table.rs b/compiler/rustc_infer/src/infer/opaque_types/table.rs index 4aa2ccab0e7..6e4cc65bec3 100644 --- a/compiler/rustc_infer/src/infer/opaque_types/table.rs +++ b/compiler/rustc_infer/src/infer/opaque_types/table.rs @@ -7,7 +7,7 @@ use super::{OpaqueTypeDecl, OpaqueTypeMap}; use crate::infer::snapshot::undo_log::{InferCtxtUndoLogs, UndoLog}; #[derive(Default, Debug, Clone)] -pub struct OpaqueTypeStorage<'tcx> { +pub(crate) struct OpaqueTypeStorage<'tcx> { /// Opaque types found in explicit return types and their /// associated fresh inference variable. Writeback resolves these /// variables to get the concrete type, which can be used to diff --git a/compiler/rustc_infer/src/infer/type_variable.rs b/compiler/rustc_infer/src/infer/type_variable.rs index 7eb2c20e0d8..c50477b2922 100644 --- a/compiler/rustc_infer/src/infer/type_variable.rs +++ b/compiler/rustc_infer/src/infer/type_variable.rs @@ -20,7 +20,7 @@ impl<'tcx> Rollback>>> for TypeVariabl } #[derive(Clone)] -pub struct TypeVariableStorage<'tcx> { +pub(crate) struct TypeVariableStorage<'tcx> { /// The origins of each type variable. values: IndexVec, /// Two variables are unified in `eq_relations` when we have a @@ -29,7 +29,7 @@ pub struct TypeVariableStorage<'tcx> { eq_relations: ut::UnificationTableStorage>, } -pub struct TypeVariableTable<'a, 'tcx> { +pub(crate) struct TypeVariableTable<'a, 'tcx> { storage: &'a mut TypeVariableStorage<'tcx>, undo_log: &'a mut InferCtxtUndoLogs<'tcx>, @@ -50,7 +50,7 @@ pub(crate) struct TypeVariableData { } #[derive(Copy, Clone, Debug)] -pub enum TypeVariableValue<'tcx> { +pub(crate) enum TypeVariableValue<'tcx> { Known { value: Ty<'tcx> }, Unknown { universe: ty::UniverseIndex }, } @@ -58,14 +58,14 @@ pub enum TypeVariableValue<'tcx> { impl<'tcx> TypeVariableValue<'tcx> { /// If this value is known, returns the type it is known to be. /// Otherwise, `None`. - pub fn known(&self) -> Option> { + pub(crate) fn known(&self) -> Option> { match *self { TypeVariableValue::Unknown { .. } => None, TypeVariableValue::Known { value } => Some(value), } } - pub fn is_unknown(&self) -> bool { + pub(crate) fn is_unknown(&self) -> bool { match *self { TypeVariableValue::Unknown { .. } => true, TypeVariableValue::Known { .. } => false, @@ -74,7 +74,7 @@ impl<'tcx> TypeVariableValue<'tcx> { } impl<'tcx> TypeVariableStorage<'tcx> { - pub fn new() -> TypeVariableStorage<'tcx> { + pub(crate) fn new() -> TypeVariableStorage<'tcx> { TypeVariableStorage { values: Default::default(), eq_relations: ut::UnificationTableStorage::new(), @@ -105,14 +105,14 @@ impl<'tcx> TypeVariableTable<'_, 'tcx> { /// /// Note that this function does not return care whether /// `vid` has been unified with something else or not. - pub fn var_origin(&self, vid: ty::TyVid) -> TypeVariableOrigin { + pub(crate) fn var_origin(&self, vid: ty::TyVid) -> TypeVariableOrigin { self.storage.values[vid].origin } /// Records that `a == b`, depending on `dir`. /// /// Precondition: neither `a` nor `b` are known. - pub fn equate(&mut self, a: ty::TyVid, b: ty::TyVid) { + pub(crate) fn equate(&mut self, a: ty::TyVid, b: ty::TyVid) { debug_assert!(self.probe(a).is_unknown()); debug_assert!(self.probe(b).is_unknown()); self.eq_relations().union(a, b); @@ -121,7 +121,7 @@ impl<'tcx> TypeVariableTable<'_, 'tcx> { /// Instantiates `vid` with the type `ty`. /// /// Precondition: `vid` must not have been previously instantiated. - pub fn instantiate(&mut self, vid: ty::TyVid, ty: Ty<'tcx>) { + pub(crate) fn instantiate(&mut self, vid: ty::TyVid, ty: Ty<'tcx>) { let vid = self.root_var(vid); debug_assert!(!ty.is_ty_var(), "instantiating ty var with var: {vid:?} {ty:?}"); debug_assert!(self.probe(vid).is_unknown()); @@ -143,7 +143,7 @@ impl<'tcx> TypeVariableTable<'_, 'tcx> { /// - `origin`: indicates *why* the type variable was created. /// The code in this module doesn't care, but it can be useful /// for improving error messages. - pub fn new_var( + pub(crate) fn new_var( &mut self, universe: ty::UniverseIndex, origin: TypeVariableOrigin, @@ -158,7 +158,7 @@ impl<'tcx> TypeVariableTable<'_, 'tcx> { } /// Returns the number of type variables created thus far. - pub fn num_vars(&self) -> usize { + pub(crate) fn num_vars(&self) -> usize { self.storage.values.len() } @@ -167,42 +167,29 @@ impl<'tcx> TypeVariableTable<'_, 'tcx> { /// will yield the same root variable (per the union-find /// algorithm), so `root_var(a) == root_var(b)` implies that `a == /// b` (transitively). - pub fn root_var(&mut self, vid: ty::TyVid) -> ty::TyVid { + pub(crate) fn root_var(&mut self, vid: ty::TyVid) -> ty::TyVid { self.eq_relations().find(vid).vid } /// Retrieves the type to which `vid` has been instantiated, if /// any. - pub fn probe(&mut self, vid: ty::TyVid) -> TypeVariableValue<'tcx> { + pub(crate) fn probe(&mut self, vid: ty::TyVid) -> TypeVariableValue<'tcx> { self.inlined_probe(vid) } /// An always-inlined variant of `probe`, for very hot call sites. #[inline(always)] - pub fn inlined_probe(&mut self, vid: ty::TyVid) -> TypeVariableValue<'tcx> { + pub(crate) fn inlined_probe(&mut self, vid: ty::TyVid) -> TypeVariableValue<'tcx> { self.eq_relations().inlined_probe_value(vid) } - /// If `t` is a type-inference variable, and it has been - /// instantiated, then return the with which it was - /// instantiated. Otherwise, returns `t`. - pub fn replace_if_possible(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { - match *t.kind() { - ty::Infer(ty::TyVar(v)) => match self.probe(v) { - TypeVariableValue::Unknown { .. } => t, - TypeVariableValue::Known { value } => value, - }, - _ => t, - } - } - #[inline] fn eq_relations(&mut self) -> super::UnificationTable<'_, 'tcx, TyVidEqKey<'tcx>> { self.storage.eq_relations.with_log(self.undo_log) } /// Returns a range of the type variables created during the snapshot. - pub fn vars_since_snapshot( + pub(crate) fn vars_since_snapshot( &mut self, value_count: usize, ) -> (Range, Vec) { @@ -215,7 +202,7 @@ impl<'tcx> TypeVariableTable<'_, 'tcx> { /// Returns indices of all variables that are not yet /// instantiated. - pub fn unresolved_variables(&mut self) -> Vec { + pub(crate) fn unresolved_variables(&mut self) -> Vec { (0..self.num_vars()) .filter_map(|i| { let vid = ty::TyVid::from_usize(i); From 5c015eed473ff648ed5febc1f8eac4d0553af845 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 1 Oct 2024 16:36:38 +1000 Subject: [PATCH 638/683] Remove unused `UnitResult` type. --- compiler/rustc_infer/src/infer/mod.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 87dae0c1e09..c98604de839 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -50,7 +50,6 @@ use snapshot::undo_log::InferCtxtUndoLogs; use tracing::{debug, instrument}; use type_variable::TypeVariableOrigin; -use crate::infer::relate::RelateResult; use crate::traits::{self, ObligationCause, ObligationInspector, PredicateObligation, TraitEngine}; pub mod at; @@ -76,7 +75,6 @@ pub struct InferOk<'tcx, T> { } pub type InferResult<'tcx, T> = Result, TypeError<'tcx>>; -pub type UnitResult<'tcx> = RelateResult<'tcx, ()>; // "unify result" pub type FixupResult = Result; // "fixup result" pub(crate) type UnificationTable<'a, 'tcx, T> = ut::UnificationTable< From 2d2755ff97d4c1909dfcd3e2c1fce806a6550919 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 1 Oct 2024 16:40:22 +1000 Subject: [PATCH 639/683] Reduce visibilities some more. It helps people reading the code understand how widely things are used. --- compiler/rustc_infer/src/infer/mod.rs | 9 +++++---- .../rustc_infer/src/infer/opaque_types/table.rs | 2 +- compiler/rustc_infer/src/infer/outlives/mod.rs | 2 +- .../rustc_infer/src/infer/outlives/verify.rs | 12 ++++++------ .../src/infer/region_constraints/mod.rs | 2 +- compiler/rustc_infer/src/infer/relate/combine.rs | 16 ++++++++-------- compiler/rustc_infer/src/infer/relate/mod.rs | 2 +- .../src/infer/relate/type_relating.rs | 4 ++-- compiler/rustc_infer/src/infer/snapshot/mod.rs | 2 +- 9 files changed, 26 insertions(+), 25 deletions(-) diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index c98604de839..8714e854114 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -14,7 +14,8 @@ use region_constraints::{ GenericKind, RegionConstraintCollector, RegionConstraintStorage, VarInfos, VerifyBound, }; pub use relate::StructurallyRelateAliases; -pub use relate::combine::{CombineFields, PredicateEmittingRelation}; +use relate::combine::CombineFields; +pub use relate::combine::PredicateEmittingRelation; use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; use rustc_data_structures::sync::Lrc; @@ -75,7 +76,7 @@ pub struct InferOk<'tcx, T> { } pub type InferResult<'tcx, T> = Result, TypeError<'tcx>>; -pub type FixupResult = Result; // "fixup result" +pub(crate) type FixupResult = Result; // "fixup result" pub(crate) type UnificationTable<'a, 'tcx, T> = ut::UnificationTable< ut::InPlace, &'a mut InferCtxtUndoLogs<'tcx>>, @@ -200,7 +201,7 @@ impl<'tcx> InferCtxtInner<'tcx> { } #[inline] - pub fn opaque_types(&mut self) -> opaque_types::OpaqueTypeTable<'_, 'tcx> { + fn opaque_types(&mut self) -> opaque_types::OpaqueTypeTable<'_, 'tcx> { self.opaque_type_storage.with_log(&mut self.undo_log) } @@ -1351,7 +1352,7 @@ impl<'tcx> InferCtxt<'tcx> { } /// See the [`region_constraints::RegionConstraintCollector::verify_generic_bound`] method. - pub fn verify_generic_bound( + pub(crate) fn verify_generic_bound( &self, origin: SubregionOrigin<'tcx>, kind: GenericKind<'tcx>, diff --git a/compiler/rustc_infer/src/infer/opaque_types/table.rs b/compiler/rustc_infer/src/infer/opaque_types/table.rs index 6e4cc65bec3..047d8edad3d 100644 --- a/compiler/rustc_infer/src/infer/opaque_types/table.rs +++ b/compiler/rustc_infer/src/infer/opaque_types/table.rs @@ -46,7 +46,7 @@ impl<'tcx> Drop for OpaqueTypeStorage<'tcx> { } } -pub struct OpaqueTypeTable<'a, 'tcx> { +pub(crate) struct OpaqueTypeTable<'a, 'tcx> { storage: &'a mut OpaqueTypeStorage<'tcx>, undo_log: &'a mut InferCtxtUndoLogs<'tcx>, diff --git a/compiler/rustc_infer/src/infer/outlives/mod.rs b/compiler/rustc_infer/src/infer/outlives/mod.rs index f5c873b0375..a270f9322f3 100644 --- a/compiler/rustc_infer/src/infer/outlives/mod.rs +++ b/compiler/rustc_infer/src/infer/outlives/mod.rs @@ -14,7 +14,7 @@ pub mod env; pub mod for_liveness; pub mod obligations; pub mod test_type_match; -pub mod verify; +pub(crate) mod verify; #[instrument(level = "debug", skip(param_env), ret)] pub fn explicit_outlives_bounds<'tcx>( diff --git a/compiler/rustc_infer/src/infer/outlives/verify.rs b/compiler/rustc_infer/src/infer/outlives/verify.rs index 74a80a1b9aa..247fbc25965 100644 --- a/compiler/rustc_infer/src/infer/outlives/verify.rs +++ b/compiler/rustc_infer/src/infer/outlives/verify.rs @@ -15,7 +15,7 @@ use crate::infer::{GenericKind, VerifyBound}; /// via a "delegate" of type `D` -- this is usually the `infcx`, which /// accrues them into the `region_obligations` code, but for NLL we /// use something else. -pub struct VerifyBoundCx<'cx, 'tcx> { +pub(crate) struct VerifyBoundCx<'cx, 'tcx> { tcx: TyCtxt<'tcx>, region_bound_pairs: &'cx RegionBoundPairs<'tcx>, /// During borrowck, if there are no outlives bounds on a generic @@ -28,7 +28,7 @@ pub struct VerifyBoundCx<'cx, 'tcx> { } impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { - pub fn new( + pub(crate) fn new( tcx: TyCtxt<'tcx>, region_bound_pairs: &'cx RegionBoundPairs<'tcx>, implicit_region_bound: Option>, @@ -38,7 +38,7 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { } #[instrument(level = "debug", skip(self))] - pub fn param_or_placeholder_bound(&self, ty: Ty<'tcx>) -> VerifyBound<'tcx> { + pub(crate) fn param_or_placeholder_bound(&self, ty: Ty<'tcx>) -> VerifyBound<'tcx> { // Start with anything like `T: 'a` we can scrape from the // environment. If the environment contains something like // `for<'a> T: 'a`, then we know that `T` outlives everything. @@ -92,7 +92,7 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { /// the clause from the environment only applies if `'0 = 'a`, /// which we don't know yet. But we would still include `'b` in /// this list. - pub fn approx_declared_bounds_from_env( + pub(crate) fn approx_declared_bounds_from_env( &self, alias_ty: ty::AliasTy<'tcx>, ) -> Vec> { @@ -101,7 +101,7 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { } #[instrument(level = "debug", skip(self))] - pub fn alias_bound(&self, alias_ty: ty::AliasTy<'tcx>) -> VerifyBound<'tcx> { + pub(crate) fn alias_bound(&self, alias_ty: ty::AliasTy<'tcx>) -> VerifyBound<'tcx> { let alias_ty_as_ty = alias_ty.to_ty(self.tcx); // Search the env for where clauses like `P: 'a`. @@ -285,7 +285,7 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { /// /// This is for simplicity, and because we are not really smart /// enough to cope with such bounds anywhere. - pub fn declared_bounds_from_definition( + pub(crate) fn declared_bounds_from_definition( &self, alias_ty: ty::AliasTy<'tcx>, ) -> impl Iterator> { diff --git a/compiler/rustc_infer/src/infer/region_constraints/mod.rs b/compiler/rustc_infer/src/infer/region_constraints/mod.rs index 82f7668b2d2..a6d1d05f6e1 100644 --- a/compiler/rustc_infer/src/infer/region_constraints/mod.rs +++ b/compiler/rustc_infer/src/infer/region_constraints/mod.rs @@ -304,7 +304,7 @@ pub struct RegionVariableInfo { pub universe: ty::UniverseIndex, } -pub struct RegionSnapshot { +pub(crate) struct RegionSnapshot { any_unifications: bool, } diff --git a/compiler/rustc_infer/src/infer/relate/combine.rs b/compiler/rustc_infer/src/infer/relate/combine.rs index 4a8c7387ddc..450437f2176 100644 --- a/compiler/rustc_infer/src/infer/relate/combine.rs +++ b/compiler/rustc_infer/src/infer/relate/combine.rs @@ -33,7 +33,7 @@ use crate::infer::{DefineOpaqueTypes, InferCtxt, TypeTrace, relate}; use crate::traits::{Obligation, PredicateObligation}; #[derive(Clone)] -pub struct CombineFields<'infcx, 'tcx> { +pub(crate) struct CombineFields<'infcx, 'tcx> { pub infcx: &'infcx InferCtxt<'tcx>, // Immutable fields pub trace: TypeTrace<'tcx>, @@ -47,7 +47,7 @@ pub struct CombineFields<'infcx, 'tcx> { } impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> { - pub fn new( + pub(crate) fn new( infcx: &'infcx InferCtxt<'tcx>, trace: TypeTrace<'tcx>, param_env: ty::ParamEnv<'tcx>, @@ -283,22 +283,22 @@ impl<'tcx> InferCtxt<'tcx> { } impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> { - pub fn tcx(&self) -> TyCtxt<'tcx> { + pub(crate) fn tcx(&self) -> TyCtxt<'tcx> { self.infcx.tcx } - pub fn equate<'a>( + pub(crate) fn equate<'a>( &'a mut self, structurally_relate_aliases: StructurallyRelateAliases, ) -> TypeRelating<'a, 'infcx, 'tcx> { TypeRelating::new(self, structurally_relate_aliases, ty::Invariant) } - pub fn sub<'a>(&'a mut self) -> TypeRelating<'a, 'infcx, 'tcx> { + pub(crate) fn sub<'a>(&'a mut self) -> TypeRelating<'a, 'infcx, 'tcx> { TypeRelating::new(self, StructurallyRelateAliases::No, ty::Covariant) } - pub fn sup<'a>(&'a mut self) -> TypeRelating<'a, 'infcx, 'tcx> { + pub(crate) fn sup<'a>(&'a mut self) -> TypeRelating<'a, 'infcx, 'tcx> { TypeRelating::new(self, StructurallyRelateAliases::No, ty::Contravariant) } @@ -310,14 +310,14 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> { LatticeOp::new(self, LatticeOpKind::Glb) } - pub fn register_obligations( + pub(crate) fn register_obligations( &mut self, obligations: impl IntoIterator>>, ) { self.goals.extend(obligations); } - pub fn register_predicates( + pub(crate) fn register_predicates( &mut self, obligations: impl IntoIterator, ty::Predicate<'tcx>>>, ) { diff --git a/compiler/rustc_infer/src/infer/relate/mod.rs b/compiler/rustc_infer/src/infer/relate/mod.rs index edc0c4f078a..85158faa65d 100644 --- a/compiler/rustc_infer/src/infer/relate/mod.rs +++ b/compiler/rustc_infer/src/infer/relate/mod.rs @@ -5,7 +5,7 @@ pub use rustc_middle::ty::relate::RelateResult; pub use rustc_next_trait_solver::relate::*; -pub use self::combine::{CombineFields, PredicateEmittingRelation}; +pub use self::combine::PredicateEmittingRelation; #[allow(hidden_glob_reexports)] pub(super) mod combine; diff --git a/compiler/rustc_infer/src/infer/relate/type_relating.rs b/compiler/rustc_infer/src/infer/relate/type_relating.rs index 7acfea643dd..7537ceec307 100644 --- a/compiler/rustc_infer/src/infer/relate/type_relating.rs +++ b/compiler/rustc_infer/src/infer/relate/type_relating.rs @@ -13,7 +13,7 @@ use crate::infer::relate::{PredicateEmittingRelation, StructurallyRelateAliases} use crate::infer::{DefineOpaqueTypes, InferCtxt, SubregionOrigin}; /// Enforce that `a` is equal to or a subtype of `b`. -pub struct TypeRelating<'combine, 'a, 'tcx> { +pub(crate) struct TypeRelating<'combine, 'a, 'tcx> { // Immutable except for the `InferCtxt` and the // resulting nested `goals`. fields: &'combine mut CombineFields<'a, 'tcx>, @@ -49,7 +49,7 @@ pub struct TypeRelating<'combine, 'a, 'tcx> { } impl<'combine, 'infcx, 'tcx> TypeRelating<'combine, 'infcx, 'tcx> { - pub fn new( + pub(crate) fn new( f: &'combine mut CombineFields<'infcx, 'tcx>, structurally_relate_aliases: StructurallyRelateAliases, ambient_variance: ty::Variance, diff --git a/compiler/rustc_infer/src/infer/snapshot/mod.rs b/compiler/rustc_infer/src/infer/snapshot/mod.rs index 964fb1f6819..07a482c2f9a 100644 --- a/compiler/rustc_infer/src/infer/snapshot/mod.rs +++ b/compiler/rustc_infer/src/infer/snapshot/mod.rs @@ -5,7 +5,7 @@ use tracing::{debug, instrument}; use super::InferCtxt; use super::region_constraints::RegionSnapshot; -mod fudge; +pub(crate) mod fudge; pub(crate) mod undo_log; use undo_log::{Snapshot, UndoLog}; From 25d1ef199353b395e60fb75937a8b4837cd3a9c4 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 1 Oct 2024 17:10:39 +1000 Subject: [PATCH 640/683] Remove `InferCtxt::err_count_on_creation`. It's no longer used meaningfully. This also means `DiagCtxtHandle::err_count_excluding_lint_errs` can be removed. --- compiler/rustc_errors/src/lib.rs | 12 ------------ compiler/rustc_infer/src/infer/at.rs | 1 - compiler/rustc_infer/src/infer/mod.rs | 20 +++----------------- 3 files changed, 3 insertions(+), 30 deletions(-) diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 39acacfbe59..10ec521908e 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -925,18 +925,6 @@ impl<'a> DiagCtxtHandle<'a> { self.inner.borrow_mut().emit_stashed_diagnostics() } - /// This excludes lint errors, and delayed bugs. - #[inline] - pub fn err_count_excluding_lint_errs(&self) -> usize { - let inner = self.inner.borrow(); - inner.err_guars.len() - + inner - .stashed_diagnostics - .values() - .filter(|(diag, guar)| guar.is_some() && diag.is_lint.is_none()) - .count() - } - /// This excludes delayed bugs. #[inline] pub fn err_count(&self) -> usize { diff --git a/compiler/rustc_infer/src/infer/at.rs b/compiler/rustc_infer/src/infer/at.rs index 6ce47db8b9b..f80737d1269 100644 --- a/compiler/rustc_infer/src/infer/at.rs +++ b/compiler/rustc_infer/src/infer/at.rs @@ -82,7 +82,6 @@ impl<'tcx> InferCtxt<'tcx> { reported_trait_errors: self.reported_trait_errors.clone(), reported_signature_mismatch: self.reported_signature_mismatch.clone(), tainted_by_errors: self.tainted_by_errors.clone(), - err_count_on_creation: self.err_count_on_creation, universe: self.universe.clone(), intercrate, next_trait_solver: self.next_trait_solver, diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 8714e854114..45b28b98c94 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -279,27 +279,14 @@ pub struct InferCtxt<'tcx> { pub reported_signature_mismatch: RefCell)>>, /// When an error occurs, we want to avoid reporting "derived" - /// errors that are due to this original failure. Normally, we - /// handle this with the `err_count_on_creation` count, which - /// basically just tracks how many errors were reported when we - /// started type-checking a fn and checks to see if any new errors - /// have been reported since then. Not great, but it works. - /// - /// However, when errors originated in other passes -- notably - /// resolve -- this heuristic breaks down. Therefore, we have this - /// auxiliary flag that one can set whenever one creates a - /// type-error that is due to an error in a prior pass. + /// errors that are due to this original failure. We have this + /// flag that one can set whenever one creates a type-error that + /// is due to an error in a prior pass. /// /// Don't read this flag directly, call `is_tainted_by_errors()` /// and `set_tainted_by_errors()`. tainted_by_errors: Cell>, - /// Track how many errors were reported when this infcx is created. - /// If the number of errors increases, that's also a sign (like - /// `tainted_by_errors`) to avoid reporting certain kinds of errors. - // FIXME(matthewjasper) Merge into `tainted_by_errors` - err_count_on_creation: usize, - /// What is the innermost universe we have created? Starts out as /// `UniverseIndex::root()` but grows from there as we enter /// universal quantifiers. @@ -656,7 +643,6 @@ impl<'tcx> InferCtxtBuilder<'tcx> { reported_trait_errors: Default::default(), reported_signature_mismatch: Default::default(), tainted_by_errors: Cell::new(None), - err_count_on_creation: tcx.dcx().err_count_excluding_lint_errs(), universe: Cell::new(ty::UniverseIndex::ROOT), intercrate, next_trait_solver, From 0ca4784c45665a0267314ddd2a12c6710fbbe2c0 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 1 Oct 2024 17:58:49 +1000 Subject: [PATCH 641/683] Fix `FIXME` comment on `FixupError`. `FixupError` is isomorphic with `TyOrConstInferVar`, so this commit changes it to just be a wrapper around `TyOrConstInferVar`. Also, move the `Display` impl for `FixupError` next to `FixupError`. --- compiler/rustc_infer/src/infer/mod.rs | 53 ++++++++++------------- compiler/rustc_infer/src/infer/resolve.rs | 12 ++--- 2 files changed, 31 insertions(+), 34 deletions(-) diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 45b28b98c94..dbdcc3e2a8a 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -495,14 +495,31 @@ pub enum NllRegionVariableOrigin { }, } -// FIXME(eddyb) investigate overlap between this and `TyOrConstInferVar`. #[derive(Copy, Clone, Debug)] -pub enum FixupError { - UnresolvedIntTy(IntVid), - UnresolvedFloatTy(FloatVid), - UnresolvedTy(TyVid), - UnresolvedConst(ConstVid), - UnresolvedEffect(EffectVid), +pub struct FixupError { + unresolved: TyOrConstInferVar, +} + +impl fmt::Display for FixupError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + use TyOrConstInferVar::*; + + match self.unresolved { + TyInt(_) => write!( + f, + "cannot determine the type of this integer; \ + add a suffix to specify the type explicitly" + ), + TyFloat(_) => write!( + f, + "cannot determine the type of this number; \ + add a suffix to specify the type explicitly" + ), + Ty(_) => write!(f, "unconstrained type"), + Const(_) => write!(f, "unconstrained const value"), + Effect(_) => write!(f, "unconstrained effect value"), + } + } } /// See the `region_obligations` field for more information. @@ -513,28 +530,6 @@ pub struct RegionObligation<'tcx> { pub origin: SubregionOrigin<'tcx>, } -impl fmt::Display for FixupError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - use self::FixupError::*; - - match *self { - UnresolvedIntTy(_) => write!( - f, - "cannot determine the type of this integer; \ - add a suffix to specify the type explicitly" - ), - UnresolvedFloatTy(_) => write!( - f, - "cannot determine the type of this number; \ - add a suffix to specify the type explicitly" - ), - UnresolvedTy(_) => write!(f, "unconstrained type"), - UnresolvedConst(_) => write!(f, "unconstrained const value"), - UnresolvedEffect(_) => write!(f, "unconstrained effect value"), - } - } -} - /// Used to configure inference contexts before their creation. pub struct InferCtxtBuilder<'tcx> { tcx: TyCtxt<'tcx>, diff --git a/compiler/rustc_infer/src/infer/resolve.rs b/compiler/rustc_infer/src/infer/resolve.rs index 671a66d504f..2c7b35af947 100644 --- a/compiler/rustc_infer/src/infer/resolve.rs +++ b/compiler/rustc_infer/src/infer/resolve.rs @@ -138,11 +138,13 @@ impl<'a, 'tcx> FallibleTypeFolder> for FullTypeResolver<'a, 'tcx> { if !t.has_infer() { Ok(t) // micro-optimize -- if there is nothing in this type that this fold affects... } else { + use super::TyOrConstInferVar::*; + let t = self.infcx.shallow_resolve(t); match *t.kind() { - ty::Infer(ty::TyVar(vid)) => Err(FixupError::UnresolvedTy(vid)), - ty::Infer(ty::IntVar(vid)) => Err(FixupError::UnresolvedIntTy(vid)), - ty::Infer(ty::FloatVar(vid)) => Err(FixupError::UnresolvedFloatTy(vid)), + ty::Infer(ty::TyVar(vid)) => Err(FixupError { unresolved: Ty(vid) }), + ty::Infer(ty::IntVar(vid)) => Err(FixupError { unresolved: TyInt(vid) }), + ty::Infer(ty::FloatVar(vid)) => Err(FixupError { unresolved: TyFloat(vid) }), ty::Infer(_) => { bug!("Unexpected type in full type resolver: {:?}", t); } @@ -171,13 +173,13 @@ impl<'a, 'tcx> FallibleTypeFolder> for FullTypeResolver<'a, 'tcx> { let c = self.infcx.shallow_resolve_const(c); match c.kind() { ty::ConstKind::Infer(InferConst::Var(vid)) => { - return Err(FixupError::UnresolvedConst(vid)); + return Err(FixupError { unresolved: super::TyOrConstInferVar::Const(vid) }); } ty::ConstKind::Infer(InferConst::Fresh(_)) => { bug!("Unexpected const in full const resolver: {:?}", c); } ty::ConstKind::Infer(InferConst::EffectVar(evid)) => { - return Err(FixupError::UnresolvedEffect(evid)); + return Err(FixupError { unresolved: super::TyOrConstInferVar::Effect(evid) }); } _ => {} } From deeb0c5cf3737d2a681334befee694cc5aa005b8 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 2 Oct 2024 08:41:38 +1000 Subject: [PATCH 642/683] Inline and remove `InferCtxtBuilder::with_defining_opaque_types`. It has a single use. --- compiler/rustc_infer/src/infer/mod.rs | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index dbdcc3e2a8a..7238c670be9 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -569,14 +569,6 @@ impl<'tcx> InferCtxtBuilder<'tcx> { self } - pub fn with_defining_opaque_types( - mut self, - defining_opaque_types: &'tcx ty::List, - ) -> Self { - self.defining_opaque_types = defining_opaque_types; - self - } - pub fn with_next_trait_solver(mut self, next_trait_solver: bool) -> Self { self.next_trait_solver = next_trait_solver; self @@ -605,14 +597,15 @@ impl<'tcx> InferCtxtBuilder<'tcx> { /// the bound values in `C` to their instantiated values in `V` /// (in other words, `S(C) = V`). pub fn build_with_canonical( - self, + mut self, span: Span, canonical: &Canonical<'tcx, T>, ) -> (InferCtxt<'tcx>, T, CanonicalVarValues<'tcx>) where T: TypeFoldable>, { - let infcx = self.with_defining_opaque_types(canonical.defining_opaque_types).build(); + self.defining_opaque_types = canonical.defining_opaque_types; + let infcx = self.build(); let (value, args) = infcx.instantiate_canonical(span, canonical); (infcx, value, args) } From 3386530c9166f5b1177f81fb2037dd0e0b5a50f1 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 2 Oct 2024 14:01:07 +1000 Subject: [PATCH 643/683] Streamline `next_*_var*` methods. Inline and remove `next_const_var_id`, `next_int_var_id`, `next_float_var_id`, all of which have a single call site. --- compiler/rustc_infer/src/infer/mod.rs | 24 ++++++------------------ 1 file changed, 6 insertions(+), 18 deletions(-) diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 7238c670be9..89dfa019253 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -892,28 +892,16 @@ impl<'tcx> InferCtxt<'tcx> { ty::Const::new_var(self.tcx, vid) } - pub fn next_const_var_id(&self, origin: ConstVariableOrigin) -> ConstVid { - self.inner - .borrow_mut() - .const_unification_table() - .new_key(ConstVariableValue::Unknown { origin, universe: self.universe() }) - .vid - } - - fn next_int_var_id(&self) -> IntVid { - self.inner.borrow_mut().int_unification_table().new_key(ty::IntVarValue::Unknown) - } - pub fn next_int_var(&self) -> Ty<'tcx> { - Ty::new_int_var(self.tcx, self.next_int_var_id()) - } - - fn next_float_var_id(&self) -> FloatVid { - self.inner.borrow_mut().float_unification_table().new_key(ty::FloatVarValue::Unknown) + let next_int_var_id = + self.inner.borrow_mut().int_unification_table().new_key(ty::IntVarValue::Unknown); + Ty::new_int_var(self.tcx, next_int_var_id) } pub fn next_float_var(&self) -> Ty<'tcx> { - Ty::new_float_var(self.tcx, self.next_float_var_id()) + let next_float_var_id = + self.inner.borrow_mut().float_unification_table().new_key(ty::FloatVarValue::Unknown); + Ty::new_float_var(self.tcx, next_float_var_id) } /// Creates a fresh region variable with the next available index. From e80096747853fc5a0c8a98e8532c2f74ba770aa2 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 2 Oct 2024 14:33:48 +1000 Subject: [PATCH 644/683] Simplify two matches. Matches involving `GenericArgKind` pairs typically use a single `_` for the impossible case. This commit shortens two verbose matches in this way. --- compiler/rustc_infer/src/infer/at.rs | 16 +--------------- compiler/rustc_middle/src/ty/relate.rs | 10 +--------- 2 files changed, 2 insertions(+), 24 deletions(-) diff --git a/compiler/rustc_infer/src/infer/at.rs b/compiler/rustc_infer/src/infer/at.rs index f80737d1269..183973af4f9 100644 --- a/compiler/rustc_infer/src/infer/at.rs +++ b/compiler/rustc_infer/src/infer/at.rs @@ -381,21 +381,7 @@ impl<'tcx> ToTrace<'tcx> for ty::GenericArg<'tcx> { (GenericArgKind::Const(a), GenericArgKind::Const(b)) => { ValuePairs::Terms(ExpectedFound::new(true, a.into(), b.into())) } - - ( - GenericArgKind::Lifetime(_), - GenericArgKind::Type(_) | GenericArgKind::Const(_), - ) - | ( - GenericArgKind::Type(_), - GenericArgKind::Lifetime(_) | GenericArgKind::Const(_), - ) - | ( - GenericArgKind::Const(_), - GenericArgKind::Lifetime(_) | GenericArgKind::Type(_), - ) => { - bug!("relating different kinds: {a:?} {b:?}") - } + _ => bug!("relating different kinds: {a:?} {b:?}"), }, } } diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs index 61c03922ac0..4c7bcb1bf2e 100644 --- a/compiler/rustc_middle/src/ty/relate.rs +++ b/compiler/rustc_middle/src/ty/relate.rs @@ -212,15 +212,7 @@ impl<'tcx> Relate> for ty::GenericArg<'tcx> { (ty::GenericArgKind::Const(a_ct), ty::GenericArgKind::Const(b_ct)) => { Ok(relation.relate(a_ct, b_ct)?.into()) } - (ty::GenericArgKind::Lifetime(unpacked), x) => { - bug!("impossible case reached: can't relate: {:?} with {:?}", unpacked, x) - } - (ty::GenericArgKind::Type(unpacked), x) => { - bug!("impossible case reached: can't relate: {:?} with {:?}", unpacked, x) - } - (ty::GenericArgKind::Const(unpacked), x) => { - bug!("impossible case reached: can't relate: {:?} with {:?}", unpacked, x) - } + _ => bug!("impossible case reached: can't relate: {a:?} with {b:?}"), } } } From afbff05c84c8c22909be929d20d6075f53d51e12 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 2 Oct 2024 16:52:55 +1000 Subject: [PATCH 645/683] Move a `use` statement so it's with the other `use` statements. --- compiler/rustc_infer/src/infer/opaque_types/mod.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/compiler/rustc_infer/src/infer/opaque_types/mod.rs b/compiler/rustc_infer/src/infer/opaque_types/mod.rs index 0c5eca6ebdf..d3afabdb7da 100644 --- a/compiler/rustc_infer/src/infer/opaque_types/mod.rs +++ b/compiler/rustc_infer/src/infer/opaque_types/mod.rs @@ -13,6 +13,7 @@ use rustc_middle::ty::{ use rustc_span::Span; use tracing::{debug, instrument}; +use super::DefineOpaqueTypes; use crate::errors::OpaqueHiddenTypeDiag; use crate::infer::{InferCtxt, InferOk}; use crate::traits::{self, Obligation}; @@ -22,8 +23,6 @@ mod table; pub(crate) type OpaqueTypeMap<'tcx> = FxIndexMap, OpaqueTypeDecl<'tcx>>; pub(crate) use table::{OpaqueTypeStorage, OpaqueTypeTable}; -use super::DefineOpaqueTypes; - /// Information about the opaque types whose values we /// are inferring in this function (these are the `impl Trait` that /// appear in the return type). From 3fdcde76d9bcbf31e2409aefede4dd8b2f7c315f Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 7 Oct 2024 09:40:52 +1100 Subject: [PATCH 646/683] Remove out-of-date comment. --- compiler/rustc_infer/src/infer/resolve.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/compiler/rustc_infer/src/infer/resolve.rs b/compiler/rustc_infer/src/infer/resolve.rs index 2c7b35af947..025c3a629fa 100644 --- a/compiler/rustc_infer/src/infer/resolve.rs +++ b/compiler/rustc_infer/src/infer/resolve.rs @@ -121,8 +121,6 @@ where value.try_fold_with(&mut FullTypeResolver { infcx }) } -// N.B. This type is not public because the protocol around checking the -// `err` field is not enforceable otherwise. struct FullTypeResolver<'a, 'tcx> { infcx: &'a InferCtxt<'tcx>, } From d793766a6199d9b7339633ad0296af63c7b4f9b8 Mon Sep 17 00:00:00 2001 From: Nathan Perry Date: Tue, 30 Jul 2024 09:48:36 -0400 Subject: [PATCH 647/683] liballoc: introduce String, Vec const-slicing This change `const`-qualifies many methods on Vec and String, notably `as_slice`, `as_str`, `len`. These changes are made behind the unstable feature flag `const_vec_string_slice` with the following tracking issue: https://github.com/rust-lang/rust/issues/129041 --- library/alloc/src/lib.rs | 1 + library/alloc/src/raw_vec.rs | 12 +-- library/alloc/src/string.rs | 38 +++++--- library/alloc/src/vec/mod.rs | 55 ++++++++--- ..._to_slice.PreCodegen.after.panic-abort.mir | 91 +++++++++---------- ...to_slice.PreCodegen.after.panic-unwind.mir | 91 +++++++++---------- tests/ui/consts/issue-94675.rs | 2 +- tests/ui/consts/issue-94675.stderr | 10 +- 8 files changed, 164 insertions(+), 136 deletions(-) diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index f0597f295b3..4a09b5dfd17 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -114,6 +114,7 @@ #![feature(const_option)] #![feature(const_pin)] #![feature(const_size_of_val)] +#![feature(const_vec_string_slice)] #![feature(core_intrinsics)] #![feature(deprecated_suggestion)] #![feature(deref_pure_trait)] diff --git a/library/alloc/src/raw_vec.rs b/library/alloc/src/raw_vec.rs index 436e0596e3d..8fdca8c4200 100644 --- a/library/alloc/src/raw_vec.rs +++ b/library/alloc/src/raw_vec.rs @@ -280,7 +280,7 @@ impl RawVec { /// `Unique::dangling()` if `capacity == 0` or `T` is zero-sized. In the former case, you must /// be careful. #[inline] - pub fn ptr(&self) -> *mut T { + pub const fn ptr(&self) -> *mut T { self.inner.ptr() } @@ -293,7 +293,7 @@ impl RawVec { /// /// This will always be `usize::MAX` if `T` is zero-sized. #[inline] - pub fn capacity(&self) -> usize { + pub const fn capacity(&self) -> usize { self.inner.capacity(size_of::()) } @@ -488,17 +488,17 @@ impl RawVecInner { } #[inline] - fn ptr(&self) -> *mut T { + const fn ptr(&self) -> *mut T { self.non_null::().as_ptr() } #[inline] - fn non_null(&self) -> NonNull { - self.ptr.cast().into() + const fn non_null(&self) -> NonNull { + self.ptr.cast().as_non_null_ptr() } #[inline] - fn capacity(&self, elem_size: usize) -> usize { + const fn capacity(&self, elem_size: usize) -> usize { if elem_size == 0 { usize::MAX } else { self.cap.0 } } diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs index d58a016b502..2815ea4da7f 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -1059,7 +1059,8 @@ impl String { #[inline] #[must_use = "`self` will be dropped if the result is not used"] #[stable(feature = "rust1", since = "1.0.0")] - pub fn into_bytes(self) -> Vec { + #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")] + pub const fn into_bytes(self) -> Vec { self.vec } @@ -1076,8 +1077,11 @@ impl String { #[must_use] #[stable(feature = "string_as_str", since = "1.7.0")] #[cfg_attr(not(test), rustc_diagnostic_item = "string_as_str")] - pub fn as_str(&self) -> &str { - self + #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")] + pub const fn as_str(&self) -> &str { + // SAFETY: String contents are stipulated to be valid UTF-8, invalid contents are an error + // at construction. + unsafe { str::from_utf8_unchecked(self.vec.as_slice()) } } /// Converts a `String` into a mutable string slice. @@ -1096,8 +1100,11 @@ impl String { #[must_use] #[stable(feature = "string_as_str", since = "1.7.0")] #[cfg_attr(not(test), rustc_diagnostic_item = "string_as_mut_str")] - pub fn as_mut_str(&mut self) -> &mut str { - self + #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")] + pub const fn as_mut_str(&mut self) -> &mut str { + // SAFETY: String contents are stipulated to be valid UTF-8, invalid contents are an error + // at construction. + unsafe { str::from_utf8_unchecked_mut(self.vec.as_mut_slice()) } } /// Appends a given string slice onto the end of this `String`. @@ -1168,7 +1175,8 @@ impl String { #[inline] #[must_use] #[stable(feature = "rust1", since = "1.0.0")] - pub fn capacity(&self) -> usize { + #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")] + pub const fn capacity(&self) -> usize { self.vec.capacity() } @@ -1431,8 +1439,9 @@ impl String { #[inline] #[must_use] #[stable(feature = "rust1", since = "1.0.0")] - pub fn as_bytes(&self) -> &[u8] { - &self.vec + #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")] + pub const fn as_bytes(&self) -> &[u8] { + self.vec.as_slice() } /// Shortens this `String` to the specified length. @@ -1784,7 +1793,8 @@ impl String { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - pub unsafe fn as_mut_vec(&mut self) -> &mut Vec { + #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")] + pub const unsafe fn as_mut_vec(&mut self) -> &mut Vec { &mut self.vec } @@ -1805,8 +1815,9 @@ impl String { #[inline] #[must_use] #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")] #[rustc_confusables("length", "size")] - pub fn len(&self) -> usize { + pub const fn len(&self) -> usize { self.vec.len() } @@ -1824,7 +1835,8 @@ impl String { #[inline] #[must_use] #[stable(feature = "rust1", since = "1.0.0")] - pub fn is_empty(&self) -> bool { + #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")] + pub const fn is_empty(&self) -> bool { self.len() == 0 } @@ -2565,7 +2577,7 @@ impl ops::Deref for String { #[inline] fn deref(&self) -> &str { - unsafe { str::from_utf8_unchecked(&self.vec) } + self.as_str() } } @@ -2576,7 +2588,7 @@ unsafe impl ops::DerefPure for String {} impl ops::DerefMut for String { #[inline] fn deref_mut(&mut self) -> &mut str { - unsafe { str::from_utf8_unchecked_mut(&mut *self.vec) } + self.as_mut_str() } } diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 13b06584223..cae47393a81 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -1240,7 +1240,8 @@ impl Vec { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - pub fn capacity(&self) -> usize { + #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")] + pub const fn capacity(&self) -> usize { self.buf.capacity() } @@ -1548,8 +1549,22 @@ impl Vec { #[inline] #[stable(feature = "vec_as_slice", since = "1.7.0")] #[cfg_attr(not(test), rustc_diagnostic_item = "vec_as_slice")] - pub fn as_slice(&self) -> &[T] { - self + #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")] + pub const fn as_slice(&self) -> &[T] { + // SAFETY: `slice::from_raw_parts` requires pointee is a contiguous, aligned buffer of size + // `len` containing properly-initialized `T`s. Data must not be mutated for the returned + // lifetime. Further, `len * mem::size_of::` <= `ISIZE::MAX`, and allocation does not + // "wrap" through overflowing memory addresses. + // + // * Vec API guarantees that self.buf: + // * contains only properly-initialized items within 0..len + // * is aligned, contiguous, and valid for `len` reads + // * obeys size and address-wrapping constraints + // + // * We only construct `&mut` references to `self.buf` through `&mut self` methods; borrow- + // check ensures that it is not possible to mutably alias `self.buf` within the + // returned lifetime. + unsafe { slice::from_raw_parts(self.as_ptr(), self.len) } } /// Extracts a mutable slice of the entire vector. @@ -1566,8 +1581,22 @@ impl Vec { #[inline] #[stable(feature = "vec_as_slice", since = "1.7.0")] #[cfg_attr(not(test), rustc_diagnostic_item = "vec_as_mut_slice")] - pub fn as_mut_slice(&mut self) -> &mut [T] { - self + #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")] + pub const fn as_mut_slice(&mut self) -> &mut [T] { + // SAFETY: `slice::from_raw_parts_mut` requires pointee is a contiguous, aligned buffer of + // size `len` containing properly-initialized `T`s. Data must not be accessed through any + // other pointer for the returned lifetime. Further, `len * mem::size_of::` <= + // `ISIZE::MAX` and allocation does not "wrap" through overflowing memory addresses. + // + // * Vec API guarantees that self.buf: + // * contains only properly-initialized items within 0..len + // * is aligned, contiguous, and valid for `len` reads + // * obeys size and address-wrapping constraints + // + // * We only construct references to `self.buf` through `&self` and `&mut self` methods; + // borrow-check ensures that it is not possible to construct a reference to `self.buf` + // within the returned lifetime. + unsafe { slice::from_raw_parts_mut(self.as_mut_ptr(), self.len) } } /// Returns a raw pointer to the vector's buffer, or a dangling raw pointer @@ -1622,9 +1651,10 @@ impl Vec { /// [`as_mut_ptr`]: Vec::as_mut_ptr /// [`as_ptr`]: Vec::as_ptr #[stable(feature = "vec_as_ptr", since = "1.37.0")] + #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")] #[rustc_never_returns_null_ptr] #[inline] - pub fn as_ptr(&self) -> *const T { + pub const fn as_ptr(&self) -> *const T { // We shadow the slice method of the same name to avoid going through // `deref`, which creates an intermediate reference. self.buf.ptr() @@ -1681,9 +1711,10 @@ impl Vec { /// [`as_mut_ptr`]: Vec::as_mut_ptr /// [`as_ptr`]: Vec::as_ptr #[stable(feature = "vec_as_ptr", since = "1.37.0")] + #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")] #[rustc_never_returns_null_ptr] #[inline] - pub fn as_mut_ptr(&mut self) -> *mut T { + pub const fn as_mut_ptr(&mut self) -> *mut T { // We shadow the slice method of the same name to avoid going through // `deref_mut`, which creates an intermediate reference. self.buf.ptr() @@ -2561,8 +2592,9 @@ impl Vec { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")] #[rustc_confusables("length", "size")] - pub fn len(&self) -> usize { + pub const fn len(&self) -> usize { self.len } @@ -2579,7 +2611,8 @@ impl Vec { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[cfg_attr(not(test), rustc_diagnostic_item = "vec_is_empty")] - pub fn is_empty(&self) -> bool { + #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")] + pub const fn is_empty(&self) -> bool { self.len() == 0 } @@ -3130,7 +3163,7 @@ impl ops::Deref for Vec { #[inline] fn deref(&self) -> &[T] { - unsafe { slice::from_raw_parts(self.as_ptr(), self.len) } + self.as_slice() } } @@ -3138,7 +3171,7 @@ impl ops::Deref for Vec { impl ops::DerefMut for Vec { #[inline] fn deref_mut(&mut self) -> &mut [T] { - unsafe { slice::from_raw_parts_mut(self.as_mut_ptr(), self.len) } + self.as_mut_slice() } } 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 0ad7f5910a0..4d964b0afb7 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 @@ -5,66 +5,61 @@ fn vec_deref_to_slice(_1: &Vec) -> &[u8] { let mut _0: &[u8]; scope 1 (inlined as Deref>::deref) { debug self => _1; - let mut _6: usize; - scope 2 (inlined Vec::::as_ptr) { + scope 2 (inlined Vec::::as_slice) { debug self => _1; - let mut _2: &alloc::raw_vec::RawVec; - scope 3 (inlined alloc::raw_vec::RawVec::::ptr) { - debug self => _2; - let mut _3: &alloc::raw_vec::RawVecInner; - scope 4 (inlined alloc::raw_vec::RawVecInner::ptr::) { - debug self => _3; - scope 5 (inlined alloc::raw_vec::RawVecInner::non_null::) { + let mut _6: usize; + scope 3 (inlined Vec::::as_ptr) { + debug self => _1; + let mut _2: &alloc::raw_vec::RawVec; + scope 4 (inlined alloc::raw_vec::RawVec::::ptr) { + debug self => _2; + let mut _3: &alloc::raw_vec::RawVecInner; + scope 5 (inlined alloc::raw_vec::RawVecInner::ptr::) { debug self => _3; - let mut _4: std::ptr::NonNull; - scope 6 (inlined Unique::::cast::) { - debug ((self: Unique).0: std::ptr::NonNull) => _4; - debug ((self: Unique).1: std::marker::PhantomData) => const PhantomData::; - scope 7 (inlined NonNull::::cast::) { - debug self => _4; - scope 8 (inlined NonNull::::as_ptr) { + scope 6 (inlined alloc::raw_vec::RawVecInner::non_null::) { + debug self => _3; + let mut _4: std::ptr::NonNull; + scope 7 (inlined Unique::::cast::) { + debug ((self: Unique).0: std::ptr::NonNull) => _4; + debug ((self: Unique).1: std::marker::PhantomData) => const PhantomData::; + scope 8 (inlined NonNull::::cast::) { debug self => _4; - let mut _5: *const u8; + scope 9 (inlined NonNull::::as_ptr) { + debug self => _4; + let mut _5: *const u8; + } } } - } - scope 9 (inlined #[track_caller] as Into>>::into) { - debug ((self: Unique).0: std::ptr::NonNull) => _4; - debug ((self: Unique).1: std::marker::PhantomData) => const PhantomData::; - scope 10 (inlined as From>>::from) { - debug ((unique: Unique).0: std::ptr::NonNull) => _4; - debug ((unique: Unique).1: std::marker::PhantomData) => const PhantomData::; - scope 11 (inlined Unique::::as_non_null_ptr) { - debug ((self: Unique).0: std::ptr::NonNull) => _4; - debug ((self: Unique).1: std::marker::PhantomData) => const PhantomData::; - } + scope 10 (inlined Unique::::as_non_null_ptr) { + debug ((self: Unique).0: std::ptr::NonNull) => _4; + debug ((self: Unique).1: std::marker::PhantomData) => const PhantomData::; } } - } - scope 12 (inlined NonNull::::as_ptr) { - debug self => _4; + scope 11 (inlined NonNull::::as_ptr) { + debug self => _4; + } } } } - } - scope 13 (inlined std::slice::from_raw_parts::<'_, u8>) { - debug data => _5; - debug len => _6; - let _7: *const [u8]; - scope 14 (inlined core::ub_checks::check_language_ub) { - scope 15 (inlined core::ub_checks::check_language_ub::runtime) { - } - } - scope 16 (inlined std::mem::size_of::) { - } - scope 17 (inlined align_of::) { - } - scope 18 (inlined slice_from_raw_parts::) { + scope 12 (inlined std::slice::from_raw_parts::<'_, u8>) { debug data => _5; debug len => _6; - scope 19 (inlined std::ptr::from_raw_parts::<[u8], u8>) { - debug data_pointer => _5; - debug metadata => _6; + let _7: *const [u8]; + scope 13 (inlined core::ub_checks::check_language_ub) { + scope 14 (inlined core::ub_checks::check_language_ub::runtime) { + } + } + scope 15 (inlined std::mem::size_of::) { + } + scope 16 (inlined align_of::) { + } + scope 17 (inlined slice_from_raw_parts::) { + debug data => _5; + debug len => _6; + scope 18 (inlined std::ptr::from_raw_parts::<[u8], u8>) { + debug data_pointer => _5; + debug metadata => _6; + } } } } 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 0ad7f5910a0..4d964b0afb7 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 @@ -5,66 +5,61 @@ fn vec_deref_to_slice(_1: &Vec) -> &[u8] { let mut _0: &[u8]; scope 1 (inlined as Deref>::deref) { debug self => _1; - let mut _6: usize; - scope 2 (inlined Vec::::as_ptr) { + scope 2 (inlined Vec::::as_slice) { debug self => _1; - let mut _2: &alloc::raw_vec::RawVec; - scope 3 (inlined alloc::raw_vec::RawVec::::ptr) { - debug self => _2; - let mut _3: &alloc::raw_vec::RawVecInner; - scope 4 (inlined alloc::raw_vec::RawVecInner::ptr::) { - debug self => _3; - scope 5 (inlined alloc::raw_vec::RawVecInner::non_null::) { + let mut _6: usize; + scope 3 (inlined Vec::::as_ptr) { + debug self => _1; + let mut _2: &alloc::raw_vec::RawVec; + scope 4 (inlined alloc::raw_vec::RawVec::::ptr) { + debug self => _2; + let mut _3: &alloc::raw_vec::RawVecInner; + scope 5 (inlined alloc::raw_vec::RawVecInner::ptr::) { debug self => _3; - let mut _4: std::ptr::NonNull; - scope 6 (inlined Unique::::cast::) { - debug ((self: Unique).0: std::ptr::NonNull) => _4; - debug ((self: Unique).1: std::marker::PhantomData) => const PhantomData::; - scope 7 (inlined NonNull::::cast::) { - debug self => _4; - scope 8 (inlined NonNull::::as_ptr) { + scope 6 (inlined alloc::raw_vec::RawVecInner::non_null::) { + debug self => _3; + let mut _4: std::ptr::NonNull; + scope 7 (inlined Unique::::cast::) { + debug ((self: Unique).0: std::ptr::NonNull) => _4; + debug ((self: Unique).1: std::marker::PhantomData) => const PhantomData::; + scope 8 (inlined NonNull::::cast::) { debug self => _4; - let mut _5: *const u8; + scope 9 (inlined NonNull::::as_ptr) { + debug self => _4; + let mut _5: *const u8; + } } } - } - scope 9 (inlined #[track_caller] as Into>>::into) { - debug ((self: Unique).0: std::ptr::NonNull) => _4; - debug ((self: Unique).1: std::marker::PhantomData) => const PhantomData::; - scope 10 (inlined as From>>::from) { - debug ((unique: Unique).0: std::ptr::NonNull) => _4; - debug ((unique: Unique).1: std::marker::PhantomData) => const PhantomData::; - scope 11 (inlined Unique::::as_non_null_ptr) { - debug ((self: Unique).0: std::ptr::NonNull) => _4; - debug ((self: Unique).1: std::marker::PhantomData) => const PhantomData::; - } + scope 10 (inlined Unique::::as_non_null_ptr) { + debug ((self: Unique).0: std::ptr::NonNull) => _4; + debug ((self: Unique).1: std::marker::PhantomData) => const PhantomData::; } } - } - scope 12 (inlined NonNull::::as_ptr) { - debug self => _4; + scope 11 (inlined NonNull::::as_ptr) { + debug self => _4; + } } } } - } - scope 13 (inlined std::slice::from_raw_parts::<'_, u8>) { - debug data => _5; - debug len => _6; - let _7: *const [u8]; - scope 14 (inlined core::ub_checks::check_language_ub) { - scope 15 (inlined core::ub_checks::check_language_ub::runtime) { - } - } - scope 16 (inlined std::mem::size_of::) { - } - scope 17 (inlined align_of::) { - } - scope 18 (inlined slice_from_raw_parts::) { + scope 12 (inlined std::slice::from_raw_parts::<'_, u8>) { debug data => _5; debug len => _6; - scope 19 (inlined std::ptr::from_raw_parts::<[u8], u8>) { - debug data_pointer => _5; - debug metadata => _6; + let _7: *const [u8]; + scope 13 (inlined core::ub_checks::check_language_ub) { + scope 14 (inlined core::ub_checks::check_language_ub::runtime) { + } + } + scope 15 (inlined std::mem::size_of::) { + } + scope 16 (inlined align_of::) { + } + scope 17 (inlined slice_from_raw_parts::) { + debug data => _5; + debug len => _6; + scope 18 (inlined std::ptr::from_raw_parts::<[u8], u8>) { + debug data_pointer => _5; + debug metadata => _6; + } } } } diff --git a/tests/ui/consts/issue-94675.rs b/tests/ui/consts/issue-94675.rs index 56c4b6ea36f..2e30eebb07b 100644 --- a/tests/ui/consts/issue-94675.rs +++ b/tests/ui/consts/issue-94675.rs @@ -1,6 +1,6 @@ //@ known-bug: #103507 -#![feature(const_trait_impl)] +#![feature(const_trait_impl, const_vec_string_slice)] struct Foo<'a> { bar: &'a mut Vec, diff --git a/tests/ui/consts/issue-94675.stderr b/tests/ui/consts/issue-94675.stderr index ebfa09b2e5d..a85c5e10374 100644 --- a/tests/ui/consts/issue-94675.stderr +++ b/tests/ui/consts/issue-94675.stderr @@ -1,11 +1,3 @@ -error[E0015]: cannot call non-const fn `Vec::::len` in constant functions - --> $DIR/issue-94675.rs:11:27 - | -LL | self.bar[0] = baz.len(); - | ^^^^^ - | - = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants - error[E0015]: cannot call non-const operator in constant functions --> $DIR/issue-94675.rs:11:17 | @@ -20,6 +12,6 @@ help: add `#![feature(effects)]` to the crate attributes to enable LL + #![feature(effects)] | -error: aborting due to 2 previous errors +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0015`. From 731469fee50133528c1904a07da73e739db6f6c4 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 7 Oct 2024 11:03:52 +1100 Subject: [PATCH 648/683] Convert `Option<&Lrc>` return types to `Option<&T>`. It's simpler and more concise. --- compiler/rustc_codegen_ssa/src/back/write.rs | 5 ++--- .../src/annotate_snippet_emitter_writer.rs | 8 ++++---- compiler/rustc_errors/src/emitter.rs | 14 +++++++------- compiler/rustc_errors/src/json.rs | 6 +++--- compiler/rustc_errors/src/lib.rs | 6 +++--- compiler/rustc_errors/src/tests.rs | 4 ++-- compiler/rustc_errors/src/translation.rs | 3 +-- .../passes/lint/check_code_block_syntax.rs | 4 ++-- src/tools/rustfmt/src/parse/session.rs | 8 ++++---- 9 files changed, 28 insertions(+), 30 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index 4d81ff933dd..e22dd8373bd 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -11,7 +11,6 @@ use rustc_ast::attr; use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; use rustc_data_structures::memmap::Mmap; use rustc_data_structures::profiling::{SelfProfilerRef, VerboseTimingGuard}; -use rustc_data_structures::sync::Lrc; use rustc_errors::emitter::Emitter; use rustc_errors::translation::Translate; use rustc_errors::{ @@ -1889,7 +1888,7 @@ impl SharedEmitter { } impl Translate for SharedEmitter { - fn fluent_bundle(&self) -> Option<&Lrc> { + fn fluent_bundle(&self) -> Option<&FluentBundle> { None } @@ -1924,7 +1923,7 @@ impl Emitter for SharedEmitter { ); } - fn source_map(&self) -> Option<&Lrc> { + fn source_map(&self) -> Option<&SourceMap> { None } } diff --git a/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs b/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs index f468fbf4497..335432c9cfe 100644 --- a/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs +++ b/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs @@ -34,8 +34,8 @@ pub struct AnnotateSnippetEmitter { } impl Translate for AnnotateSnippetEmitter { - fn fluent_bundle(&self) -> Option<&Lrc> { - self.fluent_bundle.as_ref() + fn fluent_bundle(&self) -> Option<&FluentBundle> { + self.fluent_bundle.as_deref() } fn fallback_fluent_bundle(&self) -> &FluentBundle { @@ -69,8 +69,8 @@ impl Emitter for AnnotateSnippetEmitter { ); } - fn source_map(&self) -> Option<&Lrc> { - self.source_map.as_ref() + fn source_map(&self) -> Option<&SourceMap> { + self.source_map.as_deref() } fn should_show_explain(&self) -> bool { diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index 1dc52c4d0a4..1adb6b9dcfe 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -205,7 +205,7 @@ pub trait Emitter: Translate { false } - fn source_map(&self) -> Option<&Lrc>; + fn source_map(&self) -> Option<&SourceMap>; /// Formats the substitutions of the primary_span /// @@ -481,8 +481,8 @@ pub trait Emitter: Translate { } impl Translate for HumanEmitter { - fn fluent_bundle(&self) -> Option<&Lrc> { - self.fluent_bundle.as_ref() + fn fluent_bundle(&self) -> Option<&FluentBundle> { + self.fluent_bundle.as_deref() } fn fallback_fluent_bundle(&self) -> &FluentBundle { @@ -491,8 +491,8 @@ impl Translate for HumanEmitter { } impl Emitter for HumanEmitter { - fn source_map(&self) -> Option<&Lrc> { - self.sm.as_ref() + fn source_map(&self) -> Option<&SourceMap> { + self.sm.as_deref() } fn emit_diagnostic(&mut self, mut diag: DiagInner) { @@ -540,7 +540,7 @@ pub struct SilentEmitter { } impl Translate for SilentEmitter { - fn fluent_bundle(&self) -> Option<&Lrc> { + fn fluent_bundle(&self) -> Option<&FluentBundle> { None } @@ -552,7 +552,7 @@ impl Translate for SilentEmitter { } impl Emitter for SilentEmitter { - fn source_map(&self) -> Option<&Lrc> { + fn source_map(&self) -> Option<&SourceMap> { None } diff --git a/compiler/rustc_errors/src/json.rs b/compiler/rustc_errors/src/json.rs index 1972a522e39..1534e256520 100644 --- a/compiler/rustc_errors/src/json.rs +++ b/compiler/rustc_errors/src/json.rs @@ -111,8 +111,8 @@ enum EmitTyped<'a> { } impl Translate for JsonEmitter { - fn fluent_bundle(&self) -> Option<&Lrc> { - self.fluent_bundle.as_ref() + fn fluent_bundle(&self) -> Option<&FluentBundle> { + self.fluent_bundle.as_deref() } fn fallback_fluent_bundle(&self) -> &FluentBundle { @@ -172,7 +172,7 @@ impl Emitter for JsonEmitter { } } - fn source_map(&self) -> Option<&Lrc> { + fn source_map(&self) -> Option<&SourceMap> { Some(&self.sm) } diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 39acacfbe59..e5560be4531 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -59,7 +59,7 @@ use registry::Registry; use rustc_data_structures::AtomicRef; use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; use rustc_data_structures::stable_hasher::{Hash128, StableHasher}; -use rustc_data_structures::sync::{Lock, Lrc}; +use rustc_data_structures::sync::Lock; pub use rustc_error_messages::{ DiagMessage, FluentBundle, LanguageIdentifier, LazyFallbackBundle, MultiSpan, SpanLabel, SubdiagMessage, fallback_fluent_bundle, fluent_bundle, @@ -685,13 +685,13 @@ impl DiagCtxt { unimplemented!("false emitter must only used during `wrap_emitter`") } - fn source_map(&self) -> Option<&Lrc> { + fn source_map(&self) -> Option<&SourceMap> { unimplemented!("false emitter must only used during `wrap_emitter`") } } impl translation::Translate for FalseEmitter { - fn fluent_bundle(&self) -> Option<&Lrc> { + fn fluent_bundle(&self) -> Option<&FluentBundle> { unimplemented!("false emitter must only used during `wrap_emitter`") } diff --git a/compiler/rustc_errors/src/tests.rs b/compiler/rustc_errors/src/tests.rs index 17a1635bd11..70179237e5d 100644 --- a/compiler/rustc_errors/src/tests.rs +++ b/compiler/rustc_errors/src/tests.rs @@ -1,4 +1,4 @@ -use rustc_data_structures::sync::{IntoDynSyncSend, Lrc}; +use rustc_data_structures::sync::IntoDynSyncSend; use rustc_error_messages::fluent_bundle::resolver::errors::{ReferenceKind, ResolverError}; use rustc_error_messages::{DiagMessage, langid}; @@ -12,7 +12,7 @@ struct Dummy { } impl Translate for Dummy { - fn fluent_bundle(&self) -> Option<&Lrc> { + fn fluent_bundle(&self) -> Option<&FluentBundle> { None } diff --git a/compiler/rustc_errors/src/translation.rs b/compiler/rustc_errors/src/translation.rs index e0b64b276eb..156f5e5d26e 100644 --- a/compiler/rustc_errors/src/translation.rs +++ b/compiler/rustc_errors/src/translation.rs @@ -2,7 +2,6 @@ use std::borrow::Cow; use std::env; use std::error::Report; -use rustc_data_structures::sync::Lrc; pub use rustc_error_messages::FluentArgs; use tracing::{debug, trace}; @@ -33,7 +32,7 @@ pub trait Translate { /// Return `FluentBundle` with localized diagnostics for the locale requested by the user. If no /// language was requested by the user then this will be `None` and `fallback_fluent_bundle` /// should be used. - fn fluent_bundle(&self) -> Option<&Lrc>; + fn fluent_bundle(&self) -> Option<&FluentBundle>; /// Return `FluentBundle` with localized diagnostics for the default locale of the compiler. /// Used when the user has not requested a specific language or when a localized diagnostic is diff --git a/src/librustdoc/passes/lint/check_code_block_syntax.rs b/src/librustdoc/passes/lint/check_code_block_syntax.rs index 848e70a7bdb..e0dc5b4c513 100644 --- a/src/librustdoc/passes/lint/check_code_block_syntax.rs +++ b/src/librustdoc/passes/lint/check_code_block_syntax.rs @@ -145,7 +145,7 @@ struct BufferEmitter { } impl Translate for BufferEmitter { - fn fluent_bundle(&self) -> Option<&Lrc> { + fn fluent_bundle(&self) -> Option<&rustc_errors::FluentBundle> { None } @@ -169,7 +169,7 @@ impl Emitter for BufferEmitter { } } - fn source_map(&self) -> Option<&Lrc> { + fn source_map(&self) -> Option<&SourceMap> { None } } diff --git a/src/tools/rustfmt/src/parse/session.rs b/src/tools/rustfmt/src/parse/session.rs index 9f27a05939e..54ad56ed3f3 100644 --- a/src/tools/rustfmt/src/parse/session.rs +++ b/src/tools/rustfmt/src/parse/session.rs @@ -46,7 +46,7 @@ impl SilentOnIgnoredFilesEmitter { } impl Translate for SilentOnIgnoredFilesEmitter { - fn fluent_bundle(&self) -> Option<&Lrc> { + fn fluent_bundle(&self) -> Option<&rustc_errors::FluentBundle> { self.emitter.fluent_bundle() } @@ -56,7 +56,7 @@ impl Translate for SilentOnIgnoredFilesEmitter { } impl Emitter for SilentOnIgnoredFilesEmitter { - fn source_map(&self) -> Option<&Lrc> { + fn source_map(&self) -> Option<&SourceMap> { None } @@ -344,7 +344,7 @@ mod tests { } impl Translate for TestEmitter { - fn fluent_bundle(&self) -> Option<&Lrc> { + fn fluent_bundle(&self) -> Option<&rustc_errors::FluentBundle> { None } @@ -354,7 +354,7 @@ mod tests { } impl Emitter for TestEmitter { - fn source_map(&self) -> Option<&Lrc> { + fn source_map(&self) -> Option<&SourceMap> { None } From 860cbccad993151ef87ec6c39fd1b2892b18972f Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 7 Oct 2024 13:06:28 +1100 Subject: [PATCH 649/683] Convert a `&Lrc` argument to `Lrc`. It's slightly simpler. --- compiler/rustc_infer/src/infer/mod.rs | 2 +- compiler/rustc_infer/src/infer/opaque_types/mod.rs | 10 +++++++++- .../rustc_infer/src/infer/region_constraints/mod.rs | 4 ++-- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 5fa1bf51634..040264586f6 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -776,7 +776,7 @@ impl<'tcx> InferCtxt<'tcx> { definition_span: Span, hidden_ty: Ty<'tcx>, region: ty::Region<'tcx>, - in_regions: &Lrc>>, + in_regions: Lrc>>, ) { self.inner.borrow_mut().unwrap_region_constraints().member_constraint( key, diff --git a/compiler/rustc_infer/src/infer/opaque_types/mod.rs b/compiler/rustc_infer/src/infer/opaque_types/mod.rs index 55c51bc856f..ba0a9b14ccb 100644 --- a/compiler/rustc_infer/src/infer/opaque_types/mod.rs +++ b/compiler/rustc_infer/src/infer/opaque_types/mod.rs @@ -359,7 +359,15 @@ impl<'tcx> InferCtxt<'tcx> { // not currently sound until we have existential regions. concrete_ty.visit_with(&mut ConstrainOpaqueTypeRegionVisitor { tcx: self.tcx, - op: |r| self.member_constraint(opaque_type_key, span, concrete_ty, r, &choice_regions), + op: |r| { + self.member_constraint( + opaque_type_key, + span, + concrete_ty, + r, + choice_regions.clone(), + ) + }, }); } } diff --git a/compiler/rustc_infer/src/infer/region_constraints/mod.rs b/compiler/rustc_infer/src/infer/region_constraints/mod.rs index 82f7668b2d2..f22cfed0b71 100644 --- a/compiler/rustc_infer/src/infer/region_constraints/mod.rs +++ b/compiler/rustc_infer/src/infer/region_constraints/mod.rs @@ -522,7 +522,7 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> { definition_span: Span, hidden_ty: Ty<'tcx>, member_region: ty::Region<'tcx>, - choice_regions: &Lrc>>, + choice_regions: Lrc>>, ) { debug!("member_constraint({:?} in {:#?})", member_region, choice_regions); @@ -535,7 +535,7 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> { definition_span, hidden_ty, member_region, - choice_regions: choice_regions.clone(), + choice_regions, }); } From 2123509351c970b1c3fdbb21f719862dd0ab9e00 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 7 Oct 2024 13:08:19 +1100 Subject: [PATCH 650/683] Remove an unnecessary `&Lrc<_>` local variable. --- compiler/rustc_lint/src/late.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_lint/src/late.rs b/compiler/rustc_lint/src/late.rs index de401397150..6d5903ac467 100644 --- a/compiler/rustc_lint/src/late.rs +++ b/compiler/rustc_lint/src/late.rs @@ -18,7 +18,7 @@ use std::any::Any; use std::cell::Cell; use rustc_data_structures::stack::ensure_sufficient_stack; -use rustc_data_structures::sync::{Lrc, join}; +use rustc_data_structures::sync::join; use rustc_hir as hir; use rustc_hir::def_id::{LocalDefId, LocalModDefId}; use rustc_hir::{HirId, intravisit as hir_visit}; @@ -36,8 +36,7 @@ use crate::{LateContext, LateLintPass, LintStore}; /// /// This function exists because [`Session::lint_store`] is type-erased. pub fn unerased_lint_store(sess: &Session) -> &LintStore { - let store: &Lrc<_> = sess.lint_store.as_ref().unwrap(); - let store: &dyn Any = &**store; + let store: &dyn Any = sess.lint_store.as_deref().unwrap(); store.downcast_ref().unwrap() } From 4547c0a990b88700812c4e5d14c383bdc7167c31 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 7 Oct 2024 13:25:38 +1100 Subject: [PATCH 651/683] Avoid another `&Lrc<..>` in a return value. --- compiler/rustc_span/src/lib.rs | 2 +- compiler/rustc_span/src/source_map/tests.rs | 2 +- src/tools/clippy/clippy_utils/src/source.rs | 1 + 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index b55465ddef7..5b1be5bca05 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -1380,7 +1380,7 @@ pub enum ExternalSourceKind { } impl ExternalSource { - pub fn get_source(&self) -> Option<&Lrc> { + pub fn get_source(&self) -> Option<&str> { match self { ExternalSource::Foreign { kind: ExternalSourceKind::Present(ref src), .. } => Some(src), _ => None, diff --git a/compiler/rustc_span/src/source_map/tests.rs b/compiler/rustc_span/src/source_map/tests.rs index 360baec273d..5b39706f3ad 100644 --- a/compiler/rustc_span/src/source_map/tests.rs +++ b/compiler/rustc_span/src/source_map/tests.rs @@ -257,7 +257,7 @@ fn t10() { ); imported_src_file.add_external_src(|| Some(unnormalized.to_string())); assert_eq!( - imported_src_file.external_src.borrow().get_source().unwrap().as_ref(), + imported_src_file.external_src.borrow().get_source().unwrap(), normalized, "imported source file should be normalized" ); diff --git a/src/tools/clippy/clippy_utils/src/source.rs b/src/tools/clippy/clippy_utils/src/source.rs index 4ad7575e720..eecbfb3936a 100644 --- a/src/tools/clippy/clippy_utils/src/source.rs +++ b/src/tools/clippy/clippy_utils/src/source.rs @@ -287,6 +287,7 @@ impl SourceFileRange { self.sf .src .as_ref() + .map(|src| src.as_str()) .or_else(|| self.sf.external_src.get().and_then(|src| src.get_source())) .and_then(|x| x.get(self.range.clone())) } From 64efbe2b537b5c597587655f53e6227fa682c6ba 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?= Date: Mon, 7 Oct 2024 05:03:23 +0000 Subject: [PATCH 652/683] Prune invalid `ignore-mode-*` directives These are only valid for coverage test modes. --- src/tools/compiletest/src/command-list.rs | 15 --------------- src/tools/compiletest/src/header/cfg.rs | 4 ++-- src/tools/compiletest/src/header/tests.rs | 5 +---- 3 files changed, 3 insertions(+), 21 deletions(-) diff --git a/src/tools/compiletest/src/command-list.rs b/src/tools/compiletest/src/command-list.rs index a4cedbf66e2..bcdd4a69b66 100644 --- a/src/tools/compiletest/src/command-list.rs +++ b/src/tools/compiletest/src/command-list.rs @@ -64,23 +64,8 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[ "ignore-loongarch64", "ignore-macabi", "ignore-macos", - "ignore-mode-assembly", - "ignore-mode-codegen", - "ignore-mode-codegen-units", "ignore-mode-coverage-map", "ignore-mode-coverage-run", - "ignore-mode-crashes", - "ignore-mode-debuginfo", - "ignore-mode-incremental", - "ignore-mode-js-doc-test", - "ignore-mode-mir-opt", - "ignore-mode-pretty", - "ignore-mode-run-make", - "ignore-mode-run-pass-valgrind", - "ignore-mode-rustdoc", - "ignore-mode-rustdoc-json", - "ignore-mode-ui", - "ignore-mode-ui-fulldeps", "ignore-msp430", "ignore-msvc", "ignore-musl", diff --git a/src/tools/compiletest/src/header/cfg.rs b/src/tools/compiletest/src/header/cfg.rs index 948568e63c2..f3835637a1e 100644 --- a/src/tools/compiletest/src/header/cfg.rs +++ b/src/tools/compiletest/src/header/cfg.rs @@ -1,6 +1,6 @@ use std::collections::HashSet; -use crate::common::{CompareMode, Config, Debugger, Mode}; +use crate::common::{CompareMode, Config, Debugger}; use crate::header::IgnoreDecision; const EXTRA_ARCHS: &[&str] = &["spirv"]; @@ -222,7 +222,7 @@ pub(super) fn parse_cfg_name_directive<'a>( name: format!("mode-{}", config.mode.to_str()), allowed_names: ContainsPrefixed { prefix: "mode-", - inner: Mode::STR_VARIANTS, + inner: ["coverage-run", "coverage-map"], }, message: "when the test mode is {name}", } diff --git a/src/tools/compiletest/src/header/tests.rs b/src/tools/compiletest/src/header/tests.rs index ae661200c6c..76a8b129198 100644 --- a/src/tools/compiletest/src/header/tests.rs +++ b/src/tools/compiletest/src/header/tests.rs @@ -1,6 +1,5 @@ use std::io::Read; use std::path::Path; -use std::str::FromStr; use super::iter_header; use crate::common::{Config, Debugger, Mode}; @@ -574,14 +573,12 @@ fn families() { #[test] fn ignore_mode() { - for &mode in Mode::STR_VARIANTS { + for mode in ["coverage-map", "coverage-run"] { // Indicate profiler support so that "coverage-run" tests aren't skipped. let config: Config = cfg().mode(mode).profiler_support(true).build(); let other = if mode == "coverage-run" { "coverage-map" } else { "coverage-run" }; assert_ne!(mode, other); - assert_eq!(config.mode, Mode::from_str(mode).unwrap()); - assert_ne!(config.mode, Mode::from_str(other).unwrap()); assert!(check_ignore(&config, &format!("//@ ignore-mode-{mode}"))); assert!(!check_ignore(&config, &format!("//@ ignore-mode-{other}"))); From fc64ff7ec2aad5261365c0cfc033f65140828eb2 Mon Sep 17 00:00:00 2001 From: codemountains <4kz12zz@gmail.com> Date: Mon, 7 Oct 2024 08:49:47 +0900 Subject: [PATCH 653/683] Rename nested_meta to meta_item_inner --- compiler/rustc_ast_passes/src/feature_gate.rs | 4 ++-- compiler/rustc_builtin_macros/src/derive.rs | 2 +- compiler/rustc_expand/src/expand.rs | 2 +- .../rustc_resolve/src/build_reduced_graph.rs | 16 +++++++++------- compiler/rustc_resolve/src/macros.rs | 6 +++--- src/tools/rustfmt/src/attr.rs | 6 +++--- src/tools/rustfmt/src/overflow.rs | 5 ++--- src/tools/rustfmt/src/skip.rs | 4 ++-- 8 files changed, 23 insertions(+), 22 deletions(-) diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 83931a8c1a9..42d1ef5c558 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -186,9 +186,9 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { } // Check unstable flavors of the `#[doc]` attribute. if attr.has_name(sym::doc) { - for nested_meta in attr.meta_item_list().unwrap_or_default() { + for meta_item_inner in attr.meta_item_list().unwrap_or_default() { macro_rules! gate_doc { ($($s:literal { $($name:ident => $feature:ident)* })*) => { - $($(if nested_meta.has_name(sym::$name) { + $($(if meta_item_inner.has_name(sym::$name) { let msg = concat!("`#[doc(", stringify!($name), ")]` is ", $s); gate!(self, $feature, attr.span, msg); })*)* diff --git a/compiler/rustc_builtin_macros/src/derive.rs b/compiler/rustc_builtin_macros/src/derive.rs index 361fcaa8534..60450d085f6 100644 --- a/compiler/rustc_builtin_macros/src/derive.rs +++ b/compiler/rustc_builtin_macros/src/derive.rs @@ -49,7 +49,7 @@ impl MultiItemModifier for Expander { let mut resolutions = match &meta_item.kind { MetaItemKind::List(list) => { list.iter() - .filter_map(|nested_meta| match nested_meta { + .filter_map(|meta_item_inner| match meta_item_inner { MetaItemInner::MetaItem(meta) => Some(meta), MetaItemInner::Lit(lit) => { // Reject `#[derive("Debug")]`. diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 5347381c3c3..a872b12e744 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -1863,7 +1863,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { .iter() .filter(|a| a.has_name(sym::derive)) .flat_map(|a| a.meta_item_list().unwrap_or_default()) - .filter_map(|nested_meta| match nested_meta { + .filter_map(|meta_item_inner| match meta_item_inner { MetaItemInner::MetaItem(ast::MetaItem { kind: MetaItemKind::Word, path, diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index a9ea268e51a..d836e535669 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -1072,13 +1072,13 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { import_all = Some(meta.span); break; } - MetaItemKind::List(nested_metas) => { - for nested_meta in nested_metas { - match nested_meta.ident() { - Some(ident) if nested_meta.is_word() => { + MetaItemKind::List(meta_item_inners) => { + for meta_item_inner in meta_item_inners { + match meta_item_inner.ident() { + Some(ident) if meta_item_inner.is_word() => { single_imports.push(ident) } - _ => ill_formed(nested_meta.span()), + _ => ill_formed(meta_item_inner.span()), } } } @@ -1198,8 +1198,10 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { } else if attr::contains_name(&item.attrs, sym::proc_macro_attribute) { return Some((MacroKind::Attr, item.ident, item.span)); } else if let Some(attr) = attr::find_by_name(&item.attrs, sym::proc_macro_derive) { - if let Some(nested_meta) = attr.meta_item_list().and_then(|list| list.get(0).cloned()) { - if let Some(ident) = nested_meta.ident() { + if let Some(meta_item_inner) = + attr.meta_item_list().and_then(|list| list.get(0).cloned()) + { + if let Some(ident) = meta_item_inner.ident() { return Some((MacroKind::Derive, ident, ident.span)); } } diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index 21924437a4a..fa2be8216c7 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -129,8 +129,8 @@ pub(crate) fn registered_tools(tcx: TyCtxt<'_>, (): ()) -> RegisteredTools { let mut registered_tools = RegisteredTools::default(); let (_, pre_configured_attrs) = &*tcx.crate_for_resolver(()).borrow(); for attr in attr::filter_by_name(pre_configured_attrs, sym::register_tool) { - for nested_meta in attr.meta_item_list().unwrap_or_default() { - match nested_meta.ident() { + for meta_item_inner in attr.meta_item_list().unwrap_or_default() { + match meta_item_inner.ident() { Some(ident) => { if let Some(old_ident) = registered_tools.replace(ident) { tcx.dcx().emit_err(errors::ToolWasAlreadyRegistered { @@ -142,7 +142,7 @@ pub(crate) fn registered_tools(tcx: TyCtxt<'_>, (): ()) -> RegisteredTools { } None => { tcx.dcx().emit_err(errors::ToolOnlyAcceptsIdentifiers { - span: nested_meta.span(), + span: meta_item_inner.span(), tool: sym::register_tool, }); } diff --git a/src/tools/rustfmt/src/attr.rs b/src/tools/rustfmt/src/attr.rs index ad425d0bff7..381c938ae80 100644 --- a/src/tools/rustfmt/src/attr.rs +++ b/src/tools/rustfmt/src/attr.rs @@ -90,7 +90,7 @@ fn format_derive( let item_spans = attr.meta_item_list().map(|meta_item_list| { meta_item_list .into_iter() - .map(|nested_meta_item| nested_meta_item.span()) + .map(|meta_item_inner| meta_item_inner.span()) })?; let items = itemize_list( @@ -536,7 +536,7 @@ pub(crate) trait MetaVisitor<'ast> { list: &'ast [ast::MetaItemInner], ) { for nm in list { - self.visit_nested_meta_item(nm); + self.visit_meta_item_inner(nm); } } @@ -549,7 +549,7 @@ pub(crate) trait MetaVisitor<'ast> { ) { } - fn visit_nested_meta_item(&mut self, nm: &'ast ast::MetaItemInner) { + fn visit_meta_item_inner(&mut self, nm: &'ast ast::MetaItemInner) { match nm { ast::MetaItemInner::MetaItem(ref meta_item) => self.visit_meta_item(meta_item), ast::MetaItemInner::Lit(ref lit) => self.visit_meta_item_lit(lit), diff --git a/src/tools/rustfmt/src/overflow.rs b/src/tools/rustfmt/src/overflow.rs index 3f44789bafd..728adff2c7d 100644 --- a/src/tools/rustfmt/src/overflow.rs +++ b/src/tools/rustfmt/src/overflow.rs @@ -138,7 +138,7 @@ impl<'a> OverflowableItem<'a> { OverflowableItem::Expr(expr) => is_simple_expr(expr), OverflowableItem::MacroArg(MacroArg::Keyword(..)) => true, OverflowableItem::MacroArg(MacroArg::Expr(expr)) => is_simple_expr(expr), - OverflowableItem::MetaItemInner(nested_meta_item) => match nested_meta_item { + OverflowableItem::MetaItemInner(meta_item_inner) => match meta_item_inner { ast::MetaItemInner::Lit(..) => true, ast::MetaItemInner::MetaItem(ref meta_item) => { matches!(meta_item.kind, ast::MetaItemKind::Word) @@ -184,8 +184,7 @@ impl<'a> OverflowableItem<'a> { MacroArg::Item(..) => len == 1, MacroArg::Keyword(..) => false, }, - OverflowableItem::MetaItemInner(nested_meta_item) if len == 1 => match nested_meta_item - { + OverflowableItem::MetaItemInner(meta_item_inner) if len == 1 => match meta_item_inner { ast::MetaItemInner::Lit(..) => false, ast::MetaItemInner::MetaItem(..) => true, }, diff --git a/src/tools/rustfmt/src/skip.rs b/src/tools/rustfmt/src/skip.rs index d733f7068fd..cd3860d3d7f 100644 --- a/src/tools/rustfmt/src/skip.rs +++ b/src/tools/rustfmt/src/skip.rs @@ -116,8 +116,8 @@ fn get_skip_names(kind: &str, attrs: &[ast::Attribute]) -> Vec { } if let Some(list) = attr.meta_item_list() { - for nested_meta_item in list { - if let Some(name) = nested_meta_item.ident() { + for meta_item_inner in list { + if let Some(name) = meta_item_inner.ident() { skip_names.push(name.to_string()); } } From a961be9f1338d215a356fca01ffd4db1de56279c 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?= Date: Mon, 7 Oct 2024 07:51:06 +0000 Subject: [PATCH 654/683] Remove valgrind test suite and support from compiletest --- src/tools/compiletest/src/common.rs | 8 ---- src/tools/compiletest/src/lib.rs | 6 +-- src/tools/compiletest/src/main.rs | 4 -- src/tools/compiletest/src/runtest.rs | 38 ++----------------- .../compiletest/src/runtest/incremental.rs | 34 ++++++++++++----- src/tools/compiletest/src/runtest/valgrind.rs | 34 ----------------- 6 files changed, 29 insertions(+), 95 deletions(-) delete mode 100644 src/tools/compiletest/src/runtest/valgrind.rs diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index adc89cad72f..17ec6ea4301 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -53,7 +53,6 @@ macro_rules! string_enum { string_enum! { #[derive(Clone, Copy, PartialEq, Debug)] pub enum Mode { - RunPassValgrind => "run-pass-valgrind", Pretty => "pretty", DebugInfo => "debuginfo", Codegen => "codegen", @@ -207,13 +206,6 @@ pub struct Config { /// Path to LLVM's bin directory. pub llvm_bin_dir: Option, - /// The valgrind path. - pub valgrind_path: Option, - - /// Whether to fail if we can't run run-pass-valgrind tests under valgrind - /// (or, alternatively, to silently run them like regular run-pass tests). - pub force_valgrind: bool, - /// The path to the Clang executable to run Clang-based tests with. If /// `None` then these tests will be ignored. pub run_clang_based_tests_with: Option, diff --git a/src/tools/compiletest/src/lib.rs b/src/tools/compiletest/src/lib.rs index a8355ee9590..d9f64cddf5d 100644 --- a/src/tools/compiletest/src/lib.rs +++ b/src/tools/compiletest/src/lib.rs @@ -53,8 +53,6 @@ pub fn parse_config(args: Vec) -> Config { .reqopt("", "python", "path to python to use for doc tests", "PATH") .optopt("", "jsondocck-path", "path to jsondocck to use for doc tests", "PATH") .optopt("", "jsondoclint-path", "path to jsondoclint to use for doc tests", "PATH") - .optopt("", "valgrind-path", "path to Valgrind executable for Valgrind tests", "PROGRAM") - .optflag("", "force-valgrind", "fail if Valgrind tests cannot be run under Valgrind") .optopt("", "run-clang-based-tests-with", "path to Clang executable", "PATH") .optopt("", "llvm-filecheck", "path to LLVM's FileCheck binary", "DIR") .reqopt("", "src-base", "directory to scan for test files", "PATH") @@ -65,7 +63,7 @@ pub fn parse_config(args: Vec) -> Config { "", "mode", "which sort of compile tests to run", - "run-pass-valgrind | pretty | debug-info | codegen | rustdoc \ + "pretty | debug-info | codegen | rustdoc \ | rustdoc-json | codegen-units | incremental | run-make | ui \ | js-doc-test | mir-opt | assembly | crashes", ) @@ -269,8 +267,6 @@ pub fn parse_config(args: Vec) -> Config { python: matches.opt_str("python").unwrap(), jsondocck_path: matches.opt_str("jsondocck-path"), jsondoclint_path: matches.opt_str("jsondoclint-path"), - valgrind_path: matches.opt_str("valgrind-path"), - force_valgrind: matches.opt_present("force-valgrind"), run_clang_based_tests_with: matches.opt_str("run-clang-based-tests-with"), llvm_filecheck: matches.opt_str("llvm-filecheck").map(PathBuf::from), llvm_bin_dir: matches.opt_str("llvm-bin-dir").map(PathBuf::from), diff --git a/src/tools/compiletest/src/main.rs b/src/tools/compiletest/src/main.rs index 7b85e6f80b3..9f3eef3776d 100644 --- a/src/tools/compiletest/src/main.rs +++ b/src/tools/compiletest/src/main.rs @@ -18,10 +18,6 @@ fn main() { let config = Arc::new(parse_config(env::args().collect())); - if config.valgrind_path.is_none() && config.force_valgrind { - panic!("Can't find Valgrind to run Valgrind tests"); - } - if !config.has_tidy && config.mode == Mode::Rustdoc { eprintln!("warning: `tidy` is not installed; diffs will not be generated"); } diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 74d86d2b521..ffde06fdd8b 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -20,9 +20,9 @@ use tracing::*; use crate::common::{ Assembly, Codegen, CodegenUnits, CompareMode, Config, CoverageMap, CoverageRun, Crashes, DebugInfo, Debugger, FailMode, Incremental, JsDocTest, MirOpt, PassMode, Pretty, RunMake, - RunPassValgrind, Rustdoc, RustdocJson, TestPaths, UI_EXTENSIONS, UI_FIXED, UI_RUN_STDERR, - UI_RUN_STDOUT, UI_STDERR, UI_STDOUT, UI_SVG, UI_WINDOWS_SVG, Ui, expected_output_path, - incremental_dir, output_base_dir, output_base_name, output_testname_unique, + Rustdoc, RustdocJson, TestPaths, UI_EXTENSIONS, UI_FIXED, UI_RUN_STDERR, UI_RUN_STDOUT, + UI_STDERR, UI_STDOUT, UI_SVG, UI_WINDOWS_SVG, Ui, expected_output_path, incremental_dir, + output_base_dir, output_base_name, output_testname_unique, }; use crate::compute_diff::{write_diff, write_filtered_diff}; use crate::errors::{self, Error, ErrorKind}; @@ -49,7 +49,6 @@ mod run_make; mod rustdoc; mod rustdoc_json; mod ui; -mod valgrind; // tidy-alphabet-end #[cfg(test)] @@ -253,7 +252,6 @@ impl<'test> TestCx<'test> { self.fatal("cannot use should-ice in a test that is not cfail"); } match self.config.mode { - RunPassValgrind => self.run_valgrind_test(), Pretty => self.run_pretty_test(), DebugInfo => self.run_debuginfo_test(), Codegen => self.run_codegen_test(), @@ -1500,8 +1498,7 @@ impl<'test> TestCx<'test> { Crashes => { set_mir_dump_dir(&mut rustc); } - RunPassValgrind | Pretty | DebugInfo | Rustdoc | RustdocJson | RunMake - | CodegenUnits | JsDocTest => { + Pretty | DebugInfo | Rustdoc | RustdocJson | RunMake | CodegenUnits | JsDocTest => { // do not use JSON output } } @@ -2651,33 +2648,6 @@ impl<'test> TestCx<'test> { } } - // FIXME(jieyouxu): `run_rpass_test` is hoisted out here and not in incremental because - // apparently valgrind test falls back to `run_rpass_test` if valgrind isn't available, which - // seems highly questionable to me. - fn run_rpass_test(&self) { - let emit_metadata = self.should_emit_metadata(self.pass_mode()); - let should_run = self.run_if_enabled(); - let proc_res = self.compile_test(should_run, emit_metadata); - - if !proc_res.status.success() { - self.fatal_proc_rec("compilation failed!", &proc_res); - } - - // FIXME(#41968): Move this check to tidy? - if !errors::load_errors(&self.testpaths.file, self.revision).is_empty() { - self.fatal("run-pass tests with expected warnings should be moved to ui/"); - } - - if let WillExecute::Disabled = should_run { - return; - } - - let proc_res = self.exec_compiled_test(); - if !proc_res.status.success() { - self.fatal_proc_rec("test run failed!", &proc_res); - } - } - fn aggressive_rm_rf(&self, path: &Path) -> io::Result<()> { for e in path.read_dir()? { let entry = e?; diff --git a/src/tools/compiletest/src/runtest/incremental.rs b/src/tools/compiletest/src/runtest/incremental.rs index 81b006292e4..bf2b71fef43 100644 --- a/src/tools/compiletest/src/runtest/incremental.rs +++ b/src/tools/compiletest/src/runtest/incremental.rs @@ -1,10 +1,6 @@ use super::{TestCx, WillExecute}; use crate::errors; -// FIXME(jieyouxu): `run_rpass_test` got hoisted out of this because apparently valgrind falls back -// to `run_rpass_test` if valgrind isn't available, which is questionable, but keeping it for -// refactoring changes to preserve current behavior. - impl TestCx<'_> { pub(super) fn run_incremental_test(&self) { // Basic plan for a test incremental/foo/bar.rs: @@ -73,6 +69,30 @@ impl TestCx<'_> { } } + fn run_rpass_test(&self) { + let emit_metadata = self.should_emit_metadata(self.pass_mode()); + let should_run = self.run_if_enabled(); + let proc_res = self.compile_test(should_run, emit_metadata); + + if !proc_res.status.success() { + self.fatal_proc_rec("compilation failed!", &proc_res); + } + + // FIXME(#41968): Move this check to tidy? + if !errors::load_errors(&self.testpaths.file, self.revision).is_empty() { + self.fatal("run-pass tests with expected warnings should be moved to ui/"); + } + + if let WillExecute::Disabled = should_run { + return; + } + + let proc_res = self.exec_compiled_test(); + if !proc_res.status.success() { + self.fatal_proc_rec("test run failed!", &proc_res); + } + } + fn run_cfail_test(&self) { let pm = self.pass_mode(); let proc_res = self.compile_test(WillExecute::No, self.should_emit_metadata(pm)); @@ -115,12 +135,6 @@ impl TestCx<'_> { let proc_res = self.exec_compiled_test(); - // The value our Makefile configures valgrind to return on failure - const VALGRIND_ERR: i32 = 100; - if proc_res.status.code() == Some(VALGRIND_ERR) { - self.fatal_proc_rec("run-fail test isn't valgrind-clean!", &proc_res); - } - let output_to_check = self.get_output(&proc_res); self.check_correct_failure_status(&proc_res); self.check_all_error_patterns(&output_to_check, &proc_res, pm); diff --git a/src/tools/compiletest/src/runtest/valgrind.rs b/src/tools/compiletest/src/runtest/valgrind.rs deleted file mode 100644 index 8d72c4be9ff..00000000000 --- a/src/tools/compiletest/src/runtest/valgrind.rs +++ /dev/null @@ -1,34 +0,0 @@ -use super::{Emit, TestCx, WillExecute}; - -impl TestCx<'_> { - pub(super) fn run_valgrind_test(&self) { - assert!(self.revision.is_none(), "revisions not relevant here"); - - // FIXME(jieyouxu): does this really make any sense? If a valgrind test isn't testing - // valgrind, what is it even testing? - if self.config.valgrind_path.is_none() { - assert!(!self.config.force_valgrind); - return self.run_rpass_test(); - } - - let should_run = self.run_if_enabled(); - let mut proc_res = self.compile_test(should_run, Emit::None); - - if !proc_res.status.success() { - self.fatal_proc_rec("compilation failed!", &proc_res); - } - - if let WillExecute::Disabled = should_run { - return; - } - - let mut new_config = self.config.clone(); - new_config.runner = new_config.valgrind_path.clone(); - let new_cx = TestCx { config: &new_config, ..*self }; - proc_res = new_cx.exec_compiled_test(); - - if !proc_res.status.success() { - self.fatal_proc_rec("test run failed!", &proc_res); - } - } -} From de588a6e6069f06aac04e4bd0b6d93e3db2a70e7 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?= Date: Mon, 7 Oct 2024 07:53:14 +0000 Subject: [PATCH 655/683] Remove valgrind test suite support from bootstrap --- src/bootstrap/src/core/build_steps/test.rs | 6 ------ src/bootstrap/src/core/builder.rs | 2 -- 2 files changed, 8 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index 7283b0e9574..7a49b68b91e 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -1394,12 +1394,6 @@ default_test!(Ui { path: "tests/ui", mode: "ui", suite: "ui" }); default_test!(Crashes { path: "tests/crashes", mode: "crashes", suite: "crashes" }); -default_test!(RunPassValgrind { - path: "tests/run-pass-valgrind", - mode: "run-pass-valgrind", - suite: "run-pass-valgrind" -}); - default_test!(Codegen { path: "tests/codegen", mode: "codegen", suite: "codegen" }); default_test!(CodegenUnits { diff --git a/src/bootstrap/src/core/builder.rs b/src/bootstrap/src/core/builder.rs index e7a19d0bcc0..4ca06e680d3 100644 --- a/src/bootstrap/src/core/builder.rs +++ b/src/bootstrap/src/core/builder.rs @@ -327,7 +327,6 @@ const PATH_REMAP: &[(&str, &[&str])] = &[ "tests/mir-opt", "tests/pretty", "tests/run-make", - "tests/run-pass-valgrind", "tests/rustdoc", "tests/rustdoc-gui", "tests/rustdoc-js", @@ -852,7 +851,6 @@ impl<'a> Builder<'a> { test::Tidy, test::Ui, test::Crashes, - test::RunPassValgrind, test::Coverage, test::CoverageMap, test::CoverageRun, From f1e408a8debad9b6dd230cc7b7e914e8d7c2fdd6 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?= Date: Mon, 7 Oct 2024 07:54:57 +0000 Subject: [PATCH 656/683] Remove valgrind test suite from opt-dist --- src/tools/opt-dist/src/tests.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/tools/opt-dist/src/tests.rs b/src/tools/opt-dist/src/tests.rs index 82c393d34a6..e401554640c 100644 --- a/src/tools/opt-dist/src/tests.rs +++ b/src/tools/opt-dist/src/tests.rs @@ -96,7 +96,6 @@ llvm-config = "{llvm_config}" "tests/incremental", "tests/mir-opt", "tests/pretty", - "tests/run-pass-valgrind", "tests/ui", "tests/crashes", ]; From fa3c25e1124d4cd45efde79efdd7455e48379eda 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?= Date: Mon, 7 Oct 2024 08:02:30 +0000 Subject: [PATCH 657/683] Delete the `run-pass-valgrind` test suite --- .../run-pass-valgrind/cast-enum-with-dtor.rs | 34 --------- .../cleanup-auto-borrow-obj.rs | 28 -------- tests/run-pass-valgrind/cleanup-stdin.rs | 5 -- tests/run-pass-valgrind/coerce-match-calls.rs | 21 ------ tests/run-pass-valgrind/coerce-match.rs | 31 --------- .../down-with-thread-dtors.rs | 43 ------------ tests/run-pass-valgrind/dst-dtor-1.rs | 28 -------- tests/run-pass-valgrind/dst-dtor-2.rs | 23 ------- tests/run-pass-valgrind/dst-dtor-3.rs | 26 ------- tests/run-pass-valgrind/dst-dtor-4.rs | 21 ------ tests/run-pass-valgrind/exit-flushes.rs | 19 ----- tests/run-pass-valgrind/issue-44800.rs | 12 ---- .../by-value-trait-objects-rust-call.rs | 55 --------------- .../by-value-trait-objects-rust-call2.rs | 69 ------------------- .../unsized-locals/by-value-trait-objects.rs | 48 ------------- .../long-live-the-unsized-temporary.rs | 52 -------------- 16 files changed, 515 deletions(-) delete mode 100644 tests/run-pass-valgrind/cast-enum-with-dtor.rs delete mode 100644 tests/run-pass-valgrind/cleanup-auto-borrow-obj.rs delete mode 100644 tests/run-pass-valgrind/cleanup-stdin.rs delete mode 100644 tests/run-pass-valgrind/coerce-match-calls.rs delete mode 100644 tests/run-pass-valgrind/coerce-match.rs delete mode 100644 tests/run-pass-valgrind/down-with-thread-dtors.rs delete mode 100644 tests/run-pass-valgrind/dst-dtor-1.rs delete mode 100644 tests/run-pass-valgrind/dst-dtor-2.rs delete mode 100644 tests/run-pass-valgrind/dst-dtor-3.rs delete mode 100644 tests/run-pass-valgrind/dst-dtor-4.rs delete mode 100644 tests/run-pass-valgrind/exit-flushes.rs delete mode 100644 tests/run-pass-valgrind/issue-44800.rs delete mode 100644 tests/run-pass-valgrind/unsized-locals/by-value-trait-objects-rust-call.rs delete mode 100644 tests/run-pass-valgrind/unsized-locals/by-value-trait-objects-rust-call2.rs delete mode 100644 tests/run-pass-valgrind/unsized-locals/by-value-trait-objects.rs delete mode 100644 tests/run-pass-valgrind/unsized-locals/long-live-the-unsized-temporary.rs diff --git a/tests/run-pass-valgrind/cast-enum-with-dtor.rs b/tests/run-pass-valgrind/cast-enum-with-dtor.rs deleted file mode 100644 index a57dc373478..00000000000 --- a/tests/run-pass-valgrind/cast-enum-with-dtor.rs +++ /dev/null @@ -1,34 +0,0 @@ -#![allow(dead_code, cenum_impl_drop_cast)] - -// check dtor calling order when casting enums. - -use std::mem; -use std::sync::atomic; -use std::sync::atomic::Ordering; - -enum E { - A = 0, - B = 1, - C = 2, -} - -static FLAG: atomic::AtomicUsize = atomic::AtomicUsize::new(0); - -impl Drop for E { - fn drop(&mut self) { - // avoid dtor loop - unsafe { mem::forget(mem::replace(self, E::B)) }; - - FLAG.store(FLAG.load(Ordering::SeqCst) + 1, Ordering::SeqCst); - } -} - -fn main() { - assert_eq!(FLAG.load(Ordering::SeqCst), 0); - { - let e = E::C; - assert_eq!(e as u32, 2); - assert_eq!(FLAG.load(Ordering::SeqCst), 1); - } - assert_eq!(FLAG.load(Ordering::SeqCst), 1); -} diff --git a/tests/run-pass-valgrind/cleanup-auto-borrow-obj.rs b/tests/run-pass-valgrind/cleanup-auto-borrow-obj.rs deleted file mode 100644 index e4ce80b3305..00000000000 --- a/tests/run-pass-valgrind/cleanup-auto-borrow-obj.rs +++ /dev/null @@ -1,28 +0,0 @@ -// This would previously leak the Box because we wouldn't -// schedule cleanups when auto borrowing trait objects. -// This program should be valgrind clean. - -static mut DROP_RAN: bool = false; - -struct Foo; -impl Drop for Foo { - fn drop(&mut self) { - unsafe { - DROP_RAN = true; - } - } -} - -trait Trait { - fn dummy(&self) {} -} -impl Trait for Foo {} - -pub fn main() { - { - let _x: &Trait = &*(Box::new(Foo) as Box); - } - unsafe { - assert!(DROP_RAN); - } -} diff --git a/tests/run-pass-valgrind/cleanup-stdin.rs b/tests/run-pass-valgrind/cleanup-stdin.rs deleted file mode 100644 index cf8f81cf5aa..00000000000 --- a/tests/run-pass-valgrind/cleanup-stdin.rs +++ /dev/null @@ -1,5 +0,0 @@ -fn main() { - let _ = std::io::stdin(); - let _ = std::io::stdout(); - let _ = std::io::stderr(); -} diff --git a/tests/run-pass-valgrind/coerce-match-calls.rs b/tests/run-pass-valgrind/coerce-match-calls.rs deleted file mode 100644 index 8c7375610dd..00000000000 --- a/tests/run-pass-valgrind/coerce-match-calls.rs +++ /dev/null @@ -1,21 +0,0 @@ -// Check that coercions are propagated through match and if expressions. - -//@ pretty-expanded FIXME #23616 - -use std::boxed::Box; - -pub fn main() { - let _: Box<[isize]> = if true { Box::new([1, 2, 3]) } else { Box::new([1]) }; - - let _: Box<[isize]> = match true { - true => Box::new([1, 2, 3]), - false => Box::new([1]), - }; - - // Check we don't get over-keen at propagating coercions in the case of casts. - let x = if true { 42 } else { 42u8 } as u16; - let x = match true { - true => 42, - false => 42u8, - } as u16; -} diff --git a/tests/run-pass-valgrind/coerce-match.rs b/tests/run-pass-valgrind/coerce-match.rs deleted file mode 100644 index 95f16a8cc89..00000000000 --- a/tests/run-pass-valgrind/coerce-match.rs +++ /dev/null @@ -1,31 +0,0 @@ -// Check that coercions are propagated through match and if expressions. - -//@ pretty-expanded FIXME #23616 - -pub fn main() { - let _: Box<[isize]> = if true { - let b: Box<_> = Box::new([1, 2, 3]); - b - } else { - let b: Box<_> = Box::new([1]); - b - }; - - let _: Box<[isize]> = match true { - true => { - let b: Box<_> = Box::new([1, 2, 3]); - b - } - false => { - let b: Box<_> = Box::new([1]); - b - } - }; - - // Check we don't get over-keen at propagating coercions in the case of casts. - let x = if true { 42 } else { 42u8 } as u16; - let x = match true { - true => 42, - false => 42u8, - } as u16; -} diff --git a/tests/run-pass-valgrind/down-with-thread-dtors.rs b/tests/run-pass-valgrind/down-with-thread-dtors.rs deleted file mode 100644 index 0d3745bba5b..00000000000 --- a/tests/run-pass-valgrind/down-with-thread-dtors.rs +++ /dev/null @@ -1,43 +0,0 @@ -//@ ignore-emscripten - -thread_local!(static FOO: Foo = Foo); -thread_local!(static BAR: Bar = Bar(1)); -thread_local!(static BAZ: Baz = Baz); - -static mut HIT: bool = false; - -struct Foo; -struct Bar(i32); -struct Baz; - -impl Drop for Foo { - fn drop(&mut self) { - BAR.with(|_| {}); - } -} - -impl Drop for Bar { - fn drop(&mut self) { - assert_eq!(self.0, 1); - self.0 = 2; - BAZ.with(|_| {}); - assert_eq!(self.0, 2); - } -} - -impl Drop for Baz { - fn drop(&mut self) { - unsafe { - HIT = true; - } - } -} - -fn main() { - std::thread::spawn(|| { - FOO.with(|_| {}); - }) - .join() - .unwrap(); - assert!(unsafe { HIT }); -} diff --git a/tests/run-pass-valgrind/dst-dtor-1.rs b/tests/run-pass-valgrind/dst-dtor-1.rs deleted file mode 100644 index 47065151a03..00000000000 --- a/tests/run-pass-valgrind/dst-dtor-1.rs +++ /dev/null @@ -1,28 +0,0 @@ -static mut DROP_RAN: bool = false; - -struct Foo; -impl Drop for Foo { - fn drop(&mut self) { - unsafe { - DROP_RAN = true; - } - } -} - -trait Trait { - fn dummy(&self) {} -} -impl Trait for Foo {} - -struct Fat { - f: T, -} - -pub fn main() { - { - let _x: Box> = Box::>::new(Fat { f: Foo }); - } - unsafe { - assert!(DROP_RAN); - } -} diff --git a/tests/run-pass-valgrind/dst-dtor-2.rs b/tests/run-pass-valgrind/dst-dtor-2.rs deleted file mode 100644 index d8abebfb447..00000000000 --- a/tests/run-pass-valgrind/dst-dtor-2.rs +++ /dev/null @@ -1,23 +0,0 @@ -static mut DROP_RAN: isize = 0; - -struct Foo; -impl Drop for Foo { - fn drop(&mut self) { - unsafe { - DROP_RAN += 1; - } - } -} - -struct Fat { - f: T, -} - -pub fn main() { - { - let _x: Box> = Box::>::new(Fat { f: [Foo, Foo, Foo] }); - } - unsafe { - assert_eq!(DROP_RAN, 3); - } -} diff --git a/tests/run-pass-valgrind/dst-dtor-3.rs b/tests/run-pass-valgrind/dst-dtor-3.rs deleted file mode 100644 index 09adaca21c7..00000000000 --- a/tests/run-pass-valgrind/dst-dtor-3.rs +++ /dev/null @@ -1,26 +0,0 @@ -#![feature(unsized_tuple_coercion)] - -static mut DROP_RAN: bool = false; - -struct Foo; -impl Drop for Foo { - fn drop(&mut self) { - unsafe { - DROP_RAN = true; - } - } -} - -trait Trait { - fn dummy(&self) {} -} -impl Trait for Foo {} - -pub fn main() { - { - let _x: Box<(i32, Trait)> = Box::<(i32, Foo)>::new((42, Foo)); - } - unsafe { - assert!(DROP_RAN); - } -} diff --git a/tests/run-pass-valgrind/dst-dtor-4.rs b/tests/run-pass-valgrind/dst-dtor-4.rs deleted file mode 100644 index a66ac8e3cfc..00000000000 --- a/tests/run-pass-valgrind/dst-dtor-4.rs +++ /dev/null @@ -1,21 +0,0 @@ -#![feature(unsized_tuple_coercion)] - -static mut DROP_RAN: isize = 0; - -struct Foo; -impl Drop for Foo { - fn drop(&mut self) { - unsafe { - DROP_RAN += 1; - } - } -} - -pub fn main() { - { - let _x: Box<(i32, [Foo])> = Box::<(i32, [Foo; 3])>::new((42, [Foo, Foo, Foo])); - } - unsafe { - assert_eq!(DROP_RAN, 3); - } -} diff --git a/tests/run-pass-valgrind/exit-flushes.rs b/tests/run-pass-valgrind/exit-flushes.rs deleted file mode 100644 index 4e25ef76d39..00000000000 --- a/tests/run-pass-valgrind/exit-flushes.rs +++ /dev/null @@ -1,19 +0,0 @@ -//@ ignore-wasm32 no subprocess support -//@ ignore-sgx no processes -//@ ignore-apple this needs valgrind 3.11 or higher; see -// https://github.com/rust-lang/rust/pull/30365#issuecomment-165763679 - -use std::env; -use std::process::{Command, exit}; - -fn main() { - if env::args().len() > 1 { - print!("hello!"); - exit(0); - } else { - let out = Command::new(env::args().next().unwrap()).arg("foo").output().unwrap(); - assert!(out.status.success()); - assert_eq!(String::from_utf8(out.stdout).unwrap(), "hello!"); - assert_eq!(String::from_utf8(out.stderr).unwrap(), ""); - } -} diff --git a/tests/run-pass-valgrind/issue-44800.rs b/tests/run-pass-valgrind/issue-44800.rs deleted file mode 100644 index f76657ca752..00000000000 --- a/tests/run-pass-valgrind/issue-44800.rs +++ /dev/null @@ -1,12 +0,0 @@ -use std::alloc::System; -use std::collections::VecDeque; - -#[global_allocator] -static ALLOCATOR: System = System; - -fn main() { - let mut deque = VecDeque::with_capacity(32); - deque.push_front(0); - deque.reserve(31); - deque.push_back(0); -} diff --git a/tests/run-pass-valgrind/unsized-locals/by-value-trait-objects-rust-call.rs b/tests/run-pass-valgrind/unsized-locals/by-value-trait-objects-rust-call.rs deleted file mode 100644 index 5d3f558a63a..00000000000 --- a/tests/run-pass-valgrind/unsized-locals/by-value-trait-objects-rust-call.rs +++ /dev/null @@ -1,55 +0,0 @@ -#![feature(unsized_locals)] -#![feature(unboxed_closures)] -#![feature(tuple_trait)] - -pub trait FnOnce { - type Output; - extern "rust-call" fn call_once(self, args: Args) -> Self::Output; -} - -struct A; - -impl FnOnce<()> for A { - type Output = String; - extern "rust-call" fn call_once(self, (): ()) -> Self::Output { - format!("hello") - } -} - -struct B(i32); - -impl FnOnce<()> for B { - type Output = String; - extern "rust-call" fn call_once(self, (): ()) -> Self::Output { - format!("{}", self.0) - } -} - -struct C(String); - -impl FnOnce<()> for C { - type Output = String; - extern "rust-call" fn call_once(self, (): ()) -> Self::Output { - self.0 - } -} - -struct D(Box); - -impl FnOnce<()> for D { - type Output = String; - extern "rust-call" fn call_once(self, (): ()) -> Self::Output { - *self.0 - } -} - -fn main() { - let x = *(Box::new(A) as Box>); - assert_eq!(x.call_once(()), format!("hello")); - let x = *(Box::new(B(42)) as Box>); - assert_eq!(x.call_once(()), format!("42")); - let x = *(Box::new(C(format!("jumping fox"))) as Box>); - assert_eq!(x.call_once(()), format!("jumping fox")); - let x = *(Box::new(D(Box::new(format!("lazy dog")))) as Box>); - assert_eq!(x.call_once(()), format!("lazy dog")); -} diff --git a/tests/run-pass-valgrind/unsized-locals/by-value-trait-objects-rust-call2.rs b/tests/run-pass-valgrind/unsized-locals/by-value-trait-objects-rust-call2.rs deleted file mode 100644 index 9b6648f2e27..00000000000 --- a/tests/run-pass-valgrind/unsized-locals/by-value-trait-objects-rust-call2.rs +++ /dev/null @@ -1,69 +0,0 @@ -#![feature(unsized_locals)] -#![feature(unboxed_closures)] -#![feature(tuple_trait)] - -pub trait FnOnce { - type Output; - extern "rust-call" fn call_once(self, args: Args) -> Self::Output; -} - -struct A; - -impl FnOnce<(String, Box)> for A { - type Output = String; - extern "rust-call" fn call_once(self, (s1, s2): (String, Box)) -> Self::Output { - assert_eq!(&s1 as &str, "s1"); - assert_eq!(&s2 as &str, "s2"); - format!("hello") - } -} - -struct B(i32); - -impl FnOnce<(String, Box)> for B { - type Output = String; - extern "rust-call" fn call_once(self, (s1, s2): (String, Box)) -> Self::Output { - assert_eq!(&s1 as &str, "s1"); - assert_eq!(&s2 as &str, "s2"); - format!("{}", self.0) - } -} - -struct C(String); - -impl FnOnce<(String, Box)> for C { - type Output = String; - extern "rust-call" fn call_once(self, (s1, s2): (String, Box)) -> Self::Output { - assert_eq!(&s1 as &str, "s1"); - assert_eq!(&s2 as &str, "s2"); - self.0 - } -} - -struct D(Box); - -impl FnOnce<(String, Box)> for D { - type Output = String; - extern "rust-call" fn call_once(self, (s1, s2): (String, Box)) -> Self::Output { - assert_eq!(&s1 as &str, "s1"); - assert_eq!(&s2 as &str, "s2"); - *self.0 - } -} - -fn main() { - let (s1, s2) = (format!("s1"), format!("s2").into_boxed_str()); - let x = *(Box::new(A) as Box), Output = String>>); - assert_eq!(x.call_once((s1, s2)), format!("hello")); - let (s1, s2) = (format!("s1"), format!("s2").into_boxed_str()); - let x = *(Box::new(B(42)) as Box), Output = String>>); - assert_eq!(x.call_once((s1, s2)), format!("42")); - let (s1, s2) = (format!("s1"), format!("s2").into_boxed_str()); - let x = *(Box::new(C(format!("jumping fox"))) - as Box), Output = String>>); - assert_eq!(x.call_once((s1, s2)), format!("jumping fox")); - let (s1, s2) = (format!("s1"), format!("s2").into_boxed_str()); - let x = *(Box::new(D(Box::new(format!("lazy dog")))) - as Box), Output = String>>); - assert_eq!(x.call_once((s1, s2)), format!("lazy dog")); -} diff --git a/tests/run-pass-valgrind/unsized-locals/by-value-trait-objects.rs b/tests/run-pass-valgrind/unsized-locals/by-value-trait-objects.rs deleted file mode 100644 index 3f6b6d262b5..00000000000 --- a/tests/run-pass-valgrind/unsized-locals/by-value-trait-objects.rs +++ /dev/null @@ -1,48 +0,0 @@ -#![feature(unsized_locals)] - -pub trait Foo { - fn foo(self) -> String; -} - -struct A; - -impl Foo for A { - fn foo(self) -> String { - format!("hello") - } -} - -struct B(i32); - -impl Foo for B { - fn foo(self) -> String { - format!("{}", self.0) - } -} - -struct C(String); - -impl Foo for C { - fn foo(self) -> String { - self.0 - } -} - -struct D(Box); - -impl Foo for D { - fn foo(self) -> String { - *self.0 - } -} - -fn main() { - let x = *(Box::new(A) as Box); - assert_eq!(x.foo(), format!("hello")); - let x = *(Box::new(B(42)) as Box); - assert_eq!(x.foo(), format!("42")); - let x = *(Box::new(C(format!("jumping fox"))) as Box); - assert_eq!(x.foo(), format!("jumping fox")); - let x = *(Box::new(D(Box::new(format!("lazy dog")))) as Box); - assert_eq!(x.foo(), format!("lazy dog")); -} diff --git a/tests/run-pass-valgrind/unsized-locals/long-live-the-unsized-temporary.rs b/tests/run-pass-valgrind/unsized-locals/long-live-the-unsized-temporary.rs deleted file mode 100644 index a7b9052617f..00000000000 --- a/tests/run-pass-valgrind/unsized-locals/long-live-the-unsized-temporary.rs +++ /dev/null @@ -1,52 +0,0 @@ -#![allow(incomplete_features)] -#![feature(unsized_locals, unsized_fn_params)] - -use std::fmt; - -fn gen_foo() -> Box { - Box::new(Box::new("foo")) -} - -fn foo(x: fmt::Display) { - assert_eq!(x.to_string(), "foo"); -} - -fn foo_indirect(x: fmt::Display) { - foo(x); -} - -fn main() { - foo(*gen_foo()); - foo_indirect(*gen_foo()); - - { - let x: fmt::Display = *gen_foo(); - foo(x); - } - - { - let x: fmt::Display = *gen_foo(); - let y: fmt::Display = *gen_foo(); - foo(x); - foo(y); - } - - { - let mut cnt: usize = 3; - let x = loop { - let x: fmt::Display = *gen_foo(); - if cnt == 0 { - break x; - } else { - cnt -= 1; - } - }; - foo(x); - } - - { - let x: fmt::Display = *gen_foo(); - let x = if true { x } else { *gen_foo() }; - foo(x); - } -} From da71dfbc516ec6fb7aa18e23c393ba6d1d2fb523 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 6 Oct 2024 22:42:28 -0400 Subject: [PATCH 658/683] Inline CombineFields --- compiler/rustc_infer/src/infer/at.rs | 89 +++++++-------- compiler/rustc_infer/src/infer/mod.rs | 1 - .../rustc_infer/src/infer/relate/combine.rs | 96 +--------------- .../rustc_infer/src/infer/relate/lattice.rs | 96 ++++++++++------ compiler/rustc_infer/src/infer/relate/mod.rs | 4 +- .../src/infer/relate/type_relating.rs | 106 ++++++++++-------- 6 files changed, 174 insertions(+), 218 deletions(-) diff --git a/compiler/rustc_infer/src/infer/at.rs b/compiler/rustc_infer/src/infer/at.rs index 183973af4f9..ecef90c5ca2 100644 --- a/compiler/rustc_infer/src/infer/at.rs +++ b/compiler/rustc_infer/src/infer/at.rs @@ -25,12 +25,13 @@ //! sometimes useful when the types of `c` and `d` are not traceable //! things. (That system should probably be refactored.) +use relate::lattice::{LatticeOp, LatticeOpKind}; use rustc_middle::bug; use rustc_middle::ty::{Const, ImplSubject}; use super::*; +use crate::infer::relate::type_relating::TypeRelating; use crate::infer::relate::{Relate, StructurallyRelateAliases, TypeRelation}; -use crate::traits::Obligation; /// Whether we should define opaque types or just treat them opaquely. /// @@ -108,14 +109,16 @@ impl<'a, 'tcx> At<'a, 'tcx> { where T: ToTrace<'tcx>, { - let mut fields = CombineFields::new( + let mut op = TypeRelating::new( self.infcx, ToTrace::to_trace(self.cause, expected, actual), self.param_env, define_opaque_types, + StructurallyRelateAliases::No, + ty::Contravariant, ); - fields.sup().relate(expected, actual)?; - Ok(InferOk { value: (), obligations: fields.into_obligations() }) + op.relate(expected, actual)?; + Ok(InferOk { value: (), obligations: op.into_obligations() }) } /// Makes `expected <: actual`. @@ -128,14 +131,16 @@ impl<'a, 'tcx> At<'a, 'tcx> { where T: ToTrace<'tcx>, { - let mut fields = CombineFields::new( + let mut op = TypeRelating::new( self.infcx, ToTrace::to_trace(self.cause, expected, actual), self.param_env, define_opaque_types, + StructurallyRelateAliases::No, + ty::Covariant, ); - fields.sub().relate(expected, actual)?; - Ok(InferOk { value: (), obligations: fields.into_obligations() }) + op.relate(expected, actual)?; + Ok(InferOk { value: (), obligations: op.into_obligations() }) } /// Makes `expected == actual`. @@ -167,23 +172,16 @@ impl<'a, 'tcx> At<'a, 'tcx> { where T: Relate>, { - let mut fields = CombineFields::new(self.infcx, trace, self.param_env, define_opaque_types); - fields.equate(StructurallyRelateAliases::No).relate(expected, actual)?; - Ok(InferOk { - value: (), - obligations: fields - .goals - .into_iter() - .map(|goal| { - Obligation::new( - self.infcx.tcx, - fields.trace.cause.clone(), - goal.param_env, - goal.predicate, - ) - }) - .collect(), - }) + let mut op = TypeRelating::new( + self.infcx, + trace, + self.param_env, + define_opaque_types, + StructurallyRelateAliases::No, + ty::Invariant, + ); + op.relate(expected, actual)?; + Ok(InferOk { value: (), obligations: op.into_obligations() }) } /// Equates `expected` and `found` while structurally relating aliases. @@ -198,14 +196,16 @@ impl<'a, 'tcx> At<'a, 'tcx> { T: ToTrace<'tcx>, { assert!(self.infcx.next_trait_solver()); - let mut fields = CombineFields::new( + let mut op = TypeRelating::new( self.infcx, ToTrace::to_trace(self.cause, expected, actual), self.param_env, DefineOpaqueTypes::Yes, + StructurallyRelateAliases::Yes, + ty::Invariant, ); - fields.equate(StructurallyRelateAliases::Yes).relate(expected, actual)?; - Ok(InferOk { value: (), obligations: fields.into_obligations() }) + op.relate(expected, actual)?; + Ok(InferOk { value: (), obligations: op.into_obligations() }) } pub fn relate( @@ -242,19 +242,16 @@ impl<'a, 'tcx> At<'a, 'tcx> { where T: Relate>, { - let mut fields = CombineFields::new( + let mut op = TypeRelating::new( self.infcx, TypeTrace::dummy(self.cause), self.param_env, DefineOpaqueTypes::Yes, - ); - fields.sub().relate_with_variance( + StructurallyRelateAliases::No, variance, - ty::VarianceDiagInfo::default(), - expected, - actual, - )?; - Ok(fields.goals) + ); + op.relate(expected, actual)?; + Ok(op.into_obligations().into_iter().map(|o| o.into()).collect()) } /// Used in the new solver since we don't care about tracking an `ObligationCause`. @@ -266,14 +263,16 @@ impl<'a, 'tcx> At<'a, 'tcx> { where T: Relate>, { - let mut fields = CombineFields::new( + let mut op = TypeRelating::new( self.infcx, TypeTrace::dummy(self.cause), self.param_env, DefineOpaqueTypes::Yes, + StructurallyRelateAliases::Yes, + ty::Invariant, ); - fields.equate(StructurallyRelateAliases::Yes).relate(expected, actual)?; - Ok(fields.goals) + op.relate(expected, actual)?; + Ok(op.into_obligations().into_iter().map(|o| o.into()).collect()) } /// Computes the least-upper-bound, or mutual supertype, of two @@ -290,14 +289,15 @@ impl<'a, 'tcx> At<'a, 'tcx> { where T: ToTrace<'tcx>, { - let mut fields = CombineFields::new( + let mut op = LatticeOp::new( self.infcx, ToTrace::to_trace(self.cause, expected, actual), self.param_env, define_opaque_types, + LatticeOpKind::Lub, ); - let value = fields.lub().relate(expected, actual)?; - Ok(InferOk { value, obligations: fields.into_obligations() }) + let value = op.relate(expected, actual)?; + Ok(InferOk { value, obligations: op.into_obligations() }) } /// Computes the greatest-lower-bound, or mutual subtype, of two @@ -312,14 +312,15 @@ impl<'a, 'tcx> At<'a, 'tcx> { where T: ToTrace<'tcx>, { - let mut fields = CombineFields::new( + let mut op = LatticeOp::new( self.infcx, ToTrace::to_trace(self.cause, expected, actual), self.param_env, define_opaque_types, + LatticeOpKind::Glb, ); - let value = fields.glb().relate(expected, actual)?; - Ok(InferOk { value, obligations: fields.into_obligations() }) + let value = op.relate(expected, actual)?; + Ok(InferOk { value, obligations: op.into_obligations() }) } } diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 89dfa019253..c179c1dcfe1 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -14,7 +14,6 @@ use region_constraints::{ GenericKind, RegionConstraintCollector, RegionConstraintStorage, VarInfos, VerifyBound, }; pub use relate::StructurallyRelateAliases; -use relate::combine::CombineFields; pub use relate::combine::PredicateEmittingRelation; use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; diff --git a/compiler/rustc_infer/src/infer/relate/combine.rs b/compiler/rustc_infer/src/infer/relate/combine.rs index 450437f2176..c4f5a85a8be 100644 --- a/compiler/rustc_infer/src/infer/relate/combine.rs +++ b/compiler/rustc_infer/src/infer/relate/combine.rs @@ -1,4 +1,4 @@ -//! There are four type combiners: [TypeRelating], `Lub`, and `Glb`, +//! There are four type combiners: `TypeRelating`, `Lub`, and `Glb`, //! and `NllTypeRelating` in rustc_borrowck, which is only used for NLL. //! //! Each implements the trait [TypeRelation] and contains methods for @@ -20,56 +20,13 @@ use rustc_middle::bug; use rustc_middle::infer::unify_key::EffectVarValue; -use rustc_middle::traits::solve::Goal; use rustc_middle::ty::error::{ExpectedFound, TypeError}; -use rustc_middle::ty::{self, InferConst, IntType, Ty, TyCtxt, TypeVisitableExt, UintType, Upcast}; +use rustc_middle::ty::{self, InferConst, IntType, Ty, TypeVisitableExt, UintType}; pub use rustc_next_trait_solver::relate::combine::*; use tracing::debug; -use super::lattice::{LatticeOp, LatticeOpKind}; -use super::type_relating::TypeRelating; use super::{RelateResult, StructurallyRelateAliases}; -use crate::infer::{DefineOpaqueTypes, InferCtxt, TypeTrace, relate}; -use crate::traits::{Obligation, PredicateObligation}; - -#[derive(Clone)] -pub(crate) struct CombineFields<'infcx, 'tcx> { - pub infcx: &'infcx InferCtxt<'tcx>, - // Immutable fields - pub trace: TypeTrace<'tcx>, - pub param_env: ty::ParamEnv<'tcx>, - pub define_opaque_types: DefineOpaqueTypes, - // Mutable fields - // - // Adding any additional field likely requires - // changes to the cache of `TypeRelating`. - pub goals: Vec>>, -} - -impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> { - pub(crate) fn new( - infcx: &'infcx InferCtxt<'tcx>, - trace: TypeTrace<'tcx>, - param_env: ty::ParamEnv<'tcx>, - define_opaque_types: DefineOpaqueTypes, - ) -> Self { - Self { infcx, trace, param_env, define_opaque_types, goals: vec![] } - } - - pub(crate) fn into_obligations(self) -> Vec> { - self.goals - .into_iter() - .map(|goal| { - Obligation::new( - self.infcx.tcx, - self.trace.cause.clone(), - goal.param_env, - goal.predicate, - ) - }) - .collect() - } -} +use crate::infer::{InferCtxt, relate}; impl<'tcx> InferCtxt<'tcx> { pub fn super_combine_tys( @@ -281,50 +238,3 @@ impl<'tcx> InferCtxt<'tcx> { val } } - -impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> { - pub(crate) fn tcx(&self) -> TyCtxt<'tcx> { - self.infcx.tcx - } - - pub(crate) fn equate<'a>( - &'a mut self, - structurally_relate_aliases: StructurallyRelateAliases, - ) -> TypeRelating<'a, 'infcx, 'tcx> { - TypeRelating::new(self, structurally_relate_aliases, ty::Invariant) - } - - pub(crate) fn sub<'a>(&'a mut self) -> TypeRelating<'a, 'infcx, 'tcx> { - TypeRelating::new(self, StructurallyRelateAliases::No, ty::Covariant) - } - - pub(crate) fn sup<'a>(&'a mut self) -> TypeRelating<'a, 'infcx, 'tcx> { - TypeRelating::new(self, StructurallyRelateAliases::No, ty::Contravariant) - } - - pub(crate) fn lub<'a>(&'a mut self) -> LatticeOp<'a, 'infcx, 'tcx> { - LatticeOp::new(self, LatticeOpKind::Lub) - } - - pub(crate) fn glb<'a>(&'a mut self) -> LatticeOp<'a, 'infcx, 'tcx> { - LatticeOp::new(self, LatticeOpKind::Glb) - } - - pub(crate) fn register_obligations( - &mut self, - obligations: impl IntoIterator>>, - ) { - self.goals.extend(obligations); - } - - pub(crate) fn register_predicates( - &mut self, - obligations: impl IntoIterator, ty::Predicate<'tcx>>>, - ) { - self.goals.extend( - obligations - .into_iter() - .map(|to_pred| Goal::new(self.infcx.tcx, self.param_env, to_pred)), - ) - } -} diff --git a/compiler/rustc_infer/src/infer/relate/lattice.rs b/compiler/rustc_infer/src/infer/relate/lattice.rs index 9564baa6ab2..877cb713c1e 100644 --- a/compiler/rustc_infer/src/infer/relate/lattice.rs +++ b/compiler/rustc_infer/src/infer/relate/lattice.rs @@ -24,8 +24,9 @@ use rustc_span::Span; use tracing::{debug, instrument}; use super::StructurallyRelateAliases; -use super::combine::{CombineFields, PredicateEmittingRelation}; -use crate::infer::{DefineOpaqueTypes, InferCtxt, SubregionOrigin}; +use super::combine::PredicateEmittingRelation; +use crate::infer::{DefineOpaqueTypes, InferCtxt, SubregionOrigin, TypeTrace}; +use crate::traits::{Obligation, PredicateObligation}; #[derive(Clone, Copy)] pub(crate) enum LatticeOpKind { @@ -43,23 +44,36 @@ impl LatticeOpKind { } /// A greatest lower bound" (common subtype) or least upper bound (common supertype). -pub(crate) struct LatticeOp<'combine, 'infcx, 'tcx> { - fields: &'combine mut CombineFields<'infcx, 'tcx>, +pub(crate) struct LatticeOp<'infcx, 'tcx> { + infcx: &'infcx InferCtxt<'tcx>, + // Immutable fields + trace: TypeTrace<'tcx>, + param_env: ty::ParamEnv<'tcx>, + define_opaque_types: DefineOpaqueTypes, + // Mutable fields kind: LatticeOpKind, + obligations: Vec>, } -impl<'combine, 'infcx, 'tcx> LatticeOp<'combine, 'infcx, 'tcx> { +impl<'infcx, 'tcx> LatticeOp<'infcx, 'tcx> { pub(crate) fn new( - fields: &'combine mut CombineFields<'infcx, 'tcx>, + infcx: &'infcx InferCtxt<'tcx>, + trace: TypeTrace<'tcx>, + param_env: ty::ParamEnv<'tcx>, + define_opaque_types: DefineOpaqueTypes, kind: LatticeOpKind, - ) -> LatticeOp<'combine, 'infcx, 'tcx> { - LatticeOp { fields, kind } + ) -> LatticeOp<'infcx, 'tcx> { + LatticeOp { infcx, trace, param_env, define_opaque_types, kind, obligations: vec![] } + } + + pub(crate) fn into_obligations(self) -> Vec> { + self.obligations } } -impl<'tcx> TypeRelation> for LatticeOp<'_, '_, 'tcx> { +impl<'tcx> TypeRelation> for LatticeOp<'_, 'tcx> { fn cx(&self) -> TyCtxt<'tcx> { - self.fields.tcx() + self.infcx.tcx } fn relate_with_variance>>( @@ -70,7 +84,15 @@ impl<'tcx> TypeRelation> for LatticeOp<'_, '_, 'tcx> { b: T, ) -> RelateResult<'tcx, T> { match variance { - ty::Invariant => self.fields.equate(StructurallyRelateAliases::No).relate(a, b), + ty::Invariant => { + self.obligations.extend( + self.infcx + .at(&self.trace.cause, self.param_env) + .eq_trace(self.define_opaque_types, self.trace.clone(), a, b)? + .into_obligations(), + ); + Ok(a) + } ty::Covariant => self.relate(a, b), // FIXME(#41044) -- not correct, need test ty::Bivariant => Ok(a), @@ -90,7 +112,7 @@ impl<'tcx> TypeRelation> for LatticeOp<'_, '_, 'tcx> { return Ok(a); } - let infcx = self.fields.infcx; + let infcx = self.infcx; let a = infcx.shallow_resolve(a); let b = infcx.shallow_resolve(b); @@ -115,12 +137,12 @@ impl<'tcx> TypeRelation> for LatticeOp<'_, '_, 'tcx> { // iterate on the subtype obligations that are returned, but I // think this suffices. -nmatsakis (&ty::Infer(TyVar(..)), _) => { - let v = infcx.next_ty_var(self.fields.trace.cause.span); + let v = infcx.next_ty_var(self.trace.cause.span); self.relate_bound(v, b, a)?; Ok(v) } (_, &ty::Infer(TyVar(..))) => { - let v = infcx.next_ty_var(self.fields.trace.cause.span); + let v = infcx.next_ty_var(self.trace.cause.span); self.relate_bound(v, a, b)?; Ok(v) } @@ -132,7 +154,7 @@ impl<'tcx> TypeRelation> for LatticeOp<'_, '_, 'tcx> { (&ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }), _) | (_, &ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. })) - if self.fields.define_opaque_types == DefineOpaqueTypes::Yes + if self.define_opaque_types == DefineOpaqueTypes::Yes && def_id.is_local() && !infcx.next_trait_solver() => { @@ -155,8 +177,8 @@ impl<'tcx> TypeRelation> for LatticeOp<'_, '_, 'tcx> { a: ty::Region<'tcx>, b: ty::Region<'tcx>, ) -> RelateResult<'tcx, ty::Region<'tcx>> { - let origin = SubregionOrigin::Subtype(Box::new(self.fields.trace.clone())); - let mut inner = self.fields.infcx.inner.borrow_mut(); + let origin = SubregionOrigin::Subtype(Box::new(self.trace.clone())); + let mut inner = self.infcx.inner.borrow_mut(); let mut constraints = inner.unwrap_region_constraints(); Ok(match self.kind { // GLB(&'static u8, &'a u8) == &RegionLUB('static, 'a) u8 == &'static u8 @@ -173,7 +195,7 @@ impl<'tcx> TypeRelation> for LatticeOp<'_, '_, 'tcx> { a: ty::Const<'tcx>, b: ty::Const<'tcx>, ) -> RelateResult<'tcx, ty::Const<'tcx>> { - self.fields.infcx.super_combine_consts(self, a, b) + self.infcx.super_combine_consts(self, a, b) } fn binders( @@ -202,7 +224,7 @@ impl<'tcx> TypeRelation> for LatticeOp<'_, '_, 'tcx> { } } -impl<'combine, 'infcx, 'tcx> LatticeOp<'combine, 'infcx, 'tcx> { +impl<'infcx, 'tcx> LatticeOp<'infcx, 'tcx> { // Relates the type `v` to `a` and `b` such that `v` represents // the LUB/GLB of `a` and `b` as appropriate. // @@ -210,24 +232,24 @@ impl<'combine, 'infcx, 'tcx> LatticeOp<'combine, 'infcx, 'tcx> { // relates `v` to `a` first, which may help us to avoid unnecessary // type variable obligations. See caller for details. fn relate_bound(&mut self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()> { - let mut sub = self.fields.sub(); + let at = self.infcx.at(&self.trace.cause, self.param_env); match self.kind { LatticeOpKind::Glb => { - sub.relate(v, a)?; - sub.relate(v, b)?; + self.obligations.extend(at.sub(self.define_opaque_types, v, a)?.into_obligations()); + self.obligations.extend(at.sub(self.define_opaque_types, v, b)?.into_obligations()); } LatticeOpKind::Lub => { - sub.relate(a, v)?; - sub.relate(b, v)?; + self.obligations.extend(at.sub(self.define_opaque_types, a, v)?.into_obligations()); + self.obligations.extend(at.sub(self.define_opaque_types, b, v)?.into_obligations()); } } Ok(()) } } -impl<'tcx> PredicateEmittingRelation> for LatticeOp<'_, '_, 'tcx> { +impl<'tcx> PredicateEmittingRelation> for LatticeOp<'_, 'tcx> { fn span(&self) -> Span { - self.fields.trace.span() + self.trace.span() } fn structurally_relate_aliases(&self) -> StructurallyRelateAliases { @@ -235,21 +257,27 @@ impl<'tcx> PredicateEmittingRelation> for LatticeOp<'_, '_, 'tcx } fn param_env(&self) -> ty::ParamEnv<'tcx> { - self.fields.param_env + self.param_env } fn register_predicates( &mut self, - obligations: impl IntoIterator, ty::Predicate<'tcx>>>, + preds: impl IntoIterator, ty::Predicate<'tcx>>>, ) { - self.fields.register_predicates(obligations); + self.obligations.extend(preds.into_iter().map(|pred| { + Obligation::new(self.infcx.tcx, self.trace.cause.clone(), self.param_env, pred) + })) } - fn register_goals( - &mut self, - obligations: impl IntoIterator>>, - ) { - self.fields.register_obligations(obligations); + fn register_goals(&mut self, goals: impl IntoIterator>>) { + self.obligations.extend(goals.into_iter().map(|goal| { + Obligation::new( + self.infcx.tcx, + self.trace.cause.clone(), + goal.param_env, + goal.predicate, + ) + })) } fn register_alias_relate_predicate(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) { diff --git a/compiler/rustc_infer/src/infer/relate/mod.rs b/compiler/rustc_infer/src/infer/relate/mod.rs index 85158faa65d..baab5bb274a 100644 --- a/compiler/rustc_infer/src/infer/relate/mod.rs +++ b/compiler/rustc_infer/src/infer/relate/mod.rs @@ -11,5 +11,5 @@ pub use self::combine::PredicateEmittingRelation; pub(super) mod combine; mod generalize; mod higher_ranked; -mod lattice; -mod type_relating; +pub(super) mod lattice; +pub(super) mod type_relating; diff --git a/compiler/rustc_infer/src/infer/relate/type_relating.rs b/compiler/rustc_infer/src/infer/relate/type_relating.rs index 7537ceec307..4b4b13e919c 100644 --- a/compiler/rustc_infer/src/infer/relate/type_relating.rs +++ b/compiler/rustc_infer/src/infer/relate/type_relating.rs @@ -7,29 +7,31 @@ use rustc_span::Span; use rustc_type_ir::data_structures::DelayedSet; use tracing::{debug, instrument}; -use super::combine::CombineFields; use crate::infer::BoundRegionConversionTime::HigherRankedType; use crate::infer::relate::{PredicateEmittingRelation, StructurallyRelateAliases}; -use crate::infer::{DefineOpaqueTypes, InferCtxt, SubregionOrigin}; +use crate::infer::{DefineOpaqueTypes, InferCtxt, SubregionOrigin, TypeTrace}; +use crate::traits::{Obligation, PredicateObligation}; /// Enforce that `a` is equal to or a subtype of `b`. -pub(crate) struct TypeRelating<'combine, 'a, 'tcx> { - // Immutable except for the `InferCtxt` and the - // resulting nested `goals`. - fields: &'combine mut CombineFields<'a, 'tcx>, +pub(crate) struct TypeRelating<'infcx, 'tcx> { + infcx: &'infcx InferCtxt<'tcx>, - // Immutable field. + // Immutable fields + trace: TypeTrace<'tcx>, + param_env: ty::ParamEnv<'tcx>, + define_opaque_types: DefineOpaqueTypes, structurally_relate_aliases: StructurallyRelateAliases, - // Mutable field. - ambient_variance: ty::Variance, + // Mutable fields. + ambient_variance: ty::Variance, + obligations: Vec>, /// The cache only tracks the `ambient_variance` as it's the /// only field which is mutable and which meaningfully changes /// the result when relating types. /// /// The cache does not track whether the state of the /// `InferCtxt` has been changed or whether we've added any - /// obligations to `self.fields.goals`. Whether a goal is added + /// obligations to `self.goals`. Whether a goal is added /// once or multiple times is not really meaningful. /// /// Changes in the inference state may delay some type inference to @@ -48,24 +50,35 @@ pub(crate) struct TypeRelating<'combine, 'a, 'tcx> { cache: DelayedSet<(ty::Variance, Ty<'tcx>, Ty<'tcx>)>, } -impl<'combine, 'infcx, 'tcx> TypeRelating<'combine, 'infcx, 'tcx> { +impl<'infcx, 'tcx> TypeRelating<'infcx, 'tcx> { pub(crate) fn new( - f: &'combine mut CombineFields<'infcx, 'tcx>, + infcx: &'infcx InferCtxt<'tcx>, + trace: TypeTrace<'tcx>, + param_env: ty::ParamEnv<'tcx>, + define_opaque_types: DefineOpaqueTypes, structurally_relate_aliases: StructurallyRelateAliases, ambient_variance: ty::Variance, - ) -> TypeRelating<'combine, 'infcx, 'tcx> { + ) -> TypeRelating<'infcx, 'tcx> { TypeRelating { - fields: f, + infcx, + trace, + param_env, + define_opaque_types, structurally_relate_aliases, ambient_variance, + obligations: vec![], cache: Default::default(), } } + + pub(crate) fn into_obligations(self) -> Vec> { + self.obligations + } } -impl<'tcx> TypeRelation> for TypeRelating<'_, '_, 'tcx> { +impl<'tcx> TypeRelation> for TypeRelating<'_, 'tcx> { fn cx(&self) -> TyCtxt<'tcx> { - self.fields.infcx.tcx + self.infcx.tcx } fn relate_item_args( @@ -109,7 +122,7 @@ impl<'tcx> TypeRelation> for TypeRelating<'_, '_, 'tcx> { return Ok(a); } - let infcx = self.fields.infcx; + let infcx = self.infcx; let a = infcx.shallow_resolve(a); let b = infcx.shallow_resolve(b); @@ -123,9 +136,10 @@ impl<'tcx> TypeRelation> for TypeRelating<'_, '_, 'tcx> { ty::Covariant => { // can't make progress on `A <: B` if both A and B are // type variables, so record an obligation. - self.fields.goals.push(Goal::new( + self.obligations.push(Obligation::new( self.cx(), - self.fields.param_env, + self.trace.cause.clone(), + self.param_env, ty::Binder::dummy(ty::PredicateKind::Subtype(ty::SubtypePredicate { a_is_expected: true, a, @@ -136,9 +150,10 @@ impl<'tcx> TypeRelation> for TypeRelating<'_, '_, 'tcx> { ty::Contravariant => { // can't make progress on `B <: A` if both A and B are // type variables, so record an obligation. - self.fields.goals.push(Goal::new( + self.obligations.push(Obligation::new( self.cx(), - self.fields.param_env, + self.trace.cause.clone(), + self.param_env, ty::Binder::dummy(ty::PredicateKind::Subtype(ty::SubtypePredicate { a_is_expected: false, a: b, @@ -182,14 +197,14 @@ impl<'tcx> TypeRelation> for TypeRelating<'_, '_, 'tcx> { (&ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }), _) | (_, &ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. })) - if self.fields.define_opaque_types == DefineOpaqueTypes::Yes + if self.define_opaque_types == DefineOpaqueTypes::Yes && def_id.is_local() && !infcx.next_trait_solver() => { - self.fields.goals.extend(infcx.handle_opaque_type( + self.register_goals(infcx.handle_opaque_type( a, b, - self.fields.trace.cause.span, + self.trace.cause.span, self.param_env(), )?); } @@ -210,13 +225,12 @@ impl<'tcx> TypeRelation> for TypeRelating<'_, '_, 'tcx> { a: ty::Region<'tcx>, b: ty::Region<'tcx>, ) -> RelateResult<'tcx, ty::Region<'tcx>> { - let origin = SubregionOrigin::Subtype(Box::new(self.fields.trace.clone())); + let origin = SubregionOrigin::Subtype(Box::new(self.trace.clone())); match self.ambient_variance { // Subtype(&'a u8, &'b u8) => Outlives('a: 'b) => SubRegion('b, 'a) ty::Covariant => { - self.fields - .infcx + self.infcx .inner .borrow_mut() .unwrap_region_constraints() @@ -224,16 +238,14 @@ impl<'tcx> TypeRelation> for TypeRelating<'_, '_, 'tcx> { } // Suptype(&'a u8, &'b u8) => Outlives('b: 'a) => SubRegion('a, 'b) ty::Contravariant => { - self.fields - .infcx + self.infcx .inner .borrow_mut() .unwrap_region_constraints() .make_subregion(origin, a, b); } ty::Invariant => { - self.fields - .infcx + self.infcx .inner .borrow_mut() .unwrap_region_constraints() @@ -253,7 +265,7 @@ impl<'tcx> TypeRelation> for TypeRelating<'_, '_, 'tcx> { a: ty::Const<'tcx>, b: ty::Const<'tcx>, ) -> RelateResult<'tcx, ty::Const<'tcx>> { - self.fields.infcx.super_combine_consts(self, a, b) + self.infcx.super_combine_consts(self, a, b) } fn binders( @@ -271,8 +283,8 @@ impl<'tcx> TypeRelation> for TypeRelating<'_, '_, 'tcx> { { self.relate(a, b)?; } else { - let span = self.fields.trace.cause.span; - let infcx = self.fields.infcx; + let span = self.trace.cause.span; + let infcx = self.infcx; match self.ambient_variance { // Checks whether `for<..> sub <: for<..> sup` holds. @@ -335,13 +347,13 @@ impl<'tcx> TypeRelation> for TypeRelating<'_, '_, 'tcx> { } } -impl<'tcx> PredicateEmittingRelation> for TypeRelating<'_, '_, 'tcx> { +impl<'tcx> PredicateEmittingRelation> for TypeRelating<'_, 'tcx> { fn span(&self) -> Span { - self.fields.trace.span() + self.trace.span() } fn param_env(&self) -> ty::ParamEnv<'tcx> { - self.fields.param_env + self.param_env } fn structurally_relate_aliases(&self) -> StructurallyRelateAliases { @@ -350,16 +362,22 @@ impl<'tcx> PredicateEmittingRelation> for TypeRelating<'_, '_, ' fn register_predicates( &mut self, - obligations: impl IntoIterator, ty::Predicate<'tcx>>>, + preds: impl IntoIterator, ty::Predicate<'tcx>>>, ) { - self.fields.register_predicates(obligations); + self.obligations.extend(preds.into_iter().map(|pred| { + Obligation::new(self.infcx.tcx, self.trace.cause.clone(), self.param_env, pred) + })) } - fn register_goals( - &mut self, - obligations: impl IntoIterator>>, - ) { - self.fields.register_obligations(obligations); + fn register_goals(&mut self, goals: impl IntoIterator>>) { + self.obligations.extend(goals.into_iter().map(|goal| { + Obligation::new( + self.infcx.tcx, + self.trace.cause.clone(), + goal.param_env, + goal.predicate, + ) + })) } fn register_alias_relate_predicate(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) { From 5d62afd2baa5609de649db16389c96c953a1a42f Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 6 Oct 2024 22:47:50 -0400 Subject: [PATCH 659/683] Remove unnecessary DefineOpaqueTypes from lub --- compiler/rustc_hir_typeck/src/coercion.rs | 26 +++++-------------- compiler/rustc_infer/src/infer/at.rs | 16 ++---------- .../rustc_infer/src/infer/relate/lattice.rs | 18 +++++-------- 3 files changed, 16 insertions(+), 44 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index 642db3f36b5..bd0b9870298 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -141,7 +141,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { let at = self.at(&self.cause, self.fcx.param_env); let res = if self.use_lub { - at.lub(DefineOpaqueTypes::Yes, b, a) + at.lub(b, a) } else { at.sup(DefineOpaqueTypes::Yes, b, a) .map(|InferOk { value: (), obligations }| InferOk { value: b, obligations }) @@ -1190,13 +1190,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { (ty::FnDef(..), ty::FnDef(..)) => { // Don't reify if the function types have a LUB, i.e., they // are the same function and their parameters have a LUB. - match self.commit_if_ok(|_| { - self.at(cause, self.param_env).lub( - DefineOpaqueTypes::Yes, - prev_ty, - new_ty, - ) - }) { + match self + .commit_if_ok(|_| self.at(cause, self.param_env).lub(prev_ty, new_ty)) + { // We have a LUB of prev_ty and new_ty, just return it. Ok(ok) => return Ok(self.register_infer_ok_obligations(ok)), Err(_) => { @@ -1239,7 +1235,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let (a_sig, b_sig) = self.normalize(new.span, (a_sig, b_sig)); let sig = self .at(cause, self.param_env) - .lub(DefineOpaqueTypes::Yes, a_sig, b_sig) + .lub(a_sig, b_sig) .map(|ok| self.register_infer_ok_obligations(ok))?; // Reify both sides and return the reified fn pointer type. @@ -1330,9 +1326,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); return Err(self - .commit_if_ok(|_| { - self.at(cause, self.param_env).lub(DefineOpaqueTypes::Yes, prev_ty, new_ty) - }) + .commit_if_ok(|_| self.at(cause, self.param_env).lub(prev_ty, new_ty)) .unwrap_err()); } } @@ -1344,13 +1338,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Err(e) } else { Err(self - .commit_if_ok(|_| { - self.at(cause, self.param_env).lub( - DefineOpaqueTypes::Yes, - prev_ty, - new_ty, - ) - }) + .commit_if_ok(|_| self.at(cause, self.param_env).lub(prev_ty, new_ty)) .unwrap_err()) } } diff --git a/compiler/rustc_infer/src/infer/at.rs b/compiler/rustc_infer/src/infer/at.rs index ecef90c5ca2..170f44b17e7 100644 --- a/compiler/rustc_infer/src/infer/at.rs +++ b/compiler/rustc_infer/src/infer/at.rs @@ -280,12 +280,7 @@ impl<'a, 'tcx> At<'a, 'tcx> { /// this can result in an error (e.g., if asked to compute LUB of /// u32 and i32), it is meaningful to call one of them the /// "expected type". - pub fn lub( - self, - define_opaque_types: DefineOpaqueTypes, - expected: T, - actual: T, - ) -> InferResult<'tcx, T> + pub fn lub(self, expected: T, actual: T) -> InferResult<'tcx, T> where T: ToTrace<'tcx>, { @@ -293,7 +288,6 @@ impl<'a, 'tcx> At<'a, 'tcx> { self.infcx, ToTrace::to_trace(self.cause, expected, actual), self.param_env, - define_opaque_types, LatticeOpKind::Lub, ); let value = op.relate(expected, actual)?; @@ -303,12 +297,7 @@ impl<'a, 'tcx> At<'a, 'tcx> { /// Computes the greatest-lower-bound, or mutual subtype, of two /// values. As with `lub` order doesn't matter, except for error /// cases. - pub fn glb( - self, - define_opaque_types: DefineOpaqueTypes, - expected: T, - actual: T, - ) -> InferResult<'tcx, T> + pub fn glb(self, expected: T, actual: T) -> InferResult<'tcx, T> where T: ToTrace<'tcx>, { @@ -316,7 +305,6 @@ impl<'a, 'tcx> At<'a, 'tcx> { self.infcx, ToTrace::to_trace(self.cause, expected, actual), self.param_env, - define_opaque_types, LatticeOpKind::Glb, ); let value = op.relate(expected, actual)?; diff --git a/compiler/rustc_infer/src/infer/relate/lattice.rs b/compiler/rustc_infer/src/infer/relate/lattice.rs index 877cb713c1e..8cec312abf7 100644 --- a/compiler/rustc_infer/src/infer/relate/lattice.rs +++ b/compiler/rustc_infer/src/infer/relate/lattice.rs @@ -49,7 +49,6 @@ pub(crate) struct LatticeOp<'infcx, 'tcx> { // Immutable fields trace: TypeTrace<'tcx>, param_env: ty::ParamEnv<'tcx>, - define_opaque_types: DefineOpaqueTypes, // Mutable fields kind: LatticeOpKind, obligations: Vec>, @@ -60,10 +59,9 @@ impl<'infcx, 'tcx> LatticeOp<'infcx, 'tcx> { infcx: &'infcx InferCtxt<'tcx>, trace: TypeTrace<'tcx>, param_env: ty::ParamEnv<'tcx>, - define_opaque_types: DefineOpaqueTypes, kind: LatticeOpKind, ) -> LatticeOp<'infcx, 'tcx> { - LatticeOp { infcx, trace, param_env, define_opaque_types, kind, obligations: vec![] } + LatticeOp { infcx, trace, param_env, kind, obligations: vec![] } } pub(crate) fn into_obligations(self) -> Vec> { @@ -88,7 +86,7 @@ impl<'tcx> TypeRelation> for LatticeOp<'_, 'tcx> { self.obligations.extend( self.infcx .at(&self.trace.cause, self.param_env) - .eq_trace(self.define_opaque_types, self.trace.clone(), a, b)? + .eq_trace(DefineOpaqueTypes::Yes, self.trace.clone(), a, b)? .into_obligations(), ); Ok(a) @@ -154,9 +152,7 @@ impl<'tcx> TypeRelation> for LatticeOp<'_, 'tcx> { (&ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }), _) | (_, &ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. })) - if self.define_opaque_types == DefineOpaqueTypes::Yes - && def_id.is_local() - && !infcx.next_trait_solver() => + if def_id.is_local() && !infcx.next_trait_solver() => { self.register_goals(infcx.handle_opaque_type( a, @@ -235,12 +231,12 @@ impl<'infcx, 'tcx> LatticeOp<'infcx, 'tcx> { let at = self.infcx.at(&self.trace.cause, self.param_env); match self.kind { LatticeOpKind::Glb => { - self.obligations.extend(at.sub(self.define_opaque_types, v, a)?.into_obligations()); - self.obligations.extend(at.sub(self.define_opaque_types, v, b)?.into_obligations()); + self.obligations.extend(at.sub(DefineOpaqueTypes::Yes, v, a)?.into_obligations()); + self.obligations.extend(at.sub(DefineOpaqueTypes::Yes, v, b)?.into_obligations()); } LatticeOpKind::Lub => { - self.obligations.extend(at.sub(self.define_opaque_types, a, v)?.into_obligations()); - self.obligations.extend(at.sub(self.define_opaque_types, b, v)?.into_obligations()); + self.obligations.extend(at.sub(DefineOpaqueTypes::Yes, a, v)?.into_obligations()); + self.obligations.extend(at.sub(DefineOpaqueTypes::Yes, b, v)?.into_obligations()); } } Ok(()) From 0c5d2f98d1883cfefe26d755107ccca9f0f0e9e9 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 6 Oct 2024 22:50:29 -0400 Subject: [PATCH 660/683] Remove At methods that are unused --- compiler/rustc_infer/src/infer/at.rs | 41 ---------------------------- 1 file changed, 41 deletions(-) diff --git a/compiler/rustc_infer/src/infer/at.rs b/compiler/rustc_infer/src/infer/at.rs index 170f44b17e7..5422761a6cf 100644 --- a/compiler/rustc_infer/src/infer/at.rs +++ b/compiler/rustc_infer/src/infer/at.rs @@ -184,30 +184,6 @@ impl<'a, 'tcx> At<'a, 'tcx> { Ok(InferOk { value: (), obligations: op.into_obligations() }) } - /// Equates `expected` and `found` while structurally relating aliases. - /// This should only be used inside of the next generation trait solver - /// when relating rigid aliases. - pub fn eq_structurally_relating_aliases( - self, - expected: T, - actual: T, - ) -> InferResult<'tcx, ()> - where - T: ToTrace<'tcx>, - { - assert!(self.infcx.next_trait_solver()); - let mut op = TypeRelating::new( - self.infcx, - ToTrace::to_trace(self.cause, expected, actual), - self.param_env, - DefineOpaqueTypes::Yes, - StructurallyRelateAliases::Yes, - ty::Invariant, - ); - op.relate(expected, actual)?; - Ok(InferOk { value: (), obligations: op.into_obligations() }) - } - pub fn relate( self, define_opaque_types: DefineOpaqueTypes, @@ -293,23 +269,6 @@ impl<'a, 'tcx> At<'a, 'tcx> { let value = op.relate(expected, actual)?; Ok(InferOk { value, obligations: op.into_obligations() }) } - - /// Computes the greatest-lower-bound, or mutual subtype, of two - /// values. As with `lub` order doesn't matter, except for error - /// cases. - pub fn glb(self, expected: T, actual: T) -> InferResult<'tcx, T> - where - T: ToTrace<'tcx>, - { - let mut op = LatticeOp::new( - self.infcx, - ToTrace::to_trace(self.cause, expected, actual), - self.param_env, - LatticeOpKind::Glb, - ); - let value = op.relate(expected, actual)?; - Ok(InferOk { value, obligations: op.into_obligations() }) - } } impl<'tcx> ToTrace<'tcx> for ImplSubject<'tcx> { From dde78bd9462fa50e035c46f6f7a7dba15194971e Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 7 Oct 2024 12:09:28 +0200 Subject: [PATCH 661/683] Add documentation for `runtest::check_rustdoc_test_option` method --- src/tools/compiletest/src/runtest.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 25a135aa320..0674debd6a2 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -2109,6 +2109,10 @@ impl<'test> TestCx<'test> { .collect() } + /// This method is used for `//@ check-test-line-numbers-match`. + /// + /// It checks that doctests line in the displayed doctest "name" matches where they are + /// defined in source code. fn check_rustdoc_test_option(&self, res: ProcRes) { let mut other_files = Vec::new(); let mut files: HashMap> = HashMap::new(); From 4085b48dfddd742fa4d46c594ee5662b972ae6de Mon Sep 17 00:00:00 2001 From: Michal Piotrowski Date: Mon, 7 Oct 2024 15:02:45 +0200 Subject: [PATCH 662/683] Fix used_underscore_binding in rustc_serialize --- compiler/rustc_serialize/src/opaque.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_serialize/src/opaque.rs b/compiler/rustc_serialize/src/opaque.rs index c7c561156e3..27e9f817894 100644 --- a/compiler/rustc_serialize/src/opaque.rs +++ b/compiler/rustc_serialize/src/opaque.rs @@ -437,10 +437,10 @@ impl IntEncodedWithFixedSize { impl Encodable for IntEncodedWithFixedSize { #[inline] fn encode(&self, e: &mut FileEncoder) { - let _start_pos = e.position(); + let start_pos = e.position(); e.write_array(self.0.to_le_bytes()); - let _end_pos = e.position(); - debug_assert_eq!((_end_pos - _start_pos), IntEncodedWithFixedSize::ENCODED_SIZE); + let end_pos = e.position(); + debug_assert_eq!((end_pos - start_pos), IntEncodedWithFixedSize::ENCODED_SIZE); } } From 6d246e47fb55e089589681a41db6dedb20ccdaa3 Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Wed, 11 Sep 2024 18:04:40 -0400 Subject: [PATCH 663/683] Add precondition checks to ptr::offset, ptr::add, ptr::sub --- library/core/src/ptr/const_ptr.rs | 88 ++++++++++++++++++- library/core/src/ptr/mut_ptr.rs | 88 ++++++++++++++++++- tests/codegen/option-as-slice.rs | 8 +- ...e_add_fat.PreCodegen.after.panic-abort.mir | 16 ++-- ..._add_fat.PreCodegen.after.panic-unwind.mir | 16 ++-- ..._add_thin.PreCodegen.after.panic-abort.mir | 14 ++- ...add_thin.PreCodegen.after.panic-unwind.mir | 14 ++- ...ated_loop.PreCodegen.after.panic-abort.mir | 32 ++++--- ...ted_loop.PreCodegen.after.panic-unwind.mir | 12 ++- ...ward_loop.PreCodegen.after.panic-abort.mir | 8 +- ...ard_loop.PreCodegen.after.panic-unwind.mir | 8 +- ...erse_loop.PreCodegen.after.panic-abort.mir | 14 ++- ...rse_loop.PreCodegen.after.panic-unwind.mir | 14 ++- 13 files changed, 283 insertions(+), 49 deletions(-) diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs index 332c5e904d7..4727dc77d18 100644 --- a/library/core/src/ptr/const_ptr.rs +++ b/library/core/src/ptr/const_ptr.rs @@ -395,6 +395,36 @@ impl *const T { where T: Sized, { + #[inline] + const fn runtime_offset_nowrap(this: *const (), count: isize, size: usize) -> bool { + #[inline] + fn runtime(this: *const (), count: isize, size: usize) -> bool { + // We know `size <= isize::MAX` so the `as` cast here is not lossy. + let Some(byte_offset) = count.checked_mul(size as isize) else { + return false; + }; + let (_, overflow) = this.addr().overflowing_add_signed(byte_offset); + !overflow + } + + const fn comptime(_: *const (), _: isize, _: usize) -> bool { + true + } + + // We can use const_eval_select here because this is only for UB checks. + intrinsics::const_eval_select((this, count, size), comptime, runtime) + } + + ub_checks::assert_unsafe_precondition!( + check_language_ub, + "ptr::offset requires the address calculation to not overflow", + ( + this: *const () = self as *const (), + count: isize = count, + size: usize = size_of::(), + ) => runtime_offset_nowrap(this, count, size) + ); + // SAFETY: the caller must uphold the safety contract for `offset`. unsafe { intrinsics::offset(self, count) } } @@ -726,7 +756,6 @@ impl *const T { true } - #[allow(unused_unsafe)] intrinsics::const_eval_select((this, origin), comptime, runtime) } @@ -858,6 +887,34 @@ impl *const T { where T: Sized, { + #[inline] + const fn runtime_add_nowrap(this: *const (), count: usize, size: usize) -> bool { + #[inline] + fn runtime(this: *const (), count: usize, size: usize) -> bool { + let Some(byte_offset) = count.checked_mul(size) else { + return false; + }; + let (_, overflow) = this.addr().overflowing_add(byte_offset); + byte_offset <= (isize::MAX as usize) && !overflow + } + + const fn comptime(_: *const (), _: usize, _: usize) -> bool { + true + } + + intrinsics::const_eval_select((this, count, size), comptime, runtime) + } + + ub_checks::assert_unsafe_precondition!( + check_language_ub, + "ptr::add requires that the address calculation does not overflow", + ( + this: *const () = self as *const (), + count: usize = count, + size: usize = size_of::(), + ) => runtime_add_nowrap(this, count, size) + ); + // SAFETY: the caller must uphold the safety contract for `offset`. unsafe { intrinsics::offset(self, count) } } @@ -936,6 +993,33 @@ impl *const T { where T: Sized, { + #[inline] + const fn runtime_sub_nowrap(this: *const (), count: usize, size: usize) -> bool { + #[inline] + fn runtime(this: *const (), count: usize, size: usize) -> bool { + let Some(byte_offset) = count.checked_mul(size) else { + return false; + }; + byte_offset <= (isize::MAX as usize) && this.addr() >= byte_offset + } + + const fn comptime(_: *const (), _: usize, _: usize) -> bool { + true + } + + intrinsics::const_eval_select((this, count, size), comptime, runtime) + } + + ub_checks::assert_unsafe_precondition!( + check_language_ub, + "ptr::sub requires that the address calculation does not overflow", + ( + this: *const () = self as *const (), + count: usize = count, + size: usize = size_of::(), + ) => runtime_sub_nowrap(this, count, size) + ); + if T::IS_ZST { // Pointer arithmetic does nothing when the pointee is a ZST. self @@ -943,7 +1027,7 @@ impl *const T { // SAFETY: the caller must uphold the safety contract for `offset`. // Because the pointee is *not* a ZST, that means that `count` is // at most `isize::MAX`, and thus the negation cannot overflow. - unsafe { self.offset((count as isize).unchecked_neg()) } + unsafe { intrinsics::offset(self, intrinsics::unchecked_sub(0, count as isize)) } } } diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index 287073497f8..8dbce1fdb98 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -393,6 +393,37 @@ impl *mut T { where T: Sized, { + #[inline] + const fn runtime_offset_nowrap(this: *const (), count: isize, size: usize) -> bool { + #[inline] + fn runtime(this: *const (), count: isize, size: usize) -> bool { + // `size` is the size of a Rust type, so we know that + // `size <= isize::MAX` and thus `as` cast here is not lossy. + let Some(byte_offset) = count.checked_mul(size as isize) else { + return false; + }; + let (_, overflow) = this.addr().overflowing_add_signed(byte_offset); + !overflow + } + + const fn comptime(_: *const (), _: isize, _: usize) -> bool { + true + } + + // We can use const_eval_select here because this is only for UB checks. + intrinsics::const_eval_select((this, count, size), comptime, runtime) + } + + ub_checks::assert_unsafe_precondition!( + check_language_ub, + "ptr::offset requires the address calculation to not overflow", + ( + this: *const () = self as *const (), + count: isize = count, + size: usize = size_of::(), + ) => runtime_offset_nowrap(this, count, size) + ); + // SAFETY: the caller must uphold the safety contract for `offset`. // The obtained pointer is valid for writes since the caller must // guarantee that it points to the same allocated object as `self`. @@ -940,6 +971,34 @@ impl *mut T { where T: Sized, { + #[inline] + const fn runtime_add_nowrap(this: *const (), count: usize, size: usize) -> bool { + #[inline] + fn runtime(this: *const (), count: usize, size: usize) -> bool { + let Some(byte_offset) = count.checked_mul(size) else { + return false; + }; + let (_, overflow) = this.addr().overflowing_add(byte_offset); + byte_offset <= (isize::MAX as usize) && !overflow + } + + const fn comptime(_: *const (), _: usize, _: usize) -> bool { + true + } + + intrinsics::const_eval_select((this, count, size), comptime, runtime) + } + + ub_checks::assert_unsafe_precondition!( + check_language_ub, + "ptr::add requires that the address calculation does not overflow", + ( + this: *const () = self as *const (), + count: usize = count, + size: usize = size_of::(), + ) => runtime_add_nowrap(this, count, size) + ); + // SAFETY: the caller must uphold the safety contract for `offset`. unsafe { intrinsics::offset(self, count) } } @@ -1018,6 +1077,33 @@ impl *mut T { where T: Sized, { + #[inline] + const fn runtime_sub_nowrap(this: *const (), count: usize, size: usize) -> bool { + #[inline] + fn runtime(this: *const (), count: usize, size: usize) -> bool { + let Some(byte_offset) = count.checked_mul(size) else { + return false; + }; + byte_offset <= (isize::MAX as usize) && this.addr() >= byte_offset + } + + const fn comptime(_: *const (), _: usize, _: usize) -> bool { + true + } + + intrinsics::const_eval_select((this, count, size), comptime, runtime) + } + + ub_checks::assert_unsafe_precondition!( + check_language_ub, + "ptr::sub requires that the address calculation does not overflow", + ( + this: *const () = self as *const (), + count: usize = count, + size: usize = size_of::(), + ) => runtime_sub_nowrap(this, count, size) + ); + if T::IS_ZST { // Pointer arithmetic does nothing when the pointee is a ZST. self @@ -1025,7 +1111,7 @@ impl *mut T { // SAFETY: the caller must uphold the safety contract for `offset`. // Because the pointee is *not* a ZST, that means that `count` is // at most `isize::MAX`, and thus the negation cannot overflow. - unsafe { self.offset((count as isize).unchecked_neg()) } + unsafe { intrinsics::offset(self, intrinsics::unchecked_sub(0, count as isize)) } } } diff --git a/tests/codegen/option-as-slice.rs b/tests/codegen/option-as-slice.rs index cfa479aa4b2..0edbbac1176 100644 --- a/tests/codegen/option-as-slice.rs +++ b/tests/codegen/option-as-slice.rs @@ -14,7 +14,9 @@ pub fn u64_opt_as_slice(o: &Option) -> &[u64] { // CHECK-NOT: br // CHECK-NOT: switch // CHECK-NOT: icmp - // CHECK: %[[LEN:.+]] = load i64,{{.+}} !range ![[META_U64:.+]], !noundef + // CHECK: %[[LEN:.+]] = load i64 + // CHECK-SAME: !range ![[META_U64:[0-9]+]], + // CHECK-SAME: !noundef // CHECK-NOT: select // CHECK-NOT: br // CHECK-NOT: switch @@ -51,7 +53,9 @@ pub fn u8_opt_as_slice(o: &Option) -> &[u8] { // CHECK-NOT: br // CHECK-NOT: switch // CHECK-NOT: icmp - // CHECK: %[[TAG:.+]] = load i8,{{.+}} !range ![[META_U8:.+]], !noundef + // CHECK: %[[TAG:.+]] = load i8 + // CHECK-SAME: !range ![[META_U8:[0-9]+]], + // CHECK-SAME: !noundef // CHECK: %[[LEN:.+]] = zext{{.*}} i8 %[[TAG]] to i64 // CHECK-NOT: select // CHECK-NOT: br diff --git a/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_fat.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_fat.PreCodegen.after.panic-abort.mir index 5faa1e210cf..c99c6f7de88 100644 --- a/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_fat.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_fat.PreCodegen.after.panic-abort.mir @@ -10,12 +10,18 @@ fn demo_byte_add_fat(_1: *const [u32], _2: usize) -> *const [u32] { scope 2 (inlined std::ptr::const_ptr::::cast::) { } scope 3 (inlined std::ptr::const_ptr::::add) { - } - scope 4 (inlined std::ptr::const_ptr::::with_metadata_of::<[u32]>) { - let mut _5: usize; - scope 5 (inlined std::ptr::metadata::<[u32]>) { + scope 4 (inlined core::ub_checks::check_language_ub) { + scope 5 (inlined core::ub_checks::check_language_ub::runtime) { + } } - scope 6 (inlined std::ptr::from_raw_parts::<[u32], ()>) { + scope 6 (inlined std::mem::size_of::) { + } + } + scope 7 (inlined std::ptr::const_ptr::::with_metadata_of::<[u32]>) { + let mut _5: usize; + scope 8 (inlined std::ptr::metadata::<[u32]>) { + } + scope 9 (inlined std::ptr::from_raw_parts::<[u32], ()>) { } } } diff --git a/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_fat.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_fat.PreCodegen.after.panic-unwind.mir index 5faa1e210cf..c99c6f7de88 100644 --- a/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_fat.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_fat.PreCodegen.after.panic-unwind.mir @@ -10,12 +10,18 @@ fn demo_byte_add_fat(_1: *const [u32], _2: usize) -> *const [u32] { scope 2 (inlined std::ptr::const_ptr::::cast::) { } scope 3 (inlined std::ptr::const_ptr::::add) { - } - scope 4 (inlined std::ptr::const_ptr::::with_metadata_of::<[u32]>) { - let mut _5: usize; - scope 5 (inlined std::ptr::metadata::<[u32]>) { + scope 4 (inlined core::ub_checks::check_language_ub) { + scope 5 (inlined core::ub_checks::check_language_ub::runtime) { + } } - scope 6 (inlined std::ptr::from_raw_parts::<[u32], ()>) { + scope 6 (inlined std::mem::size_of::) { + } + } + scope 7 (inlined std::ptr::const_ptr::::with_metadata_of::<[u32]>) { + let mut _5: usize; + scope 8 (inlined std::ptr::metadata::<[u32]>) { + } + scope 9 (inlined std::ptr::from_raw_parts::<[u32], ()>) { } } } diff --git a/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_thin.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_thin.PreCodegen.after.panic-abort.mir index 9429785045a..07665b2adc8 100644 --- a/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_thin.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_thin.PreCodegen.after.panic-abort.mir @@ -10,11 +10,17 @@ fn demo_byte_add_thin(_1: *const u32, _2: usize) -> *const u32 { scope 2 (inlined std::ptr::const_ptr::::cast::) { } scope 3 (inlined std::ptr::const_ptr::::add) { - } - scope 4 (inlined std::ptr::const_ptr::::with_metadata_of::) { - scope 5 (inlined std::ptr::metadata::) { + scope 4 (inlined core::ub_checks::check_language_ub) { + scope 5 (inlined core::ub_checks::check_language_ub::runtime) { + } } - scope 6 (inlined std::ptr::from_raw_parts::) { + scope 6 (inlined std::mem::size_of::) { + } + } + scope 7 (inlined std::ptr::const_ptr::::with_metadata_of::) { + scope 8 (inlined std::ptr::metadata::) { + } + scope 9 (inlined std::ptr::from_raw_parts::) { } } } diff --git a/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_thin.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_thin.PreCodegen.after.panic-unwind.mir index 9429785045a..07665b2adc8 100644 --- a/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_thin.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_thin.PreCodegen.after.panic-unwind.mir @@ -10,11 +10,17 @@ fn demo_byte_add_thin(_1: *const u32, _2: usize) -> *const u32 { scope 2 (inlined std::ptr::const_ptr::::cast::) { } scope 3 (inlined std::ptr::const_ptr::::add) { - } - scope 4 (inlined std::ptr::const_ptr::::with_metadata_of::) { - scope 5 (inlined std::ptr::metadata::) { + scope 4 (inlined core::ub_checks::check_language_ub) { + scope 5 (inlined core::ub_checks::check_language_ub::runtime) { + } } - scope 6 (inlined std::ptr::from_raw_parts::) { + scope 6 (inlined std::mem::size_of::) { + } + } + scope 7 (inlined std::ptr::const_ptr::::with_metadata_of::) { + scope 8 (inlined std::ptr::metadata::) { + } + scope 9 (inlined std::ptr::from_raw_parts::) { } } } 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 3aa483ed1ae..da3295bf8c9 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 @@ -19,30 +19,30 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { debug i => _22; debug x => _23; } - scope 17 (inlined > as Iterator>::next) { + scope 20 (inlined > as Iterator>::next) { 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 18 { + scope 21 { let _18: usize; - scope 23 { + scope 26 { } } - scope 19 { - scope 20 { - scope 26 (inlined as FromResidual>>::from_residual) { + scope 22 { + scope 23 { + scope 29 (inlined as FromResidual>>::from_residual) { } } } - scope 21 { - scope 22 { + scope 24 { + scope 25 { } } - scope 24 (inlined as Try>::branch) { + scope 27 (inlined as Try>::branch) { let mut _16: isize; let _17: &T; - scope 25 { + scope 28 { } } } @@ -64,6 +64,12 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { scope 12 (inlined NonNull::::as_ptr) { } scope 13 (inlined std::ptr::mut_ptr::::add) { + scope 14 (inlined core::ub_checks::check_language_ub) { + scope 15 (inlined core::ub_checks::check_language_ub::runtime) { + } + } + scope 16 (inlined std::mem::size_of::) { + } } } scope 8 (inlined as From<&[T]>>::from) { @@ -77,11 +83,11 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { } } } - scope 14 (inlined as Iterator>::enumerate) { - scope 15 (inlined Enumerate::>::new) { + scope 17 (inlined as Iterator>::enumerate) { + scope 18 (inlined Enumerate::>::new) { } } - scope 16 (inlined > as IntoIterator>::into_iter) { + scope 19 (inlined > as IntoIterator>::into_iter) { } bb0: { 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 4cc0aa0ed78..46c868ba8a1 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 @@ -39,6 +39,12 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { scope 12 (inlined NonNull::::as_ptr) { } scope 13 (inlined std::ptr::mut_ptr::::add) { + scope 14 (inlined core::ub_checks::check_language_ub) { + scope 15 (inlined core::ub_checks::check_language_ub::runtime) { + } + } + scope 16 (inlined std::mem::size_of::) { + } } } scope 8 (inlined as From<&[T]>>::from) { @@ -52,11 +58,11 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { } } } - scope 14 (inlined as Iterator>::enumerate) { - scope 15 (inlined Enumerate::>::new) { + scope 17 (inlined as Iterator>::enumerate) { + scope 18 (inlined Enumerate::>::new) { } } - scope 16 (inlined > as IntoIterator>::into_iter) { + scope 19 (inlined > as IntoIterator>::into_iter) { } bb0: { 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 507afa63c68..cedda097c38 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 @@ -36,6 +36,12 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () { scope 12 (inlined NonNull::::as_ptr) { } scope 13 (inlined std::ptr::mut_ptr::::add) { + scope 14 (inlined core::ub_checks::check_language_ub) { + scope 15 (inlined core::ub_checks::check_language_ub::runtime) { + } + } + scope 16 (inlined std::mem::size_of::) { + } } } scope 8 (inlined as From<&[T]>>::from) { @@ -49,7 +55,7 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () { } } } - scope 14 (inlined as IntoIterator>::into_iter) { + scope 17 (inlined as IntoIterator>::into_iter) { } bb0: { 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 a25f12edc28..e299760d982 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 @@ -36,6 +36,12 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () { scope 12 (inlined NonNull::::as_ptr) { } scope 13 (inlined std::ptr::mut_ptr::::add) { + scope 14 (inlined core::ub_checks::check_language_ub) { + scope 15 (inlined core::ub_checks::check_language_ub::runtime) { + } + } + scope 16 (inlined std::mem::size_of::) { + } } } scope 8 (inlined as From<&[T]>>::from) { @@ -49,7 +55,7 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () { } } } - scope 14 (inlined as IntoIterator>::into_iter) { + scope 17 (inlined as IntoIterator>::into_iter) { } bb0: { 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 1b397a4e4cd..d01bd4a9a4a 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 @@ -18,7 +18,7 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () { scope 2 { debug x => _17; } - scope 17 (inlined > as Iterator>::next) { + scope 20 (inlined > as Iterator>::next) { let mut _14: &mut std::slice::Iter<'_, T>; } } @@ -39,6 +39,12 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () { scope 12 (inlined NonNull::::as_ptr) { } scope 13 (inlined std::ptr::mut_ptr::::add) { + scope 14 (inlined core::ub_checks::check_language_ub) { + scope 15 (inlined core::ub_checks::check_language_ub::runtime) { + } + } + scope 16 (inlined std::mem::size_of::) { + } } } scope 8 (inlined as From<&[T]>>::from) { @@ -52,11 +58,11 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () { } } } - scope 14 (inlined as Iterator>::rev) { - scope 15 (inlined Rev::>::new) { + scope 17 (inlined as Iterator>::rev) { + scope 18 (inlined Rev::>::new) { } } - scope 16 (inlined > as IntoIterator>::into_iter) { + scope 19 (inlined > as IntoIterator>::into_iter) { } bb0: { 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 77689dd9b51..d2d0492add4 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 @@ -18,7 +18,7 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () { scope 2 { debug x => _17; } - scope 17 (inlined > as Iterator>::next) { + scope 20 (inlined > as Iterator>::next) { let mut _14: &mut std::slice::Iter<'_, T>; } } @@ -39,6 +39,12 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () { scope 12 (inlined NonNull::::as_ptr) { } scope 13 (inlined std::ptr::mut_ptr::::add) { + scope 14 (inlined core::ub_checks::check_language_ub) { + scope 15 (inlined core::ub_checks::check_language_ub::runtime) { + } + } + scope 16 (inlined std::mem::size_of::) { + } } } scope 8 (inlined as From<&[T]>>::from) { @@ -52,11 +58,11 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () { } } } - scope 14 (inlined as Iterator>::rev) { - scope 15 (inlined Rev::>::new) { + scope 17 (inlined as Iterator>::rev) { + scope 18 (inlined Rev::>::new) { } } - scope 16 (inlined > as IntoIterator>::into_iter) { + scope 19 (inlined > as IntoIterator>::into_iter) { } bb0: { From 9d5c961fa40cde6a9b70dfde3c1fe59de848d723 Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Sun, 6 Oct 2024 23:36:22 -0400 Subject: [PATCH 664/683] cfg out checks in add and sub but not offset ...because the checks in offset found bugs in a crater run. --- library/core/src/ptr/const_ptr.rs | 4 ++++ library/core/src/ptr/mut_ptr.rs | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs index 4727dc77d18..c9af7f13e46 100644 --- a/library/core/src/ptr/const_ptr.rs +++ b/library/core/src/ptr/const_ptr.rs @@ -887,6 +887,7 @@ impl *const T { where T: Sized, { + #[cfg(debug_assertions)] #[inline] const fn runtime_add_nowrap(this: *const (), count: usize, size: usize) -> bool { #[inline] @@ -905,6 +906,7 @@ impl *const T { intrinsics::const_eval_select((this, count, size), comptime, runtime) } + #[cfg(debug_assertions)] // Expensive, and doesn't catch much in the wild. ub_checks::assert_unsafe_precondition!( check_language_ub, "ptr::add requires that the address calculation does not overflow", @@ -993,6 +995,7 @@ impl *const T { where T: Sized, { + #[cfg(debug_assertions)] #[inline] const fn runtime_sub_nowrap(this: *const (), count: usize, size: usize) -> bool { #[inline] @@ -1010,6 +1013,7 @@ impl *const T { intrinsics::const_eval_select((this, count, size), comptime, runtime) } + #[cfg(debug_assertions)] // Expensive, and doesn't catch much in the wild. ub_checks::assert_unsafe_precondition!( check_language_ub, "ptr::sub requires that the address calculation does not overflow", diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index 8dbce1fdb98..e458bb4642f 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -971,6 +971,7 @@ impl *mut T { where T: Sized, { + #[cfg(debug_assertions)] #[inline] const fn runtime_add_nowrap(this: *const (), count: usize, size: usize) -> bool { #[inline] @@ -989,6 +990,7 @@ impl *mut T { intrinsics::const_eval_select((this, count, size), comptime, runtime) } + #[cfg(debug_assertions)] // Expensive, and doesn't catch much in the wild. ub_checks::assert_unsafe_precondition!( check_language_ub, "ptr::add requires that the address calculation does not overflow", @@ -1077,6 +1079,7 @@ impl *mut T { where T: Sized, { + #[cfg(debug_assertions)] #[inline] const fn runtime_sub_nowrap(this: *const (), count: usize, size: usize) -> bool { #[inline] @@ -1094,6 +1097,7 @@ impl *mut T { intrinsics::const_eval_select((this, count, size), comptime, runtime) } + #[cfg(debug_assertions)] // Expensive, and doesn't catch much in the wild. ub_checks::assert_unsafe_precondition!( check_language_ub, "ptr::sub requires that the address calculation does not overflow", From 128ccc3c26a80be2768abbdd020404fb439b905e Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Mon, 7 Oct 2024 11:18:37 -0400 Subject: [PATCH 665/683] Bless mir-opt tests --- ...e_add_fat.PreCodegen.after.panic-abort.mir | 12 ++----- ..._add_fat.PreCodegen.after.panic-unwind.mir | 12 ++----- ..._add_thin.PreCodegen.after.panic-abort.mir | 12 ++----- ...add_thin.PreCodegen.after.panic-unwind.mir | 12 ++----- ...ated_loop.PreCodegen.after.panic-abort.mir | 32 ++++++++----------- ...ted_loop.PreCodegen.after.panic-unwind.mir | 12 ++----- ...ward_loop.PreCodegen.after.panic-abort.mir | 8 +---- ...ard_loop.PreCodegen.after.panic-unwind.mir | 8 +---- ...erse_loop.PreCodegen.after.panic-abort.mir | 14 +++----- ...rse_loop.PreCodegen.after.panic-unwind.mir | 14 +++----- 10 files changed, 38 insertions(+), 98 deletions(-) diff --git a/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_fat.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_fat.PreCodegen.after.panic-abort.mir index c99c6f7de88..5faa1e210cf 100644 --- a/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_fat.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_fat.PreCodegen.after.panic-abort.mir @@ -10,18 +10,12 @@ fn demo_byte_add_fat(_1: *const [u32], _2: usize) -> *const [u32] { scope 2 (inlined std::ptr::const_ptr::::cast::) { } scope 3 (inlined std::ptr::const_ptr::::add) { - scope 4 (inlined core::ub_checks::check_language_ub) { - scope 5 (inlined core::ub_checks::check_language_ub::runtime) { - } - } - scope 6 (inlined std::mem::size_of::) { - } } - scope 7 (inlined std::ptr::const_ptr::::with_metadata_of::<[u32]>) { + scope 4 (inlined std::ptr::const_ptr::::with_metadata_of::<[u32]>) { let mut _5: usize; - scope 8 (inlined std::ptr::metadata::<[u32]>) { + scope 5 (inlined std::ptr::metadata::<[u32]>) { } - scope 9 (inlined std::ptr::from_raw_parts::<[u32], ()>) { + scope 6 (inlined std::ptr::from_raw_parts::<[u32], ()>) { } } } diff --git a/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_fat.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_fat.PreCodegen.after.panic-unwind.mir index c99c6f7de88..5faa1e210cf 100644 --- a/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_fat.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_fat.PreCodegen.after.panic-unwind.mir @@ -10,18 +10,12 @@ fn demo_byte_add_fat(_1: *const [u32], _2: usize) -> *const [u32] { scope 2 (inlined std::ptr::const_ptr::::cast::) { } scope 3 (inlined std::ptr::const_ptr::::add) { - scope 4 (inlined core::ub_checks::check_language_ub) { - scope 5 (inlined core::ub_checks::check_language_ub::runtime) { - } - } - scope 6 (inlined std::mem::size_of::) { - } } - scope 7 (inlined std::ptr::const_ptr::::with_metadata_of::<[u32]>) { + scope 4 (inlined std::ptr::const_ptr::::with_metadata_of::<[u32]>) { let mut _5: usize; - scope 8 (inlined std::ptr::metadata::<[u32]>) { + scope 5 (inlined std::ptr::metadata::<[u32]>) { } - scope 9 (inlined std::ptr::from_raw_parts::<[u32], ()>) { + scope 6 (inlined std::ptr::from_raw_parts::<[u32], ()>) { } } } diff --git a/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_thin.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_thin.PreCodegen.after.panic-abort.mir index 07665b2adc8..9429785045a 100644 --- a/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_thin.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_thin.PreCodegen.after.panic-abort.mir @@ -10,17 +10,11 @@ fn demo_byte_add_thin(_1: *const u32, _2: usize) -> *const u32 { scope 2 (inlined std::ptr::const_ptr::::cast::) { } scope 3 (inlined std::ptr::const_ptr::::add) { - scope 4 (inlined core::ub_checks::check_language_ub) { - scope 5 (inlined core::ub_checks::check_language_ub::runtime) { - } - } - scope 6 (inlined std::mem::size_of::) { - } } - scope 7 (inlined std::ptr::const_ptr::::with_metadata_of::) { - scope 8 (inlined std::ptr::metadata::) { + scope 4 (inlined std::ptr::const_ptr::::with_metadata_of::) { + scope 5 (inlined std::ptr::metadata::) { } - scope 9 (inlined std::ptr::from_raw_parts::) { + scope 6 (inlined std::ptr::from_raw_parts::) { } } } diff --git a/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_thin.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_thin.PreCodegen.after.panic-unwind.mir index 07665b2adc8..9429785045a 100644 --- a/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_thin.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_thin.PreCodegen.after.panic-unwind.mir @@ -10,17 +10,11 @@ fn demo_byte_add_thin(_1: *const u32, _2: usize) -> *const u32 { scope 2 (inlined std::ptr::const_ptr::::cast::) { } scope 3 (inlined std::ptr::const_ptr::::add) { - scope 4 (inlined core::ub_checks::check_language_ub) { - scope 5 (inlined core::ub_checks::check_language_ub::runtime) { - } - } - scope 6 (inlined std::mem::size_of::) { - } } - scope 7 (inlined std::ptr::const_ptr::::with_metadata_of::) { - scope 8 (inlined std::ptr::metadata::) { + scope 4 (inlined std::ptr::const_ptr::::with_metadata_of::) { + scope 5 (inlined std::ptr::metadata::) { } - scope 9 (inlined std::ptr::from_raw_parts::) { + scope 6 (inlined std::ptr::from_raw_parts::) { } } } 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 da3295bf8c9..3aa483ed1ae 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 @@ -19,30 +19,30 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { debug i => _22; debug x => _23; } - scope 20 (inlined > as Iterator>::next) { + scope 17 (inlined > as Iterator>::next) { 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 21 { + scope 18 { let _18: usize; - scope 26 { + scope 23 { } } - scope 22 { - scope 23 { - scope 29 (inlined as FromResidual>>::from_residual) { + scope 19 { + scope 20 { + scope 26 (inlined as FromResidual>>::from_residual) { } } } - scope 24 { - scope 25 { + scope 21 { + scope 22 { } } - scope 27 (inlined as Try>::branch) { + scope 24 (inlined as Try>::branch) { let mut _16: isize; let _17: &T; - scope 28 { + scope 25 { } } } @@ -64,12 +64,6 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { scope 12 (inlined NonNull::::as_ptr) { } scope 13 (inlined std::ptr::mut_ptr::::add) { - scope 14 (inlined core::ub_checks::check_language_ub) { - scope 15 (inlined core::ub_checks::check_language_ub::runtime) { - } - } - scope 16 (inlined std::mem::size_of::) { - } } } scope 8 (inlined as From<&[T]>>::from) { @@ -83,11 +77,11 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { } } } - scope 17 (inlined as Iterator>::enumerate) { - scope 18 (inlined Enumerate::>::new) { + scope 14 (inlined as Iterator>::enumerate) { + scope 15 (inlined Enumerate::>::new) { } } - scope 19 (inlined > as IntoIterator>::into_iter) { + scope 16 (inlined > as IntoIterator>::into_iter) { } bb0: { 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 46c868ba8a1..4cc0aa0ed78 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 @@ -39,12 +39,6 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { scope 12 (inlined NonNull::::as_ptr) { } scope 13 (inlined std::ptr::mut_ptr::::add) { - scope 14 (inlined core::ub_checks::check_language_ub) { - scope 15 (inlined core::ub_checks::check_language_ub::runtime) { - } - } - scope 16 (inlined std::mem::size_of::) { - } } } scope 8 (inlined as From<&[T]>>::from) { @@ -58,11 +52,11 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { } } } - scope 17 (inlined as Iterator>::enumerate) { - scope 18 (inlined Enumerate::>::new) { + scope 14 (inlined as Iterator>::enumerate) { + scope 15 (inlined Enumerate::>::new) { } } - scope 19 (inlined > as IntoIterator>::into_iter) { + scope 16 (inlined > as IntoIterator>::into_iter) { } bb0: { 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 cedda097c38..507afa63c68 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 @@ -36,12 +36,6 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () { scope 12 (inlined NonNull::::as_ptr) { } scope 13 (inlined std::ptr::mut_ptr::::add) { - scope 14 (inlined core::ub_checks::check_language_ub) { - scope 15 (inlined core::ub_checks::check_language_ub::runtime) { - } - } - scope 16 (inlined std::mem::size_of::) { - } } } scope 8 (inlined as From<&[T]>>::from) { @@ -55,7 +49,7 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () { } } } - scope 17 (inlined as IntoIterator>::into_iter) { + scope 14 (inlined as IntoIterator>::into_iter) { } bb0: { 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 e299760d982..a25f12edc28 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 @@ -36,12 +36,6 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () { scope 12 (inlined NonNull::::as_ptr) { } scope 13 (inlined std::ptr::mut_ptr::::add) { - scope 14 (inlined core::ub_checks::check_language_ub) { - scope 15 (inlined core::ub_checks::check_language_ub::runtime) { - } - } - scope 16 (inlined std::mem::size_of::) { - } } } scope 8 (inlined as From<&[T]>>::from) { @@ -55,7 +49,7 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () { } } } - scope 17 (inlined as IntoIterator>::into_iter) { + scope 14 (inlined as IntoIterator>::into_iter) { } bb0: { 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 d01bd4a9a4a..1b397a4e4cd 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 @@ -18,7 +18,7 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () { scope 2 { debug x => _17; } - scope 20 (inlined > as Iterator>::next) { + scope 17 (inlined > as Iterator>::next) { let mut _14: &mut std::slice::Iter<'_, T>; } } @@ -39,12 +39,6 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () { scope 12 (inlined NonNull::::as_ptr) { } scope 13 (inlined std::ptr::mut_ptr::::add) { - scope 14 (inlined core::ub_checks::check_language_ub) { - scope 15 (inlined core::ub_checks::check_language_ub::runtime) { - } - } - scope 16 (inlined std::mem::size_of::) { - } } } scope 8 (inlined as From<&[T]>>::from) { @@ -58,11 +52,11 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () { } } } - scope 17 (inlined as Iterator>::rev) { - scope 18 (inlined Rev::>::new) { + scope 14 (inlined as Iterator>::rev) { + scope 15 (inlined Rev::>::new) { } } - scope 19 (inlined > as IntoIterator>::into_iter) { + scope 16 (inlined > as IntoIterator>::into_iter) { } bb0: { 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 d2d0492add4..77689dd9b51 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 @@ -18,7 +18,7 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () { scope 2 { debug x => _17; } - scope 20 (inlined > as Iterator>::next) { + scope 17 (inlined > as Iterator>::next) { let mut _14: &mut std::slice::Iter<'_, T>; } } @@ -39,12 +39,6 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () { scope 12 (inlined NonNull::::as_ptr) { } scope 13 (inlined std::ptr::mut_ptr::::add) { - scope 14 (inlined core::ub_checks::check_language_ub) { - scope 15 (inlined core::ub_checks::check_language_ub::runtime) { - } - } - scope 16 (inlined std::mem::size_of::) { - } } } scope 8 (inlined as From<&[T]>>::from) { @@ -58,11 +52,11 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () { } } } - scope 17 (inlined as Iterator>::rev) { - scope 18 (inlined Rev::>::new) { + scope 14 (inlined as Iterator>::rev) { + scope 15 (inlined Rev::>::new) { } } - scope 19 (inlined > as IntoIterator>::into_iter) { + scope 16 (inlined > as IntoIterator>::into_iter) { } bb0: { From 65cff8a1ef706bca25d30e1f49e02af846b4a61f Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 7 Oct 2024 12:17:50 -0400 Subject: [PATCH 666/683] Mark Boxy as on vacation --- triagebot.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/triagebot.toml b/triagebot.toml index 737be4cc457..0172a80b3a5 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -921,6 +921,7 @@ cc = ["@kobzol"] warn_non_default_branch = true contributing_url = "https://rustc-dev-guide.rust-lang.org/getting-started.html" users_on_vacation = [ + "BoxyUwU", "fmease", "jhpratt", "jyn514", From 8d562f6cc57b40e3c184f0eb72cb5de845d2e046 Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Mon, 7 Oct 2024 12:23:27 -0400 Subject: [PATCH 667/683] Disable slice_iter mir-opt test in debug builds --- tests/mir-opt/pre-codegen/slice_iter.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/mir-opt/pre-codegen/slice_iter.rs b/tests/mir-opt/pre-codegen/slice_iter.rs index 3f89ab0e6f3..fee4214982d 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.rs +++ b/tests/mir-opt/pre-codegen/slice_iter.rs @@ -1,6 +1,7 @@ // skip-filecheck //@ compile-flags: -O -C debuginfo=0 -Zmir-opt-level=2 //@ only-64bit (constants for `None::<&T>` show in the output) +//@ ignore-debug: precondition checks on ptr::add are under cfg(debug_assertions) // EMIT_MIR_FOR_EACH_PANIC_STRATEGY #![crate_type = "lib"] From ad7d41ce90a78dea19b6dffe8aad22ce7b9be32f Mon Sep 17 00:00:00 2001 From: clubby789 Date: Mon, 7 Oct 2024 10:28:16 +0000 Subject: [PATCH 668/683] Test for issue 23600 --- src/tools/tidy/src/issues.txt | 1 - .../{issue-77062-large-zst-array.rs => large-zst-array-77062.rs} | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) rename tests/ui/consts/{issue-77062-large-zst-array.rs => large-zst-array-77062.rs} (53%) diff --git a/src/tools/tidy/src/issues.txt b/src/tools/tidy/src/issues.txt index 86cae849b97..8dc1ee38ffd 100644 --- a/src/tools/tidy/src/issues.txt +++ b/src/tools/tidy/src/issues.txt @@ -802,7 +802,6 @@ ui/consts/issue-70942-trait-vs-impl-mismatch.rs ui/consts/issue-73976-monomorphic.rs ui/consts/issue-73976-polymorphic.rs ui/consts/issue-76064.rs -ui/consts/issue-77062-large-zst-array.rs ui/consts/issue-78655.rs ui/consts/issue-79137-monomorphic.rs ui/consts/issue-79137-toogeneric.rs diff --git a/tests/ui/consts/issue-77062-large-zst-array.rs b/tests/ui/consts/large-zst-array-77062.rs similarity index 53% rename from tests/ui/consts/issue-77062-large-zst-array.rs rename to tests/ui/consts/large-zst-array-77062.rs index ef5178fba95..089353d0885 100644 --- a/tests/ui/consts/issue-77062-large-zst-array.rs +++ b/tests/ui/consts/large-zst-array-77062.rs @@ -1,4 +1,5 @@ //@ build-pass +pub static FOO: [(); usize::MAX] = [(); usize::MAX]; fn main() { let _ = &[(); usize::MAX]; From b577b26249826cdd8a2aa1bdafbe7d5a58ec98fd Mon Sep 17 00:00:00 2001 From: clubby789 Date: Mon, 7 Oct 2024 11:30:18 +0000 Subject: [PATCH 669/683] Add stdio configuring to run-make Rustc --- src/tools/run-make-support/src/macros.rs | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/tools/run-make-support/src/macros.rs b/src/tools/run-make-support/src/macros.rs index f7fe4f54223..be71470321c 100644 --- a/src/tools/run-make-support/src/macros.rs +++ b/src/tools/run-make-support/src/macros.rs @@ -70,6 +70,30 @@ macro_rules! impl_common_helpers { self } + /// Configuration for the child process’s standard input (stdin) handle. + /// + /// See [`std::process::Command::stdin`]. + pub fn stdin>(&mut self, cfg: T) -> &mut Self { + self.cmd.stdin(cfg); + self + } + + /// Configuration for the child process’s standard output (stdout) handle. + /// + /// See [`std::process::Command::stdout`]. + pub fn stdout>(&mut self, cfg: T) -> &mut Self { + self.cmd.stdout(cfg); + self + } + + /// Configuration for the child process’s standard error (stderr) handle. + /// + /// See [`std::process::Command::stderr`]. + pub fn stderr>(&mut self, cfg: T) -> &mut Self { + self.cmd.stderr(cfg); + self + } + /// Inspect what the underlying [`Command`] is up to the /// current construction. pub fn inspect(&mut self, inspector: I) -> &mut Self From 3afb7d687c17518684f3aa4a42909e2b1d9887be Mon Sep 17 00:00:00 2001 From: clubby789 Date: Mon, 7 Oct 2024 11:30:51 +0000 Subject: [PATCH 670/683] Migrate `emit-to-stdout` to new run-make Co-authored-by: Oneirical Co-authored-by: Chris Denton --- src/tools/run-make-support/src/macros.rs | 6 +- .../tidy/src/allowed_run_make_makefiles.txt | 1 - tests/run-make/emit-to-stdout/Makefile | 51 ------------- tests/run-make/emit-to-stdout/rmake.rs | 73 +++++++++++++++++++ 4 files changed, 76 insertions(+), 55 deletions(-) delete mode 100644 tests/run-make/emit-to-stdout/Makefile create mode 100644 tests/run-make/emit-to-stdout/rmake.rs diff --git a/src/tools/run-make-support/src/macros.rs b/src/tools/run-make-support/src/macros.rs index be71470321c..cc3d1281d0a 100644 --- a/src/tools/run-make-support/src/macros.rs +++ b/src/tools/run-make-support/src/macros.rs @@ -73,7 +73,7 @@ macro_rules! impl_common_helpers { /// Configuration for the child process’s standard input (stdin) handle. /// /// See [`std::process::Command::stdin`]. - pub fn stdin>(&mut self, cfg: T) -> &mut Self { + pub fn stdin>(&mut self, cfg: T) -> &mut Self { self.cmd.stdin(cfg); self } @@ -81,7 +81,7 @@ macro_rules! impl_common_helpers { /// Configuration for the child process’s standard output (stdout) handle. /// /// See [`std::process::Command::stdout`]. - pub fn stdout>(&mut self, cfg: T) -> &mut Self { + pub fn stdout>(&mut self, cfg: T) -> &mut Self { self.cmd.stdout(cfg); self } @@ -89,7 +89,7 @@ macro_rules! impl_common_helpers { /// Configuration for the child process’s standard error (stderr) handle. /// /// See [`std::process::Command::stderr`]. - pub fn stderr>(&mut self, cfg: T) -> &mut Self { + pub fn stderr>(&mut self, cfg: T) -> &mut Self { self.cmd.stderr(cfg); self } diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt index 50d21c7ed4c..7a0f98d59f0 100644 --- a/src/tools/tidy/src/allowed_run_make_makefiles.txt +++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt @@ -1,6 +1,5 @@ run-make/branch-protection-check-IBT/Makefile run-make/cat-and-grep-sanity-check/Makefile -run-make/emit-to-stdout/Makefile run-make/extern-fn-reachable/Makefile run-make/incr-add-rust-src-component/Makefile run-make/issue-84395-lto-embed-bitcode/Makefile diff --git a/tests/run-make/emit-to-stdout/Makefile b/tests/run-make/emit-to-stdout/Makefile deleted file mode 100644 index 80e9b6a4ded..00000000000 --- a/tests/run-make/emit-to-stdout/Makefile +++ /dev/null @@ -1,51 +0,0 @@ -include ../tools.mk - -SRC=test.rs -OUT=$(TMPDIR)/out - -all: asm llvm-ir dep-info mir llvm-bc obj metadata link multiple-types multiple-types-option-o - -asm: $(OUT) - $(RUSTC) --emit asm=$(OUT)/$@ $(SRC) - $(RUSTC) --emit asm=- $(SRC) | diff - $(OUT)/$@ -llvm-ir: $(OUT) - $(RUSTC) --emit llvm-ir=$(OUT)/$@ $(SRC) - $(RUSTC) --emit llvm-ir=- $(SRC) | diff - $(OUT)/$@ -dep-info: $(OUT) - $(RUSTC) -Z dep-info-omit-d-target=yes --emit dep-info=$(OUT)/$@ $(SRC) - $(RUSTC) --emit dep-info=- $(SRC) | diff - $(OUT)/$@ -mir: $(OUT) - $(RUSTC) --emit mir=$(OUT)/$@ $(SRC) - $(RUSTC) --emit mir=- $(SRC) | diff - $(OUT)/$@ - -llvm-bc: $(OUT) - $(RUSTC) --emit llvm-bc=- $(SRC) 1>/dev/ptmx 2>$(OUT)/$@ || true - diff $(OUT)/$@ emit-llvm-bc.stderr -obj: $(OUT) - $(RUSTC) --emit obj=- $(SRC) 1>/dev/ptmx 2>$(OUT)/$@ || true - diff $(OUT)/$@ emit-obj.stderr - -# For metadata output, a temporary directory will be created to hold the temporary -# metadata file. But when output is stdout, the temporary directory will be located -# in the same place as $(SRC), which is mounted as read-only in the tests. Thus as -# a workaround, $(SRC) is copied to the test output directory $(OUT) and we compile -# it there. -metadata: $(OUT) - cp $(SRC) $(OUT) - (cd $(OUT); $(RUSTC) --emit metadata=- $(SRC) 1>/dev/ptmx 2>$(OUT)/$@ || true) - diff $(OUT)/$@ emit-metadata.stderr - -link: $(OUT) - $(RUSTC) --emit link=- $(SRC) 1>/dev/ptmx 2>$(OUT)/$@ || true - diff $(OUT)/$@ emit-link.stderr - -multiple-types: $(OUT) - $(RUSTC) --emit asm=- --emit llvm-ir=- --emit dep-info=- --emit mir=- $(SRC) 2>$(OUT)/$@ || true - diff $(OUT)/$@ emit-multiple-types.stderr - -multiple-types-option-o: $(OUT) - $(RUSTC) -o - --emit asm,llvm-ir,dep-info,mir $(SRC) 2>$(OUT)/$@ || true - diff $(OUT)/$@ emit-multiple-types.stderr - -$(OUT): - mkdir -p $(OUT) diff --git a/tests/run-make/emit-to-stdout/rmake.rs b/tests/run-make/emit-to-stdout/rmake.rs new file mode 100644 index 00000000000..a9a3796731b --- /dev/null +++ b/tests/run-make/emit-to-stdout/rmake.rs @@ -0,0 +1,73 @@ +//! If `-o -` or `--emit KIND=-` is provided, output should be written to stdout +//! instead. Binary output (`obj`, `llvm-bc`, `link` and `metadata`) +//! being written this way will result in an error if stdout is a tty. +//! Multiple output types going to stdout will trigger an error too, +//! as they would all be mixed together. +//! +//! See . + +use std::fs::File; + +use run_make_support::{diff, run_in_tmpdir, rustc}; + +// Test emitting text outputs to stdout works correctly +fn run_diff(name: &str, file_args: &[&str]) { + rustc().emit(format!("{name}={name}")).input("test.rs").args(file_args).run(); + let out = rustc().emit(format!("{name}=-")).input("test.rs").run().stdout_utf8(); + diff().expected_file(name).actual_text("stdout", &out).run(); +} + +// Test that emitting binary formats to a terminal gives the correct error +fn run_terminal_err_diff(name: &str) { + #[cfg(not(windows))] + let terminal = File::create("/dev/ptmx").unwrap(); + // FIXME: If this test fails and the compiler does print to the console, + // then this will produce a lot of output. + // We should spawn a new console instead to print stdout. + #[cfg(windows)] + let terminal = File::options().read(true).write(true).open(r"\\.\CONOUT$").unwrap(); + + let err = File::create(name).unwrap(); + rustc().emit(format!("{name}=-")).input("test.rs").stdout(terminal).stderr(err).run_fail(); + diff().expected_file(format!("emit-{name}.stderr")).actual_file(name).run(); +} + +fn main() { + run_in_tmpdir(|| { + run_diff("asm", &[]); + run_diff("llvm-ir", &[]); + run_diff("dep-info", &["-Zdep-info-omit-d-target=yes"]); + run_diff("mir", &[]); + + run_terminal_err_diff("llvm-bc"); + run_terminal_err_diff("obj"); + run_terminal_err_diff("metadata"); + run_terminal_err_diff("link"); + + // Test error for emitting multiple types to stdout + rustc() + .input("test.rs") + .emit("asm=-") + .emit("llvm-ir=-") + .emit("dep-info=-") + .emit("mir=-") + .stderr(File::create("multiple-types").unwrap()) + .run_fail(); + diff().expected_file("emit-multiple-types.stderr").actual_file("multiple-types").run(); + + // Same as above, but using `-o` + rustc() + .input("test.rs") + .output("-") + .emit("asm,llvm-ir,dep-info,mir") + .stderr(File::create("multiple-types-option-o").unwrap()) + .run_fail(); + diff() + .expected_file("emit-multiple-types.stderr") + .actual_file("multiple-types-option-o") + .run(); + + // Test that `-o -` redirected to a file works correctly (#26719) + rustc().input("test.rs").output("-").stdout(File::create("out-stdout").unwrap()).run(); + }); +} From b27c22d6b0a230fc122d541356580f0fb2be2366 Mon Sep 17 00:00:00 2001 From: clubby789 Date: Mon, 7 Oct 2024 11:32:53 +0000 Subject: [PATCH 671/683] Add test for issue 28994 --- .../fn-pointer/hrtb-assoc-fn-traits-28994.rs | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 tests/ui/traits/fn-pointer/hrtb-assoc-fn-traits-28994.rs diff --git a/tests/ui/traits/fn-pointer/hrtb-assoc-fn-traits-28994.rs b/tests/ui/traits/fn-pointer/hrtb-assoc-fn-traits-28994.rs new file mode 100644 index 00000000000..e2f02053f95 --- /dev/null +++ b/tests/ui/traits/fn-pointer/hrtb-assoc-fn-traits-28994.rs @@ -0,0 +1,22 @@ +//@ check-pass +//! Tests that a HRTB + FnOnce bound involving an associated type don't prevent +//! a function pointer from implementing `Fn` traits. +//! Test for + +trait LifetimeToType<'a> { + type Out; +} + +impl<'a> LifetimeToType<'a> for () { + type Out = &'a (); +} + +fn id<'a>(val: &'a ()) -> <() as LifetimeToType<'a>>::Out { + val +} + +fn assert_fn FnOnce(&'a ()) -> <() as LifetimeToType<'a>>::Out>(_func: F) { } + +fn main() { + assert_fn(id); +} From fa4f18be5553bd23856abf717ad86acf0412a2ef Mon Sep 17 00:00:00 2001 From: clubby789 Date: Mon, 7 Oct 2024 11:36:47 +0000 Subject: [PATCH 672/683] Add test for issue 30472 --- .../assoc-type-hrtb-normalization-30472.rs | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 tests/ui/traits/assoc-type-hrtb-normalization-30472.rs diff --git a/tests/ui/traits/assoc-type-hrtb-normalization-30472.rs b/tests/ui/traits/assoc-type-hrtb-normalization-30472.rs new file mode 100644 index 00000000000..4ce3b9b3b77 --- /dev/null +++ b/tests/ui/traits/assoc-type-hrtb-normalization-30472.rs @@ -0,0 +1,32 @@ +//@ check-pass +//! Tests that associated type projections normalize properly in the presence of HRTBs. +//! Original issue: + + +pub trait MyFrom {} +impl MyFrom for T {} + +pub trait MyInto {} +impl MyInto for T where U: MyFrom {} + + +pub trait A<'self_> { + type T; +} +pub trait B: for<'self_> A<'self_> { + // Originally caused the `type U = usize` example below to fail with a type mismatch error + type U: for<'self_> MyFrom<>::T>; +} + + +pub struct M; +impl<'self_> A<'self_> for M { + type T = usize; +} + +impl B for M { + type U = usize; +} + + +fn main() {} From 382365bfe3f136fe97273e58532d799a82b373ea Mon Sep 17 00:00:00 2001 From: clubby789 Date: Mon, 7 Oct 2024 11:36:58 +0000 Subject: [PATCH 673/683] Add test for issue 30867 --- tests/ui/traits/hrtb-related-type-params-30867.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 tests/ui/traits/hrtb-related-type-params-30867.rs diff --git a/tests/ui/traits/hrtb-related-type-params-30867.rs b/tests/ui/traits/hrtb-related-type-params-30867.rs new file mode 100644 index 00000000000..ec1e3355bfb --- /dev/null +++ b/tests/ui/traits/hrtb-related-type-params-30867.rs @@ -0,0 +1,14 @@ +//@ check-pass +//! Tests that HRTB impl selection covers type parameters not directly related +//! to the trait. +//! Test for + +#![crate_type = "lib"] + +trait Unary {} +impl U> Unary for F {} +fn unary Unary<&'a T>, T>() {} + +pub fn test Fn(&'a i32) -> &'a i32>() { + unary::() +} From 4d7c6ca1bba06574ab04ea4f4d40f42216c05e56 Mon Sep 17 00:00:00 2001 From: rustbot <47979223+rustbot@users.noreply.github.com> Date: Mon, 7 Oct 2024 13:01:01 -0400 Subject: [PATCH 674/683] Update books --- src/doc/book | 2 +- src/doc/embedded-book | 2 +- src/doc/nomicon | 2 +- src/doc/reference | 2 +- src/doc/rust-by-example | 2 +- src/doc/rustc-dev-guide | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/doc/book b/src/doc/book index 99cf75a5414..f38ce8baef9 160000 --- a/src/doc/book +++ b/src/doc/book @@ -1 +1 @@ -Subproject commit 99cf75a5414fa8adbe3974bd0836661ca901708f +Subproject commit f38ce8baef98cb20229e56f1be2d50e345f11792 diff --git a/src/doc/embedded-book b/src/doc/embedded-book index dbae36bf3f8..f40a8b420ec 160000 --- a/src/doc/embedded-book +++ b/src/doc/embedded-book @@ -1 +1 @@ -Subproject commit dbae36bf3f8410aa4313b3bad42e374735d48a9d +Subproject commit f40a8b420ec4b4505d9489965e261f1d5c28ba23 diff --git a/src/doc/nomicon b/src/doc/nomicon index 14649f15d23..456b904f791 160000 --- a/src/doc/nomicon +++ b/src/doc/nomicon @@ -1 +1 @@ -Subproject commit 14649f15d232d509478206ee9ed5105641aa60d0 +Subproject commit 456b904f791751892b01282fd2757904993c4c26 diff --git a/src/doc/reference b/src/doc/reference index 24fb2687cdb..c64e52a3d30 160000 --- a/src/doc/reference +++ b/src/doc/reference @@ -1 +1 @@ -Subproject commit 24fb2687cdbc54fa18ae4acf5d879cfceca77b2c +Subproject commit c64e52a3d306eac0129f3ad6c6d8806ab99ae2e9 diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example index c79ec345f08..8bede1b919a 160000 --- a/src/doc/rust-by-example +++ b/src/doc/rust-by-example @@ -1 +1 @@ -Subproject commit c79ec345f08a1e94494cdc8c999709a90203fd88 +Subproject commit 8bede1b919a81ab7d0c961f6bbf68d3efa297bd2 diff --git a/src/doc/rustc-dev-guide b/src/doc/rustc-dev-guide index 555f3de2fa0..07bc9ca9eb1 160000 --- a/src/doc/rustc-dev-guide +++ b/src/doc/rustc-dev-guide @@ -1 +1 @@ -Subproject commit 555f3de2fa0d61c4294b74d245f1cbad6fcbf589 +Subproject commit 07bc9ca9eb1cd6d9fbbf758c2753b748804a134f From e23419fc97a8ca2fb3f6331115c13b2a5948d2c9 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Mon, 7 Oct 2024 10:30:27 -0700 Subject: [PATCH 675/683] rustdoc: improve ``-insertion for SCREAMING_CAMEL_CASE --- src/librustdoc/html/escape.rs | 2 +- src/librustdoc/html/escape/tests.rs | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/librustdoc/html/escape.rs b/src/librustdoc/html/escape.rs index 691f86847b5..72ad42c2bd0 100644 --- a/src/librustdoc/html/escape.rs +++ b/src/librustdoc/html/escape.rs @@ -108,7 +108,7 @@ impl<'a> fmt::Display for EscapeBodyTextWithWbr<'a> { || pk.map_or(true, |(_, t)| t.chars().any(|c| c.is_uppercase())); let next_is_underscore = || pk.map_or(true, |(_, t)| t.contains('_')); let next_is_colon = || pk.map_or(true, |(_, t)| t.contains(':')); - if i - last > 3 && is_uppercase() && !next_is_uppercase() { + if i - last > 3 && is_uppercase() && !next_is_uppercase() && !next_is_underscore() { EscapeBodyText(&text[last..i]).fmt(fmt)?; fmt.write_str("")?; last = i; diff --git a/src/librustdoc/html/escape/tests.rs b/src/librustdoc/html/escape/tests.rs index a09649e9e18..de702e16063 100644 --- a/src/librustdoc/html/escape/tests.rs +++ b/src/librustdoc/html/escape/tests.rs @@ -24,6 +24,10 @@ fn escape_body_text_with_wbr() { assert_eq!(&E("first:second").to_string(), "first:second"); assert_eq!(&E("first::second").to_string(), "first::second"); assert_eq!(&E("MY_CONSTANT").to_string(), "MY_CONSTANT"); + assert_eq!( + &E("_SIDD_MASKED_NEGATIVE_POLARITY").to_string(), + "_SIDD_MASKED_NEGATIVE_POLARITY" + ); // a string won't get wrapped if it's less than 8 bytes assert_eq!(&E("HashSet").to_string(), "HashSet"); // an individual word won't get wrapped if it's less than 4 bytes From f7eced3a21a3a0377b2a23ba6fb0f8a346e837f1 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Mon, 7 Oct 2024 13:27:50 -0700 Subject: [PATCH 676/683] Add comment to describe camelcase line break --- src/librustdoc/html/escape.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/librustdoc/html/escape.rs b/src/librustdoc/html/escape.rs index 72ad42c2bd0..31a2701f06a 100644 --- a/src/librustdoc/html/escape.rs +++ b/src/librustdoc/html/escape.rs @@ -108,6 +108,16 @@ impl<'a> fmt::Display for EscapeBodyTextWithWbr<'a> { || pk.map_or(true, |(_, t)| t.chars().any(|c| c.is_uppercase())); let next_is_underscore = || pk.map_or(true, |(_, t)| t.contains('_')); let next_is_colon = || pk.map_or(true, |(_, t)| t.contains(':')); + // Check for CamelCase. + // + // `i - last > 3` avoids turning FmRadio into FmRadio, which is technically + // correct, but needlessly bloated. + // + // is_uppercase && !next_is_uppercase checks for camelCase. HTTPSProxy, + // for example, should become HTTPSProxy. + // + // !next_is_underscore avoids turning TEST_RUN into TEST_RUN, which is also + // needlessly bloated. if i - last > 3 && is_uppercase() && !next_is_uppercase() && !next_is_underscore() { EscapeBodyText(&text[last..i]).fmt(fmt)?; fmt.write_str("")?; From 89b0f8a6891ce111ab256269dba1cfa09695b818 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Mon, 7 Oct 2024 14:36:49 -0700 Subject: [PATCH 677/683] Fix utf8-bom test The BOM was accidentally removed in https://github.com/rust-lang/rust/pull/57108 --- tests/ui/utf8-bom.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tests/ui/utf8-bom.rs b/tests/ui/utf8-bom.rs index e2e4ccd63c1..5b9e27fb7b9 100644 --- a/tests/ui/utf8-bom.rs +++ b/tests/ui/utf8-bom.rs @@ -1,6 +1,4 @@ +// This file has utf-8 BOM, it should be compiled normally without error. //@ run-pass -// - -// This file has utf-8 BOM, it should be compiled normally without error. pub fn main() {} From db6e31bba789a9afff3fdbf0633a0922bde6af6a 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?= Date: Mon, 7 Oct 2024 23:40:17 +0000 Subject: [PATCH 678/683] Remove myself from vacation --- triagebot.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/triagebot.toml b/triagebot.toml index 0172a80b3a5..d3e4af9b718 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -926,7 +926,6 @@ users_on_vacation = [ "jhpratt", "jyn514", "oli-obk", - "jieyouxu", ] [assign.adhoc_groups] From 911ac56e955f52c221660608b9389d8919cdb095 Mon Sep 17 00:00:00 2001 From: zhuyunxing Date: Wed, 19 Jun 2024 17:49:10 +0800 Subject: [PATCH 679/683] coverage. Disable supporting mcdc on llvm-18 --- compiler/rustc_codegen_llvm/src/builder.rs | 13 ++++++ .../llvm-wrapper/CoverageMappingWrapper.cpp | 45 ++++--------------- .../rustc_llvm/llvm-wrapper/RustWrapper.cpp | 14 +++--- tests/coverage/mcdc/condition-limit.coverage | 2 +- tests/coverage/mcdc/condition-limit.rs | 2 +- tests/coverage/mcdc/if.coverage | 2 +- tests/coverage/mcdc/if.rs | 2 +- .../mcdc/inlined_expressions.coverage | 2 +- tests/coverage/mcdc/inlined_expressions.rs | 2 +- tests/coverage/mcdc/nested_if.coverage | 2 +- tests/coverage/mcdc/nested_if.rs | 2 +- tests/coverage/mcdc/non_control_flow.coverage | 2 +- tests/coverage/mcdc/non_control_flow.rs | 2 +- 13 files changed, 38 insertions(+), 54 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index 4e0c62c8bf8..3abebdf6ca1 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -1683,6 +1683,11 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> { ) { debug!("mcdc_parameters() with args ({:?}, {:?}, {:?})", fn_name, hash, bitmap_bytes); + assert!( + crate::llvm_util::get_version() >= (19, 0, 0), + "MCDC intrinsics require LLVM 19 or later" + ); + let llfn = unsafe { llvm::LLVMRustGetInstrProfMCDCParametersIntrinsic(self.cx().llmod) }; let llty = self.cx.type_func( &[self.cx.type_ptr(), self.cx.type_i64(), self.cx.type_i32()], @@ -1716,6 +1721,10 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> { "mcdc_tvbitmap_update() with args ({:?}, {:?}, {:?}, {:?}, {:?})", fn_name, hash, bitmap_bytes, bitmap_index, mcdc_temp ); + assert!( + crate::llvm_util::get_version() >= (19, 0, 0), + "MCDC intrinsics require LLVM 19 or later" + ); let llfn = unsafe { llvm::LLVMRustGetInstrProfMCDCTVBitmapUpdateIntrinsic(self.cx().llmod) }; @@ -1757,6 +1766,10 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> { "mcdc_condbitmap_update() with args ({:?}, {:?}, {:?}, {:?}, {:?})", fn_name, hash, cond_loc, mcdc_temp, bool_value ); + assert!( + crate::llvm_util::get_version() >= (19, 0, 0), + "MCDC intrinsics require LLVM 19 or later" + ); let llfn = unsafe { llvm::LLVMRustGetInstrProfMCDCCondBitmapIntrinsic(self.cx().llmod) }; let llty = self.cx.type_func( &[ diff --git a/compiler/rustc_llvm/llvm-wrapper/CoverageMappingWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/CoverageMappingWrapper.cpp index 4532fd8d48d..8ee05977320 100644 --- a/compiler/rustc_llvm/llvm-wrapper/CoverageMappingWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/CoverageMappingWrapper.cpp @@ -88,38 +88,7 @@ struct LLVMRustMCDCParameters { LLVMRustMCDCBranchParameters BranchParameters; }; -// LLVM representations for `MCDCParameters` evolved from LLVM 18 to 19. -// Look at representations in 18 -// https://github.com/rust-lang/llvm-project/blob/66a2881a/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h#L253-L263 -// and representations in 19 -// https://github.com/llvm/llvm-project/blob/843cc474faefad1d639f4c44c1cf3ad7dbda76c8/llvm/include/llvm/ProfileData/Coverage/MCDCTypes.h -#if LLVM_VERSION_LT(19, 0) -static coverage::CounterMappingRegion::MCDCParameters -fromRust(LLVMRustMCDCParameters Params) { - auto parameter = coverage::CounterMappingRegion::MCDCParameters{}; - switch (Params.Tag) { - case LLVMRustMCDCParametersTag::None: - return parameter; - case LLVMRustMCDCParametersTag::Decision: - parameter.BitmapIdx = - static_cast(Params.DecisionParameters.BitmapIdx), - parameter.NumConditions = - static_cast(Params.DecisionParameters.NumConditions); - return parameter; - case LLVMRustMCDCParametersTag::Branch: - parameter.ID = static_cast( - Params.BranchParameters.ConditionID), - parameter.FalseID = - static_cast( - Params.BranchParameters.ConditionIDs[0]), - parameter.TrueID = - static_cast( - Params.BranchParameters.ConditionIDs[1]); - return parameter; - } - report_fatal_error("Bad LLVMRustMCDCParametersTag!"); -} -#else +#if LLVM_VERSION_GE(19, 0) static coverage::mcdc::Parameters fromRust(LLVMRustMCDCParameters Params) { switch (Params.Tag) { case LLVMRustMCDCParametersTag::None: @@ -214,13 +183,17 @@ extern "C" void LLVMRustCoverageWriteMappingToBuffer( RustMappingRegions, NumMappingRegions)) { MappingRegions.emplace_back( fromRust(Region.Count), fromRust(Region.FalseCount), -#if LLVM_VERSION_LT(19, 0) - // LLVM 19 may move this argument to last. - fromRust(Region.MCDCParameters), +#if LLVM_VERSION_GE(18, 0) && LLVM_VERSION_LT(19, 0) + coverage::CounterMappingRegion::MCDCParameters{}, #endif Region.FileID, Region.ExpandedFileID, // File IDs, then region info. Region.LineStart, Region.ColumnStart, Region.LineEnd, Region.ColumnEnd, - fromRust(Region.Kind)); + fromRust(Region.Kind) +#if LLVM_VERSION_GE(19, 0) + , + fromRust(Region.MCDCParameters) +#endif + ); } std::vector Expressions; diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index f9fc2bd6da3..8faa5212408 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -1539,23 +1539,21 @@ LLVMRustGetInstrProfIncrementIntrinsic(LLVMModuleRef M) { extern "C" LLVMValueRef LLVMRustGetInstrProfMCDCParametersIntrinsic(LLVMModuleRef M) { +#if LLVM_VERSION_GE(19, 0) return wrap(llvm::Intrinsic::getDeclaration( unwrap(M), llvm::Intrinsic::instrprof_mcdc_parameters)); +#else + report_fatal_error("LLVM 19.0 is required for mcdc intrinsic functions"); +#endif } extern "C" LLVMValueRef LLVMRustGetInstrProfMCDCTVBitmapUpdateIntrinsic(LLVMModuleRef M) { +#if LLVM_VERSION_GE(19, 0) return wrap(llvm::Intrinsic::getDeclaration( unwrap(M), llvm::Intrinsic::instrprof_mcdc_tvbitmap_update)); -} - -extern "C" LLVMValueRef -LLVMRustGetInstrProfMCDCCondBitmapIntrinsic(LLVMModuleRef M) { -#if LLVM_VERSION_LT(19, 0) - return wrap(llvm::Intrinsic::getDeclaration( - unwrap(M), llvm::Intrinsic::instrprof_mcdc_condbitmap_update)); #else - report_fatal_error("LLVM 18.0 is required for mcdc intrinsic functions"); + report_fatal_error("LLVM 19.0 is required for mcdc intrinsic functions"); #endif } diff --git a/tests/coverage/mcdc/condition-limit.coverage b/tests/coverage/mcdc/condition-limit.coverage index ae8596bb961..6330f2533d0 100644 --- a/tests/coverage/mcdc/condition-limit.coverage +++ b/tests/coverage/mcdc/condition-limit.coverage @@ -1,6 +1,6 @@ LL| |#![feature(coverage_attribute)] LL| |//@ edition: 2021 - LL| |//@ ignore-llvm-version: 19 - 99 + LL| |//@ min-llvm-version: 19 LL| |//@ compile-flags: -Zcoverage-options=mcdc LL| |//@ llvm-cov-flags: --show-branches=count --show-mcdc LL| | diff --git a/tests/coverage/mcdc/condition-limit.rs b/tests/coverage/mcdc/condition-limit.rs index 0d8546b01cd..2d6fd35ab57 100644 --- a/tests/coverage/mcdc/condition-limit.rs +++ b/tests/coverage/mcdc/condition-limit.rs @@ -1,6 +1,6 @@ #![feature(coverage_attribute)] //@ edition: 2021 -//@ ignore-llvm-version: 19 - 99 +//@ min-llvm-version: 19 //@ compile-flags: -Zcoverage-options=mcdc //@ llvm-cov-flags: --show-branches=count --show-mcdc diff --git a/tests/coverage/mcdc/if.coverage b/tests/coverage/mcdc/if.coverage index d71de28c6f6..d5cf590d96e 100644 --- a/tests/coverage/mcdc/if.coverage +++ b/tests/coverage/mcdc/if.coverage @@ -1,6 +1,6 @@ LL| |#![feature(coverage_attribute)] LL| |//@ edition: 2021 - LL| |//@ ignore-llvm-version: 19 - 99 + LL| |//@ min-llvm-version: 19 LL| |//@ compile-flags: -Zcoverage-options=mcdc LL| |//@ llvm-cov-flags: --show-branches=count --show-mcdc LL| | diff --git a/tests/coverage/mcdc/if.rs b/tests/coverage/mcdc/if.rs index 17247f5e0c1..6ade8d34d54 100644 --- a/tests/coverage/mcdc/if.rs +++ b/tests/coverage/mcdc/if.rs @@ -1,6 +1,6 @@ #![feature(coverage_attribute)] //@ edition: 2021 -//@ ignore-llvm-version: 19 - 99 +//@ min-llvm-version: 19 //@ compile-flags: -Zcoverage-options=mcdc //@ llvm-cov-flags: --show-branches=count --show-mcdc diff --git a/tests/coverage/mcdc/inlined_expressions.coverage b/tests/coverage/mcdc/inlined_expressions.coverage index af0b78477d4..57c655a2054 100644 --- a/tests/coverage/mcdc/inlined_expressions.coverage +++ b/tests/coverage/mcdc/inlined_expressions.coverage @@ -1,6 +1,6 @@ LL| |#![feature(coverage_attribute)] LL| |//@ edition: 2021 - LL| |//@ ignore-llvm-version: 19 - 99 + LL| |//@ min-llvm-version: 19 LL| |//@ compile-flags: -Zcoverage-options=mcdc -Copt-level=z -Cllvm-args=--inline-threshold=0 LL| |//@ llvm-cov-flags: --show-branches=count --show-mcdc LL| | diff --git a/tests/coverage/mcdc/inlined_expressions.rs b/tests/coverage/mcdc/inlined_expressions.rs index 5c1fde6681a..651e2fe8438 100644 --- a/tests/coverage/mcdc/inlined_expressions.rs +++ b/tests/coverage/mcdc/inlined_expressions.rs @@ -1,6 +1,6 @@ #![feature(coverage_attribute)] //@ edition: 2021 -//@ ignore-llvm-version: 19 - 99 +//@ min-llvm-version: 19 //@ compile-flags: -Zcoverage-options=mcdc -Copt-level=z -Cllvm-args=--inline-threshold=0 //@ llvm-cov-flags: --show-branches=count --show-mcdc diff --git a/tests/coverage/mcdc/nested_if.coverage b/tests/coverage/mcdc/nested_if.coverage index 37aa33d5c57..f14969dc8c9 100644 --- a/tests/coverage/mcdc/nested_if.coverage +++ b/tests/coverage/mcdc/nested_if.coverage @@ -1,6 +1,6 @@ LL| |#![feature(coverage_attribute)] LL| |//@ edition: 2021 - LL| |//@ ignore-llvm-version: 19 - 99 + LL| |//@ min-llvm-version: 19 LL| |//@ compile-flags: -Zcoverage-options=mcdc LL| |//@ llvm-cov-flags: --show-branches=count --show-mcdc LL| | diff --git a/tests/coverage/mcdc/nested_if.rs b/tests/coverage/mcdc/nested_if.rs index 1443ccc23ab..83f188ea47e 100644 --- a/tests/coverage/mcdc/nested_if.rs +++ b/tests/coverage/mcdc/nested_if.rs @@ -1,6 +1,6 @@ #![feature(coverage_attribute)] //@ edition: 2021 -//@ ignore-llvm-version: 19 - 99 +//@ min-llvm-version: 19 //@ compile-flags: -Zcoverage-options=mcdc //@ llvm-cov-flags: --show-branches=count --show-mcdc diff --git a/tests/coverage/mcdc/non_control_flow.coverage b/tests/coverage/mcdc/non_control_flow.coverage index 74c19cf12df..570f565de74 100644 --- a/tests/coverage/mcdc/non_control_flow.coverage +++ b/tests/coverage/mcdc/non_control_flow.coverage @@ -1,6 +1,6 @@ LL| |#![feature(coverage_attribute)] LL| |//@ edition: 2021 - LL| |//@ ignore-llvm-version: 19 - 99 + LL| |//@ min-llvm-version: 19 LL| |//@ compile-flags: -Zcoverage-options=mcdc LL| |//@ llvm-cov-flags: --show-branches=count --show-mcdc LL| | diff --git a/tests/coverage/mcdc/non_control_flow.rs b/tests/coverage/mcdc/non_control_flow.rs index e0145ed8268..6cfce6fae93 100644 --- a/tests/coverage/mcdc/non_control_flow.rs +++ b/tests/coverage/mcdc/non_control_flow.rs @@ -1,6 +1,6 @@ #![feature(coverage_attribute)] //@ edition: 2021 -//@ ignore-llvm-version: 19 - 99 +//@ min-llvm-version: 19 //@ compile-flags: -Zcoverage-options=mcdc //@ llvm-cov-flags: --show-branches=count --show-mcdc From 99bd601df5f65331b4751217eb533abeca7914cb Mon Sep 17 00:00:00 2001 From: zhuyunxing Date: Thu, 25 Jul 2024 14:26:36 +0800 Subject: [PATCH 680/683] coverage. MCDC ConditionId start from 0 to keep with llvm 19 --- .../src/coverageinfo/ffi.rs | 13 +++++---- compiler/rustc_middle/src/mir/coverage.rs | 16 ++-------- .../src/build/coverageinfo/mcdc.rs | 29 +++++++++++-------- 3 files changed, 27 insertions(+), 31 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs index 77821ca89bc..90f7dd733ca 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs @@ -111,7 +111,7 @@ enum RegionKind { } mod mcdc { - use rustc_middle::mir::coverage::{ConditionInfo, DecisionInfo}; + use rustc_middle::mir::coverage::{ConditionId, ConditionInfo, DecisionInfo}; /// Must match the layout of `LLVMRustMCDCDecisionParameters`. #[repr(C)] @@ -167,12 +167,13 @@ mod mcdc { impl From for BranchParameters { fn from(value: ConditionInfo) -> Self { + let to_llvm_cond_id = |cond_id: Option| { + cond_id.and_then(|id| LLVMConditionId::try_from(id.as_usize()).ok()).unwrap_or(-1) + }; + let ConditionInfo { condition_id, true_next_id, false_next_id } = value; Self { - condition_id: value.condition_id.as_u32() as LLVMConditionId, - condition_ids: [ - value.false_next_id.as_u32() as LLVMConditionId, - value.true_next_id.as_u32() as LLVMConditionId, - ], + condition_id: to_llvm_cond_id(Some(condition_id)), + condition_ids: [to_llvm_cond_id(false_next_id), to_llvm_cond_id(true_next_id)], } } } diff --git a/compiler/rustc_middle/src/mir/coverage.rs b/compiler/rustc_middle/src/mir/coverage.rs index bfe2a2c2cb3..9a0f5a65321 100644 --- a/compiler/rustc_middle/src/mir/coverage.rs +++ b/compiler/rustc_middle/src/mir/coverage.rs @@ -67,7 +67,7 @@ rustc_index::newtype_index! { } impl ConditionId { - pub const NONE: Self = Self::from_u32(0); + pub const START: Self = Self::from_usize(0); } /// Enum that can hold a constant zero value, the ID of an physical coverage @@ -291,18 +291,8 @@ pub struct BranchSpan { #[derive(TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable, TypeVisitable)] pub struct ConditionInfo { pub condition_id: ConditionId, - pub true_next_id: ConditionId, - pub false_next_id: ConditionId, -} - -impl Default for ConditionInfo { - fn default() -> Self { - Self { - condition_id: ConditionId::NONE, - true_next_id: ConditionId::NONE, - false_next_id: ConditionId::NONE, - } - } + pub true_next_id: Option, + pub false_next_id: Option, } #[derive(Clone, Debug)] diff --git a/compiler/rustc_mir_build/src/build/coverageinfo/mcdc.rs b/compiler/rustc_mir_build/src/build/coverageinfo/mcdc.rs index 6019a93e787..5c45a7a33a2 100644 --- a/compiler/rustc_mir_build/src/build/coverageinfo/mcdc.rs +++ b/compiler/rustc_mir_build/src/build/coverageinfo/mcdc.rs @@ -106,22 +106,27 @@ impl MCDCState { }), }; - let parent_condition = decision_ctx.decision_stack.pop_back().unwrap_or_default(); - let lhs_id = if parent_condition.condition_id == ConditionId::NONE { + let parent_condition = decision_ctx.decision_stack.pop_back().unwrap_or_else(|| { + assert_eq!( + decision.num_conditions, 0, + "decision stack must be empty only for empty decision" + ); decision.num_conditions += 1; - ConditionId::from(decision.num_conditions) - } else { - parent_condition.condition_id - }; + ConditionInfo { + condition_id: ConditionId::START, + true_next_id: None, + false_next_id: None, + } + }); + let lhs_id = parent_condition.condition_id; - decision.num_conditions += 1; let rhs_condition_id = ConditionId::from(decision.num_conditions); - + decision.num_conditions += 1; let (lhs, rhs) = match op { LogicalOp::And => { let lhs = ConditionInfo { condition_id: lhs_id, - true_next_id: rhs_condition_id, + true_next_id: Some(rhs_condition_id), false_next_id: parent_condition.false_next_id, }; let rhs = ConditionInfo { @@ -135,7 +140,7 @@ impl MCDCState { let lhs = ConditionInfo { condition_id: lhs_id, true_next_id: parent_condition.true_next_id, - false_next_id: rhs_condition_id, + false_next_id: Some(rhs_condition_id), }; let rhs = ConditionInfo { condition_id: rhs_condition_id, @@ -164,10 +169,10 @@ impl MCDCState { let Some(decision) = decision_ctx.processing_decision.as_mut() else { bug!("Processing decision should have been created before any conditions are taken"); }; - if condition_info.true_next_id == ConditionId::NONE { + if condition_info.true_next_id.is_none() { decision.end_markers.push(true_marker); } - if condition_info.false_next_id == ConditionId::NONE { + if condition_info.false_next_id.is_none() { decision.end_markers.push(false_marker); } From 6e3e19f714d0ff938c24901195f2c1be6e6e7f6f Mon Sep 17 00:00:00 2001 From: zhuyunxing Date: Thu, 25 Jul 2024 15:23:35 +0800 Subject: [PATCH 681/683] coverage. Adapt to mcdc mapping formats introduced by llvm 19 --- compiler/rustc_codegen_llvm/src/builder.rs | 63 +---- .../src/coverageinfo/mod.rs | 29 +-- compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 1 - compiler/rustc_middle/src/mir/coverage.rs | 29 +-- compiler/rustc_middle/src/mir/pretty.rs | 32 ++- .../rustc_mir_build/src/build/coverageinfo.rs | 6 +- .../src/build/coverageinfo/mcdc.rs | 88 ++++--- .../src/coverage/mappings.rs | 229 +++++++++++++----- .../rustc_mir_transform/src/coverage/mod.rs | 154 ++++++++---- tests/coverage/mcdc/condition-limit.cov-map | 96 +------- tests/coverage/mcdc/condition-limit.coverage | 68 ++---- tests/coverage/mcdc/condition-limit.rs | 22 +- tests/coverage/mcdc/if.cov-map | 30 +-- tests/coverage/mcdc/if.coverage | 16 +- tests/coverage/mcdc/if.rs | 2 +- .../coverage/mcdc/inlined_expressions.cov-map | 4 +- tests/coverage/mcdc/nested_if.cov-map | 26 +- tests/coverage/mcdc/nested_if.coverage | 24 +- tests/coverage/mcdc/non_control_flow.cov-map | 24 +- tests/coverage/mcdc/non_control_flow.coverage | 8 +- .../mcdc-condition-limit.bad.stderr | 8 - .../mcdc-condition-limit.rs | 16 +- 22 files changed, 490 insertions(+), 485 deletions(-) delete mode 100644 tests/ui/instrument-coverage/mcdc-condition-limit.bad.stderr diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index 3abebdf6ca1..30d7ba4421b 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -1679,9 +1679,9 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> { &mut self, fn_name: &'ll Value, hash: &'ll Value, - bitmap_bytes: &'ll Value, + bitmap_bits: &'ll Value, ) { - debug!("mcdc_parameters() with args ({:?}, {:?}, {:?})", fn_name, hash, bitmap_bytes); + debug!("mcdc_parameters() with args ({:?}, {:?}, {:?})", fn_name, hash, bitmap_bits); assert!( crate::llvm_util::get_version() >= (19, 0, 0), @@ -1693,7 +1693,7 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> { &[self.cx.type_ptr(), self.cx.type_i64(), self.cx.type_i32()], self.cx.type_void(), ); - let args = &[fn_name, hash, bitmap_bytes]; + let args = &[fn_name, hash, bitmap_bits]; let args = self.check_call("call", llty, llfn, args); unsafe { @@ -1713,13 +1713,12 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> { &mut self, fn_name: &'ll Value, hash: &'ll Value, - bitmap_bytes: &'ll Value, bitmap_index: &'ll Value, mcdc_temp: &'ll Value, ) { debug!( - "mcdc_tvbitmap_update() with args ({:?}, {:?}, {:?}, {:?}, {:?})", - fn_name, hash, bitmap_bytes, bitmap_index, mcdc_temp + "mcdc_tvbitmap_update() with args ({:?}, {:?}, {:?}, {:?})", + fn_name, hash, bitmap_index, mcdc_temp ); assert!( crate::llvm_util::get_version() >= (19, 0, 0), @@ -1729,16 +1728,10 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> { let llfn = unsafe { llvm::LLVMRustGetInstrProfMCDCTVBitmapUpdateIntrinsic(self.cx().llmod) }; let llty = self.cx.type_func( - &[ - self.cx.type_ptr(), - self.cx.type_i64(), - self.cx.type_i32(), - self.cx.type_i32(), - self.cx.type_ptr(), - ], + &[self.cx.type_ptr(), self.cx.type_i64(), self.cx.type_i32(), self.cx.type_ptr()], self.cx.type_void(), ); - let args = &[fn_name, hash, bitmap_bytes, bitmap_index, mcdc_temp]; + let args = &[fn_name, hash, bitmap_index, mcdc_temp]; let args = self.check_call("call", llty, llfn, args); unsafe { let _ = llvm::LLVMRustBuildCall( @@ -1754,45 +1747,15 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> { self.store(self.const_i32(0), mcdc_temp, self.tcx.data_layout.i32_align.abi); } - pub(crate) fn mcdc_condbitmap_update( - &mut self, - fn_name: &'ll Value, - hash: &'ll Value, - cond_loc: &'ll Value, - mcdc_temp: &'ll Value, - bool_value: &'ll Value, - ) { - debug!( - "mcdc_condbitmap_update() with args ({:?}, {:?}, {:?}, {:?}, {:?})", - fn_name, hash, cond_loc, mcdc_temp, bool_value - ); + pub(crate) fn mcdc_condbitmap_update(&mut self, cond_index: &'ll Value, mcdc_temp: &'ll Value) { + debug!("mcdc_condbitmap_update() with args ({:?}, {:?})", cond_index, mcdc_temp); assert!( crate::llvm_util::get_version() >= (19, 0, 0), "MCDC intrinsics require LLVM 19 or later" ); - let llfn = unsafe { llvm::LLVMRustGetInstrProfMCDCCondBitmapIntrinsic(self.cx().llmod) }; - let llty = self.cx.type_func( - &[ - self.cx.type_ptr(), - self.cx.type_i64(), - self.cx.type_i32(), - self.cx.type_ptr(), - self.cx.type_i1(), - ], - self.cx.type_void(), - ); - let args = &[fn_name, hash, cond_loc, mcdc_temp, bool_value]; - self.check_call("call", llty, llfn, args); - unsafe { - let _ = llvm::LLVMRustBuildCall( - self.llbuilder, - llty, - llfn, - args.as_ptr() as *const &llvm::Value, - args.len() as c_uint, - [].as_ptr(), - 0 as c_uint, - ); - } + let align = self.tcx.data_layout.i32_align.abi; + let current_tv_index = self.load(self.cx.type_i32(), mcdc_temp, align); + let new_tv_index = self.add(current_tv_index, cond_index); + self.store(new_tv_index, mcdc_temp, align); } } diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs index 3a80d216f47..d7d29eebf85 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs @@ -98,14 +98,14 @@ impl<'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> { }; // If there are no MC/DC bitmaps to set up, return immediately. - if function_coverage_info.mcdc_bitmap_bytes == 0 { + if function_coverage_info.mcdc_bitmap_bits == 0 { return; } let fn_name = self.get_pgo_func_name_var(instance); let hash = self.const_u64(function_coverage_info.function_source_hash); - let bitmap_bytes = self.const_u32(function_coverage_info.mcdc_bitmap_bytes); - self.mcdc_parameters(fn_name, hash, bitmap_bytes); + let bitmap_bits = self.const_u32(function_coverage_info.mcdc_bitmap_bits as u32); + self.mcdc_parameters(fn_name, hash, bitmap_bits); // Create pointers named `mcdc.addr.{i}` to stack-allocated condition bitmaps. let mut cond_bitmaps = vec![]; @@ -185,35 +185,28 @@ impl<'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> { CoverageKind::ExpressionUsed { id } => { func_coverage.mark_expression_id_seen(id); } - CoverageKind::CondBitmapUpdate { id, value, decision_depth } => { + CoverageKind::CondBitmapUpdate { index, decision_depth } => { drop(coverage_map); - assert_ne!( - id.as_u32(), - 0, - "ConditionId of evaluated conditions should never be zero" - ); let cond_bitmap = coverage_context .try_get_mcdc_condition_bitmap(&instance, decision_depth) .expect("mcdc cond bitmap should have been allocated for updating"); - let cond_loc = bx.const_i32(id.as_u32() as i32 - 1); - let bool_value = bx.const_bool(value); - let fn_name = bx.get_pgo_func_name_var(instance); - let hash = bx.const_u64(function_coverage_info.function_source_hash); - bx.mcdc_condbitmap_update(fn_name, hash, cond_loc, cond_bitmap, bool_value); + let cond_index = bx.const_i32(index as i32); + bx.mcdc_condbitmap_update(cond_index, cond_bitmap); } CoverageKind::TestVectorBitmapUpdate { bitmap_idx, decision_depth } => { drop(coverage_map); let cond_bitmap = coverage_context .try_get_mcdc_condition_bitmap(&instance, decision_depth) .expect("mcdc cond bitmap should have been allocated for merging into the global bitmap"); - let bitmap_bytes = function_coverage_info.mcdc_bitmap_bytes; - assert!(bitmap_idx < bitmap_bytes, "bitmap index of the decision out of range"); + assert!( + bitmap_idx as usize <= function_coverage_info.mcdc_bitmap_bits, + "bitmap index of the decision out of range" + ); let fn_name = bx.get_pgo_func_name_var(instance); let hash = bx.const_u64(function_coverage_info.function_source_hash); - let bitmap_bytes = bx.const_u32(bitmap_bytes); let bitmap_index = bx.const_u32(bitmap_idx); - bx.mcdc_tvbitmap_update(fn_name, hash, bitmap_bytes, bitmap_index, cond_bitmap); + bx.mcdc_tvbitmap_update(fn_name, hash, bitmap_index, cond_bitmap); } } } diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index d3950df91fb..661debbb9f1 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -1614,7 +1614,6 @@ unsafe extern "C" { pub fn LLVMRustGetInstrProfIncrementIntrinsic(M: &Module) -> &Value; pub fn LLVMRustGetInstrProfMCDCParametersIntrinsic(M: &Module) -> &Value; pub fn LLVMRustGetInstrProfMCDCTVBitmapUpdateIntrinsic(M: &Module) -> &Value; - pub fn LLVMRustGetInstrProfMCDCCondBitmapIntrinsic(M: &Module) -> &Value; pub fn LLVMRustBuildCall<'a>( B: &Builder<'a>, diff --git a/compiler/rustc_middle/src/mir/coverage.rs b/compiler/rustc_middle/src/mir/coverage.rs index 9a0f5a65321..4a876dc1228 100644 --- a/compiler/rustc_middle/src/mir/coverage.rs +++ b/compiler/rustc_middle/src/mir/coverage.rs @@ -128,8 +128,8 @@ pub enum CoverageKind { /// Marks the point in MIR control flow represented by a evaluated condition. /// - /// This is eventually lowered to `llvm.instrprof.mcdc.condbitmap.update` in LLVM IR. - CondBitmapUpdate { id: ConditionId, value: bool, decision_depth: u16 }, + /// This is eventually lowered to instruments updating mcdc temp variables. + CondBitmapUpdate { index: u32, decision_depth: u16 }, /// Marks the point in MIR control flow represented by a evaluated decision. /// @@ -145,14 +145,8 @@ impl Debug for CoverageKind { BlockMarker { id } => write!(fmt, "BlockMarker({:?})", id.index()), CounterIncrement { id } => write!(fmt, "CounterIncrement({:?})", id.index()), ExpressionUsed { id } => write!(fmt, "ExpressionUsed({:?})", id.index()), - CondBitmapUpdate { id, value, decision_depth } => { - write!( - fmt, - "CondBitmapUpdate({:?}, {:?}, depth={:?})", - id.index(), - value, - decision_depth - ) + CondBitmapUpdate { index, decision_depth } => { + write!(fmt, "CondBitmapUpdate(index={:?}, depth={:?})", index, decision_depth) } TestVectorBitmapUpdate { bitmap_idx, decision_depth } => { write!(fmt, "TestVectorUpdate({:?}, depth={:?})", bitmap_idx, decision_depth) @@ -253,7 +247,7 @@ pub struct Mapping { pub struct FunctionCoverageInfo { pub function_source_hash: u64, pub num_counters: usize, - pub mcdc_bitmap_bytes: u32, + pub mcdc_bitmap_bits: usize, pub expressions: IndexVec, pub mappings: Vec, /// The depth of the deepest decision is used to know how many @@ -275,8 +269,10 @@ pub struct CoverageInfoHi { /// data structures without having to scan the entire body first. pub num_block_markers: usize, pub branch_spans: Vec, - pub mcdc_branch_spans: Vec, - pub mcdc_decision_spans: Vec, + /// Branch spans generated by mcdc. Because of some limits mcdc builder give up generating + /// decisions including them so that they are handled as normal branch spans. + pub mcdc_degraded_branch_spans: Vec, + pub mcdc_spans: Vec<(MCDCDecisionSpan, Vec)>, } #[derive(Clone, Debug)] @@ -299,12 +295,9 @@ pub struct ConditionInfo { #[derive(TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable, TypeVisitable)] pub struct MCDCBranchSpan { pub span: Span, - /// If `None`, this actually represents a normal branch span inserted for - /// code that was too complex for MC/DC. - pub condition_info: Option, + pub condition_info: ConditionInfo, pub true_marker: BlockMarkerId, pub false_marker: BlockMarkerId, - pub decision_depth: u16, } #[derive(Copy, Clone, Debug)] @@ -318,7 +311,7 @@ pub struct DecisionInfo { #[derive(TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable, TypeVisitable)] pub struct MCDCDecisionSpan { pub span: Span, - pub num_conditions: usize, pub end_markers: Vec, pub decision_depth: u16, + pub num_conditions: usize, } diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index 9cafe804a8e..2a3a070a6e7 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -538,8 +538,8 @@ fn write_coverage_info_hi( let coverage::CoverageInfoHi { num_block_markers: _, branch_spans, - mcdc_branch_spans, - mcdc_decision_spans, + mcdc_degraded_branch_spans, + mcdc_spans, } = coverage_info_hi; // Only add an extra trailing newline if we printed at least one thing. @@ -553,29 +553,35 @@ fn write_coverage_info_hi( did_print = true; } - for coverage::MCDCBranchSpan { - span, - condition_info, - true_marker, - false_marker, - decision_depth, - } in mcdc_branch_spans + for coverage::MCDCBranchSpan { span, true_marker, false_marker, .. } in + mcdc_degraded_branch_spans { writeln!( w, - "{INDENT}coverage mcdc branch {{ condition_id: {:?}, true: {true_marker:?}, false: {false_marker:?}, depth: {decision_depth:?} }} => {span:?}", - condition_info.map(|info| info.condition_id) + "{INDENT}coverage branch {{ true: {true_marker:?}, false: {false_marker:?} }} => {span:?}", )?; did_print = true; } - for coverage::MCDCDecisionSpan { span, num_conditions, end_markers, decision_depth } in - mcdc_decision_spans + for ( + coverage::MCDCDecisionSpan { span, end_markers, decision_depth, num_conditions: _ }, + conditions, + ) in mcdc_spans { + let num_conditions = conditions.len(); writeln!( w, "{INDENT}coverage mcdc decision {{ num_conditions: {num_conditions:?}, end: {end_markers:?}, depth: {decision_depth:?} }} => {span:?}" )?; + for coverage::MCDCBranchSpan { span, condition_info, true_marker, false_marker } in + conditions + { + writeln!( + w, + "{INDENT}coverage mcdc branch {{ condition_id: {:?}, true: {true_marker:?}, false: {false_marker:?} }} => {span:?}", + condition_info.condition_id + )?; + } did_print = true; } diff --git a/compiler/rustc_mir_build/src/build/coverageinfo.rs b/compiler/rustc_mir_build/src/build/coverageinfo.rs index 204ee45bfa2..52a4a4b4b51 100644 --- a/compiler/rustc_mir_build/src/build/coverageinfo.rs +++ b/compiler/rustc_mir_build/src/build/coverageinfo.rs @@ -175,7 +175,7 @@ impl CoverageInfoBuilder { let branch_spans = branch_info.map(|branch_info| branch_info.branch_spans).unwrap_or_default(); - let (mcdc_decision_spans, mcdc_branch_spans) = + let (mcdc_spans, mcdc_degraded_branch_spans) = mcdc_info.map(MCDCInfoBuilder::into_done).unwrap_or_default(); // For simplicity, always return an info struct (without Option), even @@ -183,8 +183,8 @@ impl CoverageInfoBuilder { Box::new(CoverageInfoHi { num_block_markers, branch_spans, - mcdc_branch_spans, - mcdc_decision_spans, + mcdc_degraded_branch_spans, + mcdc_spans, }) } } diff --git a/compiler/rustc_mir_build/src/build/coverageinfo/mcdc.rs b/compiler/rustc_mir_build/src/build/coverageinfo/mcdc.rs index 5c45a7a33a2..343d4000043 100644 --- a/compiler/rustc_mir_build/src/build/coverageinfo/mcdc.rs +++ b/compiler/rustc_mir_build/src/build/coverageinfo/mcdc.rs @@ -12,16 +12,16 @@ use rustc_span::Span; use crate::build::Builder; use crate::errors::MCDCExceedsConditionLimit; -/// The MCDC bitmap scales exponentially (2^n) based on the number of conditions seen, -/// So llvm sets a maximum value prevents the bitmap footprint from growing too large without the user's knowledge. -/// This limit may be relaxed if the [upstream change](https://github.com/llvm/llvm-project/pull/82448) is merged. -const MAX_CONDITIONS_IN_DECISION: usize = 6; +/// LLVM uses `i16` to represent condition id. Hence `i16::MAX` is the hard limit for number of +/// conditions in a decision. +const MAX_CONDITIONS_IN_DECISION: usize = i16::MAX as usize; #[derive(Default)] struct MCDCDecisionCtx { /// To construct condition evaluation tree. decision_stack: VecDeque, processing_decision: Option, + conditions: Vec, } struct MCDCState { @@ -155,16 +155,29 @@ impl MCDCState { decision_ctx.decision_stack.push_back(lhs); } - fn take_condition( + fn try_finish_decision( &mut self, + span: Span, true_marker: BlockMarkerId, false_marker: BlockMarkerId, - ) -> (Option, Option) { + degraded_branches: &mut Vec, + ) -> Option<(MCDCDecisionSpan, Vec)> { let Some(decision_ctx) = self.decision_ctx_stack.last_mut() else { bug!("Unexpected empty decision_ctx_stack") }; let Some(condition_info) = decision_ctx.decision_stack.pop_back() else { - return (None, None); + let branch = MCDCBranchSpan { + span, + condition_info: ConditionInfo { + condition_id: ConditionId::START, + true_next_id: None, + false_next_id: None, + }, + true_marker, + false_marker, + }; + degraded_branches.push(branch); + return None; }; let Some(decision) = decision_ctx.processing_decision.as_mut() else { bug!("Processing decision should have been created before any conditions are taken"); @@ -175,24 +188,31 @@ impl MCDCState { if condition_info.false_next_id.is_none() { decision.end_markers.push(false_marker); } + decision_ctx.conditions.push(MCDCBranchSpan { + span, + condition_info, + true_marker, + false_marker, + }); if decision_ctx.decision_stack.is_empty() { - (Some(condition_info), decision_ctx.processing_decision.take()) + let conditions = std::mem::take(&mut decision_ctx.conditions); + decision_ctx.processing_decision.take().map(|decision| (decision, conditions)) } else { - (Some(condition_info), None) + None } } } pub(crate) struct MCDCInfoBuilder { - branch_spans: Vec, - decision_spans: Vec, + degraded_spans: Vec, + mcdc_spans: Vec<(MCDCDecisionSpan, Vec)>, state: MCDCState, } impl MCDCInfoBuilder { pub(crate) fn new() -> Self { - Self { branch_spans: vec![], decision_spans: vec![], state: MCDCState::new() } + Self { degraded_spans: vec![], mcdc_spans: vec![], state: MCDCState::new() } } pub(crate) fn visit_evaluated_condition( @@ -206,50 +226,44 @@ impl MCDCInfoBuilder { let true_marker = inject_block_marker(source_info, true_block); let false_marker = inject_block_marker(source_info, false_block); - let decision_depth = self.state.decision_depth(); - let (mut condition_info, decision_result) = - self.state.take_condition(true_marker, false_marker); // take_condition() returns Some for decision_result when the decision stack // is empty, i.e. when all the conditions of the decision were instrumented, // and the decision is "complete". - if let Some(decision) = decision_result { - match decision.num_conditions { + if let Some((decision, conditions)) = self.state.try_finish_decision( + source_info.span, + true_marker, + false_marker, + &mut self.degraded_spans, + ) { + let num_conditions = conditions.len(); + assert_eq!( + num_conditions, decision.num_conditions, + "final number of conditions is not correct" + ); + match num_conditions { 0 => { unreachable!("Decision with no condition is not expected"); } 1..=MAX_CONDITIONS_IN_DECISION => { - self.decision_spans.push(decision); + self.mcdc_spans.push((decision, conditions)); } _ => { - // Do not generate mcdc mappings and statements for decisions with too many conditions. - // Therefore, first erase the condition info of the (N-1) previous branch spans. - let rebase_idx = self.branch_spans.len() - (decision.num_conditions - 1); - for branch in &mut self.branch_spans[rebase_idx..] { - branch.condition_info = None; - } - - // Then, erase this last branch span's info too, for a total of N. - condition_info = None; + self.degraded_spans.extend(conditions); tcx.dcx().emit_warn(MCDCExceedsConditionLimit { span: decision.span, - num_conditions: decision.num_conditions, + num_conditions, max_conditions: MAX_CONDITIONS_IN_DECISION, }); } } } - self.branch_spans.push(MCDCBranchSpan { - span: source_info.span, - condition_info, - true_marker, - false_marker, - decision_depth, - }); } - pub(crate) fn into_done(self) -> (Vec, Vec) { - (self.decision_spans, self.branch_spans) + pub(crate) fn into_done( + self, + ) -> (Vec<(MCDCDecisionSpan, Vec)>, Vec) { + (self.mcdc_spans, self.degraded_spans) } } diff --git a/compiler/rustc_mir_transform/src/coverage/mappings.rs b/compiler/rustc_mir_transform/src/coverage/mappings.rs index ec5ba354805..c20f7a6f326 100644 --- a/compiler/rustc_mir_transform/src/coverage/mappings.rs +++ b/compiler/rustc_mir_transform/src/coverage/mappings.rs @@ -1,10 +1,11 @@ use std::collections::BTreeSet; +use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::graph::DirectedGraph; use rustc_index::IndexVec; use rustc_index::bit_set::BitSet; use rustc_middle::mir::coverage::{ - BlockMarkerId, BranchSpan, ConditionInfo, CoverageInfoHi, CoverageKind, + BlockMarkerId, BranchSpan, ConditionId, ConditionInfo, CoverageInfoHi, CoverageKind, }; use rustc_middle::mir::{self, BasicBlock, StatementKind}; use rustc_middle::ty::TyCtxt; @@ -38,10 +39,11 @@ pub(super) struct MCDCBranch { pub(super) span: Span, pub(super) true_bcb: BasicCoverageBlock, pub(super) false_bcb: BasicCoverageBlock, - /// If `None`, this actually represents a normal branch mapping inserted - /// for code that was too complex for MC/DC. - pub(super) condition_info: Option, - pub(super) decision_depth: u16, + pub(super) condition_info: ConditionInfo, + // Offset added to test vector idx if this branch is evaluated to true. + pub(super) true_index: usize, + // Offset added to test vector idx if this branch is evaluated to false. + pub(super) false_index: usize, } /// Associates an MC/DC decision with its join BCBs. @@ -49,11 +51,15 @@ pub(super) struct MCDCBranch { pub(super) struct MCDCDecision { pub(super) span: Span, pub(super) end_bcbs: BTreeSet, - pub(super) bitmap_idx: u32, - pub(super) num_conditions: u16, + pub(super) bitmap_idx: usize, + pub(super) num_test_vectors: usize, pub(super) decision_depth: u16, } +// LLVM uses `i32` to index the bitmap. Thus `i32::MAX` is the hard limit for number of all test vectors +// in a function. +const MCDC_MAX_BITMAP_SIZE: usize = i32::MAX as usize; + #[derive(Default)] pub(super) struct ExtractedMappings { /// Store our own copy of [`CoverageGraph::num_nodes`], so that we don't @@ -62,9 +68,9 @@ pub(super) struct ExtractedMappings { pub(super) num_bcbs: usize, pub(super) code_mappings: Vec, pub(super) branch_pairs: Vec, - pub(super) mcdc_bitmap_bytes: u32, - pub(super) mcdc_branches: Vec, - pub(super) mcdc_decisions: Vec, + pub(super) mcdc_bitmap_bits: usize, + pub(super) mcdc_degraded_branches: Vec, + pub(super) mcdc_mappings: Vec<(MCDCDecision, Vec)>, } /// Extracts coverage-relevant spans from MIR, and associates them with @@ -77,9 +83,9 @@ pub(super) fn extract_all_mapping_info_from_mir<'tcx>( ) -> ExtractedMappings { let mut code_mappings = vec![]; let mut branch_pairs = vec![]; - let mut mcdc_bitmap_bytes = 0; - let mut mcdc_branches = vec![]; - let mut mcdc_decisions = vec![]; + let mut mcdc_bitmap_bits = 0; + let mut mcdc_degraded_branches = vec![]; + let mut mcdc_mappings = vec![]; if hir_info.is_async_fn || tcx.sess.coverage_no_mir_spans() { // An async function desugars into a function that returns a future, @@ -104,18 +110,18 @@ pub(super) fn extract_all_mapping_info_from_mir<'tcx>( mir_body, hir_info.body_span, basic_coverage_blocks, - &mut mcdc_bitmap_bytes, - &mut mcdc_branches, - &mut mcdc_decisions, + &mut mcdc_bitmap_bits, + &mut mcdc_degraded_branches, + &mut mcdc_mappings, ); ExtractedMappings { num_bcbs: basic_coverage_blocks.num_nodes(), code_mappings, branch_pairs, - mcdc_bitmap_bytes, - mcdc_branches, - mcdc_decisions, + mcdc_bitmap_bits, + mcdc_degraded_branches, + mcdc_mappings, } } @@ -126,9 +132,9 @@ impl ExtractedMappings { num_bcbs, code_mappings, branch_pairs, - mcdc_bitmap_bytes: _, - mcdc_branches, - mcdc_decisions, + mcdc_bitmap_bits: _, + mcdc_degraded_branches, + mcdc_mappings, } = self; // Identify which BCBs have one or more mappings. @@ -144,7 +150,10 @@ impl ExtractedMappings { insert(true_bcb); insert(false_bcb); } - for &MCDCBranch { true_bcb, false_bcb, .. } in mcdc_branches { + for &MCDCBranch { true_bcb, false_bcb, .. } in mcdc_degraded_branches + .iter() + .chain(mcdc_mappings.iter().map(|(_, branches)| branches.into_iter()).flatten()) + { insert(true_bcb); insert(false_bcb); } @@ -152,8 +161,8 @@ impl ExtractedMappings { // MC/DC decisions refer to BCBs, but don't require those BCBs to have counters. if bcbs_with_counter_mappings.is_empty() { debug_assert!( - mcdc_decisions.is_empty(), - "A function with no counter mappings shouldn't have any decisions: {mcdc_decisions:?}", + mcdc_mappings.is_empty(), + "A function with no counter mappings shouldn't have any decisions: {mcdc_mappings:?}", ); } @@ -232,9 +241,9 @@ pub(super) fn extract_mcdc_mappings( mir_body: &mir::Body<'_>, body_span: Span, basic_coverage_blocks: &CoverageGraph, - mcdc_bitmap_bytes: &mut u32, - mcdc_branches: &mut impl Extend, - mcdc_decisions: &mut impl Extend, + mcdc_bitmap_bits: &mut usize, + mcdc_degraded_branches: &mut impl Extend, + mcdc_mappings: &mut impl Extend<(MCDCDecision, Vec)>, ) { let Some(coverage_info_hi) = mir_body.coverage_info_hi.as_deref() else { return }; @@ -257,43 +266,143 @@ pub(super) fn extract_mcdc_mappings( Some((span, true_bcb, false_bcb)) }; - mcdc_branches.extend(coverage_info_hi.mcdc_branch_spans.iter().filter_map( - |&mir::coverage::MCDCBranchSpan { - span: raw_span, - condition_info, - true_marker, - false_marker, - decision_depth, - }| { - let (span, true_bcb, false_bcb) = - check_branch_bcb(raw_span, true_marker, false_marker)?; - Some(MCDCBranch { span, true_bcb, false_bcb, condition_info, decision_depth }) - }, - )); + let to_mcdc_branch = |&mir::coverage::MCDCBranchSpan { + span: raw_span, + condition_info, + true_marker, + false_marker, + }| { + let (span, true_bcb, false_bcb) = check_branch_bcb(raw_span, true_marker, false_marker)?; + Some(MCDCBranch { + span, + true_bcb, + false_bcb, + condition_info, + true_index: usize::MAX, + false_index: usize::MAX, + }) + }; - mcdc_decisions.extend(coverage_info_hi.mcdc_decision_spans.iter().filter_map( - |decision: &mir::coverage::MCDCDecisionSpan| { - let span = unexpand_into_body_span(decision.span, body_span)?; + let mut get_bitmap_idx = |num_test_vectors: usize| -> Option { + let bitmap_idx = *mcdc_bitmap_bits; + let next_bitmap_bits = bitmap_idx.saturating_add(num_test_vectors); + (next_bitmap_bits <= MCDC_MAX_BITMAP_SIZE).then(|| { + *mcdc_bitmap_bits = next_bitmap_bits; + bitmap_idx + }) + }; + mcdc_degraded_branches + .extend(coverage_info_hi.mcdc_degraded_branch_spans.iter().filter_map(to_mcdc_branch)); - let end_bcbs = decision - .end_markers - .iter() - .map(|&marker| bcb_from_marker(marker)) - .collect::>()?; + mcdc_mappings.extend(coverage_info_hi.mcdc_spans.iter().filter_map(|(decision, branches)| { + if branches.len() == 0 { + return None; + } + let decision_span = unexpand_into_body_span(decision.span, body_span)?; - // Each decision containing N conditions needs 2^N bits of space in - // the bitmap, rounded up to a whole number of bytes. - // The decision's "bitmap index" points to its first byte in the bitmap. - let bitmap_idx = *mcdc_bitmap_bytes; - *mcdc_bitmap_bytes += (1_u32 << decision.num_conditions).div_ceil(8); - - Some(MCDCDecision { + let end_bcbs = decision + .end_markers + .iter() + .map(|&marker| bcb_from_marker(marker)) + .collect::>()?; + let mut branch_mappings: Vec<_> = branches.into_iter().filter_map(to_mcdc_branch).collect(); + if branch_mappings.len() != branches.len() { + mcdc_degraded_branches.extend(branch_mappings); + return None; + } + let num_test_vectors = calc_test_vectors_index(&mut branch_mappings); + let Some(bitmap_idx) = get_bitmap_idx(num_test_vectors) else { + // TODO warn about bitmap + mcdc_degraded_branches.extend(branch_mappings); + return None; + }; + // LLVM requires span of the decision contains all spans of its conditions. + // Usually the decision span meets the requirement well but in cases like macros it may not. + let span = branch_mappings + .iter() + .map(|branch| branch.span) + .reduce(|lhs, rhs| lhs.to(rhs)) + .map( + |joint_span| { + if decision_span.contains(joint_span) { decision_span } else { joint_span } + }, + ) + .expect("branch mappings are ensured to be non-empty as checked above"); + Some(( + MCDCDecision { span, end_bcbs, bitmap_idx, - num_conditions: decision.num_conditions as u16, + num_test_vectors, decision_depth: decision.decision_depth, - }) - }, - )); + }, + branch_mappings, + )) + })); +} + +// LLVM checks the executed test vector by accumulating indices of tested branches. +// We calculate number of all possible test vectors of the decision and assign indices +// to branches here. +// See [the rfc](https://discourse.llvm.org/t/rfc-coverage-new-algorithm-and-file-format-for-mc-dc/76798/) +// for more details about the algorithm. +// This function is mostly like [`TVIdxBuilder::TvIdxBuilder`](https://github.com/llvm/llvm-project/blob/d594d9f7f4dc6eb748b3261917db689fdc348b96/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp#L226) +fn calc_test_vectors_index(conditions: &mut Vec) -> usize { + let mut indegree_stats = IndexVec::::from_elem_n(0, conditions.len()); + // `num_paths` is `width` described at the llvm rfc, which indicates how many paths reaching the condition node. + let mut num_paths_stats = IndexVec::::from_elem_n(0, conditions.len()); + let mut next_conditions = conditions + .iter_mut() + .map(|branch| { + let ConditionInfo { condition_id, true_next_id, false_next_id } = branch.condition_info; + [true_next_id, false_next_id] + .into_iter() + .filter_map(std::convert::identity) + .for_each(|next_id| indegree_stats[next_id] += 1); + (condition_id, branch) + }) + .collect::>(); + + let mut queue = std::collections::VecDeque::from_iter( + next_conditions.swap_remove(&ConditionId::START).into_iter(), + ); + num_paths_stats[ConditionId::START] = 1; + let mut decision_end_nodes = Vec::new(); + while let Some(branch) = queue.pop_front() { + let ConditionInfo { condition_id, true_next_id, false_next_id } = branch.condition_info; + let (false_index, true_index) = (&mut branch.false_index, &mut branch.true_index); + let this_paths_count = num_paths_stats[condition_id]; + // Note. First check the false next to ensure conditions are touched in same order with llvm-cov. + for (next, index) in [(false_next_id, false_index), (true_next_id, true_index)] { + if let Some(next_id) = next { + let next_paths_count = &mut num_paths_stats[next_id]; + *index = *next_paths_count; + *next_paths_count = next_paths_count.saturating_add(this_paths_count); + let next_indegree = &mut indegree_stats[next_id]; + *next_indegree -= 1; + if *next_indegree == 0 { + queue.push_back(next_conditions.swap_remove(&next_id).expect( + "conditions with non-zero indegree before must be in next_conditions", + )); + } + } else { + decision_end_nodes.push((this_paths_count, condition_id, index)); + } + } + } + assert!(next_conditions.is_empty(), "the decision tree has untouched nodes"); + let mut cur_idx = 0; + // LLVM hopes the end nodes are sorted in descending order by `num_paths` so that it can + // optimize bitmap size for decisions in tree form such as `a && b && c && d && ...`. + decision_end_nodes.sort_by_key(|(num_paths, _, _)| usize::MAX - *num_paths); + for (num_paths, condition_id, index) in decision_end_nodes { + assert_eq!( + num_paths, num_paths_stats[condition_id], + "end nodes should not be updated since they were visited" + ); + assert_eq!(*index, usize::MAX, "end nodes should not be assigned index before"); + *index = cur_idx; + cur_idx += num_paths; + } + cur_idx } diff --git a/compiler/rustc_mir_transform/src/coverage/mod.rs b/compiler/rustc_mir_transform/src/coverage/mod.rs index 79482ba3919..d0f30314e79 100644 --- a/compiler/rustc_mir_transform/src/coverage/mod.rs +++ b/compiler/rustc_mir_transform/src/coverage/mod.rs @@ -114,16 +114,16 @@ fn instrument_function_for_coverage<'tcx>(tcx: TyCtxt<'tcx>, mir_body: &mut mir: inject_mcdc_statements(mir_body, &basic_coverage_blocks, &extracted_mappings); let mcdc_num_condition_bitmaps = extracted_mappings - .mcdc_decisions + .mcdc_mappings .iter() - .map(|&mappings::MCDCDecision { decision_depth, .. }| decision_depth) + .map(|&(mappings::MCDCDecision { decision_depth, .. }, _)| decision_depth) .max() .map_or(0, |max| usize::from(max) + 1); mir_body.function_coverage_info = Some(Box::new(FunctionCoverageInfo { function_source_hash: hir_info.function_source_hash, num_counters: coverage_counters.num_counters(), - mcdc_bitmap_bytes: extracted_mappings.mcdc_bitmap_bytes, + mcdc_bitmap_bits: extracted_mappings.mcdc_bitmap_bits, expressions: coverage_counters.into_expressions(), mappings, mcdc_num_condition_bitmaps, @@ -161,9 +161,9 @@ fn create_mappings<'tcx>( num_bcbs: _, code_mappings, branch_pairs, - mcdc_bitmap_bytes: _, - mcdc_branches, - mcdc_decisions, + mcdc_bitmap_bits: _, + mcdc_degraded_branches, + mcdc_mappings, } = extracted_mappings; let mut mappings = Vec::new(); @@ -186,26 +186,79 @@ fn create_mappings<'tcx>( }, )); - mappings.extend(mcdc_branches.iter().filter_map( - |&mappings::MCDCBranch { span, true_bcb, false_bcb, condition_info, decision_depth: _ }| { + let term_for_bcb = + |bcb| coverage_counters.term_for_bcb(bcb).expect("all BCBs with spans were given counters"); + + // MCDC branch mappings are appended with their decisions in case decisions were ignored. + mappings.extend(mcdc_degraded_branches.iter().filter_map( + |&mappings::MCDCBranch { + span, + true_bcb, + false_bcb, + condition_info: _, + true_index: _, + false_index: _, + }| { let source_region = region_for_span(span)?; let true_term = term_for_bcb(true_bcb); let false_term = term_for_bcb(false_bcb); - let kind = match condition_info { - Some(mcdc_params) => MappingKind::MCDCBranch { true_term, false_term, mcdc_params }, - None => MappingKind::Branch { true_term, false_term }, - }; - Some(Mapping { kind, source_region }) + Some(Mapping { kind: MappingKind::Branch { true_term, false_term }, source_region }) }, )); - mappings.extend(mcdc_decisions.iter().filter_map( - |&mappings::MCDCDecision { span, bitmap_idx, num_conditions, .. }| { - let source_region = region_for_span(span)?; - let kind = MappingKind::MCDCDecision(DecisionInfo { bitmap_idx, num_conditions }); - Some(Mapping { kind, source_region }) - }, - )); + for (decision, branches) in mcdc_mappings { + let num_conditions = branches.len() as u16; + let conditions = branches + .into_iter() + .filter_map( + |&mappings::MCDCBranch { + span, + true_bcb, + false_bcb, + condition_info, + true_index: _, + false_index: _, + }| { + let source_region = region_for_span(span)?; + let true_term = term_for_bcb(true_bcb); + let false_term = term_for_bcb(false_bcb); + Some(Mapping { + kind: MappingKind::MCDCBranch { + true_term, + false_term, + mcdc_params: condition_info, + }, + source_region, + }) + }, + ) + .collect::>(); + + if conditions.len() == num_conditions as usize + && let Some(source_region) = region_for_span(decision.span) + { + // LLVM requires end index for counter mapping regions. + let kind = MappingKind::MCDCDecision(DecisionInfo { + bitmap_idx: (decision.bitmap_idx + decision.num_test_vectors) as u32, + num_conditions, + }); + mappings.extend( + std::iter::once(Mapping { kind, source_region }).chain(conditions.into_iter()), + ); + } else { + mappings.extend(conditions.into_iter().map(|mapping| { + let MappingKind::MCDCBranch { true_term, false_term, mcdc_params: _ } = + mapping.kind + else { + unreachable!("all mappings here are MCDCBranch as shown above"); + }; + Mapping { + kind: MappingKind::Branch { true_term, false_term }, + source_region: mapping.source_region, + } + })) + } + } mappings } @@ -274,44 +327,41 @@ fn inject_mcdc_statements<'tcx>( basic_coverage_blocks: &CoverageGraph, extracted_mappings: &ExtractedMappings, ) { - // Inject test vector update first because `inject_statement` always insert new statement at - // head. - for &mappings::MCDCDecision { - span: _, - ref end_bcbs, - bitmap_idx, - num_conditions: _, - decision_depth, - } in &extracted_mappings.mcdc_decisions - { - for end in end_bcbs { - let end_bb = basic_coverage_blocks[*end].leader_bb(); + for (decision, conditions) in &extracted_mappings.mcdc_mappings { + // Inject test vector update first because `inject_statement` always insert new statement at head. + for &end in &decision.end_bcbs { + let end_bb = basic_coverage_blocks[end].leader_bb(); inject_statement( mir_body, - CoverageKind::TestVectorBitmapUpdate { bitmap_idx, decision_depth }, + CoverageKind::TestVectorBitmapUpdate { + bitmap_idx: decision.bitmap_idx as u32, + decision_depth: decision.decision_depth, + }, end_bb, ); } - } - for &mappings::MCDCBranch { span: _, true_bcb, false_bcb, condition_info, decision_depth } in - &extracted_mappings.mcdc_branches - { - let Some(condition_info) = condition_info else { continue }; - let id = condition_info.condition_id; - - let true_bb = basic_coverage_blocks[true_bcb].leader_bb(); - inject_statement( - mir_body, - CoverageKind::CondBitmapUpdate { id, value: true, decision_depth }, - true_bb, - ); - let false_bb = basic_coverage_blocks[false_bcb].leader_bb(); - inject_statement( - mir_body, - CoverageKind::CondBitmapUpdate { id, value: false, decision_depth }, - false_bb, - ); + for &mappings::MCDCBranch { + span: _, + true_bcb, + false_bcb, + condition_info: _, + true_index, + false_index, + } in conditions + { + for (index, bcb) in [(false_index, false_bcb), (true_index, true_bcb)] { + let bb = basic_coverage_blocks[bcb].leader_bb(); + inject_statement( + mir_body, + CoverageKind::CondBitmapUpdate { + index: index as u32, + decision_depth: decision.decision_depth, + }, + bb, + ); + } + } } } diff --git a/tests/coverage/mcdc/condition-limit.cov-map b/tests/coverage/mcdc/condition-limit.cov-map index b4447a33691..9d1e7518f9e 100644 --- a/tests/coverage/mcdc/condition-limit.cov-map +++ b/tests/coverage/mcdc/condition-limit.cov-map @@ -1,5 +1,5 @@ -Function name: condition_limit::bad -Raw bytes (204): 0x[01, 01, 2c, 01, 05, 05, 1d, 05, 1d, 7a, 19, 05, 1d, 7a, 19, 05, 1d, 76, 15, 7a, 19, 05, 1d, 76, 15, 7a, 19, 05, 1d, 72, 11, 76, 15, 7a, 19, 05, 1d, 72, 11, 76, 15, 7a, 19, 05, 1d, 6e, 0d, 72, 11, 76, 15, 7a, 19, 05, 1d, 6e, 0d, 72, 11, 76, 15, 7a, 19, 05, 1d, 9f, 01, 02, a3, 01, 1d, a7, 01, 19, ab, 01, 15, af, 01, 11, 09, 0d, 21, 9b, 01, 9f, 01, 02, a3, 01, 1d, a7, 01, 19, ab, 01, 15, af, 01, 11, 09, 0d, 11, 01, 14, 01, 03, 09, 20, 05, 02, 03, 08, 00, 09, 05, 00, 0d, 00, 0e, 20, 7a, 1d, 00, 0d, 00, 0e, 7a, 00, 12, 00, 13, 20, 76, 19, 00, 12, 00, 13, 76, 00, 17, 00, 18, 20, 72, 15, 00, 17, 00, 18, 72, 00, 1c, 00, 1d, 20, 6e, 11, 00, 1c, 00, 1d, 6e, 00, 21, 00, 22, 20, 6a, 0d, 00, 21, 00, 22, 6a, 00, 26, 00, 27, 20, 21, 09, 00, 26, 00, 27, 21, 00, 28, 02, 06, 9b, 01, 02, 06, 00, 07, 97, 01, 01, 01, 00, 02] +Function name: condition_limit::accept_7_conditions +Raw bytes (232): 0x[01, 01, 2c, 01, 05, 05, 1d, 05, 1d, 7a, 19, 05, 1d, 7a, 19, 05, 1d, 76, 15, 7a, 19, 05, 1d, 76, 15, 7a, 19, 05, 1d, 72, 11, 76, 15, 7a, 19, 05, 1d, 72, 11, 76, 15, 7a, 19, 05, 1d, 6e, 0d, 72, 11, 76, 15, 7a, 19, 05, 1d, 6e, 0d, 72, 11, 76, 15, 7a, 19, 05, 1d, 9f, 01, 02, a3, 01, 1d, a7, 01, 19, ab, 01, 15, af, 01, 11, 09, 0d, 21, 9b, 01, 9f, 01, 02, a3, 01, 1d, a7, 01, 19, ab, 01, 15, af, 01, 11, 09, 0d, 12, 01, 07, 01, 02, 09, 28, 08, 07, 02, 08, 00, 27, 30, 05, 02, 01, 07, 00, 00, 08, 00, 09, 05, 00, 0d, 00, 0e, 30, 7a, 1d, 07, 06, 00, 00, 0d, 00, 0e, 7a, 00, 12, 00, 13, 30, 76, 19, 06, 05, 00, 00, 12, 00, 13, 76, 00, 17, 00, 18, 30, 72, 15, 05, 04, 00, 00, 17, 00, 18, 72, 00, 1c, 00, 1d, 30, 6e, 11, 04, 03, 00, 00, 1c, 00, 1d, 6e, 00, 21, 00, 22, 30, 6a, 0d, 03, 02, 00, 00, 21, 00, 22, 6a, 00, 26, 00, 27, 30, 21, 09, 02, 00, 00, 00, 26, 00, 27, 21, 00, 28, 02, 06, 9b, 01, 02, 06, 00, 07, 97, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 44 @@ -47,38 +47,39 @@ Number of expressions: 44 - expression 41 operands: lhs = Expression(42, Add), rhs = Counter(5) - expression 42 operands: lhs = Expression(43, Add), rhs = Counter(4) - expression 43 operands: lhs = Counter(2), rhs = Counter(3) -Number of file 0 mappings: 17 -- Code(Counter(0)) at (prev + 20, 1) to (start + 3, 9) -- Branch { true: Counter(1), false: Expression(0, Sub) } at (prev + 3, 8) to (start + 0, 9) +Number of file 0 mappings: 18 +- Code(Counter(0)) at (prev + 7, 1) to (start + 2, 9) +- MCDCDecision { bitmap_idx: 8, conditions_num: 7 } at (prev + 2, 8) to (start + 0, 39) +- MCDCBranch { true: Counter(1), false: Expression(0, Sub), condition_id: 1, true_next_id: 7, false_next_id: 0 } at (prev + 0, 8) to (start + 0, 9) true = c1 false = (c0 - c1) - Code(Counter(1)) at (prev + 0, 13) to (start + 0, 14) -- Branch { true: Expression(30, Sub), false: Counter(7) } at (prev + 0, 13) to (start + 0, 14) +- MCDCBranch { true: Expression(30, Sub), false: Counter(7), condition_id: 7, true_next_id: 6, false_next_id: 0 } at (prev + 0, 13) to (start + 0, 14) true = (c1 - c7) false = c7 - Code(Expression(30, Sub)) at (prev + 0, 18) to (start + 0, 19) = (c1 - c7) -- Branch { true: Expression(29, Sub), false: Counter(6) } at (prev + 0, 18) to (start + 0, 19) +- MCDCBranch { true: Expression(29, Sub), false: Counter(6), condition_id: 6, true_next_id: 5, false_next_id: 0 } at (prev + 0, 18) to (start + 0, 19) true = ((c1 - c7) - c6) false = c6 - Code(Expression(29, Sub)) at (prev + 0, 23) to (start + 0, 24) = ((c1 - c7) - c6) -- Branch { true: Expression(28, Sub), false: Counter(5) } at (prev + 0, 23) to (start + 0, 24) +- MCDCBranch { true: Expression(28, Sub), false: Counter(5), condition_id: 5, true_next_id: 4, false_next_id: 0 } at (prev + 0, 23) to (start + 0, 24) true = (((c1 - c7) - c6) - c5) false = c5 - Code(Expression(28, Sub)) at (prev + 0, 28) to (start + 0, 29) = (((c1 - c7) - c6) - c5) -- Branch { true: Expression(27, Sub), false: Counter(4) } at (prev + 0, 28) to (start + 0, 29) +- MCDCBranch { true: Expression(27, Sub), false: Counter(4), condition_id: 4, true_next_id: 3, false_next_id: 0 } at (prev + 0, 28) to (start + 0, 29) true = ((((c1 - c7) - c6) - c5) - c4) false = c4 - Code(Expression(27, Sub)) at (prev + 0, 33) to (start + 0, 34) = ((((c1 - c7) - c6) - c5) - c4) -- Branch { true: Expression(26, Sub), false: Counter(3) } at (prev + 0, 33) to (start + 0, 34) +- MCDCBranch { true: Expression(26, Sub), false: Counter(3), condition_id: 3, true_next_id: 2, false_next_id: 0 } at (prev + 0, 33) to (start + 0, 34) true = (((((c1 - c7) - c6) - c5) - c4) - c3) false = c3 - Code(Expression(26, Sub)) at (prev + 0, 38) to (start + 0, 39) = (((((c1 - c7) - c6) - c5) - c4) - c3) -- Branch { true: Counter(8), false: Counter(2) } at (prev + 0, 38) to (start + 0, 39) +- MCDCBranch { true: Counter(8), false: Counter(2), condition_id: 2, true_next_id: 0, false_next_id: 0 } at (prev + 0, 38) to (start + 0, 39) true = c8 false = c2 - Code(Counter(8)) at (prev + 0, 40) to (start + 2, 6) @@ -87,76 +88,3 @@ Number of file 0 mappings: 17 - Code(Expression(37, Add)) at (prev + 1, 1) to (start + 0, 2) = (c8 + ((((((c2 + c3) + c4) + c5) + c6) + c7) + (c0 - c1))) -Function name: condition_limit::good -Raw bytes (180): 0x[01, 01, 20, 01, 05, 05, 19, 05, 19, 52, 15, 05, 19, 52, 15, 05, 19, 4e, 11, 52, 15, 05, 19, 4e, 11, 52, 15, 05, 19, 4a, 0d, 4e, 11, 52, 15, 05, 19, 4a, 0d, 4e, 11, 52, 15, 05, 19, 73, 02, 77, 19, 7b, 15, 7f, 11, 09, 0d, 1d, 6f, 73, 02, 77, 19, 7b, 15, 7f, 11, 09, 0d, 10, 01, 0c, 01, 03, 09, 28, 00, 06, 03, 08, 00, 22, 30, 05, 02, 01, 06, 00, 00, 08, 00, 09, 05, 00, 0d, 00, 0e, 30, 52, 19, 06, 05, 00, 00, 0d, 00, 0e, 52, 00, 12, 00, 13, 30, 4e, 15, 05, 04, 00, 00, 12, 00, 13, 4e, 00, 17, 00, 18, 30, 4a, 11, 04, 03, 00, 00, 17, 00, 18, 4a, 00, 1c, 00, 1d, 30, 46, 0d, 03, 02, 00, 00, 1c, 00, 1d, 46, 00, 21, 00, 22, 30, 1d, 09, 02, 00, 00, 00, 21, 00, 22, 1d, 00, 23, 02, 06, 6f, 02, 06, 00, 07, 6b, 01, 01, 00, 02] -Number of files: 1 -- file 0 => global file 1 -Number of expressions: 32 -- expression 0 operands: lhs = Counter(0), rhs = Counter(1) -- expression 1 operands: lhs = Counter(1), rhs = Counter(6) -- expression 2 operands: lhs = Counter(1), rhs = Counter(6) -- expression 3 operands: lhs = Expression(20, Sub), rhs = Counter(5) -- expression 4 operands: lhs = Counter(1), rhs = Counter(6) -- expression 5 operands: lhs = Expression(20, Sub), rhs = Counter(5) -- expression 6 operands: lhs = Counter(1), rhs = Counter(6) -- expression 7 operands: lhs = Expression(19, Sub), rhs = Counter(4) -- expression 8 operands: lhs = Expression(20, Sub), rhs = Counter(5) -- expression 9 operands: lhs = Counter(1), rhs = Counter(6) -- expression 10 operands: lhs = Expression(19, Sub), rhs = Counter(4) -- expression 11 operands: lhs = Expression(20, Sub), rhs = Counter(5) -- expression 12 operands: lhs = Counter(1), rhs = Counter(6) -- expression 13 operands: lhs = Expression(18, Sub), rhs = Counter(3) -- expression 14 operands: lhs = Expression(19, Sub), rhs = Counter(4) -- expression 15 operands: lhs = Expression(20, Sub), rhs = Counter(5) -- expression 16 operands: lhs = Counter(1), rhs = Counter(6) -- expression 17 operands: lhs = Expression(18, Sub), rhs = Counter(3) -- expression 18 operands: lhs = Expression(19, Sub), rhs = Counter(4) -- expression 19 operands: lhs = Expression(20, Sub), rhs = Counter(5) -- expression 20 operands: lhs = Counter(1), rhs = Counter(6) -- expression 21 operands: lhs = Expression(28, Add), rhs = Expression(0, Sub) -- expression 22 operands: lhs = Expression(29, Add), rhs = Counter(6) -- expression 23 operands: lhs = Expression(30, Add), rhs = Counter(5) -- expression 24 operands: lhs = Expression(31, Add), rhs = Counter(4) -- expression 25 operands: lhs = Counter(2), rhs = Counter(3) -- expression 26 operands: lhs = Counter(7), rhs = Expression(27, Add) -- expression 27 operands: lhs = Expression(28, Add), rhs = Expression(0, Sub) -- expression 28 operands: lhs = Expression(29, Add), rhs = Counter(6) -- expression 29 operands: lhs = Expression(30, Add), rhs = Counter(5) -- expression 30 operands: lhs = Expression(31, Add), rhs = Counter(4) -- expression 31 operands: lhs = Counter(2), rhs = Counter(3) -Number of file 0 mappings: 16 -- Code(Counter(0)) at (prev + 12, 1) to (start + 3, 9) -- MCDCDecision { bitmap_idx: 0, conditions_num: 6 } at (prev + 3, 8) to (start + 0, 34) -- MCDCBranch { true: Counter(1), false: Expression(0, Sub), condition_id: 1, true_next_id: 6, false_next_id: 0 } at (prev + 0, 8) to (start + 0, 9) - true = c1 - false = (c0 - c1) -- Code(Counter(1)) at (prev + 0, 13) to (start + 0, 14) -- MCDCBranch { true: Expression(20, Sub), false: Counter(6), condition_id: 6, true_next_id: 5, false_next_id: 0 } at (prev + 0, 13) to (start + 0, 14) - true = (c1 - c6) - false = c6 -- Code(Expression(20, Sub)) at (prev + 0, 18) to (start + 0, 19) - = (c1 - c6) -- MCDCBranch { true: Expression(19, Sub), false: Counter(5), condition_id: 5, true_next_id: 4, false_next_id: 0 } at (prev + 0, 18) to (start + 0, 19) - true = ((c1 - c6) - c5) - false = c5 -- Code(Expression(19, Sub)) at (prev + 0, 23) to (start + 0, 24) - = ((c1 - c6) - c5) -- MCDCBranch { true: Expression(18, Sub), false: Counter(4), condition_id: 4, true_next_id: 3, false_next_id: 0 } at (prev + 0, 23) to (start + 0, 24) - true = (((c1 - c6) - c5) - c4) - false = c4 -- Code(Expression(18, Sub)) at (prev + 0, 28) to (start + 0, 29) - = (((c1 - c6) - c5) - c4) -- MCDCBranch { true: Expression(17, Sub), false: Counter(3), condition_id: 3, true_next_id: 2, false_next_id: 0 } at (prev + 0, 28) to (start + 0, 29) - true = ((((c1 - c6) - c5) - c4) - c3) - false = c3 -- Code(Expression(17, Sub)) at (prev + 0, 33) to (start + 0, 34) - = ((((c1 - c6) - c5) - c4) - c3) -- MCDCBranch { true: Counter(7), false: Counter(2), condition_id: 2, true_next_id: 0, false_next_id: 0 } at (prev + 0, 33) to (start + 0, 34) - true = c7 - false = c2 -- Code(Counter(7)) at (prev + 0, 35) to (start + 2, 6) -- Code(Expression(27, Add)) at (prev + 2, 6) to (start + 0, 7) - = (((((c2 + c3) + c4) + c5) + c6) + (c0 - c1)) -- Code(Expression(26, Add)) at (prev + 1, 1) to (start + 0, 2) - = (c7 + (((((c2 + c3) + c4) + c5) + c6) + (c0 - c1))) - diff --git a/tests/coverage/mcdc/condition-limit.coverage b/tests/coverage/mcdc/condition-limit.coverage index 6330f2533d0..d11b8a17710 100644 --- a/tests/coverage/mcdc/condition-limit.coverage +++ b/tests/coverage/mcdc/condition-limit.coverage @@ -4,73 +4,53 @@ LL| |//@ compile-flags: -Zcoverage-options=mcdc LL| |//@ llvm-cov-flags: --show-branches=count --show-mcdc LL| | - LL| |// Check that MC/DC instrumentation can gracefully handle conditions that - LL| |// exceed LLVM's limit of 6 conditions per decision. - LL| |// - LL| |// (The limit is enforced in `compiler/rustc_mir_build/src/build/coverageinfo/mcdc.rs`.) - LL| | - LL| 1|fn good() { - LL| 1| // With only 6 conditions, perform full MC/DC instrumentation. - LL| 1| let [a, b, c, d, e, f] = <[bool; 6]>::default(); - LL| 1| if a && b && c && d && e && f { - ^0 ^0 ^0 ^0 ^0 + LL| 2|fn accept_7_conditions(bool_arr: [bool; 7]) { + LL| 2| let [a, b, c, d, e, f, g] = bool_arr; + LL| 2| if a && b && c && d && e && f && g { + ^1 ^1 ^1 ^1 ^1 ^1 ------------------ - | Branch (LL:8): [True: 0, False: 1] - | Branch (LL:13): [True: 0, False: 0] - | Branch (LL:18): [True: 0, False: 0] - | Branch (LL:23): [True: 0, False: 0] - | Branch (LL:28): [True: 0, False: 0] - | Branch (LL:33): [True: 0, False: 0] + | Branch (LL:8): [True: 1, False: 1] + | Branch (LL:13): [True: 1, False: 0] + | Branch (LL:18): [True: 1, False: 0] + | Branch (LL:23): [True: 1, False: 0] + | Branch (LL:28): [True: 1, False: 0] + | Branch (LL:33): [True: 1, False: 0] + | Branch (LL:38): [True: 1, False: 0] ------------------ - |---> MC/DC Decision Region (LL:8) to (LL:34) + |---> MC/DC Decision Region (LL:8) to (LL:39) | - | Number of Conditions: 6 + | Number of Conditions: 7 | Condition C1 --> (LL:8) | Condition C2 --> (LL:13) | Condition C3 --> (LL:18) | Condition C4 --> (LL:23) | Condition C5 --> (LL:28) | Condition C6 --> (LL:33) + | Condition C7 --> (LL:38) | | Executed MC/DC Test Vectors: | - | C1, C2, C3, C4, C5, C6 Result - | 1 { F, -, -, -, -, - = F } + | C1, C2, C3, C4, C5, C6, C7 Result + | 1 { F, -, -, -, -, -, - = F } + | 2 { T, T, T, T, T, T, T = T } | - | C1-Pair: not covered + | C1-Pair: covered: (1,2) | C2-Pair: not covered | C3-Pair: not covered | C4-Pair: not covered | C5-Pair: not covered | C6-Pair: not covered - | MC/DC Coverage for Decision: 0.00% + | C7-Pair: not covered + | MC/DC Coverage for Decision: 14.29% | ------------------ - LL| 0| core::hint::black_box("hello"); + LL| 1| core::hint::black_box("hello"); LL| 1| } - LL| 1|} - LL| | - LL| 1|fn bad() { - LL| 1| // With 7 conditions, fall back to branch instrumentation only. - LL| 1| let [a, b, c, d, e, f, g] = <[bool; 7]>::default(); - LL| 1| if a && b && c && d && e && f && g { - ^0 ^0 ^0 ^0 ^0 ^0 - ------------------ - | Branch (LL:8): [True: 0, False: 1] - | Branch (LL:13): [True: 0, False: 0] - | Branch (LL:18): [True: 0, False: 0] - | Branch (LL:23): [True: 0, False: 0] - | Branch (LL:28): [True: 0, False: 0] - | Branch (LL:33): [True: 0, False: 0] - | Branch (LL:38): [True: 0, False: 0] - ------------------ - LL| 0| core::hint::black_box("hello"); - LL| 1| } - LL| 1|} + LL| 2|} LL| | LL| |#[coverage(off)] LL| |fn main() { - LL| | good(); - LL| | bad(); + LL| | accept_7_conditions([false; 7]); + LL| | accept_7_conditions([true; 7]); LL| |} diff --git a/tests/coverage/mcdc/condition-limit.rs b/tests/coverage/mcdc/condition-limit.rs index 2d6fd35ab57..2e8f1619379 100644 --- a/tests/coverage/mcdc/condition-limit.rs +++ b/tests/coverage/mcdc/condition-limit.rs @@ -4,22 +4,8 @@ //@ compile-flags: -Zcoverage-options=mcdc //@ llvm-cov-flags: --show-branches=count --show-mcdc -// Check that MC/DC instrumentation can gracefully handle conditions that -// exceed LLVM's limit of 6 conditions per decision. -// -// (The limit is enforced in `compiler/rustc_mir_build/src/build/coverageinfo/mcdc.rs`.) - -fn good() { - // With only 6 conditions, perform full MC/DC instrumentation. - let [a, b, c, d, e, f] = <[bool; 6]>::default(); - if a && b && c && d && e && f { - core::hint::black_box("hello"); - } -} - -fn bad() { - // With 7 conditions, fall back to branch instrumentation only. - let [a, b, c, d, e, f, g] = <[bool; 7]>::default(); +fn accept_7_conditions(bool_arr: [bool; 7]) { + let [a, b, c, d, e, f, g] = bool_arr; if a && b && c && d && e && f && g { core::hint::black_box("hello"); } @@ -27,6 +13,6 @@ fn bad() { #[coverage(off)] fn main() { - good(); - bad(); + accept_7_conditions([false; 7]); + accept_7_conditions([true; 7]); } diff --git a/tests/coverage/mcdc/if.cov-map b/tests/coverage/mcdc/if.cov-map index 9a7d15f700d..576c9b14ed1 100644 --- a/tests/coverage/mcdc/if.cov-map +++ b/tests/coverage/mcdc/if.cov-map @@ -1,5 +1,5 @@ Function name: if::mcdc_check_a -Raw bytes (64): 0x[01, 01, 04, 01, 05, 09, 02, 0d, 0f, 09, 02, 08, 01, 0f, 01, 01, 09, 28, 00, 02, 01, 08, 00, 0e, 30, 05, 02, 01, 02, 00, 00, 08, 00, 09, 05, 00, 0d, 00, 0e, 30, 0d, 09, 02, 00, 00, 00, 0d, 00, 0e, 0d, 00, 0f, 02, 06, 0f, 02, 0c, 02, 06, 0b, 03, 01, 00, 02] +Raw bytes (64): 0x[01, 01, 04, 01, 05, 09, 02, 0d, 0f, 09, 02, 08, 01, 0f, 01, 01, 09, 28, 03, 02, 01, 08, 00, 0e, 30, 05, 02, 01, 02, 00, 00, 08, 00, 09, 05, 00, 0d, 00, 0e, 30, 0d, 09, 02, 00, 00, 00, 0d, 00, 0e, 0d, 00, 0f, 02, 06, 0f, 02, 0c, 02, 06, 0b, 03, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 4 @@ -9,7 +9,7 @@ Number of expressions: 4 - expression 3 operands: lhs = Counter(2), rhs = Expression(0, Sub) Number of file 0 mappings: 8 - Code(Counter(0)) at (prev + 15, 1) to (start + 1, 9) -- MCDCDecision { bitmap_idx: 0, conditions_num: 2 } at (prev + 1, 8) to (start + 0, 14) +- MCDCDecision { bitmap_idx: 3, conditions_num: 2 } at (prev + 1, 8) to (start + 0, 14) - MCDCBranch { true: Counter(1), false: Expression(0, Sub), condition_id: 1, true_next_id: 2, false_next_id: 0 } at (prev + 0, 8) to (start + 0, 9) true = c1 false = (c0 - c1) @@ -24,7 +24,7 @@ Number of file 0 mappings: 8 = (c3 + (c2 + (c0 - c1))) Function name: if::mcdc_check_b -Raw bytes (64): 0x[01, 01, 04, 01, 05, 09, 02, 0d, 0f, 09, 02, 08, 01, 17, 01, 01, 09, 28, 00, 02, 01, 08, 00, 0e, 30, 05, 02, 01, 02, 00, 00, 08, 00, 09, 05, 00, 0d, 00, 0e, 30, 0d, 09, 02, 00, 00, 00, 0d, 00, 0e, 0d, 00, 0f, 02, 06, 0f, 02, 0c, 02, 06, 0b, 03, 01, 00, 02] +Raw bytes (64): 0x[01, 01, 04, 01, 05, 09, 02, 0d, 0f, 09, 02, 08, 01, 17, 01, 01, 09, 28, 03, 02, 01, 08, 00, 0e, 30, 05, 02, 01, 02, 00, 00, 08, 00, 09, 05, 00, 0d, 00, 0e, 30, 0d, 09, 02, 00, 00, 00, 0d, 00, 0e, 0d, 00, 0f, 02, 06, 0f, 02, 0c, 02, 06, 0b, 03, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 4 @@ -34,7 +34,7 @@ Number of expressions: 4 - expression 3 operands: lhs = Counter(2), rhs = Expression(0, Sub) Number of file 0 mappings: 8 - Code(Counter(0)) at (prev + 23, 1) to (start + 1, 9) -- MCDCDecision { bitmap_idx: 0, conditions_num: 2 } at (prev + 1, 8) to (start + 0, 14) +- MCDCDecision { bitmap_idx: 3, conditions_num: 2 } at (prev + 1, 8) to (start + 0, 14) - MCDCBranch { true: Counter(1), false: Expression(0, Sub), condition_id: 1, true_next_id: 2, false_next_id: 0 } at (prev + 0, 8) to (start + 0, 9) true = c1 false = (c0 - c1) @@ -49,7 +49,7 @@ Number of file 0 mappings: 8 = (c3 + (c2 + (c0 - c1))) Function name: if::mcdc_check_both -Raw bytes (64): 0x[01, 01, 04, 01, 05, 09, 02, 0d, 0f, 09, 02, 08, 01, 1f, 01, 01, 09, 28, 00, 02, 01, 08, 00, 0e, 30, 05, 02, 01, 02, 00, 00, 08, 00, 09, 05, 00, 0d, 00, 0e, 30, 0d, 09, 02, 00, 00, 00, 0d, 00, 0e, 0d, 00, 0f, 02, 06, 0f, 02, 0c, 02, 06, 0b, 03, 01, 00, 02] +Raw bytes (64): 0x[01, 01, 04, 01, 05, 09, 02, 0d, 0f, 09, 02, 08, 01, 1f, 01, 01, 09, 28, 03, 02, 01, 08, 00, 0e, 30, 05, 02, 01, 02, 00, 00, 08, 00, 09, 05, 00, 0d, 00, 0e, 30, 0d, 09, 02, 00, 00, 00, 0d, 00, 0e, 0d, 00, 0f, 02, 06, 0f, 02, 0c, 02, 06, 0b, 03, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 4 @@ -59,7 +59,7 @@ Number of expressions: 4 - expression 3 operands: lhs = Counter(2), rhs = Expression(0, Sub) Number of file 0 mappings: 8 - Code(Counter(0)) at (prev + 31, 1) to (start + 1, 9) -- MCDCDecision { bitmap_idx: 0, conditions_num: 2 } at (prev + 1, 8) to (start + 0, 14) +- MCDCDecision { bitmap_idx: 3, conditions_num: 2 } at (prev + 1, 8) to (start + 0, 14) - MCDCBranch { true: Counter(1), false: Expression(0, Sub), condition_id: 1, true_next_id: 2, false_next_id: 0 } at (prev + 0, 8) to (start + 0, 9) true = c1 false = (c0 - c1) @@ -74,7 +74,7 @@ Number of file 0 mappings: 8 = (c3 + (c2 + (c0 - c1))) Function name: if::mcdc_check_neither -Raw bytes (64): 0x[01, 01, 04, 01, 05, 09, 02, 0d, 0f, 09, 02, 08, 01, 07, 01, 01, 09, 28, 00, 02, 01, 08, 00, 0e, 30, 05, 02, 01, 02, 00, 00, 08, 00, 09, 05, 00, 0d, 00, 0e, 30, 0d, 09, 02, 00, 00, 00, 0d, 00, 0e, 0d, 00, 0f, 02, 06, 0f, 02, 0c, 02, 06, 0b, 03, 01, 00, 02] +Raw bytes (64): 0x[01, 01, 04, 01, 05, 09, 02, 0d, 0f, 09, 02, 08, 01, 07, 01, 01, 09, 28, 03, 02, 01, 08, 00, 0e, 30, 05, 02, 01, 02, 00, 00, 08, 00, 09, 05, 00, 0d, 00, 0e, 30, 0d, 09, 02, 00, 00, 00, 0d, 00, 0e, 0d, 00, 0f, 02, 06, 0f, 02, 0c, 02, 06, 0b, 03, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 4 @@ -84,7 +84,7 @@ Number of expressions: 4 - expression 3 operands: lhs = Counter(2), rhs = Expression(0, Sub) Number of file 0 mappings: 8 - Code(Counter(0)) at (prev + 7, 1) to (start + 1, 9) -- MCDCDecision { bitmap_idx: 0, conditions_num: 2 } at (prev + 1, 8) to (start + 0, 14) +- MCDCDecision { bitmap_idx: 3, conditions_num: 2 } at (prev + 1, 8) to (start + 0, 14) - MCDCBranch { true: Counter(1), false: Expression(0, Sub), condition_id: 1, true_next_id: 2, false_next_id: 0 } at (prev + 0, 8) to (start + 0, 9) true = c1 false = (c0 - c1) @@ -99,7 +99,7 @@ Number of file 0 mappings: 8 = (c3 + (c2 + (c0 - c1))) Function name: if::mcdc_check_not_tree_decision -Raw bytes (87): 0x[01, 01, 08, 01, 05, 02, 09, 05, 09, 0d, 1e, 02, 09, 11, 1b, 0d, 1e, 02, 09, 0a, 01, 31, 01, 03, 0a, 28, 00, 03, 03, 08, 00, 15, 30, 05, 02, 01, 02, 03, 00, 09, 00, 0a, 02, 00, 0e, 00, 0f, 30, 09, 1e, 03, 02, 00, 00, 0e, 00, 0f, 0b, 00, 14, 00, 15, 30, 11, 0d, 02, 00, 00, 00, 14, 00, 15, 11, 00, 16, 02, 06, 1b, 02, 0c, 02, 06, 17, 03, 01, 00, 02] +Raw bytes (87): 0x[01, 01, 08, 01, 05, 02, 09, 05, 09, 0d, 1e, 02, 09, 11, 1b, 0d, 1e, 02, 09, 0a, 01, 31, 01, 03, 0a, 28, 05, 03, 03, 08, 00, 15, 30, 05, 02, 01, 02, 03, 00, 09, 00, 0a, 02, 00, 0e, 00, 0f, 30, 09, 1e, 03, 02, 00, 00, 0e, 00, 0f, 0b, 00, 14, 00, 15, 30, 11, 0d, 02, 00, 00, 00, 14, 00, 15, 11, 00, 16, 02, 06, 1b, 02, 0c, 02, 06, 17, 03, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 8 @@ -113,7 +113,7 @@ Number of expressions: 8 - expression 7 operands: lhs = Expression(0, Sub), rhs = Counter(2) Number of file 0 mappings: 10 - Code(Counter(0)) at (prev + 49, 1) to (start + 3, 10) -- MCDCDecision { bitmap_idx: 0, conditions_num: 3 } at (prev + 3, 8) to (start + 0, 21) +- MCDCDecision { bitmap_idx: 5, conditions_num: 3 } at (prev + 3, 8) to (start + 0, 21) - MCDCBranch { true: Counter(1), false: Expression(0, Sub), condition_id: 1, true_next_id: 2, false_next_id: 3 } at (prev + 0, 9) to (start + 0, 10) true = c1 false = (c0 - c1) @@ -134,7 +134,7 @@ Number of file 0 mappings: 10 = (c4 + (c3 + ((c0 - c1) - c2))) Function name: if::mcdc_check_tree_decision -Raw bytes (87): 0x[01, 01, 08, 01, 05, 05, 0d, 05, 0d, 0d, 11, 09, 02, 1b, 1f, 0d, 11, 09, 02, 0a, 01, 27, 01, 03, 09, 28, 00, 03, 03, 08, 00, 15, 30, 05, 02, 01, 02, 00, 00, 08, 00, 09, 05, 00, 0e, 00, 0f, 30, 0d, 0a, 02, 00, 03, 00, 0e, 00, 0f, 0a, 00, 13, 00, 14, 30, 11, 09, 03, 00, 00, 00, 13, 00, 14, 1b, 00, 16, 02, 06, 1f, 02, 0c, 02, 06, 17, 03, 01, 00, 02] +Raw bytes (87): 0x[01, 01, 08, 01, 05, 05, 0d, 05, 0d, 0d, 11, 09, 02, 1b, 1f, 0d, 11, 09, 02, 0a, 01, 27, 01, 03, 09, 28, 04, 03, 03, 08, 00, 15, 30, 05, 02, 01, 02, 00, 00, 08, 00, 09, 05, 00, 0e, 00, 0f, 30, 0d, 0a, 02, 00, 03, 00, 0e, 00, 0f, 0a, 00, 13, 00, 14, 30, 11, 09, 03, 00, 00, 00, 13, 00, 14, 1b, 00, 16, 02, 06, 1f, 02, 0c, 02, 06, 17, 03, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 8 @@ -148,7 +148,7 @@ Number of expressions: 8 - expression 7 operands: lhs = Counter(2), rhs = Expression(0, Sub) Number of file 0 mappings: 10 - Code(Counter(0)) at (prev + 39, 1) to (start + 3, 9) -- MCDCDecision { bitmap_idx: 0, conditions_num: 3 } at (prev + 3, 8) to (start + 0, 21) +- MCDCDecision { bitmap_idx: 4, conditions_num: 3 } at (prev + 3, 8) to (start + 0, 21) - MCDCBranch { true: Counter(1), false: Expression(0, Sub), condition_id: 1, true_next_id: 2, false_next_id: 0 } at (prev + 0, 8) to (start + 0, 9) true = c1 false = (c0 - c1) @@ -169,7 +169,7 @@ Number of file 0 mappings: 10 = ((c3 + c4) + (c2 + (c0 - c1))) Function name: if::mcdc_nested_if -Raw bytes (124): 0x[01, 01, 0d, 01, 05, 02, 09, 05, 09, 1b, 15, 05, 09, 1b, 15, 05, 09, 11, 15, 02, 09, 2b, 32, 0d, 2f, 11, 15, 02, 09, 0e, 01, 3b, 01, 01, 09, 28, 00, 02, 01, 08, 00, 0e, 30, 05, 02, 01, 00, 02, 00, 08, 00, 09, 02, 00, 0d, 00, 0e, 30, 09, 32, 02, 00, 00, 00, 0d, 00, 0e, 1b, 01, 09, 01, 0d, 28, 01, 02, 01, 0c, 00, 12, 30, 16, 15, 01, 02, 00, 00, 0c, 00, 0d, 16, 00, 11, 00, 12, 30, 0d, 11, 02, 00, 00, 00, 11, 00, 12, 0d, 00, 13, 02, 0a, 2f, 02, 0a, 00, 0b, 32, 01, 0c, 02, 06, 27, 03, 01, 00, 02] +Raw bytes (124): 0x[01, 01, 0d, 01, 05, 02, 09, 05, 09, 1b, 15, 05, 09, 1b, 15, 05, 09, 11, 15, 02, 09, 2b, 32, 0d, 2f, 11, 15, 02, 09, 0e, 01, 3b, 01, 01, 09, 28, 03, 02, 01, 08, 00, 0e, 30, 05, 02, 01, 00, 02, 00, 08, 00, 09, 02, 00, 0d, 00, 0e, 30, 09, 32, 02, 00, 00, 00, 0d, 00, 0e, 1b, 01, 09, 01, 0d, 28, 06, 02, 01, 0c, 00, 12, 30, 16, 15, 01, 02, 00, 00, 0c, 00, 0d, 16, 00, 11, 00, 12, 30, 0d, 11, 02, 00, 00, 00, 11, 00, 12, 0d, 00, 13, 02, 0a, 2f, 02, 0a, 00, 0b, 32, 01, 0c, 02, 06, 27, 03, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 13 @@ -188,7 +188,7 @@ Number of expressions: 13 - expression 12 operands: lhs = Expression(0, Sub), rhs = Counter(2) Number of file 0 mappings: 14 - Code(Counter(0)) at (prev + 59, 1) to (start + 1, 9) -- MCDCDecision { bitmap_idx: 0, conditions_num: 2 } at (prev + 1, 8) to (start + 0, 14) +- MCDCDecision { bitmap_idx: 3, conditions_num: 2 } at (prev + 1, 8) to (start + 0, 14) - MCDCBranch { true: Counter(1), false: Expression(0, Sub), condition_id: 1, true_next_id: 0, false_next_id: 2 } at (prev + 0, 8) to (start + 0, 9) true = c1 false = (c0 - c1) @@ -199,7 +199,7 @@ Number of file 0 mappings: 14 false = ((c0 - c1) - c2) - Code(Expression(6, Add)) at (prev + 1, 9) to (start + 1, 13) = (c1 + c2) -- MCDCDecision { bitmap_idx: 1, conditions_num: 2 } at (prev + 1, 12) to (start + 0, 18) +- MCDCDecision { bitmap_idx: 6, conditions_num: 2 } at (prev + 1, 12) to (start + 0, 18) - MCDCBranch { true: Expression(5, Sub), false: Counter(5), condition_id: 1, true_next_id: 2, false_next_id: 0 } at (prev + 0, 12) to (start + 0, 13) true = ((c1 + c2) - c5) false = c5 diff --git a/tests/coverage/mcdc/if.coverage b/tests/coverage/mcdc/if.coverage index d5cf590d96e..b000c7d5d2f 100644 --- a/tests/coverage/mcdc/if.coverage +++ b/tests/coverage/mcdc/if.coverage @@ -145,12 +145,12 @@ | C1, C2, C3 Result | 1 { F, -, - = F } | 2 { T, F, F = F } - | 3 { T, T, - = T } - | 4 { T, F, T = T } + | 3 { T, F, T = T } + | 4 { T, T, - = T } | | C1-Pair: covered: (1,3) - | C2-Pair: covered: (2,3) - | C3-Pair: covered: (2,4) + | C2-Pair: covered: (2,4) + | C3-Pair: covered: (2,3) | MC/DC Coverage for Decision: 100.00% | ------------------ @@ -162,7 +162,7 @@ LL| | LL| 4|fn mcdc_check_not_tree_decision(a: bool, b: bool, c: bool) { LL| 4| // Contradict to `mcdc_check_tree_decision`, - LL| 4| // 100% branch coverage of this expression does not mean indicates 100% mcdc coverage. + LL| 4| // 100% branch coverage of this expression does not indicate 100% mcdc coverage. LL| 4| if (a || b) && c { ^1 ------------------ @@ -181,12 +181,12 @@ | | C1, C2, C3 Result | 1 { T, -, F = F } - | 2 { T, -, T = T } - | 3 { F, T, T = T } + | 2 { F, T, T = T } + | 3 { T, -, T = T } | | C1-Pair: not covered | C2-Pair: not covered - | C3-Pair: covered: (1,2) + | C3-Pair: covered: (1,3) | MC/DC Coverage for Decision: 33.33% | ------------------ diff --git a/tests/coverage/mcdc/if.rs b/tests/coverage/mcdc/if.rs index 6ade8d34d54..a2abb2edf11 100644 --- a/tests/coverage/mcdc/if.rs +++ b/tests/coverage/mcdc/if.rs @@ -48,7 +48,7 @@ fn mcdc_check_tree_decision(a: bool, b: bool, c: bool) { fn mcdc_check_not_tree_decision(a: bool, b: bool, c: bool) { // Contradict to `mcdc_check_tree_decision`, - // 100% branch coverage of this expression does not mean indicates 100% mcdc coverage. + // 100% branch coverage of this expression does not indicate 100% mcdc coverage. if (a || b) && c { say("pass"); } else { diff --git a/tests/coverage/mcdc/inlined_expressions.cov-map b/tests/coverage/mcdc/inlined_expressions.cov-map index 09b7291c964..bfde7d75d62 100644 --- a/tests/coverage/mcdc/inlined_expressions.cov-map +++ b/tests/coverage/mcdc/inlined_expressions.cov-map @@ -1,5 +1,5 @@ Function name: inlined_expressions::inlined_instance -Raw bytes (52): 0x[01, 01, 03, 01, 05, 0b, 02, 09, 0d, 06, 01, 08, 01, 01, 06, 28, 00, 02, 01, 05, 00, 0b, 30, 05, 02, 01, 02, 00, 00, 05, 00, 06, 05, 00, 0a, 00, 0b, 30, 09, 0d, 02, 00, 00, 00, 0a, 00, 0b, 07, 01, 01, 00, 02] +Raw bytes (52): 0x[01, 01, 03, 01, 05, 0b, 02, 09, 0d, 06, 01, 08, 01, 01, 06, 28, 03, 02, 01, 05, 00, 0b, 30, 05, 02, 01, 02, 00, 00, 05, 00, 06, 05, 00, 0a, 00, 0b, 30, 09, 0d, 02, 00, 00, 00, 0a, 00, 0b, 07, 01, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 3 @@ -8,7 +8,7 @@ Number of expressions: 3 - expression 2 operands: lhs = Counter(2), rhs = Counter(3) Number of file 0 mappings: 6 - Code(Counter(0)) at (prev + 8, 1) to (start + 1, 6) -- MCDCDecision { bitmap_idx: 0, conditions_num: 2 } at (prev + 1, 5) to (start + 0, 11) +- MCDCDecision { bitmap_idx: 3, conditions_num: 2 } at (prev + 1, 5) to (start + 0, 11) - MCDCBranch { true: Counter(1), false: Expression(0, Sub), condition_id: 1, true_next_id: 2, false_next_id: 0 } at (prev + 0, 5) to (start + 0, 6) true = c1 false = (c0 - c1) diff --git a/tests/coverage/mcdc/nested_if.cov-map b/tests/coverage/mcdc/nested_if.cov-map index adeb6cbc1fb..3da98ff4a51 100644 --- a/tests/coverage/mcdc/nested_if.cov-map +++ b/tests/coverage/mcdc/nested_if.cov-map @@ -1,5 +1,5 @@ Function name: nested_if::doubly_nested_if_in_condition -Raw bytes (168): 0x[01, 01, 0e, 01, 05, 05, 11, 05, 11, 26, 19, 05, 11, 19, 1d, 19, 1d, 1d, 22, 26, 19, 05, 11, 11, 15, 09, 02, 0d, 37, 09, 02, 14, 01, 0f, 01, 01, 09, 28, 02, 02, 01, 08, 00, 4e, 30, 05, 02, 01, 02, 00, 00, 08, 00, 09, 30, 0d, 09, 02, 00, 00, 00, 0d, 00, 4e, 05, 00, 10, 00, 11, 28, 01, 02, 00, 10, 00, 36, 30, 11, 26, 01, 00, 02, 00, 10, 00, 11, 30, 15, 21, 02, 00, 00, 00, 15, 00, 36, 26, 00, 18, 00, 19, 28, 00, 02, 00, 18, 00, 1e, 30, 19, 22, 01, 02, 00, 00, 18, 00, 19, 19, 00, 1d, 00, 1e, 30, 1a, 1d, 02, 00, 00, 00, 1d, 00, 1e, 1a, 00, 21, 00, 25, 1f, 00, 2f, 00, 34, 2b, 00, 39, 00, 3e, 21, 00, 48, 00, 4c, 0d, 00, 4f, 02, 06, 37, 02, 0c, 02, 06, 33, 03, 01, 00, 02] +Raw bytes (168): 0x[01, 01, 0e, 01, 05, 05, 11, 05, 11, 26, 19, 05, 11, 19, 1d, 19, 1d, 1d, 22, 26, 19, 05, 11, 11, 15, 09, 02, 0d, 37, 09, 02, 14, 01, 0f, 01, 01, 09, 28, 09, 02, 01, 08, 00, 4e, 30, 05, 02, 01, 02, 00, 00, 08, 00, 09, 30, 0d, 09, 02, 00, 00, 00, 0d, 00, 4e, 05, 00, 10, 00, 11, 28, 06, 02, 00, 10, 00, 36, 30, 11, 26, 01, 00, 02, 00, 10, 00, 11, 30, 15, 21, 02, 00, 00, 00, 15, 00, 36, 26, 00, 18, 00, 19, 28, 03, 02, 00, 18, 00, 1e, 30, 19, 22, 01, 02, 00, 00, 18, 00, 19, 19, 00, 1d, 00, 1e, 30, 1a, 1d, 02, 00, 00, 00, 1d, 00, 1e, 1a, 00, 21, 00, 25, 1f, 00, 2f, 00, 34, 2b, 00, 39, 00, 3e, 21, 00, 48, 00, 4c, 0d, 00, 4f, 02, 06, 37, 02, 0c, 02, 06, 33, 03, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 14 @@ -19,7 +19,7 @@ Number of expressions: 14 - expression 13 operands: lhs = Counter(2), rhs = Expression(0, Sub) Number of file 0 mappings: 20 - Code(Counter(0)) at (prev + 15, 1) to (start + 1, 9) -- MCDCDecision { bitmap_idx: 2, conditions_num: 2 } at (prev + 1, 8) to (start + 0, 78) +- MCDCDecision { bitmap_idx: 9, conditions_num: 2 } at (prev + 1, 8) to (start + 0, 78) - MCDCBranch { true: Counter(1), false: Expression(0, Sub), condition_id: 1, true_next_id: 2, false_next_id: 0 } at (prev + 0, 8) to (start + 0, 9) true = c1 false = (c0 - c1) @@ -27,7 +27,7 @@ Number of file 0 mappings: 20 true = c3 false = c2 - Code(Counter(1)) at (prev + 0, 16) to (start + 0, 17) -- MCDCDecision { bitmap_idx: 1, conditions_num: 2 } at (prev + 0, 16) to (start + 0, 54) +- MCDCDecision { bitmap_idx: 6, conditions_num: 2 } at (prev + 0, 16) to (start + 0, 54) - MCDCBranch { true: Counter(4), false: Expression(9, Sub), condition_id: 1, true_next_id: 0, false_next_id: 2 } at (prev + 0, 16) to (start + 0, 17) true = c4 false = (c1 - c4) @@ -36,7 +36,7 @@ Number of file 0 mappings: 20 false = c8 - Code(Expression(9, Sub)) at (prev + 0, 24) to (start + 0, 25) = (c1 - c4) -- MCDCDecision { bitmap_idx: 0, conditions_num: 2 } at (prev + 0, 24) to (start + 0, 30) +- MCDCDecision { bitmap_idx: 3, conditions_num: 2 } at (prev + 0, 24) to (start + 0, 30) - MCDCBranch { true: Counter(6), false: Expression(8, Sub), condition_id: 1, true_next_id: 2, false_next_id: 0 } at (prev + 0, 24) to (start + 0, 25) true = c6 false = ((c1 - c4) - c6) @@ -58,7 +58,7 @@ Number of file 0 mappings: 20 = (c3 + (c2 + (c0 - c1))) Function name: nested_if::nested_if_in_condition -Raw bytes (120): 0x[01, 01, 0b, 01, 05, 05, 11, 05, 11, 1e, 15, 05, 11, 11, 15, 1e, 15, 05, 11, 09, 02, 0d, 2b, 09, 02, 0e, 01, 07, 01, 01, 09, 28, 01, 02, 01, 08, 00, 2e, 30, 05, 02, 01, 02, 00, 00, 08, 00, 09, 30, 0d, 09, 02, 00, 00, 00, 0d, 00, 2e, 05, 00, 10, 00, 11, 28, 00, 02, 00, 10, 00, 16, 30, 11, 1e, 01, 00, 02, 00, 10, 00, 11, 1e, 00, 15, 00, 16, 30, 15, 1a, 02, 00, 00, 00, 15, 00, 16, 17, 00, 19, 00, 1d, 1a, 00, 27, 00, 2c, 0d, 00, 2f, 02, 06, 2b, 02, 0c, 02, 06, 27, 03, 01, 00, 02] +Raw bytes (120): 0x[01, 01, 0b, 01, 05, 05, 11, 05, 11, 1e, 15, 05, 11, 11, 15, 1e, 15, 05, 11, 09, 02, 0d, 2b, 09, 02, 0e, 01, 07, 01, 01, 09, 28, 06, 02, 01, 08, 00, 2e, 30, 05, 02, 01, 02, 00, 00, 08, 00, 09, 30, 0d, 09, 02, 00, 00, 00, 0d, 00, 2e, 05, 00, 10, 00, 11, 28, 03, 02, 00, 10, 00, 16, 30, 11, 1e, 01, 00, 02, 00, 10, 00, 11, 1e, 00, 15, 00, 16, 30, 15, 1a, 02, 00, 00, 00, 15, 00, 16, 17, 00, 19, 00, 1d, 1a, 00, 27, 00, 2c, 0d, 00, 2f, 02, 06, 2b, 02, 0c, 02, 06, 27, 03, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 11 @@ -75,7 +75,7 @@ Number of expressions: 11 - expression 10 operands: lhs = Counter(2), rhs = Expression(0, Sub) Number of file 0 mappings: 14 - Code(Counter(0)) at (prev + 7, 1) to (start + 1, 9) -- MCDCDecision { bitmap_idx: 1, conditions_num: 2 } at (prev + 1, 8) to (start + 0, 46) +- MCDCDecision { bitmap_idx: 6, conditions_num: 2 } at (prev + 1, 8) to (start + 0, 46) - MCDCBranch { true: Counter(1), false: Expression(0, Sub), condition_id: 1, true_next_id: 2, false_next_id: 0 } at (prev + 0, 8) to (start + 0, 9) true = c1 false = (c0 - c1) @@ -83,7 +83,7 @@ Number of file 0 mappings: 14 true = c3 false = c2 - Code(Counter(1)) at (prev + 0, 16) to (start + 0, 17) -- MCDCDecision { bitmap_idx: 0, conditions_num: 2 } at (prev + 0, 16) to (start + 0, 22) +- MCDCDecision { bitmap_idx: 3, conditions_num: 2 } at (prev + 0, 16) to (start + 0, 22) - MCDCBranch { true: Counter(4), false: Expression(7, Sub), condition_id: 1, true_next_id: 0, false_next_id: 2 } at (prev + 0, 16) to (start + 0, 17) true = c4 false = (c1 - c4) @@ -103,7 +103,7 @@ Number of file 0 mappings: 14 = (c3 + (c2 + (c0 - c1))) Function name: nested_if::nested_in_then_block_in_condition -Raw bytes (176): 0x[01, 01, 12, 01, 05, 05, 11, 05, 11, 3a, 15, 05, 11, 11, 15, 33, 19, 11, 15, 19, 1d, 19, 1d, 1d, 2e, 33, 19, 11, 15, 3a, 15, 05, 11, 09, 02, 0d, 47, 09, 02, 14, 01, 22, 01, 01, 09, 28, 02, 02, 01, 08, 00, 4b, 30, 05, 02, 01, 02, 00, 00, 08, 00, 09, 30, 0d, 09, 02, 00, 00, 00, 0d, 00, 4b, 05, 00, 10, 00, 11, 28, 00, 02, 00, 10, 00, 16, 30, 11, 3a, 01, 00, 02, 00, 10, 00, 11, 3a, 00, 15, 00, 16, 30, 15, 36, 02, 00, 00, 00, 15, 00, 16, 33, 00, 1c, 00, 1d, 28, 01, 02, 00, 1c, 00, 22, 30, 19, 2e, 01, 02, 00, 00, 1c, 00, 1d, 19, 00, 21, 00, 22, 30, 26, 1d, 02, 00, 00, 00, 21, 00, 22, 26, 00, 25, 00, 29, 2b, 00, 33, 00, 38, 36, 00, 44, 00, 49, 0d, 00, 4c, 02, 06, 47, 02, 0c, 02, 06, 43, 03, 01, 00, 02] +Raw bytes (176): 0x[01, 01, 12, 01, 05, 05, 11, 05, 11, 3a, 15, 05, 11, 11, 15, 33, 19, 11, 15, 19, 1d, 19, 1d, 1d, 2e, 33, 19, 11, 15, 3a, 15, 05, 11, 09, 02, 0d, 47, 09, 02, 14, 01, 22, 01, 01, 09, 28, 09, 02, 01, 08, 00, 4b, 30, 05, 02, 01, 02, 00, 00, 08, 00, 09, 30, 0d, 09, 02, 00, 00, 00, 0d, 00, 4b, 05, 00, 10, 00, 11, 28, 03, 02, 00, 10, 00, 16, 30, 11, 3a, 01, 00, 02, 00, 10, 00, 11, 3a, 00, 15, 00, 16, 30, 15, 36, 02, 00, 00, 00, 15, 00, 16, 33, 00, 1c, 00, 1d, 28, 06, 02, 00, 1c, 00, 22, 30, 19, 2e, 01, 02, 00, 00, 1c, 00, 1d, 19, 00, 21, 00, 22, 30, 26, 1d, 02, 00, 00, 00, 21, 00, 22, 26, 00, 25, 00, 29, 2b, 00, 33, 00, 38, 36, 00, 44, 00, 49, 0d, 00, 4c, 02, 06, 47, 02, 0c, 02, 06, 43, 03, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 18 @@ -127,7 +127,7 @@ Number of expressions: 18 - expression 17 operands: lhs = Counter(2), rhs = Expression(0, Sub) Number of file 0 mappings: 20 - Code(Counter(0)) at (prev + 34, 1) to (start + 1, 9) -- MCDCDecision { bitmap_idx: 2, conditions_num: 2 } at (prev + 1, 8) to (start + 0, 75) +- MCDCDecision { bitmap_idx: 9, conditions_num: 2 } at (prev + 1, 8) to (start + 0, 75) - MCDCBranch { true: Counter(1), false: Expression(0, Sub), condition_id: 1, true_next_id: 2, false_next_id: 0 } at (prev + 0, 8) to (start + 0, 9) true = c1 false = (c0 - c1) @@ -135,7 +135,7 @@ Number of file 0 mappings: 20 true = c3 false = c2 - Code(Counter(1)) at (prev + 0, 16) to (start + 0, 17) -- MCDCDecision { bitmap_idx: 0, conditions_num: 2 } at (prev + 0, 16) to (start + 0, 22) +- MCDCDecision { bitmap_idx: 3, conditions_num: 2 } at (prev + 0, 16) to (start + 0, 22) - MCDCBranch { true: Counter(4), false: Expression(14, Sub), condition_id: 1, true_next_id: 0, false_next_id: 2 } at (prev + 0, 16) to (start + 0, 17) true = c4 false = (c1 - c4) @@ -146,7 +146,7 @@ Number of file 0 mappings: 20 false = ((c1 - c4) - c5) - Code(Expression(12, Add)) at (prev + 0, 28) to (start + 0, 29) = (c4 + c5) -- MCDCDecision { bitmap_idx: 1, conditions_num: 2 } at (prev + 0, 28) to (start + 0, 34) +- MCDCDecision { bitmap_idx: 6, conditions_num: 2 } at (prev + 0, 28) to (start + 0, 34) - MCDCBranch { true: Counter(6), false: Expression(11, Sub), condition_id: 1, true_next_id: 2, false_next_id: 0 } at (prev + 0, 28) to (start + 0, 29) true = c6 false = ((c4 + c5) - c6) @@ -167,7 +167,7 @@ Number of file 0 mappings: 20 = (c3 + (c2 + (c0 - c1))) Function name: nested_if::nested_single_condition_decision -Raw bytes (85): 0x[01, 01, 06, 01, 05, 05, 11, 05, 11, 09, 02, 0d, 17, 09, 02, 0b, 01, 17, 01, 04, 09, 28, 00, 02, 04, 08, 00, 29, 30, 05, 02, 01, 02, 00, 00, 08, 00, 09, 30, 0d, 09, 02, 00, 00, 00, 0d, 00, 29, 05, 00, 10, 00, 11, 20, 11, 0a, 00, 10, 00, 11, 11, 00, 14, 00, 19, 0a, 00, 23, 00, 27, 0d, 00, 2a, 02, 06, 17, 02, 0c, 02, 06, 13, 03, 01, 00, 02] +Raw bytes (85): 0x[01, 01, 06, 01, 05, 05, 11, 05, 11, 09, 02, 0d, 17, 09, 02, 0b, 01, 17, 01, 04, 09, 28, 03, 02, 04, 08, 00, 29, 30, 05, 02, 01, 02, 00, 00, 08, 00, 09, 30, 0d, 09, 02, 00, 00, 00, 0d, 00, 29, 05, 00, 10, 00, 11, 20, 11, 0a, 00, 10, 00, 11, 11, 00, 14, 00, 19, 0a, 00, 23, 00, 27, 0d, 00, 2a, 02, 06, 17, 02, 0c, 02, 06, 13, 03, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 6 @@ -179,7 +179,7 @@ Number of expressions: 6 - expression 5 operands: lhs = Counter(2), rhs = Expression(0, Sub) Number of file 0 mappings: 11 - Code(Counter(0)) at (prev + 23, 1) to (start + 4, 9) -- MCDCDecision { bitmap_idx: 0, conditions_num: 2 } at (prev + 4, 8) to (start + 0, 41) +- MCDCDecision { bitmap_idx: 3, conditions_num: 2 } at (prev + 4, 8) to (start + 0, 41) - MCDCBranch { true: Counter(1), false: Expression(0, Sub), condition_id: 1, true_next_id: 2, false_next_id: 0 } at (prev + 0, 8) to (start + 0, 9) true = c1 false = (c0 - c1) diff --git a/tests/coverage/mcdc/nested_if.coverage b/tests/coverage/mcdc/nested_if.coverage index f14969dc8c9..ca0cb54d581 100644 --- a/tests/coverage/mcdc/nested_if.coverage +++ b/tests/coverage/mcdc/nested_if.coverage @@ -40,11 +40,11 @@ | | C1, C2 Result | 1 { F, F = F } - | 2 { T, - = T } - | 3 { F, T = T } + | 2 { F, T = T } + | 3 { T, - = T } | - | C1-Pair: covered: (1,2) - | C2-Pair: covered: (1,3) + | C1-Pair: covered: (1,3) + | C2-Pair: covered: (1,2) | MC/DC Coverage for Decision: 100.00% | ------------------ @@ -92,11 +92,11 @@ | | C1, C2 Result | 1 { F, F = F } - | 2 { T, - = T } - | 3 { F, T = T } + | 2 { F, T = T } + | 3 { T, - = T } | - | C1-Pair: covered: (1,2) - | C2-Pair: covered: (1,3) + | C1-Pair: covered: (1,3) + | C2-Pair: covered: (1,2) | MC/DC Coverage for Decision: 100.00% | |---> MC/DC Decision Region (LL:24) to (LL:30) @@ -195,11 +195,11 @@ | | C1, C2 Result | 1 { F, F = F } - | 2 { T, - = T } - | 3 { F, T = T } + | 2 { F, T = T } + | 3 { T, - = T } | - | C1-Pair: covered: (1,2) - | C2-Pair: covered: (1,3) + | C1-Pair: covered: (1,3) + | C2-Pair: covered: (1,2) | MC/DC Coverage for Decision: 100.00% | |---> MC/DC Decision Region (LL:28) to (LL:34) diff --git a/tests/coverage/mcdc/non_control_flow.cov-map b/tests/coverage/mcdc/non_control_flow.cov-map index f8576831e75..d5383a19761 100644 --- a/tests/coverage/mcdc/non_control_flow.cov-map +++ b/tests/coverage/mcdc/non_control_flow.cov-map @@ -1,5 +1,5 @@ Function name: non_control_flow::assign_3 -Raw bytes (89): 0x[01, 01, 09, 05, 07, 0b, 11, 09, 0d, 01, 05, 01, 05, 22, 11, 01, 05, 22, 11, 01, 05, 0a, 01, 16, 01, 00, 28, 03, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 28, 00, 03, 00, 0d, 00, 18, 30, 05, 22, 01, 00, 02, 00, 0d, 00, 0e, 22, 00, 12, 00, 13, 30, 1e, 11, 02, 03, 00, 00, 12, 00, 13, 1e, 00, 17, 00, 18, 30, 09, 0d, 03, 00, 00, 00, 17, 00, 18, 03, 01, 05, 01, 02] +Raw bytes (89): 0x[01, 01, 09, 05, 07, 0b, 11, 09, 0d, 01, 05, 01, 05, 22, 11, 01, 05, 22, 11, 01, 05, 0a, 01, 16, 01, 00, 28, 03, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 28, 04, 03, 00, 0d, 00, 18, 30, 05, 22, 01, 00, 02, 00, 0d, 00, 0e, 22, 00, 12, 00, 13, 30, 1e, 11, 02, 03, 00, 00, 12, 00, 13, 1e, 00, 17, 00, 18, 30, 09, 0d, 03, 00, 00, 00, 17, 00, 18, 03, 01, 05, 01, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 9 @@ -17,7 +17,7 @@ Number of file 0 mappings: 10 - Code(Expression(0, Add)) at (prev + 1, 9) to (start + 0, 10) = (c1 + ((c2 + c3) + c4)) - Code(Counter(0)) at (prev + 0, 13) to (start + 0, 14) -- MCDCDecision { bitmap_idx: 0, conditions_num: 3 } at (prev + 0, 13) to (start + 0, 24) +- MCDCDecision { bitmap_idx: 4, conditions_num: 3 } at (prev + 0, 13) to (start + 0, 24) - MCDCBranch { true: Counter(1), false: Expression(8, Sub), condition_id: 1, true_next_id: 0, false_next_id: 2 } at (prev + 0, 13) to (start + 0, 14) true = c1 false = (c0 - c1) @@ -35,7 +35,7 @@ Number of file 0 mappings: 10 = (c1 + ((c2 + c3) + c4)) Function name: non_control_flow::assign_3_bis -Raw bytes (85): 0x[01, 01, 07, 07, 11, 09, 0d, 01, 05, 05, 09, 16, 1a, 05, 09, 01, 05, 0a, 01, 1b, 01, 00, 2c, 03, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 28, 00, 03, 00, 0d, 00, 18, 30, 05, 1a, 01, 03, 02, 00, 0d, 00, 0e, 05, 00, 12, 00, 13, 30, 09, 16, 03, 00, 02, 00, 12, 00, 13, 13, 00, 17, 00, 18, 30, 0d, 11, 02, 00, 00, 00, 17, 00, 18, 03, 01, 05, 01, 02] +Raw bytes (85): 0x[01, 01, 07, 07, 11, 09, 0d, 01, 05, 05, 09, 16, 1a, 05, 09, 01, 05, 0a, 01, 1b, 01, 00, 2c, 03, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 28, 05, 03, 00, 0d, 00, 18, 30, 05, 1a, 01, 03, 02, 00, 0d, 00, 0e, 05, 00, 12, 00, 13, 30, 09, 16, 03, 00, 02, 00, 12, 00, 13, 13, 00, 17, 00, 18, 30, 0d, 11, 02, 00, 00, 00, 17, 00, 18, 03, 01, 05, 01, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 7 @@ -51,7 +51,7 @@ Number of file 0 mappings: 10 - Code(Expression(0, Add)) at (prev + 1, 9) to (start + 0, 10) = ((c2 + c3) + c4) - Code(Counter(0)) at (prev + 0, 13) to (start + 0, 14) -- MCDCDecision { bitmap_idx: 0, conditions_num: 3 } at (prev + 0, 13) to (start + 0, 24) +- MCDCDecision { bitmap_idx: 5, conditions_num: 3 } at (prev + 0, 13) to (start + 0, 24) - MCDCBranch { true: Counter(1), false: Expression(6, Sub), condition_id: 1, true_next_id: 3, false_next_id: 2 } at (prev + 0, 13) to (start + 0, 14) true = c1 false = (c0 - c1) @@ -68,7 +68,7 @@ Number of file 0 mappings: 10 = ((c2 + c3) + c4) Function name: non_control_flow::assign_and -Raw bytes (64): 0x[01, 01, 04, 07, 0e, 09, 0d, 01, 05, 01, 05, 08, 01, 0c, 01, 00, 21, 03, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 28, 00, 02, 00, 0d, 00, 13, 30, 05, 0e, 01, 02, 00, 00, 0d, 00, 0e, 05, 00, 12, 00, 13, 30, 09, 0d, 02, 00, 00, 00, 12, 00, 13, 03, 01, 05, 01, 02] +Raw bytes (64): 0x[01, 01, 04, 07, 0e, 09, 0d, 01, 05, 01, 05, 08, 01, 0c, 01, 00, 21, 03, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 28, 03, 02, 00, 0d, 00, 13, 30, 05, 0e, 01, 02, 00, 00, 0d, 00, 0e, 05, 00, 12, 00, 13, 30, 09, 0d, 02, 00, 00, 00, 12, 00, 13, 03, 01, 05, 01, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 4 @@ -81,7 +81,7 @@ Number of file 0 mappings: 8 - Code(Expression(0, Add)) at (prev + 1, 9) to (start + 0, 10) = ((c2 + c3) + (c0 - c1)) - Code(Counter(0)) at (prev + 0, 13) to (start + 0, 14) -- MCDCDecision { bitmap_idx: 0, conditions_num: 2 } at (prev + 0, 13) to (start + 0, 19) +- MCDCDecision { bitmap_idx: 3, conditions_num: 2 } at (prev + 0, 13) to (start + 0, 19) - MCDCBranch { true: Counter(1), false: Expression(3, Sub), condition_id: 1, true_next_id: 2, false_next_id: 0 } at (prev + 0, 13) to (start + 0, 14) true = c1 false = (c0 - c1) @@ -93,7 +93,7 @@ Number of file 0 mappings: 8 = ((c2 + c3) + (c0 - c1)) Function name: non_control_flow::assign_or -Raw bytes (64): 0x[01, 01, 04, 07, 0d, 05, 09, 01, 05, 01, 05, 08, 01, 11, 01, 00, 20, 03, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 28, 00, 02, 00, 0d, 00, 13, 30, 05, 0e, 01, 00, 02, 00, 0d, 00, 0e, 0e, 00, 12, 00, 13, 30, 09, 0d, 02, 00, 00, 00, 12, 00, 13, 03, 01, 05, 01, 02] +Raw bytes (64): 0x[01, 01, 04, 07, 0d, 05, 09, 01, 05, 01, 05, 08, 01, 11, 01, 00, 20, 03, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 28, 03, 02, 00, 0d, 00, 13, 30, 05, 0e, 01, 00, 02, 00, 0d, 00, 0e, 0e, 00, 12, 00, 13, 30, 09, 0d, 02, 00, 00, 00, 12, 00, 13, 03, 01, 05, 01, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 4 @@ -106,7 +106,7 @@ Number of file 0 mappings: 8 - Code(Expression(0, Add)) at (prev + 1, 9) to (start + 0, 10) = ((c1 + c2) + c3) - Code(Counter(0)) at (prev + 0, 13) to (start + 0, 14) -- MCDCDecision { bitmap_idx: 0, conditions_num: 2 } at (prev + 0, 13) to (start + 0, 19) +- MCDCDecision { bitmap_idx: 3, conditions_num: 2 } at (prev + 0, 13) to (start + 0, 19) - MCDCBranch { true: Counter(1), false: Expression(3, Sub), condition_id: 1, true_next_id: 0, false_next_id: 2 } at (prev + 0, 13) to (start + 0, 14) true = c1 false = (c0 - c1) @@ -127,7 +127,7 @@ Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 37, 1) to (start + 2, 2) Function name: non_control_flow::func_call -Raw bytes (52): 0x[01, 01, 03, 01, 05, 0b, 02, 09, 0d, 06, 01, 29, 01, 01, 0a, 28, 00, 02, 01, 09, 00, 0f, 30, 05, 02, 01, 02, 00, 00, 09, 00, 0a, 05, 00, 0e, 00, 0f, 30, 09, 0d, 02, 00, 00, 00, 0e, 00, 0f, 07, 01, 01, 00, 02] +Raw bytes (52): 0x[01, 01, 03, 01, 05, 0b, 02, 09, 0d, 06, 01, 29, 01, 01, 0a, 28, 03, 02, 01, 09, 00, 0f, 30, 05, 02, 01, 02, 00, 00, 09, 00, 0a, 05, 00, 0e, 00, 0f, 30, 09, 0d, 02, 00, 00, 00, 0e, 00, 0f, 07, 01, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 3 @@ -136,7 +136,7 @@ Number of expressions: 3 - expression 2 operands: lhs = Counter(2), rhs = Counter(3) Number of file 0 mappings: 6 - Code(Counter(0)) at (prev + 41, 1) to (start + 1, 10) -- MCDCDecision { bitmap_idx: 0, conditions_num: 2 } at (prev + 1, 9) to (start + 0, 15) +- MCDCDecision { bitmap_idx: 3, conditions_num: 2 } at (prev + 1, 9) to (start + 0, 15) - MCDCBranch { true: Counter(1), false: Expression(0, Sub), condition_id: 1, true_next_id: 2, false_next_id: 0 } at (prev + 0, 9) to (start + 0, 10) true = c1 false = (c0 - c1) @@ -148,7 +148,7 @@ Number of file 0 mappings: 6 = ((c2 + c3) + (c0 - c1)) Function name: non_control_flow::right_comb_tree -Raw bytes (139): 0x[01, 01, 13, 07, 1a, 0b, 19, 0f, 15, 13, 11, 09, 0d, 01, 05, 01, 05, 05, 19, 05, 19, 4a, 15, 05, 19, 4a, 15, 05, 19, 46, 11, 4a, 15, 05, 19, 46, 11, 4a, 15, 05, 19, 0e, 01, 20, 01, 00, 41, 03, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 28, 00, 05, 00, 0d, 00, 2a, 30, 05, 1a, 01, 02, 00, 00, 0d, 00, 0e, 05, 00, 13, 00, 14, 30, 4a, 19, 02, 03, 00, 00, 13, 00, 14, 4a, 00, 19, 00, 1a, 30, 46, 15, 03, 04, 00, 00, 19, 00, 1a, 46, 00, 1f, 00, 20, 30, 42, 11, 04, 05, 00, 00, 1f, 00, 20, 42, 00, 24, 00, 27, 30, 09, 0d, 05, 00, 00, 00, 24, 00, 27, 03, 01, 05, 01, 02] +Raw bytes (139): 0x[01, 01, 13, 07, 1a, 0b, 19, 0f, 15, 13, 11, 09, 0d, 01, 05, 01, 05, 05, 19, 05, 19, 4a, 15, 05, 19, 4a, 15, 05, 19, 46, 11, 4a, 15, 05, 19, 46, 11, 4a, 15, 05, 19, 0e, 01, 20, 01, 00, 41, 03, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 28, 06, 05, 00, 0d, 00, 2a, 30, 05, 1a, 01, 02, 00, 00, 0d, 00, 0e, 05, 00, 13, 00, 14, 30, 4a, 19, 02, 03, 00, 00, 13, 00, 14, 4a, 00, 19, 00, 1a, 30, 46, 15, 03, 04, 00, 00, 19, 00, 1a, 46, 00, 1f, 00, 20, 30, 42, 11, 04, 05, 00, 00, 1f, 00, 20, 42, 00, 24, 00, 27, 30, 09, 0d, 05, 00, 00, 00, 24, 00, 27, 03, 01, 05, 01, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 19 @@ -176,7 +176,7 @@ Number of file 0 mappings: 14 - Code(Expression(0, Add)) at (prev + 1, 9) to (start + 0, 10) = (((((c2 + c3) + c4) + c5) + c6) + (c0 - c1)) - Code(Counter(0)) at (prev + 0, 13) to (start + 0, 14) -- MCDCDecision { bitmap_idx: 0, conditions_num: 5 } at (prev + 0, 13) to (start + 0, 42) +- MCDCDecision { bitmap_idx: 6, conditions_num: 5 } at (prev + 0, 13) to (start + 0, 42) - MCDCBranch { true: Counter(1), false: Expression(6, Sub), condition_id: 1, true_next_id: 2, false_next_id: 0 } at (prev + 0, 13) to (start + 0, 14) true = c1 false = (c0 - c1) diff --git a/tests/coverage/mcdc/non_control_flow.coverage b/tests/coverage/mcdc/non_control_flow.coverage index 570f565de74..cead419fbdf 100644 --- a/tests/coverage/mcdc/non_control_flow.coverage +++ b/tests/coverage/mcdc/non_control_flow.coverage @@ -83,11 +83,11 @@ | | C1, C2, C3 Result | 1 { F, F, - = F } - | 2 { T, -, - = T } - | 3 { F, T, T = T } + | 2 { F, T, T = T } + | 3 { T, -, - = T } | - | C1-Pair: covered: (1,2) - | C2-Pair: covered: (1,3) + | C1-Pair: covered: (1,3) + | C2-Pair: covered: (1,2) | C3-Pair: not covered | MC/DC Coverage for Decision: 66.67% | diff --git a/tests/ui/instrument-coverage/mcdc-condition-limit.bad.stderr b/tests/ui/instrument-coverage/mcdc-condition-limit.bad.stderr deleted file mode 100644 index b8b7d6e1a5e..00000000000 --- a/tests/ui/instrument-coverage/mcdc-condition-limit.bad.stderr +++ /dev/null @@ -1,8 +0,0 @@ -warning: number of conditions in decision (7) exceeds limit (6), so MC/DC analysis will not count this expression - --> $DIR/mcdc-condition-limit.rs:28:8 - | -LL | if a && b && c && d && e && f && g { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -warning: 1 warning emitted - diff --git a/tests/ui/instrument-coverage/mcdc-condition-limit.rs b/tests/ui/instrument-coverage/mcdc-condition-limit.rs index 91ff6381df7..118ae482fc6 100644 --- a/tests/ui/instrument-coverage/mcdc-condition-limit.rs +++ b/tests/ui/instrument-coverage/mcdc-condition-limit.rs @@ -1,5 +1,6 @@ //@ edition: 2021 -//@ revisions: good bad +//@ min-llvm-version: 19 +//@ revisions: good //@ check-pass //@ compile-flags: -Cinstrument-coverage -Zcoverage-options=mcdc -Zno-profiler-runtime @@ -14,18 +15,9 @@ #[cfg(good)] fn main() { - // 6 conditions is OK, so no diagnostic. - let [a, b, c, d, e, f] = <[bool; 6]>::default(); - if a && b && c && d && e && f { - core::hint::black_box("hello"); - } -} - -#[cfg(bad)] -fn main() { - // 7 conditions is too many, so issue a diagnostic. + // 7 conditions is allowed, so no diagnostic. let [a, b, c, d, e, f, g] = <[bool; 7]>::default(); - if a && b && c && d && e && f && g { //[bad]~ WARNING number of conditions in decision + if a && b && c && d && e && f && g { core::hint::black_box("hello"); } } From acd64fa0d9e5c17de02a5b2a592163a377e33bcc Mon Sep 17 00:00:00 2001 From: zhuyunxing Date: Tue, 9 Jul 2024 16:14:14 +0800 Subject: [PATCH 682/683] coverage. Warn about too many test vectors --- compiler/rustc_mir_transform/messages.ftl | 2 ++ compiler/rustc_mir_transform/src/coverage/mappings.rs | 8 +++++++- compiler/rustc_mir_transform/src/errors.rs | 8 ++++++++ 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_mir_transform/messages.ftl b/compiler/rustc_mir_transform/messages.ftl index b81c0906734..c8992b8b834 100644 --- a/compiler/rustc_mir_transform/messages.ftl +++ b/compiler/rustc_mir_transform/messages.ftl @@ -9,6 +9,8 @@ mir_transform_const_mut_borrow = taking a mutable reference to a `const` item .note2 = the mutable reference will refer to this temporary, not the original `const` item .note3 = mutable reference created due to call to this method +mir_transform_exceeds_mcdc_test_vector_limit = number of total test vectors in one function will exceed limit ({$max_num_test_vectors}) if this decision is instrumented, so MC/DC analysis ignores it + mir_transform_ffi_unwind_call = call to {$foreign -> [true] foreign function *[false] function pointer diff --git a/compiler/rustc_mir_transform/src/coverage/mappings.rs b/compiler/rustc_mir_transform/src/coverage/mappings.rs index c20f7a6f326..bc86ae22a0d 100644 --- a/compiler/rustc_mir_transform/src/coverage/mappings.rs +++ b/compiler/rustc_mir_transform/src/coverage/mappings.rs @@ -15,6 +15,7 @@ use crate::coverage::ExtractedHirInfo; use crate::coverage::graph::{BasicCoverageBlock, CoverageGraph, START_BCB}; use crate::coverage::spans::extract_refined_covspans; use crate::coverage::unexpand::unexpand_into_body_span; +use crate::errors::MCDCExceedsTestVectorLimit; /// Associates an ordinary executable code span with its corresponding BCB. #[derive(Debug)] @@ -108,6 +109,7 @@ pub(super) fn extract_all_mapping_info_from_mir<'tcx>( extract_mcdc_mappings( mir_body, + tcx, hir_info.body_span, basic_coverage_blocks, &mut mcdc_bitmap_bits, @@ -239,6 +241,7 @@ pub(super) fn extract_branch_pairs( pub(super) fn extract_mcdc_mappings( mir_body: &mir::Body<'_>, + tcx: TyCtxt<'_>, body_span: Span, basic_coverage_blocks: &CoverageGraph, mcdc_bitmap_bits: &mut usize, @@ -312,7 +315,10 @@ pub(super) fn extract_mcdc_mappings( } let num_test_vectors = calc_test_vectors_index(&mut branch_mappings); let Some(bitmap_idx) = get_bitmap_idx(num_test_vectors) else { - // TODO warn about bitmap + tcx.dcx().emit_warn(MCDCExceedsTestVectorLimit { + span: decision_span, + max_num_test_vectors: MCDC_MAX_BITMAP_SIZE, + }); mcdc_degraded_branches.extend(branch_mappings); return None; }; diff --git a/compiler/rustc_mir_transform/src/errors.rs b/compiler/rustc_mir_transform/src/errors.rs index fa279ace431..8b309147c64 100644 --- a/compiler/rustc_mir_transform/src/errors.rs +++ b/compiler/rustc_mir_transform/src/errors.rs @@ -89,6 +89,14 @@ pub(crate) struct FnItemRef { pub ident: String, } +#[derive(Diagnostic)] +#[diag(mir_transform_exceeds_mcdc_test_vector_limit)] +pub(crate) struct MCDCExceedsTestVectorLimit { + #[primary_span] + pub(crate) span: Span, + pub(crate) max_num_test_vectors: usize, +} + pub(crate) struct MustNotSupend<'a, 'tcx> { pub tcx: TyCtxt<'tcx>, pub yield_sp: Span, From 537fb8d1bb2405b118898c663bc076815a1762c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Tue, 8 Oct 2024 14:25:24 +0300 Subject: [PATCH 683/683] Preparing for merge from rust-lang/rust --- src/tools/rust-analyzer/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer/rust-version b/src/tools/rust-analyzer/rust-version index 79ed6cc7d74..f217c6a19cb 100644 --- a/src/tools/rust-analyzer/rust-version +++ b/src/tools/rust-analyzer/rust-version @@ -1 +1 @@ -1b5aa96d6016bafe50e071b45d4d2e3c90fd766f +cf24c73141a77db730f4b7fda69dcd7e8b113b51

    { | ^^^^^^^^^^ | - = note: the only supported types are integers, `bool` and `char` + = note: the only supported types are integers, `bool`, and `char` error: aborting due to 2 previous errors diff --git a/tests/ui/const-generics/raw-ptr-const-param.min.stderr b/tests/ui/const-generics/raw-ptr-const-param.min.stderr index c48eea069e0..5694b12f2d5 100644 --- a/tests/ui/const-generics/raw-ptr-const-param.min.stderr +++ b/tests/ui/const-generics/raw-ptr-const-param.min.stderr @@ -4,7 +4,7 @@ error: using raw pointers as const generic parameters is forbidden LL | struct Const; | ^^^^^^^^^^ | - = note: the only supported types are integers, `bool` and `char` + = note: the only supported types are integers, `bool`, and `char` error[E0308]: mismatched types --> $DIR/raw-ptr-const-param.rs:11:40 diff --git a/tests/ui/const-generics/slice-const-param-mismatch.min.stderr b/tests/ui/const-generics/slice-const-param-mismatch.min.stderr index 3b2410c9894..594f8b9b79a 100644 --- a/tests/ui/const-generics/slice-const-param-mismatch.min.stderr +++ b/tests/ui/const-generics/slice-const-param-mismatch.min.stderr @@ -4,7 +4,7 @@ error: `&'static str` is forbidden as the type of a const generic parameter LL | struct ConstString; | ^^^^^^^^^^^^ | - = note: the only supported types are integers, `bool` and `char` + = note: the only supported types are integers, `bool`, and `char` help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types | LL + #![feature(adt_const_params)] @@ -20,7 +20,7 @@ error: `&'static [u8]` is forbidden as the type of a const generic parameter LL | struct ConstBytes; | ^^^^^^^^^^^^^ | - = note: the only supported types are integers, `bool` and `char` + = note: the only supported types are integers, `bool`, and `char` help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types | LL + #![feature(adt_const_params)] diff --git a/tests/ui/const-generics/std/const-generics-range.min.stderr b/tests/ui/const-generics/std/const-generics-range.min.stderr index 67f137cf1a0..fd23b9b248a 100644 --- a/tests/ui/const-generics/std/const-generics-range.min.stderr +++ b/tests/ui/const-generics/std/const-generics-range.min.stderr @@ -4,7 +4,7 @@ error: `std::ops::Range` is forbidden as the type of a const generic para LL | struct _Range>; | ^^^^^^^^^^^^^^^^^^^^^^ | - = note: the only supported types are integers, `bool` and `char` + = note: the only supported types are integers, `bool`, and `char` help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types | LL + #![feature(adt_const_params)] @@ -16,7 +16,7 @@ error: `RangeFrom` is forbidden as the type of a const generic parameter LL | struct _RangeFrom>; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: the only supported types are integers, `bool` and `char` + = note: the only supported types are integers, `bool`, and `char` help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types | LL + #![feature(adt_const_params)] @@ -28,7 +28,7 @@ error: `RangeFull` is forbidden as the type of a const generic parameter LL | struct _RangeFull; | ^^^^^^^^^^^^^^^^^^^ | - = note: the only supported types are integers, `bool` and `char` + = note: the only supported types are integers, `bool`, and `char` help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types | LL + #![feature(adt_const_params)] @@ -40,7 +40,7 @@ error: `RangeInclusive` is forbidden as the type of a const generic param LL | struct _RangeInclusive>; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: the only supported types are integers, `bool` and `char` + = note: the only supported types are integers, `bool`, and `char` help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types | LL + #![feature(adt_const_params)] @@ -52,7 +52,7 @@ error: `RangeTo` is forbidden as the type of a const generic parameter LL | struct _RangeTo>; | ^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: the only supported types are integers, `bool` and `char` + = note: the only supported types are integers, `bool`, and `char` help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types | LL + #![feature(adt_const_params)] @@ -64,7 +64,7 @@ error: `RangeToInclusive` is forbidden as the type of a const generic par LL | struct _RangeToInclusive>; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: the only supported types are integers, `bool` and `char` + = note: the only supported types are integers, `bool`, and `char` help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types | LL + #![feature(adt_const_params)] diff --git a/tests/ui/const-generics/transmute-const-param-static-reference.min.stderr b/tests/ui/const-generics/transmute-const-param-static-reference.min.stderr index cf236487cf0..911afa3391d 100644 --- a/tests/ui/const-generics/transmute-const-param-static-reference.min.stderr +++ b/tests/ui/const-generics/transmute-const-param-static-reference.min.stderr @@ -4,7 +4,7 @@ error: `&'static ()` is forbidden as the type of a const generic parameter LL | struct Const; | ^^^^^^^^^^^ | - = note: the only supported types are integers, `bool` and `char` + = note: the only supported types are integers, `bool`, and `char` help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types | LL + #![feature(adt_const_params)] diff --git a/tests/ui/const-generics/type-dependent/issue-71348.min.stderr b/tests/ui/const-generics/type-dependent/issue-71348.min.stderr index 5aee282952a..8995c415863 100644 --- a/tests/ui/const-generics/type-dependent/issue-71348.min.stderr +++ b/tests/ui/const-generics/type-dependent/issue-71348.min.stderr @@ -12,7 +12,7 @@ error: `&'static str` is forbidden as the type of a const generic parameter LL | trait Get<'a, const N: &'static str> { | ^^^^^^^^^^^^ | - = note: the only supported types are integers, `bool` and `char` + = note: the only supported types are integers, `bool`, and `char` help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types | LL + #![feature(adt_const_params)] @@ -28,7 +28,7 @@ error: `&'static str` is forbidden as the type of a const generic parameter LL | fn ask<'a, const N: &'static str>(&'a self) -> &'a >::Target | ^^^^^^^^^^^^ | - = note: the only supported types are integers, `bool` and `char` + = note: the only supported types are integers, `bool`, and `char` help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types | LL + #![feature(adt_const_params)] diff --git a/tests/ui/const-generics/type-dependent/issue-71382.stderr b/tests/ui/const-generics/type-dependent/issue-71382.stderr index 69fd6f1c7d5..3830b1527c3 100644 --- a/tests/ui/const-generics/type-dependent/issue-71382.stderr +++ b/tests/ui/const-generics/type-dependent/issue-71382.stderr @@ -4,7 +4,7 @@ error: using function pointers as const generic parameters is forbidden LL | fn test u8>(&self) -> u8 { | ^^^^^^^^^^ | - = note: the only supported types are integers, `bool` and `char` + = note: the only supported types are integers, `bool`, and `char` error: aborting due to 1 previous error diff --git a/tests/ui/consts/issue-103790.rs b/tests/ui/consts/issue-103790.rs index d19115ede74..869a43e4018 100644 --- a/tests/ui/consts/issue-103790.rs +++ b/tests/ui/consts/issue-103790.rs @@ -6,6 +6,5 @@ struct S; //~| ERROR missing generics for struct `S` //~| ERROR cycle detected when computing type of `S::S` //~| ERROR `()` is forbidden as the type of a const generic parameter -//~| ERROR `S<{const error}, {const error}>` is forbidden as the type of a const generic parameter fn main() {} diff --git a/tests/ui/consts/issue-103790.stderr b/tests/ui/consts/issue-103790.stderr index c671f078cb5..1515fa60a5c 100644 --- a/tests/ui/consts/issue-103790.stderr +++ b/tests/ui/consts/issue-103790.stderr @@ -42,25 +42,13 @@ error: `()` is forbidden as the type of a const generic parameter LL | struct S; | ^^ | - = note: the only supported types are integers, `bool` and `char` + = note: the only supported types are integers, `bool`, and `char` help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types | LL + #![feature(adt_const_params)] | -error: `S<{const error}, {const error}>` is forbidden as the type of a const generic parameter - --> $DIR/issue-103790.rs:4:32 - | -LL | struct S; - | ^ - | - = note: the only supported types are integers, `bool` and `char` -help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types - | -LL + #![feature(adt_const_params)] - | - -error: aborting due to 5 previous errors +error: aborting due to 4 previous errors Some errors have detailed explanations: E0107, E0391, E0403. For more information about an error, try `rustc --explain E0107`. diff --git a/tests/ui/feature-gates/feature-gate-adt_const_params.stderr b/tests/ui/feature-gates/feature-gate-adt_const_params.stderr index 649e936888b..18d514f8cb5 100644 --- a/tests/ui/feature-gates/feature-gate-adt_const_params.stderr +++ b/tests/ui/feature-gates/feature-gate-adt_const_params.stderr @@ -4,7 +4,7 @@ error: `&'static str` is forbidden as the type of a const generic parameter LL | struct Foo; | ^^^^^^^^^^^^ | - = note: the only supported types are integers, `bool` and `char` + = note: the only supported types are integers, `bool`, and `char` help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types | LL + #![feature(adt_const_params)] diff --git a/tests/ui/feature-gates/feature-gate-unsized-const-params.stderr b/tests/ui/feature-gates/feature-gate-unsized-const-params.stderr index 0a87f34f4f5..85ca2f59cb6 100644 --- a/tests/ui/feature-gates/feature-gate-unsized-const-params.stderr +++ b/tests/ui/feature-gates/feature-gate-unsized-const-params.stderr @@ -4,7 +4,7 @@ error: `[u8]` is forbidden as the type of a const generic parameter LL | struct Foo; | ^^^^ | - = note: the only supported types are integers, `bool` and `char` + = note: the only supported types are integers, `bool`, and `char` help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types | LL + #![feature(adt_const_params)] diff --git a/tests/ui/generic-const-items/elided-lifetimes.rs b/tests/ui/generic-const-items/elided-lifetimes.rs index cca73e2e81e..90899de5af6 100644 --- a/tests/ui/generic-const-items/elided-lifetimes.rs +++ b/tests/ui/generic-const-items/elided-lifetimes.rs @@ -9,7 +9,6 @@ where const I: &str = ""; //~^ ERROR `&` without an explicit lifetime name cannot be used here -//~| ERROR `&str` is forbidden as the type of a const generic parameter const B>: () = (); //~ ERROR `'_` cannot be used here diff --git a/tests/ui/generic-const-items/elided-lifetimes.stderr b/tests/ui/generic-const-items/elided-lifetimes.stderr index 85807a1b631..2b543d02b5d 100644 --- a/tests/ui/generic-const-items/elided-lifetimes.stderr +++ b/tests/ui/generic-const-items/elided-lifetimes.stderr @@ -16,27 +16,11 @@ LL | const I: &str = ""; | ^ explicit lifetime name needed here error[E0637]: `'_` cannot be used here - --> $DIR/elided-lifetimes.rs:14:18 + --> $DIR/elided-lifetimes.rs:13:18 | LL | const B>: () = (); | ^^ `'_` is a reserved lifetime name -error: `&str` is forbidden as the type of a const generic parameter - --> $DIR/elided-lifetimes.rs:10:18 - | -LL | const I: &str = ""; - | ^^^^ - | - = note: the only supported types are integers, `bool` and `char` -help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types - | -LL + #![feature(adt_const_params)] - | -help: add `#![feature(unsized_const_params)]` to the crate attributes to enable references to implement the `ConstParamTy` trait - | -LL + #![feature(unsized_const_params)] - | - -error: aborting due to 4 previous errors +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0637`. diff --git a/tests/ui/generic-const-items/wfcheck_err_leak_issue_118179.rs b/tests/ui/generic-const-items/wfcheck_err_leak_issue_118179.rs new file mode 100644 index 00000000000..856f7b622d7 --- /dev/null +++ b/tests/ui/generic-const-items/wfcheck_err_leak_issue_118179.rs @@ -0,0 +1,7 @@ +//! Regression test for #118179: `adt_const_params` feature shouldn't leak +//! `{type error}` in error messages. + +struct G>(T); +//~^ ERROR the type of const parameters must not depend on other generic parameters + +fn main() {} diff --git a/tests/ui/generic-const-items/wfcheck_err_leak_issue_118179.stderr b/tests/ui/generic-const-items/wfcheck_err_leak_issue_118179.stderr new file mode 100644 index 00000000000..654004571db --- /dev/null +++ b/tests/ui/generic-const-items/wfcheck_err_leak_issue_118179.stderr @@ -0,0 +1,11 @@ +error[E0770]: the type of const parameters must not depend on other generic parameters + --> $DIR/wfcheck_err_leak_issue_118179.rs:4:26 + | +LL | struct G>(T); + | ^ the type must not depend on the parameter `T` + | + = note: type parameters may not be used in the type of const parameters + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0770`. diff --git a/tests/ui/lifetimes/unusual-rib-combinations.rs b/tests/ui/lifetimes/unusual-rib-combinations.rs index 0708a00d371..0e92b41ae1e 100644 --- a/tests/ui/lifetimes/unusual-rib-combinations.rs +++ b/tests/ui/lifetimes/unusual-rib-combinations.rs @@ -20,11 +20,9 @@ fn c() {} // Elided lifetime in path in ConstGeneric fn d() {} //~^ ERROR missing lifetime specifier -//~| ERROR `S<'_>` is forbidden as the type of a const generic parameter trait Foo<'a> {} struct Bar Foo<'a>)>; //~^ ERROR the type of const parameters must not depend on other generic parameters -//~| ERROR `&dyn for<'a> Foo<'a>` is forbidden as the type of a const generic parameter fn main() {} diff --git a/tests/ui/lifetimes/unusual-rib-combinations.stderr b/tests/ui/lifetimes/unusual-rib-combinations.stderr index ebf6f6ca403..b7effdc8d61 100644 --- a/tests/ui/lifetimes/unusual-rib-combinations.stderr +++ b/tests/ui/lifetimes/unusual-rib-combinations.stderr @@ -5,7 +5,7 @@ LL | fn d() {} | ^ expected named lifetime parameter error[E0770]: the type of const parameters must not depend on other generic parameters - --> $DIR/unusual-rib-combinations.rs:26:22 + --> $DIR/unusual-rib-combinations.rs:25:22 | LL | struct Bar Foo<'a>)>; | ^^ the type must not depend on the parameter `'a` @@ -40,35 +40,7 @@ error[E0308]: mismatched types LL | fn a() -> [u8; foo()] { | ^^^^^ expected `usize`, found `()` -error: `S<'_>` is forbidden as the type of a const generic parameter - --> $DIR/unusual-rib-combinations.rs:21:15 - | -LL | fn d() {} - | ^ - | - = note: the only supported types are integers, `bool` and `char` -help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types - | -LL + #![feature(adt_const_params)] - | - -error: `&dyn for<'a> Foo<'a>` is forbidden as the type of a const generic parameter - --> $DIR/unusual-rib-combinations.rs:26:21 - | -LL | struct Bar Foo<'a>)>; - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: the only supported types are integers, `bool` and `char` -help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types - | -LL + #![feature(adt_const_params)] - | -help: add `#![feature(unsized_const_params)]` to the crate attributes to enable references to implement the `ConstParamTy` trait - | -LL + #![feature(unsized_const_params)] - | - -error: aborting due to 8 previous errors +error: aborting due to 6 previous errors Some errors have detailed explanations: E0106, E0214, E0308, E0770. For more information about an error, try `rustc --explain E0106`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/mismatched_generic_args.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/mismatched_generic_args.stderr index 8c814295de4..8e12b40381f 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/mismatched_generic_args.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/mismatched_generic_args.stderr @@ -22,7 +22,7 @@ error: `Dimension` is forbidden as the type of a const generic parameter LL | pub struct Quantity(S); | ^^^^^^^^^ | - = note: the only supported types are integers, `bool` and `char` + = note: the only supported types are integers, `bool`, and `char` help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types | LL + #![feature(adt_const_params)] @@ -40,7 +40,7 @@ error: `Dimension` is forbidden as the type of a const generic parameter LL | impl Add for Quantity {} | ^^^^^^^^^ | - = note: the only supported types are integers, `bool` and `char` + = note: the only supported types are integers, `bool`, and `char` help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types | LL + #![feature(adt_const_params)] @@ -52,7 +52,7 @@ error: `Dimension` is forbidden as the type of a const generic parameter LL | pub fn add(x: Quantity) -> Quantity { | ^^^^^^^^^ | - = note: the only supported types are integers, `bool` and `char` + = note: the only supported types are integers, `bool`, and `char` help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types | LL + #![feature(adt_const_params)] diff --git a/tests/ui/specialization/default-proj-ty-as-type-of-const-issue-125757.stderr b/tests/ui/specialization/default-proj-ty-as-type-of-const-issue-125757.stderr index 7094ee8c67c..8df76b296ac 100644 --- a/tests/ui/specialization/default-proj-ty-as-type-of-const-issue-125757.stderr +++ b/tests/ui/specialization/default-proj-ty-as-type-of-const-issue-125757.stderr @@ -4,7 +4,7 @@ error: `::Type` is forbidden as the type of a const generic parame LL | struct Wrapper::Type> {} | ^^^^^^^^^^^^^^^^^^^^ | - = note: the only supported types are integers, `bool` and `char` + = note: the only supported types are integers, `bool`, and `char` error: the constant `C` is not of type `::Type` --> $DIR/default-proj-ty-as-type-of-const-issue-125757.rs:15:22 diff --git a/tests/ui/traits/next-solver/canonical/const-region-infer-to-static-in-binder.stderr b/tests/ui/traits/next-solver/canonical/const-region-infer-to-static-in-binder.stderr index e0cbee88aa1..377dfc8b529 100644 --- a/tests/ui/traits/next-solver/canonical/const-region-infer-to-static-in-binder.stderr +++ b/tests/ui/traits/next-solver/canonical/const-region-infer-to-static-in-binder.stderr @@ -10,7 +10,7 @@ error: using function pointers as const generic parameters is forbidden LL | struct X; | ^^^^ | - = note: the only supported types are integers, `bool` and `char` + = note: the only supported types are integers, `bool`, and `char` error: using function pointers as const generic parameters is forbidden --> $DIR/const-region-infer-to-static-in-binder.rs:4:20 @@ -18,7 +18,7 @@ error: using function pointers as const generic parameters is forbidden LL | struct X; | ^^^^ | - = note: the only supported types are integers, `bool` and `char` + = note: the only supported types are integers, `bool`, and `char` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: aborting due to 3 previous errors diff --git a/tests/ui/type-alias-impl-trait/const_generic_type.infer.stderr b/tests/ui/type-alias-impl-trait/const_generic_type.infer.stderr index 3b6999cabc4..b7999a695e7 100644 --- a/tests/ui/type-alias-impl-trait/const_generic_type.infer.stderr +++ b/tests/ui/type-alias-impl-trait/const_generic_type.infer.stderr @@ -4,7 +4,7 @@ error: `Bar` is forbidden as the type of a const generic parameter LL | async fn test() { | ^^^^^^^^^^ | - = note: the only supported types are integers, `bool` and `char` + = note: the only supported types are integers, `bool`, and `char` error: aborting due to 1 previous error diff --git a/tests/ui/type-alias-impl-trait/const_generic_type.no_infer.stderr b/tests/ui/type-alias-impl-trait/const_generic_type.no_infer.stderr index 55a5a3d2000..b526ab49d8d 100644 --- a/tests/ui/type-alias-impl-trait/const_generic_type.no_infer.stderr +++ b/tests/ui/type-alias-impl-trait/const_generic_type.no_infer.stderr @@ -45,7 +45,7 @@ error: `Bar` is forbidden as the type of a const generic parameter LL | async fn test() { | ^^^^^^^^^^ | - = note: the only supported types are integers, `bool` and `char` + = note: the only supported types are integers, `bool`, and `char` error: aborting due to 4 previous errors diff --git a/tests/ui/typeck/ice-unexpected-region-123863.stderr b/tests/ui/typeck/ice-unexpected-region-123863.stderr index 0479f134a38..742096f3861 100644 --- a/tests/ui/typeck/ice-unexpected-region-123863.stderr +++ b/tests/ui/typeck/ice-unexpected-region-123863.stderr @@ -4,7 +4,7 @@ error: `&'static str` is forbidden as the type of a const generic parameter LL | const fn concat_strs() -> &'static str { | ^^^^^^^^^^^^ | - = note: the only supported types are integers, `bool` and `char` + = note: the only supported types are integers, `bool`, and `char` help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types | LL + #![feature(adt_const_params)] @@ -20,7 +20,7 @@ error: `&'static str` is forbidden as the type of a const generic parameter LL | struct Inner; | ^^^^^^^^^^^^ | - = note: the only supported types are integers, `bool` and `char` + = note: the only supported types are integers, `bool`, and `char` help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types | LL + #![feature(adt_const_params)] diff --git a/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122199.rs b/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122199.rs index 3f43fbfc0cf..53363319ba0 100644 --- a/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122199.rs +++ b/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122199.rs @@ -4,7 +4,6 @@ trait Trait { //~| ERROR the trait `Trait` cannot be made into an object //~| ERROR the trait `Trait` cannot be made into an object //~| ERROR the trait `Trait` cannot be made into an object - //~| ERROR `(dyn Trait<{const error}> + 'static)` is forbidden as the type of a const generic parameter //~| WARN trait objects without an explicit `dyn` are deprecated [bare_trait_objects] //~| WARN this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! //~| WARN trait objects without an explicit `dyn` are deprecated [bare_trait_objects] @@ -15,7 +14,6 @@ trait Trait { //~| ERROR defaults for const parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions //~| ERROR associated item referring to unboxed trait object for its own trait //~| ERROR the trait `Trait` cannot be made into an object - //~| ERROR `(dyn Trait<{const error}> + 'static)` is forbidden as the type of a const generic parameter //~| WARN trait objects without an explicit `dyn` are deprecated [bare_trait_objects] //~| WARN this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! //~| WARN trait objects without an explicit `dyn` are deprecated [bare_trait_objects] diff --git a/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122199.stderr b/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122199.stderr index 6b309c223af..fefb788fac7 100644 --- a/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122199.stderr +++ b/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122199.stderr @@ -1,5 +1,5 @@ error[E0403]: the name `N` is already used for a generic parameter in this item's generic parameters - --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:12:18 + --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:11:18 | LL | trait Trait { | - first use of `N` @@ -14,13 +14,13 @@ LL | trait Trait { | ^^^ not found in this scope error[E0423]: expected value, found builtin type `u32` - --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:12:29 + --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:11:29 | LL | fn fnc(&self) -> Trait { | ^^^ not a value error[E0425]: cannot find value `bar` in this scope - --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:25:9 + --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:23:9 | LL | bar | ^^^ not found in this scope @@ -54,13 +54,13 @@ LL | trait Trait { = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information error: defaults for const parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions - --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:12:12 + --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:11:12 | LL | fn fnc(&self) -> Trait { | ^^^^^^^^^^^^^^^^^^^^ warning: trait objects without an explicit `dyn` are deprecated - --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:12:21 + --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:11:21 | LL | fn fnc(&self) -> Trait { | ^^^^^ @@ -73,7 +73,7 @@ LL | fn fnc(&self) -> Trait { | +++ warning: trait objects without an explicit `dyn` are deprecated - --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:12:44 + --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:11:44 | LL | fn fnc(&self) -> Trait { | ^^^^^ @@ -106,7 +106,7 @@ LL | trait Trait { | ^^^^^ `Trait` cannot be made into an object | note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit - --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:12:8 + --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:11:8 | LL | trait Trait { | ----- this trait cannot be made into an object... @@ -122,7 +122,7 @@ LL | trait Trait { | ^^^^^^^^^^^^^^^^^^^^ `Trait` cannot be made into an object | note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit - --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:12:8 + --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:11:8 | LL | trait Trait { | ----- this trait cannot be made into an object... @@ -131,16 +131,8 @@ LL | fn fnc(&self) -> Trait { | ^^^ ...because method `fnc` has generic type parameters = help: consider moving `fnc` to another trait -error: `(dyn Trait<{const error}> + 'static)` is forbidden as the type of a const generic parameter - --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:1:22 - | -LL | trait Trait { - | ^^^^^ - | - = note: the only supported types are integers, `bool` and `char` - error: associated item referring to unboxed trait object for its own trait - --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:12:44 + --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:11:44 | LL | trait Trait { | ----- in this trait @@ -154,7 +146,7 @@ LL | fn fnc(&self) -> Self { | ~~~~ warning: trait objects without an explicit `dyn` are deprecated - --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:12:21 + --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:11:21 | LL | fn fnc(&self) -> Trait { | ^^^^^ @@ -168,13 +160,13 @@ LL | fn fnc(&self) -> Trait { | +++ error[E0038]: the trait `Trait` cannot be made into an object - --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:12:21 + --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:11:21 | LL | fn fnc(&self) -> Trait { | ^^^^^ `Trait` cannot be made into an object | note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit - --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:12:8 + --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:11:8 | LL | trait Trait { | ----- this trait cannot be made into an object... @@ -190,7 +182,7 @@ LL | trait Trait { | ^^^^^^^^^^^^^^^^^^^^ `Trait` cannot be made into an object | note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit - --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:12:8 + --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:11:8 | LL | trait Trait { | ----- this trait cannot be made into an object... @@ -200,15 +192,7 @@ LL | fn fnc(&self) -> Trait { = help: consider moving `fnc` to another trait = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error: `(dyn Trait<{const error}> + 'static)` is forbidden as the type of a const generic parameter - --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:12:21 - | -LL | fn fnc(&self) -> Trait { - | ^^^^^ - | - = note: the only supported types are integers, `bool` and `char` - -error: aborting due to 13 previous errors; 5 warnings emitted +error: aborting due to 11 previous errors; 5 warnings emitted Some errors have detailed explanations: E0038, E0391, E0403, E0423, E0425. For more information about an error, try `rustc --explain E0038`. diff --git a/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122989.stderr b/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122989.stderr index d2b0e2d92e0..f8905437c6e 100644 --- a/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122989.stderr +++ b/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122989.stderr @@ -73,7 +73,7 @@ error: `(dyn Bar<2> + 'static)` is forbidden as the type of a const generic para LL | trait Foo> { | ^^^^^^ | - = note: the only supported types are integers, `bool` and `char` + = note: the only supported types are integers, `bool`, and `char` error[E0038]: the trait `Foo` cannot be made into an object --> $DIR/ice-hir-wf-check-anon-const-issue-122989.rs:11:11 @@ -104,7 +104,7 @@ error: `(dyn Foo<2> + 'static)` is forbidden as the type of a const generic para LL | trait Bar> {} | ^^^^^^ | - = note: the only supported types are integers, `bool` and `char` + = note: the only supported types are integers, `bool`, and `char` error: aborting due to 5 previous errors; 2 warnings emitted From 4b8a5bd511814ed97640c46ab2232acc0e0ade41 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 26 Sep 2024 16:48:32 +0200 Subject: [PATCH 422/683] panic when an interpreter error gets unintentionally discarded --- .../rustc_const_eval/src/interpret/place.rs | 19 ++- .../src/interpret/validity.rs | 38 +++--- .../src/util/check_validity_requirement.rs | 4 +- .../rustc_middle/src/mir/interpret/error.rs | 61 +++++++++- .../rustc_middle/src/mir/interpret/mod.rs | 12 +- .../src/dataflow_const_prop.rs | 61 ++++++---- compiler/rustc_mir_transform/src/gvn.rs | 115 ++++++++++-------- .../rustc_mir_transform/src/jump_threading.rs | 53 +++++--- .../src/known_panics_lint.rs | 35 +++--- src/tools/miri/src/concurrency/data_race.rs | 2 +- src/tools/miri/src/diagnostics.rs | 6 +- src/tools/miri/src/intrinsics/simd.rs | 3 +- 12 files changed, 262 insertions(+), 147 deletions(-) diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs index 32f90254a94..05264d32c6b 100644 --- a/compiler/rustc_const_eval/src/interpret/place.rs +++ b/compiler/rustc_const_eval/src/interpret/place.rs @@ -13,9 +13,9 @@ use rustc_target::abi::{Abi, Align, HasDataLayout, Size}; use tracing::{instrument, trace}; use super::{ - AllocRef, AllocRefMut, CheckAlignMsg, CtfeProvenance, ImmTy, Immediate, InterpCx, InterpResult, - Machine, MemoryKind, Misalignment, OffsetMode, OpTy, Operand, Pointer, Projectable, Provenance, - Scalar, alloc_range, mir_assign_valid_types, + AllocRef, AllocRefMut, CheckAlignMsg, CtfeProvenance, DiscardInterpError, ImmTy, Immediate, + InterpCx, InterpResult, Machine, MemoryKind, Misalignment, OffsetMode, OpTy, Operand, Pointer, + Projectable, Provenance, Scalar, alloc_range, mir_assign_valid_types, }; #[derive(Copy, Clone, Hash, PartialEq, Eq, Debug)] @@ -490,9 +490,16 @@ where // If an access is both OOB and misaligned, we want to see the bounds error. // However we have to call `check_misalign` first to make the borrow checker happy. let misalign_err = self.check_misalign(mplace.mplace.misaligned, CheckAlignMsg::BasedOn); - let a = self.get_ptr_alloc_mut(mplace.ptr(), size)?; - misalign_err?; - Ok(a) + match self.get_ptr_alloc_mut(mplace.ptr(), size) { + Ok(a) => { + misalign_err?; + Ok(a) + } + Err(e) => { + misalign_err.discard_interp_err(); + Err(e) + } + } } /// Turn a local in the current frame into a place. diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs index 203cceccd9d..3c9fdd73100 100644 --- a/compiler/rustc_const_eval/src/interpret/validity.rs +++ b/compiler/rustc_const_eval/src/interpret/validity.rs @@ -17,8 +17,8 @@ use rustc_hir as hir; use rustc_middle::bug; use rustc_middle::mir::interpret::ValidationErrorKind::{self, *}; use rustc_middle::mir::interpret::{ - ExpectedKind, InterpError, InvalidMetaKind, Misalignment, PointerKind, Provenance, - UnsupportedOpInfo, ValidationErrorInfo, alloc_range, + ExpectedKind, InterpError, InterpErrorInfo, InvalidMetaKind, Misalignment, PointerKind, + Provenance, UnsupportedOpInfo, ValidationErrorInfo, alloc_range, }; use rustc_middle::ty::layout::{LayoutCx, LayoutOf, TyAndLayout}; use rustc_middle::ty::{self, Ty}; @@ -95,16 +95,19 @@ macro_rules! try_validation { Ok(x) => x, // We catch the error and turn it into a validation failure. We are okay with // allocation here as this can only slow down builds that fail anyway. - Err(e) => match e.kind() { - $( - $($p)|+ => - throw_validation_failure!( - $where, - $kind - ) - ),+, - #[allow(unreachable_patterns)] - _ => Err::(e)?, + Err(e) => { + let (kind, backtrace) = e.into_parts(); + match kind { + $( + $($p)|+ => { + throw_validation_failure!( + $where, + $kind + ) + } + ),+, + _ => Err::(InterpErrorInfo::from_parts(kind, backtrace))?, + } } } }}; @@ -510,7 +513,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { Ub(DanglingIntPointer { addr: i, .. }) => DanglingPtrNoProvenance { ptr_kind, // FIXME this says "null pointer" when null but we need translate - pointer: format!("{}", Pointer::>::from_addr_invalid(*i)) + pointer: format!("{}", Pointer::>::from_addr_invalid(i)) }, Ub(PointerOutOfBounds { .. }) => DanglingPtrOutOfBounds { ptr_kind @@ -1231,7 +1234,8 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValueVisitor<'tcx, M> for ValidityVisitor<'rt, Err(err) => { // For some errors we might be able to provide extra information. // (This custom logic does not fit the `try_validation!` macro.) - match err.kind() { + let (kind, backtrace) = err.into_parts(); + match kind { Ub(InvalidUninitBytes(Some((_alloc_id, access)))) | Unsup(ReadPointerAsInt(Some((_alloc_id, access)))) => { // Some byte was uninitialized, determine which // element that byte belongs to so we can @@ -1242,7 +1246,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValueVisitor<'tcx, M> for ValidityVisitor<'rt, .unwrap(); self.path.push(PathElem::ArrayElem(i)); - if matches!(err.kind(), Ub(InvalidUninitBytes(_))) { + if matches!(kind, Ub(InvalidUninitBytes(_))) { throw_validation_failure!(self.path, Uninit { expected }) } else { throw_validation_failure!(self.path, PointerAsInt { expected }) @@ -1250,7 +1254,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValueVisitor<'tcx, M> for ValidityVisitor<'rt, } // Propagate upwards (that will also check for unexpected errors). - _ => return Err(err), + _ => return Err(InterpErrorInfo::from_parts(kind, backtrace)), } } } @@ -1282,7 +1286,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValueVisitor<'tcx, M> for ValidityVisitor<'rt, // It's not great to catch errors here, since we can't give a very good path, // but it's better than ICEing. Ub(InvalidVTableTrait { vtable_dyn_type, expected_dyn_type }) => { - InvalidMetaWrongTrait { vtable_dyn_type, expected_dyn_type: *expected_dyn_type } + InvalidMetaWrongTrait { vtable_dyn_type, expected_dyn_type } }, ); } diff --git a/compiler/rustc_const_eval/src/util/check_validity_requirement.rs b/compiler/rustc_const_eval/src/util/check_validity_requirement.rs index 19393188c9a..421648d9e7b 100644 --- a/compiler/rustc_const_eval/src/util/check_validity_requirement.rs +++ b/compiler/rustc_const_eval/src/util/check_validity_requirement.rs @@ -1,4 +1,5 @@ use rustc_middle::bug; +use rustc_middle::mir::interpret::DiscardInterpError; use rustc_middle::ty::layout::{ HasTyCtxt, LayoutCx, LayoutError, LayoutOf, TyAndLayout, ValidityRequirement, }; @@ -75,7 +76,8 @@ fn check_validity_requirement_strict<'tcx>( /*recursive*/ false, /*reset_provenance_and_padding*/ false, ) - .is_ok()) + .discard_interp_err() + .is_some()) } /// Implements the 'lax' (default) version of the [`check_validity_requirement`] checks; see that diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs index 46646e759d5..06fdb9e1ecd 100644 --- a/compiler/rustc_middle/src/mir/interpret/error.rs +++ b/compiler/rustc_middle/src/mir/interpret/error.rs @@ -1,7 +1,7 @@ use std::any::Any; use std::backtrace::Backtrace; use std::borrow::Cow; -use std::fmt; +use std::{fmt, mem}; use either::Either; use rustc_ast_ir::Mutability; @@ -104,13 +104,57 @@ rustc_data_structures::static_assert_size!(InterpErrorInfo<'_>, 8); /// These should always be constructed by calling `.into()` on /// an `InterpError`. In `rustc_mir::interpret`, we have `throw_err_*` /// macros for this. +/// +/// Interpreter errors must *not* be silently discarded (that will lead to a panic). Instead, +/// explicitly call `discard_interp_err` if this is really the right thing to do. Note that if +/// this happens during const-eval or in Miri, it could lead to a UB error being lost! #[derive(Debug)] pub struct InterpErrorInfo<'tcx>(Box>); +/// Calling `.ok()` on an `InterpResult` leads to a panic because of the guard. +/// To still let people opt-in to discarding interpreter errors, we have this extension trait. +pub trait DiscardInterpError { + type Output; + + fn discard_interp_err(self) -> Option; +} + +impl<'tcx, T> DiscardInterpError for InterpResult<'tcx, T> { + type Output = T; + + fn discard_interp_err(self) -> Option { + match self { + Ok(v) => Some(v), + Err(e) => { + // Disarm the guard. + mem::forget(e.0.guard); + None + } + } + } +} + +#[derive(Debug)] +struct Guard; + +impl Drop for Guard { + fn drop(&mut self) { + // We silence the guard if we are already panicking, to avoid double-panics. + if !std::thread::panicking() { + panic!( + "an interpreter error got improperly discarded; use `discard_interp_err()` instead of `ok()` if this is intentional" + ); + } + } +} + #[derive(Debug)] struct InterpErrorInfoInner<'tcx> { kind: InterpError<'tcx>, backtrace: InterpErrorBacktrace, + /// This makes us panic on drop. This is used to catch + /// accidentally discarding an interpreter error. + guard: Guard, } #[derive(Debug)] @@ -151,15 +195,25 @@ impl InterpErrorBacktrace { impl<'tcx> InterpErrorInfo<'tcx> { pub fn into_parts(self) -> (InterpError<'tcx>, InterpErrorBacktrace) { - let InterpErrorInfo(box InterpErrorInfoInner { kind, backtrace }) = self; + let InterpErrorInfo(box InterpErrorInfoInner { kind, backtrace, guard }) = self; + mem::forget(guard); // The error got explicitly discarded right here. (kind, backtrace) } pub fn into_kind(self) -> InterpError<'tcx> { - let InterpErrorInfo(box InterpErrorInfoInner { kind, .. }) = self; + let InterpErrorInfo(box InterpErrorInfoInner { kind, guard, .. }) = self; + mem::forget(guard); // The error got explicitly discarded right here. kind } + pub fn discard_interp_err(self) { + mem::forget(self.0.guard); // The error got explicitly discarded right here. + } + + pub fn from_parts(kind: InterpError<'tcx>, backtrace: InterpErrorBacktrace) -> Self { + Self(Box::new(InterpErrorInfoInner { kind, backtrace, guard: Guard })) + } + #[inline] pub fn kind(&self) -> &InterpError<'tcx> { &self.0.kind @@ -191,6 +245,7 @@ impl<'tcx> From> for InterpErrorInfo<'tcx> { InterpErrorInfo(Box::new(InterpErrorInfoInner { kind, backtrace: InterpErrorBacktrace::new(), + guard: Guard, })) } } diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs index d7809cc4343..8ce6f9d2300 100644 --- a/compiler/rustc_middle/src/mir/interpret/mod.rs +++ b/compiler/rustc_middle/src/mir/interpret/mod.rs @@ -34,12 +34,12 @@ pub use self::allocation::{ InitChunkIter, alloc_range, }; pub use self::error::{ - BadBytesAccess, CheckAlignMsg, CheckInAllocMsg, ErrorHandled, EvalStaticInitializerRawResult, - EvalToAllocationRawResult, EvalToConstValueResult, EvalToValTreeResult, ExpectedKind, - InterpError, InterpErrorInfo, InterpResult, InvalidMetaKind, InvalidProgramInfo, - MachineStopType, Misalignment, PointerKind, ReportedErrorInfo, ResourceExhaustionInfo, - ScalarSizeMismatch, UndefinedBehaviorInfo, UnsupportedOpInfo, ValidationErrorInfo, - ValidationErrorKind, + BadBytesAccess, CheckAlignMsg, CheckInAllocMsg, DiscardInterpError, ErrorHandled, + EvalStaticInitializerRawResult, EvalToAllocationRawResult, EvalToConstValueResult, + EvalToValTreeResult, ExpectedKind, InterpError, InterpErrorInfo, InterpResult, InvalidMetaKind, + InvalidProgramInfo, MachineStopType, Misalignment, PointerKind, ReportedErrorInfo, + ResourceExhaustionInfo, ScalarSizeMismatch, UndefinedBehaviorInfo, UnsupportedOpInfo, + ValidationErrorInfo, ValidationErrorKind, }; pub use self::pointer::{CtfeProvenance, Pointer, PointerArithmetic, Provenance}; pub use self::value::Scalar; diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs index 88dc8e74a8c..905143b2efb 100644 --- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs +++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs @@ -3,7 +3,9 @@ //! Currently, this pass only propagates scalar values. use rustc_const_eval::const_eval::{DummyMachine, throw_machine_stop_str}; -use rustc_const_eval::interpret::{ImmTy, Immediate, InterpCx, OpTy, PlaceTy, Projectable}; +use rustc_const_eval::interpret::{ + DiscardInterpError, ImmTy, Immediate, InterpCx, OpTy, PlaceTy, Projectable, +}; use rustc_data_structures::fx::FxHashMap; use rustc_hir::def::DefKind; use rustc_middle::bug; @@ -364,8 +366,10 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> { } } Operand::Constant(box constant) => { - if let Ok(constant) = - self.ecx.eval_mir_constant(&constant.const_, constant.span, None) + if let Some(constant) = self + .ecx + .eval_mir_constant(&constant.const_, constant.span, None) + .discard_interp_err() { self.assign_constant(state, place, constant, &[]); } @@ -387,7 +391,7 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> { for &(mut proj_elem) in projection { if let PlaceElem::Index(index) = proj_elem { if let FlatSet::Elem(index) = state.get(index.into(), &self.map) - && let Ok(offset) = index.to_target_usize(&self.tcx) + && let Some(offset) = index.to_target_usize(&self.tcx).discard_interp_err() && let Some(min_length) = offset.checked_add(1) { proj_elem = PlaceElem::ConstantIndex { offset, min_length, from_end: false }; @@ -395,35 +399,40 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> { return; } } - operand = if let Ok(operand) = self.ecx.project(&operand, proj_elem) { - operand - } else { - return; - } + operand = + if let Some(operand) = self.ecx.project(&operand, proj_elem).discard_interp_err() { + operand + } else { + return; + } } self.map.for_each_projection_value( place, operand, &mut |elem, op| match elem { - TrackElem::Field(idx) => self.ecx.project_field(op, idx.as_usize()).ok(), - TrackElem::Variant(idx) => self.ecx.project_downcast(op, idx).ok(), + TrackElem::Field(idx) => { + self.ecx.project_field(op, idx.as_usize()).discard_interp_err() + } + TrackElem::Variant(idx) => self.ecx.project_downcast(op, idx).discard_interp_err(), TrackElem::Discriminant => { - let variant = self.ecx.read_discriminant(op).ok()?; - let discr_value = - self.ecx.discriminant_for_variant(op.layout.ty, variant).ok()?; + let variant = self.ecx.read_discriminant(op).discard_interp_err()?; + let discr_value = self + .ecx + .discriminant_for_variant(op.layout.ty, variant) + .discard_interp_err()?; Some(discr_value.into()) } TrackElem::DerefLen => { - let op: OpTy<'_> = self.ecx.deref_pointer(op).ok()?.into(); - let len_usize = op.len(&self.ecx).ok()?; + let op: OpTy<'_> = self.ecx.deref_pointer(op).discard_interp_err()?.into(); + let len_usize = op.len(&self.ecx).discard_interp_err()?; let layout = self.tcx.layout_of(self.param_env.and(self.tcx.types.usize)).unwrap(); Some(ImmTy::from_uint(len_usize, layout).into()) } }, &mut |place, op| { - if let Ok(imm) = self.ecx.read_immediate_raw(op) + if let Some(imm) = self.ecx.read_immediate_raw(op).discard_interp_err() && let Some(imm) = imm.right() { let elem = self.wrap_immediate(*imm); @@ -447,11 +456,11 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> { (FlatSet::Bottom, _) | (_, FlatSet::Bottom) => (FlatSet::Bottom, FlatSet::Bottom), // Both sides are known, do the actual computation. (FlatSet::Elem(left), FlatSet::Elem(right)) => { - match self.ecx.binary_op(op, &left, &right) { + match self.ecx.binary_op(op, &left, &right).discard_interp_err() { // Ideally this would return an Immediate, since it's sometimes // a pair and sometimes not. But as a hack we always return a pair // and just make the 2nd component `Bottom` when it does not exist. - Ok(val) => { + Some(val) => { if matches!(val.layout.abi, Abi::ScalarPair(..)) { let (val, overflow) = val.to_scalar_pair(); (FlatSet::Elem(val), FlatSet::Elem(overflow)) @@ -470,7 +479,7 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> { } let arg_scalar = const_arg.to_scalar(); - let Ok(arg_value) = arg_scalar.to_bits(layout.size) else { + let Some(arg_value) = arg_scalar.to_bits(layout.size).discard_interp_err() else { return (FlatSet::Top, FlatSet::Top); }; @@ -518,8 +527,10 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> { return None; } let enum_ty_layout = self.tcx.layout_of(self.param_env.and(enum_ty)).ok()?; - let discr_value = - self.ecx.discriminant_for_variant(enum_ty_layout.ty, variant_index).ok()?; + let discr_value = self + .ecx + .discriminant_for_variant(enum_ty_layout.ty, variant_index) + .discard_interp_err()?; Some(discr_value.to_scalar()) } @@ -573,7 +584,7 @@ impl<'a, 'tcx> Collector<'a, 'tcx> { map: &Map<'tcx>, ) -> Option> { let ty = place.ty(self.local_decls, self.patch.tcx).ty; - let layout = ecx.layout_of(ty).ok()?; + let layout = ecx.layout_of(ty).discard_interp_err()?; if layout.is_zst() { return Some(Const::zero_sized(ty)); @@ -595,7 +606,7 @@ impl<'a, 'tcx> Collector<'a, 'tcx> { .intern_with_temp_alloc(layout, |ecx, dest| { try_write_constant(ecx, dest, place, ty, state, map) }) - .ok()?; + .discard_interp_err()?; return Some(Const::Val(ConstValue::Indirect { alloc_id, offset: Size::ZERO }, ty)); } @@ -830,7 +841,7 @@ impl<'tcx> MutVisitor<'tcx> for Patch<'tcx> { if let PlaceElem::Index(local) = elem { let offset = self.before_effect.get(&(location, local.into()))?; let offset = offset.try_to_scalar()?; - let offset = offset.to_target_usize(&self.tcx).ok()?; + let offset = offset.to_target_usize(&self.tcx).discard_interp_err()?; let min_length = offset.checked_add(1)?; Some(PlaceElem::ConstantIndex { offset, min_length, from_end: false }) } else { diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index f735d08fca5..4dbcc6af9bd 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -87,8 +87,8 @@ use std::borrow::Cow; use either::Either; use rustc_const_eval::const_eval::DummyMachine; use rustc_const_eval::interpret::{ - ImmTy, Immediate, InterpCx, MemPlaceMeta, MemoryKind, OpTy, Projectable, Scalar, - intern_const_alloc_for_constprop, + DiscardInterpError, ImmTy, Immediate, InterpCx, MemPlaceMeta, MemoryKind, OpTy, Projectable, + Scalar, intern_const_alloc_for_constprop, }; use rustc_data_structures::fx::FxIndexSet; use rustc_data_structures::graph::dominators::Dominators; @@ -393,7 +393,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { Repeat(..) => return None, Constant { ref value, disambiguator: _ } => { - self.ecx.eval_mir_constant(value, DUMMY_SP, None).ok()? + self.ecx.eval_mir_constant(value, DUMMY_SP, None).discard_interp_err()? } Aggregate(kind, variant, ref fields) => { let fields = fields @@ -414,34 +414,39 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { AggregateTy::RawPtr { output_pointer_ty, .. } => output_pointer_ty, }; let variant = if ty.is_enum() { Some(variant) } else { None }; - let ty = self.ecx.layout_of(ty).ok()?; + let ty = self.ecx.layout_of(ty).discard_interp_err()?; if ty.is_zst() { ImmTy::uninit(ty).into() } else if matches!(kind, AggregateTy::RawPtr { .. }) { // Pointers don't have fields, so don't `project_field` them. - let data = self.ecx.read_pointer(fields[0]).ok()?; + let data = self.ecx.read_pointer(fields[0]).discard_interp_err()?; let meta = if fields[1].layout.is_zst() { MemPlaceMeta::None } else { - MemPlaceMeta::Meta(self.ecx.read_scalar(fields[1]).ok()?) + MemPlaceMeta::Meta(self.ecx.read_scalar(fields[1]).discard_interp_err()?) }; let ptr_imm = Immediate::new_pointer_with_meta(data, meta, &self.ecx); ImmTy::from_immediate(ptr_imm, ty).into() } else if matches!(ty.abi, Abi::Scalar(..) | Abi::ScalarPair(..)) { - let dest = self.ecx.allocate(ty, MemoryKind::Stack).ok()?; + let dest = self.ecx.allocate(ty, MemoryKind::Stack).discard_interp_err()?; let variant_dest = if let Some(variant) = variant { - self.ecx.project_downcast(&dest, variant).ok()? + self.ecx.project_downcast(&dest, variant).discard_interp_err()? } else { dest.clone() }; for (field_index, op) in fields.into_iter().enumerate() { - let field_dest = self.ecx.project_field(&variant_dest, field_index).ok()?; - self.ecx.copy_op(op, &field_dest).ok()?; + let field_dest = self + .ecx + .project_field(&variant_dest, field_index) + .discard_interp_err()?; + self.ecx.copy_op(op, &field_dest).discard_interp_err()?; } - self.ecx.write_discriminant(variant.unwrap_or(FIRST_VARIANT), &dest).ok()?; + self.ecx + .write_discriminant(variant.unwrap_or(FIRST_VARIANT), &dest) + .discard_interp_err()?; self.ecx .alloc_mark_immutable(dest.ptr().provenance.unwrap().alloc_id()) - .ok()?; + .discard_interp_err()?; dest.into() } else { return None; @@ -467,7 +472,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { // This should have been replaced by a `ConstantIndex` earlier. ProjectionElem::Index(_) => return None, }; - self.ecx.project(value, elem).ok()? + self.ecx.project(value, elem).discard_interp_err()? } Address { place, kind, provenance: _ } => { if !place.is_indirect_first_projection() { @@ -475,14 +480,14 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { } let local = self.locals[place.local]?; let pointer = self.evaluated[local].as_ref()?; - let mut mplace = self.ecx.deref_pointer(pointer).ok()?; + let mut mplace = self.ecx.deref_pointer(pointer).discard_interp_err()?; for proj in place.projection.iter().skip(1) { // We have no call stack to associate a local with a value, so we cannot // interpret indexing. if matches!(proj, ProjectionElem::Index(_)) { return None; } - mplace = self.ecx.project(&mplace, proj).ok()?; + mplace = self.ecx.project(&mplace, proj).discard_interp_err()?; } let pointer = mplace.to_ref(&self.ecx); let ty = match kind { @@ -494,26 +499,28 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { ), AddressKind::Address(mutbl) => Ty::new_ptr(self.tcx, mplace.layout.ty, mutbl), }; - let layout = self.ecx.layout_of(ty).ok()?; + let layout = self.ecx.layout_of(ty).discard_interp_err()?; ImmTy::from_immediate(pointer, layout).into() } Discriminant(base) => { let base = self.evaluated[base].as_ref()?; - let variant = self.ecx.read_discriminant(base).ok()?; - let discr_value = - self.ecx.discriminant_for_variant(base.layout.ty, variant).ok()?; + let variant = self.ecx.read_discriminant(base).discard_interp_err()?; + let discr_value = self + .ecx + .discriminant_for_variant(base.layout.ty, variant) + .discard_interp_err()?; discr_value.into() } Len(slice) => { let slice = self.evaluated[slice].as_ref()?; let usize_layout = self.ecx.layout_of(self.tcx.types.usize).unwrap(); - let len = slice.len(&self.ecx).ok()?; + let len = slice.len(&self.ecx).discard_interp_err()?; let imm = ImmTy::from_uint(len, usize_layout); imm.into() } NullaryOp(null_op, ty) => { - let layout = self.ecx.layout_of(ty).ok()?; + let layout = self.ecx.layout_of(ty).discard_interp_err()?; if let NullOp::SizeOf | NullOp::AlignOf = null_op && layout.is_unsized() { @@ -535,36 +542,36 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { } UnaryOp(un_op, operand) => { let operand = self.evaluated[operand].as_ref()?; - let operand = self.ecx.read_immediate(operand).ok()?; - let val = self.ecx.unary_op(un_op, &operand).ok()?; + let operand = self.ecx.read_immediate(operand).discard_interp_err()?; + let val = self.ecx.unary_op(un_op, &operand).discard_interp_err()?; val.into() } BinaryOp(bin_op, lhs, rhs) => { let lhs = self.evaluated[lhs].as_ref()?; - let lhs = self.ecx.read_immediate(lhs).ok()?; + let lhs = self.ecx.read_immediate(lhs).discard_interp_err()?; let rhs = self.evaluated[rhs].as_ref()?; - let rhs = self.ecx.read_immediate(rhs).ok()?; - let val = self.ecx.binary_op(bin_op, &lhs, &rhs).ok()?; + let rhs = self.ecx.read_immediate(rhs).discard_interp_err()?; + let val = self.ecx.binary_op(bin_op, &lhs, &rhs).discard_interp_err()?; val.into() } Cast { kind, value, from: _, to } => match kind { CastKind::IntToInt | CastKind::IntToFloat => { let value = self.evaluated[value].as_ref()?; - let value = self.ecx.read_immediate(value).ok()?; - let to = self.ecx.layout_of(to).ok()?; - let res = self.ecx.int_to_int_or_float(&value, to).ok()?; + let value = self.ecx.read_immediate(value).discard_interp_err()?; + let to = self.ecx.layout_of(to).discard_interp_err()?; + let res = self.ecx.int_to_int_or_float(&value, to).discard_interp_err()?; res.into() } CastKind::FloatToFloat | CastKind::FloatToInt => { let value = self.evaluated[value].as_ref()?; - let value = self.ecx.read_immediate(value).ok()?; - let to = self.ecx.layout_of(to).ok()?; - let res = self.ecx.float_to_float_or_int(&value, to).ok()?; + let value = self.ecx.read_immediate(value).discard_interp_err()?; + let to = self.ecx.layout_of(to).discard_interp_err()?; + let res = self.ecx.float_to_float_or_int(&value, to).discard_interp_err()?; res.into() } CastKind::Transmute => { let value = self.evaluated[value].as_ref()?; - let to = self.ecx.layout_of(to).ok()?; + let to = self.ecx.layout_of(to).discard_interp_err()?; // `offset` for immediates only supports scalar/scalar-pair ABIs, // so bail out if the target is not one. if value.as_mplace_or_imm().is_right() { @@ -574,29 +581,29 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { _ => return None, } } - value.offset(Size::ZERO, to, &self.ecx).ok()? + value.offset(Size::ZERO, to, &self.ecx).discard_interp_err()? } CastKind::PointerCoercion(ty::adjustment::PointerCoercion::Unsize, _) => { let src = self.evaluated[value].as_ref()?; - let to = self.ecx.layout_of(to).ok()?; - let dest = self.ecx.allocate(to, MemoryKind::Stack).ok()?; - self.ecx.unsize_into(src, to, &dest.clone().into()).ok()?; + let to = self.ecx.layout_of(to).discard_interp_err()?; + let dest = self.ecx.allocate(to, MemoryKind::Stack).discard_interp_err()?; + self.ecx.unsize_into(src, to, &dest.clone().into()).discard_interp_err()?; self.ecx .alloc_mark_immutable(dest.ptr().provenance.unwrap().alloc_id()) - .ok()?; + .discard_interp_err()?; dest.into() } CastKind::FnPtrToPtr | CastKind::PtrToPtr => { let src = self.evaluated[value].as_ref()?; - let src = self.ecx.read_immediate(src).ok()?; - let to = self.ecx.layout_of(to).ok()?; - let ret = self.ecx.ptr_to_ptr(&src, to).ok()?; + let src = self.ecx.read_immediate(src).discard_interp_err()?; + let to = self.ecx.layout_of(to).discard_interp_err()?; + let ret = self.ecx.ptr_to_ptr(&src, to).discard_interp_err()?; ret.into() } CastKind::PointerCoercion(ty::adjustment::PointerCoercion::UnsafeFnPointer, _) => { let src = self.evaluated[value].as_ref()?; - let src = self.ecx.read_immediate(src).ok()?; - let to = self.ecx.layout_of(to).ok()?; + let src = self.ecx.read_immediate(src).discard_interp_err()?; + let to = self.ecx.layout_of(to).discard_interp_err()?; ImmTy::from_immediate(*src, to).into() } _ => return None, @@ -708,7 +715,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { && let Some(idx) = self.locals[idx_local] { if let Some(offset) = self.evaluated[idx].as_ref() - && let Ok(offset) = self.ecx.read_target_usize(offset) + && let Some(offset) = self.ecx.read_target_usize(offset).discard_interp_err() && let Some(min_length) = offset.checked_add(1) { projection.to_mut()[i] = @@ -868,7 +875,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { && let DefKind::Enum = self.tcx.def_kind(enum_did) { let enum_ty = self.tcx.type_of(enum_did).instantiate(self.tcx, enum_args); - let discr = self.ecx.discriminant_for_variant(enum_ty, variant).ok()?; + let discr = self.ecx.discriminant_for_variant(enum_ty, variant).discard_interp_err()?; return Some(self.insert_scalar(discr.to_scalar(), discr.layout.ty)); } @@ -1218,13 +1225,13 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { return None; } - let layout = self.ecx.layout_of(lhs_ty).ok()?; + let layout = self.ecx.layout_of(lhs_ty).discard_interp_err()?; let as_bits = |value| { let constant = self.evaluated[value].as_ref()?; if layout.abi.is_scalar() { - let scalar = self.ecx.read_scalar(constant).ok()?; - scalar.to_bits(constant.layout.size).ok() + let scalar = self.ecx.read_scalar(constant).discard_interp_err()?; + scalar.to_bits(constant.layout.size).discard_interp_err() } else { // `constant` is a wide pointer. Do not evaluate to bits. None @@ -1484,7 +1491,7 @@ fn op_to_prop_const<'tcx>( // If this constant has scalar ABI, return it as a `ConstValue::Scalar`. if let Abi::Scalar(abi::Scalar::Initialized { .. }) = op.layout.abi - && let Ok(scalar) = ecx.read_scalar(op) + && let Some(scalar) = ecx.read_scalar(op).discard_interp_err() { if !scalar.try_to_scalar_int().is_ok() { // Check that we do not leak a pointer. @@ -1498,12 +1505,12 @@ fn op_to_prop_const<'tcx>( // If this constant is already represented as an `Allocation`, // try putting it into global memory to return it. if let Either::Left(mplace) = op.as_mplace_or_imm() { - let (size, _align) = ecx.size_and_align_of_mplace(&mplace).ok()??; + let (size, _align) = ecx.size_and_align_of_mplace(&mplace).discard_interp_err()??; // Do not try interning a value that contains provenance. // Due to https://github.com/rust-lang/rust/issues/79738, doing so could lead to bugs. // FIXME: remove this hack once that issue is fixed. - let alloc_ref = ecx.get_ptr_alloc(mplace.ptr(), size).ok()??; + let alloc_ref = ecx.get_ptr_alloc(mplace.ptr(), size).discard_interp_err()??; if alloc_ref.has_provenance() { return None; } @@ -1511,7 +1518,7 @@ fn op_to_prop_const<'tcx>( let pointer = mplace.ptr().into_pointer_or_addr().ok()?; let (prov, offset) = pointer.into_parts(); let alloc_id = prov.alloc_id(); - intern_const_alloc_for_constprop(ecx, alloc_id).ok()?; + intern_const_alloc_for_constprop(ecx, alloc_id).discard_interp_err()?; // `alloc_id` may point to a static. Codegen will choke on an `Indirect` with anything // by `GlobalAlloc::Memory`, so do fall through to copying if needed. @@ -1526,7 +1533,9 @@ fn op_to_prop_const<'tcx>( } // Everything failed: create a new allocation to hold the data. - let alloc_id = ecx.intern_with_temp_alloc(op.layout, |ecx, dest| ecx.copy_op(op, dest)).ok()?; + let alloc_id = ecx + .intern_with_temp_alloc(op.layout, |ecx, dest| ecx.copy_op(op, dest)) + .discard_interp_err()?; let value = ConstValue::Indirect { alloc_id, offset: Size::ZERO }; // Check that we do not leak a pointer. diff --git a/compiler/rustc_mir_transform/src/jump_threading.rs b/compiler/rustc_mir_transform/src/jump_threading.rs index 91fbc91e1e7..e69a7e552f6 100644 --- a/compiler/rustc_mir_transform/src/jump_threading.rs +++ b/compiler/rustc_mir_transform/src/jump_threading.rs @@ -37,7 +37,9 @@ use rustc_arena::DroplessArena; use rustc_const_eval::const_eval::DummyMachine; -use rustc_const_eval::interpret::{ImmTy, Immediate, InterpCx, OpTy, Projectable}; +use rustc_const_eval::interpret::{ + DiscardInterpError, ImmTy, Immediate, InterpCx, OpTy, Projectable, +}; use rustc_data_structures::fx::FxHashSet; use rustc_index::IndexVec; use rustc_index::bit_set::BitSet; @@ -200,7 +202,9 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> { debug!(?discr, ?bb); let discr_ty = discr.ty(self.body, self.tcx).ty; - let Ok(discr_layout) = self.ecx.layout_of(discr_ty) else { return }; + let Some(discr_layout) = self.ecx.layout_of(discr_ty).discard_interp_err() else { + return; + }; let Some(discr) = self.map.find(discr.as_ref()) else { return }; debug!(?discr); @@ -388,24 +392,28 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> { lhs, constant, &mut |elem, op| match elem { - TrackElem::Field(idx) => self.ecx.project_field(op, idx.as_usize()).ok(), - TrackElem::Variant(idx) => self.ecx.project_downcast(op, idx).ok(), + TrackElem::Field(idx) => { + self.ecx.project_field(op, idx.as_usize()).discard_interp_err() + } + TrackElem::Variant(idx) => self.ecx.project_downcast(op, idx).discard_interp_err(), TrackElem::Discriminant => { - let variant = self.ecx.read_discriminant(op).ok()?; - let discr_value = - self.ecx.discriminant_for_variant(op.layout.ty, variant).ok()?; + let variant = self.ecx.read_discriminant(op).discard_interp_err()?; + let discr_value = self + .ecx + .discriminant_for_variant(op.layout.ty, variant) + .discard_interp_err()?; Some(discr_value.into()) } TrackElem::DerefLen => { - let op: OpTy<'_> = self.ecx.deref_pointer(op).ok()?.into(); - let len_usize = op.len(&self.ecx).ok()?; + let op: OpTy<'_> = self.ecx.deref_pointer(op).discard_interp_err()?.into(); + let len_usize = op.len(&self.ecx).discard_interp_err()?; let layout = self.ecx.layout_of(self.tcx.types.usize).unwrap(); Some(ImmTy::from_uint(len_usize, layout).into()) } }, &mut |place, op| { if let Some(conditions) = state.try_get_idx(place, &self.map) - && let Ok(imm) = self.ecx.read_immediate_raw(op) + && let Some(imm) = self.ecx.read_immediate_raw(op).discard_interp_err() && let Some(imm) = imm.right() && let Immediate::Scalar(Scalar::Int(int)) = *imm { @@ -429,8 +437,10 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> { match rhs { // If we expect `lhs ?= A`, we have an opportunity if we assume `constant == A`. Operand::Constant(constant) => { - let Ok(constant) = - self.ecx.eval_mir_constant(&constant.const_, constant.span, None) + let Some(constant) = self + .ecx + .eval_mir_constant(&constant.const_, constant.span, None) + .discard_interp_err() else { return; }; @@ -469,8 +479,10 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> { AggregateKind::Adt(.., Some(_)) => return, AggregateKind::Adt(_, variant_index, ..) if agg_ty.is_enum() => { if let Some(discr_target) = self.map.apply(lhs, TrackElem::Discriminant) - && let Ok(discr_value) = - self.ecx.discriminant_for_variant(agg_ty, *variant_index) + && let Some(discr_value) = self + .ecx + .discriminant_for_variant(agg_ty, *variant_index) + .discard_interp_err() { self.process_immediate(bb, discr_target, discr_value, state); } @@ -555,7 +567,9 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> { // `SetDiscriminant` may be a no-op if the assigned variant is the untagged variant // of a niche encoding. If we cannot ensure that we write to the discriminant, do // nothing. - let Ok(enum_layout) = self.ecx.layout_of(enum_ty) else { return }; + let Some(enum_layout) = self.ecx.layout_of(enum_ty).discard_interp_err() else { + return; + }; let writes_discriminant = match enum_layout.variants { Variants::Single { index } => { assert_eq!(index, *variant_index); @@ -568,7 +582,10 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> { } => *variant_index != untagged_variant, }; if writes_discriminant { - let Ok(discr) = self.ecx.discriminant_for_variant(enum_ty, *variant_index) + let Some(discr) = self + .ecx + .discriminant_for_variant(enum_ty, *variant_index) + .discard_interp_err() else { return; }; @@ -645,7 +662,9 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> { let Some(discr) = discr.place() else { return }; let discr_ty = discr.ty(self.body, self.tcx).ty; - let Ok(discr_layout) = self.ecx.layout_of(discr_ty) else { return }; + let Some(discr_layout) = self.ecx.layout_of(discr_ty).discard_interp_err() else { + return; + }; let Some(conditions) = state.try_get(discr.as_ref(), &self.map) else { return }; if let Some((value, _)) = targets.iter().find(|&(_, target)| target == target_bb) { diff --git a/compiler/rustc_mir_transform/src/known_panics_lint.rs b/compiler/rustc_mir_transform/src/known_panics_lint.rs index 783e7aabe85..b165ea53440 100644 --- a/compiler/rustc_mir_transform/src/known_panics_lint.rs +++ b/compiler/rustc_mir_transform/src/known_panics_lint.rs @@ -6,7 +6,7 @@ use std::fmt::Debug; use rustc_const_eval::const_eval::DummyMachine; use rustc_const_eval::interpret::{ - ImmTy, InterpCx, InterpResult, Projectable, Scalar, format_interp_error, + DiscardInterpError, ImmTy, InterpCx, InterpResult, Projectable, Scalar, format_interp_error, }; use rustc_data_structures::fx::FxHashSet; use rustc_hir::HirId; @@ -101,7 +101,8 @@ impl<'tcx> Value<'tcx> { } (PlaceElem::Index(idx), Value::Aggregate { fields, .. }) => { let idx = prop.get_const(idx.into())?.immediate()?; - let idx = prop.ecx.read_target_usize(idx).ok()?.try_into().ok()?; + let idx = + prop.ecx.read_target_usize(idx).discard_interp_err()?.try_into().ok()?; if idx <= FieldIdx::MAX_AS_U32 { fields.get(FieldIdx::from_u32(idx)).unwrap_or(&Value::Uninit) } else { @@ -243,6 +244,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { "known panics lint encountered formatting error: {}", format_interp_error(self.ecx.tcx.dcx(), error), ); + error.discard_interp_err(); None } } @@ -347,9 +349,9 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { // We need the type of the LHS. We cannot use `place_layout` as that is the type // of the result, which for checked binops is not the same! let left_ty = left.ty(self.local_decls(), self.tcx); - let left_size = self.ecx.layout_of(left_ty).ok()?.size; + let left_size = self.ecx.layout_of(left_ty).discard_interp_err()?.size; let right_size = r.layout.size; - let r_bits = r.to_scalar().to_bits(right_size).ok(); + let r_bits = r.to_scalar().to_bits(right_size).discard_interp_err(); if r_bits.is_some_and(|b| b >= left_size.bits() as u128) { debug!("check_binary_op: reporting assert for {:?}", location); let panic = AssertKind::Overflow( @@ -496,7 +498,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { // This can be `None` if the lhs wasn't const propagated and we just // triggered the assert on the value of the rhs. self.eval_operand(op) - .and_then(|op| self.ecx.read_immediate(&op).ok()) + .and_then(|op| self.ecx.read_immediate(&op).discard_interp_err()) .map_or(DbgVal::Underscore, |op| DbgVal::Val(op.to_const_int())) }; let msg = match msg { @@ -540,7 +542,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { return None; } use rustc_middle::mir::Rvalue::*; - let layout = self.ecx.layout_of(dest.ty(self.body, self.tcx).ty).ok()?; + let layout = self.ecx.layout_of(dest.ty(self.body, self.tcx).ty).discard_interp_err()?; trace!(?layout); let val: Value<'_> = match *rvalue { @@ -602,7 +604,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { Len(place) => { let len = match self.get_const(place)? { - Value::Immediate(src) => src.len(&self.ecx).ok()?, + Value::Immediate(src) => src.len(&self.ecx).discard_interp_err()?, Value::Aggregate { fields, .. } => fields.len() as u64, Value::Uninit => match place.ty(self.local_decls(), self.tcx).ty.kind() { ty::Array(_, n) => n.try_eval_target_usize(self.tcx, self.param_env)?, @@ -633,21 +635,21 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { Cast(ref kind, ref value, to) => match kind { CastKind::IntToInt | CastKind::IntToFloat => { let value = self.eval_operand(value)?; - let value = self.ecx.read_immediate(&value).ok()?; - let to = self.ecx.layout_of(to).ok()?; - let res = self.ecx.int_to_int_or_float(&value, to).ok()?; + let value = self.ecx.read_immediate(&value).discard_interp_err()?; + let to = self.ecx.layout_of(to).discard_interp_err()?; + let res = self.ecx.int_to_int_or_float(&value, to).discard_interp_err()?; res.into() } CastKind::FloatToFloat | CastKind::FloatToInt => { let value = self.eval_operand(value)?; - let value = self.ecx.read_immediate(&value).ok()?; - let to = self.ecx.layout_of(to).ok()?; - let res = self.ecx.float_to_float_or_int(&value, to).ok()?; + let value = self.ecx.read_immediate(&value).discard_interp_err()?; + let to = self.ecx.layout_of(to).discard_interp_err()?; + let res = self.ecx.float_to_float_or_int(&value, to).discard_interp_err()?; res.into() } CastKind::Transmute => { let value = self.eval_operand(value)?; - let to = self.ecx.layout_of(to).ok()?; + let to = self.ecx.layout_of(to).discard_interp_err()?; // `offset` for immediates only supports scalar/scalar-pair ABIs, // so bail out if the target is not one. match (value.layout.abi, to.abi) { @@ -656,7 +658,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { _ => return None, } - value.offset(Size::ZERO, to, &self.ecx).ok()?.into() + value.offset(Size::ZERO, to, &self.ecx).discard_interp_err()?.into() } _ => return None, }, @@ -781,7 +783,8 @@ impl<'tcx> Visitor<'tcx> for ConstPropagator<'_, 'tcx> { TerminatorKind::SwitchInt { ref discr, ref targets } => { if let Some(ref value) = self.eval_operand(discr) && let Some(value_const) = self.use_ecx(|this| this.ecx.read_scalar(value)) - && let Ok(constant) = value_const.to_bits(value_const.size()) + && let Some(constant) = + value_const.to_bits(value_const.size()).discard_interp_err() { // We managed to evaluate the discriminant, so we know we only need to visit // one target. diff --git a/src/tools/miri/src/concurrency/data_race.rs b/src/tools/miri/src/concurrency/data_race.rs index d1cd15aab3d..5910be22a69 100644 --- a/src/tools/miri/src/concurrency/data_race.rs +++ b/src/tools/miri/src/concurrency/data_race.rs @@ -641,7 +641,7 @@ pub trait EvalContextExt<'tcx>: MiriInterpCxExt<'tcx> { // The program didn't actually do a read, so suppress the memory access hooks. // This is also a very special exception where we just ignore an error -- if this read // was UB e.g. because the memory is uninitialized, we don't want to know! - let old_val = this.run_for_validation(|this| this.read_scalar(dest)).ok(); + let old_val = this.run_for_validation(|this| this.read_scalar(dest)).discard_interp_err(); this.allow_data_races_mut(move |this| this.write_scalar(val, dest))?; this.validate_atomic_store(dest, atomic)?; this.buffered_atomic_write(val, dest, atomic, old_val) diff --git a/src/tools/miri/src/diagnostics.rs b/src/tools/miri/src/diagnostics.rs index 4445550512b..ee087ece9d8 100644 --- a/src/tools/miri/src/diagnostics.rs +++ b/src/tools/miri/src/diagnostics.rs @@ -223,7 +223,10 @@ pub fn report_error<'tcx>( let info = info.downcast_ref::().expect("invalid MachineStop payload"); use TerminationInfo::*; let title = match info { - Exit { code, leak_check } => return Some((*code, *leak_check)), + &Exit { code, leak_check } => { + e.discard_interp_err(); + return Some((code, leak_check)); + } Abort(_) => Some("abnormal termination"), UnsupportedInIsolation(_) | Int2PtrWithStrictProvenance | UnsupportedForeignItem(_) => Some("unsupported operation"), @@ -375,6 +378,7 @@ pub fn report_error<'tcx>( InvalidProgramInfo::AlreadyReported(_) ) => { // This got already reported. No point in reporting it again. + e.discard_interp_err(); return None; } _ => diff --git a/src/tools/miri/src/intrinsics/simd.rs b/src/tools/miri/src/intrinsics/simd.rs index 802a70e5a54..7f43c61cd66 100644 --- a/src/tools/miri/src/intrinsics/simd.rs +++ b/src/tools/miri/src/intrinsics/simd.rs @@ -247,7 +247,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // This does NaN adjustments. let val = this.binary_op(mir_op, &left, &right).map_err(|err| { match err.kind() { - InterpError::UndefinedBehavior(UndefinedBehaviorInfo::ShiftOverflow { shift_amount, .. }) => { + &InterpError::UndefinedBehavior(UndefinedBehaviorInfo::ShiftOverflow { shift_amount, .. }) => { + err.discard_interp_err(); // This resets the interpreter backtrace, but it's not worth avoiding that. let shift_amount = match shift_amount { Either::Left(v) => v.to_string(), From 15ac6983930a0d49b921c0330dbbb5a4f8f1d34a Mon Sep 17 00:00:00 2001 From: lcnr Date: Mon, 30 Sep 2024 10:18:27 +0200 Subject: [PATCH 423/683] canonicalizer: rm region uniquification, add caching --- .../src/canonicalizer.rs | 247 ++++++++++-------- 1 file changed, 138 insertions(+), 109 deletions(-) diff --git a/compiler/rustc_next_trait_solver/src/canonicalizer.rs b/compiler/rustc_next_trait_solver/src/canonicalizer.rs index 196ddeb2443..5c3c35b7b3e 100644 --- a/compiler/rustc_next_trait_solver/src/canonicalizer.rs +++ b/compiler/rustc_next_trait_solver/src/canonicalizer.rs @@ -1,5 +1,6 @@ use std::cmp::Ordering; +use rustc_type_ir::data_structures::HashMap; use rustc_type_ir::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable}; use rustc_type_ir::inherent::*; use rustc_type_ir::visit::TypeVisitableExt; @@ -44,8 +45,15 @@ pub struct Canonicalizer<'a, D: SolverDelegate, I: Interner> { canonicalize_mode: CanonicalizeMode, variables: &'a mut Vec, + variable_lookup_table: HashMap, + primitive_var_infos: Vec>, binder_index: ty::DebruijnIndex, + + /// We only use the debruijn index during lookup as all other fields + /// should not be impacted by whether a type is folded once or multiple + /// times. + cache: HashMap<(ty::DebruijnIndex, I::Ty), I::Ty>, } impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { @@ -60,12 +68,14 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { canonicalize_mode, variables, + variable_lookup_table: Default::default(), primitive_var_infos: Vec::new(), binder_index: ty::INNERMOST, + + cache: Default::default(), }; let value = value.fold_with(&mut canonicalizer); - // FIXME: Restore these assertions. Should we uplift type flags? assert!(!value.has_infer(), "unexpected infer in {value:?}"); assert!(!value.has_placeholders(), "unexpected placeholders in {value:?}"); @@ -75,6 +85,37 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { Canonical { defining_opaque_types, max_universe, variables, value } } + fn get_or_insert_bound_var( + &mut self, + arg: impl Into, + canonical_var_info: CanonicalVarInfo, + ) -> ty::BoundVar { + // FIXME: 16 is made up and arbitrary. We should look at some + // perf data here. + let arg = arg.into(); + let idx = if self.variables.len() > 16 { + if self.variable_lookup_table.is_empty() { + self.variable_lookup_table.extend(self.variables.iter().copied().zip(0..)); + } + + *self.variable_lookup_table.entry(arg).or_insert_with(|| { + let var = self.variables.len(); + self.variables.push(arg); + self.primitive_var_infos.push(canonical_var_info); + var + }) + } else { + self.variables.iter().position(|&v| v == arg).unwrap_or_else(|| { + let var = self.variables.len(); + self.variables.push(arg); + self.primitive_var_infos.push(canonical_var_info); + var + }) + }; + + ty::BoundVar::from(idx) + } + fn finalize(self) -> (ty::UniverseIndex, I::CanonicalVars) { let mut var_infos = self.primitive_var_infos; // See the rustc-dev-guide section about how we deal with universes @@ -124,8 +165,8 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { // - var_infos: [E0, U1, E2, U1, E1, E6, U6], curr_compressed_uv: 2, next_orig_uv: 6 // - var_infos: [E0, U1, E1, U1, E1, E3, U3], curr_compressed_uv: 2, next_orig_uv: - // - // This algorithm runs in `O(n²)` where `n` is the number of different universe - // indices in the input. This should be fine as `n` is expected to be small. + // This algorithm runs in `O(mn)` where `n` is the number of different universes and + // `m` the number of variables. This should be fine as both are expected to be small. let mut curr_compressed_uv = ty::UniverseIndex::ROOT; let mut existential_in_new_uv = None; let mut next_orig_uv = Some(ty::UniverseIndex::ROOT); @@ -185,14 +226,16 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { for var in var_infos.iter_mut() { // We simply put all regions from the input into the highest // compressed universe, so we only deal with them at the end. - if !var.is_region() && is_existential == var.is_existential() { - update_uv(var, orig_uv, is_existential) + if !var.is_region() { + if is_existential == var.is_existential() { + update_uv(var, orig_uv, is_existential) + } } } } } - // We uniquify regions and always put them into their own universe + // We put all regions into a separate universe. let mut first_region = true; for var in var_infos.iter_mut() { if var.is_region() { @@ -208,93 +251,8 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { let var_infos = self.delegate.cx().mk_canonical_var_infos(&var_infos); (curr_compressed_uv, var_infos) } -} -impl, I: Interner> TypeFolder for Canonicalizer<'_, D, I> { - fn cx(&self) -> I { - self.delegate.cx() - } - - fn fold_binder(&mut self, t: ty::Binder) -> ty::Binder - where - T: TypeFoldable, - { - self.binder_index.shift_in(1); - let t = t.super_fold_with(self); - self.binder_index.shift_out(1); - t - } - - fn fold_region(&mut self, r: I::Region) -> I::Region { - let kind = match r.kind() { - ty::ReBound(..) => return r, - - // We may encounter `ReStatic` in item signatures or the hidden type - // of an opaque. `ReErased` should only be encountered in the hidden - // type of an opaque for regions that are ignored for the purposes of - // captures. - // - // FIXME: We should investigate the perf implications of not uniquifying - // `ReErased`. We may be able to short-circuit registering region - // obligations if we encounter a `ReErased` on one side, for example. - ty::ReStatic | ty::ReErased | ty::ReError(_) => match self.canonicalize_mode { - CanonicalizeMode::Input => CanonicalVarKind::Region(ty::UniverseIndex::ROOT), - CanonicalizeMode::Response { .. } => return r, - }, - - ty::ReEarlyParam(_) | ty::ReLateParam(_) => match self.canonicalize_mode { - CanonicalizeMode::Input => CanonicalVarKind::Region(ty::UniverseIndex::ROOT), - CanonicalizeMode::Response { .. } => { - panic!("unexpected region in response: {r:?}") - } - }, - - ty::RePlaceholder(placeholder) => match self.canonicalize_mode { - // We canonicalize placeholder regions as existentials in query inputs. - CanonicalizeMode::Input => CanonicalVarKind::Region(ty::UniverseIndex::ROOT), - CanonicalizeMode::Response { max_input_universe } => { - // If we have a placeholder region inside of a query, it must be from - // a new universe. - if max_input_universe.can_name(placeholder.universe()) { - panic!("new placeholder in universe {max_input_universe:?}: {r:?}"); - } - CanonicalVarKind::PlaceholderRegion(placeholder) - } - }, - - ty::ReVar(vid) => { - assert_eq!( - self.delegate.opportunistic_resolve_lt_var(vid), - r, - "region vid should have been resolved fully before canonicalization" - ); - match self.canonicalize_mode { - CanonicalizeMode::Input => CanonicalVarKind::Region(ty::UniverseIndex::ROOT), - CanonicalizeMode::Response { .. } => { - CanonicalVarKind::Region(self.delegate.universe_of_lt(vid).unwrap()) - } - } - } - }; - - let existing_bound_var = match self.canonicalize_mode { - CanonicalizeMode::Input => None, - CanonicalizeMode::Response { .. } => { - self.variables.iter().position(|&v| v == r.into()).map(ty::BoundVar::from) - } - }; - - let var = existing_bound_var.unwrap_or_else(|| { - let var = ty::BoundVar::from(self.variables.len()); - self.variables.push(r.into()); - self.primitive_var_infos.push(CanonicalVarInfo { kind }); - var - }); - - Region::new_anon_bound(self.cx(), self.binder_index, var) - } - - fn fold_ty(&mut self, t: I::Ty) -> I::Ty { + fn cached_fold_ty(&mut self, t: I::Ty) -> I::Ty { let kind = match t.kind() { ty::Infer(i) => match i { ty::TyVar(vid) => { @@ -368,20 +326,98 @@ impl, I: Interner> TypeFolder for Canonicaliz | ty::Tuple(_) | ty::Alias(_, _) | ty::Bound(_, _) - | ty::Error(_) => return t.super_fold_with(self), + | ty::Error(_) => { + return t.super_fold_with(self); + } }; - let var = ty::BoundVar::from( - self.variables.iter().position(|&v| v == t.into()).unwrap_or_else(|| { - let var = self.variables.len(); - self.variables.push(t.into()); - self.primitive_var_infos.push(CanonicalVarInfo { kind }); - var - }), - ); + let var = self.get_or_insert_bound_var(t, CanonicalVarInfo { kind }); Ty::new_anon_bound(self.cx(), self.binder_index, var) } +} + +impl, I: Interner> TypeFolder for Canonicalizer<'_, D, I> { + fn cx(&self) -> I { + self.delegate.cx() + } + + fn fold_binder(&mut self, t: ty::Binder) -> ty::Binder + where + T: TypeFoldable, + { + self.binder_index.shift_in(1); + let t = t.super_fold_with(self); + self.binder_index.shift_out(1); + t + } + + fn fold_region(&mut self, r: I::Region) -> I::Region { + let kind = match r.kind() { + ty::ReBound(..) => return r, + + // We may encounter `ReStatic` in item signatures or the hidden type + // of an opaque. `ReErased` should only be encountered in the hidden + // type of an opaque for regions that are ignored for the purposes of + // captures. + // + // FIXME: We should investigate the perf implications of not uniquifying + // `ReErased`. We may be able to short-circuit registering region + // obligations if we encounter a `ReErased` on one side, for example. + ty::ReStatic | ty::ReErased | ty::ReError(_) => match self.canonicalize_mode { + CanonicalizeMode::Input => CanonicalVarKind::Region(ty::UniverseIndex::ROOT), + CanonicalizeMode::Response { .. } => return r, + }, + + ty::ReEarlyParam(_) | ty::ReLateParam(_) => match self.canonicalize_mode { + CanonicalizeMode::Input => CanonicalVarKind::Region(ty::UniverseIndex::ROOT), + CanonicalizeMode::Response { .. } => { + panic!("unexpected region in response: {r:?}") + } + }, + + ty::RePlaceholder(placeholder) => match self.canonicalize_mode { + // We canonicalize placeholder regions as existentials in query inputs. + CanonicalizeMode::Input => CanonicalVarKind::Region(ty::UniverseIndex::ROOT), + CanonicalizeMode::Response { max_input_universe } => { + // If we have a placeholder region inside of a query, it must be from + // a new universe. + if max_input_universe.can_name(placeholder.universe()) { + panic!("new placeholder in universe {max_input_universe:?}: {r:?}"); + } + CanonicalVarKind::PlaceholderRegion(placeholder) + } + }, + + ty::ReVar(vid) => { + assert_eq!( + self.delegate.opportunistic_resolve_lt_var(vid), + r, + "region vid should have been resolved fully before canonicalization" + ); + match self.canonicalize_mode { + CanonicalizeMode::Input => CanonicalVarKind::Region(ty::UniverseIndex::ROOT), + CanonicalizeMode::Response { .. } => { + CanonicalVarKind::Region(self.delegate.universe_of_lt(vid).unwrap()) + } + } + } + }; + + let var = self.get_or_insert_bound_var(r, CanonicalVarInfo { kind }); + + Region::new_anon_bound(self.cx(), self.binder_index, var) + } + + fn fold_ty(&mut self, t: I::Ty) -> I::Ty { + if let Some(&ty) = self.cache.get(&(self.binder_index, t)) { + ty + } else { + let res = self.cached_fold_ty(t); + assert!(self.cache.insert((self.binder_index, t), res).is_none()); + res + } + } fn fold_const(&mut self, c: I::Const) -> I::Const { let kind = match c.kind() { @@ -419,14 +455,7 @@ impl, I: Interner> TypeFolder for Canonicaliz | ty::ConstKind::Expr(_) => return c.super_fold_with(self), }; - let var = ty::BoundVar::from( - self.variables.iter().position(|&v| v == c.into()).unwrap_or_else(|| { - let var = self.variables.len(); - self.variables.push(c.into()); - self.primitive_var_infos.push(CanonicalVarInfo { kind }); - var - }), - ); + let var = self.get_or_insert_bound_var(c, CanonicalVarInfo { kind }); Const::new_anon_bound(self.cx(), self.binder_index, var) } From 020bd6d323f20fa3c723320ee5b8484a8bcaa6cb Mon Sep 17 00:00:00 2001 From: Urgau Date: Mon, 30 Sep 2024 11:15:05 +0200 Subject: [PATCH 424/683] Improve `--print=check-cfg` documentation --- .../src/compiler-flags/print-check-cfg.md | 27 +++++++++++-------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/src/doc/unstable-book/src/compiler-flags/print-check-cfg.md b/src/doc/unstable-book/src/compiler-flags/print-check-cfg.md index ab63c986e85..8d314aa62d4 100644 --- a/src/doc/unstable-book/src/compiler-flags/print-check-cfg.md +++ b/src/doc/unstable-book/src/compiler-flags/print-check-cfg.md @@ -4,23 +4,28 @@ The tracking issue for this feature is: [#125704](https://github.com/rust-lang/r ------------------------ -This option of the `--print` flag print the list of expected cfgs. +This option of the `--print` flag print the list of all the expected cfgs. -This is related to the `--check-cfg` flag which allows specifying arbitrary expected +This is related to the [`--check-cfg` flag][check-cfg] which allows specifying arbitrary expected names and values. -This print option works similarly to `--print=cfg` (modulo check-cfg specifics): - - *check_cfg syntax*: *output of --print=check-cfg* - - `cfg(windows)`: `windows` - - `cfg(feature, values("foo", "bar"))`: `feature="foo"` and `feature="bar"` - - `cfg(feature, values(none(), ""))`: `feature` and `feature=""` - - `cfg(feature, values(any()))`: `feature=any()` - - `cfg(feature, values())`: `feature=` - - `cfg(any())`: `any()` - - *nothing*: `any()=any()` +This print option works similarly to `--print=cfg` (modulo check-cfg specifics). + +| `--check-cfg` | `--print=check-cfg` | +|-----------------------------------|-----------------------------| +| `cfg(foo)` | `foo` | +| `cfg(foo, values("bar"))` | `foo="bar"` | +| `cfg(foo, values(none(), "bar"))` | `foo` & `foo="bar"` | +| | *check-cfg specific syntax* | +| `cfg(foo, values(any())` | `foo=any()` | +| `cfg(foo, values())` | `foo=` | +| `cfg(any())` | `any()` | +| *none* | `any()=any()` | To be used like this: ```bash rustc --print=check-cfg -Zunstable-options lib.rs ``` + +[check-cfg]: https://doc.rust-lang.org/nightly/rustc/check-cfg.html From 874d55cea8af386d23663dcea1821d9697e028ff Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Mon, 30 Sep 2024 13:05:44 +0300 Subject: [PATCH 425/683] enable compiler fingerprint logs in verbose mode Signed-off-by: onur-ozkan --- src/bootstrap/src/core/builder.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/bootstrap/src/core/builder.rs b/src/bootstrap/src/core/builder.rs index 47420f8fe72..122eb50dd94 100644 --- a/src/bootstrap/src/core/builder.rs +++ b/src/bootstrap/src/core/builder.rs @@ -2012,6 +2012,11 @@ impl<'a> Builder<'a> { cargo.env("RUSTC_BACKTRACE_ON_ICE", "1"); } + if self.is_verbose() { + // This provides very useful logs especially when debugging build cache-related stuff. + cargo.env("CARGO_LOG", "cargo::core::compiler::fingerprint=info"); + } + cargo.env("RUSTC_VERBOSE", self.verbosity.to_string()); // Downstream forks of the Rust compiler might want to use a custom libc to add support for From 9cb540a13cb2249754ea3e755cb1472151d061db Mon Sep 17 00:00:00 2001 From: Urgau Date: Mon, 30 Sep 2024 12:13:17 +0200 Subject: [PATCH 426/683] Reject leading unsafe in `cfg!(...)` and `--check-cfg`. --- compiler/rustc_builtin_macros/src/cfg.rs | 2 +- compiler/rustc_interface/src/interface.rs | 2 +- .../unsafe/extraneous-unsafe-attributes.rs | 6 +++++- .../extraneous-unsafe-attributes.stderr | 20 ++++++++++++++++++- tests/ui/check-cfg/invalid-arguments.rs | 3 ++- .../invalid-arguments.unsafe_attr.stderr | 5 +++++ 6 files changed, 33 insertions(+), 5 deletions(-) create mode 100644 tests/ui/check-cfg/invalid-arguments.unsafe_attr.stderr diff --git a/compiler/rustc_builtin_macros/src/cfg.rs b/compiler/rustc_builtin_macros/src/cfg.rs index de198115fa0..cf1d5c68ead 100644 --- a/compiler/rustc_builtin_macros/src/cfg.rs +++ b/compiler/rustc_builtin_macros/src/cfg.rs @@ -43,7 +43,7 @@ fn parse_cfg<'a>(cx: &ExtCtxt<'a>, span: Span, tts: TokenStream) -> PResult<'a, return Err(cx.dcx().create_err(errors::RequiresCfgPattern { span })); } - let cfg = p.parse_meta_item(AllowLeadingUnsafe::Yes)?; + let cfg = p.parse_meta_item(AllowLeadingUnsafe::No)?; let _ = p.eat(&token::Comma); diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs index c2241773c8c..780693f8932 100644 --- a/compiler/rustc_interface/src/interface.rs +++ b/compiler/rustc_interface/src/interface.rs @@ -174,7 +174,7 @@ pub(crate) fn parse_check_cfg(dcx: DiagCtxtHandle<'_>, specs: Vec) -> Ch } }; - let meta_item = match parser.parse_meta_item(AllowLeadingUnsafe::Yes) { + let meta_item = match parser.parse_meta_item(AllowLeadingUnsafe::No) { Ok(meta_item) if parser.token == token::Eof => meta_item, Ok(..) => expected_error(), Err(err) => { diff --git a/tests/ui/attributes/unsafe/extraneous-unsafe-attributes.rs b/tests/ui/attributes/unsafe/extraneous-unsafe-attributes.rs index b561550c198..273b127bf9c 100644 --- a/tests/ui/attributes/unsafe/extraneous-unsafe-attributes.rs +++ b/tests/ui/attributes/unsafe/extraneous-unsafe-attributes.rs @@ -27,4 +27,8 @@ mod inner { #[unsafe(used)] //~ ERROR: is not an unsafe attribute static FOO: usize = 0; -fn main() {} +fn main() { + let _a = cfg!(unsafe(foo)); + //~^ ERROR: expected identifier, found keyword `unsafe` + //~^^ ERROR: invalid predicate `r#unsafe` +} diff --git a/tests/ui/attributes/unsafe/extraneous-unsafe-attributes.stderr b/tests/ui/attributes/unsafe/extraneous-unsafe-attributes.stderr index 9fb7f062b91..445d239d867 100644 --- a/tests/ui/attributes/unsafe/extraneous-unsafe-attributes.stderr +++ b/tests/ui/attributes/unsafe/extraneous-unsafe-attributes.stderr @@ -22,6 +22,23 @@ LL | #[unsafe(test)] | = note: extraneous unsafe is not allowed in attributes +error: expected identifier, found keyword `unsafe` + --> $DIR/extraneous-unsafe-attributes.rs:31:19 + | +LL | let _a = cfg!(unsafe(foo)); + | ^^^^^^ expected identifier, found keyword + | +help: escape `unsafe` to use it as an identifier + | +LL | let _a = cfg!(r#unsafe(foo)); + | ++ + +error[E0537]: invalid predicate `r#unsafe` + --> $DIR/extraneous-unsafe-attributes.rs:31:19 + | +LL | let _a = cfg!(unsafe(foo)); + | ^^^^^^^^^^^ + error: `ignore` is not an unsafe attribute --> $DIR/extraneous-unsafe-attributes.rs:13:3 | @@ -62,5 +79,6 @@ LL | #[unsafe(used)] | = note: extraneous unsafe is not allowed in attributes -error: aborting due to 8 previous errors +error: aborting due to 10 previous errors +For more information about this error, try `rustc --explain E0537`. diff --git a/tests/ui/check-cfg/invalid-arguments.rs b/tests/ui/check-cfg/invalid-arguments.rs index b8588ecb4ff..c6b1218ce27 100644 --- a/tests/ui/check-cfg/invalid-arguments.rs +++ b/tests/ui/check-cfg/invalid-arguments.rs @@ -8,7 +8,7 @@ //@ revisions: values_any_missing_values values_any_before_ident ident_in_values_1 //@ revisions: ident_in_values_2 unknown_meta_item_1 unknown_meta_item_2 unknown_meta_item_3 //@ revisions: mixed_values_any mixed_any any_values giberich unterminated -//@ revisions: none_not_empty cfg_none +//@ revisions: none_not_empty cfg_none unsafe_attr // //@ [anything_else]compile-flags: --check-cfg=anything_else(...) //@ [boolean]compile-flags: --check-cfg=cfg(true) @@ -33,5 +33,6 @@ //@ [cfg_none]compile-flags: --check-cfg=cfg(none()) //@ [giberich]compile-flags: --check-cfg=cfg(...) //@ [unterminated]compile-flags: --check-cfg=cfg( +//@ [unsafe_attr]compile-flags: --check-cfg=unsafe(cfg(foo)) fn main() {} diff --git a/tests/ui/check-cfg/invalid-arguments.unsafe_attr.stderr b/tests/ui/check-cfg/invalid-arguments.unsafe_attr.stderr new file mode 100644 index 00000000000..5236ed6f605 --- /dev/null +++ b/tests/ui/check-cfg/invalid-arguments.unsafe_attr.stderr @@ -0,0 +1,5 @@ +error: invalid `--check-cfg` argument: `unsafe(cfg(foo))` + | + = note: expected `cfg(name, values("value1", "value2", ... "valueN"))` + = note: visit for more details + From 5a7058c5a542ec42d1fa9b524f7b4f7d6845d1e9 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: Mon, 30 Sep 2024 17:07:24 +0800 Subject: [PATCH 427/683] Drop conditionally applied cargo `-Zon-broken-pipe=kill` flags These conditionally applied flags trigger rebuilds because they can invalidate previous cargo build cache. --- src/bootstrap/src/core/build_steps/compile.rs | 4 ---- src/bootstrap/src/core/build_steps/tool.rs | 11 ++++------- 2 files changed, 4 insertions(+), 11 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index eaa982d4e2b..bb1d8d27928 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -1053,10 +1053,6 @@ pub fn rustc_cargo( cargo.rustdocflag("-Zcrate-attr=warn(rust_2018_idioms)"); - // If the rustc output is piped to e.g. `head -n1` we want the process to be - // killed, rather than having an error bubble up and cause a panic. - cargo.rustflag("-Zon-broken-pipe=kill"); - if builder.config.llvm_enzyme { cargo.rustflag("-l").rustflag("Enzyme-19"); } diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs index 64dfe054d9c..fa2c1b8360f 100644 --- a/src/bootstrap/src/core/build_steps/tool.rs +++ b/src/bootstrap/src/core/build_steps/tool.rs @@ -200,6 +200,10 @@ pub fn prepare_tool_cargo( cargo.arg("--features").arg(features.join(", ")); } + // Warning: be very careful with RUSTFLAGS or command-line options, as conditionally applied + // RUSTFLAGS or cli flags can lead to hard-to-diagnose rebuilds due to flag differences, causing + // previous tool build artifacts to get invalidated. + // Enable internal lints for clippy and rustdoc // NOTE: this doesn't enable lints for any other tools unless they explicitly add `#![warn(rustc::internal)]` // See https://github.com/rust-lang/rust/pull/80573#issuecomment-754010776 @@ -209,13 +213,6 @@ pub fn prepare_tool_cargo( // See https://github.com/rust-lang/rust/issues/116538 cargo.rustflag("-Zunstable-options"); - // `-Zon-broken-pipe=kill` breaks cargo tests - if !path.ends_with("cargo") { - // If the output is piped to e.g. `head -n1` we want the process to be killed, - // rather than having an error bubble up and cause a panic. - cargo.rustflag("-Zon-broken-pipe=kill"); - } - cargo } From fd1429a56b5c6eadb6205c982f4945b631f55db9 Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Mon, 30 Sep 2024 14:20:12 +0300 Subject: [PATCH 428/683] replace manual verbose checks with `Config::is_verbose` Signed-off-by: onur-ozkan --- src/bootstrap/src/core/builder.rs | 4 ++-- src/bootstrap/src/core/config/config.rs | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/bootstrap/src/core/builder.rs b/src/bootstrap/src/core/builder.rs index 47420f8fe72..5653b29fda8 100644 --- a/src/bootstrap/src/core/builder.rs +++ b/src/bootstrap/src/core/builder.rs @@ -1562,8 +1562,8 @@ impl<'a> Builder<'a> { let libdir = self.rustc_libdir(compiler); let sysroot_str = sysroot.as_os_str().to_str().expect("sysroot should be UTF-8"); - if !matches!(self.config.dry_run, DryRun::SelfCheck) { - self.verbose_than(0, || println!("using sysroot {sysroot_str}")); + if self.is_verbose() && !matches!(self.config.dry_run, DryRun::SelfCheck) { + println!("using sysroot {sysroot_str}"); } let mut rustflags = Rustflags::new(target); diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index 77e0ece3104..0689a4caa9a 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -2428,7 +2428,7 @@ impl Config { /// Runs a function if verbosity is greater than 0 pub fn verbose(&self, f: impl Fn()) { - if self.verbose > 0 { + if self.is_verbose() { f() } } @@ -2713,7 +2713,7 @@ impl Config { .success(); if has_changes { if if_unchanged { - if self.verbose > 0 { + if self.is_verbose() { println!( "WARNING: saw changes to compiler/ or library/ since {commit}; \ ignoring `download-rustc`" @@ -2810,7 +2810,7 @@ impl Config { let has_changes = !t!(git.as_command_mut().status()).success(); if has_changes { if if_unchanged { - if self.verbose > 0 { + if self.is_verbose() { println!( "warning: saw changes to one of {modified_paths:?} since {commit}; \ ignoring `{option_name}`" From ac2e3180344bdd6092fe2b845df65c4ff4a5aa10 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 26 Sep 2024 20:16:40 +0200 Subject: [PATCH 429/683] make type-check-4 asm tests about non-const expressions --- tests/ui/asm/aarch64/type-check-4.rs | 27 ------------------------ tests/ui/asm/aarch64/type-check-4.stderr | 21 ------------------ tests/ui/asm/non-const.rs | 11 ++++++++++ tests/ui/asm/non-const.stderr | 11 ++++++++++ tests/ui/asm/x86_64/type-check-4.rs | 27 ------------------------ tests/ui/asm/x86_64/type-check-4.stderr | 21 ------------------ 6 files changed, 22 insertions(+), 96 deletions(-) delete mode 100644 tests/ui/asm/aarch64/type-check-4.rs delete mode 100644 tests/ui/asm/aarch64/type-check-4.stderr create mode 100644 tests/ui/asm/non-const.rs create mode 100644 tests/ui/asm/non-const.stderr delete mode 100644 tests/ui/asm/x86_64/type-check-4.rs delete mode 100644 tests/ui/asm/x86_64/type-check-4.stderr diff --git a/tests/ui/asm/aarch64/type-check-4.rs b/tests/ui/asm/aarch64/type-check-4.rs deleted file mode 100644 index c24567bd5b0..00000000000 --- a/tests/ui/asm/aarch64/type-check-4.rs +++ /dev/null @@ -1,27 +0,0 @@ -//@ only-aarch64 -//@ build-fail - -use std::arch::global_asm; - -fn main() {} - -// Constants must be... constant - -static mut S: i32 = 1; -const fn const_foo(x: i32) -> i32 { - x -} -const fn const_bar(x: T) -> T { - x -} -global_asm!("{}", const unsafe { S }); -//~^ ERROR: evaluation of constant value failed -//~| mutable global memory -global_asm!("{}", const const_foo(0)); -global_asm!("{}", const const_foo(unsafe { S })); -//~^ ERROR: evaluation of constant value failed -//~| mutable global memory -global_asm!("{}", const const_bar(0)); -global_asm!("{}", const const_bar(unsafe { S })); -//~^ ERROR: evaluation of constant value failed -//~| mutable global memory diff --git a/tests/ui/asm/aarch64/type-check-4.stderr b/tests/ui/asm/aarch64/type-check-4.stderr deleted file mode 100644 index 8c22dfcdb5e..00000000000 --- a/tests/ui/asm/aarch64/type-check-4.stderr +++ /dev/null @@ -1,21 +0,0 @@ -error[E0080]: evaluation of constant value failed - --> $DIR/type-check-4.rs:17:34 - | -LL | global_asm!("{}", const unsafe { S }); - | ^ constant accesses mutable global memory - -error[E0080]: evaluation of constant value failed - --> $DIR/type-check-4.rs:21:44 - | -LL | global_asm!("{}", const const_foo(unsafe { S })); - | ^ constant accesses mutable global memory - -error[E0080]: evaluation of constant value failed - --> $DIR/type-check-4.rs:25:44 - | -LL | global_asm!("{}", const const_bar(unsafe { S })); - | ^ constant accesses mutable global memory - -error: aborting due to 3 previous errors - -For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/asm/non-const.rs b/tests/ui/asm/non-const.rs new file mode 100644 index 00000000000..63c46563226 --- /dev/null +++ b/tests/ui/asm/non-const.rs @@ -0,0 +1,11 @@ +//@ needs-asm-support + +use std::arch::global_asm; + +fn main() {} + +// Constants must be... constant +fn non_const_fn(x: i32) -> i32 { x } + +global_asm!("/* {} */", const non_const_fn(0)); +//~^ERROR: cannot call non-const fn diff --git a/tests/ui/asm/non-const.stderr b/tests/ui/asm/non-const.stderr new file mode 100644 index 00000000000..5fae2ac9843 --- /dev/null +++ b/tests/ui/asm/non-const.stderr @@ -0,0 +1,11 @@ +error[E0015]: cannot call non-const fn `non_const_fn` in constants + --> $DIR/non-const.rs:10:31 + | +LL | global_asm!("/* {} */", const non_const_fn(0)); + | ^^^^^^^^^^^^^^^ + | + = note: calls in constants are limited to constant functions, tuple structs and tuple variants + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0015`. diff --git a/tests/ui/asm/x86_64/type-check-4.rs b/tests/ui/asm/x86_64/type-check-4.rs deleted file mode 100644 index ebc6edc07e4..00000000000 --- a/tests/ui/asm/x86_64/type-check-4.rs +++ /dev/null @@ -1,27 +0,0 @@ -//@ only-x86_64 -//@ build-fail - -use std::arch::global_asm; - -fn main() {} - -// Constants must be... constant - -static mut S: i32 = 1; -const fn const_foo(x: i32) -> i32 { - x -} -const fn const_bar(x: T) -> T { - x -} -global_asm!("{}", const unsafe { S }); -//~^ ERROR evaluation of constant value failed -//~| mutable global memory -global_asm!("{}", const const_foo(0)); -global_asm!("{}", const const_foo(unsafe { S })); -//~^ ERROR evaluation of constant value failed -//~| mutable global memory -global_asm!("{}", const const_bar(0)); -global_asm!("{}", const const_bar(unsafe { S })); -//~^ ERROR evaluation of constant value failed -//~| mutable global memory diff --git a/tests/ui/asm/x86_64/type-check-4.stderr b/tests/ui/asm/x86_64/type-check-4.stderr deleted file mode 100644 index 8c22dfcdb5e..00000000000 --- a/tests/ui/asm/x86_64/type-check-4.stderr +++ /dev/null @@ -1,21 +0,0 @@ -error[E0080]: evaluation of constant value failed - --> $DIR/type-check-4.rs:17:34 - | -LL | global_asm!("{}", const unsafe { S }); - | ^ constant accesses mutable global memory - -error[E0080]: evaluation of constant value failed - --> $DIR/type-check-4.rs:21:44 - | -LL | global_asm!("{}", const const_foo(unsafe { S })); - | ^ constant accesses mutable global memory - -error[E0080]: evaluation of constant value failed - --> $DIR/type-check-4.rs:25:44 - | -LL | global_asm!("{}", const const_bar(unsafe { S })); - | ^ constant accesses mutable global memory - -error: aborting due to 3 previous errors - -For more information about this error, try `rustc --explain E0080`. From ed5443fcdf3b4d02a89aec929cd62aa97586096f Mon Sep 17 00:00:00 2001 From: Ding Xiang Fei Date: Mon, 30 Sep 2024 22:21:45 +0800 Subject: [PATCH 430/683] apply suggestions --- compiler/rustc_lint/src/if_let_rescope.rs | 3 +- tests/ui/drop/lint-if-let-rescope.fixed | 17 ++++++++- tests/ui/drop/lint-if-let-rescope.rs | 17 ++++++++- tests/ui/drop/lint-if-let-rescope.stderr | 46 +++++++++++++++++++++-- 4 files changed, 75 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_lint/src/if_let_rescope.rs b/compiler/rustc_lint/src/if_let_rescope.rs index 8cb63d5cb05..8f643de836a 100644 --- a/compiler/rustc_lint/src/if_let_rescope.rs +++ b/compiler/rustc_lint/src/if_let_rescope.rs @@ -260,7 +260,8 @@ impl<'tcx> LateLintPass<'tcx> for IfLetRescope { // if let .. { body } else { break; } // } // ``` - // There is no observable from the `{ break; }` block so the edition change + // There is no observable change in drop order on the overall `if let` expression + // given that the `{ break; }` block is trivial so the edition change // means nothing substantial to this `while` statement. self.skip.insert(value.hir_id); return; diff --git a/tests/ui/drop/lint-if-let-rescope.fixed b/tests/ui/drop/lint-if-let-rescope.fixed index d579ce98236..199068d0fd2 100644 --- a/tests/ui/drop/lint-if-let-rescope.fixed +++ b/tests/ui/drop/lint-if-let-rescope.fixed @@ -1,7 +1,7 @@ //@ run-rustfix #![deny(if_let_rescope)] -#![feature(if_let_rescope)] +#![feature(if_let_rescope, stmt_expr_attributes)] #![allow(irrefutable_let_patterns, unused_parens)] fn droppy() -> Droppy { @@ -69,16 +69,29 @@ fn main() { //~| HELP: a `match` with a single arm can preserve the drop order up to Edition 2021 } + #[rustfmt::skip] if (match droppy().get() { Some(_value) => { true } _ => { false }}) { //~^ ERROR: `if let` assigns a shorter lifetime since Edition 2024 //~| WARN: this changes meaning in Rust 2024 - //~| HELP: a `match` with a single arm can preserve the drop order up to Edition 2021 //~| HELP: the value is now dropped here in Edition 2024 + //~| HELP: a `match` with a single arm can preserve the drop order up to Edition 2021 // do something + } else if (((match droppy().get() { Some(_value) => { true } _ => { false }}))) { + //~^ ERROR: `if let` assigns a shorter lifetime since Edition 2024 + //~| WARN: this changes meaning in Rust 2024 + //~| HELP: the value is now dropped here in Edition 2024 + //~| HELP: a `match` with a single arm can preserve the drop order up to Edition 2021 } while let Some(_value) = droppy().get() { // Should not lint break; } + + while (match droppy().get() { Some(_value) => { false } _ => { true }}) { + //~^ ERROR: `if let` assigns a shorter lifetime since Edition 2024 + //~| WARN: this changes meaning in Rust 2024 + //~| HELP: the value is now dropped here in Edition 2024 + //~| HELP: a `match` with a single arm can preserve the drop order up to Edition 2021 + } } diff --git a/tests/ui/drop/lint-if-let-rescope.rs b/tests/ui/drop/lint-if-let-rescope.rs index aab293cdcfc..4c043c0266c 100644 --- a/tests/ui/drop/lint-if-let-rescope.rs +++ b/tests/ui/drop/lint-if-let-rescope.rs @@ -1,7 +1,7 @@ //@ run-rustfix #![deny(if_let_rescope)] -#![feature(if_let_rescope)] +#![feature(if_let_rescope, stmt_expr_attributes)] #![allow(irrefutable_let_patterns, unused_parens)] fn droppy() -> Droppy { @@ -69,16 +69,29 @@ fn main() { //~| HELP: a `match` with a single arm can preserve the drop order up to Edition 2021 } + #[rustfmt::skip] if (if let Some(_value) = droppy().get() { true } else { false }) { //~^ ERROR: `if let` assigns a shorter lifetime since Edition 2024 //~| WARN: this changes meaning in Rust 2024 - //~| HELP: a `match` with a single arm can preserve the drop order up to Edition 2021 //~| HELP: the value is now dropped here in Edition 2024 + //~| HELP: a `match` with a single arm can preserve the drop order up to Edition 2021 // do something + } else if (((if let Some(_value) = droppy().get() { true } else { false }))) { + //~^ ERROR: `if let` assigns a shorter lifetime since Edition 2024 + //~| WARN: this changes meaning in Rust 2024 + //~| HELP: the value is now dropped here in Edition 2024 + //~| HELP: a `match` with a single arm can preserve the drop order up to Edition 2021 } while let Some(_value) = droppy().get() { // Should not lint break; } + + while (if let Some(_value) = droppy().get() { false } else { true }) { + //~^ ERROR: `if let` assigns a shorter lifetime since Edition 2024 + //~| WARN: this changes meaning in Rust 2024 + //~| HELP: the value is now dropped here in Edition 2024 + //~| HELP: a `match` with a single arm can preserve the drop order up to Edition 2021 + } } diff --git a/tests/ui/drop/lint-if-let-rescope.stderr b/tests/ui/drop/lint-if-let-rescope.stderr index 50801ae166f..ef60d141b79 100644 --- a/tests/ui/drop/lint-if-let-rescope.stderr +++ b/tests/ui/drop/lint-if-let-rescope.stderr @@ -132,7 +132,7 @@ LL | if let () = { match Droppy.get() { Some(_value) => {} _ => {}} } { | ~~~~~ +++++++++++++++++ ++++++++ error: `if let` assigns a shorter lifetime since Edition 2024 - --> $DIR/lint-if-let-rescope.rs:72:12 + --> $DIR/lint-if-let-rescope.rs:73:12 | LL | if (if let Some(_value) = droppy().get() { true } else { false }) { | ^^^^^^^^^^^^^^^^^^^--------^^^^^^ @@ -142,7 +142,7 @@ LL | if (if let Some(_value) = droppy().get() { true } else { false }) { = warning: this changes meaning in Rust 2024 = note: for more information, see issue #124085 help: the value is now dropped here in Edition 2024 - --> $DIR/lint-if-let-rescope.rs:72:53 + --> $DIR/lint-if-let-rescope.rs:73:53 | LL | if (if let Some(_value) = droppy().get() { true } else { false }) { | ^ @@ -151,5 +151,45 @@ help: a `match` with a single arm can preserve the drop order up to Edition 2021 LL | if (match droppy().get() { Some(_value) => { true } _ => { false }}) { | ~~~~~ +++++++++++++++++ ~~~~ + -error: aborting due to 6 previous errors +error: `if let` assigns a shorter lifetime since Edition 2024 + --> $DIR/lint-if-let-rescope.rs:79:21 + | +LL | } else if (((if let Some(_value) = droppy().get() { true } else { false }))) { + | ^^^^^^^^^^^^^^^^^^^--------^^^^^^ + | | + | this value has a significant drop implementation which may observe a major change in drop order and requires your discretion + | + = warning: this changes meaning in Rust 2024 + = note: for more information, see issue #124085 +help: the value is now dropped here in Edition 2024 + --> $DIR/lint-if-let-rescope.rs:79:62 + | +LL | } else if (((if let Some(_value) = droppy().get() { true } else { false }))) { + | ^ +help: a `match` with a single arm can preserve the drop order up to Edition 2021 + | +LL | } else if (((match droppy().get() { Some(_value) => { true } _ => { false }}))) { + | ~~~~~ +++++++++++++++++ ~~~~ + + +error: `if let` assigns a shorter lifetime since Edition 2024 + --> $DIR/lint-if-let-rescope.rs:91:15 + | +LL | while (if let Some(_value) = droppy().get() { false } else { true }) { + | ^^^^^^^^^^^^^^^^^^^--------^^^^^^ + | | + | this value has a significant drop implementation which may observe a major change in drop order and requires your discretion + | + = warning: this changes meaning in Rust 2024 + = note: for more information, see issue #124085 +help: the value is now dropped here in Edition 2024 + --> $DIR/lint-if-let-rescope.rs:91:57 + | +LL | while (if let Some(_value) = droppy().get() { false } else { true }) { + | ^ +help: a `match` with a single arm can preserve the drop order up to Edition 2021 + | +LL | while (match droppy().get() { Some(_value) => { false } _ => { true }}) { + | ~~~~~ +++++++++++++++++ ~~~~ + + +error: aborting due to 8 previous errors From eb75d20a55e7c6416592a6e9d4d2e7e21e08ce14 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 28 Sep 2024 14:16:05 -0400 Subject: [PATCH 431/683] Relax a debug assertion in codegen --- Cargo.lock | 1 + .../rustc_codegen_cranelift/src/unsize.rs | 17 ++------ compiler/rustc_codegen_ssa/Cargo.toml | 1 + compiler/rustc_codegen_ssa/src/base.rs | 42 ++++++++++++++++--- tests/ui/codegen/sub-principals-in-codegen.rs | 8 ++++ 5 files changed, 49 insertions(+), 20 deletions(-) create mode 100644 tests/ui/codegen/sub-principals-in-codegen.rs diff --git a/Cargo.lock b/Cargo.lock index 582b5a763e6..7ea8c300088 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3448,6 +3448,7 @@ dependencies = [ "rustc_span", "rustc_symbol_mangling", "rustc_target", + "rustc_trait_selection", "rustc_type_ir", "serde_json", "smallvec", diff --git a/compiler/rustc_codegen_cranelift/src/unsize.rs b/compiler/rustc_codegen_cranelift/src/unsize.rs index 339628053a9..5c297ebfadb 100644 --- a/compiler/rustc_codegen_cranelift/src/unsize.rs +++ b/compiler/rustc_codegen_cranelift/src/unsize.rs @@ -2,6 +2,7 @@ //! //! [`PointerCoercion::Unsize`]: `rustc_middle::ty::adjustment::PointerCoercion::Unsize` +use rustc_codegen_ssa::base::validate_trivial_unsize; use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths}; use crate::base::codegen_panic_nounwind; @@ -34,20 +35,8 @@ pub(crate) fn unsized_info<'tcx>( let old_info = old_info.expect("unsized_info: missing old info for trait upcasting coercion"); if data_a.principal_def_id() == data_b.principal_def_id() { - // Codegen takes advantage of the additional assumption, where if the - // principal trait def id of what's being casted doesn't change, - // then we don't need to adjust the vtable at all. This - // corresponds to the fact that `dyn Tr: Unsize>` - // requires that `A = B`; we don't allow *upcasting* objects - // between the same trait with different args. If we, for - // some reason, were to relax the `Unsize` trait, it could become - // unsound, so let's assert here that the trait refs are *equal*. - // - // We can use `assert_eq` because the binders should have been anonymized, - // and because higher-ranked equality now requires the binders are equal. - debug_assert_eq!( - data_a.principal(), - data_b.principal(), + debug_assert!( + validate_trivial_unsize(fx.tcx, data_a, data_b), "NOP unsize vtable changed principal trait ref: {data_a} -> {data_b}" ); return old_info; diff --git a/compiler/rustc_codegen_ssa/Cargo.toml b/compiler/rustc_codegen_ssa/Cargo.toml index 81590674ec7..346f07dfa0a 100644 --- a/compiler/rustc_codegen_ssa/Cargo.toml +++ b/compiler/rustc_codegen_ssa/Cargo.toml @@ -34,6 +34,7 @@ rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } rustc_symbol_mangling = { path = "../rustc_symbol_mangling" } rustc_target = { path = "../rustc_target" } +rustc_trait_selection = { path = "../rustc_trait_selection" } rustc_type_ir = { path = "../rustc_type_ir" } serde_json = "1.0.59" smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index 5c67600e4ee..1d391254983 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -27,6 +27,8 @@ use rustc_session::config::{self, CrateType, EntryFnType, OptLevel, OutputType}; use rustc_span::symbol::sym; use rustc_span::{DUMMY_SP, Symbol}; use rustc_target::abi::FIRST_VARIANT; +use rustc_trait_selection::infer::TyCtxtInferExt; +use rustc_trait_selection::traits::{ObligationCause, ObligationCtxt}; use tracing::{debug, info}; use crate::assert_module_sources::CguReuse; @@ -101,6 +103,38 @@ pub fn compare_simd_types<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( bx.sext(cmp, ret_ty) } +/// Codegen takes advantage of the additional assumption, where if the +/// principal trait def id of what's being casted doesn't change, +/// then we don't need to adjust the vtable at all. This +/// corresponds to the fact that `dyn Tr: Unsize>` +/// requires that `A = B`; we don't allow *upcasting* objects +/// between the same trait with different args. If we, for +/// some reason, were to relax the `Unsize` trait, it could become +/// unsound, so let's validate here that the trait refs are subtypes. +pub fn validate_trivial_unsize<'tcx>( + tcx: TyCtxt<'tcx>, + data_a: &'tcx ty::List>, + data_b: &'tcx ty::List>, +) -> bool { + match (data_a.principal(), data_b.principal()) { + (Some(principal_a), Some(principal_b)) => { + let infcx = tcx.infer_ctxt().build(); + let ocx = ObligationCtxt::new(&infcx); + let Ok(()) = ocx.sub( + &ObligationCause::dummy(), + ty::ParamEnv::reveal_all(), + principal_a, + principal_b, + ) else { + return false; + }; + ocx.select_all_or_error().is_empty() + } + (None, None) => true, + _ => false, + } +} + /// Retrieves the information we are losing (making dynamic) in an unsizing /// adjustment. /// @@ -133,12 +167,8 @@ fn unsized_info<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( // between the same trait with different args. If we, for // some reason, were to relax the `Unsize` trait, it could become // unsound, so let's assert here that the trait refs are *equal*. - // - // We can use `assert_eq` because the binders should have been anonymized, - // and because higher-ranked equality now requires the binders are equal. - debug_assert_eq!( - data_a.principal(), - data_b.principal(), + debug_assert!( + validate_trivial_unsize(cx.tcx(), data_a, data_b), "NOP unsize vtable changed principal trait ref: {data_a} -> {data_b}" ); diff --git a/tests/ui/codegen/sub-principals-in-codegen.rs b/tests/ui/codegen/sub-principals-in-codegen.rs new file mode 100644 index 00000000000..178c10da596 --- /dev/null +++ b/tests/ui/codegen/sub-principals-in-codegen.rs @@ -0,0 +1,8 @@ +//@ build-pass + +// Regression test for an overly aggressive assertion in #130855. + +fn main() { + let subtype: &(dyn for<'a> Fn(&'a i32) -> &'a i32) = &|x| x; + let supertype: &(dyn Fn(&'static i32) -> &'static i32) = subtype; +} From cbb5047d35d76cd34ccf238220ccc70316f6ab77 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 30 Sep 2024 12:42:29 -0400 Subject: [PATCH 432/683] Relate binders explicitly, do a leak check too --- compiler/rustc_codegen_ssa/src/base.rs | 45 +++++++++++++------ .../src/traits/engine.rs | 17 ++++++- 2 files changed, 47 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index 1d391254983..d91c0f0790d 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -27,7 +27,8 @@ use rustc_session::config::{self, CrateType, EntryFnType, OptLevel, OutputType}; use rustc_span::symbol::sym; use rustc_span::{DUMMY_SP, Symbol}; use rustc_target::abi::FIRST_VARIANT; -use rustc_trait_selection::infer::TyCtxtInferExt; +use rustc_trait_selection::infer::at::ToTrace; +use rustc_trait_selection::infer::{BoundRegionConversionTime, TyCtxtInferExt}; use rustc_trait_selection::traits::{ObligationCause, ObligationCtxt}; use tracing::{debug, info}; @@ -113,22 +114,38 @@ pub fn compare_simd_types<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( /// unsound, so let's validate here that the trait refs are subtypes. pub fn validate_trivial_unsize<'tcx>( tcx: TyCtxt<'tcx>, - data_a: &'tcx ty::List>, - data_b: &'tcx ty::List>, + source_data: &'tcx ty::List>, + target_data: &'tcx ty::List>, ) -> bool { - match (data_a.principal(), data_b.principal()) { - (Some(principal_a), Some(principal_b)) => { + match (source_data.principal(), target_data.principal()) { + (Some(hr_source_principal), Some(hr_target_principal)) => { let infcx = tcx.infer_ctxt().build(); + let universe = infcx.universe(); let ocx = ObligationCtxt::new(&infcx); - let Ok(()) = ocx.sub( - &ObligationCause::dummy(), - ty::ParamEnv::reveal_all(), - principal_a, - principal_b, - ) else { - return false; - }; - ocx.select_all_or_error().is_empty() + infcx.enter_forall(hr_target_principal, |target_principal| { + let source_principal = infcx.instantiate_binder_with_fresh_vars( + DUMMY_SP, + BoundRegionConversionTime::HigherRankedType, + hr_source_principal, + ); + let Ok(()) = ocx.eq_trace( + &ObligationCause::dummy(), + ty::ParamEnv::reveal_all(), + ToTrace::to_trace( + &ObligationCause::dummy(), + hr_target_principal, + hr_source_principal, + ), + target_principal, + source_principal, + ) else { + return false; + }; + if !ocx.select_all_or_error().is_empty() { + return false; + } + infcx.leak_check(universe, None).is_ok() + }) } (None, None) => true, _ => false, diff --git a/compiler/rustc_trait_selection/src/traits/engine.rs b/compiler/rustc_trait_selection/src/traits/engine.rs index de1d4ef15ac..d562692c1a8 100644 --- a/compiler/rustc_trait_selection/src/traits/engine.rs +++ b/compiler/rustc_trait_selection/src/traits/engine.rs @@ -9,12 +9,13 @@ use rustc_infer::infer::canonical::{ Canonical, CanonicalQueryResponse, CanonicalVarValues, QueryResponse, }; use rustc_infer::infer::outlives::env::OutlivesEnvironment; -use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, InferOk, RegionResolutionError}; +use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, InferOk, RegionResolutionError, TypeTrace}; use rustc_macros::extension; use rustc_middle::arena::ArenaAllocatable; use rustc_middle::traits::query::NoSolution; use rustc_middle::ty::error::TypeError; use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, Upcast, Variance}; +use rustc_type_ir::relate::Relate; use super::{FromSolverError, FulfillmentContext, ScrubbedTraitError, TraitEngine}; use crate::error_reporting::InferCtxtErrorExt; @@ -133,6 +134,20 @@ where .map(|infer_ok| self.register_infer_ok_obligations(infer_ok)) } + pub fn eq_trace>>( + &self, + cause: &ObligationCause<'tcx>, + param_env: ty::ParamEnv<'tcx>, + trace: TypeTrace<'tcx>, + expected: T, + actual: T, + ) -> Result<(), TypeError<'tcx>> { + self.infcx + .at(cause, param_env) + .eq_trace(DefineOpaqueTypes::Yes, trace, expected, actual) + .map(|infer_ok| self.register_infer_ok_obligations(infer_ok)) + } + /// Checks whether `expected` is a subtype of `actual`: `expected <: actual`. pub fn sub>( &self, From af3f212453f667981bb07c0029f86bc607f3baa9 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 29 Sep 2024 17:51:38 -0400 Subject: [PATCH 433/683] Instantiate binders in supertrait_vtable_slot --- .../src/traits/vtable.rs | 40 ++++++++++++++----- .../higher-ranked-upcasting-ok.rs | 15 +++---- 2 files changed, 38 insertions(+), 17 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/vtable.rs b/compiler/rustc_trait_selection/src/traits/vtable.rs index a2760fe6049..5aed55ef2d2 100644 --- a/compiler/rustc_trait_selection/src/traits/vtable.rs +++ b/compiler/rustc_trait_selection/src/traits/vtable.rs @@ -2,6 +2,8 @@ use std::fmt::Debug; use std::ops::ControlFlow; use rustc_hir::def_id::DefId; +use rustc_infer::infer::{BoundRegionConversionTime, TyCtxtInferExt}; +use rustc_infer::traits::ObligationCause; use rustc_infer::traits::util::PredicateSet; use rustc_middle::bug; use rustc_middle::query::Providers; @@ -13,7 +15,7 @@ use smallvec::{SmallVec, smallvec}; use tracing::debug; use crate::errors::DumpVTableEntries; -use crate::traits::{impossible_predicates, is_vtable_safe_method}; +use crate::traits::{ObligationCtxt, impossible_predicates, is_vtable_safe_method}; #[derive(Clone, Debug)] pub enum VtblSegment<'tcx> { @@ -383,17 +385,37 @@ pub(crate) fn supertrait_vtable_slot<'tcx>( let ty::Dynamic(target, _, _) = *target.kind() else { bug!(); }; - let target_principal = tcx - .normalize_erasing_regions(ty::ParamEnv::reveal_all(), target.principal()?) - .with_self_ty(tcx, tcx.types.trait_object_dummy_self); + let target_principal = target.principal()?.with_self_ty(tcx, tcx.types.trait_object_dummy_self); // Given that we have a target principal, it is a bug for there not to be a source principal. let ty::Dynamic(source, _, _) = *source.kind() else { bug!(); }; - let source_principal = tcx - .normalize_erasing_regions(ty::ParamEnv::reveal_all(), source.principal().unwrap()) - .with_self_ty(tcx, tcx.types.trait_object_dummy_self); + let source_principal = + source.principal().unwrap().with_self_ty(tcx, tcx.types.trait_object_dummy_self); + + let infcx = tcx.infer_ctxt().build(); + let param_env = ty::ParamEnv::reveal_all(); + let trait_refs_are_compatible = + |source: ty::PolyTraitRef<'tcx>, target: ty::PolyTraitRef<'tcx>| { + infcx.probe(|_| { + let ocx = ObligationCtxt::new(&infcx); + let source = ocx.normalize(&ObligationCause::dummy(), param_env, source); + let target = ocx.normalize(&ObligationCause::dummy(), param_env, target); + infcx.enter_forall(target, |target| { + let source = infcx.instantiate_binder_with_fresh_vars( + DUMMY_SP, + BoundRegionConversionTime::HigherRankedType, + source, + ); + let Ok(()) = ocx.eq(&ObligationCause::dummy(), param_env, target, source) + else { + return false; + }; + ocx.select_all_or_error().is_empty() + }) + }) + }; let vtable_segment_callback = { let mut vptr_offset = 0; @@ -404,9 +426,7 @@ pub(crate) fn supertrait_vtable_slot<'tcx>( } VtblSegment::TraitOwnEntries { trait_ref, emit_vptr } => { vptr_offset += tcx.own_existential_vtable_entries(trait_ref.def_id()).len(); - if tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), trait_ref) - == target_principal - { + if trait_refs_are_compatible(trait_ref, target_principal) { if emit_vptr { return ControlFlow::Break(Some(vptr_offset)); } else { diff --git a/tests/ui/traits/trait-upcasting/higher-ranked-upcasting-ok.rs b/tests/ui/traits/trait-upcasting/higher-ranked-upcasting-ok.rs index 7f793e1269f..c4c070e49fd 100644 --- a/tests/ui/traits/trait-upcasting/higher-ranked-upcasting-ok.rs +++ b/tests/ui/traits/trait-upcasting/higher-ranked-upcasting-ok.rs @@ -1,21 +1,22 @@ //@ revisions: current next //@ ignore-compare-mode-next-solver (explicit revisions) //@[next] compile-flags: -Znext-solver -//@ check-pass +//@ build-pass -// We should be able to instantiate a binder during trait upcasting. -// This test could be `check-pass`, but we should make sure that we -// do so in both trait solvers. +// Check that we are able to instantiate a binder during trait upcasting, +// and that it doesn't cause any issues with codegen either. #![feature(trait_upcasting)] trait Supertrait<'a, 'b> {} trait Subtrait<'a, 'b>: Supertrait<'a, 'b> {} -impl<'a> Supertrait<'a, 'a> for () {} -impl<'a> Subtrait<'a, 'a> for () {} +impl Supertrait<'_, '_> for () {} +impl Subtrait<'_, '_> for () {} fn ok(x: &dyn for<'a, 'b> Subtrait<'a, 'b>) -> &dyn for<'a> Supertrait<'a, 'a> { x } -fn main() {} +fn main() { + ok(&()); +} From d87e0ca497e70fe1c3112de0dce87fbd777f6451 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 30 Sep 2024 13:14:44 -0400 Subject: [PATCH 434/683] Extract trait_refs_are_compatible, make it instantiate binders --- .../src/traits/engine.rs | 17 ++++- .../src/traits/vtable.rs | 75 ++++++++++++------- 2 files changed, 64 insertions(+), 28 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/engine.rs b/compiler/rustc_trait_selection/src/traits/engine.rs index de1d4ef15ac..d562692c1a8 100644 --- a/compiler/rustc_trait_selection/src/traits/engine.rs +++ b/compiler/rustc_trait_selection/src/traits/engine.rs @@ -9,12 +9,13 @@ use rustc_infer::infer::canonical::{ Canonical, CanonicalQueryResponse, CanonicalVarValues, QueryResponse, }; use rustc_infer::infer::outlives::env::OutlivesEnvironment; -use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, InferOk, RegionResolutionError}; +use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, InferOk, RegionResolutionError, TypeTrace}; use rustc_macros::extension; use rustc_middle::arena::ArenaAllocatable; use rustc_middle::traits::query::NoSolution; use rustc_middle::ty::error::TypeError; use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, Upcast, Variance}; +use rustc_type_ir::relate::Relate; use super::{FromSolverError, FulfillmentContext, ScrubbedTraitError, TraitEngine}; use crate::error_reporting::InferCtxtErrorExt; @@ -133,6 +134,20 @@ where .map(|infer_ok| self.register_infer_ok_obligations(infer_ok)) } + pub fn eq_trace>>( + &self, + cause: &ObligationCause<'tcx>, + param_env: ty::ParamEnv<'tcx>, + trace: TypeTrace<'tcx>, + expected: T, + actual: T, + ) -> Result<(), TypeError<'tcx>> { + self.infcx + .at(cause, param_env) + .eq_trace(DefineOpaqueTypes::Yes, trace, expected, actual) + .map(|infer_ok| self.register_infer_ok_obligations(infer_ok)) + } + /// Checks whether `expected` is a subtype of `actual`: `expected <: actual`. pub fn sub>( &self, diff --git a/compiler/rustc_trait_selection/src/traits/vtable.rs b/compiler/rustc_trait_selection/src/traits/vtable.rs index 5aed55ef2d2..4f13524706b 100644 --- a/compiler/rustc_trait_selection/src/traits/vtable.rs +++ b/compiler/rustc_trait_selection/src/traits/vtable.rs @@ -2,6 +2,7 @@ use std::fmt::Debug; use std::ops::ControlFlow; use rustc_hir::def_id::DefId; +use rustc_infer::infer::at::ToTrace; use rustc_infer::infer::{BoundRegionConversionTime, TyCtxtInferExt}; use rustc_infer::traits::ObligationCause; use rustc_infer::traits::util::PredicateSet; @@ -24,6 +25,8 @@ pub enum VtblSegment<'tcx> { } /// Prepare the segments for a vtable +// FIXME: This should take a `PolyExistentialTraitRef`, since we don't care +// about our `Self` type here. pub fn prepare_vtable_segments<'tcx, T>( tcx: TyCtxt<'tcx>, trait_ref: ty::PolyTraitRef<'tcx>, @@ -385,7 +388,7 @@ pub(crate) fn supertrait_vtable_slot<'tcx>( let ty::Dynamic(target, _, _) = *target.kind() else { bug!(); }; - let target_principal = target.principal()?.with_self_ty(tcx, tcx.types.trait_object_dummy_self); + let target_principal = target.principal()?; // Given that we have a target principal, it is a bug for there not to be a source principal. let ty::Dynamic(source, _, _) = *source.kind() else { @@ -394,29 +397,6 @@ pub(crate) fn supertrait_vtable_slot<'tcx>( let source_principal = source.principal().unwrap().with_self_ty(tcx, tcx.types.trait_object_dummy_self); - let infcx = tcx.infer_ctxt().build(); - let param_env = ty::ParamEnv::reveal_all(); - let trait_refs_are_compatible = - |source: ty::PolyTraitRef<'tcx>, target: ty::PolyTraitRef<'tcx>| { - infcx.probe(|_| { - let ocx = ObligationCtxt::new(&infcx); - let source = ocx.normalize(&ObligationCause::dummy(), param_env, source); - let target = ocx.normalize(&ObligationCause::dummy(), param_env, target); - infcx.enter_forall(target, |target| { - let source = infcx.instantiate_binder_with_fresh_vars( - DUMMY_SP, - BoundRegionConversionTime::HigherRankedType, - source, - ); - let Ok(()) = ocx.eq(&ObligationCause::dummy(), param_env, target, source) - else { - return false; - }; - ocx.select_all_or_error().is_empty() - }) - }) - }; - let vtable_segment_callback = { let mut vptr_offset = 0; move |segment| { @@ -424,9 +404,15 @@ pub(crate) fn supertrait_vtable_slot<'tcx>( VtblSegment::MetadataDSA => { vptr_offset += TyCtxt::COMMON_VTABLE_ENTRIES.len(); } - VtblSegment::TraitOwnEntries { trait_ref, emit_vptr } => { - vptr_offset += tcx.own_existential_vtable_entries(trait_ref.def_id()).len(); - if trait_refs_are_compatible(trait_ref, target_principal) { + VtblSegment::TraitOwnEntries { trait_ref: vtable_principal, emit_vptr } => { + vptr_offset += + tcx.own_existential_vtable_entries(vtable_principal.def_id()).len(); + if trait_refs_are_compatible( + tcx, + vtable_principal + .map_bound(|t| ty::ExistentialTraitRef::erase_self_ty(tcx, t)), + target_principal, + ) { if emit_vptr { return ControlFlow::Break(Some(vptr_offset)); } else { @@ -446,6 +432,41 @@ pub(crate) fn supertrait_vtable_slot<'tcx>( prepare_vtable_segments(tcx, source_principal, vtable_segment_callback).unwrap() } +fn trait_refs_are_compatible<'tcx>( + tcx: TyCtxt<'tcx>, + hr_vtable_principal: ty::PolyExistentialTraitRef<'tcx>, + hr_target_principal: ty::PolyExistentialTraitRef<'tcx>, +) -> bool { + if hr_vtable_principal.def_id() != hr_target_principal.def_id() { + return false; + } + + let infcx = tcx.infer_ctxt().build(); + let param_env = ty::ParamEnv::reveal_all(); + let ocx = ObligationCtxt::new(&infcx); + let hr_source_principal = + ocx.normalize(&ObligationCause::dummy(), param_env, hr_vtable_principal); + let hr_target_principal = + ocx.normalize(&ObligationCause::dummy(), param_env, hr_target_principal); + infcx.enter_forall(hr_target_principal, |target_principal| { + let source_principal = infcx.instantiate_binder_with_fresh_vars( + DUMMY_SP, + BoundRegionConversionTime::HigherRankedType, + hr_source_principal, + ); + let Ok(()) = ocx.eq_trace( + &ObligationCause::dummy(), + param_env, + ToTrace::to_trace(&ObligationCause::dummy(), hr_target_principal, hr_source_principal), + target_principal, + source_principal, + ) else { + return false; + }; + ocx.select_all_or_error().is_empty() + }) +} + pub(super) fn provide(providers: &mut Providers) { *providers = Providers { own_existential_vtable_entries, From 7c552d56b2234018e6aa729cda6bdfbb7d533d28 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 30 Sep 2024 13:17:31 -0400 Subject: [PATCH 435/683] Also fix first_method_vtable_slot --- .../src/traits/vtable.rs | 25 +++++++++---------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/vtable.rs b/compiler/rustc_trait_selection/src/traits/vtable.rs index 4f13524706b..6e6f948a2cd 100644 --- a/compiler/rustc_trait_selection/src/traits/vtable.rs +++ b/compiler/rustc_trait_selection/src/traits/vtable.rs @@ -332,14 +332,10 @@ pub(crate) fn first_method_vtable_slot<'tcx>(tcx: TyCtxt<'tcx>, key: ty::TraitRe let ty::Dynamic(source, _, _) = *key.self_ty().kind() else { bug!(); }; - let source_principal = tcx - .normalize_erasing_regions(ty::ParamEnv::reveal_all(), source.principal().unwrap()) - .with_self_ty(tcx, tcx.types.trait_object_dummy_self); + let source_principal = + source.principal().unwrap().with_self_ty(tcx, tcx.types.trait_object_dummy_self); - let target_principal = tcx - .normalize_erasing_regions(ty::ParamEnv::reveal_all(), key) - // We don't care about the self type, since it will always be the same thing. - .with_self_ty(tcx, tcx.types.trait_object_dummy_self); + let target_principal = ty::Binder::dummy(ty::ExistentialTraitRef::erase_self_ty(tcx, key)); let vtable_segment_callback = { let mut vptr_offset = 0; @@ -348,15 +344,18 @@ pub(crate) fn first_method_vtable_slot<'tcx>(tcx: TyCtxt<'tcx>, key: ty::TraitRe VtblSegment::MetadataDSA => { vptr_offset += TyCtxt::COMMON_VTABLE_ENTRIES.len(); } - VtblSegment::TraitOwnEntries { trait_ref, emit_vptr } => { - if tcx - .normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), trait_ref) - == target_principal - { + VtblSegment::TraitOwnEntries { trait_ref: vtable_principal, emit_vptr } => { + if trait_refs_are_compatible( + tcx, + vtable_principal + .map_bound(|t| ty::ExistentialTraitRef::erase_self_ty(tcx, t)), + target_principal, + ) { return ControlFlow::Break(vptr_offset); } - vptr_offset += tcx.own_existential_vtable_entries(trait_ref.def_id()).len(); + vptr_offset += + tcx.own_existential_vtable_entries(vtable_principal.def_id()).len(); if emit_vptr { vptr_offset += 1; From eaaa94318b57e64a1a502a082aae2ed45e343af0 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 30 Sep 2024 13:26:02 -0400 Subject: [PATCH 436/683] Unpin `cc` and upgrade to the latest version `cc` was previously pinned because version 1.1.106 dropped support for Visual Studio 12 (2013), and we wanted to decouple that from the rest of the automated updates. As noted in [2], there is no longer anything indicating we support VS2013, so it should be okay to unpin it. `cc` 1.1.22 contains a fix that may help improve the high MSVC CI failure rate [3], so we also have motivation to update to that point. [1]: https://github.com/rust-lang/rust/issues/129307 [2]: https://github.com/rust-lang/rust/issues/129307#issuecomment-2383749868 [3]: https://github.com/rust-lang/rust/issues/127883 --- Cargo.lock | 7 +++++-- compiler/rustc_codegen_ssa/Cargo.toml | 2 +- compiler/rustc_llvm/Cargo.toml | 2 +- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 582b5a763e6..70731b198fc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -393,9 +393,12 @@ version = "0.1.0" [[package]] name = "cc" -version = "1.0.105" +version = "1.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5208975e568d83b6b05cc0a063c8e7e9acc2b43bee6da15616a5b73e109d7437" +checksum = "3bbb537bb4a30b90362caddba8f360c0a56bc13d3a5570028e7197204cb54a17" +dependencies = [ + "shlex", +] [[package]] name = "cfg-if" diff --git a/compiler/rustc_codegen_ssa/Cargo.toml b/compiler/rustc_codegen_ssa/Cargo.toml index 81590674ec7..f316a0a6cfc 100644 --- a/compiler/rustc_codegen_ssa/Cargo.toml +++ b/compiler/rustc_codegen_ssa/Cargo.toml @@ -8,7 +8,7 @@ edition = "2021" ar_archive_writer = "0.4.2" arrayvec = { version = "0.7", default-features = false } bitflags = "2.4.1" -cc = "=1.0.105" # FIXME(cc): pinned to keep support for VS2013 +cc = "1.1.23" either = "1.5.0" itertools = "0.12" jobserver = "0.1.28" diff --git a/compiler/rustc_llvm/Cargo.toml b/compiler/rustc_llvm/Cargo.toml index 1f74aaf9965..b29d6b79250 100644 --- a/compiler/rustc_llvm/Cargo.toml +++ b/compiler/rustc_llvm/Cargo.toml @@ -10,5 +10,5 @@ libc = "0.2.73" [build-dependencies] # tidy-alphabetical-start -cc = "=1.0.105" # FIXME(cc): pinned to keep support for VS2013 +cc = "1.1.23" # tidy-alphabetical-end From 041e76b7cd7c499837fcea63f7f780fdf774a1a5 Mon Sep 17 00:00:00 2001 From: Obei Sideg Date: Sat, 22 Jun 2024 22:17:57 +0300 Subject: [PATCH 437/683] Add multi-producer, multi-consumer channel (mpmc) --- library/std/src/lib.rs | 4 +- library/std/src/sync/mod.rs | 9 +- library/std/src/sync/mpmc/error.rs | 5 + library/std/src/sync/mpmc/mod.rs | 1035 ++++++++++++++++- library/std/src/sync/mpmc/tests.rs | 728 ++++++++++++ .../const-generics/issues/issue-82956.stderr | 2 +- tests/ui/issues/issue-12041.stderr | 2 +- tests/ui/lint/use_suggestion_json.stderr | 25 +- 8 files changed, 1758 insertions(+), 52 deletions(-) create mode 100644 library/std/src/sync/mpmc/tests.rs diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index b81e7c18abb..65a9aa66c7c 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -153,7 +153,7 @@ //! the [`io`], [`fs`], and [`net`] modules. //! //! The [`thread`] module contains Rust's threading abstractions. [`sync`] -//! contains further primitive shared memory types, including [`atomic`] and +//! contains further primitive shared memory types, including [`atomic`], [`mpmc`] and //! [`mpsc`], which contains the channel types for message passing. //! //! # Use before and after `main()` @@ -177,6 +177,7 @@ //! - after-main use of thread-locals, which also affects additional features: //! - [`thread::current()`] //! - [`thread::scope()`] +//! - [`sync::mpmc`] //! - [`sync::mpsc`] //! - before-main stdio file descriptors are not guaranteed to be open on unix platforms //! @@ -202,6 +203,7 @@ //! [`atomic`]: sync::atomic //! [`for`]: ../book/ch03-05-control-flow.html#looping-through-a-collection-with-for //! [`str`]: prim@str +//! [`mpmc`]: sync::mpmc //! [`mpsc`]: sync::mpsc //! [`std::cmp`]: cmp //! [`std::slice`]: mod@slice diff --git a/library/std/src/sync/mod.rs b/library/std/src/sync/mod.rs index 0fb8e669bf8..0fb77331293 100644 --- a/library/std/src/sync/mod.rs +++ b/library/std/src/sync/mod.rs @@ -133,6 +133,11 @@ //! inter-thread synchronisation mechanism, at the cost of some //! extra memory. //! +//! - [`mpmc`]: Multi-producer, multi-consumer queues, used for +//! message-based communication. Can provide a lightweight +//! inter-thread synchronisation mechanism, at the cost of some +//! extra memory. +//! //! - [`Mutex`]: Mutual Exclusion mechanism, which ensures that at //! most one thread at a time is able to access some data. //! @@ -153,6 +158,7 @@ //! [`Arc`]: crate::sync::Arc //! [`Barrier`]: crate::sync::Barrier //! [`Condvar`]: crate::sync::Condvar +//! [`mpmc`]: crate::sync::mpmc //! [`mpsc`]: crate::sync::mpsc //! [`Mutex`]: crate::sync::Mutex //! [`Once`]: crate::sync::Once @@ -193,12 +199,13 @@ pub use self::rwlock::{MappedRwLockReadGuard, MappedRwLockWriteGuard}; #[stable(feature = "rust1", since = "1.0.0")] pub use self::rwlock::{RwLock, RwLockReadGuard, RwLockWriteGuard}; +#[unstable(feature = "mpmc_channel", issue = "126840")] +pub mod mpmc; pub mod mpsc; mod barrier; mod condvar; mod lazy_lock; -mod mpmc; mod mutex; pub(crate) mod once; mod once_lock; diff --git a/library/std/src/sync/mpmc/error.rs b/library/std/src/sync/mpmc/error.rs index e3aec7e7623..e34b56d0831 100644 --- a/library/std/src/sync/mpmc/error.rs +++ b/library/std/src/sync/mpmc/error.rs @@ -7,6 +7,7 @@ use crate::{error, fmt}; /// /// [`send_timeout`]: super::Sender::send_timeout #[derive(PartialEq, Eq, Clone, Copy)] +#[unstable(feature = "mpmc_channel", issue = "126840")] pub enum SendTimeoutError { /// The message could not be sent because the channel is full and the operation timed out. /// @@ -18,12 +19,14 @@ pub enum SendTimeoutError { Disconnected(T), } +#[unstable(feature = "mpmc_channel", issue = "126840")] impl fmt::Debug for SendTimeoutError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { "SendTimeoutError(..)".fmt(f) } } +#[unstable(feature = "mpmc_channel", issue = "126840")] impl fmt::Display for SendTimeoutError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match *self { @@ -33,8 +36,10 @@ impl fmt::Display for SendTimeoutError { } } +#[unstable(feature = "mpmc_channel", issue = "126840")] impl error::Error for SendTimeoutError {} +#[unstable(feature = "mpmc_channel", issue = "126840")] impl From> for SendTimeoutError { fn from(err: SendError) -> SendTimeoutError { match err { diff --git a/library/std/src/sync/mpmc/mod.rs b/library/std/src/sync/mpmc/mod.rs index c640e07348e..77a67f4fd38 100644 --- a/library/std/src/sync/mpmc/mod.rs +++ b/library/std/src/sync/mpmc/mod.rs @@ -1,8 +1,112 @@ -//! Multi-producer multi-consumer channels. +//! Multi-producer, multi-consumer FIFO queue communication primitives. +//! +//! This module provides message-based communication over channels, concretely +//! defined by two types: +//! +//! * [`Sender`] +//! * [`Receiver`] +//! +//! [`Sender`]s are used to send data to a set of [`Receiver`]s. Both +//! sender and receiver are cloneable (multi-producer) such that many threads can send +//! simultaneously to receivers (multi-consumer). +//! +//! These channels come in two flavors: +//! +//! 1. An asynchronous, infinitely buffered channel. The [`channel`] function +//! will return a `(Sender, Receiver)` tuple where all sends will be +//! **asynchronous** (they never block). The channel conceptually has an +//! infinite buffer. +//! +//! 2. A synchronous, bounded channel. The [`sync_channel`] function will +//! return a `(SyncSender, Receiver)` tuple where the storage for pending +//! messages is a pre-allocated buffer of a fixed size. All sends will be +//! **synchronous** by blocking until there is buffer space available. Note +//! that a bound of 0 is allowed, causing the channel to become a "rendezvous" +//! channel where each sender atomically hands off a message to a receiver. +//! +//! [`send`]: Sender::send +//! +//! ## Disconnection +//! +//! The send and receive operations on channels will all return a [`Result`] +//! indicating whether the operation succeeded or not. An unsuccessful operation +//! is normally indicative of the other half of a channel having "hung up" by +//! being dropped in its corresponding thread. +//! +//! Once half of a channel has been deallocated, most operations can no longer +//! continue to make progress, so [`Err`] will be returned. Many applications +//! will continue to [`unwrap`] the results returned from this module, +//! instigating a propagation of failure among threads if one unexpectedly dies. +//! +//! [`unwrap`]: Result::unwrap +//! +//! # Examples +//! +//! Simple usage: +//! +//! ``` +//! #![feature(mpmc_channel)] +//! +//! use std::thread; +//! use std::sync::mpmc::channel; +//! +//! // Create a simple streaming channel +//! let (tx, rx) = channel(); +//! thread::spawn(move || { +//! tx.send(10).unwrap(); +//! }); +//! assert_eq!(rx.recv().unwrap(), 10); +//! ``` +//! +//! Shared usage: +//! +//! ``` +//! #![feature(mpmc_channel)] +//! +//! use std::thread; +//! use std::sync::mpmc::channel; +//! +//! // Create a shared channel that can be sent along from many threads +//! // where tx is the sending half (tx for transmission), and rx is the receiving +//! // half (rx for receiving). +//! let (tx, rx) = channel(); +//! for i in 0..10 { +//! let tx = tx.clone(); +//! thread::spawn(move || { +//! tx.send(i).unwrap(); +//! }); +//! } +//! +//! for _ in 0..5 { +//! let rx1 = rx.clone(); +//! let rx2 = rx.clone(); +//! thread::spawn(move || { +//! let j = rx1.recv().unwrap(); +//! assert!(0 <= j && j < 10); +//! }); +//! thread::spawn(move || { +//! let j = rx2.recv().unwrap(); +//! assert!(0 <= j && j < 10); +//! }); +//! } +//! ``` +//! +//! Propagating panics: +//! +//! ``` +//! #![feature(mpmc_channel)] +//! +//! use std::sync::mpmc::channel; +//! +//! // The call to recv() will return an error because the channel has already +//! // hung up (or been deallocated) +//! let (tx, rx) = channel::(); +//! drop(tx); +//! assert!(rx.recv().is_err()); +//! ``` -// This module is not currently exposed publicly, but is used -// as the implementation for the channels in `sync::mpsc`. The -// implementation comes from the crossbeam-channel crate: +// This module is used as the implementation for the channels in `sync::mpsc`. +// The implementation comes from the crossbeam-channel crate: // // Copyright (c) 2019 The Crossbeam Project Developers // @@ -46,9 +150,47 @@ use crate::fmt; use crate::panic::{RefUnwindSafe, UnwindSafe}; use crate::time::{Duration, Instant}; -/// Creates a channel of unbounded capacity. +/// Creates a new asynchronous channel, returning the sender/receiver halves. +/// All data sent on the [`Sender`] will become available on the [`Receiver`] in +/// the same order as it was sent, and no [`send`] will block the calling thread +/// (this channel has an "infinite buffer", unlike [`sync_channel`], which will +/// block after its buffer limit is reached). [`recv`] will block until a message +/// is available while there is at least one [`Sender`] alive (including clones). /// -/// This channel has a growable buffer that can hold any number of messages at a time. +/// The [`Sender`] can be cloned to [`send`] to the same channel multiple times. +/// The [`Receiver`] also can be cloned to have multi receivers. +/// +/// If the [`Receiver`] is disconnected while trying to [`send`] with the +/// [`Sender`], the [`send`] method will return a [`SendError`]. Similarly, if the +/// [`Sender`] is disconnected while trying to [`recv`], the [`recv`] method will +/// return a [`RecvError`]. +/// +/// [`send`]: Sender::send +/// [`recv`]: Receiver::recv +/// +/// # Examples +/// +/// ``` +/// #![feature(mpmc_channel)] +/// +/// use std::sync::mpmc::channel; +/// use std::thread; +/// +/// let (sender, receiver) = channel(); +/// +/// // Spawn off an expensive computation +/// thread::spawn(move || { +/// # fn expensive_computation() {} +/// sender.send(expensive_computation()).unwrap(); +/// }); +/// +/// // Do some useful work for awhile +/// +/// // Let's see what that answer was +/// println!("{:?}", receiver.recv().unwrap()); +/// ``` +#[must_use] +#[unstable(feature = "mpmc_channel", issue = "126840")] pub fn channel() -> (Sender, Receiver) { let (s, r) = counter::new(list::Channel::new()); let s = Sender { flavor: SenderFlavor::List(s) }; @@ -56,12 +198,50 @@ pub fn channel() -> (Sender, Receiver) { (s, r) } -/// Creates a channel of bounded capacity. +/// Creates a new synchronous, bounded channel. +/// All data sent on the [`Sender`] will become available on the [`Receiver`] +/// in the same order as it was sent. Like asynchronous [`channel`]s, the +/// [`Receiver`] will block until a message becomes available. `sync_channel` +/// differs greatly in the semantics of the sender, however. /// -/// This channel has a buffer that can hold at most `cap` messages at a time. +/// This channel has an internal buffer on which messages will be queued. +/// `bound` specifies the buffer size. When the internal buffer becomes full, +/// future sends will *block* waiting for the buffer to open up. Note that a +/// buffer size of 0 is valid, in which case this becomes "rendezvous channel" +/// where each [`send`] will not return until a [`recv`] is paired with it. /// -/// A special case is zero-capacity channel, which cannot hold any messages. Instead, send and -/// receive operations must appear at the same time in order to pair up and pass the message over. +/// The [`Sender`] can be cloned to [`send`] to the same channel multiple +/// times. The [`Receiver`] also can be cloned to have multi receivers. +/// +/// Like asynchronous channels, if the [`Receiver`] is disconnected while trying +/// to [`send`] with the [`Sender`], the [`send`] method will return a +/// [`SendError`]. Similarly, If the [`Sender`] is disconnected while trying +/// to [`recv`], the [`recv`] method will return a [`RecvError`]. +/// +/// [`send`]: Sender::send +/// [`recv`]: Receiver::recv +/// +/// # Examples +/// +/// ``` +/// use std::sync::mpsc::sync_channel; +/// use std::thread; +/// +/// let (sender, receiver) = sync_channel(1); +/// +/// // this returns immediately +/// sender.send(1).unwrap(); +/// +/// thread::spawn(move || { +/// // this will block until the previous message has been received +/// sender.send(2).unwrap(); +/// }); +/// +/// assert_eq!(receiver.recv().unwrap(), 1); +/// assert_eq!(receiver.recv().unwrap(), 2); +/// ``` +#[must_use] +#[unstable(feature = "mpmc_channel", issue = "126840")] pub fn sync_channel(cap: usize) -> (Sender, Receiver) { if cap == 0 { let (s, r) = counter::new(zero::Channel::new()); @@ -76,7 +256,42 @@ pub fn sync_channel(cap: usize) -> (Sender, Receiver) { } } -/// The sending side of a channel. +/// The sending-half of Rust's synchronous [`channel`] type. +/// +/// Messages can be sent through this channel with [`send`]. +/// +/// Note: all senders (the original and its clones) need to be dropped for the receiver +/// to stop blocking to receive messages with [`Receiver::recv`]. +/// +/// [`send`]: Sender::send +/// +/// # Examples +/// +/// ```rust +/// #![feature(mpmc_channel)] +/// +/// use std::sync::mpmc::channel; +/// use std::thread; +/// +/// let (sender, receiver) = channel(); +/// let sender2 = sender.clone(); +/// +/// // First thread owns sender +/// thread::spawn(move || { +/// sender.send(1).unwrap(); +/// }); +/// +/// // Second thread owns sender2 +/// thread::spawn(move || { +/// sender2.send(2).unwrap(); +/// }); +/// +/// let msg = receiver.recv().unwrap(); +/// let msg2 = receiver.recv().unwrap(); +/// +/// assert_eq!(3, msg + msg2); +/// ``` +#[unstable(feature = "mpmc_channel", issue = "126840")] pub struct Sender { flavor: SenderFlavor, } @@ -93,10 +308,14 @@ enum SenderFlavor { Zero(counter::Sender>), } +#[unstable(feature = "mpmc_channel", issue = "126840")] unsafe impl Send for Sender {} +#[unstable(feature = "mpmc_channel", issue = "126840")] unsafe impl Sync for Sender {} +#[unstable(feature = "mpmc_channel", issue = "126840")] impl UnwindSafe for Sender {} +#[unstable(feature = "mpmc_channel", issue = "126840")] impl RefUnwindSafe for Sender {} impl Sender { @@ -107,6 +326,19 @@ impl Sender { /// /// If called on a zero-capacity channel, this method will send the message only if there /// happens to be a receive operation on the other side of the channel at the same time. + /// + /// # Examples + /// + /// ```rust + /// #![feature(mpmc_channel)] + /// + /// use std::sync::mpmc::{channel, Receiver, Sender}; + /// + /// let (sender, _receiver): (Sender, Receiver) = channel(); + /// + /// assert!(sender.try_send(1).is_ok()); + /// ``` + #[unstable(feature = "mpmc_channel", issue = "126840")] pub fn try_send(&self, msg: T) -> Result<(), TrySendError> { match &self.flavor { SenderFlavor::Array(chan) => chan.try_send(msg), @@ -115,14 +347,36 @@ impl Sender { } } - /// Blocks the current thread until a message is sent or the channel is disconnected. + /// Attempts to send a value on this channel, returning it back if it could + /// not be sent. /// - /// If the channel is full and not disconnected, this call will block until the send operation - /// can proceed. If the channel becomes disconnected, this call will wake up and return an - /// error. The returned error contains the original message. + /// A successful send occurs when it is determined that the other end of + /// the channel has not hung up already. An unsuccessful send would be one + /// where the corresponding receiver has already been deallocated. Note + /// that a return value of [`Err`] means that the data will never be + /// received, but a return value of [`Ok`] does *not* mean that the data + /// will be received. It is possible for the corresponding receiver to + /// hang up immediately after this function returns [`Ok`]. /// - /// If called on a zero-capacity channel, this method will wait for a receive operation to - /// appear on the other side of the channel. + /// This method will never block the current thread. + /// + /// # Examples + /// + /// ``` + /// #![feature(mpmc_channel)] + /// + /// use std::sync::mpmc::channel; + /// + /// let (tx, rx) = channel(); + /// + /// // This send is always successful + /// tx.send(1).unwrap(); + /// + /// // This send will fail because the receiver is gone + /// drop(rx); + /// assert!(tx.send(1).is_err()); + /// ``` + #[unstable(feature = "mpmc_channel", issue = "126840")] pub fn send(&self, msg: T) -> Result<(), SendError> { match &self.flavor { SenderFlavor::Array(chan) => chan.send(msg, None), @@ -136,10 +390,6 @@ impl Sender { } } -// The methods below are not used by `sync::mpsc`, but -// are useful and we'll likely want to expose them -// eventually -#[allow(unused)] impl Sender { /// Waits for a message to be sent into the channel, but only for a limited time. /// @@ -149,6 +399,20 @@ impl Sender { /// /// If called on a zero-capacity channel, this method will wait for a receive operation to /// appear on the other side of the channel. + /// + /// # Examples + /// + /// ``` + /// #![feature(mpmc_channel)] + /// + /// use std::sync::mpmc::channel; + /// use std::time::Duration; + /// + /// let (tx, rx) = channel(); + /// + /// tx.send_timeout(1, Duration::from_millis(400)).unwrap(); + /// ``` + #[unstable(feature = "mpmc_channel", issue = "126840")] pub fn send_timeout(&self, msg: T, timeout: Duration) -> Result<(), SendTimeoutError> { match Instant::now().checked_add(timeout) { Some(deadline) => self.send_deadline(msg, deadline), @@ -165,6 +429,21 @@ impl Sender { /// /// If called on a zero-capacity channel, this method will wait for a receive operation to /// appear on the other side of the channel. + /// + /// # Examples + /// + /// ``` + /// #![feature(mpmc_channel)] + /// + /// use std::sync::mpmc::channel; + /// use std::time::{Duration, Instant}; + /// + /// let (tx, rx) = channel(); + /// + /// let t = Instant::now() + Duration::from_millis(400); + /// tx.send_deadline(1, t).unwrap(); + /// ``` + #[unstable(feature = "mpmc_channel", issue = "126840")] pub fn send_deadline(&self, msg: T, deadline: Instant) -> Result<(), SendTimeoutError> { match &self.flavor { SenderFlavor::Array(chan) => chan.send(msg, Some(deadline)), @@ -176,6 +455,31 @@ impl Sender { /// Returns `true` if the channel is empty. /// /// Note: Zero-capacity channels are always empty. + /// + /// # Examples + /// + /// ``` + /// #![feature(mpmc_channel)] + /// + /// use std::sync::mpmc; + /// use std::thread; + /// + /// let (send, _recv) = mpmc::channel(); + /// + /// let tx1 = send.clone(); + /// let tx2 = send.clone(); + /// + /// assert!(tx1.is_empty()); + /// + /// let handle = thread::spawn(move || { + /// tx2.send(1u8).unwrap(); + /// }); + /// + /// handle.join().unwrap(); + /// + /// assert!(!tx1.is_empty()); + /// ``` + #[unstable(feature = "mpmc_channel", issue = "126840")] pub fn is_empty(&self) -> bool { match &self.flavor { SenderFlavor::Array(chan) => chan.is_empty(), @@ -187,6 +491,29 @@ impl Sender { /// Returns `true` if the channel is full. /// /// Note: Zero-capacity channels are always full. + /// + /// # Examples + /// + /// ``` + /// #![feature(mpmc_channel)] + /// + /// use std::sync::mpmc; + /// use std::thread; + /// + /// let (send, _recv) = mpmc::sync_channel(1); + /// + /// let (tx1, tx2) = (send.clone(), send.clone()); + /// assert!(!tx1.is_full()); + /// + /// let handle = thread::spawn(move || { + /// tx2.send(1u8).unwrap(); + /// }); + /// + /// handle.join().unwrap(); + /// + /// assert!(tx1.is_full()); + /// ``` + #[unstable(feature = "mpmc_channel", issue = "126840")] pub fn is_full(&self) -> bool { match &self.flavor { SenderFlavor::Array(chan) => chan.is_full(), @@ -196,6 +523,29 @@ impl Sender { } /// Returns the number of messages in the channel. + /// + /// # Examples + /// + /// ``` + /// #![feature(mpmc_channel)] + /// + /// use std::sync::mpmc; + /// use std::thread; + /// + /// let (send, _recv) = mpmc::channel(); + /// let (tx1, tx2) = (send.clone(), send.clone()); + /// + /// assert_eq!(tx1.len(), 0); + /// + /// let handle = thread::spawn(move || { + /// tx2.send(1u8).unwrap(); + /// }); + /// + /// handle.join().unwrap(); + /// + /// assert_eq!(tx1.len(), 1); + /// ``` + #[unstable(feature = "mpmc_channel", issue = "126840")] pub fn len(&self) -> usize { match &self.flavor { SenderFlavor::Array(chan) => chan.len(), @@ -205,6 +555,29 @@ impl Sender { } /// If the channel is bounded, returns its capacity. + /// + /// # Examples + /// + /// ``` + /// #![feature(mpmc_channel)] + /// + /// use std::sync::mpmc; + /// use std::thread; + /// + /// let (send, _recv) = mpmc::sync_channel(3); + /// let (tx1, tx2) = (send.clone(), send.clone()); + /// + /// assert_eq!(tx1.capacity(), Some(3)); + /// + /// let handle = thread::spawn(move || { + /// tx2.send(1u8).unwrap(); + /// }); + /// + /// handle.join().unwrap(); + /// + /// assert_eq!(tx1.capacity(), Some(3)); + /// ``` + #[unstable(feature = "mpmc_channel", issue = "126840")] pub fn capacity(&self) -> Option { match &self.flavor { SenderFlavor::Array(chan) => chan.capacity(), @@ -214,6 +587,21 @@ impl Sender { } /// Returns `true` if senders belong to the same channel. + /// + /// # Examples + /// + /// ``` + /// #![feature(mpmc_channel)] + /// + /// use std::sync::mpmc; + /// + /// let (tx1, _) = mpmc::channel::(); + /// let (tx2, _) = mpmc::channel::(); + /// + /// assert!(tx1.same_channel(&tx1)); + /// assert!(!tx1.same_channel(&tx2)); + /// ``` + #[unstable(feature = "mpmc_channel", issue = "126840")] pub fn same_channel(&self, other: &Sender) -> bool { match (&self.flavor, &other.flavor) { (SenderFlavor::Array(ref a), SenderFlavor::Array(ref b)) => a == b, @@ -224,6 +612,7 @@ impl Sender { } } +#[unstable(feature = "mpmc_channel", issue = "126840")] impl Drop for Sender { fn drop(&mut self) { unsafe { @@ -236,6 +625,7 @@ impl Drop for Sender { } } +#[unstable(feature = "mpmc_channel", issue = "126840")] impl Clone for Sender { fn clone(&self) -> Self { let flavor = match &self.flavor { @@ -248,17 +638,216 @@ impl Clone for Sender { } } +#[unstable(feature = "mpmc_channel", issue = "126840")] impl fmt::Debug for Sender { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.pad("Sender { .. }") } } -/// The receiving side of a channel. +/// The receiving half of Rust's [`channel`] (or [`sync_channel`]) type. +/// Different threads can share this [`Sender`] by cloning it. +/// +/// Messages sent to the channel can be retrieved using [`recv`]. +/// +/// [`recv`]: Receiver::recv +/// +/// # Examples +/// +/// ```rust +/// #![feature(mpmc_channel)] +/// +/// use std::sync::mpmc::channel; +/// use std::thread; +/// use std::time::Duration; +/// +/// let (send, recv) = channel(); +/// +/// let tx_thread = thread::spawn(move || { +/// send.send("Hello world!").unwrap(); +/// thread::sleep(Duration::from_secs(2)); // block for two seconds +/// send.send("Delayed for 2 seconds").unwrap(); +/// }); +/// +/// let (rx1, rx2) = (recv.clone(), recv.clone()); +/// let rx_thread_1 = thread::spawn(move || { +/// println!("{}", rx1.recv().unwrap()); // Received immediately +/// }); +/// let rx_thread_2 = thread::spawn(move || { +/// println!("{}", rx2.recv().unwrap()); // Received after 2 seconds +/// }); +/// +/// tx_thread.join().unwrap(); +/// rx_thread_1.join().unwrap(); +/// rx_thread_2.join().unwrap(); +/// ``` +#[unstable(feature = "mpmc_channel", issue = "126840")] pub struct Receiver { flavor: ReceiverFlavor, } +/// An iterator over messages on a [`Receiver`], created by [`iter`]. +/// +/// This iterator will block whenever [`next`] is called, +/// waiting for a new message, and [`None`] will be returned +/// when the corresponding channel has hung up. +/// +/// [`iter`]: Receiver::iter +/// [`next`]: Iterator::next +/// +/// # Examples +/// +/// ```rust +/// #![feature(mpmc_channel)] +/// +/// use std::sync::mpmc::channel; +/// use std::thread; +/// +/// let (send, recv) = channel(); +/// +/// thread::spawn(move || { +/// send.send(1u8).unwrap(); +/// send.send(2u8).unwrap(); +/// send.send(3u8).unwrap(); +/// }); +/// +/// for x in recv.iter() { +/// println!("Got: {x}"); +/// } +/// ``` +#[unstable(feature = "mpmc_channel", issue = "126840")] +#[derive(Debug)] +pub struct Iter<'a, T: 'a> { + rx: &'a Receiver, +} + +/// An iterator that attempts to yield all pending values for a [`Receiver`], +/// created by [`try_iter`]. +/// +/// [`None`] will be returned when there are no pending values remaining or +/// if the corresponding channel has hung up. +/// +/// This iterator will never block the caller in order to wait for data to +/// become available. Instead, it will return [`None`]. +/// +/// [`try_iter`]: Receiver::try_iter +/// +/// # Examples +/// +/// ```rust +/// #![feature(mpmc_channel)] +/// +/// use std::sync::mpmc::channel; +/// use std::thread; +/// use std::time::Duration; +/// +/// let (sender, receiver) = channel(); +/// +/// // Nothing is in the buffer yet +/// assert!(receiver.try_iter().next().is_none()); +/// println!("Nothing in the buffer..."); +/// +/// thread::spawn(move || { +/// sender.send(1).unwrap(); +/// sender.send(2).unwrap(); +/// sender.send(3).unwrap(); +/// }); +/// +/// println!("Going to sleep..."); +/// thread::sleep(Duration::from_secs(2)); // block for two seconds +/// +/// for x in receiver.try_iter() { +/// println!("Got: {x}"); +/// } +/// ``` +#[unstable(feature = "mpmc_channel", issue = "126840")] +#[derive(Debug)] +pub struct TryIter<'a, T: 'a> { + rx: &'a Receiver, +} + +/// An owning iterator over messages on a [`Receiver`], +/// created by [`into_iter`]. +/// +/// This iterator will block whenever [`next`] +/// is called, waiting for a new message, and [`None`] will be +/// returned if the corresponding channel has hung up. +/// +/// [`into_iter`]: Receiver::into_iter +/// [`next`]: Iterator::next +/// +/// # Examples +/// +/// ```rust +/// #![feature(mpmc_channel)] +/// +/// use std::sync::mpmc::channel; +/// use std::thread; +/// +/// let (send, recv) = channel(); +/// +/// thread::spawn(move || { +/// send.send(1u8).unwrap(); +/// send.send(2u8).unwrap(); +/// send.send(3u8).unwrap(); +/// }); +/// +/// for x in recv.into_iter() { +/// println!("Got: {x}"); +/// } +/// ``` +#[unstable(feature = "mpmc_channel", issue = "126840")] +#[derive(Debug)] +pub struct IntoIter { + rx: Receiver, +} + +#[unstable(feature = "mpmc_channel", issue = "126840")] +impl<'a, T> Iterator for Iter<'a, T> { + type Item = T; + + fn next(&mut self) -> Option { + self.rx.recv().ok() + } +} + +#[unstable(feature = "mpmc_channel", issue = "126840")] +impl<'a, T> Iterator for TryIter<'a, T> { + type Item = T; + + fn next(&mut self) -> Option { + self.rx.try_recv().ok() + } +} + +#[unstable(feature = "mpmc_channel", issue = "126840")] +impl<'a, T> IntoIterator for &'a Receiver { + type Item = T; + type IntoIter = Iter<'a, T>; + + fn into_iter(self) -> Iter<'a, T> { + self.iter() + } +} + +#[unstable(feature = "mpmc_channel", issue = "126840")] +impl Iterator for IntoIter { + type Item = T; + fn next(&mut self) -> Option { + self.rx.recv().ok() + } +} + +#[unstable(feature = "mpmc_channel", issue = "126840")] +impl IntoIterator for Receiver { + type Item = T; + type IntoIter = IntoIter; + + fn into_iter(self) -> IntoIter { + IntoIter { rx: self } + } +} + /// Receiver flavors. enum ReceiverFlavor { /// Bounded channel based on a preallocated array. @@ -271,20 +860,46 @@ enum ReceiverFlavor { Zero(counter::Receiver>), } +#[unstable(feature = "mpmc_channel", issue = "126840")] unsafe impl Send for Receiver {} +#[unstable(feature = "mpmc_channel", issue = "126840")] unsafe impl Sync for Receiver {} +#[unstable(feature = "mpmc_channel", issue = "126840")] impl UnwindSafe for Receiver {} +#[unstable(feature = "mpmc_channel", issue = "126840")] impl RefUnwindSafe for Receiver {} impl Receiver { /// Attempts to receive a message from the channel without blocking. /// - /// This method will either receive a message from the channel immediately or return an error - /// if the channel is empty. + /// This method will never block the caller in order to wait for data to + /// become available. Instead, this will always return immediately with a + /// possible option of pending data on the channel. /// /// If called on a zero-capacity channel, this method will receive a message only if there /// happens to be a send operation on the other side of the channel at the same time. + /// + /// This is useful for a flavor of "optimistic check" before deciding to + /// block on a receiver. + /// + /// Compared with [`recv`], this function has two failure cases instead of one + /// (one for disconnection, one for an empty buffer). + /// + /// [`recv`]: Self::recv + /// + /// # Examples + /// + /// ```rust + /// #![feature(mpmc_channel)] + /// + /// use std::sync::mpmc::{Receiver, channel}; + /// + /// let (_, receiver): (_, Receiver) = channel(); + /// + /// assert!(receiver.try_recv().is_err()); + /// ``` + #[unstable(feature = "mpmc_channel", issue = "126840")] pub fn try_recv(&self) -> Result { match &self.flavor { ReceiverFlavor::Array(chan) => chan.try_recv(), @@ -293,15 +908,64 @@ impl Receiver { } } - /// Blocks the current thread until a message is received or the channel is empty and - /// disconnected. + /// Attempts to wait for a value on this receiver, returning an error if the + /// corresponding channel has hung up. /// - /// If the channel is empty and not disconnected, this call will block until the receive - /// operation can proceed. If the channel is empty and becomes disconnected, this call will - /// wake up and return an error. + /// This function will always block the current thread if there is no data + /// available and it's possible for more data to be sent (at least one sender + /// still exists). Once a message is sent to the corresponding [`Sender`], + /// this receiver will wake up and return that message. /// - /// If called on a zero-capacity channel, this method will wait for a send operation to appear - /// on the other side of the channel. + /// If the corresponding [`Sender`] has disconnected, or it disconnects while + /// this call is blocking, this call will wake up and return [`Err`] to + /// indicate that no more messages can ever be received on this channel. + /// However, since channels are buffered, messages sent before the disconnect + /// will still be properly received. + /// + /// # Examples + /// + /// ``` + /// #![feature(mpmc_channel)] + /// + /// use std::sync::mpmc; + /// use std::thread; + /// + /// let (send, recv) = mpmc::channel(); + /// let handle = thread::spawn(move || { + /// send.send(1u8).unwrap(); + /// }); + /// + /// handle.join().unwrap(); + /// + /// assert_eq!(Ok(1), recv.recv()); + /// ``` + /// + /// Buffering behavior: + /// + /// ``` + /// #![feature(mpmc_channel)] + /// + /// use std::sync::mpmc; + /// use std::thread; + /// use std::sync::mpmc::RecvError; + /// + /// let (send, recv) = mpmc::channel(); + /// let handle = thread::spawn(move || { + /// send.send(1u8).unwrap(); + /// send.send(2).unwrap(); + /// send.send(3).unwrap(); + /// drop(send); + /// }); + /// + /// // wait for the thread to join so we ensure the sender is dropped + /// handle.join().unwrap(); + /// + /// assert_eq!(Ok(1), recv.recv()); + /// assert_eq!(Ok(2), recv.recv()); + /// assert_eq!(Ok(3), recv.recv()); + /// assert_eq!(Err(RecvError), recv.recv()); + /// ``` + #[unstable(feature = "mpmc_channel", issue = "126840")] pub fn recv(&self) -> Result { match &self.flavor { ReceiverFlavor::Array(chan) => chan.recv(None), @@ -311,14 +975,65 @@ impl Receiver { .map_err(|_| RecvError) } - /// Waits for a message to be received from the channel, but only for a limited time. + /// Attempts to wait for a value on this receiver, returning an error if the + /// corresponding channel has hung up, or if it waits more than `timeout`. /// - /// If the channel is empty and not disconnected, this call will block until the receive - /// operation can proceed or the operation times out. If the channel is empty and becomes - /// disconnected, this call will wake up and return an error. + /// This function will always block the current thread if there is no data + /// available and it's possible for more data to be sent (at least one sender + /// still exists). Once a message is sent to the corresponding [`Sender`], + /// this receiver will wake up and return that message. /// - /// If called on a zero-capacity channel, this method will wait for a send operation to appear - /// on the other side of the channel. + /// If the corresponding [`Sender`] has disconnected, or it disconnects while + /// this call is blocking, this call will wake up and return [`Err`] to + /// indicate that no more messages can ever be received on this channel. + /// However, since channels are buffered, messages sent before the disconnect + /// will still be properly received. + /// + /// # Examples + /// + /// Successfully receiving value before encountering timeout: + /// + /// ```no_run + /// #![feature(mpmc_channel)] + /// + /// use std::thread; + /// use std::time::Duration; + /// use std::sync::mpmc; + /// + /// let (send, recv) = mpmc::channel(); + /// + /// thread::spawn(move || { + /// send.send('a').unwrap(); + /// }); + /// + /// assert_eq!( + /// recv.recv_timeout(Duration::from_millis(400)), + /// Ok('a') + /// ); + /// ``` + /// + /// Receiving an error upon reaching timeout: + /// + /// ```no_run + /// #![feature(mpmc_channel)] + /// + /// use std::thread; + /// use std::time::Duration; + /// use std::sync::mpmc; + /// + /// let (send, recv) = mpmc::channel(); + /// + /// thread::spawn(move || { + /// thread::sleep(Duration::from_millis(800)); + /// send.send('a').unwrap(); + /// }); + /// + /// assert_eq!( + /// recv.recv_timeout(Duration::from_millis(400)), + /// Err(mpmc::RecvTimeoutError::Timeout) + /// ); + /// ``` + #[unstable(feature = "mpmc_channel", issue = "126840")] pub fn recv_timeout(&self, timeout: Duration) -> Result { match Instant::now().checked_add(timeout) { Some(deadline) => self.recv_deadline(deadline), @@ -327,14 +1042,65 @@ impl Receiver { } } - /// Waits for a message to be received from the channel, but only for a limited time. + /// Attempts to wait for a value on this receiver, returning an error if the + /// corresponding channel has hung up, or if `deadline` is reached. /// - /// If the channel is empty and not disconnected, this call will block until the receive - /// operation can proceed or the operation times out. If the channel is empty and becomes - /// disconnected, this call will wake up and return an error. + /// This function will always block the current thread if there is no data + /// available and it's possible for more data to be sent. Once a message is + /// sent to the corresponding [`Sender`], then this receiver will wake up + /// and return that message. /// - /// If called on a zero-capacity channel, this method will wait for a send operation to appear - /// on the other side of the channel. + /// If the corresponding [`Sender`] has disconnected, or it disconnects while + /// this call is blocking, this call will wake up and return [`Err`] to + /// indicate that no more messages can ever be received on this channel. + /// However, since channels are buffered, messages sent before the disconnect + /// will still be properly received. + /// + /// # Examples + /// + /// Successfully receiving value before reaching deadline: + /// + /// ```no_run + /// #![feature(mpmc_channel)] + /// + /// use std::thread; + /// use std::time::{Duration, Instant}; + /// use std::sync::mpmc; + /// + /// let (send, recv) = mpmc::channel(); + /// + /// thread::spawn(move || { + /// send.send('a').unwrap(); + /// }); + /// + /// assert_eq!( + /// recv.recv_deadline(Instant::now() + Duration::from_millis(400)), + /// Ok('a') + /// ); + /// ``` + /// + /// Receiving an error upon reaching deadline: + /// + /// ```no_run + /// #![feature(mpmc_channel)] + /// + /// use std::thread; + /// use std::time::{Duration, Instant}; + /// use std::sync::mpmc; + /// + /// let (send, recv) = mpmc::channel(); + /// + /// thread::spawn(move || { + /// thread::sleep(Duration::from_millis(800)); + /// send.send('a').unwrap(); + /// }); + /// + /// assert_eq!( + /// recv.recv_deadline(Instant::now() + Duration::from_millis(400)), + /// Err(mpmc::RecvTimeoutError::Timeout) + /// ); + /// ``` + #[unstable(feature = "mpmc_channel", issue = "126840")] pub fn recv_deadline(&self, deadline: Instant) -> Result { match &self.flavor { ReceiverFlavor::Array(chan) => chan.recv(Some(deadline)), @@ -342,16 +1108,77 @@ impl Receiver { ReceiverFlavor::Zero(chan) => chan.recv(Some(deadline)), } } + + /// Returns an iterator that will attempt to yield all pending values. + /// It will return `None` if there are no more pending values or if the + /// channel has hung up. The iterator will never [`panic!`] or block the + /// user by waiting for values. + /// + /// # Examples + /// + /// ```no_run + /// #![feature(mpmc_channel)] + /// + /// use std::sync::mpmc::channel; + /// use std::thread; + /// use std::time::Duration; + /// + /// let (sender, receiver) = channel(); + /// + /// // nothing is in the buffer yet + /// assert!(receiver.try_iter().next().is_none()); + /// + /// thread::spawn(move || { + /// thread::sleep(Duration::from_secs(1)); + /// sender.send(1).unwrap(); + /// sender.send(2).unwrap(); + /// sender.send(3).unwrap(); + /// }); + /// + /// // nothing is in the buffer yet + /// assert!(receiver.try_iter().next().is_none()); + /// + /// // block for two seconds + /// thread::sleep(Duration::from_secs(2)); + /// + /// let mut iter = receiver.try_iter(); + /// assert_eq!(iter.next(), Some(1)); + /// assert_eq!(iter.next(), Some(2)); + /// assert_eq!(iter.next(), Some(3)); + /// assert_eq!(iter.next(), None); + /// ``` + #[unstable(feature = "mpmc_channel", issue = "126840")] + pub fn try_iter(&self) -> TryIter<'_, T> { + TryIter { rx: self } + } } -// The methods below are not used by `sync::mpsc`, but -// are useful and we'll likely want to expose them -// eventually -#[allow(unused)] impl Receiver { /// Returns `true` if the channel is empty. /// /// Note: Zero-capacity channels are always empty. + /// + /// # Examples + /// + /// ``` + /// #![feature(mpmc_channel)] + /// + /// use std::sync::mpmc; + /// use std::thread; + /// + /// let (send, recv) = mpmc::channel(); + /// + /// assert!(recv.is_empty()); + /// + /// let handle = thread::spawn(move || { + /// send.send(1u8).unwrap(); + /// }); + /// + /// handle.join().unwrap(); + /// + /// assert!(!recv.is_empty()); + /// ``` + #[unstable(feature = "mpmc_channel", issue = "126840")] pub fn is_empty(&self) -> bool { match &self.flavor { ReceiverFlavor::Array(chan) => chan.is_empty(), @@ -363,6 +1190,28 @@ impl Receiver { /// Returns `true` if the channel is full. /// /// Note: Zero-capacity channels are always full. + /// + /// # Examples + /// + /// ``` + /// #![feature(mpmc_channel)] + /// + /// use std::sync::mpmc; + /// use std::thread; + /// + /// let (send, recv) = mpmc::sync_channel(1); + /// + /// assert!(!recv.is_full()); + /// + /// let handle = thread::spawn(move || { + /// send.send(1u8).unwrap(); + /// }); + /// + /// handle.join().unwrap(); + /// + /// assert!(recv.is_full()); + /// ``` + #[unstable(feature = "mpmc_channel", issue = "126840")] pub fn is_full(&self) -> bool { match &self.flavor { ReceiverFlavor::Array(chan) => chan.is_full(), @@ -372,6 +1221,28 @@ impl Receiver { } /// Returns the number of messages in the channel. + /// + /// # Examples + /// + /// ``` + /// #![feature(mpmc_channel)] + /// + /// use std::sync::mpmc; + /// use std::thread; + /// + /// let (send, recv) = mpmc::channel(); + /// + /// assert_eq!(recv.len(), 0); + /// + /// let handle = thread::spawn(move || { + /// send.send(1u8).unwrap(); + /// }); + /// + /// handle.join().unwrap(); + /// + /// assert_eq!(recv.len(), 1); + /// ``` + #[unstable(feature = "mpmc_channel", issue = "126840")] pub fn len(&self) -> usize { match &self.flavor { ReceiverFlavor::Array(chan) => chan.len(), @@ -381,6 +1252,28 @@ impl Receiver { } /// If the channel is bounded, returns its capacity. + /// + /// # Examples + /// + /// ``` + /// #![feature(mpmc_channel)] + /// + /// use std::sync::mpmc; + /// use std::thread; + /// + /// let (send, recv) = mpmc::sync_channel(3); + /// + /// assert_eq!(recv.capacity(), Some(3)); + /// + /// let handle = thread::spawn(move || { + /// send.send(1u8).unwrap(); + /// }); + /// + /// handle.join().unwrap(); + /// + /// assert_eq!(recv.capacity(), Some(3)); + /// ``` + #[unstable(feature = "mpmc_channel", issue = "126840")] pub fn capacity(&self) -> Option { match &self.flavor { ReceiverFlavor::Array(chan) => chan.capacity(), @@ -390,6 +1283,21 @@ impl Receiver { } /// Returns `true` if receivers belong to the same channel. + /// + /// # Examples + /// + /// ``` + /// #![feature(mpmc_channel)] + /// + /// use std::sync::mpmc; + /// + /// let (_, rx1) = mpmc::channel::(); + /// let (_, rx2) = mpmc::channel::(); + /// + /// assert!(rx1.same_channel(&rx1)); + /// assert!(!rx1.same_channel(&rx2)); + /// ``` + #[unstable(feature = "mpmc_channel", issue = "126840")] pub fn same_channel(&self, other: &Receiver) -> bool { match (&self.flavor, &other.flavor) { (ReceiverFlavor::Array(a), ReceiverFlavor::Array(b)) => a == b, @@ -398,8 +1306,39 @@ impl Receiver { _ => false, } } + + /// Returns an iterator that will block waiting for messages, but never + /// [`panic!`]. It will return [`None`] when the channel has hung up. + /// + /// # Examples + /// + /// ```rust + /// #![feature(mpmc_channel)] + /// + /// use std::sync::mpmc::channel; + /// use std::thread; + /// + /// let (send, recv) = channel(); + /// + /// thread::spawn(move || { + /// send.send(1).unwrap(); + /// send.send(2).unwrap(); + /// send.send(3).unwrap(); + /// }); + /// + /// let mut iter = recv.iter(); + /// assert_eq!(iter.next(), Some(1)); + /// assert_eq!(iter.next(), Some(2)); + /// assert_eq!(iter.next(), Some(3)); + /// assert_eq!(iter.next(), None); + /// ``` + #[unstable(feature = "mpmc_channel", issue = "126840")] + pub fn iter(&self) -> Iter<'_, T> { + Iter { rx: self } + } } +#[unstable(feature = "mpmc_channel", issue = "126840")] impl Drop for Receiver { fn drop(&mut self) { unsafe { @@ -412,6 +1351,7 @@ impl Drop for Receiver { } } +#[unstable(feature = "mpmc_channel", issue = "126840")] impl Clone for Receiver { fn clone(&self) -> Self { let flavor = match &self.flavor { @@ -424,6 +1364,7 @@ impl Clone for Receiver { } } +#[unstable(feature = "mpmc_channel", issue = "126840")] impl fmt::Debug for Receiver { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.pad("Receiver { .. }") diff --git a/library/std/src/sync/mpmc/tests.rs b/library/std/src/sync/mpmc/tests.rs new file mode 100644 index 00000000000..ab14050df6c --- /dev/null +++ b/library/std/src/sync/mpmc/tests.rs @@ -0,0 +1,728 @@ +use super::*; +use crate::{env, thread}; + +pub fn stress_factor() -> usize { + match env::var("RUST_TEST_STRESS") { + Ok(val) => val.parse().unwrap(), + Err(..) => 1, + } +} + +#[test] +fn smoke() { + let (tx, rx) = channel::(); + tx.send(1).unwrap(); + assert_eq!(rx.recv().unwrap(), 1); +} + +#[test] +fn drop_full() { + let (tx, _rx) = channel::>(); + tx.send(Box::new(1)).unwrap(); +} + +#[test] +fn drop_full_shared() { + let (tx, _rx) = channel::>(); + drop(tx.clone()); + drop(tx.clone()); + tx.send(Box::new(1)).unwrap(); +} + +#[test] +fn smoke_shared() { + let (tx, rx) = channel::(); + tx.send(1).unwrap(); + assert_eq!(rx.recv().unwrap(), 1); + let tx = tx.clone(); + tx.send(1).unwrap(); + assert_eq!(rx.recv().unwrap(), 1); +} + +#[test] +fn smoke_threads() { + let (tx, rx) = channel::(); + let t1 = thread::spawn(move || { + for i in 0..2 { + tx.send(i).unwrap(); + } + }); + let t2 = thread::spawn(move || { + assert_eq!(rx.recv().unwrap(), 0); + assert_eq!(rx.recv().unwrap(), 1); + }); + t1.join().unwrap(); + t2.join().unwrap(); +} + +#[test] +fn smoke_port_gone() { + let (tx, rx) = channel::(); + drop(rx); + assert!(tx.send(1).is_err()); +} + +#[test] +fn smoke_shared_port_gone() { + let (tx, rx) = channel::(); + drop(rx); + assert!(tx.send(1).is_err()) +} + +#[test] +fn smoke_shared_port_gone2() { + let (tx, rx) = channel::(); + drop(rx); + let tx2 = tx.clone(); + drop(tx); + assert!(tx2.send(1).is_err()); +} + +#[test] +fn port_gone_concurrent() { + let (tx, rx) = channel::(); + let _t = thread::spawn(move || { + rx.recv().unwrap(); + }); + while tx.send(1).is_ok() {} +} + +#[test] +fn port_gone_concurrent_shared() { + let (tx, rx) = channel::(); + let tx2 = tx.clone(); + let _t = thread::spawn(move || { + rx.recv().unwrap(); + }); + while tx.send(1).is_ok() && tx2.send(1).is_ok() {} +} + +#[test] +fn smoke_chan_gone() { + let (tx, rx) = channel::(); + drop(tx); + assert!(rx.recv().is_err()); +} + +#[test] +fn smoke_chan_gone_shared() { + let (tx, rx) = channel::<()>(); + let tx2 = tx.clone(); + drop(tx); + drop(tx2); + assert!(rx.recv().is_err()); +} + +#[test] +fn chan_gone_concurrent() { + let (tx, rx) = channel::(); + let _t = thread::spawn(move || { + tx.send(1).unwrap(); + tx.send(1).unwrap(); + }); + while rx.recv().is_ok() {} +} + +#[test] +fn stress() { + let count = if cfg!(miri) { 100 } else { 10000 }; + let (tx, rx) = channel::(); + let t = thread::spawn(move || { + for _ in 0..count { + tx.send(1).unwrap(); + } + }); + for _ in 0..count { + assert_eq!(rx.recv().unwrap(), 1); + } + t.join().ok().expect("thread panicked"); +} + +#[test] +fn stress_shared() { + const AMT: u32 = if cfg!(miri) { 100 } else { 10000 }; + const NTHREADS: u32 = 8; + let (tx, rx) = channel::(); + + let t = thread::spawn(move || { + for _ in 0..AMT * NTHREADS { + assert_eq!(rx.recv().unwrap(), 1); + } + match rx.try_recv() { + Ok(..) => panic!(), + _ => {} + } + }); + + for _ in 0..NTHREADS { + let tx = tx.clone(); + thread::spawn(move || { + for _ in 0..AMT { + tx.send(1).unwrap(); + } + }); + } + drop(tx); + t.join().ok().expect("thread panicked"); +} + +#[test] +fn send_from_outside_runtime() { + let (tx1, rx1) = channel::<()>(); + let (tx2, rx2) = channel::(); + let t1 = thread::spawn(move || { + tx1.send(()).unwrap(); + for _ in 0..40 { + assert_eq!(rx2.recv().unwrap(), 1); + } + }); + rx1.recv().unwrap(); + let t2 = thread::spawn(move || { + for _ in 0..40 { + tx2.send(1).unwrap(); + } + }); + t1.join().ok().expect("thread panicked"); + t2.join().ok().expect("thread panicked"); +} + +#[test] +fn recv_from_outside_runtime() { + let (tx, rx) = channel::(); + let t = thread::spawn(move || { + for _ in 0..40 { + assert_eq!(rx.recv().unwrap(), 1); + } + }); + for _ in 0..40 { + tx.send(1).unwrap(); + } + t.join().ok().expect("thread panicked"); +} + +#[test] +fn no_runtime() { + let (tx1, rx1) = channel::(); + let (tx2, rx2) = channel::(); + let t1 = thread::spawn(move || { + assert_eq!(rx1.recv().unwrap(), 1); + tx2.send(2).unwrap(); + }); + let t2 = thread::spawn(move || { + tx1.send(1).unwrap(); + assert_eq!(rx2.recv().unwrap(), 2); + }); + t1.join().ok().expect("thread panicked"); + t2.join().ok().expect("thread panicked"); +} + +#[test] +fn oneshot_single_thread_close_port_first() { + // Simple test of closing without sending + let (_tx, rx) = channel::(); + drop(rx); +} + +#[test] +fn oneshot_single_thread_close_chan_first() { + // Simple test of closing without sending + let (tx, _rx) = channel::(); + drop(tx); +} + +#[test] +fn oneshot_single_thread_send_port_close() { + // Testing that the sender cleans up the payload if receiver is closed + let (tx, rx) = channel::>(); + drop(rx); + assert!(tx.send(Box::new(0)).is_err()); +} + +#[test] +fn oneshot_single_thread_recv_chan_close() { + // Receiving on a closed chan will panic + let res = thread::spawn(move || { + let (tx, rx) = channel::(); + drop(tx); + rx.recv().unwrap(); + }) + .join(); + // What is our res? + assert!(res.is_err()); +} + +#[test] +fn oneshot_single_thread_send_then_recv() { + let (tx, rx) = channel::>(); + tx.send(Box::new(10)).unwrap(); + assert!(*rx.recv().unwrap() == 10); +} + +#[test] +fn oneshot_single_thread_try_send_open() { + let (tx, rx) = channel::(); + assert!(tx.send(10).is_ok()); + assert!(rx.recv().unwrap() == 10); +} + +#[test] +fn oneshot_single_thread_try_send_closed() { + let (tx, rx) = channel::(); + drop(rx); + assert!(tx.send(10).is_err()); +} + +#[test] +fn oneshot_single_thread_try_recv_open() { + let (tx, rx) = channel::(); + tx.send(10).unwrap(); + assert!(rx.recv() == Ok(10)); +} + +#[test] +fn oneshot_single_thread_try_recv_closed() { + let (tx, rx) = channel::(); + drop(tx); + assert!(rx.recv().is_err()); +} + +#[test] +fn oneshot_single_thread_peek_data() { + let (tx, rx) = channel::(); + assert_eq!(rx.try_recv(), Err(TryRecvError::Empty)); + tx.send(10).unwrap(); + assert_eq!(rx.try_recv(), Ok(10)); +} + +#[test] +fn oneshot_single_thread_peek_close() { + let (tx, rx) = channel::(); + drop(tx); + assert_eq!(rx.try_recv(), Err(TryRecvError::Disconnected)); + assert_eq!(rx.try_recv(), Err(TryRecvError::Disconnected)); +} + +#[test] +fn oneshot_single_thread_peek_open() { + let (_tx, rx) = channel::(); + assert_eq!(rx.try_recv(), Err(TryRecvError::Empty)); +} + +#[test] +fn oneshot_multi_task_recv_then_send() { + let (tx, rx) = channel::>(); + let _t = thread::spawn(move || { + assert!(*rx.recv().unwrap() == 10); + }); + + tx.send(Box::new(10)).unwrap(); +} + +#[test] +fn oneshot_multi_task_recv_then_close() { + let (tx, rx) = channel::>(); + let _t = thread::spawn(move || { + drop(tx); + }); + let res = thread::spawn(move || { + assert!(*rx.recv().unwrap() == 10); + }) + .join(); + assert!(res.is_err()); +} + +#[test] +fn oneshot_multi_thread_close_stress() { + for _ in 0..stress_factor() { + let (tx, rx) = channel::(); + let _t = thread::spawn(move || { + drop(rx); + }); + drop(tx); + } +} + +#[test] +fn oneshot_multi_thread_send_close_stress() { + for _ in 0..stress_factor() { + let (tx, rx) = channel::(); + let _t = thread::spawn(move || { + drop(rx); + }); + let _ = thread::spawn(move || { + tx.send(1).unwrap(); + }) + .join(); + } +} + +#[test] +fn oneshot_multi_thread_recv_close_stress() { + for _ in 0..stress_factor() { + let (tx, rx) = channel::(); + thread::spawn(move || { + let res = thread::spawn(move || { + rx.recv().unwrap(); + }) + .join(); + assert!(res.is_err()); + }); + let _t = thread::spawn(move || { + thread::spawn(move || { + drop(tx); + }); + }); + } +} + +#[test] +fn oneshot_multi_thread_send_recv_stress() { + for _ in 0..stress_factor() { + let (tx, rx) = channel::>(); + let _t = thread::spawn(move || { + tx.send(Box::new(10)).unwrap(); + }); + assert!(*rx.recv().unwrap() == 10); + } +} + +#[test] +fn stream_send_recv_stress() { + for _ in 0..stress_factor() { + let (tx, rx) = channel(); + + send(tx, 0); + recv(rx, 0); + + fn send(tx: Sender>, i: i32) { + if i == 10 { + return; + } + + thread::spawn(move || { + tx.send(Box::new(i)).unwrap(); + send(tx, i + 1); + }); + } + + fn recv(rx: Receiver>, i: i32) { + if i == 10 { + return; + } + + thread::spawn(move || { + assert!(*rx.recv().unwrap() == i); + recv(rx, i + 1); + }); + } + } +} + +#[test] +fn oneshot_single_thread_recv_timeout() { + let (tx, rx) = channel(); + tx.send(()).unwrap(); + assert_eq!(rx.recv_timeout(Duration::from_millis(1)), Ok(())); + assert_eq!(rx.recv_timeout(Duration::from_millis(1)), Err(RecvTimeoutError::Timeout)); + tx.send(()).unwrap(); + assert_eq!(rx.recv_timeout(Duration::from_millis(1)), Ok(())); +} + +#[test] +fn stress_recv_timeout_two_threads() { + let (tx, rx) = channel(); + let stress = stress_factor() + 100; + let timeout = Duration::from_millis(100); + + thread::spawn(move || { + for i in 0..stress { + if i % 2 == 0 { + thread::sleep(timeout * 2); + } + tx.send(1usize).unwrap(); + } + }); + + let mut recv_count = 0; + loop { + match rx.recv_timeout(timeout) { + Ok(n) => { + assert_eq!(n, 1usize); + recv_count += 1; + } + Err(RecvTimeoutError::Timeout) => continue, + Err(RecvTimeoutError::Disconnected) => break, + } + } + + assert_eq!(recv_count, stress); +} + +#[test] +fn recv_timeout_upgrade() { + let (tx, rx) = channel::<()>(); + let timeout = Duration::from_millis(1); + let _tx_clone = tx.clone(); + + let start = Instant::now(); + assert_eq!(rx.recv_timeout(timeout), Err(RecvTimeoutError::Timeout)); + assert!(Instant::now() >= start + timeout); +} + +#[test] +fn stress_recv_timeout_shared() { + let (tx, rx) = channel(); + let stress = stress_factor() + 100; + + for i in 0..stress { + let tx = tx.clone(); + thread::spawn(move || { + thread::sleep(Duration::from_millis(i as u64 * 10)); + tx.send(1usize).unwrap(); + }); + } + + drop(tx); + + let mut recv_count = 0; + loop { + match rx.recv_timeout(Duration::from_millis(10)) { + Ok(n) => { + assert_eq!(n, 1usize); + recv_count += 1; + } + Err(RecvTimeoutError::Timeout) => continue, + Err(RecvTimeoutError::Disconnected) => break, + } + } + + assert_eq!(recv_count, stress); +} + +#[test] +fn very_long_recv_timeout_wont_panic() { + let (tx, rx) = channel::<()>(); + let join_handle = thread::spawn(move || rx.recv_timeout(Duration::from_secs(u64::MAX))); + thread::sleep(Duration::from_secs(1)); + assert!(tx.send(()).is_ok()); + assert_eq!(join_handle.join().unwrap(), Ok(())); +} + +#[test] +fn recv_a_lot() { + let count = if cfg!(miri) { 1000 } else { 10000 }; + // Regression test that we don't run out of stack in scheduler context + let (tx, rx) = channel(); + for _ in 0..count { + tx.send(()).unwrap(); + } + for _ in 0..count { + rx.recv().unwrap(); + } +} + +#[test] +fn shared_recv_timeout() { + let (tx, rx) = channel(); + let total = 5; + for _ in 0..total { + let tx = tx.clone(); + thread::spawn(move || { + tx.send(()).unwrap(); + }); + } + + for _ in 0..total { + rx.recv().unwrap(); + } + + assert_eq!(rx.recv_timeout(Duration::from_millis(1)), Err(RecvTimeoutError::Timeout)); + tx.send(()).unwrap(); + assert_eq!(rx.recv_timeout(Duration::from_millis(1)), Ok(())); +} + +#[test] +fn shared_chan_stress() { + let (tx, rx) = channel(); + let total = stress_factor() + 100; + for _ in 0..total { + let tx = tx.clone(); + thread::spawn(move || { + tx.send(()).unwrap(); + }); + } + + for _ in 0..total { + rx.recv().unwrap(); + } +} + +#[test] +fn test_nested_recv_iter() { + let (tx, rx) = channel::(); + let (total_tx, total_rx) = channel::(); + + let _t = thread::spawn(move || { + let mut acc = 0; + for x in rx.iter() { + acc += x; + } + total_tx.send(acc).unwrap(); + }); + + tx.send(3).unwrap(); + tx.send(1).unwrap(); + tx.send(2).unwrap(); + drop(tx); + assert_eq!(total_rx.recv().unwrap(), 6); +} + +#[test] +fn test_recv_iter_break() { + let (tx, rx) = channel::(); + let (count_tx, count_rx) = channel(); + + let _t = thread::spawn(move || { + let mut count = 0; + for x in rx.iter() { + if count >= 3 { + break; + } else { + count += x; + } + } + count_tx.send(count).unwrap(); + }); + + tx.send(2).unwrap(); + tx.send(2).unwrap(); + tx.send(2).unwrap(); + let _ = tx.send(2); + drop(tx); + assert_eq!(count_rx.recv().unwrap(), 4); +} + +#[test] +fn test_recv_try_iter() { + let (request_tx, request_rx) = channel(); + let (response_tx, response_rx) = channel(); + + // Request `x`s until we have `6`. + let t = thread::spawn(move || { + let mut count = 0; + loop { + for x in response_rx.try_iter() { + count += x; + if count == 6 { + return count; + } + } + request_tx.send(()).unwrap(); + } + }); + + for _ in request_rx.iter() { + if response_tx.send(2).is_err() { + break; + } + } + + assert_eq!(t.join().unwrap(), 6); +} + +#[test] +fn test_recv_into_iter_owned() { + let mut iter = { + let (tx, rx) = channel::(); + tx.send(1).unwrap(); + tx.send(2).unwrap(); + + rx.into_iter() + }; + assert_eq!(iter.next().unwrap(), 1); + assert_eq!(iter.next().unwrap(), 2); + assert_eq!(iter.next().is_none(), true); +} + +#[test] +fn test_recv_into_iter_borrowed() { + let (tx, rx) = channel::(); + tx.send(1).unwrap(); + tx.send(2).unwrap(); + drop(tx); + let mut iter = (&rx).into_iter(); + assert_eq!(iter.next().unwrap(), 1); + assert_eq!(iter.next().unwrap(), 2); + assert_eq!(iter.next().is_none(), true); +} + +#[test] +fn try_recv_states() { + let (tx1, rx1) = channel::(); + let (tx2, rx2) = channel::<()>(); + let (tx3, rx3) = channel::<()>(); + let _t = thread::spawn(move || { + rx2.recv().unwrap(); + tx1.send(1).unwrap(); + tx3.send(()).unwrap(); + rx2.recv().unwrap(); + drop(tx1); + tx3.send(()).unwrap(); + }); + + assert_eq!(rx1.try_recv(), Err(TryRecvError::Empty)); + tx2.send(()).unwrap(); + rx3.recv().unwrap(); + assert_eq!(rx1.try_recv(), Ok(1)); + assert_eq!(rx1.try_recv(), Err(TryRecvError::Empty)); + tx2.send(()).unwrap(); + rx3.recv().unwrap(); + assert_eq!(rx1.try_recv(), Err(TryRecvError::Disconnected)); +} + +// This bug used to end up in a livelock inside of the Receiver destructor +// because the internal state of the Shared packet was corrupted +#[test] +fn destroy_upgraded_shared_port_when_sender_still_active() { + let (tx, rx) = channel(); + let (tx2, rx2) = channel(); + let _t = thread::spawn(move || { + rx.recv().unwrap(); // wait on a oneshot + drop(rx); // destroy a shared + tx2.send(()).unwrap(); + }); + // make sure the other thread has gone to sleep + for _ in 0..5000 { + thread::yield_now(); + } + + // upgrade to a shared chan and send a message + let t = tx.clone(); + drop(tx); + t.send(()).unwrap(); + + // wait for the child thread to exit before we exit + rx2.recv().unwrap(); +} + +#[test] +fn issue_32114() { + let (tx, _) = channel(); + let _ = tx.send(123); + assert_eq!(tx.send(123), Err(SendError(123))); +} + +#[test] +fn issue_39364() { + let (tx, rx) = channel::<()>(); + let t = thread::spawn(move || { + thread::sleep(Duration::from_millis(300)); + let _ = tx.clone(); + // Don't drop; hand back to caller. + tx + }); + + let _ = rx.recv_timeout(Duration::from_millis(500)); + let _tx = t.join().unwrap(); // delay dropping until end of test + let _ = rx.recv_timeout(Duration::from_millis(500)); +} diff --git a/tests/ui/const-generics/issues/issue-82956.stderr b/tests/ui/const-generics/issues/issue-82956.stderr index a956fc741f4..5e380eea81c 100644 --- a/tests/ui/const-generics/issues/issue-82956.stderr +++ b/tests/ui/const-generics/issues/issue-82956.stderr @@ -14,7 +14,7 @@ LL + use std::collections::btree_map::IntoIter; | LL + use std::collections::btree_set::IntoIter; | - and 8 other candidates + and 9 other candidates error: aborting due to 1 previous error diff --git a/tests/ui/issues/issue-12041.stderr b/tests/ui/issues/issue-12041.stderr index 51061c0262e..f2c10b83383 100644 --- a/tests/ui/issues/issue-12041.stderr +++ b/tests/ui/issues/issue-12041.stderr @@ -4,7 +4,7 @@ error[E0382]: use of moved value: `tx` LL | let tx = tx; | ^^ value moved here, in previous iteration of loop | - = note: move occurs because `tx` has type `Sender`, which does not implement the `Copy` trait + = note: move occurs because `tx` has type `std::sync::mpsc::Sender`, which does not implement the `Copy` trait error: aborting due to 1 previous error diff --git a/tests/ui/lint/use_suggestion_json.stderr b/tests/ui/lint/use_suggestion_json.stderr index 4683e5dd8f3..0d4304e2e2e 100644 --- a/tests/ui/lint/use_suggestion_json.stderr +++ b/tests/ui/lint/use_suggestion_json.stderr @@ -348,6 +348,29 @@ mod foo { "label": null, "suggested_replacement": "use std::slice::Iter; +", + "suggestion_applicability": "MaybeIncorrect", + "expansion": null + }, + { + "file_name": "$DIR/use_suggestion_json.rs", + "byte_start": 541, + "byte_end": 541, + "line_start": 11, + "line_end": 11, + "column_start": 1, + "column_end": 1, + "is_primary": true, + "text": [ + { + "text": "fn main() {", + "highlight_start": 1, + "highlight_end": 1 + } + ], + "label": null, + "suggested_replacement": "use std::sync::mpmc::Iter; + ", "suggestion_applicability": "MaybeIncorrect", "expansion": null @@ -396,7 +419,7 @@ mod foo { \u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m \u001b[0m\u001b[1m\u001b[38;5;12mLL\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[38;5;10m+ use std::collections::hash_map::Iter;\u001b[0m \u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m -\u001b[0m and 8 other candidates\u001b[0m +\u001b[0m and 9 other candidates\u001b[0m " } From 7650307c0e9d10c6c0f5e1470629a23218fd7422 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 30 Sep 2024 20:49:35 +0200 Subject: [PATCH 438/683] add test ensuring we cannot call const-stable unstable functions --- .../auxiliary/unstable_but_const_stable.rs | 13 ++++++ tests/ui/consts/unstable-const-stable.rs | 14 ++++++ tests/ui/consts/unstable-const-stable.stderr | 43 +++++++++++++++++++ 3 files changed, 70 insertions(+) create mode 100644 tests/ui/consts/auxiliary/unstable_but_const_stable.rs create mode 100644 tests/ui/consts/unstable-const-stable.rs create mode 100644 tests/ui/consts/unstable-const-stable.stderr diff --git a/tests/ui/consts/auxiliary/unstable_but_const_stable.rs b/tests/ui/consts/auxiliary/unstable_but_const_stable.rs new file mode 100644 index 00000000000..88044b0272c --- /dev/null +++ b/tests/ui/consts/auxiliary/unstable_but_const_stable.rs @@ -0,0 +1,13 @@ +#![feature(staged_api, rustc_attrs, intrinsics)] +#![stable(since="1.0.0", feature = "stable")] + +extern "rust-intrinsic" { + #[unstable(feature = "unstable", issue = "42")] + #[rustc_const_stable(feature = "stable", since = "1.0.0")] + #[rustc_nounwind] + pub fn write_bytes(dst: *mut T, val: u8, count: usize); +} + +#[unstable(feature = "unstable", issue = "42")] +#[rustc_const_stable(feature = "stable", since = "1.0.0")] +pub const fn some_unstable_fn() {} diff --git a/tests/ui/consts/unstable-const-stable.rs b/tests/ui/consts/unstable-const-stable.rs new file mode 100644 index 00000000000..f69e8d0efe5 --- /dev/null +++ b/tests/ui/consts/unstable-const-stable.rs @@ -0,0 +1,14 @@ +//@ aux-build:unstable_but_const_stable.rs + +extern crate unstable_but_const_stable; +use unstable_but_const_stable::*; + +fn main() { + some_unstable_fn(); //~ERROR use of unstable library feature + unsafe { write_bytes(4 as *mut u8, 0, 0) }; //~ERROR use of unstable library feature +} + +const fn const_main() { + some_unstable_fn(); //~ERROR use of unstable library feature + unsafe { write_bytes(4 as *mut u8, 0, 0) }; //~ERROR use of unstable library feature +} diff --git a/tests/ui/consts/unstable-const-stable.stderr b/tests/ui/consts/unstable-const-stable.stderr new file mode 100644 index 00000000000..c4ffbbb60db --- /dev/null +++ b/tests/ui/consts/unstable-const-stable.stderr @@ -0,0 +1,43 @@ +error[E0658]: use of unstable library feature 'unstable' + --> $DIR/unstable-const-stable.rs:7:5 + | +LL | some_unstable_fn(); + | ^^^^^^^^^^^^^^^^ + | + = note: see issue #42 for more information + = help: add `#![feature(unstable)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: use of unstable library feature 'unstable' + --> $DIR/unstable-const-stable.rs:8:14 + | +LL | unsafe { write_bytes(4 as *mut u8, 0, 0) }; + | ^^^^^^^^^^^ + | + = note: see issue #42 for more information + = help: add `#![feature(unstable)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: use of unstable library feature 'unstable' + --> $DIR/unstable-const-stable.rs:12:5 + | +LL | some_unstable_fn(); + | ^^^^^^^^^^^^^^^^ + | + = note: see issue #42 for more information + = help: add `#![feature(unstable)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: use of unstable library feature 'unstable' + --> $DIR/unstable-const-stable.rs:13:14 + | +LL | unsafe { write_bytes(4 as *mut u8, 0, 0) }; + | ^^^^^^^^^^^ + | + = note: see issue #42 for more information + = help: add `#![feature(unstable)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0658`. From df6c27db4e0f6060339ea1289ce87b8cbb3aa729 Mon Sep 17 00:00:00 2001 From: tiif Date: Tue, 1 Oct 2024 03:00:14 +0800 Subject: [PATCH 439/683] Refactor return_read_bytes_and_count and return_written_byte_count_or_error --- src/tools/miri/src/helpers.rs | 13 +++- src/tools/miri/src/shims/unix/fd.rs | 65 ++++++++++--------- src/tools/miri/src/shims/unix/fs.rs | 20 ++++-- .../miri/src/shims/unix/linux/eventfd.rs | 19 ++---- .../miri/src/shims/unix/unnamed_socket.rs | 26 +++----- 5 files changed, 76 insertions(+), 67 deletions(-) diff --git a/src/tools/miri/src/helpers.rs b/src/tools/miri/src/helpers.rs index 0cd6ba69aac..5324e4bec5b 100644 --- a/src/tools/miri/src/helpers.rs +++ b/src/tools/miri/src/helpers.rs @@ -2,7 +2,7 @@ use std::collections::BTreeSet; use std::num::NonZero; use std::sync::Mutex; use std::time::Duration; -use std::{cmp, iter}; +use std::{cmp, io, iter}; use rand::RngCore; use rustc_apfloat::Float; @@ -839,6 +839,17 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { self.set_last_error(self.io_error_to_errnum(err)?) } + /// Sets the last OS error using a `std::io::ErrorKind` and writes -1 to dest place. + fn set_last_error_and_return( + &mut self, + err: impl Into, + dest: &MPlaceTy<'tcx>, + ) -> InterpResult<'tcx> { + self.set_last_error(self.io_error_to_errnum(err.into())?)?; + self.write_int(-1, dest)?; + Ok(()) + } + /// Helper function that consumes an `std::io::Result` and returns an /// `InterpResult<'tcx,T>::Ok` instead. In case the result is an error, this function returns /// `Ok(-1)` and sets the last OS error accordingly. diff --git a/src/tools/miri/src/shims/unix/fd.rs b/src/tools/miri/src/shims/unix/fd.rs index 6bd753d0d6b..f64d0ed1467 100644 --- a/src/tools/miri/src/shims/unix/fd.rs +++ b/src/tools/miri/src/shims/unix/fd.rs @@ -150,7 +150,10 @@ impl FileDescription for io::Stdin { helpers::isolation_abort_error("`read` from stdin")?; } let result = Read::read(&mut { self }, &mut bytes); - ecx.return_read_bytes_and_count(ptr, &bytes, result, dest) + match result { + Ok(read_size) => ecx.return_read_success(ptr, &bytes, read_size, dest), + Err(e) => ecx.set_last_error_and_return(e, dest), + } } fn is_tty(&self, communicate_allowed: bool) -> bool { @@ -181,7 +184,10 @@ impl FileDescription for io::Stdout { // the host -- there is no good in adding extra buffering // here. io::stdout().flush().unwrap(); - ecx.return_written_byte_count_or_error(result, dest) + match result { + Ok(write_size) => ecx.return_write_success(write_size, dest), + Err(e) => ecx.set_last_error_and_return(e, dest), + } } fn is_tty(&self, communicate_allowed: bool) -> bool { @@ -207,7 +213,10 @@ impl FileDescription for io::Stderr { // We allow writing to stderr even with isolation enabled. // No need to flush, stderr is not buffered. let result = Write::write(&mut { self }, bytes); - ecx.return_written_byte_count_or_error(result, dest) + match result { + Ok(write_size) => ecx.return_write_success(write_size, dest), + Err(e) => ecx.set_last_error_and_return(e, dest), + } } fn is_tty(&self, communicate_allowed: bool) -> bool { @@ -234,8 +243,7 @@ impl FileDescription for NullOutput { ecx: &mut MiriInterpCx<'tcx>, ) -> InterpResult<'tcx> { // We just don't write anything, but report to the user that we did. - let result = Ok(len); - ecx.return_written_byte_count_or_error(result, dest) + ecx.return_write_success(len, dest) } } @@ -655,46 +663,39 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } /// Helper to implement `FileDescription::read`: - /// `result` should be the return value of some underlying `read` call that used `bytes` as its output buffer. + /// This is only used when `read` is successful. + /// `actual_read_size` should be the return value of some underlying `read` call that used + /// `bytes` as its output buffer. /// The length of `bytes` must not exceed either the host's or the target's `isize`. - /// If `Result` indicates success, `bytes` is written to `buf` and the size is written to `dest`. - /// Otherwise, `-1` is written to `dest` and the last libc error is set appropriately. - fn return_read_bytes_and_count( + /// `bytes` is written to `buf` and the size is written to `dest`. + fn return_read_success( &mut self, buf: Pointer, bytes: &[u8], - result: io::Result, + actual_read_size: usize, dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - match result { - Ok(read_bytes) => { - // If reading to `bytes` did not fail, we write those bytes to the buffer. - // Crucially, if fewer than `bytes.len()` bytes were read, only write - // that much into the output buffer! - this.write_bytes_ptr(buf, bytes[..read_bytes].iter().copied())?; - // The actual read size is always less than what got originally requested so this cannot fail. - this.write_int(u64::try_from(read_bytes).unwrap(), dest)?; - Ok(()) - } - Err(e) => { - this.set_last_error_from_io_error(e)?; - this.write_int(-1, dest)?; - Ok(()) - } - } + // If reading to `bytes` did not fail, we write those bytes to the buffer. + // Crucially, if fewer than `bytes.len()` bytes were read, only write + // that much into the output buffer! + this.write_bytes_ptr(buf, bytes[..actual_read_size].iter().copied())?; + + // The actual read size is always less than what got originally requested so this cannot fail. + this.write_int(u64::try_from(actual_read_size).unwrap(), dest)?; + Ok(()) } - /// This function writes the number of written bytes (given in `result`) to `dest`, or sets the - /// last libc error and writes -1 to dest. - fn return_written_byte_count_or_error( + /// Helper to implement `FileDescription::write`: + /// This function is only used when `write` is successful, and writes `actual_write_size` to `dest` + fn return_write_success( &mut self, - result: io::Result, + actual_write_size: usize, dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - let result = this.try_unwrap_io_result(result.map(|c| i64::try_from(c).unwrap()))?; - this.write_int(result, dest)?; + // The actual write size is always less than what got originally requested so this cannot fail. + this.write_int(u64::try_from(actual_write_size).unwrap(), dest)?; Ok(()) } } diff --git a/src/tools/miri/src/shims/unix/fs.rs b/src/tools/miri/src/shims/unix/fs.rs index 92514b67bea..2fa1729ad9c 100644 --- a/src/tools/miri/src/shims/unix/fs.rs +++ b/src/tools/miri/src/shims/unix/fs.rs @@ -41,7 +41,10 @@ impl FileDescription for FileHandle { assert!(communicate_allowed, "isolation should have prevented even opening a file"); let mut bytes = vec![0; len]; let result = (&mut &self.file).read(&mut bytes); - ecx.return_read_bytes_and_count(ptr, &bytes, result, dest) + match result { + Ok(read_size) => ecx.return_read_success(ptr, &bytes, read_size, dest), + Err(e) => ecx.set_last_error_and_return(e, dest), + } } fn write<'tcx>( @@ -56,7 +59,10 @@ impl FileDescription for FileHandle { assert!(communicate_allowed, "isolation should have prevented even opening a file"); let bytes = ecx.read_bytes_ptr_strip_provenance(ptr, Size::from_bytes(len))?; let result = (&mut &self.file).write(bytes); - ecx.return_written_byte_count_or_error(result, dest) + match result { + Ok(write_size) => ecx.return_write_success(write_size, dest), + Err(e) => ecx.set_last_error_and_return(e, dest), + } } fn pread<'tcx>( @@ -84,7 +90,10 @@ impl FileDescription for FileHandle { res }; let result = f(); - ecx.return_read_bytes_and_count(ptr, &bytes, result, dest) + match result { + Ok(read_size) => ecx.return_read_success(ptr, &bytes, read_size, dest), + Err(e) => ecx.set_last_error_and_return(e, dest), + } } fn pwrite<'tcx>( @@ -112,7 +121,10 @@ impl FileDescription for FileHandle { res }; let result = f(); - ecx.return_written_byte_count_or_error(result, dest) + match result { + Ok(write_size) => ecx.return_write_success(write_size, dest), + Err(e) => ecx.set_last_error_and_return(e, dest), + } } fn seek<'tcx>( diff --git a/src/tools/miri/src/shims/unix/linux/eventfd.rs b/src/tools/miri/src/shims/unix/linux/eventfd.rs index ab7652ca721..2e485d2f4e1 100644 --- a/src/tools/miri/src/shims/unix/linux/eventfd.rs +++ b/src/tools/miri/src/shims/unix/linux/eventfd.rs @@ -1,7 +1,7 @@ //! Linux `eventfd` implementation. use std::cell::{Cell, RefCell}; use std::io; -use std::io::{Error, ErrorKind}; +use std::io::ErrorKind; use crate::concurrency::VClock; use crate::shims::unix::fd::FileDescriptionRef; @@ -66,9 +66,7 @@ impl FileDescription for Event { let ty = ecx.machine.layouts.u64; // Check the size of slice, and return error only if the size of the slice < 8. if len < ty.size.bytes_usize() { - ecx.set_last_error_from_io_error(Error::from(ErrorKind::InvalidInput))?; - ecx.write_int(-1, dest)?; - return Ok(()); + return ecx.set_last_error_and_return(ErrorKind::InvalidInput, dest); } // eventfd read at the size of u64. @@ -78,9 +76,7 @@ impl FileDescription for Event { let counter = self.counter.get(); if counter == 0 { if self.is_nonblock { - ecx.set_last_error_from_io_error(Error::from(ErrorKind::WouldBlock))?; - ecx.write_int(-1, dest)?; - return Ok(()); + return ecx.set_last_error_and_return(ErrorKind::WouldBlock, dest); } throw_unsup_format!("eventfd: blocking is unsupported"); @@ -128,8 +124,7 @@ impl FileDescription for Event { let ty = ecx.machine.layouts.u64; // Check the size of slice, and return error only if the size of the slice < 8. if len < ty.layout.size.bytes_usize() { - let result = Err(Error::from(ErrorKind::InvalidInput)); - return ecx.return_written_byte_count_or_error(result, dest); + return ecx.set_last_error_and_return(ErrorKind::InvalidInput, dest); } // Read the user supplied value from the pointer. @@ -138,8 +133,7 @@ impl FileDescription for Event { // u64::MAX as input is invalid because the maximum value of counter is u64::MAX - 1. if num == u64::MAX { - let result = Err(Error::from(ErrorKind::InvalidInput)); - return ecx.return_written_byte_count_or_error(result, dest); + return ecx.set_last_error_and_return(ErrorKind::InvalidInput, dest); } // If the addition does not let the counter to exceed the maximum value, update the counter. // Else, block. @@ -153,8 +147,7 @@ impl FileDescription for Event { } None | Some(u64::MAX) => if self.is_nonblock { - let result = Err(Error::from(ErrorKind::WouldBlock)); - return ecx.return_written_byte_count_or_error(result, dest); + return ecx.set_last_error_and_return(ErrorKind::WouldBlock, dest); } else { throw_unsup_format!("eventfd: blocking is unsupported"); }, diff --git a/src/tools/miri/src/shims/unix/unnamed_socket.rs b/src/tools/miri/src/shims/unix/unnamed_socket.rs index d1bfa563387..56327d1461a 100644 --- a/src/tools/miri/src/shims/unix/unnamed_socket.rs +++ b/src/tools/miri/src/shims/unix/unnamed_socket.rs @@ -5,7 +5,7 @@ use std::cell::{Cell, OnceCell, RefCell}; use std::collections::VecDeque; use std::io; -use std::io::{Error, ErrorKind, Read}; +use std::io::{ErrorKind, Read}; use rustc_target::abi::Size; @@ -138,8 +138,7 @@ impl FileDescription for AnonSocket { // Always succeed on read size 0. if len == 0 { - let result = Ok(0); - return ecx.return_read_bytes_and_count(ptr, &bytes, result, dest); + return ecx.return_read_success(ptr, &bytes, 0, dest); } let Some(readbuf) = &self.readbuf else { @@ -152,8 +151,7 @@ impl FileDescription for AnonSocket { if self.peer_fd().upgrade().is_none() { // Socketpair with no peer and empty buffer. // 0 bytes successfully read indicates end-of-file. - let result = Ok(0); - return ecx.return_read_bytes_and_count(ptr, &bytes, result, dest); + return ecx.return_read_success(ptr, &bytes, 0, dest); } else { if self.is_nonblock { // Non-blocking socketpair with writer and empty buffer. @@ -161,8 +159,7 @@ impl FileDescription for AnonSocket { // EAGAIN or EWOULDBLOCK can be returned for socket, // POSIX.1-2001 allows either error to be returned for this case. // Since there is no ErrorKind for EAGAIN, WouldBlock is used. - let result = Err(Error::from(ErrorKind::WouldBlock)); - return ecx.return_read_bytes_and_count(ptr, &bytes, result, dest); + return ecx.set_last_error_and_return(ErrorKind::WouldBlock, dest); } else { // Blocking socketpair with writer and empty buffer. // FIXME: blocking is currently not supported @@ -194,8 +191,7 @@ impl FileDescription for AnonSocket { ecx.check_and_update_readiness(&peer_fd)?; } - let result = Ok(actual_read_size); - ecx.return_read_bytes_and_count(ptr, &bytes, result, dest) + ecx.return_read_success(ptr, &bytes, actual_read_size, dest) } fn write<'tcx>( @@ -210,16 +206,14 @@ impl FileDescription for AnonSocket { // Always succeed on write size 0. // ("If count is zero and fd refers to a file other than a regular file, the results are not specified.") if len == 0 { - let result = Ok(0); - return ecx.return_written_byte_count_or_error(result, dest); + return ecx.return_write_success(0, dest); } // We are writing to our peer's readbuf. let Some(peer_fd) = self.peer_fd().upgrade() else { // If the upgrade from Weak to Rc fails, it indicates that all read ends have been // closed. - let result = Err(Error::from(ErrorKind::BrokenPipe)); - return ecx.return_written_byte_count_or_error(result, dest); + return ecx.set_last_error_and_return(ErrorKind::BrokenPipe, dest); }; let Some(writebuf) = &peer_fd.downcast::().unwrap().readbuf else { @@ -233,8 +227,7 @@ impl FileDescription for AnonSocket { if available_space == 0 { if self.is_nonblock { // Non-blocking socketpair with a full buffer. - let result = Err(Error::from(ErrorKind::WouldBlock)); - return ecx.return_written_byte_count_or_error(result, dest); + return ecx.set_last_error_and_return(ErrorKind::WouldBlock, dest); } else { // Blocking socketpair with a full buffer. throw_unsup_format!("socketpair write: blocking isn't supported yet"); @@ -256,8 +249,7 @@ impl FileDescription for AnonSocket { // The kernel does this even if the fd was already readable before, so we follow suit. ecx.check_and_update_readiness(&peer_fd)?; - let result = Ok(actual_write_size); - ecx.return_written_byte_count_or_error(result, dest) + ecx.return_write_success(actual_write_size, dest) } } From 19252bde65c8587bcf43ae464d49c56791696afa Mon Sep 17 00:00:00 2001 From: Lukas Markeffsky <@> Date: Sun, 29 Sep 2024 22:11:59 +0000 Subject: [PATCH 440/683] add `stable_since` convenience --- compiler/rustc_attr/src/builtin.rs | 10 ++++++++++ src/librustdoc/clean/types.rs | 5 +---- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs index 762ebc47ca9..28d73fbe9f3 100644 --- a/compiler/rustc_attr/src/builtin.rs +++ b/compiler/rustc_attr/src/builtin.rs @@ -80,6 +80,10 @@ impl Stability { pub fn is_stable(&self) -> bool { self.level.is_stable() } + + pub fn stable_since(&self) -> Option { + self.level.stable_since() + } } /// Represents the `#[rustc_const_unstable]` and `#[rustc_const_stable]` attributes. @@ -170,6 +174,12 @@ impl StabilityLevel { pub fn is_stable(&self) -> bool { matches!(self, StabilityLevel::Stable { .. }) } + pub fn stable_since(&self) -> Option { + match *self { + StabilityLevel::Stable { since, .. } => Some(since), + StabilityLevel::Unstable { .. } => None, + } + } } #[derive(Encodable, Decodable, PartialEq, Copy, Clone, Debug, Eq, Hash)] diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index b9c5e8e787b..2fccdb923d4 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -638,10 +638,7 @@ impl Item { } pub(crate) fn stable_since(&self, tcx: TyCtxt<'_>) -> Option { - match self.stability(tcx)?.level { - StabilityLevel::Stable { since, .. } => Some(since), - StabilityLevel::Unstable { .. } => None, - } + self.stability(tcx).and_then(|stability| stability.stable_since()) } pub(crate) fn is_non_exhaustive(&self) -> bool { From cd31b3acb3c963aff8d226030ac02379d741f3bd Mon Sep 17 00:00:00 2001 From: Lukas Markeffsky <@> Date: Mon, 30 Sep 2024 01:20:17 +0000 Subject: [PATCH 441/683] rustdoc: rewrite stability inheritance as a pass --- src/librustdoc/clean/auto_trait.rs | 1 + src/librustdoc/clean/blanket_impl.rs | 1 + src/librustdoc/clean/inline.rs | 1 + src/librustdoc/clean/types.rs | 55 ++++----------- src/librustdoc/html/render/print_item.rs | 31 ++++----- src/librustdoc/passes/mod.rs | 5 ++ src/librustdoc/passes/propagate_stability.rs | 72 ++++++++++++++++++++ tests/rustdoc-ui/issues/issue-91713.stdout | 2 + tests/rustdoc/stability.rs | 49 ++++++++++--- 9 files changed, 149 insertions(+), 68 deletions(-) create mode 100644 src/librustdoc/passes/propagate_stability.rs diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs index 08c88fc950d..d966f993104 100644 --- a/src/librustdoc/clean/auto_trait.rs +++ b/src/librustdoc/clean/auto_trait.rs @@ -117,6 +117,7 @@ fn synthesize_auto_trait_impl<'tcx>( name: None, inner: Box::new(clean::ItemInner { attrs: Default::default(), + stability: None, kind: clean::ImplItem(Box::new(clean::Impl { safety: hir::Safety::Safe, generics, diff --git a/src/librustdoc/clean/blanket_impl.rs b/src/librustdoc/clean/blanket_impl.rs index 36821294885..1f3cb4a61b8 100644 --- a/src/librustdoc/clean/blanket_impl.rs +++ b/src/librustdoc/clean/blanket_impl.rs @@ -87,6 +87,7 @@ pub(crate) fn synthesize_blanket_impls( item_id: clean::ItemId::Blanket { impl_id: impl_def_id, for_: item_def_id }, inner: Box::new(clean::ItemInner { attrs: Default::default(), + stability: None, kind: clean::ImplItem(Box::new(clean::Impl { safety: hir::Safety::Safe, generics: clean_ty_generics( diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index d3c4ef4dc90..e7f921eef7f 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -672,6 +672,7 @@ fn build_module_items( item_id: ItemId::DefId(did), inner: Box::new(clean::ItemInner { attrs: Default::default(), + stability: None, kind: clean::ImportItem(clean::Import::new_simple( item.ident.name, clean::ImportSource { diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 2fccdb923d4..a3277e8ca92 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -6,7 +6,7 @@ use std::{fmt, iter}; use arrayvec::ArrayVec; use rustc_ast_pretty::pprust; -use rustc_attr::{ConstStability, Deprecation, Stability, StabilityLevel, StableSince}; +use rustc_attr::{ConstStability, Deprecation, Stability, StableSince}; use rustc_const_eval::const_eval::is_unstable_const_fn; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir::def::{CtorKind, DefKind, Res}; @@ -333,6 +333,8 @@ pub(crate) struct ItemInner { /// E.g., struct vs enum vs function. pub(crate) kind: ItemKind, pub(crate) attrs: Attributes, + /// The effective stability, filled out by the `propagate-stability` pass. + pub(crate) stability: Option, } impl std::ops::Deref for Item { @@ -381,46 +383,17 @@ fn is_field_vis_inherited(tcx: TyCtxt<'_>, def_id: DefId) -> bool { } impl Item { + /// Returns the effective stability of the item. + /// + /// This method should only be called after the `propagate-stability` pass has been run. pub(crate) fn stability(&self, tcx: TyCtxt<'_>) -> Option { - let (mut def_id, mut stability) = if let Some(inlined) = self.inline_stmt_id { - let inlined_def_id = inlined.to_def_id(); - if let Some(stability) = tcx.lookup_stability(inlined_def_id) { - (inlined_def_id, stability) - } else { - // For re-exports into crates without `staged_api`, reuse the original stability. - // This is necessary, because we always want to mark unstable items. - let def_id = self.def_id()?; - return tcx.lookup_stability(def_id); - } - } else { - let def_id = self.def_id()?; - let stability = tcx.lookup_stability(def_id)?; - (def_id, stability) - }; - - let StabilityLevel::Stable { mut since, allowed_through_unstable_modules: false } = - stability.level - else { - return Some(stability); - }; - - // If any of the item's ancestors was stabilized later or is still unstable, - // then report the ancestor's stability instead. - while let Some(parent_def_id) = tcx.opt_parent(def_id) { - if let Some(parent_stability) = tcx.lookup_stability(parent_def_id) { - match parent_stability.level { - StabilityLevel::Unstable { .. } => return Some(parent_stability), - StabilityLevel::Stable { since: parent_since, .. } => { - if parent_since > since { - stability = parent_stability; - since = parent_since; - } - } - } - } - def_id = parent_def_id; - } - Some(stability) + let stability = self.inner.stability; + debug_assert!( + stability.is_some() + || self.def_id().is_none_or(|did| tcx.lookup_stability(did).is_none()), + "missing stability for cleaned item: {self:?}", + ); + stability } pub(crate) fn const_stability(&self, tcx: TyCtxt<'_>) -> Option { @@ -502,7 +475,7 @@ impl Item { Item { item_id: def_id.into(), - inner: Box::new(ItemInner { kind, attrs }), + inner: Box::new(ItemInner { kind, attrs, stability: None }), name, cfg, inline_stmt_id: None, diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index d120e7f36eb..38276e4d20c 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -436,16 +436,9 @@ fn item_module(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Item, items: } clean::ImportItem(ref import) => { - let stab_tags = if let Some(import_def_id) = import.source.did { - // Just need an item with the correct def_id and attrs - let import_item = - clean::Item { item_id: import_def_id.into(), ..(*myitem).clone() }; - - let stab_tags = Some(extra_info_tags(&import_item, item, tcx).to_string()); - stab_tags - } else { - None - }; + let stab_tags = import.source.did.map_or_else(String::new, |import_def_id| { + extra_info_tags(tcx, myitem, item, Some(import_def_id)).to_string() + }); w.write_str(ITEM_TABLE_ROW_OPEN); let id = match import.kind { @@ -454,7 +447,6 @@ fn item_module(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Item, items: } clean::ImportKind::Glob => String::new(), }; - let stab_tags = stab_tags.unwrap_or_default(); let (stab_tags_before, stab_tags_after) = if stab_tags.is_empty() { ("", "") } else { @@ -521,7 +513,7 @@ fn item_module(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Item, items: {docs_before}{docs}{docs_after}", name = EscapeBodyTextWithWbr(myitem.name.unwrap().as_str()), visibility_and_hidden = visibility_and_hidden, - stab_tags = extra_info_tags(myitem, item, tcx), + stab_tags = extra_info_tags(tcx, myitem, item, None), class = myitem.type_(), unsafety_flag = unsafety_flag, href = item_path(myitem.type_(), myitem.name.unwrap().as_str()), @@ -544,9 +536,10 @@ fn item_module(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Item, items: /// Render the stability, deprecation and portability tags that are displayed in the item's summary /// at the module level. fn extra_info_tags<'a, 'tcx: 'a>( + tcx: TyCtxt<'tcx>, item: &'a clean::Item, parent: &'a clean::Item, - tcx: TyCtxt<'tcx>, + import_def_id: Option, ) -> impl fmt::Display + 'a + Captures<'tcx> { display_fn(move |f| { fn tag_html<'a>( @@ -564,18 +557,18 @@ fn extra_info_tags<'a, 'tcx: 'a>( } // The trailing space after each tag is to space it properly against the rest of the docs. - if let Some(depr) = &item.deprecation(tcx) { + let deprecation = import_def_id + .map_or_else(|| item.deprecation(tcx), |import_did| tcx.lookup_deprecation(import_did)); + if let Some(depr) = deprecation { let message = if depr.is_in_effect() { "Deprecated" } else { "Deprecation planned" }; write!(f, "{}", tag_html("deprecated", "", message))?; } // The "rustc_private" crates are permanently unstable so it makes no sense // to render "unstable" everywhere. - if item - .stability(tcx) - .as_ref() - .is_some_and(|s| s.is_unstable() && s.feature != sym::rustc_private) - { + let stability = import_def_id + .map_or_else(|| item.stability(tcx), |import_did| tcx.lookup_stability(import_did)); + if stability.is_some_and(|s| s.is_unstable() && s.feature != sym::rustc_private) { write!(f, "{}", tag_html("unstable", "", "Experimental"))?; } diff --git a/src/librustdoc/passes/mod.rs b/src/librustdoc/passes/mod.rs index b1dc766049d..f5b78023721 100644 --- a/src/librustdoc/passes/mod.rs +++ b/src/librustdoc/passes/mod.rs @@ -23,6 +23,9 @@ pub(crate) use self::strip_priv_imports::STRIP_PRIV_IMPORTS; mod propagate_doc_cfg; pub(crate) use self::propagate_doc_cfg::PROPAGATE_DOC_CFG; +mod propagate_stability; +pub(crate) use self::propagate_stability::PROPAGATE_STABILITY; + pub(crate) mod collect_intra_doc_links; pub(crate) use self::collect_intra_doc_links::COLLECT_INTRA_DOC_LINKS; @@ -75,6 +78,7 @@ pub(crate) const PASSES: &[Pass] = &[ STRIP_PRIVATE, STRIP_PRIV_IMPORTS, PROPAGATE_DOC_CFG, + PROPAGATE_STABILITY, COLLECT_INTRA_DOC_LINKS, COLLECT_TRAIT_IMPLS, CALCULATE_DOC_COVERAGE, @@ -91,6 +95,7 @@ pub(crate) const DEFAULT_PASSES: &[ConditionalPass] = &[ ConditionalPass::new(STRIP_PRIV_IMPORTS, WhenDocumentPrivate), ConditionalPass::always(COLLECT_INTRA_DOC_LINKS), ConditionalPass::always(PROPAGATE_DOC_CFG), + ConditionalPass::always(PROPAGATE_STABILITY), ConditionalPass::always(RUN_LINTS), ]; diff --git a/src/librustdoc/passes/propagate_stability.rs b/src/librustdoc/passes/propagate_stability.rs new file mode 100644 index 00000000000..f51e993bfa5 --- /dev/null +++ b/src/librustdoc/passes/propagate_stability.rs @@ -0,0 +1,72 @@ +//! Propagates stability to child items. +//! +//! The purpose of this pass is to make items whose parents are "more unstable" +//! than the item itself inherit the parent's stability. +//! For example, [`core::error::Error`] is marked as stable since 1.0.0, but the +//! [`core::error`] module is marked as stable since 1.81.0, so we want to show +//! [`core::error::Error`] as stable since 1.81.0 as well. + +use rustc_attr::{Stability, StabilityLevel}; +use rustc_hir::def_id::CRATE_DEF_ID; + +use crate::clean::{Crate, Item, ItemId}; +use crate::core::DocContext; +use crate::fold::DocFolder; +use crate::passes::Pass; + +pub(crate) const PROPAGATE_STABILITY: Pass = Pass { + name: "propagate-stability", + run: propagate_stability, + description: "propagates stability to child items", +}; + +pub(crate) fn propagate_stability(cr: Crate, cx: &mut DocContext<'_>) -> Crate { + let crate_stability = cx.tcx.lookup_stability(CRATE_DEF_ID); + StabilityPropagator { parent_stability: crate_stability, cx }.fold_crate(cr) +} + +struct StabilityPropagator<'a, 'tcx> { + parent_stability: Option, + cx: &'a mut DocContext<'tcx>, +} + +impl<'a, 'tcx> DocFolder for StabilityPropagator<'a, 'tcx> { + fn fold_item(&mut self, mut item: Item) -> Option { + let parent_stability = self.parent_stability; + + let stability = match item.item_id { + ItemId::DefId(def_id) => { + let own_stability = self.cx.tcx.lookup_stability(def_id); + + // If any of the item's parents was stabilized later or is still unstable, + // then use the parent's stability instead. + if let Some(own_stab) = own_stability + && let StabilityLevel::Stable { + since: own_since, + allowed_through_unstable_modules: false, + } = own_stab.level + && let Some(parent_stab) = parent_stability + && (parent_stab.is_unstable() + || parent_stab + .stable_since() + .is_some_and(|parent_since| parent_since > own_since)) + { + parent_stability + } else { + own_stability + } + } + ItemId::Auto { .. } | ItemId::Blanket { .. } => { + // For now, we do now show stability for synthesized impls. + None + } + }; + + item.inner.stability = stability; + self.parent_stability = stability; + let item = self.fold_item_recur(item); + self.parent_stability = parent_stability; + + Some(item) + } +} diff --git a/tests/rustdoc-ui/issues/issue-91713.stdout b/tests/rustdoc-ui/issues/issue-91713.stdout index 1ea3dbfb59f..790e58b0df9 100644 --- a/tests/rustdoc-ui/issues/issue-91713.stdout +++ b/tests/rustdoc-ui/issues/issue-91713.stdout @@ -5,6 +5,7 @@ strip-aliased-non-local - strips all non-local private aliased items from the ou strip-private - strips all private items from a crate which cannot be seen externally, implies strip-priv-imports strip-priv-imports - strips all private import statements (`use`, `extern crate`) from a crate propagate-doc-cfg - propagates `#[doc(cfg(...))]` to child items + propagate-stability - propagates stability to child items collect-intra-doc-links - resolves intra-doc links collect-trait-impls - retrieves trait impls for items in the crate calculate-doc-coverage - counts the number of items with and without documentation @@ -19,6 +20,7 @@ strip-aliased-non-local strip-priv-imports (when --document-private-items) collect-intra-doc-links propagate-doc-cfg + propagate-stability run-lints Passes run with `--show-coverage`: diff --git a/tests/rustdoc/stability.rs b/tests/rustdoc/stability.rs index de855b43ba5..fc72154cad8 100644 --- a/tests/rustdoc/stability.rs +++ b/tests/rustdoc/stability.rs @@ -25,28 +25,61 @@ pub struct ZzStable; #[unstable(feature = "unstable", issue = "none")] pub mod unstable { - //@ !hasraw stability/unstable/struct.Foo.html '//span[@class="since"]' + //@ !hasraw stability/unstable/struct.StableInUnstable.html \ + // '//span[@class="since"]' //@ has - '//div[@class="stab unstable"]' 'experimental' #[stable(feature = "rust1", since = "1.0.0")] - pub struct Foo; + pub struct StableInUnstable; + + #[stable(feature = "rust1", since = "1.0.0")] + pub mod stable_in_unstable { + //@ !hasraw stability/unstable/stable_in_unstable/struct.Inner.html \ + // '//span[@class="since"]' + //@ has - '//div[@class="stab unstable"]' 'experimental' + #[stable(feature = "rust1", since = "1.0.0")] + pub struct Inner; + } } #[stable(feature = "rust2", since = "2.2.2")] pub mod stable_later { - //@ has stability/stable_later/struct.Bar.html '//span[@class="since"]' '2.2.2' + //@ has stability/stable_later/struct.StableInLater.html \ + // '//span[@class="since"]' '2.2.2' #[stable(feature = "rust1", since = "1.0.0")] - pub struct Bar; + pub struct StableInLater; + + #[stable(feature = "rust1", since = "1.0.0")] + pub mod stable_in_later { + //@ has stability/stable_later/stable_in_later/struct.Inner.html \ + // '//span[@class="since"]' '2.2.2' + #[stable(feature = "rust1", since = "1.0.0")] + pub struct Inner; + } } #[stable(feature = "rust1", since = "1.0.0")] pub mod stable_earlier { - //@ has stability/stable_earlier/struct.Foo.html '//span[@class="since"]' '1.0.0' + //@ has stability/stable_earlier/struct.StableInUnstable.html \ + // '//span[@class="since"]' '1.0.0' #[doc(inline)] #[stable(feature = "rust1", since = "1.0.0")] - pub use crate::unstable::Foo; + pub use crate::unstable::StableInUnstable; - //@ has stability/stable_earlier/struct.Bar.html '//span[@class="since"]' '1.0.0' + //@ has stability/stable_earlier/stable_in_unstable/struct.Inner.html \ + // '//span[@class="since"]' '1.0.0' #[doc(inline)] #[stable(feature = "rust1", since = "1.0.0")] - pub use crate::stable_later::Bar; + pub use crate::unstable::stable_in_unstable; + + //@ has stability/stable_earlier/struct.StableInLater.html \ + // '//span[@class="since"]' '1.0.0' + #[doc(inline)] + #[stable(feature = "rust1", since = "1.0.0")] + pub use crate::stable_later::StableInLater; + + //@ has stability/stable_earlier/stable_in_later/struct.Inner.html \ + // '//span[@class="since"]' '1.0.0' + #[doc(inline)] + #[stable(feature = "rust1", since = "1.0.0")] + pub use crate::stable_later::stable_in_later; } From 91d0752e1698ac393a90b8f3ad58e59d904070d9 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 30 Sep 2024 16:56:40 -0700 Subject: [PATCH 442/683] Update wasm-component-ld to 0.5.9 This updates the `wasm-component-ld` linker binary for the `wasm32-wasip2` target to 0.5.9, pulling in a few bug fixes and recent updates. --- Cargo.lock | 48 +++++++++++++------------- src/tools/wasm-component-ld/Cargo.toml | 2 +- 2 files changed, 25 insertions(+), 25 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 582b5a763e6..6c1071ccbc2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5768,16 +5768,16 @@ checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484" [[package]] name = "wasm-component-ld" -version = "0.5.8" +version = "0.5.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb17cdbc91766d4ea0bcd6026c36ba77a21b5c8199aeb1f0993461fe6a6bec2b" +checksum = "fde17bc96539700198e12516230c76095cc215c84ef39ad206e1af3f84243e0f" dependencies = [ "anyhow", "clap", "lexopt", "tempfile", "wasi-preview1-component-adapter-provider", - "wasmparser 0.217.0", + "wasmparser 0.218.0", "wat", "wit-component", "wit-parser", @@ -5801,19 +5801,19 @@ dependencies = [ [[package]] name = "wasm-encoder" -version = "0.217.0" +version = "0.218.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b88b0814c9a2b323a9b46c687e726996c255ac8b64aa237dd11c81ed4854760" +checksum = "22b896fa8ceb71091ace9bcb81e853f54043183a1c9667cf93422c40252ffa0a" dependencies = [ "leb128", - "wasmparser 0.217.0", + "wasmparser 0.218.0", ] [[package]] name = "wasm-metadata" -version = "0.217.0" +version = "0.218.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65a146bf9a60e9264f0548a2599aa9656dba9a641eff9ab88299dc2a637e483c" +checksum = "aa5eeb071abe8a2132fdd5565dabffee70775ee8c24fc7e300ac43f51f4a8a91" dependencies = [ "anyhow", "indexmap", @@ -5821,8 +5821,8 @@ dependencies = [ "serde_derive", "serde_json", "spdx", - "wasm-encoder 0.217.0", - "wasmparser 0.217.0", + "wasm-encoder 0.218.0", + "wasmparser 0.218.0", ] [[package]] @@ -5837,9 +5837,9 @@ dependencies = [ [[package]] name = "wasmparser" -version = "0.217.0" +version = "0.218.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca917a21307d3adf2b9857b94dd05ebf8496bdcff4437a9b9fb3899d3e6c74e7" +checksum = "b09e46c7fceceaa72b2dd1a8a137ea7fd8f93dfaa69806010a709918e496c5dc" dependencies = [ "ahash", "bitflags 2.6.0", @@ -5851,22 +5851,22 @@ dependencies = [ [[package]] name = "wast" -version = "217.0.0" +version = "218.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79004ecebded92d3c710d4841383368c7f04b63d0992ddd6b0c7d5029b7629b7" +checksum = "8a53cd1f0fa505df97557e36a58bddb8296e2fcdcd089529545ebfdb18a1b9d7" dependencies = [ "bumpalo", "leb128", "memchr", "unicode-width", - "wasm-encoder 0.217.0", + "wasm-encoder 0.218.0", ] [[package]] name = "wat" -version = "1.217.0" +version = "1.218.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c126271c3d92ca0f7c63e4e462e40c69cca52fd4245fcda730d1cf558fb55088" +checksum = "4f87f8e14e776762e07927c27c2054d2cf678aab9aae2d431a79b3e31e4dd391" dependencies = [ "wast", ] @@ -6143,9 +6143,9 @@ dependencies = [ [[package]] name = "wit-component" -version = "0.217.0" +version = "0.218.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7117809905e49db716d81e794f79590c052bf2fdbbcda1731ca0fb28f6f3ddf" +checksum = "aa53aa7e6bf2b3e8ccaffbcc963fbdb672a603dc0af393a481b6cec24c266406" dependencies = [ "anyhow", "bitflags 2.6.0", @@ -6154,17 +6154,17 @@ dependencies = [ "serde", "serde_derive", "serde_json", - "wasm-encoder 0.217.0", + "wasm-encoder 0.218.0", "wasm-metadata", - "wasmparser 0.217.0", + "wasmparser 0.218.0", "wit-parser", ] [[package]] name = "wit-parser" -version = "0.217.0" +version = "0.218.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb893dcd6d370cfdf19a0d9adfcd403efb8e544e1a0ea3a8b81a21fe392eaa78" +checksum = "0d3d1066ab761b115f97fef2b191090faabcb0f37b555b758d3caf42d4ed9e55" dependencies = [ "anyhow", "id-arena", @@ -6175,7 +6175,7 @@ dependencies = [ "serde_derive", "serde_json", "unicode-xid", - "wasmparser 0.217.0", + "wasmparser 0.218.0", ] [[package]] diff --git a/src/tools/wasm-component-ld/Cargo.toml b/src/tools/wasm-component-ld/Cargo.toml index 91ff19ad9fc..49f4e59650e 100644 --- a/src/tools/wasm-component-ld/Cargo.toml +++ b/src/tools/wasm-component-ld/Cargo.toml @@ -10,4 +10,4 @@ name = "wasm-component-ld" path = "src/main.rs" [dependencies] -wasm-component-ld = "0.5.4" +wasm-component-ld = "0.5.9" From 6b09a93566cc891a56a8f9bb68a25d16ca4d91d3 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 27 Sep 2024 18:35:30 -0400 Subject: [PATCH 443/683] Enable `f16` tests on non-GNU Windows There is a MinGW ABI bug that prevents `f16` and `f128` from being usable on `windows-gnu` targets. This does not affect MSVC; however, we have `f16` and `f128` tests disabled on all Windows targets. Update the gating to only affect `windows-gnu`, which means `f16` tests will be enabled. There is no effect for `f128` since the default fallback is `false`. --- library/std/build.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library/std/build.rs b/library/std/build.rs index 5da470c6462..7d37d4e9d7d 100644 --- a/library/std/build.rs +++ b/library/std/build.rs @@ -101,7 +101,7 @@ fn main() { // Unsupported ("arm64ec", _) => false, // MinGW ABI bugs - ("x86_64", "windows") => false, + ("x86_64", "windows") if target_env == "gnu" => false, // Infinite recursion ("csky", _) => false, ("hexagon", _) => false, @@ -129,10 +129,10 @@ fn main() { // ABI unsupported ("sparc", _) => false, // MinGW ABI bugs - ("x86_64", "windows") => false, + ("x86_64", "windows") if target_env == "gnu" => false, // 64-bit Linux is about the only platform to have f128 symbols by default (_, "linux") if target_pointer_width == 64 => true, - // Same as for f16, except MacOS is also missing f128 symbols. + // Almost all OSs are missing symbol. compiler-builtins will have to add them. _ => false, }; From 88c74529c1210bdf06e30b70aa51721218512090 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 1 Oct 2024 08:41:54 +0200 Subject: [PATCH 444/683] move io error handling helpers to their own file --- src/tools/miri/src/helpers.rs | 185 +------------------------- src/tools/miri/src/lib.rs | 1 + src/tools/miri/src/shims/io_error.rs | 190 +++++++++++++++++++++++++++ src/tools/miri/src/shims/mod.rs | 1 + 4 files changed, 193 insertions(+), 184 deletions(-) create mode 100644 src/tools/miri/src/shims/io_error.rs diff --git a/src/tools/miri/src/helpers.rs b/src/tools/miri/src/helpers.rs index 5324e4bec5b..da0581ea862 100644 --- a/src/tools/miri/src/helpers.rs +++ b/src/tools/miri/src/helpers.rs @@ -2,7 +2,7 @@ use std::collections::BTreeSet; use std::num::NonZero; use std::sync::Mutex; use std::time::Duration; -use std::{cmp, io, iter}; +use std::{cmp, iter}; use rand::RngCore; use rustc_apfloat::Float; @@ -31,65 +31,6 @@ pub enum AccessKind { Write, } -// This mapping should match `decode_error_kind` in -// . -const UNIX_IO_ERROR_TABLE: &[(&str, std::io::ErrorKind)] = { - use std::io::ErrorKind::*; - &[ - ("E2BIG", ArgumentListTooLong), - ("EADDRINUSE", AddrInUse), - ("EADDRNOTAVAIL", AddrNotAvailable), - ("EBUSY", ResourceBusy), - ("ECONNABORTED", ConnectionAborted), - ("ECONNREFUSED", ConnectionRefused), - ("ECONNRESET", ConnectionReset), - ("EDEADLK", Deadlock), - ("EDQUOT", FilesystemQuotaExceeded), - ("EEXIST", AlreadyExists), - ("EFBIG", FileTooLarge), - ("EHOSTUNREACH", HostUnreachable), - ("EINTR", Interrupted), - ("EINVAL", InvalidInput), - ("EISDIR", IsADirectory), - ("ELOOP", FilesystemLoop), - ("ENOENT", NotFound), - ("ENOMEM", OutOfMemory), - ("ENOSPC", StorageFull), - ("ENOSYS", Unsupported), - ("EMLINK", TooManyLinks), - ("ENAMETOOLONG", InvalidFilename), - ("ENETDOWN", NetworkDown), - ("ENETUNREACH", NetworkUnreachable), - ("ENOTCONN", NotConnected), - ("ENOTDIR", NotADirectory), - ("ENOTEMPTY", DirectoryNotEmpty), - ("EPIPE", BrokenPipe), - ("EROFS", ReadOnlyFilesystem), - ("ESPIPE", NotSeekable), - ("ESTALE", StaleNetworkFileHandle), - ("ETIMEDOUT", TimedOut), - ("ETXTBSY", ExecutableFileBusy), - ("EXDEV", CrossesDevices), - // The following have two valid options. We have both for the forwards mapping; only the - // first one will be used for the backwards mapping. - ("EPERM", PermissionDenied), - ("EACCES", PermissionDenied), - ("EWOULDBLOCK", WouldBlock), - ("EAGAIN", WouldBlock), - ] -}; -// This mapping should match `decode_error_kind` in -// . -const WINDOWS_IO_ERROR_TABLE: &[(&str, std::io::ErrorKind)] = { - use std::io::ErrorKind::*; - // FIXME: this is still incomplete. - &[ - ("ERROR_ACCESS_DENIED", PermissionDenied), - ("ERROR_FILE_NOT_FOUND", NotFound), - ("ERROR_INVALID_PARAMETER", InvalidInput), - ] -}; - /// Gets an instance for a path. /// /// A `None` namespace indicates we are looking for a module. @@ -745,130 +686,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { self.eval_context_ref().tcx.sess.target.families.iter().any(|f| f == "unix") } - /// Get last error variable as a place, lazily allocating thread-local storage for it if - /// necessary. - fn last_error_place(&mut self) -> InterpResult<'tcx, MPlaceTy<'tcx>> { - let this = self.eval_context_mut(); - if let Some(errno_place) = this.active_thread_ref().last_error.as_ref() { - Ok(errno_place.clone()) - } else { - // Allocate new place, set initial value to 0. - let errno_layout = this.machine.layouts.u32; - let errno_place = this.allocate(errno_layout, MiriMemoryKind::Machine.into())?; - this.write_scalar(Scalar::from_u32(0), &errno_place)?; - this.active_thread_mut().last_error = Some(errno_place.clone()); - Ok(errno_place) - } - } - - /// Sets the last error variable. - fn set_last_error(&mut self, scalar: Scalar) -> InterpResult<'tcx> { - let this = self.eval_context_mut(); - let errno_place = this.last_error_place()?; - this.write_scalar(scalar, &errno_place) - } - - /// Gets the last error variable. - fn get_last_error(&mut self) -> InterpResult<'tcx, Scalar> { - let this = self.eval_context_mut(); - let errno_place = this.last_error_place()?; - this.read_scalar(&errno_place) - } - - /// This function tries to produce the most similar OS error from the `std::io::ErrorKind` - /// as a platform-specific errnum. - fn io_error_to_errnum(&self, err: std::io::Error) -> InterpResult<'tcx, Scalar> { - let this = self.eval_context_ref(); - let target = &this.tcx.sess.target; - if target.families.iter().any(|f| f == "unix") { - for &(name, kind) in UNIX_IO_ERROR_TABLE { - if err.kind() == kind { - return Ok(this.eval_libc(name)); - } - } - throw_unsup_format!("unsupported io error: {err}") - } else if target.families.iter().any(|f| f == "windows") { - for &(name, kind) in WINDOWS_IO_ERROR_TABLE { - if err.kind() == kind { - return Ok(this.eval_windows("c", name)); - } - } - throw_unsup_format!("unsupported io error: {err}"); - } else { - throw_unsup_format!( - "converting io::Error into errnum is unsupported for OS {}", - target.os - ) - } - } - - /// The inverse of `io_error_to_errnum`. - #[allow(clippy::needless_return)] - fn try_errnum_to_io_error( - &self, - errnum: Scalar, - ) -> InterpResult<'tcx, Option> { - let this = self.eval_context_ref(); - let target = &this.tcx.sess.target; - if target.families.iter().any(|f| f == "unix") { - let errnum = errnum.to_i32()?; - for &(name, kind) in UNIX_IO_ERROR_TABLE { - if errnum == this.eval_libc_i32(name) { - return Ok(Some(kind)); - } - } - return Ok(None); - } else if target.families.iter().any(|f| f == "windows") { - let errnum = errnum.to_u32()?; - for &(name, kind) in WINDOWS_IO_ERROR_TABLE { - if errnum == this.eval_windows("c", name).to_u32()? { - return Ok(Some(kind)); - } - } - return Ok(None); - } else { - throw_unsup_format!( - "converting errnum into io::Error is unsupported for OS {}", - target.os - ) - } - } - - /// Sets the last OS error using a `std::io::ErrorKind`. - fn set_last_error_from_io_error(&mut self, err: std::io::Error) -> InterpResult<'tcx> { - self.set_last_error(self.io_error_to_errnum(err)?) - } - - /// Sets the last OS error using a `std::io::ErrorKind` and writes -1 to dest place. - fn set_last_error_and_return( - &mut self, - err: impl Into, - dest: &MPlaceTy<'tcx>, - ) -> InterpResult<'tcx> { - self.set_last_error(self.io_error_to_errnum(err.into())?)?; - self.write_int(-1, dest)?; - Ok(()) - } - - /// Helper function that consumes an `std::io::Result` and returns an - /// `InterpResult<'tcx,T>::Ok` instead. In case the result is an error, this function returns - /// `Ok(-1)` and sets the last OS error accordingly. - /// - /// This function uses `T: From` instead of `i32` directly because some IO related - /// functions return different integer types (like `read`, that returns an `i64`). - fn try_unwrap_io_result>( - &mut self, - result: std::io::Result, - ) -> InterpResult<'tcx, T> { - match result { - Ok(ok) => Ok(ok), - Err(e) => { - self.eval_context_mut().set_last_error_from_io_error(e)?; - Ok((-1).into()) - } - } - } - /// Dereference a pointer operand to a place using `layout` instead of the pointer's declared type fn deref_pointer_as( &self, diff --git a/src/tools/miri/src/lib.rs b/src/tools/miri/src/lib.rs index 78e7bf70455..c4adf38299c 100644 --- a/src/tools/miri/src/lib.rs +++ b/src/tools/miri/src/lib.rs @@ -150,6 +150,7 @@ pub use crate::range_map::RangeMap; pub use crate::shims::EmulateItemResult; pub use crate::shims::env::{EnvVars, EvalContextExt as _}; pub use crate::shims::foreign_items::{DynSym, EvalContextExt as _}; +pub use crate::shims::io_error::EvalContextExt as _; pub use crate::shims::os_str::EvalContextExt as _; pub use crate::shims::panic::{CatchUnwindData, EvalContextExt as _}; pub use crate::shims::time::EvalContextExt as _; diff --git a/src/tools/miri/src/shims/io_error.rs b/src/tools/miri/src/shims/io_error.rs new file mode 100644 index 00000000000..8c727f4c894 --- /dev/null +++ b/src/tools/miri/src/shims/io_error.rs @@ -0,0 +1,190 @@ +use std::io; + +use crate::*; + +// This mapping should match `decode_error_kind` in +// . +const UNIX_IO_ERROR_TABLE: &[(&str, std::io::ErrorKind)] = { + use std::io::ErrorKind::*; + &[ + ("E2BIG", ArgumentListTooLong), + ("EADDRINUSE", AddrInUse), + ("EADDRNOTAVAIL", AddrNotAvailable), + ("EBUSY", ResourceBusy), + ("ECONNABORTED", ConnectionAborted), + ("ECONNREFUSED", ConnectionRefused), + ("ECONNRESET", ConnectionReset), + ("EDEADLK", Deadlock), + ("EDQUOT", FilesystemQuotaExceeded), + ("EEXIST", AlreadyExists), + ("EFBIG", FileTooLarge), + ("EHOSTUNREACH", HostUnreachable), + ("EINTR", Interrupted), + ("EINVAL", InvalidInput), + ("EISDIR", IsADirectory), + ("ELOOP", FilesystemLoop), + ("ENOENT", NotFound), + ("ENOMEM", OutOfMemory), + ("ENOSPC", StorageFull), + ("ENOSYS", Unsupported), + ("EMLINK", TooManyLinks), + ("ENAMETOOLONG", InvalidFilename), + ("ENETDOWN", NetworkDown), + ("ENETUNREACH", NetworkUnreachable), + ("ENOTCONN", NotConnected), + ("ENOTDIR", NotADirectory), + ("ENOTEMPTY", DirectoryNotEmpty), + ("EPIPE", BrokenPipe), + ("EROFS", ReadOnlyFilesystem), + ("ESPIPE", NotSeekable), + ("ESTALE", StaleNetworkFileHandle), + ("ETIMEDOUT", TimedOut), + ("ETXTBSY", ExecutableFileBusy), + ("EXDEV", CrossesDevices), + // The following have two valid options. We have both for the forwards mapping; only the + // first one will be used for the backwards mapping. + ("EPERM", PermissionDenied), + ("EACCES", PermissionDenied), + ("EWOULDBLOCK", WouldBlock), + ("EAGAIN", WouldBlock), + ] +}; +// This mapping should match `decode_error_kind` in +// . +const WINDOWS_IO_ERROR_TABLE: &[(&str, std::io::ErrorKind)] = { + use std::io::ErrorKind::*; + // FIXME: this is still incomplete. + &[ + ("ERROR_ACCESS_DENIED", PermissionDenied), + ("ERROR_FILE_NOT_FOUND", NotFound), + ("ERROR_INVALID_PARAMETER", InvalidInput), + ] +}; + +impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {} +pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { + /// Get last error variable as a place, lazily allocating thread-local storage for it if + /// necessary. + fn last_error_place(&mut self) -> InterpResult<'tcx, MPlaceTy<'tcx>> { + let this = self.eval_context_mut(); + if let Some(errno_place) = this.active_thread_ref().last_error.as_ref() { + Ok(errno_place.clone()) + } else { + // Allocate new place, set initial value to 0. + let errno_layout = this.machine.layouts.u32; + let errno_place = this.allocate(errno_layout, MiriMemoryKind::Machine.into())?; + this.write_scalar(Scalar::from_u32(0), &errno_place)?; + this.active_thread_mut().last_error = Some(errno_place.clone()); + Ok(errno_place) + } + } + + /// Sets the last error variable. + fn set_last_error(&mut self, scalar: Scalar) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + let errno_place = this.last_error_place()?; + this.write_scalar(scalar, &errno_place) + } + + /// Gets the last error variable. + fn get_last_error(&mut self) -> InterpResult<'tcx, Scalar> { + let this = self.eval_context_mut(); + let errno_place = this.last_error_place()?; + this.read_scalar(&errno_place) + } + + /// This function tries to produce the most similar OS error from the `std::io::ErrorKind` + /// as a platform-specific errnum. + fn io_error_to_errnum(&self, err: std::io::Error) -> InterpResult<'tcx, Scalar> { + let this = self.eval_context_ref(); + let target = &this.tcx.sess.target; + if target.families.iter().any(|f| f == "unix") { + for &(name, kind) in UNIX_IO_ERROR_TABLE { + if err.kind() == kind { + return Ok(this.eval_libc(name)); + } + } + throw_unsup_format!("unsupported io error: {err}") + } else if target.families.iter().any(|f| f == "windows") { + for &(name, kind) in WINDOWS_IO_ERROR_TABLE { + if err.kind() == kind { + return Ok(this.eval_windows("c", name)); + } + } + throw_unsup_format!("unsupported io error: {err}"); + } else { + throw_unsup_format!( + "converting io::Error into errnum is unsupported for OS {}", + target.os + ) + } + } + + /// The inverse of `io_error_to_errnum`. + #[allow(clippy::needless_return)] + fn try_errnum_to_io_error( + &self, + errnum: Scalar, + ) -> InterpResult<'tcx, Option> { + let this = self.eval_context_ref(); + let target = &this.tcx.sess.target; + if target.families.iter().any(|f| f == "unix") { + let errnum = errnum.to_i32()?; + for &(name, kind) in UNIX_IO_ERROR_TABLE { + if errnum == this.eval_libc_i32(name) { + return Ok(Some(kind)); + } + } + return Ok(None); + } else if target.families.iter().any(|f| f == "windows") { + let errnum = errnum.to_u32()?; + for &(name, kind) in WINDOWS_IO_ERROR_TABLE { + if errnum == this.eval_windows("c", name).to_u32()? { + return Ok(Some(kind)); + } + } + return Ok(None); + } else { + throw_unsup_format!( + "converting errnum into io::Error is unsupported for OS {}", + target.os + ) + } + } + + /// Sets the last OS error using a `std::io::ErrorKind`. + fn set_last_error_from_io_error(&mut self, err: std::io::Error) -> InterpResult<'tcx> { + self.set_last_error(self.io_error_to_errnum(err)?) + } + + /// Sets the last OS error using a `std::io::ErrorKind` and writes -1 to dest place. + fn set_last_error_and_return( + &mut self, + err: impl Into, + dest: &MPlaceTy<'tcx>, + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + this.set_last_error(this.io_error_to_errnum(err.into())?)?; + this.write_int(-1, dest)?; + Ok(()) + } + + /// Helper function that consumes an `std::io::Result` and returns an + /// `InterpResult<'tcx,T>::Ok` instead. In case the result is an error, this function returns + /// `Ok(-1)` and sets the last OS error accordingly. + /// + /// This function uses `T: From` instead of `i32` directly because some IO related + /// functions return different integer types (like `read`, that returns an `i64`). + fn try_unwrap_io_result>( + &mut self, + result: std::io::Result, + ) -> InterpResult<'tcx, T> { + match result { + Ok(ok) => Ok(ok), + Err(e) => { + self.eval_context_mut().set_last_error_from_io_error(e)?; + Ok((-1).into()) + } + } + } +} diff --git a/src/tools/miri/src/shims/mod.rs b/src/tools/miri/src/shims/mod.rs index a689ac2b378..b9317ac1a15 100644 --- a/src/tools/miri/src/shims/mod.rs +++ b/src/tools/miri/src/shims/mod.rs @@ -12,6 +12,7 @@ mod x86; pub mod env; pub mod extern_static; pub mod foreign_items; +pub mod io_error; pub mod os_str; pub mod panic; pub mod time; From 9c21fd4b93540d841e11ba4f975660666a9bfc3f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 1 Oct 2024 09:02:33 +0200 Subject: [PATCH 445/683] make set_last_error directly callable on a bunch of ways to represent errors --- src/tools/miri/src/lib.rs | 2 +- src/tools/miri/src/shims/io_error.rs | 48 +++++++++++++++---- src/tools/miri/src/shims/unix/env.rs | 15 +++--- src/tools/miri/src/shims/unix/fd.rs | 8 ++-- .../miri/src/shims/unix/foreign_items.rs | 22 ++++----- src/tools/miri/src/shims/unix/fs.rs | 48 ++++++++----------- src/tools/miri/src/shims/unix/linux/epoll.rs | 6 +-- src/tools/miri/src/shims/unix/linux/sync.rs | 9 ++-- src/tools/miri/src/shims/windows/env.rs | 8 ++-- .../miri/src/shims/windows/foreign_items.rs | 2 +- 10 files changed, 88 insertions(+), 80 deletions(-) diff --git a/src/tools/miri/src/lib.rs b/src/tools/miri/src/lib.rs index c4adf38299c..330147c8f1c 100644 --- a/src/tools/miri/src/lib.rs +++ b/src/tools/miri/src/lib.rs @@ -150,7 +150,7 @@ pub use crate::range_map::RangeMap; pub use crate::shims::EmulateItemResult; pub use crate::shims::env::{EnvVars, EvalContextExt as _}; pub use crate::shims::foreign_items::{DynSym, EvalContextExt as _}; -pub use crate::shims::io_error::EvalContextExt as _; +pub use crate::shims::io_error::{EvalContextExt as _, LibcError}; pub use crate::shims::os_str::EvalContextExt as _; pub use crate::shims::panic::{CatchUnwindData, EvalContextExt as _}; pub use crate::shims::time::EvalContextExt as _; diff --git a/src/tools/miri/src/shims/io_error.rs b/src/tools/miri/src/shims/io_error.rs index 8c727f4c894..61b943b599d 100644 --- a/src/tools/miri/src/shims/io_error.rs +++ b/src/tools/miri/src/shims/io_error.rs @@ -2,6 +2,34 @@ use std::io; use crate::*; +/// A representation of an IO error: either a libc error name, +/// or a host error. +#[derive(Debug)] +pub enum IoError { + LibcError(&'static str), + HostError(io::Error), + Raw(Scalar), +} +pub use self::IoError::*; + +impl From for IoError { + fn from(value: io::Error) -> Self { + IoError::HostError(value) + } +} + +impl From for IoError { + fn from(value: io::ErrorKind) -> Self { + IoError::HostError(value.into()) + } +} + +impl From for IoError { + fn from(value: Scalar) -> Self { + IoError::Raw(value) + } +} + // This mapping should match `decode_error_kind` in // . const UNIX_IO_ERROR_TABLE: &[(&str, std::io::ErrorKind)] = { @@ -80,10 +108,15 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } /// Sets the last error variable. - fn set_last_error(&mut self, scalar: Scalar) -> InterpResult<'tcx> { + fn set_last_error(&mut self, err: impl Into) -> InterpResult<'tcx> { let this = self.eval_context_mut(); + let errno = match err.into() { + HostError(err) => this.io_error_to_errnum(err)?, + LibcError(name) => this.eval_libc(name), + Raw(val) => val, + }; let errno_place = this.last_error_place()?; - this.write_scalar(scalar, &errno_place) + this.write_scalar(errno, &errno_place) } /// Gets the last error variable. @@ -152,19 +185,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } } - /// Sets the last OS error using a `std::io::ErrorKind`. - fn set_last_error_from_io_error(&mut self, err: std::io::Error) -> InterpResult<'tcx> { - self.set_last_error(self.io_error_to_errnum(err)?) - } - /// Sets the last OS error using a `std::io::ErrorKind` and writes -1 to dest place. fn set_last_error_and_return( &mut self, - err: impl Into, + err: impl Into, dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - this.set_last_error(this.io_error_to_errnum(err.into())?)?; + this.set_last_error(err)?; this.write_int(-1, dest)?; Ok(()) } @@ -182,7 +210,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { match result { Ok(ok) => Ok(ok), Err(e) => { - self.eval_context_mut().set_last_error_from_io_error(e)?; + self.eval_context_mut().set_last_error(e)?; Ok((-1).into()) } } diff --git a/src/tools/miri/src/shims/unix/env.rs b/src/tools/miri/src/shims/unix/env.rs index 184a6c238b3..923de15d2da 100644 --- a/src/tools/miri/src/shims/unix/env.rs +++ b/src/tools/miri/src/shims/unix/env.rs @@ -177,8 +177,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { Ok(Scalar::from_i32(0)) // return zero on success } else { // name argument is a null pointer, points to an empty string, or points to a string containing an '=' character. - let einval = this.eval_libc("EINVAL"); - this.set_last_error(einval)?; + this.set_last_error(LibcError("EINVAL"))?; Ok(Scalar::from_i32(-1)) } } @@ -203,8 +202,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { Ok(Scalar::from_i32(0)) } else { // name argument is a null pointer, points to an empty string, or points to a string containing an '=' character. - let einval = this.eval_libc("EINVAL"); - this.set_last_error(einval)?; + this.set_last_error(LibcError("EINVAL"))?; Ok(Scalar::from_i32(-1)) } } @@ -218,7 +216,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("`getcwd`", reject_with)?; - this.set_last_error_from_io_error(ErrorKind::PermissionDenied.into())?; + this.set_last_error(ErrorKind::PermissionDenied)?; return Ok(Pointer::null()); } @@ -228,10 +226,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { if this.write_path_to_c_str(&cwd, buf, size)?.0 { return Ok(buf); } - let erange = this.eval_libc("ERANGE"); - this.set_last_error(erange)?; + this.set_last_error(LibcError("ERANGE"))?; } - Err(e) => this.set_last_error_from_io_error(e)?, + Err(e) => this.set_last_error(e)?, } Ok(Pointer::null()) @@ -245,7 +242,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("`chdir`", reject_with)?; - this.set_last_error_from_io_error(ErrorKind::PermissionDenied.into())?; + this.set_last_error(ErrorKind::PermissionDenied)?; return Ok(Scalar::from_i32(-1)); } diff --git a/src/tools/miri/src/shims/unix/fd.rs b/src/tools/miri/src/shims/unix/fd.rs index f64d0ed1467..fe634de122c 100644 --- a/src/tools/miri/src/shims/unix/fd.rs +++ b/src/tools/miri/src/shims/unix/fd.rs @@ -524,7 +524,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Reject if isolation is enabled. if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("`fcntl`", reject_with)?; - this.set_last_error_from_io_error(ErrorKind::PermissionDenied.into())?; + this.set_last_error(ErrorKind::PermissionDenied)?; return Ok(Scalar::from_i32(-1)); } @@ -606,8 +606,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { None => fd.read(&fd, communicate, buf, count, dest, this)?, Some(offset) => { let Ok(offset) = u64::try_from(offset) else { - let einval = this.eval_libc("EINVAL"); - this.set_last_error(einval)?; + this.set_last_error(LibcError("EINVAL"))?; this.write_int(-1, dest)?; return Ok(()); }; @@ -651,8 +650,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { None => fd.write(&fd, communicate, buf, count, dest, this)?, Some(offset) => { let Ok(offset) = u64::try_from(offset) else { - let einval = this.eval_libc("EINVAL"); - this.set_last_error(einval)?; + this.set_last_error(LibcError("EINVAL"))?; this.write_int(-1, dest)?; return Ok(()); }; diff --git a/src/tools/miri/src/shims/unix/foreign_items.rs b/src/tools/miri/src/shims/unix/foreign_items.rs index 528d068ea92..14af4245148 100644 --- a/src/tools/miri/src/shims/unix/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/foreign_items.rs @@ -355,8 +355,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // FreeBSD: https://man.freebsd.org/cgi/man.cgi?query=reallocarray match this.compute_size_in_bytes(Size::from_bytes(size), nmemb) { None => { - let einval = this.eval_libc("ENOMEM"); - this.set_last_error(einval)?; + let enmem = this.eval_libc("ENOMEM"); + this.set_last_error(enmem)?; this.write_null(dest)?; } Some(len) => { @@ -646,13 +646,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let chunk_size = CpuAffinityMask::chunk_size(this); if this.ptr_is_null(mask)? { - let einval = this.eval_libc("EFAULT"); - this.set_last_error(einval)?; + let efault = this.eval_libc("EFAULT"); + this.set_last_error(efault)?; this.write_int(-1, dest)?; } else if cpusetsize == 0 || cpusetsize.checked_rem(chunk_size).unwrap() != 0 { // we only copy whole chunks of size_of::() - let einval = this.eval_libc("EINVAL"); - this.set_last_error(einval)?; + this.set_last_error(LibcError("EINVAL"))?; this.write_int(-1, dest)?; } else if let Some(cpuset) = this.machine.thread_cpu_affinity.get(&thread_id) { let cpuset = cpuset.clone(); @@ -662,8 +661,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_null(dest)?; } else { // The thread whose ID is pid could not be found - let einval = this.eval_libc("ESRCH"); - this.set_last_error(einval)?; + let esrch = this.eval_libc("ESRCH"); + this.set_last_error(esrch)?; this.write_int(-1, dest)?; } } @@ -689,8 +688,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { }; if this.ptr_is_null(mask)? { - let einval = this.eval_libc("EFAULT"); - this.set_last_error(einval)?; + let efault = this.eval_libc("EFAULT"); + this.set_last_error(efault)?; this.write_int(-1, dest)?; } else { // NOTE: cpusetsize might be smaller than `CpuAffinityMask::CPU_MASK_BYTES`. @@ -707,8 +706,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } None => { // The intersection between the mask and the available CPUs was empty. - let einval = this.eval_libc("EINVAL"); - this.set_last_error(einval)?; + this.set_last_error(LibcError("EINVAL"))?; this.write_int(-1, dest)?; } } diff --git a/src/tools/miri/src/shims/unix/fs.rs b/src/tools/miri/src/shims/unix/fs.rs index 2fa1729ad9c..80e45d84398 100644 --- a/src/tools/miri/src/shims/unix/fs.rs +++ b/src/tools/miri/src/shims/unix/fs.rs @@ -534,8 +534,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let o_tmpfile = this.eval_libc_i32("O_TMPFILE"); if flag & o_tmpfile == o_tmpfile { // if the flag contains `O_TMPFILE` then we return a graceful error - let eopnotsupp = this.eval_libc("EOPNOTSUPP"); - this.set_last_error(eopnotsupp)?; + this.set_last_error(LibcError("EOPNOTSUPP"))?; return Ok(Scalar::from_i32(-1)); } } @@ -572,7 +571,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Reject if isolation is enabled. if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("`open`", reject_with)?; - this.set_last_error_from_io_error(ErrorKind::PermissionDenied.into())?; + this.set_last_error(ErrorKind::PermissionDenied)?; return Ok(Scalar::from_i32(-1)); } @@ -591,8 +590,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let seek_from = if whence == this.eval_libc_i32("SEEK_SET") { if offset < 0 { // Negative offsets return `EINVAL`. - let einval = this.eval_libc("EINVAL"); - this.set_last_error(einval)?; + this.set_last_error(LibcError("EINVAL"))?; return Ok(Scalar::from_i64(-1)); } else { SeekFrom::Start(u64::try_from(offset).unwrap()) @@ -602,8 +600,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } else if whence == this.eval_libc_i32("SEEK_END") { SeekFrom::End(i64::try_from(offset).unwrap()) } else { - let einval = this.eval_libc("EINVAL"); - this.set_last_error(einval)?; + this.set_last_error(LibcError("EINVAL"))?; return Ok(Scalar::from_i64(-1)); }; @@ -627,7 +624,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Reject if isolation is enabled. if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("`unlink`", reject_with)?; - this.set_last_error_from_io_error(ErrorKind::PermissionDenied.into())?; + this.set_last_error(ErrorKind::PermissionDenied)?; return Ok(Scalar::from_i32(-1)); } @@ -658,7 +655,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Reject if isolation is enabled. if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("`symlink`", reject_with)?; - this.set_last_error_from_io_error(ErrorKind::PermissionDenied.into())?; + this.set_last_error(ErrorKind::PermissionDenied)?; return Ok(Scalar::from_i32(-1)); } @@ -959,7 +956,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Reject if isolation is enabled. if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("`rename`", reject_with)?; - this.set_last_error_from_io_error(ErrorKind::PermissionDenied.into())?; + this.set_last_error(ErrorKind::PermissionDenied)?; return Ok(Scalar::from_i32(-1)); } @@ -983,7 +980,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Reject if isolation is enabled. if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("`mkdir`", reject_with)?; - this.set_last_error_from_io_error(ErrorKind::PermissionDenied.into())?; + this.set_last_error(ErrorKind::PermissionDenied)?; return Ok(Scalar::from_i32(-1)); } @@ -1011,7 +1008,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Reject if isolation is enabled. if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("`rmdir`", reject_with)?; - this.set_last_error_from_io_error(ErrorKind::PermissionDenied.into())?; + this.set_last_error(ErrorKind::PermissionDenied)?; return Ok(Scalar::from_i32(-1)); } @@ -1045,7 +1042,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { Ok(Scalar::from_target_usize(id, this)) } Err(e) => { - this.set_last_error_from_io_error(e)?; + this.set_last_error(e)?; Ok(Scalar::null_ptr(this)) } } @@ -1130,7 +1127,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { None } Some(Err(e)) => { - this.set_last_error_from_io_error(e)?; + this.set_last_error(e)?; None } }; @@ -1314,15 +1311,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { Ok(Scalar::from_i32(result)) } else { drop(fd); - let einval = this.eval_libc("EINVAL"); - this.set_last_error(einval)?; + this.set_last_error(LibcError("EINVAL"))?; Ok(Scalar::from_i32(-1)) } } else { drop(fd); // The file is not writable - let einval = this.eval_libc("EINVAL"); - this.set_last_error(einval)?; + this.set_last_error(LibcError("EINVAL"))?; Ok(Scalar::from_i32(-1)) } } @@ -1400,16 +1395,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let flags = this.read_scalar(flags_op)?.to_i32()?; if offset < 0 || nbytes < 0 { - let einval = this.eval_libc("EINVAL"); - this.set_last_error(einval)?; + this.set_last_error(LibcError("EINVAL"))?; return Ok(Scalar::from_i32(-1)); } let allowed_flags = this.eval_libc_i32("SYNC_FILE_RANGE_WAIT_BEFORE") | this.eval_libc_i32("SYNC_FILE_RANGE_WRITE") | this.eval_libc_i32("SYNC_FILE_RANGE_WAIT_AFTER"); if flags & allowed_flags != flags { - let einval = this.eval_libc("EINVAL"); - this.set_last_error(einval)?; + this.set_last_error(LibcError("EINVAL"))?; return Ok(Scalar::from_i32(-1)); } @@ -1471,7 +1464,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { Ok(path_bytes.len().try_into().unwrap()) } Err(e) => { - this.set_last_error_from_io_error(e)?; + this.set_last_error(e)?; Ok(-1) } } @@ -1551,7 +1544,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { Ok(Scalar::from_maybe_pointer(dest, this)) } Err(e) => { - this.set_last_error_from_io_error(e)?; + this.set_last_error(e)?; Ok(Scalar::from_target_usize(0, this)) } } @@ -1603,8 +1596,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // If we don't find the suffix, it is an error. if last_six_char_bytes != suffix_bytes { - let einval = this.eval_libc("EINVAL"); - this.set_last_error(einval)?; + this.set_last_error(LibcError("EINVAL"))?; return Ok(Scalar::from_i32(-1)); } @@ -1670,7 +1662,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { _ => { // "On error, -1 is returned, and errno is set to // indicate the error" - this.set_last_error_from_io_error(e)?; + this.set_last_error(e)?; return Ok(Scalar::from_i32(-1)); } }, @@ -1749,7 +1741,7 @@ impl FileMetadata { let metadata = match metadata { Ok(metadata) => metadata, Err(e) => { - ecx.set_last_error_from_io_error(e)?; + ecx.set_last_error(e)?; return Ok(None); } }; diff --git a/src/tools/miri/src/shims/unix/linux/epoll.rs b/src/tools/miri/src/shims/unix/linux/epoll.rs index 675a404ae11..ff0709dd5ac 100644 --- a/src/tools/miri/src/shims/unix/linux/epoll.rs +++ b/src/tools/miri/src/shims/unix/linux/epoll.rs @@ -261,8 +261,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Throw EINVAL if epfd and fd have the same value. if epfd_value == fd { - let einval = this.eval_libc("EINVAL"); - this.set_last_error(einval)?; + this.set_last_error(LibcError("EINVAL"))?; return Ok(Scalar::from_i32(-1)); } @@ -443,8 +442,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let timeout = this.read_scalar(timeout)?.to_i32()?; if epfd_value <= 0 || maxevents <= 0 { - let einval = this.eval_libc("EINVAL"); - this.set_last_error(einval)?; + this.set_last_error(LibcError("EINVAL"))?; this.write_int(-1, dest)?; return Ok(()); } diff --git a/src/tools/miri/src/shims/unix/linux/sync.rs b/src/tools/miri/src/shims/unix/linux/sync.rs index bd212039074..1d1764b3a1a 100644 --- a/src/tools/miri/src/shims/unix/linux/sync.rs +++ b/src/tools/miri/src/shims/unix/linux/sync.rs @@ -75,8 +75,7 @@ pub fn futex<'tcx>( }; if bitset == 0 { - let einval = this.eval_libc("EINVAL"); - this.set_last_error(einval)?; + this.set_last_error(LibcError("EINVAL"))?; this.write_scalar(Scalar::from_target_isize(-1, this), dest)?; return Ok(()); } @@ -88,8 +87,7 @@ pub fn futex<'tcx>( let duration = match this.read_timespec(&timeout)? { Some(duration) => duration, None => { - let einval = this.eval_libc("EINVAL"); - this.set_last_error(einval)?; + this.set_last_error(LibcError("EINVAL"))?; this.write_scalar(Scalar::from_target_isize(-1, this), dest)?; return Ok(()); } @@ -198,8 +196,7 @@ pub fn futex<'tcx>( u32::MAX }; if bitset == 0 { - let einval = this.eval_libc("EINVAL"); - this.set_last_error(einval)?; + this.set_last_error(LibcError("EINVAL"))?; this.write_scalar(Scalar::from_target_isize(-1, this), dest)?; return Ok(()); } diff --git a/src/tools/miri/src/shims/windows/env.rs b/src/tools/miri/src/shims/windows/env.rs index 9707482b1e2..cf99ac758c6 100644 --- a/src/tools/miri/src/shims/windows/env.rs +++ b/src/tools/miri/src/shims/windows/env.rs @@ -150,7 +150,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("`GetCurrentDirectoryW`", reject_with)?; - this.set_last_error_from_io_error(ErrorKind::PermissionDenied.into())?; + this.set_last_error(ErrorKind::PermissionDenied)?; return Ok(Scalar::from_u32(0)); } @@ -163,7 +163,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_path_to_wide_str(&cwd, buf, size)?, ))); } - Err(e) => this.set_last_error_from_io_error(e)?, + Err(e) => this.set_last_error(e)?, } Ok(Scalar::from_u32(0)) } @@ -182,7 +182,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("`SetCurrentDirectoryW`", reject_with)?; - this.set_last_error_from_io_error(ErrorKind::PermissionDenied.into())?; + this.set_last_error(ErrorKind::PermissionDenied)?; return Ok(this.eval_windows("c", "FALSE")); } @@ -190,7 +190,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { match env::set_current_dir(path) { Ok(()) => Ok(this.eval_windows("c", "TRUE")), Err(e) => { - this.set_last_error_from_io_error(e)?; + this.set_last_error(e)?; Ok(this.eval_windows("c", "FALSE")) } } diff --git a/src/tools/miri/src/shims/windows/foreign_items.rs b/src/tools/miri/src/shims/windows/foreign_items.rs index 22634c509be..c51726b05dc 100644 --- a/src/tools/miri/src/shims/windows/foreign_items.rs +++ b/src/tools/miri/src/shims/windows/foreign_items.rs @@ -227,7 +227,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let filename = this.read_path_from_wide_str(filename)?; let result = match win_absolute(&filename)? { Err(err) => { - this.set_last_error_from_io_error(err)?; + this.set_last_error(err)?; Scalar::from_u32(0) // return zero upon failure } Ok(abs_filename) => { From 4f4e1d42b59e96141745ace47ed7a7c96211bf33 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 1 Oct 2024 09:08:10 +0200 Subject: [PATCH 446/683] add set_last_error_and_return_i32 helper and use it in a few places --- src/tools/miri/src/shims/io_error.rs | 34 ++++++++++++++++++---------- src/tools/miri/src/shims/unix/env.rs | 10 +++----- src/tools/miri/src/shims/unix/fd.rs | 11 +++------ 3 files changed, 28 insertions(+), 27 deletions(-) diff --git a/src/tools/miri/src/shims/io_error.rs b/src/tools/miri/src/shims/io_error.rs index 61b943b599d..aa13c405145 100644 --- a/src/tools/miri/src/shims/io_error.rs +++ b/src/tools/miri/src/shims/io_error.rs @@ -119,6 +119,28 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_scalar(errno, &errno_place) } + /// Sets the last OS error and writes -1 to dest place. + fn set_last_error_and_return( + &mut self, + err: impl Into, + dest: &MPlaceTy<'tcx>, + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + this.set_last_error(err)?; + this.write_int(-1, dest)?; + Ok(()) + } + + /// Sets the last OS error and return `-1` as a `i32`-typed Scalar + fn set_last_error_and_return_i32( + &mut self, + err: impl Into, + ) -> InterpResult<'tcx, Scalar> { + let this = self.eval_context_mut(); + this.set_last_error(err)?; + Ok(Scalar::from_i32(-1)) + } + /// Gets the last error variable. fn get_last_error(&mut self) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); @@ -185,18 +207,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } } - /// Sets the last OS error using a `std::io::ErrorKind` and writes -1 to dest place. - fn set_last_error_and_return( - &mut self, - err: impl Into, - dest: &MPlaceTy<'tcx>, - ) -> InterpResult<'tcx> { - let this = self.eval_context_mut(); - this.set_last_error(err)?; - this.write_int(-1, dest)?; - Ok(()) - } - /// Helper function that consumes an `std::io::Result` and returns an /// `InterpResult<'tcx,T>::Ok` instead. In case the result is an error, this function returns /// `Ok(-1)` and sets the last OS error accordingly. diff --git a/src/tools/miri/src/shims/unix/env.rs b/src/tools/miri/src/shims/unix/env.rs index 923de15d2da..4a9e2313aad 100644 --- a/src/tools/miri/src/shims/unix/env.rs +++ b/src/tools/miri/src/shims/unix/env.rs @@ -177,8 +177,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { Ok(Scalar::from_i32(0)) // return zero on success } else { // name argument is a null pointer, points to an empty string, or points to a string containing an '=' character. - this.set_last_error(LibcError("EINVAL"))?; - Ok(Scalar::from_i32(-1)) + this.set_last_error_and_return_i32(LibcError("EINVAL")) } } @@ -202,8 +201,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { Ok(Scalar::from_i32(0)) } else { // name argument is a null pointer, points to an empty string, or points to a string containing an '=' character. - this.set_last_error(LibcError("EINVAL"))?; - Ok(Scalar::from_i32(-1)) + this.set_last_error_and_return_i32(LibcError("EINVAL")) } } @@ -242,9 +240,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("`chdir`", reject_with)?; - this.set_last_error(ErrorKind::PermissionDenied)?; - - return Ok(Scalar::from_i32(-1)); + return this.set_last_error_and_return_i32(ErrorKind::PermissionDenied); } let result = env::set_current_dir(path).map(|()| 0); diff --git a/src/tools/miri/src/shims/unix/fd.rs b/src/tools/miri/src/shims/unix/fd.rs index fe634de122c..41a819fb31f 100644 --- a/src/tools/miri/src/shims/unix/fd.rs +++ b/src/tools/miri/src/shims/unix/fd.rs @@ -524,8 +524,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Reject if isolation is enabled. if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("`fcntl`", reject_with)?; - this.set_last_error(ErrorKind::PermissionDenied)?; - return Ok(Scalar::from_i32(-1)); + return this.set_last_error_and_return_i32(ErrorKind::PermissionDenied); } this.ffullsync_fd(fd_num) @@ -606,9 +605,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { None => fd.read(&fd, communicate, buf, count, dest, this)?, Some(offset) => { let Ok(offset) = u64::try_from(offset) else { - this.set_last_error(LibcError("EINVAL"))?; - this.write_int(-1, dest)?; - return Ok(()); + return this.set_last_error_and_return(LibcError("EINVAL"), dest); }; fd.pread(communicate, offset, buf, count, dest, this)? } @@ -650,9 +647,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { None => fd.write(&fd, communicate, buf, count, dest, this)?, Some(offset) => { let Ok(offset) = u64::try_from(offset) else { - this.set_last_error(LibcError("EINVAL"))?; - this.write_int(-1, dest)?; - return Ok(()); + return this.set_last_error_and_return(LibcError("EINVAL"), dest); }; fd.pwrite(communicate, buf, count, offset, dest, this)? } From c7cd55f7c5032c646db22f144dda2f04d8ee6009 Mon Sep 17 00:00:00 2001 From: Eric Holk Date: Wed, 4 Sep 2024 17:15:13 -0700 Subject: [PATCH 447/683] Stabilize expr_2021 fragment in all editions Co-authored-by: Michael Goulet Co-authored-by: Vincenzo Palazzo --- compiler/rustc_expand/src/mbe/macro_check.rs | 4 +- compiler/rustc_expand/src/mbe/quoted.rs | 38 ++----------------- compiler/rustc_feature/src/accepted.rs | 2 + compiler/rustc_feature/src/unstable.rs | 2 - .../unused-macro-with-bad-frag-spec.stderr | 2 +- tests/ui/macros/expr_2021.rs | 14 +++++++ .../macros/expr_2021_cargo_fix_edition.fixed | 2 - .../ui/macros/expr_2021_cargo_fix_edition.rs | 2 - .../macros/expr_2021_cargo_fix_edition.stderr | 6 +-- .../expr_2021_inline_const.edi2021.stderr | 8 ++-- .../expr_2021_inline_const.edi2024.stderr | 4 +- tests/ui/macros/expr_2021_inline_const.rs | 3 -- .../expr_2024_underscore_expr.edi2021.stderr | 8 ++-- .../expr_2024_underscore_expr.edi2024.stderr | 4 +- tests/ui/macros/expr_2024_underscore_expr.rs | 3 -- ...ature-gate-expr_fragment_specifier_2024.rs | 11 ------ ...e-gate-expr_fragment_specifier_2024.stderr | 13 ------- .../macros/invalid-fragment-specifier.stderr | 4 +- tests/ui/macros/issue-21356.stderr | 2 +- .../macro-missing-fragment.e2024.stderr | 6 +-- .../metavar_cross_edition_recursive_macros.rs | 1 - 21 files changed, 44 insertions(+), 95 deletions(-) create mode 100644 tests/ui/macros/expr_2021.rs delete mode 100644 tests/ui/macros/feature-gate-expr_fragment_specifier_2024.rs delete mode 100644 tests/ui/macros/feature-gate-expr_fragment_specifier_2024.stderr diff --git a/compiler/rustc_expand/src/mbe/macro_check.rs b/compiler/rustc_expand/src/mbe/macro_check.rs index b1d898b6949..1498b9cbd5d 100644 --- a/compiler/rustc_expand/src/mbe/macro_check.rs +++ b/compiler/rustc_expand/src/mbe/macro_check.rs @@ -119,7 +119,7 @@ use rustc_span::symbol::{MacroRulesNormalizedIdent, kw}; use rustc_span::{ErrorGuaranteed, Span}; use smallvec::SmallVec; -use super::quoted::VALID_FRAGMENT_NAMES_MSG_2021; +use super::quoted::VALID_FRAGMENT_NAMES_MSG; use crate::errors; use crate::mbe::{KleeneToken, TokenTree}; @@ -274,7 +274,7 @@ fn check_binders( psess.dcx().emit_err(errors::MissingFragmentSpecifier { span, add_span: span.shrink_to_hi(), - valid: VALID_FRAGMENT_NAMES_MSG_2021, + valid: VALID_FRAGMENT_NAMES_MSG, }); } else { psess.buffer_lint( diff --git a/compiler/rustc_expand/src/mbe/quoted.rs b/compiler/rustc_expand/src/mbe/quoted.rs index f0a6c841f31..2edd289625e 100644 --- a/compiler/rustc_expand/src/mbe/quoted.rs +++ b/compiler/rustc_expand/src/mbe/quoted.rs @@ -1,4 +1,3 @@ -use rustc_ast::token::NtExprKind::*; use rustc_ast::token::{self, Delimiter, IdentIsRaw, NonterminalKind, Token}; use rustc_ast::{NodeId, tokenstream}; use rustc_ast_pretty::pprust; @@ -13,12 +12,9 @@ use crate::errors; use crate::mbe::macro_parser::count_metavar_decls; use crate::mbe::{Delimited, KleeneOp, KleeneToken, MetaVarExpr, SequenceRepetition, TokenTree}; -const VALID_FRAGMENT_NAMES_MSG: &str = "valid fragment specifiers are \ - `ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, `literal`, `path`, `meta`, `tt`, \ - `item` and `vis`"; -pub(crate) const VALID_FRAGMENT_NAMES_MSG_2021: &str = "valid fragment specifiers are \ - `ident`, `block`, `stmt`, `expr`, `expr_2021`, `pat`, `ty`, `lifetime`, `literal`, `path`, \ - `meta`, `tt`, `item` and `vis`"; +pub(crate) const VALID_FRAGMENT_NAMES_MSG: &str = "valid fragment specifiers are \ + `ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, `literal`, `path`, \ + `meta`, `tt`, `item` and `vis`, along with `expr_2021` and `pat_param` for edition compatibility"; /// Takes a `tokenstream::TokenStream` and returns a `Vec`. Specifically, this /// takes a generic `TokenStream`, such as is used in the rest of the compiler, and returns a @@ -92,39 +88,13 @@ pub(super) fn parse( }; let kind = NonterminalKind::from_symbol(fragment.name, edition) .unwrap_or_else(|| { - let help = match fragment.name { - sym::expr_2021 => { - format!( - "fragment specifier `expr_2021` \ - requires Rust 2021 or later\n\ - {VALID_FRAGMENT_NAMES_MSG}" - ) - } - _ if edition().at_least_rust_2021() - && features.expr_fragment_specifier_2024 => - { - VALID_FRAGMENT_NAMES_MSG_2021.into() - } - _ => VALID_FRAGMENT_NAMES_MSG.into(), - }; sess.dcx().emit_err(errors::InvalidFragmentSpecifier { span, fragment, - help, + help: VALID_FRAGMENT_NAMES_MSG.into(), }); NonterminalKind::Ident }); - if kind == NonterminalKind::Expr(Expr2021 { inferred: false }) - && !features.expr_fragment_specifier_2024 - { - rustc_session::parse::feature_err( - sess, - sym::expr_fragment_specifier_2024, - span, - "fragment specifier `expr_2021` is unstable", - ) - .emit(); - } result.push(TokenTree::MetaVarDecl(span, ident, Some(kind))); continue; } diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs index 5ff002dd7d2..a850eb95620 100644 --- a/compiler/rustc_feature/src/accepted.rs +++ b/compiler/rustc_feature/src/accepted.rs @@ -189,6 +189,8 @@ declare_features! ( (accepted, exhaustive_integer_patterns, "1.33.0", Some(50907)), /// Allows explicit generic arguments specification with `impl Trait` present. (accepted, explicit_generic_args_with_impl_trait, "1.63.0", Some(83701)), + /// Uses 2024 rules for matching `expr` fragments in macros. Also enables `expr_2021` fragment. + (accepted, expr_fragment_specifier_2024, "CURRENT_RUSTC_VERSION", Some(123742)), /// Allows arbitrary expressions in key-value attributes at parse time. (accepted, extended_key_value_attributes, "1.54.0", Some(78835)), /// Allows resolving absolute paths as paths from other crates. diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 1ffd35dbf91..c5530097e96 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -450,8 +450,6 @@ declare_features! ( (unstable, exhaustive_patterns, "1.13.0", Some(51085)), /// Allows explicit tail calls via `become` expression. (incomplete, explicit_tail_calls, "1.72.0", Some(112788)), - /// Uses 2024 rules for matching `expr` fragments in macros. Also enables `expr_2021` fragment. - (incomplete, expr_fragment_specifier_2024, "1.80.0", Some(123742)), /// Allows using `efiapi`, `sysv64` and `win64` as calling convention /// for functions with varargs. (unstable, extended_varargs_abi_support, "1.65.0", Some(100189)), diff --git a/tests/ui/lint/unused/unused-macro-with-bad-frag-spec.stderr b/tests/ui/lint/unused/unused-macro-with-bad-frag-spec.stderr index f027e169b42..003c6975c95 100644 --- a/tests/ui/lint/unused/unused-macro-with-bad-frag-spec.stderr +++ b/tests/ui/lint/unused/unused-macro-with-bad-frag-spec.stderr @@ -4,7 +4,7 @@ error: invalid fragment specifier `t_ty` LL | ($wrong:t_ty) => () | ^^^^^^^^^^^ | - = help: valid fragment specifiers are `ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, `literal`, `path`, `meta`, `tt`, `item` and `vis` + = help: valid fragment specifiers are `ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, `literal`, `path`, `meta`, `tt`, `item` and `vis`, along with `expr_2021` and `pat_param` for edition compatibility error: aborting due to 1 previous error diff --git a/tests/ui/macros/expr_2021.rs b/tests/ui/macros/expr_2021.rs new file mode 100644 index 00000000000..8a274e77533 --- /dev/null +++ b/tests/ui/macros/expr_2021.rs @@ -0,0 +1,14 @@ +//@ check-pass +//@ edition: 2015 + +// Ensures expr_2021 fragment specifier is accepted in old editions + +macro_rules! my_macro { + ($x:expr_2021) => { + println!("Hello, {}!", $x); + }; +} + +fn main() { + my_macro!("world"); +} diff --git a/tests/ui/macros/expr_2021_cargo_fix_edition.fixed b/tests/ui/macros/expr_2021_cargo_fix_edition.fixed index 1becd8a92d6..061a4b98033 100644 --- a/tests/ui/macros/expr_2021_cargo_fix_edition.fixed +++ b/tests/ui/macros/expr_2021_cargo_fix_edition.fixed @@ -1,8 +1,6 @@ //@ run-rustfix //@ check-pass //@ compile-flags: --edition=2021 -#![allow(incomplete_features)] -#![feature(expr_fragment_specifier_2024)] #![warn(edition_2024_expr_fragment_specifier)] macro_rules! m { diff --git a/tests/ui/macros/expr_2021_cargo_fix_edition.rs b/tests/ui/macros/expr_2021_cargo_fix_edition.rs index ec0b86d2c23..cd9cd965fad 100644 --- a/tests/ui/macros/expr_2021_cargo_fix_edition.rs +++ b/tests/ui/macros/expr_2021_cargo_fix_edition.rs @@ -1,8 +1,6 @@ //@ run-rustfix //@ check-pass //@ compile-flags: --edition=2021 -#![allow(incomplete_features)] -#![feature(expr_fragment_specifier_2024)] #![warn(edition_2024_expr_fragment_specifier)] macro_rules! m { diff --git a/tests/ui/macros/expr_2021_cargo_fix_edition.stderr b/tests/ui/macros/expr_2021_cargo_fix_edition.stderr index e8a44fed322..fe1fd4a26a0 100644 --- a/tests/ui/macros/expr_2021_cargo_fix_edition.stderr +++ b/tests/ui/macros/expr_2021_cargo_fix_edition.stderr @@ -1,5 +1,5 @@ warning: the `expr` fragment specifier will accept more expressions in the 2024 edition - --> $DIR/expr_2021_cargo_fix_edition.rs:9:9 + --> $DIR/expr_2021_cargo_fix_edition.rs:7:9 | LL | ($e:expr) => { | ^^^^ @@ -7,7 +7,7 @@ LL | ($e:expr) => { = warning: this changes meaning in Rust 2024 = note: for more information, see Migration Guide note: the lint level is defined here - --> $DIR/expr_2021_cargo_fix_edition.rs:6:9 + --> $DIR/expr_2021_cargo_fix_edition.rs:4:9 | LL | #![warn(edition_2024_expr_fragment_specifier)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -17,7 +17,7 @@ LL | ($e:expr_2021) => { | ~~~~~~~~~ warning: the `expr` fragment specifier will accept more expressions in the 2024 edition - --> $DIR/expr_2021_cargo_fix_edition.rs:13:11 + --> $DIR/expr_2021_cargo_fix_edition.rs:11:11 | LL | ($($i:expr)*) => { }; | ^^^^ diff --git a/tests/ui/macros/expr_2021_inline_const.edi2021.stderr b/tests/ui/macros/expr_2021_inline_const.edi2021.stderr index b55ae62030c..22d662aaaf2 100644 --- a/tests/ui/macros/expr_2021_inline_const.edi2021.stderr +++ b/tests/ui/macros/expr_2021_inline_const.edi2021.stderr @@ -1,5 +1,5 @@ error: no rules expected the token `const` - --> $DIR/expr_2021_inline_const.rs:26:12 + --> $DIR/expr_2021_inline_const.rs:23:12 | LL | macro_rules! m2021 { | ------------------ when calling this macro @@ -8,13 +8,13 @@ LL | m2021!(const { 1 }); | ^^^^^ no rules expected this token in macro call | note: while trying to match meta-variable `$e:expr_2021` - --> $DIR/expr_2021_inline_const.rs:10:6 + --> $DIR/expr_2021_inline_const.rs:7:6 | LL | ($e:expr_2021) => { | ^^^^^^^^^^^^ error: no rules expected the token `const` - --> $DIR/expr_2021_inline_const.rs:27:12 + --> $DIR/expr_2021_inline_const.rs:24:12 | LL | macro_rules! m2024 { | ------------------ when calling this macro @@ -23,7 +23,7 @@ LL | m2024!(const { 1 }); | ^^^^^ no rules expected this token in macro call | note: while trying to match meta-variable `$e:expr` - --> $DIR/expr_2021_inline_const.rs:16:6 + --> $DIR/expr_2021_inline_const.rs:13:6 | LL | ($e:expr) => { | ^^^^^^^ diff --git a/tests/ui/macros/expr_2021_inline_const.edi2024.stderr b/tests/ui/macros/expr_2021_inline_const.edi2024.stderr index 285db53d6c8..2555e4f757a 100644 --- a/tests/ui/macros/expr_2021_inline_const.edi2024.stderr +++ b/tests/ui/macros/expr_2021_inline_const.edi2024.stderr @@ -1,5 +1,5 @@ error: no rules expected the token `const` - --> $DIR/expr_2021_inline_const.rs:26:12 + --> $DIR/expr_2021_inline_const.rs:23:12 | LL | macro_rules! m2021 { | ------------------ when calling this macro @@ -8,7 +8,7 @@ LL | m2021!(const { 1 }); | ^^^^^ no rules expected this token in macro call | note: while trying to match meta-variable `$e:expr_2021` - --> $DIR/expr_2021_inline_const.rs:10:6 + --> $DIR/expr_2021_inline_const.rs:7:6 | LL | ($e:expr_2021) => { | ^^^^^^^^^^^^ diff --git a/tests/ui/macros/expr_2021_inline_const.rs b/tests/ui/macros/expr_2021_inline_const.rs index 06b74a466d6..39a542fe4d9 100644 --- a/tests/ui/macros/expr_2021_inline_const.rs +++ b/tests/ui/macros/expr_2021_inline_const.rs @@ -3,9 +3,6 @@ //@[edi2021]compile-flags: --edition=2021 // This test ensures that the inline const match only on edition 2024 -#![feature(expr_fragment_specifier_2024)] -#![allow(incomplete_features)] - macro_rules! m2021 { ($e:expr_2021) => { $e diff --git a/tests/ui/macros/expr_2024_underscore_expr.edi2021.stderr b/tests/ui/macros/expr_2024_underscore_expr.edi2021.stderr index 335b3f61343..34df20a69ef 100644 --- a/tests/ui/macros/expr_2024_underscore_expr.edi2021.stderr +++ b/tests/ui/macros/expr_2024_underscore_expr.edi2021.stderr @@ -1,5 +1,5 @@ error: no rules expected the token `_` - --> $DIR/expr_2024_underscore_expr.rs:22:12 + --> $DIR/expr_2024_underscore_expr.rs:19:12 | LL | macro_rules! m2021 { | ------------------ when calling this macro @@ -8,13 +8,13 @@ LL | m2021!(_); | ^ no rules expected this token in macro call | note: while trying to match meta-variable `$e:expr_2021` - --> $DIR/expr_2024_underscore_expr.rs:10:6 + --> $DIR/expr_2024_underscore_expr.rs:7:6 | LL | ($e:expr_2021) => { | ^^^^^^^^^^^^ error: no rules expected the token `_` - --> $DIR/expr_2024_underscore_expr.rs:23:12 + --> $DIR/expr_2024_underscore_expr.rs:20:12 | LL | macro_rules! m2024 { | ------------------ when calling this macro @@ -23,7 +23,7 @@ LL | m2024!(_); | ^ no rules expected this token in macro call | note: while trying to match meta-variable `$e:expr` - --> $DIR/expr_2024_underscore_expr.rs:16:6 + --> $DIR/expr_2024_underscore_expr.rs:13:6 | LL | ($e:expr) => { | ^^^^^^^ diff --git a/tests/ui/macros/expr_2024_underscore_expr.edi2024.stderr b/tests/ui/macros/expr_2024_underscore_expr.edi2024.stderr index 9e49f66a89a..372c5d8637c 100644 --- a/tests/ui/macros/expr_2024_underscore_expr.edi2024.stderr +++ b/tests/ui/macros/expr_2024_underscore_expr.edi2024.stderr @@ -1,5 +1,5 @@ error: no rules expected the token `_` - --> $DIR/expr_2024_underscore_expr.rs:22:12 + --> $DIR/expr_2024_underscore_expr.rs:19:12 | LL | macro_rules! m2021 { | ------------------ when calling this macro @@ -8,7 +8,7 @@ LL | m2021!(_); | ^ no rules expected this token in macro call | note: while trying to match meta-variable `$e:expr_2021` - --> $DIR/expr_2024_underscore_expr.rs:10:6 + --> $DIR/expr_2024_underscore_expr.rs:7:6 | LL | ($e:expr_2021) => { | ^^^^^^^^^^^^ diff --git a/tests/ui/macros/expr_2024_underscore_expr.rs b/tests/ui/macros/expr_2024_underscore_expr.rs index b2129bf154f..86e31374506 100644 --- a/tests/ui/macros/expr_2024_underscore_expr.rs +++ b/tests/ui/macros/expr_2024_underscore_expr.rs @@ -3,9 +3,6 @@ //@[edi2021]compile-flags: --edition=2021 // This test ensures that the `_` tok is considered an // expression on edition 2024. -#![feature(expr_fragment_specifier_2024)] -#![allow(incomplete_features)] - macro_rules! m2021 { ($e:expr_2021) => { $e = 1; diff --git a/tests/ui/macros/feature-gate-expr_fragment_specifier_2024.rs b/tests/ui/macros/feature-gate-expr_fragment_specifier_2024.rs deleted file mode 100644 index 5a737b29821..00000000000 --- a/tests/ui/macros/feature-gate-expr_fragment_specifier_2024.rs +++ /dev/null @@ -1,11 +0,0 @@ -//@ compile-flags: --edition=2024 -Z unstable-options - -macro_rules! m { - ($e:expr_2021) => { //~ ERROR: fragment specifier `expr_2021` is unstable - $e - }; -} - -fn main() { - m!(()); -} diff --git a/tests/ui/macros/feature-gate-expr_fragment_specifier_2024.stderr b/tests/ui/macros/feature-gate-expr_fragment_specifier_2024.stderr deleted file mode 100644 index 273a93877ce..00000000000 --- a/tests/ui/macros/feature-gate-expr_fragment_specifier_2024.stderr +++ /dev/null @@ -1,13 +0,0 @@ -error[E0658]: fragment specifier `expr_2021` is unstable - --> $DIR/feature-gate-expr_fragment_specifier_2024.rs:4:6 - | -LL | ($e:expr_2021) => { - | ^^^^^^^^^^^^ - | - = note: see issue #123742 for more information - = help: add `#![feature(expr_fragment_specifier_2024)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/macros/invalid-fragment-specifier.stderr b/tests/ui/macros/invalid-fragment-specifier.stderr index 7516dbc3a08..a51ea619b36 100644 --- a/tests/ui/macros/invalid-fragment-specifier.stderr +++ b/tests/ui/macros/invalid-fragment-specifier.stderr @@ -4,7 +4,7 @@ error: invalid fragment specifier `id` LL | ($wrong:id) => {}; | ^^^^^^^^^ | - = help: valid fragment specifiers are `ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, `literal`, `path`, `meta`, `tt`, `item` and `vis` + = help: valid fragment specifiers are `ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, `literal`, `path`, `meta`, `tt`, `item` and `vis`, along with `expr_2021` and `pat_param` for edition compatibility error: invalid fragment specifier `r#if` --> $DIR/invalid-fragment-specifier.rs:7:6 @@ -12,7 +12,7 @@ error: invalid fragment specifier `r#if` LL | ($wrong:r#if) => {}; | ^^^^^^^^^^^ | - = help: valid fragment specifiers are `ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, `literal`, `path`, `meta`, `tt`, `item` and `vis` + = help: valid fragment specifiers are `ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, `literal`, `path`, `meta`, `tt`, `item` and `vis`, along with `expr_2021` and `pat_param` for edition compatibility error: aborting due to 2 previous errors diff --git a/tests/ui/macros/issue-21356.stderr b/tests/ui/macros/issue-21356.stderr index dd09da6df4f..5ff92642514 100644 --- a/tests/ui/macros/issue-21356.stderr +++ b/tests/ui/macros/issue-21356.stderr @@ -4,7 +4,7 @@ error: invalid fragment specifier `t_ty` LL | macro_rules! test { ($wrong:t_ty ..) => () } | ^^^^^^^^^^^ | - = help: valid fragment specifiers are `ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, `literal`, `path`, `meta`, `tt`, `item` and `vis` + = help: valid fragment specifiers are `ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, `literal`, `path`, `meta`, `tt`, `item` and `vis`, along with `expr_2021` and `pat_param` for edition compatibility error: aborting due to 1 previous error diff --git a/tests/ui/macros/macro-missing-fragment.e2024.stderr b/tests/ui/macros/macro-missing-fragment.e2024.stderr index 3afa069c170..0dc48e0c7b2 100644 --- a/tests/ui/macros/macro-missing-fragment.e2024.stderr +++ b/tests/ui/macros/macro-missing-fragment.e2024.stderr @@ -5,7 +5,7 @@ LL | ( $( any_token $field_rust_type )* ) => {}; | ^^^^^^^^^^^^^^^^ | = note: fragment specifiers must be specified in the 2024 edition - = help: valid fragment specifiers are `ident`, `block`, `stmt`, `expr`, `expr_2021`, `pat`, `ty`, `lifetime`, `literal`, `path`, `meta`, `tt`, `item` and `vis` + = help: valid fragment specifiers are `ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, `literal`, `path`, `meta`, `tt`, `item` and `vis`, along with `expr_2021` and `pat_param` for edition compatibility help: try adding a specifier here | LL | ( $( any_token $field_rust_type:spec )* ) => {}; @@ -18,7 +18,7 @@ LL | ( $name ) => {}; | ^^^^^ | = note: fragment specifiers must be specified in the 2024 edition - = help: valid fragment specifiers are `ident`, `block`, `stmt`, `expr`, `expr_2021`, `pat`, `ty`, `lifetime`, `literal`, `path`, `meta`, `tt`, `item` and `vis` + = help: valid fragment specifiers are `ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, `literal`, `path`, `meta`, `tt`, `item` and `vis`, along with `expr_2021` and `pat_param` for edition compatibility help: try adding a specifier here | LL | ( $name:spec ) => {}; @@ -31,7 +31,7 @@ LL | ( $name ) => {}; | ^^^^^ | = note: fragment specifiers must be specified in the 2024 edition - = help: valid fragment specifiers are `ident`, `block`, `stmt`, `expr`, `expr_2021`, `pat`, `ty`, `lifetime`, `literal`, `path`, `meta`, `tt`, `item` and `vis` + = help: valid fragment specifiers are `ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, `literal`, `path`, `meta`, `tt`, `item` and `vis`, along with `expr_2021` and `pat_param` for edition compatibility help: try adding a specifier here | LL | ( $name:spec ) => {}; diff --git a/tests/ui/macros/metavar_cross_edition_recursive_macros.rs b/tests/ui/macros/metavar_cross_edition_recursive_macros.rs index 3eec1208b89..9a5b92f5032 100644 --- a/tests/ui/macros/metavar_cross_edition_recursive_macros.rs +++ b/tests/ui/macros/metavar_cross_edition_recursive_macros.rs @@ -6,7 +6,6 @@ // This test captures the behavior of macro-generating-macros with fragment // specifiers across edition boundaries. -#![feature(expr_fragment_specifier_2024)] #![feature(macro_metavar_expr)] #![allow(incomplete_features)] From 57b9b1f9745a56943cc0aebc4c3ec487945f044e Mon Sep 17 00:00:00 2001 From: Urgau Date: Wed, 18 Sep 2024 17:44:32 +0200 Subject: [PATCH 448/683] Use `ast::NestedMetaItem` when evaluating cfg predicate --- compiler/rustc_attr/src/builtin.rs | 35 +++++++++++++------ compiler/rustc_builtin_macros/src/cfg.rs | 9 +++-- compiler/rustc_codegen_ssa/src/lib.rs | 2 +- compiler/rustc_expand/src/config.rs | 12 ++++--- compiler/rustc_metadata/src/native_libs.rs | 9 +++-- compiler/rustc_parse/src/lib.rs | 4 +-- compiler/rustc_parse/src/parser/attr.rs | 8 +++-- compiler/rustc_session/src/cstore.rs | 2 +- .../traits/on_unimplemented.rs | 12 +++---- tests/ui/macros/cfg.rs | 2 +- tests/ui/macros/cfg.stderr | 4 +-- 11 files changed, 62 insertions(+), 37 deletions(-) diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs index 762ebc47ca9..37f70c21869 100644 --- a/compiler/rustc_attr/src/builtin.rs +++ b/compiler/rustc_attr/src/builtin.rs @@ -523,7 +523,7 @@ pub struct Condition { /// Tests if a cfg-pattern matches the cfg set pub fn cfg_matches( - cfg: &ast::MetaItem, + cfg: &ast::NestedMetaItem, sess: &Session, lint_node_id: NodeId, features: Option<&Features>, @@ -594,12 +594,26 @@ pub fn parse_version(s: Symbol) -> Option { /// Evaluate a cfg-like condition (with `any` and `all`), using `eval` to /// evaluate individual items. pub fn eval_condition( - cfg: &ast::MetaItem, + cfg: &ast::NestedMetaItem, sess: &Session, features: Option<&Features>, eval: &mut impl FnMut(Condition) -> bool, ) -> bool { let dcx = sess.dcx(); + + let cfg = match cfg { + ast::NestedMetaItem::MetaItem(meta_item) => meta_item, + _ => { + dcx.emit_err(session_diagnostics::UnsupportedLiteral { + span: cfg.span(), + reason: UnsupportedLiteralReason::Generic, + is_bytestr: false, + start_point_span: sess.source_map().start_point(cfg.span()), + }); + return false; + } + }; + match &cfg.kind { ast::MetaItemKind::List(mis) if cfg.name_or_empty() == sym::version => { try_gate_cfg(sym::version, cfg.span, sess, features); @@ -653,23 +667,19 @@ pub fn eval_condition( .iter() // We don't use any() here, because we want to evaluate all cfg condition // as eval_condition can (and does) extra checks - .fold(false, |res, mi| { - res | eval_condition(mi.meta_item().unwrap(), sess, features, eval) - }), + .fold(false, |res, mi| res | eval_condition(mi, sess, features, eval)), sym::all => mis .iter() // We don't use all() here, because we want to evaluate all cfg condition // as eval_condition can (and does) extra checks - .fold(true, |res, mi| { - res & eval_condition(mi.meta_item().unwrap(), sess, features, eval) - }), + .fold(true, |res, mi| res & eval_condition(mi, sess, features, eval)), sym::not => { let [mi] = mis.as_slice() else { dcx.emit_err(session_diagnostics::ExpectedOneCfgPattern { span: cfg.span }); return false; }; - !eval_condition(mi.meta_item().unwrap(), sess, features, eval) + !eval_condition(mi, sess, features, eval) } sym::target => { if let Some(features) = features @@ -690,7 +700,12 @@ pub fn eval_condition( seg.ident.name = Symbol::intern(&format!("target_{}", seg.ident.name)); } - res & eval_condition(&mi, sess, features, eval) + res & eval_condition( + &ast::NestedMetaItem::MetaItem(mi), + sess, + features, + eval, + ) }) } _ => { diff --git a/compiler/rustc_builtin_macros/src/cfg.rs b/compiler/rustc_builtin_macros/src/cfg.rs index cf1d5c68ead..940c94b1cfc 100644 --- a/compiler/rustc_builtin_macros/src/cfg.rs +++ b/compiler/rustc_builtin_macros/src/cfg.rs @@ -6,7 +6,6 @@ use rustc_ast::token; use rustc_ast::tokenstream::TokenStream; use rustc_errors::PResult; use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacEager, MacroExpanderResult}; -use rustc_parse::parser::attr::AllowLeadingUnsafe; use rustc_span::Span; use {rustc_ast as ast, rustc_attr as attr}; @@ -36,14 +35,18 @@ pub(crate) fn expand_cfg( }) } -fn parse_cfg<'a>(cx: &ExtCtxt<'a>, span: Span, tts: TokenStream) -> PResult<'a, ast::MetaItem> { +fn parse_cfg<'a>( + cx: &ExtCtxt<'a>, + span: Span, + tts: TokenStream, +) -> PResult<'a, ast::NestedMetaItem> { let mut p = cx.new_parser_from_tts(tts); if p.token == token::Eof { return Err(cx.dcx().create_err(errors::RequiresCfgPattern { span })); } - let cfg = p.parse_meta_item(AllowLeadingUnsafe::No)?; + let cfg = p.parse_meta_item_inner()?; let _ = p.eat(&token::Comma); diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs index 162d14272a5..3129b9ac203 100644 --- a/compiler/rustc_codegen_ssa/src/lib.rs +++ b/compiler/rustc_codegen_ssa/src/lib.rs @@ -156,7 +156,7 @@ pub struct NativeLib { pub kind: NativeLibKind, pub name: Symbol, pub filename: Option, - pub cfg: Option, + pub cfg: Option, pub verbatim: bool, pub dll_imports: Vec, } diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs index 32088374277..8ea4f901368 100644 --- a/compiler/rustc_expand/src/config.rs +++ b/compiler/rustc_expand/src/config.rs @@ -5,7 +5,9 @@ use rustc_ast::token::{Delimiter, Token, TokenKind}; use rustc_ast::tokenstream::{ AttrTokenStream, AttrTokenTree, LazyAttrTokenStream, Spacing, TokenTree, }; -use rustc_ast::{self as ast, AttrStyle, Attribute, HasAttrs, HasTokens, MetaItem, NodeId}; +use rustc_ast::{ + self as ast, AttrStyle, Attribute, HasAttrs, HasTokens, MetaItem, NestedMetaItem, NodeId, +}; use rustc_attr as attr; use rustc_data_structures::flat_map_in_place::FlatMapInPlace; use rustc_feature::{ @@ -449,7 +451,7 @@ impl<'a> StripUnconfigured<'a> { } } -pub fn parse_cfg<'a>(meta_item: &'a MetaItem, sess: &Session) -> Option<&'a MetaItem> { +pub fn parse_cfg<'a>(meta_item: &'a MetaItem, sess: &Session) -> Option<&'a NestedMetaItem> { let span = meta_item.span; match meta_item.meta_item_list() { None => { @@ -464,9 +466,9 @@ pub fn parse_cfg<'a>(meta_item: &'a MetaItem, sess: &Session) -> Option<&'a Meta sess.dcx().emit_err(InvalidCfg::MultiplePredicates { span: l.span() }); None } - Some([single]) => match single.meta_item() { - Some(meta_item) => Some(meta_item), - None => { + Some([single]) => match single.is_meta_item() { + true => Some(single), + false => { sess.dcx().emit_err(InvalidCfg::PredicateLiteral { span: single.span() }); None } diff --git a/compiler/rustc_metadata/src/native_libs.rs b/compiler/rustc_metadata/src/native_libs.rs index 82b907d2501..373b109189e 100644 --- a/compiler/rustc_metadata/src/native_libs.rs +++ b/compiler/rustc_metadata/src/native_libs.rs @@ -1,7 +1,7 @@ use std::ops::ControlFlow; use std::path::{Path, PathBuf}; -use rustc_ast::{CRATE_NODE_ID, NestedMetaItem}; +use rustc_ast::CRATE_NODE_ID; use rustc_attr as attr; use rustc_data_structures::fx::FxHashSet; use rustc_middle::query::LocalCrate; @@ -304,7 +304,12 @@ impl<'tcx> Collector<'tcx> { sess.dcx().emit_err(errors::LinkCfgForm { span: item.span() }); continue; }; - let [NestedMetaItem::MetaItem(link_cfg)] = link_cfg else { + let [link_cfg] = link_cfg else { + sess.dcx() + .emit_err(errors::LinkCfgSinglePredicate { span: item.span() }); + continue; + }; + if !link_cfg.is_meta_item() { sess.dcx() .emit_err(errors::LinkCfgSinglePredicate { span: item.span() }); continue; diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs index f7a8b8780ed..da02f98d0e5 100644 --- a/compiler/rustc_parse/src/lib.rs +++ b/compiler/rustc_parse/src/lib.rs @@ -18,7 +18,7 @@ use std::path::Path; use rustc_ast as ast; use rustc_ast::tokenstream::TokenStream; -use rustc_ast::{AttrItem, Attribute, MetaItem, token}; +use rustc_ast::{AttrItem, Attribute, NestedMetaItem, token}; use rustc_ast_pretty::pprust; use rustc_data_structures::sync::Lrc; use rustc_errors::{Diag, FatalError, PResult}; @@ -160,7 +160,7 @@ pub fn fake_token_stream_for_crate(psess: &ParseSess, krate: &ast::Crate) -> Tok pub fn parse_cfg_attr( cfg_attr: &Attribute, psess: &ParseSess, -) -> Option<(MetaItem, Vec<(AttrItem, Span)>)> { +) -> Option<(NestedMetaItem, Vec<(AttrItem, Span)>)> { const CFG_ATTR_GRAMMAR_HELP: &str = "#[cfg_attr(condition, attribute, other_attribute, ...)]"; const CFG_ATTR_NOTE_REF: &str = "for more information, visit \ "; diff --git a/compiler/rustc_parse/src/parser/attr.rs b/compiler/rustc_parse/src/parser/attr.rs index c65cf3f40f6..4aa56cb7624 100644 --- a/compiler/rustc_parse/src/parser/attr.rs +++ b/compiler/rustc_parse/src/parser/attr.rs @@ -356,8 +356,10 @@ impl<'a> Parser<'a> { } /// Parses `cfg_attr(pred, attr_item_list)` where `attr_item_list` is comma-delimited. - pub fn parse_cfg_attr(&mut self) -> PResult<'a, (ast::MetaItem, Vec<(ast::AttrItem, Span)>)> { - let cfg_predicate = self.parse_meta_item(AllowLeadingUnsafe::No)?; + pub fn parse_cfg_attr( + &mut self, + ) -> PResult<'a, (ast::NestedMetaItem, Vec<(ast::AttrItem, Span)>)> { + let cfg_predicate = self.parse_meta_item_inner()?; self.expect(&token::Comma)?; // Presumably, the majority of the time there will only be one attr. @@ -452,7 +454,7 @@ impl<'a> Parser<'a> { /// ```ebnf /// MetaItemInner = UNSUFFIXED_LIT | MetaItem ; /// ``` - fn parse_meta_item_inner(&mut self) -> PResult<'a, ast::NestedMetaItem> { + pub fn parse_meta_item_inner(&mut self) -> PResult<'a, ast::NestedMetaItem> { match self.parse_unsuffixed_meta_item_lit() { Ok(lit) => return Ok(ast::NestedMetaItem::Lit(lit)), Err(err) => err.cancel(), // we provide a better error below diff --git a/compiler/rustc_session/src/cstore.rs b/compiler/rustc_session/src/cstore.rs index 66ad70d8d18..b936a299b09 100644 --- a/compiler/rustc_session/src/cstore.rs +++ b/compiler/rustc_session/src/cstore.rs @@ -72,7 +72,7 @@ pub struct NativeLib { pub name: Symbol, /// If packed_bundled_libs enabled, actual filename of library is stored. pub filename: Option, - pub cfg: Option, + pub cfg: Option, pub foreign_module: Option, pub verbatim: Option, pub dll_imports: Vec, diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs index 2c7ca50f954..f2efc5ee47d 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs @@ -1,7 +1,7 @@ use std::iter; use std::path::PathBuf; -use rustc_ast::{AttrArgs, AttrArgsEq, AttrKind, Attribute, MetaItem, NestedMetaItem}; +use rustc_ast::{AttrArgs, AttrArgsEq, AttrKind, Attribute, NestedMetaItem}; use rustc_data_structures::fx::FxHashMap; use rustc_errors::codes::*; use rustc_errors::{ErrorGuaranteed, struct_span_code_err}; @@ -282,7 +282,7 @@ pub struct OnUnimplementedFormatString { #[derive(Debug)] pub struct OnUnimplementedDirective { - pub condition: Option, + pub condition: Option, pub subcommands: Vec, pub message: Option, pub label: Option, @@ -413,9 +413,7 @@ impl<'tcx> OnUnimplementedDirective { } else { let cond = item_iter .next() - .ok_or_else(|| tcx.dcx().emit_err(EmptyOnClauseInOnUnimplemented { span }))? - .meta_item() - .ok_or_else(|| tcx.dcx().emit_err(InvalidOnClauseInOnUnimplemented { span }))?; + .ok_or_else(|| tcx.dcx().emit_err(EmptyOnClauseInOnUnimplemented { span }))?; attr::eval_condition(cond, &tcx.sess, Some(tcx.features()), &mut |cfg| { if let Some(value) = cfg.value && let Err(guar) = parse_value(value, cfg.span) @@ -558,8 +556,8 @@ impl<'tcx> OnUnimplementedDirective { IgnoredDiagnosticOption::maybe_emit_warning( tcx, item_def_id, - directive.condition.as_ref().map(|i| i.span), - aggr.condition.as_ref().map(|i| i.span), + directive.condition.as_ref().map(|i| i.span()), + aggr.condition.as_ref().map(|i| i.span()), "condition", ); IgnoredDiagnosticOption::maybe_emit_warning( diff --git a/tests/ui/macros/cfg.rs b/tests/ui/macros/cfg.rs index 2aac50a9d01..387cc0ba8e2 100644 --- a/tests/ui/macros/cfg.rs +++ b/tests/ui/macros/cfg.rs @@ -1,6 +1,6 @@ fn main() { cfg!(); //~ ERROR macro requires a cfg-pattern - cfg!(123); //~ ERROR expected identifier + cfg!(123); //~ ERROR unsupported literal cfg!(foo = 123); //~ ERROR literal in `cfg` predicate value must be a string cfg!(foo, bar); //~ ERROR expected 1 cfg-pattern } diff --git a/tests/ui/macros/cfg.stderr b/tests/ui/macros/cfg.stderr index 2633d5f720d..5c21497dc5d 100644 --- a/tests/ui/macros/cfg.stderr +++ b/tests/ui/macros/cfg.stderr @@ -6,11 +6,11 @@ LL | cfg!(); | = note: this error originates in the macro `cfg` (in Nightly builds, run with -Z macro-backtrace for more info) -error: expected identifier, found `123` +error[E0565]: unsupported literal --> $DIR/cfg.rs:3:10 | LL | cfg!(123); - | ^^^ expected identifier + | ^^^ error[E0565]: literal in `cfg` predicate value must be a string --> $DIR/cfg.rs:4:16 From c99f29b29fa4115436c352a921f9963b173b5608 Mon Sep 17 00:00:00 2001 From: Urgau Date: Thu, 19 Sep 2024 10:13:14 +0200 Subject: [PATCH 449/683] Implement boolean lit support in cfg predicates --- compiler/rustc_ast/src/attr/mod.rs | 10 +++++++ compiler/rustc_attr/src/builtin.rs | 3 +- compiler/rustc_expand/src/config.rs | 6 ++-- compiler/rustc_metadata/src/native_libs.rs | 2 +- .../traits/on_unimplemented.rs | 4 ++- tests/ui/cfg/true-false.rs | 29 +++++++++++++++++++ 6 files changed, 48 insertions(+), 6 deletions(-) create mode 100644 tests/ui/cfg/true-false.rs diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs index 124d0acfa49..338d50cb394 100644 --- a/compiler/rustc_ast/src/attr/mod.rs +++ b/compiler/rustc_ast/src/attr/mod.rs @@ -527,6 +527,16 @@ impl NestedMetaItem { } } + /// Returns the `MetaItem` if `self` is a `NestedMetaItem::MetaItem` or if it's + /// `NestedMetaItem::Lit(MetaItemLit { kind: LitKind::Bool(_), .. })`. + pub fn meta_item_or_bool(&self) -> Option<&NestedMetaItem> { + match self { + NestedMetaItem::MetaItem(_item) => Some(self), + NestedMetaItem::Lit(MetaItemLit { kind: LitKind::Bool(_), .. }) => Some(self), + _ => None, + } + } + /// Returns the `MetaItem` if `self` is a `NestedMetaItem::MetaItem`. pub fn meta_item(&self) -> Option<&MetaItem> { match self { diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs index 37f70c21869..930fdeb975d 100644 --- a/compiler/rustc_attr/src/builtin.rs +++ b/compiler/rustc_attr/src/builtin.rs @@ -603,6 +603,7 @@ pub fn eval_condition( let cfg = match cfg { ast::NestedMetaItem::MetaItem(meta_item) => meta_item, + ast::NestedMetaItem::Lit(MetaItemLit { kind: LitKind::Bool(b), .. }) => return *b, _ => { dcx.emit_err(session_diagnostics::UnsupportedLiteral { span: cfg.span(), @@ -649,7 +650,7 @@ pub fn eval_condition( } ast::MetaItemKind::List(mis) => { for mi in mis.iter() { - if !mi.is_meta_item() { + if mi.meta_item_or_bool().is_none() { dcx.emit_err(session_diagnostics::UnsupportedLiteral { span: mi.span(), reason: UnsupportedLiteralReason::Generic, diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs index 8ea4f901368..af56169fd60 100644 --- a/compiler/rustc_expand/src/config.rs +++ b/compiler/rustc_expand/src/config.rs @@ -466,9 +466,9 @@ pub fn parse_cfg<'a>(meta_item: &'a MetaItem, sess: &Session) -> Option<&'a Nest sess.dcx().emit_err(InvalidCfg::MultiplePredicates { span: l.span() }); None } - Some([single]) => match single.is_meta_item() { - true => Some(single), - false => { + Some([single]) => match single.meta_item_or_bool() { + Some(meta_item) => Some(meta_item), + None => { sess.dcx().emit_err(InvalidCfg::PredicateLiteral { span: single.span() }); None } diff --git a/compiler/rustc_metadata/src/native_libs.rs b/compiler/rustc_metadata/src/native_libs.rs index 373b109189e..c7953d50406 100644 --- a/compiler/rustc_metadata/src/native_libs.rs +++ b/compiler/rustc_metadata/src/native_libs.rs @@ -309,7 +309,7 @@ impl<'tcx> Collector<'tcx> { .emit_err(errors::LinkCfgSinglePredicate { span: item.span() }); continue; }; - if !link_cfg.is_meta_item() { + let Some(link_cfg) = link_cfg.meta_item_or_bool() else { sess.dcx() .emit_err(errors::LinkCfgSinglePredicate { span: item.span() }); continue; diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs index f2efc5ee47d..e9a2c5b8d8e 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs @@ -413,7 +413,9 @@ impl<'tcx> OnUnimplementedDirective { } else { let cond = item_iter .next() - .ok_or_else(|| tcx.dcx().emit_err(EmptyOnClauseInOnUnimplemented { span }))?; + .ok_or_else(|| tcx.dcx().emit_err(EmptyOnClauseInOnUnimplemented { span }))? + .meta_item_or_bool() + .ok_or_else(|| tcx.dcx().emit_err(InvalidOnClauseInOnUnimplemented { span }))?; attr::eval_condition(cond, &tcx.sess, Some(tcx.features()), &mut |cfg| { if let Some(value) = cfg.value && let Err(guar) = parse_value(value, cfg.span) diff --git a/tests/ui/cfg/true-false.rs b/tests/ui/cfg/true-false.rs new file mode 100644 index 00000000000..0bd1cf427fa --- /dev/null +++ b/tests/ui/cfg/true-false.rs @@ -0,0 +1,29 @@ +//@ run-pass + +#![feature(link_cfg)] + +#[cfg(true)] +fn foo() -> bool { + cfg!(true) +} + +#[cfg(false)] +fn foo() -> bool { + cfg!(false) +} + +#[cfg_attr(true, cfg(false))] +fn foo() {} + +#[link(name = "foo", cfg(false))] +extern "C" {} + +fn main() { + assert!(foo()); + assert!(cfg!(true)); + assert!(!cfg!(false)); + assert!(cfg!(not(false))); + assert!(cfg!(all(true))); + assert!(cfg!(any(true))); + assert!(!cfg!(not(true))); +} From 4529b86196836ef1efe5c710a8874877d17b9ef8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 1 Oct 2024 11:01:45 +0200 Subject: [PATCH 450/683] make test_lots_of_insertions test take less long in Miri --- library/std/src/collections/hash/map/tests.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/collections/hash/map/tests.rs b/library/std/src/collections/hash/map/tests.rs index 2599060ef62..fa8ea95b891 100644 --- a/library/std/src/collections/hash/map/tests.rs +++ b/library/std/src/collections/hash/map/tests.rs @@ -274,7 +274,7 @@ fn test_lots_of_insertions() { for _ in 0..loops { assert!(m.is_empty()); - let count = if cfg!(miri) { 101 } else { 1001 }; + let count = if cfg!(miri) { 66 } else { 1001 }; for i in 1..count { assert!(m.insert(i, i).is_none()); From 125db409ffe4bcec2ce801d401eabd0e607ebf4a Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 25 Jul 2024 15:29:36 +0200 Subject: [PATCH 451/683] Small optimization for integers Display implementation --- library/core/src/fmt/num.rs | 134 ++++++++++++++++++++++++------------ 1 file changed, 90 insertions(+), 44 deletions(-) diff --git a/library/core/src/fmt/num.rs b/library/core/src/fmt/num.rs index e7726da8d91..5badc0a024c 100644 --- a/library/core/src/fmt/num.rs +++ b/library/core/src/fmt/num.rs @@ -208,11 +208,46 @@ static DEC_DIGITS_LUT: &[u8; 200] = b"0001020304050607080910111213141516171819\ 8081828384858687888990919293949596979899"; macro_rules! impl_Display { - ($($t:ident),* as $u:ident via $conv_fn:ident named $name:ident) => { + ($($t:ident => $size:literal $(as $positive:ident in $other:ident)? => named $name:ident,)* ; as $u:ident via $conv_fn:ident named $gen_name:ident) => { + + $( + #[stable(feature = "rust1", since = "1.0.0")] + impl fmt::Display for $t { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + // If it's a signed integer. + $( + let is_nonnegative = *self >= 0; + + #[cfg(not(feature = "optimize_for_size"))] + { + if !is_nonnegative { + // convert the negative num to positive by summing 1 to its 2s complement + return $other((!self as $positive).wrapping_add(1), false, f); + } + } + #[cfg(feature = "optimize_for_size")] + { + if !is_nonnegative { + // convert the negative num to positive by summing 1 to its 2s complement + return $other((!self.$conv_fn()).wrapping_add(1), false, f); + } + } + )? + // If it's a positive integer. + #[cfg(not(feature = "optimize_for_size"))] + { + $name(*self, true, f) + } + #[cfg(feature = "optimize_for_size")] + { + $gen_name(*self, true, f) + } + } + } + #[cfg(not(feature = "optimize_for_size"))] - fn $name(mut n: $u, is_nonnegative: bool, f: &mut fmt::Formatter<'_>) -> fmt::Result { - // 2^128 is about 3*10^38, so 39 gives an extra byte of space - let mut buf = [MaybeUninit::::uninit(); 39]; + fn $name(mut n: $t, is_nonnegative: bool, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let mut buf = [MaybeUninit::::uninit(); $size]; let mut curr = buf.len(); let buf_ptr = MaybeUninit::slice_as_mut_ptr(&mut buf); let lut_ptr = DEC_DIGITS_LUT.as_ptr(); @@ -226,22 +261,26 @@ macro_rules! impl_Display { // is safe to access. unsafe { // need at least 16 bits for the 4-characters-at-a-time to work. - assert!(crate::mem::size_of::<$u>() >= 2); + #[allow(overflowing_literals)] + #[allow(unused_comparisons)] + // This block will be removed for smaller types at compile time and in the worst + // case, it will prevent to have the `10000` literal to overflow for `i8` and `u8`. + if core::mem::size_of::<$t>() >= 2 { + // eagerly decode 4 characters at a time + while n >= 10000 { + let rem = (n % 10000) as usize; + n /= 10000; - // eagerly decode 4 characters at a time - while n >= 10000 { - let rem = (n % 10000) as usize; - n /= 10000; + let d1 = (rem / 100) << 1; + let d2 = (rem % 100) << 1; + curr -= 4; - let d1 = (rem / 100) << 1; - let d2 = (rem % 100) << 1; - curr -= 4; - - // We are allowed to copy to `buf_ptr[curr..curr + 3]` here since - // otherwise `curr < 0`. But then `n` was originally at least `10000^10` - // which is `10^40 > 2^128 > n`. - ptr::copy_nonoverlapping(lut_ptr.add(d1), buf_ptr.add(curr), 2); - ptr::copy_nonoverlapping(lut_ptr.add(d2), buf_ptr.add(curr + 2), 2); + // We are allowed to copy to `buf_ptr[curr..curr + 3]` here since + // otherwise `curr < 0`. But then `n` was originally at least `10000^10` + // which is `10^40 > 2^128 > n`. + ptr::copy_nonoverlapping(lut_ptr.add(d1 as usize), buf_ptr.add(curr), 2); + ptr::copy_nonoverlapping(lut_ptr.add(d2 as usize), buf_ptr.add(curr + 2), 2); + } } // if we reach here numbers are <= 9999, so at most 4 chars long @@ -255,6 +294,8 @@ macro_rules! impl_Display { ptr::copy_nonoverlapping(lut_ptr.add(d1), buf_ptr.add(curr), 2); } + // if we reach here numbers are <= 100, so at most 2 chars long + // The biggest it can be is 99, and 99 << 1 == 198, so a `u8` is enough. // decode last 1 or 2 chars if n < 10 { curr -= 1; @@ -273,11 +314,10 @@ macro_rules! impl_Display { slice::from_raw_parts(buf_ptr.add(curr), buf.len() - curr)) }; f.pad_integral(is_nonnegative, "", buf_slice) - } + })* #[cfg(feature = "optimize_for_size")] - fn $name(mut n: $u, is_nonnegative: bool, f: &mut fmt::Formatter<'_>) -> fmt::Result { - // 2^128 is about 3*10^38, so 39 gives an extra byte of space + fn $gen_name(mut n: $u, is_nonnegative: bool, f: &mut fmt::Formatter<'_>) -> fmt::Result { let mut buf = [MaybeUninit::::uninit(); 39]; let mut curr = buf.len(); let buf_ptr = MaybeUninit::slice_as_mut_ptr(&mut buf); @@ -306,21 +346,6 @@ macro_rules! impl_Display { }; f.pad_integral(is_nonnegative, "", buf_slice) } - - $(#[stable(feature = "rust1", since = "1.0.0")] - impl fmt::Display for $t { - #[allow(unused_comparisons)] - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let is_nonnegative = *self >= 0; - let n = if is_nonnegative { - self.$conv_fn() - } else { - // convert the negative num to positive by summing 1 to it's 2 complement - (!self.$conv_fn()).wrapping_add(1) - }; - $name(n, is_nonnegative, f) - } - })* }; } @@ -374,7 +399,6 @@ macro_rules! impl_Exp { (n, exponent, exponent, added_precision) }; - // 39 digits (worst case u128) + . = 40 // Since `curr` always decreases by the number of digits copied, this means // that `curr >= 0`. let mut buf = [MaybeUninit::::uninit(); 40]; @@ -469,7 +493,7 @@ macro_rules! impl_Exp { let n = if is_nonnegative { self.$conv_fn() } else { - // convert the negative num to positive by summing 1 to it's 2 complement + // convert the negative num to positive by summing 1 to its 2s complement (!self.$conv_fn()).wrapping_add(1) }; $name(n, is_nonnegative, false, f) @@ -484,7 +508,7 @@ macro_rules! impl_Exp { let n = if is_nonnegative { self.$conv_fn() } else { - // convert the negative num to positive by summing 1 to it's 2 complement + // convert the negative num to positive by summing 1 to its 2s complement (!self.$conv_fn()).wrapping_add(1) }; $name(n, is_nonnegative, true, f) @@ -499,8 +523,17 @@ macro_rules! impl_Exp { mod imp { use super::*; impl_Display!( - i8, u8, i16, u16, i32, u32, i64, u64, usize, isize - as u64 via to_u64 named fmt_u64 + i8 => 3 as u8 in fmt_u8 => named fmt_i8, + u8 => 3 => named fmt_u8, + i16 => 5 as u16 in fmt_u16 => named fmt_i16, + u16 => 5 => named fmt_u16, + i32 => 10 as u32 in fmt_u32 => named fmt_i32, + u32 => 10 => named fmt_u32, + i64 => 19 as u64 in fmt_u64 => named fmt_i64, + u64 => 20 => named fmt_u64, + isize => 19 as usize in fmt_usize => named fmt_isize, + usize => 20 => named fmt_usize, + ; as u64 via to_u64 named fmt_u64 ); impl_Exp!( i8, u8, i16, u16, i32, u32, i64, u64, usize, isize @@ -511,8 +544,21 @@ mod imp { #[cfg(not(any(target_pointer_width = "64", target_arch = "wasm32")))] mod imp { use super::*; - impl_Display!(i8, u8, i16, u16, i32, u32, isize, usize as u32 via to_u32 named fmt_u32); - impl_Display!(i64, u64 as u64 via to_u64 named fmt_u64); + impl_Display!( + i8 => 3 as u8 in fmt_u8 => named fmt_i8, + u8 => 3 => named fmt_u8, + i16 => 5 as u16 in fmt_u16 => named fmt_i16, + u16 => 5 => named fmt_u16, + i32 => 10 as u32 in fmt_u32 => named fmt_i32, + u32 => 10 => named fmt_u32, + isize => 10 as usize in fmt_usize => named fmt_isize, + usize => 10 => named fmt_usize, + ; as u32 via to_u32 named fmt_u32); + impl_Display!( + i64 => 19 as u64 in fmt_u64 => named fmt_i64, + u64 => 20 => named fmt_u64, + ; as u64 via to_u64 named fmt_u64); + impl_Exp!(i8, u8, i16, u16, i32, u32, isize, usize as u32 via to_u32 named exp_u32); impl_Exp!(i64, u64 as u64 via to_u64 named exp_u64); } @@ -619,7 +665,7 @@ impl fmt::Display for i128 { let n = if is_nonnegative { self.to_u128() } else { - // convert the negative num to positive by summing 1 to it's 2 complement + // convert the negative num to positive by summing 1 to its 2s complement (!self.to_u128()).wrapping_add(1) }; fmt_u128(n, is_nonnegative, f) From 884e0f0a6865049355b952b9a14c8b4bce0e73b2 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 23 Sep 2024 17:24:31 +0200 Subject: [PATCH 452/683] Simplify `impl_Display` macro --- library/core/src/fmt/num.rs | 175 ++++++++++++++++++------------------ 1 file changed, 89 insertions(+), 86 deletions(-) diff --git a/library/core/src/fmt/num.rs b/library/core/src/fmt/num.rs index 5badc0a024c..bc62f11d09f 100644 --- a/library/core/src/fmt/num.rs +++ b/library/core/src/fmt/num.rs @@ -208,7 +208,7 @@ static DEC_DIGITS_LUT: &[u8; 200] = b"0001020304050607080910111213141516171819\ 8081828384858687888990919293949596979899"; macro_rules! impl_Display { - ($($t:ident => $size:literal $(as $positive:ident in $other:ident)? => named $name:ident,)* ; as $u:ident via $conv_fn:ident named $gen_name:ident) => { + ($($t:ident => $size:literal $(as $positive:ident)? named $name:ident,)* ; as $u:ident via $conv_fn:ident named $gen_name:ident) => { $( #[stable(feature = "rust1", since = "1.0.0")] @@ -222,102 +222,105 @@ macro_rules! impl_Display { { if !is_nonnegative { // convert the negative num to positive by summing 1 to its 2s complement - return $other((!self as $positive).wrapping_add(1), false, f); + return (!self as $positive).wrapping_add(1)._fmt(false, f); } } #[cfg(feature = "optimize_for_size")] { if !is_nonnegative { // convert the negative num to positive by summing 1 to its 2s complement - return $other((!self.$conv_fn()).wrapping_add(1), false, f); + return $gen_name((!self.$conv_fn()).wrapping_add(1), false, f); } } )? // If it's a positive integer. #[cfg(not(feature = "optimize_for_size"))] { - $name(*self, true, f) + self._fmt(true, f) } #[cfg(feature = "optimize_for_size")] { - $gen_name(*self, true, f) + $gen_name(self.$conv_fn(), true, f) } } } #[cfg(not(feature = "optimize_for_size"))] - fn $name(mut n: $t, is_nonnegative: bool, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let mut buf = [MaybeUninit::::uninit(); $size]; - let mut curr = buf.len(); - let buf_ptr = MaybeUninit::slice_as_mut_ptr(&mut buf); - let lut_ptr = DEC_DIGITS_LUT.as_ptr(); + impl $t { + fn _fmt(mut self: $t, is_nonnegative: bool, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let mut buf = [MaybeUninit::::uninit(); $size]; + let mut curr = $size; + let buf_ptr = MaybeUninit::slice_as_mut_ptr(&mut buf); + let lut_ptr = DEC_DIGITS_LUT.as_ptr(); - // SAFETY: Since `d1` and `d2` are always less than or equal to `198`, we - // can copy from `lut_ptr[d1..d1 + 1]` and `lut_ptr[d2..d2 + 1]`. To show - // that it's OK to copy into `buf_ptr`, notice that at the beginning - // `curr == buf.len() == 39 > log(n)` since `n < 2^128 < 10^39`, and at - // each step this is kept the same as `n` is divided. Since `n` is always - // non-negative, this means that `curr > 0` so `buf_ptr[curr..curr + 1]` - // is safe to access. - unsafe { - // need at least 16 bits for the 4-characters-at-a-time to work. - #[allow(overflowing_literals)] - #[allow(unused_comparisons)] - // This block will be removed for smaller types at compile time and in the worst - // case, it will prevent to have the `10000` literal to overflow for `i8` and `u8`. - if core::mem::size_of::<$t>() >= 2 { - // eagerly decode 4 characters at a time - while n >= 10000 { - let rem = (n % 10000) as usize; - n /= 10000; + // SAFETY: Since `d1` and `d2` are always less than or equal to `198`, we + // can copy from `lut_ptr[d1..d1 + 1]` and `lut_ptr[d2..d2 + 1]`. To show + // that it's OK to copy into `buf_ptr`, notice that at the beginning + // `curr == buf.len() == 39 > log(n)` since `n < 2^128 < 10^39`, and at + // each step this is kept the same as `n` is divided. Since `n` is always + // non-negative, this means that `curr > 0` so `buf_ptr[curr..curr + 1]` + // is safe to access. + unsafe { + // need at least 16 bits for the 4-characters-at-a-time to work. + #[allow(overflowing_literals)] + #[allow(unused_comparisons)] + // This block will be removed for smaller types at compile time and in the worst + // case, it will prevent to have the `10000` literal to overflow for `i8` and `u8`. + if core::mem::size_of::<$t>() >= 2 { + // eagerly decode 4 characters at a time + while self >= 10000 { + let rem = (self % 10000) as usize; + self /= 10000; - let d1 = (rem / 100) << 1; - let d2 = (rem % 100) << 1; - curr -= 4; + let d1 = (rem / 100) << 1; + let d2 = (rem % 100) << 1; + curr -= 4; - // We are allowed to copy to `buf_ptr[curr..curr + 3]` here since - // otherwise `curr < 0`. But then `n` was originally at least `10000^10` - // which is `10^40 > 2^128 > n`. - ptr::copy_nonoverlapping(lut_ptr.add(d1 as usize), buf_ptr.add(curr), 2); - ptr::copy_nonoverlapping(lut_ptr.add(d2 as usize), buf_ptr.add(curr + 2), 2); + // We are allowed to copy to `buf_ptr[curr..curr + 3]` here since + // otherwise `curr < 0`. But then `n` was originally at least `10000^10` + // which is `10^40 > 2^128 > n`. + ptr::copy_nonoverlapping(lut_ptr.add(d1 as usize), buf_ptr.add(curr), 2); + ptr::copy_nonoverlapping(lut_ptr.add(d2 as usize), buf_ptr.add(curr + 2), 2); + } + } + + // if we reach here numbers are <= 9999, so at most 4 chars long + let mut n = self as usize; // possibly reduce 64bit math + + // decode 2 more chars, if > 2 chars + if n >= 100 { + let d1 = (n % 100) << 1; + n /= 100; + curr -= 2; + ptr::copy_nonoverlapping(lut_ptr.add(d1), buf_ptr.add(curr), 2); + } + + // if we reach here numbers are <= 100, so at most 2 chars long + // The biggest it can be is 99, and 99 << 1 == 198, so a `u8` is enough. + // decode last 1 or 2 chars + if n < 10 { + curr -= 1; + *buf_ptr.add(curr) = (n as u8) + b'0'; + } else { + let d1 = n << 1; + curr -= 2; + ptr::copy_nonoverlapping(lut_ptr.add(d1), buf_ptr.add(curr), 2); } } - // if we reach here numbers are <= 9999, so at most 4 chars long - let mut n = n as usize; // possibly reduce 64bit math - - // decode 2 more chars, if > 2 chars - if n >= 100 { - let d1 = (n % 100) << 1; - n /= 100; - curr -= 2; - ptr::copy_nonoverlapping(lut_ptr.add(d1), buf_ptr.add(curr), 2); - } - - // if we reach here numbers are <= 100, so at most 2 chars long - // The biggest it can be is 99, and 99 << 1 == 198, so a `u8` is enough. - // decode last 1 or 2 chars - if n < 10 { - curr -= 1; - *buf_ptr.add(curr) = (n as u8) + b'0'; - } else { - let d1 = n << 1; - curr -= 2; - ptr::copy_nonoverlapping(lut_ptr.add(d1), buf_ptr.add(curr), 2); - } + // SAFETY: `curr` > 0 (since we made `buf` large enough), and all the chars are valid + // UTF-8 since `DEC_DIGITS_LUT` is + let buf_slice = unsafe { + str::from_utf8_unchecked( + slice::from_raw_parts(buf_ptr.add(curr), buf.len() - curr)) + }; + f.pad_integral(is_nonnegative, "", buf_slice) } - - // SAFETY: `curr` > 0 (since we made `buf` large enough), and all the chars are valid - // UTF-8 since `DEC_DIGITS_LUT` is - let buf_slice = unsafe { - str::from_utf8_unchecked( - slice::from_raw_parts(buf_ptr.add(curr), buf.len() - curr)) - }; - f.pad_integral(is_nonnegative, "", buf_slice) })* #[cfg(feature = "optimize_for_size")] fn $gen_name(mut n: $u, is_nonnegative: bool, f: &mut fmt::Formatter<'_>) -> fmt::Result { + // 2^128 is about 3*10^38, so 39 gives an extra byte of space let mut buf = [MaybeUninit::::uninit(); 39]; let mut curr = buf.len(); let buf_ptr = MaybeUninit::slice_as_mut_ptr(&mut buf); @@ -523,16 +526,16 @@ macro_rules! impl_Exp { mod imp { use super::*; impl_Display!( - i8 => 3 as u8 in fmt_u8 => named fmt_i8, - u8 => 3 => named fmt_u8, - i16 => 5 as u16 in fmt_u16 => named fmt_i16, - u16 => 5 => named fmt_u16, - i32 => 10 as u32 in fmt_u32 => named fmt_i32, - u32 => 10 => named fmt_u32, - i64 => 19 as u64 in fmt_u64 => named fmt_i64, - u64 => 20 => named fmt_u64, - isize => 19 as usize in fmt_usize => named fmt_isize, - usize => 20 => named fmt_usize, + i8 => 3 as u8 named fmt_i8, + u8 => 3 named fmt_u8, + i16 => 5 as u16 named fmt_i16, + u16 => 5 named fmt_u16, + i32 => 10 as u32 named fmt_i32, + u32 => 10 named fmt_u32, + i64 => 19 as u64 named fmt_i64, + u64 => 20 named fmt_u64, + isize => 19 as usize named fmt_isize, + usize => 20 named fmt_usize, ; as u64 via to_u64 named fmt_u64 ); impl_Exp!( @@ -545,18 +548,18 @@ mod imp { mod imp { use super::*; impl_Display!( - i8 => 3 as u8 in fmt_u8 => named fmt_i8, - u8 => 3 => named fmt_u8, - i16 => 5 as u16 in fmt_u16 => named fmt_i16, - u16 => 5 => named fmt_u16, - i32 => 10 as u32 in fmt_u32 => named fmt_i32, - u32 => 10 => named fmt_u32, - isize => 10 as usize in fmt_usize => named fmt_isize, - usize => 10 => named fmt_usize, + i8 => 3 as u8 named fmt_i8, + u8 => 3 named fmt_u8, + i16 => 5 as u16 named fmt_i16, + u16 => 5 named fmt_u16, + i32 => 10 as u32 named fmt_i32, + u32 => 10 named fmt_u32, + isize => 19 as usize named fmt_isize, + usize => 20 named fmt_usize, ; as u32 via to_u32 named fmt_u32); impl_Display!( - i64 => 19 as u64 in fmt_u64 => named fmt_i64, - u64 => 20 => named fmt_u64, + i64 => 19 as u64 named fmt_i64, + u64 => 20 named fmt_u64, ; as u64 via to_u64 named fmt_u64); impl_Exp!(i8, u8, i16, u16, i32, u32, isize, usize as u32 via to_u32 named exp_u32); From 1562bf790974f0061c47d1a83b7a75cc507a744d Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 1 Oct 2024 12:01:55 +0200 Subject: [PATCH 453/683] Remove the need to provide the maximum number of digits to `impl_Display` macro --- library/core/src/fmt/num.rs | 47 +++++++++++++++++++------------------ 1 file changed, 24 insertions(+), 23 deletions(-) diff --git a/library/core/src/fmt/num.rs b/library/core/src/fmt/num.rs index bc62f11d09f..aecd725eca5 100644 --- a/library/core/src/fmt/num.rs +++ b/library/core/src/fmt/num.rs @@ -208,7 +208,7 @@ static DEC_DIGITS_LUT: &[u8; 200] = b"0001020304050607080910111213141516171819\ 8081828384858687888990919293949596979899"; macro_rules! impl_Display { - ($($t:ident => $size:literal $(as $positive:ident)? named $name:ident,)* ; as $u:ident via $conv_fn:ident named $gen_name:ident) => { + ($($t:ident $(as $positive:ident)? named $name:ident,)* ; as $u:ident via $conv_fn:ident named $gen_name:ident) => { $( #[stable(feature = "rust1", since = "1.0.0")] @@ -248,8 +248,9 @@ macro_rules! impl_Display { #[cfg(not(feature = "optimize_for_size"))] impl $t { fn _fmt(mut self: $t, is_nonnegative: bool, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let mut buf = [MaybeUninit::::uninit(); $size]; - let mut curr = $size; + const SIZE: usize = $t::MAX.ilog(10) as usize + 1; + let mut buf = [MaybeUninit::::uninit(); SIZE]; + let mut curr = SIZE; let buf_ptr = MaybeUninit::slice_as_mut_ptr(&mut buf); let lut_ptr = DEC_DIGITS_LUT.as_ptr(); @@ -526,16 +527,16 @@ macro_rules! impl_Exp { mod imp { use super::*; impl_Display!( - i8 => 3 as u8 named fmt_i8, - u8 => 3 named fmt_u8, - i16 => 5 as u16 named fmt_i16, - u16 => 5 named fmt_u16, - i32 => 10 as u32 named fmt_i32, - u32 => 10 named fmt_u32, - i64 => 19 as u64 named fmt_i64, - u64 => 20 named fmt_u64, - isize => 19 as usize named fmt_isize, - usize => 20 named fmt_usize, + i8 as u8 named fmt_i8, + u8 named fmt_u8, + i16 as u16 named fmt_i16, + u16 named fmt_u16, + i32 as u32 named fmt_i32, + u32 named fmt_u32, + i64 as u64 named fmt_i64, + u64 named fmt_u64, + isize as usize named fmt_isize, + usize named fmt_usize, ; as u64 via to_u64 named fmt_u64 ); impl_Exp!( @@ -548,18 +549,18 @@ mod imp { mod imp { use super::*; impl_Display!( - i8 => 3 as u8 named fmt_i8, - u8 => 3 named fmt_u8, - i16 => 5 as u16 named fmt_i16, - u16 => 5 named fmt_u16, - i32 => 10 as u32 named fmt_i32, - u32 => 10 named fmt_u32, - isize => 19 as usize named fmt_isize, - usize => 20 named fmt_usize, + i8 as u8 named fmt_i8, + u8 named fmt_u8, + i16 as u16 named fmt_i16, + u16 named fmt_u16, + i32 as u32 named fmt_i32, + u32 named fmt_u32, + isize as usize named fmt_isize, + usize named fmt_usize, ; as u32 via to_u32 named fmt_u32); impl_Display!( - i64 => 19 as u64 named fmt_i64, - u64 => 20 named fmt_u64, + i64 as u64 named fmt_i64, + u64 named fmt_u64, ; as u64 via to_u64 named fmt_u64); impl_Exp!(i8, u8, i16, u16, i32, u32, isize, usize as u32 via to_u32 named exp_u32); From 50a6a3565c10bdb02834a6f25677a09b9a9b4107 Mon Sep 17 00:00:00 2001 From: klensy Date: Tue, 1 Oct 2024 14:16:19 +0300 Subject: [PATCH 454/683] add fixme to remove llvm option when minimal version is 19 --- src/bootstrap/src/core/build_steps/llvm.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs index e4011221286..30213584157 100644 --- a/src/bootstrap/src/core/build_steps/llvm.rs +++ b/src/bootstrap/src/core/build_steps/llvm.rs @@ -344,6 +344,7 @@ impl Step for Llvm { .define("LLVM_INCLUDE_DOCS", "OFF") .define("LLVM_INCLUDE_BENCHMARKS", "OFF") .define("LLVM_INCLUDE_TESTS", enable_tests) + // FIXME: remove this when minimal llvm is 19 .define("LLVM_ENABLE_TERMINFO", "OFF") .define("LLVM_ENABLE_LIBEDIT", "OFF") .define("LLVM_ENABLE_BINDINGS", "OFF") From c53d4c78ad54a0eb2a117b5d47aa18b3c2bff484 Mon Sep 17 00:00:00 2001 From: Kajetan Puchalski Date: Mon, 30 Sep 2024 21:50:01 +0100 Subject: [PATCH 455/683] bootstrap: Add support for ./x setup emacs Add support for automatically setting up the recommended LSP config for Emacs. Additionally, refactor setup.rs to make it easier to add support for more editors in the future. --- src/bootstrap/src/core/build_steps/setup.rs | 186 ++++++++++++------ .../src/core/build_steps/setup/tests.rs | 9 +- src/bootstrap/src/core/builder.rs | 4 +- src/bootstrap/src/core/config/flags.rs | 3 +- src/etc/completions/x.py.sh | 2 +- src/etc/rust_analyzer_eglot.el | 50 ++--- 6 files changed, 163 insertions(+), 91 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/setup.rs b/src/bootstrap/src/core/build_steps/setup.rs index 0ee2cb451f3..7fbc5de06df 100644 --- a/src/bootstrap/src/core/build_steps/setup.rs +++ b/src/bootstrap/src/core/build_steps/setup.rs @@ -35,21 +35,6 @@ pub enum Profile { static PROFILE_DIR: &str = "src/bootstrap/defaults"; -/// A list of historical hashes of `src/etc/rust_analyzer_settings.json`. -/// New entries should be appended whenever this is updated so we can detect -/// outdated vs. user-modified settings files. -static SETTINGS_HASHES: &[&str] = &[ - "ea67e259dedf60d4429b6c349a564ffcd1563cf41c920a856d1f5b16b4701ac8", - "56e7bf011c71c5d81e0bf42e84938111847a810eee69d906bba494ea90b51922", - "af1b5efe196aed007577899db9dae15d6dbc923d6fa42fa0934e68617ba9bbe0", - "3468fea433c25fff60be6b71e8a215a732a7b1268b6a83bf10d024344e140541", - "47d227f424bf889b0d899b9cc992d5695e1b78c406e183cd78eafefbe5488923", - "b526bd58d0262dd4dda2bff5bc5515b705fb668a46235ace3e057f807963a11a", - "828666b021d837a33e78d870b56d34c88a5e2c85de58b693607ec574f0c27000", - "811fb3b063c739d261fd8590dd30242e117908f5a095d594fa04585daa18ec4d", -]; -static RUST_ANALYZER_SETTINGS: &str = include_str!("../../../../etc/rust_analyzer_settings.json"); - impl Profile { fn include_path(&self, src_path: &Path) -> PathBuf { PathBuf::from(format!("{}/{PROFILE_DIR}/config.{}.toml", src_path.display(), self)) @@ -533,46 +518,123 @@ undesirable, simply delete the `pre-push` file from .git/hooks." Ok(()) } -/// Sets up or displays `src/etc/rust_analyzer_settings.json` -#[derive(Clone, Debug, Eq, PartialEq, Hash)] -pub struct Vscode; +/// Handles editor-specific setup differences +#[derive(Clone, Debug, Eq, PartialEq)] +enum EditorKind { + Vscode, + Emacs, +} -impl Step for Vscode { - type Output = (); - const DEFAULT: bool = true; - fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { - run.alias("vscode") - } - fn make_run(run: RunConfig<'_>) { - if run.builder.config.dry_run() { - return; - } - if let [cmd] = &run.paths[..] { - if cmd.assert_single_path().path.as_path().as_os_str() == "vscode" { - run.builder.ensure(Vscode); - } +impl EditorKind { + /// A list of historical hashes of each LSP settings file + /// New entries should be appended whenever this is updated so we can detect + /// outdated vs. user-modified settings files. + fn hashes(&self) -> Vec<&str> { + match self { + EditorKind::Vscode => vec![ + "ea67e259dedf60d4429b6c349a564ffcd1563cf41c920a856d1f5b16b4701ac8", + "56e7bf011c71c5d81e0bf42e84938111847a810eee69d906bba494ea90b51922", + "af1b5efe196aed007577899db9dae15d6dbc923d6fa42fa0934e68617ba9bbe0", + "3468fea433c25fff60be6b71e8a215a732a7b1268b6a83bf10d024344e140541", + "47d227f424bf889b0d899b9cc992d5695e1b78c406e183cd78eafefbe5488923", + "b526bd58d0262dd4dda2bff5bc5515b705fb668a46235ace3e057f807963a11a", + "828666b021d837a33e78d870b56d34c88a5e2c85de58b693607ec574f0c27000", + "811fb3b063c739d261fd8590dd30242e117908f5a095d594fa04585daa18ec4d", + ], + EditorKind::Emacs => vec![ + "51068d4747a13732440d1a8b8f432603badb1864fa431d83d0fd4f8fa57039e0", + "d29af4d949bbe2371eac928a3c31cf9496b1701aa1c45f11cd6c759865ad5c45", + ], } } - fn run(self, builder: &Builder<'_>) -> Self::Output { - let config = &builder.config; - if config.dry_run() { - return; + + fn settings_path(&self, config: &Config) -> PathBuf { + config.src.join(self.settings_short_path()) + } + + fn settings_short_path(&self) -> PathBuf { + self.settings_folder().join(match self { + EditorKind::Vscode => "settings.json", + EditorKind::Emacs => ".dir-locals.el", + }) + } + + fn settings_folder(&self) -> PathBuf { + match self { + EditorKind::Vscode => PathBuf::new().join(".vscode"), + EditorKind::Emacs => PathBuf::new(), + } + } + + fn settings_template(&self) -> &str { + match self { + EditorKind::Vscode => include_str!("../../../../etc/rust_analyzer_settings.json"), + EditorKind::Emacs => include_str!("../../../../etc/rust_analyzer_eglot.el"), + } + } + + fn backup_extension(&self) -> &str { + match self { + EditorKind::Vscode => "json.bak", + EditorKind::Emacs => "el.bak", } - while !t!(create_vscode_settings_maybe(config)) {} } } -/// Create a `.vscode/settings.json` file for rustc development, or just print it +/// Helper macro for implementing the necessary Step to support editor LSP setup +/// The first argument must match the argument set up in `flags.rs` +/// The second argument must match the name of some `EditorKind` variant +/// After using the macro, the editor needs to be registered in `builder.rs` with describe!() +macro_rules! impl_editor_support { + ( $($editor:ident, $kind:ident),+ ) => {$( + #[doc = concat!(" Sets up or displays the LSP config for ", stringify!($editor), ".")] + #[derive(Clone, Debug, Eq, PartialEq, Hash)] + pub struct $kind; + + impl Step for $kind { + type Output = (); + const DEFAULT: bool = true; + fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { + run.alias(stringify!($editor)) + } + fn make_run(run: RunConfig<'_>) { + if run.builder.config.dry_run() { + return; + } + if let [cmd] = &run.paths[..] { + if cmd.assert_single_path().path.as_path().as_os_str() == stringify!($editor) { + run.builder.ensure($kind); + } + } + } + fn run(self, builder: &Builder<'_>) -> Self::Output { + let config = &builder.config; + if config.dry_run() { + return; + } + while !t!(create_editor_settings_maybe(config, EditorKind::$kind)) {} + } + } + )+}; +} + +impl_editor_support!(vscode, Vscode); +impl_editor_support!(emacs, Emacs); + +/// Create the recommended editor LSP config file for rustc development, or just print it /// If this method should be re-called, it returns `false`. -fn create_vscode_settings_maybe(config: &Config) -> io::Result { - let (current_hash, historical_hashes) = SETTINGS_HASHES.split_last().unwrap(); - let vscode_settings = config.src.join(".vscode").join("settings.json"); - // If None, no settings.json exists +fn create_editor_settings_maybe(config: &Config, editor: EditorKind) -> io::Result { + let hashes = editor.hashes(); + let (current_hash, historical_hashes) = hashes.split_last().unwrap(); + let settings_path = editor.settings_path(config); + let settings_short_path = editor.settings_short_path(); + let settings_filename = settings_short_path.to_str().unwrap(); + // If None, no settings file exists // If Some(true), is a previous version of settings.json // If Some(false), is not a previous version (i.e. user modified) // If it's up to date we can just skip this let mut mismatched_settings = None; - if let Ok(current) = fs::read_to_string(&vscode_settings) { + if let Ok(current) = fs::read_to_string(&settings_path) { let mut hasher = sha2::Sha256::new(); hasher.update(¤t); let hash = hex_encode(hasher.finalize().as_slice()); @@ -585,20 +647,23 @@ fn create_vscode_settings_maybe(config: &Config) -> io::Result { } } println!( - "\nx.py can automatically install the recommended `.vscode/settings.json` file for rustc development" + "\nx.py can automatically install the recommended `{settings_filename}` file for rustc development" ); + match mismatched_settings { Some(true) => eprintln!( - "WARNING: existing `.vscode/settings.json` is out of date, x.py will update it" + "WARNING: existing `{}` is out of date, x.py will update it", + settings_filename ), Some(false) => eprintln!( - "WARNING: existing `.vscode/settings.json` has been modified by user, x.py will back it up and replace it" + "WARNING: existing `{}` has been modified by user, x.py will back it up and replace it", + settings_filename ), _ => (), } - let should_create = match prompt_user( - "Would you like to create/update settings.json? (Press 'p' to preview values): [y/N]", - )? { + let should_create = match prompt_user(&format!( + "Would you like to create/update `{settings_filename}`? (Press 'p' to preview values): [y/N]" + ))? { Some(PromptResult::Yes) => true, Some(PromptResult::Print) => false, _ => { @@ -607,9 +672,9 @@ fn create_vscode_settings_maybe(config: &Config) -> io::Result { } }; if should_create { - let path = config.src.join(".vscode"); - if !path.exists() { - fs::create_dir(&path)?; + let settings_folder_path = config.src.join(editor.settings_folder()); + if !settings_folder_path.exists() { + fs::create_dir(settings_folder_path)?; } let verb = match mismatched_settings { // exists but outdated, we can replace this @@ -617,18 +682,21 @@ fn create_vscode_settings_maybe(config: &Config) -> io::Result { // exists but user modified, back it up Some(false) => { // exists and is not current version or outdated, so back it up - let mut backup = vscode_settings.clone(); - backup.set_extension("json.bak"); - eprintln!("WARNING: copying `settings.json` to `settings.json.bak`"); - fs::copy(&vscode_settings, &backup)?; + let backup = settings_path.clone().with_extension(editor.backup_extension()); + eprintln!( + "WARNING: copying `{}` to `{}`", + settings_path.file_name().unwrap().to_str().unwrap(), + backup.file_name().unwrap().to_str().unwrap(), + ); + fs::copy(&settings_path, &backup)?; "Updated" } _ => "Created", }; - fs::write(&vscode_settings, RUST_ANALYZER_SETTINGS)?; - println!("{verb} `.vscode/settings.json`"); + fs::write(&settings_path, editor.settings_template())?; + println!("{verb} `{}`", settings_filename); } else { - println!("\n{RUST_ANALYZER_SETTINGS}"); + println!("\n{}", editor.settings_template()); } Ok(should_create) } diff --git a/src/bootstrap/src/core/build_steps/setup/tests.rs b/src/bootstrap/src/core/build_steps/setup/tests.rs index 3552224f33b..f3d4b6aa4db 100644 --- a/src/bootstrap/src/core/build_steps/setup/tests.rs +++ b/src/bootstrap/src/core/build_steps/setup/tests.rs @@ -1,16 +1,17 @@ use sha2::Digest; -use super::{RUST_ANALYZER_SETTINGS, SETTINGS_HASHES}; +use super::EditorKind; use crate::utils::helpers::hex_encode; #[test] fn check_matching_settings_hash() { + let editor = EditorKind::Vscode; let mut hasher = sha2::Sha256::new(); - hasher.update(&RUST_ANALYZER_SETTINGS); + hasher.update(&editor.settings_template()); let hash = hex_encode(hasher.finalize().as_slice()); assert_eq!( &hash, - SETTINGS_HASHES.last().unwrap(), - "Update `SETTINGS_HASHES` with the new hash of `src/etc/rust_analyzer_settings.json`" + editor.hashes().last().unwrap(), + "Update `EditorKind::hashes()` with the new hash of `src/etc/rust_analyzer_settings.json`" ); } diff --git a/src/bootstrap/src/core/builder.rs b/src/bootstrap/src/core/builder.rs index 6ba669f3b10..91ac9cceb38 100644 --- a/src/bootstrap/src/core/builder.rs +++ b/src/bootstrap/src/core/builder.rs @@ -1000,7 +1000,9 @@ impl<'a> Builder<'a> { run::GenerateWindowsSys, run::GenerateCompletions, ), - Kind::Setup => describe!(setup::Profile, setup::Hook, setup::Link, setup::Vscode), + Kind::Setup => { + describe!(setup::Profile, setup::Hook, setup::Link, setup::Vscode, setup::Emacs) + } Kind::Clean => describe!(clean::CleanAll, clean::Rustc, clean::Std), Kind::Vendor => describe!(vendor::Vendor), // special-cased in Build::build() diff --git a/src/bootstrap/src/core/config/flags.rs b/src/bootstrap/src/core/config/flags.rs index 87db5f93fb0..73446382cc6 100644 --- a/src/bootstrap/src/core/config/flags.rs +++ b/src/bootstrap/src/core/config/flags.rs @@ -450,11 +450,12 @@ Arguments: To only set up the git hook, VS Code config or toolchain link, you may use ./x.py setup hook ./x.py setup vscode + ./x.py setup emacs ./x.py setup link", Profile::all_for_help(" ").trim_end()))] Setup { /// Either the profile for `config.toml` or another setup action. /// May be omitted to set up interactively - #[arg(value_name = "|hook|vscode|link")] + #[arg(value_name = "|hook|vscode|emacs|link")] profile: Option, }, /// Suggest a subset of tests to run, based on modified files diff --git a/src/etc/completions/x.py.sh b/src/etc/completions/x.py.sh index 2aa0d9f69cc..78d59c229d7 100644 --- a/src/etc/completions/x.py.sh +++ b/src/etc/completions/x.py.sh @@ -2741,7 +2741,7 @@ _x.py() { return 0 ;; x.py__setup) - opts="-v -i -j -h --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --help [|hook|vscode|link] [PATHS]... [ARGS]..." + opts="-v -i -j -h --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --help [|hook|vscode|emacs|link] [PATHS]... [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 diff --git a/src/etc/rust_analyzer_eglot.el b/src/etc/rust_analyzer_eglot.el index e55d80d98de..7b4309f8e18 100644 --- a/src/etc/rust_analyzer_eglot.el +++ b/src/etc/rust_analyzer_eglot.el @@ -2,28 +2,28 @@ .((eglot-workspace-configuration . (:rust-analyzer ( :check ( :invocationLocation "root" - :invocationStrategy "once" - :overrideCommand ["python3" - "x.py" - "check" - "--json-output"]) - :linkedProjects ["Cargo.toml" - "src/tools/x/Cargo.toml" - "src/bootstrap/Cargo.toml" - "src/tools/rust-analyzer/Cargo.toml" - "compiler/rustc_codegen_cranelift/Cargo.toml" - "compiler/rustc_codegen_gcc/Cargo.toml"] - :rustfmt ( :overrideCommand ["build/host/rustfmt/bin/rustfmt" - "--edition=2021"]) - :procMacro ( :server "build/host/stage0/libexec/rust-analyzer-proc-macro-srv" - :enable t) - :cargo ( :buildScripts ( :enable t - :invocationLocation "root" - :invocationStrategy "once" - :overrideCommand ["python3" - "x.py" - "check" - "--json-output"]) - :sysrootSrc "./library" - :extraEnv (:RUSTC_BOOTSTRAP "1")) - :rustc ( :source "./Cargo.toml" ))))))) + :invocationStrategy "once" + :overrideCommand ["python3" + "x.py" + "check" + "--json-output"]) + :linkedProjects ["Cargo.toml" + "src/tools/x/Cargo.toml" + "src/bootstrap/Cargo.toml" + "src/tools/rust-analyzer/Cargo.toml" + "compiler/rustc_codegen_cranelift/Cargo.toml" + "compiler/rustc_codegen_gcc/Cargo.toml"] + :rustfmt ( :overrideCommand ["build/host/rustfmt/bin/rustfmt" + "--edition=2021"]) + :procMacro ( :server "build/host/stage0/libexec/rust-analyzer-proc-macro-srv" + :enable t) + :cargo ( :buildScripts ( :enable t + :invocationLocation "root" + :invocationStrategy "once" + :overrideCommand ["python3" + "x.py" + "check" + "--json-output"]) + :sysrootSrc "./library" + :extraEnv (:RUSTC_BOOTSTRAP "1")) + :rustc ( :source "./Cargo.toml" ))))))) From dfc7e396a6426211078b24fe0a2c8f29adcbe2f2 Mon Sep 17 00:00:00 2001 From: Kajetan Puchalski Date: Mon, 30 Sep 2024 22:26:22 +0100 Subject: [PATCH 456/683] bootstrap: Add support for ./x setup helix --- src/bootstrap/src/core/build_steps/setup.rs | 9 +++++++++ src/bootstrap/src/core/builder.rs | 2 +- src/bootstrap/src/core/config/flags.rs | 3 ++- src/etc/completions/x.py.sh | 2 +- 4 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/setup.rs b/src/bootstrap/src/core/build_steps/setup.rs index 7fbc5de06df..2b5700699c4 100644 --- a/src/bootstrap/src/core/build_steps/setup.rs +++ b/src/bootstrap/src/core/build_steps/setup.rs @@ -523,6 +523,7 @@ undesirable, simply delete the `pre-push` file from .git/hooks." enum EditorKind { Vscode, Emacs, + Helix, } impl EditorKind { @@ -545,6 +546,9 @@ impl EditorKind { "51068d4747a13732440d1a8b8f432603badb1864fa431d83d0fd4f8fa57039e0", "d29af4d949bbe2371eac928a3c31cf9496b1701aa1c45f11cd6c759865ad5c45", ], + EditorKind::Helix => vec![ + "2d3069b8cf1b977e5d4023965eb6199597755e6c96c185ed5f2854f98b83d233" + ] } } @@ -556,6 +560,7 @@ impl EditorKind { self.settings_folder().join(match self { EditorKind::Vscode => "settings.json", EditorKind::Emacs => ".dir-locals.el", + EditorKind::Helix => "languages.toml", }) } @@ -563,6 +568,7 @@ impl EditorKind { match self { EditorKind::Vscode => PathBuf::new().join(".vscode"), EditorKind::Emacs => PathBuf::new(), + EditorKind::Helix => PathBuf::new().join(".helix"), } } @@ -570,6 +576,7 @@ impl EditorKind { match self { EditorKind::Vscode => include_str!("../../../../etc/rust_analyzer_settings.json"), EditorKind::Emacs => include_str!("../../../../etc/rust_analyzer_eglot.el"), + EditorKind::Helix => include_str!("../../../../etc/rust_analyzer_helix.toml"), } } @@ -577,6 +584,7 @@ impl EditorKind { match self { EditorKind::Vscode => "json.bak", EditorKind::Emacs => "el.bak", + EditorKind::Helix => "toml.bak", } } } @@ -620,6 +628,7 @@ macro_rules! impl_editor_support { impl_editor_support!(vscode, Vscode); impl_editor_support!(emacs, Emacs); +impl_editor_support!(helix, Helix); /// Create the recommended editor LSP config file for rustc development, or just print it /// If this method should be re-called, it returns `false`. diff --git a/src/bootstrap/src/core/builder.rs b/src/bootstrap/src/core/builder.rs index 91ac9cceb38..dcffeccbaff 100644 --- a/src/bootstrap/src/core/builder.rs +++ b/src/bootstrap/src/core/builder.rs @@ -1001,7 +1001,7 @@ impl<'a> Builder<'a> { run::GenerateCompletions, ), Kind::Setup => { - describe!(setup::Profile, setup::Hook, setup::Link, setup::Vscode, setup::Emacs) + describe!(setup::Profile, setup::Hook, setup::Link, setup::Vscode, setup::Emacs, setup::Helix) } Kind::Clean => describe!(clean::CleanAll, clean::Rustc, clean::Std), Kind::Vendor => describe!(vendor::Vendor), diff --git a/src/bootstrap/src/core/config/flags.rs b/src/bootstrap/src/core/config/flags.rs index 73446382cc6..2957e47c771 100644 --- a/src/bootstrap/src/core/config/flags.rs +++ b/src/bootstrap/src/core/config/flags.rs @@ -451,11 +451,12 @@ Arguments: ./x.py setup hook ./x.py setup vscode ./x.py setup emacs + ./x.py setup helix ./x.py setup link", Profile::all_for_help(" ").trim_end()))] Setup { /// Either the profile for `config.toml` or another setup action. /// May be omitted to set up interactively - #[arg(value_name = "|hook|vscode|emacs|link")] + #[arg(value_name = "|hook|vscode|emacs|helix|link")] profile: Option, }, /// Suggest a subset of tests to run, based on modified files diff --git a/src/etc/completions/x.py.sh b/src/etc/completions/x.py.sh index 78d59c229d7..15475b976ea 100644 --- a/src/etc/completions/x.py.sh +++ b/src/etc/completions/x.py.sh @@ -2741,7 +2741,7 @@ _x.py() { return 0 ;; x.py__setup) - opts="-v -i -j -h --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --help [|hook|vscode|emacs|link] [PATHS]... [ARGS]..." + opts="-v -i -j -h --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --help [|hook|vscode|emacs|helix|link] [PATHS]... [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 From 9b24fae0bec325a3aa65e9373d018eb55a327d0e Mon Sep 17 00:00:00 2001 From: Kajetan Puchalski Date: Mon, 30 Sep 2024 22:38:36 +0100 Subject: [PATCH 457/683] bootstrap: Add support for ./x setup vim --- src/bootstrap/src/core/build_steps/setup.rs | 24 +++++++++++---------- src/bootstrap/src/core/builder.rs | 10 ++++++++- src/bootstrap/src/core/config/flags.rs | 3 ++- src/bootstrap/src/utils/change_tracker.rs | 5 +++++ src/etc/completions/x.py.sh | 2 +- 5 files changed, 30 insertions(+), 14 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/setup.rs b/src/bootstrap/src/core/build_steps/setup.rs index 2b5700699c4..3aa8d3a67d8 100644 --- a/src/bootstrap/src/core/build_steps/setup.rs +++ b/src/bootstrap/src/core/build_steps/setup.rs @@ -522,6 +522,7 @@ undesirable, simply delete the `pre-push` file from .git/hooks." #[derive(Clone, Debug, Eq, PartialEq)] enum EditorKind { Vscode, + Vim, Emacs, Helix, } @@ -532,7 +533,7 @@ impl EditorKind { /// outdated vs. user-modified settings files. fn hashes(&self) -> Vec<&str> { match self { - EditorKind::Vscode => vec![ + EditorKind::Vscode | EditorKind::Vim => vec![ "ea67e259dedf60d4429b6c349a564ffcd1563cf41c920a856d1f5b16b4701ac8", "56e7bf011c71c5d81e0bf42e84938111847a810eee69d906bba494ea90b51922", "af1b5efe196aed007577899db9dae15d6dbc923d6fa42fa0934e68617ba9bbe0", @@ -546,9 +547,9 @@ impl EditorKind { "51068d4747a13732440d1a8b8f432603badb1864fa431d83d0fd4f8fa57039e0", "d29af4d949bbe2371eac928a3c31cf9496b1701aa1c45f11cd6c759865ad5c45", ], - EditorKind::Helix => vec![ - "2d3069b8cf1b977e5d4023965eb6199597755e6c96c185ed5f2854f98b83d233" - ] + EditorKind::Helix => { + vec!["2d3069b8cf1b977e5d4023965eb6199597755e6c96c185ed5f2854f98b83d233"] + } } } @@ -559,6 +560,7 @@ impl EditorKind { fn settings_short_path(&self) -> PathBuf { self.settings_folder().join(match self { EditorKind::Vscode => "settings.json", + EditorKind::Vim => "coc-settings.json", EditorKind::Emacs => ".dir-locals.el", EditorKind::Helix => "languages.toml", }) @@ -567,6 +569,7 @@ impl EditorKind { fn settings_folder(&self) -> PathBuf { match self { EditorKind::Vscode => PathBuf::new().join(".vscode"), + EditorKind::Vim => PathBuf::new().join(".vim"), EditorKind::Emacs => PathBuf::new(), EditorKind::Helix => PathBuf::new().join(".helix"), } @@ -574,18 +577,16 @@ impl EditorKind { fn settings_template(&self) -> &str { match self { - EditorKind::Vscode => include_str!("../../../../etc/rust_analyzer_settings.json"), + EditorKind::Vscode | EditorKind::Vim => { + include_str!("../../../../etc/rust_analyzer_settings.json") + } EditorKind::Emacs => include_str!("../../../../etc/rust_analyzer_eglot.el"), EditorKind::Helix => include_str!("../../../../etc/rust_analyzer_helix.toml"), } } - fn backup_extension(&self) -> &str { - match self { - EditorKind::Vscode => "json.bak", - EditorKind::Emacs => "el.bak", - EditorKind::Helix => "toml.bak", - } + fn backup_extension(&self) -> String { + format!("{}.bak", self.settings_short_path().extension().unwrap().to_str().unwrap()) } } @@ -627,6 +628,7 @@ macro_rules! impl_editor_support { } impl_editor_support!(vscode, Vscode); +impl_editor_support!(vim, Vim); impl_editor_support!(emacs, Emacs); impl_editor_support!(helix, Helix); diff --git a/src/bootstrap/src/core/builder.rs b/src/bootstrap/src/core/builder.rs index dcffeccbaff..67f9a3ab3ed 100644 --- a/src/bootstrap/src/core/builder.rs +++ b/src/bootstrap/src/core/builder.rs @@ -1001,7 +1001,15 @@ impl<'a> Builder<'a> { run::GenerateCompletions, ), Kind::Setup => { - describe!(setup::Profile, setup::Hook, setup::Link, setup::Vscode, setup::Emacs, setup::Helix) + describe!( + setup::Profile, + setup::Hook, + setup::Link, + setup::Vscode, + setup::Emacs, + setup::Helix, + setup::Vim + ) } Kind::Clean => describe!(clean::CleanAll, clean::Rustc, clean::Std), Kind::Vendor => describe!(vendor::Vendor), diff --git a/src/bootstrap/src/core/config/flags.rs b/src/bootstrap/src/core/config/flags.rs index 2957e47c771..fb27d1ebb18 100644 --- a/src/bootstrap/src/core/config/flags.rs +++ b/src/bootstrap/src/core/config/flags.rs @@ -450,13 +450,14 @@ Arguments: To only set up the git hook, VS Code config or toolchain link, you may use ./x.py setup hook ./x.py setup vscode + ./x.py setup vim ./x.py setup emacs ./x.py setup helix ./x.py setup link", Profile::all_for_help(" ").trim_end()))] Setup { /// Either the profile for `config.toml` or another setup action. /// May be omitted to set up interactively - #[arg(value_name = "|hook|vscode|emacs|helix|link")] + #[arg(value_name = "|hook|vscode|vim|emacs|helix|link")] profile: Option, }, /// Suggest a subset of tests to run, based on modified files diff --git a/src/bootstrap/src/utils/change_tracker.rs b/src/bootstrap/src/utils/change_tracker.rs index e6f7f105fa2..e6f5363dbf2 100644 --- a/src/bootstrap/src/utils/change_tracker.rs +++ b/src/bootstrap/src/utils/change_tracker.rs @@ -270,4 +270,9 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[ severity: ChangeSeverity::Info, summary: "If `llvm.download-ci-llvm` is not defined, it defaults to `true`.", }, + ChangeInfo { + change_id: 131075, + severity: ChangeSeverity::Info, + summary: "New options for ./x setup added - ./x setup [vim|emacs|helix]", + }, ]; diff --git a/src/etc/completions/x.py.sh b/src/etc/completions/x.py.sh index 15475b976ea..913b0e820cb 100644 --- a/src/etc/completions/x.py.sh +++ b/src/etc/completions/x.py.sh @@ -2741,7 +2741,7 @@ _x.py() { return 0 ;; x.py__setup) - opts="-v -i -j -h --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --help [|hook|vscode|emacs|helix|link] [PATHS]... [ARGS]..." + opts="-v -i -j -h --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --help [|hook|vscode|vim|emacs|helix|link] [PATHS]... [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 From f48194ea5578802c786edff59dd72388da0e6305 Mon Sep 17 00:00:00 2001 From: David Lattimore Date: Tue, 1 Oct 2024 08:55:10 +1000 Subject: [PATCH 458/683] Replace -Z default-hidden-visibility with -Z default-visibility MCP: https://github.com/rust-lang/compiler-team/issues/782 Co-authored-by: bjorn3 <17426603+bjorn3@users.noreply.github.com> --- compiler/rustc_codegen_gcc/src/allocator.rs | 13 +++- compiler/rustc_codegen_llvm/src/allocator.rs | 22 +++--- compiler/rustc_codegen_llvm/src/declare.rs | 13 +--- compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 11 +++ compiler/rustc_interface/src/tests.rs | 2 +- compiler/rustc_middle/src/mir/mono.rs | 11 +++ .../rustc_monomorphize/src/partitioning.rs | 34 ++++----- compiler/rustc_session/src/config.rs | 4 +- compiler/rustc_session/src/options.rs | 24 +++++-- compiler/rustc_session/src/session.rs | 12 ++-- compiler/rustc_target/src/spec/mod.rs | 69 ++++++++++++++++--- .../default-hidden-visibility.md | 12 ---- .../src/compiler-flags/default-visibility.md | 44 ++++++++++++ ...en-visibility.rs => default-visibility.rs} | 18 ++--- 14 files changed, 208 insertions(+), 81 deletions(-) delete mode 100644 src/doc/unstable-book/src/compiler-flags/default-hidden-visibility.md create mode 100644 src/doc/unstable-book/src/compiler-flags/default-visibility.md rename tests/codegen/{default-hidden-visibility.rs => default-visibility.rs} (60%) diff --git a/compiler/rustc_codegen_gcc/src/allocator.rs b/compiler/rustc_codegen_gcc/src/allocator.rs index e9498857fb9..f13a75648ae 100644 --- a/compiler/rustc_codegen_gcc/src/allocator.rs +++ b/compiler/rustc_codegen_gcc/src/allocator.rs @@ -104,10 +104,17 @@ fn create_wrapper_function( false, ); - if tcx.sess.default_hidden_visibility() { - #[cfg(feature = "master")] - func.add_attribute(FnAttribute::Visibility(gccjit::Visibility::Hidden)); + #[cfg(feature = "master")] + match tcx.sess.default_visibility() { + rustc_target::spec::SymbolVisibility::Hidden => { + func.add_attribute(FnAttribute::Visibility(gccjit::Visibility::Hidden)) + } + rustc_target::spec::SymbolVisibility::Protected => { + func.add_attribute(FnAttribute::Visibility(gccjit::Visibility::Protected)) + } + rustc_target::spec::SymbolVisibility::Interposable => {} } + if tcx.sess.must_emit_unwind_tables() { // TODO(antoyo): emit unwind tables. } diff --git a/compiler/rustc_codegen_llvm/src/allocator.rs b/compiler/rustc_codegen_llvm/src/allocator.rs index 2adac278c62..89f5305840b 100644 --- a/compiler/rustc_codegen_llvm/src/allocator.rs +++ b/compiler/rustc_codegen_llvm/src/allocator.rs @@ -77,18 +77,20 @@ pub(crate) unsafe fn codegen( // __rust_alloc_error_handler_should_panic let name = OomStrategy::SYMBOL; let ll_g = llvm::LLVMRustGetOrInsertGlobal(llmod, name.as_ptr().cast(), name.len(), i8); - if tcx.sess.default_hidden_visibility() { - llvm::LLVMRustSetVisibility(ll_g, llvm::Visibility::Hidden); - } + llvm::LLVMRustSetVisibility( + ll_g, + llvm::Visibility::from_generic(tcx.sess.default_visibility()), + ); let val = tcx.sess.opts.unstable_opts.oom.should_panic(); let llval = llvm::LLVMConstInt(i8, val as u64, False); llvm::LLVMSetInitializer(ll_g, llval); let name = NO_ALLOC_SHIM_IS_UNSTABLE; let ll_g = llvm::LLVMRustGetOrInsertGlobal(llmod, name.as_ptr().cast(), name.len(), i8); - if tcx.sess.default_hidden_visibility() { - llvm::LLVMRustSetVisibility(ll_g, llvm::Visibility::Hidden); - } + llvm::LLVMRustSetVisibility( + ll_g, + llvm::Visibility::from_generic(tcx.sess.default_visibility()), + ); let llval = llvm::LLVMConstInt(i8, 0, False); llvm::LLVMSetInitializer(ll_g, llval); } @@ -132,9 +134,11 @@ fn create_wrapper_function( None }; - if tcx.sess.default_hidden_visibility() { - llvm::LLVMRustSetVisibility(llfn, llvm::Visibility::Hidden); - } + llvm::LLVMRustSetVisibility( + llfn, + llvm::Visibility::from_generic(tcx.sess.default_visibility()), + ); + if tcx.sess.must_emit_unwind_tables() { let uwtable = attributes::uwtable_attr(llcx, tcx.sess.opts.unstable_opts.use_sync_unwind); diff --git a/compiler/rustc_codegen_llvm/src/declare.rs b/compiler/rustc_codegen_llvm/src/declare.rs index b0b29ca1280..7be44dd51b5 100644 --- a/compiler/rustc_codegen_llvm/src/declare.rs +++ b/compiler/rustc_codegen_llvm/src/declare.rs @@ -22,6 +22,7 @@ use tracing::debug; use crate::abi::{FnAbi, FnAbiLlvmExt}; use crate::context::CodegenCx; use crate::llvm::AttributePlace::Function; +use crate::llvm::Visibility; use crate::type_::Type; use crate::value::Value; use crate::{attributes, llvm}; @@ -84,11 +85,7 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { fn_type: &'ll Type, ) -> &'ll Value { // Declare C ABI functions with the visibility used by C by default. - let visibility = if self.tcx.sess.default_hidden_visibility() { - llvm::Visibility::Hidden - } else { - llvm::Visibility::Default - }; + let visibility = Visibility::from_generic(self.tcx.sess.default_visibility()); declare_raw_fn(self, name, llvm::CCallConv, unnamed, visibility, fn_type) } @@ -107,11 +104,7 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { unnamed: llvm::UnnamedAddr, fn_type: &'ll Type, ) -> &'ll Value { - let visibility = if self.tcx.sess.default_hidden_visibility() { - llvm::Visibility::Hidden - } else { - llvm::Visibility::Default - }; + let visibility = Visibility::from_generic(self.tcx.sess.default_visibility()); declare_raw_fn(self, name, callconv, unnamed, visibility, fn_type) } diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 9aabfd794ba..d3950df91fb 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -4,6 +4,7 @@ use std::marker::PhantomData; use libc::{c_char, c_int, c_uint, c_ulonglong, c_void, size_t}; +use rustc_target::spec::SymbolVisibility; use super::RustString; use super::debuginfo::{ @@ -133,6 +134,16 @@ pub enum Visibility { Protected = 2, } +impl Visibility { + pub fn from_generic(visibility: SymbolVisibility) -> Self { + match visibility { + SymbolVisibility::Hidden => Visibility::Hidden, + SymbolVisibility::Protected => Visibility::Protected, + SymbolVisibility::Interposable => Visibility::Default, + } + } +} + /// LLVMUnnamedAddr #[repr(C)] pub enum UnnamedAddr { diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index 57aa3deae80..895897eca6b 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -770,7 +770,7 @@ fn test_unstable_options_tracking_hash() { tracked!(crate_attr, vec!["abc".to_string()]); tracked!(cross_crate_inline_threshold, InliningThreshold::Always); tracked!(debug_info_for_profiling, true); - tracked!(default_hidden_visibility, Some(true)); + tracked!(default_visibility, Some(rustc_target::spec::SymbolVisibility::Hidden)); tracked!(dep_info_omit_d_target, true); tracked!(direct_access_external_data, Some(true)); tracked!(dual_proc_macros, true); diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs index 954f746ce5b..56ca9167d4d 100644 --- a/compiler/rustc_middle/src/mir/mono.rs +++ b/compiler/rustc_middle/src/mir/mono.rs @@ -15,6 +15,7 @@ use rustc_query_system::ich::StableHashingContext; use rustc_session::config::OptLevel; use rustc_span::Span; use rustc_span::symbol::Symbol; +use rustc_target::spec::SymbolVisibility; use tracing::debug; use crate::dep_graph::{DepNode, WorkProduct, WorkProductId}; @@ -305,6 +306,16 @@ pub enum Visibility { Protected, } +impl From for Visibility { + fn from(value: SymbolVisibility) -> Self { + match value { + SymbolVisibility::Hidden => Visibility::Hidden, + SymbolVisibility::Protected => Visibility::Protected, + SymbolVisibility::Interposable => Visibility::Default, + } + } +} + impl<'tcx> CodegenUnit<'tcx> { #[inline] pub fn new(name: Symbol) -> CodegenUnit<'tcx> { diff --git a/compiler/rustc_monomorphize/src/partitioning.rs b/compiler/rustc_monomorphize/src/partitioning.rs index ad05cca66ca..5bd484d7bb0 100644 --- a/compiler/rustc_monomorphize/src/partitioning.rs +++ b/compiler/rustc_monomorphize/src/partitioning.rs @@ -904,26 +904,22 @@ fn mono_item_visibility<'tcx>( } fn default_visibility(tcx: TyCtxt<'_>, id: DefId, is_generic: bool) -> Visibility { - if !tcx.sess.default_hidden_visibility() { - return Visibility::Default; - } + let export_level = if is_generic { + // Generic functions never have export-level C. + SymbolExportLevel::Rust + } else { + match tcx.reachable_non_generics(id.krate).get(&id) { + Some(SymbolExportInfo { level: SymbolExportLevel::C, .. }) => SymbolExportLevel::C, + _ => SymbolExportLevel::Rust, + } + }; + match export_level { + // C-export level items remain at `Default` to allow C code to + // access and interpose them. + SymbolExportLevel::C => Visibility::Default, - // Generic functions never have export-level C. - if is_generic { - return Visibility::Hidden; - } - - // Things with export level C don't get instantiated in - // downstream crates. - if !id.is_local() { - return Visibility::Hidden; - } - - // C-export level items remain at `Default`, all other internal - // items become `Hidden`. - match tcx.reachable_non_generics(id.krate).get(&id) { - Some(SymbolExportInfo { level: SymbolExportLevel::C, .. }) => Visibility::Default, - _ => Visibility::Hidden, + // For all other symbols, `default_visibility` determines which visibility to use. + SymbolExportLevel::Rust => tcx.sess.default_visibility().into(), } } diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index b052d8d72c7..0d293415aa9 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -3008,7 +3008,8 @@ pub(crate) mod dep_tracking { use rustc_span::edition::Edition; use rustc_target::spec::{ CodeModel, FramePointer, MergeFunctions, OnBrokenPipe, PanicStrategy, RelocModel, - RelroLevel, SanitizerSet, SplitDebuginfo, StackProtector, TargetTriple, TlsModel, WasmCAbi, + RelroLevel, SanitizerSet, SplitDebuginfo, StackProtector, SymbolVisibility, TargetTriple, + TlsModel, WasmCAbi, }; use super::{ @@ -3101,6 +3102,7 @@ pub(crate) mod dep_tracking { StackProtector, SwitchWithOptPath, SymbolManglingVersion, + SymbolVisibility, RemapPathScopeComponents, SourceFileHashAlgorithm, OutFileName, diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index aac776d2919..1de09b8be4d 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -13,8 +13,8 @@ use rustc_span::edition::Edition; use rustc_span::{RealFileName, SourceFileHashAlgorithm}; use rustc_target::spec::{ CodeModel, FramePointer, LinkerFlavorCli, MergeFunctions, OnBrokenPipe, PanicStrategy, - RelocModel, RelroLevel, SanitizerSet, SplitDebuginfo, StackProtector, TargetTriple, TlsModel, - WasmCAbi, + RelocModel, RelroLevel, SanitizerSet, SplitDebuginfo, StackProtector, SymbolVisibility, + TargetTriple, TlsModel, WasmCAbi, }; use crate::config::*; @@ -416,6 +416,8 @@ mod desc { "one of: `disabled`, `trampolines`, or `aliases`"; pub(crate) const parse_symbol_mangling_version: &str = "one of: `legacy`, `v0` (RFC 2603), or `hashed`"; + pub(crate) const parse_opt_symbol_visibility: &str = + "one of: `hidden`, `protected`, or `interposable`"; pub(crate) const parse_src_file_hash: &str = "either `md5` or `sha1`"; pub(crate) const parse_relocation_model: &str = "one of supported relocation models (`rustc --print relocation-models`)"; @@ -922,6 +924,20 @@ mod parse { true } + pub(crate) fn parse_opt_symbol_visibility( + slot: &mut Option, + v: Option<&str>, + ) -> bool { + if let Some(v) = v { + if let Ok(vis) = SymbolVisibility::from_str(v) { + *slot = Some(vis); + } else { + return false; + } + } + true + } + pub(crate) fn parse_optimization_fuel( slot: &mut Option<(String, u64)>, v: Option<&str>, @@ -1688,8 +1704,8 @@ options! { "compress debug info sections (none, zlib, zstd, default: none)"), deduplicate_diagnostics: bool = (true, parse_bool, [UNTRACKED], "deduplicate identical diagnostics (default: yes)"), - default_hidden_visibility: Option = (None, parse_opt_bool, [TRACKED], - "overrides the `default_hidden_visibility` setting of the target"), + default_visibility: Option = (None, parse_opt_symbol_visibility, [TRACKED], + "overrides the `default_visibility` setting of the target"), dep_info_omit_d_target: bool = (false, parse_bool, [TRACKED], "in dep-info output, omit targets for tracking dependencies of the dep-info files \ themselves (default: no)"), diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index adc28e38462..d67e69fe0fb 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -31,7 +31,8 @@ use rustc_span::{FileNameDisplayPreference, RealFileName, Span, Symbol}; use rustc_target::asm::InlineAsmArch; use rustc_target::spec::{ CodeModel, DebuginfoKind, PanicStrategy, RelocModel, RelroLevel, SanitizerSet, - SmallDataThresholdSupport, SplitDebuginfo, StackProtector, Target, TargetTriple, TlsModel, + SmallDataThresholdSupport, SplitDebuginfo, StackProtector, SymbolVisibility, Target, + TargetTriple, TlsModel, }; use crate::code_stats::CodeStats; @@ -617,12 +618,13 @@ impl Session { } } - /// Whether the default visibility of symbols should be "hidden" rather than "default". - pub fn default_hidden_visibility(&self) -> bool { + /// Returns the default symbol visibility. + pub fn default_visibility(&self) -> SymbolVisibility { self.opts .unstable_opts - .default_hidden_visibility - .unwrap_or(self.target.options.default_hidden_visibility) + .default_visibility + .or(self.target.options.default_visibility) + .unwrap_or(SymbolVisibility::Interposable) } } diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index f327c1fd179..d1fcfe4adef 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -830,6 +830,46 @@ impl RelroLevel { } } +#[derive(Clone, Copy, Debug, PartialEq, Hash)] +pub enum SymbolVisibility { + Hidden, + Protected, + Interposable, +} + +impl SymbolVisibility { + pub fn desc(&self) -> &str { + match *self { + SymbolVisibility::Hidden => "hidden", + SymbolVisibility::Protected => "protected", + SymbolVisibility::Interposable => "interposable", + } + } +} + +impl FromStr for SymbolVisibility { + type Err = (); + + fn from_str(s: &str) -> Result { + match s { + "hidden" => Ok(SymbolVisibility::Hidden), + "protected" => Ok(SymbolVisibility::Protected), + "interposable" => Ok(SymbolVisibility::Interposable), + _ => Err(()), + } + } +} + +impl ToJson for SymbolVisibility { + fn to_json(&self) -> Json { + match *self { + SymbolVisibility::Hidden => "hidden".to_json(), + SymbolVisibility::Protected => "protected".to_json(), + SymbolVisibility::Interposable => "interposable".to_json(), + } + } +} + impl FromStr for RelroLevel { type Err = (); @@ -2326,13 +2366,12 @@ pub struct TargetOptions { /// for this target unconditionally. pub no_builtins: bool, - /// The default visibility for symbols in this target should be "hidden" - /// rather than "default". + /// The default visibility for symbols in this target. /// - /// This value typically shouldn't be accessed directly, but through - /// the `rustc_session::Session::default_hidden_visibility` method, which - /// allows `rustc` users to override this setting using cmdline flags. - pub default_hidden_visibility: bool, + /// This value typically shouldn't be accessed directly, but through the + /// `rustc_session::Session::default_visibility` method, which allows `rustc` users to override + /// this setting using cmdline flags. + pub default_visibility: Option, /// Whether a .debug_gdb_scripts section will be added to the output object file pub emit_debug_gdb_scripts: bool, @@ -2623,7 +2662,7 @@ impl Default for TargetOptions { requires_lto: false, singlethread: false, no_builtins: false, - default_hidden_visibility: false, + default_visibility: None, emit_debug_gdb_scripts: true, requires_uwtable: false, default_uwtable: false, @@ -2963,6 +3002,18 @@ impl Target { Some(Ok(())) })).unwrap_or(Ok(())) } ); + ($key_name:ident, Option) => ( { + let name = (stringify!($key_name)).replace("_", "-"); + obj.remove(&name).and_then(|o| o.as_str().and_then(|s| { + match s.parse::() { + Ok(level) => base.$key_name = Some(level), + _ => return Some(Err(format!("'{}' is not a valid value for \ + symbol-visibility. Use 'hidden', 'protected, or 'interposable'.", + s))), + } + Some(Ok(())) + })).unwrap_or(Ok(())) + } ); ($key_name:ident, DebuginfoKind) => ( { let name = (stringify!($key_name)).replace("_", "-"); obj.remove(&name).and_then(|o| o.as_str().and_then(|s| { @@ -3353,7 +3404,7 @@ impl Target { key!(requires_lto, bool); key!(singlethread, bool); key!(no_builtins, bool); - key!(default_hidden_visibility, bool); + key!(default_visibility, Option)?; key!(emit_debug_gdb_scripts, bool); key!(requires_uwtable, bool); key!(default_uwtable, bool); @@ -3633,7 +3684,7 @@ impl ToJson for Target { target_option_val!(requires_lto); target_option_val!(singlethread); target_option_val!(no_builtins); - target_option_val!(default_hidden_visibility); + target_option_val!(default_visibility); target_option_val!(emit_debug_gdb_scripts); target_option_val!(requires_uwtable); target_option_val!(default_uwtable); diff --git a/src/doc/unstable-book/src/compiler-flags/default-hidden-visibility.md b/src/doc/unstable-book/src/compiler-flags/default-hidden-visibility.md deleted file mode 100644 index 579add4a9d9..00000000000 --- a/src/doc/unstable-book/src/compiler-flags/default-hidden-visibility.md +++ /dev/null @@ -1,12 +0,0 @@ -# `default-hidden-visibility` - -The tracking issue for this feature is: https://github.com/rust-lang/compiler-team/issues/656 - ------------------------- - -This flag can be used to override the target's -[`default_hidden_visibility`](https://doc.rust-lang.org/beta/nightly-rustc/rustc_target/spec/struct.TargetOptions.html#structfield.default_hidden_visibility) -setting. -Using `-Zdefault_hidden_visibility=yes` is roughly equivalent to Clang's -[`-fvisibility=hidden`](https://clang.llvm.org/docs/ClangCommandLineReference.html#cmdoption-clang-fvisibility) -cmdline flag. diff --git a/src/doc/unstable-book/src/compiler-flags/default-visibility.md b/src/doc/unstable-book/src/compiler-flags/default-visibility.md new file mode 100644 index 00000000000..ad9e5d84bba --- /dev/null +++ b/src/doc/unstable-book/src/compiler-flags/default-visibility.md @@ -0,0 +1,44 @@ +# `default-visibility` + +The tracking issue for this feature is: https://github.com/rust-lang/rust/issues/131090 + +------------------------ + +This flag can be used to override the target's +[`default_visibility`](https://doc.rust-lang.org/beta/nightly-rustc/rustc_target/spec/struct.TargetOptions.html#structfield.default_visibility) +setting. + +This option only affects building of shared objects and should have no effect on executables. + +Visibility an be set to one of three options: + +* protected +* hidden +* interposable + +## Hidden visibility + +Using `-Zdefault-visibility=hidden` is roughly equivalent to Clang's +[`-fvisibility=hidden`](https://clang.llvm.org/docs/ClangCommandLineReference.html#cmdoption-clang-fvisibility) +cmdline flag. Hidden symbols will not be exported from the created shared object, so cannot be +referenced from other shared objects or from executables. + +## Protected visibility + +Using `-Zdefault-visibility=protected` will cause rust-mangled symbols to be emitted with +"protected" visibility. This signals the compiler, the linker and the runtime linker that these +symbols cannot be overridden by the executable or by other shared objects earlier in the load order. + +This will allow the compiler to emit direct references to symbols, which may improve performance. It +also removes the need for these symbols to be resolved when a shared object built with this option +is loaded. + +Using protected visibility when linking with GNU ld prior to 2.40 will result in linker errors when +building for Linux. Other linkers such as LLD are not affected. + +## Interposable + +Using `-Zdefault-visibility=interposable` will cause symbols to be emitted with "default" +visibility. On platforms that support it, this makes it so that symbols can be interposed, which +means that they can be overridden by symbols with the same name from the executable or by other +shared objects earier in the load order. diff --git a/tests/codegen/default-hidden-visibility.rs b/tests/codegen/default-visibility.rs similarity index 60% rename from tests/codegen/default-hidden-visibility.rs rename to tests/codegen/default-visibility.rs index 2bea8f62a40..884d386ec20 100644 --- a/tests/codegen/default-hidden-visibility.rs +++ b/tests/codegen/default-visibility.rs @@ -1,11 +1,12 @@ -// Verifies that `Session::default_hidden_visibility` is affected when using the related cmdline -// flag. This is a regression test for https://github.com/rust-lang/compiler-team/issues/656. See +// Verifies that `Session::default_visibility` is affected when using the related cmdline +// flag. This is a regression test for https://github.com/rust-lang/compiler-team/issues/782. See // also https://github.com/rust-lang/rust/issues/73295 and // https://github.com/rust-lang/rust/issues/37530. -//@ revisions:DEFAULT YES NO -//@[YES] compile-flags: -Zdefault-hidden-visibility=yes -//@[NO] compile-flags: -Zdefault-hidden-visibility=no +//@ revisions:DEFAULT HIDDEN PROTECTED INTERPOSABLE +//@[HIDDEN] compile-flags: -Zdefault-visibility=hidden +//@[PROTECTED] compile-flags: -Zdefault-visibility=protected +//@[INTERPOSABLE] compile-flags: -Zdefault-visibility=interposable // The test scenario is specifically about visibility of symbols exported out of dynamically linked // libraries. @@ -26,6 +27,7 @@ pub static tested_symbol: [u8; 6] = *b"foobar"; // //@ only-x86_64-unknown-linux-gnu -// DEFAULT: @{{.*}}default_hidden_visibility{{.*}}tested_symbol{{.*}} = constant -// YES: @{{.*}}default_hidden_visibility{{.*}}tested_symbol{{.*}} = hidden constant -// NO: @{{.*}}default_hidden_visibility{{.*}}tested_symbol{{.*}} = constant +// HIDDEN: @{{.*}}default_visibility{{.*}}tested_symbol{{.*}} = hidden constant +// PROTECTED: @{{.*}}default_visibility{{.*}}tested_symbol{{.*}} = protected constant +// INTERPOSABLE: @{{.*}}default_visibility{{.*}}tested_symbol{{.*}} = constant +// DEFAULT: @{{.*}}default_visibility{{.*}}tested_symbol{{.*}} = constant From 13881f5404037e25a88d0b79a836e232dc73b1fc Mon Sep 17 00:00:00 2001 From: lcnr Date: Mon, 30 Sep 2024 10:18:55 +0200 Subject: [PATCH 459/683] add caches to multiple type folders --- .../rustc_infer/src/infer/relate/combine.rs | 7 +- .../src/infer/relate/type_relating.rs | 41 ++++++++- compiler/rustc_infer/src/infer/resolve.rs | 14 ++- compiler/rustc_middle/src/ty/fold.rs | 25 ++++- .../rustc_next_trait_solver/src/resolve.rs | 11 ++- .../src/solve/eval_ctxt/mod.rs | 51 +++++++--- .../src/data_structures/delayed_map.rs | 92 +++++++++++++++++++ .../mod.rs} | 3 + 8 files changed, 222 insertions(+), 22 deletions(-) create mode 100644 compiler/rustc_type_ir/src/data_structures/delayed_map.rs rename compiler/rustc_type_ir/src/{data_structures.rs => data_structures/mod.rs} (92%) diff --git a/compiler/rustc_infer/src/infer/relate/combine.rs b/compiler/rustc_infer/src/infer/relate/combine.rs index e75d7b7db14..3b2ef3fe981 100644 --- a/compiler/rustc_infer/src/infer/relate/combine.rs +++ b/compiler/rustc_infer/src/infer/relate/combine.rs @@ -36,10 +36,15 @@ use crate::traits::{Obligation, PredicateObligation}; #[derive(Clone)] pub struct CombineFields<'infcx, 'tcx> { pub infcx: &'infcx InferCtxt<'tcx>, + // Immutable fields pub trace: TypeTrace<'tcx>, pub param_env: ty::ParamEnv<'tcx>, - pub goals: Vec>>, pub define_opaque_types: DefineOpaqueTypes, + // Mutable fields + // + // Adding any additional field likely requires + // changes to the cache of `TypeRelating`. + pub goals: Vec>>, } impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> { diff --git a/compiler/rustc_infer/src/infer/relate/type_relating.rs b/compiler/rustc_infer/src/infer/relate/type_relating.rs index a402a8009ff..c8ced4a2cda 100644 --- a/compiler/rustc_infer/src/infer/relate/type_relating.rs +++ b/compiler/rustc_infer/src/infer/relate/type_relating.rs @@ -4,6 +4,7 @@ use rustc_middle::ty::relate::{ }; use rustc_middle::ty::{self, Ty, TyCtxt, TyVar}; use rustc_span::Span; +use rustc_type_ir::data_structures::DelayedSet; use tracing::{debug, instrument}; use super::combine::CombineFields; @@ -13,9 +14,36 @@ use crate::infer::{DefineOpaqueTypes, InferCtxt, SubregionOrigin}; /// Enforce that `a` is equal to or a subtype of `b`. pub struct TypeRelating<'combine, 'a, 'tcx> { + // Partially mutable. fields: &'combine mut CombineFields<'a, 'tcx>, + + // Immutable fields. structurally_relate_aliases: StructurallyRelateAliases, ambient_variance: ty::Variance, + + /// The cache has only tracks the `ambient_variance` as its the + /// only field which is mutable and which meaningfully changes + /// the result when relating types. + /// + /// The cache does not track whether the state of the + /// `InferCtxt` has been changed or whether we've added any + /// obligations to `self.fields.goals`. Whether a goal is added + /// once or multiple times is not really meaningful. + /// + /// Changes in the inference state may delay some type inference to + /// the next fulfillment loop. Given that this loop is already + /// necessary, this is also not a meaningful change. Consider + /// the following three relations: + /// ```text + /// Vec sub Vec + /// ?0 eq u32 + /// Vec sub Vec + /// ``` + /// Without a cache, the second `Vec sub Vec` would eagerly + /// constrain `?1` to `u32`. When using the cache entry from the + /// first time we've related these types, this only happens when + /// later proving the `Subtype(?0, ?1)` goal from the first relation. + cache: DelayedSet<(ty::Variance, Ty<'tcx>, Ty<'tcx>)>, } impl<'combine, 'infcx, 'tcx> TypeRelating<'combine, 'infcx, 'tcx> { @@ -24,7 +52,12 @@ impl<'combine, 'infcx, 'tcx> TypeRelating<'combine, 'infcx, 'tcx> { structurally_relate_aliases: StructurallyRelateAliases, ambient_variance: ty::Variance, ) -> TypeRelating<'combine, 'infcx, 'tcx> { - TypeRelating { fields: f, structurally_relate_aliases, ambient_variance } + TypeRelating { + fields: f, + structurally_relate_aliases, + ambient_variance, + cache: Default::default(), + } } } @@ -78,6 +111,10 @@ impl<'tcx> TypeRelation> for TypeRelating<'_, '_, 'tcx> { let a = infcx.shallow_resolve(a); let b = infcx.shallow_resolve(b); + if self.cache.contains(&(self.ambient_variance, a, b)) { + return Ok(a); + } + match (a.kind(), b.kind()) { (&ty::Infer(TyVar(a_id)), &ty::Infer(TyVar(b_id))) => { match self.ambient_variance { @@ -160,6 +197,8 @@ impl<'tcx> TypeRelation> for TypeRelating<'_, '_, 'tcx> { } } + assert!(self.cache.insert((self.ambient_variance, a, b))); + Ok(a) } diff --git a/compiler/rustc_infer/src/infer/resolve.rs b/compiler/rustc_infer/src/infer/resolve.rs index 34625ffb778..671a66d504f 100644 --- a/compiler/rustc_infer/src/infer/resolve.rs +++ b/compiler/rustc_infer/src/infer/resolve.rs @@ -2,6 +2,7 @@ use rustc_middle::bug; use rustc_middle::ty::fold::{FallibleTypeFolder, TypeFolder, TypeSuperFoldable}; use rustc_middle::ty::visit::TypeVisitableExt; use rustc_middle::ty::{self, Const, InferConst, Ty, TyCtxt, TypeFoldable}; +use rustc_type_ir::data_structures::DelayedMap; use super::{FixupError, FixupResult, InferCtxt}; @@ -15,12 +16,15 @@ use super::{FixupError, FixupResult, InferCtxt}; /// points for correctness. pub struct OpportunisticVarResolver<'a, 'tcx> { infcx: &'a InferCtxt<'tcx>, + /// We're able to use a cache here as the folder does + /// not have any mutable state. + cache: DelayedMap, Ty<'tcx>>, } impl<'a, 'tcx> OpportunisticVarResolver<'a, 'tcx> { #[inline] pub fn new(infcx: &'a InferCtxt<'tcx>) -> Self { - OpportunisticVarResolver { infcx } + OpportunisticVarResolver { infcx, cache: Default::default() } } } @@ -33,9 +37,13 @@ impl<'a, 'tcx> TypeFolder> for OpportunisticVarResolver<'a, 'tcx> { fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { if !t.has_non_region_infer() { t // micro-optimize -- if there is nothing in this type that this fold affects... + } else if let Some(&ty) = self.cache.get(&t) { + return ty; } else { - let t = self.infcx.shallow_resolve(t); - t.super_fold_with(self) + let shallow = self.infcx.shallow_resolve(t); + let res = shallow.super_fold_with(self); + assert!(self.cache.insert(t, res)); + res } } diff --git a/compiler/rustc_middle/src/ty/fold.rs b/compiler/rustc_middle/src/ty/fold.rs index 2ee7497497a..e152d3f5fbe 100644 --- a/compiler/rustc_middle/src/ty/fold.rs +++ b/compiler/rustc_middle/src/ty/fold.rs @@ -1,5 +1,6 @@ use rustc_data_structures::fx::FxIndexMap; use rustc_hir::def_id::DefId; +use rustc_type_ir::data_structures::DelayedMap; pub use rustc_type_ir::fold::{ FallibleTypeFolder, TypeFoldable, TypeFolder, TypeSuperFoldable, shift_region, shift_vars, }; @@ -131,12 +132,20 @@ impl<'a, 'tcx> TypeFolder> for RegionFolder<'a, 'tcx> { /////////////////////////////////////////////////////////////////////////// // Bound vars replacer +/// A delegate used when instantiating bound vars. +/// +/// Any implementation must make sure that each bound variable always +/// gets mapped to the same result. `BoundVarReplacer` caches by using +/// a `DelayedMap` which does not cache the first few types it encounters. pub trait BoundVarReplacerDelegate<'tcx> { fn replace_region(&mut self, br: ty::BoundRegion) -> ty::Region<'tcx>; fn replace_ty(&mut self, bt: ty::BoundTy) -> Ty<'tcx>; fn replace_const(&mut self, bv: ty::BoundVar) -> ty::Const<'tcx>; } +/// A simple delegate taking 3 mutable functions. The used functions must +/// always return the same result for each bound variable, no matter how +/// frequently they are called. pub struct FnMutDelegate<'a, 'tcx> { pub regions: &'a mut (dyn FnMut(ty::BoundRegion) -> ty::Region<'tcx> + 'a), pub types: &'a mut (dyn FnMut(ty::BoundTy) -> Ty<'tcx> + 'a), @@ -164,11 +173,15 @@ struct BoundVarReplacer<'tcx, D> { current_index: ty::DebruijnIndex, delegate: D, + + /// This cache only tracks the `DebruijnIndex` and assumes that it does not matter + /// for the delegate how often its methods get used. + cache: DelayedMap<(ty::DebruijnIndex, Ty<'tcx>), Ty<'tcx>>, } impl<'tcx, D: BoundVarReplacerDelegate<'tcx>> BoundVarReplacer<'tcx, D> { fn new(tcx: TyCtxt<'tcx>, delegate: D) -> Self { - BoundVarReplacer { tcx, current_index: ty::INNERMOST, delegate } + BoundVarReplacer { tcx, current_index: ty::INNERMOST, delegate, cache: Default::default() } } } @@ -197,7 +210,15 @@ where debug_assert!(!ty.has_vars_bound_above(ty::INNERMOST)); ty::fold::shift_vars(self.tcx, ty, self.current_index.as_u32()) } - _ if t.has_vars_bound_at_or_above(self.current_index) => t.super_fold_with(self), + _ if t.has_vars_bound_at_or_above(self.current_index) => { + if let Some(&ty) = self.cache.get(&(self.current_index, t)) { + return ty; + } + + let res = t.super_fold_with(self); + assert!(self.cache.insert((self.current_index, t), res)); + res + } _ => t, } } diff --git a/compiler/rustc_next_trait_solver/src/resolve.rs b/compiler/rustc_next_trait_solver/src/resolve.rs index 132b7400300..a37066cec66 100644 --- a/compiler/rustc_next_trait_solver/src/resolve.rs +++ b/compiler/rustc_next_trait_solver/src/resolve.rs @@ -1,3 +1,4 @@ +use rustc_type_ir::data_structures::DelayedMap; use rustc_type_ir::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable}; use rustc_type_ir::inherent::*; use rustc_type_ir::visit::TypeVisitableExt; @@ -15,11 +16,12 @@ where I: Interner, { delegate: &'a D, + cache: DelayedMap, } impl<'a, D: SolverDelegate> EagerResolver<'a, D> { pub fn new(delegate: &'a D) -> Self { - EagerResolver { delegate } + EagerResolver { delegate, cache: Default::default() } } } @@ -42,7 +44,12 @@ impl, I: Interner> TypeFolder for EagerResolv ty::Infer(ty::FloatVar(vid)) => self.delegate.opportunistic_resolve_float_var(vid), _ => { if t.has_infer() { - t.super_fold_with(self) + if let Some(&ty) = self.cache.get(&t) { + return ty; + } + let res = t.super_fold_with(self); + assert!(self.cache.insert(t, res)); + res } else { t } diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs index 12ad0724b5c..12b4b3cb3a9 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs @@ -3,7 +3,7 @@ use std::ops::ControlFlow; use derive_where::derive_where; #[cfg(feature = "nightly")] use rustc_macros::{HashStable_NoContext, TyDecodable, TyEncodable}; -use rustc_type_ir::data_structures::ensure_sufficient_stack; +use rustc_type_ir::data_structures::{HashMap, HashSet, ensure_sufficient_stack}; use rustc_type_ir::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable}; use rustc_type_ir::inherent::*; use rustc_type_ir::relate::Relate; @@ -579,18 +579,16 @@ where #[instrument(level = "trace", skip(self))] pub(super) fn add_normalizes_to_goal(&mut self, mut goal: Goal>) { - goal.predicate = goal - .predicate - .fold_with(&mut ReplaceAliasWithInfer { ecx: self, param_env: goal.param_env }); + goal.predicate = + goal.predicate.fold_with(&mut ReplaceAliasWithInfer::new(self, goal.param_env)); self.inspect.add_normalizes_to_goal(self.delegate, self.max_input_universe, goal); self.nested_goals.normalizes_to_goals.push(goal); } #[instrument(level = "debug", skip(self))] pub(super) fn add_goal(&mut self, source: GoalSource, mut goal: Goal) { - goal.predicate = goal - .predicate - .fold_with(&mut ReplaceAliasWithInfer { ecx: self, param_env: goal.param_env }); + goal.predicate = + goal.predicate.fold_with(&mut ReplaceAliasWithInfer::new(self, goal.param_env)); self.inspect.add_goal(self.delegate, self.max_input_universe, source, goal); self.nested_goals.goals.push((source, goal)); } @@ -654,6 +652,7 @@ where term: I::Term, universe_of_term: ty::UniverseIndex, delegate: &'a D, + cache: HashSet, } impl, I: Interner> ContainsTermOrNotNameable<'_, D, I> { @@ -671,6 +670,10 @@ where { type Result = ControlFlow<()>; fn visit_ty(&mut self, t: I::Ty) -> Self::Result { + if self.cache.contains(&t) { + return ControlFlow::Continue(()); + } + match t.kind() { ty::Infer(ty::TyVar(vid)) => { if let ty::TermKind::Ty(term) = self.term.kind() { @@ -683,17 +686,18 @@ where } } - self.check_nameable(self.delegate.universe_of_ty(vid).unwrap()) + self.check_nameable(self.delegate.universe_of_ty(vid).unwrap())?; } - ty::Placeholder(p) => self.check_nameable(p.universe()), + ty::Placeholder(p) => self.check_nameable(p.universe())?, _ => { if t.has_non_region_infer() || t.has_placeholders() { - t.super_visit_with(self) - } else { - ControlFlow::Continue(()) + t.super_visit_with(self)? } } } + + assert!(self.cache.insert(t)); + ControlFlow::Continue(()) } fn visit_const(&mut self, c: I::Const) -> Self::Result { @@ -728,6 +732,7 @@ where delegate: self.delegate, universe_of_term, term: goal.predicate.term, + cache: Default::default(), }; goal.predicate.alias.visit_with(&mut visitor).is_continue() && goal.param_env.visit_with(&mut visitor).is_continue() @@ -1015,6 +1020,17 @@ where { ecx: &'me mut EvalCtxt<'a, D>, param_env: I::ParamEnv, + cache: HashMap, +} + +impl<'me, 'a, D, I> ReplaceAliasWithInfer<'me, 'a, D, I> +where + D: SolverDelegate, + I: Interner, +{ + fn new(ecx: &'me mut EvalCtxt<'a, D>, param_env: I::ParamEnv) -> Self { + ReplaceAliasWithInfer { ecx, param_env, cache: Default::default() } + } } impl TypeFolder for ReplaceAliasWithInfer<'_, '_, D, I> @@ -1041,7 +1057,16 @@ where ); infer_ty } - _ => ty.super_fold_with(self), + _ if ty.has_aliases() => { + if let Some(&entry) = self.cache.get(&ty) { + return entry; + } + + let res = ty.super_fold_with(self); + assert!(self.cache.insert(ty, res).is_none()); + res + } + _ => ty, } } diff --git a/compiler/rustc_type_ir/src/data_structures/delayed_map.rs b/compiler/rustc_type_ir/src/data_structures/delayed_map.rs new file mode 100644 index 00000000000..7e7406e3706 --- /dev/null +++ b/compiler/rustc_type_ir/src/data_structures/delayed_map.rs @@ -0,0 +1,92 @@ +use std::hash::Hash; + +use crate::data_structures::{HashMap, HashSet}; + +const CACHE_CUTOFF: u32 = 32; + +/// A hashmap which only starts hashing after ignoring the first few inputs. +/// +/// This is used in type folders as in nearly all cases caching is not worth it +/// as nearly all folded types are tiny. However, there are very rare incredibly +/// large types for which caching is necessary to avoid hangs. +#[derive(Debug)] +pub struct DelayedMap { + cache: HashMap, + count: u32, +} + +impl Default for DelayedMap { + fn default() -> Self { + DelayedMap { cache: Default::default(), count: 0 } + } +} + +impl DelayedMap { + #[inline(always)] + pub fn insert(&mut self, key: K, value: V) -> bool { + if self.count >= CACHE_CUTOFF { + self.cold_insert(key, value) + } else { + self.count += 1; + true + } + } + + #[cold] + #[inline(never)] + fn cold_insert(&mut self, key: K, value: V) -> bool { + self.cache.insert(key, value).is_none() + } + + #[inline(always)] + pub fn get(&self, key: &K) -> Option<&V> { + if self.cache.is_empty() { None } else { self.cold_get(key) } + } + + #[cold] + #[inline(never)] + fn cold_get(&self, key: &K) -> Option<&V> { + self.cache.get(key) + } +} + +#[derive(Debug)] +pub struct DelayedSet { + cache: HashSet, + count: u32, +} + +impl Default for DelayedSet { + fn default() -> Self { + DelayedSet { cache: Default::default(), count: 0 } + } +} + +impl DelayedSet { + #[inline(always)] + pub fn insert(&mut self, value: T) -> bool { + if self.count >= CACHE_CUTOFF { + self.cold_insert(value) + } else { + self.count += 1; + true + } + } + + #[cold] + #[inline(never)] + fn cold_insert(&mut self, value: T) -> bool { + self.cache.insert(value) + } + + #[inline(always)] + pub fn contains(&self, value: &T) -> bool { + !self.cache.is_empty() && self.cold_contains(value) + } + + #[cold] + #[inline(never)] + fn cold_contains(&self, value: &T) -> bool { + self.cache.contains(value) + } +} diff --git a/compiler/rustc_type_ir/src/data_structures.rs b/compiler/rustc_type_ir/src/data_structures/mod.rs similarity index 92% rename from compiler/rustc_type_ir/src/data_structures.rs rename to compiler/rustc_type_ir/src/data_structures/mod.rs index 96036e53b0a..d9766d91845 100644 --- a/compiler/rustc_type_ir/src/data_structures.rs +++ b/compiler/rustc_type_ir/src/data_structures/mod.rs @@ -6,6 +6,8 @@ pub use rustc_hash::{FxHashMap as HashMap, FxHashSet as HashSet}; pub type IndexMap = indexmap::IndexMap>; pub type IndexSet = indexmap::IndexSet>; +mod delayed_map; + #[cfg(feature = "nightly")] mod impl_ { pub use rustc_data_structures::sso::{SsoHashMap, SsoHashSet}; @@ -24,4 +26,5 @@ mod impl_ { } } +pub use delayed_map::{DelayedMap, DelayedSet}; pub use impl_::*; From a7b114420c70a1c0bc082d078d5284af6ff4af23 Mon Sep 17 00:00:00 2001 From: lcnr Date: Mon, 30 Sep 2024 10:19:00 +0200 Subject: [PATCH 460/683] add tests --- .../coherence-alias-hang-with-region.rs | 30 ++++++++++++++++ .../overflow}/coherence-alias-hang.rs | 11 ++++-- .../next-solver/overflow/nalgebra-hang.rs | 35 +++++++++++++++++++ 3 files changed, 74 insertions(+), 2 deletions(-) create mode 100644 tests/ui/traits/next-solver/overflow/coherence-alias-hang-with-region.rs rename tests/ui/traits/{ => next-solver/overflow}/coherence-alias-hang.rs (57%) create mode 100644 tests/ui/traits/next-solver/overflow/nalgebra-hang.rs diff --git a/tests/ui/traits/next-solver/overflow/coherence-alias-hang-with-region.rs b/tests/ui/traits/next-solver/overflow/coherence-alias-hang-with-region.rs new file mode 100644 index 00000000000..4ade8a13ca9 --- /dev/null +++ b/tests/ui/traits/next-solver/overflow/coherence-alias-hang-with-region.rs @@ -0,0 +1,30 @@ +//@ check-pass +//@ revisions: ai ia ii +//@ compile-flags: -Znext-solver=coherence + +// Regression test for nalgebra hang . + +#![feature(lazy_type_alias)] +#![allow(incomplete_features)] + +type Id = T; +trait NotImplemented {} + +struct W<'a, T: ?Sized, U: ?Sized>(&'a (), *const T, *const U); +trait Trait { + type Assoc: ?Sized; +} +impl<'a, T: ?Sized + Trait> Trait for W<'a, T, T> { + #[cfg(ai)] + type Assoc = W<'a, T::Assoc, Id>; + #[cfg(ia)] + type Assoc = W<'a, Id, T::Assoc>; + #[cfg(ii)] + type Assoc = W<'a, Id, Id>; +} + +trait Overlap {} +impl<'a, T: ?Sized> Overlap for W<'a, T, T> {} +impl Overlap for T {} + +fn main() {} diff --git a/tests/ui/traits/coherence-alias-hang.rs b/tests/ui/traits/next-solver/overflow/coherence-alias-hang.rs similarity index 57% rename from tests/ui/traits/coherence-alias-hang.rs rename to tests/ui/traits/next-solver/overflow/coherence-alias-hang.rs index c2b4d2e42d2..0d5f42231e4 100644 --- a/tests/ui/traits/coherence-alias-hang.rs +++ b/tests/ui/traits/next-solver/overflow/coherence-alias-hang.rs @@ -1,6 +1,8 @@ //@ check-pass -//@ revisions: current next -//[next]@ compile-flags: -Znext-solver +//@ revisions: ai_current ai_next ia_current ia_next ii_current ii_next +//@[ai_next] compile-flags: -Znext-solver +//@[ia_next] compile-flags: -Znext-solver +//@[ii_next] compile-flags: -Znext-solver // Regression test for nalgebra hang . @@ -15,7 +17,12 @@ trait Trait { type Assoc: ?Sized; } impl Trait for W { + #[cfg(any(ai_current, ai_next))] type Assoc = W>; + #[cfg(any(ia_current, ia_next))] + type Assoc = W, T::Assoc>; + #[cfg(any(ii_current, ii_next))] + type Assoc = W, Id>; } trait Overlap {} diff --git a/tests/ui/traits/next-solver/overflow/nalgebra-hang.rs b/tests/ui/traits/next-solver/overflow/nalgebra-hang.rs new file mode 100644 index 00000000000..4bc6039c57d --- /dev/null +++ b/tests/ui/traits/next-solver/overflow/nalgebra-hang.rs @@ -0,0 +1,35 @@ +//@ check-pass +//@ revisions: current next +//@[next] compile-flags: -Znext-solver + +// Regression test for nalgebra hang from +// https://github.com/rust-lang/rust/pull/130654#issuecomment-2365465354 +trait HasAlias {} + +struct Dummy; +trait DummyTrait { + type DummyType; +} +impl DummyTrait for Dummy { + type DummyType = T; +} +type AliasOf = ::DummyType; + +struct Matrix(T, S); +type OMatrix = Matrix>; + +impl HasAlias for OMatrix {} + +trait SimdValue { + type Element; +} +impl> SimdValue for OMatrix { + type Element = OMatrix; +} + +trait Unimplemented {} +pub trait MyFrom {} +impl MyFrom for T {} +impl> MyFrom for OMatrix {} + +fn main() {} From f06a46ee4dc7587c5f353dc2e396e996068cebac Mon Sep 17 00:00:00 2001 From: y21 <30553356+y21@users.noreply.github.com> Date: Thu, 26 Sep 2024 14:08:22 +0200 Subject: [PATCH 461/683] consider `wait()` calls in nested bodies --- clippy_lints/src/zombie_processes.rs | 7 +++++++ tests/ui/zombie_processes.rs | 7 +++++++ 2 files changed, 14 insertions(+) diff --git a/clippy_lints/src/zombie_processes.rs b/clippy_lints/src/zombie_processes.rs index 58d71bee299..8d9241cc7d9 100644 --- a/clippy_lints/src/zombie_processes.rs +++ b/clippy_lints/src/zombie_processes.rs @@ -6,6 +6,7 @@ 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 std::ops::ControlFlow; @@ -119,6 +120,7 @@ enum WaitFinder<'a, 'tcx> { } impl<'tcx> Visitor<'tcx> for WaitFinder<'_, 'tcx> { + type NestedFilter = nested_filter::OnlyBodies; type Result = ControlFlow; fn visit_local(&mut self, l: &'tcx LetStmt<'tcx>) -> Self::Result { @@ -204,6 +206,11 @@ impl<'tcx> Visitor<'tcx> for WaitFinder<'_, 'tcx> { walk_expr(self, ex) } + + fn nested_visit_map(&mut self) -> Self::Map { + let (Self::Found(cx, _) | Self::WalkUpTo(cx, _)) = self; + cx.tcx.hir() + } } /// This function has shared logic between the different kinds of nodes that can trigger the lint. diff --git a/tests/ui/zombie_processes.rs b/tests/ui/zombie_processes.rs index a2abc7fc3a1..b41bcce3f7f 100644 --- a/tests/ui/zombie_processes.rs +++ b/tests/ui/zombie_processes.rs @@ -131,6 +131,13 @@ fn main() { } x.wait().unwrap(); } + + { + let mut x = Command::new("").spawn().unwrap(); + std::thread::spawn(move || { + x.wait().unwrap(); + }); + } } fn process_child(c: Child) { From 30ff4006e136123645b9fcca511b13652b8a5f98 Mon Sep 17 00:00:00 2001 From: Slanterns Date: Wed, 2 Oct 2024 01:27:11 +0800 Subject: [PATCH 462/683] update `Literal`'s intro --- library/proc_macro/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/proc_macro/src/lib.rs b/library/proc_macro/src/lib.rs index 5522d556a59..72b597a8083 100644 --- a/library/proc_macro/src/lib.rs +++ b/library/proc_macro/src/lib.rs @@ -1166,7 +1166,7 @@ impl fmt::Debug for Ident { } } -/// A literal string (`"hello"`), byte string (`b"hello"`), +/// A literal string (`"hello"`), byte string (`b"hello"`), C string (`c"hello"`), /// character (`'a'`), byte character (`b'a'`), an integer or floating point number /// with or without a suffix (`1`, `1u8`, `2.3`, `2.3f32`). /// Boolean literals like `true` and `false` do not belong here, they are `Ident`s. From 1c7e8246d53da3b68589c9fe2aa2c830fae3f164 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?= Date: Tue, 1 Oct 2024 18:35:26 +0000 Subject: [PATCH 463/683] Revert "Drop conditionally applied cargo `-Zon-broken-pipe=kill` flags" This reverts commit 5a7058c5a542ec42d1fa9b524f7b4f7d6845d1e9. In [#131059] we found out that `-Zon-broken-pipe=kill` is actually **load-bearing** [1] for (at least) `rustc` and `rustdoc` to have the kill-process-on-broken-pipe behavior, e.g. `rustc --print=sysroot | false` will ICE and `rustdoc --print=sysroot | false` will panic on a broken pipe. [#131059]: https://github.com/rust-lang/rust/issues/131059 [1]: https://github.com/rust-lang/rust/issues/131059#issuecomment-2385822033 --- src/bootstrap/src/core/build_steps/compile.rs | 4 ++++ src/bootstrap/src/core/build_steps/tool.rs | 11 +++++++---- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index bb1d8d27928..eaa982d4e2b 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -1053,6 +1053,10 @@ pub fn rustc_cargo( cargo.rustdocflag("-Zcrate-attr=warn(rust_2018_idioms)"); + // If the rustc output is piped to e.g. `head -n1` we want the process to be + // killed, rather than having an error bubble up and cause a panic. + cargo.rustflag("-Zon-broken-pipe=kill"); + if builder.config.llvm_enzyme { cargo.rustflag("-l").rustflag("Enzyme-19"); } diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs index fa2c1b8360f..64dfe054d9c 100644 --- a/src/bootstrap/src/core/build_steps/tool.rs +++ b/src/bootstrap/src/core/build_steps/tool.rs @@ -200,10 +200,6 @@ pub fn prepare_tool_cargo( cargo.arg("--features").arg(features.join(", ")); } - // Warning: be very careful with RUSTFLAGS or command-line options, as conditionally applied - // RUSTFLAGS or cli flags can lead to hard-to-diagnose rebuilds due to flag differences, causing - // previous tool build artifacts to get invalidated. - // Enable internal lints for clippy and rustdoc // NOTE: this doesn't enable lints for any other tools unless they explicitly add `#![warn(rustc::internal)]` // See https://github.com/rust-lang/rust/pull/80573#issuecomment-754010776 @@ -213,6 +209,13 @@ pub fn prepare_tool_cargo( // See https://github.com/rust-lang/rust/issues/116538 cargo.rustflag("-Zunstable-options"); + // `-Zon-broken-pipe=kill` breaks cargo tests + if !path.ends_with("cargo") { + // If the output is piped to e.g. `head -n1` we want the process to be killed, + // rather than having an error bubble up and cause a panic. + cargo.rustflag("-Zon-broken-pipe=kill"); + } + cargo } From 9b52fb555835224e085170b67857a250dd6f176b Mon Sep 17 00:00:00 2001 From: Eric Holk Date: Tue, 1 Oct 2024 12:44:10 -0700 Subject: [PATCH 464/683] Split out method receivers in feature gate test --- .../feature-gate-pin_ergonomics.rs | 4 ++- .../feature-gate-pin_ergonomics.stderr | 27 +++---------------- 2 files changed, 6 insertions(+), 25 deletions(-) diff --git a/tests/ui/feature-gates/feature-gate-pin_ergonomics.rs b/tests/ui/feature-gates/feature-gate-pin_ergonomics.rs index d56a046fd62..3382504af9d 100644 --- a/tests/ui/feature-gates/feature-gate-pin_ergonomics.rs +++ b/tests/ui/feature-gates/feature-gate-pin_ergonomics.rs @@ -15,8 +15,10 @@ fn foo(_: Pin<&mut Foo>) { fn bar(mut x: Pin<&mut Foo>) { foo(x); foo(x); //~ ERROR use of moved value: `x` +} - x.foo(); //~ ERROR use of moved value: `x` +fn baz(mut x: Pin<&mut Foo>) { + x.foo(); x.foo(); //~ ERROR use of moved value: `x` } diff --git a/tests/ui/feature-gates/feature-gate-pin_ergonomics.stderr b/tests/ui/feature-gates/feature-gate-pin_ergonomics.stderr index bc49088f3d7..430b7866241 100644 --- a/tests/ui/feature-gates/feature-gate-pin_ergonomics.stderr +++ b/tests/ui/feature-gates/feature-gate-pin_ergonomics.stderr @@ -17,31 +17,10 @@ LL | fn foo(_: Pin<&mut Foo>) { | in this function error[E0382]: use of moved value: `x` - --> $DIR/feature-gate-pin_ergonomics.rs:19:5 + --> $DIR/feature-gate-pin_ergonomics.rs:22:5 | -LL | fn bar(mut x: Pin<&mut Foo>) { +LL | fn baz(mut x: Pin<&mut Foo>) { | ----- move occurs because `x` has type `Pin<&mut Foo>`, which does not implement the `Copy` trait -LL | foo(x); -LL | foo(x); - | - value moved here -LL | -LL | x.foo(); - | ^ value used here after move - | -note: consider changing this parameter type in function `foo` to borrow instead if owning the value isn't necessary - --> $DIR/feature-gate-pin_ergonomics.rs:12:11 - | -LL | fn foo(_: Pin<&mut Foo>) { - | --- ^^^^^^^^^^^^^ this parameter takes ownership of the value - | | - | in this function - -error[E0382]: use of moved value: `x` - --> $DIR/feature-gate-pin_ergonomics.rs:20:5 - | -LL | fn bar(mut x: Pin<&mut Foo>) { - | ----- move occurs because `x` has type `Pin<&mut Foo>`, which does not implement the `Copy` trait -... LL | x.foo(); | ----- `x` moved due to this method call LL | x.foo(); @@ -57,6 +36,6 @@ help: consider reborrowing the `Pin` instead of moving it LL | x.as_mut().foo(); | +++++++++ -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0382`. From c4ce8c114b06840c3521a189ee44958b713fb33a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 29 Sep 2024 11:53:23 +0200 Subject: [PATCH 465/683] make InterpResult a dedicated type to avoid accidentally discarding the error --- .../src/const_eval/dummy_machine.rs | 7 +- .../src/const_eval/eval_queries.rs | 51 ++-- .../src/const_eval/machine.rs | 68 ++--- .../rustc_const_eval/src/const_eval/mod.rs | 20 +- .../src/const_eval/valtrees.rs | 8 +- .../rustc_const_eval/src/interpret/call.rs | 58 ++--- .../rustc_const_eval/src/interpret/cast.rs | 24 +- .../src/interpret/discriminant.rs | 19 +- .../src/interpret/eval_context.rs | 49 ++-- .../rustc_const_eval/src/interpret/intern.rs | 10 +- .../src/interpret/intrinsics.rs | 27 +- .../rustc_const_eval/src/interpret/machine.rs | 49 ++-- .../rustc_const_eval/src/interpret/memory.rs | 148 +++++------ .../rustc_const_eval/src/interpret/operand.rs | 51 ++-- .../src/interpret/operator.rs | 37 +-- .../rustc_const_eval/src/interpret/place.rs | 76 +++--- .../src/interpret/projection.rs | 20 +- .../rustc_const_eval/src/interpret/stack.rs | 26 +- .../rustc_const_eval/src/interpret/step.rs | 28 +- .../rustc_const_eval/src/interpret/traits.rs | 14 +- .../rustc_const_eval/src/interpret/util.rs | 8 +- .../src/interpret/validity.rs | 180 +++++++------ .../rustc_const_eval/src/interpret/visitor.rs | 10 +- .../src/util/check_validity_requirement.rs | 3 +- compiler/rustc_middle/src/lib.rs | 2 + compiler/rustc_middle/src/mir/consts.rs | 4 +- .../src/mir/interpret/allocation.rs | 15 +- .../rustc_middle/src/mir/interpret/error.rs | 239 ++++++++++++++---- .../rustc_middle/src/mir/interpret/mod.rs | 12 +- .../rustc_middle/src/mir/interpret/value.rs | 38 +-- compiler/rustc_middle/src/ty/consts.rs | 2 +- .../src/dataflow_const_prop.rs | 64 +++-- compiler/rustc_mir_transform/src/gvn.rs | 115 ++++----- .../rustc_mir_transform/src/jump_threading.rs | 44 ++-- .../src/known_panics_lint.rs | 56 ++-- src/tools/clippy/clippy_utils/src/consts.rs | 10 +- src/tools/miri/src/alloc_addresses/mod.rs | 24 +- src/tools/miri/src/borrow_tracker/mod.rs | 8 +- .../src/borrow_tracker/stacked_borrows/mod.rs | 52 ++-- .../borrow_tracker/stacked_borrows/stack.rs | 14 +- .../tree_borrows/diagnostics.rs | 4 +- .../src/borrow_tracker/tree_borrows/mod.rs | 34 +-- .../src/borrow_tracker/tree_borrows/tree.rs | 6 +- src/tools/miri/src/concurrency/data_race.rs | 36 +-- src/tools/miri/src/concurrency/init_once.rs | 8 +- src/tools/miri/src/concurrency/sync.rs | 46 ++-- src/tools/miri/src/concurrency/thread.rs | 34 +-- src/tools/miri/src/concurrency/weak_memory.rs | 22 +- src/tools/miri/src/diagnostics.rs | 6 +- src/tools/miri/src/eval.rs | 10 +- src/tools/miri/src/helpers.rs | 92 +++---- src/tools/miri/src/intrinsics/atomic.rs | 22 +- src/tools/miri/src/intrinsics/mod.rs | 18 +- src/tools/miri/src/intrinsics/simd.rs | 7 +- src/tools/miri/src/machine.rs | 48 ++-- src/tools/miri/src/operator.rs | 2 +- src/tools/miri/src/shims/alloc.rs | 20 +- src/tools/miri/src/shims/backtrace.rs | 8 +- src/tools/miri/src/shims/env.rs | 8 +- src/tools/miri/src/shims/extern_static.rs | 8 +- src/tools/miri/src/shims/foreign_items.rs | 35 +-- src/tools/miri/src/shims/native_lib.rs | 10 +- src/tools/miri/src/shims/os_str.rs | 25 +- src/tools/miri/src/shims/panic.rs | 10 +- src/tools/miri/src/shims/time.rs | 32 +-- src/tools/miri/src/shims/tls.rs | 32 +-- .../src/shims/unix/android/foreign_items.rs | 4 +- src/tools/miri/src/shims/unix/env.rs | 40 +-- src/tools/miri/src/shims/unix/fd.rs | 46 ++-- .../miri/src/shims/unix/foreign_items.rs | 6 +- .../src/shims/unix/freebsd/foreign_items.rs | 4 +- src/tools/miri/src/shims/unix/fs.rs | 225 +++++++++-------- src/tools/miri/src/shims/unix/linux/epoll.rs | 40 +-- .../miri/src/shims/unix/linux/eventfd.rs | 12 +- .../src/shims/unix/linux/foreign_items.rs | 8 +- src/tools/miri/src/shims/unix/linux/mem.rs | 6 +- src/tools/miri/src/shims/unix/linux/sync.rs | 8 +- .../src/shims/unix/macos/foreign_items.rs | 4 +- src/tools/miri/src/shims/unix/macos/sync.rs | 12 +- src/tools/miri/src/shims/unix/mem.rs | 20 +- .../src/shims/unix/solarish/foreign_items.rs | 4 +- src/tools/miri/src/shims/unix/sync.rs | 92 +++---- src/tools/miri/src/shims/unix/thread.rs | 16 +- .../miri/src/shims/unix/unnamed_socket.rs | 8 +- .../miri/src/shims/wasi/foreign_items.rs | 4 +- src/tools/miri/src/shims/windows/env.rs | 30 +-- .../miri/src/shims/windows/foreign_items.rs | 14 +- src/tools/miri/src/shims/windows/handle.rs | 6 +- src/tools/miri/src/shims/windows/sync.rs | 18 +- src/tools/miri/src/shims/windows/thread.rs | 2 +- src/tools/miri/src/shims/x86/aesni.rs | 6 +- src/tools/miri/src/shims/x86/avx.rs | 4 +- src/tools/miri/src/shims/x86/avx2.rs | 4 +- src/tools/miri/src/shims/x86/bmi.rs | 6 +- src/tools/miri/src/shims/x86/mod.rs | 88 +++---- src/tools/miri/src/shims/x86/sha.rs | 8 +- src/tools/miri/src/shims/x86/sse.rs | 4 +- src/tools/miri/src/shims/x86/sse2.rs | 4 +- src/tools/miri/src/shims/x86/sse3.rs | 4 +- src/tools/miri/src/shims/x86/sse41.rs | 4 +- src/tools/miri/src/shims/x86/sse42.rs | 16 +- src/tools/miri/src/shims/x86/ssse3.rs | 4 +- 102 files changed, 1588 insertions(+), 1466 deletions(-) diff --git a/compiler/rustc_const_eval/src/const_eval/dummy_machine.rs b/compiler/rustc_const_eval/src/const_eval/dummy_machine.rs index ed1c912e6cb..743924faa21 100644 --- a/compiler/rustc_const_eval/src/const_eval/dummy_machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/dummy_machine.rs @@ -6,7 +6,8 @@ use rustc_middle::{bug, span_bug, ty}; use rustc_span::def_id::DefId; use crate::interpret::{ - self, HasStaticRootDefId, ImmTy, Immediate, InterpCx, PointerArithmetic, throw_machine_stop, + self, HasStaticRootDefId, ImmTy, Immediate, InterpCx, PointerArithmetic, interp_ok, + throw_machine_stop, }; /// Macro for machine-specific `InterpError` without allocation. @@ -79,7 +80,7 @@ impl<'tcx> interpret::Machine<'tcx> for DummyMachine { throw_machine_stop_str!("can't access mutable globals in ConstProp"); } - Ok(()) + interp_ok(()) } fn find_mir_or_eval_fn( @@ -127,7 +128,7 @@ impl<'tcx> interpret::Machine<'tcx> for DummyMachine { right: &interpret::ImmTy<'tcx, Self::Provenance>, ) -> interpret::InterpResult<'tcx, ImmTy<'tcx, Self::Provenance>> { use rustc_middle::mir::BinOp::*; - Ok(match bin_op { + interp_ok(match bin_op { Eq | Ne | Lt | Le | Gt | Ge => { // Types can differ, e.g. fn ptrs with different `for`. assert_eq!(left.layout.abi, right.layout.abi); diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs index a241edbd77a..672353e629d 100644 --- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs @@ -20,7 +20,7 @@ use crate::const_eval::CheckAlignment; use crate::interpret::{ CtfeValidationMode, GlobalId, Immediate, InternKind, InternResult, InterpCx, InterpError, InterpResult, MPlaceTy, MemoryKind, OpTy, RefTracking, StackPopCleanup, create_static_alloc, - eval_nullary_intrinsic, intern_const_alloc_recursive, throw_exhaust, + eval_nullary_intrinsic, intern_const_alloc_recursive, interp_ok, throw_exhaust, }; use crate::{CTRL_C_RECEIVED, errors}; @@ -98,19 +98,19 @@ fn eval_body_using_ecx<'tcx, R: InterpretationResult<'tcx>>( return Err(ecx .tcx .dcx() - .emit_err(errors::DanglingPtrInFinal { span: ecx.tcx.span, kind: intern_kind }) - .into()); + .emit_err(errors::DanglingPtrInFinal { span: ecx.tcx.span, kind: intern_kind })) + .into(); } Err(InternResult::FoundBadMutablePointer) => { return Err(ecx .tcx .dcx() - .emit_err(errors::MutablePtrInFinal { span: ecx.tcx.span, kind: intern_kind }) - .into()); + .emit_err(errors::MutablePtrInFinal { span: ecx.tcx.span, kind: intern_kind })) + .into(); } } - Ok(R::make_result(ret, ecx)) + interp_ok(R::make_result(ret, ecx)) } /// The `InterpCx` is only meant to be used to do field and index projections into constants for @@ -147,7 +147,8 @@ pub fn mk_eval_cx_for_const_val<'tcx>( ty: Ty<'tcx>, ) -> Option<(CompileTimeInterpCx<'tcx>, OpTy<'tcx>)> { let ecx = mk_eval_cx_to_read_const_val(tcx.tcx, tcx.span, param_env, CanAccessMutGlobal::No); - let op = ecx.const_val_to_op(val, ty, None).ok()?; + // FIXME: is it a problem to discard the error here? + let op = ecx.const_val_to_op(val, ty, None).discard_err()?; Some((ecx, op)) } @@ -185,12 +186,16 @@ pub(super) fn op_to_const<'tcx>( _ => false, }; let immediate = if force_as_immediate { - match ecx.read_immediate(op) { + match ecx.read_immediate(op).report_err() { Ok(imm) => Right(imm), - Err(err) if !for_diagnostics => { - panic!("normalization works on validated constants: {err:?}") + Err(err) => { + if for_diagnostics { + // This discard the error, but for diagnostics that's okay. + op.as_mplace_or_imm() + } else { + panic!("normalization works on validated constants: {err:?}") + } } - _ => op.as_mplace_or_imm(), } } else { op.as_mplace_or_imm() @@ -283,17 +288,19 @@ pub fn eval_to_const_value_raw_provider<'tcx>( let ty::FnDef(_, args) = ty.kind() else { bug!("intrinsic with type {:?}", ty); }; - return eval_nullary_intrinsic(tcx, key.param_env, def_id, args).map_err(|error| { - let span = tcx.def_span(def_id); + return eval_nullary_intrinsic(tcx, key.param_env, def_id, args).report_err().map_err( + |error| { + let span = tcx.def_span(def_id); - super::report( - tcx, - error.into_kind(), - span, - || (span, vec![]), - |span, _| errors::NullaryIntrinsicError { span }, - ) - }); + super::report( + tcx, + error.into_kind(), + span, + || (span, vec![]), + |span, _| errors::NullaryIntrinsicError { span }, + ) + }, + ); } tcx.eval_to_allocation_raw(key).map(|val| turn_into_const_value(tcx, val, key)) @@ -376,6 +383,7 @@ fn eval_in_interpreter<'tcx, R: InterpretationResult<'tcx>>( ); let res = ecx.load_mir(cid.instance.def, cid.promoted); res.and_then(|body| eval_body_using_ecx(&mut ecx, cid, body)) + .report_err() .map_err(|error| report_eval_error(&ecx, cid, error)) } @@ -400,6 +408,7 @@ fn const_validate_mplace<'tcx>( } }; ecx.const_validate_operand(&mplace.into(), path, &mut ref_tracking, mode) + .report_err() // Instead of just reporting the `InterpError` via the usual machinery, we give a more targeted // error about the validation failure. .map_err(|error| report_validation_error(&ecx, cid, error, alloc_id))?; diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index 6d74998b7d8..4aec74595bc 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -24,8 +24,8 @@ use crate::fluent_generated as fluent; use crate::interpret::{ self, AllocId, AllocRange, ConstAllocation, CtfeProvenance, FnArg, Frame, GlobalAlloc, ImmTy, InterpCx, InterpResult, MPlaceTy, OpTy, Pointer, PointerArithmetic, RangeSet, Scalar, - StackPopCleanup, compile_time_machine, err_ub, throw_exhaust, throw_inval, throw_ub_custom, - throw_unsup, throw_unsup_format, + StackPopCleanup, compile_time_machine, interp_ok, throw_exhaust, throw_inval, throw_ub, + throw_ub_custom, throw_unsup, throw_unsup_format, }; /// When hitting this many interpreted terminators we emit a deny by default lint @@ -247,7 +247,7 @@ impl<'tcx> CompileTimeInterpCx<'tcx> { let msg = Symbol::intern(self.read_str(&msg_place)?); let span = self.find_closest_untracked_caller_location(); let (file, line, col) = self.location_triple_for_span(span); - return Err(ConstEvalErrKind::Panic { msg, file, line, col }.into()); + return Err(ConstEvalErrKind::Panic { msg, file, line, col }).into(); } else if self.tcx.is_lang_item(def_id, LangItem::PanicFmt) { // For panic_fmt, call const_panic_fmt instead. let const_def_id = self.tcx.require_lang_item(LangItem::ConstPanicFmt, None); @@ -259,16 +259,16 @@ impl<'tcx> CompileTimeInterpCx<'tcx> { self.cur_span(), ); - return Ok(Some(new_instance)); + return interp_ok(Some(new_instance)); } else if self.tcx.is_lang_item(def_id, LangItem::AlignOffset) { let args = self.copy_fn_args(args); // For align_offset, we replace the function call if the pointer has no address. match self.align_offset(instance, &args, dest, ret)? { - ControlFlow::Continue(()) => return Ok(Some(instance)), - ControlFlow::Break(()) => return Ok(None), + ControlFlow::Continue(()) => return interp_ok(Some(instance)), + ControlFlow::Break(()) => return interp_ok(None), } } - Ok(Some(instance)) + interp_ok(Some(instance)) } /// `align_offset(ptr, target_align)` needs special handling in const eval, because the pointer @@ -323,25 +323,25 @@ impl<'tcx> CompileTimeInterpCx<'tcx> { dest, StackPopCleanup::Goto { ret, unwind: mir::UnwindAction::Unreachable }, )?; - Ok(ControlFlow::Break(())) + interp_ok(ControlFlow::Break(())) } else { // Not alignable in const, return `usize::MAX`. let usize_max = Scalar::from_target_usize(self.target_usize_max(), self); self.write_scalar(usize_max, dest)?; self.return_to_block(ret)?; - Ok(ControlFlow::Break(())) + interp_ok(ControlFlow::Break(())) } } Err(_addr) => { // The pointer has an address, continue with function call. - Ok(ControlFlow::Continue(())) + interp_ok(ControlFlow::Continue(())) } } } /// See documentation on the `ptr_guaranteed_cmp` intrinsic. fn guaranteed_cmp(&mut self, a: Scalar, b: Scalar) -> InterpResult<'tcx, u8> { - Ok(match (a, b) { + interp_ok(match (a, b) { // Comparisons between integers are always known. (Scalar::Int { .. }, Scalar::Int { .. }) => { if a == b { @@ -403,8 +403,8 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> { instance: ty::InstanceKind<'tcx>, ) -> InterpResult<'tcx, &'tcx mir::Body<'tcx>> { match instance { - ty::InstanceKind::Item(def) => Ok(ecx.tcx.mir_for_ctfe(def)), - _ => Ok(ecx.tcx.instance_mir(instance)), + ty::InstanceKind::Item(def) => interp_ok(ecx.tcx.mir_for_ctfe(def)), + _ => interp_ok(ecx.tcx.instance_mir(instance)), } } @@ -422,7 +422,7 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> { // Replace some functions. let Some(instance) = ecx.hook_special_const_fn(orig_instance, args, dest, ret)? else { // Call has already been handled. - return Ok(None); + return interp_ok(None); }; // Only check non-glue functions @@ -444,14 +444,14 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> { // This is a const fn. Call it. // In case of replacement, we return the *original* instance to make backtraces work out // (and we hope this does not confuse the FnAbi checks too much). - Ok(Some((ecx.load_mir(instance.def, None)?, orig_instance))) + interp_ok(Some((ecx.load_mir(instance.def, None)?, orig_instance))) } fn panic_nounwind(ecx: &mut InterpCx<'tcx, Self>, msg: &str) -> InterpResult<'tcx> { let msg = Symbol::intern(msg); let span = ecx.find_closest_untracked_caller_location(); let (file, line, col) = ecx.location_triple_for_span(span); - Err(ConstEvalErrKind::Panic { msg, file, line, col }.into()) + Err(ConstEvalErrKind::Panic { msg, file, line, col }).into() } fn call_intrinsic( @@ -464,7 +464,7 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> { ) -> InterpResult<'tcx, Option>> { // Shared intrinsics. if ecx.eval_intrinsic(instance, args, dest, target)? { - return Ok(None); + return interp_ok(None); } let intrinsic_name = ecx.tcx.item_name(instance.def_id()); @@ -541,7 +541,7 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> { "intrinsic `{intrinsic_name}` is not supported at compile-time" ); } - return Ok(Some(ty::Instance { + return interp_ok(Some(ty::Instance { def: ty::InstanceKind::Item(instance.def_id()), args: instance.args, })); @@ -550,7 +550,7 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> { // Intrinsic is done, jump to next block. ecx.return_to_block(target)?; - Ok(None) + interp_ok(None) } fn assert_panic( @@ -581,7 +581,7 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> { } } }; - Err(ConstEvalErrKind::AssertFailure(err).into()) + Err(ConstEvalErrKind::AssertFailure(err)).into() } fn binary_ptr_op( @@ -652,7 +652,7 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> { } } - Ok(()) + interp_ok(()) } #[inline(always)] @@ -670,7 +670,7 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> { if !ecx.recursion_limit.value_within_limit(ecx.stack().len() + 1) { throw_exhaust!(StackFrameLimitReached) } else { - Ok(frame) + interp_ok(frame) } } @@ -700,22 +700,22 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> { if is_write { // Write access. These are never allowed, but we give a targeted error message. match alloc.mutability { - Mutability::Not => Err(err_ub!(WriteToReadOnly(alloc_id)).into()), - Mutability::Mut => Err(ConstEvalErrKind::ModifiedGlobal.into()), + Mutability::Not => throw_ub!(WriteToReadOnly(alloc_id)), + Mutability::Mut => Err(ConstEvalErrKind::ModifiedGlobal).into(), } } else { // Read access. These are usually allowed, with some exceptions. if machine.can_access_mut_global == CanAccessMutGlobal::Yes { // Machine configuration allows us read from anything (e.g., `static` initializer). - Ok(()) + interp_ok(()) } else if alloc.mutability == Mutability::Mut { // Machine configuration does not allow us to read statics (e.g., `const` // initializer). - Err(ConstEvalErrKind::ConstAccessesMutGlobal.into()) + Err(ConstEvalErrKind::ConstAccessesMutGlobal).into() } else { // Immutable global, this read is fine. assert_eq!(alloc.mutability, Mutability::Not); - Ok(()) + interp_ok(()) } } } @@ -748,9 +748,9 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> { // even when there is interior mutability.) place.map_provenance(CtfeProvenance::as_shared_ref) }; - Ok(ImmTy::from_immediate(new_place.to_ref(ecx), val.layout)) + interp_ok(ImmTy::from_immediate(new_place.to_ref(ecx), val.layout)) } else { - Ok(val.clone()) + interp_ok(val.clone()) } } @@ -763,20 +763,20 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> { ) -> InterpResult<'tcx> { if range.size == Size::ZERO { // Nothing to check. - return Ok(()); + return interp_ok(()); } // Reject writes through immutable pointers. if immutable { - return Err(ConstEvalErrKind::WriteThroughImmutablePointer.into()); + return Err(ConstEvalErrKind::WriteThroughImmutablePointer).into(); } // Everything else is fine. - Ok(()) + interp_ok(()) } fn before_alloc_read(ecx: &InterpCx<'tcx, Self>, alloc_id: AllocId) -> InterpResult<'tcx> { // Check if this is the currently evaluated static. if Some(alloc_id) == ecx.machine.static_root_ids.map(|(id, _)| id) { - return Err(ConstEvalErrKind::RecursiveStatic.into()); + return Err(ConstEvalErrKind::RecursiveStatic).into(); } // If this is another static, make sure we fire off the query to detect cycles. // But only do that when checks for static recursion are enabled. @@ -788,7 +788,7 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> { ecx.ctfe_query(|tcx| tcx.eval_static_initializer(def_id))?; } } - Ok(()) + interp_ok(()) } fn cached_union_data_range<'e>( diff --git a/compiler/rustc_const_eval/src/const_eval/mod.rs b/compiler/rustc_const_eval/src/const_eval/mod.rs index 48aeee2e6f0..ba19f642795 100644 --- a/compiler/rustc_const_eval/src/const_eval/mod.rs +++ b/compiler/rustc_const_eval/src/const_eval/mod.rs @@ -1,13 +1,12 @@ // Not in interpret to make sure we do not use private implementation details -use rustc_middle::mir::interpret::InterpErrorInfo; use rustc_middle::query::{Key, TyCtxtAt}; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::{bug, mir}; use rustc_target::abi::VariantIdx; use tracing::instrument; -use crate::interpret::{InterpCx, format_interp_error}; +use crate::interpret::InterpCx; mod dummy_machine; mod error; @@ -33,17 +32,6 @@ pub(crate) enum ValTreeCreationError<'tcx> { } pub(crate) type ValTreeCreationResult<'tcx> = Result, ValTreeCreationError<'tcx>>; -impl<'tcx> From> for ValTreeCreationError<'tcx> { - fn from(err: InterpErrorInfo<'tcx>) -> Self { - ty::tls::with(|tcx| { - bug!( - "Unexpected Undefined Behavior error during valtree construction: {}", - format_interp_error(tcx.dcx(), err), - ) - }) - } -} - #[instrument(skip(tcx), level = "debug")] pub(crate) fn try_destructure_mir_constant_for_user_output<'tcx>( tcx: TyCtxtAt<'tcx>, @@ -60,8 +48,8 @@ pub(crate) fn try_destructure_mir_constant_for_user_output<'tcx>( return None; } ty::Adt(def, _) => { - let variant = ecx.read_discriminant(&op).ok()?; - let down = ecx.project_downcast(&op, variant).ok()?; + let variant = ecx.read_discriminant(&op).discard_err()?; + let down = ecx.project_downcast(&op, variant).discard_err()?; (def.variants()[variant].fields.len(), Some(variant), down) } ty::Tuple(args) => (args.len(), None, op), @@ -70,7 +58,7 @@ pub(crate) fn try_destructure_mir_constant_for_user_output<'tcx>( let fields_iter = (0..field_count) .map(|i| { - let field_op = ecx.project_field(&down, i).ok()?; + let field_op = ecx.project_field(&down, i).discard_err()?; let val = op_to_const(&ecx, &field_op, /* for diagnostics */ true); Some((val, field_op.layout.ty)) }) diff --git a/compiler/rustc_const_eval/src/const_eval/valtrees.rs b/compiler/rustc_const_eval/src/const_eval/valtrees.rs index a11d491bdd2..9e80e666ba9 100644 --- a/compiler/rustc_const_eval/src/const_eval/valtrees.rs +++ b/compiler/rustc_const_eval/src/const_eval/valtrees.rs @@ -92,7 +92,7 @@ fn const_to_valtree_inner<'tcx>( Ok(ty::ValTree::zst()) } ty::Bool | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Char => { - let val = ecx.read_immediate(place)?; + let val = ecx.read_immediate(place).unwrap(); let val = val.to_scalar_int().unwrap(); *num_nodes += 1; @@ -114,7 +114,7 @@ fn const_to_valtree_inner<'tcx>( // equality at compile-time (see `ptr_guaranteed_cmp`). // However we allow those that are just integers in disguise. // First, get the pointer. Remember it might be wide! - let val = ecx.read_immediate(place)?; + let val = ecx.read_immediate(place).unwrap(); // We could allow wide raw pointers where both sides are integers in the future, // but for now we reject them. if matches!(val.layout.abi, Abi::ScalarPair(..)) { @@ -135,7 +135,7 @@ fn const_to_valtree_inner<'tcx>( ty::FnPtr(..) => Err(ValTreeCreationError::NonSupportedType(ty)), ty::Ref(_, _, _) => { - let derefd_place = ecx.deref_pointer(place)?; + let derefd_place = ecx.deref_pointer(place).unwrap(); const_to_valtree_inner(ecx, &derefd_place, num_nodes) } @@ -159,7 +159,7 @@ fn const_to_valtree_inner<'tcx>( bug!("uninhabited types should have errored and never gotten converted to valtree") } - let variant = ecx.read_discriminant(place)?; + let variant = ecx.read_discriminant(place).unwrap(); branches(ecx, place, def.variant(variant).fields.len(), def.is_enum().then_some(variant), num_nodes) } diff --git a/compiler/rustc_const_eval/src/interpret/call.rs b/compiler/rustc_const_eval/src/interpret/call.rs index 19aa76bf1ea..4945563f4a4 100644 --- a/compiler/rustc_const_eval/src/interpret/call.rs +++ b/compiler/rustc_const_eval/src/interpret/call.rs @@ -15,8 +15,8 @@ use tracing::{info, instrument, trace}; use super::{ CtfeProvenance, FnVal, ImmTy, InterpCx, InterpResult, MPlaceTy, Machine, OpTy, PlaceTy, - Projectable, Provenance, ReturnAction, Scalar, StackPopCleanup, StackPopInfo, throw_ub, - throw_ub_custom, throw_unsup_format, + Projectable, Provenance, ReturnAction, Scalar, StackPopCleanup, StackPopInfo, interp_ok, + throw_ub, throw_ub_custom, throw_unsup_format, }; use crate::fluent_generated as fluent; @@ -64,7 +64,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { arg: &FnArg<'tcx, M::Provenance>, field: usize, ) -> InterpResult<'tcx, FnArg<'tcx, M::Provenance>> { - Ok(match arg { + interp_ok(match arg { FnArg::Copy(op) => FnArg::Copy(self.project_field(op, field)?), FnArg::InPlace(mplace) => FnArg::InPlace(self.project_field(mplace, field)?), }) @@ -97,7 +97,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // another type. let ty::Adt(def, args) = layout.ty.kind() else { // Not an ADT, so definitely no NPO. - return Ok(layout); + return interp_ok(layout); }; let inner = if self.tcx.is_diagnostic_item(sym::Option, def.did()) { // The wrapped type is the only arg. @@ -111,10 +111,10 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { } else if rhs.is_1zst() { lhs } else { - return Ok(layout); // no NPO + return interp_ok(layout); // no NPO } } else { - return Ok(layout); // no NPO + return interp_ok(layout); // no NPO }; // Check if the inner type is one of the NPO-guaranteed ones. @@ -126,7 +126,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // Stop at NPO types so that we don't miss that attribute in the check below! def.is_struct() && !is_npo(def) }); - Ok(match inner.ty.kind() { + interp_ok(match inner.ty.kind() { ty::Ref(..) | ty::FnPtr(..) => { // Option<&T> behaves like &T, and same for fn() inner @@ -153,11 +153,11 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { ) -> InterpResult<'tcx, bool> { // Fast path: equal types are definitely compatible. if caller.ty == callee.ty { - return Ok(true); + return interp_ok(true); } // 1-ZST are compatible with all 1-ZST (and with nothing else). if caller.is_1zst() || callee.is_1zst() { - return Ok(caller.is_1zst() && callee.is_1zst()); + return interp_ok(caller.is_1zst() && callee.is_1zst()); } // Unfold newtypes and NPO optimizations. let unfold = |layout: TyAndLayout<'tcx>| { @@ -180,17 +180,17 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { _ => None, }; if let (Some(caller), Some(callee)) = (thin_pointer(caller), thin_pointer(callee)) { - return Ok(caller == callee); + return interp_ok(caller == callee); } // For wide pointers we have to get the pointee type. let pointee_ty = |ty: Ty<'tcx>| -> InterpResult<'tcx, Option>> { // We cannot use `builtin_deref` here since we need to reject `Box`. - Ok(Some(match ty.kind() { + interp_ok(Some(match ty.kind() { ty::Ref(_, ty, _) => *ty, ty::RawPtr(ty, _) => *ty, // We only accept `Box` with the default allocator. _ if ty.is_box_global(*self.tcx) => ty.expect_boxed_ty(), - _ => return Ok(None), + _ => return interp_ok(None), })) }; if let (Some(caller), Some(callee)) = (pointee_ty(caller.ty)?, pointee_ty(callee.ty)?) { @@ -202,7 +202,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { let normalize = |ty| self.tcx.normalize_erasing_regions(self.param_env, ty); ty.ptr_metadata_ty(*self.tcx, normalize) }; - return Ok(meta_ty(caller) == meta_ty(callee)); + return interp_ok(meta_ty(caller) == meta_ty(callee)); } // Compatible integer types (in particular, usize vs ptr-sized-u32/u64). @@ -217,11 +217,11 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { }; if let (Some(caller), Some(callee)) = (int_ty(caller.ty), int_ty(callee.ty)) { // This is okay if they are the same integer type. - return Ok(caller == callee); + return interp_ok(caller == callee); } // Fall back to exact equality. - Ok(caller == callee) + interp_ok(caller == callee) } fn check_argument_compat( @@ -235,13 +235,13 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // Ensure that our checks imply actual ABI compatibility for this concrete call. // (This can fail e.g. if `#[rustc_nonnull_optimization_guaranteed]` is used incorrectly.) assert!(caller_abi.eq_abi(callee_abi)); - Ok(true) + interp_ok(true) } else { trace!( "check_argument_compat: incompatible ABIs:\ncaller: {:?}\ncallee: {:?}", caller_abi, callee_abi ); - Ok(false) + interp_ok(false) } } @@ -266,7 +266,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { if !already_live { self.storage_live(callee_arg.as_local().unwrap())?; } - return Ok(()); + return interp_ok(()); } // Find next caller arg. let Some((caller_arg, caller_abi)) = caller_args.next() else { @@ -308,7 +308,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { if let FnArg::InPlace(mplace) = caller_arg { M::protect_in_place_function_argument(self, mplace)?; } - Ok(()) + interp_ok(()) } /// The main entry point for creating a new stack frame: performs ABI checks and initializes @@ -536,7 +536,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { unwind, ); } else { - Ok(()) + interp_ok(()) } } ty::InstanceKind::VTableShim(..) @@ -561,7 +561,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { unwind, )? else { - return Ok(()); + return interp_ok(()); }; // Special handling for the closure ABI: untuple the last argument. @@ -572,7 +572,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { trace!("init_fn_call: Will pass last argument by untupling"); Cow::from( args.iter() - .map(|a| Ok(a.clone())) + .map(|a| interp_ok(a.clone())) .chain( (0..untuple_arg.layout().fields.count()) .map(|i| self.fn_arg_field(untuple_arg, i)), @@ -886,27 +886,25 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // this transmute. res } else { - Ok(()) + interp_ok(()) }; // All right, now it is time to actually pop the frame. - let stack_pop_info = self.pop_stack_frame_raw(unwinding)?; - - // Report error from return value copy, if any. - copy_ret_result?; + // An error here takes precedence over the copy error. + let (stack_pop_info, ()) = self.pop_stack_frame_raw(unwinding).and(copy_ret_result)?; match stack_pop_info.return_action { ReturnAction::Normal => {} ReturnAction::NoJump => { // The hook already did everything. - return Ok(()); + return interp_ok(()); } ReturnAction::NoCleanup => { // If we are not doing cleanup, also skip everything else. assert!(self.stack().is_empty(), "only the topmost frame should ever be leaked"); assert!(!unwinding, "tried to skip cleanup during unwinding"); // Skip machine hook. - return Ok(()); + return interp_ok(()); } } @@ -931,7 +929,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { self.stack().is_empty(), "only the bottommost frame can have StackPopCleanup::Root" ); - Ok(()) + interp_ok(()) } } } diff --git a/compiler/rustc_const_eval/src/interpret/cast.rs b/compiler/rustc_const_eval/src/interpret/cast.rs index 85e7d91c2ad..565a7d16242 100644 --- a/compiler/rustc_const_eval/src/interpret/cast.rs +++ b/compiler/rustc_const_eval/src/interpret/cast.rs @@ -14,7 +14,8 @@ use tracing::trace; use super::util::ensure_monomorphic_enough; use super::{ - FnVal, ImmTy, Immediate, InterpCx, Machine, OpTy, PlaceTy, err_inval, throw_ub, throw_ub_custom, + FnVal, ImmTy, Immediate, InterpCx, Machine, OpTy, PlaceTy, err_inval, interp_ok, throw_ub, + throw_ub_custom, }; use crate::fluent_generated as fluent; @@ -157,7 +158,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { self.copy_op_allow_transmute(src, dest)?; } } - Ok(()) + interp_ok(()) } /// Handles 'IntToInt' and 'IntToFloat' casts. @@ -169,7 +170,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { assert!(src.layout.ty.is_integral() || src.layout.ty.is_char() || src.layout.ty.is_bool()); assert!(cast_to.ty.is_floating_point() || cast_to.ty.is_integral() || cast_to.ty.is_char()); - Ok(ImmTy::from_scalar( + interp_ok(ImmTy::from_scalar( self.cast_from_int_like(src.to_scalar(), src.layout, cast_to.ty)?, cast_to, )) @@ -192,7 +193,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { FloatTy::F64 => self.cast_from_float(src.to_scalar().to_f64()?, cast_to.ty), FloatTy::F128 => self.cast_from_float(src.to_scalar().to_f128()?, cast_to.ty), }; - Ok(ImmTy::from_scalar(val, cast_to)) + interp_ok(ImmTy::from_scalar(val, cast_to)) } /// Handles 'FnPtrToPtr' and 'PtrToPtr' casts. @@ -206,14 +207,14 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // Handle casting any ptr to raw ptr (might be a fat ptr). if cast_to.size == src.layout.size { // Thin or fat pointer that just has the ptr kind of target type changed. - return Ok(ImmTy::from_immediate(**src, cast_to)); + return interp_ok(ImmTy::from_immediate(**src, cast_to)); } else { // Casting the metadata away from a fat ptr. assert_eq!(src.layout.size, 2 * self.pointer_size()); assert_eq!(cast_to.size, self.pointer_size()); assert!(src.layout.ty.is_unsafe_ptr()); return match **src { - Immediate::ScalarPair(data, _) => Ok(ImmTy::from_scalar(data, cast_to)), + Immediate::ScalarPair(data, _) => interp_ok(ImmTy::from_scalar(data, cast_to)), Immediate::Scalar(..) => span_bug!( self.cur_span(), "{:?} input to a fat-to-thin cast ({} -> {})", @@ -240,7 +241,10 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { Ok(ptr) => M::expose_ptr(self, ptr)?, Err(_) => {} // Do nothing, exposing an invalid pointer (`None` provenance) is a NOP. }; - Ok(ImmTy::from_scalar(self.cast_from_int_like(scalar, src.layout, cast_to.ty)?, cast_to)) + interp_ok(ImmTy::from_scalar( + self.cast_from_int_like(scalar, src.layout, cast_to.ty)?, + cast_to, + )) } pub fn pointer_with_exposed_provenance_cast( @@ -258,7 +262,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // Then turn address into pointer. let ptr = M::ptr_from_addr_cast(self, addr)?; - Ok(ImmTy::from_scalar(Scalar::from_maybe_pointer(ptr, self), cast_to)) + interp_ok(ImmTy::from_scalar(Scalar::from_maybe_pointer(ptr, self), cast_to)) } /// Low-level cast helper function. This works directly on scalars and can take 'int-like' input @@ -280,7 +284,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { _ => span_bug!(self.cur_span(), "invalid int-like cast from {}", src_layout.ty), }; - Ok(match *cast_ty.kind() { + interp_ok(match *cast_ty.kind() { // int -> int Int(_) | Uint(_) => { let size = match *cast_ty.kind() { @@ -505,7 +509,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { self.unsize_into(&src_field, cast_ty_field, &dst_field)?; } } - Ok(()) + interp_ok(()) } _ => { // Do not ICE if we are not monomorphic enough. diff --git a/compiler/rustc_const_eval/src/interpret/discriminant.rs b/compiler/rustc_const_eval/src/interpret/discriminant.rs index 3bab2b3261e..81e0b1e12ca 100644 --- a/compiler/rustc_const_eval/src/interpret/discriminant.rs +++ b/compiler/rustc_const_eval/src/interpret/discriminant.rs @@ -7,7 +7,8 @@ use rustc_target::abi::{self, TagEncoding, VariantIdx, Variants}; use tracing::{instrument, trace}; use super::{ - ImmTy, InterpCx, InterpResult, Machine, Projectable, Scalar, Writeable, err_ub, throw_ub, + ImmTy, InterpCx, InterpResult, Machine, Projectable, Scalar, Writeable, err_ub, interp_ok, + throw_ub, }; impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { @@ -48,7 +49,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { if actual_variant != variant_index { throw_ub!(InvalidNichedEnumVariantWritten { enum_ty: dest.layout().ty }); } - Ok(()) + interp_ok(()) } } } @@ -89,7 +90,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { throw_ub!(UninhabitedEnumVariantRead(index)) } } - return Ok(index); + return interp_ok(index); } Variants::Multiple { tag, ref tag_encoding, tag_field, .. } => { (tag, tag_encoding, tag_field) @@ -205,7 +206,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { if op.layout().for_variant(self, index).abi.is_uninhabited() { throw_ub!(UninhabitedEnumVariantRead(index)) } - Ok(index) + interp_ok(index) } pub fn discriminant_for_variant( @@ -226,7 +227,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { Scalar::from_uint(variant.as_u32(), discr_layout.size) } }; - Ok(ImmTy::from_scalar(discr_value, discr_layout)) + interp_ok(ImmTy::from_scalar(discr_value, discr_layout)) } /// Computes how to write the tag of a given variant of enum `ty`: @@ -247,7 +248,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // discriminant is encoded implicitly, so any attempt to write // the wrong discriminant for a `Single` enum will reliably // result in UB. - Ok(None) + interp_ok(None) } abi::Variants::Multiple { @@ -265,7 +266,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { let tag_size = tag_layout.size(self); let tag_val = tag_size.truncate(discr_val); let tag = ScalarInt::try_from_uint(tag_val, tag_size).unwrap(); - Ok(Some((tag, tag_field))) + interp_ok(Some((tag, tag_field))) } abi::Variants::Multiple { @@ -274,7 +275,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { } if untagged_variant == variant_index => { // The untagged variant is implicitly encoded simply by having a // value that is outside the niche variants. - Ok(None) + interp_ok(None) } abi::Variants::Multiple { @@ -299,7 +300,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { let tag = self .binary_op(mir::BinOp::Add, &variant_index_relative_val, &niche_start_val)? .to_scalar_int()?; - Ok(Some((tag, tag_field))) + interp_ok(Some((tag, tag_field))) } } } diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs index f4c4a6fb0bf..5165f95afd5 100644 --- a/compiler/rustc_const_eval/src/interpret/eval_context.rs +++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs @@ -19,9 +19,9 @@ use rustc_trait_selection::traits::ObligationCtxt; use tracing::{debug, instrument, trace}; use super::{ - Frame, FrameInfo, GlobalId, InterpErrorInfo, InterpResult, MPlaceTy, Machine, MemPlaceMeta, - Memory, OpTy, Place, PlaceTy, PointerArithmetic, Projectable, Provenance, err_inval, - throw_inval, throw_ub, throw_ub_custom, + Frame, FrameInfo, GlobalId, InterpError, InterpErrorInfo, InterpResult, MPlaceTy, Machine, + MemPlaceMeta, Memory, OpTy, Place, PlaceTy, PointerArithmetic, Projectable, Provenance, + err_inval, interp_ok, throw_inval, throw_ub, throw_ub_custom, }; use crate::{ReportErrorExt, fluent_generated as fluent, util}; @@ -73,7 +73,7 @@ where } impl<'tcx, M: Machine<'tcx>> LayoutOfHelpers<'tcx> for InterpCx<'tcx, M> { - type LayoutOfResult = InterpResult<'tcx, TyAndLayout<'tcx>>; + type LayoutOfResult = Result, InterpError<'tcx>>; #[inline] fn layout_tcx_at_span(&self) -> Span { @@ -82,29 +82,24 @@ impl<'tcx, M: Machine<'tcx>> LayoutOfHelpers<'tcx> for InterpCx<'tcx, M> { } #[inline] - fn handle_layout_err( - &self, - err: LayoutError<'tcx>, - _: Span, - _: Ty<'tcx>, - ) -> InterpErrorInfo<'tcx> { - err_inval!(Layout(err)).into() + fn handle_layout_err(&self, err: LayoutError<'tcx>, _: Span, _: Ty<'tcx>) -> InterpError<'tcx> { + err_inval!(Layout(err)) } } impl<'tcx, M: Machine<'tcx>> FnAbiOfHelpers<'tcx> for InterpCx<'tcx, M> { - type FnAbiOfResult = InterpResult<'tcx, &'tcx FnAbi<'tcx, Ty<'tcx>>>; + type FnAbiOfResult = Result<&'tcx FnAbi<'tcx, Ty<'tcx>>, InterpError<'tcx>>; fn handle_fn_abi_err( &self, err: FnAbiError<'tcx>, _span: Span, _fn_abi_request: FnAbiRequest<'tcx>, - ) -> InterpErrorInfo<'tcx> { + ) -> InterpError<'tcx> { match err { - FnAbiError::Layout(err) => err_inval!(Layout(err)).into(), + FnAbiError::Layout(err) => err_inval!(Layout(err)), FnAbiError::AdjustForForeignAbi(err) => { - err_inval!(FnAbiAdjustForForeignAbi(err)).into() + err_inval!(FnAbiAdjustForForeignAbi(err)) } } } @@ -160,7 +155,7 @@ pub(super) fn from_known_layout<'tcx>( ); } } - Ok(known_layout) + interp_ok(known_layout) } } } @@ -262,7 +257,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { if let Some(err) = body.tainted_by_errors { throw_inval!(AlreadyReported(ReportedErrorInfo::tainted_by_errors(err))); } - Ok(body) + interp_ok(body) } /// Call this on things you got out of the MIR (so it is as generic as the current @@ -305,7 +300,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { trace!("param_env: {:#?}", self.param_env); trace!("args: {:#?}", args); match ty::Instance::try_resolve(*self.tcx, self.param_env, def, args) { - Ok(Some(instance)) => Ok(instance), + Ok(Some(instance)) => interp_ok(instance), Ok(None) => throw_inval!(TooGeneric), // FIXME(eddyb) this could be a bit more specific than `AlreadyReported`. @@ -401,7 +396,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { layout: &TyAndLayout<'tcx>, ) -> InterpResult<'tcx, Option<(Size, Align)>> { if layout.is_sized() { - return Ok(Some((layout.size, layout.align.abi))); + return interp_ok(Some((layout.size, layout.align.abi))); } match layout.ty.kind() { ty::Adt(..) | ty::Tuple(..) => { @@ -425,7 +420,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { else { // A field with an extern type. We don't know the actual dynamic size // or the alignment. - return Ok(None); + return interp_ok(None); }; // # First compute the dynamic alignment @@ -456,12 +451,12 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { if full_size > self.max_size_of_val() { throw_ub!(InvalidMeta(InvalidMetaKind::TooBig)); } - Ok(Some((full_size, full_align))) + interp_ok(Some((full_size, full_align))) } ty::Dynamic(expected_trait, _, ty::Dyn) => { let vtable = metadata.unwrap_meta().to_pointer(self)?; // Read size and align from vtable (already checks size). - Ok(Some(self.get_vtable_size_and_align(vtable, Some(expected_trait))?)) + interp_ok(Some(self.get_vtable_size_and_align(vtable, Some(expected_trait))?)) } ty::Slice(_) | ty::Str => { @@ -474,10 +469,10 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { if size > self.max_size_of_val() { throw_ub!(InvalidMeta(InvalidMetaKind::SliceTooBig)); } - Ok(Some((size, elem.align.abi))) + interp_ok(Some((size, elem.align.abi))) } - ty::Foreign(_) => Ok(None), + ty::Foreign(_) => interp_ok(None), _ => span_bug!(self.cur_span(), "size_and_align_of::<{}> not supported", layout.ty), } @@ -503,7 +498,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { pub fn return_to_block(&mut self, target: Option) -> InterpResult<'tcx> { if let Some(target) = target { self.go_to_block(target); - Ok(()) + interp_ok(()) } else { throw_ub!(Unreachable) } @@ -530,10 +525,10 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { M::unwind_terminate(self, reason)?; // This might have pushed a new stack frame, or it terminated execution. // Either way, `loc` will not be updated. - return Ok(()); + return interp_ok(()); } }; - Ok(()) + interp_ok(()) } /// Call a query that can return `ErrorHandled`. Should be used for statics and other globals. diff --git a/compiler/rustc_const_eval/src/interpret/intern.rs b/compiler/rustc_const_eval/src/interpret/intern.rs index 81659df7c53..7a1b92601a4 100644 --- a/compiler/rustc_const_eval/src/interpret/intern.rs +++ b/compiler/rustc_const_eval/src/interpret/intern.rs @@ -26,7 +26,9 @@ use rustc_span::def_id::LocalDefId; use rustc_span::sym; use tracing::{instrument, trace}; -use super::{AllocId, Allocation, InterpCx, MPlaceTy, Machine, MemoryKind, PlaceTy, err_ub}; +use super::{ + AllocId, Allocation, InterpCx, MPlaceTy, Machine, MemoryKind, PlaceTy, err_ub, interp_ok, +}; use crate::const_eval; use crate::errors::NestedStaticInThreadLocal; @@ -307,7 +309,7 @@ pub fn intern_const_alloc_for_constprop<'tcx, T, M: CompileTimeMachine<'tcx, T>> ) -> InterpResult<'tcx, ()> { if ecx.tcx.try_get_global_alloc(alloc_id).is_some() { // The constant is already in global memory. Do nothing. - return Ok(()); + return interp_ok(()); } // Move allocation to `tcx`. if let Some(_) = @@ -318,7 +320,7 @@ pub fn intern_const_alloc_for_constprop<'tcx, T, M: CompileTimeMachine<'tcx, T>> // proper recursive interning loop -- or just call `intern_const_alloc_recursive`. panic!("`intern_const_alloc_for_constprop` called on allocation with nested provenance") } - Ok(()) + interp_ok(()) } impl<'tcx, M: super::intern::CompileTimeMachine<'tcx, !>> InterpCx<'tcx, M> { @@ -342,6 +344,6 @@ impl<'tcx, M: super::intern::CompileTimeMachine<'tcx, !>> InterpCx<'tcx, M> { panic!("`intern_with_temp_alloc` with nested allocations"); } } - Ok(alloc_id) + interp_ok(alloc_id) } } diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index 4c34ffc5d4e..52780cc6a3a 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -18,7 +18,7 @@ use super::util::ensure_monomorphic_enough; use super::{ Allocation, CheckInAllocMsg, ConstAllocation, GlobalId, ImmTy, InterpCx, InterpResult, MPlaceTy, Machine, OpTy, Pointer, PointerArithmetic, Provenance, Scalar, err_inval, - err_ub_custom, err_unsup_format, throw_inval, throw_ub_custom, throw_ub_format, + err_ub_custom, err_unsup_format, interp_ok, throw_inval, throw_ub_custom, throw_ub_format, }; use crate::fluent_generated as fluent; @@ -39,7 +39,7 @@ pub(crate) fn eval_nullary_intrinsic<'tcx>( ) -> InterpResult<'tcx, ConstValue<'tcx>> { let tp_ty = args.type_at(0); let name = tcx.item_name(def_id); - Ok(match name { + interp_ok(match name { sym::type_name => { ensure_monomorphic_enough(tcx, tp_ty)?; let alloc = alloc_type_name(tcx, tp_ty); @@ -329,6 +329,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { fluent::const_eval_offset_from_different_allocations, name = intrinsic_name, ) + .into() })?; // Perform division by size to compute return value. @@ -378,7 +379,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { M::panic_nounwind(self, &msg)?; // Skip the `return_to_block` at the end (we panicked, we do not return). - return Ok(true); + return interp_ok(true); } } sym::simd_insert => { @@ -438,12 +439,12 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { } // Unsupported intrinsic: skip the return_to_block below. - _ => return Ok(false), + _ => return interp_ok(false), } trace!("{:?}", self.dump_place(&dest.clone().into())); self.return_to_block(ret)?; - Ok(true) + interp_ok(true) } pub(super) fn eval_nondiverging_intrinsic( @@ -457,7 +458,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { if !cond { throw_ub_custom!(fluent::const_eval_assume_false); } - Ok(()) + interp_ok(()) } NonDivergingIntrinsic::CopyNonOverlapping(mir::CopyNonOverlapping { count, @@ -499,7 +500,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { } _ => bug!("not a numeric intrinsic: {}", name), }; - Ok(Scalar::from_uint(bits_out, ret_layout.size)) + interp_ok(Scalar::from_uint(bits_out, ret_layout.size)) } pub fn exact_div( @@ -540,7 +541,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { let (val, overflowed) = self.binary_op(mir_op.wrapping_to_overflowing().unwrap(), l, r)?.to_scalar_pair(); - Ok(if overflowed.to_bool()? { + interp_ok(if overflowed.to_bool()? { let size = l.layout.size; if l.layout.abi.is_signed() { // For signed ints the saturated value depends on the sign of the first @@ -582,7 +583,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // The offset must be in bounds starting from `ptr`. self.check_ptr_access_signed(ptr, offset_bytes, CheckInAllocMsg::PointerArithmeticTest)?; // This also implies that there is no overflow, so we are done. - Ok(ptr.wrapping_signed_offset(offset_bytes, self)) + interp_ok(ptr.wrapping_signed_offset(offset_bytes, self)) } /// Copy `count*size_of::()` many bytes from `*src` to `*dst`. @@ -628,7 +629,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { self.copy_op(&right, &left)?; self.copy_op(&temp, &right)?; self.deallocate_ptr(temp.ptr(), None, kind)?; - Ok(()) + interp_ok(()) } pub fn write_bytes_intrinsic( @@ -669,7 +670,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // `Ordering`'s discriminants are -1/0/+1, so casting does the right thing. let result = Ord::cmp(left_bytes, right_bytes) as i32; - Ok(Scalar::from_i32(result)) + interp_ok(Scalar::from_i32(result)) } pub(crate) fn raw_eq_intrinsic( @@ -687,13 +688,13 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { this.check_ptr_align(ptr, layout.align.abi)?; let Some(alloc_ref) = self.get_ptr_alloc(ptr, layout.size)? else { // zero-sized access - return Ok(&[]); + return interp_ok(&[]); }; alloc_ref.get_bytes_strip_provenance() }; let lhs_bytes = get_bytes(self, lhs)?; let rhs_bytes = get_bytes(self, rhs)?; - Ok(Scalar::from_bool(lhs_bytes == rhs_bytes)) + interp_ok(Scalar::from_bool(lhs_bytes == rhs_bytes)) } } diff --git a/compiler/rustc_const_eval/src/interpret/machine.rs b/compiler/rustc_const_eval/src/interpret/machine.rs index a809f74e8eb..0f796c31222 100644 --- a/compiler/rustc_const_eval/src/interpret/machine.rs +++ b/compiler/rustc_const_eval/src/interpret/machine.rs @@ -20,7 +20,8 @@ use rustc_target::spec::abi::Abi as CallAbi; use super::{ AllocBytes, AllocId, AllocKind, AllocRange, Allocation, CTFE_ALLOC_SALT, ConstAllocation, CtfeProvenance, FnArg, Frame, ImmTy, InterpCx, InterpResult, MPlaceTy, MemoryKind, - Misalignment, OpTy, PlaceTy, Pointer, Provenance, RangeSet, throw_unsup, throw_unsup_format, + Misalignment, OpTy, PlaceTy, Pointer, Provenance, RangeSet, interp_ok, throw_unsup, + throw_unsup_format, }; /// Data returned by [`Machine::after_stack_pop`], and consumed by @@ -185,7 +186,7 @@ pub trait Machine<'tcx>: Sized { ecx: &InterpCx<'tcx, Self>, instance: ty::InstanceKind<'tcx>, ) -> InterpResult<'tcx, &'tcx mir::Body<'tcx>> { - Ok(ecx.tcx.instance_mir(instance)) + interp_ok(ecx.tcx.instance_mir(instance)) } /// Entry point to all function calls. @@ -280,7 +281,7 @@ pub trait Machine<'tcx>: Sized { /// Called before a basic block terminator is executed. #[inline] fn before_terminator(_ecx: &mut InterpCx<'tcx, Self>) -> InterpResult<'tcx> { - Ok(()) + interp_ok(()) } /// Determines the result of a `NullaryOp::UbChecks` invocation. @@ -290,7 +291,7 @@ pub trait Machine<'tcx>: Sized { /// You can use this to detect long or endlessly running programs. #[inline] fn increment_const_eval_counter(_ecx: &mut InterpCx<'tcx, Self>) -> InterpResult<'tcx> { - Ok(()) + interp_ok(()) } /// Called before a global allocation is accessed. @@ -304,7 +305,7 @@ pub trait Machine<'tcx>: Sized { _static_def_id: Option, _is_write: bool, ) -> InterpResult<'tcx> { - Ok(()) + interp_ok(()) } /// Return the `AllocId` for the given thread-local static in the current thread. @@ -422,7 +423,7 @@ pub trait Machine<'tcx>: Sized { _prov: (AllocId, Self::ProvenanceExtra), _range: AllocRange, ) -> InterpResult<'tcx> { - Ok(()) + interp_ok(()) } /// Hook for performing extra checks on any memory read access, @@ -433,7 +434,7 @@ pub trait Machine<'tcx>: Sized { /// Used to prevent statics from self-initializing by reading from their own memory /// as it is being initialized. fn before_alloc_read(_ecx: &InterpCx<'tcx, Self>, _alloc_id: AllocId) -> InterpResult<'tcx> { - Ok(()) + interp_ok(()) } /// Hook for performing extra checks on a memory write access. @@ -446,7 +447,7 @@ pub trait Machine<'tcx>: Sized { _prov: (AllocId, Self::ProvenanceExtra), _range: AllocRange, ) -> InterpResult<'tcx> { - Ok(()) + interp_ok(()) } /// Hook for performing extra operations on a memory deallocation. @@ -460,7 +461,7 @@ pub trait Machine<'tcx>: Sized { _align: Align, _kind: MemoryKind, ) -> InterpResult<'tcx> { - Ok(()) + interp_ok(()) } /// Executes a retagging operation for a single pointer. @@ -471,7 +472,7 @@ pub trait Machine<'tcx>: Sized { _kind: mir::RetagKind, val: &ImmTy<'tcx, Self::Provenance>, ) -> InterpResult<'tcx, ImmTy<'tcx, Self::Provenance>> { - Ok(val.clone()) + interp_ok(val.clone()) } /// Executes a retagging operation on a compound value. @@ -482,7 +483,7 @@ pub trait Machine<'tcx>: Sized { _kind: mir::RetagKind, _place: &PlaceTy<'tcx, Self::Provenance>, ) -> InterpResult<'tcx> { - Ok(()) + interp_ok(()) } /// Called on places used for in-place function argument and return value handling. @@ -516,7 +517,7 @@ pub trait Machine<'tcx>: Sized { /// Called immediately after a stack frame got pushed and its locals got initialized. fn after_stack_push(_ecx: &mut InterpCx<'tcx, Self>) -> InterpResult<'tcx> { - Ok(()) + interp_ok(()) } /// Called just before the return value is copied to the caller-provided return place. @@ -524,7 +525,7 @@ pub trait Machine<'tcx>: Sized { _ecx: &InterpCx<'tcx, Self>, _frame: &Frame<'tcx, Self::Provenance, Self::FrameExtra>, ) -> InterpResult<'tcx> { - Ok(()) + interp_ok(()) } /// Called immediately after a stack frame got popped, but before jumping back to the caller. @@ -537,14 +538,14 @@ pub trait Machine<'tcx>: Sized { ) -> InterpResult<'tcx, ReturnAction> { // By default, we do not support unwinding from panics assert!(!unwinding); - Ok(ReturnAction::Normal) + interp_ok(ReturnAction::Normal) } /// Called immediately after an "immediate" local variable is read /// (i.e., this is called for reads that do not end up accessing addressable memory). #[inline(always)] fn after_local_read(_ecx: &InterpCx<'tcx, Self>, _local: mir::Local) -> InterpResult<'tcx> { - Ok(()) + interp_ok(()) } /// Called immediately after an "immediate" local variable is assigned a new value @@ -556,7 +557,7 @@ pub trait Machine<'tcx>: Sized { _local: mir::Local, _storage_live: bool, ) -> InterpResult<'tcx> { - Ok(()) + interp_ok(()) } /// Called immediately after actual memory was allocated for a local @@ -567,7 +568,7 @@ pub trait Machine<'tcx>: Sized { _local: mir::Local, _mplace: &MPlaceTy<'tcx, Self::Provenance>, ) -> InterpResult<'tcx> { - Ok(()) + interp_ok(()) } /// Evaluate the given constant. The `eval` function will do all the required evaluation, @@ -645,7 +646,7 @@ pub macro compile_time_machine(<$tcx: lifetime>) { ) -> InterpResult<$tcx> { // For now we don't do any checking here. We can't use `tcx.sess` because that can differ // between crates, and we need to ensure that const-eval always behaves the same. - Ok(()) + interp_ok(()) } #[inline(always)] @@ -665,7 +666,7 @@ pub macro compile_time_machine(<$tcx: lifetime>) { fn ub_checks(_ecx: &InterpCx<$tcx, Self>) -> InterpResult<$tcx, bool> { // We can't look at `tcx.sess` here as that can differ across crates, which can lead to // unsound differences in evaluating the same constant at different instantiation sites. - Ok(true) + interp_ok(true) } #[inline(always)] @@ -675,7 +676,7 @@ pub macro compile_time_machine(<$tcx: lifetime>) { alloc: &'b Allocation, ) -> InterpResult<$tcx, Cow<'b, Allocation>> { // Overwrite default implementation: no need to adjust anything. - Ok(Cow::Borrowed(alloc)) + interp_ok(Cow::Borrowed(alloc)) } fn init_alloc_extra( @@ -685,7 +686,7 @@ pub macro compile_time_machine(<$tcx: lifetime>) { _size: Size, _align: Align, ) -> InterpResult<$tcx, Self::AllocExtra> { - Ok(()) + interp_ok(()) } fn extern_static_pointer( @@ -693,7 +694,7 @@ pub macro compile_time_machine(<$tcx: lifetime>) { def_id: DefId, ) -> InterpResult<$tcx, Pointer> { // Use the `AllocId` associated with the `DefId`. Any actual *access* will fail. - Ok(Pointer::new(ecx.tcx.reserve_and_set_static_alloc(def_id).into(), Size::ZERO)) + interp_ok(Pointer::new(ecx.tcx.reserve_and_set_static_alloc(def_id).into(), Size::ZERO)) } #[inline(always)] @@ -702,7 +703,7 @@ pub macro compile_time_machine(<$tcx: lifetime>) { ptr: Pointer, _kind: Option>, ) -> InterpResult<$tcx, Pointer> { - Ok(ptr) + interp_ok(ptr) } #[inline(always)] @@ -713,7 +714,7 @@ pub macro compile_time_machine(<$tcx: lifetime>) { // Allow these casts, but make the pointer not dereferenceable. // (I.e., they behave like transmutation.) // This is correct because no pointers can ever be exposed in compile-time evaluation. - Ok(Pointer::from_addr_invalid(addr)) + interp_ok(Pointer::from_addr_invalid(addr)) } #[inline(always)] diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs index c3b506d848c..e6ab8ca12a8 100644 --- a/compiler/rustc_const_eval/src/interpret/memory.rs +++ b/compiler/rustc_const_eval/src/interpret/memory.rs @@ -23,7 +23,7 @@ use tracing::{debug, instrument, trace}; use super::{ AllocBytes, AllocId, AllocMap, AllocRange, Allocation, CheckAlignMsg, CheckInAllocMsg, CtfeProvenance, GlobalAlloc, InterpCx, InterpResult, Machine, MayLeak, Misalignment, Pointer, - PointerArithmetic, Provenance, Scalar, alloc_range, err_ub, err_ub_custom, throw_ub, + PointerArithmetic, Provenance, Scalar, alloc_range, err_ub, err_ub_custom, interp_ok, throw_ub, throw_ub_custom, throw_unsup, throw_unsup_format, }; use crate::fluent_generated as fluent; @@ -82,7 +82,7 @@ pub enum FnVal<'tcx, Other> { impl<'tcx, Other> FnVal<'tcx, Other> { pub fn as_instance(self) -> InterpResult<'tcx, Instance<'tcx>> { match self { - FnVal::Instance(instance) => Ok(instance), + FnVal::Instance(instance) => interp_ok(instance), FnVal::Other(_) => { throw_unsup_format!("'foreign' function pointers are not supported in this context") } @@ -284,7 +284,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { self.mem_copy(ptr, new_ptr.into(), old_size.min(new_size), /*nonoverlapping*/ true)?; self.deallocate_ptr(ptr, old_size_and_align, kind)?; - Ok(new_ptr) + interp_ok(new_ptr) } #[instrument(skip(self), level = "debug")] @@ -330,8 +330,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { ) } None => err_ub!(PointerUseAfterFree(alloc_id, CheckInAllocMsg::MemoryAccessTest)), - } - .into()); + }) + .into(); }; if alloc.mutability.is_not() { @@ -376,7 +376,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { bug!("Nothing can be deallocated twice"); } - Ok(()) + interp_ok(()) } /// Internal helper function to determine the allocation and offset of a pointer (if any). @@ -395,7 +395,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { |this, alloc_id, offset, prov| { let (size, align) = this .get_live_alloc_size_and_align(alloc_id, CheckInAllocMsg::MemoryAccessTest)?; - Ok((size, align, (alloc_id, offset, prov))) + interp_ok((size, align, (alloc_id, offset, prov))) }, ) } @@ -412,9 +412,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { let size = i64::try_from(size.bytes()).unwrap(); // it would be an error to even ask for more than isize::MAX bytes Self::check_and_deref_ptr(self, ptr, size, msg, |this, alloc_id, _, _| { let (size, align) = this.get_live_alloc_size_and_align(alloc_id, msg)?; - Ok((size, align, ())) + interp_ok((size, align, ())) })?; - Ok(()) + interp_ok(()) } /// Check whether the given pointer points to live memory for a signed amount of bytes. @@ -428,9 +428,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { ) -> InterpResult<'tcx> { Self::check_and_deref_ptr(self, ptr, size, msg, |this, alloc_id, _, _| { let (size, align) = this.get_live_alloc_size_and_align(alloc_id, msg)?; - Ok((size, align, ())) + interp_ok((size, align, ())) })?; - Ok(()) + interp_ok(()) } /// Low-level helper function to check if a ptr is in-bounds and potentially return a reference @@ -455,10 +455,10 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { ) -> InterpResult<'tcx, Option> { // Everything is okay with size 0. if size == 0 { - return Ok(None); + return interp_ok(None); } - Ok(match this.borrow().ptr_try_get_alloc_id(ptr, size) { + interp_ok(match this.borrow().ptr_try_get_alloc_id(ptr, size) { Err(addr) => { // We couldn't get a proper allocation. throw_ub!(DanglingIntPointer { addr, inbounds_size: size, msg }); @@ -498,7 +498,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { if let Some(misaligned) = misaligned { throw_ub!(AlignmentCheckFailed(misaligned, msg)) } - Ok(()) + interp_ok(()) } pub(super) fn is_ptr_misaligned( @@ -634,7 +634,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // `get_global_alloc` that we can actually use directly without inserting anything anywhere. // So the error type is `InterpResult<'tcx, &Allocation>`. let a = self.memory.alloc_map.get_or(id, || { - let alloc = self.get_global_alloc(id, /*is_write*/ false).map_err(Err)?; + // We have to funnel the `InterpErrorInfo` through a `Result` to match the `get_or` API, + // so we use `report_err` for that. + let alloc = self.get_global_alloc(id, /*is_write*/ false).report_err().map_err(Err)?; match alloc { Cow::Borrowed(alloc) => { // We got a ref, cheaply return that as an "error" so that the @@ -653,8 +655,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { }); // Now unpack that funny error type match a { - Ok(a) => Ok(&a.1), - Err(a) => a, + Ok(a) => interp_ok(&a.1), + Err(a) => a.into(), } } @@ -662,7 +664,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { /// The caller is responsible for calling the access hooks! pub fn get_alloc_bytes_unchecked_raw(&self, id: AllocId) -> InterpResult<'tcx, *const u8> { let alloc = self.get_alloc_raw(id)?; - Ok(alloc.get_bytes_unchecked_raw()) + interp_ok(alloc.get_bytes_unchecked_raw()) } /// Bounds-checked *but not align-checked* allocation access. @@ -680,7 +682,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { CheckInAllocMsg::MemoryAccessTest, |this, alloc_id, offset, prov| { let alloc = this.get_alloc_raw(alloc_id)?; - Ok((alloc.size(), alloc.align, (alloc_id, offset, prov, alloc))) + interp_ok((alloc.size(), alloc.align, (alloc_id, offset, prov, alloc))) }, )?; // We want to call the hook on *all* accesses that involve an AllocId, including zero-sized @@ -703,20 +705,20 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { range, )?; } - Ok(Some(AllocRef { alloc, range, tcx: *self.tcx, alloc_id })) + interp_ok(Some(AllocRef { alloc, range, tcx: *self.tcx, alloc_id })) } else { - Ok(None) + interp_ok(None) } } /// Return the `extra` field of the given allocation. pub fn get_alloc_extra<'a>(&'a self, id: AllocId) -> InterpResult<'tcx, &'a M::AllocExtra> { - Ok(&self.get_alloc_raw(id)?.extra) + interp_ok(&self.get_alloc_raw(id)?.extra) } /// Return the `mutability` field of the given allocation. pub fn get_alloc_mutability<'a>(&'a self, id: AllocId) -> InterpResult<'tcx, Mutability> { - Ok(self.get_alloc_raw(id)?.mutability) + interp_ok(self.get_alloc_raw(id)?.mutability) } /// Gives raw mutable access to the `Allocation`, without bounds or alignment checks. @@ -750,7 +752,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { if alloc.mutability.is_not() { throw_ub!(WriteToReadOnly(id)) } - Ok((alloc, &mut self.machine)) + interp_ok((alloc, &mut self.machine)) } /// Gives raw, mutable access to the `Allocation` address, without bounds or alignment checks. @@ -760,7 +762,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { id: AllocId, ) -> InterpResult<'tcx, *mut u8> { let alloc = self.get_alloc_raw_mut(id)?.0; - Ok(alloc.get_bytes_unchecked_raw_mut()) + interp_ok(alloc.get_bytes_unchecked_raw_mut()) } /// Bounds-checked *but not align-checked* allocation access. @@ -781,7 +783,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { CheckInAllocMsg::MemoryAccessTest, |this, alloc_id, offset, prov| { let (alloc, machine) = this.get_alloc_raw_mut(alloc_id)?; - Ok((alloc.size(), alloc.align, (alloc_id, offset, prov, alloc, machine))) + interp_ok((alloc.size(), alloc.align, (alloc_id, offset, prov, alloc, machine))) }, )?; @@ -790,9 +792,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { if !validation_in_progress { M::before_memory_write(tcx, machine, &mut alloc.extra, (alloc_id, prov), range)?; } - Ok(Some(AllocRefMut { alloc, range, tcx: *tcx, alloc_id })) + interp_ok(Some(AllocRefMut { alloc, range, tcx: *tcx, alloc_id })) } else { - Ok(None) + interp_ok(None) } } @@ -802,7 +804,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { id: AllocId, ) -> InterpResult<'tcx, (&'a mut M::AllocExtra, &'a mut M)> { let (alloc, machine) = self.get_alloc_raw_mut(id)?; - Ok((&mut alloc.extra, machine)) + interp_ok((&mut alloc.extra, machine)) } /// Check whether an allocation is live. This is faster than calling @@ -904,7 +906,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { if matches!(kind, AllocKind::Dead) { throw_ub!(PointerUseAfterFree(id, msg)) } - Ok((size, align)) + interp_ok((size, align)) } fn get_fn_alloc(&self, id: AllocId) -> Option> { @@ -928,7 +930,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { throw_ub!(InvalidFunctionPointer(Pointer::new(alloc_id, offset))) } self.get_fn_alloc(alloc_id) - .ok_or_else(|| err_ub!(InvalidFunctionPointer(Pointer::new(alloc_id, offset))).into()) + .ok_or_else(|| err_ub!(InvalidFunctionPointer(Pointer::new(alloc_id, offset)))) + .into() } /// Get the dynamic type of the given vtable pointer. @@ -951,12 +954,12 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { if let Some(expected_dyn_type) = expected_trait { self.check_vtable_for_type(vtable_dyn_type, expected_dyn_type)?; } - Ok(ty) + interp_ok(ty) } pub fn alloc_mark_immutable(&mut self, id: AllocId) -> InterpResult<'tcx> { self.get_alloc_raw_mut(id)?.0.mutability = Mutability::Not; - Ok(()) + interp_ok(()) } /// Create a lazy debug printer that prints the given allocation and all allocations it points @@ -1144,10 +1147,11 @@ impl<'a, 'tcx, Prov: Provenance, Extra, Bytes: AllocBytes> pub fn write_scalar(&mut self, range: AllocRange, val: Scalar) -> InterpResult<'tcx> { let range = self.range.subrange(range); debug!("write_scalar at {:?}{range:?}: {val:?}", self.alloc_id); - Ok(self - .alloc + + self.alloc .write_scalar(&self.tcx, range, val) - .map_err(|e| e.to_interp_error(self.alloc_id))?) + .map_err(|e| e.to_interp_error(self.alloc_id)) + .into() } /// `offset` is relative to this allocation reference, not the base of the allocation. @@ -1158,26 +1162,27 @@ impl<'a, 'tcx, Prov: Provenance, Extra, Bytes: AllocBytes> /// Mark the given sub-range (relative to this allocation reference) as uninitialized. pub fn write_uninit(&mut self, range: AllocRange) -> InterpResult<'tcx> { let range = self.range.subrange(range); - Ok(self - .alloc + + self.alloc .write_uninit(&self.tcx, range) - .map_err(|e| e.to_interp_error(self.alloc_id))?) + .map_err(|e| e.to_interp_error(self.alloc_id)) + .into() } /// Mark the entire referenced range as uninitialized pub fn write_uninit_full(&mut self) -> InterpResult<'tcx> { - Ok(self - .alloc + self.alloc .write_uninit(&self.tcx, self.range) - .map_err(|e| e.to_interp_error(self.alloc_id))?) + .map_err(|e| e.to_interp_error(self.alloc_id)) + .into() } /// Remove all provenance in the reference range. pub fn clear_provenance(&mut self) -> InterpResult<'tcx> { - Ok(self - .alloc + self.alloc .clear_provenance(&self.tcx, self.range) - .map_err(|e| e.to_interp_error(self.alloc_id))?) + .map_err(|e| e.to_interp_error(self.alloc_id)) + .into() } } @@ -1189,12 +1194,10 @@ impl<'a, 'tcx, Prov: Provenance, Extra, Bytes: AllocBytes> AllocRef<'a, 'tcx, Pr read_provenance: bool, ) -> InterpResult<'tcx, Scalar> { let range = self.range.subrange(range); - let res = self - .alloc + self.alloc .read_scalar(&self.tcx, range, read_provenance) - .map_err(|e| e.to_interp_error(self.alloc_id))?; - debug!("read_scalar at {:?}{range:?}: {res:?}", self.alloc_id); - Ok(res) + .map_err(|e| e.to_interp_error(self.alloc_id)) + .into() } /// `range` is relative to this allocation reference, not the base of the allocation. @@ -1212,10 +1215,10 @@ impl<'a, 'tcx, Prov: Provenance, Extra, Bytes: AllocBytes> AllocRef<'a, 'tcx, Pr /// `range` is relative to this allocation reference, not the base of the allocation. pub fn get_bytes_strip_provenance<'b>(&'b self) -> InterpResult<'tcx, &'a [u8]> { - Ok(self - .alloc + self.alloc .get_bytes_strip_provenance(&self.tcx, self.range) - .map_err(|e| e.to_interp_error(self.alloc_id))?) + .map_err(|e| e.to_interp_error(self.alloc_id)) + .into() } /// Returns whether the allocation has provenance anywhere in the range of the `AllocRef`. @@ -1236,14 +1239,16 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { ) -> InterpResult<'tcx, &[u8]> { let Some(alloc_ref) = self.get_ptr_alloc(ptr, size)? else { // zero-sized access - return Ok(&[]); + return interp_ok(&[]); }; // Side-step AllocRef and directly access the underlying bytes more efficiently. // (We are staying inside the bounds here so all is good.) - Ok(alloc_ref - .alloc - .get_bytes_strip_provenance(&alloc_ref.tcx, alloc_ref.range) - .map_err(|e| e.to_interp_error(alloc_ref.alloc_id))?) + interp_ok( + alloc_ref + .alloc + .get_bytes_strip_provenance(&alloc_ref.tcx, alloc_ref.range) + .map_err(|e| e.to_interp_error(alloc_ref.alloc_id))?, + ) } /// Writes the given stream of bytes into memory. @@ -1263,7 +1268,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { let Some(alloc_ref) = self.get_ptr_alloc_mut(ptr, size)? else { // zero-sized access assert_matches!(src.next(), None, "iterator said it was empty but returned an element"); - return Ok(()); + return interp_ok(()); }; // Side-step AllocRef and directly access the underlying bytes more efficiently. @@ -1279,7 +1284,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { *dest = src.next().expect("iterator was shorter than it said it would be"); } assert_matches!(src.next(), None, "iterator was longer than it said it would be"); - Ok(()) + interp_ok(()) } pub fn mem_copy( @@ -1316,7 +1321,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // Source alloc preparations and access hooks. let Some((src_alloc_id, src_offset, src_prov)) = src_parts else { // Zero-sized *source*, that means dest is also zero-sized and we have nothing to do. - return Ok(()); + return interp_ok(()); }; let src_alloc = self.get_alloc_raw(src_alloc_id)?; let src_range = alloc_range(src_offset, size); @@ -1332,7 +1337,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // We already did the source checks and called the hooks so we are good to return early. let Some((dest_alloc_id, dest_offset, dest_prov)) = dest_parts else { // Zero-sized *destination*. - return Ok(()); + return interp_ok(()); }; // Prepare getting source provenance. @@ -1375,7 +1380,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { .write_uninit(&tcx, dest_range) .map_err(|e| e.to_interp_error(dest_alloc_id))?; // We can forget about the provenance, this is all not initialized anyway. - return Ok(()); + return interp_ok(()); } // SAFE: The above indexing would have panicked if there weren't at least `size` bytes @@ -1432,7 +1437,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // copy the provenance to the destination dest_alloc.provenance_apply_copy(provenance); - Ok(()) + interp_ok(()) } } @@ -1441,7 +1446,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { /// Test if this value might be null. /// If the machine does not support ptr-to-int casts, this is conservative. pub fn scalar_may_be_null(&self, scalar: Scalar) -> InterpResult<'tcx, bool> { - Ok(match scalar.try_to_scalar_int() { + interp_ok(match scalar.try_to_scalar_int() { Ok(int) => int.is_null(), Err(_) => { // Can only happen during CTFE. @@ -1508,13 +1513,14 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { ptr: Pointer>, size: i64, ) -> InterpResult<'tcx, (AllocId, Size, M::ProvenanceExtra)> { - self.ptr_try_get_alloc_id(ptr, size).map_err(|offset| { - err_ub!(DanglingIntPointer { - addr: offset, - inbounds_size: size, - msg: CheckInAllocMsg::InboundsTest + self.ptr_try_get_alloc_id(ptr, size) + .map_err(|offset| { + err_ub!(DanglingIntPointer { + addr: offset, + inbounds_size: size, + msg: CheckInAllocMsg::InboundsTest + }) }) .into() - }) } } diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs index 31ee3e6519a..7e6600060b4 100644 --- a/compiler/rustc_const_eval/src/interpret/operand.rs +++ b/compiler/rustc_const_eval/src/interpret/operand.rs @@ -16,7 +16,7 @@ use tracing::trace; use super::{ CtfeProvenance, InterpCx, InterpResult, MPlaceTy, Machine, MemPlace, MemPlaceMeta, OffsetMode, PlaceTy, Pointer, Projectable, Provenance, Scalar, alloc_range, err_ub, from_known_layout, - mir_assign_valid_types, throw_ub, + interp_ok, mir_assign_valid_types, throw_ub, }; /// An `Immediate` represents a single immediate self-contained Rust value. @@ -149,7 +149,7 @@ impl Immediate { } Immediate::Uninit => {} } - Ok(()) + interp_ok(()) } } @@ -307,7 +307,7 @@ impl<'tcx, Prov: Provenance> ImmTy<'tcx, Prov> { data_size: s.size().bytes(), })); } - Ok(s) + interp_ok(s) } #[inline] @@ -430,7 +430,7 @@ impl<'tcx, Prov: Provenance> Projectable<'tcx, Prov> for ImmTy<'tcx, Prov> { ecx: &InterpCx<'tcx, M>, ) -> InterpResult<'tcx, Self> { assert_matches!(meta, MemPlaceMeta::None); // we can't store this anywhere anyway - Ok(self.offset_(offset, layout, ecx)) + interp_ok(self.offset_(offset, layout, ecx)) } #[inline(always)] @@ -438,7 +438,7 @@ impl<'tcx, Prov: Provenance> Projectable<'tcx, Prov> for ImmTy<'tcx, Prov> { &self, _ecx: &InterpCx<'tcx, M>, ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> { - Ok(self.clone().into()) + interp_ok(self.clone().into()) } } @@ -514,11 +514,13 @@ impl<'tcx, Prov: Provenance> Projectable<'tcx, Prov> for OpTy<'tcx, Prov> { ecx: &InterpCx<'tcx, M>, ) -> InterpResult<'tcx, Self> { match self.as_mplace_or_imm() { - Left(mplace) => Ok(mplace.offset_with_meta(offset, mode, meta, layout, ecx)?.into()), + Left(mplace) => { + interp_ok(mplace.offset_with_meta(offset, mode, meta, layout, ecx)?.into()) + } Right(imm) => { assert_matches!(meta, MemPlaceMeta::None); // no place to store metadata here // Every part of an uninit is uninit. - Ok(imm.offset_(offset, layout, ecx).into()) + interp_ok(imm.offset_(offset, layout, ecx).into()) } } } @@ -528,7 +530,7 @@ impl<'tcx, Prov: Provenance> Projectable<'tcx, Prov> for OpTy<'tcx, Prov> { &self, _ecx: &InterpCx<'tcx, M>, ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> { - Ok(self.clone()) + interp_ok(self.clone()) } } @@ -543,12 +545,12 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { ) -> InterpResult<'tcx, Option>> { if mplace.layout.is_unsized() { // Don't touch unsized - return Ok(None); + return interp_ok(None); } let Some(alloc) = self.get_place_alloc(mplace)? else { // zero-sized type can be left uninit - return Ok(Some(ImmTy::uninit(mplace.layout))); + return interp_ok(Some(ImmTy::uninit(mplace.layout))); }; // It may seem like all types with `Scalar` or `ScalarPair` ABI are fair game at this point. @@ -557,7 +559,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // case where some of the bytes are initialized and others are not. So, we need an extra // check that walks over the type of `mplace` to make sure it is truly correct to treat this // like a `Scalar` (or `ScalarPair`). - Ok(match mplace.layout.abi { + interp_ok(match mplace.layout.abi { Abi::Scalar(abi::Scalar::Initialized { value: s, .. }) => { let size = s.size(self); assert_eq!(size, mplace.layout.size, "abi::Scalar size does not match layout size"); @@ -606,7 +608,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { &self, src: &impl Projectable<'tcx, M::Provenance>, ) -> InterpResult<'tcx, Either, ImmTy<'tcx, M::Provenance>>> { - Ok(match src.to_op(self)?.as_mplace_or_imm() { + interp_ok(match src.to_op(self)?.as_mplace_or_imm() { Left(ref mplace) => { if let Some(val) = self.read_immediate_from_mplace_raw(mplace)? { Right(val) @@ -637,7 +639,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { if matches!(*imm, Immediate::Uninit) { throw_ub!(InvalidUninitBytes(None)); } - Ok(imm) + interp_ok(imm) } /// Read a scalar from a place @@ -645,7 +647,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { &self, op: &impl Projectable<'tcx, M::Provenance>, ) -> InterpResult<'tcx, Scalar> { - Ok(self.read_immediate(op)?.to_scalar()) + interp_ok(self.read_immediate(op)?.to_scalar()) } // Pointer-sized reads are fairly common and need target layout access, so we wrap them in @@ -678,7 +680,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { let len = mplace.len(self)?; let bytes = self.read_bytes_ptr_strip_provenance(mplace.ptr(), Size::from_bytes(len))?; let str = std::str::from_utf8(bytes).map_err(|err| err_ub!(InvalidStr(err)))?; - Ok(str) + interp_ok(str) } /// Read from a local of the current frame. @@ -698,7 +700,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { assert!(!layout.is_unsized()); } M::after_local_read(self, local)?; - Ok(OpTy { op, layout }) + interp_ok(OpTy { op, layout }) } /// Every place can be read from, so we can turn them into an operand. @@ -709,12 +711,12 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { place: &PlaceTy<'tcx, M::Provenance>, ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> { match place.as_mplace_or_local() { - Left(mplace) => Ok(mplace.into()), + Left(mplace) => interp_ok(mplace.into()), Right((local, offset, locals_addr, _)) => { debug_assert!(place.layout.is_sized()); // only sized locals can ever be `Place::Local`. debug_assert_eq!(locals_addr, self.frame().locals_addr()); let base = self.local_to_op(local, None)?; - Ok(match offset { + interp_ok(match offset { Some(offset) => base.offset(offset, place.layout, self)?, None => { // In the common case this hasn't been projected. @@ -764,7 +766,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { ) } } - Ok(op) + interp_ok(op) } /// Evaluate the operand, returning a place where you can then find the data. @@ -794,7 +796,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { } }; trace!("{:?}: {:?}", mir_op, op); - Ok(op) + interp_ok(op) } pub(crate) fn const_val_to_op( @@ -805,12 +807,13 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> { // Other cases need layout. let adjust_scalar = |scalar| -> InterpResult<'tcx, _> { - Ok(match scalar { + interp_ok(match scalar { Scalar::Ptr(ptr, size) => Scalar::Ptr(self.global_root_pointer(ptr)?, size), Scalar::Int(int) => Scalar::Int(int), }) }; - let layout = from_known_layout(self.tcx, self.param_env, layout, || self.layout_of(ty))?; + let layout = + from_known_layout(self.tcx, self.param_env, layout, || self.layout_of(ty).into())?; let imm = match val_val { mir::ConstValue::Indirect { alloc_id, offset } => { // This is const data, no mutation allowed. @@ -818,7 +821,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { CtfeProvenance::from(alloc_id).as_immutable(), offset, ))?; - return Ok(self.ptr_to_mplace(ptr.into(), layout).into()); + return interp_ok(self.ptr_to_mplace(ptr.into(), layout).into()); } mir::ConstValue::Scalar(x) => adjust_scalar(x)?.into(), mir::ConstValue::ZeroSized => Immediate::Uninit, @@ -829,7 +832,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { Immediate::new_slice(self.global_root_pointer(ptr)?.into(), meta, self) } }; - Ok(OpTy { op: Operand::Immediate(imm), layout }) + interp_ok(OpTy { op: Operand::Immediate(imm), layout }) } } diff --git a/compiler/rustc_const_eval/src/interpret/operator.rs b/compiler/rustc_const_eval/src/interpret/operator.rs index 863b330a74c..52cd9b898bb 100644 --- a/compiler/rustc_const_eval/src/interpret/operator.rs +++ b/compiler/rustc_const_eval/src/interpret/operator.rs @@ -9,7 +9,7 @@ use rustc_span::symbol::sym; use rustc_target::abi::Size; use tracing::trace; -use super::{ImmTy, InterpCx, Machine, MemPlaceMeta, throw_ub}; +use super::{ImmTy, InterpCx, Machine, MemPlaceMeta, interp_ok, throw_ub}; impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { fn three_way_compare(&self, lhs: T, rhs: T) -> ImmTy<'tcx, M::Provenance> { @@ -156,7 +156,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { }); } - return Ok(ImmTy::from_scalar_int(result, left.layout)); + return interp_ok(ImmTy::from_scalar_int(result, left.layout)); } // For the remaining ops, the types must be the same on both sides @@ -181,10 +181,10 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { _ => None, }; if let Some(op) = op { - return Ok(ImmTy::from_bool(op(&l_signed(), &r_signed()), *self.tcx)); + return interp_ok(ImmTy::from_bool(op(&l_signed(), &r_signed()), *self.tcx)); } if bin_op == Cmp { - return Ok(self.three_way_compare(l_signed(), r_signed())); + return interp_ok(self.three_way_compare(l_signed(), r_signed())); } let op: Option (i128, bool)> = match bin_op { Div if r.is_null() => throw_ub!(DivisionByZero), @@ -221,7 +221,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { throw_ub!(ArithOverflow { intrinsic }); } let res = ImmTy::from_scalar_int(result, left.layout); - return Ok(if with_overflow { + return interp_ok(if with_overflow { let overflow = ImmTy::from_bool(overflow, *self.tcx); ImmTy::from_pair(res, overflow, *self.tcx) } else { @@ -234,10 +234,10 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { let r = r_unsigned(); if bin_op == Cmp { - return Ok(self.three_way_compare(l, r)); + return interp_ok(self.three_way_compare(l, r)); } - Ok(match bin_op { + interp_ok(match bin_op { Eq => ImmTy::from_bool(l == r, *self.tcx), Ne => ImmTy::from_bool(l != r, *self.tcx), @@ -339,7 +339,10 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { throw_ub!(PointerArithOverflow) } let offset_ptr = self.ptr_offset_inbounds(ptr, offset_bytes)?; - Ok(ImmTy::from_scalar(Scalar::from_maybe_pointer(offset_ptr, self), left.layout)) + interp_ok(ImmTy::from_scalar( + Scalar::from_maybe_pointer(offset_ptr, self), + left.layout, + )) } // Fall back to machine hook so Miri can support more pointer ops. @@ -366,20 +369,20 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { assert_eq!(left.layout.ty, right.layout.ty); let left = left.to_scalar(); let right = right.to_scalar(); - Ok(self.binary_char_op(bin_op, left.to_char()?, right.to_char()?)) + interp_ok(self.binary_char_op(bin_op, left.to_char()?, right.to_char()?)) } ty::Bool => { assert_eq!(left.layout.ty, right.layout.ty); let left = left.to_scalar(); let right = right.to_scalar(); - Ok(self.binary_bool_op(bin_op, left.to_bool()?, right.to_bool()?)) + interp_ok(self.binary_bool_op(bin_op, left.to_bool()?, right.to_bool()?)) } ty::Float(fty) => { assert_eq!(left.layout.ty, right.layout.ty); let layout = left.layout; let left = left.to_scalar(); let right = right.to_scalar(); - Ok(match fty { + interp_ok(match fty { FloatTy::F16 => { self.binary_float_op(bin_op, layout, left.to_f16()?, right.to_f16()?) } @@ -447,7 +450,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { Not => !val, _ => span_bug!(self.cur_span(), "Invalid bool op {:?}", un_op), }; - Ok(ImmTy::from_bool(res, *self.tcx)) + interp_ok(ImmTy::from_bool(res, *self.tcx)) } ty::Float(fty) => { let val = val.to_scalar(); @@ -462,7 +465,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { FloatTy::F64 => Scalar::from_f64(-val.to_f64()?), FloatTy::F128 => Scalar::from_f128(-val.to_f128()?), }; - Ok(ImmTy::from_scalar(res, layout)) + interp_ok(ImmTy::from_scalar(res, layout)) } ty::Int(..) => { let val = val.to_scalar().to_int(layout.size)?; @@ -472,7 +475,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { _ => span_bug!(self.cur_span(), "Invalid integer op {:?}", un_op), }; let res = ScalarInt::truncate_from_int(res, layout.size).0; - Ok(ImmTy::from_scalar(res.into(), layout)) + interp_ok(ImmTy::from_scalar(res.into(), layout)) } ty::Uint(..) => { let val = val.to_scalar().to_uint(layout.size)?; @@ -481,12 +484,12 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { _ => span_bug!(self.cur_span(), "Invalid unsigned integer op {:?}", un_op), }; let res = ScalarInt::truncate_from_uint(res, layout.size).0; - Ok(ImmTy::from_scalar(res.into(), layout)) + interp_ok(ImmTy::from_scalar(res.into(), layout)) } ty::RawPtr(..) | ty::Ref(..) => { assert_eq!(un_op, PtrMetadata); let (_, meta) = val.to_scalar_and_meta(); - Ok(match meta { + interp_ok(match meta { MemPlaceMeta::Meta(scalar) => { let ty = un_op.ty(*self.tcx, val.layout.ty); let layout = self.layout_of(ty)?; @@ -514,7 +517,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { let layout = self.layout_of(arg_ty)?; let usize_layout = || self.layout_of(self.tcx.types.usize).unwrap(); - Ok(match null_op { + interp_ok(match null_op { SizeOf => { if !layout.abi.is_sized() { span_bug!(self.cur_span(), "unsized type for `NullaryOp::SizeOf`"); diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs index 05264d32c6b..449d4c6bd7d 100644 --- a/compiler/rustc_const_eval/src/interpret/place.rs +++ b/compiler/rustc_const_eval/src/interpret/place.rs @@ -13,9 +13,9 @@ use rustc_target::abi::{Abi, Align, HasDataLayout, Size}; use tracing::{instrument, trace}; use super::{ - AllocRef, AllocRefMut, CheckAlignMsg, CtfeProvenance, DiscardInterpError, ImmTy, Immediate, - InterpCx, InterpResult, Machine, MemoryKind, Misalignment, OffsetMode, OpTy, Operand, Pointer, - Projectable, Provenance, Scalar, alloc_range, mir_assign_valid_types, + AllocRef, AllocRefMut, CheckAlignMsg, CtfeProvenance, ImmTy, Immediate, InterpCx, InterpResult, + Machine, MemoryKind, Misalignment, OffsetMode, OpTy, Operand, Pointer, Projectable, Provenance, + Scalar, alloc_range, interp_ok, mir_assign_valid_types, }; #[derive(Copy, Clone, Hash, PartialEq, Eq, Debug)] @@ -90,7 +90,7 @@ impl MemPlace { } OffsetMode::Wrapping => self.ptr.wrapping_offset(offset, ecx), }; - Ok(MemPlace { ptr, meta, misaligned: self.misaligned }) + interp_ok(MemPlace { ptr, meta, misaligned: self.misaligned }) } } @@ -163,7 +163,10 @@ impl<'tcx, Prov: Provenance> Projectable<'tcx, Prov> for MPlaceTy<'tcx, Prov> { layout: TyAndLayout<'tcx>, ecx: &InterpCx<'tcx, M>, ) -> InterpResult<'tcx, Self> { - Ok(MPlaceTy { mplace: self.mplace.offset_with_meta_(offset, mode, meta, ecx)?, layout }) + interp_ok(MPlaceTy { + mplace: self.mplace.offset_with_meta_(offset, mode, meta, ecx)?, + layout, + }) } #[inline(always)] @@ -171,7 +174,7 @@ impl<'tcx, Prov: Provenance> Projectable<'tcx, Prov> for MPlaceTy<'tcx, Prov> { &self, _ecx: &InterpCx<'tcx, M>, ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> { - Ok(self.clone().into()) + interp_ok(self.clone().into()) } } @@ -279,7 +282,7 @@ impl<'tcx, Prov: Provenance> Projectable<'tcx, Prov> for PlaceTy<'tcx, Prov> { layout: TyAndLayout<'tcx>, ecx: &InterpCx<'tcx, M>, ) -> InterpResult<'tcx, Self> { - Ok(match self.as_mplace_or_local() { + interp_ok(match self.as_mplace_or_local() { Left(mplace) => mplace.offset_with_meta(offset, mode, meta, layout, ecx)?.into(), Right((local, old_offset, locals_addr, _)) => { debug_assert!(layout.is_sized(), "unsized locals should live in memory"); @@ -367,7 +370,7 @@ impl<'tcx, Prov: Provenance> Writeable<'tcx, Prov> for MPlaceTy<'tcx, Prov> { &self, _ecx: &mut InterpCx<'tcx, M>, ) -> InterpResult<'tcx, MPlaceTy<'tcx, Prov>> { - Ok(self.clone()) + interp_ok(self.clone()) } } @@ -425,7 +428,7 @@ where // `ref_to_mplace` is called on raw pointers even if they don't actually get dereferenced; // we hence can't call `size_and_align_of` since that asserts more validity than we want. let ptr = ptr.to_pointer(self)?; - Ok(self.ptr_with_meta_to_mplace(ptr, meta, layout, /*unaligned*/ false)) + interp_ok(self.ptr_with_meta_to_mplace(ptr, meta, layout, /*unaligned*/ false)) } /// Turn a mplace into a (thin or wide) mutable raw pointer, pointing to the same space. @@ -437,7 +440,7 @@ where ) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>> { let imm = mplace.mplace.to_ref(self); let layout = self.layout_of(Ty::new_mut_ptr(self.tcx.tcx, mplace.layout.ty))?; - Ok(ImmTy::from_immediate(imm, layout)) + interp_ok(ImmTy::from_immediate(imm, layout)) } /// Take an operand, representing a pointer, and dereference it to a place. @@ -458,7 +461,7 @@ where trace!("deref to {} on {:?}", val.layout.ty, *val); let mplace = self.ref_to_mplace(&val)?; - Ok(mplace) + interp_ok(mplace) } #[inline] @@ -474,7 +477,7 @@ where // If an access is both OOB and misaligned, we want to see the bounds error. let a = self.get_ptr_alloc(mplace.ptr(), size)?; self.check_misalign(mplace.mplace.misaligned, CheckAlignMsg::BasedOn)?; - Ok(a) + interp_ok(a) } #[inline] @@ -489,17 +492,10 @@ where // We check alignment separately, and raise that error *after* checking everything else. // If an access is both OOB and misaligned, we want to see the bounds error. // However we have to call `check_misalign` first to make the borrow checker happy. - let misalign_err = self.check_misalign(mplace.mplace.misaligned, CheckAlignMsg::BasedOn); - match self.get_ptr_alloc_mut(mplace.ptr(), size) { - Ok(a) => { - misalign_err?; - Ok(a) - } - Err(e) => { - misalign_err.discard_interp_err(); - Err(e) - } - } + let misalign_res = self.check_misalign(mplace.mplace.misaligned, CheckAlignMsg::BasedOn); + // An error from get_ptr_alloc_mut takes precedence. + let (a, ()) = self.get_ptr_alloc_mut(mplace.ptr(), size).and(misalign_res)?; + interp_ok(a) } /// Turn a local in the current frame into a place. @@ -519,7 +515,7 @@ where Operand::Indirect(mplace) => Place::Ptr(*mplace), } }; - Ok(PlaceTy { place, layout }) + interp_ok(PlaceTy { place, layout }) } /// Computes a place. You should only use this if you intend to write into this @@ -556,7 +552,7 @@ where ) } } - Ok(place) + interp_ok(place) } /// Given a place, returns either the underlying mplace or a reference to where the value of @@ -572,7 +568,7 @@ where (&mut Immediate, TyAndLayout<'tcx>, mir::Local), >, > { - Ok(match place.to_place().as_mplace_or_local() { + interp_ok(match place.to_place().as_mplace_or_local() { Left(mplace) => Left(mplace), Right((local, offset, locals_addr, layout)) => { if offset.is_some() { @@ -617,7 +613,7 @@ where )?; } - Ok(()) + interp_ok(()) } /// Write a scalar to a place @@ -667,7 +663,7 @@ where self.write_immediate_to_mplace_no_validate(src, mplace.layout, mplace.mplace)?; } } - Ok(()) + interp_ok(()) } /// Write an immediate to memory. @@ -690,7 +686,7 @@ where let tcx = *self.tcx; let Some(mut alloc) = self.get_place_alloc_mut(&MPlaceTy { mplace: dest, layout })? else { // zero-sized access - return Ok(()); + return interp_ok(()); }; match value { @@ -715,7 +711,7 @@ where alloc.write_scalar(alloc_range(Size::ZERO, a_val.size()), a_val)?; alloc.write_scalar(alloc_range(b_offset, b_val.size()), b_val)?; // We don't have to reset padding here, `write_immediate` will anyway do a validation run. - Ok(()) + interp_ok(()) } Immediate::Uninit => alloc.write_uninit_full(), } @@ -736,12 +732,12 @@ where Left(mplace) => { let Some(mut alloc) = self.get_place_alloc_mut(&mplace)? else { // Zero-sized access - return Ok(()); + return interp_ok(()); }; alloc.write_uninit_full()?; } } - Ok(()) + interp_ok(()) } /// Remove all provenance in the given place. @@ -760,12 +756,12 @@ where Left(mplace) => { let Some(mut alloc) = self.get_place_alloc_mut(&mplace)? else { // Zero-sized access - return Ok(()); + return interp_ok(()); }; alloc.clear_provenance()?; } } - Ok(()) + interp_ok(()) } /// Copies the data from an operand to a place. @@ -848,7 +844,7 @@ where )?; } - Ok(()) + interp_ok(()) } /// Copies the data from an operand to a place. @@ -925,7 +921,7 @@ where self.mem_copy(src.ptr(), dest.ptr(), dest_size, /*nonoverlapping*/ true)?; self.check_misalign(src.mplace.misaligned, CheckAlignMsg::BasedOn)?; self.check_misalign(dest.mplace.misaligned, CheckAlignMsg::BasedOn)?; - Ok(()) + interp_ok(()) } /// Ensures that a place is in memory, and returns where it is. @@ -987,7 +983,7 @@ where Place::Ptr(mplace) => mplace, }; // Return with the original layout and align, so that the caller can go on - Ok(MPlaceTy { mplace, layout: place.layout }) + interp_ok(MPlaceTy { mplace, layout: place.layout }) } pub fn allocate_dyn( @@ -1000,7 +996,7 @@ where span_bug!(self.cur_span(), "cannot allocate space for `extern` type, size is not known") }; let ptr = self.allocate_ptr(size, align, kind)?; - Ok(self.ptr_with_meta_to_mplace(ptr.into(), meta, layout, /*unaligned*/ false)) + interp_ok(self.ptr_with_meta_to_mplace(ptr.into(), meta, layout, /*unaligned*/ false)) } pub fn allocate( @@ -1035,7 +1031,7 @@ where }; let meta = Scalar::from_target_usize(u64::try_from(str.len()).unwrap(), self); let layout = self.layout_of(self.tcx.types.str_).unwrap(); - Ok(self.ptr_with_meta_to_mplace( + interp_ok(self.ptr_with_meta_to_mplace( ptr.into(), MemPlaceMeta::Meta(meta), layout, @@ -1051,7 +1047,7 @@ where let _ = self.tcx.global_alloc(raw.alloc_id); let ptr = self.global_root_pointer(Pointer::from(raw.alloc_id))?; let layout = self.layout_of(raw.ty)?; - Ok(self.ptr_to_mplace(ptr.into(), layout)) + interp_ok(self.ptr_to_mplace(ptr.into(), layout)) } } diff --git a/compiler/rustc_const_eval/src/interpret/projection.rs b/compiler/rustc_const_eval/src/interpret/projection.rs index 621afdb1050..cc49d7cebf4 100644 --- a/compiler/rustc_const_eval/src/interpret/projection.rs +++ b/compiler/rustc_const_eval/src/interpret/projection.rs @@ -18,7 +18,7 @@ use tracing::{debug, instrument}; use super::{ InterpCx, InterpResult, MPlaceTy, Machine, MemPlaceMeta, OpTy, Provenance, Scalar, err_ub, - throw_ub, throw_unsup, + interp_ok, throw_ub, throw_unsup, }; /// Describes the constraints placed on offset-projections. @@ -54,7 +54,7 @@ pub trait Projectable<'tcx, Prov: Provenance>: Sized + std::fmt::Debug { // Go through the layout. There are lots of types that support a length, // e.g., SIMD types. (But not all repr(simd) types even have FieldsShape::Array!) match layout.fields { - abi::FieldsShape::Array { count, .. } => Ok(count), + abi::FieldsShape::Array { count, .. } => interp_ok(count), _ => bug!("len not supported on sized type {:?}", layout.ty), } } @@ -115,9 +115,9 @@ impl<'a, 'tcx, Prov: Provenance, P: Projectable<'tcx, Prov>> ArrayIterator<'a, ' &mut self, ecx: &InterpCx<'tcx, M>, ) -> InterpResult<'tcx, Option<(u64, P)>> { - let Some(idx) = self.range.next() else { return Ok(None) }; + let Some(idx) = self.range.next() else { return interp_ok(None) }; // We use `Wrapping` here since the offset has already been checked when the iterator was created. - Ok(Some(( + interp_ok(Some(( idx, self.base.offset_with_meta( self.stride * idx, @@ -258,7 +258,7 @@ where // SIMD types must be newtypes around arrays, so all we have to do is project to their only field. let array = self.project_field(base, 0)?; let len = array.len(self)?; - Ok((array, len)) + interp_ok((array, len)) } fn project_constant_index>( @@ -300,7 +300,13 @@ where debug!("project_array_fields: {base:?} {len}"); base.offset(len * stride, self.layout_of(self.tcx.types.unit).unwrap(), self)?; // Create the iterator. - Ok(ArrayIterator { base, range: 0..len, stride, field_layout, _phantom: PhantomData }) + interp_ok(ArrayIterator { + base, + range: 0..len, + stride, + field_layout, + _phantom: PhantomData, + }) } /// Subslicing @@ -367,7 +373,7 @@ where P: Projectable<'tcx, M::Provenance> + From> + std::fmt::Debug, { use rustc_middle::mir::ProjectionElem::*; - Ok(match proj_elem { + interp_ok(match proj_elem { OpaqueCast(ty) => { span_bug!(self.cur_span(), "OpaqueCast({ty}) encountered after borrowck") } diff --git a/compiler/rustc_const_eval/src/interpret/stack.rs b/compiler/rustc_const_eval/src/interpret/stack.rs index 15868f1b02d..3bc9f46aea0 100644 --- a/compiler/rustc_const_eval/src/interpret/stack.rs +++ b/compiler/rustc_const_eval/src/interpret/stack.rs @@ -17,7 +17,7 @@ use tracing::{info_span, instrument, trace}; use super::{ AllocId, CtfeProvenance, Immediate, InterpCx, InterpResult, MPlaceTy, Machine, MemPlace, MemPlaceMeta, MemoryKind, Operand, Pointer, Provenance, ReturnAction, Scalar, - from_known_layout, throw_ub, throw_unsup, + from_known_layout, interp_ok, throw_ub, throw_unsup, }; use crate::errors; @@ -189,7 +189,7 @@ impl<'tcx, Prov: Provenance> LocalState<'tcx, Prov> { pub(super) fn access(&self) -> InterpResult<'tcx, &Operand> { match &self.value { LocalValue::Dead => throw_ub!(DeadLocal), // could even be "invalid program"? - LocalValue::Live(val) => Ok(val), + LocalValue::Live(val) => interp_ok(val), } } @@ -199,7 +199,7 @@ impl<'tcx, Prov: Provenance> LocalState<'tcx, Prov> { pub(super) fn access_mut(&mut self) -> InterpResult<'tcx, &mut Operand> { match &mut self.value { LocalValue::Dead => throw_ub!(DeadLocal), // could even be "invalid program"? - LocalValue::Live(val) => Ok(val), + LocalValue::Live(val) => interp_ok(val), } } } @@ -391,7 +391,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { let span = info_span!("frame", "{}", instance); self.frame_mut().tracing_span.enter(span); - Ok(()) + interp_ok(()) } /// Low-level helper that pops a stack frame from the stack and returns some information about @@ -426,7 +426,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { return_action = ReturnAction::NoCleanup; }; - Ok(StackPopInfo { return_action, return_to_block, return_place }) + interp_ok(StackPopInfo { return_action, return_to_block, return_place }) } /// A private helper for [`pop_stack_frame_raw`](InterpCx::pop_stack_frame_raw). @@ -449,7 +449,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { } } - Ok(cleanup) + interp_ok(cleanup) } /// In the current stack frame, mark all locals as live that are not arguments and don't have @@ -464,7 +464,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { self.storage_live(local)?; } } - Ok(()) + interp_ok(()) } pub fn storage_live_dyn( @@ -550,7 +550,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // If the local is already live, deallocate its old memory. let old = mem::replace(&mut self.frame_mut().locals[local].value, local_val); self.deallocate_local(old)?; - Ok(()) + interp_ok(()) } /// Mark a storage as live, killing the previous content. @@ -566,7 +566,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // If the local is already dead, this is a NOP. let old = mem::replace(&mut self.frame_mut().locals[local].value, LocalValue::Dead); self.deallocate_local(old)?; - Ok(()) + interp_ok(()) } fn deallocate_local(&mut self, local: LocalValue) -> InterpResult<'tcx> { @@ -581,7 +581,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { ); self.deallocate_ptr(ptr, None, MemoryKind::Stack)?; }; - Ok(()) + interp_ok(()) } #[inline(always)] @@ -593,19 +593,19 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { ) -> InterpResult<'tcx, TyAndLayout<'tcx>> { let state = &frame.locals[local]; if let Some(layout) = state.layout.get() { - return Ok(layout); + return interp_ok(layout); } let layout = from_known_layout(self.tcx, self.param_env, layout, || { let local_ty = frame.body.local_decls[local].ty; let local_ty = self.instantiate_from_frame_and_normalize_erasing_regions(frame, local_ty)?; - self.layout_of(local_ty) + self.layout_of(local_ty).into() })?; // Layouts of locals are requested a lot, so we cache them. state.layout.set(Some(layout)); - Ok(layout) + interp_ok(layout) } } diff --git a/compiler/rustc_const_eval/src/interpret/step.rs b/compiler/rustc_const_eval/src/interpret/step.rs index 8e2367e0d21..aa752955675 100644 --- a/compiler/rustc_const_eval/src/interpret/step.rs +++ b/compiler/rustc_const_eval/src/interpret/step.rs @@ -14,7 +14,7 @@ use tracing::{info, instrument, trace}; use super::{ FnArg, FnVal, ImmTy, Immediate, InterpCx, InterpResult, Machine, MemPlaceMeta, PlaceTy, - Projectable, Scalar, throw_ub, + Projectable, Scalar, interp_ok, throw_ub, }; use crate::util; @@ -36,7 +36,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { #[inline(always)] pub fn step(&mut self) -> InterpResult<'tcx, bool> { if self.stack().is_empty() { - return Ok(false); + return interp_ok(false); } let Either::Left(loc) = self.frame().loc else { @@ -44,7 +44,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // Just go on unwinding. trace!("unwinding: skipping frame"); self.return_from_current_stack_frame(/* unwinding */ true)?; - return Ok(true); + return interp_ok(true); }; let basic_block = &self.body().basic_blocks[loc.block]; @@ -55,7 +55,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { assert_eq!(old_frames, self.frame_idx()); // Advance the program counter. self.frame_mut().loc.as_mut().left().unwrap().statement_index += 1; - return Ok(true); + return interp_ok(true); } M::before_terminator(self)?; @@ -67,7 +67,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { info!("// executing {:?}", loc.block); } } - Ok(true) + interp_ok(true) } /// Runs the interpretation logic for the given `mir::Statement` at the current frame and @@ -145,7 +145,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { Nop => {} } - Ok(()) + interp_ok(()) } /// Evaluate an assignment statement. @@ -277,7 +277,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { trace!("{:?}", self.dump_place(&dest)); - Ok(()) + interp_ok(()) } /// Writes the aggregate to the destination. @@ -313,7 +313,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { let ptr_imm = Immediate::new_pointer_with_meta(data, meta, self); let ptr = ImmTy::from_immediate(ptr_imm, dest.layout); self.copy_op(&ptr, dest)?; - return Ok(()); + return interp_ok(()); } _ => (FIRST_VARIANT, dest.clone(), None), }; @@ -365,7 +365,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { )?; } - Ok(()) + interp_ok(()) } /// Evaluate the arguments of a function call @@ -373,7 +373,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { &self, op: &mir::Operand<'tcx>, ) -> InterpResult<'tcx, FnArg<'tcx, M::Provenance>> { - Ok(match op { + interp_ok(match op { mir::Operand::Copy(_) | mir::Operand::Constant(_) => { // Make a regular copy. let op = self.eval_operand(op, None)?; @@ -442,7 +442,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { } }; - Ok(EvaluatedCalleeAndArgs { callee, args, fn_sig, fn_abi, with_caller_location }) + interp_ok(EvaluatedCalleeAndArgs { callee, args, fn_sig, fn_abi, with_caller_location }) } fn eval_terminator(&mut self, terminator: &mir::Terminator<'tcx>) -> InterpResult<'tcx> { @@ -537,7 +537,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // generic. In order to make sure that generic and non-generic code behaves // roughly the same (and in keeping with Mir semantics) we do nothing here. self.go_to_block(target); - return Ok(()); + return interp_ok(()); } trace!("TerminatorKind::drop: {:?}, type {}", place, place.layout.ty); self.init_drop_in_place_call(&place, instance, target, unwind)?; @@ -566,7 +566,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // By definition, a Resume terminator means // that we're unwinding self.return_from_current_stack_frame(/* unwinding */ true)?; - return Ok(()); + return interp_ok(()); } // It is UB to ever encounter this. @@ -584,6 +584,6 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { } } - Ok(()) + interp_ok(()) } } diff --git a/compiler/rustc_const_eval/src/interpret/traits.rs b/compiler/rustc_const_eval/src/interpret/traits.rs index 8eead6018ac..da7d6853c0e 100644 --- a/compiler/rustc_const_eval/src/interpret/traits.rs +++ b/compiler/rustc_const_eval/src/interpret/traits.rs @@ -5,7 +5,9 @@ use rustc_target::abi::{Align, Size}; use tracing::trace; use super::util::ensure_monomorphic_enough; -use super::{InterpCx, MPlaceTy, Machine, MemPlaceMeta, OffsetMode, Projectable, throw_ub}; +use super::{ + InterpCx, MPlaceTy, Machine, MemPlaceMeta, OffsetMode, Projectable, interp_ok, throw_ub, +}; impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { /// Creates a dynamic vtable for the given type and vtable origin. This is used only for @@ -31,7 +33,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { let salt = M::get_global_alloc_salt(self, None); let vtable_symbolic_allocation = self.tcx.reserve_and_set_vtable_alloc(ty, dyn_ty, salt); let vtable_ptr = self.global_root_pointer(Pointer::from(vtable_symbolic_allocation))?; - Ok(vtable_ptr.into()) + interp_ok(vtable_ptr.into()) } pub fn get_vtable_size_and_align( @@ -42,7 +44,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { let ty = self.get_ptr_vtable_ty(vtable, expected_trait)?; let layout = self.layout_of(ty)?; assert!(layout.is_sized(), "there are no vtables for unsized types"); - Ok((layout.size, layout.align.abi)) + interp_ok((layout.size, layout.align.abi)) } pub(super) fn vtable_entries( @@ -102,7 +104,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { } } - Ok(()) + interp_ok(()) } /// Turn a place with a `dyn Trait` type into a place with the actual dynamic type. @@ -127,7 +129,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { layout, self, )?; - Ok(mplace) + interp_ok(mplace) } /// Turn a `dyn* Trait` type into an value with the actual dynamic type. @@ -147,6 +149,6 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // `data` is already the right thing but has the wrong type. So we transmute it. let layout = self.layout_of(ty)?; let data = data.transmute(layout, self)?; - Ok(data) + interp_ok(data) } } diff --git a/compiler/rustc_const_eval/src/interpret/util.rs b/compiler/rustc_const_eval/src/interpret/util.rs index 2d53badf0f9..8bb5f173a56 100644 --- a/compiler/rustc_const_eval/src/interpret/util.rs +++ b/compiler/rustc_const_eval/src/interpret/util.rs @@ -9,7 +9,7 @@ use rustc_middle::ty::{ }; use tracing::debug; -use super::{InterpCx, MPlaceTy, MemoryKind, throw_inval}; +use super::{InterpCx, MPlaceTy, MemoryKind, interp_ok, throw_inval}; use crate::const_eval::{CompileTimeInterpCx, CompileTimeMachine, InterpretationResult}; /// Checks whether a type contains generic parameters which must be instantiated. @@ -23,7 +23,7 @@ where { debug!("ensure_monomorphic_enough: ty={:?}", ty); if !ty.has_param() { - return Ok(()); + return interp_ok(()); } struct FoundParam; @@ -78,7 +78,7 @@ where if matches!(ty.visit_with(&mut vis), ControlFlow::Break(FoundParam)) { throw_inval!(TooGeneric); } else { - Ok(()) + interp_ok(()) } } @@ -103,5 +103,5 @@ pub(crate) fn create_static_alloc<'tcx>( assert_eq!(ecx.machine.static_root_ids, None); ecx.machine.static_root_ids = Some((alloc_id, static_def_id)); assert!(ecx.memory.alloc_map.insert(alloc_id, (MemoryKind::Stack, alloc)).is_none()); - Ok(ecx.ptr_to_mplace(Pointer::from(alloc_id).into(), layout)) + interp_ok(ecx.ptr_to_mplace(Pointer::from(alloc_id).into(), layout)) } diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs index 3c9fdd73100..13641ef2bd3 100644 --- a/compiler/rustc_const_eval/src/interpret/validity.rs +++ b/compiler/rustc_const_eval/src/interpret/validity.rs @@ -18,7 +18,7 @@ use rustc_middle::bug; use rustc_middle::mir::interpret::ValidationErrorKind::{self, *}; use rustc_middle::mir::interpret::{ ExpectedKind, InterpError, InterpErrorInfo, InvalidMetaKind, Misalignment, PointerKind, - Provenance, UnsupportedOpInfo, ValidationErrorInfo, alloc_range, + Provenance, UnsupportedOpInfo, ValidationErrorInfo, alloc_range, interp_ok, }; use rustc_middle::ty::layout::{LayoutCx, LayoutOf, TyAndLayout}; use rustc_middle::ty::{self, Ty}; @@ -32,7 +32,7 @@ use super::machine::AllocMap; use super::{ AllocId, AllocKind, CheckInAllocMsg, GlobalAlloc, ImmTy, Immediate, InterpCx, InterpResult, MPlaceTy, Machine, MemPlaceMeta, PlaceTy, Pointer, Projectable, Scalar, ValueVisitor, err_ub, - format_interp_error, throw_ub, + format_interp_error, }; // for the validation errors @@ -42,7 +42,7 @@ use super::InterpError::Unsupported as Unsup; use super::UndefinedBehaviorInfo::*; use super::UnsupportedOpInfo::*; -macro_rules! throw_validation_failure { +macro_rules! err_validation_failure { ($where:expr, $kind: expr) => {{ let where_ = &$where; let path = if !where_.is_empty() { @@ -53,10 +53,16 @@ macro_rules! throw_validation_failure { None }; - throw_ub!(ValidationError(ValidationErrorInfo { path, kind: $kind })) + err_ub!(ValidationError(ValidationErrorInfo { path, kind: $kind })) }}; } +macro_rules! throw_validation_failure { + ($where:expr, $kind: expr) => { + do yeet err_validation_failure!($where, $kind) + }; +} + /// If $e throws an error matching the pattern, throw a validation failure. /// Other errors are passed back to the caller, unchanged -- and if they reach the root of /// the visitor, we make sure only validation errors and `InvalidProgram` errors are left. @@ -91,25 +97,22 @@ macro_rules! try_validation { ($e:expr, $where:expr, $( $( $p:pat_param )|+ => $kind: expr ),+ $(,)? ) => {{ - match $e { - Ok(x) => x, + $e.map_err(|e| { // We catch the error and turn it into a validation failure. We are okay with // allocation here as this can only slow down builds that fail anyway. - Err(e) => { - let (kind, backtrace) = e.into_parts(); - match kind { - $( - $($p)|+ => { - throw_validation_failure!( - $where, - $kind - ) - } - ),+, - _ => Err::(InterpErrorInfo::from_parts(kind, backtrace))?, - } + let (kind, backtrace) = e.into_parts(); + match kind { + $( + $($p)|+ => { + err_validation_failure!( + $where, + $kind + ).into() + } + ),+, + _ => InterpErrorInfo::from_parts(kind, backtrace), } - } + })? }}; } @@ -381,7 +384,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { // Undo changes self.path.truncate(path_len); // Done - Ok(r) + interp_ok(r) } fn read_immediate( @@ -389,7 +392,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { val: &PlaceTy<'tcx, M::Provenance>, expected: ExpectedKind, ) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>> { - Ok(try_validation!( + interp_ok(try_validation!( self.ecx.read_immediate(val), self.path, Ub(InvalidUninitBytes(None)) => @@ -407,7 +410,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { val: &PlaceTy<'tcx, M::Provenance>, expected: ExpectedKind, ) -> InterpResult<'tcx, Scalar> { - Ok(self.read_immediate(val, expected)?.to_scalar()) + interp_ok(self.read_immediate(val, expected)?.to_scalar()) } fn deref_pointer( @@ -472,7 +475,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { _ => bug!("Unexpected unsized type tail: {:?}", tail), } - Ok(()) + interp_ok(()) } /// Check a reference or `Box`. @@ -635,7 +638,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { } // Potentially skip recursive check. if skip_recursive_check { - return Ok(()); + return interp_ok(()); } } else { // This is not CTFE, so it's Miri with recursive checking. @@ -644,7 +647,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { // FIXME: should we also skip `UnsafeCell` behind shared references? Currently that is not // needed since validation reads bypass Stacked Borrows and data race checks. if matches!(ptr_kind, PointerKind::Box) { - return Ok(()); + return interp_ok(()); } } let path = &self.path; @@ -657,7 +660,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { new_path }); } - Ok(()) + interp_ok(()) } /// Check if this is a value of primitive type, and if yes check the validity of the value @@ -684,7 +687,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { self.ecx.clear_provenance(value)?; self.add_data_range_place(value); } - Ok(true) + interp_ok(true) } ty::Char => { let scalar = self.read_scalar(value, ExpectedKind::Char)?; @@ -699,7 +702,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { self.ecx.clear_provenance(value)?; self.add_data_range_place(value); } - Ok(true) + interp_ok(true) } ty::Float(_) | ty::Int(_) | ty::Uint(_) => { // NOTE: Keep this in sync with the array optimization for int/float @@ -716,18 +719,18 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { self.ecx.clear_provenance(value)?; self.add_data_range_place(value); } - Ok(true) + interp_ok(true) } ty::RawPtr(..) => { let place = self.deref_pointer(value, ExpectedKind::RawPtr)?; if place.layout.is_unsized() { self.check_wide_ptr_meta(place.meta(), place.layout)?; } - Ok(true) + interp_ok(true) } ty::Ref(_, _ty, mutbl) => { self.check_safe_pointer(value, PointerKind::Ref(*mutbl))?; - Ok(true) + interp_ok(true) } ty::FnPtr(..) => { let scalar = self.read_scalar(value, ExpectedKind::FnPtr)?; @@ -756,12 +759,12 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { } self.add_data_range_place(value); } - Ok(true) + interp_ok(true) } ty::Never => throw_validation_failure!(self.path, NeverVal), ty::Foreign(..) | ty::FnDef(..) => { // Nothing to check. - Ok(true) + interp_ok(true) } // The above should be all the primitive types. The rest is compound, we // check them by visiting their fields/variants. @@ -774,7 +777,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { | ty::Closure(..) | ty::Pat(..) | ty::CoroutineClosure(..) - | ty::Coroutine(..) => Ok(false), + | ty::Coroutine(..) => interp_ok(false), // Some types only occur during typechecking, they have no layout. // We should not see them here and we could not check them anyway. ty::Error(_) @@ -811,11 +814,11 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { max_value }) } else { - return Ok(()); + return interp_ok(()); } } else if scalar_layout.is_always_valid(self.ecx) { // Easy. (This is reachable if `enforce_number_validity` is set.) - return Ok(()); + return interp_ok(()); } else { // Conservatively, we reject, because the pointer *could* have a bad // value. @@ -828,7 +831,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { }; // Now compare. if valid_range.contains(bits) { - Ok(()) + interp_ok(()) } else { throw_validation_failure!(self.path, OutOfRange { value: format!("{bits}"), @@ -887,7 +890,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { } fn reset_padding(&mut self, place: &PlaceTy<'tcx, M::Provenance>) -> InterpResult<'tcx> { - let Some(data_bytes) = self.data_bytes.as_mut() else { return Ok(()) }; + let Some(data_bytes) = self.data_bytes.as_mut() else { return interp_ok(()) }; // Our value must be in memory, otherwise we would not have set up `data_bytes`. let mplace = self.ecx.force_allocation(place)?; // Determine starting offset and size. @@ -899,14 +902,14 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { // If there is no padding at all, we can skip the rest: check for // a single data range covering the entire value. if data_bytes.0 == &[(start_offset, size)] { - return Ok(()); + return interp_ok(()); } // Get a handle for the allocation. Do this only once, to avoid looking up the same // allocation over and over again. (Though to be fair, iterating the value already does // exactly that.) let Some(mut alloc) = self.ecx.get_ptr_alloc_mut(mplace.ptr(), size)? else { // A ZST, no padding to clear. - return Ok(()); + return interp_ok(()); }; // Add a "finalizer" data range at the end, so that the iteration below finds all gaps // between ranges. @@ -933,7 +936,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { padding_cleared_until = offset + size; } assert!(padding_cleared_until == start_offset + size); - Ok(()) + interp_ok(()) } /// Computes the data range of this union type: @@ -1073,7 +1076,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValueVisitor<'tcx, M> for ValidityVisitor<'rt, val: &PlaceTy<'tcx, M::Provenance>, ) -> InterpResult<'tcx, VariantIdx> { self.with_elem(PathElem::EnumTag, move |this| { - Ok(try_validation!( + interp_ok(try_validation!( this.ecx.read_discriminant(val), this.path, Ub(InvalidTag(val)) => InvalidEnumTag { @@ -1137,7 +1140,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValueVisitor<'tcx, M> for ValidityVisitor<'rt, data_bytes.add_range(base_offset + offset, size); } } - Ok(()) + interp_ok(()) } #[inline] @@ -1147,7 +1150,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValueVisitor<'tcx, M> for ValidityVisitor<'rt, val: &PlaceTy<'tcx, M::Provenance>, ) -> InterpResult<'tcx> { self.check_safe_pointer(val, PointerKind::Box)?; - Ok(()) + interp_ok(()) } #[inline] @@ -1160,7 +1163,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValueVisitor<'tcx, M> for ValidityVisitor<'rt, // We assume that the Scalar validity range does not restrict these values // any further than `try_visit_primitive` does! if self.try_visit_primitive(val)? { - return Ok(()); + return interp_ok(()); } // Special check preventing `UnsafeCell` in the inner part of constants @@ -1207,7 +1210,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValueVisitor<'tcx, M> for ValidityVisitor<'rt, // If the size is 0, there is nothing to check. // (`size` can only be 0 if `len` is 0, and empty arrays are always valid.) if size == Size::ZERO { - return Ok(()); + return interp_ok(()); } // Now that we definitely have a non-ZST array, we know it lives in memory -- except it may // be an uninitialized local variable, those are also "immediate". @@ -1227,37 +1230,33 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValueVisitor<'tcx, M> for ValidityVisitor<'rt, // No need for an alignment check here, this is not an actual memory access. let alloc = self.ecx.get_ptr_alloc(mplace.ptr(), size)?.expect("we already excluded size 0"); - match alloc.get_bytes_strip_provenance() { - // In the happy case, we needn't check anything else. - Ok(_) => {} + alloc.get_bytes_strip_provenance().map_err(|err| { // Some error happened, try to provide a more detailed description. - Err(err) => { - // For some errors we might be able to provide extra information. - // (This custom logic does not fit the `try_validation!` macro.) - let (kind, backtrace) = err.into_parts(); - match kind { - Ub(InvalidUninitBytes(Some((_alloc_id, access)))) | Unsup(ReadPointerAsInt(Some((_alloc_id, access)))) => { - // Some byte was uninitialized, determine which - // element that byte belongs to so we can - // provide an index. - let i = usize::try_from( - access.bad.start.bytes() / layout.size.bytes(), - ) - .unwrap(); - self.path.push(PathElem::ArrayElem(i)); + // For some errors we might be able to provide extra information. + // (This custom logic does not fit the `try_validation!` macro.) + let (kind, backtrace) = err.into_parts(); + match kind { + Ub(InvalidUninitBytes(Some((_alloc_id, access)))) | Unsup(ReadPointerAsInt(Some((_alloc_id, access)))) => { + // Some byte was uninitialized, determine which + // element that byte belongs to so we can + // provide an index. + let i = usize::try_from( + access.bad.start.bytes() / layout.size.bytes(), + ) + .unwrap(); + self.path.push(PathElem::ArrayElem(i)); - if matches!(kind, Ub(InvalidUninitBytes(_))) { - throw_validation_failure!(self.path, Uninit { expected }) - } else { - throw_validation_failure!(self.path, PointerAsInt { expected }) - } + if matches!(kind, Ub(InvalidUninitBytes(_))) { + err_validation_failure!(self.path, Uninit { expected }).into() + } else { + err_validation_failure!(self.path, PointerAsInt { expected }).into() } - - // Propagate upwards (that will also check for unexpected errors). - _ => return Err(InterpErrorInfo::from_parts(kind, backtrace)), } + + // Propagate upwards (that will also check for unexpected errors). + _ => return InterpErrorInfo::from_parts(kind, backtrace), } - } + })?; // Don't forget that these are all non-pointer types, and thus do not preserve // provenance. @@ -1335,7 +1334,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValueVisitor<'tcx, M> for ValidityVisitor<'rt, } } - Ok(()) + interp_ok(()) } } @@ -1351,7 +1350,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { trace!("validate_operand_internal: {:?}, {:?}", *val, val.layout.ty); // Run the visitor. - match self.run_for_validation(|ecx| { + self.run_for_validation(|ecx| { let reset_padding = reset_provenance_and_padding && { // Check if `val` is actually stored in memory. If not, padding is not even // represented and we need not reset it. @@ -1367,29 +1366,22 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { }; v.visit_value(val)?; v.reset_padding(val)?; - InterpResult::Ok(()) - }) { - Ok(()) => Ok(()), - // Pass through validation failures and "invalid program" issues. - Err(err) - if matches!( - err.kind(), - err_ub!(ValidationError { .. }) - | InterpError::InvalidProgram(_) - | InterpError::Unsupported(UnsupportedOpInfo::ExternTypeField) - ) => - { - Err(err) - } - // Complain about any other kind of error -- those are bad because we'd like to - // report them in a way that shows *where* in the value the issue lies. - Err(err) => { + interp_ok(()) + }) + .map_err(|err| { + if !matches!( + err.kind(), + err_ub!(ValidationError { .. }) + | InterpError::InvalidProgram(_) + | InterpError::Unsupported(UnsupportedOpInfo::ExternTypeField) + ) { bug!( "Unexpected error during validation: {}", format_interp_error(self.tcx.dcx(), err) ); } - } + err + }) } /// This function checks the data at `op` to be const-valid. @@ -1460,6 +1452,6 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { /*reset_provenance_and_padding*/ false, )?; } - Ok(()) + interp_ok(()) } } diff --git a/compiler/rustc_const_eval/src/interpret/visitor.rs b/compiler/rustc_const_eval/src/interpret/visitor.rs index d004a3f0892..647917dbb67 100644 --- a/compiler/rustc_const_eval/src/interpret/visitor.rs +++ b/compiler/rustc_const_eval/src/interpret/visitor.rs @@ -10,7 +10,7 @@ use rustc_middle::ty::{self, Ty}; use rustc_target::abi::{FieldIdx, FieldsShape, VariantIdx, Variants}; use tracing::trace; -use super::{InterpCx, MPlaceTy, Machine, Projectable, throw_inval}; +use super::{InterpCx, MPlaceTy, Machine, Projectable, interp_ok, throw_inval}; /// How to traverse a value and what to do when we are at the leaves. pub trait ValueVisitor<'tcx, M: Machine<'tcx>>: Sized { @@ -46,14 +46,14 @@ pub trait ValueVisitor<'tcx, M: Machine<'tcx>>: Sized { /// Visits the given value as a union. No automatic recursion can happen here. #[inline(always)] fn visit_union(&mut self, _v: &Self::V, _fields: NonZero) -> InterpResult<'tcx> { - Ok(()) + interp_ok(()) } /// Visits the given value as the pointer of a `Box`. There is nothing to recurse into. /// The type of `v` will be a raw pointer to `T`, but this is a field of `Box` and the /// pointee type is the actual `T`. `box_ty` provides the full type of the `Box` itself. #[inline(always)] fn visit_box(&mut self, _box_ty: Ty<'tcx>, _v: &Self::V) -> InterpResult<'tcx> { - Ok(()) + interp_ok(()) } /// Called each time we recurse down to a field of a "product-like" aggregate @@ -165,7 +165,7 @@ pub trait ValueVisitor<'tcx, M: Machine<'tcx>>: Sized { self.visit_field(v, 1, &alloc)?; // We visited all parts of this one. - return Ok(()); + return interp_ok(()); } // Non-normalized types should never show up here. @@ -222,6 +222,6 @@ pub trait ValueVisitor<'tcx, M: Machine<'tcx>>: Sized { Variants::Single { .. } => {} } - Ok(()) + interp_ok(()) } } diff --git a/compiler/rustc_const_eval/src/util/check_validity_requirement.rs b/compiler/rustc_const_eval/src/util/check_validity_requirement.rs index 421648d9e7b..649179d5b1e 100644 --- a/compiler/rustc_const_eval/src/util/check_validity_requirement.rs +++ b/compiler/rustc_const_eval/src/util/check_validity_requirement.rs @@ -1,5 +1,4 @@ use rustc_middle::bug; -use rustc_middle::mir::interpret::DiscardInterpError; use rustc_middle::ty::layout::{ HasTyCtxt, LayoutCx, LayoutError, LayoutOf, TyAndLayout, ValidityRequirement, }; @@ -76,7 +75,7 @@ fn check_validity_requirement_strict<'tcx>( /*recursive*/ false, /*reset_provenance_and_padding*/ false, ) - .discard_interp_err() + .discard_err() .is_some()) } diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs index a32b19b067a..70e61df1ab4 100644 --- a/compiler/rustc_middle/src/lib.rs +++ b/compiler/rustc_middle/src/lib.rs @@ -61,6 +61,8 @@ #![feature(trait_upcasting)] #![feature(trusted_len)] #![feature(try_blocks)] +#![feature(try_trait_v2)] +#![feature(try_trait_v2_yeet)] #![feature(type_alias_impl_trait)] #![feature(yeet_expr)] #![warn(unreachable_pub)] diff --git a/compiler/rustc_middle/src/mir/consts.rs b/compiler/rustc_middle/src/mir/consts.rs index b34f5b48b78..4262460d928 100644 --- a/compiler/rustc_middle/src/mir/consts.rs +++ b/compiler/rustc_middle/src/mir/consts.rs @@ -148,7 +148,7 @@ impl<'tcx> ConstValue<'tcx> { /* read_provenance */ true, ) .ok()?; - let ptr = ptr.to_pointer(&tcx).ok()?; + let ptr = ptr.to_pointer(&tcx).discard_err()?; let len = a .read_scalar( &tcx, @@ -156,7 +156,7 @@ impl<'tcx> ConstValue<'tcx> { /* read_provenance */ false, ) .ok()?; - let len = len.to_target_usize(&tcx).ok()?; + let len = len.to_target_usize(&tcx).discard_err()?; if len == 0 { return Some(&[]); } diff --git a/compiler/rustc_middle/src/mir/interpret/allocation.rs b/compiler/rustc_middle/src/mir/interpret/allocation.rs index b8ecfa3c3f9..04d035e27ba 100644 --- a/compiler/rustc_middle/src/mir/interpret/allocation.rs +++ b/compiler/rustc_middle/src/mir/interpret/allocation.rs @@ -20,7 +20,7 @@ use rustc_target::abi::{Align, HasDataLayout, Size}; use super::{ AllocId, BadBytesAccess, CtfeProvenance, InterpError, InterpResult, Pointer, PointerArithmetic, Provenance, ResourceExhaustionInfo, Scalar, ScalarSizeMismatch, UndefinedBehaviorInfo, - UnsupportedOpInfo, read_target_uint, write_target_uint, + UnsupportedOpInfo, interp_ok, read_target_uint, write_target_uint, }; use crate::ty; @@ -318,8 +318,9 @@ impl Allocation { pub fn try_uninit<'tcx>(size: Size, align: Align) -> InterpResult<'tcx, Self> { Self::uninit_inner(size, align, || { ty::tls::with(|tcx| tcx.dcx().delayed_bug("exhausted memory during interpretation")); - InterpError::ResourceExhaustion(ResourceExhaustionInfo::MemoryExhausted).into() + InterpError::ResourceExhaustion(ResourceExhaustionInfo::MemoryExhausted) }) + .into() } /// Try to create an Allocation of `size` bytes, panics if there is not enough memory @@ -355,12 +356,12 @@ impl Allocation { impl Allocation { /// Adjust allocation from the ones in `tcx` to a custom Machine instance /// with a different `Provenance` and `Byte` type. - pub fn adjust_from_tcx( + pub fn adjust_from_tcx<'tcx, Prov: Provenance, Bytes: AllocBytes>( &self, cx: &impl HasDataLayout, - mut alloc_bytes: impl FnMut(&[u8], Align) -> Result, - mut adjust_ptr: impl FnMut(Pointer) -> Result, Err>, - ) -> Result, Err> { + mut alloc_bytes: impl FnMut(&[u8], Align) -> InterpResult<'tcx, Bytes>, + mut adjust_ptr: impl FnMut(Pointer) -> InterpResult<'tcx, Pointer>, + ) -> InterpResult<'tcx, Allocation> { // Copy the data. let mut bytes = alloc_bytes(&*self.bytes, self.align)?; // Adjust provenance of pointers stored in this allocation. @@ -377,7 +378,7 @@ impl Allocation { new_provenance.push((offset, ptr_prov)); } // Create allocation. - Ok(Allocation { + interp_ok(Allocation { bytes, provenance: ProvenanceMap::from_presorted_ptrs(new_provenance), init_mask: self.init_mask.clone(), diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs index 06fdb9e1ecd..431043b0431 100644 --- a/compiler/rustc_middle/src/mir/interpret/error.rs +++ b/compiler/rustc_middle/src/mir/interpret/error.rs @@ -1,7 +1,7 @@ use std::any::Any; use std::backtrace::Backtrace; use std::borrow::Cow; -use std::{fmt, mem}; +use std::{convert, fmt, mem, ops}; use either::Either; use rustc_ast_ir::Mutability; @@ -106,55 +106,15 @@ rustc_data_structures::static_assert_size!(InterpErrorInfo<'_>, 8); /// macros for this. /// /// Interpreter errors must *not* be silently discarded (that will lead to a panic). Instead, -/// explicitly call `discard_interp_err` if this is really the right thing to do. Note that if +/// explicitly call `discard_err` if this is really the right thing to do. Note that if /// this happens during const-eval or in Miri, it could lead to a UB error being lost! #[derive(Debug)] pub struct InterpErrorInfo<'tcx>(Box>); -/// Calling `.ok()` on an `InterpResult` leads to a panic because of the guard. -/// To still let people opt-in to discarding interpreter errors, we have this extension trait. -pub trait DiscardInterpError { - type Output; - - fn discard_interp_err(self) -> Option; -} - -impl<'tcx, T> DiscardInterpError for InterpResult<'tcx, T> { - type Output = T; - - fn discard_interp_err(self) -> Option { - match self { - Ok(v) => Some(v), - Err(e) => { - // Disarm the guard. - mem::forget(e.0.guard); - None - } - } - } -} - -#[derive(Debug)] -struct Guard; - -impl Drop for Guard { - fn drop(&mut self) { - // We silence the guard if we are already panicking, to avoid double-panics. - if !std::thread::panicking() { - panic!( - "an interpreter error got improperly discarded; use `discard_interp_err()` instead of `ok()` if this is intentional" - ); - } - } -} - #[derive(Debug)] struct InterpErrorInfoInner<'tcx> { kind: InterpError<'tcx>, backtrace: InterpErrorBacktrace, - /// This makes us panic on drop. This is used to catch - /// accidentally discarding an interpreter error. - guard: Guard, } #[derive(Debug)] @@ -195,23 +155,16 @@ impl InterpErrorBacktrace { impl<'tcx> InterpErrorInfo<'tcx> { pub fn into_parts(self) -> (InterpError<'tcx>, InterpErrorBacktrace) { - let InterpErrorInfo(box InterpErrorInfoInner { kind, backtrace, guard }) = self; - mem::forget(guard); // The error got explicitly discarded right here. + let InterpErrorInfo(box InterpErrorInfoInner { kind, backtrace }) = self; (kind, backtrace) } pub fn into_kind(self) -> InterpError<'tcx> { - let InterpErrorInfo(box InterpErrorInfoInner { kind, guard, .. }) = self; - mem::forget(guard); // The error got explicitly discarded right here. - kind - } - - pub fn discard_interp_err(self) { - mem::forget(self.0.guard); // The error got explicitly discarded right here. + self.0.kind } pub fn from_parts(kind: InterpError<'tcx>, backtrace: InterpErrorBacktrace) -> Self { - Self(Box::new(InterpErrorInfoInner { kind, backtrace, guard: Guard })) + Self(Box::new(InterpErrorInfoInner { kind, backtrace })) } #[inline] @@ -245,7 +198,6 @@ impl<'tcx> From> for InterpErrorInfo<'tcx> { InterpErrorInfo(Box::new(InterpErrorInfoInner { kind, backtrace: InterpErrorBacktrace::new(), - guard: Guard, })) } } @@ -654,8 +606,6 @@ pub enum InterpError<'tcx> { MachineStop(Box), } -pub type InterpResult<'tcx, T = ()> = Result>; - impl InterpError<'_> { /// Some errors do string formatting even if the error is never printed. /// To avoid performance issues, there are places where we want to be sure to never raise these formatting errors, @@ -783,3 +733,182 @@ macro_rules! throw_exhaust { macro_rules! throw_machine_stop { ($($tt:tt)*) => { do yeet $crate::err_machine_stop!($($tt)*) }; } + +/// Guard type that panics on drop. +#[derive(Debug)] +struct Guard; + +impl Drop for Guard { + fn drop(&mut self) { + // We silence the guard if we are already panicking, to avoid double-panics. + if !std::thread::panicking() { + panic!( + "an interpreter error got improperly discarded; use `discard_err()` if this is intentional" + ); + } + } +} + +/// The result type used by the interpreter. This is a newtype around `Result` +/// to block access to operations like `ok()` that discard UB errors. +/// +/// We also make things panic if this type is ever implicitly dropped. +#[derive(Debug)] +pub struct InterpResult_<'tcx, T> { + res: Result>, + guard: Guard, +} + +// Type alias to be able to set a default type argument. +pub type InterpResult<'tcx, T = ()> = InterpResult_<'tcx, T>; + +impl<'tcx, T> ops::Try for InterpResult_<'tcx, T> { + type Output = T; + type Residual = InterpResult_<'tcx, convert::Infallible>; + + #[inline] + fn from_output(output: Self::Output) -> Self { + InterpResult_::new(Ok(output)) + } + + #[inline] + fn branch(self) -> ops::ControlFlow { + match self.disarm() { + Ok(v) => ops::ControlFlow::Continue(v), + Err(e) => ops::ControlFlow::Break(InterpResult_::new(Err(e))), + } + } +} + +impl<'tcx, T> ops::FromResidual for InterpResult_<'tcx, T> { + #[inline] + #[track_caller] + fn from_residual(residual: InterpResult_<'tcx, convert::Infallible>) -> Self { + match residual.disarm() { + Err(e) => Self::new(Err(e)), + } + } +} + +// Allow `yeet`ing `InterpError` in functions returning `InterpResult_`. +impl<'tcx, T> ops::FromResidual>> for InterpResult_<'tcx, T> { + #[inline] + fn from_residual(ops::Yeet(e): ops::Yeet>) -> Self { + Self::new(Err(e.into())) + } +} + +// Allow `?` on `Result<_, InterpError>` in functions returning `InterpResult_`. +// This is useful e.g. for `option.ok_or_else(|| err_ub!(...))`. +impl<'tcx, T, E: Into>> ops::FromResidual> + for InterpResult_<'tcx, T> +{ + #[inline] + fn from_residual(residual: Result) -> Self { + match residual { + Err(e) => Self::new(Err(e.into())), + } + } +} + +impl<'tcx, T, E: Into>> From> for InterpResult<'tcx, T> { + #[inline] + fn from(value: Result) -> Self { + Self::new(value.map_err(|e| e.into())) + } +} + +impl<'tcx, T, V: FromIterator> FromIterator> for InterpResult<'tcx, V> { + fn from_iter>>(iter: I) -> Self { + Self::new(iter.into_iter().map(|x| x.disarm()).collect()) + } +} + +impl<'tcx, T> InterpResult_<'tcx, T> { + #[inline(always)] + fn new(res: Result>) -> Self { + Self { res, guard: Guard } + } + + #[inline(always)] + fn disarm(self) -> Result> { + mem::forget(self.guard); + self.res + } + + /// Discard the error information in this result. Only use this if ignoring Undefined Behavior is okay! + #[inline] + pub fn discard_err(self) -> Option { + self.disarm().ok() + } + + /// Look at the `Result` wrapped inside of this. + /// Must only be used to report the error! + #[inline] + pub fn report_err(self) -> Result> { + self.disarm() + } + + #[inline] + pub fn map(self, f: impl FnOnce(T) -> U) -> InterpResult<'tcx, U> { + InterpResult_::new(self.disarm().map(f)) + } + + #[inline] + pub fn map_err( + self, + f: impl FnOnce(InterpErrorInfo<'tcx>) -> InterpErrorInfo<'tcx>, + ) -> InterpResult<'tcx, T> { + InterpResult_::new(self.disarm().map_err(f)) + } + + #[inline] + pub fn inspect_err(self, f: impl FnOnce(&InterpErrorInfo<'tcx>)) -> InterpResult<'tcx, T> { + InterpResult_::new(self.disarm().inspect_err(f)) + } + + #[inline] + #[track_caller] + pub fn unwrap(self) -> T { + self.disarm().unwrap() + } + + #[inline] + #[track_caller] + pub fn unwrap_or_else(self, f: impl FnOnce(InterpErrorInfo<'tcx>) -> T) -> T { + self.disarm().unwrap_or_else(f) + } + + #[inline] + #[track_caller] + pub fn expect(self, msg: &str) -> T { + self.disarm().expect(msg) + } + + #[inline] + pub fn and_then(self, f: impl FnOnce(T) -> InterpResult<'tcx, U>) -> InterpResult<'tcx, U> { + InterpResult_::new(self.disarm().and_then(|t| f(t).disarm())) + } + + /// Returns success if both `self` and `other` succeed, while ensuring we don't + /// accidentally drop an error. + /// + /// If both are an error, `self` will be reported. + #[inline] + pub fn and(self, other: InterpResult<'tcx, U>) -> InterpResult<'tcx, (T, U)> { + match self.disarm() { + Ok(t) => interp_ok((t, other?)), + Err(e) => { + // Discard the other error. + drop(other.disarm()); + // Return `self`. + InterpResult_::new(Err(e)) + } + } + } +} + +#[inline(always)] +pub fn interp_ok<'tcx, T>(x: T) -> InterpResult<'tcx, T> { + InterpResult_::new(Ok(x)) +} diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs index 8ce6f9d2300..115bcdbc589 100644 --- a/compiler/rustc_middle/src/mir/interpret/mod.rs +++ b/compiler/rustc_middle/src/mir/interpret/mod.rs @@ -34,12 +34,12 @@ pub use self::allocation::{ InitChunkIter, alloc_range, }; pub use self::error::{ - BadBytesAccess, CheckAlignMsg, CheckInAllocMsg, DiscardInterpError, ErrorHandled, - EvalStaticInitializerRawResult, EvalToAllocationRawResult, EvalToConstValueResult, - EvalToValTreeResult, ExpectedKind, InterpError, InterpErrorInfo, InterpResult, InvalidMetaKind, - InvalidProgramInfo, MachineStopType, Misalignment, PointerKind, ReportedErrorInfo, - ResourceExhaustionInfo, ScalarSizeMismatch, UndefinedBehaviorInfo, UnsupportedOpInfo, - ValidationErrorInfo, ValidationErrorKind, + BadBytesAccess, CheckAlignMsg, CheckInAllocMsg, ErrorHandled, EvalStaticInitializerRawResult, + EvalToAllocationRawResult, EvalToConstValueResult, EvalToValTreeResult, ExpectedKind, + InterpError, InterpErrorInfo, InterpResult, InvalidMetaKind, InvalidProgramInfo, + MachineStopType, Misalignment, PointerKind, ReportedErrorInfo, ResourceExhaustionInfo, + ScalarSizeMismatch, UndefinedBehaviorInfo, UnsupportedOpInfo, ValidationErrorInfo, + ValidationErrorKind, interp_ok, }; pub use self::pointer::{CtfeProvenance, Pointer, PointerArithmetic, Provenance}; pub use self::value::Scalar; diff --git a/compiler/rustc_middle/src/mir/interpret/value.rs b/compiler/rustc_middle/src/mir/interpret/value.rs index c6c2ab414ed..061a55bfda8 100644 --- a/compiler/rustc_middle/src/mir/interpret/value.rs +++ b/compiler/rustc_middle/src/mir/interpret/value.rs @@ -8,7 +8,7 @@ use rustc_target::abi::{HasDataLayout, Size}; use super::{ AllocId, CtfeProvenance, InterpResult, Pointer, PointerArithmetic, Provenance, - ScalarSizeMismatch, + ScalarSizeMismatch, interp_ok, }; use crate::ty::ScalarInt; @@ -273,10 +273,10 @@ impl<'tcx, Prov: Provenance> Scalar { .to_bits_or_ptr_internal(cx.pointer_size()) .map_err(|s| err_ub!(ScalarSizeMismatch(s)))? { - Right(ptr) => Ok(ptr.into()), + Right(ptr) => interp_ok(ptr.into()), Left(bits) => { let addr = u64::try_from(bits).unwrap(); - Ok(Pointer::from_addr_invalid(addr)) + interp_ok(Pointer::from_addr_invalid(addr)) } } } @@ -311,12 +311,12 @@ impl<'tcx, Prov: Provenance> Scalar { if matches!(self, Scalar::Ptr(..)) { *self = self.to_scalar_int()?.into(); } - Ok(()) + interp_ok(()) } #[inline(always)] pub fn to_scalar_int(self) -> InterpResult<'tcx, ScalarInt> { - self.try_to_scalar_int().map_err(|_| err_unsup!(ReadPointerAsInt(None)).into()) + self.try_to_scalar_int().map_err(|_| err_unsup!(ReadPointerAsInt(None))).into() } #[inline(always)] @@ -330,20 +330,22 @@ impl<'tcx, Prov: Provenance> Scalar { #[inline] pub fn to_bits(self, target_size: Size) -> InterpResult<'tcx, u128> { assert_ne!(target_size.bytes(), 0, "you should never look at the bits of a ZST"); - self.to_scalar_int()?.try_to_bits(target_size).map_err(|size| { - err_ub!(ScalarSizeMismatch(ScalarSizeMismatch { - target_size: target_size.bytes(), - data_size: size.bytes(), - })) + self.to_scalar_int()? + .try_to_bits(target_size) + .map_err(|size| { + err_ub!(ScalarSizeMismatch(ScalarSizeMismatch { + target_size: target_size.bytes(), + data_size: size.bytes(), + })) + }) .into() - }) } pub fn to_bool(self) -> InterpResult<'tcx, bool> { let val = self.to_u8()?; match val { - 0 => Ok(false), - 1 => Ok(true), + 0 => interp_ok(false), + 1 => interp_ok(true), _ => throw_ub!(InvalidBool(val)), } } @@ -351,7 +353,7 @@ impl<'tcx, Prov: Provenance> Scalar { pub fn to_char(self) -> InterpResult<'tcx, char> { let val = self.to_u32()?; match std::char::from_u32(val) { - Some(c) => Ok(c), + Some(c) => interp_ok(c), None => throw_ub!(InvalidChar(val)), } } @@ -392,7 +394,7 @@ impl<'tcx, Prov: Provenance> Scalar { /// Fails if the scalar is a pointer. pub fn to_target_usize(self, cx: &impl HasDataLayout) -> InterpResult<'tcx, u64> { let b = self.to_uint(cx.data_layout().pointer_size)?; - Ok(u64::try_from(b).unwrap()) + interp_ok(u64::try_from(b).unwrap()) } /// Converts the scalar to produce a signed integer of the given size. @@ -400,7 +402,7 @@ impl<'tcx, Prov: Provenance> Scalar { #[inline] pub fn to_int(self, size: Size) -> InterpResult<'tcx, i128> { let b = self.to_bits(size)?; - Ok(size.sign_extend(b)) + interp_ok(size.sign_extend(b)) } /// Converts the scalar to produce an `i8`. Fails if the scalar is a pointer. @@ -432,13 +434,13 @@ impl<'tcx, Prov: Provenance> Scalar { /// Fails if the scalar is a pointer. pub fn to_target_isize(self, cx: &impl HasDataLayout) -> InterpResult<'tcx, i64> { let b = self.to_int(cx.data_layout().pointer_size)?; - Ok(i64::try_from(b).unwrap()) + interp_ok(i64::try_from(b).unwrap()) } #[inline] pub fn to_float(self) -> InterpResult<'tcx, F> { // Going through `to_bits` to check size and truncation. - Ok(F::from_bits(self.to_bits(Size::from_bits(F::BITS))?)) + interp_ok(F::from_bits(self.to_bits(Size::from_bits(F::BITS))?)) } #[inline] diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs index 73d0acf95f4..389d20f315f 100644 --- a/compiler/rustc_middle/src/ty/consts.rs +++ b/compiler/rustc_middle/src/ty/consts.rs @@ -519,7 +519,7 @@ impl<'tcx> Const<'tcx> { } pub fn try_to_bool(self) -> Option { - self.try_to_scalar()?.to_bool().ok() + self.try_to_valtree()?.try_to_scalar_int()?.try_to_bool().ok() } #[inline] diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs index 905143b2efb..002216f50f2 100644 --- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs +++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs @@ -4,7 +4,7 @@ use rustc_const_eval::const_eval::{DummyMachine, throw_machine_stop_str}; use rustc_const_eval::interpret::{ - DiscardInterpError, ImmTy, Immediate, InterpCx, OpTy, PlaceTy, Projectable, + ImmTy, Immediate, InterpCx, OpTy, PlaceTy, Projectable, interp_ok, }; use rustc_data_structures::fx::FxHashMap; use rustc_hir::def::DefKind; @@ -238,6 +238,7 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> { FlatSet::Elem(op) => self .ecx .int_to_int_or_float(&op, layout) + .discard_err() .map_or(FlatSet::Top, |result| self.wrap_immediate(*result)), FlatSet::Bottom => FlatSet::Bottom, FlatSet::Top => FlatSet::Top, @@ -251,6 +252,7 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> { FlatSet::Elem(op) => self .ecx .float_to_float_or_int(&op, layout) + .discard_err() .map_or(FlatSet::Top, |result| self.wrap_immediate(*result)), FlatSet::Bottom => FlatSet::Bottom, FlatSet::Top => FlatSet::Top, @@ -273,6 +275,7 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> { FlatSet::Elem(value) => self .ecx .unary_op(*op, &value) + .discard_err() .map_or(FlatSet::Top, |val| self.wrap_immediate(*val)), FlatSet::Bottom => FlatSet::Bottom, FlatSet::Top => FlatSet::Top, @@ -366,10 +369,8 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> { } } Operand::Constant(box constant) => { - if let Some(constant) = self - .ecx - .eval_mir_constant(&constant.const_, constant.span, None) - .discard_interp_err() + if let Some(constant) = + self.ecx.eval_mir_constant(&constant.const_, constant.span, None).discard_err() { self.assign_constant(state, place, constant, &[]); } @@ -391,7 +392,7 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> { for &(mut proj_elem) in projection { if let PlaceElem::Index(index) = proj_elem { if let FlatSet::Elem(index) = state.get(index.into(), &self.map) - && let Some(offset) = index.to_target_usize(&self.tcx).discard_interp_err() + && let Some(offset) = index.to_target_usize(&self.tcx).discard_err() && let Some(min_length) = offset.checked_add(1) { proj_elem = PlaceElem::ConstantIndex { offset, min_length, from_end: false }; @@ -399,40 +400,35 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> { return; } } - operand = - if let Some(operand) = self.ecx.project(&operand, proj_elem).discard_interp_err() { - operand - } else { - return; - } + operand = if let Some(operand) = self.ecx.project(&operand, proj_elem).discard_err() { + operand + } else { + return; + } } self.map.for_each_projection_value( place, operand, &mut |elem, op| match elem { - TrackElem::Field(idx) => { - self.ecx.project_field(op, idx.as_usize()).discard_interp_err() - } - TrackElem::Variant(idx) => self.ecx.project_downcast(op, idx).discard_interp_err(), + TrackElem::Field(idx) => self.ecx.project_field(op, idx.as_usize()).discard_err(), + TrackElem::Variant(idx) => self.ecx.project_downcast(op, idx).discard_err(), TrackElem::Discriminant => { - let variant = self.ecx.read_discriminant(op).discard_interp_err()?; - let discr_value = self - .ecx - .discriminant_for_variant(op.layout.ty, variant) - .discard_interp_err()?; + let variant = self.ecx.read_discriminant(op).discard_err()?; + let discr_value = + self.ecx.discriminant_for_variant(op.layout.ty, variant).discard_err()?; Some(discr_value.into()) } TrackElem::DerefLen => { - let op: OpTy<'_> = self.ecx.deref_pointer(op).discard_interp_err()?.into(); - let len_usize = op.len(&self.ecx).discard_interp_err()?; + let op: OpTy<'_> = self.ecx.deref_pointer(op).discard_err()?.into(); + let len_usize = op.len(&self.ecx).discard_err()?; let layout = self.tcx.layout_of(self.param_env.and(self.tcx.types.usize)).unwrap(); Some(ImmTy::from_uint(len_usize, layout).into()) } }, &mut |place, op| { - if let Some(imm) = self.ecx.read_immediate_raw(op).discard_interp_err() + if let Some(imm) = self.ecx.read_immediate_raw(op).discard_err() && let Some(imm) = imm.right() { let elem = self.wrap_immediate(*imm); @@ -456,7 +452,7 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> { (FlatSet::Bottom, _) | (_, FlatSet::Bottom) => (FlatSet::Bottom, FlatSet::Bottom), // Both sides are known, do the actual computation. (FlatSet::Elem(left), FlatSet::Elem(right)) => { - match self.ecx.binary_op(op, &left, &right).discard_interp_err() { + match self.ecx.binary_op(op, &left, &right).discard_err() { // Ideally this would return an Immediate, since it's sometimes // a pair and sometimes not. But as a hack we always return a pair // and just make the 2nd component `Bottom` when it does not exist. @@ -479,7 +475,7 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> { } let arg_scalar = const_arg.to_scalar(); - let Some(arg_value) = arg_scalar.to_bits(layout.size).discard_interp_err() else { + let Some(arg_value) = arg_scalar.to_bits(layout.size).discard_err() else { return (FlatSet::Top, FlatSet::Top); }; @@ -527,10 +523,8 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> { return None; } let enum_ty_layout = self.tcx.layout_of(self.param_env.and(enum_ty)).ok()?; - let discr_value = self - .ecx - .discriminant_for_variant(enum_ty_layout.ty, variant_index) - .discard_interp_err()?; + let discr_value = + self.ecx.discriminant_for_variant(enum_ty_layout.ty, variant_index).discard_err()?; Some(discr_value.to_scalar()) } @@ -584,7 +578,7 @@ impl<'a, 'tcx> Collector<'a, 'tcx> { map: &Map<'tcx>, ) -> Option> { let ty = place.ty(self.local_decls, self.patch.tcx).ty; - let layout = ecx.layout_of(ty).discard_interp_err()?; + let layout = ecx.layout_of(ty).ok()?; if layout.is_zst() { return Some(Const::zero_sized(ty)); @@ -606,7 +600,7 @@ impl<'a, 'tcx> Collector<'a, 'tcx> { .intern_with_temp_alloc(layout, |ecx, dest| { try_write_constant(ecx, dest, place, ty, state, map) }) - .discard_interp_err()?; + .discard_err()?; return Some(Const::Val(ConstValue::Indirect { alloc_id, offset: Size::ZERO }, ty)); } @@ -643,7 +637,7 @@ fn try_write_constant<'tcx>( // Fast path for ZSTs. if layout.is_zst() { - return Ok(()); + return interp_ok(()); } // Fast path for scalars. @@ -728,7 +722,7 @@ fn try_write_constant<'tcx>( ty::Error(_) | ty::Infer(..) | ty::CoroutineWitness(..) => bug!(), } - Ok(()) + interp_ok(()) } impl<'mir, 'tcx> @@ -841,7 +835,7 @@ impl<'tcx> MutVisitor<'tcx> for Patch<'tcx> { if let PlaceElem::Index(local) = elem { let offset = self.before_effect.get(&(location, local.into()))?; let offset = offset.try_to_scalar()?; - let offset = offset.to_target_usize(&self.tcx).discard_interp_err()?; + let offset = offset.to_target_usize(&self.tcx).discard_err()?; let min_length = offset.checked_add(1)?; Some(PlaceElem::ConstantIndex { offset, min_length, from_end: false }) } else { diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index 4dbcc6af9bd..50c9702cb9b 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -87,8 +87,8 @@ use std::borrow::Cow; use either::Either; use rustc_const_eval::const_eval::DummyMachine; use rustc_const_eval::interpret::{ - DiscardInterpError, ImmTy, Immediate, InterpCx, MemPlaceMeta, MemoryKind, OpTy, Projectable, - Scalar, intern_const_alloc_for_constprop, + ImmTy, Immediate, InterpCx, MemPlaceMeta, MemoryKind, OpTy, Projectable, Scalar, + intern_const_alloc_for_constprop, }; use rustc_data_structures::fx::FxIndexSet; use rustc_data_structures::graph::dominators::Dominators; @@ -393,7 +393,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { Repeat(..) => return None, Constant { ref value, disambiguator: _ } => { - self.ecx.eval_mir_constant(value, DUMMY_SP, None).discard_interp_err()? + self.ecx.eval_mir_constant(value, DUMMY_SP, None).discard_err()? } Aggregate(kind, variant, ref fields) => { let fields = fields @@ -414,39 +414,37 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { AggregateTy::RawPtr { output_pointer_ty, .. } => output_pointer_ty, }; let variant = if ty.is_enum() { Some(variant) } else { None }; - let ty = self.ecx.layout_of(ty).discard_interp_err()?; + let ty = self.ecx.layout_of(ty).ok()?; if ty.is_zst() { ImmTy::uninit(ty).into() } else if matches!(kind, AggregateTy::RawPtr { .. }) { // Pointers don't have fields, so don't `project_field` them. - let data = self.ecx.read_pointer(fields[0]).discard_interp_err()?; + let data = self.ecx.read_pointer(fields[0]).discard_err()?; let meta = if fields[1].layout.is_zst() { MemPlaceMeta::None } else { - MemPlaceMeta::Meta(self.ecx.read_scalar(fields[1]).discard_interp_err()?) + MemPlaceMeta::Meta(self.ecx.read_scalar(fields[1]).discard_err()?) }; let ptr_imm = Immediate::new_pointer_with_meta(data, meta, &self.ecx); ImmTy::from_immediate(ptr_imm, ty).into() } else if matches!(ty.abi, Abi::Scalar(..) | Abi::ScalarPair(..)) { - let dest = self.ecx.allocate(ty, MemoryKind::Stack).discard_interp_err()?; + let dest = self.ecx.allocate(ty, MemoryKind::Stack).discard_err()?; let variant_dest = if let Some(variant) = variant { - self.ecx.project_downcast(&dest, variant).discard_interp_err()? + self.ecx.project_downcast(&dest, variant).discard_err()? } else { dest.clone() }; for (field_index, op) in fields.into_iter().enumerate() { - let field_dest = self - .ecx - .project_field(&variant_dest, field_index) - .discard_interp_err()?; - self.ecx.copy_op(op, &field_dest).discard_interp_err()?; + let field_dest = + self.ecx.project_field(&variant_dest, field_index).discard_err()?; + self.ecx.copy_op(op, &field_dest).discard_err()?; } self.ecx .write_discriminant(variant.unwrap_or(FIRST_VARIANT), &dest) - .discard_interp_err()?; + .discard_err()?; self.ecx .alloc_mark_immutable(dest.ptr().provenance.unwrap().alloc_id()) - .discard_interp_err()?; + .discard_err()?; dest.into() } else { return None; @@ -472,7 +470,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { // This should have been replaced by a `ConstantIndex` earlier. ProjectionElem::Index(_) => return None, }; - self.ecx.project(value, elem).discard_interp_err()? + self.ecx.project(value, elem).discard_err()? } Address { place, kind, provenance: _ } => { if !place.is_indirect_first_projection() { @@ -480,14 +478,14 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { } let local = self.locals[place.local]?; let pointer = self.evaluated[local].as_ref()?; - let mut mplace = self.ecx.deref_pointer(pointer).discard_interp_err()?; + let mut mplace = self.ecx.deref_pointer(pointer).discard_err()?; for proj in place.projection.iter().skip(1) { // We have no call stack to associate a local with a value, so we cannot // interpret indexing. if matches!(proj, ProjectionElem::Index(_)) { return None; } - mplace = self.ecx.project(&mplace, proj).discard_interp_err()?; + mplace = self.ecx.project(&mplace, proj).discard_err()?; } let pointer = mplace.to_ref(&self.ecx); let ty = match kind { @@ -499,28 +497,26 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { ), AddressKind::Address(mutbl) => Ty::new_ptr(self.tcx, mplace.layout.ty, mutbl), }; - let layout = self.ecx.layout_of(ty).discard_interp_err()?; + let layout = self.ecx.layout_of(ty).ok()?; ImmTy::from_immediate(pointer, layout).into() } Discriminant(base) => { let base = self.evaluated[base].as_ref()?; - let variant = self.ecx.read_discriminant(base).discard_interp_err()?; - let discr_value = self - .ecx - .discriminant_for_variant(base.layout.ty, variant) - .discard_interp_err()?; + let variant = self.ecx.read_discriminant(base).discard_err()?; + let discr_value = + self.ecx.discriminant_for_variant(base.layout.ty, variant).discard_err()?; discr_value.into() } Len(slice) => { let slice = self.evaluated[slice].as_ref()?; let usize_layout = self.ecx.layout_of(self.tcx.types.usize).unwrap(); - let len = slice.len(&self.ecx).discard_interp_err()?; + let len = slice.len(&self.ecx).discard_err()?; let imm = ImmTy::from_uint(len, usize_layout); imm.into() } NullaryOp(null_op, ty) => { - let layout = self.ecx.layout_of(ty).discard_interp_err()?; + let layout = self.ecx.layout_of(ty).ok()?; if let NullOp::SizeOf | NullOp::AlignOf = null_op && layout.is_unsized() { @@ -542,36 +538,36 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { } UnaryOp(un_op, operand) => { let operand = self.evaluated[operand].as_ref()?; - let operand = self.ecx.read_immediate(operand).discard_interp_err()?; - let val = self.ecx.unary_op(un_op, &operand).discard_interp_err()?; + let operand = self.ecx.read_immediate(operand).discard_err()?; + let val = self.ecx.unary_op(un_op, &operand).discard_err()?; val.into() } BinaryOp(bin_op, lhs, rhs) => { let lhs = self.evaluated[lhs].as_ref()?; - let lhs = self.ecx.read_immediate(lhs).discard_interp_err()?; + let lhs = self.ecx.read_immediate(lhs).discard_err()?; let rhs = self.evaluated[rhs].as_ref()?; - let rhs = self.ecx.read_immediate(rhs).discard_interp_err()?; - let val = self.ecx.binary_op(bin_op, &lhs, &rhs).discard_interp_err()?; + let rhs = self.ecx.read_immediate(rhs).discard_err()?; + let val = self.ecx.binary_op(bin_op, &lhs, &rhs).discard_err()?; val.into() } Cast { kind, value, from: _, to } => match kind { CastKind::IntToInt | CastKind::IntToFloat => { let value = self.evaluated[value].as_ref()?; - let value = self.ecx.read_immediate(value).discard_interp_err()?; - let to = self.ecx.layout_of(to).discard_interp_err()?; - let res = self.ecx.int_to_int_or_float(&value, to).discard_interp_err()?; + let value = self.ecx.read_immediate(value).discard_err()?; + let to = self.ecx.layout_of(to).ok()?; + let res = self.ecx.int_to_int_or_float(&value, to).discard_err()?; res.into() } CastKind::FloatToFloat | CastKind::FloatToInt => { let value = self.evaluated[value].as_ref()?; - let value = self.ecx.read_immediate(value).discard_interp_err()?; - let to = self.ecx.layout_of(to).discard_interp_err()?; - let res = self.ecx.float_to_float_or_int(&value, to).discard_interp_err()?; + let value = self.ecx.read_immediate(value).discard_err()?; + let to = self.ecx.layout_of(to).ok()?; + let res = self.ecx.float_to_float_or_int(&value, to).discard_err()?; res.into() } CastKind::Transmute => { let value = self.evaluated[value].as_ref()?; - let to = self.ecx.layout_of(to).discard_interp_err()?; + let to = self.ecx.layout_of(to).ok()?; // `offset` for immediates only supports scalar/scalar-pair ABIs, // so bail out if the target is not one. if value.as_mplace_or_imm().is_right() { @@ -581,29 +577,29 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { _ => return None, } } - value.offset(Size::ZERO, to, &self.ecx).discard_interp_err()? + value.offset(Size::ZERO, to, &self.ecx).discard_err()? } CastKind::PointerCoercion(ty::adjustment::PointerCoercion::Unsize, _) => { let src = self.evaluated[value].as_ref()?; - let to = self.ecx.layout_of(to).discard_interp_err()?; - let dest = self.ecx.allocate(to, MemoryKind::Stack).discard_interp_err()?; - self.ecx.unsize_into(src, to, &dest.clone().into()).discard_interp_err()?; + let to = self.ecx.layout_of(to).ok()?; + let dest = self.ecx.allocate(to, MemoryKind::Stack).discard_err()?; + self.ecx.unsize_into(src, to, &dest.clone().into()).discard_err()?; self.ecx .alloc_mark_immutable(dest.ptr().provenance.unwrap().alloc_id()) - .discard_interp_err()?; + .discard_err()?; dest.into() } CastKind::FnPtrToPtr | CastKind::PtrToPtr => { let src = self.evaluated[value].as_ref()?; - let src = self.ecx.read_immediate(src).discard_interp_err()?; - let to = self.ecx.layout_of(to).discard_interp_err()?; - let ret = self.ecx.ptr_to_ptr(&src, to).discard_interp_err()?; + let src = self.ecx.read_immediate(src).discard_err()?; + let to = self.ecx.layout_of(to).ok()?; + let ret = self.ecx.ptr_to_ptr(&src, to).discard_err()?; ret.into() } CastKind::PointerCoercion(ty::adjustment::PointerCoercion::UnsafeFnPointer, _) => { let src = self.evaluated[value].as_ref()?; - let src = self.ecx.read_immediate(src).discard_interp_err()?; - let to = self.ecx.layout_of(to).discard_interp_err()?; + let src = self.ecx.read_immediate(src).discard_err()?; + let to = self.ecx.layout_of(to).ok()?; ImmTy::from_immediate(*src, to).into() } _ => return None, @@ -715,7 +711,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { && let Some(idx) = self.locals[idx_local] { if let Some(offset) = self.evaluated[idx].as_ref() - && let Some(offset) = self.ecx.read_target_usize(offset).discard_interp_err() + && let Some(offset) = self.ecx.read_target_usize(offset).discard_err() && let Some(min_length) = offset.checked_add(1) { projection.to_mut()[i] = @@ -875,7 +871,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { && let DefKind::Enum = self.tcx.def_kind(enum_did) { let enum_ty = self.tcx.type_of(enum_did).instantiate(self.tcx, enum_args); - let discr = self.ecx.discriminant_for_variant(enum_ty, variant).discard_interp_err()?; + let discr = self.ecx.discriminant_for_variant(enum_ty, variant).discard_err()?; return Some(self.insert_scalar(discr.to_scalar(), discr.layout.ty)); } @@ -1225,13 +1221,13 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { return None; } - let layout = self.ecx.layout_of(lhs_ty).discard_interp_err()?; + let layout = self.ecx.layout_of(lhs_ty).ok()?; let as_bits = |value| { let constant = self.evaluated[value].as_ref()?; if layout.abi.is_scalar() { - let scalar = self.ecx.read_scalar(constant).discard_interp_err()?; - scalar.to_bits(constant.layout.size).discard_interp_err() + let scalar = self.ecx.read_scalar(constant).discard_err()?; + scalar.to_bits(constant.layout.size).discard_err() } else { // `constant` is a wide pointer. Do not evaluate to bits. None @@ -1491,7 +1487,7 @@ fn op_to_prop_const<'tcx>( // If this constant has scalar ABI, return it as a `ConstValue::Scalar`. if let Abi::Scalar(abi::Scalar::Initialized { .. }) = op.layout.abi - && let Some(scalar) = ecx.read_scalar(op).discard_interp_err() + && let Some(scalar) = ecx.read_scalar(op).discard_err() { if !scalar.try_to_scalar_int().is_ok() { // Check that we do not leak a pointer. @@ -1505,12 +1501,12 @@ fn op_to_prop_const<'tcx>( // If this constant is already represented as an `Allocation`, // try putting it into global memory to return it. if let Either::Left(mplace) = op.as_mplace_or_imm() { - let (size, _align) = ecx.size_and_align_of_mplace(&mplace).discard_interp_err()??; + let (size, _align) = ecx.size_and_align_of_mplace(&mplace).discard_err()??; // Do not try interning a value that contains provenance. // Due to https://github.com/rust-lang/rust/issues/79738, doing so could lead to bugs. // FIXME: remove this hack once that issue is fixed. - let alloc_ref = ecx.get_ptr_alloc(mplace.ptr(), size).discard_interp_err()??; + let alloc_ref = ecx.get_ptr_alloc(mplace.ptr(), size).discard_err()??; if alloc_ref.has_provenance() { return None; } @@ -1518,7 +1514,7 @@ fn op_to_prop_const<'tcx>( let pointer = mplace.ptr().into_pointer_or_addr().ok()?; let (prov, offset) = pointer.into_parts(); let alloc_id = prov.alloc_id(); - intern_const_alloc_for_constprop(ecx, alloc_id).discard_interp_err()?; + intern_const_alloc_for_constprop(ecx, alloc_id).discard_err()?; // `alloc_id` may point to a static. Codegen will choke on an `Indirect` with anything // by `GlobalAlloc::Memory`, so do fall through to copying if needed. @@ -1533,9 +1529,8 @@ fn op_to_prop_const<'tcx>( } // Everything failed: create a new allocation to hold the data. - let alloc_id = ecx - .intern_with_temp_alloc(op.layout, |ecx, dest| ecx.copy_op(op, dest)) - .discard_interp_err()?; + let alloc_id = + ecx.intern_with_temp_alloc(op.layout, |ecx, dest| ecx.copy_op(op, dest)).discard_err()?; let value = ConstValue::Indirect { alloc_id, offset: Size::ZERO }; // Check that we do not leak a pointer. diff --git a/compiler/rustc_mir_transform/src/jump_threading.rs b/compiler/rustc_mir_transform/src/jump_threading.rs index e69a7e552f6..1844b97887a 100644 --- a/compiler/rustc_mir_transform/src/jump_threading.rs +++ b/compiler/rustc_mir_transform/src/jump_threading.rs @@ -37,9 +37,7 @@ use rustc_arena::DroplessArena; use rustc_const_eval::const_eval::DummyMachine; -use rustc_const_eval::interpret::{ - DiscardInterpError, ImmTy, Immediate, InterpCx, OpTy, Projectable, -}; +use rustc_const_eval::interpret::{ImmTy, Immediate, InterpCx, OpTy, Projectable}; use rustc_data_structures::fx::FxHashSet; use rustc_index::IndexVec; use rustc_index::bit_set::BitSet; @@ -202,7 +200,7 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> { debug!(?discr, ?bb); let discr_ty = discr.ty(self.body, self.tcx).ty; - let Some(discr_layout) = self.ecx.layout_of(discr_ty).discard_interp_err() else { + let Ok(discr_layout) = self.ecx.layout_of(discr_ty) else { return; }; @@ -392,28 +390,24 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> { lhs, constant, &mut |elem, op| match elem { - TrackElem::Field(idx) => { - self.ecx.project_field(op, idx.as_usize()).discard_interp_err() - } - TrackElem::Variant(idx) => self.ecx.project_downcast(op, idx).discard_interp_err(), + TrackElem::Field(idx) => self.ecx.project_field(op, idx.as_usize()).discard_err(), + TrackElem::Variant(idx) => self.ecx.project_downcast(op, idx).discard_err(), TrackElem::Discriminant => { - let variant = self.ecx.read_discriminant(op).discard_interp_err()?; - let discr_value = self - .ecx - .discriminant_for_variant(op.layout.ty, variant) - .discard_interp_err()?; + let variant = self.ecx.read_discriminant(op).discard_err()?; + let discr_value = + self.ecx.discriminant_for_variant(op.layout.ty, variant).discard_err()?; Some(discr_value.into()) } TrackElem::DerefLen => { - let op: OpTy<'_> = self.ecx.deref_pointer(op).discard_interp_err()?.into(); - let len_usize = op.len(&self.ecx).discard_interp_err()?; + let op: OpTy<'_> = self.ecx.deref_pointer(op).discard_err()?.into(); + let len_usize = op.len(&self.ecx).discard_err()?; let layout = self.ecx.layout_of(self.tcx.types.usize).unwrap(); Some(ImmTy::from_uint(len_usize, layout).into()) } }, &mut |place, op| { if let Some(conditions) = state.try_get_idx(place, &self.map) - && let Some(imm) = self.ecx.read_immediate_raw(op).discard_interp_err() + && let Some(imm) = self.ecx.read_immediate_raw(op).discard_err() && let Some(imm) = imm.right() && let Immediate::Scalar(Scalar::Int(int)) = *imm { @@ -437,10 +431,8 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> { match rhs { // If we expect `lhs ?= A`, we have an opportunity if we assume `constant == A`. Operand::Constant(constant) => { - let Some(constant) = self - .ecx - .eval_mir_constant(&constant.const_, constant.span, None) - .discard_interp_err() + let Some(constant) = + self.ecx.eval_mir_constant(&constant.const_, constant.span, None).discard_err() else { return; }; @@ -482,7 +474,7 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> { && let Some(discr_value) = self .ecx .discriminant_for_variant(agg_ty, *variant_index) - .discard_interp_err() + .discard_err() { self.process_immediate(bb, discr_target, discr_value, state); } @@ -567,7 +559,7 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> { // `SetDiscriminant` may be a no-op if the assigned variant is the untagged variant // of a niche encoding. If we cannot ensure that we write to the discriminant, do // nothing. - let Some(enum_layout) = self.ecx.layout_of(enum_ty).discard_interp_err() else { + let Ok(enum_layout) = self.ecx.layout_of(enum_ty) else { return; }; let writes_discriminant = match enum_layout.variants { @@ -582,10 +574,8 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> { } => *variant_index != untagged_variant, }; if writes_discriminant { - let Some(discr) = self - .ecx - .discriminant_for_variant(enum_ty, *variant_index) - .discard_interp_err() + let Some(discr) = + self.ecx.discriminant_for_variant(enum_ty, *variant_index).discard_err() else { return; }; @@ -662,7 +652,7 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> { let Some(discr) = discr.place() else { return }; let discr_ty = discr.ty(self.body, self.tcx).ty; - let Some(discr_layout) = self.ecx.layout_of(discr_ty).discard_interp_err() else { + let Ok(discr_layout) = self.ecx.layout_of(discr_ty) else { return; }; let Some(conditions) = state.try_get(discr.as_ref(), &self.map) else { return }; diff --git a/compiler/rustc_mir_transform/src/known_panics_lint.rs b/compiler/rustc_mir_transform/src/known_panics_lint.rs index b165ea53440..ccc029b1e28 100644 --- a/compiler/rustc_mir_transform/src/known_panics_lint.rs +++ b/compiler/rustc_mir_transform/src/known_panics_lint.rs @@ -6,7 +6,7 @@ use std::fmt::Debug; use rustc_const_eval::const_eval::DummyMachine; use rustc_const_eval::interpret::{ - DiscardInterpError, ImmTy, InterpCx, InterpResult, Projectable, Scalar, format_interp_error, + ImmTy, InterpCx, InterpResult, Projectable, Scalar, format_interp_error, interp_ok, }; use rustc_data_structures::fx::FxHashSet; use rustc_hir::HirId; @@ -101,8 +101,7 @@ impl<'tcx> Value<'tcx> { } (PlaceElem::Index(idx), Value::Aggregate { fields, .. }) => { let idx = prop.get_const(idx.into())?.immediate()?; - let idx = - prop.ecx.read_target_usize(idx).discard_interp_err()?.try_into().ok()?; + let idx = prop.ecx.read_target_usize(idx).discard_err()?.try_into().ok()?; if idx <= FieldIdx::MAX_AS_U32 { fields.get(FieldIdx::from_u32(idx)).unwrap_or(&Value::Uninit) } else { @@ -232,22 +231,20 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { where F: FnOnce(&mut Self) -> InterpResult<'tcx, T>, { - match f(self) { - Ok(val) => Some(val), - Err(error) => { - trace!("InterpCx operation failed: {:?}", error); + f(self) + .map_err(|err| { + trace!("InterpCx operation failed: {:?}", err); // Some errors shouldn't come up because creating them causes // an allocation, which we should avoid. When that happens, // dedicated error variants should be introduced instead. assert!( - !error.kind().formatted_string(), + !err.kind().formatted_string(), "known panics lint encountered formatting error: {}", - format_interp_error(self.ecx.tcx.dcx(), error), + format_interp_error(self.ecx.tcx.dcx(), err), ); - error.discard_interp_err(); - None - } - } + err + }) + .discard_err() } /// Returns the value, if any, of evaluating `c`. @@ -317,7 +314,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { .ecx .binary_op(BinOp::SubWithOverflow, &ImmTy::from_int(0, arg.layout), &arg)? .to_scalar_pair(); - Ok((arg, overflow.to_bool()?)) + interp_ok((arg, overflow.to_bool()?)) })?; if overflow { self.report_assert_as_lint( @@ -349,9 +346,9 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { // We need the type of the LHS. We cannot use `place_layout` as that is the type // of the result, which for checked binops is not the same! let left_ty = left.ty(self.local_decls(), self.tcx); - let left_size = self.ecx.layout_of(left_ty).discard_interp_err()?.size; + let left_size = self.ecx.layout_of(left_ty).ok()?.size; let right_size = r.layout.size; - let r_bits = r.to_scalar().to_bits(right_size).discard_interp_err(); + let r_bits = r.to_scalar().to_bits(right_size).discard_err(); if r_bits.is_some_and(|b| b >= left_size.bits() as u128) { debug!("check_binary_op: reporting assert for {:?}", location); let panic = AssertKind::Overflow( @@ -498,7 +495,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { // This can be `None` if the lhs wasn't const propagated and we just // triggered the assert on the value of the rhs. self.eval_operand(op) - .and_then(|op| self.ecx.read_immediate(&op).discard_interp_err()) + .and_then(|op| self.ecx.read_immediate(&op).discard_err()) .map_or(DbgVal::Underscore, |op| DbgVal::Val(op.to_const_int())) }; let msg = match msg { @@ -542,7 +539,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { return None; } use rustc_middle::mir::Rvalue::*; - let layout = self.ecx.layout_of(dest.ty(self.body, self.tcx).ty).discard_interp_err()?; + let layout = self.ecx.layout_of(dest.ty(self.body, self.tcx).ty).ok()?; trace!(?layout); let val: Value<'_> = match *rvalue { @@ -604,7 +601,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { Len(place) => { let len = match self.get_const(place)? { - Value::Immediate(src) => src.len(&self.ecx).discard_interp_err()?, + Value::Immediate(src) => src.len(&self.ecx).discard_err()?, Value::Aggregate { fields, .. } => fields.len() as u64, Value::Uninit => match place.ty(self.local_decls(), self.tcx).ty.kind() { ty::Array(_, n) => n.try_eval_target_usize(self.tcx, self.param_env)?, @@ -617,7 +614,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { Ref(..) | RawPtr(..) => return None, NullaryOp(ref null_op, ty) => { - let op_layout = self.use_ecx(|this| this.ecx.layout_of(ty))?; + let op_layout = self.ecx.layout_of(ty).ok()?; let val = match null_op { NullOp::SizeOf => op_layout.size.bytes(), NullOp::AlignOf => op_layout.align.abi.bytes(), @@ -635,21 +632,21 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { Cast(ref kind, ref value, to) => match kind { CastKind::IntToInt | CastKind::IntToFloat => { let value = self.eval_operand(value)?; - let value = self.ecx.read_immediate(&value).discard_interp_err()?; - let to = self.ecx.layout_of(to).discard_interp_err()?; - let res = self.ecx.int_to_int_or_float(&value, to).discard_interp_err()?; + let value = self.ecx.read_immediate(&value).discard_err()?; + let to = self.ecx.layout_of(to).ok()?; + let res = self.ecx.int_to_int_or_float(&value, to).discard_err()?; res.into() } CastKind::FloatToFloat | CastKind::FloatToInt => { let value = self.eval_operand(value)?; - let value = self.ecx.read_immediate(&value).discard_interp_err()?; - let to = self.ecx.layout_of(to).discard_interp_err()?; - let res = self.ecx.float_to_float_or_int(&value, to).discard_interp_err()?; + let value = self.ecx.read_immediate(&value).discard_err()?; + let to = self.ecx.layout_of(to).ok()?; + let res = self.ecx.float_to_float_or_int(&value, to).discard_err()?; res.into() } CastKind::Transmute => { let value = self.eval_operand(value)?; - let to = self.ecx.layout_of(to).discard_interp_err()?; + let to = self.ecx.layout_of(to).ok()?; // `offset` for immediates only supports scalar/scalar-pair ABIs, // so bail out if the target is not one. match (value.layout.abi, to.abi) { @@ -658,7 +655,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { _ => return None, } - value.offset(Size::ZERO, to, &self.ecx).discard_interp_err()?.into() + value.offset(Size::ZERO, to, &self.ecx).discard_err()?.into() } _ => return None, }, @@ -783,8 +780,7 @@ impl<'tcx> Visitor<'tcx> for ConstPropagator<'_, 'tcx> { TerminatorKind::SwitchInt { ref discr, ref targets } => { if let Some(ref value) = self.eval_operand(discr) && let Some(value_const) = self.use_ecx(|this| this.ecx.read_scalar(value)) - && let Some(constant) = - value_const.to_bits(value_const.size()).discard_interp_err() + && let Some(constant) = value_const.to_bits(value_const.size()).discard_err() { // We managed to evaluate the discriminant, so we know we only need to visit // one target. diff --git a/src/tools/clippy/clippy_utils/src/consts.rs b/src/tools/clippy/clippy_utils/src/consts.rs index bf47cf6d372..53a1170d6a6 100644 --- a/src/tools/clippy/clippy_utils/src/consts.rs +++ b/src/tools/clippy/clippy_utils/src/consts.rs @@ -870,10 +870,10 @@ pub fn mir_to_const<'tcx>(tcx: TyCtxt<'tcx>, result: mir::Const<'tcx>) -> Option let range = alloc_range(offset + size * idx, size); let val = alloc.read_scalar(&tcx, range, /* read_provenance */ false).ok()?; res.push(match flt { - FloatTy::F16 => Constant::F16(f16::from_bits(val.to_u16().ok()?)), - FloatTy::F32 => Constant::F32(f32::from_bits(val.to_u32().ok()?)), - FloatTy::F64 => Constant::F64(f64::from_bits(val.to_u64().ok()?)), - FloatTy::F128 => Constant::F128(f128::from_bits(val.to_u128().ok()?)), + FloatTy::F16 => Constant::F16(f16::from_bits(val.to_u16().discard_err()?)), + FloatTy::F32 => Constant::F32(f32::from_bits(val.to_u32().discard_err()?)), + FloatTy::F64 => Constant::F64(f64::from_bits(val.to_u64().discard_err()?)), + FloatTy::F128 => Constant::F128(f128::from_bits(val.to_u128().discard_err()?)), }); } Some(Constant::Vec(res)) @@ -903,7 +903,7 @@ fn mir_is_empty<'tcx>(tcx: TyCtxt<'tcx>, result: mir::Const<'tcx>) -> Option: crate::MiriInterpCxExt<'tcx> { AllocKind::Dead => unreachable!(), }; // Ensure this pointer's provenance is exposed, so that it can be used by FFI code. - return Ok(base_ptr.expose_provenance().try_into().unwrap()); + return interp_ok(base_ptr.expose_provenance().try_into().unwrap()); } // We are not in native lib mode, so we control the addresses ourselves. if let Some((reuse_addr, clock)) = @@ -209,7 +209,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { if let Some(clock) = clock { ecx.acquire_clock(&clock); } - Ok(reuse_addr) + interp_ok(reuse_addr) } else { // We have to pick a fresh address. // Leave some space to the previous allocation, to give it some chance to be less aligned. @@ -234,7 +234,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { throw_exhaust!(AddressSpaceFull); } - Ok(base_addr) + interp_ok(base_addr) } } @@ -248,7 +248,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { let global_state = &mut *global_state; match global_state.base_addr.get(&alloc_id) { - Some(&addr) => Ok(addr), + Some(&addr) => interp_ok(addr), None => { // First time we're looking for the absolute address of this allocation. let base_addr = @@ -274,7 +274,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { }; global_state.int_to_ptr_map.insert(pos, (base_addr, alloc_id)); - Ok(base_addr) + interp_ok(base_addr) } } } @@ -287,12 +287,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let global_state = ecx.machine.alloc_addresses.get_mut(); // In strict mode, we don't need this, so we can save some cycles by not tracking it. if global_state.provenance_mode == ProvenanceMode::Strict { - return Ok(()); + return interp_ok(()); } // Exposing a dead alloc is a no-op, because it's not possible to get a dead allocation // via int2ptr. if !ecx.is_alloc_live(alloc_id) { - return Ok(()); + return interp_ok(()); } trace!("Exposing allocation id {alloc_id:?}"); let global_state = ecx.machine.alloc_addresses.get_mut(); @@ -300,7 +300,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { if ecx.machine.borrow_tracker.is_some() { ecx.expose_tag(alloc_id, tag)?; } - Ok(()) + interp_ok(()) } fn ptr_from_addr_cast(&self, addr: u64) -> InterpResult<'tcx, Pointer> { @@ -337,7 +337,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // cast is fairly irrelevant. Instead we generate this as a "wildcard" pointer, such that // *every time the pointer is used*, we do an `AllocId` lookup to find the (exposed) // allocation it might be referencing. - Ok(Pointer::new(Some(Provenance::Wildcard), Size::from_bytes(addr))) + interp_ok(Pointer::new(Some(Provenance::Wildcard), Size::from_bytes(addr))) } /// Convert a relative (tcx) pointer to a Miri pointer. @@ -359,7 +359,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { Size::from_bytes(base_addr), ); // Add offset with the right kind of pointer-overflowing arithmetic. - Ok(base_ptr.wrapping_offset(offset, ecx)) + interp_ok(base_ptr.wrapping_offset(offset, ecx)) } // This returns some prepared `MiriAllocBytes`, either because `addr_from_alloc_id` reserved @@ -390,9 +390,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { assert_eq!(prepared_alloc_bytes.len(), bytes.len()); // Copy allocation contents into prepared memory. prepared_alloc_bytes.copy_from_slice(bytes); - Ok(prepared_alloc_bytes) + interp_ok(prepared_alloc_bytes) } else { - Ok(MiriAllocBytes::from_bytes(std::borrow::Cow::Borrowed(bytes), align)) + interp_ok(MiriAllocBytes::from_bytes(std::borrow::Cow::Borrowed(bytes), align)) } } diff --git a/src/tools/miri/src/borrow_tracker/mod.rs b/src/tools/miri/src/borrow_tracker/mod.rs index 89fd8c28af2..5204558f98c 100644 --- a/src/tools/miri/src/borrow_tracker/mod.rs +++ b/src/tools/miri/src/borrow_tracker/mod.rs @@ -322,7 +322,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { match method { BorrowTrackerMethod::StackedBorrows => { this.tcx.tcx.dcx().warn("Stacked Borrows does not support named pointers; `miri_pointer_name` is a no-op"); - Ok(()) + interp_ok(()) } BorrowTrackerMethod::TreeBorrows => this.tb_give_pointer_debug_name(ptr, nth_parent, name), @@ -333,7 +333,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let this = self.eval_context_mut(); let Some(borrow_tracker) = &this.machine.borrow_tracker else { eprintln!("attempted to print borrow state, but no borrow state is being tracked"); - return Ok(()); + return interp_ok(()); }; let method = borrow_tracker.borrow().borrow_tracker_method; match method { @@ -376,7 +376,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } } borrow_tracker.borrow_mut().end_call(&frame.extra); - Ok(()) + interp_ok(()) } } @@ -489,7 +489,7 @@ impl AllocState { alloc_id: AllocId, // diagnostics ) -> InterpResult<'tcx> { match self { - AllocState::StackedBorrows(_sb) => Ok(()), + AllocState::StackedBorrows(_sb) => interp_ok(()), AllocState::TreeBorrows(tb) => tb.borrow_mut().release_protector(machine, global, tag, alloc_id), } diff --git a/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs b/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs index b270e484bdb..fdc7a675fb7 100644 --- a/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs +++ b/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs @@ -230,7 +230,7 @@ impl<'tcx> Stack { } if !item.protected() { - return Ok(()); + return interp_ok(()); } // We store tags twice, once in global.protected_tags and once in each call frame. @@ -252,10 +252,10 @@ impl<'tcx> Stack { let allowed = matches!(cause, ItemInvalidationCause::Dealloc) && matches!(protector_kind, ProtectorKind::WeakProtector); if !allowed { - return Err(dcx.protector_error(item, protector_kind).into()); + return Err(dcx.protector_error(item, protector_kind)).into(); } } - Ok(()) + interp_ok(()) } /// Test if a memory `access` using pointer tagged `tag` is granted. @@ -295,7 +295,7 @@ impl<'tcx> Stack { self.pop_items_after(first_incompatible_idx, |item| { Stack::item_invalidated(&item, global, dcx, ItemInvalidationCause::Conflict)?; dcx.log_invalidation(item.tag()); - Ok(()) + interp_ok(()) })?; } else { // On a read, *disable* all `Unique` above the granting item. This ensures U2 for read accesses. @@ -316,7 +316,7 @@ impl<'tcx> Stack { self.disable_uniques_starting_at(first_incompatible_idx, |item| { Stack::item_invalidated(&item, global, dcx, ItemInvalidationCause::Conflict)?; dcx.log_invalidation(item.tag()); - Ok(()) + interp_ok(()) })?; } @@ -345,7 +345,7 @@ impl<'tcx> Stack { } // Done. - Ok(()) + interp_ok(()) } /// Deallocate a location: Like a write access, but also there must be no @@ -367,7 +367,7 @@ impl<'tcx> Stack { Stack::item_invalidated(&item, global, dcx, ItemInvalidationCause::Dealloc)?; } - Ok(()) + interp_ok(()) } /// Derive a new pointer from one with the given tag. @@ -418,7 +418,7 @@ impl<'tcx> Stack { "reborrow: forgetting stack entirely due to SharedReadWrite reborrow from wildcard or unknown" ); self.set_unknown_bottom(global.next_ptr_tag); - return Ok(()); + return interp_ok(()); }; // SharedReadWrite can coexist with "existing loans", meaning they don't act like a write @@ -431,7 +431,7 @@ impl<'tcx> Stack { // Put the new item there. trace!("reborrow: adding item {:?}", new); self.insert(new_idx, new); - Ok(()) + interp_ok(()) } } // # Stacked Borrows Core End @@ -491,7 +491,7 @@ impl<'tcx> Stacks { f(stack, &mut dcx, &mut self.exposed_tags)?; dcx_builder = dcx.unbuild(); } - Ok(()) + interp_ok(()) } } @@ -576,7 +576,7 @@ impl Stacks { self.for_each(alloc_range(Size::ZERO, size), dcx, |stack, dcx, exposed_tags| { stack.dealloc(tag, &state, dcx, exposed_tags) })?; - Ok(()) + interp_ok(()) } } @@ -623,7 +623,7 @@ trait EvalContextPrivExt<'tcx, 'ecx>: crate::MiriInterpCxExt<'tcx> { drop(global); // don't hold that reference any longer than we have to let Some((alloc_id, base_offset, orig_tag)) = loc else { - return Ok(()) + return interp_ok(()) }; let (_size, _align, alloc_kind) = this.get_alloc_info(alloc_id); @@ -655,7 +655,7 @@ trait EvalContextPrivExt<'tcx, 'ecx>: crate::MiriInterpCxExt<'tcx> { // No stacked borrows on these allocations. } } - Ok(()) + interp_ok(()) }; if size == Size::ZERO { @@ -676,12 +676,12 @@ trait EvalContextPrivExt<'tcx, 'ecx>: crate::MiriInterpCxExt<'tcx> { { log_creation(this, Some((alloc_id, base_offset, orig_tag)))?; // Still give it the new provenance, it got retagged after all. - return Ok(Some(Provenance::Concrete { alloc_id, tag: new_tag })); + return interp_ok(Some(Provenance::Concrete { alloc_id, tag: new_tag })); } else { // This pointer doesn't come with an AllocId. :shrug: log_creation(this, None)?; // Provenance unchanged. - return Ok(place.ptr().provenance); + return interp_ok(place.ptr().provenance); } } @@ -800,12 +800,12 @@ trait EvalContextPrivExt<'tcx, 'ecx>: crate::MiriInterpCxExt<'tcx> { )?; } } - Ok(()) + interp_ok(()) })?; } } - Ok(Some(Provenance::Concrete { alloc_id, tag: new_tag })) + interp_ok(Some(Provenance::Concrete { alloc_id, tag: new_tag })) } fn sb_retag_place( @@ -832,7 +832,7 @@ trait EvalContextPrivExt<'tcx, 'ecx>: crate::MiriInterpCxExt<'tcx> { *shown = true; this.emit_diagnostic(NonHaltingDiagnostic::ExternTypeReborrow); }); - return Ok(place.clone()); + return interp_ok(place.clone()); } }; @@ -845,7 +845,7 @@ trait EvalContextPrivExt<'tcx, 'ecx>: crate::MiriInterpCxExt<'tcx> { // Adjust place. // (If the closure gets called, that means the old provenance was `Some`, and hence the new // one must also be `Some`.) - Ok(place.clone().map_provenance(|_| new_prov.unwrap())) + interp_ok(place.clone().map_provenance(|_| new_prov.unwrap())) } /// Retags an individual pointer, returning the retagged version. @@ -859,7 +859,7 @@ trait EvalContextPrivExt<'tcx, 'ecx>: crate::MiriInterpCxExt<'tcx> { let this = self.eval_context_mut(); let place = this.ref_to_mplace(val)?; let new_place = this.sb_retag_place(&place, new_perm, info)?; - Ok(ImmTy::from_immediate(new_place.to_ref(this), val.layout)) + interp_ok(ImmTy::from_immediate(new_place.to_ref(this), val.layout)) } } @@ -917,7 +917,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { in_field: self.in_field, })?; self.ecx.write_immediate(*val, place)?; - Ok(()) + interp_ok(()) } } impl<'ecx, 'tcx> ValueVisitor<'tcx, MiriMachine<'tcx>> for RetagVisitor<'ecx, 'tcx> { @@ -935,7 +935,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let new_perm = NewPermission::from_box_ty(place.layout.ty, self.kind, self.ecx); self.retag_ptr_inplace(place, new_perm)?; } - Ok(()) + interp_ok(()) } fn visit_value(&mut self, place: &PlaceTy<'tcx>) -> InterpResult<'tcx> { @@ -944,7 +944,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // This optimization is crucial for ZSTs, because they can contain way more fields // than we can ever visit. if place.layout.is_sized() && place.layout.size < self.ecx.pointer_size() { - return Ok(()); + return interp_ok(()); } // Check the type of this value to see what to do with it (retag, or recurse). @@ -983,7 +983,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } } - Ok(()) + interp_ok(()) } } } @@ -1028,7 +1028,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // No stacked borrows on these allocations. } } - Ok(()) + interp_ok(()) } fn print_stacks(&mut self, alloc_id: AllocId) -> InterpResult<'tcx> { @@ -1046,6 +1046,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } println!(" ]"); } - Ok(()) + interp_ok(()) } } diff --git a/src/tools/miri/src/borrow_tracker/stacked_borrows/stack.rs b/src/tools/miri/src/borrow_tracker/stacked_borrows/stack.rs index 6b5ef7d59c5..f024796c0a7 100644 --- a/src/tools/miri/src/borrow_tracker/stacked_borrows/stack.rs +++ b/src/tools/miri/src/borrow_tracker/stacked_borrows/stack.rs @@ -4,9 +4,9 @@ use std::ops::Range; use rustc_data_structures::fx::FxHashSet; use tracing::trace; -use crate::ProvenanceExtra; use crate::borrow_tracker::stacked_borrows::{Item, Permission}; use crate::borrow_tracker::{AccessKind, BorTag}; +use crate::{InterpResult, ProvenanceExtra, interp_ok}; /// Exactly what cache size we should use is a difficult trade-off. There will always be some /// workload which has a `BorTag` working set which exceeds the size of the cache, and ends up @@ -380,8 +380,8 @@ impl<'tcx> Stack { pub fn disable_uniques_starting_at( &mut self, disable_start: usize, - mut visitor: impl FnMut(Item) -> crate::InterpResult<'tcx>, - ) -> crate::InterpResult<'tcx> { + mut visitor: impl FnMut(Item) -> InterpResult<'tcx>, + ) -> InterpResult<'tcx> { #[cfg(feature = "stack-cache")] let unique_range = self.unique_range.clone(); #[cfg(not(feature = "stack-cache"))] @@ -420,16 +420,16 @@ impl<'tcx> Stack { #[cfg(feature = "stack-cache-consistency-check")] self.verify_cache_consistency(); - Ok(()) + interp_ok(()) } /// Produces an iterator which iterates over `range` in reverse, and when dropped removes that /// range of `Item`s from this `Stack`. - pub fn pop_items_after crate::InterpResult<'tcx>>( + pub fn pop_items_after InterpResult<'tcx>>( &mut self, start: usize, mut visitor: V, - ) -> crate::InterpResult<'tcx> { + ) -> InterpResult<'tcx> { while self.borrows.len() > start { let item = self.borrows.pop().unwrap(); visitor(item)?; @@ -474,6 +474,6 @@ impl<'tcx> Stack { #[cfg(feature = "stack-cache-consistency-check")] self.verify_cache_consistency(); - Ok(()) + interp_ok(()) } } diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/diagnostics.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/diagnostics.rs index af9ec129c69..cb840f19e3b 100644 --- a/src/tools/miri/src/borrow_tracker/tree_borrows/diagnostics.rs +++ b/src/tools/miri/src/borrow_tracker/tree_borrows/diagnostics.rs @@ -226,7 +226,7 @@ impl<'tcx> Tree { } else { eprintln!("Tag {tag:?} (to be named '{name}') not found!"); } - Ok(()) + interp_ok(()) } /// Debug helper: determines if the tree contains a tag. @@ -798,6 +798,6 @@ impl<'tcx> Tree { /* print warning message about tags not shown */ !show_unnamed, ); } - Ok(()) + interp_ok(()) } } diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs index 30e940b4439..acfb76030f5 100644 --- a/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs +++ b/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs @@ -56,7 +56,7 @@ impl<'tcx> Tree { // handle them as much as we can. let tag = match prov { ProvenanceExtra::Concrete(tag) => tag, - ProvenanceExtra::Wildcard => return Ok(()), + ProvenanceExtra::Wildcard => return interp_ok(()), }; let global = machine.borrow_tracker.as_ref().unwrap(); let span = machine.current_span(); @@ -81,7 +81,7 @@ impl<'tcx> Tree { // handle them as much as we can. let tag = match prov { ProvenanceExtra::Concrete(tag) => tag, - ProvenanceExtra::Wildcard => return Ok(()), + ProvenanceExtra::Wildcard => return interp_ok(()), }; let global = machine.borrow_tracker.as_ref().unwrap(); let span = machine.current_span(); @@ -213,7 +213,7 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> { )); } drop(global); // don't hold that reference any longer than we have to - Ok(()) + interp_ok(()) }; trace!("Reborrow of size {:?}", ptr_size); @@ -235,13 +235,13 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> { ); log_creation(this, None)?; // Keep original provenance. - return Ok(place.ptr().provenance); + return interp_ok(place.ptr().provenance); } }; log_creation(this, Some((alloc_id, base_offset, parent_prov)))?; let orig_tag = match parent_prov { - ProvenanceExtra::Wildcard => return Ok(place.ptr().provenance), // TODO: handle wildcard pointers + ProvenanceExtra::Wildcard => return interp_ok(place.ptr().provenance), // TODO: handle wildcard pointers ProvenanceExtra::Concrete(tag) => tag, }; @@ -279,7 +279,7 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> { assert_eq!(ptr_size, Size::ZERO); // we did the deref check above, size has to be 0 here // There's not actually any bytes here where accesses could even be tracked. // Just produce the new provenance, nothing else to do. - return Ok(Some(Provenance::Concrete { alloc_id, tag: new_tag })); + return interp_ok(Some(Provenance::Concrete { alloc_id, tag: new_tag })); } let span = this.machine.current_span(); @@ -312,7 +312,7 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } } - Ok(Some(Provenance::Concrete { alloc_id, tag: new_tag })) + interp_ok(Some(Provenance::Concrete { alloc_id, tag: new_tag })) } fn tb_retag_place( @@ -350,7 +350,7 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Adjust place. // (If the closure gets called, that means the old provenance was `Some`, and hence the new // one must also be `Some`.) - Ok(place.clone().map_provenance(|_| new_prov.unwrap())) + interp_ok(place.clone().map_provenance(|_| new_prov.unwrap())) } /// Retags an individual pointer, returning the retagged version. @@ -362,7 +362,7 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let this = self.eval_context_mut(); let place = this.ref_to_mplace(val)?; let new_place = this.tb_retag_place(&place, new_perm)?; - Ok(ImmTy::from_immediate(new_place.to_ref(this), val.layout)) + interp_ok(ImmTy::from_immediate(new_place.to_ref(this), val.layout)) } } @@ -384,7 +384,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { if let Some(new_perm) = new_perm { this.tb_retag_reference(val, new_perm) } else { - Ok(val.clone()) + interp_ok(val.clone()) } } @@ -421,7 +421,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let val = self.ecx.tb_retag_reference(&val, new_perm)?; self.ecx.write_immediate(*val, place)?; } - Ok(()) + interp_ok(()) } } impl<'ecx, 'tcx> ValueVisitor<'tcx, MiriMachine<'tcx>> for RetagVisitor<'ecx, 'tcx> { @@ -446,7 +446,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { ); self.retag_ptr_inplace(place, new_perm)?; } - Ok(()) + interp_ok(()) } fn visit_value(&mut self, place: &PlaceTy<'tcx>) -> InterpResult<'tcx> { @@ -455,7 +455,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // This optimization is crucial for ZSTs, because they can contain way more fields // than we can ever visit. if place.layout.is_sized() && place.layout.size < self.ecx.pointer_size() { - return Ok(()); + return interp_ok(()); } // Check the type of this value to see what to do with it (retag, or recurse). @@ -503,7 +503,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } } } - Ok(()) + interp_ok(()) } } } @@ -549,7 +549,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // No tree borrows on these allocations. } } - Ok(()) + interp_ok(()) } /// Display the tree. @@ -575,7 +575,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { Some(Provenance::Concrete { tag, alloc_id }) => (tag, alloc_id), _ => { eprintln!("Can't give the name {name} to Wildcard pointer"); - return Ok(()); + return interp_ok(()); } }; let alloc_extra = this.get_alloc_extra(alloc_id)?; @@ -605,5 +605,5 @@ fn inner_ptr_of_unique<'tcx>( assert_eq!(nonnull.layout.fields.count(), 1, "NonNull must have exactly 1 field"); let ptr = ecx.project_field(&nonnull, 0)?; // Finally a plain `*mut` - Ok(ptr) + interp_ok(ptr) } diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs index 9fe134ed34b..410f4a58ac5 100644 --- a/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs +++ b/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs @@ -637,7 +637,7 @@ impl<'tcx> Tree { { perms.insert(idx, perm); } - Ok(()) + interp_ok(()) } /// Deallocation requires @@ -688,7 +688,7 @@ impl<'tcx> Tree { }, )?; } - Ok(()) + interp_ok(()) } /// Map the per-node and per-location `LocationState::perform_access` @@ -827,7 +827,7 @@ impl<'tcx> Tree { } } } - Ok(()) + interp_ok(()) } } diff --git a/src/tools/miri/src/concurrency/data_race.rs b/src/tools/miri/src/concurrency/data_race.rs index 5910be22a69..82c4f6d3007 100644 --- a/src/tools/miri/src/concurrency/data_race.rs +++ b/src/tools/miri/src/concurrency/data_race.rs @@ -624,7 +624,7 @@ pub trait EvalContextExt<'tcx>: MiriInterpCxExt<'tcx> { let buffered_scalar = this.buffered_atomic_read(place, atomic, scalar, || { this.validate_atomic_load(place, atomic) })?; - Ok(buffered_scalar.ok_or_else(|| err_ub!(InvalidUninitBytes(None)))?) + interp_ok(buffered_scalar.ok_or_else(|| err_ub!(InvalidUninitBytes(None)))?) } /// Perform an atomic write operation at the memory location. @@ -641,7 +641,7 @@ pub trait EvalContextExt<'tcx>: MiriInterpCxExt<'tcx> { // The program didn't actually do a read, so suppress the memory access hooks. // This is also a very special exception where we just ignore an error -- if this read // was UB e.g. because the memory is uninitialized, we don't want to know! - let old_val = this.run_for_validation(|this| this.read_scalar(dest)).discard_interp_err(); + let old_val = this.run_for_validation(|this| this.read_scalar(dest)).discard_err(); this.allow_data_races_mut(move |this| this.write_scalar(val, dest))?; this.validate_atomic_store(dest, atomic)?; this.buffered_atomic_write(val, dest, atomic, old_val) @@ -668,7 +668,7 @@ pub trait EvalContextExt<'tcx>: MiriInterpCxExt<'tcx> { this.validate_atomic_rmw(place, atomic)?; this.buffered_atomic_rmw(val.to_scalar(), place, atomic, old.to_scalar())?; - Ok(old) + interp_ok(old) } /// Perform an atomic exchange with a memory place and a new @@ -688,7 +688,7 @@ pub trait EvalContextExt<'tcx>: MiriInterpCxExt<'tcx> { this.validate_atomic_rmw(place, atomic)?; this.buffered_atomic_rmw(new, place, atomic, old)?; - Ok(old) + interp_ok(old) } /// Perform an conditional atomic exchange with a memory place and a new @@ -720,7 +720,7 @@ pub trait EvalContextExt<'tcx>: MiriInterpCxExt<'tcx> { this.buffered_atomic_rmw(new_val.to_scalar(), place, atomic, old.to_scalar())?; // Return the old value. - Ok(old) + interp_ok(old) } /// Perform an atomic compare and exchange at a given memory location. @@ -777,7 +777,7 @@ pub trait EvalContextExt<'tcx>: MiriInterpCxExt<'tcx> { } // Return the old value. - Ok(res) + interp_ok(res) } /// Update the data-race detector for an atomic fence on the current thread. @@ -809,11 +809,11 @@ pub trait EvalContextExt<'tcx>: MiriInterpCxExt<'tcx> { } // Increment timestamp in case of release semantics. - Ok(atomic != AtomicFenceOrd::Acquire) + interp_ok(atomic != AtomicFenceOrd::Acquire) }, ) } else { - Ok(()) + interp_ok(()) } } @@ -1047,7 +1047,7 @@ impl VClockAlloc { let current_span = machine.current_span(); let global = machine.data_race.as_ref().unwrap(); if !global.race_detecting() { - return Ok(()); + return interp_ok(()); } let (index, mut thread_clocks) = global.active_thread_state_mut(&machine.threads); let mut alloc_ranges = self.alloc_ranges.borrow_mut(); @@ -1070,7 +1070,7 @@ impl VClockAlloc { ); } } - Ok(()) + interp_ok(()) } /// Detect data-races for an unsynchronized write operation. It will not perform @@ -1089,7 +1089,7 @@ impl VClockAlloc { let current_span = machine.current_span(); let global = machine.data_race.as_mut().unwrap(); if !global.race_detecting() { - return Ok(()); + return interp_ok(()); } let (index, mut thread_clocks) = global.active_thread_state_mut(&machine.threads); for (mem_clocks_range, mem_clocks) in @@ -1111,7 +1111,7 @@ impl VClockAlloc { ); } } - Ok(()) + interp_ok(()) } } @@ -1307,7 +1307,7 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> { } } } - Ok(()) + interp_ok(()) } /// Update the data-race detector for an atomic read occurring at the @@ -1399,9 +1399,9 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> { ) -> InterpResult<'tcx> { let this = self.eval_context_ref(); assert!(access.is_atomic()); - let Some(data_race) = &this.machine.data_race else { return Ok(()) }; + let Some(data_race) = &this.machine.data_race else { return interp_ok(()) }; if !data_race.race_detecting() { - return Ok(()); + return interp_ok(()); } let size = place.layout.size; let (alloc_id, base_offset, _prov) = this.ptr_get_alloc_id(place.ptr(), 0)?; @@ -1444,7 +1444,7 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> { } // This conservatively assumes all operations have release semantics - Ok(true) + interp_ok(true) }, )?; @@ -1460,7 +1460,7 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> { } } - Ok(()) + interp_ok(()) } } @@ -1757,7 +1757,7 @@ impl GlobalState { clocks.increment_clock(index, current_span); } } - Ok(()) + interp_ok(()) } /// Internal utility to identify a thread stored internally diff --git a/src/tools/miri/src/concurrency/init_once.rs b/src/tools/miri/src/concurrency/init_once.rs index 9c2c6ae1330..8985135f4e8 100644 --- a/src/tools/miri/src/concurrency/init_once.rs +++ b/src/tools/miri/src/concurrency/init_once.rs @@ -37,9 +37,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { lock, offset, |ecx| &mut ecx.machine.sync.init_onces, - |_| Ok(Default::default()), + |_| interp_ok(Default::default()), )? - .ok_or_else(|| err_ub_format!("init_once has invalid ID").into()) + .ok_or_else(|| err_ub_format!("init_once has invalid ID")).into() } #[inline] @@ -101,7 +101,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.unblock_thread(waiter, BlockReason::InitOnce(id))?; } - Ok(()) + interp_ok(()) } #[inline] @@ -126,7 +126,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.unblock_thread(waiter, BlockReason::InitOnce(id))?; } - Ok(()) + interp_ok(()) } /// Synchronize with the previous completion of an InitOnce. diff --git a/src/tools/miri/src/concurrency/sync.rs b/src/tools/miri/src/concurrency/sync.rs index 7fe67e5c672..3b57af641b5 100644 --- a/src/tools/miri/src/concurrency/sync.rs +++ b/src/tools/miri/src/concurrency/sync.rs @@ -206,7 +206,7 @@ pub(super) trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { )? .to_scalar_pair(); - Ok(if success.to_bool().expect("compare_exchange's second return value is a bool") { + interp_ok(if success.to_bool().expect("compare_exchange's second return value is a bool") { // We set the in-memory ID to `next_index`, now also create this object in the machine // state. let obj = create_obj(this)?; @@ -247,7 +247,7 @@ pub(super) trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { let new_index = get_objs(this).push(obj); this.write_scalar(Scalar::from_u32(new_index.to_u32()), &id_place)?; - Ok(new_index) + interp_ok(new_index) } fn condvar_reacquire_mutex( @@ -266,7 +266,7 @@ pub(super) trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { // Don't forget to write the return value. this.write_scalar(retval, &dest)?; } - Ok(()) + interp_ok(()) } } @@ -307,7 +307,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { |ecx| &mut ecx.machine.sync.mutexes, |ecx| initialize_data(ecx).map(|data| Mutex { data, ..Default::default() }), )? - .ok_or_else(|| err_ub_format!("mutex has invalid ID").into()) + .ok_or_else(|| err_ub_format!("mutex has invalid ID")).into() } /// Retrieve the additional data stored for a mutex. @@ -334,7 +334,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { |ecx| &mut ecx.machine.sync.rwlocks, |ecx| initialize_data(ecx).map(|data| RwLock { data, ..Default::default() }), )? - .ok_or_else(|| err_ub_format!("rwlock has invalid ID").into()) + .ok_or_else(|| err_ub_format!("rwlock has invalid ID")).into() } /// Retrieve the additional data stored for a rwlock. @@ -375,7 +375,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { |ecx| &mut ecx.machine.sync.condvars, |ecx| initialize_data(ecx).map(|data| Condvar { data, ..Default::default() }), )? - .ok_or_else(|| err_ub_format!("condvar has invalid ID").into()) + .ok_or_else(|| err_ub_format!("condvar has invalid ID")).into() } /// Retrieve the additional data stored for a condvar. @@ -428,11 +428,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn mutex_unlock(&mut self, id: MutexId) -> InterpResult<'tcx, Option> { let this = self.eval_context_mut(); let mutex = &mut this.machine.sync.mutexes[id]; - Ok(if let Some(current_owner) = mutex.owner { + interp_ok(if let Some(current_owner) = mutex.owner { // Mutex is locked. if current_owner != this.machine.threads.active_thread() { // Only the owner can unlock the mutex. - return Ok(None); + return interp_ok(None); } let old_lock_count = mutex.lock_count; mutex.lock_count = old_lock_count.strict_sub(1); @@ -484,7 +484,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_scalar(retval, &dest)?; } - Ok(()) + interp_ok(()) } ), ); @@ -546,7 +546,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { trace!("rwlock_reader_unlock: {:?} held one less time by {:?}", id, thread); } } - Entry::Vacant(_) => return Ok(false), // we did not even own this lock + Entry::Vacant(_) => return interp_ok(false), // we did not even own this lock } if let Some(data_race) = &this.machine.data_race { // Add this to the shared-release clock of all concurrent readers. @@ -565,7 +565,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.unblock_thread(writer, BlockReason::RwLock(id))?; } } - Ok(true) + interp_ok(true) } /// Put the reader in the queue waiting for the lock and block it. @@ -593,7 +593,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { @unblock = |this| { this.rwlock_reader_lock(id); this.write_scalar(retval, &dest)?; - Ok(()) + interp_ok(()) } ), ); @@ -620,10 +620,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let this = self.eval_context_mut(); let thread = this.active_thread(); let rwlock = &mut this.machine.sync.rwlocks[id]; - Ok(if let Some(current_writer) = rwlock.writer { + interp_ok(if let Some(current_writer) = rwlock.writer { if current_writer != thread { // Only the owner can unlock the rwlock. - return Ok(false); + return interp_ok(false); } rwlock.writer = None; trace!("rwlock_writer_unlock: {:?} unlocked by {:?}", id, thread); @@ -676,7 +676,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { @unblock = |this| { this.rwlock_writer_lock(id); this.write_scalar(retval, &dest)?; - Ok(()) + interp_ok(()) } ), ); @@ -749,7 +749,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } ), ); - Ok(()) + interp_ok(()) } /// Wake up some thread (if there is any) sleeping on the conditional @@ -764,10 +764,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { condvar.clock.clone_from(&*data_race.release_clock(&this.machine.threads)); } let Some(waiter) = condvar.waiters.pop_front() else { - return Ok(false); + return interp_ok(false); }; this.unblock_thread(waiter, BlockReason::Condvar(id))?; - Ok(true) + interp_ok(true) } /// Wait for the futex to be signaled, or a timeout. @@ -808,7 +808,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } // Write the return value. this.write_scalar(retval_succ, &dest)?; - Ok(()) + interp_ok(()) } @timeout = |this| { // Remove the waiter from the futex. @@ -818,7 +818,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Set errno and write return value. this.set_last_error(errno_timeout)?; this.write_scalar(retval_timeout, &dest)?; - Ok(()) + interp_ok(()) } ), ); @@ -828,7 +828,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn futex_wake(&mut self, addr: u64, bitset: u32) -> InterpResult<'tcx, bool> { let this = self.eval_context_mut(); let Some(futex) = this.machine.sync.futexes.get_mut(&addr) else { - return Ok(false); + return interp_ok(false); }; let data_race = &this.machine.data_race; @@ -839,10 +839,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Wake up the first thread in the queue that matches any of the bits in the bitset. let Some(i) = futex.waiters.iter().position(|w| w.bitset & bitset != 0) else { - return Ok(false); + return interp_ok(false); }; let waiter = futex.waiters.remove(i).unwrap(); this.unblock_thread(waiter.thread, BlockReason::Futex { addr })?; - Ok(true) + interp_ok(true) } } diff --git a/src/tools/miri/src/concurrency/thread.rs b/src/tools/miri/src/concurrency/thread.rs index f6b453efcbe..dcae85109a5 100644 --- a/src/tools/miri/src/concurrency/thread.rs +++ b/src/tools/miri/src/concurrency/thread.rs @@ -622,7 +622,7 @@ impl<'tcx> ThreadManager<'tcx> { } self.threads[id].join_status = ThreadJoinStatus::Detached; - Ok(()) + interp_ok(()) } /// Mark that the active thread tries to join the thread with `joined_thread_id`. @@ -657,7 +657,7 @@ impl<'tcx> ThreadManager<'tcx> { if let Some(data_race) = &mut this.machine.data_race { data_race.thread_joined(&this.machine.threads, joined_thread_id); } - Ok(()) + interp_ok(()) } ), ); @@ -667,7 +667,7 @@ impl<'tcx> ThreadManager<'tcx> { data_race.thread_joined(self, joined_thread_id); } } - Ok(()) + interp_ok(()) } /// Mark that the active thread tries to exclusively join the thread with `joined_thread_id`. @@ -754,7 +754,7 @@ impl<'tcx> ThreadManager<'tcx> { // This thread and the program can keep going. if self.threads[self.active_thread].state.is_enabled() && !self.yield_active_thread { // The currently active thread is still enabled, just continue with it. - return Ok(SchedulingAction::ExecuteStep); + return interp_ok(SchedulingAction::ExecuteStep); } // The active thread yielded or got terminated. Let's see if there are any timeouts to take // care of. We do this *before* running any other thread, to ensure that timeouts "in the @@ -764,7 +764,7 @@ impl<'tcx> ThreadManager<'tcx> { // let potential_sleep_time = self.next_callback_wait_time(clock); if potential_sleep_time == Some(Duration::ZERO) { - return Ok(SchedulingAction::ExecuteTimeoutCallback); + return interp_ok(SchedulingAction::ExecuteTimeoutCallback); } // No callbacks immediately scheduled, pick a regular thread to execute. // The active thread blocked or yielded. So we go search for another enabled thread. @@ -793,7 +793,7 @@ impl<'tcx> ThreadManager<'tcx> { } self.yield_active_thread = false; if self.threads[self.active_thread].state.is_enabled() { - return Ok(SchedulingAction::ExecuteStep); + return interp_ok(SchedulingAction::ExecuteStep); } // We have not found a thread to execute. if self.threads.iter().all(|thread| thread.state.is_terminated()) { @@ -802,7 +802,7 @@ impl<'tcx> ThreadManager<'tcx> { // All threads are currently blocked, but we have unexecuted // timeout_callbacks, which may unblock some of the threads. Hence, // sleep until the first callback. - Ok(SchedulingAction::Sleep(sleep_time)) + interp_ok(SchedulingAction::Sleep(sleep_time)) } else { throw_machine_stop!(TerminationInfo::Deadlock); } @@ -848,7 +848,7 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> { // https://github.com/rust-lang/miri/issues/1763). In this case, // just do nothing, which effectively just returns to the // scheduler. - Ok(()) + interp_ok(()) } #[inline] @@ -861,7 +861,7 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> { .expect("`on_stack_empty` not set up, or already running"); let res = callback(this)?; this.active_thread_mut().on_stack_empty = Some(callback); - Ok(res) + interp_ok(res) } } @@ -879,7 +879,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { if let Some(old_alloc) = this.machine.threads.get_thread_local_alloc_id(def_id) { // We already have a thread-specific allocation id for this // thread-local static. - Ok(old_alloc) + interp_ok(old_alloc) } else { // We need to allocate a thread-specific allocation id for this // thread-local static. @@ -892,7 +892,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let mut alloc = alloc.inner().adjust_from_tcx( &this.tcx, |bytes, align| { - Ok(MiriAllocBytes::from_bytes(std::borrow::Cow::Borrowed(bytes), align)) + interp_ok(MiriAllocBytes::from_bytes(std::borrow::Cow::Borrowed(bytes), align)) }, |ptr| this.global_root_pointer(ptr), )?; @@ -901,7 +901,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Create a fresh allocation with this content. let ptr = this.insert_allocation(alloc, MiriMemoryKind::Tls.into())?; this.machine.threads.set_thread_local_alloc(def_id, ptr); - Ok(ptr) + interp_ok(ptr) } } @@ -964,7 +964,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Restore the old active thread frame. this.machine.threads.set_active_thread_id(old_thread_id); - Ok(new_thread_id) + interp_ok(new_thread_id) } /// Handles thread termination of the active thread: wakes up threads joining on this one, @@ -1022,7 +1022,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.unblock_thread(thread, unblock_reason)?; } - Ok(()) + interp_ok(()) } /// Block the current thread, with an optional timeout. @@ -1078,7 +1078,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let old_thread = this.machine.threads.set_active_thread_id(thread); callback.unblock(this)?; this.machine.threads.set_active_thread_id(old_thread); - Ok(()) + interp_ok(()) } #[inline] @@ -1095,7 +1095,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn join_thread(&mut self, joined_thread_id: ThreadId) -> InterpResult<'tcx> { let this = self.eval_context_mut(); this.machine.threads.join_thread(joined_thread_id, this.machine.data_race.as_mut())?; - Ok(()) + interp_ok(()) } #[inline] @@ -1104,7 +1104,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.machine .threads .join_thread_exclusive(joined_thread_id, this.machine.data_race.as_mut())?; - Ok(()) + interp_ok(()) } #[inline] diff --git a/src/tools/miri/src/concurrency/weak_memory.rs b/src/tools/miri/src/concurrency/weak_memory.rs index 307695436c6..800c301a821 100644 --- a/src/tools/miri/src/concurrency/weak_memory.rs +++ b/src/tools/miri/src/concurrency/weak_memory.rs @@ -195,10 +195,10 @@ impl StoreBufferAlloc { AccessType::PerfectlyOverlapping(pos) => pos, // If there is nothing here yet, that means there wasn't an atomic write yet so // we can't return anything outdated. - _ => return Ok(None), + _ => return interp_ok(None), }; let store_buffer = Ref::map(self.store_buffers.borrow(), |buffer| &buffer[pos]); - Ok(Some(store_buffer)) + interp_ok(Some(store_buffer)) } /// Gets a mutable store buffer associated with an atomic object in this allocation, @@ -223,7 +223,7 @@ impl StoreBufferAlloc { pos_range.start } }; - Ok(&mut buffers[pos]) + interp_ok(&mut buffers[pos]) } } @@ -284,7 +284,7 @@ impl<'tcx> StoreBuffer { let (index, clocks) = global.active_thread_state(thread_mgr); let loaded = store_elem.load_impl(index, &clocks, is_seqcst); - Ok((loaded, recency)) + interp_ok((loaded, recency)) } fn buffered_write( @@ -297,7 +297,7 @@ impl<'tcx> StoreBuffer { let (index, clocks) = global.active_thread_state(thread_mgr); self.store_impl(val, index, &clocks.clock, is_seqcst); - Ok(()) + interp_ok(()) } #[allow(clippy::if_same_then_else, clippy::needless_bool)] @@ -470,7 +470,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { buffer.read_from_last_store(global, threads, atomic == AtomicRwOrd::SeqCst); buffer.buffered_write(new_val, global, threads, atomic == AtomicRwOrd::SeqCst)?; } - Ok(()) + interp_ok(()) } fn buffered_atomic_read( @@ -508,14 +508,14 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { }); } - return Ok(loaded); + return interp_ok(loaded); } } } // Race detector or weak memory disabled, simply read the latest value validate()?; - Ok(Some(latest_in_mo)) + interp_ok(Some(latest_in_mo)) } /// Add the given write to the store buffer. (Does not change machine memory.) @@ -546,7 +546,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } // Caller should've written to dest with the vanilla scalar write, we do nothing here - Ok(()) + interp_ok(()) } /// Caller should never need to consult the store buffer for the latest value. @@ -570,7 +570,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { alloc_buffers.get_store_buffer(alloc_range(base_offset, size))? else { // No store buffer, nothing to do. - return Ok(()); + return interp_ok(()); }; buffer.read_from_last_store( global, @@ -579,6 +579,6 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { ); } } - Ok(()) + interp_ok(()) } } diff --git a/src/tools/miri/src/diagnostics.rs b/src/tools/miri/src/diagnostics.rs index ee087ece9d8..5b1bad28c07 100644 --- a/src/tools/miri/src/diagnostics.rs +++ b/src/tools/miri/src/diagnostics.rs @@ -223,10 +223,7 @@ pub fn report_error<'tcx>( let info = info.downcast_ref::().expect("invalid MachineStop payload"); use TerminationInfo::*; let title = match info { - &Exit { code, leak_check } => { - e.discard_interp_err(); - return Some((code, leak_check)); - } + &Exit { code, leak_check } => return Some((code, leak_check)), Abort(_) => Some("abnormal termination"), UnsupportedInIsolation(_) | Int2PtrWithStrictProvenance | UnsupportedForeignItem(_) => Some("unsupported operation"), @@ -378,7 +375,6 @@ pub fn report_error<'tcx>( InvalidProgramInfo::AlreadyReported(_) ) => { // This got already reported. No point in reporting it again. - e.discard_interp_err(); return None; } _ => diff --git a/src/tools/miri/src/eval.rs b/src/tools/miri/src/eval.rs index 3739d46bd60..ece76e581f2 100644 --- a/src/tools/miri/src/eval.rs +++ b/src/tools/miri/src/eval.rs @@ -259,7 +259,7 @@ impl<'tcx> MainThreadState<'tcx> { throw_machine_stop!(TerminationInfo::Exit { code: exit_code, leak_check: true }); } } - Ok(Poll::Pending) + interp_ok(Poll::Pending) } } @@ -420,7 +420,7 @@ pub fn create_ecx<'tcx>( } } - Ok(ecx) + interp_ok(ecx) } /// Evaluates the entry function specified by `entry_id`. @@ -436,7 +436,7 @@ pub fn eval_entry<'tcx>( // Copy setting before we move `config`. let ignore_leaks = config.ignore_leaks; - let mut ecx = match create_ecx(tcx, entry_id, entry_type, &config) { + let mut ecx = match create_ecx(tcx, entry_id, entry_type, &config).report_err() { Ok(v) => v, Err(err) => { let (kind, backtrace) = err.into_parts(); @@ -453,7 +453,7 @@ pub fn eval_entry<'tcx>( panic::resume_unwind(panic_payload) }); // `Ok` can never happen. - let Err(res) = res; + let Err(err) = res.report_err(); // Machine cleanup. Only do this if all threads have terminated; threads that are still running // might cause Stacked Borrows errors (https://github.com/rust-lang/miri/issues/2396). @@ -466,7 +466,7 @@ pub fn eval_entry<'tcx>( } // Process the result. - let (return_code, leak_check) = report_error(&ecx, res)?; + let (return_code, leak_check) = report_error(&ecx, err)?; if leak_check && !ignore_leaks { // Check for thread leaks. if !ecx.have_all_terminated() { diff --git a/src/tools/miri/src/helpers.rs b/src/tools/miri/src/helpers.rs index 0cd6ba69aac..70ebca0f329 100644 --- a/src/tools/miri/src/helpers.rs +++ b/src/tools/miri/src/helpers.rs @@ -228,7 +228,7 @@ pub fn iter_exported_symbols<'tcx>( } } } - Ok(()) + interp_ok(()) } /// Convert a softfloat type to its corresponding hostfloat type. @@ -431,7 +431,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let field = this.project_field(dest, idx)?; this.write_int(val, &field)?; } - Ok(()) + interp_ok(()) } /// Write the given fields of the given place. @@ -445,7 +445,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let field = this.project_field_named(dest, name)?; this.write_int(val, &field)?; } - Ok(()) + interp_ok(()) } /// Write a 0 of the appropriate size to `dest`. @@ -455,7 +455,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { /// Test if this pointer equals 0. fn ptr_is_null(&self, ptr: Pointer) -> InterpResult<'tcx, bool> { - Ok(ptr.addr().bytes() == 0) + interp_ok(ptr.addr().bytes() == 0) } /// Generate some random bytes, and write them to `dest`. @@ -466,7 +466,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // any additional checks - it's okay if the pointer is invalid, // since we wouldn't actually be writing to it. if len == 0 { - return Ok(()); + return interp_ok(()); } let this = self.eval_context_mut(); @@ -571,7 +571,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } cur_addr += unsafe_cell_size; // Done - Ok(()) + interp_ok(()) }; // Run a visitor { @@ -589,7 +589,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { if unsafe_cell_size != Size::ZERO { unsafe_cell_action(&place.ptr(), unsafe_cell_size) } else { - Ok(()) + interp_ok(()) } }, }; @@ -599,7 +599,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // So pretend there is a 0-sized `UnsafeCell` at the end. unsafe_cell_action(&place.ptr().wrapping_offset(size, this), Size::ZERO)?; // Done! - return Ok(()); + return interp_ok(()); /// Visiting the memory covered by a `MemPlace`, being aware of /// whether we are inside an `UnsafeCell` or not. @@ -642,7 +642,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { (self.unsafe_cell_action)(v) } else if self.ecx.type_is_freeze(v.layout.ty) { // This is `Freeze`, there cannot be an `UnsafeCell` - Ok(()) + interp_ok(()) } else if matches!(v.layout.fields, FieldsShape::Union(..)) { // A (non-frozen) union. We fall back to whatever the type says. (self.unsafe_cell_action)(v) @@ -691,7 +691,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { if !self.eval_context_ref().machine.communicate() { self.reject_in_isolation(name, RejectOpWith::Abort)?; } - Ok(()) + interp_ok(()) } /// Helper function used inside the shims of foreign functions which reject the op @@ -713,13 +713,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { .dcx() .warn(format!("{op_name} was made to return an error due to isolation")); } - Ok(()) + interp_ok(()) } RejectOpWith::Warning => { this.emit_diagnostic(NonHaltingDiagnostic::RejectedIsolatedOp(op_name.to_string())); - Ok(()) + interp_ok(()) } - RejectOpWith::NoWarning => Ok(()), // no warning + RejectOpWith::NoWarning => interp_ok(()), // no warning } } @@ -750,14 +750,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn last_error_place(&mut self) -> InterpResult<'tcx, MPlaceTy<'tcx>> { let this = self.eval_context_mut(); if let Some(errno_place) = this.active_thread_ref().last_error.as_ref() { - Ok(errno_place.clone()) + interp_ok(errno_place.clone()) } else { // Allocate new place, set initial value to 0. let errno_layout = this.machine.layouts.u32; let errno_place = this.allocate(errno_layout, MiriMemoryKind::Machine.into())?; this.write_scalar(Scalar::from_u32(0), &errno_place)?; this.active_thread_mut().last_error = Some(errno_place.clone()); - Ok(errno_place) + interp_ok(errno_place) } } @@ -783,14 +783,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { if target.families.iter().any(|f| f == "unix") { for &(name, kind) in UNIX_IO_ERROR_TABLE { if err.kind() == kind { - return Ok(this.eval_libc(name)); + return interp_ok(this.eval_libc(name)); } } throw_unsup_format!("unsupported io error: {err}") } else if target.families.iter().any(|f| f == "windows") { for &(name, kind) in WINDOWS_IO_ERROR_TABLE { if err.kind() == kind { - return Ok(this.eval_windows("c", name)); + return interp_ok(this.eval_windows("c", name)); } } throw_unsup_format!("unsupported io error: {err}"); @@ -814,18 +814,18 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let errnum = errnum.to_i32()?; for &(name, kind) in UNIX_IO_ERROR_TABLE { if errnum == this.eval_libc_i32(name) { - return Ok(Some(kind)); + return interp_ok(Some(kind)); } } - return Ok(None); + return interp_ok(None); } else if target.families.iter().any(|f| f == "windows") { let errnum = errnum.to_u32()?; for &(name, kind) in WINDOWS_IO_ERROR_TABLE { if errnum == this.eval_windows("c", name).to_u32()? { - return Ok(Some(kind)); + return interp_ok(Some(kind)); } } - return Ok(None); + return interp_ok(None); } else { throw_unsup_format!( "converting errnum into io::Error is unsupported for OS {}", @@ -839,8 +839,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { self.set_last_error(self.io_error_to_errnum(err)?) } - /// Helper function that consumes an `std::io::Result` and returns an - /// `InterpResult<'tcx,T>::Ok` instead. In case the result is an error, this function returns + /// Helper function that consumes a `std::io::Result` and returns a + /// `InterpResult<'tcx, T>` instead. In case the result is an error, this function returns /// `Ok(-1)` and sets the last OS error accordingly. /// /// This function uses `T: From` instead of `i32` directly because some IO related @@ -850,10 +850,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { result: std::io::Result, ) -> InterpResult<'tcx, T> { match result { - Ok(ok) => Ok(ok), + Ok(ok) => interp_ok(ok), Err(e) => { self.eval_context_mut().set_last_error_from_io_error(e)?; - Ok((-1).into()) + interp_ok((-1).into()) } } } @@ -866,7 +866,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { ) -> InterpResult<'tcx, MPlaceTy<'tcx>> { let this = self.eval_context_ref(); let ptr = this.read_pointer(op)?; - Ok(this.ptr_to_mplace(ptr, layout)) + interp_ok(this.ptr_to_mplace(ptr, layout)) } /// Calculates the MPlaceTy given the offset and layout of an access on an operand @@ -884,7 +884,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Ensure that the access is within bounds. assert!(base_layout.size >= offset + value_layout.size); let value_place = op_place.offset(offset, value_layout, this)?; - Ok(value_place) + interp_ok(value_place) } fn deref_pointer_and_read( @@ -924,7 +924,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let nanoseconds_scalar = this.read_scalar(&nanoseconds_place)?; let nanoseconds = nanoseconds_scalar.to_target_isize(this)?; - Ok(try { + interp_ok(try { // tv_sec must be non-negative. let seconds: u64 = seconds.try_into().ok()?; // tv_nsec must be non-negative. @@ -947,7 +947,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let ptr = ptr.to_pointer(this)?; let len = len.to_target_usize(this)?; let bytes = this.read_bytes_ptr_strip_provenance(ptr, Size::from_bytes(len))?; - Ok(bytes) + interp_ok(bytes) } /// Read a sequence of bytes until the first null terminator. @@ -992,11 +992,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let string_length = u64::try_from(c_str.len()).unwrap(); let string_length = string_length.strict_add(1); if size < string_length { - return Ok((false, string_length)); + return interp_ok((false, string_length)); } self.eval_context_mut() .write_bytes_ptr(ptr, c_str.iter().copied().chain(iter::once(0u8)))?; - Ok((true, string_length)) + interp_ok((true, string_length)) } /// Helper function to read a sequence of unsigned integers of the given size and alignment @@ -1031,7 +1031,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } } - Ok(wchars) + interp_ok(wchars) } /// Read a sequence of u16 until the first null terminator. @@ -1056,7 +1056,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let string_length = u64::try_from(wide_str.len()).unwrap(); let string_length = string_length.strict_add(1); if size < string_length { - return Ok((false, string_length)); + return interp_ok((false, string_length)); } // Store the UTF-16 string. @@ -1068,7 +1068,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let offset = u64::try_from(offset).unwrap(); alloc.write_scalar(alloc_range(size2 * offset, size2), Scalar::from_u16(wchar))?; } - Ok((true, string_length)) + interp_ok((true, string_length)) } /// Read a sequence of wchar_t until the first null terminator. @@ -1093,7 +1093,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { abi.name() ) } - Ok(()) + interp_ok(()) } fn frame_in_std(&self) -> bool { @@ -1128,7 +1128,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // message is slightly different here to make automated analysis easier let error_msg = format!("unsupported Miri functionality: {error_msg}"); this.start_panic(error_msg.as_ref(), mir::UnwindAction::Continue)?; - Ok(()) + interp_ok(()) } else { throw_machine_stop!(TerminationInfo::UnsupportedForeignItem(error_msg)); } @@ -1148,7 +1148,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // compiler-builtins when running other crates, but Miri can still be run on // compiler-builtins itself (or any crate that uses it as a normal dependency) if self.eval_context_ref().tcx.is_compiler_builtins(instance.def_id().krate) { - return Ok(()); + return interp_ok(()); } throw_machine_stop!(TerminationInfo::SymbolShimClashing { @@ -1156,7 +1156,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { span: body.span.data(), }) } - Ok(()) + interp_ok(()) } fn check_shim<'a, const N: usize>( @@ -1242,11 +1242,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { ) { // Floating point value is NaN (flagged with INVALID_OP) or outside the range // of values of the integer type (flagged with OVERFLOW or UNDERFLOW). - Ok(None) + interp_ok(None) } else { // Floating point value can be represented by the integer type after rounding. // The INEXACT flag is ignored on purpose to allow rounding. - Ok(Some(ImmTy::from_scalar(val, cast_to))) + interp_ok(Some(ImmTy::from_scalar(val, cast_to))) } } @@ -1283,7 +1283,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { "attempted to call intrinsic `{intrinsic}` that requires missing target feature {target_feature}" ); } - Ok(()) + interp_ok(()) } /// Lookup an array of immediates stored as a linker section of name `name`. @@ -1296,7 +1296,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { iter_exported_symbols(tcx, |_cnum, def_id| { let attrs = tcx.codegen_fn_attrs(def_id); let Some(link_section) = attrs.link_section else { - return Ok(()); + return interp_ok(()); }; if link_section.as_str() == name { let instance = ty::Instance::mono(tcx, def_id); @@ -1308,10 +1308,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let val = this.read_immediate(&const_val)?; array.push(val); } - Ok(()) + interp_ok(()) })?; - Ok(array) + interp_ok(array) } } @@ -1361,7 +1361,7 @@ where &'a [OpTy<'tcx>; N]: TryFrom<&'a [OpTy<'tcx>]>, { if let Ok(ops) = args.try_into() { - return Ok(ops); + return interp_ok(ops); } throw_ub_format!("incorrect number of arguments: got {}, expected {}", args.len(), N) } @@ -1401,7 +1401,7 @@ pub(crate) fn bool_to_simd_element(b: bool, size: Size) -> Scalar { pub(crate) fn simd_element_to_bool(elem: ImmTy<'_>) -> InterpResult<'_, bool> { let val = elem.to_scalar().to_int(elem.layout.size)?; - Ok(match val { + interp_ok(match val { 0 => false, -1 => true, _ => throw_ub_format!("each element of a SIMD mask must be all-0-bits or all-1-bits"), diff --git a/src/tools/miri/src/intrinsics/atomic.rs b/src/tools/miri/src/intrinsics/atomic.rs index b6fd9ba1e82..8507b0f49de 100644 --- a/src/tools/miri/src/intrinsics/atomic.rs +++ b/src/tools/miri/src/intrinsics/atomic.rs @@ -115,9 +115,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.atomic_rmw_op(args, dest, AtomicOp::Max, rw_ord(ord))?; } - _ => return Ok(EmulateItemResult::NotSupported), + _ => return interp_ok(EmulateItemResult::NotSupported), } - Ok(EmulateItemResult::NeedsReturn) + interp_ok(EmulateItemResult::NeedsReturn) } } @@ -138,7 +138,7 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> { let val = this.read_scalar_atomic(&place, atomic)?; // Perform regular store. this.write_scalar(val, dest)?; - Ok(()) + interp_ok(()) } fn atomic_store(&mut self, args: &[OpTy<'tcx>], atomic: AtomicWriteOrd) -> InterpResult<'tcx> { @@ -151,7 +151,7 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> { let val = this.read_scalar(val)?; // Perform atomic store this.write_scalar_atomic(val, &place, atomic)?; - Ok(()) + interp_ok(()) } fn compiler_fence_intrinsic( @@ -162,7 +162,7 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> { let [] = check_arg_count(args)?; let _ = atomic; //FIXME: compiler fences are currently ignored - Ok(()) + interp_ok(()) } fn atomic_fence_intrinsic( @@ -173,7 +173,7 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> { let this = self.eval_context_mut(); let [] = check_arg_count(args)?; this.atomic_fence(atomic)?; - Ok(()) + interp_ok(()) } fn atomic_rmw_op( @@ -203,17 +203,17 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> { AtomicOp::Min => { let old = this.atomic_min_max_scalar(&place, rhs, true, atomic)?; this.write_immediate(*old, dest)?; // old value is returned - Ok(()) + interp_ok(()) } AtomicOp::Max => { let old = this.atomic_min_max_scalar(&place, rhs, false, atomic)?; this.write_immediate(*old, dest)?; // old value is returned - Ok(()) + interp_ok(()) } AtomicOp::MirOp(op, not) => { let old = this.atomic_rmw_op_immediate(&place, &rhs, op, not, atomic)?; this.write_immediate(*old, dest)?; // old value is returned - Ok(()) + interp_ok(()) } } } @@ -232,7 +232,7 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> { let old = this.atomic_exchange_scalar(&place, new, atomic)?; this.write_scalar(old, dest)?; // old value is returned - Ok(()) + interp_ok(()) } fn atomic_compare_exchange_impl( @@ -261,7 +261,7 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> { // Return old value. this.write_immediate(old, dest)?; - Ok(()) + interp_ok(()) } fn atomic_compare_exchange( diff --git a/src/tools/miri/src/intrinsics/mod.rs b/src/tools/miri/src/intrinsics/mod.rs index 23ce2f8ed1f..665dd7c441a 100644 --- a/src/tools/miri/src/intrinsics/mod.rs +++ b/src/tools/miri/src/intrinsics/mod.rs @@ -29,7 +29,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // See if the core engine can handle this intrinsic. if this.eval_intrinsic(instance, args, dest, ret)? { - return Ok(None); + return interp_ok(None); } let intrinsic_name = this.tcx.item_name(instance.def_id()); let intrinsic_name = intrinsic_name.as_str(); @@ -51,7 +51,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { "Miri can only use intrinsic fallback bodies that exactly reflect the specification: they fully check for UB and are as non-deterministic as possible. After verifying that `{intrinsic_name}` does so, add the `#[miri::intrinsic_fallback_is_spec]` attribute to it; also ping @rust-lang/miri when you do that" ); } - Ok(Some(ty::Instance { + interp_ok(Some(ty::Instance { def: ty::InstanceKind::Item(instance.def_id()), args: instance.args, })) @@ -59,14 +59,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { EmulateItemResult::NeedsReturn => { trace!("{:?}", this.dump_place(&dest.clone().into())); this.return_to_block(ret)?; - Ok(None) + interp_ok(None) } EmulateItemResult::NeedsUnwind => { // Jump to the unwind block to begin unwinding. this.unwind_to_block(unwind)?; - Ok(None) + interp_ok(None) } - EmulateItemResult::AlreadyJumped => Ok(None), + EmulateItemResult::AlreadyJumped => interp_ok(None), } } @@ -99,7 +99,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { "catch_unwind" => { this.handle_catch_unwind(args, dest, ret)?; // This pushed a stack frame, don't jump to `ret`. - return Ok(EmulateItemResult::AlreadyJumped); + return interp_ok(EmulateItemResult::AlreadyJumped); } // Raw memory accesses @@ -378,7 +378,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let ty::Float(fty) = x.layout.ty.kind() else { bug!("float_finite: non-float input type {}", x.layout.ty) }; - Ok(match fty { + interp_ok(match fty { FloatTy::F16 => x.to_scalar().to_f16()?.is_finite(), FloatTy::F32 => x.to_scalar().to_f32()?.is_finite(), FloatTy::F64 => x.to_scalar().to_f64()?.is_finite(), @@ -429,9 +429,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { throw_machine_stop!(TerminationInfo::Abort(format!("trace/breakpoint trap"))) } - _ => return Ok(EmulateItemResult::NotSupported), + _ => return interp_ok(EmulateItemResult::NotSupported), } - Ok(EmulateItemResult::NeedsReturn) + interp_ok(EmulateItemResult::NeedsReturn) } } diff --git a/src/tools/miri/src/intrinsics/simd.rs b/src/tools/miri/src/intrinsics/simd.rs index 7f43c61cd66..de293495e86 100644 --- a/src/tools/miri/src/intrinsics/simd.rs +++ b/src/tools/miri/src/intrinsics/simd.rs @@ -248,7 +248,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let val = this.binary_op(mir_op, &left, &right).map_err(|err| { match err.kind() { &InterpError::UndefinedBehavior(UndefinedBehaviorInfo::ShiftOverflow { shift_amount, .. }) => { - err.discard_interp_err(); // This resets the interpreter backtrace, but it's not worth avoiding that. let shift_amount = match shift_amount { Either::Left(v) => v.to_string(), @@ -787,9 +786,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } } - _ => return Ok(EmulateItemResult::NotSupported), + _ => return interp_ok(EmulateItemResult::NotSupported), } - Ok(EmulateItemResult::NeedsReturn) + interp_ok(EmulateItemResult::NeedsReturn) } fn fminmax_op( @@ -805,7 +804,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { }; let left = left.to_scalar(); let right = right.to_scalar(); - Ok(match float_ty { + interp_ok(match float_ty { FloatTy::F16 => unimplemented!("f16_f128"), FloatTy::F32 => { let left = left.to_f32()?; diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs index fb5ccbcd4fe..b9cebcfe9cd 100644 --- a/src/tools/miri/src/machine.rs +++ b/src/tools/miri/src/machine.rs @@ -730,7 +730,7 @@ impl<'tcx> MiriMachine<'tcx> { EnvVars::init(this, config)?; MiriMachine::init_extern_statics(this)?; ThreadManager::init(this, on_main_stack_empty); - Ok(()) + interp_ok(()) } pub(crate) fn add_extern_static(this: &mut MiriInterpCx<'tcx>, name: &str, ptr: Pointer) { @@ -992,7 +992,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { throw_ub_format!("{msg}"); } } - Ok(()) + interp_ok(()) } #[inline(always)] @@ -1019,7 +1019,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { } // Otherwise, load the MIR. - Ok(Some((ecx.load_mir(instance.def, None)?, instance))) + interp_ok(Some((ecx.load_mir(instance.def, None)?, instance))) } #[inline(always)] @@ -1072,7 +1072,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { ret: None, unwind: mir::UnwindAction::Unreachable, })?; - Ok(()) + interp_ok(()) } #[inline(always)] @@ -1097,7 +1097,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { } fn ub_checks(ecx: &InterpCx<'tcx, Self>) -> InterpResult<'tcx, bool> { - Ok(ecx.tcx.sess.ub_checks()) + interp_ok(ecx.tcx.sess.ub_checks()) } fn thread_local_static_pointer( @@ -1136,7 +1136,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { shim_align = shim_align.bytes(), ) } - Ok(ptr) + interp_ok(ptr) } else { throw_unsup_format!("extern static `{link_name}` is not supported by Miri",) } @@ -1186,7 +1186,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { .insert(id, (ecx.machine.current_span(), None)); } - Ok(AllocExtra { borrow_tracker, data_race, weak_memory, backtrace }) + interp_ok(AllocExtra { borrow_tracker, data_race, weak_memory, backtrace }) } fn adjust_alloc_root_pointer( @@ -1233,7 +1233,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { Provenance::Wildcard => { // No need to do anything for wildcard pointers as // their provenances have already been previously exposed. - Ok(()) + interp_ok(()) } } } @@ -1286,7 +1286,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { |ptr| ecx.global_root_pointer(ptr), )?; let extra = Self::init_alloc_extra(ecx, id, kind, alloc.size(), alloc.align)?; - Ok(Cow::Owned(alloc.with_extra(extra))) + interp_ok(Cow::Owned(alloc.with_extra(extra))) } #[inline(always)] @@ -1310,7 +1310,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { if let Some(weak_memory) = &alloc_extra.weak_memory { weak_memory.memory_accessed(range, machine.data_race.as_ref().unwrap()); } - Ok(()) + interp_ok(()) } #[inline(always)] @@ -1334,7 +1334,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { if let Some(weak_memory) = &alloc_extra.weak_memory { weak_memory.memory_accessed(range, machine.data_race.as_ref().unwrap()); } - Ok(()) + interp_ok(()) } #[inline(always)] @@ -1367,7 +1367,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { *deallocated_at = Some(machine.current_span()); } machine.free_alloc_id(alloc_id, size, align, kind); - Ok(()) + interp_ok(()) } #[inline(always)] @@ -1379,7 +1379,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { if ecx.machine.borrow_tracker.is_some() { ecx.retag_ptr_value(kind, val) } else { - Ok(val.clone()) + interp_ok(val.clone()) } } @@ -1392,7 +1392,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { if ecx.machine.borrow_tracker.is_some() { ecx.retag_place_contents(kind, place)?; } - Ok(()) + interp_ok(()) } fn protect_in_place_function_argument( @@ -1413,7 +1413,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { // Conveniently this also ensures that the place actually points to suitable memory. ecx.write_uninit(&protected_place)?; // Now we throw away the protected place, ensuring its tag is never used again. - Ok(()) + interp_ok(()) } #[inline(always)] @@ -1447,7 +1447,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { data_race: ecx.machine.data_race.as_ref().map(|_| data_race::FrameState::default()), }; - Ok(frame.with_extra(extra)) + interp_ok(frame.with_extra(extra)) } fn stack<'a>( @@ -1489,7 +1489,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { // Make sure some time passes. ecx.machine.clock.tick(); - Ok(()) + interp_ok(()) } #[inline(always)] @@ -1500,7 +1500,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { let stack_len = ecx.active_thread_stack().len(); ecx.active_thread_mut().set_top_user_relevant_frame(stack_len - 1); } - Ok(()) + interp_ok(()) } fn before_stack_pop( @@ -1516,7 +1516,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { // concurrency and what it prints is just plain wrong. So we print our own information // instead. (Cc https://github.com/rust-lang/miri/issues/2266) info!("Leaving {}", ecx.frame().instance()); - Ok(()) + interp_ok(()) } #[inline(always)] @@ -1554,7 +1554,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { if let Some(data_race) = &ecx.frame().extra.data_race { data_race.local_read(local, &ecx.machine); } - Ok(()) + interp_ok(()) } fn after_local_write( @@ -1565,7 +1565,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { if let Some(data_race) = &ecx.frame().extra.data_race { data_race.local_write(local, storage_live, &ecx.machine); } - Ok(()) + interp_ok(()) } fn after_local_moved_to_memory( @@ -1587,7 +1587,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { { data_race.local_moved_to_memory(local, alloc_info.data_race.as_mut().unwrap(), machine); } - Ok(()) + interp_ok(()) } fn eval_mir_constant( @@ -1611,9 +1611,9 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { Entry::Vacant(ve) => { let op = eval(ecx, val, span, layout)?; ve.insert(op.clone()); - Ok(op) + interp_ok(op) } - Entry::Occupied(oe) => Ok(oe.get().clone()), + Entry::Occupied(oe) => interp_ok(oe.get().clone()), } } diff --git a/src/tools/miri/src/operator.rs b/src/tools/miri/src/operator.rs index 6b8c0fe87ad..c0911fa717f 100644 --- a/src/tools/miri/src/operator.rs +++ b/src/tools/miri/src/operator.rs @@ -21,7 +21,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let this = self.eval_context_ref(); trace!("ptr_op: {:?} {:?} {:?}", *left, bin_op, *right); - Ok(match bin_op { + interp_ok(match bin_op { Eq | Ne | Lt | Le | Gt | Ge => { assert_eq!(left.layout.abi, right.layout.abi); // types can differ, e.g. fn ptrs with different `for` let size = this.pointer_size(); diff --git a/src/tools/miri/src/shims/alloc.rs b/src/tools/miri/src/shims/alloc.rs index 057d7ef5e67..e73344367ec 100644 --- a/src/tools/miri/src/shims/alloc.rs +++ b/src/tools/miri/src/shims/alloc.rs @@ -61,7 +61,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let Some(allocator_kind) = this.tcx.allocator_kind(()) else { // in real code, this symbol does not exist without an allocator - return Ok(EmulateItemResult::NotSupported); + return interp_ok(EmulateItemResult::NotSupported); }; match allocator_kind { @@ -71,11 +71,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // and not execute any Miri shim. Somewhat unintuitively doing so is done // by returning `NotSupported`, which triggers the `lookup_exported_symbol` // fallback case in `emulate_foreign_item`. - Ok(EmulateItemResult::NotSupported) + interp_ok(EmulateItemResult::NotSupported) } AllocatorKind::Default => { default(this)?; - Ok(EmulateItemResult::NeedsReturn) + interp_ok(EmulateItemResult::NeedsReturn) } } } @@ -92,7 +92,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { ) .unwrap(); } - Ok(ptr.into()) + interp_ok(ptr.into()) } fn posix_memalign( @@ -109,7 +109,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Align must be power of 2, and also at least ptr-sized (POSIX rules). // But failure to adhere to this is not UB, it's an error condition. if !align.is_power_of_two() || align < this.pointer_size().bytes() { - Ok(this.eval_libc("EINVAL")) + interp_ok(this.eval_libc("EINVAL")) } else { let ptr = this.allocate_ptr( Size::from_bytes(size), @@ -117,7 +117,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { MiriMemoryKind::C.into(), )?; this.write_pointer(ptr, &memptr)?; - Ok(Scalar::from_i32(0)) + interp_ok(Scalar::from_i32(0)) } } @@ -126,7 +126,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { if !this.ptr_is_null(ptr)? { this.deallocate_ptr(ptr, None, MiriMemoryKind::C.into())?; } - Ok(()) + interp_ok(()) } fn realloc(&mut self, old_ptr: Pointer, new_size: u64) -> InterpResult<'tcx, Pointer> { @@ -148,7 +148,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { new_align, MiriMemoryKind::C.into(), )?; - Ok(new_ptr.into()) + interp_ok(new_ptr.into()) } } } @@ -188,9 +188,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { Align::from_bytes(align).unwrap(), MiriMemoryKind::C.into(), )?; - Ok(ptr.into()) + interp_ok(ptr.into()) } - _ => Ok(Pointer::null()), + _ => interp_ok(Pointer::null()), } } } diff --git a/src/tools/miri/src/shims/backtrace.rs b/src/tools/miri/src/shims/backtrace.rs index 1d20189b6fd..25afda4edc8 100644 --- a/src/tools/miri/src/shims/backtrace.rs +++ b/src/tools/miri/src/shims/backtrace.rs @@ -107,7 +107,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { _ => throw_unsup_format!("unknown `miri_get_backtrace` flags {}", flags), }; - Ok(()) + interp_ok(()) } fn resolve_frame_pointer( @@ -135,7 +135,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let name = fn_instance.to_string(); let filename = lo.file.name.prefer_remapped_unconditionaly().to_string(); - Ok((fn_instance, lo, name, filename)) + interp_ok((fn_instance, lo, name, filename)) } fn handle_miri_resolve_frame( @@ -213,7 +213,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_pointer(fn_ptr, &this.project_field(dest, 4)?)?; } - Ok(()) + interp_ok(()) } fn handle_miri_resolve_frame_names( @@ -237,6 +237,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_bytes_ptr(this.read_pointer(name_ptr)?, name.bytes())?; this.write_bytes_ptr(this.read_pointer(filename_ptr)?, filename.bytes())?; - Ok(()) + interp_ok(()) } } diff --git a/src/tools/miri/src/shims/env.rs b/src/tools/miri/src/shims/env.rs index 557d648682c..e99a8fd6e8c 100644 --- a/src/tools/miri/src/shims/env.rs +++ b/src/tools/miri/src/shims/env.rs @@ -56,15 +56,15 @@ impl<'tcx> EnvVars<'tcx> { }; ecx.machine.env_vars = env_vars; - Ok(()) + interp_ok(()) } pub(crate) fn cleanup(ecx: &mut InterpCx<'tcx, MiriMachine<'tcx>>) -> InterpResult<'tcx> { let this = ecx.eval_context_mut(); match this.machine.env_vars { EnvVars::Unix(_) => UnixEnvVars::cleanup(this), - EnvVars::Windows(_) => Ok(()), // no cleanup needed - EnvVars::Uninit => Ok(()), + EnvVars::Windows(_) => interp_ok(()), // no cleanup needed + EnvVars::Uninit => interp_ok(()), } } @@ -104,7 +104,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn get_env_var(&mut self, name: &OsStr) -> InterpResult<'tcx, Option> { let this = self.eval_context_ref(); match &this.machine.env_vars { - EnvVars::Uninit => Ok(None), + EnvVars::Uninit => interp_ok(None), EnvVars::Unix(vars) => vars.get(this, name), EnvVars::Windows(vars) => vars.get(name), } diff --git a/src/tools/miri/src/shims/extern_static.rs b/src/tools/miri/src/shims/extern_static.rs index 788de8162cb..5559ea2750b 100644 --- a/src/tools/miri/src/shims/extern_static.rs +++ b/src/tools/miri/src/shims/extern_static.rs @@ -11,7 +11,7 @@ impl<'tcx> MiriMachine<'tcx> { let place = this.allocate(val.layout, MiriMemoryKind::ExternStatic.into())?; this.write_immediate(*val, &place)?; Self::add_extern_static(this, name, place.ptr()); - Ok(()) + interp_ok(()) } /// Zero-initialized pointer-sized extern statics are pretty common. @@ -26,7 +26,7 @@ impl<'tcx> MiriMachine<'tcx> { let val = ImmTy::from_int(0, this.machine.layouts.usize); Self::alloc_extern_static(this, name, val)?; } - Ok(()) + interp_ok(()) } /// Extern statics that are initialized with function pointers to the symbols of the same name. @@ -41,7 +41,7 @@ impl<'tcx> MiriMachine<'tcx> { let val = ImmTy::from_scalar(Scalar::from_pointer(ptr, this), layout); Self::alloc_extern_static(this, name, val)?; } - Ok(()) + interp_ok(()) } /// Sets up the "extern statics" for this machine. @@ -87,6 +87,6 @@ impl<'tcx> MiriMachine<'tcx> { } _ => {} // No "extern statics" supported on this target } - Ok(()) + interp_ok(()) } } diff --git a/src/tools/miri/src/shims/foreign_items.rs b/src/tools/miri/src/shims/foreign_items.rs index 6a835098e60..78b07f68b44 100644 --- a/src/tools/miri/src/shims/foreign_items.rs +++ b/src/tools/miri/src/shims/foreign_items.rs @@ -62,7 +62,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let handler = this .lookup_exported_symbol(Symbol::intern(name))? .expect("missing alloc error handler symbol"); - return Ok(Some(handler)); + return interp_ok(Some(handler)); } _ => {} } @@ -80,18 +80,18 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { EmulateItemResult::AlreadyJumped => (), EmulateItemResult::NotSupported => { if let Some(body) = this.lookup_exported_symbol(link_name)? { - return Ok(Some(body)); + return interp_ok(Some(body)); } this.handle_unsupported_foreign_item(format!( "can't call foreign function `{link_name}` on OS `{os}`", os = this.tcx.sess.target.os, ))?; - return Ok(None); + return interp_ok(None); } } - Ok(None) + interp_ok(None) } fn is_dyn_sym(&self, name: &str) -> bool { @@ -116,7 +116,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { ) -> InterpResult<'tcx> { let res = self.emulate_foreign_item(sym.0, abi, args, dest, ret, unwind)?; assert!(res.is_none(), "DynSyms that delegate are not supported"); - Ok(()) + interp_ok(()) } /// Lookup the body of a function that has `link_name` as the symbol name. @@ -143,7 +143,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { tcx.item_name(def_id) } else { // Skip over items without an explicitly defined symbol name. - return Ok(()); + return interp_ok(()); }; if symbol_name == link_name { if let Some((original_instance, original_cnum)) = instance_and_crate { @@ -175,15 +175,15 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } instance_and_crate = Some((ty::Instance::mono(tcx, def_id), cnum)); } - Ok(()) + interp_ok(()) })?; e.insert(instance_and_crate.map(|ic| ic.0)) } }; match instance { - None => Ok(None), // no symbol with this name - Some(instance) => Ok(Some((this.load_mir(instance.def, None)?, instance))), + None => interp_ok(None), // no symbol with this name + Some(instance) => interp_ok(Some((this.load_mir(instance.def, None)?, instance))), } } } @@ -214,7 +214,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { } } - Ok(()) + interp_ok(()) } fn emulate_foreign_item_inner( @@ -234,7 +234,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { // by the specified `.so` file; we should continue and check if it corresponds to // a provided shim. if this.call_native_fn(link_name, dest, args)? { - return Ok(EmulateItemResult::NeedsReturn); + return interp_ok(EmulateItemResult::NeedsReturn); } } @@ -268,7 +268,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { // // // ... // - // Ok(Scalar::from_u32(42)) + // interp_ok(Scalar::from_u32(42)) // } // ``` // You might find existing shims not following this pattern, most @@ -281,7 +281,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { "miri_start_unwind" => { let [payload] = this.check_shim(abi, Abi::Rust, link_name, args)?; this.handle_miri_start_unwind(payload)?; - return Ok(EmulateItemResult::NeedsUnwind); + return interp_ok(EmulateItemResult::NeedsUnwind); } "miri_run_provenance_gc" => { let [] = this.check_shim(abi, Abi::Rust, link_name, args)?; @@ -294,6 +294,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { err_machine_stop!(TerminationInfo::Abort(format!( "pointer passed to `miri_get_alloc_id` must not be dangling, got {ptr:?}" ))) + .into() })?; this.write_scalar(Scalar::from_u64(alloc_id.0.get()), dest)?; } @@ -524,7 +525,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { "__rust_alloc" => return this.emulate_allocator(default), "miri_alloc" => { default(this)?; - return Ok(EmulateItemResult::NeedsReturn); + return interp_ok(EmulateItemResult::NeedsReturn); } _ => unreachable!(), } @@ -584,7 +585,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { } "miri_dealloc" => { default(this)?; - return Ok(EmulateItemResult::NeedsReturn); + return interp_ok(EmulateItemResult::NeedsReturn); } _ => unreachable!(), } @@ -1000,11 +1001,11 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { shims::windows::foreign_items::EvalContextExt::emulate_foreign_item_inner( this, link_name, abi, args, dest, ), - _ => Ok(EmulateItemResult::NotSupported), + _ => interp_ok(EmulateItemResult::NotSupported), }, }; // We only fall through to here if we did *not* hit the `_` arm above, // i.e., if we actually emulated the function with one of the shims. - Ok(EmulateItemResult::NeedsReturn) + interp_ok(EmulateItemResult::NeedsReturn) } } diff --git a/src/tools/miri/src/shims/native_lib.rs b/src/tools/miri/src/shims/native_lib.rs index 2b5acee244c..3f282017bb7 100644 --- a/src/tools/miri/src/shims/native_lib.rs +++ b/src/tools/miri/src/shims/native_lib.rs @@ -73,11 +73,11 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { // have the output_type `Tuple([])`. ty::Tuple(t_list) if t_list.len() == 0 => { unsafe { ffi::call::<()>(ptr, libffi_args.as_slice()) }; - return Ok(ImmTy::uninit(dest.layout)); + return interp_ok(ImmTy::uninit(dest.layout)); } _ => throw_unsup_format!("unsupported return type for native call: {:?}", link_name), }; - Ok(ImmTy::from_scalar(scalar, dest.layout)) + interp_ok(ImmTy::from_scalar(scalar, dest.layout)) } /// Get the pointer to the function of the specified name in the shared object file, @@ -142,7 +142,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { Some(ptr) => ptr, None => { // Shared object file does not export this function -- try the shims next. - return Ok(false); + return interp_ok(false); } }; @@ -164,7 +164,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Call the function and store output, depending on return type in the function signature. let ret = this.call_native_with_args(link_name, dest, code_ptr, libffi_args)?; this.write_immediate(*ret, dest)?; - Ok(true) + interp_ok(true) } } @@ -221,7 +221,7 @@ impl<'a> CArg { /// Extract the scalar value from the result of reading a scalar from the machine, /// and convert it to a `CArg`. fn imm_to_carg<'tcx>(v: ImmTy<'tcx>, cx: &impl HasDataLayout) -> InterpResult<'tcx, CArg> { - Ok(match v.layout.ty.kind() { + interp_ok(match v.layout.ty.kind() { // If the primitive provided can be converted to a type matching the type pattern // then create a `CArg` of this primitive value with the corresponding `CArg` constructor. // the ints diff --git a/src/tools/miri/src/shims/os_str.rs b/src/tools/miri/src/shims/os_str.rs index 17c45105920..7080edb26a5 100644 --- a/src/tools/miri/src/shims/os_str.rs +++ b/src/tools/miri/src/shims/os_str.rs @@ -19,14 +19,14 @@ pub enum PathConversion { #[cfg(unix)] pub fn bytes_to_os_str<'tcx>(bytes: &[u8]) -> InterpResult<'tcx, &OsStr> { - Ok(OsStr::from_bytes(bytes)) + interp_ok(OsStr::from_bytes(bytes)) } #[cfg(not(unix))] pub fn bytes_to_os_str<'tcx>(bytes: &[u8]) -> InterpResult<'tcx, &OsStr> { // We cannot use `from_encoded_bytes_unchecked` here since we can't trust `bytes`. let s = std::str::from_utf8(bytes) .map_err(|_| err_unsup_format!("{:?} is not a valid utf-8 string", bytes))?; - Ok(OsStr::new(s)) + interp_ok(OsStr::new(s)) } impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {} @@ -50,13 +50,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { { #[cfg(windows)] pub fn u16vec_to_osstring<'tcx>(u16_vec: Vec) -> InterpResult<'tcx, OsString> { - Ok(OsString::from_wide(&u16_vec[..])) + interp_ok(OsString::from_wide(&u16_vec[..])) } #[cfg(not(windows))] pub fn u16vec_to_osstring<'tcx>(u16_vec: Vec) -> InterpResult<'tcx, OsString> { let s = String::from_utf16(&u16_vec[..]) .map_err(|_| err_unsup_format!("{:?} is not a valid utf-16 string", u16_vec))?; - Ok(s.into()) + interp_ok(s.into()) } let u16_vec = self.eval_context_ref().read_wide_str(ptr)?; @@ -87,7 +87,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { ) -> InterpResult<'tcx, (bool, u64)> { #[cfg(windows)] fn os_str_to_u16vec<'tcx>(os_str: &OsStr) -> InterpResult<'tcx, Vec> { - Ok(os_str.encode_wide().collect()) + interp_ok(os_str.encode_wide().collect()) } #[cfg(not(windows))] fn os_str_to_u16vec<'tcx>(os_str: &OsStr) -> InterpResult<'tcx, Vec> { @@ -97,7 +97,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { os_str .to_str() .map(|s| s.encode_utf16().collect()) - .ok_or_else(|| err_unsup_format!("{:?} is not a valid utf-8 string", os_str).into()) + .ok_or_else(|| err_unsup_format!("{:?} is not a valid utf-8 string", os_str)) + .into() } let u16_vec = os_str_to_u16vec(os_str)?; @@ -109,7 +110,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { self.eval_context_mut().write_wide_str(truncated_data, ptr, size)?; assert!(written && written_len == size); } - Ok((written, size_needed)) + interp_ok((written, size_needed)) } /// Helper function to write an OsStr as a 0x0000-terminated u16-sequence, which is what the @@ -148,7 +149,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let arg_place = this.allocate(this.layout_of(arg_type).unwrap(), memkind)?; let (written, _) = self.write_os_str_to_c_str(os_str, arg_place.ptr(), size).unwrap(); assert!(written); - Ok(arg_place.ptr()) + interp_ok(arg_place.ptr()) } /// Allocate enough memory to store the given `OsStr` as a null-terminated sequence of `u16`. @@ -164,7 +165,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let arg_place = this.allocate(this.layout_of(arg_type).unwrap(), memkind)?; let (written, _) = self.write_os_str_to_wide_str(os_str, arg_place.ptr(), size).unwrap(); assert!(written); - Ok(arg_place.ptr()) + interp_ok(arg_place.ptr()) } /// Read a null-terminated sequence of bytes, and perform path separator conversion if needed. @@ -175,7 +176,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let this = self.eval_context_ref(); let os_str = this.read_os_str_from_c_str(ptr)?; - Ok(match this.convert_path(Cow::Borrowed(os_str), PathConversion::TargetToHost) { + interp_ok(match this.convert_path(Cow::Borrowed(os_str), PathConversion::TargetToHost) { Cow::Borrowed(x) => Cow::Borrowed(Path::new(x)), Cow::Owned(y) => Cow::Owned(PathBuf::from(y)), }) @@ -186,7 +187,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let this = self.eval_context_ref(); let os_str = this.read_os_str_from_wide_str(ptr)?; - Ok(this.convert_path(Cow::Owned(os_str), PathConversion::TargetToHost).into_owned().into()) + interp_ok( + this.convert_path(Cow::Owned(os_str), PathConversion::TargetToHost).into_owned().into(), + ) } /// Write a Path to the machine memory (as a null-terminated sequence of bytes), diff --git a/src/tools/miri/src/shims/panic.rs b/src/tools/miri/src/shims/panic.rs index 55b814a09fa..9bb0d7d0ce6 100644 --- a/src/tools/miri/src/shims/panic.rs +++ b/src/tools/miri/src/shims/panic.rs @@ -54,7 +54,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let thread = this.active_thread_mut(); thread.panic_payloads.push(payload); - Ok(()) + interp_ok(()) } /// Handles the `try` intrinsic, the underlying implementation of `std::panicking::try`. @@ -106,7 +106,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { Some(CatchUnwindData { catch_fn, data, dest: dest.clone(), ret }); } - Ok(()) + interp_ok(()) } fn handle_stack_pop_unwind( @@ -150,9 +150,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { )?; // We pushed a new stack frame, the engine should not do any jumping now! - Ok(ReturnAction::NoJump) + interp_ok(ReturnAction::NoJump) } else { - Ok(ReturnAction::Normal) + interp_ok(ReturnAction::Normal) } } @@ -254,6 +254,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { })?; } } - Ok(()) + interp_ok(()) } } diff --git a/src/tools/miri/src/shims/time.rs b/src/tools/miri/src/shims/time.rs index 694c52b5465..21c5421f109 100644 --- a/src/tools/miri/src/shims/time.rs +++ b/src/tools/miri/src/shims/time.rs @@ -11,7 +11,7 @@ use crate::*; /// Returns the time elapsed between the provided time and the unix epoch as a `Duration`. pub fn system_time_to_duration<'tcx>(time: &SystemTime) -> InterpResult<'tcx, Duration> { time.duration_since(SystemTime::UNIX_EPOCH) - .map_err(|_| err_unsup_format!("times before the Unix epoch are not supported").into()) + .map_err(|_| err_unsup_format!("times before the Unix epoch are not supported")).into() } impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {} @@ -82,7 +82,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } else { let einval = this.eval_libc("EINVAL"); this.set_last_error(einval)?; - return Ok(Scalar::from_i32(-1)); + return interp_ok(Scalar::from_i32(-1)); }; let tv_sec = duration.as_secs(); @@ -90,7 +90,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_int_fields(&[tv_sec.into(), tv_nsec.into()], &tp)?; - Ok(Scalar::from_i32(0)) + interp_ok(Scalar::from_i32(0)) } fn gettimeofday( @@ -110,7 +110,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { if !this.ptr_is_null(tz)? { let einval = this.eval_libc("EINVAL"); this.set_last_error(einval)?; - return Ok(Scalar::from_i32(-1)); + return interp_ok(Scalar::from_i32(-1)); } let duration = system_time_to_duration(&SystemTime::now())?; @@ -119,7 +119,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_int_fields(&[tv_sec.into(), tv_usec.into()], &tv)?; - Ok(Scalar::from_i32(0)) + interp_ok(Scalar::from_i32(0)) } // The localtime() function shall convert the time in seconds since the Epoch pointed to by @@ -206,7 +206,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_pointer(tm_zone_ptr, &this.project_field_named(&result, "tm_zone")?)?; this.write_int_fields_named(&[("tm_gmtoff", tm_gmtoff.into())], &result)?; } - Ok(result.ptr()) + interp_ok(result.ptr()) } #[allow(non_snake_case, clippy::arithmetic_side_effects)] fn GetSystemTimeAsFileTime( @@ -236,7 +236,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let dwHighDateTime = u32::try_from((duration_ticks & 0xFFFFFFFF00000000) >> 32).unwrap(); this.write_int_fields(&[dwLowDateTime.into(), dwHighDateTime.into()], &filetime)?; - Ok(()) + interp_ok(()) } #[allow(non_snake_case)] @@ -255,7 +255,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { err_unsup_format!("programs running longer than 2^63 nanoseconds are not supported") })?; this.write_scalar(Scalar::from_i64(qpc), &this.deref_pointer(lpPerformanceCount_op)?)?; - Ok(Scalar::from_i32(-1)) // return non-zero on success + interp_ok(Scalar::from_i32(-1)) // return non-zero on success } #[allow(non_snake_case)] @@ -276,7 +276,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { Scalar::from_i64(1_000_000_000), &this.deref_pointer_as(lpFrequency_op, this.machine.layouts.u64)?, )?; - Ok(Scalar::from_i32(-1)) // Return non-zero on success + interp_ok(Scalar::from_i32(-1)) // Return non-zero on success } fn mach_absolute_time(&self) -> InterpResult<'tcx, Scalar> { @@ -290,7 +290,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let res = u64::try_from(duration.as_nanos()).map_err(|_| { err_unsup_format!("programs running longer than 2^64 nanoseconds are not supported") })?; - Ok(Scalar::from_u64(res)) + interp_ok(Scalar::from_u64(res)) } fn mach_timebase_info(&mut self, info_op: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> { @@ -305,7 +305,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let (numer, denom) = (1, 1); this.write_int_fields(&[numer.into(), denom.into()], &info)?; - Ok(Scalar::from_i32(0)) // KERN_SUCCESS + interp_ok(Scalar::from_i32(0)) // KERN_SUCCESS } fn nanosleep( @@ -324,7 +324,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { None => { let einval = this.eval_libc("EINVAL"); this.set_last_error(einval)?; - return Ok(Scalar::from_i32(-1)); + return interp_ok(Scalar::from_i32(-1)); } }; @@ -334,10 +334,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { callback!( @capture<'tcx> {} @unblock = |_this| { panic!("sleeping thread unblocked before time is up") } - @timeout = |_this| { Ok(()) } + @timeout = |_this| { interp_ok(()) } ), ); - Ok(Scalar::from_i32(0)) + interp_ok(Scalar::from_i32(0)) } #[allow(non_snake_case)] @@ -356,9 +356,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { callback!( @capture<'tcx> {} @unblock = |_this| { panic!("sleeping thread unblocked before time is up") } - @timeout = |_this| { Ok(()) } + @timeout = |_this| { interp_ok(()) } ), ); - Ok(()) + interp_ok(()) } } diff --git a/src/tools/miri/src/shims/tls.rs b/src/tools/miri/src/shims/tls.rs index b3ea7098dfe..94b2d1bc782 100644 --- a/src/tools/miri/src/shims/tls.rs +++ b/src/tools/miri/src/shims/tls.rs @@ -68,14 +68,14 @@ impl<'tcx> TlsData<'tcx> { if max_size.bits() < 128 && new_key >= (1u128 << max_size.bits()) { throw_unsup_format!("we ran out of TLS key space"); } - Ok(new_key) + interp_ok(new_key) } pub fn delete_tls_key(&mut self, key: TlsKey) -> InterpResult<'tcx> { match self.keys.remove(&key) { Some(_) => { trace!("TLS key {} removed", key); - Ok(()) + interp_ok(()) } None => throw_ub_format!("removing a nonexistent TLS key: {}", key), } @@ -91,7 +91,7 @@ impl<'tcx> TlsData<'tcx> { Some(TlsEntry { data, .. }) => { let value = data.get(&thread_id).copied(); trace!("TLS key {} for thread {:?} loaded: {:?}", key, thread_id, value); - Ok(value.unwrap_or_else(|| Scalar::null_ptr(cx))) + interp_ok(value.unwrap_or_else(|| Scalar::null_ptr(cx))) } None => throw_ub_format!("loading from a non-existing TLS key: {}", key), } @@ -113,7 +113,7 @@ impl<'tcx> TlsData<'tcx> { trace!("TLS key {} for thread {:?} removed", key, thread_id); data.remove(&thread_id); } - Ok(()) + interp_ok(()) } None => throw_ub_format!("storing to a non-existing TLS key: {}", key), } @@ -128,7 +128,7 @@ impl<'tcx> TlsData<'tcx> { data: Scalar, ) -> InterpResult<'tcx> { self.macos_thread_dtors.entry(thread).or_default().push((dtor, data)); - Ok(()) + interp_ok(()) } /// Returns a dtor, its argument and its index, if one is supposed to run. @@ -261,7 +261,7 @@ impl<'tcx> TlsDtorsState<'tcx> { } MacOsDtors => { match this.schedule_macos_tls_dtor()? { - Poll::Pending => return Ok(Poll::Pending), + Poll::Pending => return interp_ok(Poll::Pending), // After all macOS destructors are run, the system switches // to destroying the pthread destructors. Poll::Ready(()) => break 'new_state PthreadDtors(Default::default()), @@ -269,14 +269,14 @@ impl<'tcx> TlsDtorsState<'tcx> { } PthreadDtors(state) => { match this.schedule_next_pthread_tls_dtor(state)? { - Poll::Pending => return Ok(Poll::Pending), // just keep going + Poll::Pending => return interp_ok(Poll::Pending), // just keep going Poll::Ready(()) => break 'new_state Done, } } WindowsDtors(dtors) => { if let Some(dtor) = dtors.pop() { this.schedule_windows_tls_dtor(dtor)?; - return Ok(Poll::Pending); // we stay in this state (but `dtors` got shorter) + return interp_ok(Poll::Pending); // we stay in this state (but `dtors` got shorter) } else { // No more destructors to run. break 'new_state Done; @@ -284,13 +284,13 @@ impl<'tcx> TlsDtorsState<'tcx> { } Done => { this.machine.tls.delete_all_thread_tls(this.active_thread()); - return Ok(Poll::Ready(())); + return interp_ok(Poll::Ready(())); } } }; self.0 = new_state; - Ok(Poll::Pending) + interp_ok(Poll::Pending) } } @@ -303,7 +303,7 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Windows has a special magic linker section that is run on certain events. // We don't support most of that, but just enough to make thread-local dtors in `std` work. - Ok(this.lookup_link_section(".CRT$XLB")?) + interp_ok(this.lookup_link_section(".CRT$XLB")?) } fn schedule_windows_tls_dtor(&mut self, dtor: ImmTy<'tcx>) -> InterpResult<'tcx> { @@ -328,7 +328,7 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> { None, StackPopCleanup::Root { cleanup: true }, )?; - Ok(()) + interp_ok(()) } /// Schedule the macOS thread local storage destructors to be executed. @@ -350,10 +350,10 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> { StackPopCleanup::Root { cleanup: true }, )?; - return Ok(Poll::Pending); + return interp_ok(Poll::Pending); } - Ok(Poll::Ready(())) + interp_ok(Poll::Ready(())) } /// Schedule a pthread TLS destructor. Returns `true` if found @@ -387,9 +387,9 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> { StackPopCleanup::Root { cleanup: true }, )?; - return Ok(Poll::Pending); + return interp_ok(Poll::Pending); } - Ok(Poll::Ready(())) + interp_ok(Poll::Ready(())) } } diff --git a/src/tools/miri/src/shims/unix/android/foreign_items.rs b/src/tools/miri/src/shims/unix/android/foreign_items.rs index 42552a51eda..583a1f65009 100644 --- a/src/tools/miri/src/shims/unix/android/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/android/foreign_items.rs @@ -25,8 +25,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_scalar(errno_place.to_ref(this).to_scalar(), dest)?; } - _ => return Ok(EmulateItemResult::NotSupported), + _ => return interp_ok(EmulateItemResult::NotSupported), } - Ok(EmulateItemResult::NeedsReturn) + interp_ok(EmulateItemResult::NeedsReturn) } } diff --git a/src/tools/miri/src/shims/unix/env.rs b/src/tools/miri/src/shims/unix/env.rs index 184a6c238b3..75721814c99 100644 --- a/src/tools/miri/src/shims/unix/env.rs +++ b/src/tools/miri/src/shims/unix/env.rs @@ -47,7 +47,7 @@ impl<'tcx> UnixEnvVars<'tcx> { let environ_block = alloc_environ_block(ecx, env_vars_machine.values().copied().collect())?; ecx.write_pointer(environ_block, &environ)?; - Ok(UnixEnvVars { map: env_vars_machine, environ }) + interp_ok(UnixEnvVars { map: env_vars_machine, environ }) } pub(crate) fn cleanup(ecx: &mut InterpCx<'tcx, MiriMachine<'tcx>>) -> InterpResult<'tcx> { @@ -61,7 +61,7 @@ impl<'tcx> UnixEnvVars<'tcx> { let old_vars_ptr = ecx.read_pointer(environ)?; ecx.deallocate_ptr(old_vars_ptr, None, MiriMemoryKind::Runtime.into())?; - Ok(()) + interp_ok(()) } pub(crate) fn environ(&self) -> Pointer { @@ -77,14 +77,14 @@ impl<'tcx> UnixEnvVars<'tcx> { // but we do want to do this read so it shows up as a data race. let _vars_ptr = ecx.read_pointer(&self.environ)?; let Some(var_ptr) = self.map.get(name) else { - return Ok(None); + return interp_ok(None); }; // The offset is used to strip the "{name}=" part of the string. let var_ptr = var_ptr.wrapping_offset( Size::from_bytes(u64::try_from(name.len()).unwrap().strict_add(1)), ecx, ); - Ok(Some(var_ptr)) + interp_ok(Some(var_ptr)) } /// Implementation detail for [`InterpCx::get_env_var`]. This basically does `getenv`, complete @@ -97,9 +97,9 @@ impl<'tcx> UnixEnvVars<'tcx> { let var_ptr = self.get_ptr(ecx, name)?; if let Some(ptr) = var_ptr { let var = ecx.read_os_str_from_c_str(ptr)?; - Ok(Some(var.to_owned())) + interp_ok(Some(var.to_owned())) } else { - Ok(None) + interp_ok(None) } } } @@ -133,7 +133,7 @@ fn alloc_environ_block<'tcx>( let place = ecx.project_field(&vars_place, idx)?; ecx.write_pointer(var, &place)?; } - Ok(vars_place.ptr()) + interp_ok(vars_place.ptr()) } impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {} @@ -146,7 +146,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let name = this.read_os_str_from_c_str(name_ptr)?; let var_ptr = this.machine.env_vars.unix().get_ptr(this, name)?; - Ok(var_ptr.unwrap_or_else(Pointer::null)) + interp_ok(var_ptr.unwrap_or_else(Pointer::null)) } fn setenv( @@ -174,12 +174,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.deallocate_ptr(var, None, MiriMemoryKind::Runtime.into())?; } this.update_environ()?; - Ok(Scalar::from_i32(0)) // return zero on success + interp_ok(Scalar::from_i32(0)) // return zero on success } else { // name argument is a null pointer, points to an empty string, or points to a string containing an '=' character. let einval = this.eval_libc("EINVAL"); this.set_last_error(einval)?; - Ok(Scalar::from_i32(-1)) + interp_ok(Scalar::from_i32(-1)) } } @@ -200,12 +200,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.deallocate_ptr(var, None, MiriMemoryKind::Runtime.into())?; } this.update_environ()?; - Ok(Scalar::from_i32(0)) + interp_ok(Scalar::from_i32(0)) } else { // name argument is a null pointer, points to an empty string, or points to a string containing an '=' character. let einval = this.eval_libc("EINVAL"); this.set_last_error(einval)?; - Ok(Scalar::from_i32(-1)) + interp_ok(Scalar::from_i32(-1)) } } @@ -219,14 +219,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("`getcwd`", reject_with)?; this.set_last_error_from_io_error(ErrorKind::PermissionDenied.into())?; - return Ok(Pointer::null()); + return interp_ok(Pointer::null()); } // If we cannot get the current directory, we return null match env::current_dir() { Ok(cwd) => { if this.write_path_to_c_str(&cwd, buf, size)?.0 { - return Ok(buf); + return interp_ok(buf); } let erange = this.eval_libc("ERANGE"); this.set_last_error(erange)?; @@ -234,7 +234,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { Err(e) => this.set_last_error_from_io_error(e)?, } - Ok(Pointer::null()) + interp_ok(Pointer::null()) } fn chdir(&mut self, path_op: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> { @@ -247,11 +247,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.reject_in_isolation("`chdir`", reject_with)?; this.set_last_error_from_io_error(ErrorKind::PermissionDenied.into())?; - return Ok(Scalar::from_i32(-1)); + return interp_ok(Scalar::from_i32(-1)); } let result = env::set_current_dir(path).map(|()| 0); - Ok(Scalar::from_i32(this.try_unwrap_io_result(result)?)) + interp_ok(Scalar::from_i32(this.try_unwrap_io_result(result)?)) } /// Updates the `environ` static. @@ -267,7 +267,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let environ_block = alloc_environ_block(this, vals)?; this.write_pointer(environ_block, &environ)?; - Ok(()) + interp_ok(()) } fn getpid(&mut self) -> InterpResult<'tcx, Scalar> { @@ -278,7 +278,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // `libc::getpid` returns an i32, however, `std::process::id()` return an u32. // So we un-do the conversion that stdlib does and turn it back into an i32. // In `Scalar` representation, these are the same, so we don't need to anything else. - Ok(Scalar::from_u32(this.get_pid())) + interp_ok(Scalar::from_u32(this.get_pid())) } fn linux_gettid(&mut self) -> InterpResult<'tcx, Scalar> { @@ -290,6 +290,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Compute a TID for this thread, ensuring that the main thread has PID == TID. let tid = this.get_pid().strict_add(index); - Ok(Scalar::from_u32(tid)) + interp_ok(Scalar::from_u32(tid)) } } diff --git a/src/tools/miri/src/shims/unix/fd.rs b/src/tools/miri/src/shims/unix/fd.rs index 6bd753d0d6b..24e5d5579c3 100644 --- a/src/tools/miri/src/shims/unix/fd.rs +++ b/src/tools/miri/src/shims/unix/fd.rs @@ -277,7 +277,7 @@ impl FileDescriptionRef { fd.file_description.close(communicate_allowed, ecx) } - None => Ok(Ok(())), + None => interp_ok(Ok(())), } } @@ -414,16 +414,16 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let this = self.eval_context_mut(); let Some(fd) = this.machine.fds.get(old_fd_num) else { - return Ok(Scalar::from_i32(this.fd_not_found()?)); + return interp_ok(Scalar::from_i32(this.fd_not_found()?)); }; - Ok(Scalar::from_i32(this.machine.fds.insert(fd))) + interp_ok(Scalar::from_i32(this.machine.fds.insert(fd))) } fn dup2(&mut self, old_fd_num: i32, new_fd_num: i32) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); let Some(fd) = this.machine.fds.get(old_fd_num) else { - return Ok(Scalar::from_i32(this.fd_not_found()?)); + return interp_ok(Scalar::from_i32(this.fd_not_found()?)); }; if new_fd_num != old_fd_num { // Close new_fd if it is previously opened. @@ -433,13 +433,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { old_new_fd.close(this.machine.communicate(), this)?.ok(); } } - Ok(Scalar::from_i32(new_fd_num)) + interp_ok(Scalar::from_i32(new_fd_num)) } fn flock(&mut self, fd_num: i32, op: i32) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); let Some(fd) = this.machine.fds.get(fd_num) else { - return Ok(Scalar::from_i32(this.fd_not_found()?)); + return interp_ok(Scalar::from_i32(this.fd_not_found()?)); }; // We need to check that there aren't unsupported options in `op`. @@ -467,7 +467,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { drop(fd); // return `0` if flock is successful let result = result.map(|()| 0i32); - Ok(Scalar::from_i32(this.try_unwrap_io_result(result)?)) + interp_ok(Scalar::from_i32(this.try_unwrap_io_result(result)?)) } fn fcntl(&mut self, args: &[OpTy<'tcx>]) -> InterpResult<'tcx, Scalar> { @@ -488,7 +488,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // `FD_CLOEXEC` value without checking if the flag is set for the file because `std` // always sets this flag when opening a file. However we still need to check that the // file itself is open. - Ok(Scalar::from_i32(if this.machine.fds.is_fd_num(fd_num) { + interp_ok(Scalar::from_i32(if this.machine.fds.is_fd_num(fd_num) { this.eval_libc_i32("FD_CLOEXEC") } else { this.fd_not_found()? @@ -509,15 +509,15 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let start = this.read_scalar(&args[2])?.to_i32()?; match this.machine.fds.get(fd_num) { - Some(fd) => Ok(Scalar::from_i32(this.machine.fds.insert_with_min_num(fd, start))), - None => Ok(Scalar::from_i32(this.fd_not_found()?)), + Some(fd) => interp_ok(Scalar::from_i32(this.machine.fds.insert_with_min_num(fd, start))), + None => interp_ok(Scalar::from_i32(this.fd_not_found()?)), } } else if this.tcx.sess.target.os == "macos" && cmd == this.eval_libc_i32("F_FULLFSYNC") { // Reject if isolation is enabled. if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("`fcntl`", reject_with)?; this.set_last_error_from_io_error(ErrorKind::PermissionDenied.into())?; - return Ok(Scalar::from_i32(-1)); + return interp_ok(Scalar::from_i32(-1)); } this.ffullsync_fd(fd_num) @@ -532,12 +532,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let fd_num = this.read_scalar(fd_op)?.to_i32()?; let Some(fd) = this.machine.fds.remove(fd_num) else { - return Ok(Scalar::from_i32(this.fd_not_found()?)); + return interp_ok(Scalar::from_i32(this.fd_not_found()?)); }; let result = fd.close(this.machine.communicate(), this)?; // return `0` if close is successful let result = result.map(|()| 0i32); - Ok(Scalar::from_i32(this.try_unwrap_io_result(result)?)) + interp_ok(Scalar::from_i32(this.try_unwrap_io_result(result)?)) } /// Function used when a file descriptor does not exist. It returns `Ok(-1)`and sets @@ -548,7 +548,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let this = self.eval_context_mut(); let ebadf = this.eval_libc("EBADF"); this.set_last_error(ebadf)?; - Ok((-1).into()) + interp_ok((-1).into()) } /// Read data from `fd` into buffer specified by `buf` and `count`. @@ -586,7 +586,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { trace!("read: FD not found"); let res: i32 = this.fd_not_found()?; this.write_int(res, dest)?; - return Ok(()); + return interp_ok(()); }; trace!("read: FD mapped to {fd:?}"); @@ -601,12 +601,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let einval = this.eval_libc("EINVAL"); this.set_last_error(einval)?; this.write_int(-1, dest)?; - return Ok(()); + return interp_ok(()); }; fd.pread(communicate, offset, buf, count, dest, this)? } }; - Ok(()) + interp_ok(()) } fn write( @@ -636,7 +636,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let Some(fd) = this.machine.fds.get(fd_num) else { let res: i32 = this.fd_not_found()?; this.write_int(res, dest)?; - return Ok(()); + return interp_ok(()); }; match offset { @@ -646,12 +646,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let einval = this.eval_libc("EINVAL"); this.set_last_error(einval)?; this.write_int(-1, dest)?; - return Ok(()); + return interp_ok(()); }; fd.pwrite(communicate, buf, count, offset, dest, this)? } }; - Ok(()) + interp_ok(()) } /// Helper to implement `FileDescription::read`: @@ -675,12 +675,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_bytes_ptr(buf, bytes[..read_bytes].iter().copied())?; // The actual read size is always less than what got originally requested so this cannot fail. this.write_int(u64::try_from(read_bytes).unwrap(), dest)?; - Ok(()) + interp_ok(()) } Err(e) => { this.set_last_error_from_io_error(e)?; this.write_int(-1, dest)?; - Ok(()) + interp_ok(()) } } } @@ -695,6 +695,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let this = self.eval_context_mut(); let result = this.try_unwrap_io_result(result.map(|c| i64::try_from(c).unwrap()))?; this.write_int(result, dest)?; - Ok(()) + interp_ok(()) } } diff --git a/src/tools/miri/src/shims/unix/foreign_items.rs b/src/tools/miri/src/shims/unix/foreign_items.rs index 528d068ea92..b35fe4487b2 100644 --- a/src/tools/miri/src/shims/unix/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/foreign_items.rs @@ -828,7 +828,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // This function looks and behaves excatly like miri_start_unwind. let [payload] = this.check_shim(abi, Abi::C { unwind: true }, link_name, args)?; this.handle_miri_start_unwind(payload)?; - return Ok(EmulateItemResult::NeedsUnwind); + return interp_ok(EmulateItemResult::NeedsUnwind); } "getuid" => { let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; @@ -944,11 +944,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { "linux" => linux::EvalContextExt::emulate_foreign_item_inner(this, link_name, abi, args, dest), "macos" => macos::EvalContextExt::emulate_foreign_item_inner(this, link_name, abi, args, dest), "solaris" | "illumos" => solarish::EvalContextExt::emulate_foreign_item_inner(this, link_name, abi, args, dest), - _ => Ok(EmulateItemResult::NotSupported), + _ => interp_ok(EmulateItemResult::NotSupported), }; } }; - Ok(EmulateItemResult::NeedsReturn) + interp_ok(EmulateItemResult::NeedsReturn) } } diff --git a/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs b/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs index 36f25767a8e..e89dd488a2f 100644 --- a/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs @@ -84,8 +84,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_null(dest)?; } - _ => return Ok(EmulateItemResult::NotSupported), + _ => return interp_ok(EmulateItemResult::NotSupported), } - Ok(EmulateItemResult::NeedsReturn) + interp_ok(EmulateItemResult::NeedsReturn) } } diff --git a/src/tools/miri/src/shims/unix/fs.rs b/src/tools/miri/src/shims/unix/fs.rs index 92514b67bea..56280982e6e 100644 --- a/src/tools/miri/src/shims/unix/fs.rs +++ b/src/tools/miri/src/shims/unix/fs.rs @@ -121,7 +121,7 @@ impl FileDescription for FileHandle { offset: SeekFrom, ) -> InterpResult<'tcx, io::Result> { assert!(communicate_allowed, "isolation should have prevented even opening a file"); - Ok((&mut &self.file).seek(offset)) + interp_ok((&mut &self.file).seek(offset)) } fn close<'tcx>( @@ -136,7 +136,7 @@ impl FileDescription for FileHandle { // to handle possible errors correctly. let result = self.file.sync_all(); // Now we actually close the file and return the result. - Ok(result) + interp_ok(result) } else { // We drop the file, this closes it but ignores any errors // produced when closing it. This is done because @@ -144,7 +144,7 @@ impl FileDescription for FileHandle { // `/dev/urandom` which are read-only. Check // https://github.com/rust-lang/miri/issues/999#issuecomment-568920439 // for a deeper discussion. - Ok(Ok(())) + interp_ok(Ok(())) } } @@ -179,7 +179,7 @@ impl FileDescription for FileHandle { } ret => panic!("Unexpected return value from flock: {ret}"), }; - Ok(res) + interp_ok(res) } #[cfg(target_family = "windows")] @@ -231,7 +231,7 @@ impl FileDescription for FileHandle { } _ => panic!("Unexpected return value: {ret}"), }; - Ok(res) + interp_ok(res) } #[cfg(not(any(target_family = "unix", target_family = "windows")))] @@ -289,7 +289,7 @@ trait EvalContextExtPrivate<'tcx>: crate::MiriInterpCxExt<'tcx> { &buf, )?; - Ok(0) + interp_ok(0) } fn file_type_to_d_type( @@ -303,26 +303,30 @@ trait EvalContextExtPrivate<'tcx>: crate::MiriInterpCxExt<'tcx> { match file_type { Ok(file_type) => { match () { - _ if file_type.is_dir() => Ok(this.eval_libc("DT_DIR").to_u8()?.into()), - _ if file_type.is_file() => Ok(this.eval_libc("DT_REG").to_u8()?.into()), - _ if file_type.is_symlink() => Ok(this.eval_libc("DT_LNK").to_u8()?.into()), + _ if file_type.is_dir() => interp_ok(this.eval_libc("DT_DIR").to_u8()?.into()), + _ if file_type.is_file() => interp_ok(this.eval_libc("DT_REG").to_u8()?.into()), + _ if file_type.is_symlink() => + interp_ok(this.eval_libc("DT_LNK").to_u8()?.into()), // Certain file types are only supported when the host is a Unix system. #[cfg(unix)] _ if file_type.is_block_device() => - Ok(this.eval_libc("DT_BLK").to_u8()?.into()), + interp_ok(this.eval_libc("DT_BLK").to_u8()?.into()), #[cfg(unix)] - _ if file_type.is_char_device() => Ok(this.eval_libc("DT_CHR").to_u8()?.into()), + _ if file_type.is_char_device() => + interp_ok(this.eval_libc("DT_CHR").to_u8()?.into()), #[cfg(unix)] - _ if file_type.is_fifo() => Ok(this.eval_libc("DT_FIFO").to_u8()?.into()), + _ if file_type.is_fifo() => + interp_ok(this.eval_libc("DT_FIFO").to_u8()?.into()), #[cfg(unix)] - _ if file_type.is_socket() => Ok(this.eval_libc("DT_SOCK").to_u8()?.into()), + _ if file_type.is_socket() => + interp_ok(this.eval_libc("DT_SOCK").to_u8()?.into()), // Fallback - _ => Ok(this.eval_libc("DT_UNKNOWN").to_u8()?.into()), + _ => interp_ok(this.eval_libc("DT_UNKNOWN").to_u8()?.into()), } } Err(e) => match e.raw_os_error() { - Some(error) => Ok(error), + Some(error) => interp_ok(error), None => throw_unsup_format!( "the error {} couldn't be converted to a return value", @@ -524,7 +528,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // if the flag contains `O_TMPFILE` then we return a graceful error let eopnotsupp = this.eval_libc("EOPNOTSUPP"); this.set_last_error(eopnotsupp)?; - return Ok(Scalar::from_i32(-1)); + return interp_ok(Scalar::from_i32(-1)); } } @@ -545,7 +549,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { if path.is_symlink() { let eloop = this.eval_libc("ELOOP"); this.set_last_error(eloop)?; - return Ok(Scalar::from_i32(-1)); + return interp_ok(Scalar::from_i32(-1)); } } mirror |= o_nofollow; @@ -561,14 +565,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("`open`", reject_with)?; this.set_last_error_from_io_error(ErrorKind::PermissionDenied.into())?; - return Ok(Scalar::from_i32(-1)); + return interp_ok(Scalar::from_i32(-1)); } let fd = options .open(path) .map(|file| this.machine.fds.insert_new(FileHandle { file, writable })); - Ok(Scalar::from_i32(this.try_unwrap_io_result(fd)?)) + interp_ok(Scalar::from_i32(this.try_unwrap_io_result(fd)?)) } fn lseek64(&mut self, fd_num: i32, offset: i128, whence: i32) -> InterpResult<'tcx, Scalar> { @@ -581,7 +585,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Negative offsets return `EINVAL`. let einval = this.eval_libc("EINVAL"); this.set_last_error(einval)?; - return Ok(Scalar::from_i64(-1)); + return interp_ok(Scalar::from_i64(-1)); } else { SeekFrom::Start(u64::try_from(offset).unwrap()) } @@ -592,19 +596,19 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } else { let einval = this.eval_libc("EINVAL"); this.set_last_error(einval)?; - return Ok(Scalar::from_i64(-1)); + return interp_ok(Scalar::from_i64(-1)); }; let communicate = this.machine.communicate(); let Some(fd) = this.machine.fds.get(fd_num) else { - return Ok(Scalar::from_i64(this.fd_not_found()?)); + return interp_ok(Scalar::from_i64(this.fd_not_found()?)); }; let result = fd.seek(communicate, seek_from)?.map(|offset| i64::try_from(offset).unwrap()); drop(fd); let result = this.try_unwrap_io_result(result)?; - Ok(Scalar::from_i64(result)) + interp_ok(Scalar::from_i64(result)) } fn unlink(&mut self, path_op: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> { @@ -616,11 +620,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("`unlink`", reject_with)?; this.set_last_error_from_io_error(ErrorKind::PermissionDenied.into())?; - return Ok(Scalar::from_i32(-1)); + return interp_ok(Scalar::from_i32(-1)); } let result = remove_file(path).map(|_| 0); - Ok(Scalar::from_i32(this.try_unwrap_io_result(result)?)) + interp_ok(Scalar::from_i32(this.try_unwrap_io_result(result)?)) } fn symlink( @@ -647,11 +651,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("`symlink`", reject_with)?; this.set_last_error_from_io_error(ErrorKind::PermissionDenied.into())?; - return Ok(Scalar::from_i32(-1)); + return interp_ok(Scalar::from_i32(-1)); } let result = create_link(&target, &linkpath).map(|_| 0); - Ok(Scalar::from_i32(this.try_unwrap_io_result(result)?)) + interp_ok(Scalar::from_i32(this.try_unwrap_io_result(result)?)) } fn macos_fbsd_stat( @@ -673,16 +677,16 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.reject_in_isolation("`stat`", reject_with)?; let eacc = this.eval_libc("EACCES"); this.set_last_error(eacc)?; - return Ok(Scalar::from_i32(-1)); + return interp_ok(Scalar::from_i32(-1)); } // `stat` always follows symlinks. let metadata = match FileMetadata::from_path(this, &path, true)? { Some(metadata) => metadata, - None => return Ok(Scalar::from_i32(-1)), // `FileMetadata` has set errno + None => return interp_ok(Scalar::from_i32(-1)), // `FileMetadata` has set errno }; - Ok(Scalar::from_i32(this.macos_stat_write_buf(metadata, buf_op)?)) + interp_ok(Scalar::from_i32(this.macos_stat_write_buf(metadata, buf_op)?)) } // `lstat` is used to get symlink metadata. @@ -705,15 +709,15 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.reject_in_isolation("`lstat`", reject_with)?; let eacc = this.eval_libc("EACCES"); this.set_last_error(eacc)?; - return Ok(Scalar::from_i32(-1)); + return interp_ok(Scalar::from_i32(-1)); } let metadata = match FileMetadata::from_path(this, &path, false)? { Some(metadata) => metadata, - None => return Ok(Scalar::from_i32(-1)), // `FileMetadata` has set errno + None => return interp_ok(Scalar::from_i32(-1)), // `FileMetadata` has set errno }; - Ok(Scalar::from_i32(this.macos_stat_write_buf(metadata, buf_op)?)) + interp_ok(Scalar::from_i32(this.macos_stat_write_buf(metadata, buf_op)?)) } fn macos_fbsd_fstat( @@ -733,14 +737,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("`fstat`", reject_with)?; // Set error code as "EBADF" (bad fd) - return Ok(Scalar::from_i32(this.fd_not_found()?)); + return interp_ok(Scalar::from_i32(this.fd_not_found()?)); } let metadata = match FileMetadata::from_fd_num(this, fd)? { Some(metadata) => metadata, - None => return Ok(Scalar::from_i32(-1)), + None => return interp_ok(Scalar::from_i32(-1)), }; - Ok(Scalar::from_i32(this.macos_stat_write_buf(metadata, buf_op)?)) + interp_ok(Scalar::from_i32(this.macos_stat_write_buf(metadata, buf_op)?)) } fn linux_statx( @@ -765,7 +769,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { if this.ptr_is_null(statxbuf_ptr)? || this.ptr_is_null(pathname_ptr)? { let efault = this.eval_libc("EFAULT"); this.set_last_error(efault)?; - return Ok(Scalar::from_i32(-1)); + return interp_ok(Scalar::from_i32(-1)); } let statxbuf = this.deref_pointer_as(statxbuf_op, this.libc_ty_layout("statx"))?; @@ -807,7 +811,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.eval_libc("EBADF") }; this.set_last_error(ecode)?; - return Ok(Scalar::from_i32(-1)); + return interp_ok(Scalar::from_i32(-1)); } // the `_mask_op` parameter specifies the file information that the caller requested. @@ -829,7 +833,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { }; let metadata = match metadata { Some(metadata) => metadata, - None => return Ok(Scalar::from_i32(-1)), + None => return interp_ok(Scalar::from_i32(-1)), }; // The `mode` field specifies the type of the file and the permissions over the file for @@ -848,25 +852,25 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { .accessed .map(|tup| { mask |= this.eval_libc_u32("STATX_ATIME"); - InterpResult::Ok(tup) + interp_ok(tup) }) - .unwrap_or_else(|| Ok((0, 0)))?; + .unwrap_or_else(|| interp_ok((0, 0)))?; let (created_sec, created_nsec) = metadata .created .map(|tup| { mask |= this.eval_libc_u32("STATX_BTIME"); - InterpResult::Ok(tup) + interp_ok(tup) }) - .unwrap_or_else(|| Ok((0, 0)))?; + .unwrap_or_else(|| interp_ok((0, 0)))?; let (modified_sec, modified_nsec) = metadata .modified .map(|tup| { mask |= this.eval_libc_u32("STATX_MTIME"); - InterpResult::Ok(tup) + interp_ok(tup) }) - .unwrap_or_else(|| Ok((0, 0)))?; + .unwrap_or_else(|| interp_ok((0, 0)))?; // Now we write everything to `statxbuf`. We write a zero for the unavailable fields. this.write_int_fields_named( @@ -922,7 +926,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { &this.project_field_named(&statxbuf, "stx_mtime")?, )?; - Ok(Scalar::from_i32(0)) + interp_ok(Scalar::from_i32(0)) } fn rename( @@ -938,7 +942,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { if this.ptr_is_null(oldpath_ptr)? || this.ptr_is_null(newpath_ptr)? { let efault = this.eval_libc("EFAULT"); this.set_last_error(efault)?; - return Ok(Scalar::from_i32(-1)); + return interp_ok(Scalar::from_i32(-1)); } let oldpath = this.read_path_from_c_str(oldpath_ptr)?; @@ -948,12 +952,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("`rename`", reject_with)?; this.set_last_error_from_io_error(ErrorKind::PermissionDenied.into())?; - return Ok(Scalar::from_i32(-1)); + return interp_ok(Scalar::from_i32(-1)); } let result = rename(oldpath, newpath).map(|_| 0); - Ok(Scalar::from_i32(this.try_unwrap_io_result(result)?)) + interp_ok(Scalar::from_i32(this.try_unwrap_io_result(result)?)) } fn mkdir(&mut self, path_op: &OpTy<'tcx>, mode_op: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> { @@ -972,7 +976,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("`mkdir`", reject_with)?; this.set_last_error_from_io_error(ErrorKind::PermissionDenied.into())?; - return Ok(Scalar::from_i32(-1)); + return interp_ok(Scalar::from_i32(-1)); } #[cfg_attr(not(unix), allow(unused_mut))] @@ -988,7 +992,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let result = builder.create(path).map(|_| 0i32); - Ok(Scalar::from_i32(this.try_unwrap_io_result(result)?)) + interp_ok(Scalar::from_i32(this.try_unwrap_io_result(result)?)) } fn rmdir(&mut self, path_op: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> { @@ -1000,12 +1004,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("`rmdir`", reject_with)?; this.set_last_error_from_io_error(ErrorKind::PermissionDenied.into())?; - return Ok(Scalar::from_i32(-1)); + return interp_ok(Scalar::from_i32(-1)); } let result = remove_dir(path).map(|_| 0i32); - Ok(Scalar::from_i32(this.try_unwrap_io_result(result)?)) + interp_ok(Scalar::from_i32(this.try_unwrap_io_result(result)?)) } fn opendir(&mut self, name_op: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> { @@ -1018,7 +1022,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.reject_in_isolation("`opendir`", reject_with)?; let eacc = this.eval_libc("EACCES"); this.set_last_error(eacc)?; - return Ok(Scalar::null_ptr(this)); + return interp_ok(Scalar::null_ptr(this)); } let result = read_dir(name); @@ -1030,11 +1034,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // The libc API for opendir says that this method returns a pointer to an opaque // structure, but we are returning an ID number. Thus, pass it as a scalar of // pointer width. - Ok(Scalar::from_target_usize(id, this)) + interp_ok(Scalar::from_target_usize(id, this)) } Err(e) => { this.set_last_error_from_io_error(e)?; - Ok(Scalar::null_ptr(this)) + interp_ok(Scalar::null_ptr(this)) } } } @@ -1051,7 +1055,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.reject_in_isolation("`readdir`", reject_with)?; let eacc = this.eval_libc("EBADF"); this.set_last_error(eacc)?; - return Ok(Scalar::null_ptr(this)); + return interp_ok(Scalar::null_ptr(this)); } let open_dir = this.machine.dirs.streams.get_mut(&dirp).ok_or_else(|| { @@ -1129,7 +1133,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.deallocate_ptr(old_entry, None, MiriMemoryKind::Runtime.into())?; } - Ok(Scalar::from_maybe_pointer(entry.unwrap_or_else(Pointer::null), this)) + interp_ok(Scalar::from_maybe_pointer(entry.unwrap_or_else(Pointer::null), this)) } fn macos_fbsd_readdir_r( @@ -1150,13 +1154,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("`readdir_r`", reject_with)?; // Set error code as "EBADF" (bad fd) - return Ok(Scalar::from_i32(this.fd_not_found()?)); + return interp_ok(Scalar::from_i32(this.fd_not_found()?)); } let open_dir = this.machine.dirs.streams.get_mut(&dirp).ok_or_else(|| { err_unsup_format!("the DIR pointer passed to readdir_r did not come from opendir") })?; - Ok(Scalar::from_i32(match open_dir.read_dir.next() { + interp_ok(Scalar::from_i32(match open_dir.read_dir.next() { Some(Ok(dir_entry)) => { // Write into entry, write pointer to result, return 0 on success. // The name is written with write_os_str_to_c_str, while the rest of the @@ -1261,18 +1265,20 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let dirp = this.read_target_usize(dirp_op)?; // Reject if isolation is enabled. - Ok(Scalar::from_i32(if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { - this.reject_in_isolation("`closedir`", reject_with)?; - this.fd_not_found()? - } else if let Some(open_dir) = this.machine.dirs.streams.remove(&dirp) { - if let Some(entry) = open_dir.entry { - this.deallocate_ptr(entry, None, MiriMemoryKind::Runtime.into())?; - } - drop(open_dir); - 0 - } else { - this.fd_not_found()? - })) + interp_ok(Scalar::from_i32( + if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { + this.reject_in_isolation("`closedir`", reject_with)?; + this.fd_not_found()? + } else if let Some(open_dir) = this.machine.dirs.streams.remove(&dirp) { + if let Some(entry) = open_dir.entry { + this.deallocate_ptr(entry, None, MiriMemoryKind::Runtime.into())?; + } + drop(open_dir); + 0 + } else { + this.fd_not_found()? + }, + )) } fn ftruncate64(&mut self, fd_num: i32, length: i128) -> InterpResult<'tcx, Scalar> { @@ -1282,11 +1288,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("`ftruncate64`", reject_with)?; // Set error code as "EBADF" (bad fd) - return Ok(Scalar::from_i32(this.fd_not_found()?)); + return interp_ok(Scalar::from_i32(this.fd_not_found()?)); } let Some(fd) = this.machine.fds.get(fd_num) else { - return Ok(Scalar::from_i32(this.fd_not_found()?)); + return interp_ok(Scalar::from_i32(this.fd_not_found()?)); }; // FIXME: Support ftruncate64 for all FDs @@ -1299,19 +1305,19 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let result = file.set_len(length); drop(fd); let result = this.try_unwrap_io_result(result.map(|_| 0i32))?; - Ok(Scalar::from_i32(result)) + interp_ok(Scalar::from_i32(result)) } else { drop(fd); let einval = this.eval_libc("EINVAL"); this.set_last_error(einval)?; - Ok(Scalar::from_i32(-1)) + interp_ok(Scalar::from_i32(-1)) } } else { drop(fd); // The file is not writable let einval = this.eval_libc("EINVAL"); this.set_last_error(einval)?; - Ok(Scalar::from_i32(-1)) + interp_ok(Scalar::from_i32(-1)) } } @@ -1329,7 +1335,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("`fsync`", reject_with)?; // Set error code as "EBADF" (bad fd) - return Ok(Scalar::from_i32(this.fd_not_found()?)); + return interp_ok(Scalar::from_i32(this.fd_not_found()?)); } self.ffullsync_fd(fd) @@ -1338,7 +1344,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn ffullsync_fd(&mut self, fd_num: i32) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); let Some(fd) = this.machine.fds.get(fd_num) else { - return Ok(Scalar::from_i32(this.fd_not_found()?)); + return interp_ok(Scalar::from_i32(this.fd_not_found()?)); }; // Only regular files support synchronization. let FileHandle { file, writable } = fd.downcast::().ok_or_else(|| { @@ -1346,7 +1352,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { })?; let io_result = maybe_sync_file(file, *writable, File::sync_all); drop(fd); - Ok(Scalar::from_i32(this.try_unwrap_io_result(io_result)?)) + interp_ok(Scalar::from_i32(this.try_unwrap_io_result(io_result)?)) } fn fdatasync(&mut self, fd_op: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> { @@ -1358,11 +1364,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("`fdatasync`", reject_with)?; // Set error code as "EBADF" (bad fd) - return Ok(Scalar::from_i32(this.fd_not_found()?)); + return interp_ok(Scalar::from_i32(this.fd_not_found()?)); } let Some(fd) = this.machine.fds.get(fd) else { - return Ok(Scalar::from_i32(this.fd_not_found()?)); + return interp_ok(Scalar::from_i32(this.fd_not_found()?)); }; // Only regular files support synchronization. let FileHandle { file, writable } = fd.downcast::().ok_or_else(|| { @@ -1370,7 +1376,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { })?; let io_result = maybe_sync_file(file, *writable, File::sync_data); drop(fd); - Ok(Scalar::from_i32(this.try_unwrap_io_result(io_result)?)) + interp_ok(Scalar::from_i32(this.try_unwrap_io_result(io_result)?)) } fn sync_file_range( @@ -1390,7 +1396,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { if offset < 0 || nbytes < 0 { let einval = this.eval_libc("EINVAL"); this.set_last_error(einval)?; - return Ok(Scalar::from_i32(-1)); + return interp_ok(Scalar::from_i32(-1)); } let allowed_flags = this.eval_libc_i32("SYNC_FILE_RANGE_WAIT_BEFORE") | this.eval_libc_i32("SYNC_FILE_RANGE_WRITE") @@ -1398,18 +1404,18 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { if flags & allowed_flags != flags { let einval = this.eval_libc("EINVAL"); this.set_last_error(einval)?; - return Ok(Scalar::from_i32(-1)); + return interp_ok(Scalar::from_i32(-1)); } // Reject if isolation is enabled. if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("`sync_file_range`", reject_with)?; // Set error code as "EBADF" (bad fd) - return Ok(Scalar::from_i32(this.fd_not_found()?)); + return interp_ok(Scalar::from_i32(this.fd_not_found()?)); } let Some(fd) = this.machine.fds.get(fd) else { - return Ok(Scalar::from_i32(this.fd_not_found()?)); + return interp_ok(Scalar::from_i32(this.fd_not_found()?)); }; // Only regular files support synchronization. let FileHandle { file, writable } = fd.downcast::().ok_or_else(|| { @@ -1417,7 +1423,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { })?; let io_result = maybe_sync_file(file, *writable, File::sync_data); drop(fd); - Ok(Scalar::from_i32(this.try_unwrap_io_result(io_result)?)) + interp_ok(Scalar::from_i32(this.try_unwrap_io_result(io_result)?)) } fn readlink( @@ -1437,7 +1443,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.reject_in_isolation("`readlink`", reject_with)?; let eacc = this.eval_libc("EACCES"); this.set_last_error(eacc)?; - return Ok(-1); + return interp_ok(-1); } let result = std::fs::read_link(pathname); @@ -1456,11 +1462,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { path_bytes = &path_bytes[..bufsize] } this.write_bytes_ptr(buf, path_bytes.iter().copied())?; - Ok(path_bytes.len().try_into().unwrap()) + interp_ok(path_bytes.len().try_into().unwrap()) } Err(e) => { this.set_last_error_from_io_error(e)?; - Ok(-1) + interp_ok(-1) } } } @@ -1472,7 +1478,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let fd = this.read_scalar(miri_fd)?.to_i32()?; let error = if let Some(fd) = this.machine.fds.get(fd) { if fd.is_tty(this.machine.communicate()) { - return Ok(Scalar::from_i32(1)); + return interp_ok(Scalar::from_i32(1)); } else { this.eval_libc("ENOTTY") } @@ -1481,7 +1487,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.eval_libc("EBADF") }; this.set_last_error(error)?; - Ok(Scalar::from_i32(0)) + interp_ok(Scalar::from_i32(0)) } fn realpath( @@ -1500,7 +1506,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.reject_in_isolation("`realpath`", reject_with)?; let eacc = this.eval_libc("EACCES"); this.set_last_error(eacc)?; - return Ok(Scalar::from_target_usize(0, this)); + return interp_ok(Scalar::from_target_usize(0, this)); } let result = std::fs::canonicalize(pathname); @@ -1531,16 +1537,16 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // seems like a bit of a mess anyway: . let enametoolong = this.eval_libc("ENAMETOOLONG"); this.set_last_error(enametoolong)?; - return Ok(Scalar::from_target_usize(0, this)); + return interp_ok(Scalar::from_target_usize(0, this)); } processed_ptr }; - Ok(Scalar::from_maybe_pointer(dest, this)) + interp_ok(Scalar::from_maybe_pointer(dest, this)) } Err(e) => { this.set_last_error_from_io_error(e)?; - Ok(Scalar::from_target_usize(0, this)) + interp_ok(Scalar::from_target_usize(0, this)) } } } @@ -1575,7 +1581,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.reject_in_isolation("`mkstemp`", reject_with)?; let eacc = this.eval_libc("EACCES"); this.set_last_error(eacc)?; - return Ok(Scalar::from_i32(-1)); + return interp_ok(Scalar::from_i32(-1)); } // Get the bytes of the suffix we expect in _target_ encoding. @@ -1593,7 +1599,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { if last_six_char_bytes != suffix_bytes { let einval = this.eval_libc("EINVAL"); this.set_last_error(einval)?; - return Ok(Scalar::from_i32(-1)); + return interp_ok(Scalar::from_i32(-1)); } // At this point we know we have 6 ASCII 'X' characters as a suffix. @@ -1648,7 +1654,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { match file { Ok(f) => { let fd = this.machine.fds.insert_new(FileHandle { file: f, writable: true }); - return Ok(Scalar::from_i32(fd)); + return interp_ok(Scalar::from_i32(fd)); } Err(e) => match e.kind() { @@ -1659,7 +1665,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // "On error, -1 is returned, and errno is set to // indicate the error" this.set_last_error_from_io_error(e)?; - return Ok(Scalar::from_i32(-1)); + return interp_ok(Scalar::from_i32(-1)); } }, } @@ -1668,7 +1674,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // We ran out of attempts to create the file, return an error. let eexist = this.eval_libc("EEXIST"); this.set_last_error(eexist)?; - Ok(Scalar::from_i32(-1)) + interp_ok(Scalar::from_i32(-1)) } } @@ -1678,12 +1684,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn extract_sec_and_nsec<'tcx>( time: std::io::Result, ) -> InterpResult<'tcx, Option<(u64, u32)>> { - time.ok() - .map(|time| { + match time.ok() { + Some(time) => { let duration = system_time_to_duration(&time)?; - Ok((duration.as_secs(), duration.subsec_nanos())) - }) - .transpose() + interp_ok(Some((duration.as_secs(), duration.subsec_nanos()))) + } + None => interp_ok(None), + } } /// Stores a file's metadata in order to avoid code duplication in the different metadata related @@ -1738,7 +1745,7 @@ impl FileMetadata { Ok(metadata) => metadata, Err(e) => { ecx.set_last_error_from_io_error(e)?; - return Ok(None); + return interp_ok(None); } }; @@ -1761,6 +1768,6 @@ impl FileMetadata { let modified = extract_sec_and_nsec(metadata.modified())?; // FIXME: Provide more fields using platform specific methods. - Ok(Some(FileMetadata { mode, size, created, accessed, modified })) + interp_ok(Some(FileMetadata { mode, size, created, accessed, modified })) } } diff --git a/src/tools/miri/src/shims/unix/linux/epoll.rs b/src/tools/miri/src/shims/unix/linux/epoll.rs index 675a404ae11..08f1381caef 100644 --- a/src/tools/miri/src/shims/unix/linux/epoll.rs +++ b/src/tools/miri/src/shims/unix/linux/epoll.rs @@ -142,7 +142,7 @@ impl FileDescription for Epoll { _communicate_allowed: bool, _ecx: &mut MiriInterpCx<'tcx>, ) -> InterpResult<'tcx, io::Result<()>> { - Ok(Ok(())) + interp_ok(Ok(())) } } @@ -211,7 +211,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { epoll_instance.ready_list = Rc::new(RefCell::new(BTreeMap::new())); let fd = this.machine.fds.insert_new(Epoll::default()); - Ok(Scalar::from_i32(fd)) + interp_ok(Scalar::from_i32(fd)) } /// This function performs control operations on the `Epoll` instance referred to by the file @@ -263,12 +263,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { if epfd_value == fd { let einval = this.eval_libc("EINVAL"); this.set_last_error(einval)?; - return Ok(Scalar::from_i32(-1)); + return interp_ok(Scalar::from_i32(-1)); } // Check if epfd is a valid epoll file descriptor. let Some(epfd) = this.machine.fds.get(epfd_value) else { - return Ok(Scalar::from_i32(this.fd_not_found()?)); + return interp_ok(Scalar::from_i32(this.fd_not_found()?)); }; let epoll_file_description = epfd .downcast::() @@ -278,7 +278,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let ready_list = &epoll_file_description.ready_list; let Some(fd_ref) = this.machine.fds.get(fd) else { - return Ok(Scalar::from_i32(this.fd_not_found()?)); + return interp_ok(Scalar::from_i32(this.fd_not_found()?)); }; let id = fd_ref.get_id(); @@ -330,13 +330,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { if interest_list.contains_key(&epoll_key) { let eexist = this.eval_libc("EEXIST"); this.set_last_error(eexist)?; - return Ok(Scalar::from_i32(-1)); + return interp_ok(Scalar::from_i32(-1)); } } else { if !interest_list.contains_key(&epoll_key) { let enoent = this.eval_libc("ENOENT"); this.set_last_error(enoent)?; - return Ok(Scalar::from_i32(-1)); + return interp_ok(Scalar::from_i32(-1)); } } @@ -364,7 +364,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Notification will be returned for current epfd if there is event in the file // descriptor we registered. check_and_update_one_event_interest(&fd_ref, interest, id, this)?; - return Ok(Scalar::from_i32(0)); + return interp_ok(Scalar::from_i32(0)); } else if op == epoll_ctl_del { let epoll_key = (id, fd); @@ -372,7 +372,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let Some(epoll_interest) = interest_list.remove(&epoll_key) else { let enoent = this.eval_libc("ENOENT"); this.set_last_error(enoent)?; - return Ok(Scalar::from_i32(-1)); + return interp_ok(Scalar::from_i32(-1)); }; // All related Weak will fail to upgrade after the drop. drop(epoll_interest); @@ -390,9 +390,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { .unwrap() .retain(|event| event.upgrade().is_some()); - return Ok(Scalar::from_i32(0)); + return interp_ok(Scalar::from_i32(0)); } - Ok(Scalar::from_i32(-1)) + interp_ok(Scalar::from_i32(-1)) } /// The `epoll_wait()` system call waits for events on the `Epoll` @@ -446,7 +446,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let einval = this.eval_libc("EINVAL"); this.set_last_error(einval)?; this.write_int(-1, dest)?; - return Ok(()); + return interp_ok(()); } // This needs to come after the maxevents value check, or else maxevents.try_into().unwrap() @@ -459,7 +459,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let Some(epfd) = this.machine.fds.get(epfd_value) else { let result_value: i32 = this.fd_not_found()?; this.write_int(result_value, dest)?; - return Ok(()); + return interp_ok(()); }; // Create a weak ref of epfd and pass it to callback so we will make sure that epfd // is not close after the thread unblocks. @@ -508,7 +508,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } @unblock = |this| { blocking_epoll_callback(epfd_value, weak_epfd, &dest, &event, this)?; - Ok(()) + interp_ok(()) } @timeout = |this| { // No notification after blocking timeout. @@ -521,12 +521,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { .thread_id.borrow_mut() .retain(|&id| id != this.active_thread()); this.write_int(0, &dest)?; - Ok(()) + interp_ok(()) } ), ); } - Ok(()) + interp_ok(()) } /// For a specific file description, get its ready events and update the corresponding ready @@ -577,7 +577,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { for thread_id in waiter { this.unblock_thread(thread_id, BlockReason::Epoll)?; } - Ok(()) + interp_ok(()) } } @@ -623,9 +623,9 @@ fn check_and_update_one_event_interest<'tcx>( let event_instance = EpollEventInstance::new(flags, epoll_event_interest.data); // Triggers the notification by inserting it to the ready list. ready_list.insert(epoll_key, event_instance); - Ok(true) + interp_ok(true) } else { - Ok(false) + interp_ok(false) } } @@ -665,5 +665,5 @@ fn blocking_epoll_callback<'tcx>( } } ecx.write_int(num_of_events, dest)?; - Ok(()) + interp_ok(()) } diff --git a/src/tools/miri/src/shims/unix/linux/eventfd.rs b/src/tools/miri/src/shims/unix/linux/eventfd.rs index ab7652ca721..12e99644357 100644 --- a/src/tools/miri/src/shims/unix/linux/eventfd.rs +++ b/src/tools/miri/src/shims/unix/linux/eventfd.rs @@ -37,7 +37,7 @@ impl FileDescription for Event { // We only check the status of EPOLLIN and EPOLLOUT flags for eventfd. If other event flags // need to be supported in the future, the check should be added here. - Ok(EpollReadyEvents { + interp_ok(EpollReadyEvents { epollin: self.counter.get() != 0, epollout: self.counter.get() != MAX_COUNTER, ..EpollReadyEvents::new() @@ -49,7 +49,7 @@ impl FileDescription for Event { _communicate_allowed: bool, _ecx: &mut MiriInterpCx<'tcx>, ) -> InterpResult<'tcx, io::Result<()>> { - Ok(Ok(())) + interp_ok(Ok(())) } /// Read the counter in the buffer and return the counter if succeeded. @@ -68,7 +68,7 @@ impl FileDescription for Event { if len < ty.size.bytes_usize() { ecx.set_last_error_from_io_error(Error::from(ErrorKind::InvalidInput))?; ecx.write_int(-1, dest)?; - return Ok(()); + return interp_ok(()); } // eventfd read at the size of u64. @@ -80,7 +80,7 @@ impl FileDescription for Event { if self.is_nonblock { ecx.set_last_error_from_io_error(Error::from(ErrorKind::WouldBlock))?; ecx.write_int(-1, dest)?; - return Ok(()); + return interp_ok(()); } throw_unsup_format!("eventfd: blocking is unsupported"); @@ -100,7 +100,7 @@ impl FileDescription for Event { ecx.write_int(buf_place.layout.size.bytes(), dest)?; } - Ok(()) + interp_ok(()) } /// A write call adds the 8-byte integer value supplied in @@ -226,6 +226,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { clock: RefCell::new(VClock::default()), }); - Ok(Scalar::from_i32(fd_value)) + interp_ok(Scalar::from_i32(fd_value)) } } diff --git a/src/tools/miri/src/shims/unix/linux/foreign_items.rs b/src/tools/miri/src/shims/unix/linux/foreign_items.rs index e2e76aad7cd..9726dac7e51 100644 --- a/src/tools/miri/src/shims/unix/linux/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/linux/foreign_items.rs @@ -134,7 +134,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // The only supported flags are GRND_RANDOM and GRND_NONBLOCK, // neither of which have any effect on our current PRNG. // See for a discussion of argument sizes. - let _flags = this.read_scalar(&args[3])?.to_i32(); + let _flags = this.read_scalar(&args[3])?.to_i32()?; this.gen_random(ptr, len)?; this.write_scalar(Scalar::from_target_usize(len, this), dest)?; @@ -147,7 +147,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.handle_unsupported_foreign_item(format!( "can't execute syscall with ID {id}" ))?; - return Ok(EmulateItemResult::AlreadyJumped); + return interp_ok(EmulateItemResult::AlreadyJumped); } } } @@ -190,9 +190,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_null(dest)?; } - _ => return Ok(EmulateItemResult::NotSupported), + _ => return interp_ok(EmulateItemResult::NotSupported), }; - Ok(EmulateItemResult::NeedsReturn) + interp_ok(EmulateItemResult::NeedsReturn) } } diff --git a/src/tools/miri/src/shims/unix/linux/mem.rs b/src/tools/miri/src/shims/unix/linux/mem.rs index b11f60048a0..4f2e17d50c8 100644 --- a/src/tools/miri/src/shims/unix/linux/mem.rs +++ b/src/tools/miri/src/shims/unix/linux/mem.rs @@ -25,7 +25,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { #[allow(clippy::arithmetic_side_effects)] // PAGE_SIZE is nonzero if old_address.addr().bytes() % this.machine.page_size != 0 || new_size == 0 { this.set_last_error(this.eval_libc("EINVAL"))?; - return Ok(this.eval_libc("MAP_FAILED")); + return interp_ok(this.eval_libc("MAP_FAILED")); } if flags & this.eval_libc_i32("MREMAP_FIXED") != 0 { @@ -39,7 +39,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { if flags & this.eval_libc_i32("MREMAP_MAYMOVE") == 0 { // We only support MREMAP_MAYMOVE, so not passing the flag is just a failure this.set_last_error(this.eval_libc("EINVAL"))?; - return Ok(this.eval_libc("MAP_FAILED")); + return interp_ok(this.eval_libc("MAP_FAILED")); } let align = this.machine.page_align(); @@ -60,6 +60,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { .unwrap(); } - Ok(Scalar::from_pointer(ptr, this)) + interp_ok(Scalar::from_pointer(ptr, this)) } } diff --git a/src/tools/miri/src/shims/unix/linux/sync.rs b/src/tools/miri/src/shims/unix/linux/sync.rs index bd212039074..5108bc8299c 100644 --- a/src/tools/miri/src/shims/unix/linux/sync.rs +++ b/src/tools/miri/src/shims/unix/linux/sync.rs @@ -78,7 +78,7 @@ pub fn futex<'tcx>( let einval = this.eval_libc("EINVAL"); this.set_last_error(einval)?; this.write_scalar(Scalar::from_target_isize(-1, this), dest)?; - return Ok(()); + return interp_ok(()); } let timeout = this.deref_pointer_as(&args[3], this.libc_ty_layout("timespec"))?; @@ -91,7 +91,7 @@ pub fn futex<'tcx>( let einval = this.eval_libc("EINVAL"); this.set_last_error(einval)?; this.write_scalar(Scalar::from_target_isize(-1, this), dest)?; - return Ok(()); + return interp_ok(()); } }; let timeout_clock = if op & futex_realtime == futex_realtime { @@ -201,7 +201,7 @@ pub fn futex<'tcx>( let einval = this.eval_libc("EINVAL"); this.set_last_error(einval)?; this.write_scalar(Scalar::from_target_isize(-1, this), dest)?; - return Ok(()); + return interp_ok(()); } // Together with the SeqCst fence in futex_wait, this makes sure that futex_wait // will see the latest value on addr which could be changed by our caller @@ -221,5 +221,5 @@ pub fn futex<'tcx>( op => throw_unsup_format!("Miri does not support `futex` syscall with op={}", op), } - Ok(()) + interp_ok(()) } diff --git a/src/tools/miri/src/shims/unix/macos/foreign_items.rs b/src/tools/miri/src/shims/unix/macos/foreign_items.rs index ce4ea0816f0..2751d379dc0 100644 --- a/src/tools/miri/src/shims/unix/macos/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/macos/foreign_items.rs @@ -207,9 +207,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.os_unfair_lock_assert_not_owner(lock_op)?; } - _ => return Ok(EmulateItemResult::NotSupported), + _ => return interp_ok(EmulateItemResult::NotSupported), }; - Ok(EmulateItemResult::NeedsReturn) + interp_ok(EmulateItemResult::NeedsReturn) } } diff --git a/src/tools/miri/src/shims/unix/macos/sync.rs b/src/tools/miri/src/shims/unix/macos/sync.rs index 8f9237a1d46..2f96849d0d2 100644 --- a/src/tools/miri/src/shims/unix/macos/sync.rs +++ b/src/tools/miri/src/shims/unix/macos/sync.rs @@ -20,7 +20,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { // os_unfair_lock holds a 32-bit value, is initialized with zero and // must be assumed to be opaque. Therefore, we can just store our // internal mutex ID in the structure without anyone noticing. - this.mutex_get_or_create_id(&lock, 0, |_| Ok(None)) + this.mutex_get_or_create_id(&lock, 0, |_| interp_ok(None)) } } @@ -43,7 +43,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.mutex_lock(id); } - Ok(()) + interp_ok(()) } fn os_unfair_lock_trylock( @@ -63,7 +63,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_scalar(Scalar::from_bool(true), dest)?; } - Ok(()) + interp_ok(()) } fn os_unfair_lock_unlock(&mut self, lock_op: &OpTy<'tcx>) -> InterpResult<'tcx> { @@ -77,7 +77,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { )); } - Ok(()) + interp_ok(()) } fn os_unfair_lock_assert_owner(&mut self, lock_op: &OpTy<'tcx>) -> InterpResult<'tcx> { @@ -90,7 +90,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { )); } - Ok(()) + interp_ok(()) } fn os_unfair_lock_assert_not_owner(&mut self, lock_op: &OpTy<'tcx>) -> InterpResult<'tcx> { @@ -103,6 +103,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { )); } - Ok(()) + interp_ok(()) } } diff --git a/src/tools/miri/src/shims/unix/mem.rs b/src/tools/miri/src/shims/unix/mem.rs index 0397ba3b91a..9273748ef3b 100644 --- a/src/tools/miri/src/shims/unix/mem.rs +++ b/src/tools/miri/src/shims/unix/mem.rs @@ -49,7 +49,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { && matches!(&*this.tcx.sess.target.os, "macos" | "solaris" | "illumos") && (flags & map_fixed) != 0 { - return Ok(Scalar::from_maybe_pointer(Pointer::from_addr_invalid(addr), this)); + return interp_ok(Scalar::from_maybe_pointer(Pointer::from_addr_invalid(addr), this)); } let prot_read = this.eval_libc_i32("PROT_READ"); @@ -58,11 +58,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // First, we do some basic argument validation as required by mmap if (flags & (map_private | map_shared)).count_ones() != 1 { this.set_last_error(this.eval_libc("EINVAL"))?; - return Ok(this.eval_libc("MAP_FAILED")); + return interp_ok(this.eval_libc("MAP_FAILED")); } if length == 0 { this.set_last_error(this.eval_libc("EINVAL"))?; - return Ok(this.eval_libc("MAP_FAILED")); + return interp_ok(this.eval_libc("MAP_FAILED")); } // If a user tries to map a file, we want to loudly inform them that this is not going @@ -104,11 +104,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let align = this.machine.page_align(); let Some(map_length) = length.checked_next_multiple_of(this.machine.page_size) else { this.set_last_error(this.eval_libc("EINVAL"))?; - return Ok(this.eval_libc("MAP_FAILED")); + return interp_ok(this.eval_libc("MAP_FAILED")); }; if map_length > this.target_usize_max() { this.set_last_error(this.eval_libc("EINVAL"))?; - return Ok(this.eval_libc("MAP_FAILED")); + return interp_ok(this.eval_libc("MAP_FAILED")); } let ptr = @@ -121,7 +121,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { ) .unwrap(); - Ok(Scalar::from_pointer(ptr, this)) + interp_ok(Scalar::from_pointer(ptr, this)) } fn munmap(&mut self, addr: &OpTy<'tcx>, length: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> { @@ -135,16 +135,16 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { #[allow(clippy::arithmetic_side_effects)] // PAGE_SIZE is nonzero if addr.addr().bytes() % this.machine.page_size != 0 { this.set_last_error(this.eval_libc("EINVAL"))?; - return Ok(Scalar::from_i32(-1)); + return interp_ok(Scalar::from_i32(-1)); } let Some(length) = length.checked_next_multiple_of(this.machine.page_size) else { this.set_last_error(this.eval_libc("EINVAL"))?; - return Ok(Scalar::from_i32(-1)); + return interp_ok(Scalar::from_i32(-1)); }; if length > this.target_usize_max() { this.set_last_error(this.eval_libc("EINVAL"))?; - return Ok(this.eval_libc("MAP_FAILED")); + return interp_ok(this.eval_libc("MAP_FAILED")); } let length = Size::from_bytes(length); @@ -154,6 +154,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { MemoryKind::Machine(MiriMemoryKind::Mmap), )?; - Ok(Scalar::from_i32(0)) + interp_ok(Scalar::from_i32(0)) } } diff --git a/src/tools/miri/src/shims/unix/solarish/foreign_items.rs b/src/tools/miri/src/shims/unix/solarish/foreign_items.rs index a0cc4a62bfd..c10098f2733 100644 --- a/src/tools/miri/src/shims/unix/solarish/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/solarish/foreign_items.rs @@ -99,8 +99,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_null(dest)?; } - _ => return Ok(EmulateItemResult::NotSupported), + _ => return interp_ok(EmulateItemResult::NotSupported), } - Ok(EmulateItemResult::NeedsReturn) + interp_ok(EmulateItemResult::NeedsReturn) } } diff --git a/src/tools/miri/src/shims/unix/sync.rs b/src/tools/miri/src/shims/unix/sync.rs index fea994663c0..017291f81a2 100644 --- a/src/tools/miri/src/shims/unix/sync.rs +++ b/src/tools/miri/src/shims/unix/sync.rs @@ -10,7 +10,7 @@ use crate::*; #[inline] fn mutexattr_kind_offset<'tcx>(ecx: &MiriInterpCx<'tcx>) -> InterpResult<'tcx, u64> { - Ok(match &*ecx.tcx.sess.target.os { + interp_ok(match &*ecx.tcx.sess.target.os { "linux" | "illumos" | "solaris" | "macos" | "freebsd" | "android" => 0, os => throw_unsup_format!("`pthread_mutexattr` is not supported on {os}"), }) @@ -112,7 +112,7 @@ fn mutex_id_offset<'tcx>(ecx: &MiriInterpCx<'tcx>) -> InterpResult<'tcx, u64> { } } - Ok(offset) + interp_ok(offset) } /// Eagerly create and initialize a new mutex. @@ -125,7 +125,7 @@ fn mutex_create<'tcx>( let address = mutex.ptr().addr().bytes(); let data = Box::new(AdditionalMutexData { address, kind }); ecx.mutex_create(&mutex, mutex_id_offset(ecx)?, Some(data))?; - Ok(()) + interp_ok(()) } /// Returns the `MutexId` of the mutex stored at `mutex_op`. @@ -144,7 +144,7 @@ fn mutex_get_id<'tcx>( // an ID yet. We have to determine the mutex kind from the static initializer. let kind = mutex_kind_from_static_initializer(ecx, &mutex)?; - Ok(Some(Box::new(AdditionalMutexData { kind, address }))) + interp_ok(Some(Box::new(AdditionalMutexData { kind, address }))) })?; // Check that the mutex has not been moved since last use. @@ -155,7 +155,7 @@ fn mutex_get_id<'tcx>( throw_ub_format!("pthread_mutex_t can't be moved after first use") } - Ok(id) + interp_ok(id) } /// Returns the kind of a static initializer. @@ -163,7 +163,7 @@ fn mutex_kind_from_static_initializer<'tcx>( ecx: &MiriInterpCx<'tcx>, mutex: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx, MutexKind> { - Ok(match &*ecx.tcx.sess.target.os { + interp_ok(match &*ecx.tcx.sess.target.os { // Only linux has static initializers other than PTHREAD_MUTEX_DEFAULT. "linux" => { let offset = if ecx.pointer_size().bytes() == 8 { 16 } else { 12 }; @@ -186,7 +186,7 @@ fn mutex_translate_kind<'tcx>( ecx: &MiriInterpCx<'tcx>, kind: i32, ) -> InterpResult<'tcx, MutexKind> { - Ok(if kind == (ecx.eval_libc_i32("PTHREAD_MUTEX_NORMAL")) { + interp_ok(if kind == (ecx.eval_libc_i32("PTHREAD_MUTEX_NORMAL")) { MutexKind::Normal } else if kind == ecx.eval_libc_i32("PTHREAD_MUTEX_ERRORCHECK") { MutexKind::ErrorCheck @@ -237,7 +237,7 @@ fn rwlock_id_offset<'tcx>(ecx: &MiriInterpCx<'tcx>) -> InterpResult<'tcx, u64> { ); } - Ok(offset) + interp_ok(offset) } fn rwlock_get_id<'tcx>( @@ -248,7 +248,7 @@ fn rwlock_get_id<'tcx>( let address = rwlock.ptr().addr().bytes(); let id = ecx.rwlock_get_or_create_id(&rwlock, rwlock_id_offset(ecx)?, |_| { - Ok(Some(Box::new(AdditionalRwLockData { address }))) + interp_ok(Some(Box::new(AdditionalRwLockData { address }))) })?; // Check that the rwlock has not been moved since last use. @@ -259,7 +259,7 @@ fn rwlock_get_id<'tcx>( throw_ub_format!("pthread_rwlock_t can't be moved after first use") } - Ok(id) + interp_ok(id) } // pthread_condattr_t. @@ -268,7 +268,7 @@ fn rwlock_get_id<'tcx>( #[inline] fn condattr_clock_offset<'tcx>(ecx: &MiriInterpCx<'tcx>) -> InterpResult<'tcx, u64> { - Ok(match &*ecx.tcx.sess.target.os { + interp_ok(match &*ecx.tcx.sess.target.os { "linux" | "illumos" | "solaris" | "freebsd" | "android" => 0, // macOS does not have a clock attribute. os => throw_unsup_format!("`pthread_condattr` clock field is not supported on {os}"), @@ -292,7 +292,7 @@ fn cond_translate_clock_id<'tcx>( ecx: &MiriInterpCx<'tcx>, raw_id: i32, ) -> InterpResult<'tcx, ClockId> { - Ok(if raw_id == ecx.eval_libc_i32("CLOCK_REALTIME") { + interp_ok(if raw_id == ecx.eval_libc_i32("CLOCK_REALTIME") { ClockId::Realtime } else if raw_id == ecx.eval_libc_i32("CLOCK_MONOTONIC") { ClockId::Monotonic @@ -342,7 +342,7 @@ fn cond_id_offset<'tcx>(ecx: &MiriInterpCx<'tcx>) -> InterpResult<'tcx, u64> { ); } - Ok(offset) + interp_ok(offset) } #[derive(Debug, Clone, Copy)] @@ -369,7 +369,7 @@ fn cond_get_id<'tcx>( let address = cond.ptr().addr().bytes(); let id = ecx.condvar_get_or_create_id(&cond, cond_id_offset(ecx)?, |_ecx| { // This used the static initializer. The clock there is always CLOCK_REALTIME. - Ok(Some(Box::new(AdditionalCondData { address, clock_id: ClockId::Realtime }))) + interp_ok(Some(Box::new(AdditionalCondData { address, clock_id: ClockId::Realtime }))) })?; // Check that the mutex has not been moved since last use. @@ -380,7 +380,7 @@ fn cond_get_id<'tcx>( throw_ub_format!("pthread_cond_t can't be moved after first use") } - Ok(id) + interp_ok(id) } impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {} @@ -390,7 +390,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { mutexattr_set_kind(this, attr_op, PTHREAD_MUTEX_KIND_UNCHANGED)?; - Ok(()) + interp_ok(()) } fn pthread_mutexattr_settype( @@ -411,10 +411,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { mutexattr_set_kind(this, attr_op, kind)?; } else { let einval = this.eval_libc_i32("EINVAL"); - return Ok(Scalar::from_i32(einval)); + return interp_ok(Scalar::from_i32(einval)); } - Ok(Scalar::from_i32(0)) + interp_ok(Scalar::from_i32(0)) } fn pthread_mutexattr_destroy(&mut self, attr_op: &OpTy<'tcx>) -> InterpResult<'tcx, ()> { @@ -439,7 +439,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { &this.deref_pointer_as(attr_op, this.libc_ty_layout("pthread_mutexattr_t"))?, )?; - Ok(()) + interp_ok(()) } fn pthread_mutex_init( @@ -458,7 +458,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { mutex_create(this, mutex_op, kind)?; - Ok(()) + interp_ok(()) } fn pthread_mutex_lock( @@ -478,7 +478,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let owner_thread = this.mutex_get_owner(id); if owner_thread != this.active_thread() { this.mutex_enqueue_and_block(id, Some((Scalar::from_i32(0), dest.clone()))); - return Ok(()); + return interp_ok(()); } else { // Trying to acquire the same mutex again. match kind { @@ -498,7 +498,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { 0 }; this.write_scalar(Scalar::from_i32(ret), dest)?; - Ok(()) + interp_ok(()) } fn pthread_mutex_trylock(&mut self, mutex_op: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> { @@ -510,7 +510,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { .expect("data should always exist for pthread mutexes") .kind; - Ok(Scalar::from_i32(if this.mutex_is_locked(id) { + interp_ok(Scalar::from_i32(if this.mutex_is_locked(id) { let owner_thread = this.mutex_get_owner(id); if owner_thread != this.active_thread() { this.eval_libc_i32("EBUSY") @@ -542,7 +542,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { if let Some(_old_locked_count) = this.mutex_unlock(id)? { // The mutex was locked by the current thread. - Ok(Scalar::from_i32(0)) + interp_ok(Scalar::from_i32(0)) } else { // The mutex was locked by another thread or not locked at all. See // the “Unlock When Not Owner” column in @@ -557,7 +557,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { "unlocked a PTHREAD_MUTEX_NORMAL mutex that was not locked by the current thread" ), MutexKind::ErrorCheck | MutexKind::Recursive => - Ok(Scalar::from_i32(this.eval_libc_i32("EPERM"))), + interp_ok(Scalar::from_i32(this.eval_libc_i32("EPERM"))), } } } @@ -579,7 +579,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { )?; // FIXME: delete interpreter state associated with this mutex. - Ok(()) + interp_ok(()) } fn pthread_rwlock_rdlock( @@ -598,7 +598,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_null(dest)?; } - Ok(()) + interp_ok(()) } fn pthread_rwlock_tryrdlock(&mut self, rwlock_op: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> { @@ -607,10 +607,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let id = rwlock_get_id(this, rwlock_op)?; if this.rwlock_is_write_locked(id) { - Ok(Scalar::from_i32(this.eval_libc_i32("EBUSY"))) + interp_ok(Scalar::from_i32(this.eval_libc_i32("EBUSY"))) } else { this.rwlock_reader_lock(id); - Ok(Scalar::from_i32(0)) + interp_ok(Scalar::from_i32(0)) } } @@ -642,7 +642,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_null(dest)?; } - Ok(()) + interp_ok(()) } fn pthread_rwlock_trywrlock(&mut self, rwlock_op: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> { @@ -651,10 +651,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let id = rwlock_get_id(this, rwlock_op)?; if this.rwlock_is_locked(id) { - Ok(Scalar::from_i32(this.eval_libc_i32("EBUSY"))) + interp_ok(Scalar::from_i32(this.eval_libc_i32("EBUSY"))) } else { this.rwlock_writer_lock(id); - Ok(Scalar::from_i32(0)) + interp_ok(Scalar::from_i32(0)) } } @@ -665,7 +665,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { #[allow(clippy::if_same_then_else)] if this.rwlock_reader_unlock(id)? || this.rwlock_writer_unlock(id)? { - Ok(()) + interp_ok(()) } else { throw_ub_format!("unlocked an rwlock that was not locked by the active thread"); } @@ -688,7 +688,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { )?; // FIXME: delete interpreter state associated with this rwlock. - Ok(()) + interp_ok(()) } fn pthread_condattr_init(&mut self, attr_op: &OpTy<'tcx>) -> InterpResult<'tcx, ()> { @@ -703,7 +703,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { condattr_set_clock_id(this, attr_op, default_clock_id)?; } - Ok(()) + interp_ok(()) } fn pthread_condattr_setclock( @@ -720,10 +720,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { condattr_set_clock_id(this, attr_op, clock_id)?; } else { let einval = this.eval_libc_i32("EINVAL"); - return Ok(Scalar::from_i32(einval)); + return interp_ok(Scalar::from_i32(einval)); } - Ok(Scalar::from_i32(0)) + interp_ok(Scalar::from_i32(0)) } fn pthread_condattr_getclock( @@ -736,7 +736,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let clock_id = condattr_get_clock_id(this, attr_op)?; this.write_scalar(Scalar::from_i32(clock_id), &this.deref_pointer(clk_id_op)?)?; - Ok(()) + interp_ok(()) } fn pthread_condattr_destroy(&mut self, attr_op: &OpTy<'tcx>) -> InterpResult<'tcx, ()> { @@ -754,7 +754,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { &this.deref_pointer_as(attr_op, this.libc_ty_layout("pthread_condattr_t"))?, )?; - Ok(()) + interp_ok(()) } fn pthread_cond_init( @@ -781,21 +781,21 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { Some(Box::new(AdditionalCondData { address, clock_id })), )?; - Ok(()) + interp_ok(()) } fn pthread_cond_signal(&mut self, cond_op: &OpTy<'tcx>) -> InterpResult<'tcx, ()> { let this = self.eval_context_mut(); let id = cond_get_id(this, cond_op)?; this.condvar_signal(id)?; - Ok(()) + interp_ok(()) } fn pthread_cond_broadcast(&mut self, cond_op: &OpTy<'tcx>) -> InterpResult<'tcx, ()> { let this = self.eval_context_mut(); let id = cond_get_id(this, cond_op)?; while this.condvar_signal(id)? {} - Ok(()) + interp_ok(()) } fn pthread_cond_wait( @@ -818,7 +818,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { dest.clone(), )?; - Ok(()) + interp_ok(()) } fn pthread_cond_timedwait( @@ -845,7 +845,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { None => { let einval = this.eval_libc("EINVAL"); this.write_scalar(einval, dest)?; - return Ok(()); + return interp_ok(()); } }; let timeout_clock = match clock_id { @@ -865,7 +865,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { dest.clone(), )?; - Ok(()) + interp_ok(()) } fn pthread_cond_destroy(&mut self, cond_op: &OpTy<'tcx>) -> InterpResult<'tcx, ()> { @@ -882,6 +882,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_uninit(&this.deref_pointer_as(cond_op, this.libc_ty_layout("pthread_cond_t"))?)?; // FIXME: delete interpreter state associated with this condvar. - Ok(()) + interp_ok(()) } } diff --git a/src/tools/miri/src/shims/unix/thread.rs b/src/tools/miri/src/shims/unix/thread.rs index 96af4ae51ef..5515524f2f1 100644 --- a/src/tools/miri/src/shims/unix/thread.rs +++ b/src/tools/miri/src/shims/unix/thread.rs @@ -27,7 +27,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.machine.layouts.mut_raw_ptr, )?; - Ok(()) + interp_ok(()) } fn pthread_join(&mut self, thread: &OpTy<'tcx>, retval: &OpTy<'tcx>) -> InterpResult<'tcx, ()> { @@ -41,7 +41,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let thread_id = this.read_scalar(thread)?.to_int(this.libc_ty_layout("pthread_t").size)?; this.join_thread_exclusive(thread_id.try_into().expect("thread ID should fit in u32"))?; - Ok(()) + interp_ok(()) } fn pthread_detach(&mut self, thread: &OpTy<'tcx>) -> InterpResult<'tcx, ()> { @@ -53,14 +53,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { /*allow_terminated_joined*/ false, )?; - Ok(()) + interp_ok(()) } fn pthread_self(&mut self) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); let thread_id = this.active_thread(); - Ok(Scalar::from_uint(thread_id.to_u32(), this.libc_ty_layout("pthread_t").size)) + interp_ok(Scalar::from_uint(thread_id.to_u32(), this.libc_ty_layout("pthread_t").size)) } /// Set the name of the current thread. `max_name_len` is the maximal length of the name @@ -81,12 +81,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Comparing with `>=` to account for null terminator. if name.len() >= max_name_len { - return Ok(this.eval_libc("ERANGE")); + return interp_ok(this.eval_libc("ERANGE")); } this.set_thread_name(thread, name); - Ok(Scalar::from_u32(0)) + interp_ok(Scalar::from_u32(0)) } fn pthread_getname_np( @@ -106,7 +106,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let name = this.get_thread_name(thread).unwrap_or(b"").to_owned(); let (success, _written) = this.write_c_str(&name, name_out, len)?; - Ok(if success { Scalar::from_u32(0) } else { this.eval_libc("ERANGE") }) + interp_ok(if success { Scalar::from_u32(0) } else { this.eval_libc("ERANGE") }) } fn sched_yield(&mut self) -> InterpResult<'tcx, ()> { @@ -114,6 +114,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.yield_active_thread(); - Ok(()) + interp_ok(()) } } diff --git a/src/tools/miri/src/shims/unix/unnamed_socket.rs b/src/tools/miri/src/shims/unix/unnamed_socket.rs index d1bfa563387..763f9f24027 100644 --- a/src/tools/miri/src/shims/unix/unnamed_socket.rs +++ b/src/tools/miri/src/shims/unix/unnamed_socket.rs @@ -103,7 +103,7 @@ impl FileDescription for AnonSocket { epoll_ready_events.epollerr = true; } } - Ok(epoll_ready_events) + interp_ok(epoll_ready_events) } fn close<'tcx>( @@ -122,7 +122,7 @@ impl FileDescription for AnonSocket { // Notify peer fd that close has happened, since that can unblock reads and writes. ecx.check_and_update_readiness(&peer_fd)?; } - Ok(Ok(())) + interp_ok(Ok(())) } fn read<'tcx>( @@ -344,7 +344,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_scalar(sv0, &sv)?; this.write_scalar(sv1, &sv.offset(sv.layout.size, sv.layout, this)?)?; - Ok(Scalar::from_i32(0)) + interp_ok(Scalar::from_i32(0)) } fn pipe2( @@ -396,6 +396,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_scalar(pipefd0, &pipefd)?; this.write_scalar(pipefd1, &pipefd.offset(pipefd.layout.size, pipefd.layout, this)?)?; - Ok(Scalar::from_i32(0)) + interp_ok(Scalar::from_i32(0)) } } diff --git a/src/tools/miri/src/shims/wasi/foreign_items.rs b/src/tools/miri/src/shims/wasi/foreign_items.rs index e9fe90081d0..b5de950de9a 100644 --- a/src/tools/miri/src/shims/wasi/foreign_items.rs +++ b/src/tools/miri/src/shims/wasi/foreign_items.rs @@ -33,8 +33,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_pointer(res, dest)?; } - _ => return Ok(EmulateItemResult::NotSupported), + _ => return interp_ok(EmulateItemResult::NotSupported), } - Ok(EmulateItemResult::NeedsReturn) + interp_ok(EmulateItemResult::NeedsReturn) } } diff --git a/src/tools/miri/src/shims/windows/env.rs b/src/tools/miri/src/shims/windows/env.rs index 9707482b1e2..a6ace6f9bdc 100644 --- a/src/tools/miri/src/shims/windows/env.rs +++ b/src/tools/miri/src/shims/windows/env.rs @@ -24,12 +24,12 @@ impl WindowsEnvVars { _ecx: &mut InterpCx<'tcx, MiriMachine<'tcx>>, env_vars: FxHashMap, ) -> InterpResult<'tcx, Self> { - Ok(Self { map: env_vars }) + interp_ok(Self { map: env_vars }) } /// Implementation detail for [`InterpCx::get_env_var`]. pub(crate) fn get<'tcx>(&self, name: &OsStr) -> InterpResult<'tcx, Option> { - Ok(self.map.get(name).cloned()) + interp_ok(self.map.get(name).cloned()) } } @@ -52,7 +52,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let buf_size = this.read_scalar(size_op)?.to_u32()?; // in characters let name = this.read_os_str_from_wide_str(name_ptr)?; - Ok(match this.machine.env_vars.windows().map.get(&name).cloned() { + interp_ok(match this.machine.env_vars.windows().map.get(&name).cloned() { Some(val) => { Scalar::from_u32(windows_check_buffer_size(this.write_os_str_to_wide_str( &val, @@ -89,7 +89,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let envblock_ptr = this.alloc_os_str_as_wide_str(&env_vars, MiriMemoryKind::Runtime.into())?; // If the function succeeds, the return value is a pointer to the environment block of the current process. - Ok(envblock_ptr) + interp_ok(envblock_ptr) } #[allow(non_snake_case)] @@ -100,7 +100,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let env_block_ptr = this.read_pointer(env_block_op)?; this.deallocate_ptr(env_block_ptr, None, MiriMemoryKind::Runtime.into())?; // If the function succeeds, the return value is nonzero. - Ok(Scalar::from_i32(1)) + interp_ok(Scalar::from_i32(1)) } #[allow(non_snake_case)] @@ -128,11 +128,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } else if this.ptr_is_null(value_ptr)? { // Delete environment variable `{name}` if it exists. this.machine.env_vars.windows_mut().map.remove(&name); - Ok(this.eval_windows("c", "TRUE")) + interp_ok(this.eval_windows("c", "TRUE")) } else { let value = this.read_os_str_from_wide_str(value_ptr)?; this.machine.env_vars.windows_mut().map.insert(name, value); - Ok(this.eval_windows("c", "TRUE")) + interp_ok(this.eval_windows("c", "TRUE")) } } @@ -151,7 +151,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("`GetCurrentDirectoryW`", reject_with)?; this.set_last_error_from_io_error(ErrorKind::PermissionDenied.into())?; - return Ok(Scalar::from_u32(0)); + return interp_ok(Scalar::from_u32(0)); } // If we cannot get the current directory, we return 0 @@ -159,13 +159,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { Ok(cwd) => { // This can in fact return 0. It is up to the caller to set last_error to 0 // beforehand and check it afterwards to exclude that case. - return Ok(Scalar::from_u32(windows_check_buffer_size( + return interp_ok(Scalar::from_u32(windows_check_buffer_size( this.write_path_to_wide_str(&cwd, buf, size)?, ))); } Err(e) => this.set_last_error_from_io_error(e)?, } - Ok(Scalar::from_u32(0)) + interp_ok(Scalar::from_u32(0)) } #[allow(non_snake_case)] @@ -184,14 +184,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.reject_in_isolation("`SetCurrentDirectoryW`", reject_with)?; this.set_last_error_from_io_error(ErrorKind::PermissionDenied.into())?; - return Ok(this.eval_windows("c", "FALSE")); + return interp_ok(this.eval_windows("c", "FALSE")); } match env::set_current_dir(path) { - Ok(()) => Ok(this.eval_windows("c", "TRUE")), + Ok(()) => interp_ok(this.eval_windows("c", "TRUE")), Err(e) => { this.set_last_error_from_io_error(e)?; - Ok(this.eval_windows("c", "FALSE")) + interp_ok(this.eval_windows("c", "FALSE")) } } } @@ -201,7 +201,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let this = self.eval_context_mut(); this.assert_target_os("windows", "GetCurrentProcessId"); - Ok(Scalar::from_u32(this.get_pid())) + interp_ok(Scalar::from_u32(this.get_pid())) } #[allow(non_snake_case)] @@ -227,7 +227,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } // See for docs. - Ok(match directories::UserDirs::new() { + interp_ok(match directories::UserDirs::new() { Some(dirs) => { let home = dirs.home_dir(); let size_avail = if this.ptr_is_null(size.ptr())? { diff --git a/src/tools/miri/src/shims/windows/foreign_items.rs b/src/tools/miri/src/shims/windows/foreign_items.rs index 22634c509be..a4f40f9447e 100644 --- a/src/tools/miri/src/shims/windows/foreign_items.rs +++ b/src/tools/miri/src/shims/windows/foreign_items.rs @@ -22,7 +22,7 @@ pub fn is_dyn_sym(name: &str) -> bool { #[cfg(windows)] fn win_absolute<'tcx>(path: &Path) -> InterpResult<'tcx, io::Result> { // We are on Windows so we can simply let the host do this. - Ok(path::absolute(path)) + interp_ok(path::absolute(path)) } #[cfg(unix)] @@ -33,7 +33,7 @@ fn win_absolute<'tcx>(path: &Path) -> InterpResult<'tcx, io::Result> { // If it starts with `//` (these were backslashes but are already converted) // then this is a magic special path, we just leave it unchanged. if bytes.get(0).copied() == Some(b'/') && bytes.get(1).copied() == Some(b'/') { - return Ok(Ok(path.into())); + return interp_ok(Ok(path.into())); }; // Special treatment for Windows' magic filenames: they are treated as being relative to `\\.\`. let magic_filenames = &[ @@ -43,7 +43,7 @@ fn win_absolute<'tcx>(path: &Path) -> InterpResult<'tcx, io::Result> { if magic_filenames.iter().any(|m| m.as_bytes() == bytes) { let mut result: Vec = br"//./".into(); result.extend(bytes); - return Ok(Ok(bytes_to_os_str(&result)?.into())); + return interp_ok(Ok(bytes_to_os_str(&result)?.into())); } // Otherwise we try to do something kind of close to what Windows does, but this is probably not // right in all cases. We iterate over the components between `/`, and remove trailing `.`, @@ -71,7 +71,7 @@ fn win_absolute<'tcx>(path: &Path) -> InterpResult<'tcx, io::Result> { } } // Let the host `absolute` function do working-dir handling - Ok(path::absolute(bytes_to_os_str(&result)?)) + interp_ok(path::absolute(bytes_to_os_str(&result)?)) } impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {} @@ -769,12 +769,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // This function looks and behaves excatly like miri_start_unwind. let [payload] = this.check_shim(abi, Abi::C { unwind: true }, link_name, args)?; this.handle_miri_start_unwind(payload)?; - return Ok(EmulateItemResult::NeedsUnwind); + return interp_ok(EmulateItemResult::NeedsUnwind); } - _ => return Ok(EmulateItemResult::NotSupported), + _ => return interp_ok(EmulateItemResult::NotSupported), } - Ok(EmulateItemResult::NeedsReturn) + interp_ok(EmulateItemResult::NeedsReturn) } } diff --git a/src/tools/miri/src/shims/windows/handle.rs b/src/tools/miri/src/shims/windows/handle.rs index 0a8e0e8fdfb..69d78f58bed 100644 --- a/src/tools/miri/src/shims/windows/handle.rs +++ b/src/tools/miri/src/shims/windows/handle.rs @@ -139,10 +139,10 @@ impl Handle { signed_handle as u32 } else { // if a handle doesn't fit in an i32, it isn't valid. - return Ok(None); + return interp_ok(None); }; - Ok(Self::from_packed(handle)) + interp_ok(Self::from_packed(handle)) } } @@ -167,6 +167,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { _ => this.invalid_handle("CloseHandle")?, } - Ok(()) + interp_ok(()) } } diff --git a/src/tools/miri/src/shims/windows/sync.rs b/src/tools/miri/src/shims/windows/sync.rs index 5786b17e50c..6755c23039e 100644 --- a/src/tools/miri/src/shims/windows/sync.rs +++ b/src/tools/miri/src/shims/windows/sync.rs @@ -24,7 +24,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx, bool> { let this = self.eval_context_mut(); - Ok(match this.init_once_status(id) { + interp_ok(match this.init_once_status(id) { InitOnceStatus::Uninitialized => { this.init_once_begin(id); this.write_scalar(this.eval_windows("c", "TRUE"), pending_place)?; @@ -70,7 +70,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { if this.init_once_try_begin(id, &pending_place, dest)? { // Done! - return Ok(()); + return interp_ok(()); } // We have to block, and then try again when we are woken up. @@ -86,11 +86,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { @unblock = |this| { let ret = this.init_once_try_begin(id, &pending_place, &dest)?; assert!(ret, "we were woken up but init_once_try_begin still failed"); - Ok(()) + interp_ok(()) } ), ); - Ok(()) + interp_ok(()) } fn InitOnceComplete( @@ -130,7 +130,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.init_once_fail(id)?; } - Ok(this.eval_windows("c", "TRUE")) + interp_ok(this.eval_windows("c", "TRUE")) } fn WaitOnAddress( @@ -154,7 +154,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let invalid_param = this.eval_windows("c", "ERROR_INVALID_PARAMETER"); this.set_last_error(invalid_param)?; this.write_scalar(Scalar::from_i32(0), dest)?; - return Ok(()); + return interp_ok(()); }; let size = Size::from_bytes(size); @@ -188,7 +188,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_scalar(Scalar::from_i32(1), dest)?; - Ok(()) + interp_ok(()) } fn WakeByAddressSingle(&mut self, ptr_op: &OpTy<'tcx>) -> InterpResult<'tcx> { @@ -202,7 +202,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let addr = ptr.addr().bytes(); this.futex_wake(addr, u32::MAX)?; - Ok(()) + interp_ok(()) } fn WakeByAddressAll(&mut self, ptr_op: &OpTy<'tcx>) -> InterpResult<'tcx> { let this = self.eval_context_mut(); @@ -215,6 +215,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let addr = ptr.addr().bytes(); while this.futex_wake(addr, u32::MAX)? {} - Ok(()) + interp_ok(()) } } diff --git a/src/tools/miri/src/shims/windows/thread.rs b/src/tools/miri/src/shims/windows/thread.rs index a4c177311d4..a920abea3a8 100644 --- a/src/tools/miri/src/shims/windows/thread.rs +++ b/src/tools/miri/src/shims/windows/thread.rs @@ -79,6 +79,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.join_thread(thread)?; - Ok(0) + interp_ok(0) } } diff --git a/src/tools/miri/src/shims/x86/aesni.rs b/src/tools/miri/src/shims/x86/aesni.rs index dbbae0731e0..3a8138654fd 100644 --- a/src/tools/miri/src/shims/x86/aesni.rs +++ b/src/tools/miri/src/shims/x86/aesni.rs @@ -123,9 +123,9 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } // TODO: Implement the `llvm.x86.aesni.aeskeygenassist` when possible // with an external crate. - _ => return Ok(EmulateItemResult::NotSupported), + _ => return interp_ok(EmulateItemResult::NotSupported), } - Ok(EmulateItemResult::NeedsReturn) + interp_ok(EmulateItemResult::NeedsReturn) } } @@ -162,5 +162,5 @@ fn aes_round<'tcx>( this.write_scalar(Scalar::from_u128(res), &dest)?; } - Ok(()) + interp_ok(()) } diff --git a/src/tools/miri/src/shims/x86/avx.rs b/src/tools/miri/src/shims/x86/avx.rs index 169f8f8111a..080e7c8ce0b 100644 --- a/src/tools/miri/src/shims/x86/avx.rs +++ b/src/tools/miri/src/shims/x86/avx.rs @@ -348,8 +348,8 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // The only thing that needs to be ensured is the correct calling convention. let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; } - _ => return Ok(EmulateItemResult::NotSupported), + _ => return interp_ok(EmulateItemResult::NotSupported), } - Ok(EmulateItemResult::NeedsReturn) + interp_ok(EmulateItemResult::NeedsReturn) } } diff --git a/src/tools/miri/src/shims/x86/avx2.rs b/src/tools/miri/src/shims/x86/avx2.rs index 1dda1a10a05..331b693a3e4 100644 --- a/src/tools/miri/src/shims/x86/avx2.rs +++ b/src/tools/miri/src/shims/x86/avx2.rs @@ -435,8 +435,8 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { shift_simd_by_simd(this, left, right, which, dest)?; } - _ => return Ok(EmulateItemResult::NotSupported), + _ => return interp_ok(EmulateItemResult::NotSupported), } - Ok(EmulateItemResult::NeedsReturn) + interp_ok(EmulateItemResult::NeedsReturn) } } diff --git a/src/tools/miri/src/shims/x86/bmi.rs b/src/tools/miri/src/shims/x86/bmi.rs index e70757f4397..59e76abf179 100644 --- a/src/tools/miri/src/shims/x86/bmi.rs +++ b/src/tools/miri/src/shims/x86/bmi.rs @@ -30,7 +30,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.expect_target_feature_for_intrinsic(link_name, target_feature)?; if is_64_bit && this.tcx.sess.target.arch != "x86_64" { - return Ok(EmulateItemResult::NotSupported); + return interp_ok(EmulateItemResult::NotSupported); } let [left, right] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; @@ -93,7 +93,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } result } - _ => return Ok(EmulateItemResult::NotSupported), + _ => return interp_ok(EmulateItemResult::NotSupported), }; let result = if is_64_bit { @@ -103,6 +103,6 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { }; this.write_scalar(result, dest)?; - Ok(EmulateItemResult::NeedsReturn) + interp_ok(EmulateItemResult::NeedsReturn) } } diff --git a/src/tools/miri/src/shims/x86/mod.rs b/src/tools/miri/src/shims/x86/mod.rs index 8132de7d646..19c678cb7fa 100644 --- a/src/tools/miri/src/shims/x86/mod.rs +++ b/src/tools/miri/src/shims/x86/mod.rs @@ -43,7 +43,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // https://www.intel.com/content/www/us/en/docs/cpp-compiler/developer-guide-reference/2021-8/subborrow-u32-subborrow-u64.html "addcarry.32" | "addcarry.64" | "subborrow.32" | "subborrow.64" => { if unprefixed_name.ends_with("64") && this.tcx.sess.target.arch != "x86_64" { - return Ok(EmulateItemResult::NotSupported); + return interp_ok(EmulateItemResult::NotSupported); } let [cb_in, a, b] = this.check_shim(abi, Abi::Unadjusted, link_name, args)?; @@ -67,7 +67,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let is_u64 = unprefixed_name.ends_with("64"); if is_u64 && this.tcx.sess.target.arch != "x86_64" { - return Ok(EmulateItemResult::NotSupported); + return interp_ok(EmulateItemResult::NotSupported); } let [c_in, a, b, out] = this.check_shim(abi, Abi::Unadjusted, link_name, args)?; @@ -157,9 +157,9 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { ); } - _ => return Ok(EmulateItemResult::NotSupported), + _ => return interp_ok(EmulateItemResult::NotSupported), } - Ok(EmulateItemResult::NeedsReturn) + interp_ok(EmulateItemResult::NeedsReturn) } } @@ -244,7 +244,7 @@ impl FloatBinOp { this.expect_target_feature_for_intrinsic(intrinsic, "avx")?; unord = !unord; } - Ok(Self::Cmp { gt, lt, eq, unord }) + interp_ok(Self::Cmp { gt, lt, eq, unord }) } } @@ -266,7 +266,7 @@ fn bin_op_float<'tcx, F: rustc_apfloat::Float>( Some(std::cmp::Ordering::Equal) => eq, Some(std::cmp::Ordering::Greater) => gt, }; - Ok(bool_to_simd_element(res, Size::from_bits(F::BITS))) + interp_ok(bool_to_simd_element(res, Size::from_bits(F::BITS))) } FloatBinOp::Min => { let left_scalar = left.to_scalar(); @@ -280,9 +280,9 @@ fn bin_op_float<'tcx, F: rustc_apfloat::Float>( || right.is_nan() || left >= right { - Ok(right_scalar) + interp_ok(right_scalar) } else { - Ok(left_scalar) + interp_ok(left_scalar) } } FloatBinOp::Max => { @@ -297,9 +297,9 @@ fn bin_op_float<'tcx, F: rustc_apfloat::Float>( || right.is_nan() || left <= right { - Ok(right_scalar) + interp_ok(right_scalar) } else { - Ok(left_scalar) + interp_ok(left_scalar) } } } @@ -332,7 +332,7 @@ fn bin_op_simd_float_first<'tcx, F: rustc_apfloat::Float>( this.copy_op(&this.project_index(&left, i)?, &this.project_index(&dest, i)?)?; } - Ok(()) + interp_ok(()) } /// Performs `which` operation on each component of `left` and @@ -360,7 +360,7 @@ fn bin_op_simd_float_all<'tcx, F: rustc_apfloat::Float>( this.write_scalar(res, &dest)?; } - Ok(()) + interp_ok(()) } #[derive(Copy, Clone)] @@ -391,7 +391,7 @@ fn unary_op_f32<'tcx>( // Apply a relative error with a magnitude on the order of 2^-12 to simulate the // inaccuracy of RCP. let res = apply_random_float_error(this, div, -12); - Ok(Scalar::from_f32(res)) + interp_ok(Scalar::from_f32(res)) } FloatUnaryOp::Rsqrt => { let op = op.to_scalar().to_u32()?; @@ -401,7 +401,7 @@ fn unary_op_f32<'tcx>( // Apply a relative error with a magnitude on the order of 2^-12 to simulate the // inaccuracy of RSQRT. let res = apply_random_float_error(this, rsqrt, -12); - Ok(Scalar::from_f32(res)) + interp_ok(Scalar::from_f32(res)) } } } @@ -442,7 +442,7 @@ fn unary_op_ss<'tcx>( this.copy_op(&this.project_index(&op, i)?, &this.project_index(&dest, i)?)?; } - Ok(()) + interp_ok(()) } /// Performs `which` operation on each component of `op`, storing the @@ -466,7 +466,7 @@ fn unary_op_ps<'tcx>( this.write_scalar(res, &dest)?; } - Ok(()) + interp_ok(()) } enum ShiftOp { @@ -532,7 +532,7 @@ fn shift_simd_by_scalar<'tcx>( this.write_scalar(res, &dest)?; } - Ok(()) + interp_ok(()) } /// Shifts each element of `left` by the corresponding element of `right`. @@ -587,7 +587,7 @@ fn shift_simd_by_simd<'tcx>( this.write_scalar(res, &dest)?; } - Ok(()) + interp_ok(()) } /// Takes a 128-bit vector, transmutes it to `[u64; 2]` and extracts @@ -633,7 +633,7 @@ fn round_first<'tcx, F: rustc_apfloat::Float>( this.copy_op(&this.project_index(&left, i)?, &this.project_index(&dest, i)?)?; } - Ok(()) + interp_ok(()) } // Rounds all elements of `op` according to `rounding`. @@ -659,7 +659,7 @@ fn round_all<'tcx, F: rustc_apfloat::Float>( )?; } - Ok(()) + interp_ok(()) } /// Gets equivalent `rustc_apfloat::Round` from rounding mode immediate of @@ -671,14 +671,14 @@ fn rounding_from_imm<'tcx>(rounding: i32) -> InterpResult<'tcx, rustc_apfloat::R match rounding & !0b1000 { // When the third bit is 0, the rounding mode is determined by the // first two bits. - 0b000 => Ok(rustc_apfloat::Round::NearestTiesToEven), - 0b001 => Ok(rustc_apfloat::Round::TowardNegative), - 0b010 => Ok(rustc_apfloat::Round::TowardPositive), - 0b011 => Ok(rustc_apfloat::Round::TowardZero), + 0b000 => interp_ok(rustc_apfloat::Round::NearestTiesToEven), + 0b001 => interp_ok(rustc_apfloat::Round::TowardNegative), + 0b010 => interp_ok(rustc_apfloat::Round::TowardPositive), + 0b011 => interp_ok(rustc_apfloat::Round::TowardZero), // When the third bit is 1, the rounding mode is determined by the // SSE status register. Since we do not support modifying it from // Miri (or Rust), we assume it to be at its default mode (round-to-nearest). - 0b100..=0b111 => Ok(rustc_apfloat::Round::NearestTiesToEven), + 0b100..=0b111 => interp_ok(rustc_apfloat::Round::NearestTiesToEven), rounding => panic!("invalid rounding mode 0x{rounding:02x}"), } } @@ -717,7 +717,7 @@ fn convert_float_to_int<'tcx>( this.write_scalar(Scalar::from_int(0, dest.layout.size), &dest)?; } - Ok(()) + interp_ok(()) } /// Calculates absolute value of integers in `op` and stores the result in `dest`. @@ -747,7 +747,7 @@ fn int_abs<'tcx>( this.write_immediate(*res, &dest)?; } - Ok(()) + interp_ok(()) } /// Splits `op` (which must be a SIMD vector) into 128-bit chunks. @@ -778,7 +778,7 @@ fn split_simd_to_128bit_chunks<'tcx, P: Projectable<'tcx, Provenance>>( .unwrap(); let chunked_op = op.transmute(chunked_layout, this)?; - Ok((num_chunks, items_per_chunk, chunked_op)) + interp_ok((num_chunks, items_per_chunk, chunked_op)) } /// Horizontally performs `which` operation on adjacent values of @@ -830,7 +830,7 @@ fn horizontal_bin_op<'tcx>( } } - Ok(()) + interp_ok(()) } /// Conditionally multiplies the packed floating-point elements in @@ -892,7 +892,7 @@ fn conditional_dot_product<'tcx>( } } - Ok(()) + interp_ok(()) } /// Calculates two booleans. @@ -923,7 +923,7 @@ fn test_bits_masked<'tcx>( masked_set &= (op & mask) == mask; } - Ok((all_zero, masked_set)) + interp_ok((all_zero, masked_set)) } /// Calculates two booleans. @@ -956,7 +956,7 @@ fn test_high_bits_masked<'tcx>( negated &= (!op & mask) >> high_bit_offset == 0; } - Ok((direct, negated)) + interp_ok((direct, negated)) } /// Conditionally loads from `ptr` according the high bit of each @@ -989,7 +989,7 @@ fn mask_load<'tcx>( } } - Ok(()) + interp_ok(()) } /// Conditionally stores into `ptr` according the high bit of each @@ -1023,7 +1023,7 @@ fn mask_store<'tcx>( } } - Ok(()) + interp_ok(()) } /// Compute the sum of absolute differences of quadruplets of unsigned @@ -1082,7 +1082,7 @@ fn mpsadbw<'tcx>( } } - Ok(()) + interp_ok(()) } /// Multiplies packed 16-bit signed integer values, truncates the 32-bit @@ -1120,7 +1120,7 @@ fn pmulhrsw<'tcx>( this.write_scalar(Scalar::from_i16(res), &dest)?; } - Ok(()) + interp_ok(()) } /// Perform a carry-less multiplication of two 64-bit integers, selected from `left` and `right` according to `imm8`, @@ -1182,7 +1182,7 @@ fn pclmulqdq<'tcx>( let dest_high = this.project_index(&dest, 1)?; this.write_scalar(Scalar::from_u64(result_high), &dest_high)?; - Ok(()) + interp_ok(()) } /// Packs two N-bit integer vectors to a single N/2-bit integers. @@ -1227,7 +1227,7 @@ fn pack_generic<'tcx>( } } - Ok(()) + interp_ok(()) } /// Converts two 16-bit integer vectors to a single 8-bit integer @@ -1245,7 +1245,7 @@ fn packsswb<'tcx>( pack_generic(this, left, right, dest, |op| { let op = op.to_i16()?; let res = i8::try_from(op).unwrap_or(if op < 0 { i8::MIN } else { i8::MAX }); - Ok(Scalar::from_i8(res)) + interp_ok(Scalar::from_i8(res)) }) } @@ -1264,7 +1264,7 @@ fn packuswb<'tcx>( pack_generic(this, left, right, dest, |op| { let op = op.to_i16()?; let res = u8::try_from(op).unwrap_or(if op < 0 { 0 } else { u8::MAX }); - Ok(Scalar::from_u8(res)) + interp_ok(Scalar::from_u8(res)) }) } @@ -1283,7 +1283,7 @@ fn packssdw<'tcx>( pack_generic(this, left, right, dest, |op| { let op = op.to_i32()?; let res = i16::try_from(op).unwrap_or(if op < 0 { i16::MIN } else { i16::MAX }); - Ok(Scalar::from_i16(res)) + interp_ok(Scalar::from_i16(res)) }) } @@ -1302,7 +1302,7 @@ fn packusdw<'tcx>( pack_generic(this, left, right, dest, |op| { let op = op.to_i32()?; let res = u16::try_from(op).unwrap_or(if op < 0 { 0 } else { u16::MAX }); - Ok(Scalar::from_u16(res)) + interp_ok(Scalar::from_u16(res)) }) } @@ -1334,7 +1334,7 @@ fn psign<'tcx>( this.write_immediate(*res, &dest)?; } - Ok(()) + interp_ok(()) } /// Calcultates either `a + b + cb_in` or `a - b - cb_in` depending on the value @@ -1358,5 +1358,5 @@ fn carrying_add<'tcx>( this.binary_op(op, &sum, &ImmTy::from_uint(cb_in, a.layout))?.to_pair(this); let cb_out = overflow1.to_scalar().to_bool()? | overflow2.to_scalar().to_bool()?; - Ok((sum, Scalar::from_u8(cb_out.into()))) + interp_ok((sum, Scalar::from_u8(cb_out.into()))) } diff --git a/src/tools/miri/src/shims/x86/sha.rs b/src/tools/miri/src/shims/x86/sha.rs index d9cd34377e6..8553771b694 100644 --- a/src/tools/miri/src/shims/x86/sha.rs +++ b/src/tools/miri/src/shims/x86/sha.rs @@ -31,7 +31,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let projected = &this.project_index(reg, i.try_into().unwrap())?; *dst = this.read_scalar(projected)?.to_u32()? } - Ok(res) + interp_ok(res) } fn write<'c>( @@ -45,7 +45,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let projected = &this.project_index(dest, i.try_into().unwrap())?; this.write_scalar(Scalar::from_u32(part), projected)?; } - Ok(()) + interp_ok(()) } match unprefixed_name { @@ -106,9 +106,9 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let result = sha256msg2(a, b); write(this, &dest, result)?; } - _ => return Ok(EmulateItemResult::NotSupported), + _ => return interp_ok(EmulateItemResult::NotSupported), } - Ok(EmulateItemResult::NeedsReturn) + interp_ok(EmulateItemResult::NeedsReturn) } } diff --git a/src/tools/miri/src/shims/x86/sse.rs b/src/tools/miri/src/shims/x86/sse.rs index 254d25bb529..013900e95d3 100644 --- a/src/tools/miri/src/shims/x86/sse.rs +++ b/src/tools/miri/src/shims/x86/sse.rs @@ -201,8 +201,8 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.copy_op(&this.project_index(&left, i)?, &this.project_index(&dest, i)?)?; } } - _ => return Ok(EmulateItemResult::NotSupported), + _ => return interp_ok(EmulateItemResult::NotSupported), } - Ok(EmulateItemResult::NeedsReturn) + interp_ok(EmulateItemResult::NeedsReturn) } } diff --git a/src/tools/miri/src/shims/x86/sse2.rs b/src/tools/miri/src/shims/x86/sse2.rs index 7c23e372664..de72e63f8af 100644 --- a/src/tools/miri/src/shims/x86/sse2.rs +++ b/src/tools/miri/src/shims/x86/sse2.rs @@ -344,8 +344,8 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.copy_op(&this.project_index(&left, i)?, &this.project_index(&dest, i)?)?; } } - _ => return Ok(EmulateItemResult::NotSupported), + _ => return interp_ok(EmulateItemResult::NotSupported), } - Ok(EmulateItemResult::NeedsReturn) + interp_ok(EmulateItemResult::NeedsReturn) } } diff --git a/src/tools/miri/src/shims/x86/sse3.rs b/src/tools/miri/src/shims/x86/sse3.rs index ef5a55d6eb2..9aa4dd59950 100644 --- a/src/tools/miri/src/shims/x86/sse3.rs +++ b/src/tools/miri/src/shims/x86/sse3.rs @@ -47,8 +47,8 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.mem_copy(src_ptr, dest.ptr(), dest.layout.size, /*nonoverlapping*/ true)?; } - _ => return Ok(EmulateItemResult::NotSupported), + _ => return interp_ok(EmulateItemResult::NotSupported), } - Ok(EmulateItemResult::NeedsReturn) + interp_ok(EmulateItemResult::NeedsReturn) } } diff --git a/src/tools/miri/src/shims/x86/sse41.rs b/src/tools/miri/src/shims/x86/sse41.rs index 8fcdc491c0c..7bf8ddea2fe 100644 --- a/src/tools/miri/src/shims/x86/sse41.rs +++ b/src/tools/miri/src/shims/x86/sse41.rs @@ -172,8 +172,8 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_scalar(Scalar::from_i32(res.into()), dest)?; } - _ => return Ok(EmulateItemResult::NotSupported), + _ => return interp_ok(EmulateItemResult::NotSupported), } - Ok(EmulateItemResult::NeedsReturn) + interp_ok(EmulateItemResult::NeedsReturn) } } diff --git a/src/tools/miri/src/shims/x86/sse42.rs b/src/tools/miri/src/shims/x86/sse42.rs index 0b6e0d9e0d7..f31cd406349 100644 --- a/src/tools/miri/src/shims/x86/sse42.rs +++ b/src/tools/miri/src/shims/x86/sse42.rs @@ -115,7 +115,7 @@ fn compare_strings<'tcx>( (false, true) => i32::from(ch.to_i8()?), (false, false) => i32::from(ch.to_u8()?), }; - Ok(result) + interp_ok(result) }; for i in 0..len2 { @@ -183,7 +183,7 @@ fn compare_strings<'tcx>( _ => (), } - Ok(result) + interp_ok(result) } /// Obtain the arguments of the intrinsic based on its name. @@ -235,7 +235,7 @@ fn deconstruct_args<'tcx>( let str1 = str1.transmute(array_layout, this)?; let str2 = str2.transmute(array_layout, this)?; - Ok((str1, str2, Some((len1, len2)), imm)) + interp_ok((str1, str2, Some((len1, len2)), imm)) } else { let [str1, str2, imm] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let imm = this.read_scalar(imm)?.to_u8()?; @@ -244,7 +244,7 @@ fn deconstruct_args<'tcx>( let str1 = str1.transmute(array_layout, this)?; let str2 = str2.transmute(array_layout, this)?; - Ok((str1, str2, None, imm)) + interp_ok((str1, str2, None, imm)) } } @@ -266,7 +266,7 @@ fn implicit_len<'tcx>( break; } } - Ok(result) + interp_ok(result) } #[inline] @@ -433,7 +433,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { }; if bit_size == 64 && this.tcx.sess.target.arch != "x86_64" { - return Ok(EmulateItemResult::NotSupported); + return interp_ok(EmulateItemResult::NotSupported); } let [left, right] = @@ -493,8 +493,8 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_scalar(result, dest)?; } - _ => return Ok(EmulateItemResult::NotSupported), + _ => return interp_ok(EmulateItemResult::NotSupported), } - Ok(EmulateItemResult::NeedsReturn) + interp_ok(EmulateItemResult::NeedsReturn) } } diff --git a/src/tools/miri/src/shims/x86/ssse3.rs b/src/tools/miri/src/shims/x86/ssse3.rs index 096b0fb9e4b..76a2451dea4 100644 --- a/src/tools/miri/src/shims/x86/ssse3.rs +++ b/src/tools/miri/src/shims/x86/ssse3.rs @@ -133,8 +133,8 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { psign(this, left, right, dest)?; } - _ => return Ok(EmulateItemResult::NotSupported), + _ => return interp_ok(EmulateItemResult::NotSupported), } - Ok(EmulateItemResult::NeedsReturn) + interp_ok(EmulateItemResult::NeedsReturn) } } From 4891dd4627be38fa6133fcf3cfb0c1a65867bf87 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 29 Sep 2024 11:53:23 +0200 Subject: [PATCH 466/683] make InterpResult a dedicated type to avoid accidentally discarding the error --- clippy_utils/src/consts.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/clippy_utils/src/consts.rs b/clippy_utils/src/consts.rs index bf47cf6d372..53a1170d6a6 100644 --- a/clippy_utils/src/consts.rs +++ b/clippy_utils/src/consts.rs @@ -870,10 +870,10 @@ pub fn mir_to_const<'tcx>(tcx: TyCtxt<'tcx>, result: mir::Const<'tcx>) -> Option let range = alloc_range(offset + size * idx, size); let val = alloc.read_scalar(&tcx, range, /* read_provenance */ false).ok()?; res.push(match flt { - FloatTy::F16 => Constant::F16(f16::from_bits(val.to_u16().ok()?)), - FloatTy::F32 => Constant::F32(f32::from_bits(val.to_u32().ok()?)), - FloatTy::F64 => Constant::F64(f64::from_bits(val.to_u64().ok()?)), - FloatTy::F128 => Constant::F128(f128::from_bits(val.to_u128().ok()?)), + FloatTy::F16 => Constant::F16(f16::from_bits(val.to_u16().discard_err()?)), + FloatTy::F32 => Constant::F32(f32::from_bits(val.to_u32().discard_err()?)), + FloatTy::F64 => Constant::F64(f64::from_bits(val.to_u64().discard_err()?)), + FloatTy::F128 => Constant::F128(f128::from_bits(val.to_u128().discard_err()?)), }); } Some(Constant::Vec(res)) @@ -903,7 +903,7 @@ fn mir_is_empty<'tcx>(tcx: TyCtxt<'tcx>, result: mir::Const<'tcx>) -> Option Date: Sun, 15 Sep 2024 18:31:58 +0200 Subject: [PATCH 467/683] Stabilize `const_slice_from_raw_parts_mut` --- library/alloc/tests/lib.rs | 1 - library/core/src/lib.rs | 1 - library/core/src/ptr/mod.rs | 2 +- library/core/src/ptr/non_null.rs | 5 ++++- library/core/src/slice/raw.rs | 3 ++- 5 files changed, 7 insertions(+), 5 deletions(-) diff --git a/library/alloc/tests/lib.rs b/library/alloc/tests/lib.rs index 1d07a7690da..58d39416d95 100644 --- a/library/alloc/tests/lib.rs +++ b/library/alloc/tests/lib.rs @@ -7,7 +7,6 @@ #![feature(const_cow_is_borrowed)] #![feature(const_heap)] #![cfg_attr(bootstrap, feature(const_mut_refs))] -#![feature(const_slice_from_raw_parts_mut)] #![feature(const_ptr_write)] #![feature(const_try)] #![feature(core_intrinsics)] diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 817d9e3b962..b5bc9855191 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -147,7 +147,6 @@ #![feature(const_replace)] #![feature(const_size_of_val)] #![feature(const_size_of_val_raw)] -#![feature(const_slice_from_raw_parts_mut)] #![feature(const_slice_from_ref)] #![feature(const_slice_split_at_mut)] #![feature(const_str_as_mut)] diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs index b6df780fe2f..205b25f2d1a 100644 --- a/library/core/src/ptr/mod.rs +++ b/library/core/src/ptr/mod.rs @@ -992,7 +992,7 @@ pub const fn slice_from_raw_parts(data: *const T, len: usize) -> *const [T] { /// ``` #[inline] #[stable(feature = "slice_from_raw_parts", since = "1.42.0")] -#[rustc_const_unstable(feature = "const_slice_from_raw_parts_mut", issue = "67456")] +#[rustc_const_stable(feature = "const_slice_from_raw_parts_mut", since = "CURRENT_RUSTC_VERSION")] #[rustc_diagnostic_item = "ptr_slice_from_raw_parts_mut"] pub const fn slice_from_raw_parts_mut(data: *mut T, len: usize) -> *mut [T] { from_raw_parts_mut(data, len) diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs index e7a265f7e2b..da2404e25f3 100644 --- a/library/core/src/ptr/non_null.rs +++ b/library/core/src/ptr/non_null.rs @@ -1433,7 +1433,10 @@ impl NonNull<[T]> { /// (Note that this example artificially demonstrates a use of this method, /// but `let slice = NonNull::from(&x[..]);` would be a better way to write code like this.) #[stable(feature = "nonnull_slice_from_raw_parts", since = "1.70.0")] - #[rustc_const_unstable(feature = "const_slice_from_raw_parts_mut", issue = "67456")] + #[rustc_const_stable( + feature = "const_slice_from_raw_parts_mut", + since = "CURRENT_RUSTC_VERSION" + )] #[must_use] #[inline] pub const fn slice_from_raw_parts(data: NonNull, len: usize) -> Self { diff --git a/library/core/src/slice/raw.rs b/library/core/src/slice/raw.rs index 2cf3fecb475..84e916b9a84 100644 --- a/library/core/src/slice/raw.rs +++ b/library/core/src/slice/raw.rs @@ -171,7 +171,8 @@ pub const unsafe fn from_raw_parts<'a, T>(data: *const T, len: usize) -> &'a [T] /// [`NonNull::dangling()`]: ptr::NonNull::dangling #[inline] #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_const_unstable(feature = "const_slice_from_raw_parts_mut", issue = "67456")] +#[rustc_const_stable(feature = "const_slice_from_raw_parts_mut", since = "CURRENT_RUSTC_VERSION")] +#[cfg_attr(bootstrap, rustc_allow_const_fn_unstable(const_mut_refs))] #[must_use] #[rustc_diagnostic_item = "slice_from_raw_parts_mut"] pub const unsafe fn from_raw_parts_mut<'a, T>(data: *mut T, len: usize) -> &'a mut [T] { From c1acccdf1744561d4dda9b943fa91d873cea3b40 Mon Sep 17 00:00:00 2001 From: joboet Date: Tue, 1 Oct 2024 14:57:38 +0200 Subject: [PATCH 468/683] std: replace `LazyBox` with `OnceBox` This PR replaces the `LazyBox` wrapper used to allocate the pthread primitives with `OnceBox`, which has a more familiar API mirroring that of `OnceLock`. This cleans up the code in preparation for larger changes like #128184 (from which this PR was split) and allows some neat optimizations, like avoid an acquire-load of the allocation pointer in `Mutex::unlock`, where the initialization of the allocation must have already been observed. Additionally, I've gotten rid of the TEEOS `Condvar` code, it's just a duplicate of the pthread one anyway and I didn't want to repeat myself. --- library/std/src/sys/sync/condvar/mod.rs | 8 +- library/std/src/sys/sync/condvar/pthread.rs | 38 ++++---- library/std/src/sys/sync/condvar/sgx.rs | 29 +++--- library/std/src/sys/sync/condvar/teeos.rs | 101 -------------------- library/std/src/sys/sync/mod.rs | 3 + library/std/src/sys/sync/mutex/mod.rs | 2 +- library/std/src/sys/sync/mutex/pthread.rs | 81 +++++++++------- library/std/src/sys/sync/mutex/sgx.rs | 28 +++--- library/std/src/sys/sync/once_box.rs | 82 ++++++++++++++++ library/std/src/sys/sync/rwlock/teeos.rs | 8 +- library/std/src/sys_common/lazy_box.rs | 88 ----------------- library/std/src/sys_common/mod.rs | 1 - 12 files changed, 185 insertions(+), 284 deletions(-) delete mode 100644 library/std/src/sys/sync/condvar/teeos.rs create mode 100644 library/std/src/sys/sync/once_box.rs delete mode 100644 library/std/src/sys_common/lazy_box.rs diff --git a/library/std/src/sys/sync/condvar/mod.rs b/library/std/src/sys/sync/condvar/mod.rs index 6849cacf88e..d0c998a5597 100644 --- a/library/std/src/sys/sync/condvar/mod.rs +++ b/library/std/src/sys/sync/condvar/mod.rs @@ -12,7 +12,10 @@ cfg_if::cfg_if! { ))] { mod futex; pub use futex::Condvar; - } else if #[cfg(target_family = "unix")] { + } else if #[cfg(any( + target_family = "unix", + target_os = "teeos", + ))] { mod pthread; pub use pthread::Condvar; } else if #[cfg(all(target_os = "windows", target_vendor = "win7"))] { @@ -24,9 +27,6 @@ cfg_if::cfg_if! { } else if #[cfg(target_os = "solid_asp3")] { mod itron; pub use itron::Condvar; - } else if #[cfg(target_os = "teeos")] { - mod teeos; - pub use teeos::Condvar; } else if #[cfg(target_os = "xous")] { mod xous; pub use xous::Condvar; diff --git a/library/std/src/sys/sync/condvar/pthread.rs b/library/std/src/sys/sync/condvar/pthread.rs index 5b5e7770b06..986cd0cb7d1 100644 --- a/library/std/src/sys/sync/condvar/pthread.rs +++ b/library/std/src/sys/sync/condvar/pthread.rs @@ -2,31 +2,25 @@ use crate::cell::UnsafeCell; use crate::ptr; use crate::sync::atomic::AtomicPtr; use crate::sync::atomic::Ordering::Relaxed; -use crate::sys::sync::{Mutex, mutex}; +use crate::sys::sync::{Mutex, OnceBox}; #[cfg(not(target_os = "nto"))] use crate::sys::time::TIMESPEC_MAX; #[cfg(target_os = "nto")] use crate::sys::time::TIMESPEC_MAX_CAPPED; -use crate::sys_common::lazy_box::{LazyBox, LazyInit}; use crate::time::Duration; struct AllocatedCondvar(UnsafeCell); pub struct Condvar { - inner: LazyBox, + inner: OnceBox, mutex: AtomicPtr, } -#[inline] -fn raw(c: &Condvar) -> *mut libc::pthread_cond_t { - c.inner.0.get() -} - unsafe impl Send for AllocatedCondvar {} unsafe impl Sync for AllocatedCondvar {} -impl LazyInit for AllocatedCondvar { - fn init() -> Box { +impl AllocatedCondvar { + fn new() -> Box { let condvar = Box::new(AllocatedCondvar(UnsafeCell::new(libc::PTHREAD_COND_INITIALIZER))); cfg_if::cfg_if! { @@ -37,7 +31,7 @@ impl LazyInit for AllocatedCondvar { target_vendor = "apple", ))] { // `pthread_condattr_setclock` is unfortunately not supported on these platforms. - } else if #[cfg(any(target_os = "espidf", target_os = "horizon"))] { + } else if #[cfg(any(target_os = "espidf", target_os = "horizon", target_os = "teeos"))] { // NOTE: ESP-IDF's PTHREAD_COND_INITIALIZER support is not released yet // So on that platform, init() should always be called // Moreover, that platform does not have pthread_condattr_setclock support, @@ -82,7 +76,11 @@ impl Drop for AllocatedCondvar { impl Condvar { pub const fn new() -> Condvar { - Condvar { inner: LazyBox::new(), mutex: AtomicPtr::new(ptr::null_mut()) } + Condvar { inner: OnceBox::new(), mutex: AtomicPtr::new(ptr::null_mut()) } + } + + fn get(&self) -> *mut libc::pthread_cond_t { + self.inner.get_or_init(AllocatedCondvar::new).0.get() } #[inline] @@ -98,21 +96,21 @@ impl Condvar { #[inline] pub fn notify_one(&self) { - let r = unsafe { libc::pthread_cond_signal(raw(self)) }; + let r = unsafe { libc::pthread_cond_signal(self.get()) }; debug_assert_eq!(r, 0); } #[inline] pub fn notify_all(&self) { - let r = unsafe { libc::pthread_cond_broadcast(raw(self)) }; + let r = unsafe { libc::pthread_cond_broadcast(self.get()) }; debug_assert_eq!(r, 0); } #[inline] pub unsafe fn wait(&self, mutex: &Mutex) { - let mutex = mutex::raw(mutex); + let mutex = mutex.get_assert_locked(); self.verify(mutex); - let r = libc::pthread_cond_wait(raw(self), mutex); + let r = libc::pthread_cond_wait(self.get(), mutex); debug_assert_eq!(r, 0); } @@ -129,7 +127,7 @@ impl Condvar { pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool { use crate::sys::time::Timespec; - let mutex = mutex::raw(mutex); + let mutex = mutex.get_assert_locked(); self.verify(mutex); #[cfg(not(target_os = "nto"))] @@ -144,7 +142,7 @@ impl Condvar { .and_then(|t| t.to_timespec_capped()) .unwrap_or(TIMESPEC_MAX_CAPPED); - let r = libc::pthread_cond_timedwait(raw(self), mutex, &timeout); + let r = libc::pthread_cond_timedwait(self.get(), mutex, &timeout); assert!(r == libc::ETIMEDOUT || r == 0); r == 0 } @@ -162,7 +160,7 @@ impl Condvar { use crate::sys::time::SystemTime; use crate::time::Instant; - let mutex = mutex::raw(mutex); + let mutex = mutex.get_assert_locked(); self.verify(mutex); // OSX implementation of `pthread_cond_timedwait` is buggy @@ -188,7 +186,7 @@ impl Condvar { .and_then(|t| t.to_timespec()) .unwrap_or(TIMESPEC_MAX); - let r = libc::pthread_cond_timedwait(raw(self), mutex, &timeout); + let r = libc::pthread_cond_timedwait(self.get(), mutex, &timeout); debug_assert!(r == libc::ETIMEDOUT || r == 0); // ETIMEDOUT is not a totally reliable method of determining timeout due diff --git a/library/std/src/sys/sync/condvar/sgx.rs b/library/std/src/sys/sync/condvar/sgx.rs index ecb5872f60d..e60715e4b59 100644 --- a/library/std/src/sys/sync/condvar/sgx.rs +++ b/library/std/src/sys/sync/condvar/sgx.rs @@ -1,44 +1,39 @@ use crate::sys::pal::waitqueue::{SpinMutex, WaitQueue, WaitVariable}; -use crate::sys::sync::Mutex; -use crate::sys_common::lazy_box::{LazyBox, LazyInit}; +use crate::sys::sync::{Mutex, OnceBox}; use crate::time::Duration; -/// FIXME: `UnsafeList` is not movable. -struct AllocatedCondvar(SpinMutex>); - pub struct Condvar { - inner: LazyBox, -} - -impl LazyInit for AllocatedCondvar { - fn init() -> Box { - Box::new(AllocatedCondvar(SpinMutex::new(WaitVariable::new(())))) - } + // FIXME: `UnsafeList` is not movable. + inner: OnceBox>>, } impl Condvar { pub const fn new() -> Condvar { - Condvar { inner: LazyBox::new() } + Condvar { inner: OnceBox::new() } + } + + fn get(&self) -> &SpinMutex> { + self.inner.get_or_init(|| Box::new(SpinMutex::new(WaitVariable::new(())))) } #[inline] pub fn notify_one(&self) { - let _ = WaitQueue::notify_one(self.inner.0.lock()); + let _ = WaitQueue::notify_one(self.get().lock()); } #[inline] pub fn notify_all(&self) { - let _ = WaitQueue::notify_all(self.inner.0.lock()); + let _ = WaitQueue::notify_all(self.get().lock()); } pub unsafe fn wait(&self, mutex: &Mutex) { - let guard = self.inner.0.lock(); + let guard = self.get().lock(); WaitQueue::wait(guard, || unsafe { mutex.unlock() }); mutex.lock() } pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool { - let success = WaitQueue::wait_timeout(&self.inner.0, dur, || unsafe { mutex.unlock() }); + let success = WaitQueue::wait_timeout(self.get(), dur, || unsafe { mutex.unlock() }); mutex.lock(); success } diff --git a/library/std/src/sys/sync/condvar/teeos.rs b/library/std/src/sys/sync/condvar/teeos.rs deleted file mode 100644 index 943867cd761..00000000000 --- a/library/std/src/sys/sync/condvar/teeos.rs +++ /dev/null @@ -1,101 +0,0 @@ -use crate::cell::UnsafeCell; -use crate::ptr; -use crate::sync::atomic::AtomicPtr; -use crate::sync::atomic::Ordering::Relaxed; -use crate::sys::sync::mutex::{self, Mutex}; -use crate::sys::time::TIMESPEC_MAX; -use crate::sys_common::lazy_box::{LazyBox, LazyInit}; -use crate::time::Duration; - -extern "C" { - pub fn pthread_cond_timedwait( - cond: *mut libc::pthread_cond_t, - lock: *mut libc::pthread_mutex_t, - adstime: *const libc::timespec, - ) -> libc::c_int; -} - -struct AllocatedCondvar(UnsafeCell); - -pub struct Condvar { - inner: LazyBox, - mutex: AtomicPtr, -} - -#[inline] -fn raw(c: &Condvar) -> *mut libc::pthread_cond_t { - c.inner.0.get() -} - -unsafe impl Send for AllocatedCondvar {} -unsafe impl Sync for AllocatedCondvar {} - -impl LazyInit for AllocatedCondvar { - fn init() -> Box { - let condvar = Box::new(AllocatedCondvar(UnsafeCell::new(libc::PTHREAD_COND_INITIALIZER))); - - let r = unsafe { libc::pthread_cond_init(condvar.0.get(), crate::ptr::null()) }; - assert_eq!(r, 0); - - condvar - } -} - -impl Drop for AllocatedCondvar { - #[inline] - fn drop(&mut self) { - let r = unsafe { libc::pthread_cond_destroy(self.0.get()) }; - debug_assert_eq!(r, 0); - } -} - -impl Condvar { - pub const fn new() -> Condvar { - Condvar { inner: LazyBox::new(), mutex: AtomicPtr::new(ptr::null_mut()) } - } - - #[inline] - fn verify(&self, mutex: *mut libc::pthread_mutex_t) { - match self.mutex.compare_exchange(ptr::null_mut(), mutex, Relaxed, Relaxed) { - Ok(_) => {} // Stored the address - Err(n) if n == mutex => {} // Lost a race to store the same address - _ => panic!("attempted to use a condition variable with two mutexes"), - } - } - - #[inline] - pub fn notify_one(&self) { - let r = unsafe { libc::pthread_cond_signal(raw(self)) }; - debug_assert_eq!(r, 0); - } - - #[inline] - pub fn notify_all(&self) { - let r = unsafe { libc::pthread_cond_broadcast(raw(self)) }; - debug_assert_eq!(r, 0); - } - - #[inline] - pub unsafe fn wait(&self, mutex: &Mutex) { - let mutex = unsafe { mutex::raw(mutex) }; - self.verify(mutex); - let r = unsafe { libc::pthread_cond_wait(raw(self), mutex) }; - debug_assert_eq!(r, 0); - } - - pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool { - use crate::sys::time::Timespec; - - let mutex = unsafe { mutex::raw(mutex) }; - self.verify(mutex); - - let timeout = Timespec::now(libc::CLOCK_MONOTONIC) - .checked_add_duration(&dur) - .and_then(|t| t.to_timespec()) - .unwrap_or(TIMESPEC_MAX); - - let r = unsafe { pthread_cond_timedwait(raw(self), mutex, &timeout) }; - assert!(r == libc::ETIMEDOUT || r == 0); - r == 0 - } -} diff --git a/library/std/src/sys/sync/mod.rs b/library/std/src/sys/sync/mod.rs index 52fac5902a2..0691e967851 100644 --- a/library/std/src/sys/sync/mod.rs +++ b/library/std/src/sys/sync/mod.rs @@ -1,11 +1,14 @@ mod condvar; mod mutex; mod once; +mod once_box; mod rwlock; mod thread_parking; pub use condvar::Condvar; pub use mutex::Mutex; pub use once::{Once, OnceState}; +#[allow(unused)] // Only used on some platforms. +use once_box::OnceBox; pub use rwlock::RwLock; pub use thread_parking::Parker; diff --git a/library/std/src/sys/sync/mutex/mod.rs b/library/std/src/sys/sync/mutex/mod.rs index 73d9bd273de..360df3fc4b5 100644 --- a/library/std/src/sys/sync/mutex/mod.rs +++ b/library/std/src/sys/sync/mutex/mod.rs @@ -19,7 +19,7 @@ cfg_if::cfg_if! { target_os = "teeos", ))] { mod pthread; - pub use pthread::{Mutex, raw}; + pub use pthread::Mutex; } else if #[cfg(all(target_os = "windows", target_vendor = "win7"))] { mod windows7; pub use windows7::{Mutex, raw}; diff --git a/library/std/src/sys/sync/mutex/pthread.rs b/library/std/src/sys/sync/mutex/pthread.rs index 1c407bc2537..87c95f45f96 100644 --- a/library/std/src/sys/sync/mutex/pthread.rs +++ b/library/std/src/sys/sync/mutex/pthread.rs @@ -2,24 +2,19 @@ use crate::cell::UnsafeCell; use crate::io::Error; use crate::mem::{MaybeUninit, forget}; use crate::sys::cvt_nz; -use crate::sys_common::lazy_box::{LazyBox, LazyInit}; +use crate::sys::sync::OnceBox; struct AllocatedMutex(UnsafeCell); pub struct Mutex { - inner: LazyBox, -} - -#[inline] -pub unsafe fn raw(m: &Mutex) -> *mut libc::pthread_mutex_t { - m.inner.0.get() + inner: OnceBox, } unsafe impl Send for AllocatedMutex {} unsafe impl Sync for AllocatedMutex {} -impl LazyInit for AllocatedMutex { - fn init() -> Box { +impl AllocatedMutex { + fn new() -> Box { let mutex = Box::new(AllocatedMutex(UnsafeCell::new(libc::PTHREAD_MUTEX_INITIALIZER))); // Issue #33770 @@ -60,24 +55,6 @@ impl LazyInit for AllocatedMutex { mutex } - - fn destroy(mutex: Box) { - // We're not allowed to pthread_mutex_destroy a locked mutex, - // so check first if it's unlocked. - if unsafe { libc::pthread_mutex_trylock(mutex.0.get()) == 0 } { - unsafe { libc::pthread_mutex_unlock(mutex.0.get()) }; - drop(mutex); - } else { - // The mutex is locked. This happens if a MutexGuard is leaked. - // In this case, we just leak the Mutex too. - forget(mutex); - } - } - - fn cancel_init(_: Box) { - // In this case, we can just drop it without any checks, - // since it cannot have been locked yet. - } } impl Drop for AllocatedMutex { @@ -99,11 +76,33 @@ impl Drop for AllocatedMutex { impl Mutex { #[inline] pub const fn new() -> Mutex { - Mutex { inner: LazyBox::new() } + Mutex { inner: OnceBox::new() } + } + + /// Gets access to the pthread mutex under the assumption that the mutex is + /// locked. + /// + /// This allows skipping the initialization check, as the mutex can only be + /// locked if it is already initialized, and allows relaxing the ordering + /// on the pointer load, since the allocation cannot have been modified + /// since the `lock` and the lock must have occurred on the current thread. + /// + /// # Safety + /// Causes undefined behaviour if the mutex is not locked. + #[inline] + pub(crate) unsafe fn get_assert_locked(&self) -> *mut libc::pthread_mutex_t { + unsafe { self.inner.get_unchecked().0.get() } } #[inline] - pub unsafe fn lock(&self) { + fn get(&self) -> *mut libc::pthread_mutex_t { + // If initialization fails, the mutex is destroyed. This is always sound, + // however, as the mutex cannot have been locked yet. + self.inner.get_or_init(AllocatedMutex::new).0.get() + } + + #[inline] + pub fn lock(&self) { #[cold] #[inline(never)] fn fail(r: i32) -> ! { @@ -111,7 +110,7 @@ impl Mutex { panic!("failed to lock mutex: {error}"); } - let r = libc::pthread_mutex_lock(raw(self)); + let r = unsafe { libc::pthread_mutex_lock(self.get()) }; // As we set the mutex type to `PTHREAD_MUTEX_NORMAL` above, we expect // the lock call to never fail. Unfortunately however, some platforms // (Solaris) do not conform to the standard, and instead always provide @@ -126,13 +125,29 @@ impl Mutex { #[inline] pub unsafe fn unlock(&self) { - let r = libc::pthread_mutex_unlock(raw(self)); + let r = libc::pthread_mutex_unlock(self.get_assert_locked()); debug_assert_eq!(r, 0); } #[inline] - pub unsafe fn try_lock(&self) -> bool { - libc::pthread_mutex_trylock(raw(self)) == 0 + pub fn try_lock(&self) -> bool { + unsafe { libc::pthread_mutex_trylock(self.get()) == 0 } + } +} + +impl Drop for Mutex { + fn drop(&mut self) { + let Some(mutex) = self.inner.take() else { return }; + // We're not allowed to pthread_mutex_destroy a locked mutex, + // so check first if it's unlocked. + if unsafe { libc::pthread_mutex_trylock(mutex.0.get()) == 0 } { + unsafe { libc::pthread_mutex_unlock(mutex.0.get()) }; + drop(mutex); + } else { + // The mutex is locked. This happens if a MutexGuard is leaked. + // In this case, we just leak the Mutex too. + forget(mutex); + } } } diff --git a/library/std/src/sys/sync/mutex/sgx.rs b/library/std/src/sys/sync/mutex/sgx.rs index 65d1e880f7b..8529e857970 100644 --- a/library/std/src/sys/sync/mutex/sgx.rs +++ b/library/std/src/sys/sync/mutex/sgx.rs @@ -1,28 +1,24 @@ use crate::sys::pal::waitqueue::{SpinMutex, WaitQueue, WaitVariable, try_lock_or_false}; -use crate::sys_common::lazy_box::{LazyBox, LazyInit}; - -/// FIXME: `UnsafeList` is not movable. -struct AllocatedMutex(SpinMutex>); +use crate::sys::sync::OnceBox; pub struct Mutex { - inner: LazyBox, -} - -impl LazyInit for AllocatedMutex { - fn init() -> Box { - Box::new(AllocatedMutex(SpinMutex::new(WaitVariable::new(false)))) - } + // FIXME: `UnsafeList` is not movable. + inner: OnceBox>>, } // Implementation according to “Operating Systems: Three Easy Pieces”, chapter 28 impl Mutex { pub const fn new() -> Mutex { - Mutex { inner: LazyBox::new() } + Mutex { inner: OnceBox::new() } + } + + fn get(&self) -> &SpinMutex> { + self.inner.get_or_init(|| Box::new(SpinMutex::new(WaitVariable::new(false)))) } #[inline] pub fn lock(&self) { - let mut guard = self.inner.0.lock(); + let mut guard = self.get().lock(); if *guard.lock_var() { // Another thread has the lock, wait WaitQueue::wait(guard, || {}) @@ -35,7 +31,9 @@ impl Mutex { #[inline] pub unsafe fn unlock(&self) { - let guard = self.inner.0.lock(); + // SAFETY: the mutex was locked by the current thread, so it has been + // initialized already. + let guard = unsafe { self.inner.get_unchecked().lock() }; if let Err(mut guard) = WaitQueue::notify_one(guard) { // No other waiters, unlock *guard.lock_var_mut() = false; @@ -46,7 +44,7 @@ impl Mutex { #[inline] pub fn try_lock(&self) -> bool { - let mut guard = try_lock_or_false!(self.inner.0); + let mut guard = try_lock_or_false!(self.get()); if *guard.lock_var() { // Another thread has the lock false diff --git a/library/std/src/sys/sync/once_box.rs b/library/std/src/sys/sync/once_box.rs new file mode 100644 index 00000000000..1422b5a1721 --- /dev/null +++ b/library/std/src/sys/sync/once_box.rs @@ -0,0 +1,82 @@ +//! A racily-initialized alternative to `OnceLock>`. +//! +//! This is used to implement synchronization primitives that need allocation, +//! like the pthread versions. + +#![allow(dead_code)] // Only used on some platforms. + +use crate::mem::replace; +use crate::ptr::null_mut; +use crate::sync::atomic::AtomicPtr; +use crate::sync::atomic::Ordering::{AcqRel, Acquire, Relaxed}; + +pub(crate) struct OnceBox { + ptr: AtomicPtr, +} + +impl OnceBox { + #[inline] + pub const fn new() -> Self { + Self { ptr: AtomicPtr::new(null_mut()) } + } + + /// Gets access to the value, assuming it is already initialized and this + /// initialization has been observed by the current thread. + /// + /// Since all modifications to the pointer have already been observed, the + /// pointer load in this function can be performed with relaxed ordering, + /// potentially allowing the optimizer to turn code like this: + /// ```rust, ignore + /// once_box.get_or_init(|| Box::new(42)); + /// unsafe { once_box.get_unchecked() } + /// ``` + /// into + /// ```rust, ignore + /// once_box.get_or_init(|| Box::new(42)) + /// ``` + /// + /// # Safety + /// This causes undefined behaviour if the assumption above is violated. + #[inline] + pub unsafe fn get_unchecked(&self) -> &T { + unsafe { &*self.ptr.load(Relaxed) } + } + + #[inline] + pub fn get_or_init(&self, f: impl FnOnce() -> Box) -> &T { + let ptr = self.ptr.load(Acquire); + match unsafe { ptr.as_ref() } { + Some(val) => val, + None => self.initialize(f), + } + } + + #[inline] + pub fn take(&mut self) -> Option> { + let ptr = replace(self.ptr.get_mut(), null_mut()); + if !ptr.is_null() { Some(unsafe { Box::from_raw(ptr) }) } else { None } + } + + #[cold] + fn initialize(&self, f: impl FnOnce() -> Box) -> &T { + let new_ptr = Box::into_raw(f()); + match self.ptr.compare_exchange(null_mut(), new_ptr, AcqRel, Acquire) { + Ok(_) => unsafe { &*new_ptr }, + Err(ptr) => { + // Lost the race to another thread. + // Drop the value we created, and use the one from the other thread instead. + drop(unsafe { Box::from_raw(new_ptr) }); + unsafe { &*ptr } + } + } + } +} + +unsafe impl Send for OnceBox {} +unsafe impl Sync for OnceBox {} + +impl Drop for OnceBox { + fn drop(&mut self) { + self.take(); + } +} diff --git a/library/std/src/sys/sync/rwlock/teeos.rs b/library/std/src/sys/sync/rwlock/teeos.rs index ef9b1ab5154..76343022383 100644 --- a/library/std/src/sys/sync/rwlock/teeos.rs +++ b/library/std/src/sys/sync/rwlock/teeos.rs @@ -14,22 +14,22 @@ impl RwLock { #[inline] pub fn read(&self) { - unsafe { self.inner.lock() }; + self.inner.lock() } #[inline] pub fn try_read(&self) -> bool { - unsafe { self.inner.try_lock() } + self.inner.try_lock() } #[inline] pub fn write(&self) { - unsafe { self.inner.lock() }; + self.inner.lock() } #[inline] pub unsafe fn try_write(&self) -> bool { - unsafe { self.inner.try_lock() } + self.inner.try_lock() } #[inline] diff --git a/library/std/src/sys_common/lazy_box.rs b/library/std/src/sys_common/lazy_box.rs deleted file mode 100644 index b45b05f63ba..00000000000 --- a/library/std/src/sys_common/lazy_box.rs +++ /dev/null @@ -1,88 +0,0 @@ -#![allow(dead_code)] // Only used on some platforms. - -// This is used to wrap pthread {Mutex, Condvar, RwLock} in. - -use crate::marker::PhantomData; -use crate::ops::{Deref, DerefMut}; -use crate::ptr::null_mut; -use crate::sync::atomic::AtomicPtr; -use crate::sync::atomic::Ordering::{AcqRel, Acquire}; - -pub(crate) struct LazyBox { - ptr: AtomicPtr, - _phantom: PhantomData, -} - -pub(crate) trait LazyInit { - /// This is called before the box is allocated, to provide the value to - /// move into the new box. - /// - /// It might be called more than once per LazyBox, as multiple threads - /// might race to initialize it concurrently, each constructing and initializing - /// their own box. All but one of them will be passed to `cancel_init` right after. - fn init() -> Box; - - /// Any surplus boxes from `init()` that lost the initialization race - /// are passed to this function for disposal. - /// - /// The default implementation calls destroy(). - fn cancel_init(x: Box) { - Self::destroy(x); - } - - /// This is called to destroy a used box. - /// - /// The default implementation just drops it. - fn destroy(_: Box) {} -} - -impl LazyBox { - #[inline] - pub const fn new() -> Self { - Self { ptr: AtomicPtr::new(null_mut()), _phantom: PhantomData } - } - - #[inline] - fn get_pointer(&self) -> *mut T { - let ptr = self.ptr.load(Acquire); - if ptr.is_null() { self.initialize() } else { ptr } - } - - #[cold] - fn initialize(&self) -> *mut T { - let new_ptr = Box::into_raw(T::init()); - match self.ptr.compare_exchange(null_mut(), new_ptr, AcqRel, Acquire) { - Ok(_) => new_ptr, - Err(ptr) => { - // Lost the race to another thread. - // Drop the box we created, and use the one from the other thread instead. - T::cancel_init(unsafe { Box::from_raw(new_ptr) }); - ptr - } - } - } -} - -impl Deref for LazyBox { - type Target = T; - #[inline] - fn deref(&self) -> &T { - unsafe { &*self.get_pointer() } - } -} - -impl DerefMut for LazyBox { - #[inline] - fn deref_mut(&mut self) -> &mut T { - unsafe { &mut *self.get_pointer() } - } -} - -impl Drop for LazyBox { - fn drop(&mut self) { - let ptr = *self.ptr.get_mut(); - if !ptr.is_null() { - T::destroy(unsafe { Box::from_raw(ptr) }); - } - } -} diff --git a/library/std/src/sys_common/mod.rs b/library/std/src/sys_common/mod.rs index aa27886ff6f..4f7a131f6bb 100644 --- a/library/std/src/sys_common/mod.rs +++ b/library/std/src/sys_common/mod.rs @@ -22,7 +22,6 @@ mod tests; pub mod fs; pub mod io; -pub mod lazy_box; pub mod process; pub mod wstr; pub mod wtf8; From 9be9141730ce8f78d5ffa9f72541f2eca13ab1d1 Mon Sep 17 00:00:00 2001 From: Henry Jiang Date: Tue, 1 Oct 2024 16:06:24 -0400 Subject: [PATCH 469/683] increase stack size for aix --- compiler/rustc_data_structures/src/stack.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/compiler/rustc_data_structures/src/stack.rs b/compiler/rustc_data_structures/src/stack.rs index 7ff1339c5ab..72add175091 100644 --- a/compiler/rustc_data_structures/src/stack.rs +++ b/compiler/rustc_data_structures/src/stack.rs @@ -5,7 +5,11 @@ const RED_ZONE: usize = 100 * 1024; // 100k // Only the first stack that is pushed, grows exponentially (2^n * STACK_PER_RECURSION) from then // on. This flag has performance relevant characteristics. Don't set it too high. +#[cfg(not(target_os="aix"))] const STACK_PER_RECURSION: usize = 1024 * 1024; // 1MB +// LLVM for AIX doesn't feature TCO, increase recursion size for workaround. +#[cfg(target_os="aix")] +const STACK_PER_RECURSION: usize = 16 * 1024 * 1024; // 16MB /// Grows the stack on demand to prevent stack overflow. Call this in strategic locations /// to "break up" recursive calls. E.g. almost any call to `visit_expr` or equivalent can benefit From 9de4b62faf0d0156106a6614589bc78da6531e13 Mon Sep 17 00:00:00 2001 From: Anushrut <32019180+AvatarSenju@users.noreply.github.com> Date: Wed, 2 Oct 2024 01:47:18 +0530 Subject: [PATCH 470/683] Update helper docs display disable option Updated helper docs via configure.py to make it clearer that users can control options with enable and disable --- src/bootstrap/configure.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bootstrap/configure.py b/src/bootstrap/configure.py index 49d564642bd..a555a26367d 100755 --- a/src/bootstrap/configure.py +++ b/src/bootstrap/configure.py @@ -193,7 +193,7 @@ if '--help' in sys.argv or '-h' in sys.argv: if option.value: print('\t{:30} {}'.format('--{}=VAL'.format(option.name), option.desc)) else: - print('\t{:30} {}'.format('--enable-{}'.format(option.name), option.desc)) + print('\t{:30} {}'.format('--enable-{} OR --disable-{}'.format(option.name, option.name), option.desc)) print('') print('This configure script is a thin configuration shim over the true') print('configuration system, `config.toml`. You can explore the comments') From c88cb08afc100a400cf8f0095bac5b83175b5791 Mon Sep 17 00:00:00 2001 From: Rob Shearman Date: Thu, 18 Jul 2024 13:38:05 +0100 Subject: [PATCH 471/683] Fix `mut_mutex_lock` when reference not ultimately mutable When there is are multiple references where one of the references isn't mutable then this results in a false-positive for `mut_mutex_lock` as it only checks the mutability of the first reference level. Fix this by using `peel_mid_ty_refs_is_mutable` which correctly determines whether the reference is ultimately mutable and thus whether `Mutex::get_lock()` can actually be used. Fixes #9854 --- clippy_lints/src/methods/mut_mutex_lock.rs | 6 +++--- tests/ui/mut_mutex_lock.fixed | 12 ++++++++++++ tests/ui/mut_mutex_lock.rs | 12 ++++++++++++ tests/ui/mut_mutex_lock.stderr | 8 +++++++- 4 files changed, 34 insertions(+), 4 deletions(-) diff --git a/clippy_lints/src/methods/mut_mutex_lock.rs b/clippy_lints/src/methods/mut_mutex_lock.rs index 83e8370f939..320523aceb6 100644 --- a/clippy_lints/src/methods/mut_mutex_lock.rs +++ b/clippy_lints/src/methods/mut_mutex_lock.rs @@ -1,17 +1,17 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::expr_custom_deref_adjustment; -use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::ty::{is_type_diagnostic_item, peel_mid_ty_refs_is_mutable}; use rustc_errors::Applicability; use rustc_hir::{Expr, Mutability}; use rustc_lint::LateContext; -use rustc_middle::ty; use rustc_span::{Span, sym}; use super::MUT_MUTEX_LOCK; pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, ex: &'tcx Expr<'tcx>, recv: &'tcx Expr<'tcx>, name_span: Span) { if matches!(expr_custom_deref_adjustment(cx, recv), None | Some(Mutability::Mut)) - && let ty::Ref(_, _, Mutability::Mut) = cx.typeck_results().expr_ty(recv).kind() + && let (_, ref_depth, Mutability::Mut) = peel_mid_ty_refs_is_mutable(cx.typeck_results().expr_ty(recv)) + && ref_depth >= 1 && let Some(method_id) = cx.typeck_results().type_dependent_def_id(ex.hir_id) && let Some(impl_id) = cx.tcx.impl_of_method(method_id) && is_type_diagnostic_item(cx, cx.tcx.type_of(impl_id).instantiate_identity(), sym::Mutex) diff --git a/tests/ui/mut_mutex_lock.fixed b/tests/ui/mut_mutex_lock.fixed index bbedbb2bed2..29c5a27cb62 100644 --- a/tests/ui/mut_mutex_lock.fixed +++ b/tests/ui/mut_mutex_lock.fixed @@ -9,6 +9,11 @@ fn mut_mutex_lock() { let mut value = value_mutex.get_mut().unwrap(); *value += 1; + + let mut value_mutex = Mutex::new(42_u8); + let mut_ref_mut_ref_mutex = &mut &mut value_mutex; + let mut value = mut_ref_mut_ref_mutex.get_mut().unwrap(); + *value += 1; } fn no_owned_mutex_lock() { @@ -24,4 +29,11 @@ fn issue9415() { *guard += 1; } +fn mut_ref_ref_mutex_lock() { + let mutex = Mutex::new(42_u8); + let mut_ref_ref_mutex = &mut &mutex; + let mut guard = mut_ref_ref_mutex.lock().unwrap(); + *guard += 1; +} + fn main() {} diff --git a/tests/ui/mut_mutex_lock.rs b/tests/ui/mut_mutex_lock.rs index 74116100e82..fcdb3ff97db 100644 --- a/tests/ui/mut_mutex_lock.rs +++ b/tests/ui/mut_mutex_lock.rs @@ -9,6 +9,11 @@ fn mut_mutex_lock() { let mut value = value_mutex.lock().unwrap(); *value += 1; + + let mut value_mutex = Mutex::new(42_u8); + let mut_ref_mut_ref_mutex = &mut &mut value_mutex; + let mut value = mut_ref_mut_ref_mutex.lock().unwrap(); + *value += 1; } fn no_owned_mutex_lock() { @@ -24,4 +29,11 @@ fn issue9415() { *guard += 1; } +fn mut_ref_ref_mutex_lock() { + let mutex = Mutex::new(42_u8); + let mut_ref_ref_mutex = &mut &mutex; + let mut guard = mut_ref_ref_mutex.lock().unwrap(); + *guard += 1; +} + fn main() {} diff --git a/tests/ui/mut_mutex_lock.stderr b/tests/ui/mut_mutex_lock.stderr index a3d4905c04c..92601c4c612 100644 --- a/tests/ui/mut_mutex_lock.stderr +++ b/tests/ui/mut_mutex_lock.stderr @@ -7,5 +7,11 @@ LL | let mut value = value_mutex.lock().unwrap(); = note: `-D clippy::mut-mutex-lock` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::mut_mutex_lock)]` -error: aborting due to 1 previous error +error: calling `&mut Mutex::lock` unnecessarily locks an exclusive (mutable) reference + --> tests/ui/mut_mutex_lock.rs:15:43 + | +LL | let mut value = mut_ref_mut_ref_mutex.lock().unwrap(); + | ^^^^ help: change this to: `get_mut` + +error: aborting due to 2 previous errors From 5b1a2b8712887fff7e0295d4e87aac24ea73797d Mon Sep 17 00:00:00 2001 From: Jack Wrenn Date: Tue, 1 Oct 2024 20:52:17 +0000 Subject: [PATCH 472/683] TransmuteFrom: Gracefully handle unnormalized types and normalization errors Fixes #130413 --- .../traits/fulfillment_errors.rs | 8 +++++ .../src/error_reporting/traits/mod.rs | 1 + compiler/rustc_transmute/src/layout/tree.rs | 5 +-- tests/ui/transmutability/assoc-bound.rs | 25 +++++++++++++++ tests/ui/transmutability/assoc-bound.stderr | 31 +++++++++++++++++++ 5 files changed, 68 insertions(+), 2 deletions(-) create mode 100644 tests/ui/transmutability/assoc-bound.rs create mode 100644 tests/ui/transmutability/assoc-bound.stderr 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 34a0f182ab4..f494d9637f3 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 @@ -245,6 +245,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { span, "silent safe transmute error" ); } + GetSafeTransmuteErrorAndReason::Default => { + (err_msg, None) + } GetSafeTransmuteErrorAndReason::Error { err_msg, safe_transmute_explanation, @@ -2221,6 +2224,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ) -> GetSafeTransmuteErrorAndReason { use rustc_transmute::Answer; + if obligation.predicate.has_non_region_param() || obligation.has_non_region_infer() { + return GetSafeTransmuteErrorAndReason::Default; + } + // Erase regions because layout code doesn't particularly care about regions. let trait_ref = self.tcx.erase_regions(self.tcx.instantiate_bound_regions_with_erased(trait_ref)); @@ -2243,6 +2250,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { let dst = trait_ref.args.type_at(0); let src = trait_ref.args.type_at(1); + let err_msg = format!("`{src}` cannot be safely transmuted into `{dst}`"); match rustc_transmute::TransmuteTypeEnv::new(self.infcx).is_transmutable( diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs index 109bae10b54..becc1acfb66 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs @@ -43,6 +43,7 @@ pub struct ImplCandidate<'tcx> { enum GetSafeTransmuteErrorAndReason { Silent, + Default, Error { err_msg: String, safe_transmute_explanation: Option }, } diff --git a/compiler/rustc_transmute/src/layout/tree.rs b/compiler/rustc_transmute/src/layout/tree.rs index 6d5859a5a65..17eddbfcd7f 100644 --- a/compiler/rustc_transmute/src/layout/tree.rs +++ b/compiler/rustc_transmute/src/layout/tree.rs @@ -195,10 +195,11 @@ pub(crate) mod rustc { impl<'tcx> From<&LayoutError<'tcx>> for Err { fn from(err: &LayoutError<'tcx>) -> Self { match err { - LayoutError::Unknown(..) | LayoutError::ReferencesError(..) => Self::UnknownLayout, + LayoutError::Unknown(..) + | LayoutError::ReferencesError(..) + | LayoutError::NormalizationFailure(..) => Self::UnknownLayout, LayoutError::SizeOverflow(..) => Self::SizeOverflow, LayoutError::Cycle(err) => Self::TypeError(*err), - err => unimplemented!("{:?}", err), } } } diff --git a/tests/ui/transmutability/assoc-bound.rs b/tests/ui/transmutability/assoc-bound.rs new file mode 100644 index 00000000000..e8a20b45cde --- /dev/null +++ b/tests/ui/transmutability/assoc-bound.rs @@ -0,0 +1,25 @@ +#![crate_type = "lib"] +#![feature(transmutability)] + +trait A { + type AssocA; +} + +trait B { + type AssocB: std::mem::TransmuteFrom<()>; +} + +impl B for (T, u8) +where + T: A, +{ + type AssocB = T::AssocA; //~ERROR: the trait bound `::AssocA: TransmuteFrom<(), Assume { alignment: false, lifetimes: false, safety: false, validity: false }>` is not satisfied [E0277] +} + + +impl B for (T, u16) +where + for<'a> &'a i32: A, +{ + type AssocB = <&'static i32 as A>::AssocA; //~ERROR: `()` cannot be safely transmuted into `<&i32 as A>::AssocA` +} diff --git a/tests/ui/transmutability/assoc-bound.stderr b/tests/ui/transmutability/assoc-bound.stderr new file mode 100644 index 00000000000..08d90894396 --- /dev/null +++ b/tests/ui/transmutability/assoc-bound.stderr @@ -0,0 +1,31 @@ +error[E0277]: the trait bound `::AssocA: TransmuteFrom<(), Assume { alignment: false, lifetimes: false, safety: false, validity: false }>` is not satisfied + --> $DIR/assoc-bound.rs:16:19 + | +LL | type AssocB = T::AssocA; + | ^^^^^^^^^ the trait `TransmuteFrom<(), Assume { alignment: false, lifetimes: false, safety: false, validity: false }>` is not implemented for `::AssocA` + | +note: required by a bound in `B::AssocB` + --> $DIR/assoc-bound.rs:9:18 + | +LL | type AssocB: std::mem::TransmuteFrom<()>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `B::AssocB` +help: consider further restricting the associated type + | +LL | T: A, ::AssocA: TransmuteFrom<(), Assume { alignment: false, lifetimes: false, safety: false, validity: false }> + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error[E0277]: `()` cannot be safely transmuted into `<&i32 as A>::AssocA` + --> $DIR/assoc-bound.rs:24:19 + | +LL | type AssocB = <&'static i32 as A>::AssocA; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `<&i32 as A>::AssocA` has an unknown layout + | +note: required by a bound in `B::AssocB` + --> $DIR/assoc-bound.rs:9:18 + | +LL | type AssocB: std::mem::TransmuteFrom<()>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `B::AssocB` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. From 162ee75e436875afc0ff877e4fca90a13f879a1c Mon Sep 17 00:00:00 2001 From: Henry Jiang Date: Tue, 1 Oct 2024 17:21:56 -0400 Subject: [PATCH 473/683] format --- compiler/rustc_data_structures/src/stack.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_data_structures/src/stack.rs b/compiler/rustc_data_structures/src/stack.rs index 72add175091..3d6d0003483 100644 --- a/compiler/rustc_data_structures/src/stack.rs +++ b/compiler/rustc_data_structures/src/stack.rs @@ -5,10 +5,10 @@ const RED_ZONE: usize = 100 * 1024; // 100k // Only the first stack that is pushed, grows exponentially (2^n * STACK_PER_RECURSION) from then // on. This flag has performance relevant characteristics. Don't set it too high. -#[cfg(not(target_os="aix"))] +#[cfg(not(target_os = "aix"))] const STACK_PER_RECURSION: usize = 1024 * 1024; // 1MB // LLVM for AIX doesn't feature TCO, increase recursion size for workaround. -#[cfg(target_os="aix")] +#[cfg(target_os = "aix")] const STACK_PER_RECURSION: usize = 16 * 1024 * 1024; // 16MB /// Grows the stack on demand to prevent stack overflow. Call this in strategic locations From 38ea690363e24acf4970b2a7e942af6c05893691 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Rakic?= Date: Tue, 1 Oct 2024 23:16:35 +0000 Subject: [PATCH 474/683] fix extension for `-Zdump-mir-dataflow` graphviz files --- compiler/rustc_mir_dataflow/src/framework/engine.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_mir_dataflow/src/framework/engine.rs b/compiler/rustc_mir_dataflow/src/framework/engine.rs index da01a974094..faf5c610a0c 100644 --- a/compiler/rustc_mir_dataflow/src/framework/engine.rs +++ b/compiler/rustc_mir_dataflow/src/framework/engine.rs @@ -285,7 +285,7 @@ where } None if dump_enabled(tcx, A::NAME, def_id) => { - create_dump_file(tcx, ".dot", false, A::NAME, &pass_name.unwrap_or("-----"), body)? + create_dump_file(tcx, "dot", false, A::NAME, &pass_name.unwrap_or("-----"), body)? } _ => return (Ok(()), results), From 98d6fdb24206f632e0f151719bbdcc73ff67ff2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Rakic?= Date: Tue, 1 Oct 2024 23:55:55 +0000 Subject: [PATCH 475/683] make `Borrows` dataflow dumps about its loan domain --- compiler/rustc_borrowck/src/dataflow.rs | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/compiler/rustc_borrowck/src/dataflow.rs b/compiler/rustc_borrowck/src/dataflow.rs index 4af5a10f581..5ea48d3fc7e 100644 --- a/compiler/rustc_borrowck/src/dataflow.rs +++ b/compiler/rustc_borrowck/src/dataflow.rs @@ -1,5 +1,3 @@ -use std::fmt; - use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::graph; use rustc_index::bit_set::BitSet; @@ -425,10 +423,6 @@ impl<'a, 'tcx> Borrows<'a, 'tcx> { Borrows { tcx, body, borrow_set, borrows_out_of_scope_at_location } } - pub fn location(&self, idx: BorrowIndex) -> &Location { - &self.borrow_set[idx].reserve_location - } - /// Add all borrows to the kill set, if those borrows are out of scope at `location`. /// That means they went out of a nonlexical scope fn kill_loans_out_of_scope_at_location( @@ -615,8 +609,4 @@ impl<'tcx> rustc_mir_dataflow::GenKillAnalysis<'tcx> for Borrows<'_, 'tcx> { } } -impl DebugWithContext> for BorrowIndex { - fn fmt_with(&self, ctxt: &Borrows<'_, '_>, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:?}", ctxt.location(*self)) - } -} +impl DebugWithContext for BorrowIndex {} From bb5a8276be2d3dbc97d0f52e90db15455d542edf Mon Sep 17 00:00:00 2001 From: Jacob Kiesel Date: Sat, 22 Jun 2024 01:27:59 -0600 Subject: [PATCH 476/683] add unstable support for outputting file checksums for use in cargo --- Cargo.lock | 26 ++++ .../src/debuginfo/metadata.rs | 1 + compiler/rustc_interface/src/interface.rs | 3 +- compiler/rustc_interface/src/lib.rs | 1 + compiler/rustc_interface/src/passes.rs | 105 +++++++++++-- compiler/rustc_interface/src/tests.rs | 2 + compiler/rustc_metadata/src/rmeta/decoder.rs | 2 + .../src/ich/impls_syntax.rs | 2 + compiler/rustc_session/src/config.rs | 4 + compiler/rustc_session/src/options.rs | 22 ++- compiler/rustc_span/Cargo.toml | 1 + compiler/rustc_span/src/lib.rs | 146 +++++++++++++++++- compiler/rustc_span/src/source_map.rs | 16 +- compiler/rustc_span/src/source_map/tests.rs | 2 + compiler/rustc_span/src/tests.rs | 10 +- src/tools/tidy/src/deps.rs | 6 + 16 files changed, 321 insertions(+), 28 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6c1071ccbc2..6348046751a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -199,6 +199,12 @@ dependencies = [ "object 0.36.4", ] +[[package]] +name = "arrayref" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b4930d2cb77ce62f89ee5d5289b4ac049559b1c45539271f5ed4fdc7db34545" + [[package]] name = "arrayvec" version = "0.7.6" @@ -262,6 +268,19 @@ version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" +[[package]] +name = "blake3" +version = "1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d08263faac5cde2a4d52b513dadb80846023aade56fcd8fc99ba73ba8050e92" +dependencies = [ + "arrayref", + "arrayvec", + "cc", + "cfg-if", + "constant_time_eq", +] + [[package]] name = "block-buffer" version = "0.10.4" @@ -719,6 +738,12 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "constant_time_eq" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7144d30dcf0fafbce74250a3963025d8d52177934239851c917d29f1df280c2" + [[package]] name = "core-foundation-sys" version = "0.8.7" @@ -4374,6 +4399,7 @@ dependencies = [ name = "rustc_span" version = "0.0.0" dependencies = [ + "blake3", "derive-where", "indexmap", "itoa", diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index 964b83c0fa0..b7a6f80956d 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -630,6 +630,7 @@ pub(crate) fn file_metadata<'ll>(cx: &CodegenCx<'ll, '_>, source_file: &SourceFi rustc_span::SourceFileHashAlgorithm::Md5 => llvm::ChecksumKind::MD5, rustc_span::SourceFileHashAlgorithm::Sha1 => llvm::ChecksumKind::SHA1, rustc_span::SourceFileHashAlgorithm::Sha256 => llvm::ChecksumKind::SHA256, + rustc_span::SourceFileHashAlgorithm::Blake3 => llvm::ChecksumKind::None, }; let hash_value = hex_encode(source_file.src_hash.hash_bytes()); diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs index bd38b3c109a..3920d3077d3 100644 --- a/compiler/rustc_interface/src/interface.rs +++ b/compiler/rustc_interface/src/interface.rs @@ -389,12 +389,13 @@ pub fn run_compiler(config: Config, f: impl FnOnce(&Compiler) -> R + Se let file_loader = config.file_loader.unwrap_or_else(|| Box::new(RealFileLoader)); let path_mapping = config.opts.file_path_mapping(); let hash_kind = config.opts.unstable_opts.src_hash_algorithm(&target); + let checksum_hash_kind = config.opts.unstable_opts.checksum_hash_algorithm(); util::run_in_thread_pool_with_globals( &early_dcx, config.opts.edition, config.opts.unstable_opts.threads, - SourceMapInputs { file_loader, path_mapping, hash_kind }, + SourceMapInputs { file_loader, path_mapping, hash_kind, checksum_hash_kind }, |current_gcx| { // The previous `early_dcx` can't be reused here because it doesn't // impl `Send`. Creating a new one is fine. diff --git a/compiler/rustc_interface/src/lib.rs b/compiler/rustc_interface/src/lib.rs index b81a7402701..1c4dda2a436 100644 --- a/compiler/rustc_interface/src/lib.rs +++ b/compiler/rustc_interface/src/lib.rs @@ -1,6 +1,7 @@ // tidy-alphabetical-start #![feature(decl_macro)] #![feature(file_buffered)] +#![feature(iter_intersperse)] #![feature(let_chains)] #![feature(try_blocks)] #![warn(unreachable_pub)] diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 84b320975bb..b9b65755db5 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -32,8 +32,8 @@ use rustc_session::cstore::Untracked; use rustc_session::output::{collect_crate_types, filename_for_input, find_crate_name}; use rustc_session::search_paths::PathKind; use rustc_session::{Limit, Session}; -use rustc_span::FileName; use rustc_span::symbol::{Symbol, sym}; +use rustc_span::{FileName, SourceFileHash, SourceFileHashAlgorithm}; use rustc_target::spec::PanicStrategy; use rustc_trait_selection::traits; use tracing::{info, instrument}; @@ -417,15 +417,23 @@ fn write_out_deps(tcx: TyCtxt<'_>, outputs: &OutputFilenames, out_filenames: &[P let result: io::Result<()> = try { // Build a list of files used to compile the output and // write Makefile-compatible dependency rules - let mut files: Vec = sess + let mut files: Vec<(String, u64, Option)> = sess .source_map() .files() .iter() .filter(|fmap| fmap.is_real_file()) .filter(|fmap| !fmap.is_imported()) - .map(|fmap| escape_dep_filename(&fmap.name.prefer_local().to_string())) + .map(|fmap| { + ( + escape_dep_filename(&fmap.name.prefer_local().to_string()), + fmap.source_len.0 as u64, + fmap.checksum_hash, + ) + }) .collect(); + let checksum_hash_algo = sess.opts.unstable_opts.checksum_hash_algorithm; + // Account for explicitly marked-to-track files // (e.g. accessed in proc macros). let file_depinfo = sess.psess.file_depinfo.borrow(); @@ -437,22 +445,58 @@ fn write_out_deps(tcx: TyCtxt<'_>, outputs: &OutputFilenames, out_filenames: &[P // The entries will be used to declare dependencies between files in a // Makefile-like output, so the iteration order does not matter. + fn hash_iter_files>( + it: impl Iterator, + checksum_hash_algo: Option, + ) -> impl Iterator)> { + it.map(move |path| { + match checksum_hash_algo.and_then(|algo| { + fs::File::open(path.as_ref()) + .and_then(|mut file| { + SourceFileHash::new(algo, &mut file).map(|h| (file, h)) + }) + .and_then(|(file, h)| file.metadata().map(|m| (m.len(), h))) + .map_err(|e| { + tracing::error!( + "failed to compute checksum, omitting it from dep-info {} {e}", + path.as_ref().display() + ) + }) + .ok() + }) { + Some((file_len, checksum)) => (path, file_len, Some(checksum)), + None => (path, 0, None), + } + }) + } + #[allow(rustc::potential_query_instability)] - let extra_tracked_files = - file_depinfo.iter().map(|path_sym| normalize_path(PathBuf::from(path_sym.as_str()))); + let extra_tracked_files = hash_iter_files( + file_depinfo.iter().map(|path_sym| normalize_path(PathBuf::from(path_sym.as_str()))), + checksum_hash_algo, + ); files.extend(extra_tracked_files); // We also need to track used PGO profile files if let Some(ref profile_instr) = sess.opts.cg.profile_use { - files.push(normalize_path(profile_instr.as_path().to_path_buf())); + files.extend(hash_iter_files( + iter::once(normalize_path(profile_instr.as_path().to_path_buf())), + checksum_hash_algo, + )); } if let Some(ref profile_sample) = sess.opts.unstable_opts.profile_sample_use { - files.push(normalize_path(profile_sample.as_path().to_path_buf())); + files.extend(hash_iter_files( + iter::once(normalize_path(profile_sample.as_path().to_path_buf())), + checksum_hash_algo, + )); } // Debugger visualizer files for debugger_visualizer in tcx.debugger_visualizers(LOCAL_CRATE) { - files.push(normalize_path(debugger_visualizer.path.clone().unwrap())); + files.extend(hash_iter_files( + iter::once(normalize_path(debugger_visualizer.path.clone().unwrap())), + checksum_hash_algo, + )); } if sess.binary_dep_depinfo() { @@ -460,33 +504,54 @@ fn write_out_deps(tcx: TyCtxt<'_>, outputs: &OutputFilenames, out_filenames: &[P if backend.contains('.') { // If the backend name contain a `.`, it is the path to an external dynamic // library. If not, it is not a path. - files.push(backend.to_string()); + files.extend(hash_iter_files( + iter::once(backend.to_string()), + checksum_hash_algo, + )); } } for &cnum in tcx.crates(()) { let source = tcx.used_crate_source(cnum); if let Some((path, _)) = &source.dylib { - files.push(escape_dep_filename(&path.display().to_string())); + files.extend(hash_iter_files( + iter::once(escape_dep_filename(&path.display().to_string())), + checksum_hash_algo, + )); } if let Some((path, _)) = &source.rlib { - files.push(escape_dep_filename(&path.display().to_string())); + files.extend(hash_iter_files( + iter::once(escape_dep_filename(&path.display().to_string())), + checksum_hash_algo, + )); } if let Some((path, _)) = &source.rmeta { - files.push(escape_dep_filename(&path.display().to_string())); + files.extend(hash_iter_files( + iter::once(escape_dep_filename(&path.display().to_string())), + checksum_hash_algo, + )); } } } let write_deps_to_file = |file: &mut dyn Write| -> io::Result<()> { for path in out_filenames { - writeln!(file, "{}: {}\n", path.display(), files.join(" "))?; + writeln!( + file, + "{}: {}\n", + path.display(), + files + .iter() + .map(|(path, _file_len, _checksum_hash_algo)| path.as_str()) + .intersperse(" ") + .collect::() + )?; } // Emit a fake target for each input file to the compilation. This // prevents `make` from spitting out an error if a file is later // deleted. For more info see #28735 - for path in files { + for (path, _file_len, _checksum_hash_algo) in &files { writeln!(file, "{path}:")?; } @@ -510,6 +575,18 @@ fn write_out_deps(tcx: TyCtxt<'_>, outputs: &OutputFilenames, out_filenames: &[P } } + // If caller requested this information, add special comments about source file checksums. + // These are not necessarily the same checksums as was used in the debug files. + if sess.opts.unstable_opts.checksum_hash_algorithm().is_some() { + for (path, file_len, checksum_hash) in + files.iter().filter_map(|(path, file_len, hash_algo)| { + hash_algo.map(|hash_algo| (path, file_len, hash_algo)) + }) + { + writeln!(file, "# checksum:{checksum_hash} file_len:{file_len} {path}")?; + } + } + Ok(()) }; diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index 895897eca6b..536ce154cd0 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -44,10 +44,12 @@ where let sysroot = filesearch::materialize_sysroot(sessopts.maybe_sysroot.clone()); let target = rustc_session::config::build_target_config(&early_dcx, &sessopts, &sysroot); let hash_kind = sessopts.unstable_opts.src_hash_algorithm(&target); + let checksum_hash_kind = sessopts.unstable_opts.checksum_hash_algorithm(); let sm_inputs = Some(SourceMapInputs { file_loader: Box::new(RealFileLoader) as _, path_mapping: sessopts.file_path_mapping(), hash_kind, + checksum_hash_kind, }); rustc_span::create_session_globals_then(DEFAULT_EDITION, sm_inputs, || { diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index 2157324d5cc..f02fd2ab6fe 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -1702,6 +1702,7 @@ impl<'a> CrateMetadataRef<'a> { let rustc_span::SourceFile { mut name, src_hash, + checksum_hash, start_pos: original_start_pos, source_len, lines, @@ -1752,6 +1753,7 @@ impl<'a> CrateMetadataRef<'a> { let local_version = sess.source_map().new_imported_source_file( name, src_hash, + checksum_hash, stable_id, source_len.to_u32(), self.cnum, diff --git a/compiler/rustc_query_system/src/ich/impls_syntax.rs b/compiler/rustc_query_system/src/ich/impls_syntax.rs index 8d7a6e4fa9b..5e450979273 100644 --- a/compiler/rustc_query_system/src/ich/impls_syntax.rs +++ b/compiler/rustc_query_system/src/ich/impls_syntax.rs @@ -68,6 +68,8 @@ impl<'a> HashStable> for SourceFile { // Do not hash the source as it is not encoded src: _, ref src_hash, + // Already includes src_hash, this is redundant + checksum_hash: _, external_src: _, start_pos: _, source_len: _, diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 0d293415aa9..d2c03e588ff 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -1242,6 +1242,10 @@ impl UnstableOptions { } }) } + + pub fn checksum_hash_algorithm(&self) -> Option { + self.checksum_hash_algorithm + } } // The type of entry function, so users can have their own entry functions diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 1de09b8be4d..a1d85dfad32 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -418,7 +418,8 @@ mod desc { "one of: `legacy`, `v0` (RFC 2603), or `hashed`"; pub(crate) const parse_opt_symbol_visibility: &str = "one of: `hidden`, `protected`, or `interposable`"; - pub(crate) const parse_src_file_hash: &str = "either `md5` or `sha1`"; + pub(crate) const parse_cargo_src_file_hash: &str = "one of `md5`, `sha1`, or `sha256`"; + pub(crate) const parse_src_file_hash: &str = "one of `md5`, `sha1`, or `sha256`"; pub(crate) const parse_relocation_model: &str = "one of supported relocation models (`rustc --print relocation-models`)"; pub(crate) const parse_code_model: &str = @@ -1288,6 +1289,23 @@ mod parse { true } + pub(crate) fn parse_cargo_src_file_hash( + slot: &mut Option, + v: Option<&str>, + ) -> bool { + match v.and_then(|s| SourceFileHashAlgorithm::from_str(s).ok()) { + Some(hash_kind) => { + if hash_kind.supported_in_cargo() { + *slot = Some(hash_kind); + } else { + return false; + } + } + _ => return false, + } + true + } + pub(crate) fn parse_target_feature(slot: &mut String, v: Option<&str>) -> bool { match v { Some(s) => { @@ -1688,6 +1706,8 @@ options! { "instrument control-flow architecture protection"), check_cfg_all_expected: bool = (false, parse_bool, [UNTRACKED], "show all expected values in check-cfg diagnostics (default: no)"), + checksum_hash_algorithm: Option = (None, parse_cargo_src_file_hash, [TRACKED], + "hash algorithm of source files used to check freshness in cargo (`sha256`)"), codegen_backend: Option = (None, parse_opt_string, [TRACKED], "the backend to use"), combine_cgu: bool = (false, parse_bool, [TRACKED], diff --git a/compiler/rustc_span/Cargo.toml b/compiler/rustc_span/Cargo.toml index 3fdfe77ead9..c52d1fcc07f 100644 --- a/compiler/rustc_span/Cargo.toml +++ b/compiler/rustc_span/Cargo.toml @@ -5,6 +5,7 @@ edition = "2021" [dependencies] # tidy-alphabetical-start +blake3 = "1.5.2" derive-where = "1.2.7" indexmap = { version = "2.0.0" } itoa = "1.0" diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index 9dbdab84a81..5ab1caaa220 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -75,7 +75,9 @@ pub mod profiling; use std::borrow::Cow; use std::cmp::{self, Ordering}; +use std::fmt::Display; use std::hash::Hash; +use std::io::{self, Read}; use std::ops::{Add, Range, Sub}; use std::path::{Path, PathBuf}; use std::str::FromStr; @@ -1395,6 +1397,27 @@ pub enum SourceFileHashAlgorithm { Md5, Sha1, Sha256, + Blake3, +} + +impl SourceFileHashAlgorithm { + pub fn supported_in_cargo(&self) -> bool { + match self { + Self::Md5 | Self::Sha1 => false, + Self::Sha256 | Self::Blake3 => true, + } + } +} + +impl Display for SourceFileHashAlgorithm { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(match self { + Self::Md5 => "md5", + Self::Sha1 => "sha1", + Self::Sha256 => "sha256", + Self::Blake3 => "blake3", + }) + } } impl FromStr for SourceFileHashAlgorithm { @@ -1405,12 +1428,13 @@ impl FromStr for SourceFileHashAlgorithm { "md5" => Ok(SourceFileHashAlgorithm::Md5), "sha1" => Ok(SourceFileHashAlgorithm::Sha1), "sha256" => Ok(SourceFileHashAlgorithm::Sha256), + "blake3" => Ok(SourceFileHashAlgorithm::Blake3), _ => Err(()), } } } -/// The hash of the on-disk source file used for debug info. +/// The hash of the on-disk source file used for debug info and cargo freshness checks. #[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] #[derive(HashStable_Generic, Encodable, Decodable)] pub struct SourceFileHash { @@ -1418,12 +1442,22 @@ pub struct SourceFileHash { value: [u8; 32], } +impl Display for SourceFileHash { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}=", self.kind)?; + for byte in self.value[0..self.hash_len()].into_iter() { + write!(f, "{byte:02x}")?; + } + Ok(()) + } +} + impl SourceFileHash { - pub fn new(kind: SourceFileHashAlgorithm, src: &str) -> SourceFileHash { + pub fn new_in_memory(kind: SourceFileHashAlgorithm, src: impl AsRef<[u8]>) -> SourceFileHash { let mut hash = SourceFileHash { kind, value: Default::default() }; let len = hash.hash_len(); let value = &mut hash.value[..len]; - let data = src.as_bytes(); + let data = src.as_ref(); match kind { SourceFileHashAlgorithm::Md5 => { value.copy_from_slice(&Md5::digest(data)); @@ -1434,13 +1468,94 @@ impl SourceFileHash { SourceFileHashAlgorithm::Sha256 => { value.copy_from_slice(&Sha256::digest(data)); } - } + SourceFileHashAlgorithm::Blake3 => value.copy_from_slice(blake3::hash(data).as_bytes()), + }; hash } + pub fn new(kind: SourceFileHashAlgorithm, src: impl Read) -> Result { + let mut hash = SourceFileHash { kind, value: Default::default() }; + let len = hash.hash_len(); + let value = &mut hash.value[..len]; + // Buffer size is the recommended amount to fully leverage SIMD instructions on AVX-512 as per + // blake3 documentation. + let mut buf = vec![0; 16 * 1024]; + + fn digest( + mut hasher: T, + mut update: impl FnMut(&mut T, &[u8]), + finish: impl FnOnce(T, &mut [u8]), + mut src: impl Read, + buf: &mut [u8], + value: &mut [u8], + ) -> Result<(), io::Error> { + loop { + let bytes_read = src.read(buf)?; + if bytes_read == 0 { + break; + } + update(&mut hasher, &buf[0..bytes_read]); + } + finish(hasher, value); + Ok(()) + } + + match kind { + SourceFileHashAlgorithm::Sha256 => { + digest( + Sha256::new(), + |h, b| { + h.update(b); + }, + |h, out| out.copy_from_slice(&h.finalize()), + src, + &mut buf, + value, + )?; + } + SourceFileHashAlgorithm::Sha1 => { + digest( + Sha1::new(), + |h, b| { + h.update(b); + }, + |h, out| out.copy_from_slice(&h.finalize()), + src, + &mut buf, + value, + )?; + } + SourceFileHashAlgorithm::Md5 => { + digest( + Md5::new(), + |h, b| { + h.update(b); + }, + |h, out| out.copy_from_slice(&h.finalize()), + src, + &mut buf, + value, + )?; + } + SourceFileHashAlgorithm::Blake3 => { + digest( + blake3::Hasher::new(), + |h, b| { + h.update(b); + }, + |h, out| out.copy_from_slice(h.finalize().as_bytes()), + src, + &mut buf, + value, + )?; + } + } + Ok(hash) + } + /// Check if the stored hash matches the hash of the string. pub fn matches(&self, src: &str) -> bool { - Self::new(self.kind, src) == *self + Self::new_in_memory(self.kind, src.as_bytes()) == *self } /// The bytes of the hash. @@ -1453,7 +1568,7 @@ impl SourceFileHash { match self.kind { SourceFileHashAlgorithm::Md5 => 16, SourceFileHashAlgorithm::Sha1 => 20, - SourceFileHashAlgorithm::Sha256 => 32, + SourceFileHashAlgorithm::Sha256 | SourceFileHashAlgorithm::Blake3 => 32, } } } @@ -1509,6 +1624,10 @@ pub struct SourceFile { pub src: Option>, /// The source code's hash. pub src_hash: SourceFileHash, + /// Used to enable cargo to use checksums to check if a crate is fresh rather + /// than mtimes. This might be the same as `src_hash`, and if the requested algorithm + /// is identical we won't compute it twice. + pub checksum_hash: Option, /// The external source code (used for external crates, which will have a `None` /// value as `self.src`. pub external_src: FreezeLock, @@ -1536,6 +1655,7 @@ impl Clone for SourceFile { name: self.name.clone(), src: self.src.clone(), src_hash: self.src_hash, + checksum_hash: self.checksum_hash, external_src: self.external_src.clone(), start_pos: self.start_pos, source_len: self.source_len, @@ -1552,6 +1672,7 @@ impl Encodable for SourceFile { fn encode(&self, s: &mut S) { self.name.encode(s); self.src_hash.encode(s); + self.checksum_hash.encode(s); // Do not encode `start_pos` as it's global state for this session. self.source_len.encode(s); @@ -1625,6 +1746,7 @@ impl Decodable for SourceFile { fn decode(d: &mut D) -> SourceFile { let name: FileName = Decodable::decode(d); let src_hash: SourceFileHash = Decodable::decode(d); + let checksum_hash: Option = Decodable::decode(d); let source_len: RelativeBytePos = Decodable::decode(d); let lines = { let num_lines: u32 = Decodable::decode(d); @@ -1650,6 +1772,7 @@ impl Decodable for SourceFile { source_len, src: None, src_hash, + checksum_hash, // Unused - the metadata decoder will construct // a new SourceFile, filling in `external_src` properly external_src: FreezeLock::frozen(ExternalSource::Unneeded), @@ -1733,9 +1856,17 @@ impl SourceFile { name: FileName, mut src: String, hash_kind: SourceFileHashAlgorithm, + checksum_hash_kind: Option, ) -> Result { // Compute the file hash before any normalization. - let src_hash = SourceFileHash::new(hash_kind, &src); + let src_hash = SourceFileHash::new_in_memory(hash_kind, src.as_bytes()); + let checksum_hash = checksum_hash_kind.map(|checksum_hash_kind| { + if checksum_hash_kind == hash_kind { + src_hash + } else { + SourceFileHash::new_in_memory(checksum_hash_kind, src.as_bytes()) + } + }); let normalized_pos = normalize_src(&mut src); let stable_id = StableSourceFileId::from_filename_in_current_crate(&name); @@ -1748,6 +1879,7 @@ impl SourceFile { name, src: Some(Lrc::new(src)), src_hash, + checksum_hash, external_src: FreezeLock::frozen(ExternalSource::Unneeded), start_pos: BytePos::from_u32(0), source_len: RelativeBytePos::from_u32(source_len), diff --git a/compiler/rustc_span/src/source_map.rs b/compiler/rustc_span/src/source_map.rs index 98447147d3e..8a023305937 100644 --- a/compiler/rustc_span/src/source_map.rs +++ b/compiler/rustc_span/src/source_map.rs @@ -175,6 +175,7 @@ pub struct SourceMapInputs { pub file_loader: Box, pub path_mapping: FilePathMapping, pub hash_kind: SourceFileHashAlgorithm, + pub checksum_hash_kind: Option, } pub struct SourceMap { @@ -187,6 +188,12 @@ pub struct SourceMap { /// The algorithm used for hashing the contents of each source file. hash_kind: SourceFileHashAlgorithm, + + /// Similar to `hash_kind`, however this algorithm is used for checksums to determine if a crate is fresh. + /// `cargo` is the primary user of these. + /// + /// If this is equal to `hash_kind` then the checksum won't be computed twice. + checksum_hash_kind: Option, } impl SourceMap { @@ -195,17 +202,19 @@ impl SourceMap { file_loader: Box::new(RealFileLoader), path_mapping, hash_kind: SourceFileHashAlgorithm::Md5, + checksum_hash_kind: None, }) } pub fn with_inputs( - SourceMapInputs { file_loader, path_mapping, hash_kind }: SourceMapInputs, + SourceMapInputs { file_loader, path_mapping, hash_kind, checksum_hash_kind }: SourceMapInputs, ) -> SourceMap { SourceMap { files: Default::default(), file_loader: IntoDynSyncSend(file_loader), path_mapping, hash_kind, + checksum_hash_kind, } } @@ -307,7 +316,8 @@ impl SourceMap { match self.source_file_by_stable_id(stable_id) { Some(lrc_sf) => Ok(lrc_sf), None => { - let source_file = SourceFile::new(filename, src, self.hash_kind)?; + let source_file = + SourceFile::new(filename, src, self.hash_kind, self.checksum_hash_kind)?; // Let's make sure the file_id we generated above actually matches // the ID we generate for the SourceFile we just created. @@ -326,6 +336,7 @@ impl SourceMap { &self, filename: FileName, src_hash: SourceFileHash, + checksum_hash: Option, stable_id: StableSourceFileId, source_len: u32, cnum: CrateNum, @@ -340,6 +351,7 @@ impl SourceMap { name: filename, src: None, src_hash, + checksum_hash, external_src: FreezeLock::new(ExternalSource::Foreign { kind: ExternalSourceKind::AbsentOk, metadata_index, diff --git a/compiler/rustc_span/src/source_map/tests.rs b/compiler/rustc_span/src/source_map/tests.rs index 0c818b94b85..360baec273d 100644 --- a/compiler/rustc_span/src/source_map/tests.rs +++ b/compiler/rustc_span/src/source_map/tests.rs @@ -229,6 +229,7 @@ fn t10() { let SourceFile { name, src_hash, + checksum_hash, source_len, lines, multibyte_chars, @@ -240,6 +241,7 @@ fn t10() { let imported_src_file = sm.new_imported_source_file( name, src_hash, + checksum_hash, stable_id, source_len.to_u32(), CrateNum::ZERO, diff --git a/compiler/rustc_span/src/tests.rs b/compiler/rustc_span/src/tests.rs index 48fa786fb1c..ed1db344634 100644 --- a/compiler/rustc_span/src/tests.rs +++ b/compiler/rustc_span/src/tests.rs @@ -3,9 +3,13 @@ use super::*; #[test] fn test_lookup_line() { let source = "abcdefghijklm\nabcdefghij\n...".to_owned(); - let mut sf = - SourceFile::new(FileName::Anon(Hash64::ZERO), source, SourceFileHashAlgorithm::Sha256) - .unwrap(); + let mut sf = SourceFile::new( + FileName::Anon(Hash64::ZERO), + source, + SourceFileHashAlgorithm::Sha256, + Some(SourceFileHashAlgorithm::Sha256), + ) + .unwrap(); sf.start_pos = BytePos(3); assert_eq!(sf.lines(), &[RelativeBytePos(0), RelativeBytePos(14), RelativeBytePos(25)]); diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index 49d5b71ff2d..1ffad06457f 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -88,7 +88,10 @@ pub(crate) const WORKSPACES: &[(&str, ExceptionList, Option<(&[&str], &[&str])>, const EXCEPTIONS: ExceptionList = &[ // tidy-alphabetical-start ("ar_archive_writer", "Apache-2.0 WITH LLVM-exception"), // rustc + ("arrayref", "BSD-2-Clause"), // rustc + ("blake3", "CC0-1.0 OR Apache-2.0 OR Apache-2.0 WITH LLVM-exception"), // rustc ("colored", "MPL-2.0"), // rustfmt + ("constant_time_eq", "CC0-1.0 OR MIT-0 OR Apache-2.0"), // rustc ("dissimilar", "Apache-2.0"), // rustdoc, rustc_lexer (few tests) via expect-test, (dev deps) ("fluent-langneg", "Apache-2.0"), // rustc (fluent translations) ("instant", "BSD-3-Clause"), // rustc_driver/tracing-subscriber/parking_lot @@ -249,14 +252,17 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[ "annotate-snippets", "anstyle", "ar_archive_writer", + "arrayref", "arrayvec", "autocfg", "bitflags", + "blake3", "block-buffer", "byteorder", // via ruzstd in object in thorin-dwp "cc", "cfg-if", "cfg_aliases", + "constant_time_eq", "cpufeatures", "crc32fast", "crossbeam-channel", From 6ff7a3e2aaa383062aef31f239a0b3939e544a86 Mon Sep 17 00:00:00 2001 From: Jacob Kiesel Date: Sat, 27 Jul 2024 12:27:49 -0600 Subject: [PATCH 477/683] Fix options help text --- compiler/rustc_session/src/options.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index a1d85dfad32..c32cf3d015f 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -1707,7 +1707,7 @@ options! { check_cfg_all_expected: bool = (false, parse_bool, [UNTRACKED], "show all expected values in check-cfg diagnostics (default: no)"), checksum_hash_algorithm: Option = (None, parse_cargo_src_file_hash, [TRACKED], - "hash algorithm of source files used to check freshness in cargo (`sha256`)"), + "hash algorithm of source files used to check freshness in cargo (`blake3` or `sha256`)"), codegen_backend: Option = (None, parse_opt_string, [TRACKED], "the backend to use"), combine_cgu: bool = (false, parse_bool, [TRACKED], From 081661b78d44bd41f8a1fd46b9ed11823cd7811e Mon Sep 17 00:00:00 2001 From: Jacob Kiesel Date: Sat, 28 Sep 2024 17:38:28 -0600 Subject: [PATCH 478/683] disregard what we believe is supported in cargo for hash type --- compiler/rustc_session/src/options.rs | 6 +----- compiler/rustc_span/src/lib.rs | 9 --------- 2 files changed, 1 insertion(+), 14 deletions(-) diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index c32cf3d015f..b78d370bce0 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -1295,11 +1295,7 @@ mod parse { ) -> bool { match v.and_then(|s| SourceFileHashAlgorithm::from_str(s).ok()) { Some(hash_kind) => { - if hash_kind.supported_in_cargo() { - *slot = Some(hash_kind); - } else { - return false; - } + *slot = Some(hash_kind); } _ => return false, } diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index 5ab1caaa220..b55465ddef7 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -1400,15 +1400,6 @@ pub enum SourceFileHashAlgorithm { Blake3, } -impl SourceFileHashAlgorithm { - pub fn supported_in_cargo(&self) -> bool { - match self { - Self::Md5 | Self::Sha1 => false, - Self::Sha256 | Self::Blake3 => true, - } - } -} - impl Display for SourceFileHashAlgorithm { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str(match self { From dba814a9221e815a589a3ba48d2ef5287cd951ab Mon Sep 17 00:00:00 2001 From: Jacob Kiesel Date: Sat, 28 Sep 2024 18:09:44 -0600 Subject: [PATCH 479/683] Pile all the checksum info into a comment that goes in the same order as the file list for the makefile --- compiler/rustc_interface/src/passes.rs | 33 ++++++++++++++++---------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index b9b65755db5..cd5624e38bd 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -536,7 +536,7 @@ fn write_out_deps(tcx: TyCtxt<'_>, outputs: &OutputFilenames, out_filenames: &[P let write_deps_to_file = |file: &mut dyn Write| -> io::Result<()> { for path in out_filenames { - writeln!( + write!( file, "{}: {}\n", path.display(), @@ -546,6 +546,25 @@ fn write_out_deps(tcx: TyCtxt<'_>, outputs: &OutputFilenames, out_filenames: &[P .intersperse(" ") .collect::() )?; + + // If caller requested this information, add special comments about source file checksums. + // These are not necessarily the same checksums as was used in the debug files. + if sess.opts.unstable_opts.checksum_hash_algorithm().is_some() { + assert!( + files.iter().all(|(_path, _file_len, hash_algo)| hash_algo.is_some()), + "all files must have a checksum hash computed to output checksum hashes" + ); + write!(file, " # ")?; + files + .iter() + .filter_map(|(_path, file_len, hash_algo)| { + hash_algo.map(|hash_algo| (path, file_len, hash_algo)) + }) + .try_for_each(|(_path, file_len, checksum_hash)| { + write!(file, "checksum:{checksum_hash} file_len:{file_len}, ") + })?; + } + writeln!(file)?; } // Emit a fake target for each input file to the compilation. This @@ -575,18 +594,6 @@ fn write_out_deps(tcx: TyCtxt<'_>, outputs: &OutputFilenames, out_filenames: &[P } } - // If caller requested this information, add special comments about source file checksums. - // These are not necessarily the same checksums as was used in the debug files. - if sess.opts.unstable_opts.checksum_hash_algorithm().is_some() { - for (path, file_len, checksum_hash) in - files.iter().filter_map(|(path, file_len, hash_algo)| { - hash_algo.map(|hash_algo| (path, file_len, hash_algo)) - }) - { - writeln!(file, "# checksum:{checksum_hash} file_len:{file_len} {path}")?; - } - } - Ok(()) }; From e3089c787ce11ea45e0bb59a7c43c2803b326290 Mon Sep 17 00:00:00 2001 From: Jacob Kiesel Date: Sat, 28 Sep 2024 18:26:18 -0600 Subject: [PATCH 480/683] improve shell help text --- compiler/rustc_session/src/options.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index b78d370bce0..d63276db493 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -418,7 +418,8 @@ mod desc { "one of: `legacy`, `v0` (RFC 2603), or `hashed`"; pub(crate) const parse_opt_symbol_visibility: &str = "one of: `hidden`, `protected`, or `interposable`"; - pub(crate) const parse_cargo_src_file_hash: &str = "one of `md5`, `sha1`, or `sha256`"; + pub(crate) const parse_cargo_src_file_hash: &str = + "one of `blake3`, `md5`, `sha1`, or `sha256`"; pub(crate) const parse_src_file_hash: &str = "one of `md5`, `sha1`, or `sha256`"; pub(crate) const parse_relocation_model: &str = "one of supported relocation models (`rustc --print relocation-models`)"; From 6708d56fd2d5f937bc4b137757f18cd7c8dbd06b Mon Sep 17 00:00:00 2001 From: Jacob Kiesel Date: Sat, 28 Sep 2024 23:13:18 -0600 Subject: [PATCH 481/683] Fix bug in depinfo output --- compiler/rustc_interface/src/passes.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index cd5624e38bd..5a8ea410a63 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -538,7 +538,7 @@ fn write_out_deps(tcx: TyCtxt<'_>, outputs: &OutputFilenames, out_filenames: &[P for path in out_filenames { write!( file, - "{}: {}\n", + "{}: {}", path.display(), files .iter() @@ -565,6 +565,7 @@ fn write_out_deps(tcx: TyCtxt<'_>, outputs: &OutputFilenames, out_filenames: &[P })?; } writeln!(file)?; + writeln!(file)?; } // Emit a fake target for each input file to the compilation. This From 6fd9ef606f61f3162590ce66e1aa79319b44f2e9 Mon Sep 17 00:00:00 2001 From: Jacob Kiesel Date: Sun, 29 Sep 2024 00:06:40 -0600 Subject: [PATCH 482/683] no need to comma delimit this, it's already space delimited --- compiler/rustc_interface/src/passes.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 5a8ea410a63..7429893b51f 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -554,14 +554,14 @@ fn write_out_deps(tcx: TyCtxt<'_>, outputs: &OutputFilenames, out_filenames: &[P files.iter().all(|(_path, _file_len, hash_algo)| hash_algo.is_some()), "all files must have a checksum hash computed to output checksum hashes" ); - write!(file, " # ")?; + write!(file, " #")?; files .iter() .filter_map(|(_path, file_len, hash_algo)| { hash_algo.map(|hash_algo| (path, file_len, hash_algo)) }) .try_for_each(|(_path, file_len, checksum_hash)| { - write!(file, "checksum:{checksum_hash} file_len:{file_len}, ") + write!(file, " checksum:{checksum_hash} file_len:{file_len}") })?; } writeln!(file)?; From 0069649c3d23282942e44ee9d5d60546ae920070 Mon Sep 17 00:00:00 2001 From: Jacob Kiesel Date: Sun, 29 Sep 2024 01:22:30 -0600 Subject: [PATCH 483/683] Add basic integration test for checksum-hash-algorithm feature --- tests/run-make/checksum-freshness/expected.d | 3 +++ tests/run-make/checksum-freshness/lib.rs | 5 +++++ tests/run-make/checksum-freshness/rmake.rs | 9 +++++++++ 3 files changed, 17 insertions(+) create mode 100644 tests/run-make/checksum-freshness/expected.d create mode 100644 tests/run-make/checksum-freshness/lib.rs create mode 100644 tests/run-make/checksum-freshness/rmake.rs diff --git a/tests/run-make/checksum-freshness/expected.d b/tests/run-make/checksum-freshness/expected.d new file mode 100644 index 00000000000..c79bc8ff7de --- /dev/null +++ b/tests/run-make/checksum-freshness/expected.d @@ -0,0 +1,3 @@ +lib.d: lib.rs # checksum:blake3=5fd6328c93a3360bc580567aec10731ab3e5efc4a0f957b1bba0db0d27af3767 file_len:110 + +lib.rs: diff --git a/tests/run-make/checksum-freshness/lib.rs b/tests/run-make/checksum-freshness/lib.rs new file mode 100644 index 00000000000..c2895dc2613 --- /dev/null +++ b/tests/run-make/checksum-freshness/lib.rs @@ -0,0 +1,5 @@ +// A basic library to be used in tests with no real purpose. + +pub fn sum(a: i32, b: i32) -> i32 { + a + b +} diff --git a/tests/run-make/checksum-freshness/rmake.rs b/tests/run-make/checksum-freshness/rmake.rs new file mode 100644 index 00000000000..071db6b145b --- /dev/null +++ b/tests/run-make/checksum-freshness/rmake.rs @@ -0,0 +1,9 @@ +use run_make_support::{rfs, rustc}; + +fn main() { + rustc().input("lib.rs").arg("-Zchecksum-hash-algorithm=blake3").emit("dep-info").run(); + let make_file_contents = rfs::read_to_string("lib.d"); + let expected_contents = rfs::read_to_string("expected.d"); + assert_eq!(make_file_contents, expected_contents); + assert!(!expected_contents.is_empty()); +} From 4d9fa6fa775fc70cdaf1996ebe2c5b034d743819 Mon Sep 17 00:00:00 2001 From: Jacob Kiesel Date: Sun, 29 Sep 2024 01:27:47 -0600 Subject: [PATCH 484/683] add another file to the integration test --- tests/run-make/checksum-freshness/expected.d | 3 ++- tests/run-make/checksum-freshness/foo.rs | 5 +++++ tests/run-make/checksum-freshness/lib.rs | 2 ++ 3 files changed, 9 insertions(+), 1 deletion(-) create mode 100644 tests/run-make/checksum-freshness/foo.rs diff --git a/tests/run-make/checksum-freshness/expected.d b/tests/run-make/checksum-freshness/expected.d index c79bc8ff7de..4b10e293229 100644 --- a/tests/run-make/checksum-freshness/expected.d +++ b/tests/run-make/checksum-freshness/expected.d @@ -1,3 +1,4 @@ -lib.d: lib.rs # checksum:blake3=5fd6328c93a3360bc580567aec10731ab3e5efc4a0f957b1bba0db0d27af3767 file_len:110 +lib.d: lib.rs foo.rs # checksum:blake3=94af75ee4ed805434484c3de51c9025278e5c3ada2315e2592052e102168a503 file_len:120 checksum:blake3=2720e17bfda4f3b2a5c96bb61b7e76ed8ebe3359b34128c0e5d8032c090a4f1a file_len:119 lib.rs: +foo.rs: diff --git a/tests/run-make/checksum-freshness/foo.rs b/tests/run-make/checksum-freshness/foo.rs new file mode 100644 index 00000000000..d3ef768f187 --- /dev/null +++ b/tests/run-make/checksum-freshness/foo.rs @@ -0,0 +1,5 @@ +// This is another file, just to prove we can handle two of them + +pub fn subtract(a: i32, b: i32) -> i32 { + a - b +} diff --git a/tests/run-make/checksum-freshness/lib.rs b/tests/run-make/checksum-freshness/lib.rs index c2895dc2613..7bc6757959b 100644 --- a/tests/run-make/checksum-freshness/lib.rs +++ b/tests/run-make/checksum-freshness/lib.rs @@ -1,5 +1,7 @@ // A basic library to be used in tests with no real purpose. +mod foo; + pub fn sum(a: i32, b: i32) -> i32 { a + b } From 15efbc6e8d78b257f594ddfb64d215c9ac3bee6d Mon Sep 17 00:00:00 2001 From: Jacob Kiesel Date: Tue, 1 Oct 2024 21:26:03 -0600 Subject: [PATCH 485/683] Write two newlines intentionally --- compiler/rustc_interface/src/passes.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 7429893b51f..a8afb8c2900 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -564,8 +564,7 @@ fn write_out_deps(tcx: TyCtxt<'_>, outputs: &OutputFilenames, out_filenames: &[P write!(file, " checksum:{checksum_hash} file_len:{file_len}") })?; } - writeln!(file)?; - writeln!(file)?; + write!(file, "\n\n")?; } // Emit a fake target for each input file to the compilation. This From b48c5f19e07c46d43d03328c86d3f7af6f9c8187 Mon Sep 17 00:00:00 2001 From: Jacob Kiesel Date: Tue, 1 Oct 2024 23:05:24 -0600 Subject: [PATCH 486/683] Restore prior behavior with less duplicate info in dep file --- compiler/rustc_interface/src/passes.rs | 35 ++++++++------------ tests/run-make/checksum-freshness/expected.d | 4 ++- 2 files changed, 17 insertions(+), 22 deletions(-) diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index a8afb8c2900..b9b65755db5 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -536,9 +536,9 @@ fn write_out_deps(tcx: TyCtxt<'_>, outputs: &OutputFilenames, out_filenames: &[P let write_deps_to_file = |file: &mut dyn Write| -> io::Result<()> { for path in out_filenames { - write!( + writeln!( file, - "{}: {}", + "{}: {}\n", path.display(), files .iter() @@ -546,25 +546,6 @@ fn write_out_deps(tcx: TyCtxt<'_>, outputs: &OutputFilenames, out_filenames: &[P .intersperse(" ") .collect::() )?; - - // If caller requested this information, add special comments about source file checksums. - // These are not necessarily the same checksums as was used in the debug files. - if sess.opts.unstable_opts.checksum_hash_algorithm().is_some() { - assert!( - files.iter().all(|(_path, _file_len, hash_algo)| hash_algo.is_some()), - "all files must have a checksum hash computed to output checksum hashes" - ); - write!(file, " #")?; - files - .iter() - .filter_map(|(_path, file_len, hash_algo)| { - hash_algo.map(|hash_algo| (path, file_len, hash_algo)) - }) - .try_for_each(|(_path, file_len, checksum_hash)| { - write!(file, " checksum:{checksum_hash} file_len:{file_len}") - })?; - } - write!(file, "\n\n")?; } // Emit a fake target for each input file to the compilation. This @@ -594,6 +575,18 @@ fn write_out_deps(tcx: TyCtxt<'_>, outputs: &OutputFilenames, out_filenames: &[P } } + // If caller requested this information, add special comments about source file checksums. + // These are not necessarily the same checksums as was used in the debug files. + if sess.opts.unstable_opts.checksum_hash_algorithm().is_some() { + for (path, file_len, checksum_hash) in + files.iter().filter_map(|(path, file_len, hash_algo)| { + hash_algo.map(|hash_algo| (path, file_len, hash_algo)) + }) + { + writeln!(file, "# checksum:{checksum_hash} file_len:{file_len} {path}")?; + } + } + Ok(()) }; diff --git a/tests/run-make/checksum-freshness/expected.d b/tests/run-make/checksum-freshness/expected.d index 4b10e293229..51467af53a2 100644 --- a/tests/run-make/checksum-freshness/expected.d +++ b/tests/run-make/checksum-freshness/expected.d @@ -1,4 +1,6 @@ -lib.d: lib.rs foo.rs # checksum:blake3=94af75ee4ed805434484c3de51c9025278e5c3ada2315e2592052e102168a503 file_len:120 checksum:blake3=2720e17bfda4f3b2a5c96bb61b7e76ed8ebe3359b34128c0e5d8032c090a4f1a file_len:119 +lib.d: lib.rs foo.rs lib.rs: foo.rs: +# checksum:blake3=94af75ee4ed805434484c3de51c9025278e5c3ada2315e2592052e102168a503 file_len:120 lib.rs +# checksum:blake3=2720e17bfda4f3b2a5c96bb61b7e76ed8ebe3359b34128c0e5d8032c090a4f1a file_len:119 foo.rs From 807e812077ff9d70840f14822ae6e0e9753bd1fb Mon Sep 17 00:00:00 2001 From: ismailarilik Date: Wed, 2 Oct 2024 08:25:55 +0300 Subject: [PATCH 487/683] Handle `rustc-hir-analysis` cases of `rustc::potential_query_instability` lint --- .../rustc_hir_analysis/src/check/wfcheck.rs | 20 ++++++++--------- .../src/coherence/inherent_impls_overlap.rs | 4 ++-- .../src/hir_ty_lowering/mod.rs | 6 ++--- compiler/rustc_hir_analysis/src/lib.rs | 1 - compiler/rustc_middle/src/ty/mod.rs | 2 +- compiler/rustc_middle/src/ty/visit.rs | 10 ++++----- compiler/rustc_resolve/src/lib.rs | 2 +- .../self-outlives-lint.stderr | 22 +++++++++---------- 8 files changed, 33 insertions(+), 34 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 70b0b3f5788..02d23b95d46 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -2,7 +2,7 @@ use std::cell::LazyCell; use std::ops::{ControlFlow, Deref}; use hir::intravisit::{self, Visitor}; -use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet}; +use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; use rustc_errors::codes::*; use rustc_errors::{Applicability, ErrorGuaranteed, pluralize, struct_span_code_err}; use rustc_hir::ItemKind; @@ -404,7 +404,7 @@ fn check_trait_item<'tcx>( /// ``` fn check_gat_where_clauses(tcx: TyCtxt<'_>, trait_def_id: LocalDefId) { // Associates every GAT's def_id to a list of possibly missing bounds detected by this lint. - let mut required_bounds_by_item = FxHashMap::default(); + let mut required_bounds_by_item = FxIndexMap::default(); let associated_items = tcx.associated_items(trait_def_id); // Loop over all GATs together, because if this lint suggests adding a where-clause bound @@ -430,7 +430,7 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, trait_def_id: LocalDefId) { // Gather the bounds with which all other items inside of this trait constrain the GAT. // This is calculated by taking the intersection of the bounds that each item // constrains the GAT with individually. - let mut new_required_bounds: Option>> = None; + let mut new_required_bounds: Option>> = None; for item in associated_items.in_definition_order() { let item_def_id = item.def_id.expect_local(); // Skip our own GAT, since it does not constrain itself at all. @@ -589,7 +589,7 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, trait_def_id: LocalDefId) { fn augment_param_env<'tcx>( tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, - new_predicates: Option<&FxHashSet>>, + new_predicates: Option<&FxIndexSet>>, ) -> ty::ParamEnv<'tcx> { let Some(new_predicates) = new_predicates else { return param_env; @@ -625,9 +625,9 @@ fn gather_gat_bounds<'tcx, T: TypeFoldable>>( wf_tys: &FxIndexSet>, gat_def_id: LocalDefId, gat_generics: &'tcx ty::Generics, -) -> Option>> { +) -> Option>> { // The bounds we that we would require from `to_check` - let mut bounds = FxHashSet::default(); + let mut bounds = FxIndexSet::default(); let (regions, types) = GATArgsCollector::visit(gat_def_id.to_def_id(), to_check); @@ -789,18 +789,18 @@ fn test_region_obligations<'tcx>( struct GATArgsCollector<'tcx> { gat: DefId, // Which region appears and which parameter index its instantiated with - regions: FxHashSet<(ty::Region<'tcx>, usize)>, + regions: FxIndexSet<(ty::Region<'tcx>, usize)>, // Which params appears and which parameter index its instantiated with - types: FxHashSet<(Ty<'tcx>, usize)>, + types: FxIndexSet<(Ty<'tcx>, usize)>, } impl<'tcx> GATArgsCollector<'tcx> { fn visit>>( gat: DefId, t: T, - ) -> (FxHashSet<(ty::Region<'tcx>, usize)>, FxHashSet<(Ty<'tcx>, usize)>) { + ) -> (FxIndexSet<(ty::Region<'tcx>, usize)>, FxIndexSet<(Ty<'tcx>, usize)>) { let mut visitor = - GATArgsCollector { gat, regions: FxHashSet::default(), types: FxHashSet::default() }; + GATArgsCollector { gat, regions: FxIndexSet::default(), types: FxIndexSet::default() }; t.visit_with(&mut visitor); (visitor.regions, visitor.types) } diff --git a/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs b/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs index b8066b4b47d..d1c888a185e 100644 --- a/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs +++ b/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs @@ -1,4 +1,4 @@ -use rustc_data_structures::fx::{FxHashSet, FxIndexMap, IndexEntry}; +use rustc_data_structures::fx::{FxIndexMap, FxIndexSet, IndexEntry}; use rustc_errors::codes::*; use rustc_errors::struct_span_code_err; use rustc_hir as hir; @@ -215,7 +215,7 @@ impl<'tcx> InherentOverlapChecker<'tcx> { struct ConnectedRegion { idents: SmallVec<[Symbol; 8]>, - impl_blocks: FxHashSet, + impl_blocks: FxIndexSet, } let mut connected_regions: IndexVec = Default::default(); // Reverse map from the Symbol to the connected region id. 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 2186952720f..6dd3a06ef37 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -23,7 +23,7 @@ mod lint; use std::slice; use rustc_ast::TraitObjectSyntax; -use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; +use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; use rustc_errors::codes::*; use rustc_errors::{ Applicability, Diag, DiagCtxtHandle, ErrorGuaranteed, FatalError, struct_span_code_err, @@ -2394,8 +2394,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { #[instrument(level = "trace", skip(self, generate_err))] fn validate_late_bound_regions<'cx>( &'cx self, - constrained_regions: FxHashSet, - referenced_regions: FxHashSet, + constrained_regions: FxIndexSet, + referenced_regions: FxIndexSet, generate_err: impl Fn(&str) -> Diag<'cx>, ) { for br in referenced_regions.difference(&constrained_regions) { diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index 92d85d48a42..7d40a7746b9 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -58,7 +58,6 @@ This API is completely unstable and subject to change. // tidy-alphabetical-start #![allow(internal_features)] #![allow(rustc::diagnostic_outside_of_impl)] -#![allow(rustc::potential_query_instability)] #![allow(rustc::untranslatable_diagnostic)] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 2b1212a5eb5..c4a28845085 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -186,7 +186,7 @@ pub struct ResolverGlobalCtxt { pub proc_macros: Vec, /// Mapping from ident span to path span for paths that don't exist as written, but that /// exist under `std`. For example, wrote `str::from_utf8` instead of `std::str::from_utf8`. - pub confused_type_with_std_module: FxHashMap, + pub confused_type_with_std_module: FxIndexMap, pub doc_link_resolutions: FxHashMap, pub doc_link_traits_in_scope: FxHashMap>, pub all_macro_rules: FxHashMap>, diff --git a/compiler/rustc_middle/src/ty/visit.rs b/compiler/rustc_middle/src/ty/visit.rs index 78d83004c14..4efaccefcf7 100644 --- a/compiler/rustc_middle/src/ty/visit.rs +++ b/compiler/rustc_middle/src/ty/visit.rs @@ -1,6 +1,6 @@ use std::ops::ControlFlow; -use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::fx::FxIndexSet; use rustc_type_ir::fold::TypeFoldable; pub use rustc_type_ir::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor}; @@ -110,7 +110,7 @@ impl<'tcx> TyCtxt<'tcx> { pub fn collect_constrained_late_bound_regions( self, value: Binder<'tcx, T>, - ) -> FxHashSet + ) -> FxIndexSet where T: TypeFoldable>, { @@ -121,7 +121,7 @@ impl<'tcx> TyCtxt<'tcx> { pub fn collect_referenced_late_bound_regions( self, value: Binder<'tcx, T>, - ) -> FxHashSet + ) -> FxIndexSet where T: TypeFoldable>, { @@ -132,7 +132,7 @@ impl<'tcx> TyCtxt<'tcx> { self, value: Binder<'tcx, T>, just_constrained: bool, - ) -> FxHashSet + ) -> FxIndexSet where T: TypeFoldable>, { @@ -148,7 +148,7 @@ impl<'tcx> TyCtxt<'tcx> { /// into a hash set. struct LateBoundRegionsCollector { current_index: ty::DebruijnIndex, - regions: FxHashSet, + regions: FxIndexSet, /// `true` if we only want regions that are known to be /// "constrained" when you equate this type with another type. In diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index b84408cd0cb..0c1a0038f9c 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -1188,7 +1188,7 @@ pub struct Resolver<'ra, 'tcx> { /// A list of proc macro LocalDefIds, written out in the order in which /// they are declared in the static array generated by proc_macro_harness. proc_macros: Vec, - confused_type_with_std_module: FxHashMap, + confused_type_with_std_module: FxIndexMap, /// Whether lifetime elision was successful. lifetime_elision_allowed: FxHashSet, diff --git a/tests/ui/generic-associated-types/self-outlives-lint.stderr b/tests/ui/generic-associated-types/self-outlives-lint.stderr index 9e9b2e18abe..58172bf06b5 100644 --- a/tests/ui/generic-associated-types/self-outlives-lint.stderr +++ b/tests/ui/generic-associated-types/self-outlives-lint.stderr @@ -108,17 +108,6 @@ LL | type Bar<'b>; = note: this bound is currently required to ensure that impls have maximum flexibility = note: we are soliciting feedback, see issue #87479 for more information -error: missing required bound on `Iterator` - --> $DIR/self-outlives-lint.rs:142:5 - | -LL | type Iterator<'a>: Iterator>; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- - | | - | help: add the required where clause: `where Self: 'a` - | - = note: this bound is currently required to ensure that impls have maximum flexibility - = note: we are soliciting feedback, see issue #87479 for more information - error: missing required bound on `Item` --> $DIR/self-outlives-lint.rs:140:5 | @@ -130,6 +119,17 @@ LL | type Item<'a>; = note: this bound is currently required to ensure that impls have maximum flexibility = note: we are soliciting feedback, see issue #87479 for more information +error: missing required bound on `Iterator` + --> $DIR/self-outlives-lint.rs:142:5 + | +LL | type Iterator<'a>: Iterator>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- + | | + | help: add the required where clause: `where Self: 'a` + | + = note: this bound is currently required to ensure that impls have maximum flexibility + = note: we are soliciting feedback, see issue #87479 for more information + error: missing required bound on `Item` --> $DIR/self-outlives-lint.rs:148:5 | From 9fa120593e2b6325812aa558fa8878d5aa6635b2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 2 Oct 2024 08:00:17 +0200 Subject: [PATCH 488/683] mpmc doctest: make sure main thread waits for child threads --- library/std/src/sync/mpmc/mod.rs | 46 +++++++++++++++++--------------- 1 file changed, 24 insertions(+), 22 deletions(-) diff --git a/library/std/src/sync/mpmc/mod.rs b/library/std/src/sync/mpmc/mod.rs index 77a67f4fd38..44e146a89ba 100644 --- a/library/std/src/sync/mpmc/mod.rs +++ b/library/std/src/sync/mpmc/mod.rs @@ -66,29 +66,31 @@ //! use std::thread; //! use std::sync::mpmc::channel; //! -//! // Create a shared channel that can be sent along from many threads -//! // where tx is the sending half (tx for transmission), and rx is the receiving -//! // half (rx for receiving). -//! let (tx, rx) = channel(); -//! for i in 0..10 { -//! let tx = tx.clone(); -//! thread::spawn(move || { -//! tx.send(i).unwrap(); -//! }); -//! } +//! thread::scope(|s| { +//! // Create a shared channel that can be sent along from many threads +//! // where tx is the sending half (tx for transmission), and rx is the receiving +//! // half (rx for receiving). +//! let (tx, rx) = channel(); +//! for i in 0..10 { +//! let tx = tx.clone(); +//! s.spawn(move || { +//! tx.send(i).unwrap(); +//! }); +//! } //! -//! for _ in 0..5 { -//! let rx1 = rx.clone(); -//! let rx2 = rx.clone(); -//! thread::spawn(move || { -//! let j = rx1.recv().unwrap(); -//! assert!(0 <= j && j < 10); -//! }); -//! thread::spawn(move || { -//! let j = rx2.recv().unwrap(); -//! assert!(0 <= j && j < 10); -//! }); -//! } +//! for _ in 0..5 { +//! let rx1 = rx.clone(); +//! let rx2 = rx.clone(); +//! s.spawn(move || { +//! let j = rx1.recv().unwrap(); +//! assert!(0 <= j && j < 10); +//! }); +//! s.spawn(move || { +//! let j = rx2.recv().unwrap(); +//! assert!(0 <= j && j < 10); +//! }); +//! } +//! }) //! ``` //! //! Propagating panics: From 58c5ac43aea5c94d61e3a7a4e8646e714230574d Mon Sep 17 00:00:00 2001 From: Jacob Kiesel Date: Wed, 2 Oct 2024 00:49:46 -0600 Subject: [PATCH 489/683] restore prior more readable suggestion --- compiler/rustc_interface/src/passes.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index b9b65755db5..204ae437a3e 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -578,13 +578,14 @@ fn write_out_deps(tcx: TyCtxt<'_>, outputs: &OutputFilenames, out_filenames: &[P // If caller requested this information, add special comments about source file checksums. // These are not necessarily the same checksums as was used in the debug files. if sess.opts.unstable_opts.checksum_hash_algorithm().is_some() { - for (path, file_len, checksum_hash) in - files.iter().filter_map(|(path, file_len, hash_algo)| { + files + .iter() + .filter_map(|(path, file_len, hash_algo)| { hash_algo.map(|hash_algo| (path, file_len, hash_algo)) }) - { - writeln!(file, "# checksum:{checksum_hash} file_len:{file_len} {path}")?; - } + .try_for_each(|(path, file_len, checksum_hash)| { + writeln!(file, "# checksum:{checksum_hash} file_len:{file_len} {path}") + })?; } Ok(()) From 8760a401bd55205a188fdc174785c6f32f4027fa Mon Sep 17 00:00:00 2001 From: Urgau Date: Wed, 2 Oct 2024 09:44:51 +0200 Subject: [PATCH 490/683] Update hashbrown to 0.15 and adjust some methods as well as removing some from std as they no longer exists in Hashbrown it-self. --- library/Cargo.lock | 4 +- library/std/Cargo.toml | 2 +- library/std/src/collections/hash/map.rs | 137 ++++++++++-------------- library/std/src/collections/hash/set.rs | 32 ------ 4 files changed, 58 insertions(+), 117 deletions(-) diff --git a/library/Cargo.lock b/library/Cargo.lock index 877ae0cc1cc..209e30b3040 100644 --- a/library/Cargo.lock +++ b/library/Cargo.lock @@ -135,9 +135,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.14.5" +version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb" dependencies = [ "allocator-api2", "compiler_builtins", diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index 7d860b49e87..63c65b8ef39 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -20,7 +20,7 @@ core = { path = "../core", public = true } compiler_builtins = { version = "0.1.130" } profiler_builtins = { path = "../profiler_builtins", optional = true } unwind = { path = "../unwind" } -hashbrown = { version = "0.14", default-features = false, features = [ +hashbrown = { version = "0.15", default-features = false, features = [ 'rustc-dep-of-std', ] } # FIXME(#127890): `object` depends on `memchr`, but `memchr` > v2.5 causes diff --git a/library/std/src/collections/hash/map.rs b/library/std/src/collections/hash/map.rs index 1a18721b15e..6f2b4100620 100644 --- a/library/std/src/collections/hash/map.rs +++ b/library/std/src/collections/hash/map.rs @@ -909,8 +909,11 @@ where /// Attempts to get mutable references to `N` values in the map at once. /// /// Returns an array of length `N` with the results of each query. For soundness, at most one - /// mutable reference will be returned to any value. `None` will be returned if any of the - /// keys are duplicates or missing. + /// mutable reference will be returned to any value. `None` will be used if the key is missing. + /// + /// # Panics + /// + /// Panics if any keys are overlapping. /// /// # Examples /// @@ -924,16 +927,23 @@ where /// libraries.insert("Herzogin-Anna-Amalia-Bibliothek".to_string(), 1691); /// libraries.insert("Library of Congress".to_string(), 1800); /// + /// // Get Athenæum and Bodleian Library + /// let [Some(a), Some(b)] = libraries.get_many_mut([ + /// "Athenæum", + /// "Bodleian Library", + /// ]) else { panic!() }; + /// + /// // Assert values of Athenæum and Library of Congress /// let got = libraries.get_many_mut([ /// "Athenæum", /// "Library of Congress", /// ]); /// assert_eq!( /// got, - /// Some([ - /// &mut 1807, - /// &mut 1800, - /// ]), + /// [ + /// Some(&mut 1807), + /// Some(&mut 1800), + /// ], /// ); /// /// // Missing keys result in None @@ -941,18 +951,31 @@ where /// "Athenæum", /// "New York Public Library", /// ]); - /// assert_eq!(got, None); + /// assert_eq!( + /// got, + /// [ + /// Some(&mut 1807), + /// None + /// ] + /// ); + /// ``` /// - /// // Duplicate keys result in None + /// ```should_panic + /// #![feature(map_many_mut)] + /// use std::collections::HashMap; + /// + /// let mut libraries = HashMap::new(); + /// libraries.insert("Athenæum".to_string(), 1807); + /// + /// // Duplicate keys panic! /// let got = libraries.get_many_mut([ /// "Athenæum", /// "Athenæum", /// ]); - /// assert_eq!(got, None); /// ``` #[inline] #[unstable(feature = "map_many_mut", issue = "97601")] - pub fn get_many_mut(&mut self, ks: [&Q; N]) -> Option<[&'_ mut V; N]> + pub fn get_many_mut(&mut self, ks: [&Q; N]) -> [Option<&'_ mut V>; N] where K: Borrow, Q: Hash + Eq, @@ -963,10 +986,10 @@ where /// Attempts to get mutable references to `N` values in the map at once, without validating that /// the values are unique. /// - /// Returns an array of length `N` with the results of each query. `None` will be returned if - /// any of the keys are missing. + /// Returns an array of length `N` with the results of each query. `None` will be used if + /// the key is missing. /// - /// For a safe alternative see [`get_many_mut`](Self::get_many_mut). + /// For a safe alternative see [`get_many_mut`](`HashMap::get_many_mut`). /// /// # Safety /// @@ -987,31 +1010,39 @@ where /// libraries.insert("Herzogin-Anna-Amalia-Bibliothek".to_string(), 1691); /// libraries.insert("Library of Congress".to_string(), 1800); /// - /// let got = libraries.get_many_mut([ + /// // SAFETY: The keys do not overlap. + /// let [Some(a), Some(b)] = (unsafe { libraries.get_many_unchecked_mut([ + /// "Athenæum", + /// "Bodleian Library", + /// ]) }) else { panic!() }; + /// + /// // SAFETY: The keys do not overlap. + /// let got = unsafe { libraries.get_many_unchecked_mut([ /// "Athenæum", /// "Library of Congress", - /// ]); + /// ]) }; /// assert_eq!( /// got, - /// Some([ - /// &mut 1807, - /// &mut 1800, - /// ]), + /// [ + /// Some(&mut 1807), + /// Some(&mut 1800), + /// ], /// ); /// - /// // Missing keys result in None - /// let got = libraries.get_many_mut([ + /// // SAFETY: The keys do not overlap. + /// let got = unsafe { libraries.get_many_unchecked_mut([ /// "Athenæum", /// "New York Public Library", - /// ]); - /// assert_eq!(got, None); + /// ]) }; + /// // Missing keys result in None + /// assert_eq!(got, [Some(&mut 1807), None]); /// ``` #[inline] #[unstable(feature = "map_many_mut", issue = "97601")] pub unsafe fn get_many_unchecked_mut( &mut self, ks: [&Q; N], - ) -> Option<[&'_ mut V; N]> + ) -> [Option<&'_ mut V>; N] where K: Borrow, Q: Hash + Eq, @@ -2978,64 +3009,6 @@ impl<'a, K, V> OccupiedEntry<'a, K, V> { pub fn remove(self) -> V { self.base.remove() } - - /// Replaces the entry, returning the old key and value. The new key in the hash map will be - /// the key used to create this entry. - /// - /// # Examples - /// - /// ``` - /// #![feature(map_entry_replace)] - /// use std::collections::hash_map::{Entry, HashMap}; - /// use std::rc::Rc; - /// - /// let mut map: HashMap, u32> = HashMap::new(); - /// map.insert(Rc::new("Stringthing".to_string()), 15); - /// - /// let my_key = Rc::new("Stringthing".to_string()); - /// - /// if let Entry::Occupied(entry) = map.entry(my_key) { - /// // Also replace the key with a handle to our other key. - /// let (old_key, old_value): (Rc, u32) = entry.replace_entry(16); - /// } - /// - /// ``` - #[inline] - #[unstable(feature = "map_entry_replace", issue = "44286")] - pub fn replace_entry(self, value: V) -> (K, V) { - self.base.replace_entry(value) - } - - /// Replaces the key in the hash map with the key used to create this entry. - /// - /// # Examples - /// - /// ``` - /// #![feature(map_entry_replace)] - /// use std::collections::hash_map::{Entry, HashMap}; - /// use std::rc::Rc; - /// - /// let mut map: HashMap, u32> = HashMap::new(); - /// let known_strings: Vec> = Vec::new(); - /// - /// // Initialise known strings, run program, etc. - /// - /// reclaim_memory(&mut map, &known_strings); - /// - /// fn reclaim_memory(map: &mut HashMap, u32>, known_strings: &[Rc] ) { - /// for s in known_strings { - /// if let Entry::Occupied(entry) = map.entry(Rc::clone(s)) { - /// // Replaces the entry's key with our version of it in `known_strings`. - /// entry.replace_key(); - /// } - /// } - /// } - /// ``` - #[inline] - #[unstable(feature = "map_entry_replace", issue = "44286")] - pub fn replace_key(self) -> K { - self.base.replace_key() - } } impl<'a, K: 'a, V: 'a> VacantEntry<'a, K, V> { diff --git a/library/std/src/collections/hash/set.rs b/library/std/src/collections/hash/set.rs index 4a113ddea3a..e69fb0878e7 100644 --- a/library/std/src/collections/hash/set.rs +++ b/library/std/src/collections/hash/set.rs @@ -724,38 +724,6 @@ where self.base.get_or_insert(value) } - /// Inserts an owned copy of the given `value` into the set if it is not - /// present, then returns a reference to the value in the set. - /// - /// # Examples - /// - /// ``` - /// #![feature(hash_set_entry)] - /// - /// use std::collections::HashSet; - /// - /// let mut set: HashSet = ["cat", "dog", "horse"] - /// .iter().map(|&pet| pet.to_owned()).collect(); - /// - /// assert_eq!(set.len(), 3); - /// for &pet in &["cat", "dog", "fish"] { - /// let value = set.get_or_insert_owned(pet); - /// assert_eq!(value, pet); - /// } - /// assert_eq!(set.len(), 4); // a new "fish" was inserted - /// ``` - #[inline] - #[unstable(feature = "hash_set_entry", issue = "60896")] - pub fn get_or_insert_owned(&mut self, value: &Q) -> &T - where - T: Borrow, - Q: Hash + Eq + ToOwned, - { - // Although the raw entry gives us `&mut T`, we only return `&T` to be consistent with - // `get`. Key mutation is "raw" because you're not supposed to affect `Eq` or `Hash`. - self.base.get_or_insert_owned(value) - } - /// Inserts a value computed from `f` into the set if the given `value` is /// not present, then returns a reference to the value in the set. /// From 37e1c955c511cc7ee8e53d848006ae8077555009 Mon Sep 17 00:00:00 2001 From: Urgau Date: Wed, 2 Oct 2024 09:45:27 +0200 Subject: [PATCH 491/683] Adjust check-cfg get_many_mut usage following API change --- compiler/rustc_session/src/config/cfg.rs | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_session/src/config/cfg.rs b/compiler/rustc_session/src/config/cfg.rs index 44b96d92b19..ccc01728958 100644 --- a/compiler/rustc_session/src/config/cfg.rs +++ b/compiler/rustc_session/src/config/cfg.rs @@ -402,18 +402,18 @@ impl CheckCfg { // Get all values map at once otherwise it would be costly. // (8 values * 220 targets ~= 1760 times, at the time of writing this comment). let [ - values_target_abi, - values_target_arch, - values_target_endian, - values_target_env, - values_target_family, - values_target_os, - values_target_pointer_width, - values_target_vendor, - ] = self - .expecteds - .get_many_mut(VALUES) - .expect("unable to get all the check-cfg values buckets"); + Some(values_target_abi), + Some(values_target_arch), + Some(values_target_endian), + Some(values_target_env), + Some(values_target_family), + Some(values_target_os), + Some(values_target_pointer_width), + Some(values_target_vendor), + ] = self.expecteds.get_many_mut(VALUES) + else { + panic!("unable to get all the check-cfg values buckets"); + }; for target in TARGETS .iter() From a923fc011bf14e94071594fd95a36c970ed8623d Mon Sep 17 00:00:00 2001 From: Urgau Date: Wed, 2 Oct 2024 11:15:48 +0200 Subject: [PATCH 492/683] Fix rustdoc-js-std path-ordering test due to API removal --- tests/rustdoc-js-std/path-ordering.js | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/rustdoc-js-std/path-ordering.js b/tests/rustdoc-js-std/path-ordering.js index e6b7bfab1e5..4bfc6256052 100644 --- a/tests/rustdoc-js-std/path-ordering.js +++ b/tests/rustdoc-js-std/path-ordering.js @@ -6,7 +6,6 @@ const EXPECTED = [ { 'path': 'std::collections::hash_set::HashSet', 'name': 'insert' }, { 'path': 'std::collections::hash_set::HashSet', 'name': 'get_or_insert' }, { 'path': 'std::collections::hash_set::HashSet', 'name': 'get_or_insert_with' }, - { 'path': 'std::collections::hash_set::HashSet', 'name': 'get_or_insert_owned' }, ], }, { From e9b2d09ad7905c51e7795730147f8d2303fb4bbd Mon Sep 17 00:00:00 2001 From: bohan Date: Wed, 2 Oct 2024 17:36:31 +0800 Subject: [PATCH 493/683] only query `params_in_repr` if def kind is adt --- compiler/rustc_middle/src/values.rs | 2 +- tests/crashes/128327.rs | 5 ----- tests/ui/infinite/auxiliary/alias.rs | 3 +++ tests/ui/infinite/infinite-assoc.rs | 16 ++++++++++++++++ tests/ui/infinite/infinite-assoc.stderr | 25 +++++++++++++++++++++++++ 5 files changed, 45 insertions(+), 6 deletions(-) delete mode 100644 tests/crashes/128327.rs create mode 100644 tests/ui/infinite/infinite-assoc.rs create mode 100644 tests/ui/infinite/infinite-assoc.stderr diff --git a/compiler/rustc_middle/src/values.rs b/compiler/rustc_middle/src/values.rs index c98d88e22d4..48ca38344cf 100644 --- a/compiler/rustc_middle/src/values.rs +++ b/compiler/rustc_middle/src/values.rs @@ -358,7 +358,7 @@ fn find_item_ty_spans( match ty.kind { hir::TyKind::Path(hir::QPath::Resolved(_, path)) => { if let Res::Def(kind, def_id) = path.res - && !matches!(kind, DefKind::TyAlias) + && matches!(kind, DefKind::Enum | DefKind::Struct | DefKind::Union) { let check_params = def_id.as_local().map_or(true, |def_id| { if def_id == needle { diff --git a/tests/crashes/128327.rs b/tests/crashes/128327.rs deleted file mode 100644 index a63f758c317..00000000000 --- a/tests/crashes/128327.rs +++ /dev/null @@ -1,5 +0,0 @@ -//@ known-bug: rust-lang/rust#128327 - -use std::ops::Deref; -struct Apple((Apple, <&'static [f64] as Deref>::Target(Banana ? Citron))); -fn main(){} diff --git a/tests/ui/infinite/auxiliary/alias.rs b/tests/ui/infinite/auxiliary/alias.rs index 59add7eb18b..5ae124e8aba 100644 --- a/tests/ui/infinite/auxiliary/alias.rs +++ b/tests/ui/infinite/auxiliary/alias.rs @@ -1,2 +1,5 @@ pub struct W(T); pub type Wrapper = W; +pub trait Trait { + type T; +} diff --git a/tests/ui/infinite/infinite-assoc.rs b/tests/ui/infinite/infinite-assoc.rs new file mode 100644 index 00000000000..d128a7e0d2d --- /dev/null +++ b/tests/ui/infinite/infinite-assoc.rs @@ -0,0 +1,16 @@ +//@ aux-build: alias.rs + +// issue#128327 + +extern crate alias; + +use alias::Trait; +struct S; +impl Trait for S { + type T = (); +} +struct A((A, ::T)); +//~^ ERROR: invalid `?` in type +//~| ERROR: recursive type `A` has infinite size + +fn main() {} diff --git a/tests/ui/infinite/infinite-assoc.stderr b/tests/ui/infinite/infinite-assoc.stderr new file mode 100644 index 00000000000..e6b91f13241 --- /dev/null +++ b/tests/ui/infinite/infinite-assoc.stderr @@ -0,0 +1,25 @@ +error: invalid `?` in type + --> $DIR/infinite-assoc.rs:12:39 + | +LL | struct A((A, ::T)); + | ^ `?` is only allowed on expressions, not types + | +help: if you meant to express that the type might not contain a value, use the `Option` wrapper type + | +LL | struct A((A, ::T>)); + | +++++++ ~ + +error[E0072]: recursive type `A` has infinite size + --> $DIR/infinite-assoc.rs:12:1 + | +LL | struct A((A, ::T)); + | ^^^^^^^^ - recursive without indirection + | +help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle + | +LL | struct A((Box, ::T)); + | ++++ + + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0072`. From aa3251dd3b3d4550bdfd740ba8b4855a6c83d3be 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: Wed, 2 Oct 2024 18:51:14 +0800 Subject: [PATCH 494/683] Replace zero-width whitespace with a visible `\` People tried to copy the `r?` which had an invisible zero-width whitespace, causing rustbot to not recognize the instruction, and which makes it difficult to figure out why it didn't work. --- .github/pull_request_template.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index fd54a153a16..ecf8f993f90 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -7,6 +7,6 @@ tracking issue or there are none, feel free to ignore this. This PR will get automatically assigned to a reviewer. In case you would like a specific user to review your work, you can assign it to them by using - r​? + r\? (with the `\` removed) --> From 7f6150b5777a25ef8975a11266b0205d6ba8ab71 Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Wed, 2 Oct 2024 19:42:06 +0800 Subject: [PATCH 495/683] Improve const traits diagnostics for new desugaring --- compiler/rustc_middle/src/macros.rs | 2 +- compiler/rustc_middle/src/ty/print/pretty.rs | 46 +++++++--- .../traits/fulfillment_errors.rs | 86 +++++++++++++++---- compiler/rustc_type_ir/src/predicate.rs | 7 ++ .../assoc-type-const-bound-usage-0.stderr | 16 +++- .../assoc-type-const-bound-usage-1.stderr | 16 +++- .../call-const-trait-method-fail.rs | 6 +- .../call-const-trait-method-fail.stderr | 29 ++----- .../call-generic-method-nonconst.rs | 7 +- .../call-generic-method-nonconst.stderr | 29 ++----- .../const-default-method-bodies.rs | 6 +- .../const-default-method-bodies.stderr | 29 ++----- .../const-fns-are-early-bound.stderr | 4 +- .../cross-crate.gatednc.stderr | 8 +- ...ault-method-body-is-const-same-trait-ck.rs | 6 +- ...-method-body-is-const-same-trait-ck.stderr | 29 ++----- .../super-traits-fail-2.rs | 3 +- .../super-traits-fail-2.yn.stderr | 10 +-- .../super-traits-fail-2.yy.stderr | 10 +-- .../super-traits-fail-3.rs | 2 +- .../super-traits-fail-3.yn.stderr | 10 +-- .../trait-where-clause-const.stderr | 16 +--- .../unsatisfied-const-trait-bound.rs | 1 - .../unsatisfied-const-trait-bound.stderr | 14 +-- 24 files changed, 224 insertions(+), 168 deletions(-) diff --git a/compiler/rustc_middle/src/macros.rs b/compiler/rustc_middle/src/macros.rs index d385be007d3..39816c17b98 100644 --- a/compiler/rustc_middle/src/macros.rs +++ b/compiler/rustc_middle/src/macros.rs @@ -67,7 +67,7 @@ macro_rules! TrivialLiftImpls { }; } -/// Used for types that are `Copy` and which **do not care arena +/// Used for types that are `Copy` and which **do not care about arena /// allocated data** (i.e., don't need to be folded). #[macro_export] macro_rules! TrivialTypeTraversalImpls { diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 8fd4c30457f..7ada5fd93ba 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -1951,19 +1951,18 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { fn pretty_print_bound_constness( &mut self, - trait_ref: ty::TraitRef<'tcx>, + constness: ty::BoundConstness, ) -> Result<(), PrintError> { define_scoped_cx!(self); - let Some(idx) = self.tcx().generics_of(trait_ref.def_id).host_effect_index else { - return Ok(()); - }; - let arg = trait_ref.args.const_at(idx); - - if arg == self.tcx().consts.false_ { - p!("const "); - } else if arg != self.tcx().consts.true_ && !arg.has_infer() { - p!("~const "); + match constness { + ty::BoundConstness::NotConst => {} + ty::BoundConstness::Const => { + p!("const "); + } + ty::BoundConstness::ConstIfConst => { + p!("~const "); + } } Ok(()) } @@ -2948,6 +2947,15 @@ impl<'tcx> ty::TraitPredicate<'tcx> { } } +#[derive(Copy, Clone, TypeFoldable, TypeVisitable, Lift)] +pub struct TraitPredPrintWithBoundConstness<'tcx>(ty::TraitPredicate<'tcx>, ty::BoundConstness); + +impl<'tcx> fmt::Debug for TraitPredPrintWithBoundConstness<'tcx> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Display::fmt(self, f) + } +} + #[extension(pub trait PrintPolyTraitPredicateExt<'tcx>)] impl<'tcx> ty::PolyTraitPredicate<'tcx> { fn print_modifiers_and_trait_path( @@ -2955,6 +2963,13 @@ impl<'tcx> ty::PolyTraitPredicate<'tcx> { ) -> ty::Binder<'tcx, TraitPredPrintModifiersAndPath<'tcx>> { self.map_bound(TraitPredPrintModifiersAndPath) } + + fn print_with_bound_constness( + self, + constness: ty::BoundConstness, + ) -> ty::Binder<'tcx, TraitPredPrintWithBoundConstness<'tcx>> { + self.map_bound(|trait_pred| TraitPredPrintWithBoundConstness(trait_pred, constness)) + } } #[derive(Debug, Copy, Clone, Lift)] @@ -3052,7 +3067,6 @@ define_print! { ty::TraitPredicate<'tcx> { p!(print(self.trait_ref.self_ty()), ": "); - p!(pretty_print_bound_constness(self.trait_ref)); if let ty::PredicatePolarity::Negative = self.polarity { p!("!"); } @@ -3184,13 +3198,21 @@ define_print_and_forward_display! { } TraitPredPrintModifiersAndPath<'tcx> { - p!(pretty_print_bound_constness(self.0.trait_ref)); if let ty::PredicatePolarity::Negative = self.0.polarity { p!("!") } p!(print(self.0.trait_ref.print_trait_sugared())); } + TraitPredPrintWithBoundConstness<'tcx> { + p!(print(self.0.trait_ref.self_ty()), ": "); + p!(pretty_print_bound_constness(self.1)); + if let ty::PredicatePolarity::Negative = self.0.polarity { + p!("!"); + } + p!(print(self.0.trait_ref.print_trait_sugared())) + } + PrintClosureAsImpl<'tcx> { p!(pretty_closure_as_impl(self.closure)) } 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 34a0f182ab4..5af117a3f48 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 @@ -19,8 +19,8 @@ use rustc_middle::ty::abstract_const::NotConstEvaluatable; use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::fold::{TypeFolder, TypeSuperFoldable}; use rustc_middle::ty::print::{ - FmtPrinter, Print, PrintTraitPredicateExt as _, PrintTraitRefExt as _, - with_forced_trimmed_paths, + FmtPrinter, Print, PrintPolyTraitPredicateExt, PrintTraitPredicateExt as _, + PrintTraitRefExt as _, with_forced_trimmed_paths, }; use rustc_middle::ty::{ self, ToPolyTraitRef, TraitRef, Ty, TyCtxt, TypeFoldable, TypeVisitableExt, Upcast, @@ -154,6 +154,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } else { (leaf_trait_predicate, &obligation) }; + + let (main_trait_predicate, leaf_trait_predicate, predicate_constness) = self.get_effects_trait_pred_override(main_trait_predicate, leaf_trait_predicate, span); + let main_trait_ref = main_trait_predicate.to_poly_trait_ref(); let leaf_trait_ref = leaf_trait_predicate.to_poly_trait_ref(); @@ -164,9 +167,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { return guar; } - // FIXME(effects) - let predicate_is_const = false; - if let Err(guar) = leaf_trait_predicate.error_reported() { return guar; @@ -227,7 +227,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { let err_msg = self.get_standard_error_message( main_trait_predicate, message, - predicate_is_const, + predicate_constness, append_const_msg, post_message, ); @@ -286,7 +286,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } if tcx.is_lang_item(leaf_trait_ref.def_id(), LangItem::Drop) - && predicate_is_const + && matches!(predicate_constness, ty::BoundConstness::ConstIfConst | ty::BoundConstness::Const) { err.note("`~const Drop` was renamed to `~const Destruct`"); err.note("See for more details"); @@ -2187,29 +2187,34 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { &self, trait_predicate: ty::PolyTraitPredicate<'tcx>, message: Option, - predicate_is_const: bool, + predicate_constness: ty::BoundConstness, append_const_msg: Option, post_message: String, ) -> String { message .and_then(|cannot_do_this| { - match (predicate_is_const, append_const_msg) { + match (predicate_constness, append_const_msg) { // do nothing if predicate is not const - (false, _) => Some(cannot_do_this), + (ty::BoundConstness::NotConst, _) => Some(cannot_do_this), // suggested using default post message - (true, Some(AppendConstMessage::Default)) => { - Some(format!("{cannot_do_this} in const contexts")) - } + ( + ty::BoundConstness::Const | ty::BoundConstness::ConstIfConst, + Some(AppendConstMessage::Default), + ) => Some(format!("{cannot_do_this} in const contexts")), // overridden post message - (true, Some(AppendConstMessage::Custom(custom_msg, _))) => { - Some(format!("{cannot_do_this}{custom_msg}")) - } + ( + ty::BoundConstness::Const | ty::BoundConstness::ConstIfConst, + Some(AppendConstMessage::Custom(custom_msg, _)), + ) => Some(format!("{cannot_do_this}{custom_msg}")), // fallback to generic message - (true, None) => None, + (ty::BoundConstness::Const | ty::BoundConstness::ConstIfConst, None) => None, } }) .unwrap_or_else(|| { - format!("the trait bound `{trait_predicate}` is not satisfied{post_message}") + format!( + "the trait bound `{}` is not satisfied{post_message}", + trait_predicate.print_with_bound_constness(predicate_constness) + ) }) } @@ -2333,6 +2338,51 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } } + /// For effects predicates such as `::Effects: Compat`, pretend that the + /// predicate that failed was `u32: Add`. Return the constness of such predicate to later + /// print as `u32: ~const Add`. + fn get_effects_trait_pred_override( + &self, + p: ty::PolyTraitPredicate<'tcx>, + leaf: ty::PolyTraitPredicate<'tcx>, + span: Span, + ) -> (ty::PolyTraitPredicate<'tcx>, ty::PolyTraitPredicate<'tcx>, ty::BoundConstness) { + let trait_ref = p.to_poly_trait_ref(); + if !self.tcx.is_lang_item(trait_ref.def_id(), LangItem::EffectsCompat) { + return (p, leaf, ty::BoundConstness::NotConst); + } + + let Some(ty::Alias(ty::AliasTyKind::Projection, projection)) = + trait_ref.self_ty().no_bound_vars().map(Ty::kind) + else { + return (p, leaf, ty::BoundConstness::NotConst); + }; + + let constness = trait_ref.skip_binder().args.const_at(1); + + let constness = if constness == self.tcx.consts.true_ || constness.is_ct_infer() { + ty::BoundConstness::NotConst + } else if constness == self.tcx.consts.false_ { + ty::BoundConstness::Const + } else if matches!(constness.kind(), ty::ConstKind::Param(_)) { + ty::BoundConstness::ConstIfConst + } else { + self.dcx().span_bug(span, format!("Unknown constness argument: {constness:?}")); + }; + + let new_pred = p.map_bound(|mut trait_pred| { + trait_pred.trait_ref = projection.trait_ref(self.tcx); + trait_pred + }); + + let new_leaf = leaf.map_bound(|mut trait_pred| { + trait_pred.trait_ref = projection.trait_ref(self.tcx); + trait_pred + }); + + (new_pred, new_leaf, constness) + } + fn add_tuple_trait_message( &self, obligation_cause_code: &ObligationCauseCode<'tcx>, diff --git a/compiler/rustc_type_ir/src/predicate.rs b/compiler/rustc_type_ir/src/predicate.rs index 76065c10d19..8146181df6c 100644 --- a/compiler/rustc_type_ir/src/predicate.rs +++ b/compiler/rustc_type_ir/src/predicate.rs @@ -755,3 +755,10 @@ impl fmt::Display for BoundConstness { } } } + +impl Lift for BoundConstness { + type Lifted = BoundConstness; + fn lift_to_interner(self, _: I) -> Option { + Some(self) + } +} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type-const-bound-usage-0.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type-const-bound-usage-0.stderr index fb491453b37..8288c660ce7 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type-const-bound-usage-0.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type-const-bound-usage-0.stderr @@ -3,11 +3,11 @@ error: using `#![feature(effects)]` without enabling next trait solver globally = note: the next trait solver must be enabled globally for the effects feature to work correctly = help: use `-Znext-solver` to enable -error[E0277]: the trait bound `Trait::{synthetic#0}: Compat` is not satisfied +error[E0277]: the trait bound `::Assoc: Trait` is not satisfied --> $DIR/assoc-type-const-bound-usage-0.rs:13:5 | LL | T::Assoc::func() - | ^^^^^^^^ the trait `Compat` is not implemented for `Trait::{synthetic#0}` + | ^^^^^^^^ the trait `Trait` is not implemented for `::Assoc` | note: required by a bound in `Trait::func` --> $DIR/assoc-type-const-bound-usage-0.rs:6:1 @@ -17,12 +17,16 @@ LL | #[const_trait] ... LL | fn func() -> i32; | ---- required by a bound in this associated function +help: consider further restricting the associated type + | +LL | const fn unqualified() -> i32 where ::Assoc: Trait { + | ++++++++++++++++++++++++++++++++ -error[E0277]: the trait bound `Trait::{synthetic#0}: Compat` is not satisfied +error[E0277]: the trait bound `::Assoc: Trait` is not satisfied --> $DIR/assoc-type-const-bound-usage-0.rs:17:5 | LL | ::Assoc::func() - | ^^^^^^^^^^^^^^^^^^^ the trait `Compat` is not implemented for `Trait::{synthetic#0}` + | ^^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `::Assoc` | note: required by a bound in `Trait::func` --> $DIR/assoc-type-const-bound-usage-0.rs:6:1 @@ -32,6 +36,10 @@ LL | #[const_trait] ... LL | fn func() -> i32; | ---- required by a bound in this associated function +help: consider further restricting the associated type + | +LL | const fn qualified() -> i32 where ::Assoc: Trait { + | ++++++++++++++++++++++++++++++++ error: aborting due to 3 previous errors diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type-const-bound-usage-1.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type-const-bound-usage-1.stderr index 392b310a4c9..0792d090321 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type-const-bound-usage-1.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type-const-bound-usage-1.stderr @@ -3,11 +3,11 @@ error: using `#![feature(effects)]` without enabling next trait solver globally = note: the next trait solver must be enabled globally for the effects feature to work correctly = help: use `-Znext-solver` to enable -error[E0277]: the trait bound `Trait::{synthetic#0}: Compat` is not satisfied +error[E0277]: the trait bound `::Assoc: Trait` is not satisfied --> $DIR/assoc-type-const-bound-usage-1.rs:15:44 | LL | fn unqualified() -> Type<{ T::Assoc::func() }> { - | ^^^^^^^^ the trait `Compat` is not implemented for `Trait::{synthetic#0}` + | ^^^^^^^^ the trait `Trait` is not implemented for `::Assoc` | note: required by a bound in `Trait::func` --> $DIR/assoc-type-const-bound-usage-1.rs:7:1 @@ -17,12 +17,16 @@ LL | #[const_trait] ... LL | fn func() -> i32; | ---- required by a bound in this associated function +help: consider further restricting the associated type + | +LL | fn unqualified() -> Type<{ T::Assoc::func() }> where ::Assoc: Trait { + | ++++++++++++++++++++++++++++++++ -error[E0277]: the trait bound `Trait::{synthetic#0}: Compat` is not satisfied +error[E0277]: the trait bound `::Assoc: Trait` is not satisfied --> $DIR/assoc-type-const-bound-usage-1.rs:19:42 | LL | fn qualified() -> Type<{ ::Assoc::func() }> { - | ^^^^^^^^^^^^^^^^^^^ the trait `Compat` is not implemented for `Trait::{synthetic#0}` + | ^^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `::Assoc` | note: required by a bound in `Trait::func` --> $DIR/assoc-type-const-bound-usage-1.rs:7:1 @@ -32,6 +36,10 @@ LL | #[const_trait] ... LL | fn func() -> i32; | ---- required by a bound in this associated function +help: consider further restricting the associated type + | +LL | fn qualified() -> Type<{ ::Assoc::func() }> where ::Assoc: Trait { + | ++++++++++++++++++++++++++++++++ error: aborting due to 3 previous errors diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-const-trait-method-fail.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/call-const-trait-method-fail.rs index bb9e9045f8f..878f9a713a0 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-const-trait-method-fail.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/call-const-trait-method-fail.rs @@ -1,4 +1,6 @@ -#![feature(const_trait_impl, effects)] //~ WARN the feature `effects` is incomplete +//@ compile-flags: -Znext-solver +#![allow(incomplete_features)] +#![feature(const_trait_impl, effects)] #[const_trait] pub trait Plus { @@ -23,7 +25,7 @@ pub const fn add_i32(a: i32, b: i32) -> i32 { pub const fn add_u32(a: u32, b: u32) -> u32 { a.plus(b) - //~^ ERROR the trait bound + //~^ ERROR the trait bound `u32: ~const Plus` } fn main() {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-const-trait-method-fail.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/call-const-trait-method-fail.stderr index 73ea1422bf9..5d2333d94fe 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-const-trait-method-fail.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/call-const-trait-method-fail.stderr @@ -1,33 +1,22 @@ -warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/call-const-trait-method-fail.rs:1:30 - | -LL | #![feature(const_trait_impl, effects)] - | ^^^^^^^ - | - = note: see issue #102090 for more information - = note: `#[warn(incomplete_features)]` on by default - -error: using `#![feature(effects)]` without enabling next trait solver globally - | - = note: the next trait solver must be enabled globally for the effects feature to work correctly - = help: use `-Znext-solver` to enable - -error[E0277]: the trait bound `Runtime: ~const Compat` is not satisfied - --> $DIR/call-const-trait-method-fail.rs:25:5 +error[E0277]: the trait bound `u32: ~const Plus` is not satisfied + --> $DIR/call-const-trait-method-fail.rs:27:5 | LL | a.plus(b) - | ^ the trait `~const Compat` is not implemented for `Runtime` + | ^ the trait `Plus` is not implemented for `u32` | - = help: the trait `Compat` is implemented for `Runtime` note: required by a bound in `Plus::plus` - --> $DIR/call-const-trait-method-fail.rs:3:1 + --> $DIR/call-const-trait-method-fail.rs:5:1 | LL | #[const_trait] | ^^^^^^^^^^^^^^ required by this bound in `Plus::plus` LL | pub trait Plus { LL | fn plus(self, rhs: Self) -> Self; | ---- required by a bound in this associated function +help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement + | +LL | pub const fn add_u32(a: u32, b: u32) -> u32 where u32: Plus { + | +++++++++++++++ -error: aborting due to 2 previous errors; 1 warning emitted +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-nonconst.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-nonconst.rs index 74e33ca72ff..f9e79d41752 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-nonconst.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-nonconst.rs @@ -1,4 +1,6 @@ -#![feature(const_trait_impl, effects)] //~ WARN the feature `effects` is incomplete +//@ compile-flags: -Znext-solver +#![allow(incomplete_features)] +#![feature(const_trait_impl, effects)] struct S; @@ -21,7 +23,6 @@ const fn equals_self(t: &T) -> bool { // it not using the impl. pub const EQ: bool = equals_self(&S); -//~^ ERROR: the trait bound `Runtime: const Compat` is not satisfied -// FIXME(effects) diagnostic +//~^ ERROR: the trait bound `S: const Foo` is not satisfied fn main() {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-nonconst.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-nonconst.stderr index b2a98041c1c..68c9fc40010 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-nonconst.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-nonconst.stderr @@ -1,32 +1,21 @@ -warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/call-generic-method-nonconst.rs:1:30 - | -LL | #![feature(const_trait_impl, effects)] - | ^^^^^^^ - | - = note: see issue #102090 for more information - = note: `#[warn(incomplete_features)]` on by default - -error: using `#![feature(effects)]` without enabling next trait solver globally - | - = note: the next trait solver must be enabled globally for the effects feature to work correctly - = help: use `-Znext-solver` to enable - -error[E0277]: the trait bound `Runtime: const Compat` is not satisfied - --> $DIR/call-generic-method-nonconst.rs:23:34 +error[E0277]: the trait bound `S: const Foo` is not satisfied + --> $DIR/call-generic-method-nonconst.rs:25:34 | LL | pub const EQ: bool = equals_self(&S); - | ----------- ^^ the trait `const Compat` is not implemented for `Runtime` + | ----------- ^^ the trait `Foo` is not implemented for `S` | | | required by a bound introduced by this call | - = help: the trait `Compat` is implemented for `Runtime` note: required by a bound in `equals_self` - --> $DIR/call-generic-method-nonconst.rs:16:25 + --> $DIR/call-generic-method-nonconst.rs:18:25 | LL | const fn equals_self(t: &T) -> bool { | ^^^^^^^^^^ required by this bound in `equals_self` +help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement + | +LL | pub const EQ: bool where S: Foo = equals_self(&S); + | ++++++++++++ -error: aborting due to 2 previous errors; 1 warning emitted +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-default-method-bodies.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-default-method-bodies.rs index 2fd58b05178..a0333153f85 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-default-method-bodies.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-default-method-bodies.rs @@ -1,4 +1,6 @@ -#![feature(const_trait_impl, effects)] //~ WARN the feature `effects` is incomplete +//@ compile-flags: -Znext-solver +#![allow(incomplete_features)] +#![feature(const_trait_impl, effects)] #[const_trait] trait ConstDefaultFn: Sized { @@ -22,7 +24,7 @@ impl const ConstDefaultFn for ConstImpl { const fn test() { NonConstImpl.a(); - //~^ ERROR the trait bound + //~^ ERROR the trait bound `NonConstImpl: ~const ConstDefaultFn` is not satisfied ConstImpl.a(); } diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-default-method-bodies.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-default-method-bodies.stderr index 02f9dffba32..0809d9c1e1d 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-default-method-bodies.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-default-method-bodies.stderr @@ -1,33 +1,22 @@ -warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/const-default-method-bodies.rs:1:30 - | -LL | #![feature(const_trait_impl, effects)] - | ^^^^^^^ - | - = note: see issue #102090 for more information - = note: `#[warn(incomplete_features)]` on by default - -error: using `#![feature(effects)]` without enabling next trait solver globally - | - = note: the next trait solver must be enabled globally for the effects feature to work correctly - = help: use `-Znext-solver` to enable - -error[E0277]: the trait bound `Runtime: ~const Compat` is not satisfied - --> $DIR/const-default-method-bodies.rs:24:18 +error[E0277]: the trait bound `NonConstImpl: ~const ConstDefaultFn` is not satisfied + --> $DIR/const-default-method-bodies.rs:26:18 | LL | NonConstImpl.a(); - | ^ the trait `~const Compat` is not implemented for `Runtime` + | ^ the trait `ConstDefaultFn` is not implemented for `NonConstImpl` | - = help: the trait `Compat` is implemented for `Runtime` note: required by a bound in `ConstDefaultFn::a` - --> $DIR/const-default-method-bodies.rs:3:1 + --> $DIR/const-default-method-bodies.rs:5:1 | LL | #[const_trait] | ^^^^^^^^^^^^^^ required by this bound in `ConstDefaultFn::a` ... LL | fn a(self) { | - required by a bound in this associated function +help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement + | +LL | const fn test() where NonConstImpl: ConstDefaultFn { + | ++++++++++++++++++++++++++++++++++ -error: aborting due to 2 previous errors; 1 warning emitted +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-fns-are-early-bound.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-fns-are-early-bound.stderr index 7aa3aa8c6bb..9eda9d98ec5 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-fns-are-early-bound.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-fns-are-early-bound.stderr @@ -1,8 +1,8 @@ -error[E0277]: the trait bound `FnOnce<()>::{synthetic#0}: const Compat` is not satisfied +error[E0277]: the trait bound `fn() {foo}: const FnOnce()` is not satisfied --> $DIR/const-fns-are-early-bound.rs:31:17 | LL | is_const_fn(foo); - | ----------- ^^^ the trait `const Compat` is not implemented for `FnOnce<()>::{synthetic#0}` + | ----------- ^^^ the trait `FnOnce()` is not implemented for fn item `fn() {foo}` | | | required by a bound introduced by this call | diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/cross-crate.gatednc.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/cross-crate.gatednc.stderr index b7209827c22..a34bae843c8 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/cross-crate.gatednc.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/cross-crate.gatednc.stderr @@ -1,8 +1,8 @@ -error[E0277]: the trait bound `cross_crate::MyTrait::{synthetic#0}: ~const Compat` is not satisfied +error[E0277]: the trait bound `cross_crate::NonConst: ~const cross_crate::MyTrait` is not satisfied --> $DIR/cross-crate.rs:19:14 | LL | NonConst.func(); - | ^^^^ the trait `~const Compat` is not implemented for `cross_crate::MyTrait::{synthetic#0}` + | ^^^^ the trait `cross_crate::MyTrait` is not implemented for `cross_crate::NonConst` | note: required by a bound in `func` --> $DIR/auxiliary/cross-crate.rs:5:1 @@ -12,6 +12,10 @@ LL | #[const_trait] ... LL | fn func(self); | ---- required by a bound in this associated function +help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement + | +LL | const fn const_context() where cross_crate::NonConst: cross_crate::MyTrait { + | +++++++++++++++++++++++++++++++++++++++++++++++++ error: aborting due to 1 previous error diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.rs index 64f23824b39..0c2d93775a4 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.rs @@ -1,4 +1,6 @@ -#![feature(const_trait_impl, effects)] //~ WARN the feature `effects` is incomplete +//@ compile-flags: -Znext-solver +#![allow(incomplete_features)] +#![feature(const_trait_impl, effects)] #[const_trait] pub trait Tr { @@ -6,7 +8,7 @@ pub trait Tr { fn b(&self) { ().a() - //~^ ERROR the trait bound + //~^ ERROR the trait bound `(): ~const Tr` is not satisfied } } diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.stderr index 1b5aa9c9191..d0f22c0b9b6 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.stderr @@ -1,33 +1,22 @@ -warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/default-method-body-is-const-same-trait-ck.rs:1:30 - | -LL | #![feature(const_trait_impl, effects)] - | ^^^^^^^ - | - = note: see issue #102090 for more information - = note: `#[warn(incomplete_features)]` on by default - -error: using `#![feature(effects)]` without enabling next trait solver globally - | - = note: the next trait solver must be enabled globally for the effects feature to work correctly - = help: use `-Znext-solver` to enable - -error[E0277]: the trait bound `Runtime: ~const Compat` is not satisfied - --> $DIR/default-method-body-is-const-same-trait-ck.rs:8:12 +error[E0277]: the trait bound `(): ~const Tr` is not satisfied + --> $DIR/default-method-body-is-const-same-trait-ck.rs:10:12 | LL | ().a() - | ^ the trait `~const Compat` is not implemented for `Runtime` + | ^ the trait `Tr` is not implemented for `()` | - = help: the trait `Compat` is implemented for `Runtime` note: required by a bound in `Tr::a` - --> $DIR/default-method-body-is-const-same-trait-ck.rs:3:1 + --> $DIR/default-method-body-is-const-same-trait-ck.rs:5:1 | LL | #[const_trait] | ^^^^^^^^^^^^^^ required by this bound in `Tr::a` LL | pub trait Tr { LL | fn a(&self) {} | - required by a bound in this associated function +help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement + | +LL | pub trait Tr where (): Tr { + | ++++++++++++ -error: aborting due to 2 previous errors; 1 warning emitted +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.rs index 0d659744e70..93a6f385e47 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.rs @@ -17,8 +17,7 @@ trait Bar: ~const Foo {} const fn foo(x: &T) { x.a(); - //[yy,yn]~^ ERROR the trait bound - // FIXME(effects) diagnostic + //[yy,yn]~^ ERROR the trait bound `T: ~const Foo` } fn main() {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.yn.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.yn.stderr index d4064e01ef1..873c57ec71f 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.yn.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.yn.stderr @@ -10,11 +10,11 @@ note: this trait is not a `#[const_trait]`, so it cannot have `~const` trait bou LL | trait Bar: ~const Foo {} | ^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0277]: the trait bound `Foo::{synthetic#0}: ~const Compat` is not satisfied +error[E0277]: the trait bound `T: ~const Foo` is not satisfied --> $DIR/super-traits-fail-2.rs:19:7 | LL | x.a(); - | ^ the trait `~const Compat` is not implemented for `Foo::{synthetic#0}` + | ^ the trait `Foo` is not implemented for `T` | note: required by a bound in `Foo::a` --> $DIR/super-traits-fail-2.rs:6:25 @@ -24,10 +24,10 @@ LL | #[cfg_attr(any(yy, yn), const_trait)] LL | trait Foo { LL | fn a(&self); | - required by a bound in this associated function -help: consider further restricting the associated type +help: consider further restricting this bound | -LL | const fn foo(x: &T) where Foo::{synthetic#0}: ~const Compat { - | +++++++++++++++++++++++++++++++++++++++ +LL | const fn foo(x: &T) { + | +++++ error: aborting due to 2 previous errors diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.yy.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.yy.stderr index 9f9f96c6b48..bea3aea2f3a 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.yy.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.yy.stderr @@ -1,8 +1,8 @@ -error[E0277]: the trait bound `Foo::{synthetic#0}: ~const Compat` is not satisfied +error[E0277]: the trait bound `T: ~const Foo` is not satisfied --> $DIR/super-traits-fail-2.rs:19:7 | LL | x.a(); - | ^ the trait `~const Compat` is not implemented for `Foo::{synthetic#0}` + | ^ the trait `Foo` is not implemented for `T` | note: required by a bound in `Foo::a` --> $DIR/super-traits-fail-2.rs:6:25 @@ -12,10 +12,10 @@ LL | #[cfg_attr(any(yy, yn), const_trait)] LL | trait Foo { LL | fn a(&self); | - required by a bound in this associated function -help: consider further restricting the associated type +help: consider further restricting this bound | -LL | const fn foo(x: &T) where Foo::{synthetic#0}: ~const Compat { - | +++++++++++++++++++++++++++++++++++++++ +LL | const fn foo(x: &T) { + | +++++ error: aborting due to 1 previous error diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.rs index c7e224dcce0..b5643b11700 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.rs @@ -20,7 +20,7 @@ trait Bar: ~const Foo {} const fn foo(x: &T) { //[yn,nn]~^ ERROR: `~const` can only be applied to `#[const_trait]` x.a(); - //[yn]~^ ERROR: the trait bound + //[yn]~^ ERROR: the trait bound `T: ~const Foo` is not satisfied } fn main() {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.yn.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.yn.stderr index 0b48633a10e..bbc95948a59 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.yn.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.yn.stderr @@ -16,11 +16,11 @@ error: `~const` can only be applied to `#[const_trait]` traits LL | const fn foo(x: &T) { | ^^^ -error[E0277]: the trait bound `Foo::{synthetic#0}: ~const Compat` is not satisfied +error[E0277]: the trait bound `T: ~const Foo` is not satisfied --> $DIR/super-traits-fail-3.rs:22:7 | LL | x.a(); - | ^ the trait `~const Compat` is not implemented for `Foo::{synthetic#0}` + | ^ the trait `Foo` is not implemented for `T` | note: required by a bound in `Foo::a` --> $DIR/super-traits-fail-3.rs:8:25 @@ -30,10 +30,10 @@ LL | #[cfg_attr(any(yy, yn), const_trait)] LL | trait Foo { LL | fn a(&self); | - required by a bound in this associated function -help: consider further restricting the associated type +help: consider further restricting this bound | -LL | const fn foo(x: &T) where Foo::{synthetic#0}: ~const Compat { - | +++++++++++++++++++++++++++++++++++++++ +LL | const fn foo(x: &T) { + | +++++ error: aborting due to 3 previous errors diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-where-clause-const.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-where-clause-const.stderr index 979f1e798e0..eaa981ec744 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-where-clause-const.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-where-clause-const.stderr @@ -1,8 +1,8 @@ -error[E0277]: the trait bound `Foo::{synthetic#0}: Compat` is not satisfied +error[E0277]: the trait bound `T: Foo` is not satisfied --> $DIR/trait-where-clause-const.rs:22:5 | LL | T::b(); - | ^ the trait `Compat` is not implemented for `Foo::{synthetic#0}` + | ^ the trait `Foo` is not implemented for `T` | note: required by a bound in `Foo::b` --> $DIR/trait-where-clause-const.rs:13:1 @@ -12,10 +12,6 @@ LL | #[const_trait] ... LL | fn b() where Self: ~const Bar; | - required by a bound in this associated function -help: consider further restricting the associated type - | -LL | const fn test1() where Foo::{synthetic#0}: Compat { - | ++++++++++++++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/trait-where-clause-const.rs:22:5 @@ -26,11 +22,11 @@ LL | T::b(); = note: expected constant `host` found constant `true` -error[E0277]: the trait bound `Foo::{synthetic#0}: Compat` is not satisfied +error[E0277]: the trait bound `T: Foo` is not satisfied --> $DIR/trait-where-clause-const.rs:25:5 | LL | T::c::(); - | ^ the trait `Compat` is not implemented for `Foo::{synthetic#0}` + | ^ the trait `Foo` is not implemented for `T` | note: required by a bound in `Foo::c` --> $DIR/trait-where-clause-const.rs:13:1 @@ -40,10 +36,6 @@ LL | #[const_trait] ... LL | fn c(); | - required by a bound in this associated function -help: consider further restricting the associated type - | -LL | const fn test1() where Foo::{synthetic#0}: Compat { - | ++++++++++++++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/trait-where-clause-const.rs:25:5 diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/unsatisfied-const-trait-bound.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/unsatisfied-const-trait-bound.rs index 5fffe54fc1a..d336719f52e 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/unsatisfied-const-trait-bound.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/unsatisfied-const-trait-bound.rs @@ -19,7 +19,6 @@ impl Trait for Ty { } fn main() { - // FIXME(effects): improve diagnostics on this require::(); } diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/unsatisfied-const-trait-bound.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/unsatisfied-const-trait-bound.stderr index 0806ffa4b5d..848aa68689b 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/unsatisfied-const-trait-bound.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/unsatisfied-const-trait-bound.stderr @@ -7,7 +7,7 @@ LL | #![feature(const_trait_impl, effects, generic_const_exprs)] = help: remove one of these features error[E0308]: mismatched types - --> $DIR/unsatisfied-const-trait-bound.rs:30:37 + --> $DIR/unsatisfied-const-trait-bound.rs:29:37 | LL | fn accept0(_: Container<{ T::make() }>) {} | ^^^^^^^^^ expected `false`, found `true` @@ -16,7 +16,7 @@ LL | fn accept0(_: Container<{ T::make() }>) {} found constant `true` error[E0308]: mismatched types - --> $DIR/unsatisfied-const-trait-bound.rs:34:50 + --> $DIR/unsatisfied-const-trait-bound.rs:33:50 | LL | const fn accept1(_: Container<{ T::make() }>) {} | ^^^^^^^^^ expected `false`, found `host` @@ -24,17 +24,21 @@ LL | const fn accept1(_: Container<{ T::make() }>) {} = note: expected constant `false` found constant `host` -error[E0277]: the trait bound `Trait::{synthetic#0}: const Compat` is not satisfied - --> $DIR/unsatisfied-const-trait-bound.rs:23:15 +error[E0277]: the trait bound `Ty: const Trait` is not satisfied + --> $DIR/unsatisfied-const-trait-bound.rs:22:15 | LL | require::(); - | ^^ the trait `const Compat` is not implemented for `Trait::{synthetic#0}` + | ^^ the trait `Trait` is not implemented for `Ty` | note: required by a bound in `require` --> $DIR/unsatisfied-const-trait-bound.rs:8:15 | LL | fn require() {} | ^^^^^^^^^^^ required by this bound in `require` +help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement + | +LL | fn main() where Ty: Trait { + | +++++++++++++++ error: aborting due to 4 previous errors From 1a04a317c447210306396e5ad4a100f423b1dfa6 Mon Sep 17 00:00:00 2001 From: lcnr Date: Wed, 2 Oct 2024 14:39:43 +0200 Subject: [PATCH 496/683] review --- .../src/infer/relate/type_relating.rs | 8 +++++--- compiler/rustc_middle/src/ty/fold.rs | 17 +++++++++-------- .../src/canonicalizer.rs | 12 +++++++----- compiler/rustc_next_trait_solver/src/resolve.rs | 2 ++ .../src/solve/eval_ctxt/mod.rs | 15 ++++++++------- 5 files changed, 31 insertions(+), 23 deletions(-) diff --git a/compiler/rustc_infer/src/infer/relate/type_relating.rs b/compiler/rustc_infer/src/infer/relate/type_relating.rs index c8ced4a2cda..7acfea643dd 100644 --- a/compiler/rustc_infer/src/infer/relate/type_relating.rs +++ b/compiler/rustc_infer/src/infer/relate/type_relating.rs @@ -14,14 +14,16 @@ use crate::infer::{DefineOpaqueTypes, InferCtxt, SubregionOrigin}; /// Enforce that `a` is equal to or a subtype of `b`. pub struct TypeRelating<'combine, 'a, 'tcx> { - // Partially mutable. + // Immutable except for the `InferCtxt` and the + // resulting nested `goals`. fields: &'combine mut CombineFields<'a, 'tcx>, - // Immutable fields. + // Immutable field. structurally_relate_aliases: StructurallyRelateAliases, + // Mutable field. ambient_variance: ty::Variance, - /// The cache has only tracks the `ambient_variance` as its the + /// The cache only tracks the `ambient_variance` as it's the /// only field which is mutable and which meaningfully changes /// the result when relating types. /// diff --git a/compiler/rustc_middle/src/ty/fold.rs b/compiler/rustc_middle/src/ty/fold.rs index e152d3f5fbe..b5a77b3c942 100644 --- a/compiler/rustc_middle/src/ty/fold.rs +++ b/compiler/rustc_middle/src/ty/fold.rs @@ -210,16 +210,17 @@ where debug_assert!(!ty.has_vars_bound_above(ty::INNERMOST)); ty::fold::shift_vars(self.tcx, ty, self.current_index.as_u32()) } - _ if t.has_vars_bound_at_or_above(self.current_index) => { - if let Some(&ty) = self.cache.get(&(self.current_index, t)) { - return ty; + _ => { + if !t.has_vars_bound_at_or_above(self.current_index) { + t + } else if let Some(&t) = self.cache.get(&(self.current_index, t)) { + t + } else { + let res = t.super_fold_with(self); + assert!(self.cache.insert((self.current_index, t), res)); + res } - - let res = t.super_fold_with(self); - assert!(self.cache.insert((self.current_index, t), res)); - res } - _ => t, } } diff --git a/compiler/rustc_next_trait_solver/src/canonicalizer.rs b/compiler/rustc_next_trait_solver/src/canonicalizer.rs index 5c3c35b7b3e..0bf9d7b9249 100644 --- a/compiler/rustc_next_trait_solver/src/canonicalizer.rs +++ b/compiler/rustc_next_trait_solver/src/canonicalizer.rs @@ -42,17 +42,19 @@ pub enum CanonicalizeMode { pub struct Canonicalizer<'a, D: SolverDelegate, I: Interner> { delegate: &'a D, + + // Immutable field. canonicalize_mode: CanonicalizeMode, + // Mutable fields. variables: &'a mut Vec, - variable_lookup_table: HashMap, - primitive_var_infos: Vec>, + variable_lookup_table: HashMap, binder_index: ty::DebruijnIndex, - /// We only use the debruijn index during lookup as all other fields - /// should not be impacted by whether a type is folded once or multiple - /// times. + /// We only use the debruijn index during lookup. We don't need to + /// track the `variables` as each generic arg only results in a single + /// bound variable regardless of how many times it is encountered. cache: HashMap<(ty::DebruijnIndex, I::Ty), I::Ty>, } diff --git a/compiler/rustc_next_trait_solver/src/resolve.rs b/compiler/rustc_next_trait_solver/src/resolve.rs index a37066cec66..f2654f7534e 100644 --- a/compiler/rustc_next_trait_solver/src/resolve.rs +++ b/compiler/rustc_next_trait_solver/src/resolve.rs @@ -16,6 +16,8 @@ where I: Interner, { delegate: &'a D, + /// We're able to use a cache here as the folder does not have any + /// mutable state. cache: DelayedMap, } diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs index 12b4b3cb3a9..baa00465c0c 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs @@ -1057,16 +1057,17 @@ where ); infer_ty } - _ if ty.has_aliases() => { - if let Some(&entry) = self.cache.get(&ty) { + _ => { + if !ty.has_aliases() { + ty + } else if let Some(&entry) = self.cache.get(&ty) { return entry; + } else { + let res = ty.super_fold_with(self); + assert!(self.cache.insert(ty, res).is_none()); + res } - - let res = ty.super_fold_with(self); - assert!(self.cache.insert(ty, res).is_none()); - res } - _ => ty, } } From d868fdce6b9ddef6abcc8de86b3ba8459def36a2 Mon Sep 17 00:00:00 2001 From: joboet Date: Thu, 18 Jul 2024 13:59:48 +0200 Subject: [PATCH 497/683] std: make `thread::current` available in all `thread_local!` destructors --- library/std/src/rt.rs | 34 ++- library/std/src/sys/pal/hermit/mod.rs | 6 +- library/std/src/sys/pal/hermit/thread.rs | 1 + library/std/src/sys/sync/rwlock/queue.rs | 6 +- .../std/src/sys/thread_local/guard/apple.rs | 1 + library/std/src/sys/thread_local/guard/key.rs | 39 ++- .../std/src/sys/thread_local/guard/solid.rs | 5 +- .../std/src/sys/thread_local/guard/windows.rs | 8 +- library/std/src/sys/thread_local/key/xous.rs | 2 + library/std/src/sys/thread_local/mod.rs | 48 ++-- .../std/src/sys/thread_local/native/mod.rs | 31 +++ library/std/src/sys/thread_local/os.rs | 34 ++- library/std/src/sys/thread_local/statik.rs | 33 ++- library/std/src/thread/current.rs | 252 ++++++++++++++++++ library/std/src/thread/local/tests.rs | 33 ++- library/std/src/thread/mod.rs | 128 +++------ 16 files changed, 529 insertions(+), 132 deletions(-) create mode 100644 library/std/src/thread/current.rs diff --git a/library/std/src/rt.rs b/library/std/src/rt.rs index b6f36931ec2..0a841f07e3b 100644 --- a/library/std/src/rt.rs +++ b/library/std/src/rt.rs @@ -21,9 +21,10 @@ pub use crate::panicking::{begin_panic, panic_count}; pub use core::panicking::{panic_display, panic_fmt}; #[rustfmt::skip] +use crate::any::Any; use crate::sync::Once; -use crate::sys; use crate::thread::{self, Thread}; +use crate::{mem, panic, sys}; // Prints to the "panic output", depending on the platform this may be: // - the standard error output @@ -66,6 +67,11 @@ macro_rules! rtunwrap { }; } +fn handle_rt_panic(e: Box) { + mem::forget(e); + rtabort!("initialization or cleanup bug"); +} + // One-time runtime initialization. // Runs before `main`. // SAFETY: must be called only once during runtime initialization. @@ -101,6 +107,20 @@ unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) { thread::set_current(thread); } +/// Clean up the thread-local runtime state. This *should* be run after all other +/// code managed by the Rust runtime, but will not cause UB if that condition is +/// not fulfilled. Also note that this function is not guaranteed to be run, but +/// skipping it will cause leaks and therefore is to be avoided. +pub(crate) fn thread_cleanup() { + // This function is run in situations where unwinding leads to an abort + // (think `extern "C"` functions). Abort here instead so that we can + // print a nice message. + panic::catch_unwind(|| { + crate::thread::drop_current(); + }) + .unwrap_or_else(handle_rt_panic); +} + // One-time runtime cleanup. // Runs after `main` or at program exit. // NOTE: this is not guaranteed to run, for example when the program aborts. @@ -123,11 +143,6 @@ fn lang_start_internal( argv: *const *const u8, sigpipe: u8, ) -> Result { - use crate::{mem, panic}; - let rt_abort = move |e| { - mem::forget(e); - rtabort!("initialization or cleanup bug"); - }; // Guard against the code called by this function from unwinding outside of the Rust-controlled // code, which is UB. This is a requirement imposed by a combination of how the // `#[lang="start"]` attribute is implemented as well as by the implementation of the panicking @@ -139,16 +154,17 @@ fn lang_start_internal( // prevent std from accidentally introducing a panic to these functions. Another is from // user code from `main` or, more nefariously, as described in e.g. issue #86030. // SAFETY: Only called once during runtime initialization. - panic::catch_unwind(move || unsafe { init(argc, argv, sigpipe) }).map_err(rt_abort)?; + panic::catch_unwind(move || unsafe { init(argc, argv, sigpipe) }) + .unwrap_or_else(handle_rt_panic); let ret_code = panic::catch_unwind(move || panic::catch_unwind(main).unwrap_or(101) as isize) .map_err(move |e| { mem::forget(e); rtabort!("drop of the panic payload panicked"); }); - panic::catch_unwind(cleanup).map_err(rt_abort)?; + panic::catch_unwind(cleanup).unwrap_or_else(handle_rt_panic); // Guard against multiple threads calling `libc::exit` concurrently. // See the documentation for `unique_thread_exit` for more information. - panic::catch_unwind(|| crate::sys::exit_guard::unique_thread_exit()).map_err(rt_abort)?; + panic::catch_unwind(crate::sys::exit_guard::unique_thread_exit).unwrap_or_else(handle_rt_panic); ret_code } diff --git a/library/std/src/sys/pal/hermit/mod.rs b/library/std/src/sys/pal/hermit/mod.rs index f49ef947174..b62afb40a61 100644 --- a/library/std/src/sys/pal/hermit/mod.rs +++ b/library/std/src/sys/pal/hermit/mod.rs @@ -92,7 +92,11 @@ pub unsafe extern "C" fn runtime_entry( unsafe { crate::sys::thread_local::destructors::run(); } - unsafe { hermit_abi::exit(result) } + crate::rt::thread_cleanup(); + + unsafe { + hermit_abi::exit(result); + } } #[inline] diff --git a/library/std/src/sys/pal/hermit/thread.rs b/library/std/src/sys/pal/hermit/thread.rs index 4c0c0919f47..41f2c3e2123 100644 --- a/library/std/src/sys/pal/hermit/thread.rs +++ b/library/std/src/sys/pal/hermit/thread.rs @@ -53,6 +53,7 @@ impl Thread { // run all destructors crate::sys::thread_local::destructors::run(); + crate::rt::thread_cleanup(); } } } diff --git a/library/std/src/sys/sync/rwlock/queue.rs b/library/std/src/sys/sync/rwlock/queue.rs index 0e658328c2e..733f51cae8c 100644 --- a/library/std/src/sys/sync/rwlock/queue.rs +++ b/library/std/src/sys/sync/rwlock/queue.rs @@ -113,7 +113,7 @@ use crate::mem; use crate::ptr::{self, NonNull, null_mut, without_provenance_mut}; use crate::sync::atomic::Ordering::{AcqRel, Acquire, Relaxed, Release}; use crate::sync::atomic::{AtomicBool, AtomicPtr}; -use crate::thread::{self, Thread}; +use crate::thread::{self, Thread, ThreadId}; // Locking uses exponential backoff. `SPIN_COUNT` indicates how many times the // locking operation will be retried. @@ -200,7 +200,9 @@ impl Node { fn prepare(&mut self) { // Fall back to creating an unnamed `Thread` handle to allow locking in // TLS destructors. - self.thread.get_or_init(|| thread::try_current().unwrap_or_else(Thread::new_unnamed)); + self.thread.get_or_init(|| { + thread::try_current().unwrap_or_else(|| Thread::new_unnamed(ThreadId::new())) + }); self.completed = AtomicBool::new(false); } diff --git a/library/std/src/sys/thread_local/guard/apple.rs b/library/std/src/sys/thread_local/guard/apple.rs index 6c27f7ae35c..fa25b116622 100644 --- a/library/std/src/sys/thread_local/guard/apple.rs +++ b/library/std/src/sys/thread_local/guard/apple.rs @@ -26,6 +26,7 @@ pub fn enable() { unsafe extern "C" fn run_dtors(_: *mut u8) { unsafe { destructors::run(); + crate::rt::thread_cleanup(); } } } diff --git a/library/std/src/sys/thread_local/guard/key.rs b/library/std/src/sys/thread_local/guard/key.rs index 77575547c14..59581e6f281 100644 --- a/library/std/src/sys/thread_local/guard/key.rs +++ b/library/std/src/sys/thread_local/guard/key.rs @@ -3,10 +3,12 @@ //! that will run all native TLS destructors in the destructor list. use crate::ptr; -use crate::sys::thread_local::destructors; use crate::sys::thread_local::key::{LazyKey, set}; +#[cfg(target_thread_local)] pub fn enable() { + use crate::sys::thread_local::destructors; + static DTORS: LazyKey = LazyKey::new(Some(run)); // Setting the key value to something other than NULL will result in the @@ -18,6 +20,41 @@ pub fn enable() { unsafe extern "C" fn run(_: *mut u8) { unsafe { destructors::run(); + // On platforms with `__cxa_thread_atexit_impl`, `destructors::run` + // does nothing on newer systems as the TLS destructors are + // registered with the system. But because all of those platforms + // call the destructors of TLS keys after the registered ones, this + // function will still be run last (at the time of writing). + crate::rt::thread_cleanup(); + } + } +} + +/// On platforms with key-based TLS, the system runs the destructors for us. +/// We still have to make sure that [`crate::rt::thread_cleanup`] is called, +/// however. This is done by defering the execution of a TLS destructor to +/// the next round of destruction inside the TLS destructors. +#[cfg(not(target_thread_local))] +pub fn enable() { + const DEFER: *mut u8 = ptr::without_provenance_mut(1); + const RUN: *mut u8 = ptr::without_provenance_mut(2); + + static CLEANUP: LazyKey = LazyKey::new(Some(run)); + + unsafe { set(CLEANUP.force(), DEFER) } + + unsafe extern "C" fn run(state: *mut u8) { + if state == DEFER { + // Make sure that this function is run again in the next round of + // TLS destruction. If there is no futher round, there will be leaks, + // but that's okay, `thread_cleanup` is not guaranteed to be called. + unsafe { set(CLEANUP.force(), RUN) } + } else { + debug_assert_eq!(state, RUN); + // If the state is still RUN in the next round of TLS destruction, + // it means that no other TLS destructors defined by this runtime + // have been run, as they would have set the state to DEFER. + crate::rt::thread_cleanup(); } } } diff --git a/library/std/src/sys/thread_local/guard/solid.rs b/library/std/src/sys/thread_local/guard/solid.rs index 054b2d561c8..3bcd46c481d 100644 --- a/library/std/src/sys/thread_local/guard/solid.rs +++ b/library/std/src/sys/thread_local/guard/solid.rs @@ -19,6 +19,9 @@ pub fn enable() { } unsafe extern "C" fn tls_dtor(_unused: *mut u8) { - unsafe { destructors::run() }; + unsafe { + destructors::run(); + crate::rt::thread_cleanup(); + } } } diff --git a/library/std/src/sys/thread_local/guard/windows.rs b/library/std/src/sys/thread_local/guard/windows.rs index bf94f7d6e3d..7ee8e695c75 100644 --- a/library/std/src/sys/thread_local/guard/windows.rs +++ b/library/std/src/sys/thread_local/guard/windows.rs @@ -80,13 +80,13 @@ pub static CALLBACK: unsafe extern "system" fn(*mut c_void, u32, *mut c_void) = unsafe extern "system" fn tls_callback(_h: *mut c_void, dw_reason: u32, _pv: *mut c_void) { if dw_reason == c::DLL_THREAD_DETACH || dw_reason == c::DLL_PROCESS_DETACH { - #[cfg(target_thread_local)] unsafe { + #[cfg(target_thread_local)] super::super::destructors::run(); - } - #[cfg(not(target_thread_local))] - unsafe { + #[cfg(not(target_thread_local))] super::super::key::run_dtors(); + + crate::rt::thread_cleanup(); } } } diff --git a/library/std/src/sys/thread_local/key/xous.rs b/library/std/src/sys/thread_local/key/xous.rs index 295fb848b30..2ab4bba7d8e 100644 --- a/library/std/src/sys/thread_local/key/xous.rs +++ b/library/std/src/sys/thread_local/key/xous.rs @@ -212,4 +212,6 @@ unsafe fn run_dtors() { unsafe { cur = (*cur).next }; } } + + crate::rt::thread_cleanup(); } diff --git a/library/std/src/sys/thread_local/mod.rs b/library/std/src/sys/thread_local/mod.rs index 3d1b91a7ea0..31d3b439060 100644 --- a/library/std/src/sys/thread_local/mod.rs +++ b/library/std/src/sys/thread_local/mod.rs @@ -31,12 +31,15 @@ cfg_if::cfg_if! { ))] { mod statik; pub use statik::{EagerStorage, LazyStorage, thread_local_inner}; + pub(crate) use statik::{LocalPointer, local_pointer}; } else if #[cfg(target_thread_local)] { mod native; pub use native::{EagerStorage, LazyStorage, thread_local_inner}; + pub(crate) use native::{LocalPointer, local_pointer}; } else { mod os; pub use os::{Storage, thread_local_inner}; + pub(crate) use os::{LocalPointer, local_pointer}; } } @@ -72,36 +75,47 @@ pub(crate) mod destructors { } /// This module provides a way to schedule the execution of the destructor list -/// on systems without a per-variable destructor system. -mod guard { +/// and the [runtime cleanup](crate::rt::thread_cleanup) function. Calling `enable` +/// should ensure that these functions are called at the right times. +pub(crate) mod guard { cfg_if::cfg_if! { if #[cfg(all(target_thread_local, target_vendor = "apple"))] { mod apple; - pub(super) use apple::enable; + pub(crate) use apple::enable; } else if #[cfg(target_os = "windows")] { mod windows; - pub(super) use windows::enable; + pub(crate) use windows::enable; } else if #[cfg(any( - all(target_family = "wasm", target_feature = "atomics"), + target_family = "wasm", + target_os = "uefi", + target_os = "zkvm", ))] { - pub(super) fn enable() { - // FIXME: Right now there is no concept of "thread exit", but - // this is likely going to show up at some point in the form of - // an exported symbol that the wasm runtime is going to be - // expected to call. For now we just leak everything, but if - // such a function starts to exist it will probably need to - // iterate the destructor list with this function: + pub(crate) fn enable() { + // FIXME: Right now there is no concept of "thread exit" on + // wasm, but this is likely going to show up at some point in + // the form of an exported symbol that the wasm runtime is going + // to be expected to call. For now we just leak everything, but + // if such a function starts to exist it will probably need to + // iterate the destructor list with these functions: + #[cfg(all(target_family = "wasm", target_feature = "atomics"))] #[allow(unused)] use super::destructors::run; + #[allow(unused)] + use crate::rt::thread_cleanup; } - } else if #[cfg(target_os = "hermit")] { - pub(super) fn enable() {} + } else if #[cfg(any( + target_os = "hermit", + target_os = "xous", + ))] { + // `std` is the only runtime, so it just calls the destructor functions + // itself when the time comes. + pub(crate) fn enable() {} } else if #[cfg(target_os = "solid_asp3")] { mod solid; - pub(super) use solid::enable; - } else if #[cfg(all(target_thread_local, not(target_family = "wasm")))] { + pub(crate) use solid::enable; + } else { mod key; - pub(super) use key::enable; + pub(crate) use key::enable; } } } diff --git a/library/std/src/sys/thread_local/native/mod.rs b/library/std/src/sys/thread_local/native/mod.rs index 1cc45fe892d..f498dee0899 100644 --- a/library/std/src/sys/thread_local/native/mod.rs +++ b/library/std/src/sys/thread_local/native/mod.rs @@ -29,6 +29,9 @@ //! eliminates the `Destroyed` state for these values, which can allow more niche //! optimizations to occur for the `State` enum. For `Drop` types, `()` is used. +use crate::cell::Cell; +use crate::ptr; + mod eager; mod lazy; @@ -107,3 +110,31 @@ pub macro thread_local_inner { $crate::thread::local_impl::thread_local_inner!(@key $t, $($init)*); }, } + +#[rustc_macro_transparency = "semitransparent"] +pub(crate) macro local_pointer { + () => {}, + ($vis:vis static $name:ident; $($rest:tt)*) => { + #[thread_local] + $vis static $name: $crate::sys::thread_local::LocalPointer = $crate::sys::thread_local::LocalPointer::__new(); + $crate::sys::thread_local::local_pointer! { $($rest)* } + }, +} + +pub(crate) struct LocalPointer { + p: Cell<*mut ()>, +} + +impl LocalPointer { + pub const fn __new() -> LocalPointer { + LocalPointer { p: Cell::new(ptr::null_mut()) } + } + + pub fn get(&self) -> *mut () { + self.p.get() + } + + pub fn set(&self, p: *mut ()) { + self.p.set(p) + } +} diff --git a/library/std/src/sys/thread_local/os.rs b/library/std/src/sys/thread_local/os.rs index f09c396ef0f..26ce3322a16 100644 --- a/library/std/src/sys/thread_local/os.rs +++ b/library/std/src/sys/thread_local/os.rs @@ -1,8 +1,8 @@ -use super::abort_on_dtor_unwind; +use super::key::{Key, LazyKey, get, set}; +use super::{abort_on_dtor_unwind, guard}; use crate::cell::Cell; use crate::marker::PhantomData; use crate::ptr; -use crate::sys::thread_local::key::{Key, LazyKey, get, set}; #[doc(hidden)] #[allow_internal_unstable(thread_local_internals)] @@ -138,5 +138,35 @@ unsafe extern "C" fn destroy_value(ptr: *mut u8) { drop(ptr); // SAFETY: `key` is the TLS key `ptr` was stored under. unsafe { set(key, ptr::null_mut()) }; + // Make sure that the runtime cleanup will be performed + // after the next round of TLS destruction. + guard::enable(); }); } + +#[rustc_macro_transparency = "semitransparent"] +pub(crate) macro local_pointer { + () => {}, + ($vis:vis static $name:ident; $($rest:tt)*) => { + $vis static $name: $crate::sys::thread_local::LocalPointer = $crate::sys::thread_local::LocalPointer::__new(); + $crate::sys::thread_local::local_pointer! { $($rest)* } + }, +} + +pub(crate) struct LocalPointer { + key: LazyKey, +} + +impl LocalPointer { + pub const fn __new() -> LocalPointer { + LocalPointer { key: LazyKey::new(None) } + } + + pub fn get(&'static self) -> *mut () { + unsafe { get(self.key.force()) as *mut () } + } + + pub fn set(&'static self, p: *mut ()) { + unsafe { set(self.key.force(), p as *mut u8) } + } +} diff --git a/library/std/src/sys/thread_local/statik.rs b/library/std/src/sys/thread_local/statik.rs index a3451ab74e0..ba94caa6690 100644 --- a/library/std/src/sys/thread_local/statik.rs +++ b/library/std/src/sys/thread_local/statik.rs @@ -1,7 +1,8 @@ //! On some targets like wasm there's no threads, so no need to generate //! thread locals and we can instead just use plain statics! -use crate::cell::UnsafeCell; +use crate::cell::{Cell, UnsafeCell}; +use crate::ptr; #[doc(hidden)] #[allow_internal_unstable(thread_local_internals)] @@ -93,3 +94,33 @@ impl LazyStorage { // SAFETY: the target doesn't have threads. unsafe impl Sync for LazyStorage {} + +#[rustc_macro_transparency = "semitransparent"] +pub(crate) macro local_pointer { + () => {}, + ($vis:vis static $name:ident; $($rest:tt)*) => { + $vis static $name: $crate::sys::thread_local::LocalPointer = $crate::sys::thread_local::LocalPointer::__new(); + $crate::sys::thread_local::local_pointer! { $($rest)* } + }, +} + +pub(crate) struct LocalPointer { + p: Cell<*mut ()>, +} + +impl LocalPointer { + pub const fn __new() -> LocalPointer { + LocalPointer { p: Cell::new(ptr::null_mut()) } + } + + pub fn get(&self) -> *mut () { + self.p.get() + } + + pub fn set(&self, p: *mut ()) { + self.p.set(p) + } +} + +// SAFETY: the target doesn't have threads. +unsafe impl Sync for LocalPointer {} diff --git a/library/std/src/thread/current.rs b/library/std/src/thread/current.rs new file mode 100644 index 00000000000..b38149a0da7 --- /dev/null +++ b/library/std/src/thread/current.rs @@ -0,0 +1,252 @@ +use super::{Thread, ThreadId}; +use crate::mem::ManuallyDrop; +use crate::ptr; +use crate::sys::thread_local::local_pointer; + +const NONE: *mut () = ptr::null_mut(); +const BUSY: *mut () = ptr::without_provenance_mut(1); +const DESTROYED: *mut () = ptr::without_provenance_mut(2); + +local_pointer! { + static CURRENT; +} + +/// Persistent storage for the thread ID. +/// +/// We store the thread ID so that it never gets destroyed during the lifetime +/// of a thread, either using `#[thread_local]` or multiple `local_pointer!`s. +mod id { + use super::*; + + cfg_if::cfg_if! { + if #[cfg(target_thread_local)] { + use crate::cell::Cell; + + #[thread_local] + static ID: Cell> = Cell::new(None); + + pub(super) const CHEAP: bool = true; + + pub(super) fn get() -> Option { + ID.get() + } + + pub(super) fn set(id: ThreadId) { + ID.set(Some(id)) + } + } else if #[cfg(target_pointer_width = "16")] { + local_pointer! { + static ID0; + static ID16; + static ID32; + static ID48; + } + + pub(super) const CHEAP: bool = false; + + pub(super) fn get() -> Option { + let id0 = ID0.get().addr() as u64; + let id16 = ID16.get().addr() as u64; + let id32 = ID32.get().addr() as u64; + let id48 = ID48.get().addr() as u64; + ThreadId::from_u64((id48 << 48) + (id32 << 32) + (id16 << 16) + id0) + } + + pub(super) fn set(id: ThreadId) { + let val = id.as_u64().get(); + ID0.set(ptr::without_provenance_mut(val as usize)); + ID16.set(ptr::without_provenance_mut((val >> 16) as usize)); + ID32.set(ptr::without_provenance_mut((val >> 32) as usize)); + ID48.set(ptr::without_provenance_mut((val >> 48) as usize)); + } + } else if #[cfg(target_pointer_width = "32")] { + local_pointer! { + static ID0; + static ID32; + } + + pub(super) const CHEAP: bool = false; + + pub(super) fn get() -> Option { + let id0 = ID0.get().addr() as u64; + let id32 = ID32.get().addr() as u64; + ThreadId::from_u64((id32 << 32) + id0) + } + + pub(super) fn set(id: ThreadId) { + let val = id.as_u64().get(); + ID0.set(ptr::without_provenance_mut(val as usize)); + ID32.set(ptr::without_provenance_mut((val >> 32) as usize)); + } + } else { + local_pointer! { + static ID; + } + + pub(super) const CHEAP: bool = true; + + pub(super) fn get() -> Option { + let id = ID.get().addr() as u64; + ThreadId::from_u64(id) + } + + pub(super) fn set(id: ThreadId) { + let val = id.as_u64().get(); + ID.set(ptr::without_provenance_mut(val as usize)); + } + } + } + + #[inline] + pub(super) fn get_or_init() -> ThreadId { + get().unwrap_or_else( + #[cold] + || { + let id = ThreadId::new(); + id::set(id); + id + }, + ) + } +} + +/// Sets the thread handle for the current thread. +/// +/// Aborts if the handle or the ID has been set already. +pub(crate) fn set_current(thread: Thread) { + if CURRENT.get() != NONE || id::get().is_some() { + // Using `panic` here can add ~3kB to the binary size. We have complete + // control over where this is called, so just abort if there is a bug. + rtabort!("thread::set_current should only be called once per thread"); + } + + id::set(thread.id()); + + // Make sure that `crate::rt::thread_cleanup` will be run, which will + // call `drop_current`. + crate::sys::thread_local::guard::enable(); + CURRENT.set(thread.into_raw().cast_mut()); +} + +/// Gets the id of the thread that invokes it. +/// +/// This function will always succeed, will always return the same value for +/// one thread and is guaranteed not to call the global allocator. +#[inline] +pub(crate) fn current_id() -> ThreadId { + // If accessing the persistant thread ID takes multiple TLS accesses, try + // to retrieve it from the current thread handle, which will only take one + // TLS access. + if !id::CHEAP { + let current = CURRENT.get(); + if current > DESTROYED { + unsafe { + let current = ManuallyDrop::new(Thread::from_raw(current)); + return current.id(); + } + } + } + + id::get_or_init() +} + +/// Gets a handle to the thread that invokes it, if the handle has been initialized. +pub(crate) fn try_current() -> Option { + let current = CURRENT.get(); + if current > DESTROYED { + unsafe { + let current = ManuallyDrop::new(Thread::from_raw(current)); + Some((*current).clone()) + } + } else { + None + } +} + +/// Gets a handle to the thread that invokes it. +/// +/// # Examples +/// +/// Getting a handle to the current thread with `thread::current()`: +/// +/// ``` +/// use std::thread; +/// +/// let handler = thread::Builder::new() +/// .name("named thread".into()) +/// .spawn(|| { +/// let handle = thread::current(); +/// assert_eq!(handle.name(), Some("named thread")); +/// }) +/// .unwrap(); +/// +/// handler.join().unwrap(); +/// ``` +#[must_use] +#[stable(feature = "rust1", since = "1.0.0")] +pub fn current() -> Thread { + let current = CURRENT.get(); + if current > DESTROYED { + unsafe { + let current = ManuallyDrop::new(Thread::from_raw(current)); + (*current).clone() + } + } else { + init_current(current) + } +} + +#[cold] +fn init_current(current: *mut ()) -> Thread { + if current == NONE { + CURRENT.set(BUSY); + // If the thread ID was initialized already, use it. + let id = id::get_or_init(); + let thread = Thread::new_unnamed(id); + + // Make sure that `crate::rt::thread_cleanup` will be run, which will + // call `drop_current`. + crate::sys::thread_local::guard::enable(); + CURRENT.set(thread.clone().into_raw().cast_mut()); + thread + } else if current == BUSY { + // BUSY exists solely for this check, but as it is in the slow path, the + // extra TLS write above shouldn't matter. The alternative is nearly always + // a stack overflow. + + // If you came across this message, contact the author of your allocator. + // If you are said author: A surprising amount of functions inside the + // standard library (e.g. `Mutex`, `thread_local!`, `File` when using long + // paths, even `panic!` when using unwinding), need memory allocation, so + // you'll get circular dependencies all over the place when using them. + // I (joboet) highly recommend using only APIs from core in your allocator + // and implementing your own system abstractions. Still, if you feel that + // a particular API should be entirely allocation-free, feel free to open + // an issue on the Rust repository, we'll see what we can do. + rtabort!( + "\n + Attempted to access thread-local data while allocating said data.\n + Do not access functions that allocate in the global allocator!\n + This is a bug in the global allocator.\n + " + ) + } else { + debug_assert_eq!(current, DESTROYED); + panic!( + "use of std::thread::current() is not possible after the thread's + local data has been destroyed" + ) + } +} + +/// This should be run in [`crate::rt::thread_cleanup`] to reset the thread +/// handle. +pub(crate) fn drop_current() { + let current = CURRENT.get(); + if current > DESTROYED { + unsafe { + CURRENT.set(DESTROYED); + drop(Thread::from_raw(current)); + } + } +} diff --git a/library/std/src/thread/local/tests.rs b/library/std/src/thread/local/tests.rs index 6abb9b85a2e..9d4f52a0921 100644 --- a/library/std/src/thread/local/tests.rs +++ b/library/std/src/thread/local/tests.rs @@ -1,7 +1,7 @@ use crate::cell::{Cell, UnsafeCell}; use crate::sync::atomic::{AtomicU8, Ordering}; use crate::sync::{Arc, Condvar, Mutex}; -use crate::thread::{self, LocalKey}; +use crate::thread::{self, Builder, LocalKey}; use crate::thread_local; #[derive(Clone, Default)] @@ -343,3 +343,34 @@ fn join_orders_after_tls_destructors() { jh2.join().unwrap(); } } + +// Test that thread::current is still available in TLS destructors. +#[test] +fn thread_current_in_dtor() { + // Go through one round of TLS destruction first. + struct Defer; + impl Drop for Defer { + fn drop(&mut self) { + RETRIEVE.with(|_| {}); + } + } + + struct RetrieveName; + impl Drop for RetrieveName { + fn drop(&mut self) { + *NAME.lock().unwrap() = Some(thread::current().name().unwrap().to_owned()); + } + } + + static NAME: Mutex> = Mutex::new(None); + + thread_local! { + static DEFER: Defer = const { Defer }; + static RETRIEVE: RetrieveName = const { RetrieveName }; + } + + Builder::new().name("test".to_owned()).spawn(|| DEFER.with(|_| {})).unwrap().join().unwrap(); + let name = NAME.lock().unwrap(); + let name = name.as_ref().unwrap(); + assert_eq!(name, "test"); +} diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs index 22d65583365..d1d4eabb9bd 100644 --- a/library/std/src/thread/mod.rs +++ b/library/std/src/thread/mod.rs @@ -141,7 +141,7 @@ //! [`Result`]: crate::result::Result //! [`Ok`]: crate::result::Result::Ok //! [`Err`]: crate::result::Result::Err -//! [`thread::current`]: current +//! [`thread::current`]: current::current //! [`thread::Result`]: Result //! [`unpark`]: Thread::unpark //! [`thread::park_timeout`]: park_timeout @@ -159,7 +159,7 @@ mod tests; use crate::any::Any; -use crate::cell::{Cell, OnceCell, UnsafeCell}; +use crate::cell::UnsafeCell; use crate::ffi::CStr; use crate::marker::PhantomData; use crate::mem::{self, ManuallyDrop, forget}; @@ -179,6 +179,12 @@ mod scoped; #[stable(feature = "scoped_threads", since = "1.63.0")] pub use scoped::{Scope, ScopedJoinHandle, scope}; +mod current; + +#[stable(feature = "rust1", since = "1.0.0")] +pub use current::current; +pub(crate) use current::{current_id, drop_current, set_current, try_current}; + //////////////////////////////////////////////////////////////////////////////// // Thread-local storage //////////////////////////////////////////////////////////////////////////////// @@ -471,7 +477,11 @@ impl Builder { amt }); - let my_thread = name.map_or_else(Thread::new_unnamed, Thread::new); + let id = ThreadId::new(); + let my_thread = match name { + Some(name) => Thread::new(id, name.into()), + None => Thread::new_unnamed(id), + }; let their_thread = my_thread.clone(); let my_packet: Arc> = Arc::new(Packet { @@ -509,6 +519,9 @@ impl Builder { let f = MaybeDangling::new(f); let main = move || { + // Immediately store the thread handle to avoid setting it or its ID + // twice, which would cause an abort. + set_current(their_thread.clone()); if let Some(name) = their_thread.cname() { imp::Thread::set_name(name); } @@ -516,7 +529,6 @@ impl Builder { crate::io::set_output_capture(output_capture); let f = f.into_inner(); - set_current(their_thread); let try_result = panic::catch_unwind(panic::AssertUnwindSafe(|| { crate::sys::backtrace::__rust_begin_short_backtrace(f) })); @@ -690,84 +702,6 @@ where Builder::new().spawn(f).expect("failed to spawn thread") } -thread_local! { - // Invariant: `CURRENT` and `CURRENT_ID` will always be initialized together. - // If `CURRENT` is initialized, then `CURRENT_ID` will hold the same value - // as `CURRENT.id()`. - static CURRENT: OnceCell = const { OnceCell::new() }; - static CURRENT_ID: Cell> = const { Cell::new(None) }; -} - -/// Sets the thread handle for the current thread. -/// -/// Aborts if the handle has been set already to reduce code size. -pub(crate) fn set_current(thread: Thread) { - let tid = thread.id(); - // Using `unwrap` here can add ~3kB to the binary size. We have complete - // control over where this is called, so just abort if there is a bug. - CURRENT.with(|current| match current.set(thread) { - Ok(()) => CURRENT_ID.set(Some(tid)), - Err(_) => rtabort!("thread::set_current should only be called once per thread"), - }); -} - -/// Gets a handle to the thread that invokes it. -/// -/// In contrast to the public `current` function, this will not panic if called -/// from inside a TLS destructor. -pub(crate) fn try_current() -> Option { - CURRENT - .try_with(|current| { - current - .get_or_init(|| { - let thread = Thread::new_unnamed(); - CURRENT_ID.set(Some(thread.id())); - thread - }) - .clone() - }) - .ok() -} - -/// Gets the id of the thread that invokes it. -#[inline] -pub(crate) fn current_id() -> ThreadId { - CURRENT_ID.get().unwrap_or_else(|| { - // If `CURRENT_ID` isn't initialized yet, then `CURRENT` must also not be initialized. - // `current()` will initialize both `CURRENT` and `CURRENT_ID` so subsequent calls to - // `current_id()` will succeed immediately. - current().id() - }) -} - -/// Gets a handle to the thread that invokes it. -/// -/// # Examples -/// -/// Getting a handle to the current thread with `thread::current()`: -/// -/// ``` -/// use std::thread; -/// -/// let handler = thread::Builder::new() -/// .name("named thread".into()) -/// .spawn(|| { -/// let handle = thread::current(); -/// assert_eq!(handle.name(), Some("named thread")); -/// }) -/// .unwrap(); -/// -/// handler.join().unwrap(); -/// ``` -#[must_use] -#[stable(feature = "rust1", since = "1.0.0")] -pub fn current() -> Thread { - try_current().expect( - "use of std::thread::current() is not possible \ - after the thread's local data has been destroyed", - ) -} - /// Cooperatively gives up a timeslice to the OS scheduler. /// /// This calls the underlying OS scheduler's yield primitive, signaling @@ -1225,8 +1159,11 @@ pub fn park_timeout(dur: Duration) { pub struct ThreadId(NonZero); impl ThreadId { + // DO NOT rely on this value. + const MAIN_THREAD: ThreadId = ThreadId(unsafe { NonZero::new_unchecked(1) }); + // Generate a new unique thread ID. - fn new() -> ThreadId { + pub(crate) fn new() -> ThreadId { #[cold] fn exhausted() -> ! { panic!("failed to generate unique thread ID: bitspace exhausted") @@ -1236,7 +1173,7 @@ impl ThreadId { if #[cfg(target_has_atomic = "64")] { use crate::sync::atomic::AtomicU64; - static COUNTER: AtomicU64 = AtomicU64::new(0); + static COUNTER: AtomicU64 = AtomicU64::new(1); let mut last = COUNTER.load(Ordering::Relaxed); loop { @@ -1252,7 +1189,7 @@ impl ThreadId { } else { use crate::sync::{Mutex, PoisonError}; - static COUNTER: Mutex = Mutex::new(0); + static COUNTER: Mutex = Mutex::new(1); let mut counter = COUNTER.lock().unwrap_or_else(PoisonError::into_inner); let Some(id) = counter.checked_add(1) else { @@ -1269,6 +1206,11 @@ impl ThreadId { } } + #[cfg(not(target_thread_local))] + fn from_u64(v: u64) -> Option { + NonZero::new(v).map(ThreadId) + } + /// This returns a numeric identifier for the thread identified by this /// `ThreadId`. /// @@ -1369,27 +1311,27 @@ impl Inner { /// should instead use a function like `spawn` to create new threads, see the /// docs of [`Builder`] and [`spawn`] for more details. /// -/// [`thread::current`]: current +/// [`thread::current`]: current::current pub struct Thread { inner: Pin>, } impl Thread { /// Used only internally to construct a thread object without spawning. - pub(crate) fn new(name: String) -> Thread { - Self::new_inner(ThreadName::Other(name.into())) + pub(crate) fn new(id: ThreadId, name: String) -> Thread { + Self::new_inner(id, ThreadName::Other(name.into())) } - pub(crate) fn new_unnamed() -> Thread { - Self::new_inner(ThreadName::Unnamed) + pub(crate) fn new_unnamed(id: ThreadId) -> Thread { + Self::new_inner(id, ThreadName::Unnamed) } // Used in runtime to construct main thread pub(crate) fn new_main() -> Thread { - Self::new_inner(ThreadName::Main) + Self::new_inner(ThreadId::MAIN_THREAD, ThreadName::Main) } - fn new_inner(name: ThreadName) -> Thread { + fn new_inner(id: ThreadId, name: ThreadName) -> Thread { // We have to use `unsafe` here to construct the `Parker` in-place, // which is required for the UNIX implementation. // @@ -1399,7 +1341,7 @@ impl Thread { let mut arc = Arc::::new_uninit(); let ptr = Arc::get_mut_unchecked(&mut arc).as_mut_ptr(); (&raw mut (*ptr).name).write(name); - (&raw mut (*ptr).id).write(ThreadId::new()); + (&raw mut (*ptr).id).write(id); Parker::new_in_place(&raw mut (*ptr).parker); Pin::new_unchecked(arc.assume_init()) }; From a71ba0cf02cdd196b9c88fd1087ccdf7048c4c21 Mon Sep 17 00:00:00 2001 From: joboet Date: Sat, 20 Jul 2024 13:00:00 +0200 Subject: [PATCH 498/683] bless miri tests --- src/tools/miri/tests/fail/tail_calls/cc-mismatch.stderr | 6 +++--- src/tools/miri/tests/pass/backtrace/backtrace-api-v0.stderr | 2 +- src/tools/miri/tests/pass/backtrace/backtrace-api-v1.stderr | 2 +- .../miri/tests/pass/backtrace/backtrace-global-alloc.stderr | 2 +- src/tools/miri/tests/pass/backtrace/backtrace-std.stderr | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/tools/miri/tests/fail/tail_calls/cc-mismatch.stderr b/src/tools/miri/tests/fail/tail_calls/cc-mismatch.stderr index b157e9f0b21..b416f0eb689 100644 --- a/src/tools/miri/tests/fail/tail_calls/cc-mismatch.stderr +++ b/src/tools/miri/tests/fail/tail_calls/cc-mismatch.stderr @@ -15,9 +15,9 @@ LL | extern "rust-call" fn call_once(self, args: Args) -> Self::Output; = note: inside `std::panicking::r#try:: i32 + std::marker::Sync + std::panic::RefUnwindSafe>` at RUSTLIB/std/src/panicking.rs:LL:CC = note: inside `std::panic::catch_unwind::<&dyn std::ops::Fn() -> i32 + std::marker::Sync + std::panic::RefUnwindSafe, i32>` at RUSTLIB/std/src/panic.rs:LL:CC = note: inside closure at RUSTLIB/std/src/rt.rs:LL:CC - = note: inside `std::panicking::r#try::do_call::<{closure@std::rt::lang_start_internal::{closure#2}}, isize>` at RUSTLIB/std/src/panicking.rs:LL:CC - = note: inside `std::panicking::r#try::` at RUSTLIB/std/src/panicking.rs:LL:CC - = note: inside `std::panic::catch_unwind::<{closure@std::rt::lang_start_internal::{closure#2}}, isize>` at RUSTLIB/std/src/panic.rs:LL:CC + = note: inside `std::panicking::r#try::do_call::<{closure@std::rt::lang_start_internal::{closure#1}}, isize>` at RUSTLIB/std/src/panicking.rs:LL:CC + = note: inside `std::panicking::r#try::` at RUSTLIB/std/src/panicking.rs:LL:CC + = note: inside `std::panic::catch_unwind::<{closure@std::rt::lang_start_internal::{closure#1}}, isize>` at RUSTLIB/std/src/panic.rs:LL:CC = note: inside `std::rt::lang_start_internal` at RUSTLIB/std/src/rt.rs:LL:CC = note: inside `std::rt::lang_start::<()>` at RUSTLIB/std/src/rt.rs:LL:CC diff --git a/src/tools/miri/tests/pass/backtrace/backtrace-api-v0.stderr b/src/tools/miri/tests/pass/backtrace/backtrace-api-v0.stderr index b87063431ad..9849a1aa74e 100644 --- a/src/tools/miri/tests/pass/backtrace/backtrace-api-v0.stderr +++ b/src/tools/miri/tests/pass/backtrace/backtrace-api-v0.stderr @@ -10,7 +10,7 @@ RUSTLIB/core/src/ops/function.rs:LL:CC (std::ops::function::impls::call_once) RUSTLIB/std/src/panicking.rs:LL:CC (std::panicking::r#try::do_call) RUSTLIB/std/src/panicking.rs:LL:CC (std::panicking::r#try) RUSTLIB/std/src/panic.rs:LL:CC (std::panic::catch_unwind) -RUSTLIB/std/src/rt.rs:LL:CC (std::rt::lang_start_internal::{closure#2}) +RUSTLIB/std/src/rt.rs:LL:CC (std::rt::lang_start_internal::{closure#1}) RUSTLIB/std/src/panicking.rs:LL:CC (std::panicking::r#try::do_call) RUSTLIB/std/src/panicking.rs:LL:CC (std::panicking::r#try) RUSTLIB/std/src/panic.rs:LL:CC (std::panic::catch_unwind) diff --git a/src/tools/miri/tests/pass/backtrace/backtrace-api-v1.stderr b/src/tools/miri/tests/pass/backtrace/backtrace-api-v1.stderr index 2c729c49ee0..48d9649c920 100644 --- a/src/tools/miri/tests/pass/backtrace/backtrace-api-v1.stderr +++ b/src/tools/miri/tests/pass/backtrace/backtrace-api-v1.stderr @@ -10,7 +10,7 @@ RUSTLIB/core/src/ops/function.rs:LL:CC (std::ops::function::impls::call_once) RUSTLIB/std/src/panicking.rs:LL:CC (std::panicking::r#try::do_call) RUSTLIB/std/src/panicking.rs:LL:CC (std::panicking::r#try) RUSTLIB/std/src/panic.rs:LL:CC (std::panic::catch_unwind) -RUSTLIB/std/src/rt.rs:LL:CC (std::rt::lang_start_internal::{closure#2}) +RUSTLIB/std/src/rt.rs:LL:CC (std::rt::lang_start_internal::{closure#1}) RUSTLIB/std/src/panicking.rs:LL:CC (std::panicking::r#try::do_call) RUSTLIB/std/src/panicking.rs:LL:CC (std::panicking::r#try) RUSTLIB/std/src/panic.rs:LL:CC (std::panic::catch_unwind) diff --git a/src/tools/miri/tests/pass/backtrace/backtrace-global-alloc.stderr b/src/tools/miri/tests/pass/backtrace/backtrace-global-alloc.stderr index d9414aa6518..667ee04e624 100644 --- a/src/tools/miri/tests/pass/backtrace/backtrace-global-alloc.stderr +++ b/src/tools/miri/tests/pass/backtrace/backtrace-global-alloc.stderr @@ -14,7 +14,7 @@ at RUSTLIB/std/src/panicking.rs:LL:CC 7: std::panic::catch_unwind at RUSTLIB/std/src/panic.rs:LL:CC - 8: std::rt::lang_start_internal::{closure#2} + 8: std::rt::lang_start_internal::{closure#1} at RUSTLIB/std/src/rt.rs:LL:CC 9: std::panicking::r#try::do_call at RUSTLIB/std/src/panicking.rs:LL:CC diff --git a/src/tools/miri/tests/pass/backtrace/backtrace-std.stderr b/src/tools/miri/tests/pass/backtrace/backtrace-std.stderr index d6d69ee837e..b3a3a9d654a 100644 --- a/src/tools/miri/tests/pass/backtrace/backtrace-std.stderr +++ b/src/tools/miri/tests/pass/backtrace/backtrace-std.stderr @@ -22,7 +22,7 @@ at RUSTLIB/std/src/panicking.rs:LL:CC 11: std::panic::catch_unwind at RUSTLIB/std/src/panic.rs:LL:CC - 12: std::rt::lang_start_internal::{closure#2} + 12: std::rt::lang_start_internal::{closure#1} at RUSTLIB/std/src/rt.rs:LL:CC 13: std::panicking::r#try::do_call at RUSTLIB/std/src/panicking.rs:LL:CC From 746c3225925ee44b37c1665617ada24c8b173b20 Mon Sep 17 00:00:00 2001 From: Mads Marquart Date: Wed, 2 Oct 2024 19:30:55 +0200 Subject: [PATCH 499/683] Fix target_vendor for aarch64-nintendo-switch-freestanding Previously set to `target_vendor = "unknown"`, but Nintendo is clearly the vendor of the Switch, and is also reflected in the target name itself. --- .../src/spec/targets/aarch64_nintendo_switch_freestanding.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/compiler/rustc_target/src/spec/targets/aarch64_nintendo_switch_freestanding.rs b/compiler/rustc_target/src/spec/targets/aarch64_nintendo_switch_freestanding.rs index d6d49a4a070..1f1cd966326 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_nintendo_switch_freestanding.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_nintendo_switch_freestanding.rs @@ -23,6 +23,7 @@ pub(crate) fn target() -> Target { linker: Some("rust-lld".into()), link_script: Some(LINKER_SCRIPT.into()), os: "horizon".into(), + vendor: "nintendo".into(), max_atomic_width: Some(128), stack_probes: StackProbeType::Inline, panic_strategy: PanicStrategy::Abort, From 3e089b0e16db2779de0c5ca7d54a462d78354fb7 Mon Sep 17 00:00:00 2001 From: Frank Rehwinkel Date: Wed, 2 Oct 2024 07:44:01 -0400 Subject: [PATCH 500/683] epoll: add data_race test This test demonstrates the need to synchronize the clock of the thread waking up from an epoll_wait from the thread that issued the epoll awake event. --- .../fail-dep/libc/libc-epoll-blocking.rs | 79 +++++++++++++++++++ .../fail-dep/libc/libc-epoll-blocking.stderr | 29 +++++++ 2 files changed, 108 insertions(+) create mode 100644 src/tools/miri/tests/fail-dep/libc/libc-epoll-blocking.rs create mode 100644 src/tools/miri/tests/fail-dep/libc/libc-epoll-blocking.stderr diff --git a/src/tools/miri/tests/fail-dep/libc/libc-epoll-blocking.rs b/src/tools/miri/tests/fail-dep/libc/libc-epoll-blocking.rs new file mode 100644 index 00000000000..fd9d1875daf --- /dev/null +++ b/src/tools/miri/tests/fail-dep/libc/libc-epoll-blocking.rs @@ -0,0 +1,79 @@ +//@only-target: linux +// test_epoll_race depends on a deterministic schedule. +//@compile-flags: -Zmiri-preemption-rate=0 + +use std::convert::TryInto; +use std::thread; + +fn main() { + test_epoll_race(); +} + +// Using `as` cast since `EPOLLET` wraps around +const EPOLL_IN_OUT_ET: u32 = (libc::EPOLLIN | libc::EPOLLOUT | libc::EPOLLET) as _; + +#[track_caller] +fn check_epoll_wait( + epfd: i32, + expected_notifications: &[(u32, u64)], + timeout: i32, +) { + let epoll_event = libc::epoll_event { events: 0, u64: 0 }; + let mut array: [libc::epoll_event; N] = [epoll_event; N]; + let maxsize = N; + let array_ptr = array.as_mut_ptr(); + let res = unsafe { libc::epoll_wait(epfd, array_ptr, maxsize.try_into().unwrap(), timeout) }; + if res < 0 { + panic!("epoll_wait failed: {}", std::io::Error::last_os_error()); + } + assert_eq!( + res, + expected_notifications.len().try_into().unwrap(), + "got wrong number of notifications" + ); + let slice = unsafe { std::slice::from_raw_parts(array_ptr, res.try_into().unwrap()) }; + for (return_event, expected_event) in slice.iter().zip(expected_notifications.iter()) { + let event = return_event.events; + let data = return_event.u64; + assert_eq!(event, expected_event.0, "got wrong events"); + assert_eq!(data, expected_event.1, "got wrong data"); + } +} + +// This test shows a data_race before epoll had vector clocks added. +fn test_epoll_race() { + // Create an epoll instance. + let epfd = unsafe { libc::epoll_create1(0) }; + assert_ne!(epfd, -1); + + // Create an eventfd instance. + let flags = libc::EFD_NONBLOCK | libc::EFD_CLOEXEC; + let fd = unsafe { libc::eventfd(0, flags) }; + + // Register eventfd with the epoll instance. + let mut ev = libc::epoll_event { events: EPOLL_IN_OUT_ET, u64: fd as u64 }; + let res = unsafe { libc::epoll_ctl(epfd, libc::EPOLL_CTL_ADD, fd, &mut ev) }; + assert_eq!(res, 0); + + static mut VAL: u8 = 0; + let thread1 = thread::spawn(move || { + // Write to the static mut variable. + unsafe { VAL = 1 }; + // Write to the eventfd instance. + let sized_8_data: [u8; 8] = 1_u64.to_ne_bytes(); + let res = unsafe { libc::write(fd, sized_8_data.as_ptr() as *const libc::c_void, 8) }; + // read returns number of bytes that have been read, which is always 8. + assert_eq!(res, 8); + }); + thread::yield_now(); + // epoll_wait for the event to happen. + let expected_event = u32::try_from(libc::EPOLLIN | libc::EPOLLOUT).unwrap(); + let expected_value = u64::try_from(fd).unwrap(); + check_epoll_wait::<8>(epfd, &[(expected_event, expected_value)], -1); + // Read from the static mut variable. + #[allow(static_mut_refs)] + unsafe { + assert_eq!(VAL, 1) //~ ERROR: Data race detected + }; + thread1.join().unwrap(); +} diff --git a/src/tools/miri/tests/fail-dep/libc/libc-epoll-blocking.stderr b/src/tools/miri/tests/fail-dep/libc/libc-epoll-blocking.stderr new file mode 100644 index 00000000000..27974981cea --- /dev/null +++ b/src/tools/miri/tests/fail-dep/libc/libc-epoll-blocking.stderr @@ -0,0 +1,29 @@ +error: Undefined Behavior: Data race detected between (1) non-atomic write on thread `unnamed-ID` and (2) retag read of type `u8` on thread `main` at ALLOC. (2) just happened here + --> tests/fail-dep/libc/libc-epoll-blocking.rs:LL:CC + | +LL | assert_eq!(VAL, 1) + | ^^^^^^^^^^^^^^^^^^ Data race detected between (1) non-atomic write on thread `unnamed-ID` and (2) retag read of type `u8` on thread `main` at ALLOC. (2) just happened here + | +help: and (1) occurred earlier here + --> tests/fail-dep/libc/libc-epoll-blocking.rs:LL:CC + | +LL | unsafe { VAL = 1 }; + | ^^^^^^^ + = help: retags occur on all (re)borrows and as well as when references are copied or moved + = help: retags permit optimizations that insert speculative reads or writes + = help: therefore from the perspective of data races, a retag has the same implications as a read or write + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: BACKTRACE (of the first span): + = note: inside `test_epoll_race` at RUSTLIB/core/src/macros/mod.rs:LL:CC +note: inside `main` + --> tests/fail-dep/libc/libc-epoll-blocking.rs:LL:CC + | +LL | test_epoll_race(); + | ^^^^^^^^^^^^^^^^^ + = note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + From 1b622f46728a51b6582b02b84407e5f64262479b Mon Sep 17 00:00:00 2001 From: Frank Rehwinkel Date: Wed, 2 Oct 2024 07:57:36 -0400 Subject: [PATCH 501/683] epoll: remove unnecessary instructions A couple of instructions were left over from an earlier rebase it would seem. They don't impact the logic but the ready_list type is about to change in the next commit. Rather than modify one of these lines in the commit that changes ready_list, only to have these lines removed later on, remove them now. They don't impact the tests results. --- src/tools/miri/src/shims/unix/linux/epoll.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/tools/miri/src/shims/unix/linux/epoll.rs b/src/tools/miri/src/shims/unix/linux/epoll.rs index ff0709dd5ac..13c44334d58 100644 --- a/src/tools/miri/src/shims/unix/linux/epoll.rs +++ b/src/tools/miri/src/shims/unix/linux/epoll.rs @@ -207,9 +207,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { ); } - let mut epoll_instance = Epoll::default(); - epoll_instance.ready_list = Rc::new(RefCell::new(BTreeMap::new())); - let fd = this.machine.fds.insert_new(Epoll::default()); Ok(Scalar::from_i32(fd)) } From 86bb1373aa94aec8d9d4c8fb692cd352eca01d90 Mon Sep 17 00:00:00 2001 From: Frank Rehwinkel Date: Wed, 2 Oct 2024 08:04:25 -0400 Subject: [PATCH 502/683] epoll: add vector clock to the epoll ready_list This adds a VClock to the epoll implementation's ready_list and has this VClock synced from the thread that updates an event in the ready_list and then has the VClocks of any threads being made runnable again, out of the calls to epoll_wait, synced from it. --- src/tools/miri/src/shims/unix/linux/epoll.rs | 37 ++++++--- .../fail-dep/libc/libc-epoll-blocking.rs | 79 ------------------- .../fail-dep/libc/libc-epoll-blocking.stderr | 29 ------- .../pass-dep/libc/libc-epoll-blocking.rs | 41 +++++++++- 4 files changed, 67 insertions(+), 119 deletions(-) delete mode 100644 src/tools/miri/tests/fail-dep/libc/libc-epoll-blocking.rs delete mode 100644 src/tools/miri/tests/fail-dep/libc/libc-epoll-blocking.stderr diff --git a/src/tools/miri/src/shims/unix/linux/epoll.rs b/src/tools/miri/src/shims/unix/linux/epoll.rs index 13c44334d58..88fab8aa010 100644 --- a/src/tools/miri/src/shims/unix/linux/epoll.rs +++ b/src/tools/miri/src/shims/unix/linux/epoll.rs @@ -4,6 +4,7 @@ use std::io; use std::rc::{Rc, Weak}; use std::time::Duration; +use crate::concurrency::VClock; use crate::shims::unix::fd::{FdId, FileDescriptionRef, WeakFileDescriptionRef}; use crate::shims::unix::*; use crate::*; @@ -19,7 +20,7 @@ struct Epoll { /// and file descriptor value. // This is an Rc because EpollInterest need to hold a reference to update // it. - ready_list: Rc>>, + ready_list: Rc, /// A list of thread ids blocked on this epoll instance. thread_id: RefCell>, } @@ -63,7 +64,7 @@ pub struct EpollEventInterest { /// data: u64, /// Ready list of the epoll instance under which this EpollEventInterest is registered. - ready_list: Rc>>, + ready_list: Rc, /// The epoll file description that this EpollEventInterest is registered under. weak_epfd: WeakFileDescriptionRef, } @@ -88,6 +89,12 @@ pub struct EpollReadyEvents { pub epollerr: bool, } +#[derive(Debug, Default)] +struct ReadyList { + mapping: RefCell>, + clock: RefCell, +} + impl EpollReadyEvents { pub fn new() -> Self { EpollReadyEvents { @@ -127,7 +134,7 @@ impl EpollReadyEvents { } impl Epoll { - fn get_ready_list(&self) -> Rc>> { + fn get_ready_list(&self) -> Rc { Rc::clone(&self.ready_list) } } @@ -374,7 +381,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { drop(epoll_interest); // Remove related epoll_interest from ready list. - ready_list.borrow_mut().remove(&epoll_key); + ready_list.mapping.borrow_mut().remove(&epoll_key); // Remove dangling EpollEventInterest from its global table. // .unwrap() below should succeed because the file description id must have registered @@ -469,7 +476,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { .downcast::() .ok_or_else(|| err_unsup_format!("non-epoll FD passed to `epoll_wait`"))?; let binding = epoll_file_description.get_ready_list(); - ready_list_empty = binding.borrow_mut().is_empty(); + ready_list_empty = binding.mapping.borrow_mut().is_empty(); thread_ids = epoll_file_description.thread_id.borrow_mut(); } if timeout == 0 || !ready_list_empty { @@ -558,9 +565,15 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // holds a strong ref to epoll_interest. let epfd = epoll_interest.borrow().weak_epfd.upgrade().unwrap(); // FIXME: We can randomly pick a thread to unblock. - if let Some(thread_id) = - epfd.downcast::().unwrap().thread_id.borrow_mut().pop() - { + + let epoll = epfd.downcast::().unwrap(); + + // Synchronize running thread to the epoll ready list. + if let Some(clock) = &this.release_clock() { + epoll.ready_list.clock.borrow_mut().join(clock); + } + + if let Some(thread_id) = epoll.thread_id.borrow_mut().pop() { waiter.push(thread_id); }; } @@ -614,7 +627,7 @@ fn check_and_update_one_event_interest<'tcx>( // insert an epoll_return to the ready list. if flags != 0 { let epoll_key = (id, epoll_event_interest.fd_num); - let ready_list = &mut epoll_event_interest.ready_list.borrow_mut(); + let ready_list = &mut epoll_event_interest.ready_list.mapping.borrow_mut(); let event_instance = EpollEventInstance::new(flags, epoll_event_interest.data); // Triggers the notification by inserting it to the ready list. ready_list.insert(epoll_key, event_instance); @@ -641,7 +654,11 @@ fn blocking_epoll_callback<'tcx>( .ok_or_else(|| err_unsup_format!("non-epoll FD passed to `epoll_wait`"))?; let ready_list = epoll_file_description.get_ready_list(); - let mut ready_list = ready_list.borrow_mut(); + + // Synchronize waking thread from the epoll ready list. + ecx.acquire_clock(&ready_list.clock.borrow()); + + let mut ready_list = ready_list.mapping.borrow_mut(); let mut num_of_events: i32 = 0; let mut array_iter = ecx.project_array_fields(events)?; diff --git a/src/tools/miri/tests/fail-dep/libc/libc-epoll-blocking.rs b/src/tools/miri/tests/fail-dep/libc/libc-epoll-blocking.rs deleted file mode 100644 index fd9d1875daf..00000000000 --- a/src/tools/miri/tests/fail-dep/libc/libc-epoll-blocking.rs +++ /dev/null @@ -1,79 +0,0 @@ -//@only-target: linux -// test_epoll_race depends on a deterministic schedule. -//@compile-flags: -Zmiri-preemption-rate=0 - -use std::convert::TryInto; -use std::thread; - -fn main() { - test_epoll_race(); -} - -// Using `as` cast since `EPOLLET` wraps around -const EPOLL_IN_OUT_ET: u32 = (libc::EPOLLIN | libc::EPOLLOUT | libc::EPOLLET) as _; - -#[track_caller] -fn check_epoll_wait( - epfd: i32, - expected_notifications: &[(u32, u64)], - timeout: i32, -) { - let epoll_event = libc::epoll_event { events: 0, u64: 0 }; - let mut array: [libc::epoll_event; N] = [epoll_event; N]; - let maxsize = N; - let array_ptr = array.as_mut_ptr(); - let res = unsafe { libc::epoll_wait(epfd, array_ptr, maxsize.try_into().unwrap(), timeout) }; - if res < 0 { - panic!("epoll_wait failed: {}", std::io::Error::last_os_error()); - } - assert_eq!( - res, - expected_notifications.len().try_into().unwrap(), - "got wrong number of notifications" - ); - let slice = unsafe { std::slice::from_raw_parts(array_ptr, res.try_into().unwrap()) }; - for (return_event, expected_event) in slice.iter().zip(expected_notifications.iter()) { - let event = return_event.events; - let data = return_event.u64; - assert_eq!(event, expected_event.0, "got wrong events"); - assert_eq!(data, expected_event.1, "got wrong data"); - } -} - -// This test shows a data_race before epoll had vector clocks added. -fn test_epoll_race() { - // Create an epoll instance. - let epfd = unsafe { libc::epoll_create1(0) }; - assert_ne!(epfd, -1); - - // Create an eventfd instance. - let flags = libc::EFD_NONBLOCK | libc::EFD_CLOEXEC; - let fd = unsafe { libc::eventfd(0, flags) }; - - // Register eventfd with the epoll instance. - let mut ev = libc::epoll_event { events: EPOLL_IN_OUT_ET, u64: fd as u64 }; - let res = unsafe { libc::epoll_ctl(epfd, libc::EPOLL_CTL_ADD, fd, &mut ev) }; - assert_eq!(res, 0); - - static mut VAL: u8 = 0; - let thread1 = thread::spawn(move || { - // Write to the static mut variable. - unsafe { VAL = 1 }; - // Write to the eventfd instance. - let sized_8_data: [u8; 8] = 1_u64.to_ne_bytes(); - let res = unsafe { libc::write(fd, sized_8_data.as_ptr() as *const libc::c_void, 8) }; - // read returns number of bytes that have been read, which is always 8. - assert_eq!(res, 8); - }); - thread::yield_now(); - // epoll_wait for the event to happen. - let expected_event = u32::try_from(libc::EPOLLIN | libc::EPOLLOUT).unwrap(); - let expected_value = u64::try_from(fd).unwrap(); - check_epoll_wait::<8>(epfd, &[(expected_event, expected_value)], -1); - // Read from the static mut variable. - #[allow(static_mut_refs)] - unsafe { - assert_eq!(VAL, 1) //~ ERROR: Data race detected - }; - thread1.join().unwrap(); -} diff --git a/src/tools/miri/tests/fail-dep/libc/libc-epoll-blocking.stderr b/src/tools/miri/tests/fail-dep/libc/libc-epoll-blocking.stderr deleted file mode 100644 index 27974981cea..00000000000 --- a/src/tools/miri/tests/fail-dep/libc/libc-epoll-blocking.stderr +++ /dev/null @@ -1,29 +0,0 @@ -error: Undefined Behavior: Data race detected between (1) non-atomic write on thread `unnamed-ID` and (2) retag read of type `u8` on thread `main` at ALLOC. (2) just happened here - --> tests/fail-dep/libc/libc-epoll-blocking.rs:LL:CC - | -LL | assert_eq!(VAL, 1) - | ^^^^^^^^^^^^^^^^^^ Data race detected between (1) non-atomic write on thread `unnamed-ID` and (2) retag read of type `u8` on thread `main` at ALLOC. (2) just happened here - | -help: and (1) occurred earlier here - --> tests/fail-dep/libc/libc-epoll-blocking.rs:LL:CC - | -LL | unsafe { VAL = 1 }; - | ^^^^^^^ - = help: retags occur on all (re)borrows and as well as when references are copied or moved - = help: retags permit optimizations that insert speculative reads or writes - = help: therefore from the perspective of data races, a retag has the same implications as a read or write - = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior - = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: BACKTRACE (of the first span): - = note: inside `test_epoll_race` at RUSTLIB/core/src/macros/mod.rs:LL:CC -note: inside `main` - --> tests/fail-dep/libc/libc-epoll-blocking.rs:LL:CC - | -LL | test_epoll_race(); - | ^^^^^^^^^^^^^^^^^ - = note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info) - -note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace - -error: aborting due to 1 previous error - diff --git a/src/tools/miri/tests/pass-dep/libc/libc-epoll-blocking.rs b/src/tools/miri/tests/pass-dep/libc/libc-epoll-blocking.rs index eb38529ae57..d7675a40163 100644 --- a/src/tools/miri/tests/pass-dep/libc/libc-epoll-blocking.rs +++ b/src/tools/miri/tests/pass-dep/libc/libc-epoll-blocking.rs @@ -1,5 +1,5 @@ //@only-target: linux -// test_epoll_block_then_unblock depends on a deterministic schedule. +// test_epoll_block_then_unblock and test_epoll_race depend on a deterministic schedule. //@compile-flags: -Zmiri-preemption-rate=0 use std::convert::TryInto; @@ -12,6 +12,7 @@ fn main() { test_epoll_block_without_notification(); test_epoll_block_then_unblock(); test_notification_after_timeout(); + test_epoll_race(); } // Using `as` cast since `EPOLLET` wraps around @@ -137,3 +138,41 @@ fn test_notification_after_timeout() { let expected_value = fds[0] as u64; check_epoll_wait::<1>(epfd, &[(expected_event, expected_value)], 10); } + +// This test shows a data_race before epoll had vector clocks added. +fn test_epoll_race() { + // Create an epoll instance. + let epfd = unsafe { libc::epoll_create1(0) }; + assert_ne!(epfd, -1); + + // Create an eventfd instance. + let flags = libc::EFD_NONBLOCK | libc::EFD_CLOEXEC; + let fd = unsafe { libc::eventfd(0, flags) }; + + // Register eventfd with the epoll instance. + let mut ev = libc::epoll_event { events: EPOLL_IN_OUT_ET, u64: fd as u64 }; + let res = unsafe { libc::epoll_ctl(epfd, libc::EPOLL_CTL_ADD, fd, &mut ev) }; + assert_eq!(res, 0); + + static mut VAL: u8 = 0; + let thread1 = thread::spawn(move || { + // Write to the static mut variable. + unsafe { VAL = 1 }; + // Write to the eventfd instance. + let sized_8_data: [u8; 8] = 1_u64.to_ne_bytes(); + let res = unsafe { libc::write(fd, sized_8_data.as_ptr() as *const libc::c_void, 8) }; + // read returns number of bytes that have been read, which is always 8. + assert_eq!(res, 8); + }); + thread::yield_now(); + // epoll_wait for the event to happen. + let expected_event = u32::try_from(libc::EPOLLIN | libc::EPOLLOUT).unwrap(); + let expected_value = u64::try_from(fd).unwrap(); + check_epoll_wait::<8>(epfd, &[(expected_event, expected_value)], -1); + // Read from the static mut variable. + #[allow(static_mut_refs)] + unsafe { + assert_eq!(VAL, 1) + }; + thread1.join().unwrap(); +} From 81202c8b13c6ff64c14fd740757ba3e283adfec7 Mon Sep 17 00:00:00 2001 From: Frank Rehwinkel Date: Wed, 2 Oct 2024 08:13:11 -0400 Subject: [PATCH 503/683] epoll: remove extraneous clone of ready_list A simplification that doesn't impact the epoll implementation's logic. It is not necessary to clone the ready_list before reading its `is_empty` state. This avoids the clone step but more importantly avoids the invisible drop step of the clone. --- src/tools/miri/src/shims/unix/linux/epoll.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/tools/miri/src/shims/unix/linux/epoll.rs b/src/tools/miri/src/shims/unix/linux/epoll.rs index 88fab8aa010..c4bd38c47e5 100644 --- a/src/tools/miri/src/shims/unix/linux/epoll.rs +++ b/src/tools/miri/src/shims/unix/linux/epoll.rs @@ -475,8 +475,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let epoll_file_description = epfd .downcast::() .ok_or_else(|| err_unsup_format!("non-epoll FD passed to `epoll_wait`"))?; - let binding = epoll_file_description.get_ready_list(); - ready_list_empty = binding.mapping.borrow_mut().is_empty(); + ready_list_empty = epoll_file_description.ready_list.mapping.borrow().is_empty(); thread_ids = epoll_file_description.thread_id.borrow_mut(); } if timeout == 0 || !ready_list_empty { From 51537c686c16121aecb5a2b916a1c91a68d60770 Mon Sep 17 00:00:00 2001 From: Mads Marquart Date: Wed, 2 Oct 2024 20:08:48 +0200 Subject: [PATCH 504/683] Fix target_vendor in non-idf Xtensa ESP32 targets The Xtensa ESP32 targets are the following: - xtensa-esp32-none-elf - xtensa-esp32-espidf - xtensa-esp32s2-none-elf - xtensa-esp32s2-espidf - xtensa-esp32s3-none-elf - xtensa-esp32s3-espidf The ESP-IDF targets already set `target_vendor="espressif"`, however, the ESP32 is produced by Espressif regardless of whether using the IDF or not, so we should set the target vendor there as well. --- compiler/rustc_target/src/spec/targets/xtensa_esp32_none_elf.rs | 1 + .../rustc_target/src/spec/targets/xtensa_esp32s2_none_elf.rs | 1 + .../rustc_target/src/spec/targets/xtensa_esp32s3_none_elf.rs | 1 + 3 files changed, 3 insertions(+) diff --git a/compiler/rustc_target/src/spec/targets/xtensa_esp32_none_elf.rs b/compiler/rustc_target/src/spec/targets/xtensa_esp32_none_elf.rs index 51960dbec4a..254ae54db21 100644 --- a/compiler/rustc_target/src/spec/targets/xtensa_esp32_none_elf.rs +++ b/compiler/rustc_target/src/spec/targets/xtensa_esp32_none_elf.rs @@ -15,6 +15,7 @@ pub(crate) fn target() -> Target { }, options: TargetOptions { + vendor: "espressif".into(), cpu: "esp32".into(), linker: Some("xtensa-esp32-elf-gcc".into()), max_atomic_width: Some(32), diff --git a/compiler/rustc_target/src/spec/targets/xtensa_esp32s2_none_elf.rs b/compiler/rustc_target/src/spec/targets/xtensa_esp32s2_none_elf.rs index 21330615a87..34d8383a604 100644 --- a/compiler/rustc_target/src/spec/targets/xtensa_esp32s2_none_elf.rs +++ b/compiler/rustc_target/src/spec/targets/xtensa_esp32s2_none_elf.rs @@ -15,6 +15,7 @@ pub(crate) fn target() -> Target { }, options: TargetOptions { + vendor: "espressif".into(), cpu: "esp32-s2".into(), linker: Some("xtensa-esp32s2-elf-gcc".into()), max_atomic_width: Some(32), diff --git a/compiler/rustc_target/src/spec/targets/xtensa_esp32s3_none_elf.rs b/compiler/rustc_target/src/spec/targets/xtensa_esp32s3_none_elf.rs index fca47b4bdb1..023a67f2871 100644 --- a/compiler/rustc_target/src/spec/targets/xtensa_esp32s3_none_elf.rs +++ b/compiler/rustc_target/src/spec/targets/xtensa_esp32s3_none_elf.rs @@ -15,6 +15,7 @@ pub(crate) fn target() -> Target { }, options: TargetOptions { + vendor: "espressif".into(), cpu: "esp32-s3".into(), linker: Some("xtensa-esp32s3-elf-gcc".into()), max_atomic_width: Some(32), From 033fdda46c55ece534fdd5aabf0c1e70bb73b1ee Mon Sep 17 00:00:00 2001 From: Mads Marquart Date: Wed, 2 Oct 2024 20:30:51 +0200 Subject: [PATCH 505/683] Fix target_env in avr-unknown-gnu-atmega328 The target name itself contains GNU, we should set that in the environment as well. --- compiler/rustc_target/src/spec/base/avr_gnu.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/compiler/rustc_target/src/spec/base/avr_gnu.rs b/compiler/rustc_target/src/spec/base/avr_gnu.rs index fb97738618b..4f348af21ad 100644 --- a/compiler/rustc_target/src/spec/base/avr_gnu.rs +++ b/compiler/rustc_target/src/spec/base/avr_gnu.rs @@ -19,6 +19,8 @@ pub(crate) fn target(target_cpu: &'static str, mmcu: &'static str) -> Target { llvm_target: "avr-unknown-unknown".into(), pointer_width: 16, options: TargetOptions { + env: "gnu".into(), + c_int_width: "16".into(), cpu: target_cpu.into(), exe_suffix: ".elf".into(), From 0ae796440a476a4ffe982fbb7cc54a9097e7f161 Mon Sep 17 00:00:00 2001 From: Mads Marquart Date: Wed, 2 Oct 2024 20:54:09 +0200 Subject: [PATCH 506/683] Fix target_abi in SOLID targets The `armv7a-kmc-solid_asp3-eabi` and `armv7a-kmc-solid_asp3-eabihf` targets clearly have the ABI in their name, so it should also be exposed in Rust's `target_abi` cfg variable. --- .../rustc_target/src/spec/targets/armv7a_kmc_solid_asp3_eabi.rs | 1 + .../src/spec/targets/armv7a_kmc_solid_asp3_eabihf.rs | 1 + 2 files changed, 2 insertions(+) diff --git a/compiler/rustc_target/src/spec/targets/armv7a_kmc_solid_asp3_eabi.rs b/compiler/rustc_target/src/spec/targets/armv7a_kmc_solid_asp3_eabi.rs index 7e14c5efe71..e5ae1064d97 100644 --- a/compiler/rustc_target/src/spec/targets/armv7a_kmc_solid_asp3_eabi.rs +++ b/compiler/rustc_target/src/spec/targets/armv7a_kmc_solid_asp3_eabi.rs @@ -14,6 +14,7 @@ pub(crate) fn target() -> Target { data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), arch: "arm".into(), options: TargetOptions { + abi: "eabi".into(), linker: Some("arm-kmc-eabi-gcc".into()), features: "+v7,+soft-float,+thumb2,-neon".into(), relocation_model: RelocModel::Static, diff --git a/compiler/rustc_target/src/spec/targets/armv7a_kmc_solid_asp3_eabihf.rs b/compiler/rustc_target/src/spec/targets/armv7a_kmc_solid_asp3_eabihf.rs index 1958f4a7c30..0879fa24a1b 100644 --- a/compiler/rustc_target/src/spec/targets/armv7a_kmc_solid_asp3_eabihf.rs +++ b/compiler/rustc_target/src/spec/targets/armv7a_kmc_solid_asp3_eabihf.rs @@ -14,6 +14,7 @@ pub(crate) fn target() -> Target { data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), arch: "arm".into(), options: TargetOptions { + abi: "eabihf".into(), linker: Some("arm-kmc-eabi-gcc".into()), features: "+v7,+vfp3,-d32,+thumb2,-neon".into(), relocation_model: RelocModel::Static, From a0228686d16baea8880320905a484cfbfe36d8bc Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Fri, 27 Sep 2024 13:17:27 -0700 Subject: [PATCH 507/683] library: Stabilize `const_str_from_utf8_unchecked_mut` Const-stabilizes: - `str::from_utf8_unchecked_mut` --- library/core/src/lib.rs | 1 - library/core/src/str/converts.rs | 5 ++++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 01cadd78cc0..9edc1a8c1f5 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -152,7 +152,6 @@ #![feature(const_slice_from_ref)] #![feature(const_slice_split_at_mut)] #![feature(const_str_as_mut)] -#![feature(const_str_from_utf8_unchecked_mut)] #![feature(const_strict_overflow_ops)] #![feature(const_swap)] #![feature(const_try)] diff --git a/library/core/src/str/converts.rs b/library/core/src/str/converts.rs index d6459607221..e932b652e2d 100644 --- a/library/core/src/str/converts.rs +++ b/library/core/src/str/converts.rs @@ -195,7 +195,10 @@ pub const unsafe fn from_utf8_unchecked(v: &[u8]) -> &str { #[inline] #[must_use] #[stable(feature = "str_mut_extras", since = "1.20.0")] -#[rustc_const_unstable(feature = "const_str_from_utf8_unchecked_mut", issue = "91005")] +#[rustc_const_stable( + feature = "const_str_from_utf8_unchecked_mut", + since = "CURRENT_RUSTC_VERSION" +)] #[rustc_diagnostic_item = "str_from_utf8_unchecked_mut"] pub const unsafe fn from_utf8_unchecked_mut(v: &mut [u8]) -> &mut str { // SAFETY: the caller must guarantee that the bytes `v` From bcc78bdc29ed8183f60b3275ce8ac292bd771ab4 Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Fri, 27 Sep 2024 13:30:21 -0700 Subject: [PATCH 508/683] library: Stabilize `const_str_as_mut` Const-stabilizes: - `str::as_bytes_mut` - `str::as_mut_ptr` --- library/core/src/lib.rs | 1 - library/core/src/str/converts.rs | 1 + library/core/src/str/mod.rs | 6 ++++-- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 9edc1a8c1f5..ba30c4eab11 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -151,7 +151,6 @@ #![feature(const_slice_from_raw_parts_mut)] #![feature(const_slice_from_ref)] #![feature(const_slice_split_at_mut)] -#![feature(const_str_as_mut)] #![feature(const_strict_overflow_ops)] #![feature(const_swap)] #![feature(const_try)] diff --git a/library/core/src/str/converts.rs b/library/core/src/str/converts.rs index e932b652e2d..194db56fdaf 100644 --- a/library/core/src/str/converts.rs +++ b/library/core/src/str/converts.rs @@ -195,6 +195,7 @@ pub const unsafe fn from_utf8_unchecked(v: &[u8]) -> &str { #[inline] #[must_use] #[stable(feature = "str_mut_extras", since = "1.20.0")] +#[cfg_attr(bootstrap, rustc_allow_const_fn_unstable(const_mut_refs))] #[rustc_const_stable( feature = "const_str_from_utf8_unchecked_mut", since = "CURRENT_RUSTC_VERSION" diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs index 3d535214637..e93c52f2799 100644 --- a/library/core/src/str/mod.rs +++ b/library/core/src/str/mod.rs @@ -339,7 +339,8 @@ impl str { /// assert_eq!("🍔∈🌏", s); /// ``` #[stable(feature = "str_mut_extras", since = "1.20.0")] - #[rustc_const_unstable(feature = "const_str_as_mut", issue = "130086")] + #[cfg_attr(bootstrap, rustc_allow_const_fn_unstable(const_mut_refs))] + #[rustc_const_stable(feature = "const_str_as_mut", since = "CURRENT_RUSTC_VERSION")] #[must_use] #[inline(always)] pub const unsafe fn as_bytes_mut(&mut self) -> &mut [u8] { @@ -385,7 +386,8 @@ impl str { /// It is your responsibility to make sure that the string slice only gets /// modified in a way that it remains valid UTF-8. #[stable(feature = "str_as_mut_ptr", since = "1.36.0")] - #[rustc_const_unstable(feature = "const_str_as_mut", issue = "130086")] + #[cfg_attr(bootstrap, rustc_allow_const_fn_unstable(const_mut_refs))] + #[rustc_const_stable(feature = "const_str_as_mut", since = "CURRENT_RUSTC_VERSION")] #[rustc_never_returns_null_ptr] #[must_use] #[inline(always)] From 966405d1072bda18810a886418be1ed7da4dac15 Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Fri, 27 Sep 2024 13:34:06 -0700 Subject: [PATCH 509/683] library: Stabilize `const_ptr_as_ref` Const-stabilizes: - `NonNull::as_mut` --- library/core/src/lib.rs | 1 - library/core/src/ptr/non_null.rs | 3 ++- library/core/tests/lib.rs | 1 - 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index ba30c4eab11..bcc38720ad1 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -140,7 +140,6 @@ #![feature(const_option_ext)] #![feature(const_pin)] #![feature(const_pointer_is_aligned)] -#![feature(const_ptr_as_ref)] #![feature(const_ptr_is_null)] #![feature(const_ptr_sub_ptr)] #![feature(const_ptr_write)] diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs index daa40b3c9d2..f89db6a4470 100644 --- a/library/core/src/ptr/non_null.rs +++ b/library/core/src/ptr/non_null.rs @@ -394,7 +394,8 @@ impl NonNull { /// /// [the module documentation]: crate::ptr#safety #[stable(feature = "nonnull", since = "1.25.0")] - #[rustc_const_unstable(feature = "const_ptr_as_ref", issue = "91822")] + #[cfg_attr(bootstrap, rustc_allow_const_fn_unstable(const_mut_refs))] + #[rustc_const_stable(feature = "const_ptr_as_ref", since = "CURRENT_RUSTC_VERSION")] #[must_use] #[inline(always)] pub const unsafe fn as_mut<'a>(&mut self) -> &'a mut T { diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index 604c0d48743..ae055fd6a2b 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -30,7 +30,6 @@ #![feature(const_option_ext)] #![feature(const_pin)] #![feature(const_pointer_is_aligned)] -#![feature(const_ptr_as_ref)] #![feature(const_ptr_write)] #![feature(const_result)] #![feature(const_slice_from_ref)] From 75db6b29b5ad03f4ca4a8cfcc18f76feca32731a Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Fri, 27 Sep 2024 13:49:49 -0700 Subject: [PATCH 510/683] library: Stabilize `const_unsafecell_get_mut` Const-stabilizes: - `UnsafeCell::get_mut` --- library/core/src/cell.rs | 3 ++- library/core/src/lib.rs | 1 - 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs index c99f1aece4f..a5cfddd281d 100644 --- a/library/core/src/cell.rs +++ b/library/core/src/cell.rs @@ -2173,7 +2173,8 @@ impl UnsafeCell { /// ``` #[inline(always)] #[stable(feature = "unsafe_cell_get_mut", since = "1.50.0")] - #[rustc_const_unstable(feature = "const_unsafecell_get_mut", issue = "88836")] + #[cfg_attr(bootstrap, rustc_allow_const_fn_unstable(const_mut_refs))] + #[rustc_const_stable(feature = "const_unsafecell_get_mut", since = "CURRENT_RUSTC_VERSION")] pub const fn get_mut(&mut self) -> &mut T { &mut self.value } diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index bcc38720ad1..dc5716a5bb3 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -158,7 +158,6 @@ #![feature(const_typed_swap)] #![feature(const_ub_checks)] #![feature(const_unicode_case_lookup)] -#![feature(const_unsafecell_get_mut)] #![feature(coverage_attribute)] #![feature(do_not_recommend)] #![feature(duration_consts_float)] From ac53f1f242433b9cc5c440e85aa40468f9ca256a Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Fri, 27 Sep 2024 13:50:09 -0700 Subject: [PATCH 511/683] library: Stabilize `const_slice_first_last` Const-stabilizes: - `slice::first_mut` - `slice::split_first_mut` - `slice::last_mut` - `slice::split_last_mut` --- library/core/src/slice/mod.rs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index dd8fa1ae343..ae988deb28f 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -172,7 +172,8 @@ impl [T] { /// assert_eq!(None, y.first_mut()); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_slice_first_last", issue = "83570")] + #[cfg_attr(bootstrap, rustc_allow_const_fn_unstable(const_mut_refs))] + #[rustc_const_stable(feature = "const_slice_first_last", since = "CURRENT_RUSTC_VERSION")] #[inline] #[must_use] pub const fn first_mut(&mut self) -> Option<&mut T> { @@ -214,7 +215,8 @@ impl [T] { /// assert_eq!(x, &[3, 4, 5]); /// ``` #[stable(feature = "slice_splits", since = "1.5.0")] - #[rustc_const_unstable(feature = "const_slice_first_last", issue = "83570")] + #[cfg_attr(bootstrap, rustc_allow_const_fn_unstable(const_mut_refs))] + #[rustc_const_stable(feature = "const_slice_first_last", since = "CURRENT_RUSTC_VERSION")] #[inline] #[must_use] pub const fn split_first_mut(&mut self) -> Option<(&mut T, &mut [T])> { @@ -256,7 +258,8 @@ impl [T] { /// assert_eq!(x, &[4, 5, 3]); /// ``` #[stable(feature = "slice_splits", since = "1.5.0")] - #[rustc_const_unstable(feature = "const_slice_first_last", issue = "83570")] + #[cfg_attr(bootstrap, rustc_allow_const_fn_unstable(const_mut_refs))] + #[rustc_const_stable(feature = "const_slice_first_last", since = "CURRENT_RUSTC_VERSION")] #[inline] #[must_use] pub const fn split_last_mut(&mut self) -> Option<(&mut T, &mut [T])> { @@ -298,7 +301,8 @@ impl [T] { /// assert_eq!(None, y.last_mut()); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_slice_first_last", issue = "83570")] + #[cfg_attr(bootstrap, rustc_allow_const_fn_unstable(const_mut_refs))] + #[rustc_const_stable(feature = "const_slice_first_last", since = "CURRENT_RUSTC_VERSION")] #[inline] #[must_use] pub const fn last_mut(&mut self) -> Option<&mut T> { From f95bdf453e4f4c0a5ac244ff5878264b61ccaa8e Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 2 Oct 2024 21:52:44 -0400 Subject: [PATCH 512/683] Remove redundant in_trait from hir::TyKind::OpaqueDef --- compiler/rustc_ast_lowering/src/lib.rs | 1 - compiler/rustc_borrowck/src/diagnostics/region_name.rs | 2 +- compiler/rustc_hir/src/hir.rs | 4 ++-- compiler/rustc_hir/src/intravisit.rs | 2 +- compiler/rustc_hir_analysis/src/collect/predicates_of.rs | 2 +- compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs | 2 +- compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs | 4 ++-- compiler/rustc_middle/src/ty/diagnostics.rs | 2 +- compiler/rustc_passes/src/dead.rs | 2 +- .../infer/nice_region_error/static_impl_trait.rs | 2 +- .../rustc_trait_selection/src/error_reporting/infer/region.rs | 2 +- compiler/rustc_ty_utils/src/assoc.rs | 2 +- src/librustdoc/clean/mod.rs | 2 +- .../clippy/clippy_lints/src/extra_unused_type_parameters.rs | 2 +- src/tools/clippy/clippy_lints/src/lifetimes.rs | 2 +- src/tools/clippy/clippy_lints/src/manual_async_fn.rs | 2 +- src/tools/clippy/clippy_utils/src/hir_utils.rs | 3 +-- 17 files changed, 18 insertions(+), 20 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index c6cb7aa7dd5..8f8fe9e8580 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -1776,7 +1776,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { hir::TyKind::OpaqueDef( hir::ItemId { owner_id: hir::OwnerId { def_id: opaque_ty_def_id } }, generic_args, - in_trait, ) } diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs index 2f22e1532c1..d4598a1f582 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs @@ -832,7 +832,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> { fn get_future_inner_return_ty(&self, hir_ty: &'tcx hir::Ty<'tcx>) -> &'tcx hir::Ty<'tcx> { let hir = self.infcx.tcx.hir(); - let hir::TyKind::OpaqueDef(id, _, _) = hir_ty.kind else { + let hir::TyKind::OpaqueDef(id, _) = hir_ty.kind else { span_bug!( hir_ty.span, "lowered return type of async fn is not OpaqueDef: {:?}", diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 71216023ecc..ac23443fee2 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -2632,7 +2632,7 @@ impl<'hir> Ty<'hir> { } TyKind::Tup(tys) => tys.iter().any(Self::is_suggestable_infer_ty), TyKind::Ptr(mut_ty) | TyKind::Ref(_, mut_ty) => mut_ty.ty.is_suggestable_infer_ty(), - TyKind::OpaqueDef(_, generic_args, _) => are_suggestable_generic_args(generic_args), + TyKind::OpaqueDef(_, generic_args) => are_suggestable_generic_args(generic_args), TyKind::Path(QPath::TypeRelative(ty, segment)) => { ty.is_suggestable_infer_ty() || are_suggestable_generic_args(segment.args().args) } @@ -2856,7 +2856,7 @@ pub enum TyKind<'hir> { /// possibly parameters) that are actually bound on the `impl Trait`. /// /// The last parameter specifies whether this opaque appears in a trait definition. - OpaqueDef(ItemId, &'hir [GenericArg<'hir>], bool), + OpaqueDef(ItemId, &'hir [GenericArg<'hir>]), /// A trait object type `Bound1 + Bound2 + Bound3` /// where `Bound` is a trait or a lifetime. TraitObject( diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 4da32245785..d0a8aaa85bb 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -894,7 +894,7 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty<'v>) -> V::Resul TyKind::Path(ref qpath) => { try_visit!(visitor.visit_qpath(qpath, typ.hir_id, typ.span)); } - TyKind::OpaqueDef(item_id, lifetimes, _in_trait) => { + TyKind::OpaqueDef(item_id, lifetimes) => { try_visit!(visitor.visit_nested_item(item_id)); walk_list!(visitor, visit_generic_arg, lifetimes); } diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index 9e970462205..33f6623edfd 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -332,7 +332,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen // and the duplicated parameter, to ensure that they do not get out of sync. if let Node::Item(&Item { kind: ItemKind::OpaqueTy(..), .. }) = node { let opaque_ty_node = tcx.parent_hir_node(hir_id); - let Node::Ty(&hir::Ty { kind: TyKind::OpaqueDef(_, lifetimes, _), .. }) = opaque_ty_node + let Node::Ty(&hir::Ty { kind: TyKind::OpaqueDef(_, lifetimes), .. }) = opaque_ty_node else { bug!("unexpected {opaque_ty_node:?}") }; diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs index c9b949ad88d..30944b5e990 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -689,7 +689,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { }; self.with(scope, |this| this.visit_ty(mt.ty)); } - hir::TyKind::OpaqueDef(item_id, lifetimes, _in_trait) => { + hir::TyKind::OpaqueDef(item_id, lifetimes) => { // Resolve the lifetimes in the bounds to the lifetime defs in the generics. // `fn foo<'a>() -> impl MyTrait<'a> { ... }` desugars to // `type MyAnonTy<'b> = impl MyTrait<'b>;` 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 2186952720f..496f54e31d2 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -2087,11 +2087,11 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let opt_self_ty = maybe_qself.as_ref().map(|qself| self.lower_ty(qself)); self.lower_path(opt_self_ty, path, hir_ty.hir_id, false) } - &hir::TyKind::OpaqueDef(item_id, lifetimes, in_trait) => { + &hir::TyKind::OpaqueDef(item_id, lifetimes) => { let opaque_ty = tcx.hir().item(item_id); match opaque_ty.kind { - hir::ItemKind::OpaqueTy(&hir::OpaqueTy { .. }) => { + hir::ItemKind::OpaqueTy(&hir::OpaqueTy { in_trait, .. }) => { let local_def_id = item_id.owner_id.def_id; // If this is an RPITIT and we are using the new RPITIT lowering scheme, we // generate the def_id of an associated type for the trait and return as diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs index 992eb264163..d98e18c1b0c 100644 --- a/compiler/rustc_middle/src/ty/diagnostics.rs +++ b/compiler/rustc_middle/src/ty/diagnostics.rs @@ -510,7 +510,7 @@ impl<'v> hir::intravisit::Visitor<'v> for TraitObjectVisitor<'v> { ) => { self.0.push(ty); } - hir::TyKind::OpaqueDef(item_id, _, _) => { + hir::TyKind::OpaqueDef(item_id, _) => { self.0.push(ty); let item = self.1.item(item_id); hir::intravisit::walk_item(self, item); diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index aa329fc546e..100f3e80603 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -656,7 +656,7 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> { } fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) { - if let TyKind::OpaqueDef(item_id, _, _) = ty.kind { + if let TyKind::OpaqueDef(item_id, _) = ty.kind { let item = self.tcx.hir().item(item_id); intravisit::walk_item(self, item); } diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs index 4bde120cba9..31256bca55e 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs @@ -284,7 +284,7 @@ pub fn suggest_new_region_bound( } match fn_return.kind { // FIXME(precise_captures): Suggest adding to `use<...>` list instead. - TyKind::OpaqueDef(item_id, _, _) => { + TyKind::OpaqueDef(item_id, _) => { let item = tcx.hir().item(item_id); let ItemKind::OpaqueTy(opaque) = &item.kind else { return; diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs index 41fe8a2bf22..4c3a0112488 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs @@ -857,7 +857,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } fn visit_ty(&mut self, ty: &'hir hir::Ty<'hir>) { - let hir::TyKind::OpaqueDef(item_id, _, _) = ty.kind else { + let hir::TyKind::OpaqueDef(item_id, _) = ty.kind else { return hir::intravisit::walk_ty(self, ty); }; let opaque_ty = self.tcx.hir().item(item_id).expect_opaque_ty(); diff --git a/compiler/rustc_ty_utils/src/assoc.rs b/compiler/rustc_ty_utils/src/assoc.rs index 6726db8bb54..45fe199c335 100644 --- a/compiler/rustc_ty_utils/src/assoc.rs +++ b/compiler/rustc_ty_utils/src/assoc.rs @@ -323,7 +323,7 @@ fn associated_types_for_impl_traits_in_associated_fn( impl<'tcx> Visitor<'tcx> for RPITVisitor<'tcx> { fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) { - if let hir::TyKind::OpaqueDef(item_id, _, _) = ty.kind + if let hir::TyKind::OpaqueDef(item_id, _) = ty.kind && self.rpits.insert(item_id.owner_id.def_id) { let opaque_item = diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 3d845cf878f..b79458eaa78 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1828,7 +1828,7 @@ pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> T Array(Box::new(clean_ty(ty, cx)), length.into()) } TyKind::Tup(tys) => Tuple(tys.iter().map(|ty| clean_ty(ty, cx)).collect()), - TyKind::OpaqueDef(item_id, _, _) => { + TyKind::OpaqueDef(item_id, _) => { let item = cx.tcx.hir().item(item_id); if let hir::ItemKind::OpaqueTy(ty) = item.kind { ImplTrait(ty.bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect()) diff --git a/src/tools/clippy/clippy_lints/src/extra_unused_type_parameters.rs b/src/tools/clippy/clippy_lints/src/extra_unused_type_parameters.rs index bf9388b4a70..a7fb9535e79 100644 --- a/src/tools/clippy/clippy_lints/src/extra_unused_type_parameters.rs +++ b/src/tools/clippy/clippy_lints/src/extra_unused_type_parameters.rs @@ -199,7 +199,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for TypeWalker<'cx, 'tcx> { fn visit_ty(&mut self, t: &'tcx Ty<'tcx>) { if let Some((def_id, _)) = t.peel_refs().as_generic_param() { self.ty_params.remove(&def_id); - } else if let TyKind::OpaqueDef(id, _, _) = t.kind { + } else if let TyKind::OpaqueDef(id, _) = t.kind { // Explicitly walk OpaqueDef. Normally `walk_ty` would do the job, but it calls // `visit_nested_item`, which checks that `Self::NestedFilter::INTER` is set. We're // using `OnlyBodies`, so the check ends up failing and the type isn't fully walked. diff --git a/src/tools/clippy/clippy_lints/src/lifetimes.rs b/src/tools/clippy/clippy_lints/src/lifetimes.rs index 755afe959b3..d3cc5ea628c 100644 --- a/src/tools/clippy/clippy_lints/src/lifetimes.rs +++ b/src/tools/clippy/clippy_lints/src/lifetimes.rs @@ -523,7 +523,7 @@ impl<'a, 'tcx> Visitor<'tcx> for RefVisitor<'a, 'tcx> { fn visit_ty(&mut self, ty: &'tcx Ty<'_>) { match ty.kind { - TyKind::OpaqueDef(item, bounds, _) => { + TyKind::OpaqueDef(item, bounds) => { let map = self.cx.tcx.hir(); let item = map.item(item); let len = self.lts.len(); diff --git a/src/tools/clippy/clippy_lints/src/manual_async_fn.rs b/src/tools/clippy/clippy_lints/src/manual_async_fn.rs index fc3bba9e512..7097c85156c 100644 --- a/src/tools/clippy/clippy_lints/src/manual_async_fn.rs +++ b/src/tools/clippy/clippy_lints/src/manual_async_fn.rs @@ -105,7 +105,7 @@ fn future_trait_ref<'tcx>( cx: &LateContext<'tcx>, ty: &'tcx Ty<'tcx>, ) -> Option<(&'tcx TraitRef<'tcx>, Vec)> { - if let TyKind::OpaqueDef(item_id, bounds, false) = ty.kind + if let TyKind::OpaqueDef(item_id, bounds) = ty.kind && let item = cx.tcx.hir().item(item_id) && let ItemKind::OpaqueTy(opaque) = &item.kind && let Some(trait_ref) = opaque.bounds.iter().find_map(|bound| { diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs index 76900379ac7..b2d75125ccd 100644 --- a/src/tools/clippy/clippy_utils/src/hir_utils.rs +++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs @@ -1115,9 +1115,8 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { } }, TyKind::Path(ref qpath) => self.hash_qpath(qpath), - TyKind::OpaqueDef(_, arg_list, in_trait) => { + TyKind::OpaqueDef(_, arg_list) => { self.hash_generic_args(arg_list); - in_trait.hash(&mut self.s); }, TyKind::TraitObject(_, lifetime, _) => { self.hash_lifetime(lifetime); From cb7e3695e8e7ea04377f60977b65ba324273b63d Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 2 Oct 2024 22:04:18 -0400 Subject: [PATCH 513/683] Use named fields for OpaqueTyOrigin --- compiler/rustc_ast_lowering/src/lib.rs | 12 +++++++----- .../src/region_infer/opaque_types.rs | 4 ++-- compiler/rustc_hir/src/hir.rs | 10 ++++++++-- compiler/rustc_hir_analysis/src/check/check.rs | 16 ++++++++-------- .../src/check/compare_impl_item/refine.rs | 4 ++-- .../src/collect/generics_of.rs | 3 ++- .../src/collect/item_bounds.rs | 4 ++-- .../src/collect/resolve_bound_vars.rs | 4 ++-- .../rustc_hir_analysis/src/collect/type_of.rs | 3 ++- compiler/rustc_hir_typeck/src/_match.rs | 3 ++- .../rustc_lint/src/impl_trait_overcaptures.rs | 4 ++-- .../src/opaque_hidden_inferred_bound.rs | 6 +++--- compiler/rustc_metadata/src/rmeta/encoder.rs | 6 +++--- .../src/error_reporting/infer/region.rs | 2 +- .../error_reporting/traits/fulfillment_errors.rs | 2 +- compiler/rustc_ty_utils/src/assoc.rs | 3 ++- compiler/rustc_ty_utils/src/opaque_types.rs | 3 ++- src/librustdoc/visit_ast.rs | 2 +- src/tools/clippy/clippy_lints/src/len_zero.rs | 2 +- 19 files changed, 53 insertions(+), 40 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 8f8fe9e8580..c8aa8d701b9 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -1555,7 +1555,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { .map(|(ident, id, _)| Lifetime { id, ident }) .collect() } - hir::OpaqueTyOrigin::FnReturn(..) => { + hir::OpaqueTyOrigin::FnReturn { .. } => { if matches!( fn_kind.expect("expected RPITs to be lowered with a FnKind"), FnDeclKind::Impl | FnDeclKind::Trait @@ -1576,7 +1576,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { lifetime_collector::lifetimes_in_bounds(self.resolver, bounds) } } - hir::OpaqueTyOrigin::AsyncFn(..) => { + hir::OpaqueTyOrigin::AsyncFn { .. } => { unreachable!("should be using `lower_async_fn_ret_ty`") } } @@ -1867,7 +1867,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { | FnDeclKind::Inherent | FnDeclKind::Trait | FnDeclKind::Impl => ImplTraitContext::OpaqueTy { - origin: hir::OpaqueTyOrigin::FnReturn(self.local_def_id(fn_node_id)), + origin: hir::OpaqueTyOrigin::FnReturn { + parent: self.local_def_id(fn_node_id), + }, fn_kind: Some(kind), }, FnDeclKind::ExternFn => { @@ -1952,7 +1954,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let opaque_ty_ref = self.lower_opaque_inner( opaque_ty_node_id, - hir::OpaqueTyOrigin::AsyncFn(fn_def_id), + hir::OpaqueTyOrigin::AsyncFn { parent: fn_def_id }, matches!(fn_kind, FnDeclKind::Trait), captured_lifetimes, span, @@ -1963,7 +1965,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { coro, opaque_ty_span, ImplTraitContext::OpaqueTy { - origin: hir::OpaqueTyOrigin::FnReturn(fn_def_id), + origin: hir::OpaqueTyOrigin::FnReturn { parent: fn_def_id }, fn_kind: Some(fn_kind), }, ); diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs index 3cf21d4a36b..1f6aa598059 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs @@ -503,8 +503,8 @@ impl<'tcx> LazyOpaqueTyEnv<'tcx> { let &Self { tcx, def_id, .. } = self; let origin = tcx.opaque_type_origin(def_id); let parent = match origin { - hir::OpaqueTyOrigin::FnReturn(parent) - | hir::OpaqueTyOrigin::AsyncFn(parent) + hir::OpaqueTyOrigin::FnReturn { parent } + | hir::OpaqueTyOrigin::AsyncFn { parent } | hir::OpaqueTyOrigin::TyAlias { parent, .. } => parent, }; let param_env = tcx.param_env(parent); diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index ac23443fee2..68195c46f5c 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -2806,9 +2806,15 @@ pub struct PreciseCapturingNonLifetimeArg { #[derive(Copy, Clone, PartialEq, Eq, Debug, HashStable_Generic)] pub enum OpaqueTyOrigin { /// `-> impl Trait` - FnReturn(LocalDefId), + FnReturn { + /// The defining function. + parent: LocalDefId, + }, /// `async fn` - AsyncFn(LocalDefId), + AsyncFn { + /// The defining function. + parent: LocalDefId, + }, /// type aliases: `type Foo = impl Trait;` TyAlias { /// The type alias or associated type parent of the TAIT/ATPIT diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index d725772a5b3..feba484229b 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -336,9 +336,9 @@ fn check_opaque_meets_bounds<'tcx>( origin: &hir::OpaqueTyOrigin, ) -> Result<(), ErrorGuaranteed> { let defining_use_anchor = match *origin { - hir::OpaqueTyOrigin::FnReturn(did) - | hir::OpaqueTyOrigin::AsyncFn(did) - | hir::OpaqueTyOrigin::TyAlias { parent: did, .. } => did, + hir::OpaqueTyOrigin::FnReturn { parent } + | hir::OpaqueTyOrigin::AsyncFn { parent } + | hir::OpaqueTyOrigin::TyAlias { parent, .. } => parent, }; let param_env = tcx.param_env(defining_use_anchor); @@ -346,8 +346,8 @@ fn check_opaque_meets_bounds<'tcx>( let ocx = ObligationCtxt::new_with_diagnostics(&infcx); let args = match *origin { - hir::OpaqueTyOrigin::FnReturn(parent) - | hir::OpaqueTyOrigin::AsyncFn(parent) + hir::OpaqueTyOrigin::FnReturn { parent } + | hir::OpaqueTyOrigin::AsyncFn { parent } | hir::OpaqueTyOrigin::TyAlias { parent, .. } => GenericArgs::identity_for_item( tcx, parent, ) @@ -409,7 +409,7 @@ fn check_opaque_meets_bounds<'tcx>( let outlives_env = OutlivesEnvironment::with_bounds(param_env, implied_bounds); ocx.resolve_regions_and_report_errors(defining_use_anchor, &outlives_env)?; - if let hir::OpaqueTyOrigin::FnReturn(..) | hir::OpaqueTyOrigin::AsyncFn(..) = origin { + if let hir::OpaqueTyOrigin::FnReturn { .. } | hir::OpaqueTyOrigin::AsyncFn { .. } = origin { // HACK: this should also fall through to the hidden type check below, but the original // implementation had a bug where equivalent lifetimes are not identical. This caused us // to reject existing stable code that is otherwise completely fine. The real fix is to @@ -736,8 +736,8 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) { check_opaque_precise_captures(tcx, def_id); let origin = tcx.opaque_type_origin(def_id); - if let hir::OpaqueTyOrigin::FnReturn(fn_def_id) - | hir::OpaqueTyOrigin::AsyncFn(fn_def_id) = origin + if let hir::OpaqueTyOrigin::FnReturn { parent: fn_def_id } + | hir::OpaqueTyOrigin::AsyncFn { parent: fn_def_id } = origin && let hir::Node::TraitItem(trait_item) = tcx.hir_node_by_def_id(fn_def_id) && let (_, hir::TraitFn::Required(..)) = trait_item.expect_fn() { diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs index e07b587508a..3375fc303f1 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs @@ -94,8 +94,8 @@ pub(super) fn check_refining_return_position_impl_trait_in_trait<'tcx>( if !tcx.hir().get_if_local(impl_opaque.def_id).is_some_and(|node| { matches!( node.expect_item().expect_opaque_ty().origin, - hir::OpaqueTyOrigin::AsyncFn(def_id) | hir::OpaqueTyOrigin::FnReturn(def_id) - if def_id == impl_m.def_id.expect_local() + hir::OpaqueTyOrigin::AsyncFn { parent } | hir::OpaqueTyOrigin::FnReturn { parent } + if parent == impl_m.def_id.expect_local() ) }) { report_mismatched_rpitit_signature( diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs index 0a8eef2006d..73e98c67cdc 100644 --- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs @@ -210,7 +210,8 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { Node::Item(item) => match item.kind { ItemKind::OpaqueTy(&hir::OpaqueTy { origin: - hir::OpaqueTyOrigin::FnReturn(fn_def_id) | hir::OpaqueTyOrigin::AsyncFn(fn_def_id), + hir::OpaqueTyOrigin::FnReturn { parent: fn_def_id } + | hir::OpaqueTyOrigin::AsyncFn { parent: fn_def_id }, in_trait, .. }) => { diff --git a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs index f44b4728ad5..07a8c3a9e84 100644 --- a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs +++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs @@ -388,8 +388,8 @@ pub(super) fn explicit_item_bounds_with_filter( span, .. }) => { - let (hir::OpaqueTyOrigin::FnReturn(fn_def_id) - | hir::OpaqueTyOrigin::AsyncFn(fn_def_id)) = *origin + let (hir::OpaqueTyOrigin::FnReturn { parent: fn_def_id } + | hir::OpaqueTyOrigin::AsyncFn { parent: fn_def_id }) = *origin else { span_bug!(*span, "RPITIT cannot be a TAIT, but got origin {origin:?}"); }; diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs index 30944b5e990..60788641da0 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -515,8 +515,8 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { } hir::ItemKind::OpaqueTy(&hir::OpaqueTy { origin: - hir::OpaqueTyOrigin::FnReturn(parent) - | hir::OpaqueTyOrigin::AsyncFn(parent) + hir::OpaqueTyOrigin::FnReturn { parent } + | hir::OpaqueTyOrigin::AsyncFn { parent } | hir::OpaqueTyOrigin::TyAlias { parent, .. }, generics, .. diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs index 48b5e87cbd0..313d7dd6265 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs @@ -618,7 +618,8 @@ pub(super) fn type_of_opaque( // Opaque types desugared from `impl Trait`. ItemKind::OpaqueTy(&OpaqueTy { origin: - hir::OpaqueTyOrigin::FnReturn(owner) | hir::OpaqueTyOrigin::AsyncFn(owner), + hir::OpaqueTyOrigin::FnReturn { parent: owner } + | hir::OpaqueTyOrigin::AsyncFn { parent: owner }, in_trait, .. }) => { diff --git a/compiler/rustc_hir_typeck/src/_match.rs b/compiler/rustc_hir_typeck/src/_match.rs index bf8ed017cf7..204138ffd44 100644 --- a/compiler/rustc_hir_typeck/src/_match.rs +++ b/compiler/rustc_hir_typeck/src/_match.rs @@ -602,7 +602,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .map(|(k, _)| (k.def_id, k.args))?, _ => return None, }; - let hir::OpaqueTyOrigin::FnReturn(parent_def_id) = self.tcx.opaque_type_origin(def_id) + let hir::OpaqueTyOrigin::FnReturn { parent: parent_def_id } = + self.tcx.opaque_type_origin(def_id) else { return None; }; diff --git a/compiler/rustc_lint/src/impl_trait_overcaptures.rs b/compiler/rustc_lint/src/impl_trait_overcaptures.rs index a073d16f634..c13f4c7746d 100644 --- a/compiler/rustc_lint/src/impl_trait_overcaptures.rs +++ b/compiler/rustc_lint/src/impl_trait_overcaptures.rs @@ -259,8 +259,8 @@ where // If it's owned by this function && let opaque = self.tcx.hir_node_by_def_id(opaque_def_id).expect_item().expect_opaque_ty() - && let hir::OpaqueTyOrigin::FnReturn(parent_def_id) = opaque.origin - && parent_def_id == self.parent_def_id + && let hir::OpaqueTyOrigin::FnReturn { parent } = opaque.origin + && parent == self.parent_def_id { let opaque_span = self.tcx.def_span(opaque_def_id); let new_capture_rules = diff --git a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs index 83652bbf546..87fa38a282e 100644 --- a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs +++ b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs @@ -77,7 +77,7 @@ impl<'tcx> LateLintPass<'tcx> for OpaqueHiddenInferredBound { // That's because although we may have an opaque type on the function, // it won't have a hidden type, so proving predicates about it is // not really meaningful. - if let hir::OpaqueTyOrigin::FnReturn(method_def_id) = opaque.origin + if let hir::OpaqueTyOrigin::FnReturn { parent: method_def_id } = opaque.origin && let hir::Node::TraitItem(trait_item) = cx.tcx.hir_node_by_def_id(method_def_id) && !trait_item.defaultness.has_value() { @@ -103,7 +103,7 @@ impl<'tcx> LateLintPass<'tcx> for OpaqueHiddenInferredBound { && cx.tcx.parent(opaque_ty.def_id) == def_id && matches!( opaque.origin, - hir::OpaqueTyOrigin::FnReturn(_) | hir::OpaqueTyOrigin::AsyncFn(_) + hir::OpaqueTyOrigin::FnReturn { .. } | hir::OpaqueTyOrigin::AsyncFn { .. } ) { return; @@ -114,7 +114,7 @@ impl<'tcx> LateLintPass<'tcx> for OpaqueHiddenInferredBound { // return type is well-formed in traits even when `Self` isn't sized. if let ty::Param(param_ty) = *proj_term.kind() && param_ty.name == kw::SelfUpper - && matches!(opaque.origin, hir::OpaqueTyOrigin::AsyncFn(_)) + && matches!(opaque.origin, hir::OpaqueTyOrigin::AsyncFn { .. }) && opaque.in_trait { return; diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 5f756672b04..61eb7260384 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1186,9 +1186,9 @@ fn should_encode_type(tcx: TyCtxt<'_>, def_id: LocalDefId, def_kind: DefKind) -> DefKind::OpaqueTy => { let origin = tcx.opaque_type_origin(def_id); - if let hir::OpaqueTyOrigin::FnReturn(fn_def_id) - | hir::OpaqueTyOrigin::AsyncFn(fn_def_id) = origin - && let hir::Node::TraitItem(trait_item) = tcx.hir_node_by_def_id(fn_def_id) + if let hir::OpaqueTyOrigin::FnReturn { parent } + | hir::OpaqueTyOrigin::AsyncFn { parent } = origin + && let hir::Node::TraitItem(trait_item) = tcx.hir_node_by_def_id(parent) && let (_, hir::TraitFn::Required(..)) = trait_item.expect_fn() { false diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs index 4c3a0112488..673756076b1 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs @@ -1271,7 +1271,7 @@ fn suggest_precise_capturing<'tcx>( let hir::OpaqueTy { bounds, origin, .. } = tcx.hir_node_by_def_id(opaque_def_id).expect_item().expect_opaque_ty(); - let hir::OpaqueTyOrigin::FnReturn(fn_def_id) = *origin else { + let hir::OpaqueTyOrigin::FnReturn { parent: fn_def_id } = *origin else { return; }; 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 34a0f182ab4..43762b1004b 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 @@ -2580,7 +2580,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { def_id: DefId, ) -> ErrorGuaranteed { let name = match self.tcx.opaque_type_origin(def_id.expect_local()) { - hir::OpaqueTyOrigin::FnReturn(_) | hir::OpaqueTyOrigin::AsyncFn(_) => { + hir::OpaqueTyOrigin::FnReturn { .. } | hir::OpaqueTyOrigin::AsyncFn { .. } => { "opaque type".to_string() } hir::OpaqueTyOrigin::TyAlias { .. } => { diff --git a/compiler/rustc_ty_utils/src/assoc.rs b/compiler/rustc_ty_utils/src/assoc.rs index 45fe199c335..f8cfeb500a5 100644 --- a/compiler/rustc_ty_utils/src/assoc.rs +++ b/compiler/rustc_ty_utils/src/assoc.rs @@ -379,7 +379,8 @@ fn associated_type_for_impl_trait_in_trait( tcx: TyCtxt<'_>, opaque_ty_def_id: LocalDefId, ) -> LocalDefId { - let (hir::OpaqueTyOrigin::FnReturn(fn_def_id) | hir::OpaqueTyOrigin::AsyncFn(fn_def_id)) = + let (hir::OpaqueTyOrigin::FnReturn { parent: fn_def_id } + | hir::OpaqueTyOrigin::AsyncFn { parent: fn_def_id }) = tcx.opaque_type_origin(opaque_ty_def_id) else { bug!("expected opaque for {opaque_ty_def_id:?}"); diff --git a/compiler/rustc_ty_utils/src/opaque_types.rs b/compiler/rustc_ty_utils/src/opaque_types.rs index bac0d020d72..7c4b4887b2d 100644 --- a/compiler/rustc_ty_utils/src/opaque_types.rs +++ b/compiler/rustc_ty_utils/src/opaque_types.rs @@ -141,7 +141,8 @@ impl<'tcx> OpaqueTypeCollector<'tcx> { let origin = self.tcx.opaque_type_origin(alias_ty.def_id.expect_local()); trace!(?origin); match origin { - rustc_hir::OpaqueTyOrigin::FnReturn(_) | rustc_hir::OpaqueTyOrigin::AsyncFn(_) => {} + rustc_hir::OpaqueTyOrigin::FnReturn { .. } + | rustc_hir::OpaqueTyOrigin::AsyncFn { .. } => {} rustc_hir::OpaqueTyOrigin::TyAlias { in_assoc_ty, .. } => { if !in_assoc_ty && !self.check_tait_defining_scope(alias_ty.def_id.expect_local()) { return; diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index 2cf703f57c0..c44e5ecaba8 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -515,7 +515,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { self.add_to_current_mod(item, renamed, import_id); } hir::ItemKind::OpaqueTy(hir::OpaqueTy { - origin: hir::OpaqueTyOrigin::AsyncFn(_) | hir::OpaqueTyOrigin::FnReturn(_), + origin: hir::OpaqueTyOrigin::AsyncFn { .. } | hir::OpaqueTyOrigin::FnReturn { .. }, .. }) => { // return-position impl traits are never nameable, and should never be documented. diff --git a/src/tools/clippy/clippy_lints/src/len_zero.rs b/src/tools/clippy/clippy_lints/src/len_zero.rs index 8bc2a56af99..0cbcdbeb90a 100644 --- a/src/tools/clippy/clippy_lints/src/len_zero.rs +++ b/src/tools/clippy/clippy_lints/src/len_zero.rs @@ -313,7 +313,7 @@ fn extract_future_output<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<& kind: ItemKind::OpaqueTy(opaque), .. } = item - && let OpaqueTyOrigin::AsyncFn(_) = opaque.origin + && let OpaqueTyOrigin::AsyncFn { .. } = opaque.origin && let [GenericBound::Trait(trait_ref, _)] = &opaque.bounds && let Some(segment) = trait_ref.trait_ref.path.segments.last() && let Some(generic_args) = segment.args From 7cd466a03606313dad4fa22fd5cf444204138fc8 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 2 Oct 2024 22:21:37 -0400 Subject: [PATCH 514/683] Move in_trait into OpaqueTyOrigin --- compiler/rustc_ast_lowering/src/item.rs | 2 - compiler/rustc_ast_lowering/src/lib.rs | 80 +++++++++---------- .../src/region_infer/opaque_types.rs | 4 +- compiler/rustc_hir/src/hir.rs | 14 +++- .../rustc_hir_analysis/src/check/check.rs | 12 +-- .../src/check/compare_impl_item/refine.rs | 2 +- .../src/collect/generics_of.rs | 7 +- .../src/collect/item_bounds.rs | 70 +++++++++------- .../src/collect/resolve_bound_vars.rs | 4 +- .../rustc_hir_analysis/src/collect/type_of.rs | 9 ++- .../src/hir_ty_lowering/mod.rs | 34 ++++++-- compiler/rustc_hir_typeck/src/_match.rs | 2 +- .../rustc_lint/src/impl_trait_overcaptures.rs | 2 +- .../src/opaque_hidden_inferred_bound.rs | 8 +- compiler/rustc_metadata/src/rmeta/encoder.rs | 4 +- compiler/rustc_middle/src/hir/map/mod.rs | 8 +- compiler/rustc_privacy/src/lib.rs | 3 +- .../src/error_reporting/infer/region.rs | 2 +- compiler/rustc_ty_utils/src/assoc.rs | 4 +- 19 files changed, 146 insertions(+), 125 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 7bb3b2fa290..1273b50dff8 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -286,7 +286,6 @@ impl<'hir> LoweringContext<'_, 'hir> { parent: this.local_def_id(id), in_assoc_ty: false, }, - fn_kind: None, }), }, ); @@ -983,7 +982,6 @@ impl<'hir> LoweringContext<'_, 'hir> { parent: this.local_def_id(i.id), in_assoc_ty: true, }, - fn_kind: None, }); hir::ImplItemKind::Type(ty) } diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index c8aa8d701b9..9275308cccb 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -288,12 +288,7 @@ enum ImplTraitContext { /// Example: `fn foo() -> impl Debug`, where `impl Debug` is conceptually /// equivalent to a new opaque type like `type T = impl Debug; fn foo() -> T`. /// - OpaqueTy { - origin: hir::OpaqueTyOrigin, - /// Only used to change the lifetime capture rules, since - /// RPITIT captures all in scope, RPIT does not. - fn_kind: Option, - }, + OpaqueTy { origin: hir::OpaqueTyOrigin }, /// `impl Trait` is unstably accepted in this position. FeatureGated(ImplTraitPosition, Symbol), /// `impl Trait` is not accepted in this position. @@ -1404,14 +1399,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { TyKind::ImplTrait(def_node_id, bounds) => { let span = t.span; match itctx { - ImplTraitContext::OpaqueTy { origin, fn_kind } => self.lower_opaque_impl_trait( - span, - origin, - *def_node_id, - bounds, - fn_kind, - itctx, - ), + ImplTraitContext::OpaqueTy { origin } => { + self.lower_opaque_impl_trait(span, origin, *def_node_id, bounds, itctx) + } ImplTraitContext::Universal => { if let Some(span) = bounds.iter().find_map(|bound| match *bound { ast::GenericBound::Use(_, span) => Some(span), @@ -1513,7 +1503,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { origin: hir::OpaqueTyOrigin, opaque_ty_node_id: NodeId, bounds: &GenericBounds, - fn_kind: Option, itctx: ImplTraitContext, ) -> hir::TyKind<'hir> { // Make sure we know that some funky desugaring has been going on here. @@ -1555,11 +1544,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { .map(|(ident, id, _)| Lifetime { id, ident }) .collect() } - hir::OpaqueTyOrigin::FnReturn { .. } => { - if matches!( - fn_kind.expect("expected RPITs to be lowered with a FnKind"), - FnDeclKind::Impl | FnDeclKind::Trait - ) || self.tcx.features().lifetime_capture_rules_2024 + hir::OpaqueTyOrigin::FnReturn { in_trait_or_impl, .. } => { + if in_trait_or_impl.is_some() + || self.tcx.features().lifetime_capture_rules_2024 || span.at_least_rust_2024() { // return-position impl trait in trait was decided to capture all @@ -1583,9 +1570,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { }; debug!(?captured_lifetimes_to_duplicate); - match fn_kind { - // Deny `use<>` on RPITIT in trait/trait-impl for now. - Some(FnDeclKind::Trait | FnDeclKind::Impl) => { + // Feature gate for RPITIT + use<..> + match origin { + rustc_hir::OpaqueTyOrigin::FnReturn { in_trait_or_impl: Some(_), .. } => { if let Some(span) = bounds.iter().find_map(|bound| match *bound { ast::GenericBound::Use(_, span) => Some(span), _ => None, @@ -1593,20 +1580,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { self.tcx.dcx().emit_err(errors::NoPreciseCapturesOnRpitit { span }); } } - None - | Some( - FnDeclKind::Fn - | FnDeclKind::Inherent - | FnDeclKind::ExternFn - | FnDeclKind::Closure - | FnDeclKind::Pointer, - ) => {} + _ => {} } self.lower_opaque_inner( opaque_ty_node_id, origin, - matches!(fn_kind, Some(FnDeclKind::Trait)), captured_lifetimes_to_duplicate, span, opaque_ty_span, @@ -1618,7 +1597,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { &mut self, opaque_ty_node_id: NodeId, origin: hir::OpaqueTyOrigin, - in_trait: bool, captured_lifetimes_to_duplicate: FxIndexSet, span: Span, opaque_ty_span: Span, @@ -1747,7 +1725,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { bounds, origin, lifetime_mapping, - in_trait, }; // Generate an `type Foo = impl Trait;` declaration. @@ -1863,14 +1840,23 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { None => match &decl.output { FnRetTy::Ty(ty) => { let itctx = match kind { - FnDeclKind::Fn - | FnDeclKind::Inherent - | FnDeclKind::Trait - | FnDeclKind::Impl => ImplTraitContext::OpaqueTy { + FnDeclKind::Fn | FnDeclKind::Inherent => ImplTraitContext::OpaqueTy { origin: hir::OpaqueTyOrigin::FnReturn { parent: self.local_def_id(fn_node_id), + in_trait_or_impl: None, + }, + }, + FnDeclKind::Trait => ImplTraitContext::OpaqueTy { + origin: hir::OpaqueTyOrigin::FnReturn { + parent: self.local_def_id(fn_node_id), + in_trait_or_impl: Some(hir::RpitContext::Trait), + }, + }, + FnDeclKind::Impl => ImplTraitContext::OpaqueTy { + origin: hir::OpaqueTyOrigin::FnReturn { + parent: self.local_def_id(fn_node_id), + in_trait_or_impl: Some(hir::RpitContext::TraitImpl), }, - fn_kind: Some(kind), }, FnDeclKind::ExternFn => { ImplTraitContext::Disallowed(ImplTraitPosition::ExternFnReturn) @@ -1952,10 +1938,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { .map(|(ident, id, _)| Lifetime { id, ident }) .collect(); + let in_trait_or_impl = match fn_kind { + FnDeclKind::Trait => Some(hir::RpitContext::Trait), + FnDeclKind::Impl => Some(hir::RpitContext::TraitImpl), + FnDeclKind::Fn | FnDeclKind::Inherent => None, + FnDeclKind::ExternFn | FnDeclKind::Closure | FnDeclKind::Pointer => unreachable!(), + }; + let opaque_ty_ref = self.lower_opaque_inner( opaque_ty_node_id, - hir::OpaqueTyOrigin::AsyncFn { parent: fn_def_id }, - matches!(fn_kind, FnDeclKind::Trait), + hir::OpaqueTyOrigin::AsyncFn { parent: fn_def_id, in_trait_or_impl }, captured_lifetimes, span, opaque_ty_span, @@ -1965,8 +1957,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { coro, opaque_ty_span, ImplTraitContext::OpaqueTy { - origin: hir::OpaqueTyOrigin::FnReturn { parent: fn_def_id }, - fn_kind: Some(fn_kind), + origin: hir::OpaqueTyOrigin::FnReturn { + parent: fn_def_id, + in_trait_or_impl, + }, }, ); arena_vec![this; bound] diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs index 1f6aa598059..2f90e916281 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs @@ -503,8 +503,8 @@ impl<'tcx> LazyOpaqueTyEnv<'tcx> { let &Self { tcx, def_id, .. } = self; let origin = tcx.opaque_type_origin(def_id); let parent = match origin { - hir::OpaqueTyOrigin::FnReturn { parent } - | hir::OpaqueTyOrigin::AsyncFn { parent } + hir::OpaqueTyOrigin::FnReturn { parent, .. } + | hir::OpaqueTyOrigin::AsyncFn { parent, .. } | hir::OpaqueTyOrigin::TyAlias { parent, .. } => parent, }; let param_env = tcx.param_env(parent); diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 68195c46f5c..f58ec22aea9 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -2762,10 +2762,6 @@ pub struct OpaqueTy<'hir> { /// This mapping associated a captured lifetime (first parameter) with the new /// early-bound lifetime that was generated for the opaque. pub lifetime_mapping: &'hir [(&'hir Lifetime, LocalDefId)], - /// Whether the opaque is a return-position impl trait (or async future) - /// originating from a trait method. This makes it so that the opaque is - /// lowered as an associated type. - pub in_trait: bool, } #[derive(Debug, Clone, Copy, HashStable_Generic)] @@ -2802,6 +2798,12 @@ pub struct PreciseCapturingNonLifetimeArg { pub res: Res, } +#[derive(Copy, Clone, PartialEq, Eq, Debug, HashStable_Generic)] +pub enum RpitContext { + Trait, + TraitImpl, +} + /// From whence the opaque type came. #[derive(Copy, Clone, PartialEq, Eq, Debug, HashStable_Generic)] pub enum OpaqueTyOrigin { @@ -2809,11 +2811,15 @@ pub enum OpaqueTyOrigin { FnReturn { /// The defining function. parent: LocalDefId, + // Whether this is an RPITIT (return position impl trait in trait) + in_trait_or_impl: Option, }, /// `async fn` AsyncFn { /// The defining function. parent: LocalDefId, + // Whether this is an AFIT (async fn in trait) + in_trait_or_impl: Option, }, /// type aliases: `type Foo = impl Trait;` TyAlias { diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index feba484229b..312212232bc 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -336,8 +336,8 @@ fn check_opaque_meets_bounds<'tcx>( origin: &hir::OpaqueTyOrigin, ) -> Result<(), ErrorGuaranteed> { let defining_use_anchor = match *origin { - hir::OpaqueTyOrigin::FnReturn { parent } - | hir::OpaqueTyOrigin::AsyncFn { parent } + hir::OpaqueTyOrigin::FnReturn { parent, .. } + | hir::OpaqueTyOrigin::AsyncFn { parent, .. } | hir::OpaqueTyOrigin::TyAlias { parent, .. } => parent, }; let param_env = tcx.param_env(defining_use_anchor); @@ -346,8 +346,8 @@ fn check_opaque_meets_bounds<'tcx>( let ocx = ObligationCtxt::new_with_diagnostics(&infcx); let args = match *origin { - hir::OpaqueTyOrigin::FnReturn { parent } - | hir::OpaqueTyOrigin::AsyncFn { parent } + hir::OpaqueTyOrigin::FnReturn { parent, .. } + | hir::OpaqueTyOrigin::AsyncFn { parent, .. } | hir::OpaqueTyOrigin::TyAlias { parent, .. } => GenericArgs::identity_for_item( tcx, parent, ) @@ -736,8 +736,8 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) { check_opaque_precise_captures(tcx, def_id); let origin = tcx.opaque_type_origin(def_id); - if let hir::OpaqueTyOrigin::FnReturn { parent: fn_def_id } - | hir::OpaqueTyOrigin::AsyncFn { parent: fn_def_id } = origin + if let hir::OpaqueTyOrigin::FnReturn { parent: fn_def_id, .. } + | hir::OpaqueTyOrigin::AsyncFn { parent: fn_def_id, .. } = origin && let hir::Node::TraitItem(trait_item) = tcx.hir_node_by_def_id(fn_def_id) && let (_, hir::TraitFn::Required(..)) = trait_item.expect_fn() { diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs index 3375fc303f1..35c2b7e7ce2 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs @@ -94,7 +94,7 @@ pub(super) fn check_refining_return_position_impl_trait_in_trait<'tcx>( if !tcx.hir().get_if_local(impl_opaque.def_id).is_some_and(|node| { matches!( node.expect_item().expect_opaque_ty().origin, - hir::OpaqueTyOrigin::AsyncFn { parent } | hir::OpaqueTyOrigin::FnReturn { parent } + hir::OpaqueTyOrigin::AsyncFn { parent, .. } | hir::OpaqueTyOrigin::FnReturn { parent, .. } if parent == impl_m.def_id.expect_local() ) }) { diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs index 73e98c67cdc..8ff9640a874 100644 --- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs @@ -210,12 +210,11 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { Node::Item(item) => match item.kind { ItemKind::OpaqueTy(&hir::OpaqueTy { origin: - hir::OpaqueTyOrigin::FnReturn { parent: fn_def_id } - | hir::OpaqueTyOrigin::AsyncFn { parent: fn_def_id }, - in_trait, + hir::OpaqueTyOrigin::FnReturn { parent: fn_def_id, in_trait_or_impl } + | hir::OpaqueTyOrigin::AsyncFn { parent: fn_def_id, in_trait_or_impl }, .. }) => { - if in_trait { + if in_trait_or_impl.is_some() { assert_matches!(tcx.def_kind(fn_def_id), DefKind::AssocFn); } else { assert_matches!(tcx.def_kind(fn_def_id), DefKind::AssocFn | DefKind::Fn); diff --git a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs index 07a8c3a9e84..2418037ae96 100644 --- a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs +++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs @@ -370,39 +370,47 @@ pub(super) fn explicit_item_bounds_with_filter( .. }) => associated_type_bounds(tcx, def_id, bounds, *span, filter), hir::Node::Item(hir::Item { - kind: hir::ItemKind::OpaqueTy(hir::OpaqueTy { bounds, in_trait: false, .. }), + kind: hir::ItemKind::OpaqueTy(hir::OpaqueTy { bounds, origin, .. }), span, .. - }) => { - let args = GenericArgs::identity_for_item(tcx, def_id); - let item_ty = Ty::new_opaque(tcx, def_id.to_def_id(), args); - let bounds = opaque_type_bounds(tcx, def_id, bounds, item_ty, *span, filter); - assert_only_contains_predicates_from(filter, bounds, item_ty); - bounds - } - // Since RPITITs are lowered as projections in `::lower_ty`, when we're - // asking for the item bounds of the *opaques* in a trait's default method signature, we - // need to map these projections back to opaques. - hir::Node::Item(hir::Item { - kind: hir::ItemKind::OpaqueTy(hir::OpaqueTy { bounds, in_trait: true, origin, .. }), - span, - .. - }) => { - let (hir::OpaqueTyOrigin::FnReturn { parent: fn_def_id } - | hir::OpaqueTyOrigin::AsyncFn { parent: fn_def_id }) = *origin - else { - span_bug!(*span, "RPITIT cannot be a TAIT, but got origin {origin:?}"); - }; - let args = GenericArgs::identity_for_item(tcx, def_id); - let item_ty = Ty::new_opaque(tcx, def_id.to_def_id(), args); - let bounds = &*tcx.arena.alloc_slice( - &opaque_type_bounds(tcx, def_id, bounds, item_ty, *span, filter) - .to_vec() - .fold_with(&mut AssocTyToOpaque { tcx, fn_def_id: fn_def_id.to_def_id() }), - ); - assert_only_contains_predicates_from(filter, bounds, item_ty); - bounds - } + }) => match origin { + // Since RPITITs are lowered as projections in `::lower_ty`, + // when we're asking for the item bounds of the *opaques* in a trait's default + // method signature, we need to map these projections back to opaques. + rustc_hir::OpaqueTyOrigin::FnReturn { + parent, + in_trait_or_impl: Some(hir::RpitContext::Trait), + } + | rustc_hir::OpaqueTyOrigin::AsyncFn { + parent, + in_trait_or_impl: Some(hir::RpitContext::Trait), + } => { + let args = GenericArgs::identity_for_item(tcx, def_id); + let item_ty = Ty::new_opaque(tcx, def_id.to_def_id(), args); + let bounds = &*tcx.arena.alloc_slice( + &opaque_type_bounds(tcx, def_id, bounds, item_ty, *span, filter) + .to_vec() + .fold_with(&mut AssocTyToOpaque { tcx, fn_def_id: parent.to_def_id() }), + ); + assert_only_contains_predicates_from(filter, bounds, item_ty); + bounds + } + rustc_hir::OpaqueTyOrigin::FnReturn { + parent: _, + in_trait_or_impl: None | Some(hir::RpitContext::TraitImpl), + } + | rustc_hir::OpaqueTyOrigin::AsyncFn { + parent: _, + in_trait_or_impl: None | Some(hir::RpitContext::TraitImpl), + } + | rustc_hir::OpaqueTyOrigin::TyAlias { parent: _, .. } => { + let args = GenericArgs::identity_for_item(tcx, def_id); + let item_ty = Ty::new_opaque(tcx, def_id.to_def_id(), args); + let bounds = opaque_type_bounds(tcx, def_id, bounds, item_ty, *span, filter); + assert_only_contains_predicates_from(filter, bounds, item_ty); + bounds + } + }, hir::Node::Item(hir::Item { kind: hir::ItemKind::TyAlias(..), .. }) => &[], _ => bug!("item_bounds called on {:?}", def_id), }; diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs index 60788641da0..a15621bf28b 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -515,8 +515,8 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { } hir::ItemKind::OpaqueTy(&hir::OpaqueTy { origin: - hir::OpaqueTyOrigin::FnReturn { parent } - | hir::OpaqueTyOrigin::AsyncFn { parent } + hir::OpaqueTyOrigin::FnReturn { parent, .. } + | hir::OpaqueTyOrigin::AsyncFn { parent, .. } | hir::OpaqueTyOrigin::TyAlias { parent, .. }, generics, .. diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs index 313d7dd6265..3af4d1f5eda 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs @@ -618,12 +618,13 @@ pub(super) fn type_of_opaque( // Opaque types desugared from `impl Trait`. ItemKind::OpaqueTy(&OpaqueTy { origin: - hir::OpaqueTyOrigin::FnReturn { parent: owner } - | hir::OpaqueTyOrigin::AsyncFn { parent: owner }, - in_trait, + hir::OpaqueTyOrigin::FnReturn { parent: owner, in_trait_or_impl } + | hir::OpaqueTyOrigin::AsyncFn { parent: owner, in_trait_or_impl }, .. }) => { - if in_trait && !tcx.defaultness(owner).has_value() { + if in_trait_or_impl == Some(hir::RpitContext::Trait) + && !tcx.defaultness(owner).has_value() + { span_bug!( tcx.def_span(def_id), "tried to get type of this RPITIT with no definition" 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 496f54e31d2..24a8fdf0f6b 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -2091,17 +2091,37 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let opaque_ty = tcx.hir().item(item_id); match opaque_ty.kind { - hir::ItemKind::OpaqueTy(&hir::OpaqueTy { in_trait, .. }) => { + hir::ItemKind::OpaqueTy(&hir::OpaqueTy { origin, .. }) => { let local_def_id = item_id.owner_id.def_id; // If this is an RPITIT and we are using the new RPITIT lowering scheme, we // generate the def_id of an associated type for the trait and return as // type a projection. - let def_id = if in_trait { - tcx.associated_type_for_impl_trait_in_trait(local_def_id).to_def_id() - } else { - local_def_id.to_def_id() - }; - self.lower_opaque_ty(def_id, lifetimes, in_trait) + match origin { + hir::OpaqueTyOrigin::FnReturn { + in_trait_or_impl: Some(hir::RpitContext::Trait), + .. + } + | hir::OpaqueTyOrigin::AsyncFn { + in_trait_or_impl: Some(hir::RpitContext::Trait), + .. + } => self.lower_opaque_ty( + tcx.associated_type_for_impl_trait_in_trait(local_def_id) + .to_def_id(), + lifetimes, + true, + ), + hir::OpaqueTyOrigin::FnReturn { + in_trait_or_impl: None | Some(hir::RpitContext::TraitImpl), + .. + } + | hir::OpaqueTyOrigin::AsyncFn { + in_trait_or_impl: None | Some(hir::RpitContext::TraitImpl), + .. + } + | hir::OpaqueTyOrigin::TyAlias { .. } => { + self.lower_opaque_ty(local_def_id.to_def_id(), lifetimes, false) + } + } } ref i => bug!("`impl Trait` pointed to non-opaque type?? {:#?}", i), } diff --git a/compiler/rustc_hir_typeck/src/_match.rs b/compiler/rustc_hir_typeck/src/_match.rs index 204138ffd44..2dbadf8198b 100644 --- a/compiler/rustc_hir_typeck/src/_match.rs +++ b/compiler/rustc_hir_typeck/src/_match.rs @@ -602,7 +602,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .map(|(k, _)| (k.def_id, k.args))?, _ => return None, }; - let hir::OpaqueTyOrigin::FnReturn { parent: parent_def_id } = + let hir::OpaqueTyOrigin::FnReturn { parent: parent_def_id, .. } = self.tcx.opaque_type_origin(def_id) else { return None; diff --git a/compiler/rustc_lint/src/impl_trait_overcaptures.rs b/compiler/rustc_lint/src/impl_trait_overcaptures.rs index c13f4c7746d..5aeaad42069 100644 --- a/compiler/rustc_lint/src/impl_trait_overcaptures.rs +++ b/compiler/rustc_lint/src/impl_trait_overcaptures.rs @@ -259,7 +259,7 @@ where // If it's owned by this function && let opaque = self.tcx.hir_node_by_def_id(opaque_def_id).expect_item().expect_opaque_ty() - && let hir::OpaqueTyOrigin::FnReturn { parent } = opaque.origin + && let hir::OpaqueTyOrigin::FnReturn { parent, .. } = opaque.origin && parent == self.parent_def_id { let opaque_span = self.tcx.def_span(opaque_def_id); diff --git a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs index 87fa38a282e..342ebfa0b06 100644 --- a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs +++ b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs @@ -77,7 +77,7 @@ impl<'tcx> LateLintPass<'tcx> for OpaqueHiddenInferredBound { // That's because although we may have an opaque type on the function, // it won't have a hidden type, so proving predicates about it is // not really meaningful. - if let hir::OpaqueTyOrigin::FnReturn { parent: method_def_id } = opaque.origin + if let hir::OpaqueTyOrigin::FnReturn { parent: method_def_id, .. } = opaque.origin && let hir::Node::TraitItem(trait_item) = cx.tcx.hir_node_by_def_id(method_def_id) && !trait_item.defaultness.has_value() { @@ -114,8 +114,10 @@ impl<'tcx> LateLintPass<'tcx> for OpaqueHiddenInferredBound { // return type is well-formed in traits even when `Self` isn't sized. if let ty::Param(param_ty) = *proj_term.kind() && param_ty.name == kw::SelfUpper - && matches!(opaque.origin, hir::OpaqueTyOrigin::AsyncFn { .. }) - && opaque.in_trait + && matches!(opaque.origin, hir::OpaqueTyOrigin::AsyncFn { + in_trait_or_impl: Some(hir::RpitContext::Trait), + .. + }) { return; } diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 61eb7260384..610c682d3a4 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1186,8 +1186,8 @@ fn should_encode_type(tcx: TyCtxt<'_>, def_id: LocalDefId, def_kind: DefKind) -> DefKind::OpaqueTy => { let origin = tcx.opaque_type_origin(def_id); - if let hir::OpaqueTyOrigin::FnReturn { parent } - | hir::OpaqueTyOrigin::AsyncFn { parent } = origin + if let hir::OpaqueTyOrigin::FnReturn { parent, .. } + | hir::OpaqueTyOrigin::AsyncFn { parent, .. } = origin && let hir::Node::TraitItem(trait_item) = tcx.hir_node_by_def_id(parent) && let (_, hir::TraitFn::Required(..)) = trait_item.expect_fn() { diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index e11361a615f..72e6c96e6f6 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -1139,13 +1139,7 @@ fn hir_id_to_string(map: Map<'_>, id: HirId) -> String { ItemKind::ForeignMod { .. } => "foreign mod", ItemKind::GlobalAsm(..) => "global asm", ItemKind::TyAlias(..) => "ty", - ItemKind::OpaqueTy(opaque) => { - if opaque.in_trait { - "opaque type in trait" - } else { - "opaque type" - } - } + ItemKind::OpaqueTy(..) => "opaque type", ItemKind::Enum(..) => "enum", ItemKind::Struct(..) => "struct", ItemKind::Union(..) => "union", diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 9094b00fbfb..015e45ad670 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -636,8 +636,7 @@ impl<'tcx> EmbargoVisitor<'tcx> { impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> { fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) { if self.impl_trait_pass - && let hir::ItemKind::OpaqueTy(opaque) = item.kind - && !opaque.in_trait + && let hir::ItemKind::OpaqueTy(..) = item.kind { // FIXME: This is some serious pessimization intended to workaround deficiencies // in the reachability pass (`middle/reachable.rs`). Types are marked as link-time diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs index 673756076b1..a2d717817db 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs @@ -1271,7 +1271,7 @@ fn suggest_precise_capturing<'tcx>( let hir::OpaqueTy { bounds, origin, .. } = tcx.hir_node_by_def_id(opaque_def_id).expect_item().expect_opaque_ty(); - let hir::OpaqueTyOrigin::FnReturn { parent: fn_def_id } = *origin else { + let hir::OpaqueTyOrigin::FnReturn { parent: fn_def_id, .. } = *origin else { return; }; diff --git a/compiler/rustc_ty_utils/src/assoc.rs b/compiler/rustc_ty_utils/src/assoc.rs index f8cfeb500a5..e41f2c8ce48 100644 --- a/compiler/rustc_ty_utils/src/assoc.rs +++ b/compiler/rustc_ty_utils/src/assoc.rs @@ -379,8 +379,8 @@ fn associated_type_for_impl_trait_in_trait( tcx: TyCtxt<'_>, opaque_ty_def_id: LocalDefId, ) -> LocalDefId { - let (hir::OpaqueTyOrigin::FnReturn { parent: fn_def_id } - | hir::OpaqueTyOrigin::AsyncFn { parent: fn_def_id }) = + let (hir::OpaqueTyOrigin::FnReturn { parent: fn_def_id, .. } + | hir::OpaqueTyOrigin::AsyncFn { parent: fn_def_id, .. }) = tcx.opaque_type_origin(opaque_ty_def_id) else { bug!("expected opaque for {opaque_ty_def_id:?}"); From 6e8573c520086db6cc7993a1a2608cc9347832a4 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 2 Oct 2024 23:00:08 -0400 Subject: [PATCH 515/683] Visit in embargo visitor if trait method has body --- compiler/rustc_privacy/src/lib.rs | 48 ++++++++++++++++++++++++------- 1 file changed, 38 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 015e45ad670..d00e7eff752 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -636,17 +636,45 @@ impl<'tcx> EmbargoVisitor<'tcx> { impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> { fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) { if self.impl_trait_pass - && let hir::ItemKind::OpaqueTy(..) = item.kind + && let hir::ItemKind::OpaqueTy(opaque) = item.kind { - // FIXME: This is some serious pessimization intended to workaround deficiencies - // in the reachability pass (`middle/reachable.rs`). Types are marked as link-time - // reachable if they are returned via `impl Trait`, even from private functions. - let pub_ev = EffectiveVisibility::from_vis(ty::Visibility::Public); - self.reach_through_impl_trait(item.owner_id.def_id, pub_ev) - .generics() - .predicates() - .ty(); - return; + let should_visit = match opaque.origin { + hir::OpaqueTyOrigin::FnReturn { + parent, + in_trait_or_impl: Some(hir::RpitContext::Trait), + } + | hir::OpaqueTyOrigin::AsyncFn { + parent, + in_trait_or_impl: Some(hir::RpitContext::Trait), + } => match self.tcx.hir_node_by_def_id(parent).expect_trait_item().expect_fn().1 { + hir::TraitFn::Required(_) => false, + hir::TraitFn::Provided(..) => true, + }, + + // Always visit RPITs in functions that have definitions, + // and all TAITs. + hir::OpaqueTyOrigin::FnReturn { + in_trait_or_impl: None | Some(hir::RpitContext::TraitImpl), + .. + } + | hir::OpaqueTyOrigin::AsyncFn { + in_trait_or_impl: None | Some(hir::RpitContext::TraitImpl), + .. + } + | hir::OpaqueTyOrigin::TyAlias { .. } => true, + }; + + if should_visit { + // FIXME: This is some serious pessimization intended to workaround deficiencies + // in the reachability pass (`middle/reachable.rs`). Types are marked as link-time + // reachable if they are returned via `impl Trait`, even from private functions. + let pub_ev = EffectiveVisibility::from_vis(ty::Visibility::Public); + self.reach_through_impl_trait(item.owner_id.def_id, pub_ev) + .generics() + .predicates() + .ty(); + return; + } } // Update levels of nested things and mark all items From 11f738fcb2ae4ecd6821309290a468a6ebcbaaa9 Mon Sep 17 00:00:00 2001 From: ltdk Date: Sat, 17 Aug 2024 20:33:31 -0400 Subject: [PATCH 516/683] impl Default for Hash{Map,Set} iterators that don't already have it --- library/std/src/collections/hash/map.rs | 64 +++++++++++++++++++++++++ library/std/src/collections/hash/set.rs | 16 +++++++ 2 files changed, 80 insertions(+) diff --git a/library/std/src/collections/hash/map.rs b/library/std/src/collections/hash/map.rs index 6f2b4100620..f2e523dca77 100644 --- a/library/std/src/collections/hash/map.rs +++ b/library/std/src/collections/hash/map.rs @@ -1438,6 +1438,14 @@ impl Clone for Iter<'_, K, V> { } } +#[stable(feature = "default_iters_hash", since = "CURRENT_RUSTC_VERSION")] +impl Default for Iter<'_, K, V> { + #[inline] + fn default() -> Self { + Iter { base: Default::default() } + } +} + #[stable(feature = "std_debug", since = "1.16.0")] impl fmt::Debug for Iter<'_, K, V> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -1476,6 +1484,14 @@ impl<'a, K, V> IterMut<'a, K, V> { } } +#[stable(feature = "default_iters_hash", since = "CURRENT_RUSTC_VERSION")] +impl Default for IterMut<'_, K, V> { + #[inline] + fn default() -> Self { + IterMut { base: Default::default() } + } +} + /// An owning iterator over the entries of a `HashMap`. /// /// This `struct` is created by the [`into_iter`] method on [`HashMap`] @@ -1506,6 +1522,14 @@ impl IntoIter { } } +#[stable(feature = "default_iters_hash", since = "CURRENT_RUSTC_VERSION")] +impl Default for IntoIter { + #[inline] + fn default() -> Self { + IntoIter { base: Default::default() } + } +} + /// An iterator over the keys of a `HashMap`. /// /// This `struct` is created by the [`keys`] method on [`HashMap`]. See its @@ -1538,6 +1562,14 @@ impl Clone for Keys<'_, K, V> { } } +#[stable(feature = "default_iters_hash", since = "CURRENT_RUSTC_VERSION")] +impl Default for Keys<'_, K, V> { + #[inline] + fn default() -> Self { + Keys { inner: Default::default() } + } +} + #[stable(feature = "std_debug", since = "1.16.0")] impl fmt::Debug for Keys<'_, K, V> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -1577,6 +1609,14 @@ impl Clone for Values<'_, K, V> { } } +#[stable(feature = "default_iters_hash", since = "CURRENT_RUSTC_VERSION")] +impl Default for Values<'_, K, V> { + #[inline] + fn default() -> Self { + Values { inner: Default::default() } + } +} + #[stable(feature = "std_debug", since = "1.16.0")] impl fmt::Debug for Values<'_, K, V> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -1665,6 +1705,14 @@ pub struct ValuesMut<'a, K: 'a, V: 'a> { inner: IterMut<'a, K, V>, } +#[stable(feature = "default_iters_hash", since = "CURRENT_RUSTC_VERSION")] +impl Default for ValuesMut<'_, K, V> { + #[inline] + fn default() -> Self { + ValuesMut { inner: Default::default() } + } +} + /// An owning iterator over the keys of a `HashMap`. /// /// This `struct` is created by the [`into_keys`] method on [`HashMap`]. @@ -1687,6 +1735,14 @@ pub struct IntoKeys { inner: IntoIter, } +#[stable(feature = "default_iters_hash", since = "CURRENT_RUSTC_VERSION")] +impl Default for IntoKeys { + #[inline] + fn default() -> Self { + IntoKeys { inner: Default::default() } + } +} + /// An owning iterator over the values of a `HashMap`. /// /// This `struct` is created by the [`into_values`] method on [`HashMap`]. @@ -1709,6 +1765,14 @@ pub struct IntoValues { inner: IntoIter, } +#[stable(feature = "default_iters_hash", since = "CURRENT_RUSTC_VERSION")] +impl Default for IntoValues { + #[inline] + fn default() -> Self { + IntoValues { inner: Default::default() } + } +} + /// A builder for computing where in a HashMap a key-value pair would be stored. /// /// See the [`HashMap::raw_entry_mut`] docs for usage examples. diff --git a/library/std/src/collections/hash/set.rs b/library/std/src/collections/hash/set.rs index e69fb0878e7..210f5715225 100644 --- a/library/std/src/collections/hash/set.rs +++ b/library/std/src/collections/hash/set.rs @@ -1244,6 +1244,14 @@ pub struct Iter<'a, K: 'a> { base: base::Iter<'a, K>, } +#[stable(feature = "default_iters_hash", since = "CURRENT_RUSTC_VERSION")] +impl Default for Iter<'_, K> { + #[inline] + fn default() -> Self { + Iter { base: Default::default() } + } +} + /// An owning iterator over the items of a `HashSet`. /// /// This `struct` is created by the [`into_iter`] method on [`HashSet`] @@ -1265,6 +1273,14 @@ pub struct IntoIter { base: base::IntoIter, } +#[stable(feature = "default_iters_hash", since = "CURRENT_RUSTC_VERSION")] +impl Default for IntoIter { + #[inline] + fn default() -> Self { + IntoIter { base: Default::default() } + } +} + /// A draining iterator over the items of a `HashSet`. /// /// This `struct` is created by the [`drain`] method on [`HashSet`]. From 4b48d72eaa7f4d934f56bcf2b6d0348954977823 Mon Sep 17 00:00:00 2001 From: Jaken Herman Date: Wed, 2 Oct 2024 00:24:42 -0500 Subject: [PATCH 517/683] Add `get_line` confusable to `Stdin::read_line()` Add tests for addition of `#[rustc_confusables("get_line")]` --- library/std/src/io/stdio.rs | 1 + tests/ui/attributes/rustc_confusables_std_cases.rs | 4 ++++ .../attributes/rustc_confusables_std_cases.stderr | 13 ++++++++++++- 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/library/std/src/io/stdio.rs b/library/std/src/io/stdio.rs index 6de069a518e..bf242e715bd 100644 --- a/library/std/src/io/stdio.rs +++ b/library/std/src/io/stdio.rs @@ -394,6 +394,7 @@ impl Stdin { /// in which case it will wait for the Enter key to be pressed before /// continuing #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_confusables("get_line")] pub fn read_line(&self, buf: &mut String) -> io::Result { self.lock().read_line(buf) } diff --git a/tests/ui/attributes/rustc_confusables_std_cases.rs b/tests/ui/attributes/rustc_confusables_std_cases.rs index d9121695950..4f6baea26df 100644 --- a/tests/ui/attributes/rustc_confusables_std_cases.rs +++ b/tests/ui/attributes/rustc_confusables_std_cases.rs @@ -23,4 +23,8 @@ fn main() { //~^ HELP you might have meant to use `push_str` String::new().append(""); //~ ERROR E0599 //~^ HELP you might have meant to use `push_str` + let mut buffer = String::new(); + let stdin = std::io::stdin(); + stdin.get_line(&mut buffer).unwrap(); //~ ERROR E0599 + //~^ HELP you might have meant to use `read_line` } diff --git a/tests/ui/attributes/rustc_confusables_std_cases.stderr b/tests/ui/attributes/rustc_confusables_std_cases.stderr index f4b6947ccd9..7bf96241ca7 100644 --- a/tests/ui/attributes/rustc_confusables_std_cases.stderr +++ b/tests/ui/attributes/rustc_confusables_std_cases.stderr @@ -106,7 +106,18 @@ help: you might have meant to use `push_str` LL | String::new().push_str(""); | ~~~~~~~~ -error: aborting due to 8 previous errors +error[E0599]: no method named `get_line` found for struct `Stdin` in the current scope + --> $DIR/rustc_confusables_std_cases.rs:28:11 + | +LL | stdin.get_line(&mut buffer).unwrap(); + | ^^^^^^^^ method not found in `Stdin` + | +help: you might have meant to use `read_line` + | +LL | stdin.read_line(&mut buffer).unwrap(); + | ~~~~~~~~~ + +error: aborting due to 9 previous errors Some errors have detailed explanations: E0308, E0599. For more information about an error, try `rustc --explain E0308`. From 3d8bd6bbc5dc51fbcc8d912a46f117611c98ee0d Mon Sep 17 00:00:00 2001 From: ismailarilik Date: Thu, 3 Oct 2024 08:23:30 +0300 Subject: [PATCH 518/683] Handle `rustc_metadata` cases of `rustc::potential_query_instability` lint --- compiler/rustc_metadata/src/lib.rs | 1 - compiler/rustc_metadata/src/locator.rs | 20 ++++++++++---------- compiler/rustc_middle/src/ty/mod.rs | 4 ++-- compiler/rustc_resolve/src/lib.rs | 4 ++-- 4 files changed, 14 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_metadata/src/lib.rs b/compiler/rustc_metadata/src/lib.rs index 10f2087d1e6..f206dba6cf4 100644 --- a/compiler/rustc_metadata/src/lib.rs +++ b/compiler/rustc_metadata/src/lib.rs @@ -1,6 +1,5 @@ // tidy-alphabetical-start #![allow(internal_features)] -#![allow(rustc::potential_query_instability)] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(control_flow_enum)] diff --git a/compiler/rustc_metadata/src/locator.rs b/compiler/rustc_metadata/src/locator.rs index 089ac060ba8..99c673b021a 100644 --- a/compiler/rustc_metadata/src/locator.rs +++ b/compiler/rustc_metadata/src/locator.rs @@ -218,7 +218,7 @@ use std::ops::Deref; use std::path::{Path, PathBuf}; use std::{cmp, fmt}; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; use rustc_data_structures::memmap::Mmap; use rustc_data_structures::owned_slice::slice_owned; use rustc_data_structures::svh::Svh; @@ -385,7 +385,7 @@ impl<'a> CrateLocator<'a> { let dylib_suffix = &self.target.dll_suffix; let staticlib_suffix = &self.target.staticlib_suffix; - let mut candidates: FxHashMap<_, (FxHashMap<_, _>, FxHashMap<_, _>, FxHashMap<_, _>)> = + let mut candidates: FxIndexMap<_, (FxIndexMap<_, _>, FxIndexMap<_, _>, FxIndexMap<_, _>)> = Default::default(); // First, find all possible candidate rlibs and dylibs purely based on @@ -460,7 +460,7 @@ impl<'a> CrateLocator<'a> { // A Library candidate is created if the metadata for the set of // libraries corresponds to the crate id and hash criteria that this // search is being performed for. - let mut libraries = FxHashMap::default(); + let mut libraries = FxIndexMap::default(); for (_hash, (rlibs, rmetas, dylibs)) in candidates { if let Some((svh, lib)) = self.extract_lib(rlibs, rmetas, dylibs)? { libraries.insert(svh, lib); @@ -494,9 +494,9 @@ impl<'a> CrateLocator<'a> { fn extract_lib( &mut self, - rlibs: FxHashMap, - rmetas: FxHashMap, - dylibs: FxHashMap, + rlibs: FxIndexMap, + rmetas: FxIndexMap, + dylibs: FxIndexMap, ) -> Result, CrateError> { let mut slot = None; // Order here matters, rmeta should come first. See comment in @@ -534,7 +534,7 @@ impl<'a> CrateLocator<'a> { // The `PathBuf` in `slot` will only be used for diagnostic purposes. fn extract_one( &mut self, - m: FxHashMap, + m: FxIndexMap, flavor: CrateFlavor, slot: &mut Option<(Svh, MetadataBlob, PathBuf)>, ) -> Result, CrateError> { @@ -702,9 +702,9 @@ impl<'a> CrateLocator<'a> { // First, filter out all libraries that look suspicious. We only accept // files which actually exist that have the correct naming scheme for // rlibs/dylibs. - let mut rlibs = FxHashMap::default(); - let mut rmetas = FxHashMap::default(); - let mut dylibs = FxHashMap::default(); + let mut rlibs = FxIndexMap::default(); + let mut rmetas = FxIndexMap::default(); + let mut dylibs = FxIndexMap::default(); for loc in &self.exact_paths { if !loc.canonicalized().exists() { return Err(CrateError::ExternLocationNotExist( diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index c4a28845085..f32daee7c44 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -187,8 +187,8 @@ pub struct ResolverGlobalCtxt { /// Mapping from ident span to path span for paths that don't exist as written, but that /// exist under `std`. For example, wrote `str::from_utf8` instead of `std::str::from_utf8`. pub confused_type_with_std_module: FxIndexMap, - pub doc_link_resolutions: FxHashMap, - pub doc_link_traits_in_scope: FxHashMap>, + pub doc_link_resolutions: FxIndexMap, + pub doc_link_traits_in_scope: FxIndexMap>, pub all_macro_rules: FxHashMap>, pub stripped_cfg_items: Steal>, } diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 0c1a0038f9c..fcbbb523cfc 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -1196,8 +1196,8 @@ pub struct Resolver<'ra, 'tcx> { stripped_cfg_items: Vec>, effective_visibilities: EffectiveVisibilities, - doc_link_resolutions: FxHashMap, - doc_link_traits_in_scope: FxHashMap>, + doc_link_resolutions: FxIndexMap, + doc_link_traits_in_scope: FxIndexMap>, all_macro_rules: FxHashMap, /// Invocation ids of all glob delegations. From be819d415952f877019e6a0fea269e2aaccc552b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 3 Oct 2024 07:47:41 +0200 Subject: [PATCH 519/683] Preparing for merge from rustc --- src/tools/miri/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index b05c409f823..fe0421b2075 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -76ed7a1fa40c3f54d3fd3f834e12bf9c932d0146 +ad9c494835e746fb7c8a26eeed0ad90e4e834058 From 32d49680d6088623f8d709a90247f65b4b81cfd6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 3 Oct 2024 07:59:28 +0200 Subject: [PATCH 520/683] fmt --- src/tools/miri/src/concurrency/init_once.rs | 3 ++- src/tools/miri/src/concurrency/sync.rs | 9 ++++--- src/tools/miri/src/helpers.rs | 24 ++++++++++--------- src/tools/miri/src/shims/time.rs | 3 ++- src/tools/miri/src/shims/unix/fd.rs | 3 ++- .../data_race/mixed_size_read_read_write.rs | 2 +- .../fail/data_race/mixed_size_read_write.rs | 2 +- 7 files changed, 27 insertions(+), 19 deletions(-) diff --git a/src/tools/miri/src/concurrency/init_once.rs b/src/tools/miri/src/concurrency/init_once.rs index 8985135f4e8..7a9b12bbe82 100644 --- a/src/tools/miri/src/concurrency/init_once.rs +++ b/src/tools/miri/src/concurrency/init_once.rs @@ -39,7 +39,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { |ecx| &mut ecx.machine.sync.init_onces, |_| interp_ok(Default::default()), )? - .ok_or_else(|| err_ub_format!("init_once has invalid ID")).into() + .ok_or_else(|| err_ub_format!("init_once has invalid ID")) + .into() } #[inline] diff --git a/src/tools/miri/src/concurrency/sync.rs b/src/tools/miri/src/concurrency/sync.rs index 3b57af641b5..5627ccdbbea 100644 --- a/src/tools/miri/src/concurrency/sync.rs +++ b/src/tools/miri/src/concurrency/sync.rs @@ -307,7 +307,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { |ecx| &mut ecx.machine.sync.mutexes, |ecx| initialize_data(ecx).map(|data| Mutex { data, ..Default::default() }), )? - .ok_or_else(|| err_ub_format!("mutex has invalid ID")).into() + .ok_or_else(|| err_ub_format!("mutex has invalid ID")) + .into() } /// Retrieve the additional data stored for a mutex. @@ -334,7 +335,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { |ecx| &mut ecx.machine.sync.rwlocks, |ecx| initialize_data(ecx).map(|data| RwLock { data, ..Default::default() }), )? - .ok_or_else(|| err_ub_format!("rwlock has invalid ID")).into() + .ok_or_else(|| err_ub_format!("rwlock has invalid ID")) + .into() } /// Retrieve the additional data stored for a rwlock. @@ -375,7 +377,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { |ecx| &mut ecx.machine.sync.condvars, |ecx| initialize_data(ecx).map(|data| Condvar { data, ..Default::default() }), )? - .ok_or_else(|| err_ub_format!("condvar has invalid ID")).into() + .ok_or_else(|| err_ub_format!("condvar has invalid ID")) + .into() } /// Retrieve the additional data stored for a condvar. diff --git a/src/tools/miri/src/helpers.rs b/src/tools/miri/src/helpers.rs index b12a1939e25..013bfe03aaf 100644 --- a/src/tools/miri/src/helpers.rs +++ b/src/tools/miri/src/helpers.rs @@ -752,17 +752,19 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let nanoseconds_scalar = this.read_scalar(&nanoseconds_place)?; let nanoseconds = nanoseconds_scalar.to_target_isize(this)?; - interp_ok(try { - // tv_sec must be non-negative. - let seconds: u64 = seconds.try_into().ok()?; - // tv_nsec must be non-negative. - let nanoseconds: u32 = nanoseconds.try_into().ok()?; - if nanoseconds >= 1_000_000_000 { - // tv_nsec must not be greater than 999,999,999. - None? - } - Duration::new(seconds, nanoseconds) - }) + interp_ok( + try { + // tv_sec must be non-negative. + let seconds: u64 = seconds.try_into().ok()?; + // tv_nsec must be non-negative. + let nanoseconds: u32 = nanoseconds.try_into().ok()?; + if nanoseconds >= 1_000_000_000 { + // tv_nsec must not be greater than 999,999,999. + None? + } + Duration::new(seconds, nanoseconds) + }, + ) } /// Read bytes from a byte slice. diff --git a/src/tools/miri/src/shims/time.rs b/src/tools/miri/src/shims/time.rs index 21c5421f109..12c7679608d 100644 --- a/src/tools/miri/src/shims/time.rs +++ b/src/tools/miri/src/shims/time.rs @@ -11,7 +11,8 @@ use crate::*; /// Returns the time elapsed between the provided time and the unix epoch as a `Duration`. pub fn system_time_to_duration<'tcx>(time: &SystemTime) -> InterpResult<'tcx, Duration> { time.duration_since(SystemTime::UNIX_EPOCH) - .map_err(|_| err_unsup_format!("times before the Unix epoch are not supported")).into() + .map_err(|_| err_unsup_format!("times before the Unix epoch are not supported")) + .into() } impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {} diff --git a/src/tools/miri/src/shims/unix/fd.rs b/src/tools/miri/src/shims/unix/fd.rs index cf8e629cea1..f2d3115f985 100644 --- a/src/tools/miri/src/shims/unix/fd.rs +++ b/src/tools/miri/src/shims/unix/fd.rs @@ -517,7 +517,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let start = this.read_scalar(&args[2])?.to_i32()?; match this.machine.fds.get(fd_num) { - Some(fd) => interp_ok(Scalar::from_i32(this.machine.fds.insert_with_min_num(fd, start))), + Some(fd) => + interp_ok(Scalar::from_i32(this.machine.fds.insert_with_min_num(fd, start))), None => interp_ok(Scalar::from_i32(this.fd_not_found()?)), } } else if this.tcx.sess.target.os == "macos" && cmd == this.eval_libc_i32("F_FULLFSYNC") { diff --git a/src/tools/miri/tests/fail/data_race/mixed_size_read_read_write.rs b/src/tools/miri/tests/fail/data_race/mixed_size_read_read_write.rs index ece5bd31274..e76654806bb 100644 --- a/src/tools/miri/tests/fail/data_race/mixed_size_read_read_write.rs +++ b/src/tools/miri/tests/fail/data_race/mixed_size_read_read_write.rs @@ -4,7 +4,7 @@ // Two variants: the atomic store matches the size of the first or second atomic load. //@revisions: match_first_load match_second_load -use std::sync::atomic::{AtomicU16, AtomicU8, Ordering}; +use std::sync::atomic::{AtomicU8, AtomicU16, Ordering}; use std::thread; fn convert(a: &AtomicU16) -> &[AtomicU8; 2] { diff --git a/src/tools/miri/tests/fail/data_race/mixed_size_read_write.rs b/src/tools/miri/tests/fail/data_race/mixed_size_read_write.rs index acc12427b3f..53016bab780 100644 --- a/src/tools/miri/tests/fail/data_race/mixed_size_read_write.rs +++ b/src/tools/miri/tests/fail/data_race/mixed_size_read_write.rs @@ -4,7 +4,7 @@ // Two revisions, depending on which access goes first. //@revisions: read_write write_read -use std::sync::atomic::{AtomicU16, AtomicU8, Ordering}; +use std::sync::atomic::{AtomicU8, AtomicU16, Ordering}; use std::thread; fn convert(a: &AtomicU16) -> &[AtomicU8; 2] { From 9b35886adfe5da4163e95508f586dc071eec4d0f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 3 Oct 2024 08:19:07 +0200 Subject: [PATCH 521/683] make sure we also detect mixed-size races that begin at different addresses --- .../mixed_size_write_write.fst.stderr | 22 +++++++++++++++++++ .../fail/data_race/mixed_size_write_write.rs | 4 +++- .../mixed_size_write_write.snd.stderr | 22 +++++++++++++++++++ 3 files changed, 47 insertions(+), 1 deletion(-) create mode 100644 src/tools/miri/tests/fail/data_race/mixed_size_write_write.fst.stderr create mode 100644 src/tools/miri/tests/fail/data_race/mixed_size_write_write.snd.stderr diff --git a/src/tools/miri/tests/fail/data_race/mixed_size_write_write.fst.stderr b/src/tools/miri/tests/fail/data_race/mixed_size_write_write.fst.stderr new file mode 100644 index 00000000000..a353910dcc9 --- /dev/null +++ b/src/tools/miri/tests/fail/data_race/mixed_size_write_write.fst.stderr @@ -0,0 +1,22 @@ +error: Undefined Behavior: Race condition detected between (1) 2-byte atomic store on thread `unnamed-ID` and (2) 1-byte atomic store on thread `unnamed-ID` at ALLOC. (2) just happened here + --> tests/fail/data_race/mixed_size_write_write.rs:LL:CC + | +LL | a8[idx].store(1, Ordering::SeqCst); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Race condition detected between (1) 2-byte atomic store on thread `unnamed-ID` and (2) 1-byte atomic store on thread `unnamed-ID` at ALLOC. (2) just happened here + | +help: and (1) occurred earlier here + --> tests/fail/data_race/mixed_size_write_write.rs:LL:CC + | +LL | a16.store(1, Ordering::SeqCst); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = help: overlapping unsynchronized atomic accesses must use the same access size + = help: see https://doc.rust-lang.org/nightly/std/sync/atomic/index.html#memory-model-for-atomic-accesses for more information about the Rust memory model + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: BACKTRACE (of the first span) on thread `unnamed-ID`: + = note: inside closure at tests/fail/data_race/mixed_size_write_write.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + diff --git a/src/tools/miri/tests/fail/data_race/mixed_size_write_write.rs b/src/tools/miri/tests/fail/data_race/mixed_size_write_write.rs index 89afda2fff5..545e354a037 100644 --- a/src/tools/miri/tests/fail/data_race/mixed_size_write_write.rs +++ b/src/tools/miri/tests/fail/data_race/mixed_size_write_write.rs @@ -1,6 +1,7 @@ //@compile-flags: -Zmiri-preemption-rate=0.0 -Zmiri-disable-weak-memory-emulation // Avoid accidental synchronization via address reuse inside `thread::spawn`. //@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0 +//@revisions: fst snd use std::sync::atomic::{AtomicU8, AtomicU16, Ordering}; use std::thread; @@ -21,7 +22,8 @@ fn main() { a16.store(1, Ordering::SeqCst); }); s.spawn(|| { - a8[0].store(1, Ordering::SeqCst); + let idx = if cfg!(fst) { 0 } else { 1 }; + a8[idx].store(1, Ordering::SeqCst); //~^ ERROR: Race condition detected between (1) 2-byte atomic store on thread `unnamed-1` and (2) 1-byte atomic store on thread `unnamed-2` }); }); diff --git a/src/tools/miri/tests/fail/data_race/mixed_size_write_write.snd.stderr b/src/tools/miri/tests/fail/data_race/mixed_size_write_write.snd.stderr new file mode 100644 index 00000000000..3b9c0491502 --- /dev/null +++ b/src/tools/miri/tests/fail/data_race/mixed_size_write_write.snd.stderr @@ -0,0 +1,22 @@ +error: Undefined Behavior: Race condition detected between (1) 2-byte atomic store on thread `unnamed-ID` and (2) 1-byte atomic store on thread `unnamed-ID` at ALLOC+0x1. (2) just happened here + --> tests/fail/data_race/mixed_size_write_write.rs:LL:CC + | +LL | a8[idx].store(1, Ordering::SeqCst); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Race condition detected between (1) 2-byte atomic store on thread `unnamed-ID` and (2) 1-byte atomic store on thread `unnamed-ID` at ALLOC+0x1. (2) just happened here + | +help: and (1) occurred earlier here + --> tests/fail/data_race/mixed_size_write_write.rs:LL:CC + | +LL | a16.store(1, Ordering::SeqCst); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = help: overlapping unsynchronized atomic accesses must use the same access size + = help: see https://doc.rust-lang.org/nightly/std/sync/atomic/index.html#memory-model-for-atomic-accesses for more information about the Rust memory model + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: BACKTRACE (of the first span) on thread `unnamed-ID`: + = note: inside closure at tests/fail/data_race/mixed_size_write_write.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + From a8f9a32650122dd7c54ad20d1230bcb62c6506ff Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 30 Sep 2024 17:49:51 +0200 Subject: [PATCH 522/683] interpret: Immediate::offset: use shared sanity-check function to ensure invariant --- .../rustc_const_eval/src/interpret/operand.rs | 64 ++++++++++--------- .../rustc_const_eval/src/interpret/place.rs | 8 ++- .../src/interpret/projection.rs | 4 ++ 3 files changed, 45 insertions(+), 31 deletions(-) diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs index 291664d556a..3b5af113e99 100644 --- a/compiler/rustc_const_eval/src/interpret/operand.rs +++ b/compiler/rustc_const_eval/src/interpret/operand.rs @@ -113,28 +113,47 @@ impl Immediate { } /// Assert that this immediate is a valid value for the given ABI. - pub fn assert_matches_abi(self, abi: Abi, cx: &impl HasDataLayout) { + pub fn assert_matches_abi(self, abi: Abi, msg: &str, cx: &impl HasDataLayout) { match (self, abi) { (Immediate::Scalar(scalar), Abi::Scalar(s)) => { - assert_eq!(scalar.size(), s.size(cx)); + assert_eq!(scalar.size(), s.size(cx), "{msg}: scalar value has wrong size"); if !matches!(s.primitive(), abi::Pointer(..)) { // This is not a pointer, it should not carry provenance. - assert!(matches!(scalar, Scalar::Int(..))); + assert!( + matches!(scalar, Scalar::Int(..)), + "{msg}: scalar value should be an integer, but has provenance" + ); } } (Immediate::ScalarPair(a_val, b_val), Abi::ScalarPair(a, b)) => { - assert_eq!(a_val.size(), a.size(cx)); + assert_eq!( + a_val.size(), + a.size(cx), + "{msg}: first component of scalar pair has wrong size" + ); if !matches!(a.primitive(), abi::Pointer(..)) { - assert!(matches!(a_val, Scalar::Int(..))); + assert!( + matches!(a_val, Scalar::Int(..)), + "{msg}: first component of scalar pair should be an integer, but has provenance" + ); } - assert_eq!(b_val.size(), b.size(cx)); + assert_eq!( + b_val.size(), + b.size(cx), + "{msg}: second component of scalar pair has wrong size" + ); if !matches!(b.primitive(), abi::Pointer(..)) { - assert!(matches!(b_val, Scalar::Int(..))); + assert!( + matches!(b_val, Scalar::Int(..)), + "{msg}: second component of scalar pair should be an integer, but has provenance" + ); } } - (Immediate::Uninit, _) => {} + (Immediate::Uninit, _) => { + assert!(abi.is_sized(), "{msg}: unsized immediates are not a thing"); + } _ => { - bug!("value {self:?} does not match ABI {abi:?})",) + bug!("{msg}: value {self:?} does not match ABI {abi:?})",) } } } @@ -241,6 +260,7 @@ impl<'tcx, Prov: Provenance> ImmTy<'tcx, Prov> { #[inline(always)] pub fn from_immediate(imm: Immediate, layout: TyAndLayout<'tcx>) -> Self { + // Without a `cx` we cannot call `assert_matches_abi`. debug_assert!( match (imm, layout.abi) { (Immediate::Scalar(..), Abi::Scalar(..)) => true, @@ -261,7 +281,6 @@ impl<'tcx, Prov: Provenance> ImmTy<'tcx, Prov> { #[inline] pub fn from_scalar_int(s: ScalarInt, layout: TyAndLayout<'tcx>) -> Self { - assert_eq!(s.size(), layout.size); Self::from_scalar(Scalar::from(s), layout) } @@ -334,7 +353,10 @@ impl<'tcx, Prov: Provenance> ImmTy<'tcx, Prov> { /// given layout. // Not called `offset` to avoid confusion with the trait method. fn offset_(&self, offset: Size, layout: TyAndLayout<'tcx>, cx: &impl HasDataLayout) -> Self { - debug_assert!(layout.is_sized(), "unsized immediates are not a thing"); + // Verify that the input matches its type. + if cfg!(debug_assertions) { + self.assert_matches_abi(self.layout.abi, "invalid input to Immediate::offset", cx); + } // `ImmTy` have already been checked to be in-bounds, so we can just check directly if this // remains in-bounds. This cannot actually be violated since projections are type-checked // and bounds-checked. @@ -368,32 +390,14 @@ impl<'tcx, Prov: Provenance> ImmTy<'tcx, Prov> { // the field covers the entire type _ if layout.size == self.layout.size => { assert_eq!(offset.bytes(), 0); - assert!( - match (self.layout.abi, layout.abi) { - (Abi::Scalar(l), Abi::Scalar(r)) => l.size(cx) == r.size(cx), - (Abi::ScalarPair(l1, l2), Abi::ScalarPair(r1, r2)) => - l1.size(cx) == r1.size(cx) && l2.size(cx) == r2.size(cx), - _ => false, - }, - "cannot project into {} immediate with equally-sized field {}\nouter ABI: {:#?}\nfield ABI: {:#?}", - self.layout.ty, - layout.ty, - self.layout.abi, - layout.abi, - ); **self } // extract fields from types with `ScalarPair` ABI (Immediate::ScalarPair(a_val, b_val), Abi::ScalarPair(a, b)) => { - assert_matches!(layout.abi, Abi::Scalar(..)); Immediate::from(if offset.bytes() == 0 { - // It is "okay" to transmute from `usize` to a pointer (GVN relies on that). - // So only compare the size. - assert_eq!(layout.size, a.size(cx)); a_val } else { assert_eq!(offset, a.size(cx).align_to(b.align(cx).abi)); - assert_eq!(layout.size, b.size(cx)); b_val }) } @@ -405,6 +409,8 @@ impl<'tcx, Prov: Provenance> ImmTy<'tcx, Prov> { self.layout ), }; + // Ensure the new layout matches the new value. + inner_val.assert_matches_abi(layout.abi, "invalid field type in Immediate::offset", cx); ImmTy::from_immediate(inner_val, layout) } diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs index 49656e10f2a..81b926a1b65 100644 --- a/compiler/rustc_const_eval/src/interpret/place.rs +++ b/compiler/rustc_const_eval/src/interpret/place.rs @@ -658,7 +658,11 @@ where // Things can ge wrong in quite weird ways when this is violated. // Unfortunately this is too expensive to do in release builds. if cfg!(debug_assertions) { - src.assert_matches_abi(local_layout.abi, self); + src.assert_matches_abi( + local_layout.abi, + "invalid immediate for given destination place", + self, + ); } } Left(mplace) => { @@ -679,7 +683,7 @@ where ) -> InterpResult<'tcx> { // We use the sizes from `value` below. // Ensure that matches the type of the place it is written to. - value.assert_matches_abi(layout.abi, self); + value.assert_matches_abi(layout.abi, "invalid immediate for given destination place", self); // Note that it is really important that the type here is the right one, and matches the // type things are read at. In case `value` is a `ScalarPair`, we don't do any magic here // to handle padding properly, which is only correct if we never look at this data with the diff --git a/compiler/rustc_const_eval/src/interpret/projection.rs b/compiler/rustc_const_eval/src/interpret/projection.rs index cc49d7cebf4..e636090a324 100644 --- a/compiler/rustc_const_eval/src/interpret/projection.rs +++ b/compiler/rustc_const_eval/src/interpret/projection.rs @@ -82,6 +82,10 @@ pub trait Projectable<'tcx, Prov: Provenance>: Sized + std::fmt::Debug { self.offset_with_meta(offset, OffsetMode::Inbounds, MemPlaceMeta::None, layout, ecx) } + /// This does an offset-by-zero, which is effectively a transmute. Note however that + /// not all transmutes are supported by all projectables -- specifically, if this is an + /// `OpTy` or `ImmTy`, the new layout must have almost the same ABI as the old one + /// (only changing the `valid_range` is allowed and turning integers into pointers). fn transmute>( &self, layout: TyAndLayout<'tcx>, From 2cf155924fb6f7d4f85f49c0642b2d40b22a13b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Wed, 4 Sep 2024 11:22:43 +0200 Subject: [PATCH 523/683] Do not include `libstd.so` in sysroot when we statically link to libstd --- src/bootstrap/src/bin/rustc.rs | 1 - src/bootstrap/src/core/build_steps/compile.rs | 18 +++++++++++++++++- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/bootstrap/src/bin/rustc.rs b/src/bootstrap/src/bin/rustc.rs index d04e2fbeb78..780979ed981 100644 --- a/src/bootstrap/src/bin/rustc.rs +++ b/src/bootstrap/src/bin/rustc.rs @@ -95,7 +95,6 @@ fn main() { // When statically linking `std` into `rustc_driver`, remove `-C prefer-dynamic` if env::var("RUSTC_LINK_STD_INTO_RUSTC_DRIVER").unwrap() == "1" && crate_name == Some("rustc_driver") - && stage != "0" { if let Some(pos) = args.iter().enumerate().position(|(i, a)| { a == "-C" && args.get(i + 1).map(|a| a == "prefer-dynamic").unwrap_or(false) diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index eaa982d4e2b..c274bcc2df7 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -1923,8 +1923,24 @@ impl Step for Assemble { let src_libdir = builder.sysroot_libdir(build_compiler, host); for f in builder.read_dir(&src_libdir) { let filename = f.file_name().into_string().unwrap(); - if (is_dylib(&filename) || is_debug_info(&filename)) && !proc_macros.contains(&filename) + + let is_proc_macro = proc_macros.contains(&filename); + let is_dylib_or_debug = is_dylib(&filename) || is_debug_info(&filename); + + // If we link statically to stdlib, do not copy the libstd dynamic library file + // Currently, we do not avoid the copy on Windows, as it seems to be causing issues in + // post-optimization stage0 tests. + let can_be_rustc_dynamic_dep = if builder + .link_std_into_rustc_driver(target_compiler.host) + && !target_compiler.host.is_windows() { + let is_std = filename.starts_with("std-") || filename.starts_with("libstd-"); + !is_std + } else { + true + }; + + if is_dylib_or_debug && can_be_rustc_dynamic_dep && !is_proc_macro { builder.copy_link(&f.path(), &rustc_libdir.join(&filename)); } } From 3a0ed0c6e3209ae1bce3079eea944c07b58f225f Mon Sep 17 00:00:00 2001 From: Orion Gonzalez Date: Wed, 2 Oct 2024 23:35:17 +0200 Subject: [PATCH 524/683] add direnv to gitignore --- .gitignore | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.gitignore b/.gitignore index d6d8b99f602..2f88b275301 100644 --- a/.gitignore +++ b/.gitignore @@ -86,4 +86,8 @@ package.json ## Rustdoc GUI tests tests/rustdoc-gui/src/**.lock +## direnv +.envrc +.direnv/ + # Before adding new lines, see the comment at the top. From 510e262deb6c5eba94e0aad2f609448271f80264 Mon Sep 17 00:00:00 2001 From: Orion Gonzalez Date: Wed, 2 Oct 2024 23:35:48 +0200 Subject: [PATCH 525/683] add nix files to gitignore --- .gitignore | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.gitignore b/.gitignore index 2f88b275301..b170dca88fa 100644 --- a/.gitignore +++ b/.gitignore @@ -90,4 +90,9 @@ tests/rustdoc-gui/src/**.lock .envrc .direnv/ +## nix +flake.nix +flake.lock +default.nix + # Before adding new lines, see the comment at the top. From 83d0d9f292d4c98d26cd007f294ab91789b1378d Mon Sep 17 00:00:00 2001 From: ismailarilik Date: Thu, 3 Oct 2024 12:47:08 +0300 Subject: [PATCH 526/683] Handle `rustc_query_impl` cases of `rustc::potential_query_instability` lint --- compiler/rustc_query_impl/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_query_impl/src/lib.rs b/compiler/rustc_query_impl/src/lib.rs index 69742bb49b1..df898e0587f 100644 --- a/compiler/rustc_query_impl/src/lib.rs +++ b/compiler/rustc_query_impl/src/lib.rs @@ -2,7 +2,7 @@ // tidy-alphabetical-start #![allow(internal_features)] -#![allow(rustc::potential_query_instability, unused_parens)] +#![allow(unused_parens)] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(min_specialization)] From 8e382ba022fc7f8f6f7e0abca5e8052039a81202 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Thu, 3 Oct 2024 16:53:51 +1000 Subject: [PATCH 527/683] Avoid ICE in coverage builds with bad `#[coverage(..)]` attributes This code can sometimes witness malformed coverage attributes in builds that are going to fail, so use `span_delayed_bug` to avoid an inappropriate ICE in that case. --- .../rustc_mir_transform/src/coverage/query.rs | 3 ++- tests/crashes/127880.rs | 5 ---- .../ui/coverage-attr/bad-attr-ice.feat.stderr | 15 +++++++++++ .../coverage-attr/bad-attr-ice.nofeat.stderr | 26 +++++++++++++++++++ tests/ui/coverage-attr/bad-attr-ice.rs | 16 ++++++++++++ 5 files changed, 59 insertions(+), 6 deletions(-) delete mode 100644 tests/crashes/127880.rs create mode 100644 tests/ui/coverage-attr/bad-attr-ice.feat.stderr create mode 100644 tests/ui/coverage-attr/bad-attr-ice.nofeat.stderr create mode 100644 tests/ui/coverage-attr/bad-attr-ice.rs diff --git a/compiler/rustc_mir_transform/src/coverage/query.rs b/compiler/rustc_mir_transform/src/coverage/query.rs index e65a5fdd5e7..df151f8cca3 100644 --- a/compiler/rustc_mir_transform/src/coverage/query.rs +++ b/compiler/rustc_mir_transform/src/coverage/query.rs @@ -63,7 +63,8 @@ fn coverage_attr_on(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { Some([item]) if item.has_name(sym::on) => return true, Some(_) | None => { // Other possibilities should have been rejected by `rustc_parse::validate_attr`. - tcx.dcx().span_bug(attr.span, "unexpected value of coverage attribute"); + // Use `span_delayed_bug` to avoid an ICE in failing builds (#127880). + tcx.dcx().span_delayed_bug(attr.span, "unexpected value of coverage attribute"); } } } diff --git a/tests/crashes/127880.rs b/tests/crashes/127880.rs deleted file mode 100644 index 6c625eac691..00000000000 --- a/tests/crashes/127880.rs +++ /dev/null @@ -1,5 +0,0 @@ -//@ known-bug: #127880 -//@ compile-flags: -Cinstrument-coverage - -#[coverage] -fn main() {} diff --git a/tests/ui/coverage-attr/bad-attr-ice.feat.stderr b/tests/ui/coverage-attr/bad-attr-ice.feat.stderr new file mode 100644 index 00000000000..9e3cd41c277 --- /dev/null +++ b/tests/ui/coverage-attr/bad-attr-ice.feat.stderr @@ -0,0 +1,15 @@ +error: malformed `coverage` attribute input + --> $DIR/bad-attr-ice.rs:10:1 + | +LL | #[coverage] + | ^^^^^^^^^^^ + | +help: the following are the possible correct uses + | +LL | #[coverage(off)] + | +LL | #[coverage(on)] + | + +error: aborting due to 1 previous error + diff --git a/tests/ui/coverage-attr/bad-attr-ice.nofeat.stderr b/tests/ui/coverage-attr/bad-attr-ice.nofeat.stderr new file mode 100644 index 00000000000..d73636e158b --- /dev/null +++ b/tests/ui/coverage-attr/bad-attr-ice.nofeat.stderr @@ -0,0 +1,26 @@ +error: malformed `coverage` attribute input + --> $DIR/bad-attr-ice.rs:10:1 + | +LL | #[coverage] + | ^^^^^^^^^^^ + | +help: the following are the possible correct uses + | +LL | #[coverage(off)] + | +LL | #[coverage(on)] + | + +error[E0658]: the `#[coverage]` attribute is an experimental feature + --> $DIR/bad-attr-ice.rs:10:1 + | +LL | #[coverage] + | ^^^^^^^^^^^ + | + = note: see issue #84605 for more information + = help: add `#![feature(coverage_attribute)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/coverage-attr/bad-attr-ice.rs b/tests/ui/coverage-attr/bad-attr-ice.rs new file mode 100644 index 00000000000..ae4d27d65eb --- /dev/null +++ b/tests/ui/coverage-attr/bad-attr-ice.rs @@ -0,0 +1,16 @@ +#![cfg_attr(feat, feature(coverage_attribute))] +//@ revisions: feat nofeat +//@ compile-flags: -Cinstrument-coverage +//@ needs-profiler-support + +// Malformed `#[coverage(..)]` attributes should not cause an ICE when built +// with `-Cinstrument-coverage`. +// Regression test for . + +#[coverage] +//~^ ERROR malformed `coverage` attribute input +//[nofeat]~| the `#[coverage]` attribute is an experimental feature +fn main() {} + +// FIXME(#130766): When the `#[coverage(..)]` attribute is stabilized, +// get rid of the revisions and just make this a normal test. From 8918a9d265c38945fe442a8fcec71995f6e52b5a Mon Sep 17 00:00:00 2001 From: Michal Piotrowski Date: Thu, 3 Oct 2024 13:15:48 +0200 Subject: [PATCH 528/683] Fix needless_lifetimes in stable_mir --- compiler/stable_mir/src/mir/visit.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/stable_mir/src/mir/visit.rs b/compiler/stable_mir/src/mir/visit.rs index aeae866e9d3..e2d1ff7fdd3 100644 --- a/compiler/stable_mir/src/mir/visit.rs +++ b/compiler/stable_mir/src/mir/visit.rs @@ -76,9 +76,9 @@ pub trait MirVisitor { self.super_place(place, ptx, location) } - fn visit_projection_elem<'a>( + fn visit_projection_elem( &mut self, - place_ref: PlaceRef<'a>, + place_ref: PlaceRef<'_>, elem: &ProjectionElem, ptx: PlaceContext, location: Location, From c994a60fd4f848005beeef17bf6a13e1347103b8 Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Thu, 3 Oct 2024 14:48:03 +0200 Subject: [PATCH 529/683] Bump nightly version -> 2024-10-03 --- rust-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain b/rust-toolchain index b431599c224..f0c8651efce 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,4 +1,4 @@ [toolchain] -channel = "nightly-2024-09-22" +channel = "nightly-2024-10-03" components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"] profile = "minimal" From 9c91a4ef1652e5f01742185f43541ab22e6f01db Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 3 Oct 2024 09:40:53 -0400 Subject: [PATCH 530/683] Failing diff test --- ...itwise_not.JumpThreading.panic-unwind.diff | 47 +++++++++++++++++++ tests/mir-opt/jump_threading.rs | 11 +++++ 2 files changed, 58 insertions(+) create mode 100644 tests/mir-opt/jump_threading.bitwise_not.JumpThreading.panic-unwind.diff diff --git a/tests/mir-opt/jump_threading.bitwise_not.JumpThreading.panic-unwind.diff b/tests/mir-opt/jump_threading.bitwise_not.JumpThreading.panic-unwind.diff new file mode 100644 index 00000000000..fb64fff7e11 --- /dev/null +++ b/tests/mir-opt/jump_threading.bitwise_not.JumpThreading.panic-unwind.diff @@ -0,0 +1,47 @@ +- // MIR for `bitwise_not` before JumpThreading ++ // MIR for `bitwise_not` after JumpThreading + + fn bitwise_not() -> i32 { + let mut _0: i32; + let mut _1: i32; + let mut _2: bool; + let mut _3: i32; + let mut _4: i32; + scope 1 { + debug a => _1; + } + + bb0: { + StorageLive(_1); + _1 = const 0_i32; + _1 = const 1_i32; + StorageLive(_2); + StorageLive(_3); + StorageLive(_4); + _4 = copy _1; + _3 = Not(move _4); + StorageDead(_4); + _2 = Eq(move _3, const 0_i32); +- switchInt(move _2) -> [0: bb2, otherwise: bb1]; ++ goto -> bb1; + } + + bb1: { + StorageDead(_3); + _0 = const 1_i32; + goto -> bb3; + } + + bb2: { + StorageDead(_3); + _0 = const 0_i32; + goto -> bb3; + } + + bb3: { + StorageDead(_2); + StorageDead(_1); + return; + } + } + diff --git a/tests/mir-opt/jump_threading.rs b/tests/mir-opt/jump_threading.rs index 9487a4e7e5f..4094dec0cbf 100644 --- a/tests/mir-opt/jump_threading.rs +++ b/tests/mir-opt/jump_threading.rs @@ -531,6 +531,16 @@ fn floats() -> u32 { if x == 0.0 { 0 } else { 1 } } +pub fn bitwise_not() -> i32 { + // CHECK-LABEL: fn bitwise_not( + // CHECK: switchInt( + + // Test for #131195, which was optimizing `!a == b` into `a != b`. + let mut a: i32 = 0; + a = 1; + if !a == 0 { 1 } else { 0 } +} + fn main() { // CHECK-LABEL: fn main( too_complex(Ok(0)); @@ -562,3 +572,4 @@ fn main() { // EMIT_MIR jump_threading.assume.JumpThreading.diff // EMIT_MIR jump_threading.aggregate_copy.JumpThreading.diff // EMIT_MIR jump_threading.floats.JumpThreading.diff +// EMIT_MIR jump_threading.bitwise_not.JumpThreading.diff From d47e388843f682f57262f020edd9909c850a0c49 Mon Sep 17 00:00:00 2001 From: EFanZh Date: Thu, 3 Oct 2024 22:15:52 +0800 Subject: [PATCH 531/683] Avoid emptiness check in `PeekMut::pop` --- library/alloc/src/collections/binary_heap/mod.rs | 5 ++++- tests/codegen/binary-heap-peek-mut-pop-no-panic.rs | 13 +++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) create mode 100644 tests/codegen/binary-heap-peek-mut-pop-no-panic.rs diff --git a/library/alloc/src/collections/binary_heap/mod.rs b/library/alloc/src/collections/binary_heap/mod.rs index 5e59abf54ee..59f10b09c73 100644 --- a/library/alloc/src/collections/binary_heap/mod.rs +++ b/library/alloc/src/collections/binary_heap/mod.rs @@ -374,7 +374,10 @@ impl<'a, T: Ord, A: Allocator> PeekMut<'a, T, A> { // the caller could've mutated the element. It is removed from the // heap on the next line and pop() is not sensitive to its value. } - this.heap.pop().unwrap() + + // SAFETY: Have a `PeekMut` element proves that the associated binary heap being non-empty, + // so the `pop` operation will not fail. + unsafe { this.heap.pop().unwrap_unchecked() } } } diff --git a/tests/codegen/binary-heap-peek-mut-pop-no-panic.rs b/tests/codegen/binary-heap-peek-mut-pop-no-panic.rs new file mode 100644 index 00000000000..9cf4f210e52 --- /dev/null +++ b/tests/codegen/binary-heap-peek-mut-pop-no-panic.rs @@ -0,0 +1,13 @@ +//@ compile-flags: -O +//@ ignore-debug +#![crate_type = "lib"] + +use std::collections::binary_heap::PeekMut; + +// CHECK-LABEL: @peek_mut_pop +#[no_mangle] +pub fn peek_mut_pop(peek_mut: PeekMut) -> u32 { + // CHECK-NOT: panic + // CHECK-NOT: unwrap_failed + PeekMut::pop(peek_mut) +} From 456be106b714b3b2f5f3d43c801e28bb69fcc789 Mon Sep 17 00:00:00 2001 From: Kajetan Puchalski Date: Thu, 3 Oct 2024 15:22:44 +0100 Subject: [PATCH 532/683] bootstrap: Consolidate editor LSP setup Consolidate LSP setup for different editors into one `./x setup editor`. --- src/bootstrap/src/core/build_steps/setup.rs | 118 ++++++++++++-------- src/bootstrap/src/core/builder.rs | 10 +- src/bootstrap/src/core/config/flags.rs | 9 +- src/bootstrap/src/utils/change_tracker.rs | 2 +- src/etc/completions/x.py.sh | 2 +- 5 files changed, 78 insertions(+), 63 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/setup.rs b/src/bootstrap/src/core/build_steps/setup.rs index 3aa8d3a67d8..51964977933 100644 --- a/src/bootstrap/src/core/build_steps/setup.rs +++ b/src/bootstrap/src/core/build_steps/setup.rs @@ -528,6 +528,35 @@ enum EditorKind { } impl EditorKind { + fn prompt_user() -> io::Result> { + let prompt_str = "Available editors: +1. vscode +2. vim +3. emacs +4. helix + +Select which editor you would like to set up [default: None]: "; + + let mut input = String::new(); + loop { + print!("{}", prompt_str); + io::stdout().flush()?; + input.clear(); + io::stdin().read_line(&mut input)?; + match input.trim().to_lowercase().as_str() { + "1" | "vscode" => return Ok(Some(EditorKind::Vscode)), + "2" | "vim" => return Ok(Some(EditorKind::Vim)), + "3" | "emacs" => return Ok(Some(EditorKind::Emacs)), + "4" | "helix" => return Ok(Some(EditorKind::Helix)), + "" => return Ok(None), + _ => { + eprintln!("ERROR: unrecognized option '{}'", input.trim()); + eprintln!("NOTE: press Ctrl+C to exit"); + } + }; + } + } + /// A list of historical hashes of each LSP settings file /// New entries should be appended whenever this is updated so we can detect /// outdated vs. user-modified settings files. @@ -568,10 +597,10 @@ impl EditorKind { fn settings_folder(&self) -> PathBuf { match self { - EditorKind::Vscode => PathBuf::new().join(".vscode"), - EditorKind::Vim => PathBuf::new().join(".vim"), + EditorKind::Vscode => PathBuf::from(".vscode"), + EditorKind::Vim => PathBuf::from(".vim"), EditorKind::Emacs => PathBuf::new(), - EditorKind::Helix => PathBuf::new().join(".helix"), + EditorKind::Helix => PathBuf::from(".helix"), } } @@ -590,47 +619,46 @@ impl EditorKind { } } -/// Helper macro for implementing the necessary Step to support editor LSP setup -/// The first argument must match the argument set up in `flags.rs` -/// The second argument must match the name of some `EditorKind` variant -/// After using the macro, the editor needs to be registered in `builder.rs` with describe!() -macro_rules! impl_editor_support { - ( $($editor:ident, $kind:ident),+ ) => {$( - #[doc = concat!(" Sets up or displays the LSP config for ", stringify!($editor), ".")] - #[derive(Clone, Debug, Eq, PartialEq, Hash)] - pub struct $kind; +/// Sets up or displays the LSP config for one of the supported editors +#[derive(Clone, Debug, Eq, PartialEq, Hash)] +pub struct Editor; - impl Step for $kind { - type Output = (); - const DEFAULT: bool = true; - fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { - run.alias(stringify!($editor)) - } - fn make_run(run: RunConfig<'_>) { - if run.builder.config.dry_run() { - return; - } - if let [cmd] = &run.paths[..] { - if cmd.assert_single_path().path.as_path().as_os_str() == stringify!($editor) { - run.builder.ensure($kind); - } - } - } - fn run(self, builder: &Builder<'_>) -> Self::Output { - let config = &builder.config; - if config.dry_run() { - return; - } - while !t!(create_editor_settings_maybe(config, EditorKind::$kind)) {} +impl Step for Editor { + type Output = (); + const DEFAULT: bool = true; + + fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { + run.alias("editor") + } + + fn make_run(run: RunConfig<'_>) { + if run.builder.config.dry_run() { + return; + } + if let [cmd] = &run.paths[..] { + if cmd.assert_single_path().path.as_path().as_os_str() == "editor" { + run.builder.ensure(Editor); } } - )+}; -} + } -impl_editor_support!(vscode, Vscode); -impl_editor_support!(vim, Vim); -impl_editor_support!(emacs, Emacs); -impl_editor_support!(helix, Helix); + fn run(self, builder: &Builder<'_>) -> Self::Output { + let config = &builder.config; + if config.dry_run() { + return; + } + match EditorKind::prompt_user() { + Ok(editor_kind) => { + if let Some(editor_kind) = editor_kind { + while !t!(create_editor_settings_maybe(config, editor_kind.clone())) {} + } else { + println!("Ok, skipping editor setup!"); + } + } + Err(e) => eprintln!("Could not determine the editor: {e}"), + } + } +} /// Create the recommended editor LSP config file for rustc development, or just print it /// If this method should be re-called, it returns `false`. @@ -662,13 +690,11 @@ fn create_editor_settings_maybe(config: &Config, editor: EditorKind) -> io::Resu ); match mismatched_settings { - Some(true) => eprintln!( - "WARNING: existing `{}` is out of date, x.py will update it", - settings_filename - ), + Some(true) => { + eprintln!("WARNING: existing `{settings_filename}` is out of date, x.py will update it") + } Some(false) => eprintln!( - "WARNING: existing `{}` has been modified by user, x.py will back it up and replace it", - settings_filename + "WARNING: existing `{settings_filename}` has been modified by user, x.py will back it up and replace it" ), _ => (), } diff --git a/src/bootstrap/src/core/builder.rs b/src/bootstrap/src/core/builder.rs index 67f9a3ab3ed..abc7a228893 100644 --- a/src/bootstrap/src/core/builder.rs +++ b/src/bootstrap/src/core/builder.rs @@ -1001,15 +1001,7 @@ impl<'a> Builder<'a> { run::GenerateCompletions, ), Kind::Setup => { - describe!( - setup::Profile, - setup::Hook, - setup::Link, - setup::Vscode, - setup::Emacs, - setup::Helix, - setup::Vim - ) + describe!(setup::Profile, setup::Hook, setup::Link, setup::Editor) } Kind::Clean => describe!(clean::CleanAll, clean::Rustc, clean::Std), Kind::Vendor => describe!(vendor::Vendor), diff --git a/src/bootstrap/src/core/config/flags.rs b/src/bootstrap/src/core/config/flags.rs index fb27d1ebb18..3aefe517a5b 100644 --- a/src/bootstrap/src/core/config/flags.rs +++ b/src/bootstrap/src/core/config/flags.rs @@ -447,17 +447,14 @@ Arguments: The profile is optional and you will be prompted interactively if it is not given. The following profiles are available: {} - To only set up the git hook, VS Code config or toolchain link, you may use + To only set up the git hook, editor config or toolchain link, you may use ./x.py setup hook - ./x.py setup vscode - ./x.py setup vim - ./x.py setup emacs - ./x.py setup helix + ./x.py setup editor ./x.py setup link", Profile::all_for_help(" ").trim_end()))] Setup { /// Either the profile for `config.toml` or another setup action. /// May be omitted to set up interactively - #[arg(value_name = "|hook|vscode|vim|emacs|helix|link")] + #[arg(value_name = "|hook|editor|link")] profile: Option, }, /// Suggest a subset of tests to run, based on modified files diff --git a/src/bootstrap/src/utils/change_tracker.rs b/src/bootstrap/src/utils/change_tracker.rs index e6f5363dbf2..b37786496cb 100644 --- a/src/bootstrap/src/utils/change_tracker.rs +++ b/src/bootstrap/src/utils/change_tracker.rs @@ -273,6 +273,6 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[ ChangeInfo { change_id: 131075, severity: ChangeSeverity::Info, - summary: "New options for ./x setup added - ./x setup [vim|emacs|helix]", + summary: "New option `./x setup editor` added, replacing `./x setup vscode` and adding support for vim, emacs and helix.", }, ]; diff --git a/src/etc/completions/x.py.sh b/src/etc/completions/x.py.sh index 913b0e820cb..ba7f2c9fb5d 100644 --- a/src/etc/completions/x.py.sh +++ b/src/etc/completions/x.py.sh @@ -2741,7 +2741,7 @@ _x.py() { return 0 ;; x.py__setup) - opts="-v -i -j -h --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --help [|hook|vscode|vim|emacs|helix|link] [PATHS]... [ARGS]..." + opts="-v -i -j -h --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --help [|hook|editor|link] [PATHS]... [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 From bc5f9520c117b372b7ad7326fda1252cd9da3f4e Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 3 Oct 2024 15:19:23 -0400 Subject: [PATCH 533/683] Remove crashes, add comment --- .../traits/fulfillment_errors.rs | 2 ++ tests/crashes/125881.rs | 8 ----- tests/crashes/126377.rs | 29 ------------------- tests/crashes/130413.rs | 17 ----------- 4 files changed, 2 insertions(+), 54 deletions(-) delete mode 100644 tests/crashes/125881.rs delete mode 100644 tests/crashes/126377.rs delete mode 100644 tests/crashes/130413.rs 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 f494d9637f3..e2d067e012c 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 @@ -2224,6 +2224,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ) -> GetSafeTransmuteErrorAndReason { use rustc_transmute::Answer; + // We don't assemble a transmutability candidate for types that are generic + // and we should have ambiguity for types that still have non-region infer. if obligation.predicate.has_non_region_param() || obligation.has_non_region_infer() { return GetSafeTransmuteErrorAndReason::Default; } diff --git a/tests/crashes/125881.rs b/tests/crashes/125881.rs deleted file mode 100644 index a38f1891b61..00000000000 --- a/tests/crashes/125881.rs +++ /dev/null @@ -1,8 +0,0 @@ -//@ known-bug: rust-lang/rust#125881 -#![crate_type = "lib"] -#![feature(transmutability)] -#![feature(unboxed_closures,effects)] - -const fn test() -> impl std::mem::TransmuteFrom() { - || {} -} diff --git a/tests/crashes/126377.rs b/tests/crashes/126377.rs deleted file mode 100644 index f6727bcc0a4..00000000000 --- a/tests/crashes/126377.rs +++ /dev/null @@ -1,29 +0,0 @@ -//@ known-bug: rust-lang/rust#126377 - -#![feature(effects)] -#![feature(generic_const_exprs)] - -mod assert { - use std::mem::{Assume, TransmuteFrom}; - - pub fn is_transmutable< - Src, - Dst, - const ASSUME_ALIGNMENT: bool, - const ASSUME_LIFETIMES: bool, - const ASSUME_SAFETY: bool, - const ASSUME_VALIDITY: bool, - >() - where - Dst: TransmuteFrom< - Src, - { } - >, - {} -} - -const fn from_options() -> Assume { - #[repr(C)] struct Src; - #[repr(C)] struct Dst; - assert::is_transmutable::(); -} diff --git a/tests/crashes/130413.rs b/tests/crashes/130413.rs deleted file mode 100644 index 08435ac6450..00000000000 --- a/tests/crashes/130413.rs +++ /dev/null @@ -1,17 +0,0 @@ -//@ known-bug: #130413 - -#![feature(transmutability)] -trait Aaa { - type Y; -} - -trait Bbb { - type B: std::mem::TransmuteFrom<()>; -} - -impl Bbb for T -where - T: Aaa, -{ - type B = T::Y; -} From f0bfba258330884df9c9d14a0aafd741ca9bbdc9 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 3 Oct 2024 09:47:06 -0400 Subject: [PATCH 534/683] Disable jump threading UnOp::Not for non-bool --- .../rustc_mir_transform/src/jump_threading.rs | 8 ++++ ...bitwise_not.JumpThreading.panic-abort.diff | 46 +++++++++++++++++++ ...itwise_not.JumpThreading.panic-unwind.diff | 3 +- 3 files changed, 55 insertions(+), 2 deletions(-) create mode 100644 tests/mir-opt/jump_threading.bitwise_not.JumpThreading.panic-abort.diff diff --git a/compiler/rustc_mir_transform/src/jump_threading.rs b/compiler/rustc_mir_transform/src/jump_threading.rs index 1844b97887a..9b9b0b705bf 100644 --- a/compiler/rustc_mir_transform/src/jump_threading.rs +++ b/compiler/rustc_mir_transform/src/jump_threading.rs @@ -494,8 +494,16 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> { } // Transfer the conditions on the copy rhs, after inversing polarity. Rvalue::UnaryOp(UnOp::Not, Operand::Move(place) | Operand::Copy(place)) => { + if !place.ty(self.body, self.tcx).ty.is_bool() { + // Constructing the conditions by inverting the polarity + // of equality is only correct for bools. That is to say, + // `!a == b` is not `a != b` for integers greater than 1 bit. + return; + } let Some(conditions) = state.try_get_idx(lhs, &self.map) else { return }; let Some(place) = self.map.find(place.as_ref()) else { return }; + // FIXME: I think This could be generalized to not bool if we + // actually perform a logical not on the condition's value. let conds = conditions.map(self.arena, Condition::inv); state.insert_value_idx(place, conds, &self.map); } diff --git a/tests/mir-opt/jump_threading.bitwise_not.JumpThreading.panic-abort.diff b/tests/mir-opt/jump_threading.bitwise_not.JumpThreading.panic-abort.diff new file mode 100644 index 00000000000..047441e6099 --- /dev/null +++ b/tests/mir-opt/jump_threading.bitwise_not.JumpThreading.panic-abort.diff @@ -0,0 +1,46 @@ +- // MIR for `bitwise_not` before JumpThreading ++ // MIR for `bitwise_not` after JumpThreading + + fn bitwise_not() -> i32 { + let mut _0: i32; + let mut _1: i32; + let mut _2: bool; + let mut _3: i32; + let mut _4: i32; + scope 1 { + debug a => _1; + } + + bb0: { + StorageLive(_1); + _1 = const 0_i32; + _1 = const 1_i32; + StorageLive(_2); + StorageLive(_3); + StorageLive(_4); + _4 = copy _1; + _3 = Not(move _4); + StorageDead(_4); + _2 = Eq(move _3, const 0_i32); + switchInt(move _2) -> [0: bb2, otherwise: bb1]; + } + + bb1: { + StorageDead(_3); + _0 = const 1_i32; + goto -> bb3; + } + + bb2: { + StorageDead(_3); + _0 = const 0_i32; + goto -> bb3; + } + + bb3: { + StorageDead(_2); + StorageDead(_1); + return; + } + } + diff --git a/tests/mir-opt/jump_threading.bitwise_not.JumpThreading.panic-unwind.diff b/tests/mir-opt/jump_threading.bitwise_not.JumpThreading.panic-unwind.diff index fb64fff7e11..047441e6099 100644 --- a/tests/mir-opt/jump_threading.bitwise_not.JumpThreading.panic-unwind.diff +++ b/tests/mir-opt/jump_threading.bitwise_not.JumpThreading.panic-unwind.diff @@ -22,8 +22,7 @@ _3 = Not(move _4); StorageDead(_4); _2 = Eq(move _3, const 0_i32); -- switchInt(move _2) -> [0: bb2, otherwise: bb1]; -+ goto -> bb1; + switchInt(move _2) -> [0: bb2, otherwise: bb1]; } bb1: { From 0aab10135dd3d4e43e44ba5c375f5fae382cae49 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 3 Oct 2024 16:20:26 +1000 Subject: [PATCH 535/683] Merge `rustc_infer::infer::relate::{glb,lub}`. Most of the code in these two modules is duplicated in the other module. This commit eliminates the duplication by replacing them with a new module `lattice_op`. The new `LatticeOpKind` enum is used to distinguish between glb and lub in the few places where the behaviour differs. --- .../rustc_infer/src/infer/relate/combine.rs | 13 +- compiler/rustc_infer/src/infer/relate/glb.rs | 159 -------------- .../rustc_infer/src/infer/relate/lattice.rs | 197 +++++++++++++++++- compiler/rustc_infer/src/infer/relate/lub.rs | 158 -------------- compiler/rustc_infer/src/infer/relate/mod.rs | 2 - 5 files changed, 196 insertions(+), 333 deletions(-) delete mode 100644 compiler/rustc_infer/src/infer/relate/glb.rs delete mode 100644 compiler/rustc_infer/src/infer/relate/lub.rs diff --git a/compiler/rustc_infer/src/infer/relate/combine.rs b/compiler/rustc_infer/src/infer/relate/combine.rs index e75d7b7db14..d9e59d67ba3 100644 --- a/compiler/rustc_infer/src/infer/relate/combine.rs +++ b/compiler/rustc_infer/src/infer/relate/combine.rs @@ -1,4 +1,4 @@ -//! There are four type combiners: [TypeRelating], [Lub], and [Glb], +//! There are four type combiners: [TypeRelating], `Lub`, and `Glb`, //! and `NllTypeRelating` in rustc_borrowck, which is only used for NLL. //! //! Each implements the trait [TypeRelation] and contains methods for @@ -26,8 +26,7 @@ use rustc_middle::ty::{self, InferConst, IntType, Ty, TyCtxt, TypeVisitableExt, pub use rustc_next_trait_solver::relate::combine::*; use tracing::debug; -use super::glb::Glb; -use super::lub::Lub; +use super::lattice::{LatticeOp, LatticeOpKind}; use super::type_relating::TypeRelating; use super::{RelateResult, StructurallyRelateAliases}; use crate::infer::{DefineOpaqueTypes, InferCtxt, TypeTrace, relate}; @@ -298,12 +297,12 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> { TypeRelating::new(self, StructurallyRelateAliases::No, ty::Contravariant) } - pub fn lub<'a>(&'a mut self) -> Lub<'a, 'infcx, 'tcx> { - Lub::new(self) + pub(crate) fn lub<'a>(&'a mut self) -> LatticeOp<'a, 'infcx, 'tcx> { + LatticeOp::new(self, LatticeOpKind::Lub) } - pub fn glb<'a>(&'a mut self) -> Glb<'a, 'infcx, 'tcx> { - Glb::new(self) + pub(crate) fn glb<'a>(&'a mut self) -> LatticeOp<'a, 'infcx, 'tcx> { + LatticeOp::new(self, LatticeOpKind::Glb) } pub fn register_obligations( diff --git a/compiler/rustc_infer/src/infer/relate/glb.rs b/compiler/rustc_infer/src/infer/relate/glb.rs deleted file mode 100644 index ed108f42969..00000000000 --- a/compiler/rustc_infer/src/infer/relate/glb.rs +++ /dev/null @@ -1,159 +0,0 @@ -//! Greatest lower bound. See [`lattice`]. - -use rustc_middle::traits::solve::Goal; -use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation}; -use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt}; -use rustc_span::Span; -use tracing::{debug, instrument}; - -use super::StructurallyRelateAliases; -use super::combine::{CombineFields, PredicateEmittingRelation}; -use super::lattice::{self, LatticeDir}; -use crate::infer::{DefineOpaqueTypes, InferCtxt, SubregionOrigin}; -use crate::traits::ObligationCause; - -/// "Greatest lower bound" (common subtype) -pub struct Glb<'combine, 'infcx, 'tcx> { - fields: &'combine mut CombineFields<'infcx, 'tcx>, -} - -impl<'combine, 'infcx, 'tcx> Glb<'combine, 'infcx, 'tcx> { - pub fn new(fields: &'combine mut CombineFields<'infcx, 'tcx>) -> Glb<'combine, 'infcx, 'tcx> { - Glb { fields } - } -} - -impl<'tcx> TypeRelation> for Glb<'_, '_, 'tcx> { - fn cx(&self) -> TyCtxt<'tcx> { - self.fields.tcx() - } - - fn relate_with_variance>>( - &mut self, - variance: ty::Variance, - _info: ty::VarianceDiagInfo>, - a: T, - b: T, - ) -> RelateResult<'tcx, T> { - match variance { - ty::Invariant => self.fields.equate(StructurallyRelateAliases::No).relate(a, b), - ty::Covariant => self.relate(a, b), - // FIXME(#41044) -- not correct, need test - ty::Bivariant => Ok(a), - ty::Contravariant => self.fields.lub().relate(a, b), - } - } - - #[instrument(skip(self), level = "trace")] - fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { - lattice::super_lattice_tys(self, a, b) - } - - #[instrument(skip(self), level = "trace")] - fn regions( - &mut self, - a: ty::Region<'tcx>, - b: ty::Region<'tcx>, - ) -> RelateResult<'tcx, ty::Region<'tcx>> { - let origin = SubregionOrigin::Subtype(Box::new(self.fields.trace.clone())); - // GLB(&'static u8, &'a u8) == &RegionLUB('static, 'a) u8 == &'static u8 - Ok(self.fields.infcx.inner.borrow_mut().unwrap_region_constraints().lub_regions( - self.cx(), - origin, - a, - b, - )) - } - - #[instrument(skip(self), level = "trace")] - fn consts( - &mut self, - a: ty::Const<'tcx>, - b: ty::Const<'tcx>, - ) -> RelateResult<'tcx, ty::Const<'tcx>> { - self.fields.infcx.super_combine_consts(self, a, b) - } - - fn binders( - &mut self, - a: ty::Binder<'tcx, T>, - b: ty::Binder<'tcx, T>, - ) -> RelateResult<'tcx, ty::Binder<'tcx, T>> - where - T: Relate>, - { - // GLB of a binder and itself is just itself - if a == b { - return Ok(a); - } - - debug!("binders(a={:?}, b={:?})", a, b); - if a.skip_binder().has_escaping_bound_vars() || b.skip_binder().has_escaping_bound_vars() { - // When higher-ranked types are involved, computing the GLB is - // very challenging, switch to invariance. This is obviously - // overly conservative but works ok in practice. - self.relate_with_variance(ty::Invariant, ty::VarianceDiagInfo::default(), a, b)?; - Ok(a) - } else { - Ok(ty::Binder::dummy(self.relate(a.skip_binder(), b.skip_binder())?)) - } - } -} - -impl<'combine, 'infcx, 'tcx> LatticeDir<'infcx, 'tcx> for Glb<'combine, 'infcx, 'tcx> { - fn infcx(&self) -> &'infcx InferCtxt<'tcx> { - self.fields.infcx - } - - fn cause(&self) -> &ObligationCause<'tcx> { - &self.fields.trace.cause - } - - fn relate_bound(&mut self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()> { - let mut sub = self.fields.sub(); - sub.relate(v, a)?; - sub.relate(v, b)?; - Ok(()) - } - - fn define_opaque_types(&self) -> DefineOpaqueTypes { - self.fields.define_opaque_types - } -} - -impl<'tcx> PredicateEmittingRelation> for Glb<'_, '_, 'tcx> { - fn span(&self) -> Span { - self.fields.trace.span() - } - - fn structurally_relate_aliases(&self) -> StructurallyRelateAliases { - StructurallyRelateAliases::No - } - - fn param_env(&self) -> ty::ParamEnv<'tcx> { - self.fields.param_env - } - - fn register_predicates( - &mut self, - obligations: impl IntoIterator, ty::Predicate<'tcx>>>, - ) { - self.fields.register_predicates(obligations); - } - - fn register_goals( - &mut self, - obligations: impl IntoIterator>>, - ) { - self.fields.register_obligations(obligations); - } - - fn register_alias_relate_predicate(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) { - self.register_predicates([ty::Binder::dummy(ty::PredicateKind::AliasRelate( - a.into(), - b.into(), - // FIXME(deferred_projection_equality): This isn't right, I think? - ty::AliasRelationDirection::Equate, - ))]); - } -} diff --git a/compiler/rustc_infer/src/infer/relate/lattice.rs b/compiler/rustc_infer/src/infer/relate/lattice.rs index 1d3f45465d6..1e4db708986 100644 --- a/compiler/rustc_infer/src/infer/relate/lattice.rs +++ b/compiler/rustc_infer/src/infer/relate/lattice.rs @@ -17,12 +17,15 @@ //! //! [lattices]: https://en.wikipedia.org/wiki/Lattice_(order) -use rustc_middle::ty::relate::RelateResult; -use rustc_middle::ty::{self, Ty, TyVar}; -use tracing::instrument; +use rustc_middle::traits::solve::Goal; +use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation}; +use rustc_middle::ty::{self, Ty, TyCtxt, TyVar, TypeVisitableExt}; +use rustc_span::Span; +use tracing::{debug, instrument}; -use super::combine::PredicateEmittingRelation; -use crate::infer::{DefineOpaqueTypes, InferCtxt}; +use super::StructurallyRelateAliases; +use super::combine::{CombineFields, PredicateEmittingRelation}; +use crate::infer::{DefineOpaqueTypes, InferCtxt, SubregionOrigin}; use crate::traits::ObligationCause; /// Trait for returning data about a lattice, and for abstracting @@ -30,7 +33,7 @@ use crate::traits::ObligationCause; /// /// GLB moves "down" the lattice (to smaller values); LUB moves /// "up" the lattice (to bigger values). -pub(crate) trait LatticeDir<'f, 'tcx>: PredicateEmittingRelation> { +trait LatticeDir<'f, 'tcx>: PredicateEmittingRelation> { fn infcx(&self) -> &'f InferCtxt<'tcx>; fn cause(&self) -> &ObligationCause<'tcx>; @@ -48,7 +51,7 @@ pub(crate) trait LatticeDir<'f, 'tcx>: PredicateEmittingRelation /// Relates two types using a given lattice. #[instrument(skip(this), level = "debug")] -pub fn super_lattice_tys<'a, 'tcx: 'a, L>( +fn super_lattice_tys<'a, 'tcx: 'a, L>( this: &mut L, a: Ty<'tcx>, b: Ty<'tcx>, @@ -113,3 +116,183 @@ where _ => infcx.super_combine_tys(this, a, b), } } + +#[derive(Clone, Copy)] +pub(crate) enum LatticeOpKind { + Glb, + Lub, +} + +impl LatticeOpKind { + fn invert(self) -> Self { + match self { + LatticeOpKind::Glb => LatticeOpKind::Lub, + LatticeOpKind::Lub => LatticeOpKind::Glb, + } + } +} + +/// A greatest lower bound" (common subtype) or least upper bound (common supertype). +pub(crate) struct LatticeOp<'combine, 'infcx, 'tcx> { + fields: &'combine mut CombineFields<'infcx, 'tcx>, + kind: LatticeOpKind, +} + +impl<'combine, 'infcx, 'tcx> LatticeOp<'combine, 'infcx, 'tcx> { + pub(crate) fn new( + fields: &'combine mut CombineFields<'infcx, 'tcx>, + kind: LatticeOpKind, + ) -> LatticeOp<'combine, 'infcx, 'tcx> { + LatticeOp { fields, kind } + } +} + +impl<'tcx> TypeRelation> for LatticeOp<'_, '_, 'tcx> { + fn cx(&self) -> TyCtxt<'tcx> { + self.fields.tcx() + } + + fn relate_with_variance>>( + &mut self, + variance: ty::Variance, + _info: ty::VarianceDiagInfo>, + a: T, + b: T, + ) -> RelateResult<'tcx, T> { + match variance { + ty::Invariant => self.fields.equate(StructurallyRelateAliases::No).relate(a, b), + ty::Covariant => self.relate(a, b), + // FIXME(#41044) -- not correct, need test + ty::Bivariant => Ok(a), + ty::Contravariant => { + self.kind = self.kind.invert(); + let res = self.relate(a, b); + self.kind = self.kind.invert(); + res + } + } + } + + #[instrument(skip(self), level = "trace")] + fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { + super_lattice_tys(self, a, b) + } + + #[instrument(skip(self), level = "trace")] + fn regions( + &mut self, + a: ty::Region<'tcx>, + b: ty::Region<'tcx>, + ) -> RelateResult<'tcx, ty::Region<'tcx>> { + let origin = SubregionOrigin::Subtype(Box::new(self.fields.trace.clone())); + let mut inner = self.fields.infcx.inner.borrow_mut(); + let mut constraints = inner.unwrap_region_constraints(); + Ok(match self.kind { + // GLB(&'static u8, &'a u8) == &RegionLUB('static, 'a) u8 == &'static u8 + LatticeOpKind::Glb => constraints.lub_regions(self.cx(), origin, a, b), + + // LUB(&'static u8, &'a u8) == &RegionGLB('static, 'a) u8 == &'a u8 + LatticeOpKind::Lub => constraints.glb_regions(self.cx(), origin, a, b), + }) + } + + #[instrument(skip(self), level = "trace")] + fn consts( + &mut self, + a: ty::Const<'tcx>, + b: ty::Const<'tcx>, + ) -> RelateResult<'tcx, ty::Const<'tcx>> { + self.fields.infcx.super_combine_consts(self, a, b) + } + + fn binders( + &mut self, + a: ty::Binder<'tcx, T>, + b: ty::Binder<'tcx, T>, + ) -> RelateResult<'tcx, ty::Binder<'tcx, T>> + where + T: Relate>, + { + // GLB/LUB of a binder and itself is just itself + if a == b { + return Ok(a); + } + + debug!("binders(a={:?}, b={:?})", a, b); + if a.skip_binder().has_escaping_bound_vars() || b.skip_binder().has_escaping_bound_vars() { + // When higher-ranked types are involved, computing the GLB/LUB is + // very challenging, switch to invariance. This is obviously + // overly conservative but works ok in practice. + self.relate_with_variance(ty::Invariant, ty::VarianceDiagInfo::default(), a, b)?; + Ok(a) + } else { + Ok(ty::Binder::dummy(self.relate(a.skip_binder(), b.skip_binder())?)) + } + } +} + +impl<'combine, 'infcx, 'tcx> LatticeDir<'infcx, 'tcx> for LatticeOp<'combine, 'infcx, 'tcx> { + fn infcx(&self) -> &'infcx InferCtxt<'tcx> { + self.fields.infcx + } + + fn cause(&self) -> &ObligationCause<'tcx> { + &self.fields.trace.cause + } + + fn relate_bound(&mut self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()> { + let mut sub = self.fields.sub(); + match self.kind { + LatticeOpKind::Glb => { + sub.relate(v, a)?; + sub.relate(v, b)?; + } + LatticeOpKind::Lub => { + sub.relate(a, v)?; + sub.relate(b, v)?; + } + } + Ok(()) + } + + fn define_opaque_types(&self) -> DefineOpaqueTypes { + self.fields.define_opaque_types + } +} + +impl<'tcx> PredicateEmittingRelation> for LatticeOp<'_, '_, 'tcx> { + fn span(&self) -> Span { + self.fields.trace.span() + } + + fn structurally_relate_aliases(&self) -> StructurallyRelateAliases { + StructurallyRelateAliases::No + } + + fn param_env(&self) -> ty::ParamEnv<'tcx> { + self.fields.param_env + } + + fn register_predicates( + &mut self, + obligations: impl IntoIterator, ty::Predicate<'tcx>>>, + ) { + self.fields.register_predicates(obligations); + } + + fn register_goals( + &mut self, + obligations: impl IntoIterator>>, + ) { + self.fields.register_obligations(obligations); + } + + fn register_alias_relate_predicate(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) { + self.register_predicates([ty::Binder::dummy(ty::PredicateKind::AliasRelate( + a.into(), + b.into(), + // FIXME(deferred_projection_equality): This isn't right, I think? + ty::AliasRelationDirection::Equate, + ))]); + } +} diff --git a/compiler/rustc_infer/src/infer/relate/lub.rs b/compiler/rustc_infer/src/infer/relate/lub.rs deleted file mode 100644 index 35c7ab5000d..00000000000 --- a/compiler/rustc_infer/src/infer/relate/lub.rs +++ /dev/null @@ -1,158 +0,0 @@ -//! Least upper bound. See [`lattice`]. - -use rustc_middle::traits::solve::Goal; -use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation}; -use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt}; -use rustc_span::Span; -use tracing::{debug, instrument}; - -use super::StructurallyRelateAliases; -use super::combine::{CombineFields, PredicateEmittingRelation}; -use super::lattice::{self, LatticeDir}; -use crate::infer::{DefineOpaqueTypes, InferCtxt, SubregionOrigin}; -use crate::traits::ObligationCause; - -/// "Least upper bound" (common supertype) -pub struct Lub<'combine, 'infcx, 'tcx> { - fields: &'combine mut CombineFields<'infcx, 'tcx>, -} - -impl<'combine, 'infcx, 'tcx> Lub<'combine, 'infcx, 'tcx> { - pub fn new(fields: &'combine mut CombineFields<'infcx, 'tcx>) -> Lub<'combine, 'infcx, 'tcx> { - Lub { fields } - } -} - -impl<'tcx> TypeRelation> for Lub<'_, '_, 'tcx> { - fn cx(&self) -> TyCtxt<'tcx> { - self.fields.tcx() - } - - fn relate_with_variance>>( - &mut self, - variance: ty::Variance, - _info: ty::VarianceDiagInfo>, - a: T, - b: T, - ) -> RelateResult<'tcx, T> { - match variance { - ty::Invariant => self.fields.equate(StructurallyRelateAliases::No).relate(a, b), - ty::Covariant => self.relate(a, b), - // FIXME(#41044) -- not correct, need test - ty::Bivariant => Ok(a), - ty::Contravariant => self.fields.glb().relate(a, b), - } - } - - fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { - lattice::super_lattice_tys(self, a, b) - } - - #[instrument(skip(self), level = "trace")] - fn regions( - &mut self, - a: ty::Region<'tcx>, - b: ty::Region<'tcx>, - ) -> RelateResult<'tcx, ty::Region<'tcx>> { - let origin = SubregionOrigin::Subtype(Box::new(self.fields.trace.clone())); - // LUB(&'static u8, &'a u8) == &RegionGLB('static, 'a) u8 == &'a u8 - Ok(self.fields.infcx.inner.borrow_mut().unwrap_region_constraints().glb_regions( - self.cx(), - origin, - a, - b, - )) - } - - #[instrument(skip(self), level = "trace")] - fn consts( - &mut self, - a: ty::Const<'tcx>, - b: ty::Const<'tcx>, - ) -> RelateResult<'tcx, ty::Const<'tcx>> { - self.fields.infcx.super_combine_consts(self, a, b) - } - - fn binders( - &mut self, - a: ty::Binder<'tcx, T>, - b: ty::Binder<'tcx, T>, - ) -> RelateResult<'tcx, ty::Binder<'tcx, T>> - where - T: Relate>, - { - // LUB of a binder and itself is just itself - if a == b { - return Ok(a); - } - - debug!("binders(a={:?}, b={:?})", a, b); - if a.skip_binder().has_escaping_bound_vars() || b.skip_binder().has_escaping_bound_vars() { - // When higher-ranked types are involved, computing the LUB is - // very challenging, switch to invariance. This is obviously - // overly conservative but works ok in practice. - self.relate_with_variance(ty::Invariant, ty::VarianceDiagInfo::default(), a, b)?; - Ok(a) - } else { - Ok(ty::Binder::dummy(self.relate(a.skip_binder(), b.skip_binder())?)) - } - } -} - -impl<'combine, 'infcx, 'tcx> LatticeDir<'infcx, 'tcx> for Lub<'combine, 'infcx, 'tcx> { - fn infcx(&self) -> &'infcx InferCtxt<'tcx> { - self.fields.infcx - } - - fn cause(&self) -> &ObligationCause<'tcx> { - &self.fields.trace.cause - } - - fn relate_bound(&mut self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()> { - let mut sub = self.fields.sub(); - sub.relate(a, v)?; - sub.relate(b, v)?; - Ok(()) - } - - fn define_opaque_types(&self) -> DefineOpaqueTypes { - self.fields.define_opaque_types - } -} - -impl<'tcx> PredicateEmittingRelation> for Lub<'_, '_, 'tcx> { - fn span(&self) -> Span { - self.fields.trace.span() - } - - fn structurally_relate_aliases(&self) -> StructurallyRelateAliases { - StructurallyRelateAliases::No - } - - fn param_env(&self) -> ty::ParamEnv<'tcx> { - self.fields.param_env - } - - fn register_predicates( - &mut self, - obligations: impl IntoIterator, ty::Predicate<'tcx>>>, - ) { - self.fields.register_predicates(obligations); - } - - fn register_goals( - &mut self, - obligations: impl IntoIterator>>, - ) { - self.fields.register_obligations(obligations) - } - - fn register_alias_relate_predicate(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) { - self.register_predicates([ty::Binder::dummy(ty::PredicateKind::AliasRelate( - a.into(), - b.into(), - // FIXME(deferred_projection_equality): This isn't right, I think? - ty::AliasRelationDirection::Equate, - ))]); - } -} diff --git a/compiler/rustc_infer/src/infer/relate/mod.rs b/compiler/rustc_infer/src/infer/relate/mod.rs index 183ea5b3309..edc0c4f078a 100644 --- a/compiler/rustc_infer/src/infer/relate/mod.rs +++ b/compiler/rustc_infer/src/infer/relate/mod.rs @@ -10,8 +10,6 @@ pub use self::combine::{CombineFields, PredicateEmittingRelation}; #[allow(hidden_glob_reexports)] pub(super) mod combine; mod generalize; -mod glb; mod higher_ranked; mod lattice; -mod lub; mod type_relating; From ee227dec8c84fc5a65ef798af93863a97794502e Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 3 Oct 2024 17:41:32 +1000 Subject: [PATCH 536/683] Remove `LatticeDir` trait. It's no longer necessary now that the `glb` and `lub` modules have been merged. --- .../rustc_infer/src/infer/relate/lattice.rs | 173 +++++++----------- 1 file changed, 69 insertions(+), 104 deletions(-) diff --git a/compiler/rustc_infer/src/infer/relate/lattice.rs b/compiler/rustc_infer/src/infer/relate/lattice.rs index 1e4db708986..9564baa6ab2 100644 --- a/compiler/rustc_infer/src/infer/relate/lattice.rs +++ b/compiler/rustc_infer/src/infer/relate/lattice.rs @@ -26,96 +26,6 @@ use tracing::{debug, instrument}; use super::StructurallyRelateAliases; use super::combine::{CombineFields, PredicateEmittingRelation}; use crate::infer::{DefineOpaqueTypes, InferCtxt, SubregionOrigin}; -use crate::traits::ObligationCause; - -/// Trait for returning data about a lattice, and for abstracting -/// over the "direction" of the lattice operation (LUB/GLB). -/// -/// GLB moves "down" the lattice (to smaller values); LUB moves -/// "up" the lattice (to bigger values). -trait LatticeDir<'f, 'tcx>: PredicateEmittingRelation> { - fn infcx(&self) -> &'f InferCtxt<'tcx>; - - fn cause(&self) -> &ObligationCause<'tcx>; - - fn define_opaque_types(&self) -> DefineOpaqueTypes; - - // Relates the type `v` to `a` and `b` such that `v` represents - // the LUB/GLB of `a` and `b` as appropriate. - // - // Subtle hack: ordering *may* be significant here. This method - // relates `v` to `a` first, which may help us to avoid unnecessary - // type variable obligations. See caller for details. - fn relate_bound(&mut self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()>; -} - -/// Relates two types using a given lattice. -#[instrument(skip(this), level = "debug")] -fn super_lattice_tys<'a, 'tcx: 'a, L>( - this: &mut L, - a: Ty<'tcx>, - b: Ty<'tcx>, -) -> RelateResult<'tcx, Ty<'tcx>> -where - L: LatticeDir<'a, 'tcx>, -{ - if a == b { - return Ok(a); - } - - let infcx = this.infcx(); - - let a = infcx.shallow_resolve(a); - let b = infcx.shallow_resolve(b); - - match (a.kind(), b.kind()) { - // If one side is known to be a variable and one is not, - // create a variable (`v`) to represent the LUB. Make sure to - // relate `v` to the non-type-variable first (by passing it - // first to `relate_bound`). Otherwise, we would produce a - // subtype obligation that must then be processed. - // - // Example: if the LHS is a type variable, and RHS is - // `Box`, then we current compare `v` to the RHS first, - // which will instantiate `v` with `Box`. Then when `v` - // is compared to the LHS, we instantiate LHS with `Box`. - // But if we did in reverse order, we would create a `v <: - // LHS` (or vice versa) constraint and then instantiate - // `v`. This would require further processing to achieve same - // end-result; in particular, this screws up some of the logic - // in coercion, which expects LUB to figure out that the LHS - // is (e.g.) `Box`. A more obvious solution might be to - // iterate on the subtype obligations that are returned, but I - // think this suffices. -nmatsakis - (&ty::Infer(TyVar(..)), _) => { - let v = infcx.next_ty_var(this.cause().span); - this.relate_bound(v, b, a)?; - Ok(v) - } - (_, &ty::Infer(TyVar(..))) => { - let v = infcx.next_ty_var(this.cause().span); - this.relate_bound(v, a, b)?; - Ok(v) - } - - ( - &ty::Alias(ty::Opaque, ty::AliasTy { def_id: a_def_id, .. }), - &ty::Alias(ty::Opaque, ty::AliasTy { def_id: b_def_id, .. }), - ) if a_def_id == b_def_id => infcx.super_combine_tys(this, a, b), - - (&ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }), _) - | (_, &ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. })) - if this.define_opaque_types() == DefineOpaqueTypes::Yes - && def_id.is_local() - && !this.infcx().next_trait_solver() => - { - this.register_goals(infcx.handle_opaque_type(a, b, this.span(), this.param_env())?); - Ok(a) - } - - _ => infcx.super_combine_tys(this, a, b), - } -} #[derive(Clone, Copy)] pub(crate) enum LatticeOpKind { @@ -173,9 +83,70 @@ impl<'tcx> TypeRelation> for LatticeOp<'_, '_, 'tcx> { } } + /// Relates two types using a given lattice. #[instrument(skip(self), level = "trace")] fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { - super_lattice_tys(self, a, b) + if a == b { + return Ok(a); + } + + let infcx = self.fields.infcx; + + let a = infcx.shallow_resolve(a); + let b = infcx.shallow_resolve(b); + + match (a.kind(), b.kind()) { + // If one side is known to be a variable and one is not, + // create a variable (`v`) to represent the LUB. Make sure to + // relate `v` to the non-type-variable first (by passing it + // first to `relate_bound`). Otherwise, we would produce a + // subtype obligation that must then be processed. + // + // Example: if the LHS is a type variable, and RHS is + // `Box`, then we current compare `v` to the RHS first, + // which will instantiate `v` with `Box`. Then when `v` + // is compared to the LHS, we instantiate LHS with `Box`. + // But if we did in reverse order, we would create a `v <: + // LHS` (or vice versa) constraint and then instantiate + // `v`. This would require further processing to achieve same + // end-result; in particular, this screws up some of the logic + // in coercion, which expects LUB to figure out that the LHS + // is (e.g.) `Box`. A more obvious solution might be to + // iterate on the subtype obligations that are returned, but I + // think this suffices. -nmatsakis + (&ty::Infer(TyVar(..)), _) => { + let v = infcx.next_ty_var(self.fields.trace.cause.span); + self.relate_bound(v, b, a)?; + Ok(v) + } + (_, &ty::Infer(TyVar(..))) => { + let v = infcx.next_ty_var(self.fields.trace.cause.span); + self.relate_bound(v, a, b)?; + Ok(v) + } + + ( + &ty::Alias(ty::Opaque, ty::AliasTy { def_id: a_def_id, .. }), + &ty::Alias(ty::Opaque, ty::AliasTy { def_id: b_def_id, .. }), + ) if a_def_id == b_def_id => infcx.super_combine_tys(self, a, b), + + (&ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }), _) + | (_, &ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. })) + if self.fields.define_opaque_types == DefineOpaqueTypes::Yes + && def_id.is_local() + && !infcx.next_trait_solver() => + { + self.register_goals(infcx.handle_opaque_type( + a, + b, + self.span(), + self.param_env(), + )?); + Ok(a) + } + + _ => infcx.super_combine_tys(self, a, b), + } } #[instrument(skip(self), level = "trace")] @@ -231,15 +202,13 @@ impl<'tcx> TypeRelation> for LatticeOp<'_, '_, 'tcx> { } } -impl<'combine, 'infcx, 'tcx> LatticeDir<'infcx, 'tcx> for LatticeOp<'combine, 'infcx, 'tcx> { - fn infcx(&self) -> &'infcx InferCtxt<'tcx> { - self.fields.infcx - } - - fn cause(&self) -> &ObligationCause<'tcx> { - &self.fields.trace.cause - } - +impl<'combine, 'infcx, 'tcx> LatticeOp<'combine, 'infcx, 'tcx> { + // Relates the type `v` to `a` and `b` such that `v` represents + // the LUB/GLB of `a` and `b` as appropriate. + // + // Subtle hack: ordering *may* be significant here. This method + // relates `v` to `a` first, which may help us to avoid unnecessary + // type variable obligations. See caller for details. fn relate_bound(&mut self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()> { let mut sub = self.fields.sub(); match self.kind { @@ -254,10 +223,6 @@ impl<'combine, 'infcx, 'tcx> LatticeDir<'infcx, 'tcx> for LatticeOp<'combine, 'i } Ok(()) } - - fn define_opaque_types(&self) -> DefineOpaqueTypes { - self.fields.define_opaque_types - } } impl<'tcx> PredicateEmittingRelation> for LatticeOp<'_, '_, 'tcx> { From d19bd66a4e88116af18a1f5a6ab4ffe2f5bd1956 Mon Sep 17 00:00:00 2001 From: The Miri Cronjob Bot Date: Fri, 4 Oct 2024 05:00:12 +0000 Subject: [PATCH 537/683] Preparing for merge from rustc --- src/tools/miri/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index fe0421b2075..eb4dfcf57cf 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -ad9c494835e746fb7c8a26eeed0ad90e4e834058 +7067e4aee45c18cfa1c6af3bf79bd097684fb294 From 253fec494fa336ee27c6cb027ffdb3d6e0b632c3 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Thu, 3 Oct 2024 17:42:08 -0700 Subject: [PATCH 538/683] rustdoc: prevent ctors from resolving --- compiler/rustc_resolve/src/lib.rs | 4 +- .../intra-doc/disambiguator-mismatch.rs | 4 +- .../intra-doc/disambiguator-mismatch.stderr | 6 +- tests/rustdoc-ui/intra-doc/value-ctor.rs | 35 +++++++++++ tests/rustdoc-ui/intra-doc/value-ctor.stderr | 62 +++++++++++++++++++ 5 files changed, 105 insertions(+), 6 deletions(-) create mode 100644 tests/rustdoc-ui/intra-doc/value-ctor.rs create mode 100644 tests/rustdoc-ui/intra-doc/value-ctor.stderr diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index fcbbb523cfc..24a0c252e55 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -2148,7 +2148,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { match self.maybe_resolve_path(&segments, Some(ns), &parent_scope, None) { PathResult::Module(ModuleOrUniformRoot::Module(module)) => Some(module.res().unwrap()), - PathResult::NonModule(path_res) => path_res.full_res(), + PathResult::NonModule(path_res) => { + path_res.full_res().filter(|res| !matches!(res, Res::Def(DefKind::Ctor(..), _))) + } PathResult::Module(ModuleOrUniformRoot::ExternPrelude) | PathResult::Failed { .. } => { None } diff --git a/tests/rustdoc-ui/intra-doc/disambiguator-mismatch.rs b/tests/rustdoc-ui/intra-doc/disambiguator-mismatch.rs index 8142bd83877..f63a9e87497 100644 --- a/tests/rustdoc-ui/intra-doc/disambiguator-mismatch.rs +++ b/tests/rustdoc-ui/intra-doc/disambiguator-mismatch.rs @@ -91,7 +91,7 @@ struct X { //~| HELP prefix with `field@` /// Link to [field@S::A] -//~^ ERROR incompatible link kind for `S::A` -//~| NOTE this link resolved +//~^ ERROR unresolved link to `S::A` +//~| NOTE this link resolves //~| HELP prefix with `variant@` pub fn f() {} diff --git a/tests/rustdoc-ui/intra-doc/disambiguator-mismatch.stderr b/tests/rustdoc-ui/intra-doc/disambiguator-mismatch.stderr index 488120304fd..66b910eed81 100644 --- a/tests/rustdoc-ui/intra-doc/disambiguator-mismatch.stderr +++ b/tests/rustdoc-ui/intra-doc/disambiguator-mismatch.stderr @@ -160,13 +160,13 @@ help: to link to the field, prefix with `field@` LL | /// Link to [field@X::y] | ~~~~~~ -error: incompatible link kind for `S::A` +error: unresolved link to `S::A` --> $DIR/disambiguator-mismatch.rs:93:14 | LL | /// Link to [field@S::A] - | ^^^^^^^^^^ this link resolved to a unit variant, which is not a field + | ^^^^^^^^^^ this link resolves to the variant `A`, which is not in the value namespace | -help: to link to the unit variant, prefix with `variant@` +help: to link to the variant, prefix with `variant@` | LL | /// Link to [variant@S::A] | ~~~~~~~~ diff --git a/tests/rustdoc-ui/intra-doc/value-ctor.rs b/tests/rustdoc-ui/intra-doc/value-ctor.rs new file mode 100644 index 00000000000..6f57b7c6f10 --- /dev/null +++ b/tests/rustdoc-ui/intra-doc/value-ctor.rs @@ -0,0 +1,35 @@ +// https://github.com/rust-lang/rust/issues/130591 +#![deny(rustdoc::broken_intra_doc_links)] +#![crate_name = "foo"] + +/// [value@Foo::X] //~ERROR broken +pub enum Foo { + X, +} + +/// [tst][value@MyStruct] //~ERROR broken +pub struct MyStruct; + +pub enum MyEnum { + Internals, +} + +pub use MyEnum::*; + +/// In this context, [a][type@Internals] is a struct, +/// while [b][value@Internals] fails. //~ERROR broken +/// Also, [c][struct@Internals] is a struct, +/// while [d][variant@Internals] fails. //~ERROR broken +pub struct Internals { + foo: (), +} + +pub mod inside { + pub struct Internals2; +} + +use inside::*; + +/// In this context, [a][type@Internals2] is an enum, +/// while [b][value@Internals2] fails. //~ERROR broken +pub enum Internals2 {} diff --git a/tests/rustdoc-ui/intra-doc/value-ctor.stderr b/tests/rustdoc-ui/intra-doc/value-ctor.stderr new file mode 100644 index 00000000000..8d2a6649f4c --- /dev/null +++ b/tests/rustdoc-ui/intra-doc/value-ctor.stderr @@ -0,0 +1,62 @@ +error: unresolved link to `Foo::X` + --> $DIR/value-ctor.rs:5:6 + | +LL | /// [value@Foo::X] + | ^^^^^^^^^^^^ this link resolves to the variant `X`, which is not in the value namespace + | +note: the lint level is defined here + --> $DIR/value-ctor.rs:2:9 + | +LL | #![deny(rustdoc::broken_intra_doc_links)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: to link to the variant, prefix with `variant@` + | +LL | /// [variant@Foo::X] + | ~~~~~~~~ + +error: unresolved link to `MyStruct` + --> $DIR/value-ctor.rs:10:11 + | +LL | /// [tst][value@MyStruct] + | ^^^^^^^^^^^^^^ this link resolves to the struct `MyStruct`, which is not in the value namespace + | +help: to link to the struct, prefix with `struct@` + | +LL | /// [tst][struct@MyStruct] + | ~~~~~~~ + +error: unresolved link to `Internals` + --> $DIR/value-ctor.rs:20:15 + | +LL | /// while [b][value@Internals] fails. + | ^^^^^^^^^^^^^^^ this link resolves to the struct `Internals`, which is not in the value namespace + | +help: to link to the struct, prefix with `struct@` + | +LL | /// while [b][struct@Internals] fails. + | ~~~~~~~ + +error: incompatible link kind for `Internals` + --> $DIR/value-ctor.rs:22:15 + | +LL | /// while [d][variant@Internals] fails. + | ^^^^^^^^^^^^^^^^^ this link resolved to a struct, which is not a variant + | +help: to link to the struct, prefix with `struct@` + | +LL | /// while [d][struct@Internals] fails. + | ~~~~~~~ + +error: unresolved link to `Internals2` + --> $DIR/value-ctor.rs:34:15 + | +LL | /// while [b][value@Internals2] fails. + | ^^^^^^^^^^^^^^^^ this link resolves to the enum `Internals2`, which is not in the value namespace + | +help: to link to the enum, prefix with `enum@` + | +LL | /// while [b][enum@Internals2] fails. + | ~~~~~ + +error: aborting due to 5 previous errors + From 89e84c053dd10a0dff22754cebc40ca917ebae82 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 4 Oct 2024 13:47:32 +1000 Subject: [PATCH 539/683] Use `Rc` less in `MirBorrowckCtxt`. The `regioncx` and `borrow_set` fields can be references instead of `Rc`. They use the existing `'a` lifetime. This avoids some heap allocations and is a bit simpler. --- .../src/diagnostics/find_use.rs | 5 +-- compiler/rustc_borrowck/src/lib.rs | 37 ++++++++----------- 2 files changed, 17 insertions(+), 25 deletions(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/find_use.rs b/compiler/rustc_borrowck/src/diagnostics/find_use.rs index d8fa5506a99..26a090f5579 100644 --- a/compiler/rustc_borrowck/src/diagnostics/find_use.rs +++ b/compiler/rustc_borrowck/src/diagnostics/find_use.rs @@ -1,5 +1,4 @@ use std::collections::VecDeque; -use std::rc::Rc; use rustc_data_structures::fx::FxIndexSet; use rustc_middle::mir::visit::{MirVisitable, PlaceContext, Visitor}; @@ -11,7 +10,7 @@ use crate::region_infer::{Cause, RegionInferenceContext}; pub(crate) fn find<'tcx>( body: &Body<'tcx>, - regioncx: &Rc>, + regioncx: &RegionInferenceContext<'tcx>, tcx: TyCtxt<'tcx>, region_vid: RegionVid, start_point: Location, @@ -23,7 +22,7 @@ pub(crate) fn find<'tcx>( struct UseFinder<'a, 'tcx> { body: &'a Body<'tcx>, - regioncx: &'a Rc>, + regioncx: &'a RegionInferenceContext<'tcx>, tcx: TyCtxt<'tcx>, region_vid: RegionVid, start_point: Location, diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index a11eca0b9c7..b251d3734d0 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -201,8 +201,7 @@ fn do_mir_borrowck<'tcx>( .into_results_cursor(body); let locals_are_invalidated_at_exit = tcx.hir().body_owner_kind(def).is_fn_or_closure(); - let borrow_set = - Rc::new(BorrowSet::build(tcx, body, locals_are_invalidated_at_exit, &move_data)); + let borrow_set = BorrowSet::build(tcx, body, locals_are_invalidated_at_exit, &move_data); // Compute non-lexical lifetimes. let nll::NllOutput { @@ -246,8 +245,6 @@ fn do_mir_borrowck<'tcx>( // usage significantly on some benchmarks. drop(flow_inits); - let regioncx = Rc::new(regioncx); - let flow_borrows = Borrows::new(tcx, body, ®ioncx, &borrow_set) .into_engine(tcx, body) .pass_name("borrowck") @@ -289,10 +286,10 @@ fn do_mir_borrowck<'tcx>( access_place_error_reported: Default::default(), reservation_error_reported: Default::default(), uninitialized_error_reported: Default::default(), - regioncx: regioncx.clone(), + regioncx: ®ioncx, used_mut: Default::default(), used_mut_upvars: SmallVec::new(), - borrow_set: Rc::clone(&borrow_set), + borrow_set: &borrow_set, upvars: &[], local_names: IndexVec::from_elem(None, &promoted_body.local_decls), region_names: RefCell::default(), @@ -330,10 +327,10 @@ fn do_mir_borrowck<'tcx>( access_place_error_reported: Default::default(), reservation_error_reported: Default::default(), uninitialized_error_reported: Default::default(), - regioncx: Rc::clone(®ioncx), + regioncx: ®ioncx, used_mut: Default::default(), used_mut_upvars: SmallVec::new(), - borrow_set: Rc::clone(&borrow_set), + borrow_set: &borrow_set, upvars: tcx.closure_captures(def), local_names, region_names: RefCell::default(), @@ -423,8 +420,8 @@ fn do_mir_borrowck<'tcx>( Some(Box::new(BodyWithBorrowckFacts { body: body_owned, promoted, - borrow_set, - region_inference_context: regioncx, + borrow_set: Rc::new(borrow_set), + region_inference_context: Rc::new(regioncx), location_table: polonius_input.as_ref().map(|_| location_table), input_facts: polonius_input, output_facts, @@ -570,10 +567,10 @@ struct MirBorrowckCtxt<'a, 'infcx, 'tcx> { used_mut_upvars: SmallVec<[FieldIdx; 8]>, /// Region inference context. This contains the results from region inference and lets us e.g. /// find out which CFG points are contained in each borrow region. - regioncx: Rc>, + regioncx: &'a RegionInferenceContext<'tcx>, /// The set of borrows extracted from the MIR - borrow_set: Rc>, + borrow_set: &'a BorrowSet<'tcx>, /// Information about upvars not necessarily preserved in types or MIR upvars: &'tcx [&'tcx ty::CapturedPlace<'tcx>], @@ -800,9 +797,8 @@ impl<'a, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'a, 'tcx, R> TerminatorKind::Yield { value: _, resume: _, resume_arg: _, drop: _ } => { if self.movable_coroutine { // Look for any active borrows to locals - let borrow_set = self.borrow_set.clone(); for i in state.borrows.iter() { - let borrow = &borrow_set[i]; + let borrow = &self.borrow_set[i]; self.check_for_local_borrow(borrow, span); } } @@ -816,9 +812,8 @@ impl<'a, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'a, 'tcx, R> // Often, the storage will already have been killed by an explicit // StorageDead, but we don't always emit those (notably on unwind paths), // so this "extra check" serves as a kind of backup. - let borrow_set = self.borrow_set.clone(); for i in state.borrows.iter() { - let borrow = &borrow_set[i]; + let borrow = &self.borrow_set[i]; self.check_for_invalidation_at_exit(loc, borrow, span); } } @@ -1037,13 +1032,12 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { state: &BorrowckDomain<'a, 'tcx>, ) -> bool { let mut error_reported = false; - let borrow_set = Rc::clone(&self.borrow_set); // 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(borrow_set.len()); + polonius_output = BitSet::new_empty(self.borrow_set.len()); for &idx in polonius.errors_at(location) { polonius_output.insert(idx); } @@ -1057,7 +1051,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { self.infcx.tcx, self.body, (sd, place_span.0), - &borrow_set, + self.borrow_set, |borrow_index| borrows_in_scope.contains(borrow_index), |this, borrow_index, borrow| match (rw, borrow.kind) { // Obviously an activation is compatible with its own @@ -1580,9 +1574,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { // Two-phase borrow support: For each activation that is newly // generated at this statement, check if it interferes with // another borrow. - let borrow_set = self.borrow_set.clone(); - for &borrow_index in borrow_set.activations_at_location(location) { - let borrow = &borrow_set[borrow_index]; + for &borrow_index in self.borrow_set.activations_at_location(location) { + let borrow = &self.borrow_set[borrow_index]; // only mutable borrows should be 2-phase assert!(match borrow.kind { From 3d7fe9e7dd07fcf1f5d9d7aac6f3ed4963bd4e58 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 4 Oct 2024 14:02:53 +1000 Subject: [PATCH 540/683] Use `Box` instead of `Rc` for `polonius_output`. Refcounting isn't needed. --- compiler/rustc_borrowck/src/consumers.rs | 2 +- compiler/rustc_borrowck/src/lib.rs | 2 +- compiler/rustc_borrowck/src/nll.rs | 4 ++-- compiler/rustc_borrowck/src/region_infer/mod.rs | 8 +++++--- 4 files changed, 9 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_borrowck/src/consumers.rs b/compiler/rustc_borrowck/src/consumers.rs index c994c4dc1e4..9f3f2320ba4 100644 --- a/compiler/rustc_borrowck/src/consumers.rs +++ b/compiler/rustc_borrowck/src/consumers.rs @@ -79,7 +79,7 @@ pub struct BodyWithBorrowckFacts<'tcx> { pub input_facts: Option>, /// Polonius output facts. Populated when using /// [`ConsumerOptions::PoloniusOutputFacts`]. - pub output_facts: Option>, + pub output_facts: Option>, } /// This function computes borrowck facts for the given body. The [`ConsumerOptions`] diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index b251d3734d0..b8cc8fe1fd1 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -586,7 +586,7 @@ struct MirBorrowckCtxt<'a, 'infcx, 'tcx> { next_region_name: RefCell, /// Results of Polonius analysis. - polonius_output: Option>, + polonius_output: Option>, diags: diags::BorrowckDiags<'infcx, 'tcx>, move_errors: Vec>, diff --git a/compiler/rustc_borrowck/src/nll.rs b/compiler/rustc_borrowck/src/nll.rs index d85af52b01e..6823e7df430 100644 --- a/compiler/rustc_borrowck/src/nll.rs +++ b/compiler/rustc_borrowck/src/nll.rs @@ -42,7 +42,7 @@ pub(crate) struct NllOutput<'tcx> { pub regioncx: RegionInferenceContext<'tcx>, pub opaque_type_values: FxIndexMap>, pub polonius_input: Option>, - pub polonius_output: Option>, + pub polonius_output: Option>, pub opt_closure_req: Option>, pub nll_errors: RegionErrors<'tcx>, } @@ -184,7 +184,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(Rc::new(Output::compute(all_facts, algorithm, false))) + Some(Box::new(Output::compute(all_facts, algorithm, false))) } else { None } diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index c62ea870acf..192061ce8a4 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -637,7 +637,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { &mut self, infcx: &InferCtxt<'tcx>, body: &Body<'tcx>, - polonius_output: Option>, + polonius_output: Option>, ) -> (Option>, RegionErrors<'tcx>) { let mir_def_id = body.source.def_id(); self.propagate_constraints(); @@ -663,7 +663,9 @@ impl<'tcx> RegionInferenceContext<'tcx> { self.check_polonius_subset_errors( outlives_requirements.as_mut(), &mut errors_buffer, - polonius_output.expect("Polonius output is unavailable despite `-Z polonius`"), + polonius_output + .as_ref() + .expect("Polonius output is unavailable despite `-Z polonius`"), ); } else { self.check_universal_regions(outlives_requirements.as_mut(), &mut errors_buffer); @@ -1411,7 +1413,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { &self, mut propagated_outlives_requirements: Option<&mut Vec>>, errors_buffer: &mut RegionErrors<'tcx>, - polonius_output: Rc, + polonius_output: &PoloniusOutput, ) { debug!( "check_polonius_subset_errors: {} subset_errors", From d9975ce2b4e1c191b6b5a113cb548344c32f3a2b Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 4 Oct 2024 14:08:04 +1000 Subject: [PATCH 541/683] Avoid `Rc` in `BodyWithBorrowckFacts`. It can own these two fields. --- compiler/rustc_borrowck/src/consumers.rs | 6 ++---- compiler/rustc_borrowck/src/lib.rs | 5 ++--- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_borrowck/src/consumers.rs b/compiler/rustc_borrowck/src/consumers.rs index 9f3f2320ba4..7ace38c3e85 100644 --- a/compiler/rustc_borrowck/src/consumers.rs +++ b/compiler/rustc_borrowck/src/consumers.rs @@ -1,7 +1,5 @@ //! This file provides API for compiler consumers. -use std::rc::Rc; - use rustc_hir::def_id::LocalDefId; use rustc_index::{IndexSlice, IndexVec}; use rustc_middle::mir::{Body, Promoted}; @@ -65,10 +63,10 @@ pub struct BodyWithBorrowckFacts<'tcx> { /// The mir bodies of promoteds. pub promoted: IndexVec>, /// The set of borrows occurring in `body` with data about them. - pub borrow_set: Rc>, + pub borrow_set: BorrowSet<'tcx>, /// Context generated during borrowck, intended to be passed to /// [`calculate_borrows_out_of_scope_at_location`]. - pub region_inference_context: Rc>, + pub region_inference_context: RegionInferenceContext<'tcx>, /// The table that maps Polonius points to locations in the table. /// 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 b8cc8fe1fd1..42b1e0036ad 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -20,7 +20,6 @@ use std::cell::RefCell; use std::collections::BTreeMap; use std::marker::PhantomData; use std::ops::Deref; -use std::rc::Rc; use consumers::{BodyWithBorrowckFacts, ConsumerOptions}; use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; @@ -420,8 +419,8 @@ fn do_mir_borrowck<'tcx>( Some(Box::new(BodyWithBorrowckFacts { body: body_owned, promoted, - borrow_set: Rc::new(borrow_set), - region_inference_context: Rc::new(regioncx), + borrow_set, + region_inference_context: regioncx, location_table: polonius_input.as_ref().map(|_| location_table), input_facts: polonius_input, output_facts, From 56e849ca21be4ee606f655691c134d82f70675b6 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 4 Oct 2024 14:18:17 +1000 Subject: [PATCH 542/683] Avoid `&Rc` arguments. Either `&T` or `Rc` is preferable. --- compiler/rustc_borrowck/src/nll.rs | 8 ++++---- compiler/rustc_borrowck/src/region_infer/mod.rs | 4 ++-- compiler/rustc_borrowck/src/region_infer/values.rs | 11 ++++++----- .../src/type_check/free_region_relations.rs | 4 ++-- .../rustc_borrowck/src/type_check/liveness/mod.rs | 4 +--- .../rustc_borrowck/src/type_check/liveness/trace.rs | 4 +--- compiler/rustc_borrowck/src/type_check/mod.rs | 12 ++++++------ 7 files changed, 22 insertions(+), 25 deletions(-) diff --git a/compiler/rustc_borrowck/src/nll.rs b/compiler/rustc_borrowck/src/nll.rs index 6823e7df430..f3207c26bfc 100644 --- a/compiler/rustc_borrowck/src/nll.rs +++ b/compiler/rustc_borrowck/src/nll.rs @@ -98,7 +98,7 @@ pub(crate) fn compute_regions<'a, 'tcx>( let universal_regions = Rc::new(universal_regions); - let elements = &Rc::new(DenseLocationMap::new(body)); + let elements = Rc::new(DenseLocationMap::new(body)); // Run the MIR type-checker. let MirTypeckResults { constraints, universal_region_relations, opaque_type_values } = @@ -107,13 +107,13 @@ pub(crate) fn compute_regions<'a, 'tcx>( param_env, body, promoted, - &universal_regions, + universal_regions.clone(), location_table, borrow_set, &mut all_facts, flow_inits, move_data, - elements, + elements.clone(), upvars, ); @@ -165,7 +165,7 @@ pub(crate) fn compute_regions<'a, 'tcx>( universe_causes, type_tests, liveness_constraints, - elements, + elements.clone(), ); // If requested: dump NLL facts, and run legacy polonius analysis. diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index 192061ce8a4..e85f529bf0e 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -407,7 +407,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { universe_causes: FxIndexMap>, type_tests: Vec>, liveness_constraints: LivenessValues, - elements: &Rc, + elements: Rc, ) -> Self { debug!("universal_regions: {:#?}", universal_regions); debug!("outlives constraints: {:#?}", outlives_constraints); @@ -430,7 +430,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { } let mut scc_values = - RegionValues::new(elements, universal_regions.len(), &placeholder_indices); + RegionValues::new(elements, 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 b95fe5b5028..662e6fa46b5 100644 --- a/compiler/rustc_borrowck/src/region_infer/values.rs +++ b/compiler/rustc_borrowck/src/region_infer/values.rs @@ -275,15 +275,16 @@ 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, + elements: Rc, num_universal_regions: usize, - placeholder_indices: &Rc, + placeholder_indices: Rc, ) -> Self { + let num_points = elements.num_points(); let num_placeholders = placeholder_indices.len(); Self { - elements: elements.clone(), - points: SparseIntervalMatrix::new(elements.num_points()), - placeholder_indices: placeholder_indices.clone(), + elements, + points: SparseIntervalMatrix::new(num_points), + placeholder_indices, free_regions: SparseBitMatrix::new(num_universal_regions), placeholders: SparseBitMatrix::new(num_placeholders), } diff --git a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs index 6977fed59ed..cded9935f97 100644 --- a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs +++ b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs @@ -54,7 +54,7 @@ pub(crate) fn create<'tcx>( infcx: &InferCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, implicit_region_bound: ty::Region<'tcx>, - universal_regions: &Rc>, + universal_regions: Rc>, constraints: &mut MirTypeckRegionConstraints<'tcx>, ) -> CreateResult<'tcx> { UniversalRegionRelationsBuilder { @@ -62,7 +62,7 @@ pub(crate) fn create<'tcx>( param_env, implicit_region_bound, constraints, - universal_regions: universal_regions.clone(), + universal_regions, region_bound_pairs: Default::default(), outlives: Default::default(), inverse_outlives: Default::default(), diff --git a/compiler/rustc_borrowck/src/type_check/liveness/mod.rs b/compiler/rustc_borrowck/src/type_check/liveness/mod.rs index d4900d21f8f..b8e35f882ec 100644 --- a/compiler/rustc_borrowck/src/type_check/liveness/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/liveness/mod.rs @@ -1,5 +1,3 @@ -use std::rc::Rc; - use itertools::{Either, Itertools}; use rustc_data_structures::fx::FxHashSet; use rustc_middle::mir::visit::{TyContext, Visitor}; @@ -33,7 +31,7 @@ mod trace; pub(super) fn generate<'a, 'tcx>( typeck: &mut TypeChecker<'_, 'tcx>, body: &Body<'tcx>, - elements: &Rc, + elements: &DenseLocationMap, flow_inits: &mut ResultsCursor<'a, 'tcx, MaybeInitializedPlaces<'a, 'tcx>>, move_data: &MoveData<'tcx>, ) { diff --git a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs index 8cbe3ac6701..a5175e653d8 100644 --- a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs +++ b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs @@ -1,5 +1,3 @@ -use std::rc::Rc; - use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_index::bit_set::BitSet; use rustc_index::interval::IntervalSet; @@ -40,7 +38,7 @@ use crate::type_check::{NormalizeLocation, TypeChecker}; pub(super) fn trace<'a, 'tcx>( typeck: &mut TypeChecker<'_, 'tcx>, body: &Body<'tcx>, - elements: &Rc, + elements: &DenseLocationMap, flow_inits: &mut ResultsCursor<'a, 'tcx, MaybeInitializedPlaces<'a, 'tcx>>, move_data: &MoveData<'tcx>, relevant_live_locals: Vec, diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 6b17879de26..82aeca66693 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -121,13 +121,13 @@ pub(crate) fn type_check<'a, 'tcx>( param_env: ty::ParamEnv<'tcx>, body: &Body<'tcx>, promoted: &IndexSlice>, - universal_regions: &Rc>, + universal_regions: Rc>, location_table: &LocationTable, borrow_set: &BorrowSet<'tcx>, all_facts: &mut Option, flow_inits: &mut ResultsCursor<'a, 'tcx, MaybeInitializedPlaces<'a, 'tcx>>, move_data: &MoveData<'tcx>, - elements: &Rc, + elements: Rc, upvars: &[&ty::CapturedPlace<'tcx>], ) -> MirTypeckResults<'tcx> { let implicit_region_bound = ty::Region::new_var(infcx.tcx, universal_regions.fr_fn_body); @@ -150,14 +150,14 @@ pub(crate) fn type_check<'a, 'tcx>( infcx, param_env, implicit_region_bound, - universal_regions, + universal_regions.clone(), &mut constraints, ); debug!(?normalized_inputs_and_output); let mut borrowck_context = BorrowCheckContext { - universal_regions, + universal_regions: &universal_regions, location_table, borrow_set, all_facts, @@ -181,10 +181,10 @@ pub(crate) fn type_check<'a, 'tcx>( verifier.visit_body(body); checker.typeck_mir(body); - checker.equate_inputs_and_outputs(body, universal_regions, &normalized_inputs_and_output); + checker.equate_inputs_and_outputs(body, &universal_regions, &normalized_inputs_and_output); checker.check_signature_annotation(body); - liveness::generate(&mut checker, body, elements, flow_inits, move_data); + liveness::generate(&mut checker, body, &elements, flow_inits, move_data); translate_outlives_facts(&mut checker); let opaque_type_values = infcx.take_opaque_types(); From c69d174311386b79d14881123b3acf7d8617e3b3 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 4 Oct 2024 15:38:29 +1000 Subject: [PATCH 543/683] Remove unnecessary lifetime in `ConditionVisitor`. By making it own two of its fields. --- .../src/diagnostics/conflict_errors.rs | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 60ea0d1edbf..c687be69b1a 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -708,9 +708,9 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { // for the branching codepaths that aren't covered, to point at them. let map = self.infcx.tcx.hir(); let body = map.body_owned_by(self.mir_def_id()); - let mut visitor = - ConditionVisitor { tcx: self.infcx.tcx, spans: &spans, name: &name, errors: vec![] }; + let mut visitor = ConditionVisitor { tcx: self.infcx.tcx, spans, name, errors: vec![] }; visitor.visit_body(&body); + let spans = visitor.spans; let mut show_assign_sugg = false; let isnt_initialized = if let InitializationRequiringAction::PartialAssignment @@ -4465,20 +4465,20 @@ impl<'hir> Visitor<'hir> for BreakFinder { /// Given a set of spans representing statements initializing the relevant binding, visit all the /// function expressions looking for branching code paths that *do not* initialize the binding. -struct ConditionVisitor<'b, 'tcx> { +struct ConditionVisitor<'tcx> { tcx: TyCtxt<'tcx>, - spans: &'b [Span], - name: &'b str, + spans: Vec, + name: String, errors: Vec<(Span, String)>, } -impl<'b, 'v, 'tcx> Visitor<'v> for ConditionVisitor<'b, 'tcx> { +impl<'v, 'tcx> Visitor<'v> for ConditionVisitor<'tcx> { fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) { match ex.kind { hir::ExprKind::If(cond, body, None) => { // `if` expressions with no `else` that initialize the binding might be missing an // `else` arm. - if ReferencedStatementsVisitor(self.spans).visit_expr(body).is_break() { + if ReferencedStatementsVisitor(&self.spans).visit_expr(body).is_break() { self.errors.push(( cond.span, format!( @@ -4495,8 +4495,8 @@ impl<'b, 'v, 'tcx> Visitor<'v> for ConditionVisitor<'b, 'tcx> { hir::ExprKind::If(cond, body, Some(other)) => { // `if` expressions where the binding is only initialized in one of the two arms // might be missing a binding initialization. - let a = ReferencedStatementsVisitor(self.spans).visit_expr(body).is_break(); - let b = ReferencedStatementsVisitor(self.spans).visit_expr(other).is_break(); + let a = ReferencedStatementsVisitor(&self.spans).visit_expr(body).is_break(); + let b = ReferencedStatementsVisitor(&self.spans).visit_expr(other).is_break(); match (a, b) { (true, true) | (false, false) => {} (true, false) => { @@ -4536,7 +4536,7 @@ impl<'b, 'v, 'tcx> Visitor<'v> for ConditionVisitor<'b, 'tcx> { // arms might be missing an initialization. let results: Vec = arms .iter() - .map(|arm| ReferencedStatementsVisitor(self.spans).visit_arm(arm).is_break()) + .map(|arm| ReferencedStatementsVisitor(&self.spans).visit_arm(arm).is_break()) .collect(); if results.iter().any(|x| *x) && !results.iter().all(|x| *x) { for (arm, seen) in arms.iter().zip(results) { From 62ef411631efb25134e29da76fcdb7802aa94bd4 Mon Sep 17 00:00:00 2001 From: Urgau Date: Thu, 19 Sep 2024 11:19:35 +0200 Subject: [PATCH 544/683] Feature gate boolean lit support in cfg predicates --- compiler/rustc_attr/src/builtin.rs | 20 ++++++++- compiler/rustc_feature/src/unstable.rs | 2 + compiler/rustc_span/src/symbol.rs | 1 + .../language-features/cfg-boolean-literals.md | 22 ++++++++++ tests/ui/cfg/raw-true-false.rs | 19 ++++++++ tests/ui/cfg/true-false.rs | 1 + .../feature-gate-cfg-boolean-literals.rs | 10 +++++ .../feature-gate-cfg-boolean-literals.stderr | 43 +++++++++++++++++++ 8 files changed, 116 insertions(+), 2 deletions(-) create mode 100644 src/doc/unstable-book/src/language-features/cfg-boolean-literals.md create mode 100644 tests/ui/cfg/raw-true-false.rs create mode 100644 tests/ui/feature-gates/feature-gate-cfg-boolean-literals.rs create mode 100644 tests/ui/feature-gates/feature-gate-cfg-boolean-literals.stderr diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs index 930fdeb975d..a3c6132d484 100644 --- a/compiler/rustc_attr/src/builtin.rs +++ b/compiler/rustc_attr/src/builtin.rs @@ -18,7 +18,7 @@ use rustc_session::parse::feature_err; use rustc_session::{RustcVersion, Session}; use rustc_span::Span; use rustc_span::hygiene::Transparency; -use rustc_span::symbol::{Symbol, sym}; +use rustc_span::symbol::{Symbol, kw, sym}; use crate::fluent_generated; use crate::session_diagnostics::{self, IncorrectReprFormatGenericCause}; @@ -603,7 +603,23 @@ pub fn eval_condition( let cfg = match cfg { ast::NestedMetaItem::MetaItem(meta_item) => meta_item, - ast::NestedMetaItem::Lit(MetaItemLit { kind: LitKind::Bool(b), .. }) => return *b, + ast::NestedMetaItem::Lit(MetaItemLit { kind: LitKind::Bool(b), .. }) => { + if let Some(features) = features { + // we can't use `try_gate_cfg` as symbols don't differentiate between `r#true` + // and `true`, and we want to keep the former working without feature gate + gate_cfg( + &(( + if *b { kw::True } else { kw::False }, + sym::cfg_boolean_literals, + |features: &Features| features.cfg_boolean_literals, + )), + cfg.span(), + sess, + features, + ); + } + return *b; + } _ => { dcx.emit_err(session_diagnostics::UnsupportedLiteral { span: cfg.span(), diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 1ffd35dbf91..643a95e6ea1 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -371,6 +371,8 @@ declare_features! ( (unstable, async_for_loop, "1.77.0", Some(118898)), /// Allows using C-variadics. (unstable, c_variadic, "1.34.0", Some(44930)), + /// Allows the use of `#[cfg()]`. + (unstable, cfg_boolean_literals, "CURRENT_RUSTC_VERSION", Some(131204)), /// Allows the use of `#[cfg(overflow_checks)` to check if integer overflow behaviour. (unstable, cfg_overflow_checks, "1.71.0", Some(111466)), /// Provides the relocation model information as cfg entry diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 8f226b26bef..ea8c5f135ab 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -543,6 +543,7 @@ symbols! { cfg_accessible, cfg_attr, cfg_attr_multi, + cfg_boolean_literals, cfg_doctest, cfg_eval, cfg_fmt_debug, diff --git a/src/doc/unstable-book/src/language-features/cfg-boolean-literals.md b/src/doc/unstable-book/src/language-features/cfg-boolean-literals.md new file mode 100644 index 00000000000..ad795ff9d9b --- /dev/null +++ b/src/doc/unstable-book/src/language-features/cfg-boolean-literals.md @@ -0,0 +1,22 @@ +# `cfg_boolean_literals` + +The tracking issue for this feature is: [#131204] + +[#131204]: https://github.com/rust-lang/rust/issues/131204 + +------------------------ + +The `cfg_boolean_literals` feature makes it possible to use the `true`/`false` +literal as cfg predicate. They always evaluate to true/false respectively. + +## Examples + +```rust +#![feature(cfg_boolean_literals)] + +#[cfg(true)] +const A: i32 = 5; + +#[cfg(all(false))] +const A: i32 = 58 * 89; +``` diff --git a/tests/ui/cfg/raw-true-false.rs b/tests/ui/cfg/raw-true-false.rs new file mode 100644 index 00000000000..4cb8bb71c92 --- /dev/null +++ b/tests/ui/cfg/raw-true-false.rs @@ -0,0 +1,19 @@ +//@ check-pass +//@ compile-flags: --cfg false --check-cfg=cfg(r#false) + +#![deny(warnings)] + +#[expect(unexpected_cfgs)] +mod a { + #[cfg(r#true)] + pub fn foo() {} +} + +mod b { + #[cfg(r#false)] + pub fn bar() {} +} + +fn main() { + b::bar() +} diff --git a/tests/ui/cfg/true-false.rs b/tests/ui/cfg/true-false.rs index 0bd1cf427fa..03d96fbafec 100644 --- a/tests/ui/cfg/true-false.rs +++ b/tests/ui/cfg/true-false.rs @@ -1,6 +1,7 @@ //@ run-pass #![feature(link_cfg)] +#![feature(cfg_boolean_literals)] #[cfg(true)] fn foo() -> bool { diff --git a/tests/ui/feature-gates/feature-gate-cfg-boolean-literals.rs b/tests/ui/feature-gates/feature-gate-cfg-boolean-literals.rs new file mode 100644 index 00000000000..6784b445049 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-cfg-boolean-literals.rs @@ -0,0 +1,10 @@ +#[cfg(true)] //~ ERROR `cfg(true)` is experimental +fn foo() {} + +#[cfg_attr(true, cfg(false))] //~ ERROR `cfg(true)` is experimental +//~^ ERROR `cfg(false)` is experimental +fn foo() {} + +fn main() { + cfg!(false); //~ ERROR `cfg(false)` is experimental +} diff --git a/tests/ui/feature-gates/feature-gate-cfg-boolean-literals.stderr b/tests/ui/feature-gates/feature-gate-cfg-boolean-literals.stderr new file mode 100644 index 00000000000..64491464f1d --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-cfg-boolean-literals.stderr @@ -0,0 +1,43 @@ +error[E0658]: `cfg(true)` is experimental and subject to change + --> $DIR/feature-gate-cfg-boolean-literals.rs:1:7 + | +LL | #[cfg(true)] + | ^^^^ + | + = note: see issue #131204 for more information + = help: add `#![feature(cfg_boolean_literals)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: `cfg(true)` is experimental and subject to change + --> $DIR/feature-gate-cfg-boolean-literals.rs:4:12 + | +LL | #[cfg_attr(true, cfg(false))] + | ^^^^ + | + = note: see issue #131204 for more information + = help: add `#![feature(cfg_boolean_literals)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: `cfg(false)` is experimental and subject to change + --> $DIR/feature-gate-cfg-boolean-literals.rs:4:22 + | +LL | #[cfg_attr(true, cfg(false))] + | ^^^^^ + | + = note: see issue #131204 for more information + = help: add `#![feature(cfg_boolean_literals)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: `cfg(false)` is experimental and subject to change + --> $DIR/feature-gate-cfg-boolean-literals.rs:9:10 + | +LL | cfg!(false); + | ^^^^^ + | + = note: see issue #131204 for more information + = help: add `#![feature(cfg_boolean_literals)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0658`. From 781f1840cd37348ce4d76fff2b04e1ada531864e Mon Sep 17 00:00:00 2001 From: Urgau Date: Sun, 29 Sep 2024 23:40:06 +0200 Subject: [PATCH 545/683] Adjust rustdoc for literal boolean support --- src/librustdoc/clean/cfg.rs | 10 +++-- src/librustdoc/clean/cfg/tests.rs | 51 ++++++++++++++++--------- src/librustdoc/clean/types.rs | 5 ++- src/librustdoc/visit_ast.rs | 2 +- tests/rustdoc-ui/cfg-boolean-literal.rs | 19 +++++++++ 5 files changed, 64 insertions(+), 23 deletions(-) create mode 100644 tests/rustdoc-ui/cfg-boolean-literal.rs diff --git a/src/librustdoc/clean/cfg.rs b/src/librustdoc/clean/cfg.rs index 26739219085..53830016a80 100644 --- a/src/librustdoc/clean/cfg.rs +++ b/src/librustdoc/clean/cfg.rs @@ -6,7 +6,7 @@ use std::fmt::{self, Write}; use std::{mem, ops}; -use rustc_ast::{LitKind, MetaItem, MetaItemKind, NestedMetaItem}; +use rustc_ast::{LitKind, MetaItem, MetaItemKind, MetaItemLit, NestedMetaItem}; use rustc_data_structures::fx::FxHashSet; use rustc_feature::Features; use rustc_session::parse::ParseSess; @@ -48,6 +48,10 @@ impl Cfg { ) -> Result, InvalidCfgError> { match nested_cfg { NestedMetaItem::MetaItem(ref cfg) => Cfg::parse_without(cfg, exclude), + NestedMetaItem::Lit(MetaItemLit { kind: LitKind::Bool(b), .. }) => match *b { + true => Ok(Some(Cfg::True)), + false => Ok(Some(Cfg::False)), + }, NestedMetaItem::Lit(ref lit) => { Err(InvalidCfgError { msg: "unexpected literal", span: lit.span }) } @@ -120,8 +124,8 @@ impl Cfg { /// /// If the content is not properly formatted, it will return an error indicating what and where /// the error is. - pub(crate) fn parse(cfg: &MetaItem) -> Result { - Self::parse_without(cfg, &FxHashSet::default()).map(|ret| ret.unwrap()) + pub(crate) fn parse(cfg: &NestedMetaItem) -> Result { + Self::parse_nested(cfg, &FxHashSet::default()).map(|ret| ret.unwrap()) } /// Checks whether the given configuration can be matched in the current session. diff --git a/src/librustdoc/clean/cfg/tests.rs b/src/librustdoc/clean/cfg/tests.rs index 0ab655103e2..d4b11451c89 100644 --- a/src/librustdoc/clean/cfg/tests.rs +++ b/src/librustdoc/clean/cfg/tests.rs @@ -1,4 +1,5 @@ -use rustc_ast::{MetaItemLit, Path, Safety, StrStyle}; +use rustc_ast::ast::LitIntType; +use rustc_ast::{MetaItemLit, NestedMetaItem, Path, Safety, StrStyle}; use rustc_span::symbol::{Ident, kw}; use rustc_span::{DUMMY_SP, create_default_session_globals_then}; use thin_vec::thin_vec; @@ -13,52 +14,52 @@ fn name_value_cfg(name: &str, value: &str) -> Cfg { Cfg::Cfg(Symbol::intern(name), Some(Symbol::intern(value))) } -fn dummy_meta_item_word(name: &str) -> MetaItem { - MetaItem { +fn dummy_lit(symbol: Symbol, kind: LitKind) -> NestedMetaItem { + NestedMetaItem::Lit(MetaItemLit { symbol, suffix: None, kind, span: DUMMY_SP }) +} + +fn dummy_meta_item_word(name: &str) -> NestedMetaItem { + NestedMetaItem::MetaItem(MetaItem { unsafety: Safety::Default, path: Path::from_ident(Ident::from_str(name)), kind: MetaItemKind::Word, span: DUMMY_SP, - } + }) } -fn dummy_meta_item_name_value(name: &str, symbol: Symbol, kind: LitKind) -> MetaItem { +fn dummy_meta_item_name_value(name: &str, symbol: Symbol, kind: LitKind) -> NestedMetaItem { let lit = MetaItemLit { symbol, suffix: None, kind, span: DUMMY_SP }; - MetaItem { + NestedMetaItem::MetaItem(MetaItem { unsafety: Safety::Default, path: Path::from_ident(Ident::from_str(name)), kind: MetaItemKind::NameValue(lit), span: DUMMY_SP, - } + }) } macro_rules! dummy_meta_item_list { ($name:ident, [$($list:ident),* $(,)?]) => { - MetaItem { + NestedMetaItem::MetaItem(MetaItem { unsafety: Safety::Default, path: Path::from_ident(Ident::from_str(stringify!($name))), kind: MetaItemKind::List(thin_vec![ $( - NestedMetaItem::MetaItem( - dummy_meta_item_word(stringify!($list)), - ), + dummy_meta_item_word(stringify!($list)), )* ]), span: DUMMY_SP, - } + }) }; ($name:ident, [$($list:expr),* $(,)?]) => { - MetaItem { + NestedMetaItem::MetaItem(MetaItem { unsafety: Safety::Default, path: Path::from_ident(Ident::from_str(stringify!($name))), kind: MetaItemKind::List(thin_vec![ - $( - NestedMetaItem::MetaItem($list), - )* + $($list,)* ]), span: DUMMY_SP, - } + }) }; } @@ -251,6 +252,14 @@ fn test_cfg_or() { #[test] fn test_parse_ok() { create_default_session_globals_then(|| { + let r#true = Symbol::intern("true"); + let mi = dummy_lit(r#true, LitKind::Bool(true)); + assert_eq!(Cfg::parse(&mi), Ok(Cfg::True)); + + let r#false = Symbol::intern("false"); + let mi = dummy_lit(r#false, LitKind::Bool(false)); + assert_eq!(Cfg::parse(&mi), Ok(Cfg::False)); + let mi = dummy_meta_item_word("all"); assert_eq!(Cfg::parse(&mi), Ok(word_cfg("all"))); @@ -309,6 +318,14 @@ fn test_parse_err() { let mi = dummy_meta_item_list!(not, [dummy_meta_item_list!(foo, []),]); assert!(Cfg::parse(&mi).is_err()); + + let c = Symbol::intern("e"); + let mi = dummy_lit(c, LitKind::Char('e')); + assert!(Cfg::parse(&mi).is_err()); + + let five = Symbol::intern("5"); + let mi = dummy_lit(five, LitKind::Int(5.into(), LitIntType::Unsuffixed)); + assert!(Cfg::parse(&mi).is_err()); }) } diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index b9c5e8e787b..7e822011a67 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -5,6 +5,7 @@ use std::sync::{Arc, OnceLock as OnceCell}; use std::{fmt, iter}; use arrayvec::ArrayVec; +use rustc_ast::NestedMetaItem; use rustc_ast_pretty::pprust; use rustc_attr::{ConstStability, Deprecation, Stability, StabilityLevel, StableSince}; use rustc_const_eval::const_eval::is_unstable_const_fn; @@ -1016,7 +1017,7 @@ pub(crate) trait AttributesExt { .peekable(); if doc_cfg.peek().is_some() && doc_cfg_active { doc_cfg - .filter_map(|attr| Cfg::parse(attr.meta_item()?).ok()) + .filter_map(|attr| Cfg::parse(&attr).ok()) .fold(Cfg::True, |cfg, new_cfg| cfg & new_cfg) } else if doc_auto_cfg_active { // If there is no `doc(cfg())`, then we retrieve the `cfg()` attributes (because @@ -1072,7 +1073,7 @@ pub(crate) trait AttributesExt { let mut meta = attr.meta_item().unwrap().clone(); meta.path = ast::Path::from_ident(Ident::with_dummy_span(sym::target_feature)); - if let Ok(feat_cfg) = Cfg::parse(&meta) { + if let Ok(feat_cfg) = Cfg::parse(&NestedMetaItem::MetaItem(meta)) { cfg &= feat_cfg; } } diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index 2cf703f57c0..2fcb147688d 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -164,7 +164,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { .unwrap_or(&[]) .iter() .filter_map(|attr| { - Cfg::parse(attr.meta_item()?) + Cfg::parse(attr) .map_err(|e| self.cx.sess().dcx().span_err(e.span, e.msg)) .ok() }) diff --git a/tests/rustdoc-ui/cfg-boolean-literal.rs b/tests/rustdoc-ui/cfg-boolean-literal.rs new file mode 100644 index 00000000000..4d4e599bfee --- /dev/null +++ b/tests/rustdoc-ui/cfg-boolean-literal.rs @@ -0,0 +1,19 @@ +//@ check-pass + +#![feature(cfg_boolean_literals)] +#![feature(doc_cfg)] + +#[doc(cfg(false))] +pub fn foo() {} + +#[doc(cfg(true))] +pub fn bar() {} + +#[doc(cfg(any(true)))] +pub fn zoo() {} + +#[doc(cfg(all(true)))] +pub fn toy() {} + +#[doc(cfg(not(true)))] +pub fn nay() {} From a3ffa1eae507809628decc6250b28db6ab167b11 Mon Sep 17 00:00:00 2001 From: Urgau Date: Tue, 1 Oct 2024 10:25:18 +0200 Subject: [PATCH 546/683] Improve non-boolean literal error in cfg predicate --- compiler/rustc_attr/messages.ftl | 2 ++ compiler/rustc_attr/src/builtin.rs | 3 ++- compiler/rustc_attr/src/session_diagnostics.rs | 1 + tests/ui/macros/cfg.rs | 2 +- tests/ui/macros/cfg.stderr | 2 +- 5 files changed, 7 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_attr/messages.ftl b/compiler/rustc_attr/messages.ftl index 5d9ac23ec49..adabf18ca85 100644 --- a/compiler/rustc_attr/messages.ftl +++ b/compiler/rustc_attr/messages.ftl @@ -107,6 +107,8 @@ attr_unknown_version_literal = attr_unstable_cfg_target_compact = compact `cfg(target(..))` is experimental and subject to change +attr_unsupported_literal_cfg_boolean = + literal in `cfg` predicate value must be a boolean attr_unsupported_literal_cfg_string = literal in `cfg` predicate value must be a string attr_unsupported_literal_deprecated_kv_pair = diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs index a3c6132d484..af73281c316 100644 --- a/compiler/rustc_attr/src/builtin.rs +++ b/compiler/rustc_attr/src/builtin.rs @@ -36,6 +36,7 @@ pub fn is_builtin_attr(attr: &Attribute) -> bool { pub(crate) enum UnsupportedLiteralReason { Generic, CfgString, + CfgBoolean, DeprecatedString, DeprecatedKvPair, } @@ -623,7 +624,7 @@ pub fn eval_condition( _ => { dcx.emit_err(session_diagnostics::UnsupportedLiteral { span: cfg.span(), - reason: UnsupportedLiteralReason::Generic, + reason: UnsupportedLiteralReason::CfgBoolean, is_bytestr: false, start_point_span: sess.source_map().start_point(cfg.span()), }); diff --git a/compiler/rustc_attr/src/session_diagnostics.rs b/compiler/rustc_attr/src/session_diagnostics.rs index 959a5a4bba7..626840aa6a3 100644 --- a/compiler/rustc_attr/src/session_diagnostics.rs +++ b/compiler/rustc_attr/src/session_diagnostics.rs @@ -206,6 +206,7 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for UnsupportedLiteral { let mut diag = Diag::new(dcx, level, match self.reason { UnsupportedLiteralReason::Generic => fluent::attr_unsupported_literal_generic, UnsupportedLiteralReason::CfgString => fluent::attr_unsupported_literal_cfg_string, + UnsupportedLiteralReason::CfgBoolean => fluent::attr_unsupported_literal_cfg_boolean, UnsupportedLiteralReason::DeprecatedString => { fluent::attr_unsupported_literal_deprecated_string } diff --git a/tests/ui/macros/cfg.rs b/tests/ui/macros/cfg.rs index 387cc0ba8e2..50998572274 100644 --- a/tests/ui/macros/cfg.rs +++ b/tests/ui/macros/cfg.rs @@ -1,6 +1,6 @@ fn main() { cfg!(); //~ ERROR macro requires a cfg-pattern - cfg!(123); //~ ERROR unsupported literal + cfg!(123); //~ ERROR literal in `cfg` predicate value must be a boolean cfg!(foo = 123); //~ ERROR literal in `cfg` predicate value must be a string cfg!(foo, bar); //~ ERROR expected 1 cfg-pattern } diff --git a/tests/ui/macros/cfg.stderr b/tests/ui/macros/cfg.stderr index 5c21497dc5d..53326914865 100644 --- a/tests/ui/macros/cfg.stderr +++ b/tests/ui/macros/cfg.stderr @@ -6,7 +6,7 @@ LL | cfg!(); | = note: this error originates in the macro `cfg` (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0565]: unsupported literal +error[E0565]: literal in `cfg` predicate value must be a boolean --> $DIR/cfg.rs:3:10 | LL | cfg!(123); From eefe3200cd26a1810a50c7016d07d28862e0744e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonathan=20D=C3=B6nszelmann?= Date: Fri, 4 Oct 2024 09:38:14 +0200 Subject: [PATCH 547/683] remove blank issue template --- .github/ISSUE_TEMPLATE/blank_issue.md | 4 ---- 1 file changed, 4 deletions(-) delete mode 100644 .github/ISSUE_TEMPLATE/blank_issue.md diff --git a/.github/ISSUE_TEMPLATE/blank_issue.md b/.github/ISSUE_TEMPLATE/blank_issue.md deleted file mode 100644 index 9aef3ebe637..00000000000 --- a/.github/ISSUE_TEMPLATE/blank_issue.md +++ /dev/null @@ -1,4 +0,0 @@ ---- -name: Blank Issue -about: Create a blank issue. ---- From dc88a6a788ebbcc2c342b2cfb584f48b2b78b43f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 4 Oct 2024 10:12:05 +0200 Subject: [PATCH 548/683] clippy --- src/tools/miri/cargo-miri/src/phases.rs | 1 - src/tools/miri/src/concurrency/vector_clock.rs | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/tools/miri/cargo-miri/src/phases.rs b/src/tools/miri/cargo-miri/src/phases.rs index 52bc8e1a3b6..f1f76fd338c 100644 --- a/src/tools/miri/cargo-miri/src/phases.rs +++ b/src/tools/miri/cargo-miri/src/phases.rs @@ -668,7 +668,6 @@ pub fn phase_runner(mut binary_args: impl Iterator, phase: Runner RunnerPhase::Rustdoc => { cmd.stdin(std::process::Stdio::piped()); // the warning is wrong, we have a `wait` inside the `scope` closure. - #[expect(clippy::zombie_processes)] let mut child = cmd.spawn().expect("failed to spawn process"); let child_stdin = child.stdin.take().unwrap(); // Write stdin in a background thread, as it may block. diff --git a/src/tools/miri/src/concurrency/vector_clock.rs b/src/tools/miri/src/concurrency/vector_clock.rs index f9025e06c68..34572663429 100644 --- a/src/tools/miri/src/concurrency/vector_clock.rs +++ b/src/tools/miri/src/concurrency/vector_clock.rs @@ -151,7 +151,7 @@ impl VClock { /// Load the internal timestamp slice in the vector clock #[inline] pub(super) fn as_slice(&self) -> &[VTimestamp] { - debug_assert!(!self.0.last().is_some_and(|t| t.time() == 0)); + debug_assert!(self.0.last().is_none_or(|t| t.time() != 0)); self.0.as_slice() } From 32099dbc1e112e34047a8ee458bf35aae76c7b46 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 4 Oct 2024 12:11:23 +0200 Subject: [PATCH 549/683] Enable `--no-sandbox` option by default for rustdoc GUI tests --- .../host-x86_64/x86_64-gnu-tools/Dockerfile | 2 +- src/tools/rustdoc-gui/tester.js | 26 +------------------ tests/rustdoc-gui/README.md | 7 ----- 3 files changed, 2 insertions(+), 33 deletions(-) diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile index 6a09ab3065f..145f41f21e1 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile @@ -100,4 +100,4 @@ RUN /scripts/build-gccjit.sh /scripts # the local version of the package is different than the one used by the CI. ENV SCRIPT /tmp/checktools.sh ../x.py && \ npm install browser-ui-test@$(head -n 1 /tmp/browser-ui-test.version) --unsafe-perm=true && \ - python3 ../x.py test tests/rustdoc-gui --stage 2 --test-args "'--no-sandbox --jobs 1'" + python3 ../x.py test tests/rustdoc-gui --stage 2 --test-args "'--jobs 1'" diff --git a/src/tools/rustdoc-gui/tester.js b/src/tools/rustdoc-gui/tester.js index 8f6626f6296..c5874b4ee02 100644 --- a/src/tools/rustdoc-gui/tester.js +++ b/src/tools/rustdoc-gui/tester.js @@ -19,7 +19,6 @@ function showHelp() { console.log(" --debug : show extra information about script run"); console.log(" --show-text : render font in pages"); console.log(" --no-headless : disable headless mode"); - console.log(" --no-sandbox : disable sandbox mode"); console.log(" --help : show this message then quit"); console.log(" --tests-folder [PATH] : location of the .GOML tests folder"); console.log(" --jobs [NUMBER] : number of threads to run tests on"); @@ -40,7 +39,6 @@ function parseOptions(args) { "no_headless": false, "jobs": -1, "executable_path": null, - "no_sandbox": false, }; const correspondences = { "--doc-folder": "doc_folder", @@ -49,7 +47,6 @@ function parseOptions(args) { "--show-text": "show_text", "--no-headless": "no_headless", "--executable-path": "executable_path", - "--no-sandbox": "no_sandbox", }; for (let i = 0; i < args.length; ++i) { @@ -80,9 +77,6 @@ function parseOptions(args) { } else if (arg === "--help") { showHelp(); process.exit(0); - } else if (arg === "--no-sandbox") { - console.log("`--no-sandbox` is being used. Be very careful!"); - opts[correspondences[arg]] = true; } else if (correspondences[arg]) { opts[correspondences[arg]] = true; } else { @@ -203,6 +197,7 @@ async function main(argv) { const args = [ "--variable", "DOC_PATH", opts["doc_folder"].split("\\").join("/"), "--enable-fail-on-js-error", "--allow-file-access-from-files", + "--no-sandbox", ]; if (opts["debug"]) { debug = true; @@ -211,9 +206,6 @@ async function main(argv) { if (opts["show_text"]) { args.push("--show-text"); } - if (opts["no_sandbox"]) { - args.push("--no-sandbox"); - } if (opts["no_headless"]) { args.push("--no-headless"); headless = false; @@ -262,19 +254,6 @@ async function main(argv) { console.log(`Running ${files.length} rustdoc-gui ...`); } - // We catch this "event" to display a nicer message in case of unexpected exit (because of a - // missing `--no-sandbox`). - const exitHandling = () => { - if (!opts["no_sandbox"]) { - console.log(""); - console.log( - "`browser-ui-test` crashed unexpectedly. Please try again with adding `--test-args \ ---no-sandbox` at the end. For example: `x.py test tests/rustdoc-gui --test-args --no-sandbox`"); - console.log(""); - } - }; - process.on("exit", exitHandling); - const originalFilesLen = files.length; const results = createEmptyResults(); const status_bar = char_printer(files.length); @@ -299,9 +278,6 @@ async function main(argv) { Array.prototype.push.apply(results.failed, new_results.failed); Array.prototype.push.apply(results.errored, new_results.errored); - // We don't need this listener anymore. - process.removeListener("exit", exitHandling); - if (debug) { results.successful.sort(by_filename); results.successful.forEach(r => { diff --git a/tests/rustdoc-gui/README.md b/tests/rustdoc-gui/README.md index 1126a72ab67..efd513715d4 100644 --- a/tests/rustdoc-gui/README.md +++ b/tests/rustdoc-gui/README.md @@ -23,12 +23,5 @@ $ ./x.py test tests/rustdoc-gui --stage 1 --test-args --no-headless To see the supported options, use `--help`. -Important to be noted: if the chromium instance crashes when you run it, you might need to -use `--no-sandbox` to make it work: - -```bash -$ ./x.py test tests/rustdoc-gui --stage 1 --test-args --no-sandbox -``` - [browser-ui-test]: https://github.com/GuillaumeGomez/browser-UI-test/ [puppeteer]: https://pptr.dev/ From 68034f837a39387e49fc7d7c5b088f5372a1127e Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 4 Oct 2024 11:24:18 +0200 Subject: [PATCH 550/683] Disable -Zdual-proc-macros if the target doesn't support proc-macros --- src/bootstrap/src/core/builder.rs | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/src/bootstrap/src/core/builder.rs b/src/bootstrap/src/core/builder.rs index 47420f8fe72..837ea276d13 100644 --- a/src/bootstrap/src/core/builder.rs +++ b/src/bootstrap/src/core/builder.rs @@ -1683,10 +1683,24 @@ impl<'a> Builder<'a> { match mode { Mode::Std | Mode::ToolBootstrap | Mode::ToolStd => {} Mode::Rustc | Mode::Codegen | Mode::ToolRustc => { - // Build proc macros both for the host and the target + // Build proc macros both for the host and the target unless proc-macros are not + // supported by the target. if target != compiler.host && cmd_kind != Kind::Check { - cargo.arg("-Zdual-proc-macros"); - rustflags.arg("-Zdual-proc-macros"); + let error = command(self.rustc(compiler)) + .arg("--target") + .arg(target.rustc_target_arg()) + .arg("--print=file-names") + .arg("--crate-type=proc-macro") + .arg("-") + .run_capture(self) + .stderr(); + let not_supported = error + .lines() + .any(|line| line.contains("unsupported crate type `proc-macro`")); + if !not_supported { + cargo.arg("-Zdual-proc-macros"); + rustflags.arg("-Zdual-proc-macros"); + } } } } From bf1f5c902bf367de1578f9598deda011d9d307e2 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 4 Oct 2024 11:36:39 +0200 Subject: [PATCH 551/683] Avoid unused import warning for the Ctrl-C handler on wasm --- compiler/rustc_driver_impl/src/lib.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index 76b7270d4b8..a59dea557bb 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -29,13 +29,12 @@ use std::path::PathBuf; use std::process::{self, Command, Stdio}; use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::{Arc, OnceLock}; -use std::time::{Duration, Instant, SystemTime}; +use std::time::{Instant, SystemTime}; use std::{env, str}; use rustc_ast as ast; use rustc_codegen_ssa::traits::CodegenBackend; use rustc_codegen_ssa::{CodegenErrors, CodegenResults}; -use rustc_const_eval::CTRL_C_RECEIVED; use rustc_data_structures::profiling::{ TimePassesFormat, get_resident_set_size, print_time_passes_entry, }; @@ -1577,8 +1576,8 @@ pub fn install_ctrlc_handler() { // time to check CTRL_C_RECEIVED and run its own shutdown logic, but after a short amount // of time exit the process. This sleep+exit ensures that even if nobody is checking // CTRL_C_RECEIVED, the compiler exits reasonably promptly. - CTRL_C_RECEIVED.store(true, Ordering::Relaxed); - std::thread::sleep(Duration::from_millis(100)); + rustc_const_eval::CTRL_C_RECEIVED.store(true, Ordering::Relaxed); + std::thread::sleep(std::time::Duration::from_millis(100)); std::process::exit(1); }) .expect("Unable to install ctrlc handler"); From 0369ee4c9b4cb51a774976ae54b052a71d370270 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?= Date: Fri, 4 Oct 2024 11:20:38 +0000 Subject: [PATCH 552/683] Week off of reviews to focus on docs Dedicating a week to work on rustc-dev-guide. --- triagebot.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/triagebot.toml b/triagebot.toml index aba36692828..8f3af1f25bd 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -925,6 +925,7 @@ users_on_vacation = [ "jhpratt", "jyn514", "oli-obk", + "jieyouxu", ] [assign.adhoc_groups] From 018ba0528fa5d22712397e520351295f8582a525 Mon Sep 17 00:00:00 2001 From: Urgau Date: Thu, 3 Oct 2024 15:05:23 +0200 Subject: [PATCH 553/683] Use wide pointers consistenly across the compiler --- .../example/std_example.rs | 4 +-- compiler/rustc_codegen_cranelift/src/base.rs | 10 +++---- .../rustc_codegen_cranelift/src/common.rs | 2 +- .../src/debuginfo/types.rs | 2 +- .../rustc_codegen_gcc/src/intrinsic/simd.rs | 4 +-- compiler/rustc_codegen_gcc/src/type_of.rs | 2 +- compiler/rustc_codegen_llvm/src/abi.rs | 2 +- .../src/debuginfo/metadata.rs | 30 +++++++++---------- .../rustc_codegen_llvm/src/debuginfo/utils.rs | 18 +++++------ compiler/rustc_codegen_llvm/src/intrinsic.rs | 4 +-- compiler/rustc_codegen_llvm/src/type_of.rs | 2 +- compiler/rustc_codegen_ssa/messages.ftl | 2 +- compiler/rustc_codegen_ssa/src/errors.rs | 4 +-- compiler/rustc_codegen_ssa/src/mir/mod.rs | 6 ++-- compiler/rustc_codegen_ssa/src/mir/operand.rs | 2 +- compiler/rustc_codegen_ssa/src/mir/rvalue.rs | 14 ++++----- .../rustc_const_eval/src/interpret/cast.rs | 6 ++-- .../src/error_codes/E0607.md | 10 +++---- .../rustc_hir_analysis/src/check/check.rs | 2 +- .../src/coherence/builtin.rs | 2 +- compiler/rustc_hir_typeck/messages.ftl | 8 ++--- compiler/rustc_hir_typeck/src/cast.rs | 20 ++++++------- compiler/rustc_hir_typeck/src/errors.rs | 4 +-- compiler/rustc_hir_typeck/src/expectation.rs | 2 +- compiler/rustc_hir_typeck/src/expr.rs | 2 +- compiler/rustc_middle/src/ty/adjustment.rs | 6 ++-- compiler/rustc_middle/src/ty/layout.rs | 14 ++++----- compiler/rustc_middle/src/ty/sty.rs | 4 +-- compiler/rustc_mir_transform/src/gvn.rs | 6 ++-- compiler/rustc_monomorphize/src/collector.rs | 8 ++--- compiler/rustc_target/src/abi/call/mod.rs | 2 +- compiler/rustc_target/src/abi/mod.rs | 2 +- compiler/rustc_ty_utils/src/abi.rs | 14 ++++----- compiler/stable_mir/src/mir/body.rs | 6 ++-- tests/ui/cast/fat-ptr-cast.stderr | 2 +- ...e_elem_ty_mismatch_in_unsizing_cast.stderr | 2 +- tests/ui/error-codes/E0607.stderr | 2 +- tests/ui/error-festival.stderr | 2 +- tests/ui/issues/issue-31511.rs | 2 +- tests/ui/issues/issue-31511.stderr | 2 +- tests/ui/mismatched_types/cast-rfc0401.stderr | 2 +- 41 files changed, 120 insertions(+), 120 deletions(-) diff --git a/compiler/rustc_codegen_cranelift/example/std_example.rs b/compiler/rustc_codegen_cranelift/example/std_example.rs index ebaa9c69c81..3078288c286 100644 --- a/compiler/rustc_codegen_cranelift/example/std_example.rs +++ b/compiler/rustc_codegen_cranelift/example/std_example.rs @@ -168,7 +168,7 @@ fn main() { foo(I64X2([0, 0])); - transmute_fat_pointer(); + transmute_wide_pointer(); rust_call_abi(); @@ -192,7 +192,7 @@ type TwoPtrs = i64; #[cfg(target_pointer_width = "64")] type TwoPtrs = i128; -fn transmute_fat_pointer() -> TwoPtrs { +fn transmute_wide_pointer() -> TwoPtrs { unsafe { transmute::<_, TwoPtrs>("true !") } } diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs index 1ce0aacab49..09680622069 100644 --- a/compiler/rustc_codegen_cranelift/src/base.rs +++ b/compiler/rustc_codegen_cranelift/src/base.rs @@ -713,17 +713,17 @@ fn codegen_stmt<'tcx>( let from_ty = operand.layout().ty; let to_ty = fx.monomorphize(to_ty); - fn is_fat_ptr<'tcx>(fx: &FunctionCx<'_, '_, 'tcx>, ty: Ty<'tcx>) -> bool { + fn is_wide_ptr<'tcx>(fx: &FunctionCx<'_, '_, 'tcx>, ty: Ty<'tcx>) -> bool { ty.builtin_deref(true) .is_some_and(|pointee_ty| has_ptr_meta(fx.tcx, pointee_ty)) } - if is_fat_ptr(fx, from_ty) { - if is_fat_ptr(fx, to_ty) { - // fat-ptr -> fat-ptr + if is_wide_ptr(fx, from_ty) { + if is_wide_ptr(fx, to_ty) { + // wide-ptr -> wide-ptr lval.write_cvalue(fx, operand.cast_pointer_to(dest_layout)); } else { - // fat-ptr -> thin-ptr + // wide-ptr -> thin-ptr let (ptr, _extra) = operand.load_scalar_pair(fx); lval.write_cvalue(fx, CValue::by_val(ptr, dest_layout)) } diff --git a/compiler/rustc_codegen_cranelift/src/common.rs b/compiler/rustc_codegen_cranelift/src/common.rs index e78ba5a3415..69a32cc3d43 100644 --- a/compiler/rustc_codegen_cranelift/src/common.rs +++ b/compiler/rustc_codegen_cranelift/src/common.rs @@ -101,7 +101,7 @@ fn clif_pair_type_from_ty<'tcx>( }) } -/// Is a pointer to this type a fat ptr? +/// Is a pointer to this type a wide ptr? pub(crate) fn has_ptr_meta<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool { if ty.is_sized(tcx, ParamEnv::reveal_all()) { return false; diff --git a/compiler/rustc_codegen_cranelift/src/debuginfo/types.rs b/compiler/rustc_codegen_cranelift/src/debuginfo/types.rs index a710701e72c..714742aeaff 100644 --- a/compiler/rustc_codegen_cranelift/src/debuginfo/types.rs +++ b/compiler/rustc_codegen_cranelift/src/debuginfo/types.rs @@ -139,7 +139,7 @@ impl DebugContext { pointer_type_id } else { - // FIXME implement debuginfo for fat pointers + // FIXME implement debuginfo for wide pointers self.placeholder_for_type(tcx, type_dbg, ptr_type) } } diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs b/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs index eeab2a5f155..4e1b99fdebf 100644 --- a/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs +++ b/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs @@ -478,7 +478,7 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( let metadata = p_ty.ptr_metadata_ty(bx.tcx, |ty| { bx.tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), ty) }); - require!(metadata.is_unit(), InvalidMonomorphization::CastFatPointer { + require!(metadata.is_unit(), InvalidMonomorphization::CastWidePointer { span, name, ty: in_elem @@ -493,7 +493,7 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( let metadata = p_ty.ptr_metadata_ty(bx.tcx, |ty| { bx.tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), ty) }); - require!(metadata.is_unit(), InvalidMonomorphization::CastFatPointer { + require!(metadata.is_unit(), InvalidMonomorphization::CastWidePointer { span, name, ty: out_elem diff --git a/compiler/rustc_codegen_gcc/src/type_of.rs b/compiler/rustc_codegen_gcc/src/type_of.rs index cb45bbde2c2..5b0d862ae6d 100644 --- a/compiler/rustc_codegen_gcc/src/type_of.rs +++ b/compiler/rustc_codegen_gcc/src/type_of.rs @@ -207,7 +207,7 @@ impl<'tcx> LayoutGccExt<'tcx> for TyAndLayout<'tcx> { // layout. if let Abi::Scalar(ref scalar) = self.abi { // Use a different cache for scalars because pointers to DSTs - // can be either fat or thin (data pointers of fat pointers). + // can be either wide or thin (data pointers of wide pointers). if let Some(&ty) = cx.scalar_types.borrow().get(&self.ty) { return ty; } diff --git a/compiler/rustc_codegen_llvm/src/abi.rs b/compiler/rustc_codegen_llvm/src/abi.rs index 3d75393bf06..6a29eb5fa04 100644 --- a/compiler/rustc_codegen_llvm/src/abi.rs +++ b/compiler/rustc_codegen_llvm/src/abi.rs @@ -7,7 +7,7 @@ use rustc_codegen_ssa::mir::place::{PlaceRef, PlaceValue}; use rustc_codegen_ssa::traits::*; use rustc_middle::ty::Ty; use rustc_middle::ty::layout::LayoutOf; -pub(crate) use rustc_middle::ty::layout::{FAT_PTR_ADDR, FAT_PTR_EXTRA}; +pub(crate) use rustc_middle::ty::layout::{WIDE_PTR_ADDR, WIDE_PTR_EXTRA}; use rustc_middle::{bug, ty}; use rustc_session::config; pub(crate) use rustc_target::abi::call::*; diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index b7a6f80956d..15d441a986d 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -34,7 +34,7 @@ use super::utils::{ }; use crate::common::CodegenCx; use crate::debuginfo::metadata::type_map::build_type_with_children; -use crate::debuginfo::utils::{FatPtrKind, fat_pointer_kind}; +use crate::debuginfo::utils::{WidePtrKind, wide_pointer_kind}; use crate::llvm::debuginfo::{ DIDescriptor, DIFile, DIFlags, DILexicalBlock, DIScope, DIType, DebugEmissionKind, DebugNameTableKind, @@ -161,7 +161,7 @@ fn build_pointer_or_reference_di_node<'ll, 'tcx>( unique_type_id: UniqueTypeId<'tcx>, ) -> DINodeCreationResult<'ll> { // The debuginfo generated by this function is only valid if `ptr_type` is really just - // a (fat) pointer. Make sure it is not called for e.g. `Box`. + // a (wide) pointer. Make sure it is not called for e.g. `Box`. assert_eq!( cx.size_and_align_of(ptr_type), cx.size_and_align_of(Ty::new_mut_ptr(cx.tcx, pointee_type)) @@ -174,7 +174,7 @@ fn build_pointer_or_reference_di_node<'ll, 'tcx>( let data_layout = &cx.tcx.data_layout; let ptr_type_debuginfo_name = compute_debuginfo_type_name(cx.tcx, ptr_type, true); - match fat_pointer_kind(cx, pointee_type) { + match wide_pointer_kind(cx, pointee_type) { None => { // This is a thin pointer. Create a regular pointer type and give it the correct name. assert_eq!( @@ -197,7 +197,7 @@ fn build_pointer_or_reference_di_node<'ll, 'tcx>( DINodeCreationResult { di_node, already_stored_in_typemap: false } } - Some(fat_pointer_kind) => { + Some(wide_pointer_kind) => { type_map::build_type_with_children( cx, type_map::stub( @@ -210,7 +210,7 @@ fn build_pointer_or_reference_di_node<'ll, 'tcx>( DIFlags::FlagZero, ), |cx, owner| { - // FIXME: If this fat pointer is a `Box` then we don't want to use its + // FIXME: If this wide pointer is a `Box` then we don't want to use its // type layout and instead use the layout of the raw pointer inside // of it. // The proper way to handle this is to not treat Box as a pointer @@ -227,16 +227,16 @@ fn build_pointer_or_reference_di_node<'ll, 'tcx>( }; let layout = cx.layout_of(layout_type); - let addr_field = layout.field(cx, abi::FAT_PTR_ADDR); - let extra_field = layout.field(cx, abi::FAT_PTR_EXTRA); + let addr_field = layout.field(cx, abi::WIDE_PTR_ADDR); + let extra_field = layout.field(cx, abi::WIDE_PTR_EXTRA); - let (addr_field_name, extra_field_name) = match fat_pointer_kind { - FatPtrKind::Dyn => ("pointer", "vtable"), - FatPtrKind::Slice => ("data_ptr", "length"), + let (addr_field_name, extra_field_name) = match wide_pointer_kind { + WidePtrKind::Dyn => ("pointer", "vtable"), + WidePtrKind::Slice => ("data_ptr", "length"), }; - assert_eq!(abi::FAT_PTR_ADDR, 0); - assert_eq!(abi::FAT_PTR_EXTRA, 1); + assert_eq!(abi::WIDE_PTR_ADDR, 0); + assert_eq!(abi::WIDE_PTR_EXTRA, 1); // The data pointer type is a regular, thin pointer, regardless of whether this // is a slice or a trait object. @@ -258,7 +258,7 @@ fn build_pointer_or_reference_di_node<'ll, 'tcx>( owner, addr_field_name, (addr_field.size, addr_field.align.abi), - layout.fields.offset(abi::FAT_PTR_ADDR), + layout.fields.offset(abi::WIDE_PTR_ADDR), DIFlags::FlagZero, data_ptr_type_di_node, ), @@ -267,7 +267,7 @@ fn build_pointer_or_reference_di_node<'ll, 'tcx>( owner, extra_field_name, (extra_field.size, extra_field.align.abi), - layout.fields.offset(abi::FAT_PTR_EXTRA), + layout.fields.offset(abi::WIDE_PTR_EXTRA), DIFlags::FlagZero, type_di_node(cx, extra_field.ty), ), @@ -391,7 +391,7 @@ fn build_dyn_type_di_node<'ll, 'tcx>( /// /// NOTE: We currently emit just emit the debuginfo for the element type here /// (i.e. `T` for slices and `u8` for `str`), so that we end up with -/// `*const T` for the `data_ptr` field of the corresponding fat-pointer +/// `*const T` for the `data_ptr` field of the corresponding wide-pointer /// debuginfo of `&[T]`. /// /// It would be preferable and more accurate if we emitted a DIArray of T diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/utils.rs b/compiler/rustc_codegen_llvm/src/debuginfo/utils.rs index acb15449ce3..960487ada16 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/utils.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/utils.rs @@ -49,23 +49,23 @@ pub(crate) fn get_namespace_for_item<'ll>(cx: &CodegenCx<'ll, '_>, def_id: DefId } #[derive(Debug, PartialEq, Eq)] -pub(crate) enum FatPtrKind { +pub(crate) enum WidePtrKind { Slice, Dyn, } /// Determines if `pointee_ty` is slice-like or trait-object-like, i.e. -/// if the second field of the fat pointer is a length or a vtable-pointer. -/// If `pointee_ty` does not require a fat pointer (because it is Sized) then +/// if the second field of the wide pointer is a length or a vtable-pointer. +/// If `pointee_ty` does not require a wide pointer (because it is Sized) then /// the function returns `None`. -pub(crate) fn fat_pointer_kind<'ll, 'tcx>( +pub(crate) fn wide_pointer_kind<'ll, 'tcx>( cx: &CodegenCx<'ll, 'tcx>, pointee_ty: Ty<'tcx>, -) -> Option { +) -> Option { let pointee_tail_ty = cx.tcx.struct_tail_for_codegen(pointee_ty, cx.param_env()); let layout = cx.layout_of(pointee_tail_ty); trace!( - "fat_pointer_kind: {:?} has layout {:?} (is_unsized? {})", + "wide_pointer_kind: {:?} has layout {:?} (is_unsized? {})", pointee_tail_ty, layout, layout.is_unsized() @@ -76,8 +76,8 @@ pub(crate) fn fat_pointer_kind<'ll, 'tcx>( } match *pointee_tail_ty.kind() { - ty::Str | ty::Slice(_) => Some(FatPtrKind::Slice), - ty::Dynamic(..) => Some(FatPtrKind::Dyn), + ty::Str | ty::Slice(_) => Some(WidePtrKind::Slice), + ty::Dynamic(..) => Some(WidePtrKind::Dyn), ty::Foreign(_) => { // Assert that pointers to foreign types really are thin: assert_eq!( @@ -90,7 +90,7 @@ pub(crate) fn fat_pointer_kind<'ll, 'tcx>( // For all other pointee types we should already have returned None // at the beginning of the function. panic!( - "fat_pointer_kind() - Encountered unexpected `pointee_tail_ty`: {pointee_tail_ty:?}" + "wide_pointer_kind() - Encountered unexpected `pointee_tail_ty`: {pointee_tail_ty:?}" ) } } diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index c66c80da9fc..30c6f08e894 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -2185,7 +2185,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>( let metadata = p_ty.ptr_metadata_ty(bx.tcx, |ty| { bx.tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), ty) }); - require!(metadata.is_unit(), InvalidMonomorphization::CastFatPointer { + require!(metadata.is_unit(), InvalidMonomorphization::CastWidePointer { span, name, ty: in_elem @@ -2200,7 +2200,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>( let metadata = p_ty.ptr_metadata_ty(bx.tcx, |ty| { bx.tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), ty) }); - require!(metadata.is_unit(), InvalidMonomorphization::CastFatPointer { + require!(metadata.is_unit(), InvalidMonomorphization::CastWidePointer { span, name, ty: out_elem diff --git a/compiler/rustc_codegen_llvm/src/type_of.rs b/compiler/rustc_codegen_llvm/src/type_of.rs index 6e429a1674a..7071dd86ee0 100644 --- a/compiler/rustc_codegen_llvm/src/type_of.rs +++ b/compiler/rustc_codegen_llvm/src/type_of.rs @@ -199,7 +199,7 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyAndLayout<'tcx> { // layout. if let Abi::Scalar(scalar) = self.abi { // Use a different cache for scalars because pointers to DSTs - // can be either fat or thin (data pointers of fat pointers). + // can be either wide or thin (data pointers of wide pointers). if let Some(&llty) = cx.scalar_lltypes.borrow().get(&self.ty) { return llty; } diff --git a/compiler/rustc_codegen_ssa/messages.ftl b/compiler/rustc_codegen_ssa/messages.ftl index 9091602d75b..f02b0f72674 100644 --- a/compiler/rustc_codegen_ssa/messages.ftl +++ b/compiler/rustc_codegen_ssa/messages.ftl @@ -82,7 +82,7 @@ codegen_ssa_invalid_monomorphization_basic_integer_type = invalid monomorphizati codegen_ssa_invalid_monomorphization_cannot_return = invalid monomorphization of `{$name}` intrinsic: cannot return `{$ret_ty}`, expected `u{$expected_int_bits}` or `[u8; {$expected_bytes}]` -codegen_ssa_invalid_monomorphization_cast_fat_pointer = invalid monomorphization of `{$name}` intrinsic: cannot cast fat pointer `{$ty}` +codegen_ssa_invalid_monomorphization_cast_wide_pointer = invalid monomorphization of `{$name}` intrinsic: cannot cast wide pointer `{$ty}` codegen_ssa_invalid_monomorphization_expected_element_type = invalid monomorphization of `{$name}` intrinsic: expected element type `{$expected_element}` of second argument `{$second_arg}` to be a pointer to the element type `{$in_elem}` of the first argument `{$in_ty}`, found `{$expected_element}` != `{$mutability} {$in_elem}` diff --git a/compiler/rustc_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs index 08b326e3ac3..ab909abcead 100644 --- a/compiler/rustc_codegen_ssa/src/errors.rs +++ b/compiler/rustc_codegen_ssa/src/errors.rs @@ -916,8 +916,8 @@ pub enum InvalidMonomorphization<'tcx> { ret_ty: Ty<'tcx>, }, - #[diag(codegen_ssa_invalid_monomorphization_cast_fat_pointer, code = E0511)] - CastFatPointer { + #[diag(codegen_ssa_invalid_monomorphization_cast_wide_pointer, code = E0511)] + CastWidePointer { #[primary_span] span: Span, name: Symbol, diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs index c4fb24aa625..8bd172a9ce6 100644 --- a/compiler/rustc_codegen_ssa/src/mir/mod.rs +++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs @@ -133,9 +133,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { enum LocalRef<'tcx, V> { Place(PlaceRef<'tcx, V>), /// `UnsizedPlace(p)`: `p` itself is a thin pointer (indirect place). - /// `*p` is the fat pointer that references the actual unsized place. + /// `*p` is the wide pointer that references the actual unsized place. /// Every time it is initialized, we have to reallocate the place - /// and update the fat pointer. That's the reason why it is indirect. + /// and update the wide pointer. That's the reason why it is indirect. UnsizedPlace(PlaceRef<'tcx, V>), /// The backend [`OperandValue`] has already been generated. Operand(OperandRef<'tcx, V>), @@ -429,7 +429,7 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( // Unsized indirect qrguments PassMode::Indirect { attrs: _, meta_attrs: Some(_), on_stack: _ } => { // As the storage for the indirect argument lives during - // the whole function call, we just copy the fat pointer. + // the whole function call, we just copy the wide pointer. let llarg = bx.get_param(llarg_idx); llarg_idx += 1; let llextra = bx.get_param(llarg_idx); diff --git a/compiler/rustc_codegen_ssa/src/mir/operand.rs b/compiler/rustc_codegen_ssa/src/mir/operand.rs index 17f66c12a03..0bcd7d6d081 100644 --- a/compiler/rustc_codegen_ssa/src/mir/operand.rs +++ b/compiler/rustc_codegen_ssa/src/mir/operand.rs @@ -41,7 +41,7 @@ pub enum OperandValue { /// The backend value in this variant must be the *immediate* backend type, /// as returned by [`LayoutTypeCodegenMethods::immediate_backend_type`]. Immediate(V), - /// A pair of immediate LLVM values. Used by fat pointers too. + /// A pair of immediate LLVM values. Used by wide pointers too. /// /// An `OperandValue` *must* be this variant for any type for which /// [`LayoutTypeCodegenMethods::is_backend_scalar_pair`] returns `true`. diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index f9c0f3ce941..a132ca69540 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -38,10 +38,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { ref source, _, ) => { - // The destination necessarily contains a fat pointer, so if - // it's a scalar pair, it's a fat pointer or newtype thereof. + // The destination necessarily contains a wide pointer, so if + // it's a scalar pair, it's a wide pointer or newtype thereof. if bx.cx().is_backend_scalar_pair(dest.layout) { - // Into-coerce of a thin pointer to a fat pointer -- just + // Into-coerce of a thin pointer to a wide pointer -- just // use the operand path. let temp = self.codegen_rvalue_operand(bx, rvalue); temp.val.store(bx, dest); @@ -519,7 +519,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { if bx.cx().is_backend_scalar_pair(cast) { OperandValue::Pair(data_ptr, meta) } else { - // Cast of fat-ptr to thin-ptr is an extraction of data-ptr. + // Cast of wide-ptr to thin-ptr is an extraction of data-ptr. OperandValue::Immediate(data_ptr) } } else { @@ -622,7 +622,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { ( OperandValue::Pair(lhs_addr, lhs_extra), OperandValue::Pair(rhs_addr, rhs_extra), - ) => self.codegen_fat_ptr_binop( + ) => self.codegen_wide_ptr_binop( bx, op, lhs_addr, @@ -984,7 +984,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } } - fn codegen_fat_ptr_binop( + fn codegen_wide_ptr_binop( &mut self, bx: &mut Bx, op: mir::BinOp, @@ -1021,7 +1021,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { bx.or(lhs, rhs) } _ => { - bug!("unexpected fat ptr binop"); + bug!("unexpected wide ptr binop"); } } } diff --git a/compiler/rustc_const_eval/src/interpret/cast.rs b/compiler/rustc_const_eval/src/interpret/cast.rs index 565a7d16242..30b5a8d70bc 100644 --- a/compiler/rustc_const_eval/src/interpret/cast.rs +++ b/compiler/rustc_const_eval/src/interpret/cast.rs @@ -204,12 +204,12 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { ) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>> { assert!(src.layout.ty.is_any_ptr()); assert!(cast_to.ty.is_unsafe_ptr()); - // Handle casting any ptr to raw ptr (might be a fat ptr). + // Handle casting any ptr to raw ptr (might be a wide ptr). if cast_to.size == src.layout.size { - // Thin or fat pointer that just has the ptr kind of target type changed. + // Thin or wide pointer that just has the ptr kind of target type changed. return interp_ok(ImmTy::from_immediate(**src, cast_to)); } else { - // Casting the metadata away from a fat ptr. + // Casting the metadata away from a wide ptr. assert_eq!(src.layout.size, 2 * self.pointer_size()); assert_eq!(cast_to.size, self.pointer_size()); assert!(src.layout.ty.is_unsafe_ptr()); diff --git a/compiler/rustc_error_codes/src/error_codes/E0607.md b/compiler/rustc_error_codes/src/error_codes/E0607.md index 0545246929f..8ebc227114d 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0607.md +++ b/compiler/rustc_error_codes/src/error_codes/E0607.md @@ -1,4 +1,4 @@ -A cast between a thin and a fat pointer was attempted. +A cast between a thin and a wide pointer was attempted. Erroneous code example: @@ -7,18 +7,18 @@ let v = core::ptr::null::(); v as *const [u8]; ``` -First: what are thin and fat pointers? +First: what are thin and wide pointers? Thin pointers are "simple" pointers: they are purely a reference to a memory address. -Fat pointers are pointers referencing Dynamically Sized Types (also called +Wide pointers are pointers referencing Dynamically Sized Types (also called DSTs). DSTs don't have a statically known size, therefore they can only exist behind some kind of pointer that contains additional information. For example, slices and trait objects are DSTs. In the case of slices, the additional -information the fat pointer holds is their size. +information the wide pointer holds is their size. -To fix this error, don't try to cast directly between thin and fat pointers. +To fix this error, don't try to cast directly between thin and wide pointers. For more information about type casts, take a look at the section of the [The Rust Reference][1] on type cast expressions. diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index d725772a5b3..3692555a6c6 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -1105,7 +1105,7 @@ fn check_simd(tcx: TyCtxt<'_>, sp: Span, def_id: LocalDefId) { // Check that we use types valid for use in the lanes of a SIMD "vector register" // These are scalar types which directly match a "machine" type // Yes: Integers, floats, "thin" pointers - // No: char, "fat" pointers, compound types + // No: char, "wide" pointers, compound types match element_ty.kind() { ty::Param(_) => (), // pass struct([T; 4]) through, let monomorphization catch errors ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::RawPtr(_, _) => (), // struct([u8; 4]) is ok diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs index bea8d28a9f7..76c75d976ee 100644 --- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs +++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs @@ -424,7 +424,7 @@ pub(crate) fn coerce_unsized_info<'tcx>( // Here `U = [i32; 3]` and `V = [i32]`. At runtime, // when this coercion occurs, we would be changing the // field `ptr` from a thin pointer of type `*mut [i32; - // 3]` to a fat pointer of type `*mut [i32]` (with + // 3]` to a wide pointer of type `*mut [i32]` (with // extra data `3`). **The purpose of this check is to // make sure that we know how to do this conversion.** // diff --git a/compiler/rustc_hir_typeck/messages.ftl b/compiler/rustc_hir_typeck/messages.ftl index 39d430cf73b..3669100ed91 100644 --- a/compiler/rustc_hir_typeck/messages.ftl +++ b/compiler/rustc_hir_typeck/messages.ftl @@ -23,17 +23,17 @@ hir_typeck_cannot_cast_to_bool = cannot cast `{$expr_ty}` as `bool` hir_typeck_cast_enum_drop = cannot cast enum `{$expr_ty}` into integer `{$cast_ty}` because it implements `Drop` -hir_typeck_cast_thin_pointer_to_fat_pointer = cannot cast thin pointer `{$expr_ty}` to fat pointer `{$cast_ty}` +hir_typeck_cast_thin_pointer_to_wide_pointer = cannot cast thin pointer `{$expr_ty}` to wide pointer `{$cast_ty}` .teach_help = Thin pointers are "simple" pointers: they are purely a reference to a memory address. - Fat pointers are pointers referencing "Dynamically Sized Types" (also + Wide pointers are pointers referencing "Dynamically Sized Types" (also called DST). DST don't have a statically known size, therefore they can only exist behind some kind of pointers that contain additional information. Slices and trait objects are DSTs. In the case of slices, - the additional information the fat pointer holds is their size. + the additional information the wide pointer holds is their size. - To fix this error, don't try to cast directly between thin and fat + To fix this error, don't try to cast directly between thin and wide pointers. For more information about casts, take a look at The Book: diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs index fcd2940b83a..12fcbc7e50a 100644 --- a/compiler/rustc_hir_typeck/src/cast.rs +++ b/compiler/rustc_hir_typeck/src/cast.rs @@ -66,7 +66,7 @@ pub(crate) struct CastCheck<'tcx> { } /// The kind of pointer and associated metadata (thin, length or vtable) - we -/// only allow casts between fat pointers if their metadata have the same +/// only allow casts between wide pointers if their metadata have the same /// kind. #[derive(Debug, Copy, Clone, PartialEq, Eq, TypeVisitable, TypeFoldable)] enum PointerKind<'tcx> { @@ -162,7 +162,7 @@ enum CastError<'tcx> { src_kind: PointerKind<'tcx>, dst_kind: PointerKind<'tcx>, }, - /// Cast of thin to fat raw ptr (e.g., `*const () as *const [u8]`). + /// Cast of thin to wide raw ptr (e.g., `*const () as *const [u8]`). SizedUnsizedCast, IllegalCast, NeedDeref, @@ -172,12 +172,12 @@ enum CastError<'tcx> { NonScalar, UnknownExprPtrKind, UnknownCastPtrKind, - /// Cast of int to (possibly) fat raw pointer. + /// Cast of int to (possibly) wide raw pointer. /// /// Argument is the specific name of the metadata in plain words, such as "a vtable" /// or "a length". If this argument is None, then the metadata is unknown, for example, /// when we're typechecking a type parameter with a ?Sized bound. - IntToFatCast(Option<&'static str>), + IntToWideCast(Option<&'static str>), ForeignNonExhaustiveAdt, } @@ -545,14 +545,14 @@ impl<'a, 'tcx> CastCheck<'tcx> { err.emit(); } CastError::SizedUnsizedCast => { - fcx.dcx().emit_err(errors::CastThinPointerToFatPointer { + fcx.dcx().emit_err(errors::CastThinPointerToWidePointer { span: self.span, expr_ty: self.expr_ty, cast_ty: fcx.ty_to_string(self.cast_ty), teach: fcx.tcx.sess.teach(E0607), }); } - CastError::IntToFatCast(known_metadata) => { + CastError::IntToWideCast(known_metadata) => { let expr_if_nightly = fcx.tcx.sess.is_nightly_build().then_some(self.expr_span); let cast_ty = fcx.resolve_vars_if_possible(self.cast_ty); let expr_ty = fcx.ty_to_string(self.expr_ty); @@ -861,7 +861,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { return Ok(CastKind::PtrPtrCast); } - // We can't cast to fat pointer if source pointer kind is unknown + // We can't cast to wide pointer if source pointer kind is unknown let Some(src_kind) = src_kind else { return Err(CastError::UnknownCastPtrKind); }; @@ -1054,10 +1054,10 @@ impl<'a, 'tcx> CastCheck<'tcx> { match fcx.pointer_kind(m_cast.ty, self.span)? { None => Err(CastError::UnknownCastPtrKind), Some(PointerKind::Thin) => Ok(CastKind::AddrPtrCast), - Some(PointerKind::VTable(_)) => Err(CastError::IntToFatCast(Some("a vtable"))), - Some(PointerKind::Length) => Err(CastError::IntToFatCast(Some("a length"))), + Some(PointerKind::VTable(_)) => Err(CastError::IntToWideCast(Some("a vtable"))), + Some(PointerKind::Length) => Err(CastError::IntToWideCast(Some("a length"))), Some(PointerKind::OfAlias(_) | PointerKind::OfParam(_)) => { - Err(CastError::IntToFatCast(None)) + Err(CastError::IntToWideCast(None)) } } } diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs index a692642ccfc..cceaabaff65 100644 --- a/compiler/rustc_hir_typeck/src/errors.rs +++ b/compiler/rustc_hir_typeck/src/errors.rs @@ -699,8 +699,8 @@ pub(crate) struct ReplaceWithName { } #[derive(Diagnostic)] -#[diag(hir_typeck_cast_thin_pointer_to_fat_pointer, code = E0607)] -pub(crate) struct CastThinPointerToFatPointer<'tcx> { +#[diag(hir_typeck_cast_thin_pointer_to_wide_pointer, code = E0607)] +pub(crate) struct CastThinPointerToWidePointer<'tcx> { #[primary_span] pub span: Span, pub expr_ty: Ty<'tcx>, diff --git a/compiler/rustc_hir_typeck/src/expectation.rs b/compiler/rustc_hir_typeck/src/expectation.rs index 67f4dbee3cb..4653458b5dd 100644 --- a/compiler/rustc_hir_typeck/src/expectation.rs +++ b/compiler/rustc_hir_typeck/src/expectation.rs @@ -55,7 +55,7 @@ impl<'a, 'tcx> Expectation<'tcx> { /// be checked higher up, as is the case with `&expr` and `box expr`), but /// is useful in determining the concrete type. /// - /// The primary use case is where the expected type is a fat pointer, + /// The primary use case is where the expected type is a wide pointer, /// like `&[isize]`. For example, consider the following statement: /// /// let x: &[isize] = &[1, 2, 3]; diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index b34ed4640db..e3c7dded0ca 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -413,7 +413,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty::Ref(_, ty, _) | ty::RawPtr(ty, _) => { if oprnd.is_syntactic_place_expr() { // Places may legitimately have unsized types. - // For example, dereferences of a fat pointer and + // For example, dereferences of a wide pointer and // the last field of a struct can be unsized. ExpectHasType(*ty) } else { diff --git a/compiler/rustc_middle/src/ty/adjustment.rs b/compiler/rustc_middle/src/ty/adjustment.rs index 41a20e89cbf..71833eea5c0 100644 --- a/compiler/rustc_middle/src/ty/adjustment.rs +++ b/compiler/rustc_middle/src/ty/adjustment.rs @@ -25,10 +25,10 @@ pub enum PointerCoercion { ArrayToPointer, /// Unsize a pointer/reference value, e.g., `&[T; n]` to - /// `&[T]`. Note that the source could be a thin or fat pointer. - /// This will do things like convert thin pointers to fat + /// `&[T]`. Note that the source could be a thin or wide pointer. + /// This will do things like convert thin pointers to wide /// pointers, or convert structs containing thin pointers to - /// structs containing fat pointers, or convert between fat + /// structs containing wide pointers, or convert between wide /// pointers. We don't store the details of how the transform is /// done (in fact, we don't know that, because it might depend on /// the precise type parameters). We just store the target diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index cf0c29e0c8c..4ba2a9b1d73 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -164,17 +164,17 @@ impl Primitive { } } -/// The first half of a fat pointer. +/// The first half of a wide pointer. /// /// - For a trait object, this is the address of the box. /// - For a slice, this is the base address. -pub const FAT_PTR_ADDR: usize = 0; +pub const WIDE_PTR_ADDR: usize = 0; -/// The second half of a fat pointer. +/// The second half of a wide pointer. /// /// - For a trait object, this is the address of the vtable. /// - For a slice, this is the length. -pub const FAT_PTR_EXTRA: usize = 1; +pub const WIDE_PTR_EXTRA: usize = 1; /// The maximum supported number of lanes in a SIMD vector. /// @@ -312,7 +312,7 @@ pub enum SizeSkeleton<'tcx> { /// that another SizeSkeleton is of equal size. Generic(ty::Const<'tcx>), - /// A potentially-fat pointer. + /// A potentially-wide pointer. Pointer { /// If true, this pointer is never null. non_zero: bool, @@ -785,11 +785,11 @@ where bug!("TyAndLayout::field({:?}): not applicable", this) } - // Potentially-fat pointers. + // Potentially-wide pointers. ty::Ref(_, pointee, _) | ty::RawPtr(pointee, _) => { assert!(i < this.fields.count()); - // Reuse the fat `*T` type as its own thin pointer data field. + // Reuse the wide `*T` type as its own thin pointer data field. // This provides information about, e.g., DST struct pointees // (which may have no non-DST form), and will work as long // as the `Abi` or `FieldsShape` is checked by users. diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index db9978a7f53..489bd49f3e4 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -1589,7 +1589,7 @@ impl<'tcx> Ty<'tcx> { .map_bound(|fn_sig| fn_sig.output().no_bound_vars().unwrap()) } - /// Returns the type of metadata for (potentially fat) pointers to this type, + /// Returns the type of metadata for (potentially wide) pointers to this type, /// or the struct tail if the metadata type cannot be determined. pub fn ptr_metadata_ty_or_tail( self, @@ -1648,7 +1648,7 @@ impl<'tcx> Ty<'tcx> { } } - /// Returns the type of metadata for (potentially fat) pointers to this type. + /// Returns the type of metadata for (potentially wide) pointers to this type. /// Causes an ICE if the metadata type cannot be determined. pub fn ptr_metadata_ty( self, diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index 50c9702cb9b..0bb46675e9a 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -1137,7 +1137,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { (UnOp::PtrMetadata, Value::Aggregate(AggregateTy::RawPtr { .. }, _, fields)) => { return Some(fields[1]); } - // We have an unsizing cast, which assigns the length to fat pointer metadata. + // We have an unsizing cast, which assigns the length to wide pointer metadata. ( UnOp::PtrMetadata, Value::Cast { @@ -1421,7 +1421,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { let mut inner = self.simplify_place_value(place, location)?; - // The length information is stored in the fat pointer. + // The length information is stored in the wide pointer. // Reborrowing copies length information from one pointer to the other. while let Value::Address { place: borrowed, .. } = self.get(inner) && let [PlaceElem::Deref] = borrowed.projection[..] @@ -1430,7 +1430,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { inner = borrowed; } - // We have an unsizing cast, which assigns the length to fat pointer metadata. + // We have an unsizing cast, which assigns the length to wide pointer metadata. if let Value::Cast { kind, from, to, .. } = self.get(inner) && let CastKind::PointerCoercion(ty::adjustment::PointerCoercion::Unsize, _) = kind && let Some(from) = from.builtin_deref(true) diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 05b3859e554..b4d084d4dff 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -119,7 +119,7 @@ //! //! #### Unsizing Casts //! A subtle way of introducing use edges is by casting to a trait object. -//! Since the resulting fat-pointer contains a reference to a vtable, we need to +//! Since the resulting wide-pointer contains a reference to a vtable, we need to //! instantiate all dyn-compatible methods of the trait, as we need to store //! pointers to these functions even if they never get called anywhere. This can //! be seen as a special case of taking a function reference. @@ -661,7 +661,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> { let span = self.body.source_info(location).span; match *rvalue { - // When doing an cast from a regular pointer to a fat pointer, we + // When doing an cast from a regular pointer to a wide pointer, we // have to instantiate all methods of the trait being cast to, so we // can build the appropriate vtable. mir::Rvalue::Cast( @@ -985,7 +985,7 @@ fn should_codegen_locally<'tcx>(tcx: TyCtxtAt<'tcx>, instance: Instance<'tcx>) - /// ``` /// /// Then the output of this function would be (SomeStruct, SomeTrait) since for -/// constructing the `target` fat-pointer we need the vtable for that pair. +/// constructing the `target` wide-pointer we need the vtable for that pair. /// /// Things can get more complicated though because there's also the case where /// the unsized type occurs as a field: @@ -999,7 +999,7 @@ fn should_codegen_locally<'tcx>(tcx: TyCtxtAt<'tcx>, instance: Instance<'tcx>) - /// ``` /// /// In this case, if `T` is sized, `&ComplexStruct` is a thin pointer. If `T` -/// is unsized, `&SomeStruct` is a fat pointer, and the vtable it points to is +/// is unsized, `&SomeStruct` is a wide pointer, and the vtable it points to is /// for the pair of `T` (which is a trait) and the concrete type that `T` was /// originally coerced from: /// diff --git a/compiler/rustc_target/src/abi/call/mod.rs b/compiler/rustc_target/src/abi/call/mod.rs index f4469467249..352861c5ccb 100644 --- a/compiler/rustc_target/src/abi/call/mod.rs +++ b/compiler/rustc_target/src/abi/call/mod.rs @@ -637,7 +637,7 @@ impl<'a, Ty> ArgAbi<'a, Ty> { } } - /// Pass this argument indirectly, by passing a (thin or fat) pointer to the argument instead. + /// Pass this argument indirectly, by passing a (thin or wide) pointer to the argument instead. /// This is valid for both sized and unsized arguments. pub fn make_indirect(&mut self) { match self.mode { diff --git a/compiler/rustc_target/src/abi/mod.rs b/compiler/rustc_target/src/abi/mod.rs index 3eaff652618..fc92e755fea 100644 --- a/compiler/rustc_target/src/abi/mod.rs +++ b/compiler/rustc_target/src/abi/mod.rs @@ -135,7 +135,7 @@ impl<'a> Layout<'a> { /// Note that the layout is NOT guaranteed to always be identical /// to that obtained from `layout_of(ty)`, as we need to produce /// layouts for which Rust types do not exist, such as enum variants -/// or synthetic fields of enums (i.e., discriminants) and fat pointers. +/// or synthetic fields of enums (i.e., discriminants) and wide pointers. #[derive(Copy, Clone, PartialEq, Eq, Hash, HashStable_Generic)] pub struct TyAndLayout<'a, Ty> { pub ty: Ty, diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs index f23c2cf2c07..3d6c09bf89c 100644 --- a/compiler/rustc_ty_utils/src/abi.rs +++ b/compiler/rustc_ty_utils/src/abi.rs @@ -357,7 +357,7 @@ fn fn_abi_of_instance<'tcx>( ) } -// Handle safe Rust thin and fat pointers. +// Handle safe Rust thin and wide pointers. fn adjust_for_rust_scalar<'tcx>( cx: LayoutCx<'tcx>, attrs: &mut ArgAttributes, @@ -810,7 +810,7 @@ fn make_thin_self_ptr<'tcx>( layout: TyAndLayout<'tcx>, ) -> TyAndLayout<'tcx> { let tcx = cx.tcx(); - let fat_pointer_ty = if layout.is_unsized() { + let wide_pointer_ty = if layout.is_unsized() { // unsized `self` is passed as a pointer to `self` // FIXME (mikeyhew) change this to use &own if it is ever added to the language Ty::new_mut_ptr(tcx, layout.ty) @@ -825,15 +825,15 @@ fn make_thin_self_ptr<'tcx>( // elsewhere in the compiler as a method on a `dyn Trait`. // To get the type `*mut RcBox`, we just keep unwrapping newtypes until we // get a built-in pointer type - let mut fat_pointer_layout = layout; - while !fat_pointer_layout.ty.is_unsafe_ptr() && !fat_pointer_layout.ty.is_ref() { - fat_pointer_layout = fat_pointer_layout + let mut wide_pointer_layout = layout; + while !wide_pointer_layout.ty.is_unsafe_ptr() && !wide_pointer_layout.ty.is_ref() { + wide_pointer_layout = wide_pointer_layout .non_1zst_field(cx) .expect("not exactly one non-1-ZST field in a `DispatchFromDyn` type") .1 } - fat_pointer_layout.ty + wide_pointer_layout.ty }; // we now have a type like `*mut RcBox` @@ -842,7 +842,7 @@ fn make_thin_self_ptr<'tcx>( let unit_ptr_ty = Ty::new_mut_ptr(tcx, tcx.types.unit); TyAndLayout { - ty: fat_pointer_ty, + ty: wide_pointer_ty, // NOTE(eddyb) using an empty `ParamEnv`, and `unwrap`-ing the `Result` // should always work because the type is always `*mut ()`. diff --git a/compiler/stable_mir/src/mir/body.rs b/compiler/stable_mir/src/mir/body.rs index ab9fc218d19..9f4db7e4833 100644 --- a/compiler/stable_mir/src/mir/body.rs +++ b/compiler/stable_mir/src/mir/body.rs @@ -946,10 +946,10 @@ pub enum PointerCoercion { ArrayToPointer, /// Unsize a pointer/reference value, e.g., `&[T; n]` to - /// `&[T]`. Note that the source could be a thin or fat pointer. - /// This will do things like convert thin pointers to fat + /// `&[T]`. Note that the source could be a thin or wide pointer. + /// This will do things like convert thin pointers to wide /// pointers, or convert structs containing thin pointers to - /// structs containing fat pointers, or convert between fat + /// structs containing wide pointers, or convert between wide /// pointers. Unsize, } diff --git a/tests/ui/cast/fat-ptr-cast.stderr b/tests/ui/cast/fat-ptr-cast.stderr index 18e7b68ff3c..2b0bceebf15 100644 --- a/tests/ui/cast/fat-ptr-cast.stderr +++ b/tests/ui/cast/fat-ptr-cast.stderr @@ -44,7 +44,7 @@ LL | p as usize; | = help: cast through a thin pointer first -error[E0607]: cannot cast thin pointer `*const i32` to fat pointer `*const [i32]` +error[E0607]: cannot cast thin pointer `*const i32` to wide pointer `*const [i32]` --> $DIR/fat-ptr-cast.rs:19:5 | LL | q as *const [i32]; diff --git a/tests/ui/consts/slice_elem_ty_mismatch_in_unsizing_cast.stderr b/tests/ui/consts/slice_elem_ty_mismatch_in_unsizing_cast.stderr index 3b861d784d8..19e7a723a22 100644 --- a/tests/ui/consts/slice_elem_ty_mismatch_in_unsizing_cast.stderr +++ b/tests/ui/consts/slice_elem_ty_mismatch_in_unsizing_cast.stderr @@ -1,4 +1,4 @@ -error[E0607]: cannot cast thin pointer `*const [i64; 0]` to fat pointer `*const [u8]` +error[E0607]: cannot cast thin pointer `*const [i64; 0]` to wide pointer `*const [u8]` --> $DIR/slice_elem_ty_mismatch_in_unsizing_cast.rs:1:31 | LL | const FOO: &str = unsafe { &*(1_usize as *const [i64; 0] as *const [u8] as *const str) }; diff --git a/tests/ui/error-codes/E0607.stderr b/tests/ui/error-codes/E0607.stderr index 835ababf449..3fa134c2028 100644 --- a/tests/ui/error-codes/E0607.stderr +++ b/tests/ui/error-codes/E0607.stderr @@ -1,4 +1,4 @@ -error[E0607]: cannot cast thin pointer `*const u8` to fat pointer `*const [u8]` +error[E0607]: cannot cast thin pointer `*const u8` to wide pointer `*const [u8]` --> $DIR/E0607.rs:3:5 | LL | v as *const [u8]; diff --git a/tests/ui/error-festival.stderr b/tests/ui/error-festival.stderr index 9d75671c4e6..26393352b2b 100644 --- a/tests/ui/error-festival.stderr +++ b/tests/ui/error-festival.stderr @@ -81,7 +81,7 @@ help: dereference the expression LL | let y: u32 = *x as u32; | + -error[E0607]: cannot cast thin pointer `*const u8` to fat pointer `*const [u8]` +error[E0607]: cannot cast thin pointer `*const u8` to wide pointer `*const [u8]` --> $DIR/error-festival.rs:41:5 | LL | v as *const [u8]; diff --git a/tests/ui/issues/issue-31511.rs b/tests/ui/issues/issue-31511.rs index 53fecb01663..6c8df1157c6 100644 --- a/tests/ui/issues/issue-31511.rs +++ b/tests/ui/issues/issue-31511.rs @@ -1,6 +1,6 @@ fn cast_thin_to_fat(x: *const ()) { x as *const [u8]; - //~^ ERROR: cannot cast thin pointer `*const ()` to fat pointer `*const [u8]` + //~^ ERROR: cannot cast thin pointer `*const ()` to wide pointer `*const [u8]` } fn main() {} diff --git a/tests/ui/issues/issue-31511.stderr b/tests/ui/issues/issue-31511.stderr index 177b78754cc..2048bd7ec16 100644 --- a/tests/ui/issues/issue-31511.stderr +++ b/tests/ui/issues/issue-31511.stderr @@ -1,4 +1,4 @@ -error[E0607]: cannot cast thin pointer `*const ()` to fat pointer `*const [u8]` +error[E0607]: cannot cast thin pointer `*const ()` to wide pointer `*const [u8]` --> $DIR/issue-31511.rs:2:5 | LL | x as *const [u8]; diff --git a/tests/ui/mismatched_types/cast-rfc0401.stderr b/tests/ui/mismatched_types/cast-rfc0401.stderr index 3d12ba9899b..2e5cbb90036 100644 --- a/tests/ui/mismatched_types/cast-rfc0401.stderr +++ b/tests/ui/mismatched_types/cast-rfc0401.stderr @@ -158,7 +158,7 @@ LL | let _ = 42usize as *const [u8]; | | | consider casting this expression to `*const ()`, then using `core::ptr::from_raw_parts` -error[E0607]: cannot cast thin pointer `*const u8` to fat pointer `*const [u8]` +error[E0607]: cannot cast thin pointer `*const u8` to wide pointer `*const [u8]` --> $DIR/cast-rfc0401.rs:52:13 | LL | let _ = v as *const [u8]; From f59c8fffe3c821f93ced12e628404f9ba7eec3bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Mon, 9 Sep 2024 10:24:35 +0200 Subject: [PATCH 554/683] Avoid dynamic linking to libstd in `command-current-dir` test --- src/bootstrap/src/core/build_steps/compile.rs | 4 ++-- tests/ui/command/command-current-dir.rs | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index c274bcc2df7..b5be7d841dd 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -1928,8 +1928,8 @@ impl Step for Assemble { let is_dylib_or_debug = is_dylib(&filename) || is_debug_info(&filename); // If we link statically to stdlib, do not copy the libstd dynamic library file - // Currently, we do not avoid the copy on Windows, as it seems to be causing issues in - // post-optimization stage0 tests. + // FIXME: Also do this for Windows once incremental post-optimization stage0 tests + // work without std.dll (see https://github.com/rust-lang/rust/pull/131188). let can_be_rustc_dynamic_dep = if builder .link_std_into_rustc_driver(target_compiler.host) && !target_compiler.host.is_windows() diff --git a/tests/ui/command/command-current-dir.rs b/tests/ui/command/command-current-dir.rs index 95c16bce6e8..23269e41231 100644 --- a/tests/ui/command/command-current-dir.rs +++ b/tests/ui/command/command-current-dir.rs @@ -1,4 +1,5 @@ //@ run-pass +//@ no-prefer-dynamic We move the binary around, so do not depend dynamically on libstd //@ ignore-wasm32 no processes //@ ignore-sgx no processes //@ ignore-fuchsia Needs directory creation privilege From ea3d336bbb6bb0808a01aeb361cc7a43b128b215 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Fri, 4 Oct 2024 15:46:19 +0200 Subject: [PATCH 555/683] Remove mw from triagebot.toml cc https://github.com/rust-lang/team/pull/1565 --- triagebot.toml | 3 --- 1 file changed, 3 deletions(-) diff --git a/triagebot.toml b/triagebot.toml index aba36692828..1695b8ddfe6 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -938,7 +938,6 @@ compiler-team = [ "@oli-obk", "@pnkfelix", "@wesleywiser", - "@michaelwoerister", ] compiler-team-contributors = [ "@TaKO8Ki", @@ -989,7 +988,6 @@ query-system = [ "@cjgillot", ] incremental = [ - "@michaelwoerister", "@wesleywiser", ] diagnostics = [ @@ -1048,7 +1046,6 @@ ast_lowering = [ "@spastorino", ] debuginfo = [ - "@michaelwoerister", "@davidtwco" ] fallback = [ From c6774f19e7093633749ad6fa2474c04e7e2fcdb8 Mon Sep 17 00:00:00 2001 From: Taiki Endo Date: Fri, 4 Oct 2024 23:33:30 +0900 Subject: [PATCH 556/683] Fix typo in csky-unknown-linux-gnuabiv2.md --- .../rustc/src/platform-support/csky-unknown-linux-gnuabiv2.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustc/src/platform-support/csky-unknown-linux-gnuabiv2.md b/src/doc/rustc/src/platform-support/csky-unknown-linux-gnuabiv2.md index e72bfb8bae7..32e4f855313 100644 --- a/src/doc/rustc/src/platform-support/csky-unknown-linux-gnuabiv2.md +++ b/src/doc/rustc/src/platform-support/csky-unknown-linux-gnuabiv2.md @@ -80,7 +80,7 @@ cd hello_world ```sh CARGO_TARGET_CSKY_UNKNOWN_LINUX_GNUABIV2_RUNNER=${QEMU_PATH}/bin/qemu-cskyv2 -L ${TOOLCHAIN_PATH}/csky-linux-gnuabiv2/libc \ CARGO_TARGET_CSKY_UNKNOWN_LINUX_GNUABIV2_LINKER=${TOOLCHAIN_PATH}/bin/csky-linux-gnuabiv2-gcc \ -RUSTFLAGS="-C target-features=+crt-static" \ +RUSTFLAGS="-C target-feature=+crt-static" \ cargo +stage2 run --target csky-unknown-linux-gnuabiv2 ``` From d00b754721a1cfb4feaa1e06d65c836f856e3c4e Mon Sep 17 00:00:00 2001 From: Tobias Decking Date: Tue, 17 Sep 2024 15:16:55 +0200 Subject: [PATCH 557/683] Implement LLVM x86 gfni intrinsics --- src/tools/miri/src/shims/x86/gfni.rs | 196 +++++++ src/tools/miri/src/shims/x86/mod.rs | 8 + .../pass/shims/x86/intrinsics-x86-gfni.rs | 518 ++++++++++++++++++ 3 files changed, 722 insertions(+) create mode 100644 src/tools/miri/src/shims/x86/gfni.rs create mode 100644 src/tools/miri/tests/pass/shims/x86/intrinsics-x86-gfni.rs diff --git a/src/tools/miri/src/shims/x86/gfni.rs b/src/tools/miri/src/shims/x86/gfni.rs new file mode 100644 index 00000000000..c91b8c835f2 --- /dev/null +++ b/src/tools/miri/src/shims/x86/gfni.rs @@ -0,0 +1,196 @@ +use rustc_span::Symbol; +use rustc_target::spec::abi::Abi; + +use crate::*; + +impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {} +pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { + fn emulate_x86_gfni_intrinsic( + &mut self, + link_name: Symbol, + abi: Abi, + args: &[OpTy<'tcx>], + dest: &MPlaceTy<'tcx>, + ) -> InterpResult<'tcx, EmulateItemResult> { + let this = self.eval_context_mut(); + + // Prefix should have already been checked. + let unprefixed_name = link_name.as_str().strip_prefix("llvm.x86.").unwrap(); + + this.expect_target_feature_for_intrinsic(link_name, "gfni")?; + if unprefixed_name.ends_with(".256") { + this.expect_target_feature_for_intrinsic(link_name, "avx")?; + } else if unprefixed_name.ends_with(".512") { + this.expect_target_feature_for_intrinsic(link_name, "avx512f")?; + } + + match unprefixed_name { + // Used to implement the `_mm{, 256, 512}_gf2p8affine_epi64_epi8` functions. + // See `affine_transform` for details. + // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=gf2p8affine_ + "vgf2p8affineqb.128" | "vgf2p8affineqb.256" | "vgf2p8affineqb.512" => { + let [left, right, imm8] = + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + affine_transform(this, left, right, imm8, dest, /* inverse */ false)?; + } + // Used to implement the `_mm{, 256, 512}_gf2p8affineinv_epi64_epi8` functions. + // See `affine_transform` for details. + // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=gf2p8affineinv + "vgf2p8affineinvqb.128" | "vgf2p8affineinvqb.256" | "vgf2p8affineinvqb.512" => { + let [left, right, imm8] = + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + affine_transform(this, left, right, imm8, dest, /* inverse */ true)?; + } + // Used to implement the `_mm{, 256, 512}_gf2p8mul_epi8` functions. + // Multiplies packed 8-bit integers in `left` and `right` in the finite field GF(2^8) + // and store the results in `dst`. The field GF(2^8) is represented in + // polynomial representation with the reduction polynomial x^8 + x^4 + x^3 + x + 1. + // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=gf2p8mul + "vgf2p8mulb.128" | "vgf2p8mulb.256" | "vgf2p8mulb.512" => { + let [left, right] = + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + + let (left, left_len) = this.project_to_simd(left)?; + let (right, right_len) = this.project_to_simd(right)?; + let (dest, dest_len) = this.project_to_simd(dest)?; + + assert_eq!(left_len, right_len); + assert_eq!(dest_len, right_len); + + for i in 0..dest_len { + let left = this.read_scalar(&this.project_index(&left, i)?)?.to_u8()?; + let right = this.read_scalar(&this.project_index(&right, i)?)?.to_u8()?; + let dest = this.project_index(&dest, i)?; + this.write_scalar(Scalar::from_u8(gf2p8_mul(left, right)), &dest)?; + } + } + _ => return interp_ok(EmulateItemResult::NotSupported), + } + interp_ok(EmulateItemResult::NeedsReturn) + } +} + +/// Calculates the affine transformation `right * left + imm8` inside the finite field GF(2^8). +/// `right` is an 8x8 bit matrix, `left` and `imm8` are bit vectors. +/// If `inverse` is set, then the inverse transformation with respect to the reduction polynomial +/// x^8 + x^4 + x^3 + x + 1 is performed instead. +fn affine_transform<'tcx>( + this: &mut MiriInterpCx<'tcx>, + left: &OpTy<'tcx>, + right: &OpTy<'tcx>, + imm8: &OpTy<'tcx>, + dest: &MPlaceTy<'tcx>, + inverse: bool, +) -> InterpResult<'tcx, ()> { + let (left, left_len) = this.project_to_simd(left)?; + let (right, right_len) = this.project_to_simd(right)?; + let (dest, dest_len) = this.project_to_simd(dest)?; + + assert_eq!(dest_len, right_len); + assert_eq!(dest_len, left_len); + + let imm8 = this.read_scalar(imm8)?.to_u8()?; + + // Each 8x8 bit matrix gets multiplied with eight bit vectors. + // Therefore, the iteration is done in chunks of eight. + for i in (0..dest_len).step_by(8) { + // Get the bit matrix. + let mut matrix = [0u8; 8]; + for j in 0..8 { + matrix[usize::try_from(j).unwrap()] = + this.read_scalar(&this.project_index(&right, i.wrapping_add(j))?)?.to_u8()?; + } + + // Multiply the matrix with the vector and perform the addition. + for j in 0..8 { + let index = i.wrapping_add(j); + let left = this.read_scalar(&this.project_index(&left, index)?)?.to_u8()?; + let left = if inverse { TABLE[usize::from(left)] } else { left }; + + let mut res = 0; + + // Do the matrix multiplication. + for bit in 0u8..8 { + let mut b = matrix[usize::from(bit)] & left; + + // Calculate the parity bit. + b = (b & 0b1111) ^ (b >> 4); + b = (b & 0b11) ^ (b >> 2); + b = (b & 0b1) ^ (b >> 1); + + res |= b << 7u8.wrapping_sub(bit); + } + + // Perform the addition. + res ^= imm8; + + let dest = this.project_index(&dest, index)?; + this.write_scalar(Scalar::from_u8(res), &dest)?; + } + } + + interp_ok(()) +} + +/// A lookup table for computing the inverse byte for the inverse affine transformation. +// This is a evaluated at compile time. Trait based conversion is not available. +/// See for the +/// definition of `gf_inv` which was used for the creation of this table. +#[allow(clippy::cast_possible_truncation)] +static TABLE: [u8; 256] = { + let mut array = [0; 256]; + + let mut i = 1; + while i < 256 { + let mut x = i as u8; + let mut y = gf2p8_mul(x, x); + x = y; + let mut j = 2; + while j < 8 { + x = gf2p8_mul(x, x); + y = gf2p8_mul(x, y); + j += 1; + } + array[i] = y; + i += 1; + } + + array +}; + +/// Multiplies packed 8-bit integers in `left` and `right` in the finite field GF(2^8) +/// and store the results in `dst`. The field GF(2^8) is represented in +/// polynomial representation with the reduction polynomial x^8 + x^4 + x^3 + x + 1. +/// See for details. +// This is a const function. Trait based conversion is not available. +#[allow(clippy::cast_possible_truncation)] +const fn gf2p8_mul(left: u8, right: u8) -> u8 { + // This implementation is based on the `gf2p8mul_byte` definition found inside the Intel intrinsics guide. + // See https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=gf2p8mul + // for more information. + + const POLYNOMIAL: u32 = 0x11b; + + let left = left as u32; + let right = right as u32; + + let mut result = 0u32; + + let mut i = 0u32; + while i < 8 { + if left & (1 << i) != 0 { + result ^= right << i; + } + i = i.wrapping_add(1); + } + + let mut i = 14u32; + while i >= 8 { + if result & (1 << i) != 0 { + result ^= POLYNOMIAL << i.wrapping_sub(8); + } + i = i.wrapping_sub(1); + } + + result as u8 +} diff --git a/src/tools/miri/src/shims/x86/mod.rs b/src/tools/miri/src/shims/x86/mod.rs index 19c678cb7fa..9339d301aee 100644 --- a/src/tools/miri/src/shims/x86/mod.rs +++ b/src/tools/miri/src/shims/x86/mod.rs @@ -15,6 +15,7 @@ mod aesni; mod avx; mod avx2; mod bmi; +mod gfni; mod sha; mod sse; mod sse2; @@ -106,6 +107,13 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this, link_name, abi, args, dest, ); } + // The GFNI extension does not get its own namespace. + // Check for instruction names instead. + name if name.starts_with("vgf2p8affine") || name.starts_with("vgf2p8mulb") => { + return gfni::EvalContextExt::emulate_x86_gfni_intrinsic( + this, link_name, abi, args, dest, + ); + } name if name.starts_with("sha") => { return sha::EvalContextExt::emulate_x86_sha_intrinsic( this, link_name, abi, args, dest, diff --git a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-gfni.rs b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-gfni.rs new file mode 100644 index 00000000000..a629e2acfe9 --- /dev/null +++ b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-gfni.rs @@ -0,0 +1,518 @@ +// We're testing x86 target specific features +//@only-target: x86_64 i686 +//@compile-flags: -C target-feature=+gfni,+avx512f + +// The constants in the tests below are just bit patterns. They should not +// be interpreted as integers; signedness does not make sense for them, but +// __mXXXi happens to be defined in terms of signed integers. +#![allow(overflowing_literals)] +#![feature(avx512_target_feature)] +#![feature(stdarch_x86_avx512)] + +#[cfg(target_arch = "x86")] +use std::arch::x86::*; +#[cfg(target_arch = "x86_64")] +use std::arch::x86_64::*; +use std::hint::black_box; +use std::mem::{size_of, transmute}; + +const IDENTITY_BYTE: i32 = 0; +const CONSTANT_BYTE: i32 = 0x63; + +fn main() { + // Mostly copied from library/stdarch/crates/core_arch/src/x86/gfni.rs + + assert!(is_x86_feature_detected!("avx512f")); + assert!(is_x86_feature_detected!("gfni")); + + unsafe { + let byte_mul_test_data = generate_byte_mul_test_data(); + let affine_mul_test_data_identity = generate_affine_mul_test_data(IDENTITY_BYTE as u8); + let affine_mul_test_data_constant = generate_affine_mul_test_data(CONSTANT_BYTE as u8); + let inv_tests_data = generate_inv_tests_data(); + + test_mm512_gf2p8mul_epi8(&byte_mul_test_data); + test_mm256_gf2p8mul_epi8(&byte_mul_test_data); + test_mm_gf2p8mul_epi8(&byte_mul_test_data); + test_mm512_gf2p8affine_epi64_epi8(&byte_mul_test_data, &affine_mul_test_data_identity); + test_mm256_gf2p8affine_epi64_epi8(&byte_mul_test_data, &affine_mul_test_data_identity); + test_mm_gf2p8affine_epi64_epi8(&byte_mul_test_data, &affine_mul_test_data_identity); + test_mm512_gf2p8affineinv_epi64_epi8(&inv_tests_data, &affine_mul_test_data_constant); + test_mm256_gf2p8affineinv_epi64_epi8(&inv_tests_data, &affine_mul_test_data_constant); + test_mm_gf2p8affineinv_epi64_epi8(&inv_tests_data, &affine_mul_test_data_constant); + } +} + +#[target_feature(enable = "gfni,avx512f")] +unsafe fn test_mm512_gf2p8mul_epi8( + byte_mul_test_data: &([u8; NUM_TEST_ENTRIES], [u8; NUM_TEST_ENTRIES], [u8; NUM_TEST_ENTRIES]), +) { + let (left, right, expected) = byte_mul_test_data; + + for i in 0..NUM_TEST_WORDS_512 { + let left = load_m512i_word(left, i); + let right = load_m512i_word(right, i); + let expected = load_m512i_word(expected, i); + let result = _mm512_gf2p8mul_epi8(left, right); + assert_eq_m512i(result, expected); + } +} + +#[target_feature(enable = "gfni,avx")] +unsafe fn test_mm256_gf2p8mul_epi8( + byte_mul_test_data: &([u8; NUM_TEST_ENTRIES], [u8; NUM_TEST_ENTRIES], [u8; NUM_TEST_ENTRIES]), +) { + let (left, right, expected) = byte_mul_test_data; + + for i in 0..NUM_TEST_WORDS_256 { + let left = load_m256i_word(left, i); + let right = load_m256i_word(right, i); + let expected = load_m256i_word(expected, i); + let result = _mm256_gf2p8mul_epi8(left, right); + assert_eq_m256i(result, expected); + } +} + +#[target_feature(enable = "gfni")] +unsafe fn test_mm_gf2p8mul_epi8( + byte_mul_test_data: &([u8; NUM_TEST_ENTRIES], [u8; NUM_TEST_ENTRIES], [u8; NUM_TEST_ENTRIES]), +) { + let (left, right, expected) = byte_mul_test_data; + + for i in 0..NUM_TEST_WORDS_128 { + let left = load_m128i_word(left, i); + let right = load_m128i_word(right, i); + let expected = load_m128i_word(expected, i); + let result = _mm_gf2p8mul_epi8(left, right); + assert_eq_m128i(result, expected); + } +} + +#[target_feature(enable = "gfni,avx512f")] +unsafe fn test_mm512_gf2p8affine_epi64_epi8( + byte_mul_test_data: &([u8; NUM_TEST_ENTRIES], [u8; NUM_TEST_ENTRIES], [u8; NUM_TEST_ENTRIES]), + affine_mul_test_data_identity: &( + [u64; NUM_TEST_WORDS_64], + [u8; NUM_TEST_ENTRIES], + [u8; NUM_TEST_ENTRIES], + ), +) { + let identity: i64 = 0x01_02_04_08_10_20_40_80; + let constant: i64 = 0; + let identity = _mm512_set1_epi64(identity); + let constant = _mm512_set1_epi64(constant); + let constant_reference = _mm512_set1_epi8(CONSTANT_BYTE as i8); + + let (bytes, more_bytes, _) = byte_mul_test_data; + let (matrices, vectors, references) = affine_mul_test_data_identity; + + for i in 0..NUM_TEST_WORDS_512 { + let data = load_m512i_word(bytes, i); + let result = _mm512_gf2p8affine_epi64_epi8::(data, identity); + assert_eq_m512i(result, data); + let result = _mm512_gf2p8affine_epi64_epi8::(data, constant); + assert_eq_m512i(result, constant_reference); + let data = load_m512i_word(more_bytes, i); + let result = _mm512_gf2p8affine_epi64_epi8::(data, identity); + assert_eq_m512i(result, data); + let result = _mm512_gf2p8affine_epi64_epi8::(data, constant); + assert_eq_m512i(result, constant_reference); + + let matrix = load_m512i_word(matrices, i); + let vector = load_m512i_word(vectors, i); + let reference = load_m512i_word(references, i); + + let result = _mm512_gf2p8affine_epi64_epi8::(vector, matrix); + assert_eq_m512i(result, reference); + } +} + +#[target_feature(enable = "gfni,avx")] +unsafe fn test_mm256_gf2p8affine_epi64_epi8( + byte_mul_test_data: &([u8; NUM_TEST_ENTRIES], [u8; NUM_TEST_ENTRIES], [u8; NUM_TEST_ENTRIES]), + affine_mul_test_data_identity: &( + [u64; NUM_TEST_WORDS_64], + [u8; NUM_TEST_ENTRIES], + [u8; NUM_TEST_ENTRIES], + ), +) { + let identity: i64 = 0x01_02_04_08_10_20_40_80; + let constant: i64 = 0; + let identity = _mm256_set1_epi64x(identity); + let constant = _mm256_set1_epi64x(constant); + let constant_reference = _mm256_set1_epi8(CONSTANT_BYTE as i8); + + let (bytes, more_bytes, _) = byte_mul_test_data; + let (matrices, vectors, references) = affine_mul_test_data_identity; + + for i in 0..NUM_TEST_WORDS_256 { + let data = load_m256i_word(bytes, i); + let result = _mm256_gf2p8affine_epi64_epi8::(data, identity); + assert_eq_m256i(result, data); + let result = _mm256_gf2p8affine_epi64_epi8::(data, constant); + assert_eq_m256i(result, constant_reference); + let data = load_m256i_word(more_bytes, i); + let result = _mm256_gf2p8affine_epi64_epi8::(data, identity); + assert_eq_m256i(result, data); + let result = _mm256_gf2p8affine_epi64_epi8::(data, constant); + assert_eq_m256i(result, constant_reference); + + let matrix = load_m256i_word(matrices, i); + let vector = load_m256i_word(vectors, i); + let reference = load_m256i_word(references, i); + + let result = _mm256_gf2p8affine_epi64_epi8::(vector, matrix); + assert_eq_m256i(result, reference); + } +} + +#[target_feature(enable = "gfni")] +unsafe fn test_mm_gf2p8affine_epi64_epi8( + byte_mul_test_data: &([u8; NUM_TEST_ENTRIES], [u8; NUM_TEST_ENTRIES], [u8; NUM_TEST_ENTRIES]), + affine_mul_test_data_identity: &( + [u64; NUM_TEST_WORDS_64], + [u8; NUM_TEST_ENTRIES], + [u8; NUM_TEST_ENTRIES], + ), +) { + let identity: i64 = 0x01_02_04_08_10_20_40_80; + let constant: i64 = 0; + let identity = _mm_set1_epi64x(identity); + let constant = _mm_set1_epi64x(constant); + let constant_reference = _mm_set1_epi8(CONSTANT_BYTE as i8); + + let (bytes, more_bytes, _) = byte_mul_test_data; + let (matrices, vectors, references) = affine_mul_test_data_identity; + + for i in 0..NUM_TEST_WORDS_128 { + let data = load_m128i_word(bytes, i); + let result = _mm_gf2p8affine_epi64_epi8::(data, identity); + assert_eq_m128i(result, data); + let result = _mm_gf2p8affine_epi64_epi8::(data, constant); + assert_eq_m128i(result, constant_reference); + let data = load_m128i_word(more_bytes, i); + let result = _mm_gf2p8affine_epi64_epi8::(data, identity); + assert_eq_m128i(result, data); + let result = _mm_gf2p8affine_epi64_epi8::(data, constant); + assert_eq_m128i(result, constant_reference); + + let matrix = load_m128i_word(matrices, i); + let vector = load_m128i_word(vectors, i); + let reference = load_m128i_word(references, i); + + let result = _mm_gf2p8affine_epi64_epi8::(vector, matrix); + assert_eq_m128i(result, reference); + } +} + +#[target_feature(enable = "gfni,avx512f")] +unsafe fn test_mm512_gf2p8affineinv_epi64_epi8( + inv_tests_data: &([u8; NUM_BYTES], [u8; NUM_BYTES]), + affine_mul_test_data_constant: &( + [u64; NUM_TEST_WORDS_64], + [u8; NUM_TEST_ENTRIES], + [u8; NUM_TEST_ENTRIES], + ), +) { + let identity: i64 = 0x01_02_04_08_10_20_40_80; + let identity = _mm512_set1_epi64(identity); + + // validate inversion + let (inputs, results) = inv_tests_data; + + for i in 0..NUM_BYTES_WORDS_512 { + let input = load_m512i_word(inputs, i); + let reference = load_m512i_word(results, i); + let result = _mm512_gf2p8affineinv_epi64_epi8::(input, identity); + let remultiplied = _mm512_gf2p8mul_epi8(result, input); + assert_eq_m512i(remultiplied, reference); + } + + // validate subsequent affine operation + let (matrices, vectors, _affine_expected) = affine_mul_test_data_constant; + + for i in 0..NUM_TEST_WORDS_512 { + let vector = load_m512i_word(vectors, i); + let matrix = load_m512i_word(matrices, i); + + let inv_vec = _mm512_gf2p8affineinv_epi64_epi8::(vector, identity); + let reference = _mm512_gf2p8affine_epi64_epi8::(inv_vec, matrix); + let result = _mm512_gf2p8affineinv_epi64_epi8::(vector, matrix); + assert_eq_m512i(result, reference); + } + + // validate everything by virtue of checking against the AES SBox + const AES_S_BOX_MATRIX: i64 = 0xF1_E3_C7_8F_1F_3E_7C_F8; + let sbox_matrix = _mm512_set1_epi64(AES_S_BOX_MATRIX); + + for i in 0..NUM_BYTES_WORDS_512 { + let reference = load_m512i_word(&AES_S_BOX, i); + let input = load_m512i_word(inputs, i); + let result = _mm512_gf2p8affineinv_epi64_epi8::(input, sbox_matrix); + assert_eq_m512i(result, reference); + } +} + +#[target_feature(enable = "gfni,avx")] +unsafe fn test_mm256_gf2p8affineinv_epi64_epi8( + inv_tests_data: &([u8; NUM_BYTES], [u8; NUM_BYTES]), + affine_mul_test_data_constant: &( + [u64; NUM_TEST_WORDS_64], + [u8; NUM_TEST_ENTRIES], + [u8; NUM_TEST_ENTRIES], + ), +) { + let identity: i64 = 0x01_02_04_08_10_20_40_80; + let identity = _mm256_set1_epi64x(identity); + + // validate inversion + let (inputs, results) = inv_tests_data; + + for i in 0..NUM_BYTES_WORDS_256 { + let input = load_m256i_word(inputs, i); + let reference = load_m256i_word(results, i); + let result = _mm256_gf2p8affineinv_epi64_epi8::(input, identity); + let remultiplied = _mm256_gf2p8mul_epi8(result, input); + assert_eq_m256i(remultiplied, reference); + } + + // validate subsequent affine operation + let (matrices, vectors, _affine_expected) = affine_mul_test_data_constant; + + for i in 0..NUM_TEST_WORDS_256 { + let vector = load_m256i_word(vectors, i); + let matrix = load_m256i_word(matrices, i); + + let inv_vec = _mm256_gf2p8affineinv_epi64_epi8::(vector, identity); + let reference = _mm256_gf2p8affine_epi64_epi8::(inv_vec, matrix); + let result = _mm256_gf2p8affineinv_epi64_epi8::(vector, matrix); + assert_eq_m256i(result, reference); + } + + // validate everything by virtue of checking against the AES SBox + const AES_S_BOX_MATRIX: i64 = 0xF1_E3_C7_8F_1F_3E_7C_F8; + let sbox_matrix = _mm256_set1_epi64x(AES_S_BOX_MATRIX); + + for i in 0..NUM_BYTES_WORDS_256 { + let reference = load_m256i_word(&AES_S_BOX, i); + let input = load_m256i_word(inputs, i); + let result = _mm256_gf2p8affineinv_epi64_epi8::(input, sbox_matrix); + assert_eq_m256i(result, reference); + } +} + +#[target_feature(enable = "gfni")] +unsafe fn test_mm_gf2p8affineinv_epi64_epi8( + inv_tests_data: &([u8; NUM_BYTES], [u8; NUM_BYTES]), + affine_mul_test_data_constant: &( + [u64; NUM_TEST_WORDS_64], + [u8; NUM_TEST_ENTRIES], + [u8; NUM_TEST_ENTRIES], + ), +) { + let identity: i64 = 0x01_02_04_08_10_20_40_80; + let identity = _mm_set1_epi64x(identity); + + // validate inversion + let (inputs, results) = inv_tests_data; + + for i in 0..NUM_BYTES_WORDS_128 { + let input = load_m128i_word(inputs, i); + let reference = load_m128i_word(results, i); + let result = _mm_gf2p8affineinv_epi64_epi8::(input, identity); + let remultiplied = _mm_gf2p8mul_epi8(result, input); + assert_eq_m128i(remultiplied, reference); + } + + // validate subsequent affine operation + let (matrices, vectors, _affine_expected) = affine_mul_test_data_constant; + + for i in 0..NUM_TEST_WORDS_128 { + let vector = load_m128i_word(vectors, i); + let matrix = load_m128i_word(matrices, i); + + let inv_vec = _mm_gf2p8affineinv_epi64_epi8::(vector, identity); + let reference = _mm_gf2p8affine_epi64_epi8::(inv_vec, matrix); + let result = _mm_gf2p8affineinv_epi64_epi8::(vector, matrix); + assert_eq_m128i(result, reference); + } + + // validate everything by virtue of checking against the AES SBox + const AES_S_BOX_MATRIX: i64 = 0xF1_E3_C7_8F_1F_3E_7C_F8; + let sbox_matrix = _mm_set1_epi64x(AES_S_BOX_MATRIX); + + for i in 0..NUM_BYTES_WORDS_128 { + let reference = load_m128i_word(&AES_S_BOX, i); + let input = load_m128i_word(inputs, i); + let result = _mm_gf2p8affineinv_epi64_epi8::(input, sbox_matrix); + assert_eq_m128i(result, reference); + } +} + +/* Various utilities for processing SIMD values. */ + +#[target_feature(enable = "sse2")] +unsafe fn load_m128i_word(data: &[T], word_index: usize) -> __m128i { + let byte_offset = word_index * 16 / size_of::(); + let pointer = data.as_ptr().add(byte_offset) as *const __m128i; + _mm_loadu_si128(black_box(pointer)) +} + +#[target_feature(enable = "avx")] +unsafe fn load_m256i_word(data: &[T], word_index: usize) -> __m256i { + let byte_offset = word_index * 32 / size_of::(); + let pointer = data.as_ptr().add(byte_offset) as *const __m256i; + _mm256_loadu_si256(black_box(pointer)) +} + +#[target_feature(enable = "avx512f")] +unsafe fn load_m512i_word(data: &[T], word_index: usize) -> __m512i { + let byte_offset = word_index * 64 / size_of::(); + let pointer = data.as_ptr().add(byte_offset) as *const i32; + _mm512_loadu_si512(black_box(pointer)) +} + +#[track_caller] +#[target_feature(enable = "sse2")] +unsafe fn assert_eq_m128i(a: __m128i, b: __m128i) { + assert_eq!(transmute::<_, [u64; 2]>(a), transmute::<_, [u64; 2]>(b)) +} + +#[track_caller] +#[target_feature(enable = "avx")] +unsafe fn assert_eq_m256i(a: __m256i, b: __m256i) { + assert_eq!(transmute::<_, [u64; 4]>(a), transmute::<_, [u64; 4]>(b)) +} + +#[track_caller] +#[target_feature(enable = "avx512f")] +unsafe fn assert_eq_m512i(a: __m512i, b: __m512i) { + assert_eq!(transmute::<_, [u64; 8]>(a), transmute::<_, [u64; 8]>(b)) +} + +/* Software implementation of the hardware intrinsics. */ + +fn mulbyte(left: u8, right: u8) -> u8 { + // this implementation follows the description in + // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm512_gf2p8mul_epi8 + const REDUCTION_POLYNOMIAL: u16 = 0x11b; + let left: u16 = left.into(); + let right: u16 = right.into(); + let mut carryless_product: u16 = 0; + + // Carryless multiplication + for i in 0..8 { + if ((left >> i) & 0x01) != 0 { + carryless_product ^= right << i; + } + } + + // reduction, adding in "0" where appropriate to clear out high bits + // note that REDUCTION_POLYNOMIAL is zero in this context + for i in (8..=14).rev() { + if ((carryless_product >> i) & 0x01) != 0 { + carryless_product ^= REDUCTION_POLYNOMIAL << (i - 8); + } + } + + carryless_product as u8 +} + +/// Calculates the bitwise XOR of all bits inside a byte. +fn parity(input: u8) -> u8 { + let mut accumulator = 0; + for i in 0..8 { + accumulator ^= (input >> i) & 0x01; + } + accumulator +} + +/// Calculates `matrix * x + b` inside the finite field GF(2). +fn mat_vec_multiply_affine(matrix: u64, x: u8, b: u8) -> u8 { + // this implementation follows the description in + // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_gf2p8affine_epi64_epi8 + let mut accumulator = 0; + + for bit in 0..8 { + accumulator |= parity(x & matrix.to_le_bytes()[bit]) << (7 - bit); + } + + accumulator ^ b +} + +/* Test data generation. */ + +const NUM_TEST_WORDS_512: usize = 4; +const NUM_TEST_WORDS_256: usize = NUM_TEST_WORDS_512 * 2; +const NUM_TEST_WORDS_128: usize = NUM_TEST_WORDS_256 * 2; +const NUM_TEST_ENTRIES: usize = NUM_TEST_WORDS_512 * 64; +const NUM_TEST_WORDS_64: usize = NUM_TEST_WORDS_128 * 2; +const NUM_BYTES: usize = 256; +const NUM_BYTES_WORDS_128: usize = NUM_BYTES / 16; +const NUM_BYTES_WORDS_256: usize = NUM_BYTES_WORDS_128 / 2; +const NUM_BYTES_WORDS_512: usize = NUM_BYTES_WORDS_256 / 2; + +fn generate_affine_mul_test_data( + immediate: u8, +) -> ([u64; NUM_TEST_WORDS_64], [u8; NUM_TEST_ENTRIES], [u8; NUM_TEST_ENTRIES]) { + let mut left: [u64; NUM_TEST_WORDS_64] = [0; NUM_TEST_WORDS_64]; + let mut right: [u8; NUM_TEST_ENTRIES] = [0; NUM_TEST_ENTRIES]; + let mut result: [u8; NUM_TEST_ENTRIES] = [0; NUM_TEST_ENTRIES]; + + for i in 0..NUM_TEST_WORDS_64 { + left[i] = (i as u64) * 103 * 101; + for j in 0..8 { + let j64 = j as u64; + right[i * 8 + j] = ((left[i] + j64) % 256) as u8; + result[i * 8 + j] = mat_vec_multiply_affine(left[i], right[i * 8 + j], immediate); + } + } + + (left, right, result) +} + +fn generate_inv_tests_data() -> ([u8; NUM_BYTES], [u8; NUM_BYTES]) { + let mut input: [u8; NUM_BYTES] = [0; NUM_BYTES]; + let mut result: [u8; NUM_BYTES] = [0; NUM_BYTES]; + + for i in 0..NUM_BYTES { + input[i] = (i % 256) as u8; + result[i] = if i == 0 { 0 } else { 1 }; + } + + (input, result) +} + +const AES_S_BOX: [u8; NUM_BYTES] = [ + 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, + 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, + 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, + 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, + 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, + 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, + 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, + 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, + 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, + 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, + 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, + 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, + 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, + 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, + 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, + 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16, +]; + +fn generate_byte_mul_test_data() +-> ([u8; NUM_TEST_ENTRIES], [u8; NUM_TEST_ENTRIES], [u8; NUM_TEST_ENTRIES]) { + let mut left: [u8; NUM_TEST_ENTRIES] = [0; NUM_TEST_ENTRIES]; + let mut right: [u8; NUM_TEST_ENTRIES] = [0; NUM_TEST_ENTRIES]; + let mut result: [u8; NUM_TEST_ENTRIES] = [0; NUM_TEST_ENTRIES]; + + for i in 0..NUM_TEST_ENTRIES { + left[i] = (i % 256) as u8; + right[i] = left[i].wrapping_mul(101); + result[i] = mulbyte(left[i], right[i]); + } + + (left, right, result) +} From cc36e0d9832349a8834b4800f6b6ca27ab9cba56 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 4 Oct 2024 17:53:44 +0200 Subject: [PATCH 558/683] Fix list margins --- src/librustdoc/html/static/css/rustdoc.css | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index beac7e73c62..5f6f3c65c7f 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -961,10 +961,13 @@ pre, .rustdoc.src .example-wrap, .example-wrap .src-line-numbers { } .docblock li { - margin-bottom: .8em; + margin-bottom: .4em; } -.docblock li p { - margin-bottom: .1em; +.docblock li p:not(:last-child) { + /* This margin is voluntarily smaller than `.docblock li` to keep the visual + list element items separated while also having a visual separation (although + smaller) for paragraphs. */ + margin-bottom: .3em; } /* "where ..." clauses with block display are also smaller */ From 1c63ec9fa002980fb792d8630661e931ebf9ac06 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 3 Oct 2024 18:09:00 +0200 Subject: [PATCH 559/683] Add GUI regression test for #130622 and for #131223 --- tests/rustdoc-gui/list-margins.goml | 11 +++++++++++ tests/rustdoc-gui/src/test_docs/lib.rs | 24 ++++++++++++++++++++++++ 2 files changed, 35 insertions(+) create mode 100644 tests/rustdoc-gui/list-margins.goml diff --git a/tests/rustdoc-gui/list-margins.goml b/tests/rustdoc-gui/list-margins.goml new file mode 100644 index 00000000000..c83f5898e8e --- /dev/null +++ b/tests/rustdoc-gui/list-margins.goml @@ -0,0 +1,11 @@ +// This test ensures that the documentation list markers are correctly placed. +// It also serves as a regression test for . + +go-to: "file://" + |DOC_PATH| + "/test_docs/long_list/index.html" +show-text: true + +// 0.3em +assert-css: (".docblock li p:not(last-child)", {"margin-bottom": "4.8px"}) +assert-css: (".docblock li p + p:last-child", {"margin-bottom": "0px"}) +// 0.4em +assert-css: (".docblock li", {"margin-bottom": "6.4px"}) diff --git a/tests/rustdoc-gui/src/test_docs/lib.rs b/tests/rustdoc-gui/src/test_docs/lib.rs index 7397992c0ab..352995c4903 100644 --- a/tests/rustdoc-gui/src/test_docs/lib.rs +++ b/tests/rustdoc-gui/src/test_docs/lib.rs @@ -628,3 +628,27 @@ pub mod short_docs { /// subt_vec_num(x: &[f64], y: f64) pub fn subt_vec_num() {} } + +pub mod long_list { + //! bla + //! + //! * Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque et libero ut leo + //! interdum laoreet vitae a mi. Aliquam erat volutpat. Suspendisse volutpat non quam non + //! commodo. + //! + //! Praesent enim neque, imperdiet sed nisl at, lobortis egestas augue. Sed vitae tristique + //! augue. Phasellus vel pretium lectus. + //! * Praesent enim neque, imperdiet sed nisl at, lobortis egestas augue. Sed vitae tristique + //! augue. Phasellus vel pretium lectus. + //! * Praesent enim neque, imperdiet sed nisl at, lobortis egestas augue. Sed vitae tristique + //! augue. Phasellus vel pretium lectus. + //! + //! Another list: + //! + //! * [`TryFromBytes`](#a) indicates that a type may safely be converted from certain byte + //! sequence (conditional on runtime checks) + //! * [`FromZeros`](#a) indicates that a sequence of zero bytes represents a valid instance of + //! a type + //! * [`FromBytes`](#a) indicates that a type may safely be converted from an arbitrary byte + //! sequence +} From 3686e59913967072e47d64a6a466a6f5d9386c09 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Fri, 4 Oct 2024 09:45:34 -0700 Subject: [PATCH 560/683] rustdoc: cleaner errors on disambiguator/namespace mismatches --- .../passes/collect_intra_doc_links.rs | 21 ++++++++++++++----- .../intra-doc/disambiguator-mismatch.stderr | 6 +++--- tests/rustdoc-ui/intra-doc/errors.rs | 2 +- tests/rustdoc-ui/intra-doc/errors.stderr | 4 ++-- .../issue-110495-suffix-with-space.stderr | 4 ++-- .../rustdoc-ui/intra-doc/weird-syntax.stderr | 20 +++++++++--------- 6 files changed, 34 insertions(+), 23 deletions(-) diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 0dba16cbaf3..def9ac3ce4b 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -1996,11 +1996,22 @@ fn resolution_failure( &diag_info, ); - format!( - "this link resolves to {}, which is not in the {} namespace", - item(res), - expected_ns.descr() - ) + if let Some(disambiguator) = disambiguator + && !matches!(disambiguator, Disambiguator::Namespace(..)) + { + format!( + "this link resolves to {}, which is not {} {}", + item(res), + disambiguator.article(), + disambiguator.descr() + ) + } else { + format!( + "this link resolves to {}, which is not in the {} namespace", + item(res), + expected_ns.descr() + ) + } } }; if let Some(span) = sp { diff --git a/tests/rustdoc-ui/intra-doc/disambiguator-mismatch.stderr b/tests/rustdoc-ui/intra-doc/disambiguator-mismatch.stderr index 66b910eed81..ef7fec77b1e 100644 --- a/tests/rustdoc-ui/intra-doc/disambiguator-mismatch.stderr +++ b/tests/rustdoc-ui/intra-doc/disambiguator-mismatch.stderr @@ -74,7 +74,7 @@ error: unresolved link to `m` --> $DIR/disambiguator-mismatch.rs:52:14 | LL | /// Link to [m()] - | ^^^ this link resolves to the macro `m`, which is not in the value namespace + | ^^^ this link resolves to the macro `m`, which is not a function | help: to link to the macro, add an exclamation mark | @@ -142,7 +142,7 @@ error: unresolved link to `std` --> $DIR/disambiguator-mismatch.rs:83:14 | LL | /// Link to [fn@std] - | ^^^^^^ this link resolves to the crate `std`, which is not in the value namespace + | ^^^^^^ this link resolves to the crate `std`, which is not a function | help: to link to the crate, prefix with `mod@` | @@ -164,7 +164,7 @@ error: unresolved link to `S::A` --> $DIR/disambiguator-mismatch.rs:93:14 | LL | /// Link to [field@S::A] - | ^^^^^^^^^^ this link resolves to the variant `A`, which is not in the value namespace + | ^^^^^^^^^^ this link resolves to the variant `A`, which is not a field | help: to link to the variant, prefix with `variant@` | diff --git a/tests/rustdoc-ui/intra-doc/errors.rs b/tests/rustdoc-ui/intra-doc/errors.rs index f37f49c24cc..e885a3b35f6 100644 --- a/tests/rustdoc-ui/intra-doc/errors.rs +++ b/tests/rustdoc-ui/intra-doc/errors.rs @@ -98,7 +98,7 @@ pub trait T { /// [m()] //~^ ERROR unresolved link //~| HELP to link to the macro -//~| NOTE not in the value namespace +//~| NOTE not a function #[macro_export] macro_rules! m { () => {}; diff --git a/tests/rustdoc-ui/intra-doc/errors.stderr b/tests/rustdoc-ui/intra-doc/errors.stderr index a982bba0095..07d328f99a3 100644 --- a/tests/rustdoc-ui/intra-doc/errors.stderr +++ b/tests/rustdoc-ui/intra-doc/errors.stderr @@ -104,7 +104,7 @@ error: unresolved link to `S` --> $DIR/errors.rs:68:6 | LL | /// [S!] - | ^^ this link resolves to the struct `S`, which is not in the macro namespace + | ^^ this link resolves to the struct `S`, which is not a macro | help: to link to the struct, prefix with `struct@` | @@ -158,7 +158,7 @@ error: unresolved link to `m` --> $DIR/errors.rs:98:6 | LL | /// [m()] - | ^^^ this link resolves to the macro `m`, which is not in the value namespace + | ^^^ this link resolves to the macro `m`, which is not a function | help: to link to the macro, add an exclamation mark | diff --git a/tests/rustdoc-ui/intra-doc/issue-110495-suffix-with-space.stderr b/tests/rustdoc-ui/intra-doc/issue-110495-suffix-with-space.stderr index 6c834fd0a1b..a347044bfe9 100644 --- a/tests/rustdoc-ui/intra-doc/issue-110495-suffix-with-space.stderr +++ b/tests/rustdoc-ui/intra-doc/issue-110495-suffix-with-space.stderr @@ -2,7 +2,7 @@ error: unresolved link to `Clone` --> $DIR/issue-110495-suffix-with-space.rs:3:6 | LL | //! [Clone ()]. - | ^^^^^^^^ this link resolves to the trait `Clone`, which is not in the value namespace + | ^^^^^^^^ this link resolves to the trait `Clone`, which is not a function | note: the lint level is defined here --> $DIR/issue-110495-suffix-with-space.rs:2:9 @@ -31,7 +31,7 @@ error: unresolved link to `Clone` --> $DIR/issue-110495-suffix-with-space.rs:5:7 | LL | //! [`Clone ()`]. - | ^^^^^^^^ this link resolves to the trait `Clone`, which is not in the value namespace + | ^^^^^^^^ this link resolves to the trait `Clone`, which is not a function | help: to link to the trait, prefix with `trait@` | diff --git a/tests/rustdoc-ui/intra-doc/weird-syntax.stderr b/tests/rustdoc-ui/intra-doc/weird-syntax.stderr index f50feb57fcc..17bcbc783fd 100644 --- a/tests/rustdoc-ui/intra-doc/weird-syntax.stderr +++ b/tests/rustdoc-ui/intra-doc/weird-syntax.stderr @@ -40,7 +40,7 @@ error: unresolved link to `Clone` --> $DIR/weird-syntax.rs:27:9 | LL | /// [ `Clone ()` ] - | ^^^^^^^^ this link resolves to the trait `Clone`, which is not in the value namespace + | ^^^^^^^^ this link resolves to the trait `Clone`, which is not a function | help: to link to the trait, prefix with `trait@` | @@ -52,7 +52,7 @@ error: unresolved link to `Clone` --> $DIR/weird-syntax.rs:30:7 | LL | /// [`Clone ()` ] - | ^^^^^^^^ this link resolves to the trait `Clone`, which is not in the value namespace + | ^^^^^^^^ this link resolves to the trait `Clone`, which is not a function | help: to link to the trait, prefix with `trait@` | @@ -64,7 +64,7 @@ error: unresolved link to `Clone` --> $DIR/weird-syntax.rs:33:9 | LL | /// [ `Clone ()`] - | ^^^^^^^^ this link resolves to the trait `Clone`, which is not in the value namespace + | ^^^^^^^^ this link resolves to the trait `Clone`, which is not a function | help: to link to the trait, prefix with `trait@` | @@ -76,7 +76,7 @@ error: unresolved link to `Clone` --> $DIR/weird-syntax.rs:36:9 | LL | /// [```Clone ()```] - | ^^^^^^^^ this link resolves to the trait `Clone`, which is not in the value namespace + | ^^^^^^^^ this link resolves to the trait `Clone`, which is not a function | help: to link to the trait, prefix with `trait@` | @@ -88,7 +88,7 @@ error: unresolved link to `Clone` --> $DIR/weird-syntax.rs:42:13 | LL | /// [ ``` Clone () ``` ] - | ^^^^^^^^ this link resolves to the trait `Clone`, which is not in the value namespace + | ^^^^^^^^ this link resolves to the trait `Clone`, which is not a function | help: to link to the trait, prefix with `trait@` | @@ -122,7 +122,7 @@ error: unresolved link to `Clone` --> $DIR/weird-syntax.rs:74:9 | LL | /// [x][Clone()] - | ^^^^^^^ this link resolves to the trait `Clone`, which is not in the value namespace + | ^^^^^^^ this link resolves to the trait `Clone`, which is not a function | help: to link to the trait, prefix with `trait@` | @@ -134,7 +134,7 @@ error: unresolved link to `Clone` --> $DIR/weird-syntax.rs:77:9 | LL | /// [x][Clone ()] - | ^^^^^^^^^ this link resolves to the trait `Clone`, which is not in the value namespace + | ^^^^^^^^^ this link resolves to the trait `Clone`, which is not a function | help: to link to the trait, prefix with `trait@` | @@ -176,7 +176,7 @@ error: unresolved link to `Clone` --> $DIR/weird-syntax.rs:97:9 | LL | /// [w](Clone\(\)) - | ^^^^^^^^^ this link resolves to the trait `Clone`, which is not in the value namespace + | ^^^^^^^^^ this link resolves to the trait `Clone`, which is not a function | help: to link to the trait, prefix with `trait@` | @@ -188,7 +188,7 @@ error: unresolved link to `Clone` --> $DIR/weird-syntax.rs:103:9 | LL | /// [w](Clone()) - | ^^^^^^^ this link resolves to the trait `Clone`, which is not in the value namespace + | ^^^^^^^ this link resolves to the trait `Clone`, which is not a function | help: to link to the trait, prefix with `trait@` | @@ -256,7 +256,7 @@ error: unresolved link to `Clone` --> $DIR/weird-syntax.rs:132:9 | LL | /// The [cln][] link here will produce a plain text suggestion - | ^^^^^ this link resolves to the trait `Clone`, which is not in the value namespace + | ^^^^^ this link resolves to the trait `Clone`, which is not a function | = help: to link to the trait, prefix with `trait@`: trait@Clone From be2540a1f0cd5c791a8f9662691f4ce5d85553d5 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 4 Oct 2024 14:02:09 -0400 Subject: [PATCH 561/683] Fix some pub(crate) that were undetected bc of instrument --- compiler/rustc_borrowck/src/renumber.rs | 2 +- .../src/type_check/constraint_conversion.rs | 2 +- compiler/rustc_hir_typeck/src/_match.rs | 2 +- compiler/rustc_hir_typeck/src/cast.rs | 2 +- compiler/rustc_hir_typeck/src/closure.rs | 2 +- compiler/rustc_hir_typeck/src/demand.rs | 4 ++-- .../rustc_hir_typeck/src/fn_ctxt/_impl.rs | 22 +++++++++++-------- .../rustc_hir_typeck/src/fn_ctxt/checks.rs | 1 - .../src/fn_ctxt/suggestions.rs | 1 - compiler/rustc_hir_typeck/src/method/mod.rs | 8 +++---- compiler/rustc_hir_typeck/src/method/probe.rs | 4 ++-- .../rustc_hir_typeck/src/method/suggest.rs | 2 +- .../rustc_mir_dataflow/src/elaborate_drops.rs | 2 +- .../src/cfi/typeid/itanium_cxx_abi/encode.rs | 2 +- .../cfi/typeid/itanium_cxx_abi/transform.rs | 2 +- .../src/maybe_transmutable/mod.rs | 2 +- 16 files changed, 31 insertions(+), 29 deletions(-) diff --git a/compiler/rustc_borrowck/src/renumber.rs b/compiler/rustc_borrowck/src/renumber.rs index 0a375c7fae8..b7aef71eb54 100644 --- a/compiler/rustc_borrowck/src/renumber.rs +++ b/compiler/rustc_borrowck/src/renumber.rs @@ -11,7 +11,7 @@ use crate::BorrowckInferCtxt; /// Replaces all free regions appearing in the MIR with fresh /// inference variables, returning the number of variables created. #[instrument(skip(infcx, body, promoted), level = "debug")] -pub fn renumber_mir<'tcx>( +pub(crate) fn renumber_mir<'tcx>( infcx: &BorrowckInferCtxt<'tcx>, body: &mut Body<'tcx>, promoted: &mut IndexSlice>, diff --git a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs index fc1600ea4a6..6c86968389a 100644 --- a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs +++ b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs @@ -97,7 +97,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { /// that we computed for the closure. This has the effect of adding new outlives obligations /// to existing region variables in `closure_args`. #[instrument(skip(self), level = "debug")] - pub fn apply_closure_requirements( + pub(crate) fn apply_closure_requirements( &mut self, closure_requirements: &ClosureRegionRequirements<'tcx>, closure_def_id: DefId, diff --git a/compiler/rustc_hir_typeck/src/_match.rs b/compiler/rustc_hir_typeck/src/_match.rs index 2dbadf8198b..0d9d1910ae0 100644 --- a/compiler/rustc_hir_typeck/src/_match.rs +++ b/compiler/rustc_hir_typeck/src/_match.rs @@ -15,7 +15,7 @@ use crate::{Diverges, Expectation, FnCtxt, Needs}; impl<'a, 'tcx> FnCtxt<'a, 'tcx> { #[instrument(skip(self), level = "debug", ret)] - pub fn check_match( + pub(crate) fn check_match( &self, expr: &'tcx hir::Expr<'tcx>, scrut: &'tcx hir::Expr<'tcx>, diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs index fcd2940b83a..71047b5e01d 100644 --- a/compiler/rustc_hir_typeck/src/cast.rs +++ b/compiler/rustc_hir_typeck/src/cast.rs @@ -671,7 +671,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { } #[instrument(skip(fcx), level = "debug")] - pub fn check(mut self, fcx: &FnCtxt<'a, 'tcx>) { + pub(crate) fn check(mut self, fcx: &FnCtxt<'a, 'tcx>) { self.expr_ty = fcx.structurally_resolve_type(self.expr_span, self.expr_ty); self.cast_ty = fcx.structurally_resolve_type(self.cast_span, self.cast_ty); diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs index 3e7ce2955fc..fcaa5751152 100644 --- a/compiler/rustc_hir_typeck/src/closure.rs +++ b/compiler/rustc_hir_typeck/src/closure.rs @@ -44,7 +44,7 @@ struct ClosureSignatures<'tcx> { impl<'a, 'tcx> FnCtxt<'a, 'tcx> { #[instrument(skip(self, closure), level = "debug")] - pub fn check_expr_closure( + pub(crate) fn check_expr_closure( &self, closure: &hir::Closure<'tcx>, expr_span: Span, diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs index cfa8fc4bbf2..777248ff873 100644 --- a/compiler/rustc_hir_typeck/src/demand.rs +++ b/compiler/rustc_hir_typeck/src/demand.rs @@ -182,7 +182,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } #[instrument(skip(self), level = "debug")] - pub fn demand_suptype_with_origin( + pub(crate) fn demand_suptype_with_origin( &'a self, cause: &ObligationCause<'tcx>, expected: Ty<'tcx>, @@ -247,7 +247,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// N.B., this code relies on `self.diverges` to be accurate. In particular, assignments to `!` /// will be permitted if the diverges flag is currently "always". #[instrument(level = "debug", skip(self, expr, expected_ty_expr, allow_two_phase))] - pub fn demand_coerce_diag( + pub(crate) fn demand_coerce_diag( &'a self, mut expr: &'tcx hir::Expr<'tcx>, checked_ty: Ty<'tcx>, diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index 62107877283..380d9126964 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -187,7 +187,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } #[instrument(level = "debug", skip(self))] - pub fn write_method_call_and_enforce_effects( + pub(crate) fn write_method_call_and_enforce_effects( &self, hir_id: HirId, span: Span, @@ -214,7 +214,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// occurred**, so that annotations like `Vec<_>` are preserved /// properly. #[instrument(skip(self), level = "debug")] - pub fn write_user_type_annotation_from_args( + pub(crate) fn write_user_type_annotation_from_args( &self, hir_id: HirId, def_id: DefId, @@ -235,7 +235,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } #[instrument(skip(self), level = "debug")] - pub fn write_user_type_annotation( + pub(crate) fn write_user_type_annotation( &self, hir_id: HirId, canonical_user_type_annotation: CanonicalUserType<'tcx>, @@ -254,7 +254,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } #[instrument(skip(self, expr), level = "debug")] - pub fn apply_adjustments(&self, expr: &hir::Expr<'_>, adj: Vec>) { + pub(crate) fn apply_adjustments(&self, expr: &hir::Expr<'_>, adj: Vec>) { debug!("expr = {:#?}", expr); if adj.is_empty() { @@ -448,7 +448,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } #[instrument(level = "debug", skip_all)] - pub fn lower_ty_saving_user_provided_ty(&self, hir_ty: &hir::Ty<'tcx>) -> Ty<'tcx> { + pub(crate) fn lower_ty_saving_user_provided_ty(&self, hir_ty: &hir::Ty<'tcx>) -> Ty<'tcx> { let ty = self.lower_ty(hir_ty); debug!(?ty); @@ -736,7 +736,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Resolves an associated value path into a base type and associated constant, or method /// resolution. The newly resolved definition is written into `type_dependent_defs`. #[instrument(level = "trace", skip(self), ret)] - pub fn resolve_ty_and_res_fully_qualified_call( + pub(crate) fn resolve_ty_and_res_fully_qualified_call( &self, qpath: &'tcx QPath<'tcx>, hir_id: HirId, @@ -995,7 +995,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Instantiates the given path, which must refer to an item with the given // number of type parameters and type. #[instrument(skip(self, span), level = "debug")] - pub fn instantiate_value_path( + pub(crate) fn instantiate_value_path( &self, segments: &'tcx [hir::PathSegment<'tcx>], self_ty: Option>, @@ -1446,7 +1446,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// variable. This is different from `structurally_resolve_type` which errors /// in this case. #[instrument(level = "debug", skip(self, sp), ret)] - pub fn try_structurally_resolve_type(&self, sp: Span, ty: Ty<'tcx>) -> Ty<'tcx> { + pub(crate) fn try_structurally_resolve_type(&self, sp: Span, ty: Ty<'tcx>) -> Ty<'tcx> { let ty = self.resolve_vars_with_obligations(ty); if self.next_trait_solver() @@ -1471,7 +1471,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } #[instrument(level = "debug", skip(self, sp), ret)] - pub fn try_structurally_resolve_const(&self, sp: Span, ct: ty::Const<'tcx>) -> ty::Const<'tcx> { + pub(crate) fn try_structurally_resolve_const( + &self, + sp: Span, + ct: ty::Const<'tcx>, + ) -> ty::Const<'tcx> { // FIXME(min_const_generic_exprs): We could process obligations here if `ct` is a var. if self.next_trait_solver() diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 550c58b5a17..fa471647d02 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -984,7 +984,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.suggest_deref_unwrap_or( &mut err, - error_span, callee_ty, call_ident, expected_ty, diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index 487cc7e55cd..d0e91ec07f6 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -1462,7 +1462,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub(crate) fn suggest_deref_unwrap_or( &self, err: &mut Diag<'_>, - error_span: Span, callee_ty: Option>, call_ident: Option, expected_ty: Ty<'tcx>, diff --git a/compiler/rustc_hir_typeck/src/method/mod.rs b/compiler/rustc_hir_typeck/src/method/mod.rs index 3e9cb0ac2c8..cb8b1df2c6e 100644 --- a/compiler/rustc_hir_typeck/src/method/mod.rs +++ b/compiler/rustc_hir_typeck/src/method/mod.rs @@ -94,7 +94,7 @@ pub(crate) enum CandidateSource { impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Determines whether the type `self_ty` supports a visible method named `method_name` or not. #[instrument(level = "debug", skip(self))] - pub fn method_exists_for_diagnostic( + pub(crate) fn method_exists_for_diagnostic( &self, method_name: Ident, self_ty: Ty<'tcx>, @@ -178,7 +178,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// * `self_expr`: the self expression (`foo`) /// * `args`: the expressions of the arguments (`a, b + 1, ...`) #[instrument(level = "debug", skip(self))] - pub fn lookup_method( + pub(crate) fn lookup_method( &self, self_ty: Ty<'tcx>, segment: &'tcx hir::PathSegment<'tcx>, @@ -281,7 +281,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } #[instrument(level = "debug", skip(self, call_expr))] - pub fn lookup_probe( + pub(crate) fn lookup_probe( &self, method_name: Ident, self_ty: Ty<'tcx>, @@ -498,7 +498,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// * `self_ty_span` the span for the type being searched within (span of `Foo`) /// * `expr_id`: the [`hir::HirId`] of the expression composing the entire call #[instrument(level = "debug", skip(self), ret)] - pub fn resolve_fully_qualified_call( + pub(crate) fn resolve_fully_qualified_call( &self, span: Span, method_name: Ident, diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index 3bb7070d61d..3005945a20a 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -224,7 +224,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// would use to decide if a method is a plausible fit for /// ambiguity purposes). #[instrument(level = "debug", skip(self, candidate_filter))] - pub fn probe_for_return_type_for_diagnostic( + pub(crate) fn probe_for_return_type_for_diagnostic( &self, span: Span, mode: Mode, @@ -267,7 +267,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } #[instrument(level = "debug", skip(self))] - pub fn probe_for_name( + pub(crate) fn probe_for_name( &self, mode: Mode, item_name: Ident, diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index a37e9744293..4f726f3ed38 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -183,7 +183,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } #[instrument(level = "debug", skip(self))] - pub fn report_method_error( + pub(crate) fn report_method_error( &self, call_id: HirId, rcvr_ty: Ty<'tcx>, diff --git a/compiler/rustc_mir_dataflow/src/elaborate_drops.rs b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs index f2541c37167..a3b117a3f19 100644 --- a/compiler/rustc_mir_dataflow/src/elaborate_drops.rs +++ b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs @@ -225,7 +225,7 @@ where // FIXME: I think we should just control the flags externally, // and then we do not need this machinery. #[instrument(level = "debug")] - pub fn elaborate_drop(&mut self, bb: BasicBlock) { + fn elaborate_drop(&mut self, bb: BasicBlock) { match self.elaborator.drop_style(self.path, DropFlagMode::Deep) { DropStyle::Dead => { self.elaborator diff --git a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs index 320d6616384..53834198f63 100644 --- a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs +++ b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs @@ -315,7 +315,7 @@ fn encode_region<'tcx>(region: Region<'tcx>, dict: &mut FxHashMap, /// Encodes a ty:Ty using the Itanium C++ ABI with vendor extended type qualifiers and types for /// Rust types that are not used at the FFI boundary. #[instrument(level = "trace", skip(tcx, dict))] -pub fn encode_ty<'tcx>( +pub(crate) fn encode_ty<'tcx>( tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, dict: &mut FxHashMap, usize>, diff --git a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs index 5f7184a4240..83dcceeaa84 100644 --- a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs +++ b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs @@ -291,7 +291,7 @@ fn trait_object_ty<'tcx>(tcx: TyCtxt<'tcx>, poly_trait_ref: ty::PolyTraitRef<'tc /// the Fn trait that defines the method (for being attached as a secondary type id). /// #[instrument(level = "trace", skip(tcx))] -pub fn transform_instance<'tcx>( +pub(crate) fn transform_instance<'tcx>( tcx: TyCtxt<'tcx>, mut instance: Instance<'tcx>, options: TransformTyOptions, diff --git a/compiler/rustc_transmute/src/maybe_transmutable/mod.rs b/compiler/rustc_transmute/src/maybe_transmutable/mod.rs index 1e5da4ec49d..9dabcea706f 100644 --- a/compiler/rustc_transmute/src/maybe_transmutable/mod.rs +++ b/compiler/rustc_transmute/src/maybe_transmutable/mod.rs @@ -40,7 +40,7 @@ mod rustc { /// This method begins by converting `src` and `dst` from `Ty`s to `Tree`s, /// then computes an answer using those trees. #[instrument(level = "debug", skip(self), fields(src = ?self.src, dst = ?self.dst))] - pub fn answer(self) -> Answer< as QueryContext>::Ref> { + pub(crate) fn answer(self) -> Answer< as QueryContext>::Ref> { let Self { src, dst, assume, context } = self; let layout_cx = LayoutCx::new(context, ParamEnv::reveal_all()); From f46e1624cbee1558cccf10f0b392ea22c4165e45 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Fri, 4 Oct 2024 20:11:26 +0200 Subject: [PATCH 562/683] Prefer refutable slice patterns over len check + index op --- .../src/borrow_tracker/tree_borrows/tree.rs | 5 ++-- src/tools/miri/src/shims/unix/fd.rs | 14 ++++----- src/tools/miri/src/shims/unix/fs.rs | 8 ++--- .../src/shims/unix/linux/foreign_items.rs | 10 +++---- src/tools/miri/src/shims/unix/linux/sync.rs | 30 +++++++++---------- 5 files changed, 34 insertions(+), 33 deletions(-) diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs index 410f4a58ac5..15cefab1a68 100644 --- a/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs +++ b/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs @@ -859,14 +859,15 @@ impl Tree { ) -> Option { let node = self.nodes.get(idx).unwrap(); + let [child_idx] = node.children[..] else { return None }; + // We never want to replace the root node, as it is also kept in `root_ptr_tags`. - if node.children.len() != 1 || live.contains(&node.tag) || node.parent.is_none() { + if live.contains(&node.tag) || node.parent.is_none() { return None; } // Since protected nodes are never GC'd (see `borrow_tracker::FrameExtra::visit_provenance`), // we know that `node` is not protected because otherwise `live` would // have contained `node.tag`. - let child_idx = node.children[0]; let child = self.nodes.get(child_idx).unwrap(); // Check that for that one child, `can_be_replaced_by_child` holds for the permission // on all locations. diff --git a/src/tools/miri/src/shims/unix/fd.rs b/src/tools/miri/src/shims/unix/fd.rs index f2d3115f985..34e29760da7 100644 --- a/src/tools/miri/src/shims/unix/fd.rs +++ b/src/tools/miri/src/shims/unix/fd.rs @@ -481,14 +481,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn fcntl(&mut self, args: &[OpTy<'tcx>]) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); - if args.len() < 2 { + let [fd_num, cmd, ..] = args else { throw_ub_format!( "incorrect number of arguments for fcntl: got {}, expected at least 2", args.len() ); - } - let fd_num = this.read_scalar(&args[0])?.to_i32()?; - let cmd = this.read_scalar(&args[1])?.to_i32()?; + }; + let fd_num = this.read_scalar(fd_num)?.to_i32()?; + let cmd = this.read_scalar(cmd)?.to_i32()?; // We only support getting the flags for a descriptor. if cmd == this.eval_libc_i32("F_GETFD") { @@ -508,13 +508,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // because exec() isn't supported. The F_DUPFD and F_DUPFD_CLOEXEC commands only // differ in whether the FD_CLOEXEC flag is pre-set on the new file descriptor, // thus they can share the same implementation here. - if args.len() < 3 { + let [_, _, start, ..] = args else { throw_ub_format!( "incorrect number of arguments for fcntl with cmd=`F_DUPFD`/`F_DUPFD_CLOEXEC`: got {}, expected at least 3", args.len() ); - } - let start = this.read_scalar(&args[2])?.to_i32()?; + }; + let start = this.read_scalar(start)?.to_i32()?; match this.machine.fds.get(fd_num) { Some(fd) => diff --git a/src/tools/miri/src/shims/unix/fs.rs b/src/tools/miri/src/shims/unix/fs.rs index 2df178c4385..6c9a2beac2d 100644 --- a/src/tools/miri/src/shims/unix/fs.rs +++ b/src/tools/miri/src/shims/unix/fs.rs @@ -433,18 +433,18 @@ fn maybe_sync_file( impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {} pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn open(&mut self, args: &[OpTy<'tcx>]) -> InterpResult<'tcx, Scalar> { - if args.len() < 2 { + let [path_raw, flag, ..] = args else { throw_ub_format!( "incorrect number of arguments for `open`: got {}, expected at least 2", args.len() ); - } + }; let this = self.eval_context_mut(); - let path_raw = this.read_pointer(&args[0])?; + let path_raw = this.read_pointer(path_raw)?; let path = this.read_path_from_c_str(path_raw)?; - let flag = this.read_scalar(&args[1])?.to_i32()?; + let flag = this.read_scalar(flag)?.to_i32()?; let mut options = OpenOptions::new(); diff --git a/src/tools/miri/src/shims/unix/linux/foreign_items.rs b/src/tools/miri/src/shims/unix/linux/foreign_items.rs index 9726dac7e51..4b5f3b6c81b 100644 --- a/src/tools/miri/src/shims/unix/linux/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/linux/foreign_items.rs @@ -122,19 +122,19 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { id if id == sys_getrandom => { // Used by getrandom 0.1 // The first argument is the syscall id, so skip over it. - if args.len() < 4 { + let [_, ptr, len, flags, ..] = args else { throw_ub_format!( "incorrect number of arguments for `getrandom` syscall: got {}, expected at least 4", args.len() ); - } + }; - let ptr = this.read_pointer(&args[1])?; - let len = this.read_target_usize(&args[2])?; + let ptr = this.read_pointer(ptr)?; + let len = this.read_target_usize(len)?; // The only supported flags are GRND_RANDOM and GRND_NONBLOCK, // neither of which have any effect on our current PRNG. // See for a discussion of argument sizes. - let _flags = this.read_scalar(&args[3])?.to_i32()?; + let _flags = this.read_scalar(flags)?.to_i32()?; this.gen_random(ptr, len)?; this.write_scalar(Scalar::from_target_usize(len, this), dest)?; diff --git a/src/tools/miri/src/shims/unix/linux/sync.rs b/src/tools/miri/src/shims/unix/linux/sync.rs index 404479e76e3..5833ec64fc6 100644 --- a/src/tools/miri/src/shims/unix/linux/sync.rs +++ b/src/tools/miri/src/shims/unix/linux/sync.rs @@ -15,19 +15,19 @@ pub fn futex<'tcx>( // may or may not be left out from the `syscall()` call. // Therefore we don't use `check_arg_count` here, but only check for the // number of arguments to fall within a range. - if args.len() < 3 { + let [addr, op, val, ..] = args else { throw_ub_format!( "incorrect number of arguments for `futex` syscall: got {}, expected at least 3", args.len() ); - } + }; // The first three arguments (after the syscall number itself) are the same to all futex operations: // (int *addr, int op, int val). // We checked above that these definitely exist. - let addr = this.read_pointer(&args[0])?; - let op = this.read_scalar(&args[1])?.to_i32()?; - let val = this.read_scalar(&args[2])?.to_i32()?; + let addr = this.read_pointer(addr)?; + let op = this.read_scalar(op)?.to_i32()?; + let val = this.read_scalar(val)?.to_i32()?; // This is a vararg function so we have to bring our own type for this pointer. let addr = this.ptr_to_mplace(addr, this.machine.layouts.i32); @@ -55,15 +55,15 @@ pub fn futex<'tcx>( let wait_bitset = op & !futex_realtime == futex_wait_bitset; let bitset = if wait_bitset { - if args.len() < 6 { + let [_, _, _, timeout, uaddr2, bitset, ..] = args else { throw_ub_format!( "incorrect number of arguments for `futex` syscall with `op=FUTEX_WAIT_BITSET`: got {}, expected at least 6", args.len() ); - } - let _timeout = this.read_pointer(&args[3])?; - let _uaddr2 = this.read_pointer(&args[4])?; - this.read_scalar(&args[5])?.to_u32()? + }; + let _timeout = this.read_pointer(timeout)?; + let _uaddr2 = this.read_pointer(uaddr2)?; + this.read_scalar(bitset)?.to_u32()? } else { if args.len() < 4 { throw_ub_format!( @@ -183,15 +183,15 @@ pub fn futex<'tcx>( // Same as FUTEX_WAKE, but allows you to specify a bitset to select which threads to wake up. op if op == futex_wake || op == futex_wake_bitset => { let bitset = if op == futex_wake_bitset { - if args.len() < 6 { + let [_, _, _, timeout, uaddr2, bitset, ..] = args else { throw_ub_format!( "incorrect number of arguments for `futex` syscall with `op=FUTEX_WAKE_BITSET`: got {}, expected at least 6", args.len() ); - } - let _timeout = this.read_pointer(&args[3])?; - let _uaddr2 = this.read_pointer(&args[4])?; - this.read_scalar(&args[5])?.to_u32()? + }; + let _timeout = this.read_pointer(timeout)?; + let _uaddr2 = this.read_pointer(uaddr2)?; + this.read_scalar(bitset)?.to_u32()? } else { u32::MAX }; From f51d8e3276b783a51b04139bf8e7bff099fb3769 Mon Sep 17 00:00:00 2001 From: Mads Marquart Date: Wed, 2 Oct 2024 21:20:01 +0200 Subject: [PATCH 563/683] Fix target_abi in sparc-unknown-none-elf This was previously set to `target_abi = "elf"`, but `elf` is not used elsewhere as a target ABI (even though there's many targets that have it in their name). --- .../rustc_target/src/spec/targets/sparc_unknown_none_elf.rs | 1 - tests/ui/check-cfg/well-known-values.stderr | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/compiler/rustc_target/src/spec/targets/sparc_unknown_none_elf.rs b/compiler/rustc_target/src/spec/targets/sparc_unknown_none_elf.rs index 0cd4faefd6b..0157d03f854 100644 --- a/compiler/rustc_target/src/spec/targets/sparc_unknown_none_elf.rs +++ b/compiler/rustc_target/src/spec/targets/sparc_unknown_none_elf.rs @@ -7,7 +7,6 @@ pub(crate) fn target() -> Target { linker: Some("sparc-elf-gcc".into()), endian: Endian::Big, cpu: "v7".into(), - abi: "elf".into(), max_atomic_width: Some(32), atomic_cas: true, panic_strategy: PanicStrategy::Abort, diff --git a/tests/ui/check-cfg/well-known-values.stderr b/tests/ui/check-cfg/well-known-values.stderr index 3c99fdd3821..c6d403104ea 100644 --- a/tests/ui/check-cfg/well-known-values.stderr +++ b/tests/ui/check-cfg/well-known-values.stderr @@ -129,7 +129,7 @@ warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` LL | target_abi = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: expected values for `target_abi` are: ``, `abi64`, `abiv2`, `abiv2hf`, `eabi`, `eabihf`, `elf`, `fortanix`, `ilp32`, `llvm`, `macabi`, `sim`, `softfloat`, `spe`, `uwp`, `vec-extabi`, and `x32` + = note: expected values for `target_abi` are: ``, `abi64`, `abiv2`, `abiv2hf`, `eabi`, `eabihf`, `fortanix`, `ilp32`, `llvm`, `macabi`, `sim`, `softfloat`, `spe`, `uwp`, `vec-extabi`, and `x32` = note: see for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` From e08002f6d0bfcea06357137dd52ee2c163757154 Mon Sep 17 00:00:00 2001 From: okaneco <47607823+okaneco@users.noreply.github.com> Date: Fri, 4 Oct 2024 14:56:15 -0400 Subject: [PATCH 564/683] Stabilize `BufRead::skip_until` --- library/std/src/io/mod.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index dd6458c38c6..8fedcb241d0 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -2382,8 +2382,6 @@ pub trait BufRead: Read { /// about Ferris from a binary string, skipping the fun fact: /// /// ``` - /// #![feature(bufread_skip_until)] - /// /// use std::io::{self, BufRead}; /// /// let mut cursor = io::Cursor::new(b"Ferris\0Likes long walks on the beach\0Crustacean\0"); @@ -2407,7 +2405,7 @@ pub trait BufRead: Read { /// assert_eq!(num_bytes, 11); /// assert_eq!(animal, b"Crustacean\0"); /// ``` - #[unstable(feature = "bufread_skip_until", issue = "111735")] + #[stable(feature = "bufread_skip_until", since = "CURRENT_RUSTC_VERSION")] fn skip_until(&mut self, byte: u8) -> Result { skip_until(self, byte) } From d0a467a89f513c1eaef5e99cb446c66dc37c2837 Mon Sep 17 00:00:00 2001 From: Weihang Lo Date: Fri, 4 Oct 2024 16:37:09 -0400 Subject: [PATCH 565/683] Update cargo --- src/tools/cargo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/cargo b/src/tools/cargo index 80d82ca22ab..ad074abe3a1 160000 --- a/src/tools/cargo +++ b/src/tools/cargo @@ -1 +1 @@ -Subproject commit 80d82ca22abbee5fb7b51fa1abeb1ae34e99e88a +Subproject commit ad074abe3a18ce8444c06f962ceecfd056acfc73 From ae5f58d906e755bff56dd9667c1d8b13ca236286 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 14 Sep 2024 15:43:03 -0400 Subject: [PATCH 566/683] Check elaborated projections from dyn don't mention unconstrained late bound lifetimes --- .../src/hir_ty_lowering/dyn_compatibility.rs | 50 +++++++++++++++++++ ...ted-predicates-unconstrained-late-bound.rs | 24 +++++++++ ...predicates-unconstrained-late-bound.stderr | 9 ++++ tests/ui/traits/object/pretty.rs | 4 +- tests/ui/traits/object/pretty.stderr | 13 +---- 5 files changed, 86 insertions(+), 14 deletions(-) create mode 100644 tests/ui/traits/object/elaborated-predicates-unconstrained-late-bound.rs create mode 100644 tests/ui/traits/object/elaborated-predicates-unconstrained-late-bound.stderr diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs index e7b8e6e69b0..f8ae9adebe3 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs @@ -174,6 +174,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { // Include projections defined on supertraits. projection_bounds.push((pred, span)); } + + self.check_elaborated_projection_mentions_input_lifetimes(pred, span); } _ => (), } @@ -360,6 +362,54 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { Ty::new_dynamic(tcx, existential_predicates, region_bound, representation) } + + /// Check that elaborating the principal of a trait ref doesn't lead to projections + /// that are unconstrained. This can happen because an otherwise unconstrained + /// *type variable* can be substituted with a type that has late-bound regions. See + /// `elaborated-predicates-unconstrained-late-bound.rs` for a test. + fn check_elaborated_projection_mentions_input_lifetimes( + &self, + pred: ty::PolyProjectionPredicate<'tcx>, + span: Span, + ) { + let tcx = self.tcx(); + + // Find any late-bound regions declared in `ty` that are not + // declared in the trait-ref or assoc_item. These are not well-formed. + // + // Example: + // + // for<'a> ::Item = &'a str // <-- 'a is bad + // for<'a> >::Output = &'a str // <-- 'a is ok + let late_bound_in_projection_term = + tcx.collect_constrained_late_bound_regions(pred.map_bound(|pred| pred.projection_term)); + let late_bound_in_term = + tcx.collect_referenced_late_bound_regions(pred.map_bound(|pred| pred.term)); + debug!(?late_bound_in_projection_term); + debug!(?late_bound_in_term); + + // FIXME: point at the type params that don't have appropriate lifetimes: + // struct S1 Fn(&i32, &i32) -> &'a i32>(F); + // ---- ---- ^^^^^^^ + // NOTE(associated_const_equality): This error should be impossible to trigger + // with associated const equality constraints. + self.validate_late_bound_regions( + late_bound_in_projection_term, + late_bound_in_term, + |br_name| { + let item_name = tcx.item_name(pred.projection_def_id()); + struct_span_code_err!( + self.dcx(), + span, + E0582, + "binding for associated type `{}` references {}, \ + which does not appear in the trait input types", + item_name, + br_name + ) + }, + ); + } } fn replace_dummy_self_with_error<'tcx, T: TypeFoldable>>( diff --git a/tests/ui/traits/object/elaborated-predicates-unconstrained-late-bound.rs b/tests/ui/traits/object/elaborated-predicates-unconstrained-late-bound.rs new file mode 100644 index 00000000000..b174776c596 --- /dev/null +++ b/tests/ui/traits/object/elaborated-predicates-unconstrained-late-bound.rs @@ -0,0 +1,24 @@ +// Make sure that when elaborating the principal of a dyn trait for projection predicates +// we don't end up in a situation where we have an unconstrained late-bound lifetime in +// the output of a projection. + +// Fix for . + +trait A: B {} + +trait B { + type T; +} + +struct Erase(T::T); + +fn main() { + let x = { + let x = String::from("hello"); + + Erase:: A<&'a _>>(x.as_str()) + //~^ ERROR binding for associated type `T` references lifetime `'a`, which does not appear in the trait input types + }; + + dbg!(x.0); +} diff --git a/tests/ui/traits/object/elaborated-predicates-unconstrained-late-bound.stderr b/tests/ui/traits/object/elaborated-predicates-unconstrained-late-bound.stderr new file mode 100644 index 00000000000..bb3cc4b3fd7 --- /dev/null +++ b/tests/ui/traits/object/elaborated-predicates-unconstrained-late-bound.stderr @@ -0,0 +1,9 @@ +error[E0582]: binding for associated type `T` references lifetime `'a`, which does not appear in the trait input types + --> $DIR/elaborated-predicates-unconstrained-late-bound.rs:19:21 + | +LL | Erase:: A<&'a _>>(x.as_str()) + | ^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0582`. diff --git a/tests/ui/traits/object/pretty.rs b/tests/ui/traits/object/pretty.rs index 6660ff040f7..603d7af5260 100644 --- a/tests/ui/traits/object/pretty.rs +++ b/tests/ui/traits/object/pretty.rs @@ -13,7 +13,7 @@ trait SuperGeneric<'a> { } trait AnyGeneric<'a>: SuperGeneric<'a> {} trait FixedGeneric1<'a>: SuperGeneric<'a, Assoc2 = &'a u8> {} -trait FixedGeneric2<'a>: Super {} +// trait FixedGeneric2<'a>: Super {} // Unsound! trait FixedHrtb: for<'a> SuperGeneric<'a, Assoc2 = &'a u8> {} trait AnyDifferentBinders: for<'a> SuperGeneric<'a, Assoc2 = &'a u8> + Super {} trait FixedDifferentBinders: for<'a> SuperGeneric<'a, Assoc2 = &'a u8> + Super {} @@ -32,7 +32,7 @@ fn dyn_fixed_static(x: &dyn FixedStatic) { x } //~ERROR mismatched types fn dyn_super_generic(x: &dyn for<'a> SuperGeneric<'a, Assoc2 = &'a u8>) { x } //~ERROR mismatched types fn dyn_any_generic(x: &dyn for<'a> AnyGeneric<'a, Assoc2 = &'a u8>) { x } //~ERROR mismatched types fn dyn_fixed_generic1(x: &dyn for<'a> FixedGeneric1<'a>) { x } //~ERROR mismatched types -fn dyn_fixed_generic2(x: &dyn for<'a> FixedGeneric2<'a>) { x } //~ERROR mismatched types +// fn dyn_fixed_generic2(x: &dyn for<'a> FixedGeneric2<'a>) { x } // Unsound! fn dyn_fixed_generic_multi(x: &dyn for<'a> FixedGeneric1<'a, Assoc2 = &u8>) { x } //~ERROR mismatched types fn dyn_fixed_hrtb(x: &dyn FixedHrtb) { x } //~ERROR mismatched types fn dyn_any_different_binders(x: &dyn AnyDifferentBinders) { x } //~ERROR mismatched types diff --git a/tests/ui/traits/object/pretty.stderr b/tests/ui/traits/object/pretty.stderr index ca56bdbb67a..af941e69c5f 100644 --- a/tests/ui/traits/object/pretty.stderr +++ b/tests/ui/traits/object/pretty.stderr @@ -106,17 +106,6 @@ LL | fn dyn_fixed_generic1(x: &dyn for<'a> FixedGeneric1<'a>) { x } = note: expected unit type `()` found reference `&dyn for<'a> FixedGeneric1<'a>` -error[E0308]: mismatched types - --> $DIR/pretty.rs:35:60 - | -LL | fn dyn_fixed_generic2(x: &dyn for<'a> FixedGeneric2<'a>) { x } - | - ^ expected `()`, found `&dyn FixedGeneric2<'a>` - | | - | help: try adding a return type: `-> &dyn for<'a> FixedGeneric2<'a>` - | - = note: expected unit type `()` - found reference `&dyn for<'a> FixedGeneric2<'a>` - error[E0308]: mismatched types --> $DIR/pretty.rs:36:79 | @@ -172,6 +161,6 @@ LL | fn dyn_has_gat(x: &dyn HasGat = ()>) { x } = note: expected unit type `()` found reference `&dyn HasGat = ()>` -error: aborting due to 15 previous errors; 1 warning emitted +error: aborting due to 14 previous errors; 1 warning emitted For more information about this error, try `rustc --explain E0308`. From fd7ee484f9da99120116dc560452dd551d4c6496 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 14 Sep 2024 15:55:16 -0400 Subject: [PATCH 567/683] Elaborate supertrait span correctly to label the error better --- .../src/hir_ty_lowering/dyn_compatibility.rs | 20 +++++++--- compiler/rustc_middle/src/ty/predicate.rs | 4 ++ compiler/rustc_type_ir/src/elaborate.rs | 40 +++++++++++++++++++ compiler/rustc_type_ir/src/inherent.rs | 2 + ...predicates-unconstrained-late-bound.stderr | 3 ++ 5 files changed, 64 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs index f8ae9adebe3..394a263fbb5 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs @@ -13,6 +13,7 @@ use rustc_middle::ty::{ use rustc_span::{ErrorGuaranteed, Span}; use rustc_trait_selection::error_reporting::traits::report_dyn_incompatibility; use rustc_trait_selection::traits::{self, hir_ty_lowering_dyn_compatibility_violations}; +use rustc_type_ir::elaborate::ClauseWithSupertraitSpan; use smallvec::{SmallVec, smallvec}; use tracing::{debug, instrument}; @@ -124,16 +125,19 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { .into_iter() .filter(|(trait_ref, _)| !tcx.trait_is_auto(trait_ref.def_id())); - for (base_trait_ref, span) in regular_traits_refs_spans { + for (base_trait_ref, original_span) in regular_traits_refs_spans { let base_pred: ty::Predicate<'tcx> = base_trait_ref.upcast(tcx); - for pred in traits::elaborate(tcx, [base_pred]).filter_only_self() { + for ClauseWithSupertraitSpan { pred, original_span, supertrait_span } in + traits::elaborate(tcx, [ClauseWithSupertraitSpan::new(base_pred, original_span)]) + .filter_only_self() + { debug!("observing object predicate `{pred:?}`"); let bound_predicate = pred.kind(); match bound_predicate.skip_binder() { ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) => { let pred = bound_predicate.rebind(pred); - associated_types.entry(span).or_default().extend( + associated_types.entry(original_span).or_default().extend( tcx.associated_items(pred.def_id()) .in_definition_order() .filter(|item| item.kind == ty::AssocKind::Type) @@ -172,10 +176,14 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { // the discussion in #56288 for alternatives. if !references_self { // Include projections defined on supertraits. - projection_bounds.push((pred, span)); + projection_bounds.push((pred, original_span)); } - self.check_elaborated_projection_mentions_input_lifetimes(pred, span); + self.check_elaborated_projection_mentions_input_lifetimes( + pred, + original_span, + supertrait_span, + ); } _ => (), } @@ -371,6 +379,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { &self, pred: ty::PolyProjectionPredicate<'tcx>, span: Span, + supertrait_span: Span, ) { let tcx = self.tcx(); @@ -407,6 +416,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { item_name, br_name ) + .with_span_label(supertrait_span, "due to this supertrait") }, ); } diff --git a/compiler/rustc_middle/src/ty/predicate.rs b/compiler/rustc_middle/src/ty/predicate.rs index fd4e8f1cd4e..d20cb368278 100644 --- a/compiler/rustc_middle/src/ty/predicate.rs +++ b/compiler/rustc_middle/src/ty/predicate.rs @@ -179,6 +179,10 @@ pub struct Clause<'tcx>( ); impl<'tcx> rustc_type_ir::inherent::Clause> for Clause<'tcx> { + fn as_predicate(self) -> Predicate<'tcx> { + self.as_predicate() + } + fn instantiate_supertrait(self, tcx: TyCtxt<'tcx>, trait_ref: ty::PolyTraitRef<'tcx>) -> Self { self.instantiate_supertrait(tcx, trait_ref) } diff --git a/compiler/rustc_type_ir/src/elaborate.rs b/compiler/rustc_type_ir/src/elaborate.rs index 61736633cfa..dac45ff2aba 100644 --- a/compiler/rustc_type_ir/src/elaborate.rs +++ b/compiler/rustc_type_ir/src/elaborate.rs @@ -44,6 +44,46 @@ pub trait Elaboratable { ) -> Self; } +pub struct ClauseWithSupertraitSpan { + pub pred: I::Predicate, + // Span of the original elaborated predicate. + pub original_span: I::Span, + // Span of the supertrait predicatae that lead to this clause. + pub supertrait_span: I::Span, +} +impl ClauseWithSupertraitSpan { + pub fn new(pred: I::Predicate, span: I::Span) -> Self { + ClauseWithSupertraitSpan { pred, original_span: span, supertrait_span: span } + } +} +impl Elaboratable for ClauseWithSupertraitSpan { + fn predicate(&self) -> ::Predicate { + self.pred + } + + fn child(&self, clause: ::Clause) -> Self { + ClauseWithSupertraitSpan { + pred: clause.as_predicate(), + original_span: self.original_span, + supertrait_span: self.supertrait_span, + } + } + + fn child_with_derived_cause( + &self, + clause: ::Clause, + supertrait_span: ::Span, + _parent_trait_pred: crate::Binder>, + _index: usize, + ) -> Self { + ClauseWithSupertraitSpan { + pred: clause.as_predicate(), + original_span: self.original_span, + supertrait_span: supertrait_span, + } + } +} + pub fn elaborate>( cx: I, obligations: impl IntoIterator, diff --git a/compiler/rustc_type_ir/src/inherent.rs b/compiler/rustc_type_ir/src/inherent.rs index 59a83ea5412..69665df4bfc 100644 --- a/compiler/rustc_type_ir/src/inherent.rs +++ b/compiler/rustc_type_ir/src/inherent.rs @@ -460,6 +460,8 @@ pub trait Clause>: + IntoKind>> + Elaboratable { + fn as_predicate(self) -> I::Predicate; + fn as_trait_clause(self) -> Option>> { self.kind() .map_bound(|clause| if let ty::ClauseKind::Trait(t) = clause { Some(t) } else { None }) diff --git a/tests/ui/traits/object/elaborated-predicates-unconstrained-late-bound.stderr b/tests/ui/traits/object/elaborated-predicates-unconstrained-late-bound.stderr index bb3cc4b3fd7..067eaf5e7f3 100644 --- a/tests/ui/traits/object/elaborated-predicates-unconstrained-late-bound.stderr +++ b/tests/ui/traits/object/elaborated-predicates-unconstrained-late-bound.stderr @@ -1,6 +1,9 @@ error[E0582]: binding for associated type `T` references lifetime `'a`, which does not appear in the trait input types --> $DIR/elaborated-predicates-unconstrained-late-bound.rs:19:21 | +LL | trait A: B {} + | ----- due to this supertrait +... LL | Erase:: A<&'a _>>(x.as_str()) | ^^^^^^^^^^^^^^^^ From b955480d05dcbe0fc29e329862c827eb28b0b189 Mon Sep 17 00:00:00 2001 From: Alan Wu Date: Thu, 3 Oct 2024 17:57:12 -0400 Subject: [PATCH 568/683] Update compiler-builtins to 0.1.132 This commit updates compiler-builtins from 0.1.130 to 0.1.132. PRs in the delta: - rust-lang/compiler-builtins#698 - rust-lang/compiler-builtins#699 - rust-lang/compiler-builtins#701 - rust-lang/compiler-builtins#704 - rust-lang/compiler-builtins#627 - rust-lang/compiler-builtins#706 --- library/Cargo.lock | 4 ++-- library/alloc/Cargo.toml | 2 +- library/std/Cargo.toml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/library/Cargo.lock b/library/Cargo.lock index 209e30b3040..66ded59ae36 100644 --- a/library/Cargo.lock +++ b/library/Cargo.lock @@ -61,9 +61,9 @@ dependencies = [ [[package]] name = "compiler_builtins" -version = "0.1.130" +version = "0.1.132" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e64c30475571756801eff60a811520c3d18e0ceb9c56c97bad2047ae601f6709" +checksum = "88f58330b127df19326d19e9debbb722578589cb1b9c061b5cdc4036d038b54b" dependencies = [ "cc", "rustc-std-workspace-core", diff --git a/library/alloc/Cargo.toml b/library/alloc/Cargo.toml index 11db50a0fdf..fa18c7aec74 100644 --- a/library/alloc/Cargo.toml +++ b/library/alloc/Cargo.toml @@ -10,7 +10,7 @@ edition = "2021" [dependencies] core = { path = "../core" } -compiler_builtins = { version = "0.1.130", features = ['rustc-dep-of-std'] } +compiler_builtins = { version = "0.1.132", features = ['rustc-dep-of-std'] } [dev-dependencies] rand = { version = "0.8.5", default-features = false, features = ["alloc"] } diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index 63c65b8ef39..6bf70e1d82a 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -17,7 +17,7 @@ cfg-if = { version = "1.0", features = ['rustc-dep-of-std'] } panic_unwind = { path = "../panic_unwind", optional = true } panic_abort = { path = "../panic_abort" } core = { path = "../core", public = true } -compiler_builtins = { version = "0.1.130" } +compiler_builtins = { version = "0.1.132" } profiler_builtins = { path = "../profiler_builtins", optional = true } unwind = { path = "../unwind" } hashbrown = { version = "0.15", default-features = false, features = [ From e057c43382a1eacc5941bc4e78b36dc122b32419 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Fri, 4 Oct 2024 22:59:03 +0000 Subject: [PATCH 569/683] Account for `impl Trait {` when `impl Trait for Type {` was intended On editions where bare traits are never allowed, detect if the user has written `impl Trait` with no type, silence any dyn-compatibility errors, and provide a structured suggestion for the potentially missing type: ``` error[E0782]: trait objects must include the `dyn` keyword --> $DIR/missing-for-type-in-impl.rs:8:6 | LL | impl Foo { | ^^^^^^^^ | help: add `dyn` keyword before this trait | LL | impl dyn Foo { | +++ help: you might have intended to implement this trait for a given type | LL | impl Foo for /* Type */ { | ++++++++++++++ ``` --- .../src/hir_ty_lowering/lint.rs | 17 +++-- .../traits/fulfillment_errors.rs | 22 +++++- .../missing-for-type-in-impl.e2015.stderr | 74 +++++++++++++++++++ .../missing-for-type-in-impl.e2021.stderr | 31 ++++++++ tests/ui/traits/missing-for-type-in-impl.rs | 22 ++++++ 5 files changed, 158 insertions(+), 8 deletions(-) create mode 100644 tests/ui/traits/missing-for-type-in-impl.e2015.stderr create mode 100644 tests/ui/traits/missing-for-type-in-impl.e2021.stderr create mode 100644 tests/ui/traits/missing-for-type-in-impl.rs diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs index a70f881f5fe..5607fe873f6 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs @@ -108,17 +108,20 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let tcx = self.tcx(); let parent_id = tcx.hir().get_parent_item(self_ty.hir_id).def_id; if let hir::Node::Item(hir::Item { - kind: - hir::ItemKind::Impl(hir::Impl { - self_ty: impl_self_ty, - of_trait: Some(of_trait_ref), - generics, - .. - }), + kind: hir::ItemKind::Impl(hir::Impl { self_ty: impl_self_ty, of_trait, generics, .. }), .. }) = tcx.hir_node_by_def_id(parent_id) && self_ty.hir_id == impl_self_ty.hir_id { + let Some(of_trait_ref) = of_trait else { + diag.span_suggestion_verbose( + impl_self_ty.span.shrink_to_hi(), + "you might have intended to implement this trait for a given type", + format!(" for /* Type */"), + Applicability::HasPlaceholders, + ); + return; + }; if !of_trait_ref.trait_def_id().is_some_and(|def_id| def_id.is_local()) { return; } 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 1889ecc7670..824c25db07d 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 @@ -1,6 +1,7 @@ use core::ops::ControlFlow; use std::borrow::Cow; +use rustc_ast::TraitObjectSyntax; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::unord::UnordSet; use rustc_errors::codes::*; @@ -573,7 +574,26 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ty::PredicateKind::DynCompatible(trait_def_id) => { let violations = self.tcx.dyn_compatibility_violations(trait_def_id); - report_dyn_incompatibility(self.tcx, span, None, trait_def_id, violations) + let mut err = report_dyn_incompatibility( + self.tcx, + span, + None, + trait_def_id, + violations, + ); + if let hir::Node::Item(item) = + self.tcx.hir_node_by_def_id(obligation.cause.body_id) + && let hir::ItemKind::Impl(impl_) = item.kind + && let None = impl_.of_trait + && let hir::TyKind::TraitObject(_, _, syntax) = impl_.self_ty.kind + && let TraitObjectSyntax::None = syntax + && impl_.self_ty.span.edition().at_least_rust_2021() + { + // Silence the dyn-compatibility error in favor of the missing dyn on + // self type error. #131051. + err.downgrade_to_delayed_bug(); + } + err } ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(ty)) => { diff --git a/tests/ui/traits/missing-for-type-in-impl.e2015.stderr b/tests/ui/traits/missing-for-type-in-impl.e2015.stderr new file mode 100644 index 00000000000..541b49b024f --- /dev/null +++ b/tests/ui/traits/missing-for-type-in-impl.e2015.stderr @@ -0,0 +1,74 @@ +warning: trait objects without an explicit `dyn` are deprecated + --> $DIR/missing-for-type-in-impl.rs:8:6 + | +LL | impl Foo { + | ^^^^^^^^ + | + = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! + = note: for more information, see + = note: `#[warn(bare_trait_objects)]` on by default +help: if this is a dyn-compatible trait, use `dyn` + | +LL | impl dyn Foo { + | +++ +help: you might have intended to implement this trait for a given type + | +LL | impl Foo for /* Type */ { + | ++++++++++++++ + +warning: trait objects without an explicit `dyn` are deprecated + --> $DIR/missing-for-type-in-impl.rs:8:6 + | +LL | impl Foo { + | ^^^^^^^^ + | + = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! + = note: for more information, see + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: if this is a dyn-compatible trait, use `dyn` + | +LL | impl dyn Foo { + | +++ +help: you might have intended to implement this trait for a given type + | +LL | impl Foo for /* Type */ { + | ++++++++++++++ + +error[E0038]: the trait `Foo` cannot be made into an object + --> $DIR/missing-for-type-in-impl.rs:8:6 + | +LL | impl Foo { + | ^^^^^^^^ `Foo` cannot be made into an object + | +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit + --> $DIR/missing-for-type-in-impl.rs:4:8 + | +LL | trait Foo { + | --- this trait cannot be made into an object... +LL | fn id(me: T) -> T; + | ^^ ...because associated function `id` has no `self` parameter +help: consider turning `id` into a method by giving it a `&self` argument + | +LL | fn id(&self, me: T) -> T; + | ++++++ +help: alternatively, consider constraining `id` so it does not apply to trait objects + | +LL | fn id(me: T) -> T where Self: Sized; + | +++++++++++++++++ + +error[E0277]: the trait bound `i64: Foo` is not satisfied + --> $DIR/missing-for-type-in-impl.rs:19:19 + | +LL | let x: i64 = >::id(10); + | ^^^ the trait `Foo` is not implemented for `i64` + | +help: this trait has no implementations, consider adding one + --> $DIR/missing-for-type-in-impl.rs:3:1 + | +LL | trait Foo { + | ^^^^^^^^^^^^ + +error: aborting due to 2 previous errors; 2 warnings emitted + +Some errors have detailed explanations: E0038, E0277. +For more information about an error, try `rustc --explain E0038`. diff --git a/tests/ui/traits/missing-for-type-in-impl.e2021.stderr b/tests/ui/traits/missing-for-type-in-impl.e2021.stderr new file mode 100644 index 00000000000..b5a607a54cb --- /dev/null +++ b/tests/ui/traits/missing-for-type-in-impl.e2021.stderr @@ -0,0 +1,31 @@ +error[E0277]: the trait bound `i64: Foo` is not satisfied + --> $DIR/missing-for-type-in-impl.rs:19:19 + | +LL | let x: i64 = >::id(10); + | ^^^ the trait `Foo` is not implemented for `i64` + | +help: this trait has no implementations, consider adding one + --> $DIR/missing-for-type-in-impl.rs:3:1 + | +LL | trait Foo { + | ^^^^^^^^^^^^ + +error[E0782]: trait objects must include the `dyn` keyword + --> $DIR/missing-for-type-in-impl.rs:8:6 + | +LL | impl Foo { + | ^^^^^^^^ + | +help: add `dyn` keyword before this trait + | +LL | impl dyn Foo { + | +++ +help: you might have intended to implement this trait for a given type + | +LL | impl Foo for /* Type */ { + | ++++++++++++++ + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0277, E0782. +For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/missing-for-type-in-impl.rs b/tests/ui/traits/missing-for-type-in-impl.rs new file mode 100644 index 00000000000..7d4ad479e77 --- /dev/null +++ b/tests/ui/traits/missing-for-type-in-impl.rs @@ -0,0 +1,22 @@ +//@revisions: e2021 e2015 +//@[e2021]edition: 2021 +trait Foo { + fn id(me: T) -> T; +} + +/* note the "missing" for ... (in this case for i64, in order for this to compile) */ +impl Foo { +//[e2021]~^ ERROR trait objects must include the `dyn` keyword +//[e2015]~^^ WARNING trait objects without an explicit `dyn` are deprecated +//[e2015]~| WARNING trait objects without an explicit `dyn` are deprecated +//[e2015]~| WARNING this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! +//[e2015]~| WARNING this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! +//[e2015]~| ERROR the trait `Foo` cannot be made into an object + fn id(me: i64) -> i64 {me} +} + +fn main() { + let x: i64 = >::id(10); + //~^ ERROR the trait bound `i64: Foo` is not satisfied + println!("{}", x); +} From 99144726a43b6ed5a5010837080f2a7c70c4ec52 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sun, 18 Aug 2024 15:48:22 +0000 Subject: [PATCH 570/683] Make query backtrace more useful. --- compiler/rustc_middle/src/query/mod.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 989fbd711c3..9b7dfaab601 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1738,16 +1738,16 @@ rustc_queries! { /// Does lifetime resolution on items. Importantly, we can't resolve /// lifetimes directly on things like trait methods, because of trait params. /// See `rustc_resolve::late::lifetimes` for details. - query resolve_bound_vars(_: hir::OwnerId) -> &'tcx ResolveBoundVars { + query resolve_bound_vars(def_id: hir::OwnerId) -> &'tcx ResolveBoundVars { arena_cache - desc { "resolving lifetimes" } + desc { |tcx| "resolving lifetimes for `{}`", tcx.def_path_str(def_id) } } - query named_variable_map(_: hir::OwnerId) -> + query named_variable_map(def_id: hir::OwnerId) -> Option<&'tcx FxIndexMap> { - desc { "looking up a named region" } + desc { |tcx| "looking up a named region inside `{}`", tcx.def_path_str(def_id) } } - query is_late_bound_map(_: hir::OwnerId) -> Option<&'tcx FxIndexSet> { - desc { "testing if a region is late bound" } + query is_late_bound_map(def_id: hir::OwnerId) -> Option<&'tcx FxIndexSet> { + desc { |tcx| "testing if a region is late bound inside `{}`", tcx.def_path_str(def_id) } } /// For a given item's generic parameter, gets the default lifetimes to be used /// for each parameter if a trait object were to be passed for that parameter. @@ -1758,9 +1758,9 @@ rustc_queries! { desc { "looking up lifetime defaults for generic parameter `{}`", tcx.def_path_str(key) } separate_provide_extern } - query late_bound_vars_map(_: hir::OwnerId) + query late_bound_vars_map(def_id: hir::OwnerId) -> Option<&'tcx FxIndexMap>> { - desc { "looking up late bound vars" } + desc { |tcx| "looking up late bound vars inside `{}`", tcx.def_path_str(def_id) } } /// Computes the visibility of the provided `def_id`. From 4ec7839afa30aae41ee01326b0273ca1ba8e027b Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Thu, 22 Aug 2024 00:55:35 +0000 Subject: [PATCH 571/683] Make naming more consistent. --- compiler/rustc_middle/src/query/mod.rs | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 9b7dfaab601..1f0aab6d6b3 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1738,29 +1738,29 @@ rustc_queries! { /// Does lifetime resolution on items. Importantly, we can't resolve /// lifetimes directly on things like trait methods, because of trait params. /// See `rustc_resolve::late::lifetimes` for details. - query resolve_bound_vars(def_id: hir::OwnerId) -> &'tcx ResolveBoundVars { + query resolve_bound_vars(owner_id: hir::OwnerId) -> &'tcx ResolveBoundVars { arena_cache - desc { |tcx| "resolving lifetimes for `{}`", tcx.def_path_str(def_id) } + desc { |tcx| "resolving lifetimes for `{}`", tcx.def_path_str(owner_id) } } - query named_variable_map(def_id: hir::OwnerId) -> + query named_variable_map(owner_id: hir::OwnerId) -> Option<&'tcx FxIndexMap> { - desc { |tcx| "looking up a named region inside `{}`", tcx.def_path_str(def_id) } + desc { |tcx| "looking up a named region inside `{}`", tcx.def_path_str(owner_id) } } - query is_late_bound_map(def_id: hir::OwnerId) -> Option<&'tcx FxIndexSet> { - desc { |tcx| "testing if a region is late bound inside `{}`", tcx.def_path_str(def_id) } + query is_late_bound_map(owner_id: hir::OwnerId) -> Option<&'tcx FxIndexSet> { + desc { |tcx| "testing if a region is late bound inside `{}`", tcx.def_path_str(owner_id) } } /// For a given item's generic parameter, gets the default lifetimes to be used /// for each parameter if a trait object were to be passed for that parameter. /// For example, for `T` in `struct Foo<'a, T>`, this would be `'static`. /// For `T` in `struct Foo<'a, T: 'a>`, this would instead be `'a`. /// This query will panic if passed something that is not a type parameter. - query object_lifetime_default(key: DefId) -> ObjectLifetimeDefault { - desc { "looking up lifetime defaults for generic parameter `{}`", tcx.def_path_str(key) } + query object_lifetime_default(def_id: DefId) -> ObjectLifetimeDefault { + desc { "looking up lifetime defaults for generic parameter `{}`", tcx.def_path_str(def_id) } separate_provide_extern } - query late_bound_vars_map(def_id: hir::OwnerId) + query late_bound_vars_map(owner_id: hir::OwnerId) -> Option<&'tcx FxIndexMap>> { - desc { |tcx| "looking up late bound vars inside `{}`", tcx.def_path_str(def_id) } + desc { |tcx| "looking up late bound vars inside `{}`", tcx.def_path_str(owner_id) } } /// Computes the visibility of the provided `def_id`. From d6f247f3d52f529e7145eb355ac9660a49d0d8c9 Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Fri, 9 Aug 2024 20:43:30 -0700 Subject: [PATCH 572/683] rm `ItemKind::OpaqueTy` This introduce an additional collection of opaques on HIR, as they can no longer be listed using the free item list. --- compiler/rustc_ast_lowering/src/index.rs | 8 ++ compiler/rustc_ast_lowering/src/lib.rs | 27 +++---- .../src/diagnostics/region_name.rs | 10 +-- .../src/region_infer/opaque_types.rs | 4 +- compiler/rustc_hir/src/hir.rs | 15 ++-- compiler/rustc_hir/src/intravisit.rs | 25 +++++-- compiler/rustc_hir/src/target.rs | 5 -- .../rustc_hir_analysis/src/check/check.rs | 16 ++-- .../src/check/compare_impl_item/refine.rs | 2 +- compiler/rustc_hir_analysis/src/collect.rs | 40 +++------- .../rustc_hir_analysis/src/collect/dump.rs | 11 +-- .../src/collect/generics_of.rs | 57 +++++++-------- .../src/collect/item_bounds.rs | 13 +--- .../src/collect/predicates_of.rs | 2 +- .../src/collect/resolve_bound_vars.rs | 73 ++++++++----------- .../rustc_hir_analysis/src/collect/type_of.rs | 62 ++++++---------- .../src/hir_ty_lowering/mod.rs | 65 ++++++++--------- .../rustc_hir_analysis/src/variance/dump.rs | 13 ++-- compiler/rustc_hir_pretty/src/lib.rs | 15 ++-- .../src/fn_ctxt/suggestions.rs | 5 +- compiler/rustc_lint/src/async_fn_in_trait.rs | 7 +- .../rustc_lint/src/impl_trait_overcaptures.rs | 2 +- .../src/opaque_hidden_inferred_bound.rs | 6 +- compiler/rustc_lint/src/types.rs | 1 - compiler/rustc_middle/src/hir/map/mod.rs | 31 +++++++- compiler/rustc_middle/src/hir/mod.rs | 12 +++ compiler/rustc_middle/src/ty/context.rs | 11 +-- compiler/rustc_middle/src/ty/diagnostics.rs | 10 +-- compiler/rustc_middle/src/ty/sty.rs | 2 + compiler/rustc_passes/src/check_attr.rs | 2 - compiler/rustc_passes/src/dead.rs | 10 +-- compiler/rustc_passes/src/hir_stats.rs | 1 - compiler/rustc_passes/src/reachable.rs | 4 +- compiler/rustc_privacy/src/lib.rs | 18 ++--- .../nice_region_error/static_impl_trait.rs | 9 +-- .../error_reporting/infer/note_and_explain.rs | 2 +- .../src/error_reporting/infer/region.rs | 11 +-- .../src/error_reporting/infer/suggest.rs | 8 +- .../src/error_reporting/traits/suggestions.rs | 18 +++-- compiler/rustc_ty_utils/src/assoc.rs | 15 ++-- compiler/rustc_ty_utils/src/opaque_types.rs | 1 + src/librustdoc/clean/mod.rs | 12 +-- src/librustdoc/html/render/span_map.rs | 1 - src/librustdoc/visit_ast.rs | 10 --- .../clippy_utils/src/check_proc_macro.rs | 2 +- 45 files changed, 306 insertions(+), 368 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/index.rs b/compiler/rustc_ast_lowering/src/index.rs index e77c0fb3a3e..6289966561f 100644 --- a/compiler/rustc_ast_lowering/src/index.rs +++ b/compiler/rustc_ast_lowering/src/index.rs @@ -226,6 +226,14 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> { }); } + fn visit_opaque_ty(&mut self, opaq: &'hir OpaqueTy<'hir>) { + self.insert(opaq.span, opaq.hir_id, Node::OpaqueTy(opaq)); + + self.with_parent(opaq.hir_id, |this| { + intravisit::walk_opaque_ty(this, opaq); + }); + } + fn visit_anon_const(&mut self, constant: &'hir AnonConst) { // FIXME: use real span? self.insert(DUMMY_SP, constant.hir_id, Node::AnonConst(constant)); diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 9275308cccb..b26797f4203 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -1603,7 +1603,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { lower_item_bounds: impl FnOnce(&mut Self) -> &'hir [hir::GenericBound<'hir>], ) -> hir::TyKind<'hir> { let opaque_ty_def_id = self.local_def_id(opaque_ty_node_id); - debug!(?opaque_ty_def_id); + let opaque_ty_hir_id = self.lower_node_id(opaque_ty_node_id); + debug!(?opaque_ty_def_id, ?opaque_ty_hir_id); // Map from captured (old) lifetime to synthetic (new) lifetime. // Used to resolve lifetimes in the bounds of the opaque. @@ -1676,7 +1677,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } } - self.with_hir_id_owner(opaque_ty_node_id, |this| { + let opaque_ty_def = self.with_def_id_parent(opaque_ty_def_id, |this| { // Install the remapping from old to new (if any). This makes sure that // any lifetimes that would have resolved to the def-id of captured // lifetimes are remapped to the new *synthetic* lifetimes of the opaque. @@ -1714,7 +1715,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let lifetime_mapping = self.arena.alloc_slice(&synthesized_lifetime_args); - let opaque_ty_item = hir::OpaqueTy { + trace!("registering opaque type with id {:#?}", opaque_ty_def_id); + let opaque_ty_def = hir::OpaqueTy { + hir_id: opaque_ty_hir_id, + def_id: opaque_ty_def_id, generics: this.arena.alloc(hir::Generics { params: generic_params, predicates: &[], @@ -1725,19 +1729,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { bounds, origin, lifetime_mapping, - }; - - // Generate an `type Foo = impl Trait;` declaration. - trace!("registering opaque type with id {:#?}", opaque_ty_def_id); - let opaque_ty_item = hir::Item { - owner_id: hir::OwnerId { def_id: opaque_ty_def_id }, - ident: Ident::empty(), - kind: hir::ItemKind::OpaqueTy(this.arena.alloc(opaque_ty_item)), - vis_span: this.lower_span(span.shrink_to_lo()), span: this.lower_span(opaque_ty_span), }; - - hir::OwnerNode::Item(this.arena.alloc(opaque_ty_item)) + this.arena.alloc(opaque_ty_def) }); let generic_args = self.arena.alloc_from_iter( @@ -1750,10 +1744,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // Foo = impl Trait` is, internally, created as a child of the // async fn, so the *type parameters* are inherited. It's // only the lifetime parameters that we must supply. - hir::TyKind::OpaqueDef( - hir::ItemId { owner_id: hir::OwnerId { def_id: opaque_ty_def_id } }, - generic_args, - ) + hir::TyKind::OpaqueDef(opaque_ty_def, generic_args) } fn lower_precise_capturing_args( diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs index d4598a1f582..1a5f9bdb154 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs @@ -830,20 +830,14 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> { /// /// [`OpaqueDef`]: hir::TyKind::OpaqueDef fn get_future_inner_return_ty(&self, hir_ty: &'tcx hir::Ty<'tcx>) -> &'tcx hir::Ty<'tcx> { - let hir = self.infcx.tcx.hir(); - - let hir::TyKind::OpaqueDef(id, _) = hir_ty.kind else { + let hir::TyKind::OpaqueDef(opaque_ty, _) = hir_ty.kind else { span_bug!( hir_ty.span, "lowered return type of async fn is not OpaqueDef: {:?}", hir_ty ); }; - let opaque_ty = hir.item(id); - if let hir::ItemKind::OpaqueTy(hir::OpaqueTy { - bounds: [hir::GenericBound::Trait(trait_ref, _)], - .. - }) = opaque_ty.kind + if let hir::OpaqueTy { bounds: [hir::GenericBound::Trait(trait_ref, _)], .. } = opaque_ty && let Some(segment) = trait_ref.trait_ref.path.segments.last() && let Some(args) = segment.args && let [constraint] = args.constraints diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs index 2f90e916281..a16c1931a55 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs @@ -329,8 +329,8 @@ fn check_opaque_type_well_formed<'tcx>( ) -> Result, ErrorGuaranteed> { // Only check this for TAIT. RPIT already supports `tests/ui/impl-trait/nested-return-type2.rs` // on stable and we'd break that. - let opaque_ty_hir = tcx.hir().expect_item(def_id); - let OpaqueTyOrigin::TyAlias { .. } = opaque_ty_hir.expect_opaque_ty().origin else { + let opaque_ty_hir = tcx.hir().expect_opaque_ty(def_id); + let OpaqueTyOrigin::TyAlias { .. } = opaque_ty_hir.origin else { return Ok(definition_ty); }; let param_env = tcx.param_env(def_id); diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index f58ec22aea9..2ef6fa53f4e 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -2749,6 +2749,8 @@ pub struct BareFnTy<'hir> { #[derive(Debug, Clone, Copy, HashStable_Generic)] pub struct OpaqueTy<'hir> { + pub hir_id: HirId, + pub def_id: LocalDefId, pub generics: &'hir Generics<'hir>, pub bounds: GenericBounds<'hir>, pub origin: OpaqueTyOrigin, @@ -2762,6 +2764,7 @@ pub struct OpaqueTy<'hir> { /// This mapping associated a captured lifetime (first parameter) with the new /// early-bound lifetime that was generated for the opaque. pub lifetime_mapping: &'hir [(&'hir Lifetime, LocalDefId)], + pub span: Span, } #[derive(Debug, Clone, Copy, HashStable_Generic)] @@ -2868,7 +2871,7 @@ pub enum TyKind<'hir> { /// possibly parameters) that are actually bound on the `impl Trait`. /// /// The last parameter specifies whether this opaque appears in a trait definition. - OpaqueDef(ItemId, &'hir [GenericArg<'hir>]), + OpaqueDef(&'hir OpaqueTy<'hir>, &'hir [GenericArg<'hir>]), /// A trait object type `Bound1 + Bound2 + Bound3` /// where `Bound` is a trait or a lifetime. TraitObject( @@ -3337,8 +3340,6 @@ impl<'hir> Item<'hir> { expect_ty_alias, (&'hir Ty<'hir>, &'hir Generics<'hir>), ItemKind::TyAlias(ty, generics), (ty, generics); - expect_opaque_ty, &OpaqueTy<'hir>, ItemKind::OpaqueTy(ty), ty; - expect_enum, (&EnumDef<'hir>, &'hir Generics<'hir>), ItemKind::Enum(def, generics), (def, generics); expect_struct, (&VariantData<'hir>, &'hir Generics<'hir>), @@ -3451,8 +3452,6 @@ pub enum ItemKind<'hir> { GlobalAsm(&'hir InlineAsm<'hir>), /// A type alias, e.g., `type Foo = Bar`. TyAlias(&'hir Ty<'hir>, &'hir Generics<'hir>), - /// An opaque `impl Trait` type alias, e.g., `type Foo = impl Bar;`. - OpaqueTy(&'hir OpaqueTy<'hir>), /// An enum definition, e.g., `enum Foo {C, D}`. Enum(EnumDef<'hir>, &'hir Generics<'hir>), /// A struct definition, e.g., `struct Foo {x: A}`. @@ -3496,7 +3495,6 @@ impl ItemKind<'_> { ItemKind::Fn(_, ref generics, _) | ItemKind::TyAlias(_, ref generics) | ItemKind::Const(_, ref generics, _) - | ItemKind::OpaqueTy(OpaqueTy { ref generics, .. }) | ItemKind::Enum(_, ref generics) | ItemKind::Struct(_, ref generics) | ItemKind::Union(_, ref generics) @@ -3519,7 +3517,6 @@ impl ItemKind<'_> { ItemKind::ForeignMod { .. } => "extern block", ItemKind::GlobalAsm(..) => "global asm item", ItemKind::TyAlias(..) => "type alias", - ItemKind::OpaqueTy(..) => "opaque type", ItemKind::Enum(..) => "enum", ItemKind::Struct(..) => "struct", ItemKind::Union(..) => "union", @@ -3806,6 +3803,7 @@ pub enum Node<'hir> { Ty(&'hir Ty<'hir>), AssocItemConstraint(&'hir AssocItemConstraint<'hir>), TraitRef(&'hir TraitRef<'hir>), + OpaqueTy(&'hir OpaqueTy<'hir>), Pat(&'hir Pat<'hir>), PatField(&'hir PatField<'hir>), Arm(&'hir Arm<'hir>), @@ -3871,6 +3869,7 @@ impl<'hir> Node<'hir> { | Node::Crate(..) | Node::Ty(..) | Node::TraitRef(..) + | Node::OpaqueTy(..) | Node::Infer(..) | Node::WhereBoundPredicate(..) | Node::ArrayLenInfer(..) @@ -3996,6 +3995,7 @@ impl<'hir> Node<'hir> { | Node::TraitItem(TraitItem { generics, .. }) | Node::ImplItem(ImplItem { generics, .. }) => Some(generics), Node::Item(item) => item.kind.generics(), + Node::OpaqueTy(opaque) => Some(opaque.generics), _ => None, } } @@ -4055,6 +4055,7 @@ impl<'hir> Node<'hir> { expect_ty, &'hir Ty<'hir>, Node::Ty(n), n; expect_assoc_item_constraint, &'hir AssocItemConstraint<'hir>, Node::AssocItemConstraint(n), n; expect_trait_ref, &'hir TraitRef<'hir>, Node::TraitRef(n), n; + expect_opaque_ty, &'hir OpaqueTy<'hir>, Node::OpaqueTy(n), n; expect_pat, &'hir Pat<'hir>, Node::Pat(n), n; expect_pat_field, &'hir PatField<'hir>, Node::PatField(n), n; expect_arm, &'hir Arm<'hir>, Node::Arm(n), n; diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index d0a8aaa85bb..58916d05865 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -111,6 +111,7 @@ impl<'a> FnKind<'a> { pub trait Map<'hir> { /// Retrieves the `Node` corresponding to `id`. fn hir_node(&self, hir_id: HirId) -> Node<'hir>; + fn hir_node_by_def_id(&self, def_id: LocalDefId) -> Node<'hir>; fn body(&self, id: BodyId) -> &'hir Body<'hir>; fn item(&self, id: ItemId) -> &'hir Item<'hir>; fn trait_item(&self, id: TraitItemId) -> &'hir TraitItem<'hir>; @@ -123,6 +124,9 @@ impl<'hir> Map<'hir> for ! { fn hir_node(&self, _: HirId) -> Node<'hir> { *self; } + fn hir_node_by_def_id(&self, _: LocalDefId) -> Node<'hir> { + *self; + } fn body(&self, _: BodyId) -> &'hir Body<'hir> { *self; } @@ -423,6 +427,9 @@ pub trait Visitor<'v>: Sized { fn visit_poly_trait_ref(&mut self, t: &'v PolyTraitRef<'v>) -> Self::Result { walk_poly_trait_ref(self, t) } + fn visit_opaque_ty(&mut self, opaque: &'v OpaqueTy<'v>) -> Self::Result { + walk_opaque_ty(self, opaque) + } fn visit_variant_data(&mut self, s: &'v VariantData<'v>) -> Self::Result { walk_struct_def(self, s) } @@ -536,11 +543,6 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) -> V:: try_visit!(visitor.visit_ty(ty)); try_visit!(visitor.visit_generics(generics)); } - ItemKind::OpaqueTy(&OpaqueTy { generics, bounds, .. }) => { - try_visit!(visitor.visit_id(item.hir_id())); - try_visit!(walk_generics(visitor, generics)); - walk_list!(visitor, visit_param_bound, bounds); - } ItemKind::Enum(ref enum_definition, ref generics) => { try_visit!(visitor.visit_generics(generics)); // `visit_enum_def()` takes care of visiting the `Item`'s `HirId`. @@ -894,8 +896,8 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty<'v>) -> V::Resul TyKind::Path(ref qpath) => { try_visit!(visitor.visit_qpath(qpath, typ.hir_id, typ.span)); } - TyKind::OpaqueDef(item_id, lifetimes) => { - try_visit!(visitor.visit_nested_item(item_id)); + TyKind::OpaqueDef(opaque, lifetimes) => { + try_visit!(visitor.visit_opaque_ty(opaque)); walk_list!(visitor, visit_generic_arg, lifetimes); } TyKind::Array(ref ty, ref length) => { @@ -1185,6 +1187,15 @@ pub fn walk_poly_trait_ref<'v, V: Visitor<'v>>( visitor.visit_trait_ref(&trait_ref.trait_ref) } +pub fn walk_opaque_ty<'v, V: Visitor<'v>>(visitor: &mut V, opaque: &'v OpaqueTy<'v>) -> V::Result { + let &OpaqueTy { hir_id, def_id: _, generics, bounds, origin: _, lifetime_mapping: _, span: _ } = + opaque; + try_visit!(visitor.visit_id(hir_id)); + try_visit!(walk_generics(visitor, generics)); + walk_list!(visitor, visit_param_bound, bounds); + V::Result::output() +} + pub fn walk_struct_def<'v, V: Visitor<'v>>( visitor: &mut V, struct_definition: &'v VariantData<'v>, diff --git a/compiler/rustc_hir/src/target.rs b/compiler/rustc_hir/src/target.rs index 155270ca6a7..6ff57396b4a 100644 --- a/compiler/rustc_hir/src/target.rs +++ b/compiler/rustc_hir/src/target.rs @@ -34,7 +34,6 @@ pub enum Target { ForeignMod, GlobalAsm, TyAlias, - OpaqueTy, Enum, Variant, Struct, @@ -79,7 +78,6 @@ impl Target { | Target::ForeignMod | Target::GlobalAsm | Target::TyAlias - | Target::OpaqueTy | Target::Enum | Target::Variant | Target::Struct @@ -114,7 +112,6 @@ impl Target { ItemKind::ForeignMod { .. } => Target::ForeignMod, ItemKind::GlobalAsm(..) => Target::GlobalAsm, ItemKind::TyAlias(..) => Target::TyAlias, - ItemKind::OpaqueTy(..) => Target::OpaqueTy, ItemKind::Enum(..) => Target::Enum, ItemKind::Struct(..) => Target::Struct, ItemKind::Union(..) => Target::Union, @@ -137,7 +134,6 @@ impl Target { DefKind::ForeignMod => Target::ForeignMod, DefKind::GlobalAsm => Target::GlobalAsm, DefKind::TyAlias => Target::TyAlias, - DefKind::OpaqueTy => Target::OpaqueTy, DefKind::Enum => Target::Enum, DefKind::Struct => Target::Struct, DefKind::Union => Target::Union, @@ -191,7 +187,6 @@ impl Target { Target::ForeignMod => "foreign module", Target::GlobalAsm => "global asm", Target::TyAlias => "type alias", - Target::OpaqueTy => "opaque type", Target::Enum => "enum", Target::Variant => "enum variant", Target::Struct => "struct", diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 785258d011c..eb62ff86c71 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -252,10 +252,7 @@ fn check_static_inhabited(tcx: TyCtxt<'_>, def_id: LocalDefId) { /// Checks that an opaque type does not contain cycles and does not use `Self` or `T::Foo` /// projections that would result in "inheriting lifetimes". fn check_opaque(tcx: TyCtxt<'_>, def_id: LocalDefId) { - let item = tcx.hir().expect_item(def_id); - let hir::ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) = item.kind else { - tcx.dcx().span_bug(item.span, "expected opaque item"); - }; + let hir::OpaqueTy { origin, .. } = tcx.hir().expect_opaque_ty(def_id); // HACK(jynelson): trying to infer the type of `impl trait` breaks documenting // `async-std` (and `pub async fn` in general). @@ -265,16 +262,16 @@ fn check_opaque(tcx: TyCtxt<'_>, def_id: LocalDefId) { return; } - let span = tcx.def_span(item.owner_id.def_id); + let span = tcx.def_span(def_id); - if tcx.type_of(item.owner_id.def_id).instantiate_identity().references_error() { + if tcx.type_of(def_id).instantiate_identity().references_error() { return; } - if check_opaque_for_cycles(tcx, item.owner_id.def_id, span).is_err() { + if check_opaque_for_cycles(tcx, def_id, span).is_err() { return; } - let _ = check_opaque_meets_bounds(tcx, item.owner_id.def_id, span, origin); + let _ = check_opaque_meets_bounds(tcx, def_id, span, origin); } /// Checks that an opaque type does not contain cycles. @@ -481,8 +478,7 @@ fn sanity_check_found_hidden_type<'tcx>( /// 2. Checking that all lifetimes that are implicitly captured are mentioned. /// 3. Asserting that all parameters mentioned in the captures list are invariant. fn check_opaque_precise_captures<'tcx>(tcx: TyCtxt<'tcx>, opaque_def_id: LocalDefId) { - let hir::OpaqueTy { bounds, .. } = - *tcx.hir_node_by_def_id(opaque_def_id).expect_item().expect_opaque_ty(); + let hir::OpaqueTy { bounds, .. } = *tcx.hir_node_by_def_id(opaque_def_id).expect_opaque_ty(); let Some(precise_capturing_args) = bounds.iter().find_map(|bound| match *bound { hir::GenericBound::Use(bounds, ..) => Some(bounds), _ => None, diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs index 35c2b7e7ce2..80334c6efe7 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs @@ -93,7 +93,7 @@ pub(super) fn check_refining_return_position_impl_trait_in_trait<'tcx>( // it's a refinement to a TAIT. if !tcx.hir().get_if_local(impl_opaque.def_id).is_some_and(|node| { matches!( - node.expect_item().expect_opaque_ty().origin, + node.expect_opaque_ty().origin, hir::OpaqueTyOrigin::AsyncFn { parent, .. } | hir::OpaqueTyOrigin::FnReturn { parent, .. } if parent == impl_m.def_id.expect_local() ) diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 93b021be245..bb517eec64d 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -260,8 +260,8 @@ fn reject_placeholder_type_signatures_in_item<'tcx>( | hir::ItemKind::Trait(_, _, generics, ..) | hir::ItemKind::Impl(hir::Impl { generics, .. }) | hir::ItemKind::Struct(_, generics) => (generics, true), - hir::ItemKind::OpaqueTy(hir::OpaqueTy { generics, .. }) - | hir::ItemKind::TyAlias(_, generics) => (generics, false), + // FIXME: how to handle opaque types since no longer items + hir::ItemKind::TyAlias(_, generics) => (generics, false), // `static`, `fn` and `const` are handled elsewhere to suggest appropriate type. _ => return, }; @@ -731,18 +731,8 @@ fn lower_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) { } } - // Don't call `type_of` on opaque types, since that depends on type - // checking function bodies. `check_item_type` ensures that it's called - // instead. - hir::ItemKind::OpaqueTy(..) => { - tcx.ensure().generics_of(def_id); - tcx.ensure().predicates_of(def_id); - tcx.ensure().explicit_item_bounds(def_id); - tcx.ensure().explicit_item_super_predicates(def_id); - tcx.ensure().item_bounds(def_id); - tcx.ensure().item_super_predicates(def_id); - } - + // FIXME: ok to ignore opaque tys in collection? + // hir::ItemKind::TyAlias(..) => { tcx.ensure().generics_of(def_id); tcx.ensure().type_of(def_id); @@ -1852,12 +1842,8 @@ fn coroutine_for_closure(tcx: TyCtxt<'_>, def_id: LocalDefId) -> DefId { } fn is_type_alias_impl_trait<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> bool { - match tcx.hir_node_by_def_id(def_id) { - Node::Item(hir::Item { kind: hir::ItemKind::OpaqueTy(opaque), .. }) => { - matches!(opaque.origin, hir::OpaqueTyOrigin::TyAlias { .. }) - } - _ => bug!("tried getting opaque_ty_origin for non-opaque: {:?}", def_id), - } + let opaque = tcx.hir().expect_opaque_ty(def_id); + matches!(opaque.origin, hir::OpaqueTyOrigin::TyAlias { .. }) } fn rendered_precise_capturing_args<'tcx>( @@ -1870,12 +1856,10 @@ fn rendered_precise_capturing_args<'tcx>( return tcx.rendered_precise_capturing_args(opaque_def_id); } - tcx.hir_node_by_def_id(def_id).expect_item().expect_opaque_ty().bounds.iter().find_map( - |bound| match bound { - hir::GenericBound::Use(args, ..) => { - Some(&*tcx.arena.alloc_from_iter(args.iter().map(|arg| arg.name()))) - } - _ => None, - }, - ) + tcx.hir_node_by_def_id(def_id).expect_opaque_ty().bounds.iter().find_map(|bound| match bound { + hir::GenericBound::Use(args, ..) => { + Some(&*tcx.arena.alloc_from_iter(args.iter().map(|arg| arg.name()))) + } + _ => None, + }) } diff --git a/compiler/rustc_hir_analysis/src/collect/dump.rs b/compiler/rustc_hir_analysis/src/collect/dump.rs index d76d9213129..8648a7d1e32 100644 --- a/compiler/rustc_hir_analysis/src/collect/dump.rs +++ b/compiler/rustc_hir_analysis/src/collect/dump.rs @@ -1,4 +1,3 @@ -use rustc_hir::def::DefKind; use rustc_hir::def_id::{CRATE_DEF_ID, LocalDefId}; use rustc_hir::intravisit; use rustc_middle::hir::nested_filter::OnlyBodies; @@ -10,12 +9,10 @@ pub(crate) fn opaque_hidden_types(tcx: TyCtxt<'_>) { return; } - for id in tcx.hir().items() { - let DefKind::OpaqueTy = tcx.def_kind(id.owner_id) else { continue }; - - let ty = tcx.type_of(id.owner_id).instantiate_identity(); - - tcx.dcx().emit_err(crate::errors::TypeOf { span: tcx.def_span(id.owner_id), ty }); + for id in tcx.hir_crate_items(()).opaques() { + let ty = tcx.type_of(id).instantiate_identity(); + let span = tcx.def_span(id); + tcx.dcx().emit_err(crate::errors::TypeOf { span, ty }); } } diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs index 8ff9640a874..14b6b17ed18 100644 --- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs @@ -24,6 +24,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { if let Some(ty::ImplTraitInTraitData::Trait { fn_def_id, opaque_def_id }) = tcx.opt_rpitit_info(def_id.to_def_id()) { + debug!("RPITIT fn_def_id={fn_def_id:?} opaque_def_id={opaque_def_id:?}"); let trait_def_id = tcx.parent(fn_def_id); let opaque_ty_generics = tcx.generics_of(opaque_def_id); let opaque_ty_parent_count = opaque_ty_generics.parent_count; @@ -207,36 +208,33 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { | Node::Expr(&hir::Expr { kind: hir::ExprKind::Closure { .. }, .. }) => { Some(tcx.typeck_root_def_id(def_id.to_def_id())) } - Node::Item(item) => match item.kind { - ItemKind::OpaqueTy(&hir::OpaqueTy { - origin: - hir::OpaqueTyOrigin::FnReturn { parent: fn_def_id, in_trait_or_impl } - | hir::OpaqueTyOrigin::AsyncFn { parent: fn_def_id, in_trait_or_impl }, - .. - }) => { - if in_trait_or_impl.is_some() { - assert_matches!(tcx.def_kind(fn_def_id), DefKind::AssocFn); - } else { - assert_matches!(tcx.def_kind(fn_def_id), DefKind::AssocFn | DefKind::Fn); - } - Some(fn_def_id.to_def_id()) + Node::OpaqueTy(&hir::OpaqueTy { + origin: + hir::OpaqueTyOrigin::FnReturn { parent: fn_def_id, in_trait_or_impl } + | hir::OpaqueTyOrigin::AsyncFn { parent: fn_def_id, in_trait_or_impl }, + .. + }) => { + if in_trait_or_impl.is_some() { + assert_matches!(tcx.def_kind(fn_def_id), DefKind::AssocFn); + } else { + assert_matches!(tcx.def_kind(fn_def_id), DefKind::AssocFn | DefKind::Fn); } - ItemKind::OpaqueTy(&hir::OpaqueTy { - origin: hir::OpaqueTyOrigin::TyAlias { parent, in_assoc_ty }, - .. - }) => { - if in_assoc_ty { - assert_matches!(tcx.def_kind(parent), DefKind::AssocTy); - } else { - assert_matches!(tcx.def_kind(parent), DefKind::TyAlias); - } - debug!("generics_of: parent of opaque ty {:?} is {:?}", def_id, parent); - // Opaque types are always nested within another item, and - // inherit the generics of the item. - Some(parent.to_def_id()) + Some(fn_def_id.to_def_id()) + } + Node::OpaqueTy(&hir::OpaqueTy { + origin: hir::OpaqueTyOrigin::TyAlias { parent, in_assoc_ty }, + .. + }) => { + if in_assoc_ty { + assert_matches!(tcx.def_kind(parent), DefKind::AssocTy); + } else { + assert_matches!(tcx.def_kind(parent), DefKind::TyAlias); } - _ => None, - }, + debug!("generics_of: parent of opaque ty {:?} is {:?}", def_id, parent); + // Opaque types are always nested within another item, and + // inherit the generics of the item. + Some(parent.to_def_id()) + } _ => None, }; @@ -272,13 +270,14 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { ItemKind::TyAlias(..) | ItemKind::Enum(..) | ItemKind::Struct(..) - | ItemKind::OpaqueTy(..) | ItemKind::Union(..) => (None, Defaults::Allowed), ItemKind::Const(..) => (None, Defaults::Deny), _ => (None, Defaults::FutureCompatDisallowed), } } + Node::OpaqueTy(..) => (None, Defaults::Allowed), + // GATs Node::TraitItem(item) if matches!(item.kind, TraitItemKind::Type(..)) => { (None, Defaults::Deny) diff --git a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs index 2418037ae96..4346504450d 100644 --- a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs +++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs @@ -335,8 +335,7 @@ pub(super) fn explicit_item_bounds_with_filter( // RPITIT's bounds are the same as opaque type bounds, but with // a projection self type. Some(ty::ImplTraitInTraitData::Trait { opaque_def_id, .. }) => { - let item = tcx.hir_node_by_def_id(opaque_def_id.expect_local()).expect_item(); - let opaque_ty = item.expect_opaque_ty(); + let opaque_ty = tcx.hir_node_by_def_id(opaque_def_id.expect_local()).expect_opaque_ty(); let item_ty = Ty::new_projection_from_args( tcx, def_id.to_def_id(), @@ -347,7 +346,7 @@ pub(super) fn explicit_item_bounds_with_filter( opaque_def_id.expect_local(), opaque_ty.bounds, item_ty, - item.span, + opaque_ty.span, filter, ); assert_only_contains_predicates_from(filter, bounds, item_ty); @@ -369,11 +368,7 @@ pub(super) fn explicit_item_bounds_with_filter( span, .. }) => associated_type_bounds(tcx, def_id, bounds, *span, filter), - hir::Node::Item(hir::Item { - kind: hir::ItemKind::OpaqueTy(hir::OpaqueTy { bounds, origin, .. }), - span, - .. - }) => match origin { + hir::Node::OpaqueTy(hir::OpaqueTy { bounds, origin, span, .. }) => match origin { // Since RPITITs are lowered as projections in `::lower_ty`, // when we're asking for the item bounds of the *opaques* in a trait's default // method signature, we need to map these projections back to opaques. @@ -412,7 +407,7 @@ pub(super) fn explicit_item_bounds_with_filter( } }, hir::Node::Item(hir::Item { kind: hir::ItemKind::TyAlias(..), .. }) => &[], - _ => bug!("item_bounds called on {:?}", def_id), + node => bug!("item_bounds called on {def_id:?} => {node:?}"), }; ty::EarlyBinder::bind(bounds) diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index 33f6623edfd..6d30f7c7b9d 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -330,7 +330,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen // Opaque types duplicate some of their generic parameters. // We create bi-directional Outlives predicates between the original // and the duplicated parameter, to ensure that they do not get out of sync. - if let Node::Item(&Item { kind: ItemKind::OpaqueTy(..), .. }) = node { + if let Node::OpaqueTy(..) = node { let opaque_ty_node = tcx.parent_hir_node(hir_id); let Node::Ty(&hir::Ty { kind: TyKind::OpaqueDef(_, lifetimes), .. }) = opaque_ty_node else { diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs index a15621bf28b..513d4e9b4a5 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -486,6 +486,31 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { } } + #[instrument(level = "debug", skip(self))] + fn visit_opaque_ty(&mut self, opaque: &'tcx rustc_hir::OpaqueTy<'tcx>) { + // We want to start our early-bound indices at the end of the parent scope, + // not including any parent `impl Trait`s. + let mut bound_vars = FxIndexMap::default(); + debug!(?opaque.generics.params); + for param in opaque.generics.params { + let (def_id, reg) = ResolvedArg::early(param); + bound_vars.insert(def_id, reg); + } + + let hir_id = self.tcx.local_def_id_to_hir_id(opaque.def_id); + let scope = Scope::Binder { + hir_id, + bound_vars, + s: self.scope, + scope_type: BinderScopeType::Normal, + where_bound_origin: None, + }; + self.with(scope, |this| { + let scope = Scope::TraitRefBoundary { s: this.scope }; + this.with(scope, |this| intravisit::walk_opaque_ty(this, opaque)) + }) + } + #[instrument(level = "debug", skip(self))] fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) { match &item.kind { @@ -513,38 +538,6 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { // These sorts of items have no lifetime parameters at all. intravisit::walk_item(self, item); } - hir::ItemKind::OpaqueTy(&hir::OpaqueTy { - origin: - hir::OpaqueTyOrigin::FnReturn { parent, .. } - | hir::OpaqueTyOrigin::AsyncFn { parent, .. } - | hir::OpaqueTyOrigin::TyAlias { parent, .. }, - generics, - .. - }) => { - // We want to start our early-bound indices at the end of the parent scope, - // not including any parent `impl Trait`s. - let mut bound_vars = FxIndexMap::default(); - debug!(?generics.params); - for param in generics.params { - let (def_id, reg) = ResolvedArg::early(param); - bound_vars.insert(def_id, reg); - } - - let scope = Scope::Root { opt_parent_item: Some(parent) }; - self.with(scope, |this| { - let scope = Scope::Binder { - hir_id: item.hir_id(), - bound_vars, - s: this.scope, - scope_type: BinderScopeType::Normal, - where_bound_origin: None, - }; - this.with(scope, |this| { - let scope = Scope::TraitRefBoundary { s: this.scope }; - this.with(scope, |this| intravisit::walk_item(this, item)) - }); - }) - } hir::ItemKind::TyAlias(_, generics) | hir::ItemKind::Const(_, generics, _) | hir::ItemKind::Enum(_, generics) @@ -689,17 +682,14 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { }; self.with(scope, |this| this.visit_ty(mt.ty)); } - hir::TyKind::OpaqueDef(item_id, lifetimes) => { + hir::TyKind::OpaqueDef(opaque_ty, lifetimes) => { + self.visit_opaque_ty(opaque_ty); + // Resolve the lifetimes in the bounds to the lifetime defs in the generics. // `fn foo<'a>() -> impl MyTrait<'a> { ... }` desugars to // `type MyAnonTy<'b> = impl MyTrait<'b>;` // ^ ^ this gets resolved in the scope of // the opaque_ty generics - let opaque_ty = self.tcx.hir().item(item_id); - match &opaque_ty.kind { - hir::ItemKind::OpaqueTy(hir::OpaqueTy { origin: _, .. }) => {} - i => bug!("`impl Trait` pointed to non-opaque type?? {:#?}", i), - }; // Resolve the lifetimes that are applied to the opaque type. // These are resolved in the current scope. @@ -722,9 +712,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { { // Opaques do not declare their own lifetimes, so if a lifetime comes from an opaque // it must be a reified late-bound lifetime from a trait goal. - hir::Node::Item(hir::Item { - kind: hir::ItemKind::OpaqueTy { .. }, .. - }) => "higher-ranked lifetime from outer `impl Trait`", + hir::Node::OpaqueTy(_) => "higher-ranked lifetime from outer `impl Trait`", // Other items are fine. hir::Node::Item(_) | hir::Node::TraitItem(_) | hir::Node::ImplItem(_) => { continue; @@ -740,8 +728,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { let (span, label) = if lifetime.ident.span == self.tcx.def_span(lifetime_def_id) { - let opaque_span = self.tcx.def_span(item_id.owner_id); - (opaque_span, Some(opaque_span)) + (opaque_ty.span, Some(opaque_ty.span)) } else { (lifetime.ident.span, None) }; diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs index 3af4d1f5eda..470bcaeded1 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs @@ -529,10 +529,6 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_ let args = ty::GenericArgs::identity_for_item(tcx, def_id); Ty::new_adt(tcx, def, args) } - ItemKind::OpaqueTy(..) => tcx.type_of_opaque(def_id).map_or_else( - |CyclePlaceholder(guar)| Ty::new_error(tcx, guar), - |ty| ty.instantiate_identity(), - ), ItemKind::Trait(..) | ItemKind::TraitAlias(..) | ItemKind::Macro(..) @@ -545,6 +541,11 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_ } }, + Node::OpaqueTy(..) => tcx.type_of_opaque(def_id).map_or_else( + |CyclePlaceholder(guar)| Ty::new_error(tcx, guar), + |ty| ty.instantiate_identity(), + ), + Node::ForeignItem(foreign_item) => match foreign_item.kind { ForeignItemKind::Fn(..) => { let args = ty::GenericArgs::identity_for_item(tcx, def_id); @@ -603,42 +604,25 @@ pub(super) fn type_of_opaque( def_id: DefId, ) -> Result>, CyclePlaceholder> { if let Some(def_id) = def_id.as_local() { - use rustc_hir::*; - - Ok(ty::EarlyBinder::bind(match tcx.hir_node_by_def_id(def_id) { - Node::Item(item) => match item.kind { - ItemKind::OpaqueTy(OpaqueTy { - origin: hir::OpaqueTyOrigin::TyAlias { in_assoc_ty: false, .. }, - .. - }) => opaque::find_opaque_ty_constraints_for_tait(tcx, def_id), - ItemKind::OpaqueTy(OpaqueTy { - origin: hir::OpaqueTyOrigin::TyAlias { in_assoc_ty: true, .. }, - .. - }) => opaque::find_opaque_ty_constraints_for_impl_trait_in_assoc_type(tcx, def_id), - // Opaque types desugared from `impl Trait`. - ItemKind::OpaqueTy(&OpaqueTy { - origin: - hir::OpaqueTyOrigin::FnReturn { parent: owner, in_trait_or_impl } - | hir::OpaqueTyOrigin::AsyncFn { parent: owner, in_trait_or_impl }, - .. - }) => { - if in_trait_or_impl == Some(hir::RpitContext::Trait) - && !tcx.defaultness(owner).has_value() - { - span_bug!( - tcx.def_span(def_id), - "tried to get type of this RPITIT with no definition" - ); - } - opaque::find_opaque_ty_constraints_for_rpit(tcx, def_id, owner) + Ok(ty::EarlyBinder::bind(match tcx.hir_node_by_def_id(def_id).expect_opaque_ty().origin { + hir::OpaqueTyOrigin::TyAlias { in_assoc_ty: false, .. } => { + opaque::find_opaque_ty_constraints_for_tait(tcx, def_id) + } + hir::OpaqueTyOrigin::TyAlias { in_assoc_ty: true, .. } => { + opaque::find_opaque_ty_constraints_for_impl_trait_in_assoc_type(tcx, def_id) + } + // Opaque types desugared from `impl Trait`. + hir::OpaqueTyOrigin::FnReturn { parent: owner, in_trait_or_impl } + | hir::OpaqueTyOrigin::AsyncFn { parent: owner, in_trait_or_impl } => { + if in_trait_or_impl == Some(hir::RpitContext::Trait) + && !tcx.defaultness(owner).has_value() + { + span_bug!( + tcx.def_span(def_id), + "tried to get type of this RPITIT with no definition" + ); } - _ => { - span_bug!(item.span, "type_of_opaque: unexpected item type: {:?}", item.kind); - } - }, - - x => { - bug!("unexpected sort of node in type_of_opaque(): {:?}", x); + opaque::find_opaque_ty_constraints_for_rpit(tcx, def_id, owner) } })) } else { 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 95f83836d75..28a1fc88741 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -2087,43 +2087,36 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let opt_self_ty = maybe_qself.as_ref().map(|qself| self.lower_ty(qself)); self.lower_path(opt_self_ty, path, hir_ty.hir_id, false) } - &hir::TyKind::OpaqueDef(item_id, lifetimes) => { - let opaque_ty = tcx.hir().item(item_id); + &hir::TyKind::OpaqueDef(opaque_ty, lifetimes) => { + let local_def_id = opaque_ty.def_id; - match opaque_ty.kind { - hir::ItemKind::OpaqueTy(&hir::OpaqueTy { origin, .. }) => { - let local_def_id = item_id.owner_id.def_id; - // If this is an RPITIT and we are using the new RPITIT lowering scheme, we - // generate the def_id of an associated type for the trait and return as - // type a projection. - match origin { - hir::OpaqueTyOrigin::FnReturn { - in_trait_or_impl: Some(hir::RpitContext::Trait), - .. - } - | hir::OpaqueTyOrigin::AsyncFn { - in_trait_or_impl: Some(hir::RpitContext::Trait), - .. - } => self.lower_opaque_ty( - tcx.associated_type_for_impl_trait_in_trait(local_def_id) - .to_def_id(), - lifetimes, - true, - ), - hir::OpaqueTyOrigin::FnReturn { - in_trait_or_impl: None | Some(hir::RpitContext::TraitImpl), - .. - } - | hir::OpaqueTyOrigin::AsyncFn { - in_trait_or_impl: None | Some(hir::RpitContext::TraitImpl), - .. - } - | hir::OpaqueTyOrigin::TyAlias { .. } => { - self.lower_opaque_ty(local_def_id.to_def_id(), lifetimes, false) - } - } + // If this is an RPITIT and we are using the new RPITIT lowering scheme, we + // generate the def_id of an associated type for the trait and return as + // type a projection. + match opaque_ty.origin { + hir::OpaqueTyOrigin::FnReturn { + in_trait_or_impl: Some(hir::RpitContext::Trait), + .. + } + | hir::OpaqueTyOrigin::AsyncFn { + in_trait_or_impl: Some(hir::RpitContext::Trait), + .. + } => self.lower_opaque_ty( + tcx.associated_type_for_impl_trait_in_trait(local_def_id).to_def_id(), + lifetimes, + true, + ), + hir::OpaqueTyOrigin::FnReturn { + in_trait_or_impl: None | Some(hir::RpitContext::TraitImpl), + .. + } + | hir::OpaqueTyOrigin::AsyncFn { + in_trait_or_impl: None | Some(hir::RpitContext::TraitImpl), + .. + } + | hir::OpaqueTyOrigin::TyAlias { .. } => { + self.lower_opaque_ty(local_def_id.to_def_id(), lifetimes, false) } - ref i => bug!("`impl Trait` pointed to non-opaque type?? {:#?}", i), } } // If we encounter a type relative path with RTN generics, then it must have @@ -2289,7 +2282,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { span_bug!( tcx.def_span(param.def_id), "only expected lifetime for opaque's own generics, got {:?}", - param.kind + param ); }; let hir::GenericArg::Lifetime(lifetime) = &lifetimes[i] else { diff --git a/compiler/rustc_hir_analysis/src/variance/dump.rs b/compiler/rustc_hir_analysis/src/variance/dump.rs index dbaf9c2c6f0..a0fdf95a831 100644 --- a/compiler/rustc_hir_analysis/src/variance/dump.rs +++ b/compiler/rustc_hir_analysis/src/variance/dump.rs @@ -1,6 +1,5 @@ use std::fmt::Write; -use rustc_hir::def::DefKind; use rustc_hir::def_id::{CRATE_DEF_ID, LocalDefId}; use rustc_middle::ty::{GenericArgs, TyCtxt}; use rustc_span::symbol::sym; @@ -24,18 +23,18 @@ fn format_variances(tcx: TyCtxt<'_>, def_id: LocalDefId) -> String { } pub(crate) fn variances(tcx: TyCtxt<'_>) { - if tcx.has_attr(CRATE_DEF_ID, sym::rustc_variance_of_opaques) { - for id in tcx.hir().items() { - let DefKind::OpaqueTy = tcx.def_kind(id.owner_id) else { continue }; + let crate_items = tcx.hir_crate_items(()); + if tcx.has_attr(CRATE_DEF_ID, sym::rustc_variance_of_opaques) { + for id in crate_items.opaques() { tcx.dcx().emit_err(crate::errors::VariancesOf { - span: tcx.def_span(id.owner_id), - variances: format_variances(tcx, id.owner_id.def_id), + span: tcx.def_span(id), + variances: format_variances(tcx, id), }); } } - for id in tcx.hir().items() { + for id in crate_items.free_items() { if !tcx.has_attr(id.owner_id, sym::rustc_variance) { continue; } diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 1c52283d537..9fe6a8ee342 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -96,6 +96,7 @@ impl<'a> State<'a> { Node::Ty(a) => self.print_type(a), Node::AssocItemConstraint(a) => self.print_assoc_item_constraint(a), Node::TraitRef(a) => self.print_trait_ref(a), + Node::OpaqueTy(o) => self.print_opaque_ty(o), Node::Pat(a) => self.print_pat(a), Node::PatField(a) => self.print_patfield(a), Node::Arm(a) => self.print_arm(a), @@ -568,11 +569,6 @@ impl<'a> State<'a> { state.print_type(ty); }); } - hir::ItemKind::OpaqueTy(opaque_ty) => { - self.print_item_type(item, opaque_ty.generics, |state| { - state.print_bounds("= impl", opaque_ty.bounds) - }); - } hir::ItemKind::Enum(ref enum_definition, params) => { self.print_enum_def(enum_definition, params, item.ident.name, item.span); } @@ -665,6 +661,15 @@ impl<'a> State<'a> { self.print_path(t.path, false); } + fn print_opaque_ty(&mut self, o: &hir::OpaqueTy<'_>) { + self.head("opaque"); + self.print_generic_params(o.generics.params); + self.print_where_clause(o.generics); + self.word("{"); + self.print_bounds("impl", o.bounds); + self.word("}"); + } + fn print_formal_generic_params(&mut self, generic_params: &[hir::GenericParam<'_>]) { if !generic_params.is_empty() { self.word("for"); diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index 487cc7e55cd..2c5f8adcb5d 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -847,11 +847,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return true; } hir::FnRetTy::Return(hir_ty) => { - if let hir::TyKind::OpaqueDef(item_id, ..) = hir_ty.kind + if let hir::TyKind::OpaqueDef(op_ty, ..) = hir_ty.kind // FIXME: account for RPITIT. - && let hir::Node::Item(hir::Item { - kind: hir::ItemKind::OpaqueTy(op_ty), .. - }) = self.tcx.hir_node(item_id.hir_id()) && let [hir::GenericBound::Trait(trait_ref, _)] = op_ty.bounds && let Some(hir::PathSegment { args: Some(generic_args), .. }) = trait_ref.trait_ref.path.segments.last() diff --git a/compiler/rustc_lint/src/async_fn_in_trait.rs b/compiler/rustc_lint/src/async_fn_in_trait.rs index d9040207300..63a8a949e96 100644 --- a/compiler/rustc_lint/src/async_fn_in_trait.rs +++ b/compiler/rustc_lint/src/async_fn_in_trait.rs @@ -104,8 +104,9 @@ impl<'tcx> LateLintPass<'tcx> for AsyncFnInTrait { return; } - let hir::FnRetTy::Return(hir::Ty { kind: hir::TyKind::OpaqueDef(def, ..), .. }) = - sig.decl.output + let hir::FnRetTy::Return(hir::Ty { + kind: hir::TyKind::OpaqueDef(opaq_def, ..), .. + }) = sig.decl.output else { // This should never happen, but let's not ICE. return; @@ -114,7 +115,7 @@ impl<'tcx> LateLintPass<'tcx> for AsyncFnInTrait { cx.tcx, sig, body, - def.owner_id.def_id, + opaq_def.def_id, " + Send", ); cx.tcx.emit_node_span_lint( diff --git a/compiler/rustc_lint/src/impl_trait_overcaptures.rs b/compiler/rustc_lint/src/impl_trait_overcaptures.rs index 5aeaad42069..d029ad93407 100644 --- a/compiler/rustc_lint/src/impl_trait_overcaptures.rs +++ b/compiler/rustc_lint/src/impl_trait_overcaptures.rs @@ -258,7 +258,7 @@ where && self.seen.insert(opaque_def_id) // If it's owned by this function && let opaque = - self.tcx.hir_node_by_def_id(opaque_def_id).expect_item().expect_opaque_ty() + self.tcx.hir_node_by_def_id(opaque_def_id).expect_opaque_ty() && let hir::OpaqueTyOrigin::FnReturn { parent, .. } = opaque.origin && parent == self.parent_def_id { diff --git a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs index 342ebfa0b06..ffbcf7f808e 100644 --- a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs +++ b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs @@ -68,8 +68,8 @@ declare_lint! { declare_lint_pass!(OpaqueHiddenInferredBound => [OPAQUE_HIDDEN_INFERRED_BOUND]); impl<'tcx> LateLintPass<'tcx> for OpaqueHiddenInferredBound { - fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) { - let hir::ItemKind::OpaqueTy(opaque) = &item.kind else { + fn check_ty(&mut self, cx: &LateContext<'tcx>, ty: &'tcx hir::Ty<'tcx>) { + let hir::TyKind::OpaqueDef(opaque, _) = &ty.kind else { return; }; @@ -84,7 +84,7 @@ impl<'tcx> LateLintPass<'tcx> for OpaqueHiddenInferredBound { return; } - let def_id = item.owner_id.def_id.to_def_id(); + let def_id = opaque.def_id.to_def_id(); let infcx = &cx.tcx.infer_ctxt().build(); // For every projection predicate in the opaque type's explicit bounds, // check that the type that we're assigning actually satisfies the bounds diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index 75611d71025..db4413149a4 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -1419,7 +1419,6 @@ impl<'tcx> LateLintPass<'tcx> for ImproperCTypesDefinitions { hir::ItemKind::Impl(..) | hir::ItemKind::TraitAlias(..) | hir::ItemKind::Trait(..) - | hir::ItemKind::OpaqueTy(..) | hir::ItemKind::GlobalAsm(..) | hir::ItemKind::ForeignMod { .. } | hir::ItemKind::Mod(..) diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index 72e6c96e6f6..8fd5ff1f369 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -732,6 +732,19 @@ impl<'hir> Map<'hir> { } } + #[track_caller] + pub fn expect_opaque_ty(self, id: LocalDefId) -> &'hir OpaqueTy<'hir> { + match self.tcx.hir_node_by_def_id(id) { + Node::OpaqueTy(opaq) => opaq, + _ => { + bug!( + "expected opaque type definition, found {}", + self.node_to_string(self.tcx.local_def_id_to_hir_id(id)) + ) + } + } + } + pub fn expect_expr(self, id: HirId) -> &'hir Expr<'hir> { match self.tcx.hir_node(id) { Node::Expr(expr) => expr, @@ -923,6 +936,7 @@ impl<'hir> Map<'hir> { Node::Ty(ty) => ty.span, Node::AssocItemConstraint(constraint) => constraint.span, Node::TraitRef(tr) => tr.path.span, + Node::OpaqueTy(op) => op.span, Node::Pat(pat) => pat.span, Node::PatField(field) => field.span, Node::Arm(arm) => arm.span, @@ -1006,6 +1020,10 @@ impl<'hir> intravisit::Map<'hir> for Map<'hir> { self.tcx.hir_node(hir_id) } + fn hir_node_by_def_id(&self, def_id: LocalDefId) -> Node<'hir> { + self.tcx.hir_node_by_def_id(def_id) + } + fn body(&self, id: BodyId) -> &'hir Body<'hir> { (*self).body(id) } @@ -1139,7 +1157,6 @@ fn hir_id_to_string(map: Map<'_>, id: HirId) -> String { ItemKind::ForeignMod { .. } => "foreign mod", ItemKind::GlobalAsm(..) => "global asm", ItemKind::TyAlias(..) => "ty", - ItemKind::OpaqueTy(..) => "opaque type", ItemKind::Enum(..) => "enum", ItemKind::Struct(..) => "struct", ItemKind::Union(..) => "union", @@ -1191,6 +1208,7 @@ fn hir_id_to_string(map: Map<'_>, id: HirId) -> String { Node::Ty(_) => node_str("type"), Node::AssocItemConstraint(_) => node_str("assoc item constraint"), Node::TraitRef(_) => node_str("trait ref"), + Node::OpaqueTy(_) => node_str("opaque type"), Node::Pat(_) => node_str("pat"), Node::PatField(_) => node_str("pattern field"), Node::Param(_) => node_str("param"), @@ -1228,6 +1246,7 @@ pub(super) fn hir_module_items(tcx: TyCtxt<'_>, module_id: LocalModDefId) -> Mod impl_items, foreign_items, body_owners, + opaques, .. } = collector; ModuleItems { @@ -1237,6 +1256,7 @@ pub(super) fn hir_module_items(tcx: TyCtxt<'_>, module_id: LocalModDefId) -> Mod impl_items: impl_items.into_boxed_slice(), foreign_items: foreign_items.into_boxed_slice(), body_owners: body_owners.into_boxed_slice(), + opaques: opaques.into_boxed_slice(), } } @@ -1256,6 +1276,7 @@ pub(crate) fn hir_crate_items(tcx: TyCtxt<'_>, _: ()) -> ModuleItems { impl_items, foreign_items, body_owners, + opaques, .. } = collector; @@ -1266,6 +1287,7 @@ pub(crate) fn hir_crate_items(tcx: TyCtxt<'_>, _: ()) -> ModuleItems { impl_items: impl_items.into_boxed_slice(), foreign_items: foreign_items.into_boxed_slice(), body_owners: body_owners.into_boxed_slice(), + opaques: opaques.into_boxed_slice(), } } @@ -1280,6 +1302,7 @@ struct ItemCollector<'tcx> { impl_items: Vec, foreign_items: Vec, body_owners: Vec, + opaques: Vec, } impl<'tcx> ItemCollector<'tcx> { @@ -1293,6 +1316,7 @@ impl<'tcx> ItemCollector<'tcx> { impl_items: Vec::default(), foreign_items: Vec::default(), body_owners: Vec::default(), + opaques: Vec::default(), } } } @@ -1338,6 +1362,11 @@ impl<'hir> Visitor<'hir> for ItemCollector<'hir> { intravisit::walk_inline_const(self, c) } + fn visit_opaque_ty(&mut self, o: &'hir OpaqueTy<'hir>) { + self.opaques.push(o.def_id); + intravisit::walk_opaque_ty(self, o) + } + fn visit_expr(&mut self, ex: &'hir Expr<'hir>) { if let ExprKind::Closure(closure) = ex.kind { self.body_owners.push(closure.def_id); diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs index 7a07ef80ded..ad0d70152e1 100644 --- a/compiler/rustc_middle/src/hir/mod.rs +++ b/compiler/rustc_middle/src/hir/mod.rs @@ -28,6 +28,7 @@ pub struct ModuleItems { trait_items: Box<[TraitItemId]>, impl_items: Box<[ImplItemId]>, foreign_items: Box<[ForeignItemId]>, + opaques: Box<[LocalDefId]>, body_owners: Box<[LocalDefId]>, } @@ -65,6 +66,10 @@ impl ModuleItems { .chain(self.foreign_items.iter().map(|id| id.owner_id)) } + pub fn opaques(&self) -> impl Iterator + '_ { + self.opaques.iter().copied() + } + pub fn definitions(&self) -> impl Iterator + '_ { self.owners().map(|id| id.def_id) } @@ -96,6 +101,13 @@ impl ModuleItems { ) -> Result<(), ErrorGuaranteed> { try_par_for_each_in(&self.foreign_items[..], |&id| f(id)) } + + pub fn par_opaques( + &self, + f: impl Fn(LocalDefId) -> Result<(), ErrorGuaranteed> + DynSend + DynSync, + ) -> Result<(), ErrorGuaranteed> { + try_par_for_each_in(&self.opaques[..], |&id| f(id)) + } } impl<'tcx> TyCtxt<'tcx> { diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 2ffb273cb6f..d6547b51186 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -56,7 +56,7 @@ use rustc_type_ir::lang_items::TraitSolverLangItem; pub use rustc_type_ir::lift::Lift; use rustc_type_ir::solve::SolverMode; use rustc_type_ir::{CollectAndApply, Interner, TypeFlags, WithCachedTypeInfo, search_graph}; -use tracing::{debug, instrument}; +use tracing::{debug, trace}; use crate::arena::Arena; use crate::dep_graph::{DepGraph, DepKindStruct}; @@ -2073,9 +2073,11 @@ impl<'tcx> TyCtxt<'tcx> { } /// Returns the origin of the opaque type `def_id`. - #[instrument(skip(self), level = "trace", ret)] + #[track_caller] pub fn opaque_type_origin(self, def_id: LocalDefId) -> hir::OpaqueTyOrigin { - self.hir().expect_item(def_id).expect_opaque_ty().origin + let origin = self.hir().expect_opaque_ty(def_id).origin; + trace!("opaque_type_origin({def_id:?}) => {origin:?}"); + origin } } @@ -3031,8 +3033,7 @@ impl<'tcx> TyCtxt<'tcx> { loop { let parent = self.local_parent(opaque_lifetime_param_def_id); - let hir::OpaqueTy { lifetime_mapping, .. } = - self.hir_node_by_def_id(parent).expect_item().expect_opaque_ty(); + let hir::OpaqueTy { lifetime_mapping, .. } = self.hir().expect_opaque_ty(parent); let Some((lifetime, _)) = lifetime_mapping .iter() diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs index d98e18c1b0c..751f0c71eb4 100644 --- a/compiler/rustc_middle/src/ty/diagnostics.rs +++ b/compiler/rustc_middle/src/ty/diagnostics.rs @@ -507,14 +507,8 @@ impl<'v> hir::intravisit::Visitor<'v> for TraitObjectVisitor<'v> { .. }, _, - ) => { - self.0.push(ty); - } - hir::TyKind::OpaqueDef(item_id, _) => { - self.0.push(ty); - let item = self.1.item(item_id); - hir::intravisit::walk_item(self, item); - } + ) + | hir::TyKind::OpaqueDef(..) => self.0.push(ty), _ => {} } hir::intravisit::walk_ty(self, ty); diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 489bd49f3e4..a55ca5a0173 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -21,6 +21,7 @@ use rustc_target::spec::abi; use rustc_type_ir::TyKind::*; use rustc_type_ir::visit::TypeVisitableExt; use rustc_type_ir::{self as ir, BoundVar, CollectAndApply, DynKind}; +use tracing::instrument; use ty::util::{AsyncDropGlueMorphology, IntTypeExt}; use super::GenericParamDefKind; @@ -500,6 +501,7 @@ impl<'tcx> Ty<'tcx> { } #[inline] + #[instrument(level = "debug", skip(tcx))] pub fn new_opaque(tcx: TyCtxt<'tcx>, def_id: DefId, args: GenericArgsRef<'tcx>) -> Ty<'tcx> { Ty::new_alias(tcx, ty::Opaque, AliasTy::new_from_args(tcx, def_id, args)) } diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index a24259a1e35..b3334bb70aa 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -814,7 +814,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | Target::Mod | Target::GlobalAsm | Target::TyAlias - | Target::OpaqueTy | Target::Enum | Target::Variant | Target::Struct @@ -1328,7 +1327,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { ) { let article = match target { Target::ExternCrate - | Target::OpaqueTy | Target::Enum | Target::Impl | Target::Expression diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index 100f3e80603..af17fbf7e4d 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -41,6 +41,7 @@ fn should_explore(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { | Node::TraitItem(..) | Node::Variant(..) | Node::AnonConst(..) + | Node::OpaqueTy(..) ) } @@ -494,6 +495,7 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { Node::ForeignItem(foreign_item) => { intravisit::walk_foreign_item(self, foreign_item); } + Node::OpaqueTy(opaq) => intravisit::walk_opaque_ty(self, opaq), _ => {} } self.repr_has_repr_simd = had_repr_simd; @@ -655,14 +657,6 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> { intravisit::walk_path(self, path); } - fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) { - if let TyKind::OpaqueDef(item_id, _) = ty.kind { - let item = self.tcx.hir().item(item_id); - intravisit::walk_item(self, item); - } - intravisit::walk_ty(self, ty); - } - fn visit_anon_const(&mut self, c: &'tcx hir::AnonConst) { // When inline const blocks are used in pattern position, paths // referenced by it should be considered as used. diff --git a/compiler/rustc_passes/src/hir_stats.rs b/compiler/rustc_passes/src/hir_stats.rs index 903fb114744..8ad14b6eb74 100644 --- a/compiler/rustc_passes/src/hir_stats.rs +++ b/compiler/rustc_passes/src/hir_stats.rs @@ -230,7 +230,6 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> { ForeignMod, GlobalAsm, TyAlias, - OpaqueTy, Enum, Struct, Union, diff --git a/compiler/rustc_passes/src/reachable.rs b/compiler/rustc_passes/src/reachable.rs index 925ee262022..056318fbcb7 100644 --- a/compiler/rustc_passes/src/reachable.rs +++ b/compiler/rustc_passes/src/reachable.rs @@ -236,7 +236,6 @@ impl<'tcx> ReachableContext<'tcx> { // worklist, as determined by the privacy pass hir::ItemKind::ExternCrate(_) | hir::ItemKind::Use(..) - | hir::ItemKind::OpaqueTy(..) | hir::ItemKind::TyAlias(..) | hir::ItemKind::Macro(..) | hir::ItemKind::Mod(..) @@ -287,7 +286,8 @@ impl<'tcx> ReachableContext<'tcx> { | Node::Field(_) | Node::Ty(_) | Node::Crate(_) - | Node::Synthetic => {} + | Node::Synthetic + | Node::OpaqueTy(..) => {} _ => { bug!( "found unexpected node kind in worklist: {} ({:?})", diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index d00e7eff752..36eada4c1d7 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -634,10 +634,8 @@ impl<'tcx> EmbargoVisitor<'tcx> { } impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> { - fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) { - if self.impl_trait_pass - && let hir::ItemKind::OpaqueTy(opaque) = item.kind - { + fn visit_opaque_ty(&mut self, opaque: &'tcx hir::OpaqueTy<'tcx>) { + if self.impl_trait_pass { let should_visit = match opaque.origin { hir::OpaqueTyOrigin::FnReturn { parent, @@ -669,14 +667,16 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> { // in the reachability pass (`middle/reachable.rs`). Types are marked as link-time // reachable if they are returned via `impl Trait`, even from private functions. let pub_ev = EffectiveVisibility::from_vis(ty::Visibility::Public); - self.reach_through_impl_trait(item.owner_id.def_id, pub_ev) - .generics() - .predicates() - .ty(); + self.reach_through_impl_trait(opaque.def_id, pub_ev).generics().predicates().ty(); return; } } + // Visit nested items. + intravisit::walk_opaque_ty(self, opaque) + } + + fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) { // Update levels of nested things and mark all items // in interfaces of reachable items as reachable. let item_ev = self.get(item.owner_id.def_id); @@ -686,7 +686,7 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> { | hir::ItemKind::ExternCrate(..) | hir::ItemKind::GlobalAsm(..) => {} // The interface is empty, and all nested items are processed by `visit_item`. - hir::ItemKind::Mod(..) | hir::ItemKind::OpaqueTy(..) => {} + hir::ItemKind::Mod(..) => {} hir::ItemKind::Macro(macro_def, _) => { if let Some(item_ev) = item_ev { self.update_reachability_from_macro(item.owner_id.def_id, macro_def, item_ev); diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs index 31256bca55e..a6ecd1cc987 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs @@ -284,14 +284,9 @@ pub fn suggest_new_region_bound( } match fn_return.kind { // FIXME(precise_captures): Suggest adding to `use<...>` list instead. - TyKind::OpaqueDef(item_id, _) => { - let item = tcx.hir().item(item_id); - let ItemKind::OpaqueTy(opaque) = &item.kind else { - return; - }; - + TyKind::OpaqueDef(opaque, _) => { // Get the identity type for this RPIT - let did = item_id.owner_id.to_def_id(); + let did = opaque.def_id.to_def_id(); let ty = Ty::new_opaque(tcx, did, ty::GenericArgs::identity_for_item(tcx, did)); if let Some(span) = opaque.bounds.iter().find_map(|arg| match arg { diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs index 7802d5bf7a6..cf0ab630f2e 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs @@ -720,7 +720,7 @@ fn foo(&self) -> Self::T { String::new() } if let ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) = *proj_ty.self_ty().kind() { let opaque_local_def_id = def_id.as_local(); let opaque_hir_ty = if let Some(opaque_local_def_id) = opaque_local_def_id { - tcx.hir().expect_item(opaque_local_def_id).expect_opaque_ty() + tcx.hir().expect_opaque_ty(opaque_local_def_id) } else { return false; }; diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs index a2d717817db..94610a9e0e6 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs @@ -842,14 +842,13 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { lifetime: Region<'tcx>, add_lt_suggs: &mut Vec<(Span, String)>, ) -> String { - struct LifetimeReplaceVisitor<'a, 'tcx> { - tcx: TyCtxt<'tcx>, + struct LifetimeReplaceVisitor<'a> { needle: hir::LifetimeName, new_lt: &'a str, add_lt_suggs: &'a mut Vec<(Span, String)>, } - impl<'hir, 'tcx> hir::intravisit::Visitor<'hir> for LifetimeReplaceVisitor<'_, 'tcx> { + impl<'hir> hir::intravisit::Visitor<'hir> for LifetimeReplaceVisitor<'_> { fn visit_lifetime(&mut self, lt: &'hir hir::Lifetime) { if lt.res == self.needle { self.add_lt_suggs.push(lt.suggestion(self.new_lt)); @@ -857,10 +856,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } fn visit_ty(&mut self, ty: &'hir hir::Ty<'hir>) { - let hir::TyKind::OpaqueDef(item_id, _) = ty.kind else { + let hir::TyKind::OpaqueDef(opaque_ty, _) = ty.kind else { return hir::intravisit::walk_ty(self, ty); }; - let opaque_ty = self.tcx.hir().item(item_id).expect_opaque_ty(); if let Some(&(_, b)) = opaque_ty.lifetime_mapping.iter().find(|&(a, _)| a.res == self.needle) { @@ -905,7 +903,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { }; let mut visitor = LifetimeReplaceVisitor { - tcx: self.tcx, needle: hir::LifetimeName::Param(lifetime_def_id), add_lt_suggs, new_lt: &new_lt, @@ -1269,7 +1266,7 @@ fn suggest_precise_capturing<'tcx>( diag: &mut Diag<'_>, ) { let hir::OpaqueTy { bounds, origin, .. } = - tcx.hir_node_by_def_id(opaque_def_id).expect_item().expect_opaque_ty(); + tcx.hir_node_by_def_id(opaque_def_id).expect_opaque_ty(); let hir::OpaqueTyOrigin::FnReturn { parent: fn_def_id, .. } = *origin else { return; diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs index 6c3f3afce11..709b6eb18e3 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs @@ -731,12 +731,12 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { let exp_local_id = exp_def_id.as_local()?; match ( - &self.tcx.hir().expect_item(last_local_id).kind, - &self.tcx.hir().expect_item(exp_local_id).kind, + &self.tcx.hir().expect_opaque_ty(last_local_id), + &self.tcx.hir().expect_opaque_ty(exp_local_id), ) { ( - hir::ItemKind::OpaqueTy(hir::OpaqueTy { bounds: last_bounds, .. }), - hir::ItemKind::OpaqueTy(hir::OpaqueTy { bounds: exp_bounds, .. }), + hir::OpaqueTy { bounds: last_bounds, .. }, + hir::OpaqueTy { bounds: exp_bounds, .. }, ) if std::iter::zip(*last_bounds, *exp_bounds).all(|(left, right)| match ( left, right, ) { diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs index 6df7fac949c..87834c329e1 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -355,12 +355,12 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { | hir::ItemKind::Fn(_, generics, _) | hir::ItemKind::TyAlias(_, generics) | hir::ItemKind::Const(_, generics, _) - | hir::ItemKind::TraitAlias(generics, _) - | hir::ItemKind::OpaqueTy(hir::OpaqueTy { generics, .. }), + | hir::ItemKind::TraitAlias(generics, _), .. }) | hir::Node::TraitItem(hir::TraitItem { generics, .. }) | hir::Node::ImplItem(hir::ImplItem { generics, .. }) + | hir::Node::OpaqueTy(hir::OpaqueTy { generics, .. }) if param_ty => { // We skip the 0'th arg (self) because we do not want @@ -421,10 +421,12 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { | hir::ItemKind::Fn(_, generics, _) | hir::ItemKind::TyAlias(_, generics) | hir::ItemKind::Const(_, generics, _) - | hir::ItemKind::TraitAlias(generics, _) - | hir::ItemKind::OpaqueTy(hir::OpaqueTy { generics, .. }), + | hir::ItemKind::TraitAlias(generics, _), .. - }) if !param_ty => { + }) + | hir::Node::OpaqueTy(hir::OpaqueTy { generics, .. }) + if !param_ty => + { // Missing generic type parameter bound. if suggest_arbitrary_trait_bound( self.tcx, @@ -4542,7 +4544,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { // ... whose signature is `async` (i.e. this is an AFIT) let (sig, body) = item.expect_fn(); - let hir::FnRetTy::Return(hir::Ty { kind: hir::TyKind::OpaqueDef(def, ..), .. }) = + let hir::FnRetTy::Return(hir::Ty { kind: hir::TyKind::OpaqueDef(opaq_def, ..), .. }) = sig.decl.output else { // This should never happen, but let's not ICE. @@ -4551,7 +4553,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { // Check that this is *not* a nested `impl Future` RPIT in an async fn // (i.e. `async fn foo() -> impl Future`) - if def.owner_id.to_def_id() != opaque_def_id { + if opaq_def.def_id.to_def_id() != opaque_def_id { return; } @@ -5159,7 +5161,7 @@ pub fn suggest_desugaring_async_fn_to_impl_future_in_trait<'tcx>( }; let async_span = tcx.sess.source_map().span_extend_while_whitespace(async_span); - let future = tcx.hir_node_by_def_id(opaque_def_id).expect_item().expect_opaque_ty(); + let future = tcx.hir_node_by_def_id(opaque_def_id).expect_opaque_ty(); let [hir::GenericBound::Trait(trait_ref, _)] = future.bounds else { // `async fn` should always lower to a single bound... but don't ICE. return None; diff --git a/compiler/rustc_ty_utils/src/assoc.rs b/compiler/rustc_ty_utils/src/assoc.rs index e41f2c8ce48..a057caa9329 100644 --- a/compiler/rustc_ty_utils/src/assoc.rs +++ b/compiler/rustc_ty_utils/src/assoc.rs @@ -316,19 +316,16 @@ fn associated_types_for_impl_traits_in_associated_fn( match tcx.def_kind(parent_def_id) { DefKind::Trait => { - struct RPITVisitor<'tcx> { + struct RPITVisitor { rpits: FxIndexSet, - tcx: TyCtxt<'tcx>, } - impl<'tcx> Visitor<'tcx> for RPITVisitor<'tcx> { + impl<'tcx> Visitor<'tcx> for RPITVisitor { fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) { - if let hir::TyKind::OpaqueDef(item_id, _) = ty.kind - && self.rpits.insert(item_id.owner_id.def_id) + if let hir::TyKind::OpaqueDef(opaq, _) = ty.kind + && self.rpits.insert(opaq.def_id) { - let opaque_item = - self.tcx.hir().expect_item(item_id.owner_id.def_id).expect_opaque_ty(); - for bound in opaque_item.bounds { + for bound in opaq.bounds { intravisit::walk_param_bound(self, bound); } } @@ -336,7 +333,7 @@ fn associated_types_for_impl_traits_in_associated_fn( } } - let mut visitor = RPITVisitor { tcx, rpits: FxIndexSet::default() }; + let mut visitor = RPITVisitor { rpits: FxIndexSet::default() }; if let Some(output) = tcx.hir().get_fn_output(fn_def_id) { visitor.visit_fn_ret_ty(output); diff --git a/compiler/rustc_ty_utils/src/opaque_types.rs b/compiler/rustc_ty_utils/src/opaque_types.rs index 7c4b4887b2d..5e2232ff47d 100644 --- a/compiler/rustc_ty_utils/src/opaque_types.rs +++ b/compiler/rustc_ty_utils/src/opaque_types.rs @@ -132,6 +132,7 @@ impl<'tcx> OpaqueTypeCollector<'tcx> { TaitInBodyFinder { collector: self }.visit_expr(body); } + #[instrument(level = "debug", skip(self))] fn visit_opaque_ty(&mut self, alias_ty: ty::AliasTy<'tcx>) { if !self.seen.insert(alias_ty.def_id.expect_local()) { return; diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index b79458eaa78..fa73733360c 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1828,13 +1828,8 @@ pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> T Array(Box::new(clean_ty(ty, cx)), length.into()) } TyKind::Tup(tys) => Tuple(tys.iter().map(|ty| clean_ty(ty, cx)).collect()), - TyKind::OpaqueDef(item_id, _) => { - let item = cx.tcx.hir().item(item_id); - if let hir::ItemKind::OpaqueTy(ty) = item.kind { - ImplTrait(ty.bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect()) - } else { - unreachable!() - } + TyKind::OpaqueDef(ty, _) => { + ImplTrait(ty.bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect()) } TyKind::Path(_) => clean_qpath(ty, cx), TyKind::TraitObject(bounds, lifetime, _) => { @@ -2736,9 +2731,6 @@ fn clean_maybe_renamed_item<'tcx>( type_: clean_ty(ty, cx), kind: ConstantKind::Local { body: body_id, def_id }, })), - // clean_ty changes types which reference an OpaqueTy item to instead be - // an ImplTrait, so it's ok to return nothing here. - ItemKind::OpaqueTy(_) => return vec![], ItemKind::TyAlias(hir_ty, generics) => { *cx.current_type_aliases.entry(def_id).or_insert(0) += 1; let rustdoc_ty = clean_ty(hir_ty, cx); diff --git a/src/librustdoc/html/render/span_map.rs b/src/librustdoc/html/render/span_map.rs index 2143f1ff236..7e1ea5cde83 100644 --- a/src/librustdoc/html/render/span_map.rs +++ b/src/librustdoc/html/render/span_map.rs @@ -243,7 +243,6 @@ impl<'tcx> Visitor<'tcx> for SpanMapVisitor<'tcx> { | ItemKind::ExternCrate(_) | ItemKind::ForeignMod { .. } | ItemKind::GlobalAsm(_) - | ItemKind::OpaqueTy(_) // We already have "visit_mod" above so no need to check it here. | ItemKind::Mod(_) => {} } diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index 6defe91d383..f789aca7378 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -505,21 +505,11 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { | hir::ItemKind::Struct(..) | hir::ItemKind::Union(..) | hir::ItemKind::TyAlias(..) - | hir::ItemKind::OpaqueTy(hir::OpaqueTy { - origin: hir::OpaqueTyOrigin::TyAlias { .. }, - .. - }) | hir::ItemKind::Static(..) | hir::ItemKind::Trait(..) | hir::ItemKind::TraitAlias(..) => { self.add_to_current_mod(item, renamed, import_id); } - hir::ItemKind::OpaqueTy(hir::OpaqueTy { - origin: hir::OpaqueTyOrigin::AsyncFn { .. } | hir::OpaqueTyOrigin::FnReturn { .. }, - .. - }) => { - // return-position impl traits are never nameable, and should never be documented. - } hir::ItemKind::Const(..) => { // Underscore constants do not correspond to a nameable item and // so are never useful in documentation. diff --git a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs index 9143d292f67..b18997e6ee4 100644 --- a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs +++ b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs @@ -220,7 +220,7 @@ fn item_search_pat(item: &Item<'_>) -> (Pat, Pat) { ItemKind::Const(..) => (Pat::Str("const"), Pat::Str(";")), ItemKind::Fn(sig, ..) => (fn_header_search_pat(sig.header), Pat::Str("")), ItemKind::ForeignMod { .. } => (Pat::Str("extern"), Pat::Str("}")), - ItemKind::TyAlias(..) | ItemKind::OpaqueTy(_) => (Pat::Str("type"), Pat::Str(";")), + ItemKind::TyAlias(..) => (Pat::Str("type"), Pat::Str(";")), ItemKind::Enum(..) => (Pat::Str("enum"), Pat::Str("}")), ItemKind::Struct(VariantData::Struct { .. }, _) => (Pat::Str("struct"), Pat::Str("}")), ItemKind::Struct(..) => (Pat::Str("struct"), Pat::Str(";")), From 68f7ed4495ac5b000a5dc17fc0fd8d8760e68727 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sun, 18 Aug 2024 14:33:03 +0000 Subject: [PATCH 573/683] WfCheck opaques. --- .../rustc_hir_analysis/src/check/wfcheck.rs | 30 +++++++++++-------- compiler/rustc_hir_analysis/src/collect.rs | 13 ++++++++ compiler/rustc_middle/src/query/mod.rs | 2 +- 3 files changed, 32 insertions(+), 13 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 02d23b95d46..3a9d2640eee 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -185,15 +185,16 @@ where } } -fn check_well_formed(tcx: TyCtxt<'_>, def_id: hir::OwnerId) -> Result<(), ErrorGuaranteed> { - let node = tcx.hir_owner_node(def_id); +fn check_well_formed(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(), ErrorGuaranteed> { + let node = tcx.hir_node_by_def_id(def_id); let mut res = match node { - hir::OwnerNode::Crate(_) => bug!("check_well_formed cannot be applied to the crate root"), - hir::OwnerNode::Item(item) => check_item(tcx, item), - hir::OwnerNode::TraitItem(item) => check_trait_item(tcx, item), - hir::OwnerNode::ImplItem(item) => check_impl_item(tcx, item), - hir::OwnerNode::ForeignItem(item) => check_foreign_item(tcx, item), - hir::OwnerNode::Synthetic => unreachable!(), + hir::Node::Crate(_) => bug!("check_well_formed cannot be applied to the crate root"), + hir::Node::Item(item) => check_item(tcx, item), + hir::Node::TraitItem(item) => check_trait_item(tcx, item), + hir::Node::ImplItem(item) => check_impl_item(tcx, item), + hir::Node::ForeignItem(item) => check_foreign_item(tcx, item), + hir::Node::OpaqueTy(_) => Ok(crate::check::check::check_item_type(tcx, def_id)), + _ => unreachable!(), }; if let Some(generics) = node.generics() { @@ -201,6 +202,7 @@ fn check_well_formed(tcx: TyCtxt<'_>, def_id: hir::OwnerId) -> Result<(), ErrorG res = res.and(check_param_wf(tcx, param)); } } + res } @@ -2172,10 +2174,14 @@ impl<'tcx> WfCheckingCtxt<'_, 'tcx> { fn check_mod_type_wf(tcx: TyCtxt<'_>, module: LocalModDefId) -> Result<(), ErrorGuaranteed> { let items = tcx.hir_module_items(module); - let mut res = items.par_items(|item| tcx.ensure().check_well_formed(item.owner_id)); - res = res.and(items.par_impl_items(|item| tcx.ensure().check_well_formed(item.owner_id))); - res = res.and(items.par_trait_items(|item| tcx.ensure().check_well_formed(item.owner_id))); - res = res.and(items.par_foreign_items(|item| tcx.ensure().check_well_formed(item.owner_id))); + let mut res = items.par_items(|item| tcx.ensure().check_well_formed(item.owner_id.def_id)); + res = + res.and(items.par_impl_items(|item| tcx.ensure().check_well_formed(item.owner_id.def_id))); + res = + res.and(items.par_trait_items(|item| tcx.ensure().check_well_formed(item.owner_id.def_id))); + res = res + .and(items.par_foreign_items(|item| tcx.ensure().check_well_formed(item.owner_id.def_id))); + res = res.and(items.par_opaques(|item| tcx.ensure().check_well_formed(item))); if module == LocalModDefId::CRATE_DEF_ID { super::entry::check_for_entry_fn(tcx); } diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index bb517eec64d..02ad5355d25 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -328,6 +328,19 @@ impl<'tcx> Visitor<'tcx> for CollectItemTypesVisitor<'tcx> { intravisit::walk_expr(self, expr); } + /// Don't call `type_of` on opaque types, since that depends on type checking function bodies. + /// `check_item_type` ensures that it's called instead. + fn visit_opaque_ty(&mut self, opaque: &'tcx hir::OpaqueTy<'tcx>) { + let def_id = opaque.def_id; + self.tcx.ensure().generics_of(def_id); + self.tcx.ensure().predicates_of(def_id); + self.tcx.ensure().explicit_item_bounds(def_id); + self.tcx.ensure().explicit_item_super_predicates(def_id); + self.tcx.ensure().item_bounds(def_id); + self.tcx.ensure().item_super_predicates(def_id); + intravisit::walk_opaque_ty(self, opaque); + } + fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem<'tcx>) { lower_trait_item(self.tcx, trait_item.trait_item_id()); intravisit::walk_trait_item(self, trait_item); diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 1f0aab6d6b3..bd6a7578a68 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1552,7 +1552,7 @@ rustc_queries! { feedable } - query check_well_formed(key: hir::OwnerId) -> Result<(), ErrorGuaranteed> { + query check_well_formed(key: LocalDefId) -> Result<(), ErrorGuaranteed> { desc { |tcx| "checking that `{}` is well-formed", tcx.def_path_str(key) } ensure_forwards_result_if_red } From e740c7b6241f5396db081d34a33894fb8bcfbffe Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sun, 18 Aug 2024 15:25:42 +0000 Subject: [PATCH 574/683] Visit opaques for visibilities. --- compiler/rustc_privacy/src/lib.rs | 98 +++++++++++++++---------------- 1 file changed, 47 insertions(+), 51 deletions(-) diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 36eada4c1d7..f67c4cb922c 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -402,8 +402,6 @@ struct EmbargoVisitor<'tcx> { /// n::p::f() /// } macro_reachable: FxHashSet<(LocalModDefId, LocalModDefId)>, - /// Preliminary pass for marking all underlying types of `impl Trait`s as reachable. - impl_trait_pass: bool, /// Has something changed in the level map? changed: bool, } @@ -634,48 +632,6 @@ impl<'tcx> EmbargoVisitor<'tcx> { } impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> { - fn visit_opaque_ty(&mut self, opaque: &'tcx hir::OpaqueTy<'tcx>) { - if self.impl_trait_pass { - let should_visit = match opaque.origin { - hir::OpaqueTyOrigin::FnReturn { - parent, - in_trait_or_impl: Some(hir::RpitContext::Trait), - } - | hir::OpaqueTyOrigin::AsyncFn { - parent, - in_trait_or_impl: Some(hir::RpitContext::Trait), - } => match self.tcx.hir_node_by_def_id(parent).expect_trait_item().expect_fn().1 { - hir::TraitFn::Required(_) => false, - hir::TraitFn::Provided(..) => true, - }, - - // Always visit RPITs in functions that have definitions, - // and all TAITs. - hir::OpaqueTyOrigin::FnReturn { - in_trait_or_impl: None | Some(hir::RpitContext::TraitImpl), - .. - } - | hir::OpaqueTyOrigin::AsyncFn { - in_trait_or_impl: None | Some(hir::RpitContext::TraitImpl), - .. - } - | hir::OpaqueTyOrigin::TyAlias { .. } => true, - }; - - if should_visit { - // FIXME: This is some serious pessimization intended to workaround deficiencies - // in the reachability pass (`middle/reachable.rs`). Types are marked as link-time - // reachable if they are returned via `impl Trait`, even from private functions. - let pub_ev = EffectiveVisibility::from_vis(ty::Visibility::Public); - self.reach_through_impl_trait(opaque.def_id, pub_ev).generics().predicates().ty(); - return; - } - } - - // Visit nested items. - intravisit::walk_opaque_ty(self, opaque) - } - fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) { // Update levels of nested things and mark all items // in interfaces of reachable items as reachable. @@ -1752,19 +1708,59 @@ fn effective_visibilities(tcx: TyCtxt<'_>, (): ()) -> &EffectiveVisibilities { tcx, effective_visibilities: tcx.resolutions(()).effective_visibilities.clone(), macro_reachable: Default::default(), - // HACK(jynelson): trying to infer the type of `impl Trait` breaks `async-std` (and - // `pub async fn` in general). Since rustdoc never needs to do codegen and doesn't - // care about link-time reachability, keep them unreachable (issue #75100). - impl_trait_pass: !tcx.sess.opts.actually_rustdoc, changed: false, }; visitor.effective_visibilities.check_invariants(tcx); - if visitor.impl_trait_pass { + + // HACK(jynelson): trying to infer the type of `impl Trait` breaks `async-std` (and + // `pub async fn` in general). Since rustdoc never needs to do codegen and doesn't + // care about link-time reachability, keep them unreachable (issue #75100). + let impl_trait_pass = !tcx.sess.opts.actually_rustdoc; + if impl_trait_pass { // Underlying types of `impl Trait`s are marked as reachable unconditionally, // so this pass doesn't need to be a part of the fixed point iteration below. - tcx.hir().visit_all_item_likes_in_crate(&mut visitor); - visitor.impl_trait_pass = false; + let krate = tcx.hir_crate_items(()); + for id in krate.opaques() { + let opaque = tcx.hir_node_by_def_id(id).expect_opaque_ty(); + let should_visit = match opaque.origin { + hir::OpaqueTyOrigin::FnReturn { + parent, + in_trait_or_impl: Some(hir::RpitContext::Trait), + } + | hir::OpaqueTyOrigin::AsyncFn { + parent, + in_trait_or_impl: Some(hir::RpitContext::Trait), + } => match tcx.hir_node_by_def_id(parent).expect_trait_item().expect_fn().1 { + hir::TraitFn::Required(_) => false, + hir::TraitFn::Provided(..) => true, + }, + + // Always visit RPITs in functions that have definitions, + // and all TAITs. + hir::OpaqueTyOrigin::FnReturn { + in_trait_or_impl: None | Some(hir::RpitContext::TraitImpl), + .. + } + | hir::OpaqueTyOrigin::AsyncFn { + in_trait_or_impl: None | Some(hir::RpitContext::TraitImpl), + .. + } + | hir::OpaqueTyOrigin::TyAlias { .. } => true, + }; + if should_visit { + // FIXME: This is some serious pessimization intended to workaround deficiencies + // in the reachability pass (`middle/reachable.rs`). Types are marked as link-time + // reachable if they are returned via `impl Trait`, even from private functions. + let pub_ev = EffectiveVisibility::from_vis(ty::Visibility::Public); + visitor + .reach_through_impl_trait(opaque.def_id, pub_ev) + .generics() + .predicates() + .ty(); + } + } + visitor.changed = false; } From d9f15faf3a7ceebca239f511d5f06ada5a87b281 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Thu, 22 Aug 2024 00:55:09 +0000 Subject: [PATCH 575/683] Bless ui tests. --- .../associated-type-bounds/duplicate.stderr | 66 +++++----- .../async-await/async-fn/edition-2015.stderr | 20 +-- .../inference_var_self_argument.stderr | 18 +-- tests/ui/async-await/issue-66312.stderr | 12 +- tests/ui/const-generics/opaque_types.stderr | 16 +-- tests/ui/delegation/unsupported.stderr | 32 ++--- ...ature-gate-impl_trait_in_assoc_type.stderr | 16 +-- .../impl-fn-predefined-lifetimes.stderr | 5 +- .../ui/impl-trait/issues/issue-78722-2.stderr | 12 +- ...s-impl-trait-declaration-too-subtle.stderr | 44 +++---- tests/ui/impl-trait/where-allowed.stderr | 114 +++++++++--------- tests/ui/privacy/private-type-in-interface.rs | 2 - .../privacy/private-type-in-interface.stderr | 16 +-- .../const-impl-trait.stderr | 64 +++++----- tests/ui/self/arbitrary-self-opaque.stderr | 18 +-- ...f_types_pin_lifetime_mismatch-async.stderr | 12 +- tests/ui/self/elision/lt-ref-self-async.fixed | 12 +- .../ui/self/elision/lt-ref-self-async.stderr | 24 ++-- tests/ui/self/elision/ref-assoc-async.stderr | 20 +-- .../ui/self/elision/ref-mut-self-async.stderr | 24 ++-- .../self/elision/ref-mut-struct-async.stderr | 20 +-- tests/ui/self/elision/ref-self-async.stderr | 28 ++--- tests/ui/self/elision/ref-struct-async.stderr | 20 +-- .../const_generic_type.no_infer.stderr | 16 +-- .../constrain_inputs.stderr | 26 ++-- .../generic_underconstrained.stderr | 32 ++--- .../generic_underconstrained2.stderr | 64 +++++----- ...iled-to-resolve-instance-for-110696.stderr | 12 +- .../in-where-clause.stderr | 50 ++++---- .../ui/type-alias-impl-trait/issue-53092-2.rs | 9 +- .../issue-53092-2.stderr | 70 +++-------- .../issue-84660-unsoundness.current.stderr | 18 +-- .../issue-84660-unsoundness.next.stderr | 18 +-- .../nested-in-anon-const.stderr | 16 +-- ...alias-impl-trait-with-cycle-error-4.stderr | 14 +-- .../ui/typeck/typeck_type_placeholder_item.rs | 4 +- .../typeck_type_placeholder_item.stderr | 91 +++++++------- 37 files changed, 495 insertions(+), 560 deletions(-) diff --git a/tests/ui/associated-type-bounds/duplicate.stderr b/tests/ui/associated-type-bounds/duplicate.stderr index cf4809991c3..0dabcbdce1b 100644 --- a/tests/ui/associated-type-bounds/duplicate.stderr +++ b/tests/ui/associated-type-bounds/duplicate.stderr @@ -208,17 +208,6 @@ LL | fn FRPIT1() -> impl Iterator { | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error[E0282]: type annotations needed - --> $DIR/duplicate.rs:136:5 - | -LL | iter::empty() - | ^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `empty` - | -help: consider specifying the generic argument - | -LL | iter::empty::() - | +++++ - error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified --> $DIR/duplicate.rs:139:42 | @@ -237,17 +226,6 @@ LL | fn FRPIT2() -> impl Iterator { | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error[E0282]: type annotations needed - --> $DIR/duplicate.rs:142:5 - | -LL | iter::empty() - | ^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `empty` - | -help: consider specifying the generic argument - | -LL | iter::empty::() - | +++++ - error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified --> $DIR/duplicate.rs:145:45 | @@ -266,17 +244,6 @@ LL | fn FRPIT3() -> impl Iterator { | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error[E0282]: type annotations needed - --> $DIR/duplicate.rs:148:5 - | -LL | iter::empty() - | ^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `empty` - | -help: consider specifying the generic argument - | -LL | iter::empty::() - | +++++ - error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified --> $DIR/duplicate.rs:151:40 | @@ -697,6 +664,39 @@ LL | type A: Iterator; | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +error[E0282]: type annotations needed + --> $DIR/duplicate.rs:136:5 + | +LL | iter::empty() + | ^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `empty` + | +help: consider specifying the generic argument + | +LL | iter::empty::() + | +++++ + +error[E0282]: type annotations needed + --> $DIR/duplicate.rs:142:5 + | +LL | iter::empty() + | ^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `empty` + | +help: consider specifying the generic argument + | +LL | iter::empty::() + | +++++ + +error[E0282]: type annotations needed + --> $DIR/duplicate.rs:148:5 + | +LL | iter::empty() + | ^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `empty` + | +help: consider specifying the generic argument + | +LL | iter::empty::() + | +++++ + error: aborting due to 81 previous errors Some errors have detailed explanations: E0282, E0719. diff --git a/tests/ui/async-await/async-fn/edition-2015.stderr b/tests/ui/async-await/async-fn/edition-2015.stderr index 23ffee0d0a6..358bb3e112e 100644 --- a/tests/ui/async-await/async-fn/edition-2015.stderr +++ b/tests/ui/async-await/async-fn/edition-2015.stderr @@ -38,16 +38,6 @@ LL | fn foo(x: impl async Fn()) -> impl async Fn() { x } = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date = help: to use an async block, remove the `||`: `async {` -error[E0658]: use of unstable library feature 'async_closure' - --> $DIR/edition-2015.rs:1:22 - | -LL | fn foo(x: impl async Fn()) -> impl async Fn() { x } - | ^^^^ - | - = note: see issue #62290 for more information - = help: add `#![feature(async_closure)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - error[E0658]: use of unstable library feature 'async_closure' --> $DIR/edition-2015.rs:1:42 | @@ -58,6 +48,16 @@ LL | fn foo(x: impl async Fn()) -> impl async Fn() { x } = help: add `#![feature(async_closure)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date +error[E0658]: use of unstable library feature 'async_closure' + --> $DIR/edition-2015.rs:1:22 + | +LL | fn foo(x: impl async Fn()) -> impl async Fn() { x } + | ^^^^ + | + = note: see issue #62290 for more information + = help: add `#![feature(async_closure)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + error: aborting due to 6 previous errors For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/async-await/inference_var_self_argument.stderr b/tests/ui/async-await/inference_var_self_argument.stderr index 7bfa9be66dd..7b7b3dbc757 100644 --- a/tests/ui/async-await/inference_var_self_argument.stderr +++ b/tests/ui/async-await/inference_var_self_argument.stderr @@ -1,3 +1,12 @@ +error[E0307]: invalid `self` parameter type: `&dyn Foo` + --> $DIR/inference_var_self_argument.rs:5:24 + | +LL | async fn foo(self: &dyn Foo) { + | ^^^^^^^^ + | + = note: type of `self` must be `Self` or a type that dereferences to it + = help: consider changing to `self`, `&self`, `&mut self`, `self: Box`, `self: Rc`, `self: Arc`, or `self: Pin