diff options
383 files changed, 7044 insertions, 3156 deletions
diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs index b40066d05d3..d20f19e60e8 100644 --- a/.git-blame-ignore-revs +++ b/.git-blame-ignore-revs @@ -6,3 +6,7 @@ a06baa56b95674fc626b3c3fd680d6a65357fe60 971c549ca334b7b7406e61e958efcca9c4152822 # refactor infcx building 283abbf0e7d20176f76006825b5c52e9a4234e4c +# format libstd/sys +c34fbfaad38cf5829ef5cfe780dc9d58480adeaa +# move tests +cf2dff2b1e3fa55fa5415d524200070d0d7aacfe diff --git a/Cargo.lock b/Cargo.lock index 4bea3af7f3b..65436e2bac3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3013,9 +3013,9 @@ dependencies = [ [[package]] name = "pest" -version = "2.3.0" +version = "2.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b0560d531d1febc25a3c9398a62a71256c0178f2e3443baedd9ad4bb8c9deb4" +checksum = "0f6e86fb9e7026527a0d46bc308b841d73170ef8f443e1807f6ef88526a816d4" dependencies = [ "thiserror", "ucd-trie", @@ -3023,9 +3023,9 @@ dependencies = [ [[package]] name = "pest_derive" -version = "2.3.0" +version = "2.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "905708f7f674518498c1f8d644481440f476d39ca6ecae83319bba7c6c12da91" +checksum = "96504449aa860c8dcde14f9fba5c58dc6658688ca1fe363589d6327b8662c603" dependencies = [ "pest", "pest_generator", @@ -3033,9 +3033,9 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.3.0" +version = "2.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5803d8284a629cc999094ecd630f55e91b561a1d1ba75e233b00ae13b91a69ad" +checksum = "798e0220d1111ae63d66cb66a5dcb3fc2d986d520b98e49e1852bfdb11d7c5e7" dependencies = [ "pest", "pest_meta", @@ -3046,13 +3046,13 @@ dependencies = [ [[package]] name = "pest_meta" -version = "2.3.0" +version = "2.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1538eb784f07615c6d9a8ab061089c6c54a344c5b4301db51990ca1c241e8c04" +checksum = "984298b75898e30a843e278a9f2452c31e349a073a0ce6fd950a12a74464e065" dependencies = [ "once_cell", "pest", - "sha-1", + "sha1", ] [[package]] @@ -4273,6 +4273,7 @@ version = "0.0.0" dependencies = [ "rustc_span", "tracing", + "tracing-core", "tracing-subscriber", "tracing-tree", ] @@ -4683,7 +4684,7 @@ dependencies = [ "rustc_macros", "rustc_serialize", "scoped-tls", - "sha-1", + "sha1", "sha2", "tracing", "unicode-width", @@ -5093,17 +5094,6 @@ dependencies = [ ] [[package]] -name = "sha-1" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "028f48d513f9678cda28f6e4064755b3fbb2af6acd672f2c209b62323f7aea0f" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest", -] - -[[package]] name = "sha1" version = "0.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -5528,18 +5518,18 @@ checksum = "ceb05e71730d396f960f8f3901cdb41be2d339b303e9d7d3a07c5ff0536e671b" [[package]] name = "thiserror" -version = "1.0.33" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d0a539a918745651435ac7db7a18761589a94cd7e94cd56999f828bf73c8a57" +checksum = "6a9cd18aa97d5c45c6603caea1da6628790b37f7a34b6ca89522331c5180fed0" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.33" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c251e90f708e16c49a16f4917dc2131e75222b72edfa9cb7f7c58ae56aae0c09" +checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f" dependencies = [ "proc-macro2", "quote", @@ -5820,9 +5810,9 @@ dependencies = [ [[package]] name = "ucd-trie" -version = "0.1.3" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c" +checksum = "9e79c4d996edb816c91e4308506774452e55e95c3c9de07b6729e17e15a5ef81" [[package]] name = "ui_test" diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index e656fb3740b..7de594719dd 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -1307,6 +1307,7 @@ impl Expr { pub struct Closure { pub binder: ClosureBinder, pub capture_clause: CaptureBy, + pub constness: Const, pub asyncness: Async, pub movability: Movability, pub fn_decl: P<FnDecl>, diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index c572171e8f4..77f342d1eb3 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -1362,6 +1362,7 @@ pub fn noop_visit_expr<T: MutVisitor>( ExprKind::Closure(box Closure { binder, capture_clause: _, + constness, asyncness, movability: _, fn_decl, @@ -1370,6 +1371,7 @@ pub fn noop_visit_expr<T: MutVisitor>( fn_arg_span: _, }) => { vis.visit_closure_binder(binder); + visit_constness(constness, vis); vis.visit_asyncness(asyncness); vis.visit_fn_decl(fn_decl); vis.visit_expr(body); diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index df7145a722a..e8823eff83a 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -836,6 +836,7 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) { binder, capture_clause: _, asyncness: _, + constness: _, movability: _, fn_decl, body, diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 14f082be9ba..c3611b2f522 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -209,6 +209,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ExprKind::Closure(box Closure { binder, capture_clause, + constness, asyncness, movability, fn_decl, @@ -233,6 +234,7 @@ impl<'hir> LoweringContext<'_, 'hir> { binder, *capture_clause, e.id, + *constness, *movability, fn_decl, body, @@ -651,6 +653,7 @@ impl<'hir> LoweringContext<'_, 'hir> { fn_decl_span: self.lower_span(span), fn_arg_span: None, movability: Some(hir::Movability::Static), + constness: hir::Constness::NotConst, }); hir::ExprKind::Closure(c) @@ -890,6 +893,7 @@ impl<'hir> LoweringContext<'_, 'hir> { binder: &ClosureBinder, capture_clause: CaptureBy, closure_id: NodeId, + constness: Const, movability: Movability, decl: &FnDecl, body: &Expr, @@ -927,6 +931,7 @@ impl<'hir> LoweringContext<'_, 'hir> { fn_decl_span: self.lower_span(fn_decl_span), fn_arg_span: Some(self.lower_span(fn_arg_span)), movability: generator_option, + constness: self.lower_constness(constness), }); hir::ExprKind::Closure(c) @@ -1041,6 +1046,7 @@ impl<'hir> LoweringContext<'_, 'hir> { fn_decl_span: self.lower_span(fn_decl_span), fn_arg_span: Some(self.lower_span(fn_arg_span)), movability: None, + constness: hir::Constness::NotConst, }); hir::ExprKind::Closure(c) } diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index ea30bed5ace..065779d0670 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -1239,7 +1239,7 @@ impl<'hir> LoweringContext<'_, 'hir> { } } - fn lower_constness(&mut self, c: Const) -> hir::Constness { + pub(super) fn lower_constness(&mut self, c: Const) -> hir::Constness { match c { Const::Yes(_) => hir::Constness::Const, Const::No => hir::Constness::NotConst, diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 2e135aafb1e..41d4a5679f1 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -416,8 +416,7 @@ fn compute_hir_hash( pub fn lower_to_hir(tcx: TyCtxt<'_>, (): ()) -> hir::Crate<'_> { let sess = tcx.sess; - let krate = tcx.untracked_crate.steal(); - let mut resolver = tcx.resolver_for_lowering(()).steal(); + let (mut resolver, krate) = tcx.resolver_for_lowering(()).steal(); let ast_index = index_crate(&resolver.node_id_to_def_id, &krate); let mut owners = IndexVec::from_fn_n( diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 039338f543c..89ba6f936d1 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -385,6 +385,14 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { ast::ExprKind::TryBlock(_) => { gate_feature_post!(&self, try_blocks, e.span, "`try` expression is experimental"); } + ast::ExprKind::Closure(box ast::Closure { constness: ast::Const::Yes(_), .. }) => { + gate_feature_post!( + &self, + const_closures, + e.span, + "const closures are experimental" + ); + } _ => {} } visit::walk_expr(self, e) diff --git a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs index 3b17f6dd627..b125c6407d0 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs @@ -399,6 +399,7 @@ impl<'a> State<'a> { ast::ExprKind::Closure(box ast::Closure { binder, capture_clause, + constness, asyncness, movability, fn_decl, @@ -407,6 +408,7 @@ impl<'a> State<'a> { fn_arg_span: _, }) => { self.print_closure_binder(binder); + self.print_constness(*constness); self.print_movability(*movability); self.print_asyncness(*asyncness); self.print_capture_clause(*capture_clause); diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 6658ee89ad6..968c1f49b95 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -6,6 +6,7 @@ use rustc_errors::{ struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, MultiSpan, }; use rustc_hir as hir; +use rustc_hir::def::Res; use rustc_hir::intravisit::{walk_block, walk_expr, Visitor}; use rustc_hir::{AsyncGeneratorKind, GeneratorKind, LangItem}; use rustc_infer::infer::TyCtxtInferExt; @@ -20,7 +21,7 @@ use rustc_middle::ty::{self, suggest_constraining_type_params, PredicateKind, Ty use rustc_mir_dataflow::move_paths::{InitKind, MoveOutIndex, MovePathIndex}; use rustc_span::def_id::LocalDefId; use rustc_span::hygiene::DesugaringKind; -use rustc_span::symbol::sym; +use rustc_span::symbol::{kw, sym}; use rustc_span::{BytePos, Span, Symbol}; use rustc_trait_selection::infer::InferCtxtExt; @@ -29,6 +30,7 @@ use crate::borrowck_errors; use crate::diagnostics::conflict_errors::StorageDeadOrDrop::LocalStorageDead; use crate::diagnostics::find_all_local_uses; +use crate::diagnostics::mutability_errors::mut_borrow_of_mutable_ref; use crate::{ borrow_set::BorrowData, diagnostics::Instance, prefixes::IsPrefixOf, InitializationRequiringAction, MirBorrowckCtxt, PrefixSet, WriteKind, @@ -356,7 +358,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { if let Some(hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, _, body_id), .. - })) = hir.find(hir.local_def_id_to_hir_id(self.mir_def_id())) + })) = hir.find(self.mir_hir_id()) && let Some(hir::Node::Expr(expr)) = hir.find(body_id.hir_id) { let place = &self.move_data.move_paths[mpi].place; @@ -948,7 +950,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } (BorrowKind::Mut { .. }, BorrowKind::Shared) => { first_borrow_desc = "immutable "; - self.cannot_reborrow_already_borrowed( + let mut err = self.cannot_reborrow_already_borrowed( span, &desc_place, &msg_place, @@ -958,7 +960,13 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { "immutable", &msg_borrow, None, - ) + ); + self.suggest_binding_for_closure_capture_self( + &mut err, + issued_borrow.borrowed_place, + &issued_spans, + ); + err } (BorrowKind::Mut { .. }, BorrowKind::Mut { .. }) => { @@ -1240,6 +1248,138 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } } + fn suggest_binding_for_closure_capture_self( + &self, + err: &mut Diagnostic, + borrowed_place: Place<'tcx>, + issued_spans: &UseSpans<'tcx>, + ) { + let UseSpans::ClosureUse { capture_kind_span, .. } = issued_spans else { return }; + let hir = self.infcx.tcx.hir(); + + // check whether the borrowed place is capturing `self` by mut reference + let local = borrowed_place.local; + let Some(_) = self + .body + .local_decls + .get(local) + .map(|l| mut_borrow_of_mutable_ref(l, self.local_names[local])) else { return }; + + struct ExpressionFinder<'hir> { + capture_span: Span, + closure_change_spans: Vec<Span>, + closure_arg_span: Option<Span>, + in_closure: bool, + suggest_arg: String, + hir: rustc_middle::hir::map::Map<'hir>, + closure_local_id: Option<hir::HirId>, + closure_call_changes: Vec<(Span, String)>, + } + impl<'hir> Visitor<'hir> for ExpressionFinder<'hir> { + fn visit_expr(&mut self, e: &'hir hir::Expr<'hir>) { + if e.span.contains(self.capture_span) { + if let hir::ExprKind::Closure(&hir::Closure { + movability: None, + body, + fn_arg_span, + fn_decl: hir::FnDecl{ inputs, .. }, + .. + }) = e.kind && + let Some(hir::Node::Expr(body )) = self.hir.find(body.hir_id) { + self.suggest_arg = "this: &Self".to_string(); + if inputs.len() > 0 { + self.suggest_arg.push_str(", "); + } + self.in_closure = true; + self.closure_arg_span = fn_arg_span; + self.visit_expr(body); + self.in_closure = false; + } + } + if let hir::Expr { kind: hir::ExprKind::Path(path), .. } = e { + if let hir::QPath::Resolved(_, hir::Path { segments: [seg], ..}) = path && + seg.ident.name == kw::SelfLower && self.in_closure { + self.closure_change_spans.push(e.span); + } + } + hir::intravisit::walk_expr(self, e); + } + + fn visit_local(&mut self, local: &'hir hir::Local<'hir>) { + if let hir::Pat { kind: hir::PatKind::Binding(_, hir_id, _ident, _), .. } = local.pat && + let Some(init) = local.init + { + if let hir::Expr { kind: hir::ExprKind::Closure(&hir::Closure { + movability: None, + .. + }), .. } = init && + init.span.contains(self.capture_span) { + self.closure_local_id = Some(*hir_id); + } + } + hir::intravisit::walk_local(self, local); + } + + fn visit_stmt(&mut self, s: &'hir hir::Stmt<'hir>) { + if let hir::StmtKind::Semi(e) = s.kind && + let hir::ExprKind::Call(hir::Expr { kind: hir::ExprKind::Path(path), ..}, args) = e.kind && + let hir::QPath::Resolved(_, hir::Path { segments: [seg], ..}) = path && + let Res::Local(hir_id) = seg.res && + Some(hir_id) == self.closure_local_id { + let (span, arg_str) = if args.len() > 0 { + (args[0].span.shrink_to_lo(), "self, ".to_string()) + } else { + let span = e.span.trim_start(seg.ident.span).unwrap_or(e.span); + (span, "(self)".to_string()) + }; + self.closure_call_changes.push((span, arg_str)); + } + hir::intravisit::walk_stmt(self, s); + } + } + + if let Some(hir::Node::ImplItem( + hir::ImplItem { kind: hir::ImplItemKind::Fn(_fn_sig, body_id), .. } + )) = hir.find(self.mir_hir_id()) && + let Some(hir::Node::Expr(expr)) = hir.find(body_id.hir_id) { + let mut finder = ExpressionFinder { + capture_span: *capture_kind_span, + closure_change_spans: vec![], + closure_arg_span: None, + in_closure: false, + suggest_arg: String::new(), + closure_local_id: None, + closure_call_changes: vec![], + hir, + }; + finder.visit_expr(expr); + + if finder.closure_change_spans.is_empty() || finder.closure_call_changes.is_empty() { + return; + } + + let mut sugg = vec![]; + let sm = self.infcx.tcx.sess.source_map(); + + if let Some(span) = finder.closure_arg_span { + sugg.push((sm.next_point(span.shrink_to_lo()).shrink_to_hi(), finder.suggest_arg)); + } + for span in finder.closure_change_spans { + sugg.push((span, "this".to_string())); + } + + for (span, suggest) in finder.closure_call_changes { + sugg.push((span, suggest)); + } + + err.multipart_suggestion_verbose( + "try explicitly pass `&Self` into the Closure as an argument", + sugg, + Applicability::MachineApplicable, + ); + } + } + /// Returns the description of the root place for a conflicting borrow and the full /// descriptions of the places that caused the conflict. /// diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index b9cfc7e6961..45b15c2c5bd 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -1094,7 +1094,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { } } -fn mut_borrow_of_mutable_ref(local_decl: &LocalDecl<'_>, local_name: Option<Symbol>) -> bool { +pub fn mut_borrow_of_mutable_ref(local_decl: &LocalDecl<'_>, local_name: Option<Symbol>) -> bool { debug!("local_info: {:?}, ty.kind(): {:?}", local_decl.local_info, local_decl.ty.kind()); match local_decl.local_info.as_deref() { diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs index e8a4d1c37c1..f3050a6ef3f 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs @@ -79,7 +79,7 @@ impl<'tcx> RegionErrors<'tcx> { #[track_caller] pub fn push(&mut self, val: impl Into<RegionErrorKind<'tcx>>) { let val = val.into(); - self.1.sess.delay_span_bug(DUMMY_SP, "{val:?}"); + self.1.sess.delay_span_bug(DUMMY_SP, format!("{val:?}")); self.0.push(val); } pub fn is_empty(&self) -> bool { diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 8ca7103ed48..342abf81f6a 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -1231,12 +1231,21 @@ pub fn linker_and_flavor(sess: &Session) -> (PathBuf, LinkerFlavor) { sess.emit_fatal(errors::LinkerFileStem); }); + // Remove any version postfix. + let stem = stem + .rsplit_once('-') + .and_then(|(lhs, rhs)| rhs.chars().all(char::is_numeric).then_some(lhs)) + .unwrap_or(stem); + + // GCC can have an optional target prefix. let flavor = if stem == "emcc" { LinkerFlavor::EmCc } else if stem == "gcc" || stem.ends_with("-gcc") + || stem == "g++" + || stem.ends_with("-g++") || stem == "clang" - || stem.ends_with("-clang") + || stem == "clang++" { LinkerFlavor::from_cli(LinkerFlavorCli::Gcc, &sess.target) } else if stem == "wasm-ld" || stem.ends_with("-wasm-ld") { diff --git a/compiler/rustc_codegen_ssa/src/back/metadata.rs b/compiler/rustc_codegen_ssa/src/back/metadata.rs index 51c5c375d51..5ad2744f61d 100644 --- a/compiler/rustc_codegen_ssa/src/back/metadata.rs +++ b/compiler/rustc_codegen_ssa/src/back/metadata.rs @@ -165,11 +165,23 @@ pub(crate) fn create_object_file(sess: &Session) -> Option<write::Object<'static }; e_flags } - Architecture::Riscv64 if sess.target.options.features.contains("+d") => { - // copied from `riscv64-linux-gnu-gcc foo.c -c`, note though - // that the `+d` target feature represents whether the double - // float abi is enabled. - let e_flags = elf::EF_RISCV_RVC | elf::EF_RISCV_FLOAT_ABI_DOUBLE; + Architecture::Riscv32 | Architecture::Riscv64 => { + // Source: https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/079772828bd10933d34121117a222b4cc0ee2200/riscv-elf.adoc + let mut e_flags: u32 = 0x0; + let features = &sess.target.options.features; + // Check if compressed is enabled + if features.contains("+c") { + e_flags |= elf::EF_RISCV_RVC; + } + + // Select the appropriate floating-point ABI + if features.contains("+d") { + e_flags |= elf::EF_RISCV_FLOAT_ABI_DOUBLE; + } else if features.contains("+f") { + e_flags |= elf::EF_RISCV_FLOAT_ABI_SINGLE; + } else { + e_flags |= elf::EF_RISCV_FLOAT_ABI_SOFT; + } e_flags } _ => 0, diff --git a/compiler/rustc_const_eval/src/const_eval/fn_queries.rs b/compiler/rustc_const_eval/src/const_eval/fn_queries.rs index f1674d04f8d..351c701305a 100644 --- a/compiler/rustc_const_eval/src/const_eval/fn_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/fn_queries.rs @@ -41,6 +41,7 @@ fn constness(tcx: TyCtxt<'_>, def_id: DefId) -> hir::Constness { }; if is_const { hir::Constness::Const } else { hir::Constness::NotConst } } + hir::Node::Expr(e) if let hir::ExprKind::Closure(c) = e.kind => c.constness, _ => { if let Some(fn_kind) = node.fn_kind() { if fn_kind.constness() == hir::Constness::Const { diff --git a/compiler/rustc_const_eval/src/lib.rs b/compiler/rustc_const_eval/src/lib.rs index 443c01fdb90..46e7b09a55e 100644 --- a/compiler/rustc_const_eval/src/lib.rs +++ b/compiler/rustc_const_eval/src/lib.rs @@ -20,6 +20,7 @@ Rust MIR: a lowered representation of Rust. #![feature(trusted_step)] #![feature(try_blocks)] #![feature(yeet_expr)] +#![feature(if_let_guard)] #![feature(is_some_and)] #![recursion_limit = "256"] diff --git a/compiler/rustc_const_eval/src/transform/check_consts/check.rs b/compiler/rustc_const_eval/src/transform/check_consts/check.rs index 54213d55a2d..d4c75cd55ce 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs @@ -242,7 +242,7 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> { // impl trait is gone in MIR, so check the return type of a const fn by its signature // instead of the type of the return place. self.span = body.local_decls[RETURN_PLACE].source_info.span; - let return_ty = tcx.fn_sig(def_id).output(); + let return_ty = self.ccx.fn_sig().output(); self.check_local_or_return_ty(return_ty.skip_binder(), RETURN_PLACE); } @@ -730,6 +730,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { substs, span: *fn_span, from_hir_call: *from_hir_call, + feature: Some(sym::const_trait_impl), }); return; } @@ -782,6 +783,20 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { ); return; } + Ok(Some(ImplSource::Closure(data))) => { + if !tcx.is_const_fn_raw(data.closure_def_id) { + self.check_op(ops::FnCallNonConst { + caller, + callee, + substs, + span: *fn_span, + from_hir_call: *from_hir_call, + feature: None, + }); + + return; + } + } Ok(Some(ImplSource::UserDefined(data))) => { let callee_name = tcx.item_name(callee); if let Some(&did) = tcx @@ -802,6 +817,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { substs, span: *fn_span, from_hir_call: *from_hir_call, + feature: None, }); return; } @@ -844,6 +860,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { substs, span: *fn_span, from_hir_call: *from_hir_call, + feature: None, }); return; } @@ -903,6 +920,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { substs, span: *fn_span, from_hir_call: *from_hir_call, + feature: None, }); return; } diff --git a/compiler/rustc_const_eval/src/transform/check_consts/mod.rs b/compiler/rustc_const_eval/src/transform/check_consts/mod.rs index 0a90572d39e..54868e418c4 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/mod.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/mod.rs @@ -8,7 +8,7 @@ use rustc_attr as attr; use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_middle::mir; -use rustc_middle::ty::{self, TyCtxt}; +use rustc_middle::ty::{self, PolyFnSig, TyCtxt}; use rustc_span::Symbol; pub use self::qualifs::Qualif; @@ -64,6 +64,17 @@ impl<'mir, 'tcx> ConstCx<'mir, 'tcx> { fn is_async(&self) -> bool { self.tcx.asyncness(self.def_id()).is_async() } + + pub fn fn_sig(&self) -> PolyFnSig<'tcx> { + let did = self.def_id().to_def_id(); + if self.tcx.is_closure(did) { + let ty = self.tcx.type_of(did); + let ty::Closure(_, substs) = ty.kind() else { bug!("type_of closure not ty::Closure") }; + substs.as_closure().sig() + } else { + self.tcx.fn_sig(did) + } + } } pub fn rustc_allow_const_fn_unstable( diff --git a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs index b19d270e610..0cb5d2ff8c7 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs @@ -111,6 +111,7 @@ pub struct FnCallNonConst<'tcx> { pub substs: SubstsRef<'tcx>, pub span: Span, pub from_hir_call: bool, + pub feature: Option<Symbol>, } impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> { @@ -119,7 +120,7 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> { ccx: &ConstCx<'_, 'tcx>, _: Span, ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { - let FnCallNonConst { caller, callee, substs, span, from_hir_call } = *self; + let FnCallNonConst { caller, callee, substs, span, from_hir_call, feature } = *self; let ConstCx { tcx, param_env, .. } = *ccx; let diag_trait = |err, self_ty: Ty<'_>, trait_id| { @@ -318,6 +319,13 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> { ccx.const_kind(), )); + if let Some(feature) = feature && ccx.tcx.sess.is_nightly_build() { + err.help(&format!( + "add `#![feature({})]` to the crate attributes to enable", + feature, + )); + } + if let ConstContext::Static(_) = ccx.const_kind() { err.note("consider wrapping this expression in `Lazy::new(|| ...)` from the `once_cell` crate: https://crates.io/crates/once_cell"); } diff --git a/compiler/rustc_data_structures/src/steal.rs b/compiler/rustc_data_structures/src/steal.rs index a3ece655047..9a0fd52677d 100644 --- a/compiler/rustc_data_structures/src/steal.rs +++ b/compiler/rustc_data_structures/src/steal.rs @@ -41,6 +41,11 @@ impl<T> Steal<T> { } #[track_caller] + pub fn get_mut(&mut self) -> &mut T { + self.value.get_mut().as_mut().expect("attempt to read from stolen value") + } + + #[track_caller] pub fn steal(&self) -> T { let value_ref = &mut *self.value.try_write().expect("stealing value which is locked"); let value = value_ref.take(); diff --git a/compiler/rustc_driver/src/lib.rs b/compiler/rustc_driver/src/lib.rs index fcb73c64356..a62e5dec4b8 100644 --- a/compiler/rustc_driver/src/lib.rs +++ b/compiler/rustc_driver/src/lib.rs @@ -231,6 +231,10 @@ fn run_compiler( registry: diagnostics_registry(), }; + if !tracing::dispatcher::has_been_set() { + init_rustc_env_logger_with_backtrace_option(&config.opts.unstable_opts.log_backtrace); + } + match make_input(config.opts.error_format, &matches.free) { Err(reported) => return Err(reported), Ok(Some((input, input_file_path))) => { @@ -309,8 +313,8 @@ fn run_compiler( if let Some(ppm) = &sess.opts.pretty { if ppm.needs_ast_map() { - let expanded_crate = queries.expansion()?.peek().0.clone(); - queries.global_ctxt()?.peek_mut().enter(|tcx| { + let expanded_crate = queries.expansion()?.borrow().0.clone(); + queries.global_ctxt()?.enter(|tcx| { pretty::print_after_hir_lowering( tcx, compiler.input(), @@ -321,7 +325,7 @@ fn run_compiler( Ok(()) })?; } else { - let krate = queries.parse()?.take(); + let krate = queries.parse()?.steal(); pretty::print_after_parsing( sess, compiler.input(), @@ -343,7 +347,8 @@ fn run_compiler( } { - let (_, lint_store) = &*queries.register_plugins()?.peek(); + let plugins = queries.register_plugins()?; + let (_, lint_store) = &*plugins.borrow(); // Lint plugins are registered; now we can process command line flags. if sess.opts.describe_lints { @@ -371,7 +376,7 @@ fn run_compiler( return early_exit(); } - queries.global_ctxt()?.peek_mut().enter(|tcx| { + queries.global_ctxt()?.enter(|tcx| { let result = tcx.analysis(()); if sess.opts.unstable_opts.save_analysis { let crate_name = tcx.crate_name(LOCAL_CRATE); @@ -1299,7 +1304,14 @@ pub fn install_ice_hook() { /// This allows tools to enable rust logging without having to magically match rustc's /// tracing crate version. pub fn init_rustc_env_logger() { - if let Err(error) = rustc_log::init_rustc_env_logger() { + init_rustc_env_logger_with_backtrace_option(&None); +} + +/// This allows tools to enable rust logging without having to magically match rustc's +/// tracing crate version. In contrast to `init_rustc_env_logger` it allows you to +/// choose a target module you wish to show backtraces along with its logging. +pub fn init_rustc_env_logger_with_backtrace_option(backtrace_target: &Option<String>) { + if let Err(error) = rustc_log::init_rustc_env_logger_with_backtrace_option(backtrace_target) { early_error(ErrorOutputType::default(), &error.to_string()); } } @@ -1365,7 +1377,6 @@ mod signal_handler { pub fn main() -> ! { let start_time = Instant::now(); let start_rss = get_resident_set_size(); - init_rustc_env_logger(); signal_handler::install(); let mut callbacks = TimePassesCallbacks::default(); install_ice_hook(); diff --git a/compiler/rustc_error_codes/src/error_codes.rs b/compiler/rustc_error_codes/src/error_codes.rs index a132a8146e9..24258974bb9 100644 --- a/compiler/rustc_error_codes/src/error_codes.rs +++ b/compiler/rustc_error_codes/src/error_codes.rs @@ -618,7 +618,7 @@ E0791: include_str!("./error_codes/E0791.md"), // E0487, // unsafe use of destructor: destructor might be called while... // E0488, // lifetime of variable does not enclose its declaration // E0489, // type/lifetime parameter not in scope here - E0490, // a value of type `..` is borrowed for too long +// E0490, // removed: unreachable E0523, // two dependencies have same (crate-name, disambiguator) but different SVH // E0526, // shuffle indices are not constant // E0540, // multiple rustc_deprecated attributes diff --git a/compiler/rustc_error_messages/locales/en-US/hir_typeck.ftl b/compiler/rustc_error_messages/locales/en-US/hir_typeck.ftl index 0612dbae0b6..ca72b7faa92 100644 --- a/compiler/rustc_error_messages/locales/en-US/hir_typeck.ftl +++ b/compiler/rustc_error_messages/locales/en-US/hir_typeck.ftl @@ -46,3 +46,14 @@ hir_typeck_add_missing_parentheses_in_range = you must surround the range in par hir_typeck_op_trait_generic_params = `{$method_name}` must not have any generic parameters + +hir_typeck_lang_start_incorrect_number_params = incorrect number of parameters for the `start` lang item +hir_typeck_lang_start_incorrect_number_params_note_expected_count = the `start` lang item should have four parameters, but found {$found_param_count} + +hir_typeck_lang_start_expected_sig_note = the `start` lang item should have the signature `fn(fn() -> T, isize, *const *const u8, u8) -> isize` + +hir_typeck_lang_start_incorrect_param = parameter {$param_num} of the `start` lang item is incorrect + .suggestion = change the type from `{$found_ty}` to `{$expected_ty}` + +hir_typeck_lang_start_incorrect_ret_ty = the return type of the `start` lang item is incorrect + .suggestion = change the type from `{$found_ty}` to `{$expected_ty}` diff --git a/compiler/rustc_error_messages/locales/en-US/infer.ftl b/compiler/rustc_error_messages/locales/en-US/infer.ftl index c1cb07cf0df..ae0091b0373 100644 --- a/compiler/rustc_error_messages/locales/en-US/infer.ftl +++ b/compiler/rustc_error_messages/locales/en-US/infer.ftl @@ -101,7 +101,6 @@ infer_subtype_2 = ...so that {$requirement -> infer_reborrow = ...so that reference does not outlive borrowed content infer_reborrow_upvar = ...so that closure can access `{$name}` infer_relate_object_bound = ...so that it can be closed over into an object -infer_data_borrowed = ...so that the type `{$name}` is not borrowed for too long infer_reference_outlives_referent = ...so that the reference type `{$name}` does not outlive the data it points at infer_relate_param_bound = ...so that the type `{$name}` will meet its required lifetime bounds{$continues -> [true] ... diff --git a/compiler/rustc_error_messages/locales/en-US/interface.ftl b/compiler/rustc_error_messages/locales/en-US/interface.ftl index bbcb8fc28cf..688b0447222 100644 --- a/compiler/rustc_error_messages/locales/en-US/interface.ftl +++ b/compiler/rustc_error_messages/locales/en-US/interface.ftl @@ -41,3 +41,6 @@ interface_rustc_error_unexpected_annotation = interface_failed_writing_file = failed to write file {$path}: {$error}" + +interface_proc_macro_crate_panic_abort = + building proc macro crate with `panic=abort` may crash the compiler should the proc-macro panic diff --git a/compiler/rustc_error_messages/locales/en-US/lint.ftl b/compiler/rustc_error_messages/locales/en-US/lint.ftl index 2eb409a5ddd..d63ff77d8e2 100644 --- a/compiler/rustc_error_messages/locales/en-US/lint.ftl +++ b/compiler/rustc_error_messages/locales/en-US/lint.ftl @@ -15,6 +15,43 @@ lint_enum_intrinsics_mem_variant = lint_expectation = this lint expectation is unfulfilled .note = the `unfulfilled_lint_expectations` lint can't be expected and will always produce this message + .rationale = {$rationale} + +lint_for_loops_over_fallibles = + for loop over {$article} `{$ty}`. This is more readably written as an `if let` statement + .suggestion = consider using `if let` to clear intent + .remove_next = to iterate over `{$recv_snip}` remove the call to `next` + .use_while_let = to check pattern in a loop use `while let` + .use_question_mark = consider unwrapping the `Result` with `?` to iterate over its contents + +lint_non_binding_let_on_sync_lock = + non-binding let on a synchronization lock + +lint_non_binding_let_on_drop_type = + non-binding let on a type that implements `Drop` + +lint_non_binding_let_suggestion = + consider binding to an unused variable to avoid immediately dropping the value + +lint_non_binding_let_multi_suggestion = + consider immediately dropping the value + +lint_deprecated_lint_name = + lint name `{$name}` is deprecated and may not have an effect in the future. + .suggestion = change it to + +lint_renamed_or_removed_lint = {$msg} + .suggestion = use the new name + +lint_unknown_lint = + unknown lint: `{$name}` + .suggestion = did you mean + +lint_ignored_unless_crate_specified = {$level}({$name}) is ignored unless specified at crate level + +lint_unknown_gated_lint = + unknown lint: `{$name}` + .note = the `{$name}` lint is unstable lint_hidden_unicode_codepoints = unicode codepoint changing visible direction of text present in {$label} .label = this {$label} contains {$count -> @@ -55,6 +92,8 @@ lint_diag_out_of_impl = lint_untranslatable_diag = diagnostics should be created using translatable messages +lint_bad_opt_access = {$msg} + 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 @@ -331,6 +370,8 @@ lint_builtin_anonymous_params = anonymous parameters are deprecated and will be .suggestion = try naming the parameter or explicitly ignoring it lint_builtin_deprecated_attr_link = use of deprecated attribute `{$name}`: {$reason}. See {$link} + .msg_suggestion = {$msg} + .default_suggestion = remove this attribute lint_builtin_deprecated_attr_used = use of deprecated attribute `{$name}`: no longer used. lint_builtin_deprecated_attr_default_suggestion = remove this attribute @@ -391,10 +432,16 @@ lint_builtin_incomplete_features = the feature `{$name}` is incomplete and may n .note = see issue #{$n} <https://github.com/rust-lang/rust/issues/{$n}> for more information .help = consider using `min_{$name}` instead, which is more stable and complete -lint_builtin_clashing_extern_same_name = `{$this_fi}` redeclared with a different signature +lint_builtin_unpermitted_type_init_zeroed = the type `{$ty}` does not permit zero-initialization +lint_builtin_unpermitted_type_init_unint = the type `{$ty}` does not permit being left uninitialized + +lint_builtin_unpermitted_type_init_label = this code causes undefined behavior when executed +lint_builtin_unpermitted_type_init_label_suggestion = help: use `MaybeUninit<T>` instead, and only call `assume_init` after initialization is done + +lint_builtin_clashing_extern_same_name = `{$this}` redeclared with a different signature .previous_decl_label = `{$orig}` previously declared here .mismatch_label = this signature doesn't match the previous declaration -lint_builtin_clashing_extern_diff_name = `{$this_fi}` redeclares `{$orig}` with a different signature +lint_builtin_clashing_extern_diff_name = `{$this}` redeclares `{$orig}` with a different signature .previous_decl_label = `{$orig}` previously declared here .mismatch_label = this signature doesn't match the previous declaration @@ -403,6 +450,16 @@ lint_builtin_deref_nullptr = dereferencing a null pointer lint_builtin_asm_labels = avoid using named labels in inline assembly +lint_builtin_special_module_name_used_lib = found module declaration for lib.rs + .note = lib.rs is the root of this crate's library target + .help = to refer to it from other targets, use the library's name as the path + +lint_builtin_special_module_name_used_main = found module declaration for main.rs + .note = a binary crate cannot be used as library + +lint_supertrait_as_deref_target = `{$t}` implements `Deref` with supertrait `{$target_principal}` as target + .label = target type is set here + lint_overruled_attribute = {$lint_level}({$lint_source}) incompatible with previous forbid .label = overruled by previous forbid diff --git a/compiler/rustc_error_messages/locales/en-US/passes.ftl b/compiler/rustc_error_messages/locales/en-US/passes.ftl index 001e53d1d0e..91857dd227d 100644 --- a/compiler/rustc_error_messages/locales/en-US/passes.ftl +++ b/compiler/rustc_error_messages/locales/en-US/passes.ftl @@ -4,6 +4,9 @@ -passes_see_issue = see issue #{$issue} <https://github.com/rust-lang/rust/issues/{$issue}> for more information +passes_incorrect_do_not_recommend_location = + `#[do_not_recommend]` can only be placed on trait implementations + passes_outer_crate_level_attr = crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` diff --git a/compiler/rustc_expand/src/build.rs b/compiler/rustc_expand/src/build.rs index 93b3af4ab97..9b16e79d49a 100644 --- a/compiler/rustc_expand/src/build.rs +++ b/compiler/rustc_expand/src/build.rs @@ -533,6 +533,7 @@ impl<'a> ExtCtxt<'a> { ast::ExprKind::Closure(Box::new(ast::Closure { binder: ast::ClosureBinder::NotPresent, capture_clause: ast::CaptureBy::Ref, + constness: ast::Const::No, asyncness: ast::Async::No, movability: ast::Movability::Movable, fn_decl, diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs index fcbc5bacfcc..aab4b604fad 100644 --- a/compiler/rustc_feature/src/accepted.rs +++ b/compiler/rustc_feature/src/accepted.rs @@ -48,6 +48,8 @@ declare_features! ( /// Allows `#[target_feature(...)]` on aarch64 platforms (accepted, aarch64_target_feature, "1.61.0", Some(44839), None), + /// Allows using the `efiapi` ABI. + (accepted, abi_efiapi, "CURRENT_RUSTC_VERSION", Some(65815), None), /// Allows the sysV64 ABI to be specified on all platforms /// instead of just the platforms on which it is the C ABI. (accepted, abi_sysv64, "1.24.0", Some(36167), None), diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index f0bc35d06bf..196c31302a0 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -281,8 +281,6 @@ declare_features! ( (active, abi_avr_interrupt, "1.45.0", Some(69664), None), /// Allows `extern "C-cmse-nonsecure-call" fn()`. (active, abi_c_cmse_nonsecure_call, "1.51.0", Some(81391), None), - /// Allows using the `efiapi` ABI. - (active, abi_efiapi, "1.40.0", Some(65815), None), /// Allows `extern "msp430-interrupt" fn()`. (active, abi_msp430_interrupt, "1.16.0", Some(38487), None), /// Allows `extern "ptx-*" fn()`. @@ -341,7 +339,9 @@ declare_features! ( (active, collapse_debuginfo, "1.65.0", Some(100758), None), /// Allows `async {}` expressions in const contexts. (active, const_async_blocks, "1.53.0", Some(85368), None), - // Allows limiting the evaluation steps of const expressions + /// Allows `const || {}` closures in const contexts. + (incomplete, const_closures, "CURRENT_RUSTC_VERSION", Some(106003), None), + /// Allows limiting the evaluation steps of const expressions (active, const_eval_limit, "1.43.0", Some(67217), None), /// Allows the definition of `const extern fn` and `const unsafe extern fn`. (active, const_extern_fn, "1.40.0", Some(64926), None), diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index bc897ed8112..60f5b79de10 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -938,6 +938,7 @@ pub struct Crate<'hir> { pub struct Closure<'hir> { pub def_id: LocalDefId, pub binder: ClosureBinder, + pub constness: Constness, pub capture_clause: CaptureBy, pub bound_generic_params: &'hir [GenericParam<'hir>], pub fn_decl: &'hir FnDecl<'hir>, diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 6c475b659eb..02641b7cf8f 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -742,6 +742,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>) fn_decl_span: _, fn_arg_span: _, movability: _, + constness: _, }) => { walk_list!(visitor, visit_generic_param, bound_generic_params); visitor.visit_fn(FnKind::Closure, fn_decl, body, expression.span, expression.hir_id) diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs index 9fa0e6e8eaa..3521911b055 100644 --- a/compiler/rustc_hir_analysis/src/astconv/mod.rs +++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs @@ -27,6 +27,7 @@ use rustc_hir::def::{CtorOf, DefKind, Namespace, Res}; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::intravisit::{walk_generics, Visitor as _}; use rustc_hir::{GenericArg, GenericArgs, OpaqueTyOrigin}; +use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::middle::stability::AllowUnstable; use rustc_middle::ty::subst::{self, GenericArgKind, InternalSubsts, SubstsRef}; use rustc_middle::ty::GenericParamDefKind; @@ -1643,8 +1644,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { fn report_ambiguous_associated_type( &self, span: Span, - type_str: &str, - trait_str: &str, + types: &[String], + traits: &[String], name: Symbol, ) -> ErrorGuaranteed { let mut err = struct_span_err!(self.tcx().sess, span, E0223, "ambiguous associated type"); @@ -1655,19 +1656,92 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { .keys() .any(|full_span| full_span.contains(span)) { - err.span_suggestion( + err.span_suggestion_verbose( span.shrink_to_lo(), "you are looking for the module in `std`, not the primitive type", "std::", Applicability::MachineApplicable, ); } else { - err.span_suggestion( - span, - "use fully-qualified syntax", - format!("<{} as {}>::{}", type_str, trait_str, name), - Applicability::HasPlaceholders, - ); + match (types, traits) { + ([], []) => { + err.span_suggestion_verbose( + span, + &format!( + "if there were a type named `Type` that implements a trait named \ + `Trait` with associated type `{name}`, you could use the \ + fully-qualified path", + ), + format!("<Type as Trait>::{name}"), + Applicability::HasPlaceholders, + ); + } + ([], [trait_str]) => { + err.span_suggestion_verbose( + span, + &format!( + "if there were a type named `Example` that implemented `{trait_str}`, \ + you could use the fully-qualified path", + ), + format!("<Example as {trait_str}>::{name}"), + Applicability::HasPlaceholders, + ); + } + ([], traits) => { + err.span_suggestions( + span, + &format!( + "if there were a type named `Example` that implemented one of the \ + traits with associated type `{name}`, you could use the \ + fully-qualified path", + ), + traits + .iter() + .map(|trait_str| format!("<Example as {trait_str}>::{name}")) + .collect::<Vec<_>>(), + Applicability::HasPlaceholders, + ); + } + ([type_str], []) => { + err.span_suggestion_verbose( + span, + &format!( + "if there were a trait named `Example` with associated type `{name}` \ + implemented for `{type_str}`, you could use the fully-qualified path", + ), + format!("<{type_str} as Example>::{name}"), + Applicability::HasPlaceholders, + ); + } + (types, []) => { + err.span_suggestions( + span, + &format!( + "if there were a trait named `Example` with associated type `{name}` \ + implemented for one of the types, you could use the fully-qualified \ + path", + ), + types + .into_iter() + .map(|type_str| format!("<{type_str} as Example>::{name}")), + Applicability::HasPlaceholders, + ); + } + (types, traits) => { + let mut suggestions = vec![]; + for type_str in types { + for trait_str in traits { + suggestions.push(format!("<{type_str} as {trait_str}>::{name}")); + } + } + err.span_suggestions( + span, + "use the fully-qualified path", + suggestions, + Applicability::MachineApplicable, + ); + } + } } err.emit() } @@ -2050,12 +2124,64 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { err.emit() } else if let Err(reported) = qself_ty.error_reported() { reported + } else if let ty::Alias(ty::Opaque, alias_ty) = qself_ty.kind() { + // `<impl Trait as OtherTrait>::Assoc` makes no sense. + struct_span_err!( + tcx.sess, + tcx.def_span(alias_ty.def_id), + E0667, + "`impl Trait` is not allowed in path parameters" + ) + .emit() // Already reported in an earlier stage. } else { + // Find all the `impl`s that `qself_ty` has for any trait that has the + // associated type, so that we suggest the right one. + let infcx = tcx.infer_ctxt().build(); + // We create a fresh `ty::ParamEnv` instead of the one for `self.item_def_id()` + // to avoid a cycle error in `src/test/ui/resolve/issue-102946.rs`. + let param_env = ty::ParamEnv::empty(); + let traits: Vec<_> = self + .tcx() + .all_traits() + .filter(|trait_def_id| { + // Consider only traits with the associated type + tcx.associated_items(*trait_def_id) + .in_definition_order() + .any(|i| { + i.kind.namespace() == Namespace::TypeNS + && i.ident(tcx).normalize_to_macros_2_0() == assoc_ident + && matches!(i.kind, ty::AssocKind::Type) + }) + // Consider only accessible traits + && tcx.visibility(*trait_def_id) + .is_accessible_from(self.item_def_id(), tcx) + && tcx.all_impls(*trait_def_id) + .any(|impl_def_id| { + let trait_ref = tcx.bound_impl_trait_ref(impl_def_id); + trait_ref.map_or(false, |trait_ref| { + let impl_ = trait_ref.subst( + tcx, + infcx.fresh_substs_for_item(span, impl_def_id), + ); + infcx + .can_eq( + param_env, + tcx.erase_regions(impl_.self_ty()), + tcx.erase_regions(qself_ty), + ) + .is_ok() + }) + && tcx.impl_polarity(impl_def_id) != ty::ImplPolarity::Negative + }) + }) + .map(|trait_def_id| tcx.def_path_str(trait_def_id)) + .collect(); + // Don't print `TyErr` to the user. self.report_ambiguous_associated_type( span, - &qself_ty.to_string(), - "Trait", + &[qself_ty.to_string()], + &traits, assoc_ident.name, ) }; @@ -2173,16 +2299,30 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let is_part_of_self_trait_constraints = def_id == trait_def_id; let is_part_of_fn_in_self_trait = parent_def_id == Some(trait_def_id); - let type_name = if is_part_of_self_trait_constraints || is_part_of_fn_in_self_trait { - "Self" + let type_names = if is_part_of_self_trait_constraints || is_part_of_fn_in_self_trait { + vec!["Self".to_string()] } else { - "Type" + // Find all the types that have an `impl` for the trait. + tcx.all_impls(trait_def_id) + .filter(|impl_def_id| { + // Consider only accessible traits + tcx.visibility(*impl_def_id).is_accessible_from(self.item_def_id(), tcx) + && tcx.impl_polarity(impl_def_id) != ty::ImplPolarity::Negative + }) + .filter_map(|impl_def_id| tcx.impl_trait_ref(impl_def_id)) + .map(|impl_| impl_.self_ty()) + // We don't care about blanket impls. + .filter(|self_ty| !self_ty.has_non_region_param()) + .map(|self_ty| tcx.erase_regions(self_ty).to_string()) + .collect() }; - + // FIXME: also look at `tcx.generics_of(self.item_def_id()).params` any that + // references the trait. Relevant for the first case in + // `src/test/ui/associated-types/associated-types-in-ambiguous-context.rs` let reported = self.report_ambiguous_associated_type( span, - type_name, - &path_str, + &type_names, + &[path_str], item_segment.ident.name, ); return tcx.ty_error_with_guaranteed(reported) diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index 7af89934d14..2cdf7579471 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -2,7 +2,9 @@ use super::potentially_plural_count; use crate::errors::LifetimesOrBoundsMismatchOnTrait; use hir::def_id::{DefId, LocalDefId}; use rustc_data_structures::fx::{FxHashMap, FxIndexSet}; -use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticId, ErrorGuaranteed}; +use rustc_errors::{ + pluralize, struct_span_err, Applicability, DiagnosticId, ErrorGuaranteed, MultiSpan, +}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::intravisit; @@ -320,15 +322,6 @@ fn compare_method_predicate_entailment<'tcx>( ty::Binder::dummy(ty::PredicateKind::WellFormed(unnormalized_impl_fty.into())), )); } - let emit_implied_wf_lint = || { - infcx.tcx.struct_span_lint_hir( - rustc_session::lint::builtin::IMPLIED_BOUNDS_ENTAILMENT, - impl_m_hir_id, - infcx.tcx.def_span(impl_m.def_id), - "impl method assumes more implied bounds than the corresponding trait method", - |lint| lint, - ); - }; // Check that all obligations are satisfied by the implementation's // version. @@ -346,7 +339,7 @@ fn compare_method_predicate_entailment<'tcx>( ) .map(|()| { // If the skip-mode was successful, emit a lint. - emit_implied_wf_lint(); + emit_implied_wf_lint(infcx.tcx, impl_m, impl_m_hir_id, vec![]); }); } CheckImpliedWfMode::Skip => { @@ -382,8 +375,16 @@ fn compare_method_predicate_entailment<'tcx>( CheckImpliedWfMode::Skip, ) .map(|()| { + let bad_args = extract_bad_args_for_implies_lint( + tcx, + &errors, + (trait_m, trait_sig), + // Unnormalized impl sig corresponds to the HIR types written + (impl_m, unnormalized_impl_sig), + impl_m_hir_id, + ); // If the skip-mode was successful, emit a lint. - emit_implied_wf_lint(); + emit_implied_wf_lint(tcx, impl_m, impl_m_hir_id, bad_args); }); } CheckImpliedWfMode::Skip => { @@ -400,6 +401,141 @@ fn compare_method_predicate_entailment<'tcx>( Ok(()) } +fn extract_bad_args_for_implies_lint<'tcx>( + tcx: TyCtxt<'tcx>, + errors: &[infer::RegionResolutionError<'tcx>], + (trait_m, trait_sig): (&ty::AssocItem, ty::FnSig<'tcx>), + (impl_m, impl_sig): (&ty::AssocItem, ty::FnSig<'tcx>), + hir_id: hir::HirId, +) -> Vec<(Span, Option<String>)> { + let mut blame_generics = vec![]; + for error in errors { + // Look for the subregion origin that contains an input/output type + let origin = match error { + infer::RegionResolutionError::ConcreteFailure(o, ..) => o, + infer::RegionResolutionError::GenericBoundFailure(o, ..) => o, + infer::RegionResolutionError::SubSupConflict(_, _, o, ..) => o, + infer::RegionResolutionError::UpperBoundUniverseConflict(.., o, _) => o, + }; + // Extract (possible) input/output types from origin + match origin { + infer::SubregionOrigin::Subtype(trace) => { + if let Some((a, b)) = trace.values.ty() { + blame_generics.extend([a, b]); + } + } + infer::SubregionOrigin::RelateParamBound(_, ty, _) => blame_generics.push(*ty), + infer::SubregionOrigin::ReferenceOutlivesReferent(ty, _) => blame_generics.push(*ty), + _ => {} + } + } + + let fn_decl = tcx.hir().fn_decl_by_hir_id(hir_id).unwrap(); + let opt_ret_ty = match fn_decl.output { + hir::FnRetTy::DefaultReturn(_) => None, + hir::FnRetTy::Return(ty) => Some(ty), + }; + + // Map late-bound regions from trait to impl, so the names are right. + let mapping = std::iter::zip( + tcx.fn_sig(trait_m.def_id).bound_vars(), + tcx.fn_sig(impl_m.def_id).bound_vars(), + ) + .filter_map(|(impl_bv, trait_bv)| { + if let ty::BoundVariableKind::Region(impl_bv) = impl_bv + && let ty::BoundVariableKind::Region(trait_bv) = trait_bv + { + Some((impl_bv, trait_bv)) + } else { + None + } + }) + .collect(); + + // For each arg, see if it was in the "blame" of any of the region errors. + // If so, then try to produce a suggestion to replace the argument type with + // one from the trait. + let mut bad_args = vec![]; + for (idx, (ty, hir_ty)) in + std::iter::zip(impl_sig.inputs_and_output, fn_decl.inputs.iter().chain(opt_ret_ty)) + .enumerate() + { + let expected_ty = trait_sig.inputs_and_output[idx] + .fold_with(&mut RemapLateBound { tcx, mapping: &mapping }); + if blame_generics.iter().any(|blame| ty.contains(*blame)) { + let expected_ty_sugg = expected_ty.to_string(); + bad_args.push(( + hir_ty.span, + // Only suggest something if it actually changed. + (expected_ty_sugg != ty.to_string()).then_some(expected_ty_sugg), + )); + } + } + + bad_args +} + +struct RemapLateBound<'a, 'tcx> { + tcx: TyCtxt<'tcx>, + mapping: &'a FxHashMap<ty::BoundRegionKind, ty::BoundRegionKind>, +} + +impl<'tcx> TypeFolder<'tcx> for RemapLateBound<'_, 'tcx> { + fn tcx(&self) -> TyCtxt<'tcx> { + self.tcx + } + + fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { + if let ty::ReFree(fr) = *r { + self.tcx.mk_region(ty::ReFree(ty::FreeRegion { + bound_region: self + .mapping + .get(&fr.bound_region) + .copied() + .unwrap_or(fr.bound_region), + ..fr + })) + } else { + r + } + } +} + +fn emit_implied_wf_lint<'tcx>( + tcx: TyCtxt<'tcx>, + impl_m: &ty::AssocItem, + hir_id: hir::HirId, + bad_args: Vec<(Span, Option<String>)>, +) { + let span: MultiSpan = if bad_args.is_empty() { + tcx.def_span(impl_m.def_id).into() + } else { + bad_args.iter().map(|(span, _)| *span).collect::<Vec<_>>().into() + }; + tcx.struct_span_lint_hir( + rustc_session::lint::builtin::IMPLIED_BOUNDS_ENTAILMENT, + hir_id, + span, + "impl method assumes more implied bounds than the corresponding trait method", + |lint| { + let bad_args: Vec<_> = + bad_args.into_iter().filter_map(|(span, sugg)| Some((span, sugg?))).collect(); + if !bad_args.is_empty() { + lint.multipart_suggestion( + format!( + "replace {} type{} to make the impl signature compatible", + pluralize!("this", bad_args.len()), + pluralize!(bad_args.len()) + ), + bad_args, + Applicability::MaybeIncorrect, + ); + } + lint + }, + ); +} + #[derive(Debug, PartialEq, Eq)] enum CheckImpliedWfMode { /// Checks implied well-formedness of the impl method. If it fails, we will diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index d1f4dbc8d84..92fd4625ee8 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -1254,7 +1254,11 @@ fn check_impl<'tcx>( // therefore don't need to be WF (the trait's `Self: Trait` predicate // won't hold). let trait_ref = tcx.impl_trait_ref(item.owner_id).unwrap(); - let trait_ref = wfcx.normalize(ast_trait_ref.path.span, None, trait_ref); + let trait_ref = wfcx.normalize( + ast_trait_ref.path.span, + Some(WellFormedLoc::Ty(item.hir_id().expect_owner().def_id)), + trait_ref, + ); let trait_pred = ty::TraitPredicate { trait_ref, constness: match constness { @@ -1263,7 +1267,7 @@ fn check_impl<'tcx>( }, polarity: ty::ImplPolarity::Positive, }; - let obligations = traits::wf::trait_obligations( + let mut obligations = traits::wf::trait_obligations( wfcx.infcx, wfcx.param_env, wfcx.body_id, @@ -1271,6 +1275,13 @@ fn check_impl<'tcx>( ast_trait_ref.path.span, item, ); + for obligation in &mut obligations { + if let Some(pred) = obligation.predicate.to_opt_poly_trait_pred() + && pred.self_ty().skip_binder() == trait_ref.self_ty() + { + obligation.cause.span = ast_self_ty.span; + } + } debug!(?obligations); wfcx.register_obligations(obligations); } diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs index 96221c3e3d8..9a5f447c260 100644 --- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs @@ -4,6 +4,7 @@ use hir::{ GenericParamKind, HirId, Node, }; use rustc_hir as hir; +use rustc_hir::def::DefKind; use rustc_hir::def_id::DefId; use rustc_middle::ty::{self, TyCtxt}; use rustc_session::lint; @@ -142,7 +143,20 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics { Some(tcx.typeck_root_def_id(def_id)) } Node::Item(item) => match item.kind { - ItemKind::OpaqueTy(hir::OpaqueTy { .. }) => { + ItemKind::OpaqueTy(hir::OpaqueTy { + origin: + hir::OpaqueTyOrigin::FnReturn(fn_def_id) | hir::OpaqueTyOrigin::AsyncFn(fn_def_id), + in_trait, + .. + }) => { + if in_trait { + 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()) + } + ItemKind::OpaqueTy(hir::OpaqueTy { origin: hir::OpaqueTyOrigin::TyAlias, .. }) => { let parent_id = tcx.hir().get_parent_item(hir_id); assert_ne!(parent_id, hir::CRATE_OWNER_ID); debug!("generics_of: parent of opaque ty {:?} is {:?}", def_id, parent_id); diff --git a/compiler/rustc_hir_analysis/src/hir_wf_check.rs b/compiler/rustc_hir_analysis/src/hir_wf_check.rs index 4f9d5826583..2dbfc1bc9a2 100644 --- a/compiler/rustc_hir_analysis/src/hir_wf_check.rs +++ b/compiler/rustc_hir_analysis/src/hir_wf_check.rs @@ -114,34 +114,46 @@ fn diagnostic_hir_wf_check<'tcx>( // Get the starting `hir::Ty` using our `WellFormedLoc`. // We will walk 'into' this type to try to find // a more precise span for our predicate. - let ty = match loc { + let tys = match loc { WellFormedLoc::Ty(_) => match hir.get(hir_id) { hir::Node::ImplItem(item) => match item.kind { - hir::ImplItemKind::Type(ty) => Some(ty), - hir::ImplItemKind::Const(ty, _) => Some(ty), + hir::ImplItemKind::Type(ty) => vec![ty], + hir::ImplItemKind::Const(ty, _) => vec![ty], ref item => bug!("Unexpected ImplItem {:?}", item), }, hir::Node::TraitItem(item) => match item.kind { - hir::TraitItemKind::Type(_, ty) => ty, - hir::TraitItemKind::Const(ty, _) => Some(ty), + hir::TraitItemKind::Type(_, ty) => ty.into_iter().collect(), + hir::TraitItemKind::Const(ty, _) => vec![ty], ref item => bug!("Unexpected TraitItem {:?}", item), }, hir::Node::Item(item) => match item.kind { - hir::ItemKind::Static(ty, _, _) | hir::ItemKind::Const(ty, _) => Some(ty), - hir::ItemKind::Impl(ref impl_) => { - assert!(impl_.of_trait.is_none(), "Unexpected trait impl: {:?}", impl_); - Some(impl_.self_ty) - } + hir::ItemKind::Static(ty, _, _) | hir::ItemKind::Const(ty, _) => vec![ty], + hir::ItemKind::Impl(ref impl_) => match &impl_.of_trait { + Some(t) => t + .path + .segments + .last() + .iter() + .flat_map(|seg| seg.args().args) + .filter_map(|arg| { + if let hir::GenericArg::Type(ty) = arg { Some(*ty) } else { None } + }) + .chain([impl_.self_ty]) + .collect(), + None => { + vec![impl_.self_ty] + } + }, ref item => bug!("Unexpected item {:?}", item), }, - hir::Node::Field(field) => Some(field.ty), + hir::Node::Field(field) => vec![field.ty], hir::Node::ForeignItem(ForeignItem { kind: ForeignItemKind::Static(ty, _), .. - }) => Some(*ty), + }) => vec![*ty], hir::Node::GenericParam(hir::GenericParam { kind: hir::GenericParamKind::Type { default: Some(ty), .. }, .. - }) => Some(*ty), + }) => vec![*ty], ref node => bug!("Unexpected node {:?}", node), }, WellFormedLoc::Param { function: _, param_idx } => { @@ -149,16 +161,16 @@ fn diagnostic_hir_wf_check<'tcx>( // Get return type if param_idx as usize == fn_decl.inputs.len() { match fn_decl.output { - hir::FnRetTy::Return(ty) => Some(ty), + hir::FnRetTy::Return(ty) => vec![ty], // The unit type `()` is always well-formed - hir::FnRetTy::DefaultReturn(_span) => None, + hir::FnRetTy::DefaultReturn(_span) => vec![], } } else { - Some(&fn_decl.inputs[param_idx as usize]) + vec![&fn_decl.inputs[param_idx as usize]] } } }; - if let Some(ty) = ty { + for ty in tys { visitor.visit_ty(ty); } visitor.cause diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 3e3af8395a1..f74c551a45b 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -1464,6 +1464,7 @@ impl<'a> State<'a> { } hir::ExprKind::Closure(&hir::Closure { binder, + constness, capture_clause, bound_generic_params, fn_decl, @@ -1474,6 +1475,7 @@ impl<'a> State<'a> { def_id: _, }) => { self.print_closure_binder(binder, bound_generic_params); + self.print_constness(constness); self.print_capture_clause(capture_clause); self.print_closure_params(fn_decl, body); @@ -2272,10 +2274,7 @@ impl<'a> State<'a> { } pub fn print_fn_header_info(&mut self, header: hir::FnHeader) { - match header.constness { - hir::Constness::NotConst => {} - hir::Constness::Const => self.word_nbsp("const"), - } + self.print_constness(header.constness); match header.asyncness { hir::IsAsync::NotAsync => {} @@ -2292,6 +2291,13 @@ impl<'a> State<'a> { self.word("fn") } + pub fn print_constness(&mut self, s: hir::Constness) { + match s { + hir::Constness::NotConst => {} + hir::Constness::Const => self.word_nbsp("const"), + } + } + pub fn print_unsafety(&mut self, s: hir::Unsafety) { match s { hir::Unsafety::Normal => {} diff --git a/compiler/rustc_hir_typeck/src/check.rs b/compiler/rustc_hir_typeck/src/check.rs index 32f86b8042c..57feefbcab6 100644 --- a/compiler/rustc_hir_typeck/src/check.rs +++ b/compiler/rustc_hir_typeck/src/check.rs @@ -1,4 +1,7 @@ use crate::coercion::CoerceMany; +use crate::errors::{ + LangStartIncorrectNumberArgs, LangStartIncorrectParam, LangStartIncorrectRetTy, +}; use crate::gather_locals::GatherLocalsVisitor; use crate::FnCtxt; use crate::GeneratorTypes; @@ -9,8 +12,9 @@ use rustc_hir::lang_items::LangItem; use rustc_hir_analysis::check::fn_maybe_err; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_infer::infer::RegionVariableOrigin; -use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_middle::ty::{self, Binder, Ty, TyCtxt}; use rustc_span::def_id::LocalDefId; +use rustc_target::spec::abi::Abi; use rustc_trait_selection::traits; use std::cell::RefCell; @@ -168,6 +172,10 @@ pub(super) fn check_fn<'a, 'tcx>( check_panic_info_fn(tcx, panic_impl_did.expect_local(), fn_sig, decl, declared_ret_ty); } + if let Some(lang_start_defid) = tcx.lang_items().start_fn() && lang_start_defid == hir.local_def_id(fn_id).to_def_id() { + check_lang_start_fn(tcx, fn_sig, decl, fn_def_id); + } + gen_ty } @@ -223,3 +231,126 @@ fn check_panic_info_fn( tcx.sess.span_err(span, "should have no const parameters"); } } + +fn check_lang_start_fn<'tcx>( + tcx: TyCtxt<'tcx>, + fn_sig: ty::FnSig<'tcx>, + decl: &'tcx hir::FnDecl<'tcx>, + def_id: LocalDefId, +) { + let inputs = fn_sig.inputs(); + + let arg_count = inputs.len(); + if arg_count != 4 { + tcx.sess.emit_err(LangStartIncorrectNumberArgs { + params_span: tcx.def_span(def_id), + found_param_count: arg_count, + }); + } + + // only check args if they should exist by checking the count + // note: this does not handle args being shifted or their order swapped very nicely + // but it's a lang item, users shouldn't frequently encounter this + + // first arg is `main: fn() -> T` + if let Some(&main_arg) = inputs.get(0) { + // make a Ty for the generic on the fn for diagnostics + // FIXME: make the lang item generic checks check for the right generic *kind* + // for example `start`'s generic should be a type parameter + let generics = tcx.generics_of(def_id); + let fn_generic = generics.param_at(0, tcx); + let generic_tykind = + ty::Param(ty::ParamTy { index: fn_generic.index, name: fn_generic.name }); + let generic_ty = tcx.mk_ty(generic_tykind); + let expected_fn_sig = + tcx.mk_fn_sig([].iter(), &generic_ty, false, hir::Unsafety::Normal, Abi::Rust); + let expected_ty = tcx.mk_fn_ptr(Binder::dummy(expected_fn_sig)); + + // we emit the same error to suggest changing the arg no matter what's wrong with the arg + let emit_main_fn_arg_err = || { + tcx.sess.emit_err(LangStartIncorrectParam { + param_span: decl.inputs[0].span, + param_num: 1, + expected_ty: expected_ty, + found_ty: main_arg, + }); + }; + + if let ty::FnPtr(main_fn_sig) = main_arg.kind() { + let main_fn_inputs = main_fn_sig.inputs(); + if main_fn_inputs.iter().count() != 0 { + emit_main_fn_arg_err(); + } + + let output = main_fn_sig.output(); + output.map_bound(|ret_ty| { + // if the output ty is a generic, it's probably the right one + if !matches!(ret_ty.kind(), ty::Param(_)) { + emit_main_fn_arg_err(); + } + }); + } else { + emit_main_fn_arg_err(); + } + } + + // second arg is isize + if let Some(&argc_arg) = inputs.get(1) { + if argc_arg != tcx.types.isize { + tcx.sess.emit_err(LangStartIncorrectParam { + param_span: decl.inputs[1].span, + param_num: 2, + expected_ty: tcx.types.isize, + found_ty: argc_arg, + }); + } + } + + // third arg is `*const *const u8` + if let Some(&argv_arg) = inputs.get(2) { + let mut argv_is_okay = false; + if let ty::RawPtr(outer_ptr) = argv_arg.kind() { + if outer_ptr.mutbl.is_not() { + if let ty::RawPtr(inner_ptr) = outer_ptr.ty.kind() { + if inner_ptr.mutbl.is_not() && inner_ptr.ty == tcx.types.u8 { + argv_is_okay = true; + } + } + } + } + + if !argv_is_okay { + let inner_ptr_ty = + tcx.mk_ptr(ty::TypeAndMut { mutbl: hir::Mutability::Not, ty: tcx.types.u8 }); + let expected_ty = + tcx.mk_ptr(ty::TypeAndMut { mutbl: hir::Mutability::Not, ty: inner_ptr_ty }); + tcx.sess.emit_err(LangStartIncorrectParam { + param_span: decl.inputs[2].span, + param_num: 3, + expected_ty, + found_ty: argv_arg, + }); + } + } + + // fourth arg is `sigpipe: u8` + if let Some(&sigpipe_arg) = inputs.get(3) { + if sigpipe_arg != tcx.types.u8 { + tcx.sess.emit_err(LangStartIncorrectParam { + param_span: decl.inputs[3].span, + param_num: 4, + expected_ty: tcx.types.u8, + found_ty: sigpipe_arg, + }); + } + } + + // output type is isize + if fn_sig.output() != tcx.types.isize { + tcx.sess.emit_err(LangStartIncorrectRetTy { + ret_span: decl.output.span(), + expected_ty: tcx.types.isize, + found_ty: fn_sig.output(), + }); + } +} diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs index 507272fdec5..5b4fd5e4a52 100644 --- a/compiler/rustc_hir_typeck/src/errors.rs +++ b/compiler/rustc_hir_typeck/src/errors.rs @@ -172,3 +172,36 @@ impl AddToDiagnostic for TypeMismatchFruTypo { ); } } + +#[derive(Diagnostic)] +#[diag(hir_typeck_lang_start_incorrect_number_params)] +#[note(hir_typeck_lang_start_incorrect_number_params_note_expected_count)] +#[note(hir_typeck_lang_start_expected_sig_note)] +pub struct LangStartIncorrectNumberArgs { + #[primary_span] + pub params_span: Span, + pub found_param_count: usize, +} + +#[derive(Diagnostic)] +#[diag(hir_typeck_lang_start_incorrect_param)] +pub struct LangStartIncorrectParam<'tcx> { + #[primary_span] + #[suggestion(style = "short", code = "{expected_ty}", applicability = "machine-applicable")] + pub param_span: Span, + + pub param_num: usize, + pub expected_ty: Ty<'tcx>, + pub found_ty: Ty<'tcx>, +} + +#[derive(Diagnostic)] +#[diag(hir_typeck_lang_start_incorrect_ret_ty)] +pub struct LangStartIncorrectRetTy<'tcx> { + #[primary_span] + #[suggestion(style = "short", code = "{expected_ty}", applicability = "machine-applicable")] + pub ret_span: Span, + + pub expected_ty: Ty<'tcx>, + pub found_ty: Ty<'tcx>, +} diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 080ae6b9466..533a3c768eb 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -1782,9 +1782,9 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { // like when you have two references but one is `usize` and the other // is `f32`. In those cases we still want to show the `note`. If the // value from `ef` is `Infer(_)`, then we ignore it. - if !ef.expected.is_ty_infer() { + if !ef.expected.is_ty_or_numeric_infer() { ef.expected != values.expected - } else if !ef.found.is_ty_infer() { + } else if !ef.found.is_ty_or_numeric_infer() { ef.found != values.found } else { false diff --git a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs index a4c36b4c9cd..b8c843a8a5a 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs @@ -78,7 +78,7 @@ impl InferenceDiagnosticsData { } fn where_x_is_kind(&self, in_type: Ty<'_>) -> &'static str { - if in_type.is_ty_infer() { + if in_type.is_ty_or_numeric_infer() { "" } else if self.name == "_" { // FIXME: Consider specializing this message if there is a single `_` @@ -195,12 +195,12 @@ fn ty_to_string<'tcx>( // invalid pseudo-syntax, we want the `fn`-pointer output instead. (ty::FnDef(..), _) => ty.fn_sig(infcx.tcx).print(printer).unwrap().into_buffer(), (_, Some(def_id)) - if ty.is_ty_infer() + if ty.is_ty_or_numeric_infer() && infcx.tcx.get_diagnostic_item(sym::iterator_collect_fn) == Some(def_id) => { "Vec<_>".to_string() } - _ if ty.is_ty_infer() => "/* Type */".to_string(), + _ if ty.is_ty_or_numeric_infer() => "/* Type */".to_string(), // FIXME: The same thing for closures, but this only works when the closure // does not capture anything. // @@ -680,7 +680,7 @@ impl<'tcx> InferSourceKind<'tcx> { | InferSourceKind::ClosureReturn { ty, .. } => { if ty.is_closure() { ("closure", closure_as_fn_str(infcx, ty)) - } else if !ty.is_ty_infer() { + } else if !ty.is_ty_or_numeric_infer() { ("normal", ty_to_string(infcx, ty, None)) } else { ("other", String::new()) @@ -813,7 +813,7 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> { self.attempt += 1; if let Some(InferSource { kind: InferSourceKind::GenericArg { def_id: did, ..}, .. }) = self.infer_source && let InferSourceKind::LetBinding { ref ty, ref mut def_id, ..} = new_source.kind - && ty.is_ty_infer() + && ty.is_ty_or_numeric_infer() { // Customize the output so we talk about `let x: Vec<_> = iter.collect();` instead of // `let x: _ = iter.collect();`, as this is a very common case. diff --git a/compiler/rustc_infer/src/infer/error_reporting/note.rs b/compiler/rustc_infer/src/infer/error_reporting/note.rs index 7bb79d7bda8..7504ed094a3 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/note.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/note.rs @@ -29,15 +29,6 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { RegionOriginNote::Plain { span, msg: fluent::infer_relate_object_bound } .add_to_diagnostic(err); } - infer::DataBorrowed(ty, span) => { - RegionOriginNote::WithName { - span, - msg: fluent::infer_data_borrowed, - name: &self.ty_to_string(ty), - continues: false, - } - .add_to_diagnostic(err); - } infer::ReferenceOutlivesReferent(ty, span) => { RegionOriginNote::WithName { span, @@ -227,32 +218,6 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { ); err } - infer::DataBorrowed(ty, span) => { - let mut err = struct_span_err!( - self.tcx.sess, - span, - E0490, - "a value of type `{}` is borrowed for too long", - self.ty_to_string(ty) - ); - note_and_explain_region( - self.tcx, - &mut err, - "the type is valid for ", - sub, - "", - None, - ); - note_and_explain_region( - self.tcx, - &mut err, - "but the borrow lasts for ", - sup, - "", - None, - ); - err - } infer::ReferenceOutlivesReferent(ty, span) => { let mut err = struct_span_err!( self.tcx.sess, diff --git a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs index da2c6fbc05f..897545046c3 100644 --- a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs +++ b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs @@ -702,26 +702,8 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { // Obtain the spans for all the places that can // influence the constraints on this value for // richer diagnostics in `static_impl_trait`. - let influences: Vec<Span> = self - .data - .constraints - .iter() - .filter_map(|(constraint, origin)| match (constraint, origin) { - ( - Constraint::VarSubVar(_, sup), - SubregionOrigin::DataBorrowed(_, sp), - ) if sup == &node_vid => Some(*sp), - _ => None, - }) - .collect(); - - self.collect_error_for_expanding_node( - graph, - &mut dup_vec, - node_vid, - errors, - influences, - ); + + self.collect_error_for_expanding_node(graph, &mut dup_vec, node_vid, errors); } } } @@ -775,7 +757,6 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { dup_vec: &mut IndexVec<RegionVid, Option<RegionVid>>, node_idx: RegionVid, errors: &mut Vec<RegionResolutionError<'tcx>>, - influences: Vec<Span>, ) { // Errors in expanding nodes result from a lower-bound that is // not contained by an upper-bound. @@ -830,7 +811,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { lower_bound.region, upper_bound.origin.clone(), upper_bound.region, - influences, + vec![], )); return; } diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 8825b5e12c3..4acd0d0edfe 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -410,9 +410,6 @@ pub enum SubregionOrigin<'tcx> { /// Creating a pointer `b` to contents of another reference Reborrow(Span), - /// Data with type `Ty<'tcx>` was borrowed - DataBorrowed(Ty<'tcx>, Span), - /// (&'a &'b T) where a >= b ReferenceOutlivesReferent(Ty<'tcx>, Span), @@ -1978,7 +1975,6 @@ impl<'tcx> SubregionOrigin<'tcx> { RelateParamBound(a, ..) => a, RelateRegionParamBound(a) => a, Reborrow(a) => a, - DataBorrowed(_, a) => a, ReferenceOutlivesReferent(_, a) => a, CompareImplItemObligation { span, .. } => span, AscribeUserTypeProvePredicate(span) => span, diff --git a/compiler/rustc_interface/Cargo.toml b/compiler/rustc_interface/Cargo.toml index e67dec31dce..f817c5bc1cd 100644 --- a/compiler/rustc_interface/Cargo.toml +++ b/compiler/rustc_interface/Cargo.toml @@ -45,6 +45,7 @@ rustc_plugin_impl = { path = "../rustc_plugin_impl" } rustc_privacy = { path = "../rustc_privacy" } rustc_query_impl = { path = "../rustc_query_impl" } rustc_resolve = { path = "../rustc_resolve" } +rustc_target = { path = "../rustc_target" } rustc_trait_selection = { path = "../rustc_trait_selection" } rustc_ty_utils = { path = "../rustc_ty_utils" } diff --git a/compiler/rustc_interface/src/errors.rs b/compiler/rustc_interface/src/errors.rs index f5135c78dc8..15d7e977bbe 100644 --- a/compiler/rustc_interface/src/errors.rs +++ b/compiler/rustc_interface/src/errors.rs @@ -87,3 +87,7 @@ pub struct FailedWritingFile<'a> { pub path: &'a Path, pub error: io::Error, } + +#[derive(Diagnostic)] +#[diag(interface_proc_macro_crate_panic_abort)] +pub struct ProcMacroCratePanicAbort; diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 86d56385bc9..50c40206d80 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -1,7 +1,8 @@ use crate::errors::{ CantEmitMIR, EmojiIdentifier, ErrorWritingDependencies, FerrisIdentifier, GeneratedFileConflictsWithDirectory, InputFileWouldBeOverWritten, MixedBinCrate, - MixedProcMacroCrate, OutDirError, ProcMacroDocWithoutArg, TempsDirError, + MixedProcMacroCrate, OutDirError, ProcMacroCratePanicAbort, ProcMacroDocWithoutArg, + TempsDirError, }; use crate::interface::{Compiler, Result}; use crate::proc_macro_decls; @@ -36,6 +37,7 @@ use rustc_session::search_paths::PathKind; use rustc_session::{Limit, Session}; use rustc_span::symbol::{sym, Symbol}; use rustc_span::FileName; +use rustc_target::spec::PanicStrategy; use rustc_trait_selection::traits; use std::any::Any; @@ -380,6 +382,10 @@ pub fn configure_and_expand( } } + if is_proc_macro_crate && sess.panic_strategy() == PanicStrategy::Abort { + sess.emit_warning(ProcMacroCratePanicAbort); + } + // For backwards compatibility, we don't try to run proc macro injection // if rustdoc is run on a proc macro crate without '--crate-type proc-macro' being // specified. This should only affect users who manually invoke 'rustdoc', as @@ -817,23 +823,26 @@ pub fn create_global_ctxt<'tcx>( lint_store, arena, hir_arena, - untracked_resolutions, untracked, - krate, dep_graph, queries.on_disk_cache.as_ref().map(OnDiskCache::as_dyn), queries.as_dyn(), rustc_query_impl::query_callbacks(arena), - crate_name, - outputs, ) }) }); let mut qcx = QueryContext { gcx }; qcx.enter(|tcx| { - tcx.feed_unit_query() - .resolver_for_lowering(tcx.arena.alloc(Steal::new(untracked_resolver_for_lowering))) + let feed = tcx.feed_unit_query(); + feed.resolver_for_lowering( + tcx.arena.alloc(Steal::new((untracked_resolver_for_lowering, krate))), + ); + feed.resolutions(tcx.arena.alloc(untracked_resolutions)); + feed.output_filenames(tcx.arena.alloc(std::sync::Arc::new(outputs))); + feed.features_query(sess.features_untracked()); + let feed = tcx.feed_local_crate(); + feed.crate_name(crate_name); }); qcx } diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs index 1d0c7f5b7a3..041bb9eb7a1 100644 --- a/compiler/rustc_interface/src/queries.rs +++ b/compiler/rustc_interface/src/queries.rs @@ -5,6 +5,7 @@ use crate::passes::{self, BoxedResolver, QueryContext}; use rustc_ast as ast; use rustc_codegen_ssa::traits::CodegenBackend; use rustc_codegen_ssa::CodegenResults; +use rustc_data_structures::steal::Steal; use rustc_data_structures::svh::Svh; use rustc_data_structures::sync::{Lrc, OnceCell, WorkerLocal}; use rustc_hir::def_id::LOCAL_CRATE; @@ -19,43 +20,53 @@ use rustc_session::{output::find_crate_name, Session}; use rustc_span::symbol::sym; use rustc_span::Symbol; use std::any::Any; -use std::cell::{Ref, RefCell, RefMut}; +use std::cell::{RefCell, RefMut}; use std::rc::Rc; use std::sync::Arc; /// Represent the result of a query. /// -/// This result can be stolen with the [`take`] method and generated with the [`compute`] method. +/// This result can be stolen once with the [`steal`] method and generated with the [`compute`] method. /// -/// [`take`]: Self::take +/// [`steal`]: Steal::steal /// [`compute`]: Self::compute pub struct Query<T> { - result: RefCell<Option<Result<T>>>, + /// `None` means no value has been computed yet. + result: RefCell<Option<Result<Steal<T>>>>, } impl<T> Query<T> { - fn compute<F: FnOnce() -> Result<T>>(&self, f: F) -> Result<&Query<T>> { - self.result.borrow_mut().get_or_insert_with(f).as_ref().map(|_| self).map_err(|&err| err) + fn compute<F: FnOnce() -> Result<T>>(&self, f: F) -> Result<QueryResult<'_, T>> { + RefMut::filter_map( + self.result.borrow_mut(), + |r: &mut Option<Result<Steal<T>>>| -> Option<&mut Steal<T>> { + r.get_or_insert_with(|| f().map(Steal::new)).as_mut().ok() + }, + ) + .map_err(|r| *r.as_ref().unwrap().as_ref().map(|_| ()).unwrap_err()) + .map(QueryResult) } +} + +pub struct QueryResult<'a, T>(RefMut<'a, Steal<T>>); + +impl<'a, T> std::ops::Deref for QueryResult<'a, T> { + type Target = RefMut<'a, Steal<T>>; - /// Takes ownership of the query result. Further attempts to take or peek the query - /// result will panic unless it is generated by calling the `compute` method. - pub fn take(&self) -> T { - self.result.borrow_mut().take().expect("missing query result").unwrap() + fn deref(&self) -> &Self::Target { + &self.0 } +} - /// Borrows the query result using the RefCell. Panics if the result is stolen. - pub fn peek(&self) -> Ref<'_, T> { - Ref::map(self.result.borrow(), |r| { - r.as_ref().unwrap().as_ref().expect("missing query result") - }) +impl<'a, T> std::ops::DerefMut for QueryResult<'a, T> { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 } +} - /// Mutably borrows the query result using the RefCell. Panics if the result is stolen. - pub fn peek_mut(&self) -> RefMut<'_, T> { - RefMut::map(self.result.borrow_mut(), |r| { - r.as_mut().unwrap().as_mut().expect("missing query result") - }) +impl<'a, 'tcx> QueryResult<'a, QueryContext<'tcx>> { + pub fn enter<T>(mut self, f: impl FnOnce(TyCtxt<'tcx>) -> T) -> T { + (*self.0).get_mut().enter(f) } } @@ -111,24 +122,24 @@ impl<'tcx> Queries<'tcx> { self.compiler.codegen_backend() } - fn dep_graph_future(&self) -> Result<&Query<Option<DepGraphFuture>>> { + fn dep_graph_future(&self) -> Result<QueryResult<'_, Option<DepGraphFuture>>> { self.dep_graph_future.compute(|| { let sess = self.session(); Ok(sess.opts.build_dep_graph().then(|| rustc_incremental::load_dep_graph(sess))) }) } - pub fn parse(&self) -> Result<&Query<ast::Crate>> { + pub fn parse(&self) -> Result<QueryResult<'_, ast::Crate>> { self.parse.compute(|| { passes::parse(self.session(), &self.compiler.input) .map_err(|mut parse_error| parse_error.emit()) }) } - pub fn register_plugins(&self) -> Result<&Query<(ast::Crate, Lrc<LintStore>)>> { + pub fn register_plugins(&self) -> Result<QueryResult<'_, (ast::Crate, Lrc<LintStore>)>> { self.register_plugins.compute(|| { - let crate_name = *self.crate_name()?.peek(); - let krate = self.parse()?.take(); + let crate_name = *self.crate_name()?.borrow(); + let krate = self.parse()?.steal(); let empty: &(dyn Fn(&Session, &mut LintStore) + Sync + Send) = &|_, _| {}; let (krate, lint_store) = passes::register_plugins( @@ -150,11 +161,11 @@ impl<'tcx> Queries<'tcx> { }) } - pub fn crate_name(&self) -> Result<&Query<Symbol>> { + pub fn crate_name(&self) -> Result<QueryResult<'_, Symbol>> { self.crate_name.compute(|| { Ok({ let parse_result = self.parse()?; - let krate = parse_result.peek(); + let krate = parse_result.borrow(); // parse `#[crate_name]` even if `--crate-name` was passed, to make sure it matches. find_crate_name(self.session(), &krate.attrs, &self.compiler.input) }) @@ -163,11 +174,12 @@ impl<'tcx> Queries<'tcx> { pub fn expansion( &self, - ) -> Result<&Query<(Lrc<ast::Crate>, Rc<RefCell<BoxedResolver>>, Lrc<LintStore>)>> { + ) -> Result<QueryResult<'_, (Lrc<ast::Crate>, Rc<RefCell<BoxedResolver>>, Lrc<LintStore>)>> + { trace!("expansion"); self.expansion.compute(|| { - let crate_name = *self.crate_name()?.peek(); - let (krate, lint_store) = self.register_plugins()?.take(); + let crate_name = *self.crate_name()?.borrow(); + let (krate, lint_store) = self.register_plugins()?.steal(); let _timer = self.session().timer("configure_and_expand"); let sess = self.session(); let mut resolver = passes::create_resolver( @@ -183,10 +195,10 @@ impl<'tcx> Queries<'tcx> { }) } - fn dep_graph(&self) -> Result<&Query<DepGraph>> { + fn dep_graph(&self) -> Result<QueryResult<'_, DepGraph>> { self.dep_graph.compute(|| { let sess = self.session(); - let future_opt = self.dep_graph_future()?.take(); + let future_opt = self.dep_graph_future()?.steal(); let dep_graph = future_opt .and_then(|future| { let (prev_graph, prev_work_products) = @@ -199,10 +211,11 @@ impl<'tcx> Queries<'tcx> { }) } - pub fn prepare_outputs(&self) -> Result<&Query<OutputFilenames>> { + pub fn prepare_outputs(&self) -> Result<QueryResult<'_, OutputFilenames>> { self.prepare_outputs.compute(|| { - let (krate, boxed_resolver, _) = &*self.expansion()?.peek(); - let crate_name = *self.crate_name()?.peek(); + let expansion = self.expansion()?; + let (krate, boxed_resolver, _) = &*expansion.borrow(); + let crate_name = *self.crate_name()?.borrow(); passes::prepare_outputs( self.session(), self.compiler, @@ -213,12 +226,12 @@ impl<'tcx> Queries<'tcx> { }) } - pub fn global_ctxt(&'tcx self) -> Result<&Query<QueryContext<'tcx>>> { + pub fn global_ctxt(&'tcx self) -> Result<QueryResult<'_, QueryContext<'tcx>>> { self.global_ctxt.compute(|| { - let crate_name = *self.crate_name()?.peek(); - let outputs = self.prepare_outputs()?.take(); - let dep_graph = self.dep_graph()?.peek().clone(); - let (krate, resolver, lint_store) = self.expansion()?.take(); + let crate_name = *self.crate_name()?.borrow(); + let outputs = self.prepare_outputs()?.steal(); + let dep_graph = self.dep_graph()?.borrow().clone(); + let (krate, resolver, lint_store) = self.expansion()?.steal(); Ok(passes::create_global_ctxt( self.compiler, lint_store, @@ -235,9 +248,9 @@ impl<'tcx> Queries<'tcx> { }) } - pub fn ongoing_codegen(&'tcx self) -> Result<&Query<Box<dyn Any>>> { + pub fn ongoing_codegen(&'tcx self) -> Result<QueryResult<'_, Box<dyn Any>>> { self.ongoing_codegen.compute(|| { - self.global_ctxt()?.peek_mut().enter(|tcx| { + self.global_ctxt()?.enter(|tcx| { tcx.analysis(()).ok(); // Don't do code generation if there were any errors @@ -293,12 +306,10 @@ impl<'tcx> Queries<'tcx> { let sess = self.session().clone(); let codegen_backend = self.codegen_backend().clone(); - let dep_graph = self.dep_graph()?.peek().clone(); - let (crate_hash, prepare_outputs) = self - .global_ctxt()? - .peek_mut() - .enter(|tcx| (tcx.crate_hash(LOCAL_CRATE), tcx.output_filenames(()).clone())); - let ongoing_codegen = self.ongoing_codegen()?.take(); + let (crate_hash, prepare_outputs, dep_graph) = self.global_ctxt()?.enter(|tcx| { + (tcx.crate_hash(LOCAL_CRATE), tcx.output_filenames(()).clone(), tcx.dep_graph.clone()) + }); + let ongoing_codegen = self.ongoing_codegen()?.steal(); Ok(Linker { sess, @@ -382,6 +393,7 @@ impl Compiler { // NOTE: intentionally does not compute the global context if it hasn't been built yet, // since that likely means there was a parse error. if let Some(Ok(gcx)) = &mut *queries.global_ctxt.result.borrow_mut() { + let gcx = gcx.get_mut(); // We assume that no queries are run past here. If there are new queries // after this point, they'll show up as "<unknown>" in self-profiling data. { diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index a3b9891ee64..07b28cc86ce 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -748,6 +748,7 @@ fn test_unstable_options_tracking_hash() { tracked!(link_only, true); tracked!(llvm_plugins, vec![String::from("plugin_name")]); tracked!(location_detail, LocationDetail { file: true, line: false, column: false }); + tracked!(log_backtrace, Some("filter".to_string())); tracked!(maximal_hir_to_mir_coverage, true); tracked!(merge_functions, Some(MergeFunctions::Disabled)); tracked!(mir_emit_retag, true); diff --git a/compiler/rustc_lint/src/array_into_iter.rs b/compiler/rustc_lint/src/array_into_iter.rs index abebc533cc1..3593f141df6 100644 --- a/compiler/rustc_lint/src/array_into_iter.rs +++ b/compiler/rustc_lint/src/array_into_iter.rs @@ -1,5 +1,5 @@ +use crate::lints::{ArrayIntoIterDiag, ArrayIntoIterDiagSub}; use crate::{LateContext, LateLintPass, LintContext}; -use rustc_errors::{fluent, Applicability}; use rustc_hir as hir; use rustc_middle::ty; use rustc_middle::ty::adjustment::{Adjust, Adjustment}; @@ -118,41 +118,23 @@ impl<'tcx> LateLintPass<'tcx> for ArrayIntoIter { // to an array or to a slice. _ => bug!("array type coerced to something other than array or slice"), }; - cx.struct_span_lint( + let sub = if self.for_expr_span == expr.span { + Some(ArrayIntoIterDiagSub::RemoveIntoIter { + span: receiver_arg.span.shrink_to_hi().to(expr.span.shrink_to_hi()), + }) + } else if receiver_ty.is_array() { + Some(ArrayIntoIterDiagSub::UseExplicitIntoIter { + start_span: expr.span.shrink_to_lo(), + end_span: receiver_arg.span.shrink_to_hi().to(expr.span.shrink_to_hi()), + }) + } else { + None + }; + cx.emit_spanned_lint( ARRAY_INTO_ITER, call.ident.span, - fluent::lint_array_into_iter, - |diag| { - diag.set_arg("target", target); - diag.span_suggestion( - call.ident.span, - fluent::use_iter_suggestion, - "iter", - Applicability::MachineApplicable, - ); - if self.for_expr_span == expr.span { - diag.span_suggestion( - receiver_arg.span.shrink_to_hi().to(expr.span.shrink_to_hi()), - fluent::remove_into_iter_suggestion, - "", - Applicability::MaybeIncorrect, - ); - } else if receiver_ty.is_array() { - diag.multipart_suggestion( - fluent::use_explicit_into_iter_suggestion, - vec![ - (expr.span.shrink_to_lo(), "IntoIterator::into_iter(".into()), - ( - receiver_arg.span.shrink_to_hi().to(expr.span.shrink_to_hi()), - ")".into(), - ), - ], - Applicability::MaybeIncorrect, - ); - } - diag - }, - ) + ArrayIntoIterDiag { target, suggestion: call.ident.span, sub }, + ); } } } diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index d58168ff377..6f445426df7 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -22,6 +22,23 @@ use crate::{ errors::BuiltinEllpisisInclusiveRangePatterns, + lints::{ + BuiltinAnonymousParams, BuiltinBoxPointers, BuiltinClashingExtern, + BuiltinClashingExternSub, BuiltinConstNoMangle, BuiltinDeprecatedAttrLink, + BuiltinDeprecatedAttrLinkSuggestion, BuiltinDeprecatedAttrUsed, BuiltinDerefNullptr, + BuiltinEllipsisInclusiveRangePatternsLint, BuiltinExplicitOutlives, + BuiltinExplicitOutlivesSuggestion, BuiltinIncompleteFeatures, + BuiltinIncompleteFeaturesHelp, BuiltinIncompleteFeaturesNote, BuiltinKeywordIdents, + BuiltinMissingCopyImpl, BuiltinMissingDebugImpl, BuiltinMissingDoc, + BuiltinMutablesTransmutes, BuiltinNoMangleGeneric, BuiltinNonShorthandFieldPatterns, + BuiltinSpecialModuleNameUsed, BuiltinTrivialBounds, BuiltinTypeAliasGenericBounds, + BuiltinTypeAliasGenericBoundsSuggestion, BuiltinTypeAliasWhereClause, + BuiltinUnexpectedCliConfigName, BuiltinUnexpectedCliConfigValue, + BuiltinUngatedAsyncFnTrackCaller, BuiltinUnnameableTestItems, BuiltinUnpermittedTypeInit, + BuiltinUnpermittedTypeInitSub, BuiltinUnreachablePub, BuiltinUnsafe, + BuiltinUnstableFeatures, BuiltinUnusedDocComment, BuiltinUnusedDocCommentSub, + BuiltinWhileTrue, SuggestChangingAssocTypes, + }, types::{transparent_newtype_field, CItemKind}, EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext, }; @@ -33,10 +50,7 @@ use rustc_ast::{self as ast, *}; use rustc_ast_pretty::pprust::{self, expr_to_string}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::stack::ensure_sufficient_stack; -use rustc_errors::{ - fluent, Applicability, DelayDm, Diagnostic, DiagnosticBuilder, DiagnosticMessage, - DiagnosticStyledString, MultiSpan, -}; +use rustc_errors::{fluent, Applicability, DecorateLint, MultiSpan}; use rustc_feature::{deprecated_attributes, AttributeGate, BuiltinAttribute, GateIssue, Stability}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; @@ -110,25 +124,17 @@ impl EarlyLintPass for WhileTrue { && !cond.span.from_expansion() { let condition_span = e.span.with_hi(cond.span.hi()); - cx.struct_span_lint( - WHILE_TRUE, - condition_span, - fluent::lint_builtin_while_true, - |lint| { - lint.span_suggestion_short( - condition_span, - fluent::suggestion, - format!( + let replace = format!( "{}loop", label.map_or_else(String::new, |label| format!( "{}: ", label.ident, )) - ), - Applicability::MachineApplicable, - ) - }, - ) + ); + cx.emit_spanned_lint(WHILE_TRUE, condition_span, BuiltinWhileTrue { + suggestion: condition_span, + replace, + }); } } } @@ -164,12 +170,7 @@ impl BoxPointers { for leaf in ty.walk() { if let GenericArgKind::Type(leaf_ty) = leaf.unpack() { if leaf_ty.is_box() { - cx.struct_span_lint( - BOX_POINTERS, - span, - fluent::lint_builtin_box_pointers, - |lint| lint.set_arg("ty", ty), - ); + cx.emit_spanned_lint(BOX_POINTERS, span, BuiltinBoxPointers { ty }); } } } @@ -267,19 +268,13 @@ impl<'tcx> LateLintPass<'tcx> for NonShorthandFieldPatterns { if cx.tcx.find_field_index(ident, &variant) == Some(cx.typeck_results().field_index(fieldpat.hir_id)) { - cx.struct_span_lint( + cx.emit_spanned_lint( NON_SHORTHAND_FIELD_PATTERNS, fieldpat.span, - fluent::lint_builtin_non_shorthand_field_patterns, - |lint| { - let suggested_ident = - format!("{}{}", binding_annot.prefix_str(), ident); - lint.set_arg("ident", ident).span_suggestion( - fieldpat.span, - fluent::suggestion, - suggested_ident, - Applicability::MachineApplicable, - ) + BuiltinNonShorthandFieldPatterns { + ident, + suggestion: fieldpat.span, + prefix: binding_annot.prefix_str(), }, ); } @@ -321,48 +316,21 @@ impl UnsafeCode { &self, cx: &EarlyContext<'_>, span: Span, - msg: impl Into<DiagnosticMessage>, - decorate: impl for<'a, 'b> FnOnce( - &'b mut DiagnosticBuilder<'a, ()>, - ) -> &'b mut DiagnosticBuilder<'a, ()>, + decorate: impl for<'a> DecorateLint<'a, ()>, ) { // This comes from a macro that has `#[allow_internal_unsafe]`. if span.allows_unsafe() { return; } - cx.struct_span_lint(UNSAFE_CODE, span, msg, decorate); - } - - fn report_overridden_symbol_name( - &self, - cx: &EarlyContext<'_>, - span: Span, - msg: DiagnosticMessage, - ) { - self.report_unsafe(cx, span, msg, |lint| { - lint.note(fluent::lint_builtin_overridden_symbol_name) - }) - } - - fn report_overridden_symbol_section( - &self, - cx: &EarlyContext<'_>, - span: Span, - msg: DiagnosticMessage, - ) { - self.report_unsafe(cx, span, msg, |lint| { - lint.note(fluent::lint_builtin_overridden_symbol_section) - }) + cx.emit_spanned_lint(UNSAFE_CODE, span, decorate); } } impl EarlyLintPass for UnsafeCode { fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &ast::Attribute) { if attr.has_name(sym::allow_internal_unsafe) { - self.report_unsafe(cx, attr.span, fluent::lint_builtin_allow_internal_unsafe, |lint| { - lint - }); + self.report_unsafe(cx, attr.span, BuiltinUnsafe::AllowInternalUnsafe); } } @@ -371,7 +339,7 @@ impl EarlyLintPass for UnsafeCode { if let ast::ExprKind::Block(ref blk, _) = e.kind { // Don't warn about generated blocks; that'll just pollute the output. if blk.rules == ast::BlockCheckMode::Unsafe(ast::UserProvided) { - self.report_unsafe(cx, blk.span, fluent::lint_builtin_unsafe_block, |lint| lint); + self.report_unsafe(cx, blk.span, BuiltinUnsafe::UnsafeBlock); } } } @@ -379,62 +347,38 @@ impl EarlyLintPass for UnsafeCode { fn check_item(&mut self, cx: &EarlyContext<'_>, it: &ast::Item) { match it.kind { ast::ItemKind::Trait(box ast::Trait { unsafety: ast::Unsafe::Yes(_), .. }) => { - self.report_unsafe(cx, it.span, fluent::lint_builtin_unsafe_trait, |lint| lint) + self.report_unsafe(cx, it.span, BuiltinUnsafe::UnsafeTrait); } ast::ItemKind::Impl(box ast::Impl { unsafety: ast::Unsafe::Yes(_), .. }) => { - self.report_unsafe(cx, it.span, fluent::lint_builtin_unsafe_impl, |lint| lint) + self.report_unsafe(cx, it.span, BuiltinUnsafe::UnsafeImpl); } ast::ItemKind::Fn(..) => { if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::no_mangle) { - self.report_overridden_symbol_name( - cx, - attr.span, - fluent::lint_builtin_no_mangle_fn, - ); + self.report_unsafe(cx, attr.span, BuiltinUnsafe::NoMangleFn); } if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::export_name) { - self.report_overridden_symbol_name( - cx, - attr.span, - fluent::lint_builtin_export_name_fn, - ); + self.report_unsafe(cx, attr.span, BuiltinUnsafe::ExportNameFn); } if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::link_section) { - self.report_overridden_symbol_section( - cx, - attr.span, - fluent::lint_builtin_link_section_fn, - ); + self.report_unsafe(cx, attr.span, BuiltinUnsafe::LinkSectionFn); } } ast::ItemKind::Static(..) => { if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::no_mangle) { - self.report_overridden_symbol_name( - cx, - attr.span, - fluent::lint_builtin_no_mangle_static, - ); + self.report_unsafe(cx, attr.span, BuiltinUnsafe::NoMangleStatic); } if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::export_name) { - self.report_overridden_symbol_name( - cx, - attr.span, - fluent::lint_builtin_export_name_static, - ); + self.report_unsafe(cx, attr.span, BuiltinUnsafe::ExportNameStatic); } if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::link_section) { - self.report_overridden_symbol_section( - cx, - attr.span, - fluent::lint_builtin_link_section_static, - ); + self.report_unsafe(cx, attr.span, BuiltinUnsafe::LinkSectionStatic); } } @@ -445,18 +389,10 @@ impl EarlyLintPass for UnsafeCode { fn check_impl_item(&mut self, cx: &EarlyContext<'_>, it: &ast::AssocItem) { if let ast::AssocItemKind::Fn(..) = it.kind { if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::no_mangle) { - self.report_overridden_symbol_name( - cx, - attr.span, - fluent::lint_builtin_no_mangle_method, - ); + self.report_unsafe(cx, attr.span, BuiltinUnsafe::NoMangleMethod); } if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::export_name) { - self.report_overridden_symbol_name( - cx, - attr.span, - fluent::lint_builtin_export_name_method, - ); + self.report_unsafe(cx, attr.span, BuiltinUnsafe::ExportNameMethod); } } } @@ -471,13 +407,13 @@ impl EarlyLintPass for UnsafeCode { body, ) = fk { - let msg = match ctxt { + let decorator = match ctxt { FnCtxt::Foreign => return, - FnCtxt::Free => fluent::lint_builtin_decl_unsafe_fn, - FnCtxt::Assoc(_) if body.is_none() => fluent::lint_builtin_decl_unsafe_method, - FnCtxt::Assoc(_) => fluent::lint_builtin_impl_unsafe_method, + FnCtxt::Free => BuiltinUnsafe::DeclUnsafeFn, + FnCtxt::Assoc(_) if body.is_none() => BuiltinUnsafe::DeclUnsafeMethod, + FnCtxt::Assoc(_) => BuiltinUnsafe::ImplUnsafeMethod, }; - self.report_unsafe(cx, span, msg, |lint| lint); + self.report_unsafe(cx, span, decorator); } } } @@ -578,11 +514,10 @@ impl MissingDoc { let attrs = cx.tcx.hir().attrs(cx.tcx.hir().local_def_id_to_hir_id(def_id)); let has_doc = attrs.iter().any(has_doc); if !has_doc { - cx.struct_span_lint( + cx.emit_spanned_lint( MISSING_DOCS, cx.tcx.def_span(def_id), - fluent::lint_builtin_missing_doc, - |lint| lint.set_arg("article", article).set_arg("desc", desc), + BuiltinMissingDoc { article, desc }, ); } } @@ -799,12 +734,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingCopyImplementations { ) .is_ok() { - cx.struct_span_lint( - MISSING_COPY_IMPLEMENTATIONS, - item.span, - fluent::lint_builtin_missing_copy_impl, - |lint| lint, - ) + cx.emit_spanned_lint(MISSING_COPY_IMPLEMENTATIONS, item.span, BuiltinMissingCopyImpl); } } } @@ -878,11 +808,10 @@ impl<'tcx> LateLintPass<'tcx> for MissingDebugImplementations { } if !self.impling_types.as_ref().unwrap().contains(&item.owner_id.def_id) { - cx.struct_span_lint( + cx.emit_spanned_lint( MISSING_DEBUG_IMPLEMENTATIONS, item.span, - fluent::lint_builtin_missing_debug_impl, - |lint| lint.set_arg("debug", cx.tcx.def_path_str(debug)), + BuiltinMissingDebugImpl { tcx: cx.tcx, def_id: debug }, ); } } @@ -958,19 +887,11 @@ impl EarlyLintPass for AnonymousParameters { } else { ("<type>", Applicability::HasPlaceholders) }; - cx.struct_span_lint( + cx.emit_spanned_lint( ANONYMOUS_PARAMETERS, arg.pat.span, - fluent::lint_builtin_anonymous_params, - |lint| { - lint.span_suggestion( - arg.pat.span, - fluent::suggestion, - format!("_: {}", ty_snip), - appl, - ) - }, - ) + BuiltinAnonymousParams { suggestion: (arg.pat.span, appl), ty_snip }, + ); } } } @@ -1005,42 +926,30 @@ impl EarlyLintPass for DeprecatedAttr { _, ) = gate { - // FIXME(davidtwco) translatable deprecated attr - cx.struct_span_lint( + let suggestion = match suggestion { + Some(msg) => { + BuiltinDeprecatedAttrLinkSuggestion::Msg { suggestion: attr.span, msg } + } + None => { + BuiltinDeprecatedAttrLinkSuggestion::Default { suggestion: attr.span } + } + }; + cx.emit_spanned_lint( DEPRECATED, attr.span, - fluent::lint_builtin_deprecated_attr_link, - |lint| { - lint.set_arg("name", name) - .set_arg("reason", reason) - .set_arg("link", link) - .span_suggestion_short( - attr.span, - suggestion.map(|s| s.into()).unwrap_or( - fluent::lint_builtin_deprecated_attr_default_suggestion, - ), - "", - Applicability::MachineApplicable, - ) - }, + BuiltinDeprecatedAttrLink { name, reason, link, suggestion }, ); } return; } } if attr.has_name(sym::no_start) || attr.has_name(sym::crate_id) { - cx.struct_span_lint( + cx.emit_spanned_lint( DEPRECATED, attr.span, - fluent::lint_builtin_deprecated_attr_used, - |lint| { - lint.set_arg("name", pprust::path_to_string(&attr.get_normal_item().path)) - .span_suggestion_short( - attr.span, - fluent::lint_builtin_deprecated_attr_default_suggestion, - "", - Applicability::MachineApplicable, - ) + BuiltinDeprecatedAttrUsed { + name: pprust::path_to_string(&attr.get_normal_item().path), + suggestion: attr.span, }, ); } @@ -1069,20 +978,18 @@ fn warn_if_doc(cx: &EarlyContext<'_>, node_span: Span, node_kind: &str, attrs: & let span = sugared_span.take().unwrap_or(attr.span); if is_doc_comment || attr.has_name(sym::doc) { - cx.struct_span_lint( + let sub = match attr.kind { + AttrKind::DocComment(CommentKind::Line, _) | AttrKind::Normal(..) => { + BuiltinUnusedDocCommentSub::PlainHelp + } + AttrKind::DocComment(CommentKind::Block, _) => { + BuiltinUnusedDocCommentSub::BlockHelp + } + }; + cx.emit_spanned_lint( UNUSED_DOC_COMMENTS, span, - fluent::lint_builtin_unused_doc_comment, - |lint| { - lint.set_arg("kind", node_kind).span_label(node_span, fluent::label).help( - match attr.kind { - AttrKind::DocComment(CommentKind::Line, _) | AttrKind::Normal(..) => { - fluent::plain_help - } - AttrKind::DocComment(CommentKind::Block, _) => fluent::block_help, - }, - ) - }, + BuiltinUnusedDocComment { kind: node_kind, label: node_span, sub }, ); } } @@ -1197,20 +1104,10 @@ impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems { match param.kind { GenericParamKind::Lifetime { .. } => {} GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => { - cx.struct_span_lint( + cx.emit_spanned_lint( NO_MANGLE_GENERIC_ITEMS, span, - fluent::lint_builtin_no_mangle_generic, - |lint| { - lint.span_suggestion_short( - no_mangle_attr.span, - fluent::suggestion, - "", - // Use of `#[no_mangle]` suggests FFI intent; correct - // fix may be to monomorphize source by hand - Applicability::MaybeIncorrect, - ) - }, + BuiltinNoMangleGeneric { suggestion: no_mangle_attr.span }, ); break; } @@ -1225,30 +1122,23 @@ impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems { } hir::ItemKind::Const(..) => { if cx.sess().contains_name(attrs, sym::no_mangle) { + // account for "pub const" (#45562) + let start = cx + .tcx + .sess + .source_map() + .span_to_snippet(it.span) + .map(|snippet| snippet.find("const").unwrap_or(0)) + .unwrap_or(0) as u32; + // `const` is 5 chars + let suggestion = it.span.with_hi(BytePos(it.span.lo().0 + start + 5)); + // Const items do not refer to a particular location in memory, and therefore // don't have anything to attach a symbol to - cx.struct_span_lint( + cx.emit_spanned_lint( NO_MANGLE_CONST_ITEMS, it.span, - fluent::lint_builtin_const_no_mangle, - |lint| { - // account for "pub const" (#45562) - let start = cx - .tcx - .sess - .source_map() - .span_to_snippet(it.span) - .map(|snippet| snippet.find("const").unwrap_or(0)) - .unwrap_or(0) as u32; - // `const` is 5 chars - let const_span = it.span.with_hi(BytePos(it.span.lo().0 + start + 5)); - lint.span_suggestion( - const_span, - fluent::suggestion, - "pub static", - Applicability::MachineApplicable, - ) - }, + BuiltinConstNoMangle { suggestion }, ); } } @@ -1309,12 +1199,7 @@ impl<'tcx> LateLintPass<'tcx> for MutableTransmutes { get_transmute_from_to(cx, expr).map(|(ty1, ty2)| (ty1.kind(), ty2.kind())) { if from_mutbl < to_mutbl { - cx.struct_span_lint( - MUTABLE_TRANSMUTES, - expr.span, - fluent::lint_builtin_mutable_transmutes, - |lint| lint, - ); + cx.emit_spanned_lint(MUTABLE_TRANSMUTES, expr.span, BuiltinMutablesTransmutes); } } @@ -1362,12 +1247,7 @@ impl<'tcx> LateLintPass<'tcx> for UnstableFeatures { if attr.has_name(sym::feature) { if let Some(items) = attr.meta_item_list() { for item in items { - cx.struct_span_lint( - UNSTABLE_FEATURES, - item.span(), - fluent::lint_builtin_unstable_features, - |lint| lint, - ); + cx.emit_spanned_lint(UNSTABLE_FEATURES, item.span(), BuiltinUnstableFeatures); } } } @@ -1422,20 +1302,10 @@ impl<'tcx> LateLintPass<'tcx> for UngatedAsyncFnTrackCaller { // Now, check if the function has the `#[track_caller]` attribute && let Some(attr) = attrs.iter().find(|attr| attr.has_name(sym::track_caller)) { - cx.struct_span_lint( - UNGATED_ASYNC_FN_TRACK_CALLER, - attr.span, - fluent::lint_ungated_async_fn_track_caller, - |lint| { - lint.span_label(span, fluent::label); - rustc_session::parse::add_feature_diagnostics( - lint, - &cx.tcx.sess.parse_sess, - sym::closure_track_caller, - ); - lint - }, - ); + cx.emit_spanned_lint(UNGATED_ASYNC_FN_TRACK_CALLER, attr.span, BuiltinUngatedAsyncFnTrackCaller { + label: span, + parse_sess: &cx.tcx.sess.parse_sess, + }); } } } @@ -1493,18 +1363,13 @@ impl UnreachablePub { applicability = Applicability::MaybeIncorrect; } let def_span = cx.tcx.def_span(def_id); - cx.struct_span_lint( + cx.emit_spanned_lint( UNREACHABLE_PUB, def_span, - fluent::lint_builtin_unreachable_pub, - |lint| { - lint.set_arg("what", what); - - lint.span_suggestion(vis_span, fluent::suggestion, "pub(crate)", applicability); - if exportable { - lint.help(fluent::help); - } - lint + BuiltinUnreachablePub { + what, + suggestion: (vis_span, applicability), + help: exportable.then_some(()), }, ); } @@ -1569,7 +1434,7 @@ declare_lint_pass!( ); impl TypeAliasBounds { - fn is_type_variable_assoc(qpath: &hir::QPath<'_>) -> bool { + pub(crate) fn is_type_variable_assoc(qpath: &hir::QPath<'_>) -> bool { match *qpath { hir::QPath::TypeRelative(ref ty, _) => { // If this is a type variable, we found a `T::Assoc`. @@ -1583,29 +1448,6 @@ impl TypeAliasBounds { hir::QPath::Resolved(..) | hir::QPath::LangItem(..) => false, } } - - fn suggest_changing_assoc_types(ty: &hir::Ty<'_>, err: &mut Diagnostic) { - // Access to associates types should use `<T as Bound>::Assoc`, which does not need a - // bound. Let's see if this type does that. - - // We use a HIR visitor to walk the type. - use rustc_hir::intravisit::{self, Visitor}; - struct WalkAssocTypes<'a> { - err: &'a mut Diagnostic, - } - impl Visitor<'_> for WalkAssocTypes<'_> { - fn visit_qpath(&mut self, qpath: &hir::QPath<'_>, id: hir::HirId, span: Span) { - if TypeAliasBounds::is_type_variable_assoc(qpath) { - self.err.span_help(span, fluent::lint_builtin_type_alias_bounds_help); - } - intravisit::walk_qpath(self, qpath, id) - } - } - - // Let's go for a walk! - let mut visitor = WalkAssocTypes { err }; - visitor.visit_ty(ty); - } } impl<'tcx> LateLintPass<'tcx> for TypeAliasBounds { @@ -1639,35 +1481,31 @@ impl<'tcx> LateLintPass<'tcx> for TypeAliasBounds { let mut suggested_changing_assoc_types = false; if !where_spans.is_empty() { - cx.lint(TYPE_ALIAS_BOUNDS, fluent::lint_builtin_type_alias_where_clause, |lint| { - lint.set_span(where_spans); - lint.span_suggestion( - type_alias_generics.where_clause_span, - fluent::suggestion, - "", - Applicability::MachineApplicable, - ); - if !suggested_changing_assoc_types { - TypeAliasBounds::suggest_changing_assoc_types(ty, lint); - suggested_changing_assoc_types = true; - } - lint + let sub = (!suggested_changing_assoc_types).then(|| { + suggested_changing_assoc_types = true; + SuggestChangingAssocTypes { ty } }); + cx.emit_spanned_lint( + TYPE_ALIAS_BOUNDS, + where_spans, + BuiltinTypeAliasWhereClause { + suggestion: type_alias_generics.where_clause_span, + sub, + }, + ); } if !inline_spans.is_empty() { - cx.lint(TYPE_ALIAS_BOUNDS, fluent::lint_builtin_type_alias_generic_bounds, |lint| { - lint.set_span(inline_spans); - lint.multipart_suggestion( - fluent::suggestion, - inline_sugg, - Applicability::MachineApplicable, - ); - if !suggested_changing_assoc_types { - TypeAliasBounds::suggest_changing_assoc_types(ty, lint); - } - lint + let suggestion = BuiltinTypeAliasGenericBoundsSuggestion { suggestions: inline_sugg }; + let sub = (!suggested_changing_assoc_types).then(|| { + suggested_changing_assoc_types = true; + SuggestChangingAssocTypes { ty } }); + cx.emit_spanned_lint( + TYPE_ALIAS_BOUNDS, + inline_spans, + BuiltinTypeAliasGenericBounds { suggestion, sub }, + ); } } } @@ -1767,14 +1605,10 @@ impl<'tcx> LateLintPass<'tcx> for TrivialConstraints { TypeWellFormedFromEnv(..) => continue, }; if predicate.is_global() { - cx.struct_span_lint( + cx.emit_spanned_lint( TRIVIAL_BOUNDS, span, - fluent::lint_builtin_trivial_bounds, - |lint| { - lint.set_arg("predicate_kind_name", predicate_kind_name) - .set_arg("predicate", predicate) - }, + BuiltinTrivialBounds { predicate_kind_name, predicate }, ); } } @@ -1875,8 +1709,6 @@ impl EarlyLintPass for EllipsisInclusiveRangePatterns { }; if let Some((start, end, join)) = endpoints { - let msg = fluent::lint_builtin_ellipsis_inclusive_range_patterns; - let suggestion = fluent::suggestion; if parenthesise { self.node_id = Some(pat.id); let end = expr_to_string(&end); @@ -1891,14 +1723,14 @@ impl EarlyLintPass for EllipsisInclusiveRangePatterns { replace, }); } else { - cx.struct_span_lint(ELLIPSIS_INCLUSIVE_RANGE_PATTERNS, pat.span, msg, |lint| { - lint.span_suggestion( - pat.span, - suggestion, + cx.emit_spanned_lint( + ELLIPSIS_INCLUSIVE_RANGE_PATTERNS, + pat.span, + BuiltinEllipsisInclusiveRangePatternsLint::Parenthesise { + suggestion: pat.span, replace, - Applicability::MachineApplicable, - ) - }); + }, + ); } } else { let replace = "..="; @@ -1909,14 +1741,13 @@ impl EarlyLintPass for EllipsisInclusiveRangePatterns { replace: replace.to_string(), }); } else { - cx.struct_span_lint(ELLIPSIS_INCLUSIVE_RANGE_PATTERNS, join, msg, |lint| { - lint.span_suggestion_short( - join, - suggestion, - replace, - Applicability::MachineApplicable, - ) - }); + cx.emit_spanned_lint( + ELLIPSIS_INCLUSIVE_RANGE_PATTERNS, + join, + BuiltinEllipsisInclusiveRangePatternsLint::NonParenthesise { + suggestion: join, + }, + ); } }; } @@ -1996,12 +1827,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnameableTestItems { let attrs = cx.tcx.hir().attrs(it.hir_id()); if let Some(attr) = cx.sess().find_by_name(attrs, sym::rustc_test_marker) { - cx.struct_span_lint( - UNNAMEABLE_TEST_ITEMS, - attr.span, - fluent::lint_builtin_unnameable_test_items, - |lint| lint, - ); + cx.emit_spanned_lint(UNNAMEABLE_TEST_ITEMS, attr.span, BuiltinUnnameableTestItems); } } @@ -2117,18 +1943,10 @@ impl KeywordIdents { return; } - cx.struct_span_lint( + cx.emit_spanned_lint( KEYWORD_IDENTS, ident.span, - fluent::lint_builtin_keyword_idents, - |lint| { - lint.set_arg("kw", ident).set_arg("next", next_edition).span_suggestion( - ident.span, - fluent::suggestion, - format!("r#{}", ident), - Applicability::MachineApplicable, - ) - }, + BuiltinKeywordIdents { kw: ident, next: next_edition, suggestion: ident.span }, ); } } @@ -2405,16 +2223,15 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitOutlivesRequirements { Applicability::MaybeIncorrect }; - cx.struct_span_lint( + cx.emit_spanned_lint( EXPLICIT_OUTLIVES_REQUIREMENTS, lint_spans.clone(), - fluent::lint_builtin_explicit_outlives, - |lint| { - lint.set_arg("count", bound_count).multipart_suggestion( - fluent::suggestion, - lint_spans.into_iter().map(|span| (span, String::new())).collect(), + BuiltinExplicitOutlives { + count: bound_count, + suggestion: BuiltinExplicitOutlivesSuggestion { + spans: lint_spans, applicability, - ) + }, }, ); } @@ -2463,24 +2280,18 @@ impl EarlyLintPass for IncompleteFeatures { .chain(features.declared_lib_features.iter().map(|(name, span)| (name, span))) .filter(|(&name, _)| features.incomplete(name)) .for_each(|(&name, &span)| { - cx.struct_span_lint( + let note = rustc_feature::find_feature_issue(name, GateIssue::Language) + .map(|n| BuiltinIncompleteFeaturesNote { n }); + let help = if HAS_MIN_FEATURES.contains(&name) { + Some(BuiltinIncompleteFeaturesHelp) + } else { + None + }; + cx.emit_spanned_lint( INCOMPLETE_FEATURES, span, - fluent::lint_builtin_incomplete_features, - |lint| { - lint.set_arg("name", name); - if let Some(n) = - rustc_feature::find_feature_issue(name, GateIssue::Language) - { - lint.set_arg("n", n); - lint.note(fluent::note); - } - if HAS_MIN_FEATURES.contains(&name) { - lint.help(fluent::help); - } - lint - }, - ) + BuiltinIncompleteFeatures { name, note, help }, + ); }); } } @@ -2525,6 +2336,36 @@ declare_lint! { declare_lint_pass!(InvalidValue => [INVALID_VALUE]); +/// Information about why a type cannot be initialized this way. +pub struct InitError { + pub(crate) message: String, + /// Spans from struct fields and similar that can be obtained from just the type. + pub(crate) span: Option<Span>, + /// Used to report a trace through adts. + pub(crate) nested: Option<Box<InitError>>, +} +impl InitError { + fn spanned(self, span: Span) -> InitError { + Self { span: Some(span), ..self } + } + + fn nested(self, nested: impl Into<Option<InitError>>) -> InitError { + assert!(self.nested.is_none()); + Self { nested: nested.into().map(Box::new), ..self } + } +} + +impl<'a> From<&'a str> for InitError { + fn from(s: &'a str) -> Self { + s.to_owned().into() + } +} +impl From<String> for InitError { + fn from(message: String) -> Self { + Self { message, span: None, nested: None } + } +} + impl<'tcx> LateLintPass<'tcx> for InvalidValue { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &hir::Expr<'_>) { #[derive(Debug, Copy, Clone, PartialEq)] @@ -2533,36 +2374,6 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue { Uninit, } - /// Information about why a type cannot be initialized this way. - struct InitError { - message: String, - /// Spans from struct fields and similar that can be obtained from just the type. - span: Option<Span>, - /// Used to report a trace through adts. - nested: Option<Box<InitError>>, - } - impl InitError { - fn spanned(self, span: Span) -> InitError { - Self { span: Some(span), ..self } - } - - fn nested(self, nested: impl Into<Option<InitError>>) -> InitError { - assert!(self.nested.is_none()); - Self { nested: nested.into().map(Box::new), ..self } - } - } - - impl<'a> From<&'a str> for InitError { - fn from(s: &'a str) -> Self { - s.to_owned().into() - } - } - impl From<String> for InitError { - fn from(message: String) -> Self { - Self { message, span: None, nested: None } - } - } - /// Test if this constant is all-0. fn is_zero(expr: &hir::Expr<'_>) -> bool { use hir::ExprKind::*; @@ -2786,46 +2597,16 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue { // using zeroed or uninitialized memory. // We are extremely conservative with what we warn about. let conjured_ty = cx.typeck_results().expr_ty(expr); - if let Some(mut err) = with_no_trimmed_paths!(ty_find_init_error(cx, conjured_ty, init)) - { - // FIXME(davidtwco): make translatable - cx.struct_span_lint( + if let Some(err) = with_no_trimmed_paths!(ty_find_init_error(cx, conjured_ty, init)) { + let msg = match init { + InitKind::Zeroed => fluent::lint_builtin_unpermitted_type_init_zeroed, + InitKind::Uninit => fluent::lint_builtin_unpermitted_type_init_unint, + }; + let sub = BuiltinUnpermittedTypeInitSub { err }; + cx.emit_spanned_lint( INVALID_VALUE, expr.span, - DelayDm(|| { - format!( - "the type `{}` does not permit {}", - conjured_ty, - match init { - InitKind::Zeroed => "zero-initialization", - InitKind::Uninit => "being left uninitialized", - }, - ) - }), - |lint| { - lint.span_label( - expr.span, - "this code causes undefined behavior when executed", - ); - lint.span_label( - expr.span, - "help: use `MaybeUninit<T>` instead, \ - and only call `assume_init` after initialization is done", - ); - loop { - if let Some(span) = err.span { - lint.span_note(span, &err.message); - } else { - lint.note(&err.message); - } - if let Some(e) = err.nested { - err = *e; - } else { - break; - } - } - lint - }, + BuiltinUnpermittedTypeInit { msg, ty: conjured_ty, label: expr.span, sub }, ); } } @@ -3171,31 +2952,39 @@ impl<'tcx> LateLintPass<'tcx> for ClashingExternDeclarations { SymbolName::Normal(_) => fi.span, SymbolName::Link(_, annot_span) => fi.span.to(annot_span), }; - // Finally, emit the diagnostic. - let msg = if orig.get_name() == this_fi.ident.name { - fluent::lint_builtin_clashing_extern_same_name + // Finally, emit the diagnostic. + let this = this_fi.ident.name; + let orig = orig.get_name(); + let previous_decl_label = get_relevant_span(orig_fi); + let mismatch_label = get_relevant_span(this_fi); + let sub = BuiltinClashingExternSub { + tcx, + expected: existing_decl_ty, + found: this_decl_ty, + }; + let decorator = if orig == this { + BuiltinClashingExtern::SameName { + this, + orig, + previous_decl_label, + mismatch_label, + sub, + } } else { - fluent::lint_builtin_clashing_extern_diff_name + BuiltinClashingExtern::DiffName { + this, + orig, + previous_decl_label, + mismatch_label, + sub, + } }; - tcx.struct_span_lint_hir( + tcx.emit_spanned_lint( CLASHING_EXTERN_DECLARATIONS, this_fi.hir_id(), get_relevant_span(this_fi), - msg, - |lint| { - let mut expected_str = DiagnosticStyledString::new(); - expected_str.push(existing_decl_ty.fn_sig(tcx).to_string(), false); - let mut found_str = DiagnosticStyledString::new(); - found_str.push(this_decl_ty.fn_sig(tcx).to_string(), true); - - lint.set_arg("this_fi", this_fi.ident.name) - .set_arg("orig", orig.get_name()) - .span_label(get_relevant_span(orig_fi), fluent::previous_decl_label) - .span_label(get_relevant_span(this_fi), fluent::mismatch_label) - // FIXME(davidtwco): translatable expected/found - .note_expected_found(&"", expected_str, &"", found_str) - }, + decorator, ); } } @@ -3275,11 +3064,10 @@ impl<'tcx> LateLintPass<'tcx> for DerefNullPtr { if let rustc_hir::ExprKind::Unary(rustc_hir::UnOp::Deref, expr_deref) = expr.kind { if is_null_ptr(cx, expr_deref) { - cx.struct_span_lint( + cx.emit_spanned_lint( DEREF_NULLPTR, expr.span, - fluent::lint_builtin_deref_nullptr, - |lint| lint.span_label(expr.span, fluent::label), + BuiltinDerefNullptr { label: expr.span }, ); } } @@ -3324,6 +3112,7 @@ declare_lint! { declare_lint_pass!(NamedAsmLabels => [NAMED_ASM_LABELS]); impl<'tcx> LateLintPass<'tcx> for NamedAsmLabels { + #[allow(rustc::diagnostic_outside_of_impl)] fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) { if let hir::Expr { kind: hir::ExprKind::InlineAsm(hir::InlineAsm { template_strs, .. }), @@ -3464,16 +3253,17 @@ impl EarlyLintPass for SpecialModuleName { } match item.ident.name.as_str() { - "lib" => cx.struct_span_lint(SPECIAL_MODULE_NAME, item.span, "found module declaration for lib.rs", |lint| { - lint - .note("lib.rs is the root of this crate's library target") - .help("to refer to it from other targets, use the library's name as the path") - }), - "main" => cx.struct_span_lint(SPECIAL_MODULE_NAME, item.span, "found module declaration for main.rs", |lint| { - lint - .note("a binary crate cannot be used as library") - }), - _ => continue + "lib" => cx.emit_spanned_lint( + SPECIAL_MODULE_NAME, + item.span, + BuiltinSpecialModuleNameUsed::Lib, + ), + "main" => cx.emit_spanned_lint( + SPECIAL_MODULE_NAME, + item.span, + BuiltinSpecialModuleNameUsed::Main, + ), + _ => continue, } } } @@ -3489,31 +3279,16 @@ impl EarlyLintPass for UnexpectedCfgs { let cfg = &cx.sess().parse_sess.config; let check_cfg = &cx.sess().parse_sess.check_config; for &(name, value) in cfg { - if let Some(names_valid) = &check_cfg.names_valid { - if !names_valid.contains(&name) { - cx.lookup( - UNEXPECTED_CFGS, - None::<MultiSpan>, - fluent::lint_builtin_unexpected_cli_config_name, - |diag| diag.help(fluent::help).set_arg("name", name), - ); - } + if let Some(names_valid) = &check_cfg.names_valid && !names_valid.contains(&name){ + cx.emit_lint(UNEXPECTED_CFGS, BuiltinUnexpectedCliConfigName { + name, + }); } - if let Some(value) = value { - if let Some(values) = &check_cfg.values_valid.get(&name) { - if !values.contains(&value) { - cx.lookup( - UNEXPECTED_CFGS, - None::<MultiSpan>, - fluent::lint_builtin_unexpected_cli_config_value, - |diag| { - diag.help(fluent::help) - .set_arg("name", name) - .set_arg("value", value) - }, - ); - } - } + if let Some(value) = value && let Some(values) = check_cfg.values_valid.get(&name) && !values.contains(&value) { + cx.emit_lint( + UNEXPECTED_CFGS, + BuiltinUnexpectedCliConfigValue { name, value }, + ); } } } diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index a16bb7f1a5f..c9b9a622571 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -965,6 +965,7 @@ pub trait LintContext: Sized { /// Note that this function should only be called for [`LintExpectationId`]s /// retrieved from the current lint pass. Buffered or manually created ids can /// cause ICEs. + #[rustc_lint_diagnostics] fn fulfill_expectation(&self, expectation: LintExpectationId) { // We need to make sure that submitted expectation ids are correctly fulfilled suppressed // and stored between compilation sessions. To not manually do these steps, we simply create @@ -1011,6 +1012,7 @@ impl<'tcx> LintContext for LateContext<'tcx> { &*self.lint_store } + #[rustc_lint_diagnostics] fn lookup<S: Into<MultiSpan>>( &self, lint: &'static Lint, @@ -1045,6 +1047,7 @@ impl LintContext for EarlyContext<'_> { self.builder.lint_store() } + #[rustc_lint_diagnostics] fn lookup<S: Into<MultiSpan>>( &self, lint: &'static Lint, diff --git a/compiler/rustc_lint/src/deref_into_dyn_supertrait.rs b/compiler/rustc_lint/src/deref_into_dyn_supertrait.rs index 1d29a234a3c..dff5a645c17 100644 --- a/compiler/rustc_lint/src/deref_into_dyn_supertrait.rs +++ b/compiler/rustc_lint/src/deref_into_dyn_supertrait.rs @@ -1,6 +1,8 @@ -use crate::{LateContext, LateLintPass, LintContext}; +use crate::{ + lints::{SupertraitAsDerefTarget, SupertraitAsDerefTargetLabel}, + LateContext, LateLintPass, LintContext, +}; -use rustc_errors::DelayDm; use rustc_hir as hir; use rustc_middle::{traits::util::supertraits, ty}; use rustc_span::sym; @@ -71,22 +73,14 @@ impl<'tcx> LateLintPass<'tcx> for DerefIntoDynSupertrait { && supertraits(cx.tcx, t_principal.with_self_ty(cx.tcx, cx.tcx.types.trait_object_dummy_self)) .any(|sup| sup.map_bound(|x| ty::ExistentialTraitRef::erase_self_ty(cx.tcx, x)) == target_principal) { - cx.struct_span_lint( - DEREF_INTO_DYN_SUPERTRAIT, - cx.tcx.def_span(item.owner_id.def_id), - DelayDm(|| { - format!( - "`{t}` implements `Deref` with supertrait `{target_principal}` as target" - ) - }), - |lint| { - if let Some(target_span) = impl_.items.iter().find_map(|i| (i.ident.name == sym::Target).then_some(i.span)) { - lint.span_label(target_span, "target type is set here"); - } - - lint - }, - ) + let label = impl_.items.iter().find_map(|i| (i.ident.name == sym::Target).then_some(i.span)).map(|label| SupertraitAsDerefTargetLabel { + label, + }); + cx.emit_spanned_lint(DEREF_INTO_DYN_SUPERTRAIT, cx.tcx.def_span(item.owner_id.def_id), SupertraitAsDerefTarget { + t, + target_principal: target_principal.to_string(), + label, + }); } } } diff --git a/compiler/rustc_lint/src/early.rs b/compiler/rustc_lint/src/early.rs index d757471dcee..f9b2df49592 100644 --- a/compiler/rustc_lint/src/early.rs +++ b/compiler/rustc_lint/src/early.rs @@ -40,6 +40,7 @@ pub struct EarlyContextAndPass<'a, T: EarlyLintPass> { impl<'a, T: EarlyLintPass> EarlyContextAndPass<'a, T> { // This always-inlined function is for the hot call site. #[inline(always)] + #[allow(rustc::diagnostic_outside_of_impl)] fn inlined_check_id(&mut self, id: ast::NodeId) { for early_lint in self.context.buffered.take(id) { let BufferedEarlyLint { span, msg, node_id: _, lint_id, diagnostic } = early_lint; diff --git a/compiler/rustc_lint/src/enum_intrinsics_non_enums.rs b/compiler/rustc_lint/src/enum_intrinsics_non_enums.rs index f9d7466228a..73bd4173270 100644 --- a/compiler/rustc_lint/src/enum_intrinsics_non_enums.rs +++ b/compiler/rustc_lint/src/enum_intrinsics_non_enums.rs @@ -1,5 +1,8 @@ -use crate::{context::LintContext, LateContext, LateLintPass}; -use rustc_errors::fluent; +use crate::{ + context::LintContext, + lints::{EnumIntrinsicsMemDiscriminate, EnumIntrinsicsMemVariant}, + LateContext, LateLintPass, +}; use rustc_hir as hir; use rustc_middle::ty::{visit::TypeVisitable, Ty}; use rustc_span::{symbol::sym, Span}; @@ -50,11 +53,10 @@ fn enforce_mem_discriminant( ) { let ty_param = cx.typeck_results().node_substs(func_expr.hir_id).type_at(0); if is_non_enum(ty_param) { - cx.struct_span_lint( + cx.emit_spanned_lint( ENUM_INTRINSICS_NON_ENUMS, expr_span, - fluent::lint_enum_intrinsics_mem_discriminant, - |lint| lint.set_arg("ty_param", ty_param).span_note(args_span, fluent::note), + EnumIntrinsicsMemDiscriminate { ty_param, note: args_span }, ); } } @@ -62,11 +64,10 @@ fn enforce_mem_discriminant( fn enforce_mem_variant_count(cx: &LateContext<'_>, func_expr: &hir::Expr<'_>, span: Span) { let ty_param = cx.typeck_results().node_substs(func_expr.hir_id).type_at(0); if is_non_enum(ty_param) { - cx.struct_span_lint( + cx.emit_spanned_lint( ENUM_INTRINSICS_NON_ENUMS, span, - fluent::lint_enum_intrinsics_mem_variant, - |lint| lint.set_arg("ty_param", ty_param).note(fluent::note), + EnumIntrinsicsMemVariant { ty_param }, ); } } diff --git a/compiler/rustc_lint/src/errors.rs b/compiler/rustc_lint/src/errors.rs index 1a769893f55..f3ae2609186 100644 --- a/compiler/rustc_lint/src/errors.rs +++ b/compiler/rustc_lint/src/errors.rs @@ -8,12 +8,12 @@ use rustc_span::{Span, Symbol}; #[derive(Diagnostic)] #[diag(lint_overruled_attribute, code = "E0453")] -pub struct OverruledAttribute { +pub struct OverruledAttribute<'a> { #[primary_span] pub span: Span, #[label] pub overruled: Span, - pub lint_level: String, + pub lint_level: &'a str, pub lint_source: Symbol, #[subdiagnostic] pub sub: OverruledAttributeSub, @@ -38,6 +38,7 @@ impl AddToDiagnostic for OverruledAttributeSub { OverruledAttributeSub::NodeSource { span, reason } => { diag.span_label(span, fluent::lint_node_source); if let Some(rationale) = reason { + #[allow(rustc::untranslatable_diagnostic)] diag.note(rationale.as_str()); } } diff --git a/compiler/rustc_lint/src/expect.rs b/compiler/rustc_lint/src/expect.rs index cf8f31bcbd0..e9eb14ea188 100644 --- a/compiler/rustc_lint/src/expect.rs +++ b/compiler/rustc_lint/src/expect.rs @@ -1,8 +1,7 @@ -use crate::builtin; -use rustc_errors::fluent; -use rustc_hir::HirId; +use crate::lints::{Expectation, ExpectationNote}; use rustc_middle::ty::query::Providers; -use rustc_middle::{lint::LintExpectation, ty::TyCtxt}; +use rustc_middle::ty::TyCtxt; +use rustc_session::lint::builtin::UNFULFILLED_LINT_EXPECTATIONS; use rustc_session::lint::LintExpectationId; use rustc_span::symbol::sym; use rustc_span::Symbol; @@ -12,7 +11,7 @@ pub(crate) fn provide(providers: &mut Providers) { } fn check_expectations(tcx: TyCtxt<'_>, tool_filter: Option<Symbol>) { - if !tcx.sess.features_untracked().enabled(sym::lint_reasons) { + if !tcx.features().enabled(sym::lint_reasons) { return; } @@ -28,34 +27,17 @@ fn check_expectations(tcx: TyCtxt<'_>, tool_filter: Option<Symbol>) { if !fulfilled_expectations.contains(&id) && tool_filter.map_or(true, |filter| expectation.lint_tool == Some(filter)) { - emit_unfulfilled_expectation_lint(tcx, *hir_id, expectation); + let rationale = expectation.reason.map(|rationale| ExpectationNote { rationale }); + let note = expectation.is_unfulfilled_lint_expectations.then_some(()); + tcx.emit_spanned_lint( + UNFULFILLED_LINT_EXPECTATIONS, + *hir_id, + expectation.emission_span, + Expectation { rationale, note }, + ); } } else { unreachable!("at this stage all `LintExpectationId`s are stable"); } } } - -fn emit_unfulfilled_expectation_lint( - tcx: TyCtxt<'_>, - hir_id: HirId, - expectation: &LintExpectation, -) { - tcx.struct_span_lint_hir( - builtin::UNFULFILLED_LINT_EXPECTATIONS, - hir_id, - expectation.emission_span, - fluent::lint_expectation, - |lint| { - if let Some(rationale) = expectation.reason { - lint.note(rationale.as_str()); - } - - if expectation.is_unfulfilled_lint_expectations { - lint.note(fluent::note); - } - - lint - }, - ); -} diff --git a/compiler/rustc_lint/src/for_loops_over_fallibles.rs b/compiler/rustc_lint/src/for_loops_over_fallibles.rs index 182734fa9fc..5219992ee94 100644 --- a/compiler/rustc_lint/src/for_loops_over_fallibles.rs +++ b/compiler/rustc_lint/src/for_loops_over_fallibles.rs @@ -1,7 +1,12 @@ -use crate::{LateContext, LateLintPass, LintContext}; +use crate::{ + lints::{ + ForLoopsOverFalliblesDiag, ForLoopsOverFalliblesLoopSub, ForLoopsOverFalliblesQuestionMark, + ForLoopsOverFalliblesSuggestion, + }, + LateContext, LateLintPass, LintContext, +}; use hir::{Expr, Pat}; -use rustc_errors::{Applicability, DelayDm}; use rustc_hir as hir; use rustc_infer::{infer::TyCtxtInferExt, traits::ObligationCause}; use rustc_middle::ty::{self, List}; @@ -53,53 +58,29 @@ impl<'tcx> LateLintPass<'tcx> for ForLoopsOverFallibles { _ => return, }; - let msg = DelayDm(|| { - format!( - "for loop over {article} `{ty}`. This is more readably written as an `if let` statement", - ) - }); - - cx.struct_span_lint(FOR_LOOPS_OVER_FALLIBLES, arg.span, msg, |lint| { - if let Some(recv) = extract_iterator_next_call(cx, arg) + let sub = if let Some(recv) = extract_iterator_next_call(cx, arg) && let Ok(recv_snip) = cx.sess().source_map().span_to_snippet(recv.span) { - lint.span_suggestion( - recv.span.between(arg.span.shrink_to_hi()), - format!("to iterate over `{recv_snip}` remove the call to `next`"), - ".by_ref()", - Applicability::MaybeIncorrect - ); + ForLoopsOverFalliblesLoopSub::RemoveNext { suggestion: recv.span.between(arg.span.shrink_to_hi()), recv_snip } } else { - lint.multipart_suggestion_verbose( - "to check pattern in a loop use `while let`", - vec![ - // NB can't use `until` here because `expr.span` and `pat.span` have different syntax contexts - (expr.span.with_hi(pat.span.lo()), format!("while let {var}(")), - (pat.span.between(arg.span), ") = ".to_string()), - ], - Applicability::MaybeIncorrect - ); - } - - if suggest_question_mark(cx, adt, substs, expr.span) { - lint.span_suggestion( - arg.span.shrink_to_hi(), - "consider unwrapping the `Result` with `?` to iterate over its contents", - "?", - Applicability::MaybeIncorrect, - ); - } - - lint.multipart_suggestion_verbose( - "consider using `if let` to clear intent", - vec![ - // NB can't use `until` here because `expr.span` and `pat.span` have different syntax contexts - (expr.span.with_hi(pat.span.lo()), format!("if let {var}(")), - (pat.span.between(arg.span), ") = ".to_string()), - ], - Applicability::MaybeIncorrect, - ) - }) + ForLoopsOverFalliblesLoopSub::UseWhileLet { start_span: expr.span.with_hi(pat.span.lo()), end_span: pat.span.between(arg.span), var } + } ; + let question_mark = if suggest_question_mark(cx, adt, substs, expr.span) { + Some(ForLoopsOverFalliblesQuestionMark { suggestion: arg.span.shrink_to_hi() }) + } else { + None + }; + let suggestion = ForLoopsOverFalliblesSuggestion { + var, + start_span: expr.span.with_hi(pat.span.lo()), + end_span: pat.span.between(arg.span), + }; + + cx.emit_spanned_lint( + FOR_LOOPS_OVER_FALLIBLES, + arg.span, + ForLoopsOverFalliblesDiag { article, ty, sub, question_mark, suggestion }, + ); } } diff --git a/compiler/rustc_lint/src/hidden_unicode_codepoints.rs b/compiler/rustc_lint/src/hidden_unicode_codepoints.rs index dc2f5c0e296..7c1af6bee1d 100644 --- a/compiler/rustc_lint/src/hidden_unicode_codepoints.rs +++ b/compiler/rustc_lint/src/hidden_unicode_codepoints.rs @@ -1,7 +1,12 @@ -use crate::{EarlyContext, EarlyLintPass, LintContext}; +use crate::{ + lints::{ + HiddenUnicodeCodepointsDiag, HiddenUnicodeCodepointsDiagLabels, + HiddenUnicodeCodepointsDiagSub, + }, + EarlyContext, EarlyLintPass, LintContext, +}; use ast::util::unicode::{contains_text_flow_control_chars, TEXT_FLOW_CONTROL_CHARS}; use rustc_ast as ast; -use rustc_errors::{fluent, Applicability, SuggestionStyle}; use rustc_span::{BytePos, Span, Symbol}; declare_lint! { @@ -60,55 +65,19 @@ impl HiddenUnicodeCodepoints { }) .collect(); - cx.struct_span_lint( + let count = spans.len(); + let labels = point_at_inner_spans + .then_some(HiddenUnicodeCodepointsDiagLabels { spans: spans.clone() }); + let sub = if point_at_inner_spans && !spans.is_empty() { + HiddenUnicodeCodepointsDiagSub::Escape { spans } + } else { + HiddenUnicodeCodepointsDiagSub::NoEscape { spans } + }; + + cx.emit_spanned_lint( TEXT_DIRECTION_CODEPOINT_IN_LITERAL, span, - fluent::lint_hidden_unicode_codepoints, - |lint| { - lint.set_arg("label", label); - lint.set_arg("count", spans.len()); - lint.span_label(span, fluent::label); - lint.note(fluent::note); - if point_at_inner_spans { - for (c, span) in &spans { - lint.span_label(*span, format!("{:?}", c)); - } - } - if point_at_inner_spans && !spans.is_empty() { - lint.multipart_suggestion_with_style( - fluent::suggestion_remove, - spans.iter().map(|(_, span)| (*span, "".to_string())).collect(), - Applicability::MachineApplicable, - SuggestionStyle::HideCodeAlways, - ); - lint.multipart_suggestion( - fluent::suggestion_escape, - spans - .into_iter() - .map(|(c, span)| { - let c = format!("{:?}", c); - (span, c[1..c.len() - 1].to_string()) - }) - .collect(), - Applicability::MachineApplicable, - ); - } else { - // FIXME: in other suggestions we've reversed the inner spans of doc comments. We - // should do the same here to provide the same good suggestions as we do for - // literals above. - lint.set_arg( - "escaped", - spans - .into_iter() - .map(|(c, _)| format!("{:?}", c)) - .collect::<Vec<String>>() - .join(", "), - ); - lint.note(fluent::suggestion_remove); - lint.note(fluent::no_suggestion_note_escape); - } - lint - }, + HiddenUnicodeCodepointsDiag { label, count, span_label: span, labels, sub }, ); } } diff --git a/compiler/rustc_lint/src/internal.rs b/compiler/rustc_lint/src/internal.rs index 48902cd0569..5eb54cc0034 100644 --- a/compiler/rustc_lint/src/internal.rs +++ b/compiler/rustc_lint/src/internal.rs @@ -1,9 +1,12 @@ //! Some lints that are only useful in the compiler or crates that use compiler internals, such as //! Clippy. +use crate::lints::{ + BadOptAccessDiag, DefaultHashTypesDiag, DiagOutOfImpl, LintPassByHand, NonExistantDocKeyword, + QueryInstability, TyQualified, TykindDiag, TykindKind, UntranslatableDiag, +}; use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext}; use rustc_ast as ast; -use rustc_errors::{fluent, Applicability}; use rustc_hir::def::Res; use rustc_hir::{def_id::DefId, Expr, ExprKind, GenericArg, PatKind, Path, PathSegment, QPath}; use rustc_hir::{HirId, Impl, Item, ItemKind, Node, Pat, Ty, TyKind}; @@ -29,20 +32,15 @@ impl LateLintPass<'_> for DefaultHashTypes { // don't lint imports, only actual usages return; } - let replace = match cx.tcx.get_diagnostic_name(def_id) { + let preferred = match cx.tcx.get_diagnostic_name(def_id) { Some(sym::HashMap) => "FxHashMap", Some(sym::HashSet) => "FxHashSet", _ => return, }; - cx.struct_span_lint( + cx.emit_spanned_lint( DEFAULT_HASH_TYPES, path.span, - fluent::lint_default_hash_types, - |lint| { - lint.set_arg("preferred", replace) - .set_arg("used", cx.tcx.item_name(def_id)) - .note(fluent::note) - }, + DefaultHashTypesDiag { preferred, used: cx.tcx.item_name(def_id) }, ); } } @@ -83,12 +81,11 @@ impl LateLintPass<'_> for QueryStability { if let Ok(Some(instance)) = ty::Instance::resolve(cx.tcx, cx.param_env, def_id, substs) { let def_id = instance.def_id(); if cx.tcx.has_attr(def_id, sym::rustc_lint_query_instability) { - cx.struct_span_lint( + cx.emit_spanned_lint( POTENTIAL_QUERY_INSTABILITY, span, - fluent::lint_query_instability, - |lint| lint.set_arg("query", cx.tcx.item_name(def_id)).note(fluent::note), - ) + QueryInstability { query: cx.tcx.item_name(def_id) }, + ); } } } @@ -126,14 +123,8 @@ impl<'tcx> LateLintPass<'tcx> for TyTyKind { let span = path.span.with_hi( segment.args.map_or(segment.ident.span, |a| a.span_ext).hi() ); - cx.struct_span_lint(USAGE_OF_TY_TYKIND, path.span, fluent::lint_tykind_kind, |lint| { - lint - .span_suggestion( - span, - fluent::suggestion, - "ty", - Applicability::MaybeIncorrect, // ty maybe needs an import - ) + cx.emit_spanned_lint(USAGE_OF_TY_TYKIND, path.span, TykindKind { + suggestion: span, }); } } @@ -190,39 +181,17 @@ impl<'tcx> LateLintPass<'tcx> for TyTyKind { match span { Some(span) => { - cx.struct_span_lint( - USAGE_OF_TY_TYKIND, - path.span, - fluent::lint_tykind_kind, - |lint| lint.span_suggestion( - span, - fluent::suggestion, - "ty", - Applicability::MaybeIncorrect, // ty maybe needs an import - ) - ) + cx.emit_spanned_lint(USAGE_OF_TY_TYKIND, path.span, TykindKind { + suggestion: span, + }); }, - None => cx.struct_span_lint( - USAGE_OF_TY_TYKIND, - path.span, - fluent::lint_tykind, - |lint| lint.help(fluent::help) - ) - } - } else if !ty.span.from_expansion() && let Some(t) = is_ty_or_ty_ctxt(cx, &path) { - if path.segments.len() > 1 { - cx.struct_span_lint(USAGE_OF_QUALIFIED_TY, path.span, fluent::lint_ty_qualified, |lint| { - lint - .set_arg("ty", t.clone()) - .span_suggestion( - path.span, - fluent::suggestion, - t, - // The import probably needs to be changed - Applicability::MaybeIncorrect, - ) - }) + None => cx.emit_spanned_lint(USAGE_OF_TY_TYKIND, path.span, TykindDiag), } + } else if !ty.span.from_expansion() && path.segments.len() > 1 && let Some(t) = is_ty_or_ty_ctxt(cx, &path) { + cx.emit_spanned_lint(USAGE_OF_QUALIFIED_TY, path.span, TyQualified { + ty: t.clone(), + suggestion: path.span, + }); } } _ => {} @@ -303,12 +272,11 @@ impl EarlyLintPass for LintPassImpl { && call_site.ctxt().outer_expn_data().kind != ExpnKind::Macro(MacroKind::Bang, sym::declare_lint_pass) { - cx.struct_span_lint( + cx.emit_spanned_lint( LINT_PASS_IMPL_WITHOUT_MACRO, lint_pass.path.span, - fluent::lint_lintpass_by_hand, - |lint| lint.help(fluent::help), - ) + LintPassByHand, + ); } } } @@ -338,17 +306,16 @@ impl<'tcx> LateLintPass<'tcx> for ExistingDocKeyword { if let Some(list) = attr.meta_item_list() { for nested in list { if nested.has_name(sym::keyword) { - let v = nested + let keyword = nested .value_str() .expect("#[doc(keyword = \"...\")] expected a value!"); - if is_doc_keyword(v) { + if is_doc_keyword(keyword) { return; } - cx.struct_span_lint( + cx.emit_spanned_lint( EXISTING_DOC_KEYWORD, attr.span, - fluent::lint_non_existant_doc_keyword, - |lint| lint.set_arg("keyword", v).help(fluent::help), + NonExistantDocKeyword { keyword }, ); } } @@ -407,12 +374,7 @@ impl LateLintPass<'_> for Diagnostics { } debug!(?found_impl); if !found_parent_with_attr && !found_impl { - cx.struct_span_lint( - DIAGNOSTIC_OUTSIDE_OF_IMPL, - span, - fluent::lint_diag_out_of_impl, - |lint| lint, - ) + cx.emit_spanned_lint(DIAGNOSTIC_OUTSIDE_OF_IMPL, span, DiagOutOfImpl); } let mut found_diagnostic_message = false; @@ -428,12 +390,7 @@ impl LateLintPass<'_> for Diagnostics { } debug!(?found_diagnostic_message); if !found_parent_with_attr && !found_diagnostic_message { - cx.struct_span_lint( - UNTRANSLATABLE_DIAGNOSTIC, - span, - fluent::lint_untranslatable_diag, - |lint| lint, - ) + cx.emit_spanned_lint(UNTRANSLATABLE_DIAGNOSTIC, span, UntranslatableDiag); } } } @@ -465,9 +422,9 @@ impl LateLintPass<'_> for BadOptAccess { let Some(lit) = item.lit() && let ast::LitKind::Str(val, _) = lit.kind { - cx.struct_span_lint(BAD_OPT_ACCESS, expr.span, val.as_str(), |lint| - lint - ); + cx.emit_spanned_lint(BAD_OPT_ACCESS, expr.span, BadOptAccessDiag { + msg: val.as_str(), + }); } } } diff --git a/compiler/rustc_lint/src/let_underscore.rs b/compiler/rustc_lint/src/let_underscore.rs index 04d844d21dc..b83a9665fc0 100644 --- a/compiler/rustc_lint/src/let_underscore.rs +++ b/compiler/rustc_lint/src/let_underscore.rs @@ -1,5 +1,8 @@ -use crate::{LateContext, LateLintPass, LintContext}; -use rustc_errors::{Applicability, DiagnosticBuilder, MultiSpan}; +use crate::{ + lints::{NonBindingLet, NonBindingLetSub}, + LateContext, LateLintPass, LintContext, +}; +use rustc_errors::MultiSpan; use rustc_hir as hir; use rustc_middle::ty; use rustc_span::Symbol; @@ -119,6 +122,11 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore { _ => false, }; + let sub = NonBindingLetSub { + suggestion: local.pat.span, + multi_suggestion_start: local.span.until(init.span), + multi_suggestion_end: init.span.shrink_to_hi(), + }; if is_sync_lock { let mut span = MultiSpan::from_spans(vec![local.pat.span, init.span]); span.push_span_label( @@ -129,41 +137,14 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore { init.span, "this binding will immediately drop the value assigned to it".to_string(), ); - cx.struct_span_lint( - LET_UNDERSCORE_LOCK, - span, - "non-binding let on a synchronization lock", - |lint| build_lint(lint, local, init.span), - ) + cx.emit_spanned_lint(LET_UNDERSCORE_LOCK, span, NonBindingLet::SyncLock { sub }); } else { - cx.struct_span_lint( + cx.emit_spanned_lint( LET_UNDERSCORE_DROP, local.span, - "non-binding let on a type that implements `Drop`", - |lint| build_lint(lint, local, init.span), - ) + NonBindingLet::DropType { sub }, + ); } } } } - -fn build_lint<'a, 'b>( - lint: &'a mut DiagnosticBuilder<'b, ()>, - local: &hir::Local<'_>, - init_span: rustc_span::Span, -) -> &'a mut DiagnosticBuilder<'b, ()> { - lint.span_suggestion_verbose( - local.pat.span, - "consider binding to an unused variable to avoid immediately dropping the value", - "_unused", - Applicability::MachineApplicable, - ) - .multipart_suggestion( - "consider immediately dropping the value", - vec![ - (local.span.until(init_span), "drop(".to_string()), - (init_span.shrink_to_hi(), ")".to_string()), - ], - Applicability::MachineApplicable, - ) -} diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs index e9d3d44a3f9..09dfb1022d8 100644 --- a/compiler/rustc_lint/src/levels.rs +++ b/compiler/rustc_lint/src/levels.rs @@ -1,9 +1,13 @@ use crate::context::{CheckLintNameResult, LintStore}; use crate::late::unerased_lint_store; +use crate::lints::{ + DeprecatedLintName, IgnoredUnlessCrateSpecified, OverruledAtributeLint, RenamedOrRemovedLint, + RenamedOrRemovedLintSuggestion, UnknownLint, UnknownLintSuggestion, +}; use rustc_ast as ast; use rustc_ast_pretty::pprust; use rustc_data_structures::fx::FxHashMap; -use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, DiagnosticMessage, MultiSpan}; +use rustc_errors::{fluent, DecorateLint, DiagnosticBuilder, DiagnosticMessage, MultiSpan}; use rustc_hir as hir; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::HirId; @@ -15,6 +19,7 @@ use rustc_middle::lint::{ }; use rustc_middle::ty::query::Providers; use rustc_middle::ty::{RegisteredTools, TyCtxt}; +use rustc_session::lint::builtin::{RENAMED_AND_REMOVED_LINTS, UNKNOWN_LINTS, UNUSED_ATTRIBUTES}; use rustc_session::lint::{ builtin::{self, FORBIDDEN_LINT_GROUPS, SINGLE_USE_LIFETIMES, UNFULFILLED_LINT_EXPECTATIONS}, Level, Lint, LintExpectationId, LintId, @@ -583,57 +588,32 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> { old_src, id_name ); - - let decorate_diag = |diag: &mut Diagnostic| { - diag.span_label(src.span(), "overruled by previous forbid"); - match old_src { - LintLevelSource::Default => { - diag.note(&format!( - "`forbid` lint level is the default for {}", - id.to_string() - )); - } - LintLevelSource::Node { span, reason, .. } => { - diag.span_label(span, "`forbid` level set here"); - if let Some(rationale) = reason { - diag.note(rationale.as_str()); - } - } - LintLevelSource::CommandLine(_, _) => { - diag.note("`forbid` lint level was set on command line"); - } + let sub = match old_src { + LintLevelSource::Default => { + OverruledAttributeSub::DefaultSource { id: id.to_string() } } + LintLevelSource::Node { span, reason, .. } => { + OverruledAttributeSub::NodeSource { span, reason } + } + LintLevelSource::CommandLine(_, _) => OverruledAttributeSub::CommandLineSource, }; if !fcw_warning { self.sess.emit_err(OverruledAttribute { span: src.span(), overruled: src.span(), - lint_level: level.as_str().to_string(), + lint_level: level.as_str(), lint_source: src.name(), - sub: match old_src { - LintLevelSource::Default => { - OverruledAttributeSub::DefaultSource { id: id.to_string() } - } - LintLevelSource::Node { span, reason, .. } => { - OverruledAttributeSub::NodeSource { span, reason } - } - LintLevelSource::CommandLine(_, _) => { - OverruledAttributeSub::CommandLineSource - } - }, + sub, }); } else { - self.struct_lint( + self.emit_spanned_lint( FORBIDDEN_LINT_GROUPS, - Some(src.span().into()), - format!( - "{}({}) incompatible with previous forbid", - level.as_str(), - src.name(), - ), - |lint| { - decorate_diag(lint); - lint + src.span().into(), + OverruledAtributeLint { + overruled: src.span(), + lint_level: level.as_str(), + lint_source: src.name(), + sub, }, ); } @@ -858,25 +838,13 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> { } Err((Some(ids), ref new_lint_name)) => { let lint = builtin::RENAMED_AND_REMOVED_LINTS; - let (lvl, src) = self.provider.get_lint_level(lint, &sess); - struct_lint_level( - self.sess, + self.emit_spanned_lint( lint, - lvl, - src, - Some(sp.into()), - format!( - "lint name `{}` is deprecated \ - and may not have an effect in the future.", - name - ), - |lint| { - lint.span_suggestion( - sp, - "change it to", - new_lint_name, - Applicability::MachineApplicable, - ) + sp.into(), + DeprecatedLintName { + name, + suggestion: sp, + replace: &new_lint_name, }, ); @@ -917,54 +885,29 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> { _ if !self.warn_about_weird_lints => {} CheckLintNameResult::Warning(msg, renamed) => { - let lint = builtin::RENAMED_AND_REMOVED_LINTS; - let (renamed_lint_level, src) = self.provider.get_lint_level(lint, &sess); - struct_lint_level( - self.sess, - lint, - renamed_lint_level, - src, - Some(sp.into()), - msg, - |lint| { - if let Some(new_name) = &renamed { - lint.span_suggestion( - sp, - "use the new name", - new_name, - Applicability::MachineApplicable, - ); - } - lint - }, + let suggestion = + renamed.as_ref().map(|replace| RenamedOrRemovedLintSuggestion { + suggestion: sp, + replace: replace.as_str(), + }); + self.emit_spanned_lint( + RENAMED_AND_REMOVED_LINTS, + sp.into(), + RenamedOrRemovedLint { msg, suggestion }, ); } CheckLintNameResult::NoLint(suggestion) => { - let lint = builtin::UNKNOWN_LINTS; - let (level, src) = self.provider.get_lint_level(lint, self.sess); let name = if let Some(tool_ident) = tool_ident { format!("{}::{}", tool_ident.name, name) } else { name.to_string() }; - struct_lint_level( - self.sess, - lint, - level, - src, - Some(sp.into()), - format!("unknown lint: `{}`", name), - |lint| { - if let Some(suggestion) = suggestion { - lint.span_suggestion( - sp, - "did you mean", - suggestion, - Applicability::MaybeIncorrect, - ); - } - lint - }, + let suggestion = suggestion + .map(|replace| UnknownLintSuggestion { suggestion: sp, replace }); + self.emit_spanned_lint( + UNKNOWN_LINTS, + sp.into(), + UnknownLint { name, suggestion }, ); } } @@ -1010,20 +953,10 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> { continue }; - let lint = builtin::UNUSED_ATTRIBUTES; - let (lint_level, lint_src) = self.provider.get_lint_level(lint, &self.sess); - struct_lint_level( - self.sess, - lint, - lint_level, - lint_src, - Some(lint_attr_span.into()), - format!( - "{}({}) is ignored unless specified at crate level", - level.as_str(), - lint_attr_name - ), - |lint| lint, + self.emit_spanned_lint( + UNUSED_ATTRIBUTES, + lint_attr_span.into(), + IgnoredUnlessCrateSpecified { level: level.as_str(), name: lint_attr_name }, ); // don't set a separate error for every lint in the group break; @@ -1047,11 +980,10 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> { level, src, Some(span.into()), - format!("unknown lint: `{}`", lint_id.lint.name_lower()), + fluent::lint_unknown_gated_lint, |lint| { - lint.note( - &format!("the `{}` lint is unstable", lint_id.lint.name_lower(),), - ); + lint.set_arg("name", lint_id.lint.name_lower()); + lint.note(fluent::note); add_feature_diagnostics(lint, &self.sess.parse_sess, feature); lint }, @@ -1086,6 +1018,25 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> { let (level, src) = self.lint_level(lint); struct_lint_level(self.sess, lint, level, src, span, msg, decorate) } + + pub fn emit_spanned_lint( + &self, + lint: &'static Lint, + span: MultiSpan, + decorate: impl for<'a> DecorateLint<'a, ()>, + ) { + let (level, src) = self.lint_level(lint); + struct_lint_level(self.sess, lint, level, src, Some(span), decorate.msg(), |lint| { + decorate.decorate_lint(lint) + }); + } + + pub fn emit_lint(&self, lint: &'static Lint, decorate: impl for<'a> DecorateLint<'a, ()>) { + let (level, src) = self.lint_level(lint); + struct_lint_level(self.sess, lint, level, src, None, decorate.msg(), |lint| { + decorate.decorate_lint(lint) + }); + } } pub(crate) fn provide(providers: &mut Providers) { diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 1275d6f223c..3d818154cb9 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -38,6 +38,8 @@ #![feature(never_type)] #![feature(rustc_attrs)] #![recursion_limit = "256"] +#![deny(rustc::untranslatable_diagnostic)] +#![deny(rustc::diagnostic_outside_of_impl)] #[macro_use] extern crate rustc_middle; @@ -60,6 +62,7 @@ mod internal; mod late; mod let_underscore; mod levels; +mod lints; mod methods; mod non_ascii_idents; mod non_fmt_panic; diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs new file mode 100644 index 00000000000..c3782a49689 --- /dev/null +++ b/compiler/rustc_lint/src/lints.rs @@ -0,0 +1,1479 @@ +#![allow(rustc::untranslatable_diagnostic)] +#![allow(rustc::diagnostic_outside_of_impl)] +use std::num::NonZeroU32; + +use rustc_errors::{ + fluent, AddToDiagnostic, Applicability, DecorateLint, DiagnosticMessage, + DiagnosticStyledString, SuggestionStyle, +}; +use rustc_hir::def_id::DefId; +use rustc_macros::{LintDiagnostic, Subdiagnostic}; +use rustc_middle::ty::{Predicate, Ty, TyCtxt}; +use rustc_session::parse::ParseSess; +use rustc_span::{edition::Edition, sym, symbol::Ident, Span, Symbol}; + +use crate::{ + builtin::InitError, builtin::TypeAliasBounds, errors::OverruledAttributeSub, LateContext, +}; + +// array_into_iter.rs +#[derive(LintDiagnostic)] +#[diag(lint_array_into_iter)] +pub struct ArrayIntoIterDiag<'a> { + pub target: &'a str, + #[suggestion(use_iter_suggestion, code = "iter", applicability = "machine-applicable")] + pub suggestion: Span, + #[subdiagnostic] + pub sub: Option<ArrayIntoIterDiagSub>, +} + +#[derive(Subdiagnostic)] +pub enum ArrayIntoIterDiagSub { + #[suggestion(remove_into_iter_suggestion, code = "", applicability = "maybe-incorrect")] + RemoveIntoIter { + #[primary_span] + span: Span, + }, + #[multipart_suggestion(use_explicit_into_iter_suggestion, applicability = "maybe-incorrect")] + UseExplicitIntoIter { + #[suggestion_part(code = "IntoIterator::into_iter(")] + start_span: Span, + #[suggestion_part(code = ")")] + end_span: Span, + }, +} + +// builtin.rs +#[derive(LintDiagnostic)] +#[diag(lint_builtin_while_true)] +pub struct BuiltinWhileTrue { + #[suggestion(style = "short", code = "{replace}", applicability = "machine-applicable")] + pub suggestion: Span, + pub replace: String, +} + +#[derive(LintDiagnostic)] +#[diag(lint_builtin_box_pointers)] +pub struct BuiltinBoxPointers<'a> { + pub ty: Ty<'a>, +} + +#[derive(LintDiagnostic)] +#[diag(lint_builtin_non_shorthand_field_patterns)] +pub struct BuiltinNonShorthandFieldPatterns { + pub ident: Ident, + #[suggestion(code = "{prefix}{ident}", applicability = "machine-applicable")] + pub suggestion: Span, + pub prefix: &'static str, +} + +#[derive(LintDiagnostic)] +pub enum BuiltinUnsafe { + #[diag(lint_builtin_allow_internal_unsafe)] + AllowInternalUnsafe, + #[diag(lint_builtin_unsafe_block)] + UnsafeBlock, + #[diag(lint_builtin_unsafe_trait)] + UnsafeTrait, + #[diag(lint_builtin_unsafe_impl)] + UnsafeImpl, + #[diag(lint_builtin_no_mangle_fn)] + #[note(lint_builtin_overridden_symbol_name)] + NoMangleFn, + #[diag(lint_builtin_export_name_fn)] + #[note(lint_builtin_overridden_symbol_name)] + ExportNameFn, + #[diag(lint_builtin_link_section_fn)] + #[note(lint_builtin_overridden_symbol_section)] + LinkSectionFn, + #[diag(lint_builtin_no_mangle_static)] + #[note(lint_builtin_overridden_symbol_name)] + NoMangleStatic, + #[diag(lint_builtin_export_name_static)] + #[note(lint_builtin_overridden_symbol_name)] + ExportNameStatic, + #[diag(lint_builtin_link_section_static)] + #[note(lint_builtin_overridden_symbol_section)] + LinkSectionStatic, + #[diag(lint_builtin_no_mangle_method)] + #[note(lint_builtin_overridden_symbol_name)] + NoMangleMethod, + #[diag(lint_builtin_export_name_method)] + #[note(lint_builtin_overridden_symbol_name)] + ExportNameMethod, + #[diag(lint_builtin_decl_unsafe_fn)] + DeclUnsafeFn, + #[diag(lint_builtin_decl_unsafe_method)] + DeclUnsafeMethod, + #[diag(lint_builtin_impl_unsafe_method)] + ImplUnsafeMethod, +} + +#[derive(LintDiagnostic)] +#[diag(lint_builtin_missing_doc)] +pub struct BuiltinMissingDoc<'a> { + pub article: &'a str, + pub desc: &'a str, +} + +#[derive(LintDiagnostic)] +#[diag(lint_builtin_missing_copy_impl)] +pub struct BuiltinMissingCopyImpl; + +pub struct BuiltinMissingDebugImpl<'a> { + pub tcx: TyCtxt<'a>, + pub def_id: DefId, +} + +// Needed for def_path_str +impl<'a> DecorateLint<'a, ()> for BuiltinMissingDebugImpl<'_> { + fn decorate_lint<'b>( + self, + diag: &'b mut rustc_errors::DiagnosticBuilder<'a, ()>, + ) -> &'b mut rustc_errors::DiagnosticBuilder<'a, ()> { + diag.set_arg("debug", self.tcx.def_path_str(self.def_id)); + diag + } + + fn msg(&self) -> DiagnosticMessage { + fluent::lint_builtin_missing_debug_impl + } +} + +#[derive(LintDiagnostic)] +#[diag(lint_builtin_anonymous_params)] +pub struct BuiltinAnonymousParams<'a> { + #[suggestion(code = "_: {ty_snip}")] + pub suggestion: (Span, Applicability), + pub ty_snip: &'a str, +} + +// FIXME(davidtwco) translatable deprecated attr +#[derive(LintDiagnostic)] +#[diag(lint_builtin_deprecated_attr_link)] +pub struct BuiltinDeprecatedAttrLink<'a> { + pub name: Symbol, + pub reason: &'a str, + pub link: &'a str, + #[subdiagnostic] + pub suggestion: BuiltinDeprecatedAttrLinkSuggestion<'a>, +} + +#[derive(Subdiagnostic)] +pub enum BuiltinDeprecatedAttrLinkSuggestion<'a> { + #[suggestion(msg_suggestion, code = "", applicability = "machine-applicable")] + Msg { + #[primary_span] + suggestion: Span, + msg: &'a str, + }, + #[suggestion(default_suggestion, code = "", applicability = "machine-applicable")] + Default { + #[primary_span] + suggestion: Span, + }, +} + +#[derive(LintDiagnostic)] +#[diag(lint_builtin_deprecated_attr_used)] +pub struct BuiltinDeprecatedAttrUsed { + pub name: String, + #[suggestion( + lint_builtin_deprecated_attr_default_suggestion, + style = "short", + code = "", + applicability = "machine-applicable" + )] + pub suggestion: Span, +} + +#[derive(LintDiagnostic)] +#[diag(lint_builtin_unused_doc_comment)] +pub struct BuiltinUnusedDocComment<'a> { + pub kind: &'a str, + #[label] + pub label: Span, + #[subdiagnostic] + pub sub: BuiltinUnusedDocCommentSub, +} + +#[derive(Subdiagnostic)] +pub enum BuiltinUnusedDocCommentSub { + #[help(plain_help)] + PlainHelp, + #[help(block_help)] + BlockHelp, +} + +#[derive(LintDiagnostic)] +#[diag(lint_builtin_no_mangle_generic)] +pub struct BuiltinNoMangleGeneric { + // Use of `#[no_mangle]` suggests FFI intent; correct + // fix may be to monomorphize source by hand + #[suggestion(style = "short", code = "", applicability = "maybe-incorrect")] + pub suggestion: Span, +} + +#[derive(LintDiagnostic)] +#[diag(lint_builtin_const_no_mangle)] +pub struct BuiltinConstNoMangle { + #[suggestion(code = "pub static", applicability = "machine-applicable")] + pub suggestion: Span, +} + +#[derive(LintDiagnostic)] +#[diag(lint_builtin_mutable_transmutes)] +pub struct BuiltinMutablesTransmutes; + +#[derive(LintDiagnostic)] +#[diag(lint_builtin_unstable_features)] +pub struct BuiltinUnstableFeatures; + +// lint_ungated_async_fn_track_caller +pub struct BuiltinUngatedAsyncFnTrackCaller<'a> { + pub label: Span, + pub parse_sess: &'a ParseSess, +} + +impl<'a> DecorateLint<'a, ()> for BuiltinUngatedAsyncFnTrackCaller<'_> { + fn decorate_lint<'b>( + self, + diag: &'b mut rustc_errors::DiagnosticBuilder<'a, ()>, + ) -> &'b mut rustc_errors::DiagnosticBuilder<'a, ()> { + diag.span_label(self.label, fluent::label); + rustc_session::parse::add_feature_diagnostics( + diag, + &self.parse_sess, + sym::closure_track_caller, + ); + diag + } + + fn msg(&self) -> DiagnosticMessage { + fluent::lint_ungated_async_fn_track_caller + } +} + +#[derive(LintDiagnostic)] +#[diag(lint_builtin_unreachable_pub)] +pub struct BuiltinUnreachablePub<'a> { + pub what: &'a str, + #[suggestion(code = "pub(crate)")] + pub suggestion: (Span, Applicability), + #[help] + pub help: Option<()>, +} + +pub struct SuggestChangingAssocTypes<'a, 'b> { + pub ty: &'a rustc_hir::Ty<'b>, +} + +impl AddToDiagnostic for SuggestChangingAssocTypes<'_, '_> { + fn add_to_diagnostic_with<F>(self, diag: &mut rustc_errors::Diagnostic, _: F) + where + F: Fn( + &mut rustc_errors::Diagnostic, + rustc_errors::SubdiagnosticMessage, + ) -> rustc_errors::SubdiagnosticMessage, + { + // Access to associates types should use `<T as Bound>::Assoc`, which does not need a + // bound. Let's see if this type does that. + + // We use a HIR visitor to walk the type. + use rustc_hir::intravisit::{self, Visitor}; + struct WalkAssocTypes<'a> { + err: &'a mut rustc_errors::Diagnostic, + } + impl Visitor<'_> for WalkAssocTypes<'_> { + fn visit_qpath( + &mut self, + qpath: &rustc_hir::QPath<'_>, + id: rustc_hir::HirId, + span: Span, + ) { + if TypeAliasBounds::is_type_variable_assoc(qpath) { + self.err.span_help(span, fluent::lint_builtin_type_alias_bounds_help); + } + intravisit::walk_qpath(self, qpath, id) + } + } + + // Let's go for a walk! + let mut visitor = WalkAssocTypes { err: diag }; + visitor.visit_ty(self.ty); + } +} + +#[derive(LintDiagnostic)] +#[diag(lint_builtin_type_alias_where_clause)] +pub struct BuiltinTypeAliasWhereClause<'a, 'b> { + #[suggestion(code = "", applicability = "machine-applicable")] + pub suggestion: Span, + #[subdiagnostic] + pub sub: Option<SuggestChangingAssocTypes<'a, 'b>>, +} + +#[derive(LintDiagnostic)] +#[diag(lint_builtin_type_alias_generic_bounds)] +pub struct BuiltinTypeAliasGenericBounds<'a, 'b> { + #[subdiagnostic] + pub suggestion: BuiltinTypeAliasGenericBoundsSuggestion, + #[subdiagnostic] + pub sub: Option<SuggestChangingAssocTypes<'a, 'b>>, +} + +pub struct BuiltinTypeAliasGenericBoundsSuggestion { + pub suggestions: Vec<(Span, String)>, +} + +impl AddToDiagnostic for BuiltinTypeAliasGenericBoundsSuggestion { + fn add_to_diagnostic_with<F>(self, diag: &mut rustc_errors::Diagnostic, _: F) + where + F: Fn( + &mut rustc_errors::Diagnostic, + rustc_errors::SubdiagnosticMessage, + ) -> rustc_errors::SubdiagnosticMessage, + { + diag.multipart_suggestion( + fluent::suggestion, + self.suggestions, + Applicability::MachineApplicable, + ); + } +} + +#[derive(LintDiagnostic)] +#[diag(lint_builtin_trivial_bounds)] +pub struct BuiltinTrivialBounds<'a> { + pub predicate_kind_name: &'a str, + pub predicate: Predicate<'a>, +} + +#[derive(LintDiagnostic)] +pub enum BuiltinEllipsisInclusiveRangePatternsLint { + #[diag(lint_builtin_ellipsis_inclusive_range_patterns)] + Parenthesise { + #[suggestion(code = "{replace}", applicability = "machine-applicable")] + suggestion: Span, + replace: String, + }, + #[diag(lint_builtin_ellipsis_inclusive_range_patterns)] + NonParenthesise { + #[suggestion(style = "short", code = "..=", applicability = "machine-applicable")] + suggestion: Span, + }, +} + +#[derive(LintDiagnostic)] +#[diag(lint_builtin_unnameable_test_items)] +pub struct BuiltinUnnameableTestItems; + +#[derive(LintDiagnostic)] +#[diag(lint_builtin_keyword_idents)] +pub struct BuiltinKeywordIdents { + pub kw: Ident, + pub next: Edition, + #[suggestion(code = "r#{kw}", applicability = "machine-applicable")] + pub suggestion: Span, +} + +#[derive(LintDiagnostic)] +#[diag(lint_builtin_explicit_outlives)] +pub struct BuiltinExplicitOutlives { + pub count: usize, + #[subdiagnostic] + pub suggestion: BuiltinExplicitOutlivesSuggestion, +} + +#[derive(Subdiagnostic)] +#[multipart_suggestion(suggestion)] +pub struct BuiltinExplicitOutlivesSuggestion { + #[suggestion_part(code = "")] + pub spans: Vec<Span>, + #[applicability] + pub applicability: Applicability, +} + +#[derive(LintDiagnostic)] +#[diag(lint_builtin_incomplete_features)] +pub struct BuiltinIncompleteFeatures { + pub name: Symbol, + #[subdiagnostic] + pub note: Option<BuiltinIncompleteFeaturesNote>, + #[subdiagnostic] + pub help: Option<BuiltinIncompleteFeaturesHelp>, +} + +#[derive(Subdiagnostic)] +#[help(help)] +pub struct BuiltinIncompleteFeaturesHelp; + +#[derive(Subdiagnostic)] +#[note(note)] +pub struct BuiltinIncompleteFeaturesNote { + pub n: NonZeroU32, +} + +pub struct BuiltinUnpermittedTypeInit<'a> { + pub msg: DiagnosticMessage, + pub ty: Ty<'a>, + pub label: Span, + pub sub: BuiltinUnpermittedTypeInitSub, +} + +impl<'a> DecorateLint<'a, ()> for BuiltinUnpermittedTypeInit<'_> { + fn decorate_lint<'b>( + self, + diag: &'b mut rustc_errors::DiagnosticBuilder<'a, ()>, + ) -> &'b mut rustc_errors::DiagnosticBuilder<'a, ()> { + diag.set_arg("ty", self.ty); + diag.span_label(self.label, fluent::lint_builtin_unpermitted_type_init_label); + diag.span_label(self.label, fluent::lint_builtin_unpermitted_type_init_label_suggestion); + self.sub.add_to_diagnostic(diag); + diag + } + + fn msg(&self) -> rustc_errors::DiagnosticMessage { + self.msg.clone() + } +} + +// FIXME(davidtwco): make translatable +pub struct BuiltinUnpermittedTypeInitSub { + pub err: InitError, +} + +impl AddToDiagnostic for BuiltinUnpermittedTypeInitSub { + fn add_to_diagnostic_with<F>(self, diag: &mut rustc_errors::Diagnostic, _: F) + where + F: Fn( + &mut rustc_errors::Diagnostic, + rustc_errors::SubdiagnosticMessage, + ) -> rustc_errors::SubdiagnosticMessage, + { + let mut err = self.err; + loop { + if let Some(span) = err.span { + diag.span_note(span, err.message); + } else { + diag.note(err.message); + } + if let Some(e) = err.nested { + err = *e; + } else { + break; + } + } + } +} + +#[derive(LintDiagnostic)] +pub enum BuiltinClashingExtern<'a> { + #[diag(lint_builtin_clashing_extern_same_name)] + SameName { + this: Symbol, + orig: Symbol, + #[label(previous_decl_label)] + previous_decl_label: Span, + #[label(mismatch_label)] + mismatch_label: Span, + #[subdiagnostic] + sub: BuiltinClashingExternSub<'a>, + }, + #[diag(lint_builtin_clashing_extern_diff_name)] + DiffName { + this: Symbol, + orig: Symbol, + #[label(previous_decl_label)] + previous_decl_label: Span, + #[label(mismatch_label)] + mismatch_label: Span, + #[subdiagnostic] + sub: BuiltinClashingExternSub<'a>, + }, +} + +// FIXME(davidtwco): translatable expected/found +pub struct BuiltinClashingExternSub<'a> { + pub tcx: TyCtxt<'a>, + pub expected: Ty<'a>, + pub found: Ty<'a>, +} + +impl AddToDiagnostic for BuiltinClashingExternSub<'_> { + fn add_to_diagnostic_with<F>(self, diag: &mut rustc_errors::Diagnostic, _: F) + where + F: Fn( + &mut rustc_errors::Diagnostic, + rustc_errors::SubdiagnosticMessage, + ) -> rustc_errors::SubdiagnosticMessage, + { + let mut expected_str = DiagnosticStyledString::new(); + expected_str.push(self.expected.fn_sig(self.tcx).to_string(), false); + let mut found_str = DiagnosticStyledString::new(); + found_str.push(self.found.fn_sig(self.tcx).to_string(), true); + diag.note_expected_found(&"", expected_str, &"", found_str); + } +} + +#[derive(LintDiagnostic)] +#[diag(lint_builtin_deref_nullptr)] +pub struct BuiltinDerefNullptr { + #[label] + pub label: Span, +} + +// FIXME: migrate fluent::lint::builtin_asm_labels + +#[derive(LintDiagnostic)] +pub enum BuiltinSpecialModuleNameUsed { + #[diag(lint_builtin_special_module_name_used_lib)] + #[note] + #[help] + Lib, + #[diag(lint_builtin_special_module_name_used_main)] + #[note] + Main, +} + +#[derive(LintDiagnostic)] +#[diag(lint_builtin_unexpected_cli_config_name)] +#[help] +pub struct BuiltinUnexpectedCliConfigName { + pub name: Symbol, +} + +#[derive(LintDiagnostic)] +#[diag(lint_builtin_unexpected_cli_config_value)] +#[help] +pub struct BuiltinUnexpectedCliConfigValue { + pub name: Symbol, + pub value: Symbol, +} + +// deref_into_dyn_supertrait.rs +#[derive(LintDiagnostic)] +#[diag(lint_supertrait_as_deref_target)] +pub struct SupertraitAsDerefTarget<'a> { + pub t: Ty<'a>, + pub target_principal: String, + // pub target_principal: Binder<'a, ExistentialTraitRef<'b>>, + #[subdiagnostic] + pub label: Option<SupertraitAsDerefTargetLabel>, +} + +#[derive(Subdiagnostic)] +#[label(label)] +pub struct SupertraitAsDerefTargetLabel { + #[primary_span] + pub label: Span, +} + +// enum_intrinsics_non_enums.rs +#[derive(LintDiagnostic)] +#[diag(lint_enum_intrinsics_mem_discriminant)] +pub struct EnumIntrinsicsMemDiscriminate<'a> { + pub ty_param: Ty<'a>, + #[note] + pub note: Span, +} + +#[derive(LintDiagnostic)] +#[diag(lint_enum_intrinsics_mem_variant)] +#[note] +pub struct EnumIntrinsicsMemVariant<'a> { + pub ty_param: Ty<'a>, +} + +// expect.rs +#[derive(LintDiagnostic)] +#[diag(lint_expectation)] +pub struct Expectation { + #[subdiagnostic] + pub rationale: Option<ExpectationNote>, + #[note] + pub note: Option<()>, +} + +#[derive(Subdiagnostic)] +#[note(rationale)] +pub struct ExpectationNote { + pub rationale: Symbol, +} + +// for_loops_over_fallibles.rs +#[derive(LintDiagnostic)] +#[diag(lint_for_loops_over_fallibles)] +pub struct ForLoopsOverFalliblesDiag<'a> { + pub article: &'static str, + pub ty: &'static str, + #[subdiagnostic] + pub sub: ForLoopsOverFalliblesLoopSub<'a>, + #[subdiagnostic] + pub question_mark: Option<ForLoopsOverFalliblesQuestionMark>, + #[subdiagnostic] + pub suggestion: ForLoopsOverFalliblesSuggestion<'a>, +} + +#[derive(Subdiagnostic)] +pub enum ForLoopsOverFalliblesLoopSub<'a> { + #[suggestion(remove_next, code = ".by_ref()", applicability = "maybe-incorrect")] + RemoveNext { + #[primary_span] + suggestion: Span, + recv_snip: String, + }, + #[multipart_suggestion(use_while_let, applicability = "maybe-incorrect")] + UseWhileLet { + #[suggestion_part(code = "while let {var}(")] + start_span: Span, + #[suggestion_part(code = ") = ")] + end_span: Span, + var: &'a str, + }, +} + +#[derive(Subdiagnostic)] +#[suggestion(use_question_mark, code = "?", applicability = "maybe-incorrect")] +pub struct ForLoopsOverFalliblesQuestionMark { + #[primary_span] + pub suggestion: Span, +} + +#[derive(Subdiagnostic)] +#[multipart_suggestion(suggestion, applicability = "maybe-incorrect")] +pub struct ForLoopsOverFalliblesSuggestion<'a> { + pub var: &'a str, + #[suggestion_part(code = "if let {var}(")] + pub start_span: Span, + #[suggestion_part(code = ") = ")] + pub end_span: Span, +} + +// hidden_unicode_codepoints.rs +#[derive(LintDiagnostic)] +#[diag(lint_hidden_unicode_codepoints)] +#[note] +pub struct HiddenUnicodeCodepointsDiag<'a> { + pub label: &'a str, + pub count: usize, + #[label] + pub span_label: Span, + #[subdiagnostic] + pub labels: Option<HiddenUnicodeCodepointsDiagLabels>, + #[subdiagnostic] + pub sub: HiddenUnicodeCodepointsDiagSub, +} + +pub struct HiddenUnicodeCodepointsDiagLabels { + pub spans: Vec<(char, Span)>, +} + +impl AddToDiagnostic for HiddenUnicodeCodepointsDiagLabels { + fn add_to_diagnostic_with<F>(self, diag: &mut rustc_errors::Diagnostic, _: F) + where + F: Fn( + &mut rustc_errors::Diagnostic, + rustc_errors::SubdiagnosticMessage, + ) -> rustc_errors::SubdiagnosticMessage, + { + for (c, span) in self.spans { + diag.span_label(span, format!("{:?}", c)); + } + } +} + +pub enum HiddenUnicodeCodepointsDiagSub { + Escape { spans: Vec<(char, Span)> }, + NoEscape { spans: Vec<(char, Span)> }, +} + +// Used because of multiple multipart_suggestion and note +impl AddToDiagnostic for HiddenUnicodeCodepointsDiagSub { + fn add_to_diagnostic_with<F>(self, diag: &mut rustc_errors::Diagnostic, _: F) + where + F: Fn( + &mut rustc_errors::Diagnostic, + rustc_errors::SubdiagnosticMessage, + ) -> rustc_errors::SubdiagnosticMessage, + { + match self { + HiddenUnicodeCodepointsDiagSub::Escape { spans } => { + diag.multipart_suggestion_with_style( + fluent::suggestion_remove, + spans.iter().map(|(_, span)| (*span, "".to_string())).collect(), + Applicability::MachineApplicable, + SuggestionStyle::HideCodeAlways, + ); + diag.multipart_suggestion( + fluent::suggestion_escape, + spans + .into_iter() + .map(|(c, span)| { + let c = format!("{:?}", c); + (span, c[1..c.len() - 1].to_string()) + }) + .collect(), + Applicability::MachineApplicable, + ); + } + HiddenUnicodeCodepointsDiagSub::NoEscape { spans } => { + // FIXME: in other suggestions we've reversed the inner spans of doc comments. We + // should do the same here to provide the same good suggestions as we do for + // literals above. + diag.set_arg( + "escaped", + spans + .into_iter() + .map(|(c, _)| format!("{:?}", c)) + .collect::<Vec<String>>() + .join(", "), + ); + diag.note(fluent::suggestion_remove); + diag.note(fluent::no_suggestion_note_escape); + } + } + } +} + +// internal.rs +#[derive(LintDiagnostic)] +#[diag(lint_default_hash_types)] +#[note] +pub struct DefaultHashTypesDiag<'a> { + pub preferred: &'a str, + pub used: Symbol, +} + +#[derive(LintDiagnostic)] +#[diag(lint_query_instability)] +#[note] +pub struct QueryInstability { + pub query: Symbol, +} + +#[derive(LintDiagnostic)] +#[diag(lint_tykind_kind)] +pub struct TykindKind { + #[suggestion(code = "ty", applicability = "maybe-incorrect")] + pub suggestion: Span, +} + +#[derive(LintDiagnostic)] +#[diag(lint_tykind)] +#[help] +pub struct TykindDiag; + +#[derive(LintDiagnostic)] +#[diag(lint_ty_qualified)] +pub struct TyQualified { + pub ty: String, + #[suggestion(code = "{ty}", applicability = "maybe-incorrect")] + pub suggestion: Span, +} + +#[derive(LintDiagnostic)] +#[diag(lint_lintpass_by_hand)] +#[help] +pub struct LintPassByHand; + +#[derive(LintDiagnostic)] +#[diag(lint_non_existant_doc_keyword)] +#[help] +pub struct NonExistantDocKeyword { + pub keyword: Symbol, +} + +#[derive(LintDiagnostic)] +#[diag(lint_diag_out_of_impl)] +pub struct DiagOutOfImpl; + +#[derive(LintDiagnostic)] +#[diag(lint_untranslatable_diag)] +pub struct UntranslatableDiag; + +#[derive(LintDiagnostic)] +#[diag(lint_bad_opt_access)] +pub struct BadOptAccessDiag<'a> { + pub msg: &'a str, +} + +// let_underscore.rs +#[derive(LintDiagnostic)] +pub enum NonBindingLet { + #[diag(lint_non_binding_let_on_sync_lock)] + SyncLock { + #[subdiagnostic] + sub: NonBindingLetSub, + }, + #[diag(lint_non_binding_let_on_drop_type)] + DropType { + #[subdiagnostic] + sub: NonBindingLetSub, + }, +} + +pub struct NonBindingLetSub { + pub suggestion: Span, + pub multi_suggestion_start: Span, + pub multi_suggestion_end: Span, +} + +impl AddToDiagnostic for NonBindingLetSub { + fn add_to_diagnostic_with<F>(self, diag: &mut rustc_errors::Diagnostic, _: F) + where + F: Fn( + &mut rustc_errors::Diagnostic, + rustc_errors::SubdiagnosticMessage, + ) -> rustc_errors::SubdiagnosticMessage, + { + diag.span_suggestion_verbose( + self.suggestion, + fluent::lint_non_binding_let_suggestion, + "_unused", + Applicability::MachineApplicable, + ); + diag.multipart_suggestion( + fluent::lint_non_binding_let_multi_suggestion, + vec![ + (self.multi_suggestion_start, "drop(".to_string()), + (self.multi_suggestion_end, ")".to_string()), + ], + Applicability::MachineApplicable, + ); + } +} + +// levels.rs +#[derive(LintDiagnostic)] +#[diag(lint_overruled_attribute)] +pub struct OverruledAtributeLint<'a> { + #[label] + pub overruled: Span, + pub lint_level: &'a str, + pub lint_source: Symbol, + #[subdiagnostic] + pub sub: OverruledAttributeSub, +} + +#[derive(LintDiagnostic)] +#[diag(lint_deprecated_lint_name)] +pub struct DeprecatedLintName<'a> { + pub name: String, + #[suggestion(code = "{replace}", applicability = "machine-applicable")] + pub suggestion: Span, + pub replace: &'a str, +} + +// FIXME: Non-translatable msg +#[derive(LintDiagnostic)] +#[diag(lint_renamed_or_removed_lint)] +pub struct RenamedOrRemovedLint<'a> { + pub msg: &'a str, + #[subdiagnostic] + pub suggestion: Option<RenamedOrRemovedLintSuggestion<'a>>, +} + +#[derive(Subdiagnostic)] +#[suggestion(suggestion, code = "{replace}", applicability = "machine-applicable")] +pub struct RenamedOrRemovedLintSuggestion<'a> { + #[primary_span] + pub suggestion: Span, + pub replace: &'a str, +} + +#[derive(LintDiagnostic)] +#[diag(lint_unknown_lint)] +pub struct UnknownLint { + pub name: String, + #[subdiagnostic] + pub suggestion: Option<UnknownLintSuggestion>, +} + +#[derive(Subdiagnostic)] +#[suggestion(suggestion, code = "{replace}", applicability = "maybe-incorrect")] +pub struct UnknownLintSuggestion { + #[primary_span] + pub suggestion: Span, + pub replace: Symbol, +} + +#[derive(LintDiagnostic)] +#[diag(lint_ignored_unless_crate_specified)] +pub struct IgnoredUnlessCrateSpecified<'a> { + pub level: &'a str, + pub name: Symbol, +} + +// methods.rs +#[derive(LintDiagnostic)] +#[diag(lint_cstring_ptr)] +#[note] +#[help] +pub struct CStringPtr { + #[label(as_ptr_label)] + pub as_ptr: Span, + #[label(unwrap_label)] + pub unwrap: Span, +} + +// non_ascii_idents.rs +#[derive(LintDiagnostic)] +#[diag(lint_identifier_non_ascii_char)] +pub struct IdentifierNonAsciiChar; + +#[derive(LintDiagnostic)] +#[diag(lint_identifier_uncommon_codepoints)] +pub struct IdentifierUncommonCodepoints; + +#[derive(LintDiagnostic)] +#[diag(lint_confusable_identifier_pair)] +pub struct ConfusableIdentifierPair { + pub existing_sym: Symbol, + pub sym: Symbol, + #[label] + pub label: Span, +} + +#[derive(LintDiagnostic)] +#[diag(lint_mixed_script_confusables)] +#[note(includes_note)] +#[note] +pub struct MixedScriptConfusables { + pub set: String, + pub includes: String, +} + +// non_fmt_panic.rs +pub struct NonFmtPanicUnused { + pub count: usize, + pub suggestion: Option<Span>, +} + +// Used because of two suggestions based on one Option<Span> +impl<'a> DecorateLint<'a, ()> for NonFmtPanicUnused { + fn decorate_lint<'b>( + self, + diag: &'b mut rustc_errors::DiagnosticBuilder<'a, ()>, + ) -> &'b mut rustc_errors::DiagnosticBuilder<'a, ()> { + diag.set_arg("count", self.count); + diag.note(fluent::note); + if let Some(span) = self.suggestion { + diag.span_suggestion( + span.shrink_to_hi(), + fluent::add_args_suggestion, + ", ...", + Applicability::HasPlaceholders, + ); + diag.span_suggestion( + span.shrink_to_lo(), + fluent::add_fmt_suggestion, + "\"{}\", ", + Applicability::MachineApplicable, + ); + } + diag + } + + fn msg(&self) -> rustc_errors::DiagnosticMessage { + fluent::lint_non_fmt_panic_unused + } +} + +#[derive(LintDiagnostic)] +#[diag(lint_non_fmt_panic_braces)] +#[note] +pub struct NonFmtPanicBraces { + pub count: usize, + #[suggestion(code = "\"{{}}\", ", applicability = "machine-applicable")] + pub suggestion: Option<Span>, +} + +// nonstandard_style.rs +#[derive(LintDiagnostic)] +#[diag(lint_non_camel_case_type)] +pub struct NonCamelCaseType<'a> { + pub sort: &'a str, + pub name: &'a str, + #[subdiagnostic] + pub sub: NonCamelCaseTypeSub, +} + +#[derive(Subdiagnostic)] +pub enum NonCamelCaseTypeSub { + #[label(label)] + Label { + #[primary_span] + span: Span, + }, + #[suggestion(suggestion, code = "{replace}", applicability = "maybe-incorrect")] + Suggestion { + #[primary_span] + span: Span, + replace: String, + }, +} + +#[derive(LintDiagnostic)] +#[diag(lint_non_snake_case)] +pub struct NonSnakeCaseDiag<'a> { + pub sort: &'a str, + pub name: &'a str, + pub sc: String, + #[subdiagnostic] + pub sub: NonSnakeCaseDiagSub, +} + +pub enum NonSnakeCaseDiagSub { + Label { span: Span }, + Help, + RenameOrConvertSuggestion { span: Span, suggestion: Ident }, + ConvertSuggestion { span: Span, suggestion: String }, + SuggestionAndNote { span: Span }, +} + +impl AddToDiagnostic for NonSnakeCaseDiagSub { + fn add_to_diagnostic_with<F>(self, diag: &mut rustc_errors::Diagnostic, _: F) + where + F: Fn( + &mut rustc_errors::Diagnostic, + rustc_errors::SubdiagnosticMessage, + ) -> rustc_errors::SubdiagnosticMessage, + { + match self { + NonSnakeCaseDiagSub::Label { span } => { + diag.span_label(span, fluent::label); + } + NonSnakeCaseDiagSub::Help => { + diag.help(fluent::help); + } + NonSnakeCaseDiagSub::ConvertSuggestion { span, suggestion } => { + diag.span_suggestion( + span, + fluent::convert_suggestion, + suggestion, + Applicability::MaybeIncorrect, + ); + } + NonSnakeCaseDiagSub::RenameOrConvertSuggestion { span, suggestion } => { + diag.span_suggestion( + span, + fluent::rename_or_convert_suggestion, + suggestion, + Applicability::MaybeIncorrect, + ); + } + NonSnakeCaseDiagSub::SuggestionAndNote { span } => { + diag.note(fluent::cannot_convert_note); + diag.span_suggestion( + span, + fluent::rename_suggestion, + "", + Applicability::MaybeIncorrect, + ); + } + } + } +} + +#[derive(LintDiagnostic)] +#[diag(lint_non_upper_case_global)] +pub struct NonUpperCaseGlobal<'a> { + pub sort: &'a str, + pub name: &'a str, + #[subdiagnostic] + pub sub: NonUpperCaseGlobalSub, +} + +#[derive(Subdiagnostic)] +pub enum NonUpperCaseGlobalSub { + #[label(label)] + Label { + #[primary_span] + span: Span, + }, + #[suggestion(suggestion, code = "{replace}", applicability = "maybe-incorrect")] + Suggestion { + #[primary_span] + span: Span, + replace: String, + }, +} + +// noop_method_call.rs +#[derive(LintDiagnostic)] +#[diag(lint_noop_method_call)] +#[note] +pub struct NoopMethodCallDiag<'a> { + pub method: Symbol, + pub receiver_ty: Ty<'a>, + #[label] + pub label: Span, +} + +// pass_by_value.rs +#[derive(LintDiagnostic)] +#[diag(lint_pass_by_value)] +pub struct PassByValueDiag { + pub ty: String, + #[suggestion(code = "{ty}", applicability = "maybe-incorrect")] + pub suggestion: Span, +} + +// redundant_semicolon.rs +#[derive(LintDiagnostic)] +#[diag(lint_redundant_semicolons)] +pub struct RedundantSemicolonsDiag { + pub multiple: bool, + #[suggestion(code = "", applicability = "maybe-incorrect")] + pub suggestion: Span, +} + +// traits.rs +pub struct DropTraitConstraintsDiag<'a> { + pub predicate: Predicate<'a>, + pub tcx: TyCtxt<'a>, + pub def_id: DefId, +} + +// Needed for def_path_str +impl<'a> DecorateLint<'a, ()> for DropTraitConstraintsDiag<'_> { + fn decorate_lint<'b>( + self, + diag: &'b mut rustc_errors::DiagnosticBuilder<'a, ()>, + ) -> &'b mut rustc_errors::DiagnosticBuilder<'a, ()> { + diag.set_arg("predicate", self.predicate); + diag.set_arg("needs_drop", self.tcx.def_path_str(self.def_id)) + } + + fn msg(&self) -> rustc_errors::DiagnosticMessage { + fluent::lint_drop_trait_constraints + } +} + +pub struct DropGlue<'a> { + pub tcx: TyCtxt<'a>, + pub def_id: DefId, +} + +// Needed for def_path_str +impl<'a> DecorateLint<'a, ()> for DropGlue<'_> { + fn decorate_lint<'b>( + self, + diag: &'b mut rustc_errors::DiagnosticBuilder<'a, ()>, + ) -> &'b mut rustc_errors::DiagnosticBuilder<'a, ()> { + diag.set_arg("needs_drop", self.tcx.def_path_str(self.def_id)) + } + + fn msg(&self) -> rustc_errors::DiagnosticMessage { + fluent::lint_drop_glue + } +} + +// types.rs +#[derive(LintDiagnostic)] +#[diag(lint_range_endpoint_out_of_range)] +pub struct RangeEndpointOutOfRange<'a> { + pub ty: &'a str, + #[suggestion(code = "{start}..={literal}{suffix}", applicability = "machine-applicable")] + pub suggestion: Span, + pub start: String, + pub literal: u128, + pub suffix: &'a str, +} + +#[derive(LintDiagnostic)] +#[diag(lint_overflowing_bin_hex)] +pub struct OverflowingBinHex<'a> { + pub ty: &'a str, + pub lit: String, + pub dec: u128, + pub actually: String, + #[subdiagnostic] + pub sign: OverflowingBinHexSign, + #[subdiagnostic] + pub sub: Option<OverflowingBinHexSub<'a>>, +} + +pub enum OverflowingBinHexSign { + Positive, + Negative, +} + +impl AddToDiagnostic for OverflowingBinHexSign { + fn add_to_diagnostic_with<F>(self, diag: &mut rustc_errors::Diagnostic, _: F) + where + F: Fn( + &mut rustc_errors::Diagnostic, + rustc_errors::SubdiagnosticMessage, + ) -> rustc_errors::SubdiagnosticMessage, + { + match self { + OverflowingBinHexSign::Positive => { + diag.note(fluent::positive_note); + } + OverflowingBinHexSign::Negative => { + diag.note(fluent::negative_note); + diag.note(fluent::negative_becomes_note); + } + } + } +} + +#[derive(Subdiagnostic)] +pub enum OverflowingBinHexSub<'a> { + #[suggestion( + suggestion, + code = "{sans_suffix}{suggestion_ty}", + applicability = "machine-applicable" + )] + Suggestion { + #[primary_span] + span: Span, + suggestion_ty: &'a str, + sans_suffix: &'a str, + }, + #[help(help)] + Help { suggestion_ty: &'a str }, +} + +#[derive(LintDiagnostic)] +#[diag(lint_overflowing_int)] +#[note] +pub struct OverflowingInt<'a> { + pub ty: &'a str, + pub lit: String, + pub min: i128, + pub max: u128, + #[subdiagnostic] + pub help: Option<OverflowingIntHelp<'a>>, +} + +#[derive(Subdiagnostic)] +#[help(help)] +pub struct OverflowingIntHelp<'a> { + pub suggestion_ty: &'a str, +} + +#[derive(LintDiagnostic)] +#[diag(lint_only_cast_u8_to_char)] +pub struct OnlyCastu8ToChar { + #[suggestion(code = "'\\u{{{literal:X}}}'", applicability = "machine-applicable")] + pub span: Span, + pub literal: u128, +} + +#[derive(LintDiagnostic)] +#[diag(lint_overflowing_uint)] +#[note] +pub struct OverflowingUInt<'a> { + pub ty: &'a str, + pub lit: String, + pub min: u128, + pub max: u128, +} + +#[derive(LintDiagnostic)] +#[diag(lint_overflowing_literal)] +#[note] +pub struct OverflowingLiteral<'a> { + pub ty: &'a str, + pub lit: String, +} + +#[derive(LintDiagnostic)] +#[diag(lint_unused_comparisons)] +pub struct UnusedComparisons; + +pub struct ImproperCTypes<'a> { + pub ty: Ty<'a>, + pub desc: &'a str, + pub label: Span, + pub help: Option<DiagnosticMessage>, + pub note: DiagnosticMessage, + pub span_note: Option<Span>, +} + +// Used because of the complexity of Option<DiagnosticMessage>, DiagnosticMessage, and Option<Span> +impl<'a> DecorateLint<'a, ()> for ImproperCTypes<'_> { + fn decorate_lint<'b>( + self, + diag: &'b mut rustc_errors::DiagnosticBuilder<'a, ()>, + ) -> &'b mut rustc_errors::DiagnosticBuilder<'a, ()> { + diag.set_arg("ty", self.ty); + diag.set_arg("desc", self.desc); + diag.span_label(self.label, fluent::label); + if let Some(help) = self.help { + diag.help(help); + } + diag.note(self.note); + if let Some(note) = self.span_note { + diag.span_note(note, fluent::note); + } + diag + } + + fn msg(&self) -> rustc_errors::DiagnosticMessage { + fluent::lint_improper_ctypes + } +} + +#[derive(LintDiagnostic)] +#[diag(lint_variant_size_differences)] +pub struct VariantSizeDifferencesDiag { + pub largest: u64, +} + +#[derive(LintDiagnostic)] +#[diag(lint_atomic_ordering_load)] +#[help] +pub struct AtomicOrderingLoad; + +#[derive(LintDiagnostic)] +#[diag(lint_atomic_ordering_store)] +#[help] +pub struct AtomicOrderingStore; + +#[derive(LintDiagnostic)] +#[diag(lint_atomic_ordering_fence)] +#[help] +pub struct AtomicOrderingFence; + +#[derive(LintDiagnostic)] +#[diag(lint_atomic_ordering_invalid)] +#[help] +pub struct InvalidAtomicOrderingDiag { + pub method: Symbol, + #[label] + pub fail_order_arg_span: Span, +} + +// unused.rs +#[derive(LintDiagnostic)] +#[diag(lint_unused_op)] +pub struct UnusedOp<'a> { + pub op: &'a str, + #[label] + pub label: Span, + #[suggestion(style = "verbose", code = "let _ = ", applicability = "machine-applicable")] + pub suggestion: Span, +} + +#[derive(LintDiagnostic)] +#[diag(lint_unused_result)] +pub struct UnusedResult<'a> { + pub ty: Ty<'a>, +} + +// FIXME(davidtwco): this isn't properly translatable becauses of the +// pre/post strings +#[derive(LintDiagnostic)] +#[diag(lint_unused_closure)] +#[note] +pub struct UnusedClosure<'a> { + pub count: usize, + pub pre: &'a str, + pub post: &'a str, +} + +// FIXME(davidtwco): this isn't properly translatable becauses of the +// pre/post strings +#[derive(LintDiagnostic)] +#[diag(lint_unused_generator)] +#[note] +pub struct UnusedGenerator<'a> { + pub count: usize, + pub pre: &'a str, + pub post: &'a str, +} + +// FIXME(davidtwco): this isn't properly translatable becauses of the pre/post +// strings +pub struct UnusedDef<'a, 'b> { + pub pre: &'a str, + pub post: &'a str, + pub cx: &'a LateContext<'b>, + pub def_id: DefId, + pub note: Option<Symbol>, +} + +// Needed because of def_path_str +impl<'a> DecorateLint<'a, ()> for UnusedDef<'_, '_> { + fn decorate_lint<'b>( + self, + diag: &'b mut rustc_errors::DiagnosticBuilder<'a, ()>, + ) -> &'b mut rustc_errors::DiagnosticBuilder<'a, ()> { + diag.set_arg("pre", self.pre); + diag.set_arg("post", self.post); + diag.set_arg("def", self.cx.tcx.def_path_str(self.def_id)); + // check for #[must_use = "..."] + if let Some(note) = self.note { + diag.note(note.as_str()); + } + diag + } + + fn msg(&self) -> rustc_errors::DiagnosticMessage { + fluent::lint_unused_def + } +} + +#[derive(LintDiagnostic)] +#[diag(lint_path_statement_drop)] +pub struct PathStatementDrop { + #[subdiagnostic] + pub sub: PathStatementDropSub, +} + +#[derive(Subdiagnostic)] +pub enum PathStatementDropSub { + #[suggestion(suggestion, code = "drop({snippet});", applicability = "machine-applicable")] + Suggestion { + #[primary_span] + span: Span, + snippet: String, + }, + #[help(help)] + Help { + #[primary_span] + span: Span, + }, +} + +#[derive(LintDiagnostic)] +#[diag(lint_path_statement_no_effect)] +pub struct PathStatementNoEffect; + +#[derive(LintDiagnostic)] +#[diag(lint_unused_delim)] +pub struct UnusedDelim<'a> { + pub delim: &'static str, + pub item: &'a str, + #[subdiagnostic] + pub suggestion: Option<UnusedDelimSuggestion>, +} + +#[derive(Subdiagnostic)] +#[multipart_suggestion(suggestion, applicability = "machine-applicable")] +pub struct UnusedDelimSuggestion { + #[suggestion_part(code = "{start_replace}")] + pub start_span: Span, + pub start_replace: &'static str, + #[suggestion_part(code = "{end_replace}")] + pub end_span: Span, + pub end_replace: &'static str, +} + +#[derive(LintDiagnostic)] +#[diag(lint_unused_import_braces)] +pub struct UnusedImportBracesDiag { + pub node: Symbol, +} + +#[derive(LintDiagnostic)] +#[diag(lint_unused_allocation)] +pub struct UnusedAllocationDiag; + +#[derive(LintDiagnostic)] +#[diag(lint_unused_allocation_mut)] +pub struct UnusedAllocationMutDiag; diff --git a/compiler/rustc_lint/src/methods.rs b/compiler/rustc_lint/src/methods.rs index e2d7d5b49f6..3045fc1a476 100644 --- a/compiler/rustc_lint/src/methods.rs +++ b/compiler/rustc_lint/src/methods.rs @@ -1,7 +1,7 @@ +use crate::lints::CStringPtr; use crate::LateContext; use crate::LateLintPass; use crate::LintContext; -use rustc_errors::fluent; use rustc_hir::{Expr, ExprKind, PathSegment}; use rustc_middle::ty; use rustc_span::{symbol::sym, ExpnKind, Span}; @@ -90,16 +90,10 @@ fn lint_cstring_as_ptr( if cx.tcx.is_diagnostic_item(sym::Result, def.did()) { if let ty::Adt(adt, _) = substs.type_at(0).kind() { if cx.tcx.is_diagnostic_item(sym::cstring_type, adt.did()) { - cx.struct_span_lint( + cx.emit_spanned_lint( TEMPORARY_CSTRING_AS_PTR, as_ptr_span, - fluent::lint_cstring_ptr, - |diag| { - diag.span_label(as_ptr_span, fluent::as_ptr_label) - .span_label(unwrap.span, fluent::unwrap_label) - .note(fluent::note) - .help(fluent::help) - }, + CStringPtr { as_ptr: as_ptr_span, unwrap: unwrap.span }, ); } } diff --git a/compiler/rustc_lint/src/non_ascii_idents.rs b/compiler/rustc_lint/src/non_ascii_idents.rs index dea9506acb2..f130a98185d 100644 --- a/compiler/rustc_lint/src/non_ascii_idents.rs +++ b/compiler/rustc_lint/src/non_ascii_idents.rs @@ -1,7 +1,10 @@ +use crate::lints::{ + ConfusableIdentifierPair, IdentifierNonAsciiChar, IdentifierUncommonCodepoints, + MixedScriptConfusables, +}; use crate::{EarlyContext, EarlyLintPass, LintContext}; use rustc_ast as ast; use rustc_data_structures::fx::FxHashMap; -use rustc_errors::fluent; use rustc_span::symbol::Symbol; declare_lint! { @@ -180,21 +183,11 @@ impl EarlyLintPass for NonAsciiIdents { continue; } has_non_ascii_idents = true; - cx.struct_span_lint( - NON_ASCII_IDENTS, - sp, - fluent::lint_identifier_non_ascii_char, - |lint| lint, - ); + cx.emit_spanned_lint(NON_ASCII_IDENTS, sp, IdentifierNonAsciiChar); if check_uncommon_codepoints && !symbol_str.chars().all(GeneralSecurityProfile::identifier_allowed) { - cx.struct_span_lint( - UNCOMMON_CODEPOINTS, - sp, - fluent::lint_identifier_uncommon_codepoints, - |lint| lint, - ) + cx.emit_spanned_lint(UNCOMMON_CODEPOINTS, sp, IdentifierUncommonCodepoints); } } @@ -222,14 +215,13 @@ impl EarlyLintPass for NonAsciiIdents { .entry(skeleton_sym) .and_modify(|(existing_symbol, existing_span, existing_is_ascii)| { if !*existing_is_ascii || !is_ascii { - cx.struct_span_lint( + cx.emit_spanned_lint( CONFUSABLE_IDENTS, sp, - fluent::lint_confusable_identifier_pair, - |lint| { - lint.set_arg("existing_sym", *existing_symbol) - .set_arg("sym", symbol) - .span_label(*existing_span, fluent::label) + ConfusableIdentifierPair { + existing_sym: *existing_symbol, + sym: symbol, + label: *existing_span, }, ); } @@ -331,24 +323,18 @@ impl EarlyLintPass for NonAsciiIdents { } for ((sp, ch_list), script_set) in lint_reports { - cx.struct_span_lint( + let mut includes = String::new(); + for (idx, ch) in ch_list.into_iter().enumerate() { + if idx != 0 { + includes += ", "; + } + let char_info = format!("'{}' (U+{:04X})", ch, ch as u32); + includes += &char_info; + } + cx.emit_spanned_lint( MIXED_SCRIPT_CONFUSABLES, sp, - fluent::lint_mixed_script_confusables, - |lint| { - let mut includes = String::new(); - for (idx, ch) in ch_list.into_iter().enumerate() { - if idx != 0 { - includes += ", "; - } - let char_info = format!("'{}' (U+{:04X})", ch, ch as u32); - includes += &char_info; - } - lint.set_arg("set", script_set.to_string()) - .set_arg("includes", includes) - .note(fluent::includes_note) - .note(fluent::note) - }, + MixedScriptConfusables { set: script_set.to_string(), includes }, ); } } diff --git a/compiler/rustc_lint/src/non_fmt_panic.rs b/compiler/rustc_lint/src/non_fmt_panic.rs index 8dccfe0046c..4a02c6cce47 100644 --- a/compiler/rustc_lint/src/non_fmt_panic.rs +++ b/compiler/rustc_lint/src/non_fmt_panic.rs @@ -1,3 +1,4 @@ +use crate::lints::{NonFmtPanicBraces, NonFmtPanicUnused}; use crate::{LateContext, LateLintPass, LintContext}; use rustc_ast as ast; use rustc_errors::{fluent, Applicability}; @@ -118,6 +119,7 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc arg_span = expn.call_site; } + #[allow(rustc::diagnostic_outside_of_impl)] cx.struct_span_lint(NON_FMT_PANICS, arg_span, fluent::lint_non_fmt_panic, |lint| { lint.set_arg("name", symbol); lint.note(fluent::note); @@ -253,25 +255,14 @@ fn check_panic_str<'tcx>( .map(|span| fmt_span.from_inner(InnerSpan::new(span.start, span.end))) .collect(), }; - cx.struct_span_lint(NON_FMT_PANICS, arg_spans, fluent::lint_non_fmt_panic_unused, |lint| { - lint.set_arg("count", n_arguments); - lint.note(fluent::note); - if is_arg_inside_call(arg.span, span) { - lint.span_suggestion( - arg.span.shrink_to_hi(), - fluent::add_args_suggestion, - ", ...", - Applicability::HasPlaceholders, - ); - lint.span_suggestion( - arg.span.shrink_to_lo(), - fluent::add_fmt_suggestion, - "\"{}\", ", - Applicability::MachineApplicable, - ); - } - lint - }); + cx.emit_spanned_lint( + NON_FMT_PANICS, + arg_spans, + NonFmtPanicUnused { + count: n_arguments, + suggestion: is_arg_inside_call(arg.span, span).then_some(arg.span), + }, + ); } else { let brace_spans: Option<Vec<_>> = snippet.filter(|s| s.starts_with('"') || s.starts_with("r#")).map(|s| { @@ -281,22 +272,12 @@ fn check_panic_str<'tcx>( .collect() }); let count = brace_spans.as_ref().map(|v| v.len()).unwrap_or(/* any number >1 */ 2); - cx.struct_span_lint( + cx.emit_spanned_lint( NON_FMT_PANICS, brace_spans.unwrap_or_else(|| vec![span]), - fluent::lint_non_fmt_panic_braces, - |lint| { - lint.set_arg("count", count); - lint.note(fluent::note); - if is_arg_inside_call(arg.span, span) { - lint.span_suggestion( - arg.span.shrink_to_lo(), - fluent::suggestion, - "\"{}\", ", - Applicability::MachineApplicable, - ); - } - lint + NonFmtPanicBraces { + count, + suggestion: is_arg_inside_call(arg.span, span).then_some(arg.span.shrink_to_lo()), }, ); } diff --git a/compiler/rustc_lint/src/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs index f37d6e9a63d..74d234fabea 100644 --- a/compiler/rustc_lint/src/nonstandard_style.rs +++ b/compiler/rustc_lint/src/nonstandard_style.rs @@ -1,7 +1,10 @@ +use crate::lints::{ + NonCamelCaseType, NonCamelCaseTypeSub, NonSnakeCaseDiag, NonSnakeCaseDiagSub, + NonUpperCaseGlobal, NonUpperCaseGlobalSub, +}; use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext}; use rustc_ast as ast; use rustc_attr as attr; -use rustc_errors::{fluent, Applicability}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::intravisit::FnKind; @@ -136,30 +139,17 @@ impl NonCamelCaseTypes { let name = ident.name.as_str(); if !is_camel_case(name) { - cx.struct_span_lint( + let cc = to_camel_case(name); + let sub = if *name != cc { + NonCamelCaseTypeSub::Suggestion { span: ident.span, replace: cc } + } else { + NonCamelCaseTypeSub::Label { span: ident.span } + }; + cx.emit_spanned_lint( NON_CAMEL_CASE_TYPES, ident.span, - fluent::lint_non_camel_case_type, - |lint| { - let cc = to_camel_case(name); - // We cannot provide meaningful suggestions - // if the characters are in the category of "Lowercase Letter". - if *name != cc { - lint.span_suggestion( - ident.span, - fluent::suggestion, - to_camel_case(name), - Applicability::MaybeIncorrect, - ); - } else { - lint.span_label(ident.span, fluent::label); - } - - lint.set_arg("sort", sort); - lint.set_arg("name", name); - lint - }, - ) + NonCamelCaseType { sort, name, sub }, + ); } } } @@ -294,47 +284,37 @@ impl NonSnakeCase { let name = ident.name.as_str(); if !is_snake_case(name) { - cx.struct_span_lint(NON_SNAKE_CASE, ident.span, fluent::lint_non_snake_case, |lint| { - let sc = NonSnakeCase::to_snake_case(name); - // We cannot provide meaningful suggestions - // if the characters are in the category of "Uppercase Letter". - if name != sc { - // We have a valid span in almost all cases, but we don't have one when linting a crate - // name provided via the command line. - if !ident.span.is_dummy() { - let sc_ident = Ident::from_str_and_span(&sc, ident.span); - let (message, suggestion) = if sc_ident.is_reserved() { - // We shouldn't suggest a reserved identifier to fix non-snake-case identifiers. - // Instead, recommend renaming the identifier entirely or, if permitted, - // escaping it to create a raw identifier. - if sc_ident.name.can_be_raw() { - (fluent::rename_or_convert_suggestion, sc_ident.to_string()) - } else { - lint.note(fluent::cannot_convert_note); - (fluent::rename_suggestion, String::new()) + let span = ident.span; + let sc = NonSnakeCase::to_snake_case(name); + // We cannot provide meaningful suggestions + // if the characters are in the category of "Uppercase Letter". + let sub = if name != sc { + // We have a valid span in almost all cases, but we don't have one when linting a crate + // name provided via the command line. + if !span.is_dummy() { + let sc_ident = Ident::from_str_and_span(&sc, span); + if sc_ident.is_reserved() { + // We shouldn't suggest a reserved identifier to fix non-snake-case identifiers. + // Instead, recommend renaming the identifier entirely or, if permitted, + // escaping it to create a raw identifier. + if sc_ident.name.can_be_raw() { + NonSnakeCaseDiagSub::RenameOrConvertSuggestion { + span, + suggestion: sc_ident, } } else { - (fluent::convert_suggestion, sc.clone()) - }; - - lint.span_suggestion( - ident.span, - message, - suggestion, - Applicability::MaybeIncorrect, - ); + NonSnakeCaseDiagSub::SuggestionAndNote { span } + } } else { - lint.help(fluent::help); + NonSnakeCaseDiagSub::ConvertSuggestion { span, suggestion: sc.clone() } } } else { - lint.span_label(ident.span, fluent::label); + NonSnakeCaseDiagSub::Help } - - lint.set_arg("sort", sort); - lint.set_arg("name", name); - lint.set_arg("sc", sc); - lint - }); + } else { + NonSnakeCaseDiagSub::Label { span } + }; + cx.emit_spanned_lint(NON_SNAKE_CASE, span, NonSnakeCaseDiag { sort, name, sc, sub }); } } } @@ -490,30 +470,19 @@ impl NonUpperCaseGlobals { fn check_upper_case(cx: &LateContext<'_>, sort: &str, ident: &Ident) { let name = ident.name.as_str(); if name.chars().any(|c| c.is_lowercase()) { - cx.struct_span_lint( + let uc = NonSnakeCase::to_snake_case(&name).to_uppercase(); + // We cannot provide meaningful suggestions + // if the characters are in the category of "Lowercase Letter". + let sub = if *name != uc { + NonUpperCaseGlobalSub::Suggestion { span: ident.span, replace: uc } + } else { + NonUpperCaseGlobalSub::Label { span: ident.span } + }; + cx.emit_spanned_lint( NON_UPPER_CASE_GLOBALS, ident.span, - fluent::lint_non_upper_case_global, - |lint| { - let uc = NonSnakeCase::to_snake_case(&name).to_uppercase(); - // We cannot provide meaningful suggestions - // if the characters are in the category of "Lowercase Letter". - if *name != uc { - lint.span_suggestion( - ident.span, - fluent::suggestion, - uc, - Applicability::MaybeIncorrect, - ); - } else { - lint.span_label(ident.span, fluent::label); - } - - lint.set_arg("sort", sort); - lint.set_arg("name", name); - lint - }, - ) + NonUpperCaseGlobal { sort, name, sub }, + ); } } } diff --git a/compiler/rustc_lint/src/noop_method_call.rs b/compiler/rustc_lint/src/noop_method_call.rs index 2ef425a1093..d67a00619dd 100644 --- a/compiler/rustc_lint/src/noop_method_call.rs +++ b/compiler/rustc_lint/src/noop_method_call.rs @@ -1,7 +1,7 @@ use crate::context::LintContext; +use crate::lints::NoopMethodCallDiag; use crate::LateContext; use crate::LateLintPass; -use rustc_errors::fluent; use rustc_hir::def::DefKind; use rustc_hir::{Expr, ExprKind}; use rustc_middle::ty; @@ -85,11 +85,10 @@ impl<'tcx> LateLintPass<'tcx> for NoopMethodCall { } let expr_span = expr.span; let span = expr_span.with_lo(receiver.span.hi()); - cx.struct_span_lint(NOOP_METHOD_CALL, span, fluent::lint_noop_method_call, |lint| { - lint.set_arg("method", call.ident.name) - .set_arg("receiver_ty", receiver_ty) - .span_label(span, fluent::label) - .note(fluent::note) - }); + cx.emit_spanned_lint( + NOOP_METHOD_CALL, + span, + NoopMethodCallDiag { method: call.ident.name, receiver_ty, label: span }, + ); } } diff --git a/compiler/rustc_lint/src/pass_by_value.rs b/compiler/rustc_lint/src/pass_by_value.rs index 22caadfab17..57482a9edba 100644 --- a/compiler/rustc_lint/src/pass_by_value.rs +++ b/compiler/rustc_lint/src/pass_by_value.rs @@ -1,5 +1,5 @@ +use crate::lints::PassByValueDiag; use crate::{LateContext, LateLintPass, LintContext}; -use rustc_errors::{fluent, Applicability}; use rustc_hir as hir; use rustc_hir::def::Res; use rustc_hir::{GenericArg, PathSegment, QPath, TyKind}; @@ -29,20 +29,11 @@ impl<'tcx> LateLintPass<'tcx> for PassByValue { } } if let Some(t) = path_for_pass_by_value(cx, &inner_ty) { - cx.struct_span_lint( + cx.emit_spanned_lint( PASS_BY_VALUE, ty.span, - fluent::lint_pass_by_value, - |lint| { - lint.set_arg("ty", t.clone()).span_suggestion( - ty.span, - fluent::suggestion, - t, - // Changing type of function argument - Applicability::MaybeIncorrect, - ) - }, - ) + PassByValueDiag { ty: t.clone(), suggestion: ty.span }, + ); } } _ => {} diff --git a/compiler/rustc_lint/src/redundant_semicolon.rs b/compiler/rustc_lint/src/redundant_semicolon.rs index 3521de7fc08..9a8b14b4907 100644 --- a/compiler/rustc_lint/src/redundant_semicolon.rs +++ b/compiler/rustc_lint/src/redundant_semicolon.rs @@ -1,6 +1,5 @@ -use crate::{EarlyContext, EarlyLintPass, LintContext}; +use crate::{lints::RedundantSemicolonsDiag, EarlyContext, EarlyLintPass, LintContext}; use rustc_ast::{Block, StmtKind}; -use rustc_errors::{fluent, Applicability}; use rustc_span::Span; declare_lint! { @@ -48,18 +47,10 @@ fn maybe_lint_redundant_semis(cx: &EarlyContext<'_>, seq: &mut Option<(Span, boo return; } - cx.struct_span_lint( + cx.emit_spanned_lint( REDUNDANT_SEMICOLONS, span, - fluent::lint_redundant_semicolons, - |lint| { - lint.set_arg("multiple", multiple).span_suggestion( - span, - fluent::suggestion, - "", - Applicability::MaybeIncorrect, - ) - }, + RedundantSemicolonsDiag { multiple, suggestion: span }, ); } } diff --git a/compiler/rustc_lint/src/traits.rs b/compiler/rustc_lint/src/traits.rs index 1b21c2dac37..7ea1a138b7e 100644 --- a/compiler/rustc_lint/src/traits.rs +++ b/compiler/rustc_lint/src/traits.rs @@ -1,7 +1,7 @@ +use crate::lints::{DropGlue, DropTraitConstraintsDiag}; use crate::LateContext; use crate::LateLintPass; use crate::LintContext; -use rustc_errors::fluent; use rustc_hir as hir; use rustc_span::symbol::sym; @@ -101,17 +101,13 @@ impl<'tcx> LateLintPass<'tcx> for DropTraitConstraints { if trait_predicate.trait_ref.self_ty().is_impl_trait() { continue; } - let Some(needs_drop) = cx.tcx.get_diagnostic_item(sym::needs_drop) else { - continue; + let Some(def_id) = cx.tcx.get_diagnostic_item(sym::needs_drop) else { + return }; - cx.struct_span_lint( + cx.emit_spanned_lint( DROP_BOUNDS, span, - fluent::lint_drop_trait_constraints, - |lint| { - lint.set_arg("predicate", predicate) - .set_arg("needs_drop", cx.tcx.def_path_str(needs_drop)) - }, + DropTraitConstraintsDiag { predicate, tcx: cx.tcx, def_id }, ); } } @@ -123,12 +119,11 @@ impl<'tcx> LateLintPass<'tcx> for DropTraitConstraints { }; for bound in &bounds[..] { let def_id = bound.trait_ref.trait_def_id(); - if cx.tcx.lang_items().drop_trait() == def_id - && let Some(needs_drop) = cx.tcx.get_diagnostic_item(sym::needs_drop) - { - cx.struct_span_lint(DYN_DROP, bound.span, fluent::lint_drop_glue, |lint| { - lint.set_arg("needs_drop", cx.tcx.def_path_str(needs_drop)) - }); + if cx.tcx.lang_items().drop_trait() == def_id { + let Some(def_id) = cx.tcx.get_diagnostic_item(sym::needs_drop) else { + return + }; + cx.emit_spanned_lint(DYN_DROP, bound.span, DropGlue { tcx: cx.tcx, def_id }); } } } diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index fa415243ba0..f2ab44ac97c 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -1,11 +1,16 @@ +use crate::lints::{ + AtomicOrderingFence, AtomicOrderingLoad, AtomicOrderingStore, ImproperCTypes, + InvalidAtomicOrderingDiag, OnlyCastu8ToChar, OverflowingBinHex, OverflowingBinHexSign, + OverflowingBinHexSub, OverflowingInt, OverflowingIntHelp, OverflowingLiteral, OverflowingUInt, + RangeEndpointOutOfRange, UnusedComparisons, VariantSizeDifferencesDiag, +}; use crate::{LateContext, LateLintPass, LintContext}; use rustc_ast as ast; use rustc_attr as attr; use rustc_data_structures::fx::FxHashSet; -use rustc_errors::{fluent, Applicability, DiagnosticMessage}; +use rustc_errors::{fluent, DiagnosticMessage}; use rustc_hir as hir; use rustc_hir::{is_range_literal, Expr, ExprKind, Node}; -use rustc_macros::LintDiagnostic; use rustc_middle::ty::layout::{IntegerExt, LayoutOf, SizeSkeleton}; use rustc_middle::ty::subst::SubstsRef; use rustc_middle::ty::{self, AdtKind, DefIdTree, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable}; @@ -146,32 +151,22 @@ fn lint_overflowing_range_endpoint<'tcx>( }; let Ok(start) = cx.sess().source_map().span_to_snippet(eps[0].span) else { return false }; - cx.struct_span_lint( + use rustc_ast::{LitIntType, LitKind}; + let suffix = match lit.node { + LitKind::Int(_, LitIntType::Signed(s)) => s.name_str(), + LitKind::Int(_, LitIntType::Unsigned(s)) => s.name_str(), + LitKind::Int(_, LitIntType::Unsuffixed) => "", + _ => bug!(), + }; + cx.emit_spanned_lint( OVERFLOWING_LITERALS, struct_expr.span, - fluent::lint_range_endpoint_out_of_range, - |lint| { - use ast::{LitIntType, LitKind}; - - lint.set_arg("ty", ty); - - // We need to preserve the literal's suffix, - // as it may determine typing information. - let suffix = match lit.node { - LitKind::Int(_, LitIntType::Signed(s)) => s.name_str(), - LitKind::Int(_, LitIntType::Unsigned(s)) => s.name_str(), - LitKind::Int(_, LitIntType::Unsuffixed) => "", - _ => bug!(), - }; - let suggestion = format!("{}..={}{}", start, lit_val - 1, suffix); - lint.span_suggestion( - struct_expr.span, - fluent::suggestion, - suggestion, - Applicability::MachineApplicable, - ); - - lint + RangeEndpointOutOfRange { + ty, + suggestion: struct_expr.span, + start, + literal: lit_val - 1, + suffix, }, ); @@ -228,58 +223,37 @@ fn report_bin_hex_error( val: u128, negative: bool, ) { - cx.struct_span_lint( - OVERFLOWING_LITERALS, - expr.span, - fluent::lint_overflowing_bin_hex, - |lint| { - let (t, actually) = match ty { - attr::IntType::SignedInt(t) => { - let actually = if negative { - -(size.sign_extend(val) as i128) - } else { - size.sign_extend(val) as i128 - }; - (t.name_str(), actually.to_string()) - } - attr::IntType::UnsignedInt(t) => { - let actually = size.truncate(val); - (t.name_str(), actually.to_string()) - } + let (t, actually) = match ty { + attr::IntType::SignedInt(t) => { + let actually = if negative { + -(size.sign_extend(val) as i128) + } else { + size.sign_extend(val) as i128 }; - - if negative { - // If the value is negative, - // emits a note about the value itself, apart from the literal. - lint.note(fluent::negative_note); - lint.note(fluent::negative_becomes_note); + (t.name_str(), actually.to_string()) + } + attr::IntType::UnsignedInt(t) => { + let actually = size.truncate(val); + (t.name_str(), actually.to_string()) + } + }; + let sign = + if negative { OverflowingBinHexSign::Negative } else { OverflowingBinHexSign::Positive }; + let sub = get_type_suggestion(cx.typeck_results().node_type(expr.hir_id), val, negative).map( + |suggestion_ty| { + if let Some(pos) = repr_str.chars().position(|c| c == 'i' || c == 'u') { + let (sans_suffix, _) = repr_str.split_at(pos); + OverflowingBinHexSub::Suggestion { span: expr.span, suggestion_ty, sans_suffix } } else { - lint.note(fluent::positive_note); - } - if let Some(sugg_ty) = - get_type_suggestion(cx.typeck_results().node_type(expr.hir_id), val, negative) - { - lint.set_arg("suggestion_ty", sugg_ty); - if let Some(pos) = repr_str.chars().position(|c| c == 'i' || c == 'u') { - let (sans_suffix, _) = repr_str.split_at(pos); - lint.span_suggestion( - expr.span, - fluent::suggestion, - format!("{}{}", sans_suffix, sugg_ty), - Applicability::MachineApplicable, - ); - } else { - lint.help(fluent::help); - } + OverflowingBinHexSub::Help { suggestion_ty } } - lint.set_arg("ty", t) - .set_arg("lit", repr_str) - .set_arg("dec", val) - .set_arg("actually", actually); - - lint }, ); + cx.emit_spanned_lint( + OVERFLOWING_LITERALS, + expr.span, + OverflowingBinHex { ty: t, lit: repr_str.clone(), dec: val, actually, sign, sub }, + ) } // This function finds the next fitting type and generates a suggestion string. @@ -363,28 +337,19 @@ fn lint_int_literal<'tcx>( return; } - cx.struct_span_lint(OVERFLOWING_LITERALS, e.span, fluent::lint_overflowing_int, |lint| { - lint.set_arg("ty", t.name_str()) - .set_arg( - "lit", - cx.sess() - .source_map() - .span_to_snippet(lit.span) - .expect("must get snippet from literal"), - ) - .set_arg("min", min) - .set_arg("max", max) - .note(fluent::note); - - if let Some(sugg_ty) = - get_type_suggestion(cx.typeck_results().node_type(e.hir_id), v, negative) - { - lint.set_arg("suggestion_ty", sugg_ty); - lint.help(fluent::help); - } - - lint - }); + let lit = cx + .sess() + .source_map() + .span_to_snippet(lit.span) + .expect("must get snippet from literal"); + let help = get_type_suggestion(cx.typeck_results().node_type(e.hir_id), v, negative) + .map(|suggestion_ty| OverflowingIntHelp { suggestion_ty }); + + cx.emit_spanned_lint( + OVERFLOWING_LITERALS, + e.span, + OverflowingInt { ty: t.name_str(), lit, min, max, help }, + ); } } @@ -408,18 +373,10 @@ fn lint_uint_literal<'tcx>( match par_e.kind { hir::ExprKind::Cast(..) => { if let ty::Char = cx.typeck_results().expr_ty(par_e).kind() { - cx.struct_span_lint( + cx.emit_spanned_lint( OVERFLOWING_LITERALS, par_e.span, - fluent::lint_only_cast_u8_to_char, - |lint| { - lint.span_suggestion( - par_e.span, - fluent::suggestion, - format!("'\\u{{{:X}}}'", lit_val), - Applicability::MachineApplicable, - ) - }, + OnlyCastu8ToChar { span: par_e.span, literal: lit_val }, ); return; } @@ -443,19 +400,20 @@ fn lint_uint_literal<'tcx>( ); return; } - cx.struct_span_lint(OVERFLOWING_LITERALS, e.span, fluent::lint_overflowing_uint, |lint| { - lint.set_arg("ty", t.name_str()) - .set_arg( - "lit", - cx.sess() - .source_map() - .span_to_snippet(lit.span) - .expect("must get snippet from literal"), - ) - .set_arg("min", min) - .set_arg("max", max) - .note(fluent::note) - }); + cx.emit_spanned_lint( + OVERFLOWING_LITERALS, + e.span, + OverflowingUInt { + ty: t.name_str(), + lit: cx + .sess() + .source_map() + .span_to_snippet(lit.span) + .expect("must get snippet from literal"), + min, + max, + }, + ); } } @@ -484,20 +442,16 @@ fn lint_literal<'tcx>( _ => bug!(), }; if is_infinite == Ok(true) { - cx.struct_span_lint( + cx.emit_spanned_lint( OVERFLOWING_LITERALS, e.span, - fluent::lint_overflowing_literal, - |lint| { - lint.set_arg("ty", t.name_str()) - .set_arg( - "lit", - cx.sess() - .source_map() - .span_to_snippet(lit.span) - .expect("must get snippet from literal"), - ) - .note(fluent::note) + OverflowingLiteral { + ty: t.name_str(), + lit: cx + .sess() + .source_map() + .span_to_snippet(lit.span) + .expect("must get snippet from literal"), }, ); } @@ -517,12 +471,7 @@ impl<'tcx> LateLintPass<'tcx> for TypeLimits { } hir::ExprKind::Binary(binop, ref l, ref r) => { if is_comparison(binop) && !check_limits(cx, binop, &l, &r) { - cx.struct_span_lint( - UNUSED_COMPARISONS, - e.span, - fluent::lint_unused_comparisons, - |lint| lint, - ); + cx.emit_spanned_lint(UNUSED_COMPARISONS, e.span, UnusedComparisons); } } hir::ExprKind::Lit(ref lit) => lint_literal(cx, self, e, lit), @@ -878,39 +827,39 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { ) -> FfiResult<'tcx> { use FfiResult::*; - if def.repr().transparent() { + let transparent_safety = def.repr().transparent().then(|| { // Can assume that at most one field is not a ZST, so only check // that field's type for FFI-safety. if let Some(field) = transparent_newtype_field(self.cx.tcx, variant) { - self.check_field_type_for_ffi(cache, field, substs) + return self.check_field_type_for_ffi(cache, field, substs); } else { // All fields are ZSTs; this means that the type should behave - // like (), which is FFI-unsafe + // like (), which is FFI-unsafe... except if all fields are PhantomData, + // which is tested for below FfiUnsafe { ty, reason: fluent::lint_improper_ctypes_struct_zst, help: None } } - } else { - // We can't completely trust repr(C) markings; make sure the fields are - // actually safe. - let mut all_phantom = !variant.fields.is_empty(); - for field in &variant.fields { - match self.check_field_type_for_ffi(cache, &field, substs) { - FfiSafe => { - all_phantom = false; - } - FfiPhantom(..) if def.is_enum() => { - return FfiUnsafe { - ty, - reason: fluent::lint_improper_ctypes_enum_phantomdata, - help: None, - }; - } - FfiPhantom(..) => {} - r => return r, + }); + // We can't completely trust repr(C) markings; make sure the fields are + // actually safe. + let mut all_phantom = !variant.fields.is_empty(); + for field in &variant.fields { + match self.check_field_type_for_ffi(cache, &field, substs) { + FfiSafe => { + all_phantom = false; + } + FfiPhantom(..) if !def.repr().transparent() && def.is_enum() => { + return FfiUnsafe { + ty, + reason: fluent::lint_improper_ctypes_enum_phantomdata, + help: None, + }; } + FfiPhantom(..) => {} + r => return transparent_safety.unwrap_or(r), } - - if all_phantom { FfiPhantom(ty) } else { FfiSafe } } + + if all_phantom { FfiPhantom(ty) } else { transparent_safety.unwrap_or(FfiSafe) } } /// Checks if the given type is "ffi-safe" (has a stable, well-defined @@ -1174,26 +1123,21 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { CItemKind::Declaration => IMPROPER_CTYPES, CItemKind::Definition => IMPROPER_CTYPES_DEFINITIONS, }; - - self.cx.struct_span_lint(lint, sp, fluent::lint_improper_ctypes, |lint| { - let item_description = match self.mode { - CItemKind::Declaration => "block", - CItemKind::Definition => "fn", + let desc = match self.mode { + CItemKind::Declaration => "block", + CItemKind::Definition => "fn", + }; + let span_note = if let ty::Adt(def, _) = ty.kind() + && let Some(sp) = self.cx.tcx.hir().span_if_local(def.did()) { + Some(sp) + } else { + None }; - lint.set_arg("ty", ty); - lint.set_arg("desc", item_description); - lint.span_label(sp, fluent::label); - if let Some(help) = help { - lint.help(help); - } - lint.note(note); - if let ty::Adt(def, _) = ty.kind() { - if let Some(sp) = self.cx.tcx.hir().span_if_local(def.did()) { - lint.span_note(sp, fluent::note); - } - } - lint - }); + self.cx.emit_spanned_lint( + lint, + sp, + ImproperCTypes { ty, desc, label: sp, help, note, span_note }, + ); } fn check_for_opaque_ty(&mut self, sp: Span, ty: Ty<'tcx>) -> bool { @@ -1397,11 +1341,10 @@ impl<'tcx> LateLintPass<'tcx> for VariantSizeDifferences { // We only warn if the largest variant is at least thrice as large as // the second-largest. if largest > slargest * 3 && slargest > 0 { - cx.struct_span_lint( + cx.emit_spanned_lint( VARIANT_SIZE_DIFFERENCES, enum_definition.variants[largest_index].span, - fluent::lint_variant_size_differences, - |lint| lint.set_arg("largest", largest), + VariantSizeDifferencesDiag { largest }, ); } } @@ -1509,17 +1452,19 @@ impl InvalidAtomicOrdering { fn check_atomic_load_store(cx: &LateContext<'_>, expr: &Expr<'_>) { if let Some((method, args)) = Self::inherent_atomic_method_call(cx, expr, &[sym::load, sym::store]) - && let Some((ordering_arg, invalid_ordering, msg)) = match method { - sym::load => Some((&args[0], sym::Release, fluent::lint_atomic_ordering_load)), - sym::store => Some((&args[1], sym::Acquire, fluent::lint_atomic_ordering_store)), + && let Some((ordering_arg, invalid_ordering)) = match method { + sym::load => Some((&args[0], sym::Release)), + sym::store => Some((&args[1], sym::Acquire)), _ => None, } && let Some(ordering) = Self::match_ordering(cx, ordering_arg) && (ordering == invalid_ordering || ordering == sym::AcqRel) { - cx.struct_span_lint(INVALID_ATOMIC_ORDERING, ordering_arg.span, msg, |lint| { - lint.help(fluent::help) - }); + if method == sym::load { + cx.emit_spanned_lint(INVALID_ATOMIC_ORDERING, ordering_arg.span, AtomicOrderingLoad); + } else { + cx.emit_spanned_lint(INVALID_ATOMIC_ORDERING, ordering_arg.span, AtomicOrderingStore); + }; } } @@ -1530,10 +1475,7 @@ impl InvalidAtomicOrdering { && matches!(cx.tcx.get_diagnostic_name(def_id), Some(sym::fence | sym::compiler_fence)) && Self::match_ordering(cx, &args[0]) == Some(sym::Relaxed) { - cx.struct_span_lint(INVALID_ATOMIC_ORDERING, args[0].span, fluent::lint_atomic_ordering_fence, |lint| { - lint - .help(fluent::help) - }); + cx.emit_spanned_lint(INVALID_ATOMIC_ORDERING, args[0].span, AtomicOrderingFence); } } @@ -1550,15 +1492,6 @@ impl InvalidAtomicOrdering { let Some(fail_ordering) = Self::match_ordering(cx, fail_order_arg) else { return }; if matches!(fail_ordering, sym::Release | sym::AcqRel) { - #[derive(LintDiagnostic)] - #[diag(lint_atomic_ordering_invalid)] - #[help] - struct InvalidAtomicOrderingDiag { - method: Symbol, - #[label] - fail_order_arg_span: Span, - } - cx.emit_spanned_lint( INVALID_ATOMIC_ORDERING, fail_order_arg.span, diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index 525079681ca..ac2b32b44e6 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -1,9 +1,14 @@ +use crate::lints::{ + PathStatementDrop, PathStatementDropSub, PathStatementNoEffect, UnusedAllocationDiag, + UnusedAllocationMutDiag, UnusedClosure, UnusedDef, UnusedDelim, UnusedDelimSuggestion, + UnusedGenerator, UnusedImportBracesDiag, UnusedOp, UnusedResult, +}; use crate::Lint; use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext}; use rustc_ast as ast; use rustc_ast::util::{classify, parser}; use rustc_ast::{ExprKind, StmtKind}; -use rustc_errors::{fluent, pluralize, Applicability, MultiSpan}; +use rustc_errors::{pluralize, MultiSpan}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; @@ -163,23 +168,20 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { let mut op_warned = false; if let Some(must_use_op) = must_use_op { - cx.struct_span_lint(UNUSED_MUST_USE, expr.span, fluent::lint_unused_op, |lint| { - lint.set_arg("op", must_use_op) - .span_label(expr.span, fluent::label) - .span_suggestion_verbose( - expr.span.shrink_to_lo(), - fluent::suggestion, - "let _ = ", - Applicability::MachineApplicable, - ) - }); + cx.emit_spanned_lint( + UNUSED_MUST_USE, + expr.span, + UnusedOp { + op: must_use_op, + label: expr.span, + suggestion: expr.span.shrink_to_lo(), + }, + ); op_warned = true; } if !(type_lint_emitted_or_suppressed || fn_warned || op_warned) { - cx.struct_span_lint(UNUSED_RESULTS, s.span, fluent::lint_unused_result, |lint| { - lint.set_arg("ty", ty) - }); + cx.emit_spanned_lint(UNUSED_RESULTS, s.span, UnusedResult { ty }); } fn check_fn_must_use(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool { @@ -402,47 +404,31 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { ); } MustUsePath::Closure(span) => { - cx.struct_span_lint( + cx.emit_spanned_lint( UNUSED_MUST_USE, *span, - fluent::lint_unused_closure, - |lint| { - // FIXME(davidtwco): this isn't properly translatable because of the - // pre/post strings - lint.set_arg("count", plural_len) - .set_arg("pre", descr_pre) - .set_arg("post", descr_post) - .note(fluent::note) - }, + UnusedClosure { count: plural_len, pre: descr_pre, post: descr_post }, ); } MustUsePath::Generator(span) => { - cx.struct_span_lint( + cx.emit_spanned_lint( UNUSED_MUST_USE, *span, - fluent::lint_unused_generator, - |lint| { - // FIXME(davidtwco): this isn't properly translatable because of the - // pre/post strings - lint.set_arg("count", plural_len) - .set_arg("pre", descr_pre) - .set_arg("post", descr_post) - .note(fluent::note) - }, + UnusedGenerator { count: plural_len, pre: descr_pre, post: descr_post }, ); } MustUsePath::Def(span, def_id, reason) => { - cx.struct_span_lint(UNUSED_MUST_USE, *span, fluent::lint_unused_def, |lint| { - // FIXME(davidtwco): this isn't properly translatable because of the pre/post - // strings - lint.set_arg("pre", descr_pre); - lint.set_arg("post", descr_post); - lint.set_arg("def", cx.tcx.def_path_str(*def_id)); - if let Some(note) = reason { - lint.note(note.as_str()); - } - lint - }); + cx.emit_spanned_lint( + UNUSED_MUST_USE, + *span, + UnusedDef { + pre: descr_pre, + post: descr_post, + cx, + def_id: *def_id, + note: *reason, + }, + ); } } } @@ -478,31 +464,15 @@ impl<'tcx> LateLintPass<'tcx> for PathStatements { if let hir::ExprKind::Path(_) = expr.kind { let ty = cx.typeck_results().expr_ty(expr); if ty.needs_drop(cx.tcx, cx.param_env) { - cx.struct_span_lint( - PATH_STATEMENTS, - s.span, - fluent::lint_path_statement_drop, - |lint| { - if let Ok(snippet) = cx.sess().source_map().span_to_snippet(expr.span) { - lint.span_suggestion( - s.span, - fluent::suggestion, - format!("drop({});", snippet), - Applicability::MachineApplicable, - ); - } else { - lint.span_help(s.span, fluent::suggestion); - } - lint - }, - ); + let sub = if let Ok(snippet) = cx.sess().source_map().span_to_snippet(expr.span) + { + PathStatementDropSub::Suggestion { span: s.span, snippet } + } else { + PathStatementDropSub::Help { span: s.span } + }; + cx.emit_spanned_lint(PATH_STATEMENTS, s.span, PathStatementDrop { sub }) } else { - cx.struct_span_lint( - PATH_STATEMENTS, - s.span, - fluent::lint_path_statement_no_effect, - |lint| lint, - ); + cx.emit_spanned_lint(PATH_STATEMENTS, s.span, PathStatementNoEffect); } } } @@ -695,36 +665,35 @@ trait UnusedDelimLint { } else { MultiSpan::from(value_span) }; - cx.struct_span_lint(self.lint(), primary_span, fluent::lint_unused_delim, |lint| { - lint.set_arg("delim", Self::DELIM_STR); - lint.set_arg("item", msg); - if let Some((lo, hi)) = spans { - let sm = cx.sess().source_map(); - let lo_replace = + let suggestion = spans.map(|(lo, hi)| { + let sm = cx.sess().source_map(); + let lo_replace = if keep_space.0 && let Ok(snip) = sm.span_to_prev_source(lo) && !snip.ends_with(' ') { - " ".to_string() + " " } else { - "".to_string() + "" }; - let hi_replace = + let hi_replace = if keep_space.1 && let Ok(snip) = sm.span_to_next_source(hi) && !snip.starts_with(' ') { - " ".to_string() + " " } else { - "".to_string() + "" }; - - let replacement = vec![(lo, lo_replace), (hi, hi_replace)]; - lint.multipart_suggestion( - fluent::suggestion, - replacement, - Applicability::MachineApplicable, - ); + UnusedDelimSuggestion { + start_span: lo, + start_replace: lo_replace, + end_span: hi, + end_replace: hi_replace, } - lint }); + cx.emit_spanned_lint( + self.lint(), + primary_span, + UnusedDelim { delim: Self::DELIM_STR, item: msg, suggestion }, + ); } fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) { @@ -1297,11 +1266,10 @@ impl UnusedImportBraces { ast::UseTreeKind::Nested(_) => return, }; - cx.struct_span_lint( + cx.emit_spanned_lint( UNUSED_IMPORT_BRACES, item.span, - fluent::lint_unused_import_braces, - |lint| lint.set_arg("node", node_name), + UnusedImportBracesDiag { node: node_name }, ); } } @@ -1351,17 +1319,14 @@ impl<'tcx> LateLintPass<'tcx> for UnusedAllocation { for adj in cx.typeck_results().expr_adjustments(e) { if let adjustment::Adjust::Borrow(adjustment::AutoBorrow::Ref(_, m)) = adj.kind { - cx.struct_span_lint( - UNUSED_ALLOCATION, - e.span, - match m { - adjustment::AutoBorrowMutability::Not => fluent::lint_unused_allocation, - adjustment::AutoBorrowMutability::Mut { .. } => { - fluent::lint_unused_allocation_mut - } - }, - |lint| lint, - ); + match m { + adjustment::AutoBorrowMutability::Not => { + cx.emit_spanned_lint(UNUSED_ALLOCATION, e.span, UnusedAllocationDiag); + } + adjustment::AutoBorrowMutability::Mut { .. } => { + cx.emit_spanned_lint(UNUSED_ALLOCATION, e.span, UnusedAllocationMutDiag); + } + }; } } } diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 28317d6cea0..6cdf5097083 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -4033,10 +4033,10 @@ declare_lint! { /// /// This can be used to implement an unsound API if used incorrectly. pub IMPLIED_BOUNDS_ENTAILMENT, - Warn, + Deny, "impl method assumes more implied bounds than its corresponding trait method", @future_incompatible = FutureIncompatibleInfo { reference: "issue #105572 <https://github.com/rust-lang/rust/issues/105572>", - reason: FutureIncompatibilityReason::FutureReleaseError, + reason: FutureIncompatibilityReason::FutureReleaseErrorReportNow, }; } diff --git a/compiler/rustc_log/Cargo.toml b/compiler/rustc_log/Cargo.toml index 3c50827c1ab..7f955b0a750 100644 --- a/compiler/rustc_log/Cargo.toml +++ b/compiler/rustc_log/Cargo.toml @@ -7,6 +7,7 @@ edition = "2021" tracing = "0.1.28" tracing-subscriber = { version = "0.3.3", default-features = false, features = ["fmt", "env-filter", "smallvec", "parking_lot", "ansi"] } tracing-tree = "0.2.0" +tracing-core = "0.1.28" [dev-dependencies] rustc_span = { path = "../rustc_span" } diff --git a/compiler/rustc_log/src/lib.rs b/compiler/rustc_log/src/lib.rs index 4cac88aff64..fc1cabd2de9 100644 --- a/compiler/rustc_log/src/lib.rs +++ b/compiler/rustc_log/src/lib.rs @@ -45,16 +45,34 @@ use std::env::{self, VarError}; use std::fmt::{self, Display}; use std::io::{self, IsTerminal}; +use tracing_core::{Event, Subscriber}; use tracing_subscriber::filter::{Directive, EnvFilter, LevelFilter}; +use tracing_subscriber::fmt::{ + format::{self, FormatEvent, FormatFields}, + FmtContext, +}; use tracing_subscriber::layer::SubscriberExt; pub fn init_rustc_env_logger() -> Result<(), Error> { - init_env_logger("RUSTC_LOG") + init_rustc_env_logger_with_backtrace_option(&None) +} + +pub fn init_rustc_env_logger_with_backtrace_option( + backtrace_target: &Option<String>, +) -> Result<(), Error> { + init_env_logger_with_backtrace_option("RUSTC_LOG", backtrace_target) } /// In contrast to `init_rustc_env_logger` this allows you to choose an env var /// other than `RUSTC_LOG`. pub fn init_env_logger(env: &str) -> Result<(), Error> { + init_env_logger_with_backtrace_option(env, &None) +} + +pub fn init_env_logger_with_backtrace_option( + env: &str, + backtrace_target: &Option<String>, +) -> Result<(), Error> { let filter = match env::var(env) { Ok(env) => EnvFilter::new(env), _ => EnvFilter::default().add_directive(Directive::from(LevelFilter::WARN)), @@ -88,11 +106,47 @@ pub fn init_env_logger(env: &str) -> Result<(), Error> { let layer = layer.with_thread_ids(true).with_thread_names(true); let subscriber = tracing_subscriber::Registry::default().with(filter).with(layer); - tracing::subscriber::set_global_default(subscriber).unwrap(); + match backtrace_target { + Some(str) => { + let fmt_layer = tracing_subscriber::fmt::layer() + .with_writer(io::stderr) + .without_time() + .event_format(BacktraceFormatter { backtrace_target: str.to_string() }); + let subscriber = subscriber.with(fmt_layer); + tracing::subscriber::set_global_default(subscriber).unwrap(); + } + None => { + tracing::subscriber::set_global_default(subscriber).unwrap(); + } + }; Ok(()) } +struct BacktraceFormatter { + backtrace_target: String, +} + +impl<S, N> FormatEvent<S, N> for BacktraceFormatter +where + S: Subscriber + for<'a> tracing_subscriber::registry::LookupSpan<'a>, + N: for<'a> FormatFields<'a> + 'static, +{ + fn format_event( + &self, + _ctx: &FmtContext<'_, S, N>, + mut writer: format::Writer<'_>, + event: &Event<'_>, + ) -> fmt::Result { + let target = event.metadata().target(); + if !target.contains(&self.backtrace_target) { + return Ok(()); + } + let backtrace = std::backtrace::Backtrace::capture(); + writeln!(writer, "stack backtrace: \n{:?}", backtrace) + } +} + pub fn stdout_isatty() -> bool { io::stdout().is_terminal() } diff --git a/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs b/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs index 82f6812026a..e405462bbb8 100644 --- a/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs +++ b/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs @@ -382,10 +382,26 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> { return Ok(quote! { #diag.subdiagnostic(#binding); }); } } - (Meta::List(_), "subdiagnostic") => { - throw_invalid_attr!(attr, &meta, |diag| { - diag.help("`subdiagnostic` does not support nested attributes") - }) + (Meta::List(MetaList { ref nested, .. }), "subdiagnostic") => { + if nested.len() == 1 + && let Some(NestedMeta::Meta(Meta::Path(path))) = nested.first() + && path.is_ident("eager") { + let handler = match &self.parent.kind { + DiagnosticDeriveKind::Diagnostic { handler } => handler, + DiagnosticDeriveKind::LintDiagnostic => { + throw_invalid_attr!(attr, &meta, |diag| { + diag.help("eager subdiagnostics are not supported on lints") + }) + } + }; + return Ok(quote! { #diag.eager_subdiagnostic(#handler, #binding); }); + } else { + throw_invalid_attr!(attr, &meta, |diag| { + diag.help( + "`eager` is the only supported nested attribute for `subdiagnostic`", + ) + }) + } } _ => (), } diff --git a/compiler/rustc_macros/src/lib.rs b/compiler/rustc_macros/src/lib.rs index ac916bb6068..bb3722fe156 100644 --- a/compiler/rustc_macros/src/lib.rs +++ b/compiler/rustc_macros/src/lib.rs @@ -1,5 +1,6 @@ #![feature(allow_internal_unstable)] #![feature(if_let_guard)] +#![feature(let_chains)] #![feature(never_type)] #![feature(proc_macro_diagnostic)] #![feature(proc_macro_span)] diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index bdc4ae391f0..030328d1e26 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1686,6 +1686,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } ty::Closure(_, substs) => { + let constness = self.tcx.constness(def_id.to_def_id()); + self.tables.constness.set(def_id.to_def_id().index, constness); record!(self.tables.fn_sig[def_id.to_def_id()] <- substs.as_closure().sig()); } diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs index 75282f958b5..f816d614500 100644 --- a/compiler/rustc_middle/src/arena.rs +++ b/compiler/rustc_middle/src/arena.rs @@ -30,7 +30,12 @@ macro_rules! arena_types { [decode] typeck_results: rustc_middle::ty::TypeckResults<'tcx>, [decode] borrowck_result: rustc_middle::mir::BorrowCheckResult<'tcx>, - [] resolver: rustc_data_structures::steal::Steal<rustc_middle::ty::ResolverAstLowering>, + [] resolver: rustc_data_structures::steal::Steal<( + rustc_middle::ty::ResolverAstLowering, + rustc_data_structures::sync::Lrc<rustc_ast::Crate>, + )>, + [] output_filenames: std::sync::Arc<rustc_session::config::OutputFilenames>, + [] resolutions: rustc_middle::ty::ResolverGlobalCtxt, [decode] unsafety_check_result: rustc_middle::mir::UnsafetyCheckResult, [decode] code_region: rustc_middle::mir::coverage::CodeRegion, [] const_allocs: rustc_middle::mir::interpret::Allocation, diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index 883554f959c..48bae7a2d4e 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -485,7 +485,9 @@ impl<'hir> Map<'hir> { BodyOwnerKind::Static(mt) => ConstContext::Static(mt), BodyOwnerKind::Fn if self.tcx.is_constructor(def_id.to_def_id()) => return None, - BodyOwnerKind::Fn if self.tcx.is_const_fn_raw(def_id.to_def_id()) => { + BodyOwnerKind::Fn | BodyOwnerKind::Closure + if self.tcx.is_const_fn_raw(def_id.to_def_id()) => + { ConstContext::ConstFn } BodyOwnerKind::Fn if self.tcx.is_const_default_method(def_id.to_def_id()) => { diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 076ce1bdb34..86655915736 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -27,12 +27,12 @@ rustc_queries! { } query resolutions(_: ()) -> &'tcx ty::ResolverGlobalCtxt { - eval_always + feedable no_hash desc { "getting the resolver outputs" } } - query resolver_for_lowering(_: ()) -> &'tcx Steal<ty::ResolverAstLowering> { + query resolver_for_lowering(_: ()) -> &'tcx Steal<(ty::ResolverAstLowering, Lrc<ast::Crate>)> { feedable no_hash desc { "getting the resolver for lowering" } @@ -1673,7 +1673,7 @@ rustc_queries! { /// Gets the name of the crate. query crate_name(_: CrateNum) -> Symbol { - eval_always + feedable desc { "fetching what a crate is named" } separate_provide_extern } @@ -1857,7 +1857,7 @@ rustc_queries! { /// This query returns an `&Arc` because codegen backends need the value even after the `TyCtxt` /// has been destroyed. query output_filenames(_: ()) -> &'tcx Arc<OutputFilenames> { - eval_always + feedable desc { "getting output filenames" } } @@ -2041,7 +2041,7 @@ rustc_queries! { } query features_query(_: ()) -> &'tcx rustc_feature::Features { - eval_always + feedable desc { "looking up enabled feature gates" } } diff --git a/compiler/rustc_middle/src/traits/select.rs b/compiler/rustc_middle/src/traits/select.rs index ec69864c951..1cc9fd526b4 100644 --- a/compiler/rustc_middle/src/traits/select.rs +++ b/compiler/rustc_middle/src/traits/select.rs @@ -131,7 +131,9 @@ pub enum SelectionCandidate<'tcx> { /// Implementation of a `Fn`-family trait by one of the anonymous types /// generated for an `||` expression. - ClosureCandidate, + ClosureCandidate { + is_const: bool, + }, /// Implementation of a `Generator` trait by one of the anonymous types /// generated for a generator. diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 5de414077a2..63f31e5a11f 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -51,7 +51,7 @@ use rustc_macros::HashStable; use rustc_query_system::dep_graph::DepNodeIndex; use rustc_query_system::ich::StableHashingContext; use rustc_serialize::opaque::{FileEncodeResult, FileEncoder}; -use rustc_session::config::{CrateType, OutputFilenames}; +use rustc_session::config::CrateType; use rustc_session::cstore::{CrateStoreDyn, Untracked}; use rustc_session::lint::Lint; use rustc_session::Limit; @@ -74,7 +74,6 @@ use std::hash::{Hash, Hasher}; use std::iter; use std::mem; use std::ops::{Bound, Deref}; -use std::sync::Arc; pub trait OnDiskCache<'tcx>: rustc_data_structures::sync::Sync { /// Creates a new `OnDiskCache` instance from the serialized data in `data`. @@ -363,6 +362,9 @@ impl<'tcx> TyCtxt<'tcx> { pub fn feed_unit_query(self) -> TyCtxtFeed<'tcx, ()> { TyCtxtFeed { tcx: self, key: () } } + pub fn feed_local_crate(self) -> TyCtxtFeed<'tcx, CrateNum> { + TyCtxtFeed { tcx: self, key: LOCAL_CRATE } + } } impl<'tcx, KEY: Copy> TyCtxtFeed<'tcx, KEY> { @@ -428,11 +430,6 @@ pub struct GlobalCtxt<'tcx> { pub consts: CommonConsts<'tcx>, untracked: Untracked, - /// Output of the resolver. - pub(crate) untracked_resolutions: ty::ResolverGlobalCtxt, - /// The entire crate as AST. This field serves as the input for the hir_crate query, - /// which lowers it from AST to HIR. It must not be read or used by anything else. - pub untracked_crate: Steal<Lrc<ast::Crate>>, /// This provides access to the incremental compilation on-disk cache for query results. /// Do not access this directly. It is only meant to be used by @@ -457,17 +454,11 @@ pub struct GlobalCtxt<'tcx> { /// Merge this with `selection_cache`? pub evaluation_cache: traits::EvaluationCache<'tcx>, - /// The definite name of the current crate after taking into account - /// attributes, commandline parameters, etc. - crate_name: Symbol, - /// Data layout specification for the current target. pub data_layout: TargetDataLayout, /// Stores memory for globals (statics/consts). pub(crate) alloc_map: Lock<interpret::AllocMap<'tcx>>, - - output_filenames: Arc<OutputFilenames>, } impl<'tcx> TyCtxt<'tcx> { @@ -592,15 +583,11 @@ impl<'tcx> TyCtxt<'tcx> { lint_store: Lrc<dyn Any + sync::Send + sync::Sync>, arena: &'tcx WorkerLocal<Arena<'tcx>>, hir_arena: &'tcx WorkerLocal<hir::Arena<'tcx>>, - untracked_resolutions: ty::ResolverGlobalCtxt, untracked: Untracked, - krate: Lrc<ast::Crate>, dep_graph: DepGraph, on_disk_cache: Option<&'tcx dyn OnDiskCache<'tcx>>, queries: &'tcx dyn query::QueryEngine<'tcx>, query_kinds: &'tcx [DepKindStruct<'tcx>], - crate_name: Symbol, - output_filenames: OutputFilenames, ) -> GlobalCtxt<'tcx> { let data_layout = s.target.parse_data_layout().unwrap_or_else(|err| { s.emit_fatal(err); @@ -622,8 +609,6 @@ impl<'tcx> TyCtxt<'tcx> { lifetimes: common_lifetimes, consts: common_consts, untracked, - untracked_resolutions, - untracked_crate: Steal::new(krate), on_disk_cache, queries, query_caches: query::QueryCaches::default(), @@ -632,10 +617,8 @@ impl<'tcx> TyCtxt<'tcx> { pred_rcache: Default::default(), selection_cache: Default::default(), evaluation_cache: Default::default(), - crate_name, data_layout, alloc_map: Lock::new(interpret::AllocMap::new()), - output_filenames: Arc::new(output_filenames), } } @@ -810,7 +793,7 @@ impl<'tcx> TyCtxt<'tcx> { // statements within the query system and we'd run into endless // recursion otherwise. let (crate_name, stable_crate_id) = if def_id.is_local() { - (self.crate_name, self.sess.local_stable_crate_id()) + (self.crate_name(LOCAL_CRATE), self.sess.local_stable_crate_id()) } else { let cstore = &*self.untracked.cstore; (cstore.crate_name(def_id.krate), cstore.stable_crate_id(def_id.krate)) @@ -2407,13 +2390,8 @@ fn ptr_eq<T, U>(t: *const T, u: *const U) -> bool { } pub fn provide(providers: &mut ty::query::Providers) { - providers.resolutions = |tcx, ()| &tcx.untracked_resolutions; providers.module_reexports = |tcx, id| tcx.resolutions(()).reexport_map.get(&id).map(|v| &v[..]); - providers.crate_name = |tcx, id| { - assert_eq!(id, LOCAL_CRATE); - tcx.crate_name - }; providers.maybe_unused_trait_imports = |tcx, ()| &tcx.resolutions(()).maybe_unused_trait_imports; providers.maybe_unused_extern_crates = @@ -2424,8 +2402,6 @@ pub fn provide(providers: &mut ty::query::Providers) { providers.extern_mod_stmt_cnum = |tcx, id| tcx.resolutions(()).extern_crate_map.get(&id).cloned(); - providers.output_filenames = |tcx, ()| &tcx.output_filenames; - providers.features_query = |tcx, ()| tcx.sess.features_untracked(); providers.is_panic_runtime = |tcx, cnum| { assert_eq!(cnum, LOCAL_CRATE); tcx.sess.contains_name(tcx.hir().krate_attrs(), sym::panic_runtime) diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index fa571d480b6..993e95b3514 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -2465,8 +2465,10 @@ impl<'tcx> TyCtxt<'tcx> { #[inline] pub fn is_const_fn_raw(self, def_id: DefId) -> bool { - matches!(self.def_kind(def_id), DefKind::Fn | DefKind::AssocFn | DefKind::Ctor(..)) - && self.constness(def_id) == hir::Constness::Const + matches!( + self.def_kind(def_id), + DefKind::Fn | DefKind::AssocFn | DefKind::Ctor(..) | DefKind::Closure + ) && self.constness(def_id) == hir::Constness::Const } #[inline] diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index f7e4c821569..bd5b04d5b2b 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -1686,7 +1686,7 @@ impl<'tcx> Ty<'tcx> { } #[inline] - pub fn is_ty_infer(self) -> bool { + pub fn is_ty_or_numeric_infer(self) -> bool { matches!(self.kind(), Infer(_)) } diff --git a/compiler/rustc_middle/src/ty/subst.rs b/compiler/rustc_middle/src/ty/subst.rs index 0c33e5bda1a..2dec58ea82a 100644 --- a/compiler/rustc_middle/src/ty/subst.rs +++ b/compiler/rustc_middle/src/ty/subst.rs @@ -202,7 +202,7 @@ impl<'tcx> GenericArg<'tcx> { pub fn is_non_region_infer(self) -> bool { match self.unpack() { GenericArgKind::Lifetime(_) => false, - GenericArgKind::Type(ty) => ty.is_ty_infer(), + GenericArgKind::Type(ty) => ty.is_ty_or_numeric_infer(), GenericArgKind::Const(ct) => ct.is_ct_infer(), } } diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index f5093fb02a8..dd2b03988c3 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -1325,7 +1325,10 @@ impl<'a> Parser<'a> { self.parse_array_or_repeat_expr(Delimiter::Bracket) } else if self.check_path() { self.parse_path_start_expr() - } else if self.check_keyword(kw::Move) || self.check_keyword(kw::Static) { + } else if self.check_keyword(kw::Move) + || self.check_keyword(kw::Static) + || self.check_const_closure() + { self.parse_closure_expr() } else if self.eat_keyword(kw::If) { self.parse_if_expr() @@ -2065,6 +2068,8 @@ impl<'a> Parser<'a> { ClosureBinder::NotPresent }; + let constness = self.parse_constness(Case::Sensitive); + let movability = if self.eat_keyword(kw::Static) { Movability::Static } else { Movability::Movable }; @@ -2111,6 +2116,7 @@ impl<'a> Parser<'a> { ExprKind::Closure(Box::new(ast::Closure { binder, capture_clause, + constness, asyncness, movability, fn_decl, diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 49d31981539..2fd2a4e5154 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -736,6 +736,16 @@ impl<'a> Parser<'a> { self.check_or_expected(self.token.can_begin_const_arg(), TokenType::Const) } + fn check_const_closure(&self) -> bool { + self.is_keyword_ahead(0, &[kw::Const]) + && self.look_ahead(1, |t| match &t.kind { + token::Ident(kw::Move | kw::Static | kw::Async, _) + | token::OrOr + | token::BinOp(token::Or) => true, + _ => false, + }) + } + fn check_inline_const(&self, dist: usize) -> bool { self.is_keyword_ahead(dist, &[kw::Const]) && self.look_ahead(dist + 1, |t| match &t.kind { diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index c59c06ac31e..f9f9799d3e4 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -82,6 +82,7 @@ impl CheckAttrVisitor<'_> { let attrs = self.tcx.hir().attrs(hir_id); for attr in attrs { let attr_is_valid = match attr.name_or_empty() { + sym::do_not_recommend => self.check_do_not_recommend(attr.span, target), sym::inline => self.check_inline(hir_id, attr, span, target), sym::no_coverage => self.check_no_coverage(hir_id, attr, span, target), sym::non_exhaustive => self.check_non_exhaustive(hir_id, attr, span, target), @@ -241,6 +242,16 @@ impl CheckAttrVisitor<'_> { ); } + /// Checks if `#[do_not_recommend]` is applied on a trait impl. + fn check_do_not_recommend(&self, attr_span: Span, target: Target) -> bool { + if let Target::Impl = target { + true + } else { + self.tcx.sess.emit_err(errors::IncorrectDoNotRecommendLocation { span: attr_span }); + false + } + } + /// Checks if an `#[inline]` is applied to a function or a closure. Returns `true` if valid. fn check_inline(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) -> bool { match target { diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index c6cd69add28..9c6519ea4bb 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -14,6 +14,13 @@ use rustc_span::{Span, Symbol, DUMMY_SP}; use crate::lang_items::Duplicate; +#[derive(Diagnostic)] +#[diag(passes_incorrect_do_not_recommend_location)] +pub struct IncorrectDoNotRecommendLocation { + #[primary_span] + pub span: Span, +} + #[derive(LintDiagnostic)] #[diag(passes_outer_crate_level_attr)] pub struct OuterCrateLevelAttr; diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 58f6fd2b006..b1b04c92a75 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -334,6 +334,15 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { self.r.field_names.insert(def_id, field_names); } + fn insert_field_visibilities_local(&mut self, def_id: DefId, vdata: &ast::VariantData) { + let field_vis = vdata + .fields() + .iter() + .map(|field| field.vis.span.until(field.ident.map_or(field.ty.span, |i| i.span))) + .collect(); + self.r.field_visibility_spans.insert(def_id, field_vis); + } + fn insert_field_names_extern(&mut self, def_id: DefId) { let field_names = self.r.cstore().struct_field_names_untracked(def_id, self.r.session).collect(); @@ -737,6 +746,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { // Record field names for error reporting. self.insert_field_names_local(def_id, vdata); + self.insert_field_visibilities_local(def_id, vdata); // If this is a tuple or unit struct, define a name // in the value namespace as well. @@ -770,6 +780,8 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { Res::Def(DefKind::Ctor(CtorOf::Struct, ctor_kind), ctor_def_id.to_def_id()); self.r.define(parent, ident, ValueNS, (ctor_res, ctor_vis, sp, expansion)); self.r.visibilities.insert(ctor_def_id, ctor_vis); + // We need the field visibility spans also for the constructor for E0603. + self.insert_field_visibilities_local(ctor_def_id.to_def_id(), vdata); self.r .struct_constructors @@ -783,6 +795,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { // Record field names for error reporting. self.insert_field_names_local(def_id, vdata); + self.insert_field_visibilities_local(def_id, vdata); } ItemKind::Trait(..) => { @@ -1510,6 +1523,7 @@ impl<'a, 'b> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b> { // Record field names for error reporting. self.insert_field_names_local(def_id.to_def_id(), &variant.data); + self.insert_field_visibilities_local(def_id.to_def_id(), &variant.data); visit::walk_variant(self, variant); } diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 7d62d67d64f..fb2aebbd18a 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -6,7 +6,9 @@ use rustc_ast::{self as ast, Crate, ItemKind, ModKind, NodeId, Path, CRATE_NODE_ use rustc_ast_pretty::pprust; use rustc_data_structures::fx::FxHashSet; use rustc_errors::struct_span_err; -use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, MultiSpan}; +use rustc_errors::{ + pluralize, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, MultiSpan, +}; use rustc_feature::BUILTIN_ATTRIBUTES; use rustc_hir::def::Namespace::{self, *}; use rustc_hir::def::{self, CtorKind, CtorOf, DefKind, NonMacroAttrKind, PerNS}; @@ -165,7 +167,7 @@ impl<'a> Resolver<'a> { ); err.emit(); } else if let Some((span, msg, sugg, appl)) = suggestion { - err.span_suggestion(span, msg, sugg, appl); + err.span_suggestion_verbose(span, msg, sugg, appl); err.emit(); } else if let [segment] = path.as_slice() && is_call { err.stash(segment.ident.span, rustc_errors::StashKey::CallIntoMethod); @@ -1604,6 +1606,16 @@ impl<'a> Resolver<'a> { err.span_label(ident.span, &format!("private {}", descr)); if let Some(span) = ctor_fields_span { err.span_label(span, "a constructor is private if any of the fields is private"); + if let Res::Def(_, d) = res && let Some(fields) = self.field_visibility_spans.get(&d) { + err.multipart_suggestion_verbose( + &format!( + "consider making the field{} publicly accessible", + pluralize!(fields.len()) + ), + fields.iter().map(|span| (*span, "pub ".to_string())).collect(), + Applicability::MaybeIncorrect, + ); + } } // Print the whole import chain to make it easier to see what happens. diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 74522f18542..d92b046d0b9 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -1451,6 +1451,17 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { .collect(); if non_visible_spans.len() > 0 { + if let Some(fields) = self.r.field_visibility_spans.get(&def_id) { + err.multipart_suggestion_verbose( + &format!( + "consider making the field{} publicly accessible", + pluralize!(fields.len()) + ), + fields.iter().map(|span| (*span, "pub ".to_string())).collect(), + Applicability::MaybeIncorrect, + ); + } + let mut m: MultiSpan = non_visible_spans.clone().into(); non_visible_spans .into_iter() @@ -2054,7 +2065,11 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { path: &[Segment], ) -> Option<(Span, &'static str, String, Applicability)> { let (ident, span) = match path { - [segment] if !segment.has_generic_args && segment.ident.name != kw::SelfUpper => { + [segment] + if !segment.has_generic_args + && segment.ident.name != kw::SelfUpper + && segment.ident.name != kw::Dyn => + { (segment.ident.to_string(), segment.ident.span) } _ => return None, diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 2182b736937..f950e4a9bee 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -881,6 +881,10 @@ pub struct Resolver<'a> { /// Used for hints during error reporting. field_names: FxHashMap<DefId, Vec<Spanned<Symbol>>>, + /// Span of the privacy modifier in fields of an item `DefId` accessible with dot syntax. + /// Used for hints during error reporting. + field_visibility_spans: FxHashMap<DefId, Vec<Span>>, + /// All imports known to succeed or fail. determined_imports: Vec<&'a Import<'a>>, @@ -1133,7 +1137,7 @@ impl<'a, 'b> DefIdTree for &'a Resolver<'b> { } } -impl Resolver<'_> { +impl<'a> Resolver<'a> { fn opt_local_def_id(&self, node: NodeId) -> Option<LocalDefId> { self.node_id_to_def_id.get(&node).copied() } @@ -1190,6 +1194,10 @@ impl Resolver<'_> { self.cstore().item_generics_num_lifetimes(def_id, self.session) } } + + pub fn sess(&self) -> &'a Session { + self.session + } } impl<'a> Resolver<'a> { @@ -1268,6 +1276,7 @@ impl<'a> Resolver<'a> { has_self: FxHashSet::default(), field_names: FxHashMap::default(), + field_visibility_spans: FxHashMap::default(), determined_imports: Vec::new(), indeterminate_imports: Vec::new(), diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index b062b43873b..7b5fd6cc2a8 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -1411,6 +1411,8 @@ options! { "what location details should be tracked when using caller_location, either \ `none`, or a comma separated list of location details, for which \ valid options are `file`, `line`, and `column` (default: `file,line,column`)"), + log_backtrace: Option<String> = (None, parse_opt_string, [TRACKED], + "add a backtrace along with logging"), ls: bool = (false, parse_bool, [UNTRACKED], "list the symbols defined by a library crate (default: no)"), macro_backtrace: bool = (false, parse_bool, [UNTRACKED], diff --git a/compiler/rustc_span/Cargo.toml b/compiler/rustc_span/Cargo.toml index 5ce2577b63c..ae81d95e279 100644 --- a/compiler/rustc_span/Cargo.toml +++ b/compiler/rustc_span/Cargo.toml @@ -15,6 +15,6 @@ scoped-tls = "1.0" unicode-width = "0.1.4" cfg-if = "1.0" tracing = "0.1" -sha1 = { package = "sha-1", version = "0.10.0" } +sha1 = "0.10.0" sha2 = "0.10.1" md5 = { package = "md-5", version = "0.10.0" } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index fbb12701d96..706002f79b1 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -498,6 +498,7 @@ symbols! { console, const_allocate, const_async_blocks, + const_closures, const_compare_raw_pointers, const_constructor, const_deallocate, diff --git a/compiler/rustc_target/src/spec/abi.rs b/compiler/rustc_target/src/spec/abi.rs index cb2a0c04c6a..d4f7ed31b89 100644 --- a/compiler/rustc_target/src/spec/abi.rs +++ b/compiler/rustc_target/src/spec/abi.rs @@ -149,7 +149,7 @@ pub fn is_stable(name: &str) -> Result<(), AbiDisabled> { match name { // Stable "Rust" | "C" | "cdecl" | "stdcall" | "fastcall" | "aapcs" | "win64" | "sysv64" - | "system" => Ok(()), + | "system" | "efiapi" => Ok(()), "rust-intrinsic" => Err(AbiDisabled::Unstable { feature: sym::intrinsics, explain: "intrinsics are subject to change", @@ -198,10 +198,6 @@ pub fn is_stable(name: &str) -> Result<(), AbiDisabled> { feature: sym::abi_avr_interrupt, explain: "avr-interrupt and avr-non-blocking-interrupt ABIs are experimental and subject to change", }), - "efiapi" => Err(AbiDisabled::Unstable { - feature: sym::abi_efiapi, - explain: "efiapi ABI is experimental and subject to change", - }), "C-cmse-nonsecure-call" => Err(AbiDisabled::Unstable { feature: sym::abi_c_cmse_nonsecure_call, explain: "C-cmse-nonsecure-call ABI is experimental and subject to change", diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/method_chain.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/method_chain.rs index 27c207528c7..ba9ee57d409 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/method_chain.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/method_chain.rs @@ -55,7 +55,7 @@ impl<'a, 'tcx> TypeRelation<'tcx> for CollectAllMismatches<'a, 'tcx> { fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { self.infcx.probe(|_| { - if a.is_ty_infer() || b.is_ty_infer() { + if a.is_ty_var() || b.is_ty_var() { Ok(a) } else { self.infcx.super_combine_tys(self, a, b).or_else(|e| { @@ -71,10 +71,13 @@ impl<'a, 'tcx> TypeRelation<'tcx> for CollectAllMismatches<'a, 'tcx> { a: ty::Const<'tcx>, b: ty::Const<'tcx>, ) -> RelateResult<'tcx, ty::Const<'tcx>> { - if a == b { - return Ok(a); - } - relate::super_relate_consts(self, a, b) // could do something similar here for constants! + self.infcx.probe(|_| { + if a.is_ct_infer() || b.is_ct_infer() { + Ok(a) + } else { + relate::super_relate_consts(self, a, b) // could do something similar here for constants! + } + }) } fn binders<T: Relate<'tcx>>( diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index 20bede22c34..0c7ffb056cc 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -2252,8 +2252,11 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { Ok(None) => { let ambiguities = ambiguity::recompute_applicable_impls(self.infcx, &obligation); - let has_non_region_infer = - trait_ref.skip_binder().substs.types().any(|t| !t.is_ty_infer()); + let has_non_region_infer = trait_ref + .skip_binder() + .substs + .types() + .any(|t| !t.is_ty_or_numeric_infer()); // It doesn't make sense to talk about applicable impls if there are more // than a handful of them. if ambiguities.len() > 1 && ambiguities.len() < 10 && has_non_region_infer { 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 170c1673dbd..8c291d1595d 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -255,18 +255,19 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // touch bound regions, they just capture the in-scope // type/region parameters match *obligation.self_ty().skip_binder().kind() { - ty::Closure(_, closure_substs) => { + ty::Closure(def_id, closure_substs) => { + let is_const = self.tcx().is_const_fn_raw(def_id); debug!(?kind, ?obligation, "assemble_unboxed_candidates"); match self.infcx.closure_kind(closure_substs) { Some(closure_kind) => { debug!(?closure_kind, "assemble_unboxed_candidates"); if closure_kind.extends(kind) { - candidates.vec.push(ClosureCandidate); + candidates.vec.push(ClosureCandidate { is_const }); } } None => { debug!("assemble_unboxed_candidates: closure_kind not yet known"); - candidates.vec.push(ClosureCandidate); + candidates.vec.push(ClosureCandidate { is_const }); } } } diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 15526b34ed2..a41d10f1043 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -84,7 +84,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ImplSource::Object(data) } - ClosureCandidate => { + ClosureCandidate { .. } => { let vtable_closure = self.confirm_closure_candidate(obligation)?; ImplSource::Closure(vtable_closure) } diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 2615e262282..305902af7c8 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -1365,15 +1365,18 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // const param ParamCandidate(trait_pred) if trait_pred.is_const_if_const() => {} // const projection - ProjectionCandidate(_, ty::BoundConstness::ConstIfConst) => {} + ProjectionCandidate(_, ty::BoundConstness::ConstIfConst) // auto trait impl - AutoImplCandidate => {} + | AutoImplCandidate // generator / future, this will raise error in other places // or ignore error with const_async_blocks feature - GeneratorCandidate => {} - FutureCandidate => {} + | GeneratorCandidate + | FutureCandidate // FnDef where the function is const - FnPointerCandidate { is_const: true } => {} + | FnPointerCandidate { is_const: true } + | ConstDestructCandidate(_) + | ClosureCandidate { is_const: true } => {} + FnPointerCandidate { is_const: false } => { if let ty::FnDef(def_id, _) = obligation.self_ty().skip_binder().kind() && tcx.trait_of_item(*def_id).is_some() { // Trait methods are not seen as const unless the trait is implemented as const. @@ -1382,7 +1385,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { continue } } - ConstDestructCandidate(_) => {} + _ => { // reject all other types of candidates continue; @@ -1844,7 +1847,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ( ParamCandidate(ref cand), ImplCandidate(..) - | ClosureCandidate + | ClosureCandidate { .. } | GeneratorCandidate | FutureCandidate | FnPointerCandidate { .. } @@ -1863,7 +1866,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } ( ImplCandidate(_) - | ClosureCandidate + | ClosureCandidate { .. } | GeneratorCandidate | FutureCandidate | FnPointerCandidate { .. } @@ -1894,7 +1897,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ( ObjectCandidate(_) | ProjectionCandidate(..), ImplCandidate(..) - | ClosureCandidate + | ClosureCandidate { .. } | GeneratorCandidate | FutureCandidate | FnPointerCandidate { .. } @@ -1907,7 +1910,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ( ImplCandidate(..) - | ClosureCandidate + | ClosureCandidate { .. } | GeneratorCandidate | FutureCandidate | FnPointerCandidate { .. } @@ -1989,7 +1992,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // Everything else is ambiguous ( ImplCandidate(_) - | ClosureCandidate + | ClosureCandidate { .. } | GeneratorCandidate | FutureCandidate | FnPointerCandidate { .. } @@ -1999,7 +2002,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { | BuiltinCandidate { has_nested: true } | TraitAliasCandidate, ImplCandidate(_) - | ClosureCandidate + | ClosureCandidate { .. } | GeneratorCandidate | FutureCandidate | FnPointerCandidate { .. } diff --git a/library/alloc/src/collections/binary_heap.rs b/library/alloc/src/collections/binary_heap/mod.rs index 4583bc9a158..4583bc9a158 100644 --- a/library/alloc/src/collections/binary_heap.rs +++ b/library/alloc/src/collections/binary_heap/mod.rs diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs index ebf5baa3c02..a7d6fec7d3d 100644 --- a/library/core/src/cmp.rs +++ b/library/core/src/cmp.rs @@ -1234,17 +1234,23 @@ where F: ~const Destruct, K: ~const Destruct, { - const fn imp<T, F: ~const FnMut(&T) -> K, K: ~const Ord>( - f: &mut F, - (v1, v2): (&T, &T), - ) -> Ordering - where - T: ~const Destruct, - K: ~const Destruct, - { - f(v1).cmp(&f(v2)) + cfg_if! { + if #[cfg(bootstrap)] { + const fn imp<T, F: ~const FnMut(&T) -> K, K: ~const Ord>( + f: &mut F, + (v1, v2): (&T, &T), + ) -> Ordering + where + T: ~const Destruct, + K: ~const Destruct, + { + f(v1).cmp(&f(v2)) + } + min_by(v1, v2, ConstFnMutClosure::new(&mut f, imp)) + } else { + min_by(v1, v2, const |v1, v2| f(v1).cmp(&f(v2))) + } } - min_by(v1, v2, ConstFnMutClosure::new(&mut f, imp)) } /// Compares and returns the maximum of two values. diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs index 51e6a76cea8..fa5073e3304 100644 --- a/library/core/src/fmt/mod.rs +++ b/library/core/src/fmt/mod.rs @@ -174,6 +174,11 @@ pub trait Write { /// This method should generally not be invoked manually, but rather through /// the [`write!`] macro itself. /// + /// # Errors + /// + /// This function will return an instance of [`Error`] on error. Please see + /// [write_str](Write::write_str) for details. + /// /// # Examples /// /// ``` diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index 99aaf798e41..a4a665d48d5 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -58,6 +58,11 @@ fn _assert_is_object_safe(_: &dyn Iterator<Item = ()>) {} note = "if you want to iterate between `start` until a value `end`, use the exclusive range \ syntax `start..end` or the inclusive range syntax `start..=end`" ), + on( + _Self = "{float}", + note = "if you want to iterate between `start` until a value `end`, use the exclusive range \ + syntax `start..end` or the inclusive range syntax `start..=end`" + ), label = "`{Self}` is not an iterator", message = "`{Self}` is not an iterator" )] diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index e898bca88e4..8790649abe6 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -191,6 +191,7 @@ #![feature(cfg_sanitize)] #![feature(cfg_target_has_atomic)] #![feature(cfg_target_has_atomic_equal_alignment)] +#![cfg_attr(not(bootstrap), feature(const_closures))] #![feature(const_fn_floating_point_arithmetic)] #![feature(const_mut_refs)] #![feature(const_precise_live_drops)] diff --git a/library/core/src/option.rs b/library/core/src/option.rs index 39462dca4ff..7cc00e3f8d1 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -652,13 +652,14 @@ impl<T> Option<T> { /// /// # Examples /// - /// Converts an <code>Option<[String]></code> into an <code>Option<[usize]></code>, preserving - /// the original. The [`map`] method takes the `self` argument by value, consuming the original, - /// so this technique uses `as_ref` to first take an `Option` to a reference - /// to the value inside the original. + /// Calculates the length of an <code>Option<[String]></code> as an <code>Option<[usize]></code> + /// without moving the [`String`]. The [`map`] method takes the `self` argument by value, + /// consuming the original, so this technique uses `as_ref` to first take an `Option` to a + /// reference to the value inside the original. /// /// [`map`]: Option::map /// [String]: ../../std/string/struct.String.html "String" + /// [`String`]: ../../std/string/struct.String.html "String" /// /// ``` /// let text: Option<String> = Some("Hello, world!".to_string()); @@ -946,8 +947,8 @@ impl<T> Option<T> { /// /// # Examples /// - /// Converts an <code>Option<[String]></code> into an <code>Option<[usize]></code>, consuming - /// the original: + /// Calculates the length of an <code>Option<[String]></code> as an + /// <code>Option<[usize]></code>, consuming the original: /// /// [String]: ../../std/string/struct.String.html "String" /// ``` diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs index edc68d6fae5..14367eb09bc 100644 --- a/library/core/src/sync/atomic.rs +++ b/library/core/src/sync/atomic.rs @@ -1786,6 +1786,42 @@ impl<T> AtomicPtr<T> { // SAFETY: data races are prevented by atomic intrinsics. unsafe { atomic_xor(self.p.get(), core::ptr::invalid_mut(val), order).cast() } } + + /// Returns a mutable pointer to the underlying pointer. + /// + /// Doing non-atomic reads and writes on the resulting integer can be a data race. + /// This method is mostly useful for FFI, where the function signature may use + /// `*mut *mut T` instead of `&AtomicPtr<T>`. + /// + /// Returning an `*mut` pointer from a shared reference to this atomic is safe because the + /// atomic types work with interior mutability. All modifications of an atomic change the value + /// through a shared reference, and can do so safely as long as they use atomic operations. Any + /// use of the returned raw pointer requires an `unsafe` block and still has to uphold the same + /// restriction: operations on it must be atomic. + /// + /// # Examples + /// + /// ```ignore (extern-declaration) + /// #![feature(atomic_mut_ptr)] + //// use std::sync::atomic::AtomicPtr; + /// + /// extern "C" { + /// fn my_atomic_op(arg: *mut *mut u32); + /// } + /// + /// let mut value = 17; + /// let atomic = AtomicPtr::new(&mut value); + /// + /// // SAFETY: Safe as long as `my_atomic_op` is atomic. + /// unsafe { + /// my_atomic_op(atomic.as_mut_ptr()); + /// } + /// ``` + #[inline] + #[unstable(feature = "atomic_mut_ptr", reason = "recently added", issue = "66893")] + pub fn as_mut_ptr(&self) -> *mut *mut T { + self.p.get() + } } #[cfg(target_has_atomic_load_store = "8")] @@ -2678,9 +2714,9 @@ macro_rules! atomic_int { #[doc = concat!(" fn my_atomic_op(arg: *mut ", stringify!($int_type), ");")] /// } /// - #[doc = concat!("let mut atomic = ", stringify!($atomic_type), "::new(1);")] + #[doc = concat!("let atomic = ", stringify!($atomic_type), "::new(1);")] /// - // SAFETY: Safe as long as `my_atomic_op` is atomic. + /// // SAFETY: Safe as long as `my_atomic_op` is atomic. /// unsafe { /// my_atomic_op(atomic.as_mut_ptr()); /// } diff --git a/library/std/src/personality/dwarf/eh.rs b/library/std/src/personality/dwarf/eh.rs index a783e187004..87585a8fcd0 100644 --- a/library/std/src/personality/dwarf/eh.rs +++ b/library/std/src/personality/dwarf/eh.rs @@ -84,7 +84,7 @@ pub unsafe fn find_eh_action(lsda: *const u8, context: &EHContext<'_>) -> Result let cs_start = read_encoded_pointer(&mut reader, context, call_site_encoding)?; let cs_len = read_encoded_pointer(&mut reader, context, call_site_encoding)?; let cs_lpad = read_encoded_pointer(&mut reader, context, call_site_encoding)?; - let cs_action = reader.read_uleb128(); + let cs_action_entry = reader.read_uleb128(); // Callsite table is sorted by cs_start, so if we've passed the ip, we // may stop searching. if ip < func_start + cs_start { @@ -95,7 +95,7 @@ pub unsafe fn find_eh_action(lsda: *const u8, context: &EHContext<'_>) -> Result return Ok(EHAction::None); } else { let lpad = lpad_base + cs_lpad; - return Ok(interpret_cs_action(cs_action, lpad)); + return Ok(interpret_cs_action(action_table as *mut u8, cs_action_entry, lpad)); } } } @@ -113,26 +113,39 @@ pub unsafe fn find_eh_action(lsda: *const u8, context: &EHContext<'_>) -> Result let mut idx = ip; loop { let cs_lpad = reader.read_uleb128(); - let cs_action = reader.read_uleb128(); + let cs_action_entry = reader.read_uleb128(); idx -= 1; if idx == 0 { // Can never have null landing pad for sjlj -- that would have // been indicated by a -1 call site index. let lpad = (cs_lpad + 1) as usize; - return Ok(interpret_cs_action(cs_action, lpad)); + return Ok(interpret_cs_action(action_table as *mut u8, cs_action_entry, lpad)); } } } } -fn interpret_cs_action(cs_action: u64, lpad: usize) -> EHAction { - if cs_action == 0 { - // If cs_action is 0 then this is a cleanup (Drop::drop). We run these +unsafe fn interpret_cs_action( + action_table: *mut u8, + cs_action_entry: u64, + lpad: usize, +) -> EHAction { + if cs_action_entry == 0 { + // If cs_action_entry is 0 then this is a cleanup (Drop::drop). We run these // for both Rust panics and foreign exceptions. EHAction::Cleanup(lpad) } else { - // Stop unwinding Rust panics at catch_unwind. - EHAction::Catch(lpad) + // If lpad != 0 and cs_action_entry != 0, we have to check ttype_index. + // If ttype_index == 0 under the condition, we take cleanup action. + let action_record = (action_table as *mut u8).offset(cs_action_entry as isize - 1); + let mut action_reader = DwarfReader::new(action_record); + let ttype_index = action_reader.read_sleb128(); + if ttype_index == 0 { + EHAction::Cleanup(lpad) + } else { + // Stop unwinding Rust panics at catch_unwind. + EHAction::Catch(lpad) + } } } diff --git a/library/std/src/sync/mpmc/array.rs b/library/std/src/sync/mpmc/array.rs index f71edc6c525..c1e3e48b044 100644 --- a/library/std/src/sync/mpmc/array.rs +++ b/library/std/src/sync/mpmc/array.rs @@ -168,7 +168,7 @@ impl<T> Channel<T> { return true; } Err(_) => { - backoff.spin(); + backoff.spin_light(); tail = self.tail.load(Ordering::Relaxed); } } @@ -182,11 +182,11 @@ impl<T> Channel<T> { return false; } - backoff.spin(); + backoff.spin_light(); tail = self.tail.load(Ordering::Relaxed); } else { // Snooze because we need to wait for the stamp to get updated. - backoff.snooze(); + backoff.spin_heavy(); tail = self.tail.load(Ordering::Relaxed); } } @@ -251,7 +251,7 @@ impl<T> Channel<T> { return true; } Err(_) => { - backoff.spin(); + backoff.spin_light(); head = self.head.load(Ordering::Relaxed); } } @@ -273,11 +273,11 @@ impl<T> Channel<T> { } } - backoff.spin(); + backoff.spin_light(); head = self.head.load(Ordering::Relaxed); } else { // Snooze because we need to wait for the stamp to get updated. - backoff.snooze(); + backoff.spin_heavy(); head = self.head.load(Ordering::Relaxed); } } @@ -330,7 +330,7 @@ impl<T> Channel<T> { if backoff.is_completed() { break; } else { - backoff.spin(); + backoff.spin_light(); } } diff --git a/library/std/src/sync/mpmc/list.rs b/library/std/src/sync/mpmc/list.rs index 2d5b2fb3b23..ec6c0726ac7 100644 --- a/library/std/src/sync/mpmc/list.rs +++ b/library/std/src/sync/mpmc/list.rs @@ -46,7 +46,7 @@ impl<T> Slot<T> { fn wait_write(&self) { let backoff = Backoff::new(); while self.state.load(Ordering::Acquire) & WRITE == 0 { - backoff.snooze(); + backoff.spin_heavy(); } } } @@ -82,7 +82,7 @@ impl<T> Block<T> { if !next.is_null() { return next; } - backoff.snooze(); + backoff.spin_heavy(); } } @@ -191,7 +191,7 @@ impl<T> Channel<T> { // If we reached the end of the block, wait until the next one is installed. if offset == BLOCK_CAP { - backoff.snooze(); + backoff.spin_heavy(); tail = self.tail.index.load(Ordering::Acquire); block = self.tail.block.load(Ordering::Acquire); continue; @@ -247,7 +247,7 @@ impl<T> Channel<T> { return true; }, Err(_) => { - backoff.spin(); + backoff.spin_light(); tail = self.tail.index.load(Ordering::Acquire); block = self.tail.block.load(Ordering::Acquire); } @@ -286,7 +286,7 @@ impl<T> Channel<T> { // If we reached the end of the block, wait until the next one is installed. if offset == BLOCK_CAP { - backoff.snooze(); + backoff.spin_heavy(); head = self.head.index.load(Ordering::Acquire); block = self.head.block.load(Ordering::Acquire); continue; @@ -320,7 +320,7 @@ impl<T> Channel<T> { // The block can be null here only if the first message is being sent into the channel. // In that case, just wait until it gets initialized. if block.is_null() { - backoff.snooze(); + backoff.spin_heavy(); head = self.head.index.load(Ordering::Acquire); block = self.head.block.load(Ordering::Acquire); continue; @@ -351,7 +351,7 @@ impl<T> Channel<T> { return true; }, Err(_) => { - backoff.spin(); + backoff.spin_light(); head = self.head.index.load(Ordering::Acquire); block = self.head.block.load(Ordering::Acquire); } @@ -542,7 +542,7 @@ impl<T> Channel<T> { // New updates to tail will be rejected by MARK_BIT and aborted unless it's // at boundary. We need to wait for the updates take affect otherwise there // can be memory leaks. - backoff.snooze(); + backoff.spin_heavy(); tail = self.tail.index.load(Ordering::Acquire); } diff --git a/library/std/src/sync/mpmc/mod.rs b/library/std/src/sync/mpmc/mod.rs index cef99c58843..7a602cecd3b 100644 --- a/library/std/src/sync/mpmc/mod.rs +++ b/library/std/src/sync/mpmc/mod.rs @@ -43,7 +43,7 @@ mod zero; use crate::fmt; use crate::panic::{RefUnwindSafe, UnwindSafe}; use crate::time::{Duration, Instant}; -use error::*; +pub use error::*; /// Creates a channel of unbounded capacity. /// diff --git a/library/std/src/sync/mpmc/utils.rs b/library/std/src/sync/mpmc/utils.rs index e030c55ce8f..cfe42750d52 100644 --- a/library/std/src/sync/mpmc/utils.rs +++ b/library/std/src/sync/mpmc/utils.rs @@ -91,9 +91,8 @@ impl<T> DerefMut for CachePadded<T> { } const SPIN_LIMIT: u32 = 6; -const YIELD_LIMIT: u32 = 10; -/// Performs exponential backoff in spin loops. +/// Performs quadratic backoff in spin loops. pub struct Backoff { step: Cell<u32>, } @@ -104,25 +103,27 @@ impl Backoff { Backoff { step: Cell::new(0) } } - /// Backs off in a lock-free loop. + /// Backs off using lightweight spinning. /// - /// This method should be used when we need to retry an operation because another thread made - /// progress. + /// This method should be used for: + /// - Retrying an operation because another thread made progress. i.e. on CAS failure. + /// - Waiting for an operation to complete by spinning optimistically for a few iterations + /// before falling back to parking the thread (see `Backoff::is_completed`). #[inline] - pub fn spin(&self) { + pub fn spin_light(&self) { let step = self.step.get().min(SPIN_LIMIT); for _ in 0..step.pow(2) { crate::hint::spin_loop(); } - if self.step.get() <= SPIN_LIMIT { - self.step.set(self.step.get() + 1); - } + self.step.set(self.step.get() + 1); } - /// Backs off in a blocking loop. + /// Backs off using heavyweight spinning. + /// + /// This method should be used in blocking loops where parking the thread is not an option. #[inline] - pub fn snooze(&self) { + pub fn spin_heavy(&self) { if self.step.get() <= SPIN_LIMIT { for _ in 0..self.step.get().pow(2) { crate::hint::spin_loop() @@ -131,14 +132,12 @@ impl Backoff { crate::thread::yield_now(); } - if self.step.get() <= YIELD_LIMIT { - self.step.set(self.step.get() + 1); - } + self.step.set(self.step.get() + 1); } - /// Returns `true` if quadratic backoff has completed and blocking the thread is advised. + /// Returns `true` if quadratic backoff has completed and parking the thread is advised. #[inline] pub fn is_completed(&self) -> bool { - self.step.get() > YIELD_LIMIT + self.step.get() > SPIN_LIMIT } } diff --git a/library/std/src/sync/mpmc/zero.rs b/library/std/src/sync/mpmc/zero.rs index fccd6c29a7e..33f768dcbe9 100644 --- a/library/std/src/sync/mpmc/zero.rs +++ b/library/std/src/sync/mpmc/zero.rs @@ -57,7 +57,7 @@ impl<T> Packet<T> { fn wait_ready(&self) { let backoff = Backoff::new(); while !self.ready.load(Ordering::Acquire) { - backoff.snooze(); + backoff.spin_heavy(); } } } diff --git a/library/std/src/sync/mpsc/mod.rs b/library/std/src/sync/mpsc/mod.rs index adb488d4378..6e3c28f10bb 100644 --- a/library/std/src/sync/mpsc/mod.rs +++ b/library/std/src/sync/mpsc/mod.rs @@ -738,6 +738,15 @@ impl<T> SyncSender<T> { pub fn try_send(&self, t: T) -> Result<(), TrySendError<T>> { self.inner.try_send(t) } + + // Attempts to send for a value on this receiver, returning an error if the + // corresponding channel has hung up, or if it waits more than `timeout`. + // + // This method is currently private and only used for tests. + #[allow(unused)] + fn send_timeout(&self, t: T, timeout: Duration) -> Result<(), mpmc::SendTimeoutError<T>> { + self.inner.send_timeout(t, timeout) + } } #[stable(feature = "rust1", since = "1.0.0")] diff --git a/library/std/src/sync/mpsc/sync_tests.rs b/library/std/src/sync/mpsc/sync_tests.rs index 63c79436974..9d2f92ffc9b 100644 --- a/library/std/src/sync/mpsc/sync_tests.rs +++ b/library/std/src/sync/mpsc/sync_tests.rs @@ -1,5 +1,6 @@ use super::*; use crate::env; +use crate::sync::mpmc::SendTimeoutError; use crate::thread; use crate::time::Duration; @@ -42,6 +43,13 @@ fn recv_timeout() { } #[test] +fn send_timeout() { + let (tx, _rx) = sync_channel::<i32>(1); + assert_eq!(tx.send_timeout(1, Duration::from_millis(1)), Ok(())); + assert_eq!(tx.send_timeout(1, Duration::from_millis(1)), Err(SendTimeoutError::Timeout(1))); +} + +#[test] fn smoke_threads() { let (tx, rx) = sync_channel::<i32>(0); let _t = thread::spawn(move || { diff --git a/src/ci/docker/host-x86_64/mingw-check/Dockerfile b/src/ci/docker/host-x86_64/mingw-check/Dockerfile index adf6bb4b377..d5bc76eeb23 100644 --- a/src/ci/docker/host-x86_64/mingw-check/Dockerfile +++ b/src/ci/docker/host-x86_64/mingw-check/Dockerfile @@ -45,6 +45,7 @@ ENV SCRIPT python3 ../x.py --stage 2 test src/tools/expand-yaml-anchors && \ python3 ../x.py test --stage 0 src/tools/compiletest && \ python3 ../x.py test --stage 0 core alloc std test proc_macro && \ # Build both public and internal documentation. + RUSTDOCFLAGS=\"--document-private-items --document-hidden-items\" python3 ../x.py doc --stage 0 compiler && \ RUSTDOCFLAGS=\"--document-private-items --document-hidden-items\" python3 ../x.py doc --stage 0 library/test && \ /scripts/validate-toolstate.sh && \ /scripts/validate-error-codes.sh && \ diff --git a/src/doc/rustdoc/src/lints.md b/src/doc/rustdoc/src/lints.md index bff01d7cb7c..45db3bb9b00 100644 --- a/src/doc/rustdoc/src/lints.md +++ b/src/doc/rustdoc/src/lints.md @@ -261,7 +261,7 @@ typo mistakes for some common attributes. ## `invalid_html_tags` -This lint is **allowed by default** and is **nightly-only**. It detects unclosed +This lint **warns by default**. It detects unclosed or invalid HTML tags. For example: ```rust diff --git a/src/doc/unstable-book/src/language-features/abi-efiapi.md b/src/doc/unstable-book/src/language-features/abi-efiapi.md deleted file mode 100644 index b492da88474..00000000000 --- a/src/doc/unstable-book/src/language-features/abi-efiapi.md +++ /dev/null @@ -1,23 +0,0 @@ -# `abi_efiapi` - -The tracking issue for this feature is: [#65815] - -[#65815]: https://github.com/rust-lang/rust/issues/65815 - ------------------------- - -The `efiapi` calling convention can be used for defining a function with -an ABI compatible with the UEFI Interfaces as defined in the [UEFI -Specification]. - -Example: - -```rust,ignore (not-all-targets-support-uefi) -#![feature(abi_efiapi)] - -extern "efiapi" { fn f1(); } - -extern "efiapi" fn f2() { todo!() } -``` - -[UEFI Specification]: https://uefi.org/specs/UEFI/2.10/ diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 5c63efef717..87de41fde63 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -676,7 +676,8 @@ impl Item { } let header = match *self.kind { ItemKind::ForeignFunctionItem(_) => { - let abi = tcx.fn_sig(self.item_id.as_def_id().unwrap()).abi(); + let def_id = self.item_id.as_def_id().unwrap(); + let abi = tcx.fn_sig(def_id).abi(); hir::FnHeader { unsafety: if abi == Abi::RustIntrinsic { intrinsic_operation_unsafety(tcx, self.item_id.as_def_id().unwrap()) @@ -684,7 +685,14 @@ impl Item { hir::Unsafety::Unsafe }, abi, - constness: hir::Constness::NotConst, + constness: if abi == Abi::RustIntrinsic + && tcx.is_const_fn(def_id) + && is_unstable_const_fn(tcx, def_id).is_none() + { + hir::Constness::Const + } else { + hir::Constness::NotConst + }, asyncness: hir::IsAsync::NotAsync, } } diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index 81d9c46447a..d1b6d470e86 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -115,9 +115,7 @@ pub(crate) fn run(options: RustdocOptions) -> Result<(), ErrorGuaranteed> { let (tests, unused_extern_reports, compiling_test_count) = interface::run_compiler(config, |compiler| { compiler.enter(|queries| { - let mut global_ctxt = queries.global_ctxt()?.take(); - - let collector = global_ctxt.enter(|tcx| { + let collector = queries.global_ctxt()?.enter(|tcx| { let crate_attrs = tcx.hir().attrs(CRATE_HIR_ID); let opts = scrape_test_config(crate_attrs); @@ -156,9 +154,7 @@ pub(crate) fn run(options: RustdocOptions) -> Result<(), ErrorGuaranteed> { let unused_extern_reports = collector.unused_extern_reports.clone(); let compiling_test_count = collector.compiling_test_count.load(Ordering::SeqCst); - let ret: Result<_, ErrorGuaranteed> = - Ok((collector.tests, unused_extern_reports, compiling_test_count)); - ret + Ok((collector.tests, unused_extern_reports, compiling_test_count)) }) })?; @@ -1225,7 +1221,7 @@ impl<'a, 'hir, 'tcx> HirCollector<'a, 'hir, 'tcx> { ) { let ast_attrs = self.tcx.hir().attrs(hir_id); if let Some(ref cfg) = ast_attrs.cfg(self.tcx, &FxHashSet::default()) { - if !cfg.matches(&self.sess.parse_sess, Some(self.sess.features_untracked())) { + if !cfg.matches(&self.sess.parse_sess, Some(self.tcx.features())) { return; } } diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 8bccf68029a..19f7b2270a7 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -513,7 +513,7 @@ fn document_full_inner( debug!("Doc block: =====\n{}\n=====", s); if is_collapsible { w.write_str( - "<details class=\"rustdoc-toggle top-doc\" open>\ + "<details class=\"toggle top-doc\" open>\ <summary class=\"hideme\">\ <span>Expand description</span>\ </summary>", @@ -1514,7 +1514,7 @@ fn render_impl( let toggled = !doc_buffer.is_empty(); if toggled { let method_toggle_class = if item_type.is_method() { " method-toggle" } else { "" }; - write!(w, "<details class=\"rustdoc-toggle{}\" open><summary>", method_toggle_class); + write!(w, "<details class=\"toggle{}\" open><summary>", method_toggle_class); } match &*item.kind { clean::MethodItem(..) | clean::TyMethodItem(_) => { @@ -1730,7 +1730,7 @@ fn render_impl( close_tags.insert_str(0, "</details>"); write!( w, - "<details class=\"rustdoc-toggle implementors-toggle\"{}>", + "<details class=\"toggle implementors-toggle\"{}>", if rendering_params.toggle_open_by_default { " open" } else { "" } ); write!(w, "<summary>") @@ -2999,7 +2999,7 @@ fn render_call_locations(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Ite if it.peek().is_some() { write!( w, - "<details class=\"rustdoc-toggle more-examples-toggle\">\ + "<details class=\"toggle more-examples-toggle\">\ <summary class=\"hideme\">\ <span>More examples</span>\ </summary>\ diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index c16d6477fc3..d6e57decdcf 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -204,7 +204,7 @@ fn should_hide_fields(n_fields: usize) -> bool { fn toggle_open(w: &mut Buffer, text: impl fmt::Display) { write!( w, - "<details class=\"rustdoc-toggle type-contents-toggle\">\ + "<details class=\"toggle type-contents-toggle\">\ <summary class=\"hideme\">\ <span>Show {}</span>\ </summary>", @@ -733,7 +733,7 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean: let toggled = !content.is_empty(); if toggled { let method_toggle_class = if item_type.is_method() { " method-toggle" } else { "" }; - write!(w, "<details class=\"rustdoc-toggle{method_toggle_class}\" open><summary>"); + write!(w, "<details class=\"toggle{method_toggle_class}\" open><summary>"); } write!(w, "<section id=\"{}\" class=\"method has-srclink\">", id); render_rightside(w, cx, m, t, RenderMode::Normal); @@ -1840,7 +1840,7 @@ fn document_non_exhaustive(w: &mut Buffer, item: &clean::Item) { if item.is_non_exhaustive() { write!( w, - "<details class=\"rustdoc-toggle non-exhaustive\">\ + "<details class=\"toggle non-exhaustive\">\ <summary class=\"hideme\"><span>{}</span></summary>\ <div class=\"docblock\">", { diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index b2fa6e82acc..8773bd2f114 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -317,7 +317,7 @@ main { margin-right: auto; } -details:not(.rustdoc-toggle) summary { +details:not(.toggle) summary { margin-bottom: .6em; } @@ -1401,7 +1401,7 @@ details.dir-entry a { Unfortunately we can't yet specify contain: content or contain: strict because the [-]/[+] toggles extend past the boundaries of the <details> https://developer.mozilla.org/en-US/docs/Web/CSS/contain */ -details.rustdoc-toggle { +details.toggle { contain: layout; position: relative; } @@ -1409,26 +1409,26 @@ details.rustdoc-toggle { /* The hideme class is used on summary tags that contain a span with placeholder text shown only when the toggle is closed. For instance, "Expand description" or "Show methods". */ -details.rustdoc-toggle > summary.hideme { +details.toggle > summary.hideme { cursor: pointer; font-size: 1rem; } -details.rustdoc-toggle > summary { +details.toggle > summary { list-style: none; /* focus outline is shown on `::before` instead of this */ outline: none; } -details.rustdoc-toggle > summary::-webkit-details-marker, -details.rustdoc-toggle > summary::marker { +details.toggle > summary::-webkit-details-marker, +details.toggle > summary::marker { display: none; } -details.rustdoc-toggle > summary.hideme > span { +details.toggle > summary.hideme > span { margin-left: 9px; } -details.rustdoc-toggle > summary::before { +details.toggle > summary::before { background: url("toggle-plus-1092eb4930d581b0.svg") no-repeat top left; content: ""; cursor: pointer; @@ -1440,14 +1440,14 @@ details.rustdoc-toggle > summary::before { filter: var(--toggle-filter); } -details.rustdoc-toggle > summary.hideme > span, +details.toggle > summary.hideme > span, .more-examples-toggle summary, .more-examples-toggle .hide-more { color: var(--toggles-color); } /* Screen readers see the text version at the end the line. Visual readers see the icon at the start of the line, but small and transparent. */ -details.rustdoc-toggle > summary::after { +details.toggle > summary::after { content: "Expand"; overflow: hidden; width: 0; @@ -1455,17 +1455,17 @@ details.rustdoc-toggle > summary::after { position: absolute; } -details.rustdoc-toggle > summary.hideme::after { +details.toggle > summary.hideme::after { /* "hideme" toggles already have a description when they're contracted */ content: ""; } -details.rustdoc-toggle > summary:focus::before, -details.rustdoc-toggle > summary:hover::before { +details.toggle > summary:focus::before, +details.toggle > summary:hover::before { opacity: 1; } -details.rustdoc-toggle > summary:focus-visible::before { +details.toggle > summary:focus-visible::before { /* The SVG is black, and gets turned white using a filter in the dark themes. Do the same with the outline. The dotted 1px style is copied from Firefox's focus ring style. @@ -1478,17 +1478,17 @@ details.non-exhaustive { margin-bottom: 8px; } -details.rustdoc-toggle > summary.hideme::before { +details.toggle > summary.hideme::before { position: relative; } -details.rustdoc-toggle > summary:not(.hideme)::before { +details.toggle > summary:not(.hideme)::before { position: absolute; left: -24px; top: 4px; } -.impl-items > details.rustdoc-toggle > summary:not(.hideme)::before { +.impl-items > details.toggle > summary:not(.hideme)::before { position: absolute; left: -24px; } @@ -1498,19 +1498,19 @@ details.rustdoc-toggle > summary:not(.hideme)::before { affect the layout of the items to its right. To do that, we use absolute positioning. Note that we also set position: relative on the parent <details> to make this work properly. */ -details.rustdoc-toggle[open] > summary.hideme { +details.toggle[open] > summary.hideme { position: absolute; } -details.rustdoc-toggle[open] > summary.hideme > span { +details.toggle[open] > summary.hideme > span { display: none; } -details.rustdoc-toggle[open] > summary::before { +details.toggle[open] > summary::before { background: url("toggle-minus-31bbd6e4c77f5c96.svg") no-repeat top left; } -details.rustdoc-toggle[open] > summary::after { +details.toggle[open] > summary::after { content: "Collapse"; } @@ -1660,8 +1660,8 @@ in storage.js display: block; } - #main-content > details.rustdoc-toggle > summary::before, - #main-content > div > details.rustdoc-toggle > summary::before { + #main-content > details.toggle > summary::before, + #main-content > div > details.toggle > summary::before { left: -11px; } @@ -1715,12 +1715,12 @@ in storage.js } /* Position of the "[-]" element. */ - details.rustdoc-toggle:not(.top-doc) > summary { + details.toggle:not(.top-doc) > summary { margin-left: 10px; } - .impl-items > details.rustdoc-toggle > summary:not(.hideme)::before, - #main-content > details.rustdoc-toggle:not(.top-doc) > summary::before, - #main-content > div > details.rustdoc-toggle > summary::before { + .impl-items > details.toggle > summary:not(.hideme)::before, + #main-content > details.toggle:not(.top-doc) > summary::before, + #main-content > div > details.toggle > summary::before { left: -11px; } @@ -1753,8 +1753,8 @@ in storage.js @media print { nav.sidebar, nav.sub, .out-of-band, a.srclink, #copy-path, - details.rustdoc-toggle[open] > summary::before, details.rustdoc-toggle > summary::before, - details.rustdoc-toggle.top-doc > summary { + details.toggle[open] > summary::before, details.toggle > summary::before, + details.toggle.top-doc > summary { display: none; } @@ -1796,24 +1796,24 @@ in storage.js .impl, #implementors-list > .docblock, .impl-items > section, -.impl-items > .rustdoc-toggle > summary, +.impl-items > .toggle > summary, .methods > section, -.methods > .rustdoc-toggle > summary +.methods > .toggle > summary { margin-bottom: 0.75em; } .variants > .docblock, .implementors-toggle > .docblock, -.impl-items > .rustdoc-toggle[open]:not(:last-child), -.methods > .rustdoc-toggle[open]:not(:last-child), +.impl-items > .toggle[open]:not(:last-child), +.methods > .toggle[open]:not(:last-child), .implementors-toggle[open]:not(:last-child) { margin-bottom: 2em; } -#trait-implementations-list .impl-items > .rustdoc-toggle:not(:last-child), -#synthetic-implementations-list .impl-items > .rustdoc-toggle:not(:last-child), -#blanket-implementations-list .impl-items > .rustdoc-toggle:not(:last-child) { +#trait-implementations-list .impl-items > .toggle:not(:last-child), +#synthetic-implementations-list .impl-items > .toggle:not(:last-child), +#blanket-implementations-list .impl-items > .toggle:not(:last-child) { margin-bottom: 1em; } diff --git a/src/librustdoc/html/static/css/settings.css b/src/librustdoc/html/static/css/settings.css index 875a260c811..91419093147 100644 --- a/src/librustdoc/html/static/css/settings.css +++ b/src/librustdoc/html/static/css/settings.css @@ -9,7 +9,7 @@ } .setting-line .radio-line input, -.setting-line .toggle input { +.setting-line .settings-toggle input { margin-right: 0.3em; height: 1.2rem; width: 1.2rem; @@ -22,14 +22,14 @@ .setting-line .radio-line input { border-radius: 50%; } -.setting-line .toggle input:checked { +.setting-line .settings-toggle input:checked { content: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40">\ <path d="M7,25L17,32L33,12" fill="none" stroke="black" stroke-width="5"/>\ <path d="M7,23L17,30L33,10" fill="none" stroke="white" stroke-width="5"/></svg>'); } .setting-line .radio-line input + span, -.setting-line .toggle span { +.setting-line .settings-toggle span { padding-bottom: 1px; } @@ -50,7 +50,7 @@ margin-left: 0.5em; } -.toggle { +.settings-toggle { position: relative; width: 100%; margin-right: 20px; @@ -67,11 +67,11 @@ box-shadow: inset 0 0 0 3px var(--main-background-color); background-color: var(--settings-input-color); } -.setting-line .toggle input:checked { +.setting-line .settings-toggle input:checked { background-color: var(--settings-input-color); } .setting-line .radio-line input:focus, -.setting-line .toggle input:focus { +.setting-line .settings-toggle input:focus { box-shadow: 0 0 1px 1px var(--settings-input-color); } /* In here we combine both `:focus` and `:checked` properties. */ @@ -80,6 +80,6 @@ 0 0 2px 2px var(--settings-input-color); } .setting-line .radio-line input:hover, -.setting-line .toggle input:hover { +.setting-line .settings-toggle input:hover { border-color: var(--settings-input-color) !important; } diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js index 51aee8e7c89..b05151f39b8 100644 --- a/src/librustdoc/html/static/js/main.js +++ b/src/librustdoc/html/static/js/main.js @@ -620,7 +620,7 @@ function loadCss(cssUrl) { function expandAllDocs() { const innerToggle = document.getElementById(toggleAllDocsId); removeClass(innerToggle, "will-expand"); - onEachLazy(document.getElementsByClassName("rustdoc-toggle"), e => { + onEachLazy(document.getElementsByClassName("toggle"), e => { if (!hasClass(e, "type-contents-toggle") && !hasClass(e, "more-examples-toggle")) { e.open = true; } @@ -632,7 +632,7 @@ function loadCss(cssUrl) { function collapseAllDocs() { const innerToggle = document.getElementById(toggleAllDocsId); addClass(innerToggle, "will-expand"); - onEachLazy(document.getElementsByClassName("rustdoc-toggle"), e => { + onEachLazy(document.getElementsByClassName("toggle"), e => { if (e.parentNode.id !== "implementations-list" || (!hasClass(e, "implementors-toggle") && !hasClass(e, "type-contents-toggle")) @@ -680,7 +680,7 @@ function loadCss(cssUrl) { setImplementorsTogglesOpen("blanket-implementations-list", false); } - onEachLazy(document.getElementsByClassName("rustdoc-toggle"), e => { + onEachLazy(document.getElementsByClassName("toggle"), e => { if (!hideLargeItemContents && hasClass(e, "type-contents-toggle")) { e.open = true; } @@ -823,7 +823,7 @@ function loadCss(cssUrl) { }); }); - onEachLazy(document.querySelectorAll(".rustdoc-toggle > summary:not(.hideme)"), el => { + onEachLazy(document.querySelectorAll(".toggle > summary:not(.hideme)"), el => { el.addEventListener("click", e => { if (e.target.tagName !== "SUMMARY" && e.target.tagName !== "A") { e.preventDefault(); diff --git a/src/librustdoc/html/static/js/settings.js b/src/librustdoc/html/static/js/settings.js index 589bfc79360..9ed8f63610f 100644 --- a/src/librustdoc/html/static/js/settings.js +++ b/src/librustdoc/html/static/js/settings.js @@ -150,10 +150,10 @@ }); output += "</div></div>"; } else { - // This is a toggle. + // This is a checkbox toggle. const checked = setting["default"] === true ? " checked" : ""; output += `\ -<label class="toggle">\ +<label class="settings-toggle">\ <input type="checkbox" id="${js_data_name}"${checked}>\ <span class="label">${setting_name}</span>\ </label>`; diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index ef1d7da5a34..86454e1f2eb 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -772,7 +772,6 @@ fn main_args(at_args: &[String]) -> MainResult { let crate_version = options.crate_version.clone(); let output_format = options.output_format; - let externs = options.externs.clone(); let scrape_examples_options = options.scrape_examples_options.clone(); let bin_crate = options.bin_crate; @@ -800,13 +799,12 @@ fn main_args(at_args: &[String]) -> MainResult { // FIXME(#83761): Resolver cloning can lead to inconsistencies between data in the // two copies because one of the copies can be modified after `TyCtxt` construction. let (resolver, resolver_caches) = { - let (krate, resolver, _) = &*abort_on_err(queries.expansion(), sess).peek(); + let expansion = abort_on_err(queries.expansion(), sess); + let (krate, resolver, _) = &*expansion.borrow(); let resolver_caches = resolver.borrow_mut().access(|resolver| { collect_intra_doc_links::early_resolve_intra_doc_links( resolver, - sess, krate, - externs, render_options.document_private, ) }); @@ -817,7 +815,7 @@ fn main_args(at_args: &[String]) -> MainResult { sess.fatal("Compilation failed, aborting rustdoc"); } - let mut global_ctxt = abort_on_err(queries.global_ctxt(), sess).peek_mut(); + let global_ctxt = abort_on_err(queries.global_ctxt(), sess); global_ctxt.enter(|tcx| { let (krate, render_opts, mut cache) = sess.time("run_global_ctxt", || { diff --git a/src/librustdoc/passes/collect_intra_doc_links/early.rs b/src/librustdoc/passes/collect_intra_doc_links/early.rs index 1b373cfe5bb..42677bd8497 100644 --- a/src/librustdoc/passes/collect_intra_doc_links/early.rs +++ b/src/librustdoc/passes/collect_intra_doc_links/early.rs @@ -12,8 +12,6 @@ use rustc_hir::def_id::{DefId, DefIdMap, DefIdSet, CRATE_DEF_ID}; use rustc_hir::TraitCandidate; use rustc_middle::ty::{DefIdTree, Visibility}; use rustc_resolve::{ParentScope, Resolver}; -use rustc_session::config::Externs; -use rustc_session::Session; use rustc_span::symbol::sym; use rustc_span::{Symbol, SyntaxContext}; @@ -22,16 +20,13 @@ use std::mem; pub(crate) fn early_resolve_intra_doc_links( resolver: &mut Resolver<'_>, - sess: &Session, krate: &ast::Crate, - externs: Externs, document_private_items: bool, ) -> ResolverCaches { let parent_scope = ParentScope::module(resolver.expect_module(CRATE_DEF_ID.to_def_id()), resolver); let mut link_resolver = EarlyDocLinkResolver { resolver, - sess, parent_scope, visited_mods: Default::default(), markdown_links: Default::default(), @@ -52,7 +47,9 @@ pub(crate) fn early_resolve_intra_doc_links( // the known necessary crates. Load them all unconditionally until we find a way to fix this. // DO NOT REMOVE THIS without first testing on the reproducer in // https://github.com/jyn514/objr/commit/edcee7b8124abf0e4c63873e8422ff81beb11ebb - for (extern_name, _) in externs.iter().filter(|(_, entry)| entry.add_prelude) { + for (extern_name, _) in + link_resolver.resolver.sess().opts.externs.iter().filter(|(_, entry)| entry.add_prelude) + { link_resolver.resolver.resolve_rustdoc_path(extern_name, TypeNS, parent_scope); } @@ -73,7 +70,6 @@ fn doc_attrs<'a>(attrs: impl Iterator<Item = &'a ast::Attribute>) -> Attributes struct EarlyDocLinkResolver<'r, 'ra> { resolver: &'r mut Resolver<'ra>, - sess: &'r Session, parent_scope: ParentScope<'ra>, visited_mods: DefIdSet, markdown_links: FxHashMap<String, Vec<PreprocessedMarkdownLink>>, @@ -166,7 +162,7 @@ impl<'ra> EarlyDocLinkResolver<'_, 'ra> { fn resolve_doc_links_extern_impl(&mut self, def_id: DefId, is_inherent: bool) { self.resolve_doc_links_extern_outer_fixme(def_id, def_id); let assoc_item_def_ids = Vec::from_iter( - self.resolver.cstore().associated_item_def_ids_untracked(def_id, self.sess), + self.resolver.cstore().associated_item_def_ids_untracked(def_id, self.resolver.sess()), ); for assoc_def_id in assoc_item_def_ids { if !is_inherent || self.resolver.cstore().visibility_untracked(assoc_def_id).is_public() @@ -191,7 +187,9 @@ impl<'ra> EarlyDocLinkResolver<'_, 'ra> { if !self.resolver.cstore().may_have_doc_links_untracked(def_id) { return; } - let attrs = Vec::from_iter(self.resolver.cstore().item_attrs_untracked(def_id, self.sess)); + let attrs = Vec::from_iter( + self.resolver.cstore().item_attrs_untracked(def_id, self.resolver.sess()), + ); let parent_scope = ParentScope::module( self.resolver.get_nearest_non_block_module( self.resolver.opt_parent(scope_id).unwrap_or(scope_id), @@ -205,7 +203,9 @@ impl<'ra> EarlyDocLinkResolver<'_, 'ra> { if !self.resolver.cstore().may_have_doc_links_untracked(def_id) { return; } - let attrs = Vec::from_iter(self.resolver.cstore().item_attrs_untracked(def_id, self.sess)); + let attrs = Vec::from_iter( + self.resolver.cstore().item_attrs_untracked(def_id, self.resolver.sess()), + ); let parent_scope = ParentScope::module(self.resolver.expect_module(def_id), self.resolver); self.resolve_doc_links(doc_attrs(attrs.iter()), parent_scope); } @@ -321,7 +321,7 @@ impl<'ra> EarlyDocLinkResolver<'_, 'ra> { let field_def_ids = Vec::from_iter( self.resolver .cstore() - .associated_item_def_ids_untracked(def_id, self.sess), + .associated_item_def_ids_untracked(def_id, self.resolver.sess()), ); for field_def_id in field_def_ids { self.resolve_doc_links_extern_outer(field_def_id, scope_id); diff --git a/src/librustdoc/passes/strip_priv_imports.rs b/src/librustdoc/passes/strip_priv_imports.rs index 3bac5a8e5d7..4c992e94833 100644 --- a/src/librustdoc/passes/strip_priv_imports.rs +++ b/src/librustdoc/passes/strip_priv_imports.rs @@ -12,5 +12,6 @@ pub(crate) const STRIP_PRIV_IMPORTS: Pass = Pass { }; pub(crate) fn strip_priv_imports(krate: clean::Crate, cx: &mut DocContext<'_>) -> clean::Crate { - ImportStripper { tcx: cx.tcx }.fold_crate(krate) + let is_json_output = cx.output_format.is_json() && !cx.show_coverage; + ImportStripper { tcx: cx.tcx, is_json_output }.fold_crate(krate) } diff --git a/src/librustdoc/passes/strip_private.rs b/src/librustdoc/passes/strip_private.rs index 8fc42462de9..bb6dccb7c94 100644 --- a/src/librustdoc/passes/strip_private.rs +++ b/src/librustdoc/passes/strip_private.rs @@ -28,7 +28,8 @@ pub(crate) fn strip_private(mut krate: clean::Crate, cx: &mut DocContext<'_>) -> is_json_output, tcx: cx.tcx, }; - krate = ImportStripper { tcx: cx.tcx }.fold_crate(stripper.fold_crate(krate)); + krate = + ImportStripper { tcx: cx.tcx, is_json_output }.fold_crate(stripper.fold_crate(krate)); } // strip all impls referencing private items diff --git a/src/librustdoc/passes/stripper.rs b/src/librustdoc/passes/stripper.rs index f8a0d77538d..048ed264623 100644 --- a/src/librustdoc/passes/stripper.rs +++ b/src/librustdoc/passes/stripper.rs @@ -97,17 +97,7 @@ impl<'a, 'tcx> DocFolder for Stripper<'a, 'tcx> { } // handled in the `strip-priv-imports` pass - clean::ExternCrateItem { .. } => {} - clean::ImportItem(ref imp) => { - // Because json doesn't inline imports from private modules, we need to mark - // the imported item as retained so it's impls won't be stripped. - // - // FIXME: Is it necessary to check for json output here: See - // https://github.com/rust-lang/rust/pull/100325#discussion_r941495215 - if let Some(did) = imp.source.did && self.is_json_output { - self.retained.insert(did.into()); - } - } + clean::ExternCrateItem { .. } | clean::ImportItem(_) => {} clean::ImplItem(..) => {} @@ -243,12 +233,25 @@ impl<'a> DocFolder for ImplStripper<'a, '_> { /// This stripper discards all private import statements (`use`, `extern crate`) pub(crate) struct ImportStripper<'tcx> { pub(crate) tcx: TyCtxt<'tcx>, + pub(crate) is_json_output: bool, +} + +impl<'tcx> ImportStripper<'tcx> { + fn import_should_be_hidden(&self, i: &Item, imp: &clean::Import) -> bool { + if self.is_json_output { + // FIXME: This should be handled the same way as for HTML output. + imp.imported_item_is_doc_hidden(self.tcx) + } else { + i.attrs.lists(sym::doc).has_word(sym::hidden) + } + } } impl<'tcx> DocFolder for ImportStripper<'tcx> { fn fold_item(&mut self, i: Item) -> Option<Item> { match *i.kind { - clean::ImportItem(imp) if imp.imported_item_is_doc_hidden(self.tcx) => None, + clean::ImportItem(imp) if self.import_should_be_hidden(&i, &imp) => None, + clean::ImportItem(_) if i.attrs.lists(sym::doc).has_word(sym::hidden) => None, clean::ExternCrateItem { .. } | clean::ImportItem(..) if i.visibility(self.tcx) != Some(Visibility::Public) => { diff --git a/src/tools/clippy/.github/driver.sh b/src/tools/clippy/.github/driver.sh index 6ff189fc859..798782340ee 100644 --- a/src/tools/clippy/.github/driver.sh +++ b/src/tools/clippy/.github/driver.sh @@ -17,6 +17,13 @@ test "$sysroot" = $desired_sysroot sysroot=$(SYSROOT=$desired_sysroot ./target/debug/clippy-driver --print sysroot) test "$sysroot" = $desired_sysroot +# Check that the --sysroot argument is only passed once (SYSROOT is ignored) +( + cd rustc_tools_util + touch src/lib.rs + SYSROOT=/tmp RUSTFLAGS="--sysroot=$(rustc --print sysroot)" ../target/debug/cargo-clippy clippy --verbose +) + # Make sure this isn't set - clippy-driver should cope without it unset CARGO_MANIFEST_DIR diff --git a/src/tools/clippy/CHANGELOG.md b/src/tools/clippy/CHANGELOG.md index 02f3188f8be..8e31e8f0d98 100644 --- a/src/tools/clippy/CHANGELOG.md +++ b/src/tools/clippy/CHANGELOG.md @@ -4137,6 +4137,7 @@ Released 2018-09-13 [`derive_hash_xor_eq`]: https://rust-lang.github.io/rust-clippy/master/index.html#derive_hash_xor_eq [`derive_ord_xor_partial_ord`]: https://rust-lang.github.io/rust-clippy/master/index.html#derive_ord_xor_partial_ord [`derive_partial_eq_without_eq`]: https://rust-lang.github.io/rust-clippy/master/index.html#derive_partial_eq_without_eq +[`derived_hash_with_manual_eq`]: https://rust-lang.github.io/rust-clippy/master/index.html#derived_hash_with_manual_eq [`disallowed_macros`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_macros [`disallowed_method`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_method [`disallowed_methods`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_methods diff --git a/src/tools/clippy/book/src/installation.md b/src/tools/clippy/book/src/installation.md index b2a28d0be62..cce888b17d4 100644 --- a/src/tools/clippy/book/src/installation.md +++ b/src/tools/clippy/book/src/installation.md @@ -1,6 +1,6 @@ # Installation -If you're using `rustup` to install and manage you're Rust toolchains, Clippy is +If you're using `rustup` to install and manage your Rust toolchains, Clippy is usually **already installed**. In that case you can skip this chapter and go to the [Usage] chapter. diff --git a/src/tools/clippy/clippy_dev/src/lib.rs b/src/tools/clippy/clippy_dev/src/lib.rs index 80bb83af43b..e70488165b9 100644 --- a/src/tools/clippy/clippy_dev/src/lib.rs +++ b/src/tools/clippy/clippy_dev/src/lib.rs @@ -5,6 +5,9 @@ // warn on lints, that are included in `rust-lang/rust`s bootstrap #![warn(rust_2018_idioms, unused_lifetimes)] +// The `rustc_driver` crate seems to be required in order to use the `rust_lexer` crate. +#[allow(unused_extern_crates)] +extern crate rustc_driver; extern crate rustc_lexer; use std::path::PathBuf; diff --git a/src/tools/clippy/clippy_lints/src/attrs.rs b/src/tools/clippy/clippy_lints/src/attrs.rs index 0710ac0bb0a..751c262673b 100644 --- a/src/tools/clippy/clippy_lints/src/attrs.rs +++ b/src/tools/clippy/clippy_lints/src/attrs.rs @@ -472,7 +472,7 @@ fn check_clippy_lint_names(cx: &LateContext<'_>, name: Symbol, items: &[NestedMe fn check_lint_reason(cx: &LateContext<'_>, name: Symbol, items: &[NestedMetaItem], attr: &'_ Attribute) { // Check for the feature - if !cx.tcx.sess.features_untracked().lint_reasons { + if !cx.tcx.features().lint_reasons { return; } diff --git a/src/tools/clippy/clippy_lints/src/box_default.rs b/src/tools/clippy/clippy_lints/src/box_default.rs index 91900542af8..9d98a6bab71 100644 --- a/src/tools/clippy/clippy_lints/src/box_default.rs +++ b/src/tools/clippy/clippy_lints/src/box_default.rs @@ -8,7 +8,7 @@ use rustc_hir::{ Block, Expr, ExprKind, Local, Node, QPath, TyKind, }; use rustc_lint::{LateContext, LateLintPass, LintContext}; -use rustc_middle::lint::in_external_macro; +use rustc_middle::{lint::in_external_macro, ty::print::with_forced_trimmed_paths}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::sym; @@ -59,7 +59,7 @@ impl LateLintPass<'_> for BoxDefault { if is_plain_default(arg_path) || given_type(cx, expr) { "Box::default()".into() } else { - format!("Box::<{arg_ty}>::default()") + with_forced_trimmed_paths!(format!("Box::<{arg_ty}>::default()")) }, Applicability::MachineApplicable ); diff --git a/src/tools/clippy/clippy_lints/src/copies.rs b/src/tools/clippy/clippy_lints/src/copies.rs index 0e3d9317590..f10c35cde52 100644 --- a/src/tools/clippy/clippy_lints/src/copies.rs +++ b/src/tools/clippy/clippy_lints/src/copies.rs @@ -525,7 +525,11 @@ fn check_for_warn_of_moved_symbol(cx: &LateContext<'_>, symbols: &[(HirId, Symbo .iter() .filter(|&&(_, name)| !name.as_str().starts_with('_')) .any(|&(_, name)| { - let mut walker = ContainsName { name, result: false }; + let mut walker = ContainsName { + name, + result: false, + cx, + }; // Scan block block diff --git a/src/tools/clippy/clippy_lints/src/dbg_macro.rs b/src/tools/clippy/clippy_lints/src/dbg_macro.rs index fe9f4f9ae3c..799e71e847a 100644 --- a/src/tools/clippy/clippy_lints/src/dbg_macro.rs +++ b/src/tools/clippy/clippy_lints/src/dbg_macro.rs @@ -10,11 +10,11 @@ use rustc_span::sym; declare_clippy_lint! { /// ### What it does - /// Checks for usage of dbg!() macro. + /// Checks for usage of the [`dbg!`](https://doc.rust-lang.org/std/macro.dbg.html) macro. /// /// ### Why is this bad? - /// `dbg!` macro is intended as a debugging tool. It - /// should not be in version control. + /// The `dbg!` macro is intended as a debugging tool. It should not be present in released + /// software or committed to a version control system. /// /// ### Example /// ```rust,ignore @@ -91,8 +91,8 @@ impl LateLintPass<'_> for DbgMacro { cx, DBG_MACRO, macro_call.span, - "`dbg!` macro is intended as a debugging tool", - "ensure to avoid having uses of it in version control", + "the `dbg!` macro is intended as a debugging tool", + "remove the invocation before committing it to a version control system", suggestion, applicability, ); diff --git a/src/tools/clippy/clippy_lints/src/declared_lints.rs b/src/tools/clippy/clippy_lints/src/declared_lints.rs index 2982460c9cf..91ca73633f0 100644 --- a/src/tools/clippy/clippy_lints/src/declared_lints.rs +++ b/src/tools/clippy/clippy_lints/src/declared_lints.rs @@ -111,7 +111,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::dereference::NEEDLESS_BORROW_INFO, crate::dereference::REF_BINDING_TO_REFERENCE_INFO, crate::derivable_impls::DERIVABLE_IMPLS_INFO, - crate::derive::DERIVE_HASH_XOR_EQ_INFO, + crate::derive::DERIVED_HASH_WITH_MANUAL_EQ_INFO, crate::derive::DERIVE_ORD_XOR_PARTIAL_ORD_INFO, crate::derive::DERIVE_PARTIAL_EQ_WITHOUT_EQ_INFO, crate::derive::EXPL_IMPL_CLONE_ON_COPY_INFO, diff --git a/src/tools/clippy/clippy_lints/src/default.rs b/src/tools/clippy/clippy_lints/src/default.rs index 7f937de1dd3..a04693f4637 100644 --- a/src/tools/clippy/clippy_lints/src/default.rs +++ b/src/tools/clippy/clippy_lints/src/default.rs @@ -11,6 +11,7 @@ use rustc_hir::def::Res; use rustc_hir::{Block, Expr, ExprKind, PatKind, QPath, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; +use rustc_middle::ty::print::with_forced_trimmed_paths; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::symbol::{Ident, Symbol}; use rustc_span::Span; @@ -98,9 +99,7 @@ impl<'tcx> LateLintPass<'tcx> for Default { if let ty::Adt(def, ..) = expr_ty.kind(); if !is_from_proc_macro(cx, expr); then { - // TODO: Work out a way to put "whatever the imported way of referencing - // this type in this file" rather than a fully-qualified type. - let replacement = format!("{}::default()", cx.tcx.def_path_str(def.did())); + let replacement = with_forced_trimmed_paths!(format!("{}::default()", cx.tcx.def_path_str(def.did()))); span_lint_and_sugg( cx, DEFAULT_TRAIT_ACCESS, @@ -170,7 +169,7 @@ impl<'tcx> LateLintPass<'tcx> for Default { // find out if and which field was set by this `consecutive_statement` if let Some((field_ident, assign_rhs)) = field_reassigned_by_stmt(consecutive_statement, binding_name) { // interrupt and cancel lint if assign_rhs references the original binding - if contains_name(binding_name, assign_rhs) { + if contains_name(binding_name, assign_rhs, cx) { cancel_lint = true; break; } diff --git a/src/tools/clippy/clippy_lints/src/dereference.rs b/src/tools/clippy/clippy_lints/src/dereference.rs index f327c9a71b3..05f2b92c037 100644 --- a/src/tools/clippy/clippy_lints/src/dereference.rs +++ b/src/tools/clippy/clippy_lints/src/dereference.rs @@ -1282,10 +1282,10 @@ fn referent_used_exactly_once<'tcx>( possible_borrowers.push((body_owner_local_def_id, PossibleBorrowerMap::new(cx, mir))); } let possible_borrower = &mut possible_borrowers.last_mut().unwrap().1; - // If `place.local` were not included here, the `copyable_iterator::warn` test would fail. The - // reason is that `PossibleBorrowerVisitor::visit_terminator` considers `place.local` a possible - // borrower of itself. See the comment in that method for an explanation as to why. - possible_borrower.at_most_borrowers(cx, &[local, place.local], place.local, location) + // If `only_borrowers` were used here, the `copyable_iterator::warn` test would fail. The reason is + // that `PossibleBorrowerVisitor::visit_terminator` considers `place.local` a possible borrower of + // itself. See the comment in that method for an explanation as to why. + possible_borrower.bounded_borrowers(&[local], &[local, place.local], place.local, location) && used_exactly_once(mir, place.local).unwrap_or(false) } else { false diff --git a/src/tools/clippy/clippy_lints/src/derivable_impls.rs b/src/tools/clippy/clippy_lints/src/derivable_impls.rs index ae8f6b79449..bc18e2e5ed5 100644 --- a/src/tools/clippy/clippy_lints/src/derivable_impls.rs +++ b/src/tools/clippy/clippy_lints/src/derivable_impls.rs @@ -1,12 +1,15 @@ use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::msrvs::{self, Msrv}; +use clippy_utils::source::indent_of; use clippy_utils::{is_default_equivalent, peel_blocks}; use rustc_errors::Applicability; use rustc_hir::{ - def::{DefKind, Res}, - Body, Expr, ExprKind, GenericArg, Impl, ImplItemKind, Item, ItemKind, Node, PathSegment, QPath, TyKind, + def::{CtorKind, CtorOf, DefKind, Res}, + Body, Expr, ExprKind, GenericArg, Impl, ImplItemKind, Item, ItemKind, Node, PathSegment, QPath, Ty, TyKind, }; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_middle::ty::{AdtDef, DefIdTree}; +use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::sym; declare_clippy_lint! { @@ -51,7 +54,18 @@ declare_clippy_lint! { "manual implementation of the `Default` trait which is equal to a derive" } -declare_lint_pass!(DerivableImpls => [DERIVABLE_IMPLS]); +pub struct DerivableImpls { + msrv: Msrv, +} + +impl DerivableImpls { + #[must_use] + pub fn new(msrv: Msrv) -> Self { + DerivableImpls { msrv } + } +} + +impl_lint_pass!(DerivableImpls => [DERIVABLE_IMPLS]); fn is_path_self(e: &Expr<'_>) -> bool { if let ExprKind::Path(QPath::Resolved(_, p)) = e.kind { @@ -61,6 +75,98 @@ fn is_path_self(e: &Expr<'_>) -> bool { } } +fn check_struct<'tcx>( + cx: &LateContext<'tcx>, + item: &'tcx Item<'_>, + self_ty: &Ty<'_>, + func_expr: &Expr<'_>, + adt_def: AdtDef<'_>, +) { + if let TyKind::Path(QPath::Resolved(_, p)) = self_ty.kind { + if let Some(PathSegment { args: Some(a), .. }) = p.segments.last() { + for arg in a.args { + if !matches!(arg, GenericArg::Lifetime(_)) { + return; + } + } + } + } + let should_emit = match peel_blocks(func_expr).kind { + ExprKind::Tup(fields) => fields.iter().all(|e| is_default_equivalent(cx, e)), + ExprKind::Call(callee, args) if is_path_self(callee) => args.iter().all(|e| is_default_equivalent(cx, e)), + ExprKind::Struct(_, fields, _) => fields.iter().all(|ef| is_default_equivalent(cx, ef.expr)), + _ => false, + }; + + if should_emit { + let struct_span = cx.tcx.def_span(adt_def.did()); + span_lint_and_then(cx, DERIVABLE_IMPLS, item.span, "this `impl` can be derived", |diag| { + diag.span_suggestion_hidden( + item.span, + "remove the manual implementation...", + String::new(), + Applicability::MachineApplicable, + ); + diag.span_suggestion( + struct_span.shrink_to_lo(), + "...and instead derive it", + "#[derive(Default)]\n".to_string(), + Applicability::MachineApplicable, + ); + }); + } +} + +fn check_enum<'tcx>(cx: &LateContext<'tcx>, item: &'tcx Item<'_>, func_expr: &Expr<'_>, adt_def: AdtDef<'_>) { + if_chain! { + if let ExprKind::Path(QPath::Resolved(None, p)) = &peel_blocks(func_expr).kind; + if let Res::Def(DefKind::Ctor(CtorOf::Variant, CtorKind::Const), id) = p.res; + if let variant_id = cx.tcx.parent(id); + if let Some(variant_def) = adt_def.variants().iter().find(|v| v.def_id == variant_id); + if variant_def.fields.is_empty(); + if !variant_def.is_field_list_non_exhaustive(); + + then { + let enum_span = cx.tcx.def_span(adt_def.did()); + let indent_enum = indent_of(cx, enum_span).unwrap_or(0); + let variant_span = cx.tcx.def_span(variant_def.def_id); + let indent_variant = indent_of(cx, variant_span).unwrap_or(0); + span_lint_and_then( + cx, + DERIVABLE_IMPLS, + item.span, + "this `impl` can be derived", + |diag| { + diag.span_suggestion_hidden( + item.span, + "remove the manual implementation...", + String::new(), + Applicability::MachineApplicable + ); + diag.span_suggestion( + enum_span.shrink_to_lo(), + "...and instead derive it...", + format!( + "#[derive(Default)]\n{indent}", + indent = " ".repeat(indent_enum), + ), + Applicability::MachineApplicable + ); + diag.span_suggestion( + variant_span.shrink_to_lo(), + "...and mark the default variant", + format!( + "#[default]\n{indent}", + indent = " ".repeat(indent_variant), + ), + Applicability::MachineApplicable + ); + } + ); + } + } +} + impl<'tcx> LateLintPass<'tcx> for DerivableImpls { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) { if_chain! { @@ -83,49 +189,16 @@ impl<'tcx> LateLintPass<'tcx> for DerivableImpls { if !attrs.iter().any(|attr| attr.doc_str().is_some()); if let child_attrs = cx.tcx.hir().attrs(impl_item_hir); if !child_attrs.iter().any(|attr| attr.doc_str().is_some()); - if adt_def.is_struct(); - then { - if let TyKind::Path(QPath::Resolved(_, p)) = self_ty.kind { - if let Some(PathSegment { args: Some(a), .. }) = p.segments.last() { - for arg in a.args { - if !matches!(arg, GenericArg::Lifetime(_)) { - return; - } - } - } - } - let should_emit = match peel_blocks(func_expr).kind { - ExprKind::Tup(fields) => fields.iter().all(|e| is_default_equivalent(cx, e)), - ExprKind::Call(callee, args) - if is_path_self(callee) => args.iter().all(|e| is_default_equivalent(cx, e)), - ExprKind::Struct(_, fields, _) => fields.iter().all(|ef| is_default_equivalent(cx, ef.expr)), - _ => false, - }; - if should_emit { - let struct_span = cx.tcx.def_span(adt_def.did()); - span_lint_and_then( - cx, - DERIVABLE_IMPLS, - item.span, - "this `impl` can be derived", - |diag| { - diag.span_suggestion_hidden( - item.span, - "remove the manual implementation...", - String::new(), - Applicability::MachineApplicable - ); - diag.span_suggestion( - struct_span.shrink_to_lo(), - "...and instead derive it", - "#[derive(Default)]\n".to_string(), - Applicability::MachineApplicable - ); - } - ); + then { + if adt_def.is_struct() { + check_struct(cx, item, self_ty, func_expr, adt_def); + } else if adt_def.is_enum() && self.msrv.meets(msrvs::DEFAULT_ENUM_ATTRIBUTE) { + check_enum(cx, item, func_expr, adt_def); } } } } + + extract_msrv_attr!(LateContext); } diff --git a/src/tools/clippy/clippy_lints/src/derive.rs b/src/tools/clippy/clippy_lints/src/derive.rs index cf3483d4c00..f4b15e0916d 100644 --- a/src/tools/clippy/clippy_lints/src/derive.rs +++ b/src/tools/clippy/clippy_lints/src/derive.rs @@ -14,8 +14,8 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::nested_filter; use rustc_middle::traits::Reveal; use rustc_middle::ty::{ - self, Binder, BoundConstness, Clause, GenericParamDefKind, ImplPolarity, ParamEnv, PredicateKind, TraitPredicate, - Ty, TyCtxt, + self, Binder, BoundConstness, Clause, GenericArgKind, GenericParamDefKind, ImplPolarity, ParamEnv, PredicateKind, + TraitPredicate, Ty, TyCtxt, }; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; @@ -46,7 +46,7 @@ declare_clippy_lint! { /// } /// ``` #[clippy::version = "pre 1.29.0"] - pub DERIVE_HASH_XOR_EQ, + pub DERIVED_HASH_WITH_MANUAL_EQ, correctness, "deriving `Hash` but implementing `PartialEq` explicitly" } @@ -197,7 +197,7 @@ declare_clippy_lint! { declare_lint_pass!(Derive => [ EXPL_IMPL_CLONE_ON_COPY, - DERIVE_HASH_XOR_EQ, + DERIVED_HASH_WITH_MANUAL_EQ, DERIVE_ORD_XOR_PARTIAL_ORD, UNSAFE_DERIVE_DESERIALIZE, DERIVE_PARTIAL_EQ_WITHOUT_EQ @@ -226,7 +226,7 @@ impl<'tcx> LateLintPass<'tcx> for Derive { } } -/// Implementation of the `DERIVE_HASH_XOR_EQ` lint. +/// Implementation of the `DERIVED_HASH_WITH_MANUAL_EQ` lint. fn check_hash_peq<'tcx>( cx: &LateContext<'tcx>, span: Span, @@ -243,7 +243,7 @@ fn check_hash_peq<'tcx>( cx.tcx.for_each_relevant_impl(peq_trait_def_id, ty, |impl_id| { let peq_is_automatically_derived = cx.tcx.has_attr(impl_id, sym::automatically_derived); - if peq_is_automatically_derived == hash_is_automatically_derived { + if !hash_is_automatically_derived || peq_is_automatically_derived { return; } @@ -252,17 +252,11 @@ fn check_hash_peq<'tcx>( // Only care about `impl PartialEq<Foo> for Foo` // For `impl PartialEq<B> for A, input_types is [A, B] if trait_ref.substs.type_at(1) == ty { - let mess = if peq_is_automatically_derived { - "you are implementing `Hash` explicitly but have derived `PartialEq`" - } else { - "you are deriving `Hash` but have implemented `PartialEq` explicitly" - }; - span_lint_and_then( cx, - DERIVE_HASH_XOR_EQ, + DERIVED_HASH_WITH_MANUAL_EQ, span, - mess, + "you are deriving `Hash` but have implemented `PartialEq` explicitly", |diag| { if let Some(local_def_id) = impl_id.as_local() { let hir_id = cx.tcx.hir().local_def_id_to_hir_id(local_def_id); @@ -366,6 +360,15 @@ fn check_copy_clone<'tcx>(cx: &LateContext<'tcx>, item: &Item<'_>, trait_ref: &h if ty_subs.types().any(|ty| !implements_trait(cx, ty, clone_id, &[])) { return; } + // `#[repr(packed)]` structs with type/const parameters can't derive `Clone`. + // https://github.com/rust-lang/rust-clippy/issues/10188 + if ty_adt.repr().packed() + && ty_subs + .iter() + .any(|arg| matches!(arg.unpack(), GenericArgKind::Type(_) | GenericArgKind::Const(_))) + { + return; + } span_lint_and_note( cx, diff --git a/src/tools/clippy/clippy_lints/src/drop_forget_ref.rs b/src/tools/clippy/clippy_lints/src/drop_forget_ref.rs index 4721a7b3705..11e1bcdf12d 100644 --- a/src/tools/clippy/clippy_lints/src/drop_forget_ref.rs +++ b/src/tools/clippy/clippy_lints/src/drop_forget_ref.rs @@ -206,7 +206,7 @@ impl<'tcx> LateLintPass<'tcx> for DropForgetRef { let is_copy = is_copy(cx, arg_ty); let drop_is_single_call_in_arm = is_single_call_in_arm(cx, arg, expr); let (lint, msg) = match fn_name { - sym::mem_drop if arg_ty.is_ref() => (DROP_REF, DROP_REF_SUMMARY), + sym::mem_drop if arg_ty.is_ref() && !drop_is_single_call_in_arm => (DROP_REF, DROP_REF_SUMMARY), sym::mem_forget if arg_ty.is_ref() => (FORGET_REF, FORGET_REF_SUMMARY), sym::mem_drop if is_copy && !drop_is_single_call_in_arm => (DROP_COPY, DROP_COPY_SUMMARY), sym::mem_forget if is_copy => (FORGET_COPY, FORGET_COPY_SUMMARY), diff --git a/src/tools/clippy/clippy_lints/src/empty_structs_with_brackets.rs b/src/tools/clippy/clippy_lints/src/empty_structs_with_brackets.rs index 08bf80a4229..c3a020433de 100644 --- a/src/tools/clippy/clippy_lints/src/empty_structs_with_brackets.rs +++ b/src/tools/clippy/clippy_lints/src/empty_structs_with_brackets.rs @@ -45,7 +45,7 @@ impl EarlyLintPass for EmptyStructsWithBrackets { span_after_ident, "remove the brackets", ";", - Applicability::MachineApplicable); + Applicability::Unspecified); }, ); } diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs index dcd8ca81ae8..d8e2ae02c5a 100644 --- a/src/tools/clippy/clippy_lints/src/lib.rs +++ b/src/tools/clippy/clippy_lints/src/lib.rs @@ -639,7 +639,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|_| Box::new(panic_unimplemented::PanicUnimplemented)); store.register_late_pass(|_| Box::new(strings::StringLitAsBytes)); store.register_late_pass(|_| Box::new(derive::Derive)); - store.register_late_pass(|_| Box::new(derivable_impls::DerivableImpls)); + store.register_late_pass(move |_| Box::new(derivable_impls::DerivableImpls::new(msrv()))); store.register_late_pass(|_| Box::new(drop_forget_ref::DropForgetRef)); store.register_late_pass(|_| Box::new(empty_enum::EmptyEnum)); store.register_late_pass(|_| Box::new(invalid_upcast_comparisons::InvalidUpcastComparisons)); diff --git a/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs b/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs index 27ba27202bf..3bca93d80aa 100644 --- a/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs +++ b/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs @@ -81,7 +81,7 @@ pub(super) fn check<'tcx>( let skip = if starts_at_zero { String::new() - } else if visitor.indexed_mut.contains(&indexed) && contains_name(indexed, start) { + } else if visitor.indexed_mut.contains(&indexed) && contains_name(indexed, start, cx) { return; } else { format!(".skip({})", snippet(cx, start.span, "..")) @@ -109,7 +109,7 @@ pub(super) fn check<'tcx>( if is_len_call(end, indexed) || is_end_eq_array_len(cx, end, limits, indexed_ty) { String::new() - } else if visitor.indexed_mut.contains(&indexed) && contains_name(indexed, take_expr) { + } else if visitor.indexed_mut.contains(&indexed) && contains_name(indexed, take_expr, cx) { return; } else { match limits { diff --git a/src/tools/clippy/clippy_lints/src/loops/single_element_loop.rs b/src/tools/clippy/clippy_lints/src/loops/single_element_loop.rs index f4b47808dfa..744fd61bd13 100644 --- a/src/tools/clippy/clippy_lints/src/loops/single_element_loop.rs +++ b/src/tools/clippy/clippy_lints/src/loops/single_element_loop.rs @@ -1,6 +1,7 @@ use super::SINGLE_ELEMENT_LOOP; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::{indent_of, snippet_with_applicability}; +use clippy_utils::visitors::contains_break_or_continue; use if_chain::if_chain; use rustc_ast::util::parser::PREC_PREFIX; use rustc_ast::Mutability; @@ -67,6 +68,7 @@ pub(super) fn check<'tcx>( if_chain! { if let ExprKind::Block(block, _) = body.kind; if !block.stmts.is_empty(); + if !contains_break_or_continue(body); then { let mut applicability = Applicability::MachineApplicable; let pat_snip = snippet_with_applicability(cx, pat.span, "..", &mut applicability); diff --git a/src/tools/clippy/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs b/src/tools/clippy/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs index d226c0bba65..0b3bf22743f 100644 --- a/src/tools/clippy/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs +++ b/src/tools/clippy/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs @@ -1,7 +1,10 @@ -use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::source::snippet_opt; +use clippy_utils::source::{indent_of, reindent_multiline}; use clippy_utils::ty::is_type_lang_item; use if_chain::if_chain; 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, Span}; @@ -15,6 +18,15 @@ pub(super) fn check<'tcx>( recv: &'tcx Expr<'_>, arg: &'tcx Expr<'_>, ) { + if let ExprKind::MethodCall(path_segment, ..) = recv.kind { + if matches!( + path_segment.ident.name.as_str(), + "to_lowercase" | "to_uppercase" | "to_ascii_lowercase" | "to_ascii_uppercase" + ) { + return; + } + } + if_chain! { if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id); if let Some(impl_id) = cx.tcx.impl_of_method(method_id); @@ -28,13 +40,37 @@ pub(super) fn check<'tcx>( let recv_ty = cx.typeck_results().expr_ty(recv).peel_refs(); if recv_ty.is_str() || is_type_lang_item(cx, recv_ty, LangItem::String); then { - span_lint_and_help( + span_lint_and_then( cx, CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS, - call_span, + recv.span.to(call_span), "case-sensitive file extension comparison", - None, - "consider using a case-insensitive comparison instead", + |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}"); + } + + let suggestion_source = reindent_multiline( + format!( + "std::path::Path::new({}) + .extension() + .map_or(false, |ext| ext.eq_ignore_ascii_case(\"{}\"))", + recv_source, ext_str.strip_prefix('.').unwrap()).into(), + true, + Some(indent_of(cx, call_span).unwrap_or(0) + 4) + ); + + diag.span_suggestion( + recv.span.to(call_span), + "use std::path::Path", + suggestion_source, + Applicability::MaybeIncorrect, + ); + } + } ); } } diff --git a/src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs b/src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs index 7c7938dd2e8..3795c0ec250 100644 --- a/src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs +++ b/src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs @@ -6,7 +6,7 @@ use clippy_utils::ty::is_copy; use rustc_errors::Applicability; use rustc_hir::{BindingAnnotation, ByRef, Expr, ExprKind, MatchSource, Node, PatKind, QPath}; use rustc_lint::LateContext; -use rustc_middle::ty::{self, adjustment::Adjust}; +use rustc_middle::ty::{self, adjustment::Adjust, print::with_forced_trimmed_paths}; use rustc_span::symbol::{sym, Symbol}; use super::CLONE_DOUBLE_REF; @@ -47,10 +47,10 @@ pub(super) fn check( cx, CLONE_DOUBLE_REF, expr.span, - &format!( + &with_forced_trimmed_paths!(format!( "using `clone` on a double-reference; \ this will copy the reference of type `{ty}` instead of cloning the inner type" - ), + )), |diag| { if let Some(snip) = sugg::Sugg::hir_opt(cx, arg) { let mut ty = innermost; @@ -61,11 +61,11 @@ pub(super) fn check( } let refs = "&".repeat(n + 1); let derefs = "*".repeat(n); - let explicit = format!("<{refs}{ty}>::clone({snip})"); + let explicit = with_forced_trimmed_paths!(format!("<{refs}{ty}>::clone({snip})")); diag.span_suggestion( expr.span, "try dereferencing it", - format!("{refs}({derefs}{}).clone()", snip.deref()), + with_forced_trimmed_paths!(format!("{refs}({derefs}{}).clone()", snip.deref())), Applicability::MaybeIncorrect, ); diag.span_suggestion( @@ -129,7 +129,9 @@ pub(super) fn check( cx, CLONE_ON_COPY, expr.span, - &format!("using `clone` on type `{ty}` which implements the `Copy` trait"), + &with_forced_trimmed_paths!(format!( + "using `clone` on type `{ty}` which implements the `Copy` trait" + )), help, sugg, app, diff --git a/src/tools/clippy/clippy_lints/src/methods/filter_map.rs b/src/tools/clippy/clippy_lints/src/methods/filter_map.rs index f888c58a72d..fc80f2eeae0 100644 --- a/src/tools/clippy/clippy_lints/src/methods/filter_map.rs +++ b/src/tools/clippy/clippy_lints/src/methods/filter_map.rs @@ -30,12 +30,12 @@ fn is_method(cx: &LateContext<'_>, expr: &hir::Expr<'_>, method_name: Symbol) -> match closure_expr.kind { hir::ExprKind::MethodCall(hir::PathSegment { ident, .. }, receiver, ..) => { if_chain! { - if ident.name == method_name; - if let hir::ExprKind::Path(path) = &receiver.kind; - if let Res::Local(ref local) = cx.qpath_res(path, receiver.hir_id); - then { - return arg_id == *local - } + if ident.name == method_name; + if let hir::ExprKind::Path(path) = &receiver.kind; + if let Res::Local(ref local) = cx.qpath_res(path, receiver.hir_id); + then { + return arg_id == *local + } } false }, @@ -92,92 +92,92 @@ pub(super) fn check( } if_chain! { - if is_trait_method(cx, map_recv, sym::Iterator); - - // filter(|x| ...is_some())... - if let ExprKind::Closure(&Closure { body: filter_body_id, .. }) = filter_arg.kind; - let filter_body = cx.tcx.hir().body(filter_body_id); - if let [filter_param] = filter_body.params; - // optional ref pattern: `filter(|&x| ..)` - let (filter_pat, is_filter_param_ref) = if let PatKind::Ref(ref_pat, _) = filter_param.pat.kind { - (ref_pat, true) - } else { - (filter_param.pat, false) + if is_trait_method(cx, map_recv, sym::Iterator); + + // filter(|x| ...is_some())... + if let ExprKind::Closure(&Closure { body: filter_body_id, .. }) = filter_arg.kind; + let filter_body = cx.tcx.hir().body(filter_body_id); + if let [filter_param] = filter_body.params; + // optional ref pattern: `filter(|&x| ..)` + let (filter_pat, is_filter_param_ref) = if let PatKind::Ref(ref_pat, _) = filter_param.pat.kind { + (ref_pat, true) + } else { + (filter_param.pat, false) + }; + // closure ends with is_some() or is_ok() + if let PatKind::Binding(_, filter_param_id, _, None) = filter_pat.kind; + if let ExprKind::MethodCall(path, filter_arg, [], _) = filter_body.value.kind; + if let Some(opt_ty) = cx.typeck_results().expr_ty(filter_arg).peel_refs().ty_adt_def(); + if let Some(is_result) = if cx.tcx.is_diagnostic_item(sym::Option, opt_ty.did()) { + Some(false) + } else if cx.tcx.is_diagnostic_item(sym::Result, opt_ty.did()) { + Some(true) + } else { + None + }; + if path.ident.name.as_str() == if is_result { "is_ok" } else { "is_some" }; + + // ...map(|x| ...unwrap()) + if let ExprKind::Closure(&Closure { body: map_body_id, .. }) = map_arg.kind; + let map_body = cx.tcx.hir().body(map_body_id); + if let [map_param] = map_body.params; + if let PatKind::Binding(_, map_param_id, map_param_ident, None) = map_param.pat.kind; + // closure ends with expect() or unwrap() + if let ExprKind::MethodCall(seg, map_arg, ..) = map_body.value.kind; + if matches!(seg.ident.name, sym::expect | sym::unwrap | sym::unwrap_or); + + // .filter(..).map(|y| f(y).copied().unwrap()) + // ~~~~ + let map_arg_peeled = match map_arg.kind { + ExprKind::MethodCall(method, original_arg, [], _) if acceptable_methods(method) => { + original_arg + }, + _ => map_arg, + }; + + // .filter(|x| x.is_some()).map(|y| y[.acceptable_method()].unwrap()) + let simple_equal = path_to_local_id(filter_arg, filter_param_id) + && path_to_local_id(map_arg_peeled, map_param_id); + + let eq_fallback = |a: &Expr<'_>, b: &Expr<'_>| { + // in `filter(|x| ..)`, replace `*x` with `x` + let a_path = if_chain! { + if !is_filter_param_ref; + if let ExprKind::Unary(UnOp::Deref, expr_path) = a.kind; + then { expr_path } else { a } }; - // closure ends with is_some() or is_ok() - if let PatKind::Binding(_, filter_param_id, _, None) = filter_pat.kind; - if let ExprKind::MethodCall(path, filter_arg, [], _) = filter_body.value.kind; - if let Some(opt_ty) = cx.typeck_results().expr_ty(filter_arg).peel_refs().ty_adt_def(); - if let Some(is_result) = if cx.tcx.is_diagnostic_item(sym::Option, opt_ty.did()) { - Some(false) - } else if cx.tcx.is_diagnostic_item(sym::Result, opt_ty.did()) { - Some(true) + // let the filter closure arg and the map closure arg be equal + path_to_local_id(a_path, filter_param_id) + && path_to_local_id(b, map_param_id) + && cx.typeck_results().expr_ty_adjusted(a) == cx.typeck_results().expr_ty_adjusted(b) + }; + + if simple_equal || SpanlessEq::new(cx).expr_fallback(eq_fallback).eq_expr(filter_arg, map_arg_peeled); + then { + let span = filter_span.with_hi(expr.span.hi()); + let (filter_name, lint) = if is_find { + ("find", MANUAL_FIND_MAP) } else { - None - }; - if path.ident.name.as_str() == if is_result { "is_ok" } else { "is_some" }; - - // ...map(|x| ...unwrap()) - if let ExprKind::Closure(&Closure { body: map_body_id, .. }) = map_arg.kind; - let map_body = cx.tcx.hir().body(map_body_id); - if let [map_param] = map_body.params; - if let PatKind::Binding(_, map_param_id, map_param_ident, None) = map_param.pat.kind; - // closure ends with expect() or unwrap() - if let ExprKind::MethodCall(seg, map_arg, ..) = map_body.value.kind; - if matches!(seg.ident.name, sym::expect | sym::unwrap | sym::unwrap_or); - - // .filter(..).map(|y| f(y).copied().unwrap()) - // ~~~~ - let map_arg_peeled = match map_arg.kind { - ExprKind::MethodCall(method, original_arg, [], _) if acceptable_methods(method) => { - original_arg - }, - _ => map_arg, + ("filter", MANUAL_FILTER_MAP) }; + let msg = format!("`{filter_name}(..).map(..)` can be simplified as `{filter_name}_map(..)`"); + let (to_opt, deref) = if is_result { + (".ok()", String::new()) + } else { + let derefs = cx.typeck_results() + .expr_adjustments(map_arg) + .iter() + .filter(|adj| matches!(adj.kind, Adjust::Deref(_))) + .count(); - // .filter(|x| x.is_some()).map(|y| y[.acceptable_method()].unwrap()) - let simple_equal = path_to_local_id(filter_arg, filter_param_id) - && path_to_local_id(map_arg_peeled, map_param_id); - - let eq_fallback = |a: &Expr<'_>, b: &Expr<'_>| { - // in `filter(|x| ..)`, replace `*x` with `x` - let a_path = if_chain! { - if !is_filter_param_ref; - if let ExprKind::Unary(UnOp::Deref, expr_path) = a.kind; - then { expr_path } else { a } - }; - // let the filter closure arg and the map closure arg be equal - path_to_local_id(a_path, filter_param_id) - && path_to_local_id(b, map_param_id) - && cx.typeck_results().expr_ty_adjusted(a) == cx.typeck_results().expr_ty_adjusted(b) + ("", "*".repeat(derefs)) }; - - if simple_equal || SpanlessEq::new(cx).expr_fallback(eq_fallback).eq_expr(filter_arg, map_arg_peeled); - then { - let span = filter_span.with_hi(expr.span.hi()); - let (filter_name, lint) = if is_find { - ("find", MANUAL_FIND_MAP) - } else { - ("filter", MANUAL_FILTER_MAP) - }; - let msg = format!("`{filter_name}(..).map(..)` can be simplified as `{filter_name}_map(..)`"); - let (to_opt, deref) = if is_result { - (".ok()", String::new()) - } else { - let derefs = cx.typeck_results() - .expr_adjustments(map_arg) - .iter() - .filter(|adj| matches!(adj.kind, Adjust::Deref(_))) - .count(); - - ("", "*".repeat(derefs)) - }; - let sugg = format!( - "{filter_name}_map(|{map_param_ident}| {deref}{}{to_opt})", - snippet(cx, map_arg.span, ".."), - ); - span_lint_and_sugg(cx, lint, span, &msg, "try", sugg, Applicability::MachineApplicable); - } + let sugg = format!( + "{filter_name}_map(|{map_param_ident}| {deref}{}{to_opt})", + snippet(cx, map_arg.span, ".."), + ); + span_lint_and_sugg(cx, lint, span, &msg, "try", sugg, Applicability::MachineApplicable); + } } } diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs b/src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs index 2244ebfb129..c87f5daab6f 100644 --- a/src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs +++ b/src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs @@ -6,7 +6,7 @@ use clippy_utils::source::{snippet, snippet_with_applicability}; use clippy_utils::sugg; use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::visitors::is_local_used; -use rustc_hir::{BindingAnnotation, Body, BorrowKind, Expr, ExprKind, Mutability, Pat, PatKind}; +use rustc_hir::{BindingAnnotation, Body, BorrowKind, ByRef, Expr, ExprKind, Mutability, Pat, PatKind}; use rustc_lint::{LateContext, LintContext}; use rustc_middle::ty; use rustc_span::sym; @@ -30,9 +30,9 @@ pub(super) fn check<'tcx>( if let Body {params: [p], value: body_expr, generator_kind: _ } = cx.tcx.hir().body(c.body); if let PatKind::Tuple([key_pat, val_pat], _) = p.pat.kind; - let (replacement_kind, binded_ident) = match (&key_pat.kind, &val_pat.kind) { - (key, PatKind::Binding(_, _, value, _)) if pat_is_wild(cx, key, m_arg) => ("value", value), - (PatKind::Binding(_, _, key, _), value) if pat_is_wild(cx, value, m_arg) => ("key", key), + let (replacement_kind, annotation, bound_ident) = match (&key_pat.kind, &val_pat.kind) { + (key, PatKind::Binding(ann, _, value, _)) if pat_is_wild(cx, key, m_arg) => ("value", ann, value), + (PatKind::Binding(ann, _, key, _), value) if pat_is_wild(cx, value, m_arg) => ("key", ann, key), _ => return, }; @@ -47,7 +47,7 @@ pub(super) fn check<'tcx>( if_chain! { if let ExprKind::Path(rustc_hir::QPath::Resolved(_, path)) = body_expr.kind; if let [local_ident] = path.segments; - if local_ident.ident.as_str() == binded_ident.as_str(); + if local_ident.ident.as_str() == bound_ident.as_str(); then { span_lint_and_sugg( @@ -60,13 +60,23 @@ pub(super) fn check<'tcx>( applicability, ); } else { + let ref_annotation = if annotation.0 == ByRef::Yes { + "ref " + } else { + "" + }; + let mut_annotation = if annotation.1 == Mutability::Mut { + "mut " + } else { + "" + }; span_lint_and_sugg( cx, ITER_KV_MAP, expr.span, &format!("iterating on a map's {replacement_kind}s"), "try", - format!("{recv_snippet}.{into_prefix}{replacement_kind}s().map(|{binded_ident}| {})", + format!("{recv_snippet}.{into_prefix}{replacement_kind}s().map(|{ref_annotation}{mut_annotation}{bound_ident}| {})", snippet_with_applicability(cx, body_expr.span, "/* body */", &mut applicability)), applicability, ); diff --git a/src/tools/clippy/clippy_lints/src/methods/suspicious_to_owned.rs b/src/tools/clippy/clippy_lints/src/methods/suspicious_to_owned.rs index 15c1c618c51..fe88fa41fd9 100644 --- a/src/tools/clippy/clippy_lints/src/methods/suspicious_to_owned.rs +++ b/src/tools/clippy/clippy_lints/src/methods/suspicious_to_owned.rs @@ -5,7 +5,7 @@ use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; -use rustc_middle::ty; +use rustc_middle::ty::{self, print::with_forced_trimmed_paths}; use rustc_span::sym; use super::SUSPICIOUS_TO_OWNED; @@ -24,7 +24,9 @@ pub fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>) - cx, SUSPICIOUS_TO_OWNED, expr.span, - &format!("this `to_owned` call clones the {input_type} itself and does not cause the {input_type} contents to become owned"), + &with_forced_trimmed_paths!(format!( + "this `to_owned` call clones the {input_type} itself and does not cause the {input_type} contents to become owned" + )), "consider using, depending on intent", format!("{recv_snip}.clone()` or `{recv_snip}.into_owned()"), app, diff --git a/src/tools/clippy/clippy_lints/src/mutex_atomic.rs b/src/tools/clippy/clippy_lints/src/mutex_atomic.rs index 09cb5333176..dc866ab6373 100644 --- a/src/tools/clippy/clippy_lints/src/mutex_atomic.rs +++ b/src/tools/clippy/clippy_lints/src/mutex_atomic.rs @@ -1,6 +1,6 @@ //! Checks for uses of mutex where an atomic value could be used //! -//! This lint is **warn** by default +//! This lint is **allow** by default use clippy_utils::diagnostics::span_lint; use clippy_utils::ty::is_type_diagnostic_item; @@ -20,6 +20,10 @@ declare_clippy_lint! { /// `std::sync::atomic::AtomicBool` and `std::sync::atomic::AtomicPtr` are leaner and /// faster. /// + /// On the other hand, `Mutex`es are, in general, easier to + /// verify correctness. An atomic does not behave the same as + /// an equivalent mutex. See [this issue](https://github.com/rust-lang/rust-clippy/issues/4295)'s commentary for more details. + /// /// ### Known problems /// This lint cannot detect if the mutex is actually used /// for waiting before a critical section. @@ -39,8 +43,8 @@ declare_clippy_lint! { /// ``` #[clippy::version = "pre 1.29.0"] pub MUTEX_ATOMIC, - nursery, - "using a mutex where an atomic value could be used instead" + restriction, + "using a mutex where an atomic value could be used instead." } declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs b/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs index 4fbc8398e37..cff82b875f1 100644 --- a/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs +++ b/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs @@ -2,7 +2,7 @@ use super::ARITHMETIC_SIDE_EFFECTS; use clippy_utils::{ consts::{constant, constant_simple}, diagnostics::span_lint, - peel_hir_expr_refs, + peel_hir_expr_refs, peel_hir_expr_unary, }; use rustc_ast as ast; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; @@ -98,8 +98,11 @@ impl ArithmeticSideEffects { } /// If `expr` is not a literal integer like `1`, returns `None`. + /// + /// Returns the absolute value of the expression, if this is an integer literal. fn literal_integer(expr: &hir::Expr<'_>) -> Option<u128> { - if let hir::ExprKind::Lit(ref lit) = expr.kind && let ast::LitKind::Int(n, _) = lit.node { + let actual = peel_hir_expr_unary(expr).0; + if let hir::ExprKind::Lit(ref lit) = actual.kind && let ast::LitKind::Int(n, _) = lit.node { Some(n) } else { @@ -123,12 +126,12 @@ impl ArithmeticSideEffects { if !matches!( op.node, hir::BinOpKind::Add - | hir::BinOpKind::Sub - | hir::BinOpKind::Mul | hir::BinOpKind::Div + | hir::BinOpKind::Mul | hir::BinOpKind::Rem | hir::BinOpKind::Shl | hir::BinOpKind::Shr + | hir::BinOpKind::Sub ) { return; }; diff --git a/src/tools/clippy/clippy_lints/src/ranges.rs b/src/tools/clippy/clippy_lints/src/ranges.rs index 0a1b9d173cf..fc655fe2d0b 100644 --- a/src/tools/clippy/clippy_lints/src/ranges.rs +++ b/src/tools/clippy/clippy_lints/src/ranges.rs @@ -103,7 +103,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does /// Checks for range expressions `x..y` where both `x` and `y` - /// are constant and `x` is greater or equal to `y`. + /// are constant and `x` is greater to `y`. Also triggers if `x` is equal to `y` when they are conditions to a `for` loop. /// /// ### Why is this bad? /// Empty ranges yield no values so iterating them is a no-op. diff --git a/src/tools/clippy/clippy_lints/src/redundant_clone.rs b/src/tools/clippy/clippy_lints/src/redundant_clone.rs index 0e7c5cca724..c1677fb3da1 100644 --- a/src/tools/clippy/clippy_lints/src/redundant_clone.rs +++ b/src/tools/clippy/clippy_lints/src/redundant_clone.rs @@ -131,7 +131,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClone { // `res = clone(arg)` can be turned into `res = move arg;` // if `arg` is the only borrow of `cloned` at this point. - if cannot_move_out || !possible_borrower.at_most_borrowers(cx, &[arg], cloned, loc) { + if cannot_move_out || !possible_borrower.only_borrowers(&[arg], cloned, loc) { continue; } @@ -178,7 +178,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClone { // StorageDead(pred_arg); // res = to_path_buf(cloned); // ``` - if cannot_move_out || !possible_borrower.at_most_borrowers(cx, &[arg, cloned], local, loc) { + if cannot_move_out || !possible_borrower.only_borrowers(&[arg, cloned], local, loc) { continue; } diff --git a/src/tools/clippy/clippy_lints/src/renamed_lints.rs b/src/tools/clippy/clippy_lints/src/renamed_lints.rs index 72c25592609..9f487dedb8c 100644 --- a/src/tools/clippy/clippy_lints/src/renamed_lints.rs +++ b/src/tools/clippy/clippy_lints/src/renamed_lints.rs @@ -9,6 +9,7 @@ pub static RENAMED_LINTS: &[(&str, &str)] = &[ ("clippy::box_vec", "clippy::box_collection"), ("clippy::const_static_lifetime", "clippy::redundant_static_lifetimes"), ("clippy::cyclomatic_complexity", "clippy::cognitive_complexity"), + ("clippy::derive_hash_xor_eq", "clippy::derived_hash_with_manual_eq"), ("clippy::disallowed_method", "clippy::disallowed_methods"), ("clippy::disallowed_type", "clippy::disallowed_types"), ("clippy::eval_order_dependence", "clippy::mixed_read_write_in_expression"), diff --git a/src/tools/clippy/clippy_lints/src/returns.rs b/src/tools/clippy/clippy_lints/src/returns.rs index d4d50660520..bbbd9e4989e 100644 --- a/src/tools/clippy/clippy_lints/src/returns.rs +++ b/src/tools/clippy/clippy_lints/src/returns.rs @@ -210,22 +210,25 @@ fn check_final_expr<'tcx>( // if desugar of `do yeet`, don't lint if let Some(inner_expr) = inner && let ExprKind::Call(path_expr, _) = inner_expr.kind - && let ExprKind::Path(QPath::LangItem(LangItem::TryTraitFromYeet, _, _)) = path_expr.kind { - return; + && let ExprKind::Path(QPath::LangItem(LangItem::TryTraitFromYeet, _, _)) = path_expr.kind + { + return; } - if cx.tcx.hir().attrs(expr.hir_id).is_empty() { - let borrows = inner.map_or(false, |inner| last_statement_borrows(cx, inner)); - if !borrows { - // check if expr return nothing - let ret_span = if inner.is_none() && replacement == RetReplacement::Empty { - extend_span_to_previous_non_ws(cx, peeled_drop_expr.span) - } else { - peeled_drop_expr.span - }; - - emit_return_lint(cx, ret_span, semi_spans, inner.as_ref().map(|i| i.span), replacement); - } + if !cx.tcx.hir().attrs(expr.hir_id).is_empty() { + return; + } + let borrows = inner.map_or(false, |inner| last_statement_borrows(cx, inner)); + if borrows { + return; } + // check if expr return nothing + let ret_span = if inner.is_none() && replacement == RetReplacement::Empty { + extend_span_to_previous_non_ws(cx, peeled_drop_expr.span) + } else { + peeled_drop_expr.span + }; + + emit_return_lint(cx, ret_span, semi_spans, inner.as_ref().map(|i| i.span), replacement); }, ExprKind::If(_, then, else_clause_opt) => { check_block_return(cx, &then.kind, semi_spans.clone()); @@ -292,7 +295,7 @@ fn last_statement_borrows<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { ControlFlow::Break(()) } else { - ControlFlow::Continue(Descend::from(!expr.span.from_expansion())) + ControlFlow::Continue(Descend::from(!e.span.from_expansion())) } }) .is_some() diff --git a/src/tools/clippy/clippy_lints/src/types/mod.rs b/src/tools/clippy/clippy_lints/src/types/mod.rs index c14f056a1f2..229478b7ce3 100644 --- a/src/tools/clippy/clippy_lints/src/types/mod.rs +++ b/src/tools/clippy/clippy_lints/src/types/mod.rs @@ -127,7 +127,7 @@ declare_clippy_lint! { /// `Vec` or a `VecDeque` (formerly called `RingBuf`). /// /// ### Why is this bad? - /// Gankro says: + /// Gankra says: /// /// > The TL;DR of `LinkedList` is that it's built on a massive amount of /// pointers and indirection. diff --git a/src/tools/clippy/clippy_lints/src/unused_self.rs b/src/tools/clippy/clippy_lints/src/unused_self.rs index 42bccc7212b..f864c520302 100644 --- a/src/tools/clippy/clippy_lints/src/unused_self.rs +++ b/src/tools/clippy/clippy_lints/src/unused_self.rs @@ -1,9 +1,11 @@ use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::macros::root_macro_call_first_node; use clippy_utils::visitors::is_local_used; use if_chain::if_chain; -use rustc_hir::{Impl, ImplItem, ImplItemKind, ItemKind}; +use rustc_hir::{Body, Impl, ImplItem, ImplItemKind, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_tool_lint, impl_lint_pass}; +use std::ops::ControlFlow; declare_clippy_lint! { /// ### What it does @@ -57,6 +59,20 @@ impl<'tcx> LateLintPass<'tcx> for UnusedSelf { let parent = cx.tcx.hir().get_parent_item(impl_item.hir_id()).def_id; let parent_item = cx.tcx.hir().expect_item(parent); let assoc_item = cx.tcx.associated_item(impl_item.owner_id); + let contains_todo = |cx, body: &'_ Body<'_>| -> bool { + clippy_utils::visitors::for_each_expr(body.value, |e| { + if let Some(macro_call) = root_macro_call_first_node(cx, e) { + if cx.tcx.item_name(macro_call.def_id).as_str() == "todo" { + ControlFlow::Break(()) + } else { + ControlFlow::Continue(()) + } + } else { + ControlFlow::Continue(()) + } + }) + .is_some() + }; if_chain! { if let ItemKind::Impl(Impl { of_trait: None, .. }) = parent_item.kind; if assoc_item.fn_has_self_parameter; @@ -65,6 +81,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedSelf { let body = cx.tcx.hir().body(*body_id); if let [self_param, ..] = body.params; if !is_local_used(cx, body, self_param.pat.hir_id); + if !contains_todo(cx, body); then { span_lint_and_help( cx, @@ -72,7 +89,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedSelf { self_param.span, "unused `self` argument", None, - "consider refactoring to a associated function", + "consider refactoring to an associated function", ); } } diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs index c86f24cbd37..c4d8c28f060 100644 --- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs +++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs @@ -1058,7 +1058,7 @@ fn get_parent_local<'hir>(cx: &LateContext<'hir>, expr: &'hir hir::Expr<'hir>) - fn get_parent_local_hir_id<'hir>(cx: &LateContext<'hir>, hir_id: hir::HirId) -> Option<&'hir hir::Local<'hir>> { let map = cx.tcx.hir(); - match map.find_parent((hir_id)) { + match map.find_parent(hir_id) { Some(hir::Node::Local(local)) => Some(local), Some(hir::Node::Pat(pattern)) => get_parent_local_hir_id(cx, pattern.hir_id), _ => None, diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index 8290fe9ecb4..7a4a9036dd3 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -22,6 +22,9 @@ extern crate rustc_ast; extern crate rustc_ast_pretty; extern crate rustc_attr; extern crate rustc_data_structures; +// The `rustc_driver` crate seems to be required in order to use the `rust_ast` crate. +#[allow(unused_extern_crates)] +extern crate rustc_driver; extern crate rustc_errors; extern crate rustc_hir; extern crate rustc_hir_typeck; @@ -116,6 +119,8 @@ use crate::consts::{constant, Constant}; use crate::ty::{can_partially_move_ty, expr_sig, is_copy, is_recursively_primitive_type, ty_is_fn_once_param}; use crate::visitors::for_each_expr; +use rustc_middle::hir::nested_filter; + #[macro_export] macro_rules! extract_msrv_attr { ($context:ident) => { @@ -1253,22 +1258,33 @@ pub fn get_item_name(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<Symbol> { } } -pub struct ContainsName { +pub struct ContainsName<'a, 'tcx> { + pub cx: &'a LateContext<'tcx>, pub name: Symbol, pub result: bool, } -impl<'tcx> Visitor<'tcx> for ContainsName { +impl<'a, 'tcx> Visitor<'tcx> for ContainsName<'a, 'tcx> { + type NestedFilter = nested_filter::OnlyBodies; + fn visit_name(&mut self, name: Symbol) { if self.name == name { self.result = true; } } + + fn nested_visit_map(&mut self) -> Self::Map { + self.cx.tcx.hir() + } } /// Checks if an `Expr` contains a certain name. -pub fn contains_name(name: Symbol, expr: &Expr<'_>) -> bool { - let mut cn = ContainsName { name, result: false }; +pub fn contains_name<'tcx>(name: Symbol, expr: &'tcx Expr<'_>, cx: &LateContext<'tcx>) -> bool { + let mut cn = ContainsName { + name, + result: false, + cx, + }; cn.visit_expr(expr); cn.result } @@ -1304,6 +1320,7 @@ pub fn get_parent_expr_for_hir<'tcx>(cx: &LateContext<'tcx>, hir_id: hir::HirId) } } +/// Gets the enclosing block, if any. pub fn get_enclosing_block<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId) -> Option<&'tcx Block<'tcx>> { let map = &cx.tcx.hir(); let enclosing_node = map @@ -2244,6 +2261,18 @@ pub fn peel_n_hir_expr_refs<'a>(expr: &'a Expr<'a>, count: usize) -> (&'a Expr<' (e, count - remaining) } +/// Peels off all unary operators of an expression. Returns the underlying expression and the number +/// of operators removed. +pub fn peel_hir_expr_unary<'a>(expr: &'a Expr<'a>) -> (&'a Expr<'a>, usize) { + let mut count: usize = 0; + let mut curr_expr = expr; + while let ExprKind::Unary(_, local_expr) = curr_expr.kind { + count = count.wrapping_add(1); + curr_expr = local_expr; + } + (curr_expr, count) +} + /// Peels off all references on the expression. Returns the underlying expression and the number of /// references removed. pub fn peel_hir_expr_refs<'a>(expr: &'a Expr<'a>) -> (&'a Expr<'a>, usize) { diff --git a/src/tools/clippy/clippy_utils/src/mir/possible_borrower.rs b/src/tools/clippy/clippy_utils/src/mir/possible_borrower.rs index 395d46e7a2f..9adae773389 100644 --- a/src/tools/clippy/clippy_utils/src/mir/possible_borrower.rs +++ b/src/tools/clippy/clippy_utils/src/mir/possible_borrower.rs @@ -1,16 +1,11 @@ -use super::possible_origin::PossibleOriginVisitor; +use super::{possible_origin::PossibleOriginVisitor, transitive_relation::TransitiveRelation}; use crate::ty::is_copy; -use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; +use rustc_data_structures::fx::FxHashMap; use rustc_index::bit_set::{BitSet, HybridBitSet}; use rustc_lint::LateContext; -use rustc_middle::mir::{ - self, visit::Visitor as _, BasicBlock, Local, Location, Mutability, Statement, StatementKind, Terminator, -}; -use rustc_middle::ty::{self, visit::TypeVisitor, TyCtxt}; -use rustc_mir_dataflow::{ - fmt::DebugWithContext, impls::MaybeStorageLive, lattice::JoinSemiLattice, Analysis, AnalysisDomain, - CallReturnPlaces, ResultsCursor, -}; +use rustc_middle::mir::{self, visit::Visitor as _, Mutability}; +use rustc_middle::ty::{self, visit::TypeVisitor}; +use rustc_mir_dataflow::{impls::MaybeStorageLive, Analysis, ResultsCursor}; use std::borrow::Cow; use std::ops::ControlFlow; @@ -18,120 +13,78 @@ use std::ops::ControlFlow; /// For example, `b = &a; c = &a;` will make `b` and (transitively) `c` /// possible borrowers of `a`. #[allow(clippy::module_name_repetitions)] -struct PossibleBorrowerAnalysis<'b, 'tcx> { - tcx: TyCtxt<'tcx>, +struct PossibleBorrowerVisitor<'a, 'b, 'tcx> { + possible_borrower: TransitiveRelation, body: &'b mir::Body<'tcx>, + cx: &'a LateContext<'tcx>, possible_origin: FxHashMap<mir::Local, HybridBitSet<mir::Local>>, } -#[derive(Clone, Debug, Eq, PartialEq)] -struct PossibleBorrowerState { - map: FxIndexMap<Local, BitSet<Local>>, - domain_size: usize, -} - -impl PossibleBorrowerState { - fn new(domain_size: usize) -> Self { +impl<'a, 'b, 'tcx> PossibleBorrowerVisitor<'a, 'b, 'tcx> { + fn new( + cx: &'a LateContext<'tcx>, + body: &'b mir::Body<'tcx>, + possible_origin: FxHashMap<mir::Local, HybridBitSet<mir::Local>>, + ) -> Self { Self { - map: FxIndexMap::default(), - domain_size, + possible_borrower: TransitiveRelation::default(), + cx, + body, + possible_origin, } } - #[allow(clippy::similar_names)] - fn add(&mut self, borrowed: Local, borrower: Local) { - self.map - .entry(borrowed) - .or_insert(BitSet::new_empty(self.domain_size)) - .insert(borrower); - } -} - -impl<C> DebugWithContext<C> for PossibleBorrowerState { - fn fmt_with(&self, _ctxt: &C, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - <_ as std::fmt::Debug>::fmt(self, f) - } - fn fmt_diff_with(&self, _old: &Self, _ctxt: &C, _f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - unimplemented!() - } -} + fn into_map( + self, + cx: &'a LateContext<'tcx>, + maybe_live: ResultsCursor<'b, 'tcx, MaybeStorageLive<'tcx>>, + ) -> PossibleBorrowerMap<'b, 'tcx> { + let mut map = FxHashMap::default(); + for row in (1..self.body.local_decls.len()).map(mir::Local::from_usize) { + if is_copy(cx, self.body.local_decls[row].ty) { + continue; + } -impl JoinSemiLattice for PossibleBorrowerState { - fn join(&mut self, other: &Self) -> bool { - let mut changed = false; - for (&borrowed, borrowers) in other.map.iter() { + let mut borrowers = self.possible_borrower.reachable_from(row, self.body.local_decls.len()); + borrowers.remove(mir::Local::from_usize(0)); if !borrowers.is_empty() { - changed |= self - .map - .entry(borrowed) - .or_insert(BitSet::new_empty(self.domain_size)) - .union(borrowers); + map.insert(row, borrowers); } } - changed - } -} - -impl<'b, 'tcx> AnalysisDomain<'tcx> for PossibleBorrowerAnalysis<'b, 'tcx> { - type Domain = PossibleBorrowerState; - - const NAME: &'static str = "possible_borrower"; - - fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain { - PossibleBorrowerState::new(body.local_decls.len()) - } - - fn initialize_start_block(&self, _body: &mir::Body<'tcx>, _entry_set: &mut Self::Domain) {} -} -impl<'b, 'tcx> PossibleBorrowerAnalysis<'b, 'tcx> { - fn new( - tcx: TyCtxt<'tcx>, - body: &'b mir::Body<'tcx>, - possible_origin: FxHashMap<mir::Local, HybridBitSet<mir::Local>>, - ) -> Self { - Self { - tcx, - body, - possible_origin, + let bs = BitSet::new_empty(self.body.local_decls.len()); + PossibleBorrowerMap { + map, + maybe_live, + bitset: (bs.clone(), bs), } } } -impl<'b, 'tcx> Analysis<'tcx> for PossibleBorrowerAnalysis<'b, 'tcx> { - fn apply_call_return_effect( - &self, - _state: &mut Self::Domain, - _block: BasicBlock, - _return_places: CallReturnPlaces<'_, 'tcx>, - ) { - } - - fn apply_statement_effect(&self, state: &mut Self::Domain, statement: &Statement<'tcx>, _location: Location) { - if let StatementKind::Assign(box (place, rvalue)) = &statement.kind { - let lhs = place.local; - match rvalue { - mir::Rvalue::Ref(_, _, borrowed) => { - state.add(borrowed.local, lhs); - }, - other => { - if ContainsRegion - .visit_ty(place.ty(&self.body.local_decls, self.tcx).ty) - .is_continue() - { - return; +impl<'a, 'b, 'tcx> mir::visit::Visitor<'tcx> for PossibleBorrowerVisitor<'a, 'b, 'tcx> { + fn visit_assign(&mut self, place: &mir::Place<'tcx>, rvalue: &mir::Rvalue<'_>, _location: mir::Location) { + let lhs = place.local; + match rvalue { + mir::Rvalue::Ref(_, _, borrowed) => { + self.possible_borrower.add(borrowed.local, lhs); + }, + other => { + if ContainsRegion + .visit_ty(place.ty(&self.body.local_decls, self.cx.tcx).ty) + .is_continue() + { + return; + } + rvalue_locals(other, |rhs| { + if lhs != rhs { + self.possible_borrower.add(rhs, lhs); } - rvalue_locals(other, |rhs| { - if lhs != rhs { - state.add(rhs, lhs); - } - }); - }, - } + }); + }, } } - fn apply_terminator_effect(&self, state: &mut Self::Domain, terminator: &Terminator<'tcx>, _location: Location) { + fn visit_terminator(&mut self, terminator: &mir::Terminator<'_>, _loc: mir::Location) { if let mir::TerminatorKind::Call { args, destination: mir::Place { local: dest, .. }, @@ -171,10 +124,10 @@ impl<'b, 'tcx> Analysis<'tcx> for PossibleBorrowerAnalysis<'b, 'tcx> { for y in mutable_variables { for x in &immutable_borrowers { - state.add(*x, y); + self.possible_borrower.add(*x, y); } for x in &mutable_borrowers { - state.add(*x, y); + self.possible_borrower.add(*x, y); } } } @@ -210,98 +163,73 @@ fn rvalue_locals(rvalue: &mir::Rvalue<'_>, mut visit: impl FnMut(mir::Local)) { } } -/// Result of `PossibleBorrowerAnalysis`. +/// Result of `PossibleBorrowerVisitor`. #[allow(clippy::module_name_repetitions)] pub struct PossibleBorrowerMap<'b, 'tcx> { - body: &'b mir::Body<'tcx>, - possible_borrower: ResultsCursor<'b, 'tcx, PossibleBorrowerAnalysis<'b, 'tcx>>, - maybe_live: ResultsCursor<'b, 'tcx, MaybeStorageLive<'b>>, - pushed: BitSet<Local>, - stack: Vec<Local>, + /// Mapping `Local -> its possible borrowers` + pub map: FxHashMap<mir::Local, HybridBitSet<mir::Local>>, + maybe_live: ResultsCursor<'b, 'tcx, MaybeStorageLive<'tcx>>, + // Caches to avoid allocation of `BitSet` on every query + pub bitset: (BitSet<mir::Local>, BitSet<mir::Local>), } -impl<'b, 'tcx> PossibleBorrowerMap<'b, 'tcx> { - pub fn new(cx: &LateContext<'tcx>, mir: &'b mir::Body<'tcx>) -> Self { +impl<'a, 'b, 'tcx> PossibleBorrowerMap<'b, 'tcx> { + pub fn new(cx: &'a LateContext<'tcx>, mir: &'b mir::Body<'tcx>) -> Self { let possible_origin = { let mut vis = PossibleOriginVisitor::new(mir); vis.visit_body(mir); vis.into_map(cx) }; - let possible_borrower = PossibleBorrowerAnalysis::new(cx.tcx, mir, possible_origin) + let maybe_storage_live_result = MaybeStorageLive::new(Cow::Owned(BitSet::new_empty(mir.local_decls.len()))) .into_engine(cx.tcx, mir) - .pass_name("possible_borrower") + .pass_name("redundant_clone") .iterate_to_fixpoint() .into_results_cursor(mir); - let maybe_live = MaybeStorageLive::new(Cow::Owned(BitSet::new_empty(mir.local_decls.len()))) - .into_engine(cx.tcx, mir) - .pass_name("possible_borrower") - .iterate_to_fixpoint() - .into_results_cursor(mir); - PossibleBorrowerMap { - body: mir, - possible_borrower, - maybe_live, - pushed: BitSet::new_empty(mir.local_decls.len()), - stack: Vec::with_capacity(mir.local_decls.len()), - } + let mut vis = PossibleBorrowerVisitor::new(cx, mir, possible_origin); + vis.visit_body(mir); + vis.into_map(cx, maybe_storage_live_result) } - /// Returns true if the set of borrowers of `borrowed` living at `at` includes no more than - /// `borrowers`. - /// Notes: - /// 1. It would be nice if `PossibleBorrowerMap` could store `cx` so that `at_most_borrowers` - /// would not require it to be passed in. But a `PossibleBorrowerMap` is stored in `LintPass` - /// `Dereferencing`, which outlives any `LateContext`. - /// 2. In all current uses of `at_most_borrowers`, `borrowers` is a slice of at most two - /// elements. Thus, `borrowers.contains(...)` is effectively a constant-time operation. If - /// `at_most_borrowers`'s uses were to expand beyond this, its implementation might have to be - /// adjusted. - pub fn at_most_borrowers( + /// Returns true if the set of borrowers of `borrowed` living at `at` matches with `borrowers`. + pub fn only_borrowers(&mut self, borrowers: &[mir::Local], borrowed: mir::Local, at: mir::Location) -> bool { + self.bounded_borrowers(borrowers, borrowers, borrowed, at) + } + + /// Returns true if the set of borrowers of `borrowed` living at `at` includes at least `below` + /// but no more than `above`. + pub fn bounded_borrowers( &mut self, - cx: &LateContext<'tcx>, - borrowers: &[mir::Local], + below: &[mir::Local], + above: &[mir::Local], borrowed: mir::Local, at: mir::Location, ) -> bool { - if is_copy(cx, self.body.local_decls[borrowed].ty) { - return true; - } - - self.possible_borrower.seek_before_primary_effect(at); - self.maybe_live.seek_before_primary_effect(at); - - let possible_borrower = &self.possible_borrower.get().map; - let maybe_live = &self.maybe_live; - - self.pushed.clear(); - self.stack.clear(); + self.maybe_live.seek_after_primary_effect(at); - if let Some(borrowers) = possible_borrower.get(&borrowed) { - for b in borrowers.iter() { - if self.pushed.insert(b) { - self.stack.push(b); - } + self.bitset.0.clear(); + let maybe_live = &mut self.maybe_live; + if let Some(bitset) = self.map.get(&borrowed) { + for b in bitset.iter().filter(move |b| maybe_live.contains(*b)) { + self.bitset.0.insert(b); } } else { - // Nothing borrows `borrowed` at `at`. - return true; + return false; } - while let Some(borrower) = self.stack.pop() { - if maybe_live.contains(borrower) && !borrowers.contains(&borrower) { - return false; - } + self.bitset.1.clear(); + for b in below { + self.bitset.1.insert(*b); + } - if let Some(borrowers) = possible_borrower.get(&borrower) { - for b in borrowers.iter() { - if self.pushed.insert(b) { - self.stack.push(b); - } - } - } + if !self.bitset.0.superset(&self.bitset.1) { + return false; + } + + for b in above { + self.bitset.0.remove(*b); } - true + self.bitset.0.is_empty() } pub fn local_is_alive_at(&mut self, local: mir::Local, at: mir::Location) -> bool { diff --git a/src/tools/clippy/clippy_utils/src/msrvs.rs b/src/tools/clippy/clippy_utils/src/msrvs.rs index ba5bc9c3135..dbf9f3b621d 100644 --- a/src/tools/clippy/clippy_utils/src/msrvs.rs +++ b/src/tools/clippy/clippy_utils/src/msrvs.rs @@ -20,8 +20,9 @@ macro_rules! msrv_aliases { // names may refer to stabilized feature flags or library items msrv_aliases! { 1,65,0 { LET_ELSE } - 1,62,0 { BOOL_THEN_SOME } + 1,62,0 { BOOL_THEN_SOME, DEFAULT_ENUM_ATTRIBUTE } 1,58,0 { FORMAT_ARGS_CAPTURE, PATTERN_TRAIT_CHAR_ARRAY } + 1,55,0 { SEEK_REWIND } 1,53,0 { OR_PATTERNS, MANUAL_BITS, BTREE_MAP_RETAIN, BTREE_SET_RETAIN, ARRAY_INTO_ITERATOR } 1,52,0 { STR_SPLIT_ONCE, REM_EUCLID_CONST } 1,51,0 { BORROW_AS_PTR, SEEK_FROM_CURRENT, UNSIGNED_ABS } @@ -45,7 +46,6 @@ msrv_aliases! { 1,18,0 { HASH_MAP_RETAIN, HASH_SET_RETAIN } 1,17,0 { FIELD_INIT_SHORTHAND, STATIC_IN_CONST, EXPECT_ERR } 1,16,0 { STR_REPEAT } - 1,55,0 { SEEK_REWIND } } fn parse_msrv(msrv: &str, sess: Option<&Session>, span: Option<Span>) -> Option<RustcVersion> { diff --git a/src/tools/clippy/clippy_utils/src/paths.rs b/src/tools/clippy/clippy_utils/src/paths.rs index 9ca50105ae5..95eebab7567 100644 --- a/src/tools/clippy/clippy_utils/src/paths.rs +++ b/src/tools/clippy/clippy_utils/src/paths.rs @@ -47,7 +47,6 @@ pub const IDENT: [&str; 3] = ["rustc_span", "symbol", "Ident"]; #[cfg(feature = "internal")] 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 ITER_COUNT: [&str; 6] = ["core", "iter", "traits", "iterator", "Iterator", "count"]; pub const ITER_EMPTY: [&str; 5] = ["core", "iter", "sources", "empty", "Empty"]; pub const ITERTOOLS_NEXT_TUPLE: [&str; 3] = ["itertools", "Itertools", "next_tuple"]; #[cfg(feature = "internal")] diff --git a/src/tools/clippy/clippy_utils/src/visitors.rs b/src/tools/clippy/clippy_utils/src/visitors.rs index 863fb60fcfc..14c01a60b4c 100644 --- a/src/tools/clippy/clippy_utils/src/visitors.rs +++ b/src/tools/clippy/clippy_utils/src/visitors.rs @@ -724,3 +724,14 @@ pub fn for_each_local_assignment<'tcx, B>( ControlFlow::Continue(()) } } + +pub fn contains_break_or_continue(expr: &Expr<'_>) -> bool { + for_each_expr(expr, |e| { + if matches!(e.kind, ExprKind::Break(..) | ExprKind::Continue(..)) { + ControlFlow::Break(()) + } else { + ControlFlow::Continue(()) + } + }) + .is_some() +} diff --git a/src/tools/clippy/rust-toolchain b/src/tools/clippy/rust-toolchain index 9399d422036..40a6f47095e 100644 --- a/src/tools/clippy/rust-toolchain +++ b/src/tools/clippy/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2022-12-29" +channel = "nightly-2023-01-12" components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"] diff --git a/src/tools/clippy/src/driver.rs b/src/tools/clippy/src/driver.rs index bcc096c570e..d521e8d8839 100644 --- a/src/tools/clippy/src/driver.rs +++ b/src/tools/clippy/src/driver.rs @@ -256,11 +256,14 @@ pub fn main() { LazyLock::force(&ICE_HOOK); exit(rustc_driver::catch_with_exit_code(move || { let mut orig_args: Vec<String> = env::args().collect(); + let has_sysroot_arg = arg_value(&orig_args, "--sysroot", |_| true).is_some(); let sys_root_env = std::env::var("SYSROOT").ok(); let pass_sysroot_env_if_given = |args: &mut Vec<String>, sys_root_env| { if let Some(sys_root) = sys_root_env { - args.extend(vec!["--sysroot".into(), sys_root]); + if !has_sysroot_arg { + args.extend(vec!["--sysroot".into(), sys_root]); + } }; }; diff --git a/src/tools/clippy/tests/integration.rs b/src/tools/clippy/tests/integration.rs index 818ff70b33f..a771d8b87c8 100644 --- a/src/tools/clippy/tests/integration.rs +++ b/src/tools/clippy/tests/integration.rs @@ -1,3 +1,12 @@ +//! This test is meant to only be run in CI. To run it locally use: +//! +//! `env INTEGRATION=rust-lang/log cargo test --test integration --features=integration` +//! +//! You can use a different `INTEGRATION` value to test different repositories. +//! +//! This test will clone the specified repository and run Clippy on it. The test succeeds, if +//! Clippy doesn't produce an ICE. Lint warnings are ignored by this test. + #![cfg(feature = "integration")] #![cfg_attr(feature = "deny-warnings", deny(warnings))] #![warn(rust_2018_idioms, unused_lifetimes)] diff --git a/src/tools/clippy/tests/ui-toml/arithmetic_side_effects_allowed/arithmetic_side_effects_allowed.rs b/src/tools/clippy/tests/ui-toml/arithmetic_side_effects_allowed/arithmetic_side_effects_allowed.rs index 36db9e54a22..fb5b1b193f8 100644 --- a/src/tools/clippy/tests/ui-toml/arithmetic_side_effects_allowed/arithmetic_side_effects_allowed.rs +++ b/src/tools/clippy/tests/ui-toml/arithmetic_side_effects_allowed/arithmetic_side_effects_allowed.rs @@ -107,7 +107,7 @@ fn rhs_is_different() { fn unary() { // is explicitly on the list let _ = -OutOfNames; - // is specifically on the list + // is explicitly on the list let _ = -Foo; // not on the list let _ = -Bar; diff --git a/src/tools/clippy/tests/ui-toml/dbg_macro/dbg_macro.stderr b/src/tools/clippy/tests/ui-toml/dbg_macro/dbg_macro.stderr index 46efb86dcfc..859383a7119 100644 --- a/src/tools/clippy/tests/ui-toml/dbg_macro/dbg_macro.stderr +++ b/src/tools/clippy/tests/ui-toml/dbg_macro/dbg_macro.stderr @@ -1,99 +1,99 @@ -error: `dbg!` macro is intended as a debugging tool +error: the `dbg!` macro is intended as a debugging tool --> $DIR/dbg_macro.rs:5:22 | LL | if let Some(n) = dbg!(n.checked_sub(4)) { n } else { n } | ^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::dbg-macro` implied by `-D warnings` -help: ensure to avoid having uses of it in version control +help: remove the invocation before committing it to a version control system | LL | if let Some(n) = n.checked_sub(4) { n } else { n } | ~~~~~~~~~~~~~~~~ -error: `dbg!` macro is intended as a debugging tool +error: the `dbg!` macro is intended as a debugging tool --> $DIR/dbg_macro.rs:9:8 | LL | if dbg!(n <= 1) { | ^^^^^^^^^^^^ | -help: ensure to avoid having uses of it in version control +help: remove the invocation before committing it to a version control system | LL | if n <= 1 { | ~~~~~~ -error: `dbg!` macro is intended as a debugging tool +error: the `dbg!` macro is intended as a debugging tool --> $DIR/dbg_macro.rs:10:9 | LL | dbg!(1) | ^^^^^^^ | -help: ensure to avoid having uses of it in version control +help: remove the invocation before committing it to a version control system | LL | 1 | -error: `dbg!` macro is intended as a debugging tool +error: the `dbg!` macro is intended as a debugging tool --> $DIR/dbg_macro.rs:12:9 | LL | dbg!(n * factorial(n - 1)) | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | -help: ensure to avoid having uses of it in version control +help: remove the invocation before committing it to a version control system | LL | n * factorial(n - 1) | -error: `dbg!` macro is intended as a debugging tool +error: the `dbg!` macro is intended as a debugging tool --> $DIR/dbg_macro.rs:17:5 | LL | dbg!(42); | ^^^^^^^^ | -help: ensure to avoid having uses of it in version control +help: remove the invocation before committing it to a version control system | LL | 42; | ~~ -error: `dbg!` macro is intended as a debugging tool +error: the `dbg!` macro is intended as a debugging tool --> $DIR/dbg_macro.rs:18:5 | LL | dbg!(dbg!(dbg!(42))); | ^^^^^^^^^^^^^^^^^^^^ | -help: ensure to avoid having uses of it in version control +help: remove the invocation before committing it to a version control system | LL | dbg!(dbg!(42)); | ~~~~~~~~~~~~~~ -error: `dbg!` macro is intended as a debugging tool +error: the `dbg!` macro is intended as a debugging tool --> $DIR/dbg_macro.rs:19:14 | LL | foo(3) + dbg!(factorial(4)); | ^^^^^^^^^^^^^^^^^^ | -help: ensure to avoid having uses of it in version control +help: remove the invocation before committing it to a version control system | LL | foo(3) + factorial(4); | ~~~~~~~~~~~~ -error: `dbg!` macro is intended as a debugging tool +error: the `dbg!` macro is intended as a debugging tool --> $DIR/dbg_macro.rs:20:5 | LL | dbg!(1, 2, dbg!(3, 4)); | ^^^^^^^^^^^^^^^^^^^^^^ | -help: ensure to avoid having uses of it in version control +help: remove the invocation before committing it to a version control system | LL | (1, 2, dbg!(3, 4)); | ~~~~~~~~~~~~~~~~~~ -error: `dbg!` macro is intended as a debugging tool +error: the `dbg!` macro is intended as a debugging tool --> $DIR/dbg_macro.rs:21:5 | LL | dbg!(1, 2, 3, 4, 5); | ^^^^^^^^^^^^^^^^^^^ | -help: ensure to avoid having uses of it in version control +help: remove the invocation before committing it to a version control system | LL | (1, 2, 3, 4, 5); | ~~~~~~~~~~~~~~~ diff --git a/src/tools/clippy/tests/ui/arithmetic_side_effects.rs b/src/tools/clippy/tests/ui/arithmetic_side_effects.rs index b5ed8988a51..918cf81c600 100644 --- a/src/tools/clippy/tests/ui/arithmetic_side_effects.rs +++ b/src/tools/clippy/tests/ui/arithmetic_side_effects.rs @@ -2,6 +2,7 @@ clippy::assign_op_pattern, clippy::erasing_op, clippy::identity_op, + clippy::no_effect, clippy::op_ref, clippy::unnecessary_owned_empty_strings, arithmetic_overflow, @@ -12,31 +13,95 @@ use core::num::{Saturating, Wrapping}; +#[derive(Clone, Copy)] pub struct Custom; macro_rules! impl_arith { - ( $( $_trait:ident, $ty:ty, $method:ident; )* ) => { + ( $( $_trait:ident, $lhs:ty, $rhs:ty, $method:ident; )* ) => { $( - impl core::ops::$_trait<$ty> for Custom { - type Output = Self; - fn $method(self, _: $ty) -> Self::Output { Self } + impl core::ops::$_trait<$lhs> for $rhs { + type Output = Custom; + fn $method(self, _: $lhs) -> Self::Output { todo!() } + } + )* + } +} + +macro_rules! impl_assign_arith { + ( $( $_trait:ident, $lhs:ty, $rhs:ty, $method:ident; )* ) => { + $( + impl core::ops::$_trait<$lhs> for $rhs { + fn $method(&mut self, _: $lhs) {} } )* } } impl_arith!( - Add, i32, add; - Div, i32, div; - Mul, i32, mul; - Sub, i32, sub; - - Add, f64, add; - Div, f64, div; - Mul, f64, mul; - Sub, f64, sub; + Add, Custom, Custom, add; + Div, Custom, Custom, div; + Mul, Custom, Custom, mul; + Rem, Custom, Custom, rem; + Sub, Custom, Custom, sub; + + Add, Custom, &Custom, add; + Div, Custom, &Custom, div; + Mul, Custom, &Custom, mul; + Rem, Custom, &Custom, rem; + Sub, Custom, &Custom, sub; + + Add, &Custom, Custom, add; + Div, &Custom, Custom, div; + Mul, &Custom, Custom, mul; + Rem, &Custom, Custom, rem; + Sub, &Custom, Custom, sub; + + Add, &Custom, &Custom, add; + Div, &Custom, &Custom, div; + Mul, &Custom, &Custom, mul; + Rem, &Custom, &Custom, rem; + Sub, &Custom, &Custom, sub; +); + +impl_assign_arith!( + AddAssign, Custom, Custom, add_assign; + DivAssign, Custom, Custom, div_assign; + MulAssign, Custom, Custom, mul_assign; + RemAssign, Custom, Custom, rem_assign; + SubAssign, Custom, Custom, sub_assign; + + AddAssign, Custom, &Custom, add_assign; + DivAssign, Custom, &Custom, div_assign; + MulAssign, Custom, &Custom, mul_assign; + RemAssign, Custom, &Custom, rem_assign; + SubAssign, Custom, &Custom, sub_assign; + + AddAssign, &Custom, Custom, add_assign; + DivAssign, &Custom, Custom, div_assign; + MulAssign, &Custom, Custom, mul_assign; + RemAssign, &Custom, Custom, rem_assign; + SubAssign, &Custom, Custom, sub_assign; + + AddAssign, &Custom, &Custom, add_assign; + DivAssign, &Custom, &Custom, div_assign; + MulAssign, &Custom, &Custom, mul_assign; + RemAssign, &Custom, &Custom, rem_assign; + SubAssign, &Custom, &Custom, sub_assign; ); +impl core::ops::Neg for Custom { + type Output = Custom; + fn neg(self) -> Self::Output { + todo!() + } +} +impl core::ops::Neg for &Custom { + type Output = Custom; + fn neg(self) -> Self::Output { + todo!() + } +} + pub fn association_with_structures_should_not_trigger_the_lint() { enum Foo { Bar = -2, @@ -125,6 +190,18 @@ pub fn non_overflowing_ops_or_ops_already_handled_by_the_compiler_should_not_tri _n *= &0; _n *= 1; _n *= &1; + _n += -0; + _n += &-0; + _n -= -0; + _n -= &-0; + _n /= -99; + _n /= &-99; + _n %= -99; + _n %= &-99; + _n *= -0; + _n *= &-0; + _n *= -1; + _n *= &-1; // Binary _n = _n + 0; @@ -158,8 +235,9 @@ pub fn non_overflowing_ops_or_ops_already_handled_by_the_compiler_should_not_tri _n = -&i32::MIN; } -pub fn runtime_ops() { +pub fn unknown_ops_or_runtime_ops_that_can_overflow() { let mut _n = i32::MAX; + let mut _custom = Custom; // Assign _n += 1; @@ -172,6 +250,36 @@ pub fn runtime_ops() { _n %= &0; _n *= 2; _n *= &2; + _n += -1; + _n += &-1; + _n -= -1; + _n -= &-1; + _n /= -0; + _n /= &-0; + _n %= -0; + _n %= &-0; + _n *= -2; + _n *= &-2; + _custom += Custom; + _custom += &Custom; + _custom -= Custom; + _custom -= &Custom; + _custom /= Custom; + _custom /= &Custom; + _custom %= Custom; + _custom %= &Custom; + _custom *= Custom; + _custom *= &Custom; + _custom += -Custom; + _custom += &-Custom; + _custom -= -Custom; + _custom -= &-Custom; + _custom /= -Custom; + _custom /= &-Custom; + _custom %= -Custom; + _custom %= &-Custom; + _custom *= -Custom; + _custom *= &-Custom; // Binary _n = _n + 1; @@ -193,36 +301,73 @@ pub fn runtime_ops() { _n = 23 + &85; _n = &23 + 85; _n = &23 + &85; - - // Custom - let _ = Custom + 0; - let _ = Custom + 1; - let _ = Custom + 2; - let _ = Custom + 0.0; - let _ = Custom + 1.0; - let _ = Custom + 2.0; - let _ = Custom - 0; - let _ = Custom - 1; - let _ = Custom - 2; - let _ = Custom - 0.0; - let _ = Custom - 1.0; - let _ = Custom - 2.0; - let _ = Custom / 0; - let _ = Custom / 1; - let _ = Custom / 2; - let _ = Custom / 0.0; - let _ = Custom / 1.0; - let _ = Custom / 2.0; - let _ = Custom * 0; - let _ = Custom * 1; - let _ = Custom * 2; - let _ = Custom * 0.0; - let _ = Custom * 1.0; - let _ = Custom * 2.0; + _custom = _custom + _custom; + _custom = _custom + &_custom; + _custom = Custom + _custom; + _custom = &Custom + _custom; + _custom = _custom - Custom; + _custom = _custom - &Custom; + _custom = Custom - _custom; + _custom = &Custom - _custom; + _custom = _custom / Custom; + _custom = _custom / &Custom; + _custom = _custom % Custom; + _custom = _custom % &Custom; + _custom = _custom * Custom; + _custom = _custom * &Custom; + _custom = Custom * _custom; + _custom = &Custom * _custom; + _custom = Custom + &Custom; + _custom = &Custom + Custom; + _custom = &Custom + &Custom; // Unary _n = -_n; _n = -&_n; + _custom = -_custom; + _custom = -&_custom; +} + +// Copied and pasted from the `integer_arithmetic` lint for comparison. +pub fn integer_arithmetic() { + let mut i = 1i32; + let mut var1 = 0i32; + let mut var2 = -1i32; + + 1 + i; + i * 2; + 1 % i / 2; + i - 2 + 2 - i; + -i; + i >> 1; + i << 1; + + -1; + -(-1); + + i & 1; + i | 1; + i ^ 1; + + i += 1; + i -= 1; + i *= 2; + i /= 2; + i /= 0; + i /= -1; + i /= var1; + i /= var2; + i %= 2; + i %= 0; + i %= -1; + i %= var1; + i %= var2; + i <<= 3; + i >>= 2; + + i |= 1; + i &= 1; + i ^= i; } fn main() {} diff --git a/src/tools/clippy/tests/ui/arithmetic_side_effects.stderr b/src/tools/clippy/tests/ui/arithmetic_side_effects.stderr index 9fe4b7cf28d..5e349f6b497 100644 --- a/src/tools/clippy/tests/ui/arithmetic_side_effects.stderr +++ b/src/tools/clippy/tests/ui/arithmetic_side_effects.stderr @@ -1,5 +1,5 @@ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:165:5 + --> $DIR/arithmetic_side_effects.rs:243:5 | LL | _n += 1; | ^^^^^^^ @@ -7,328 +7,592 @@ LL | _n += 1; = note: `-D clippy::arithmetic-side-effects` implied by `-D warnings` error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:166:5 + --> $DIR/arithmetic_side_effects.rs:244:5 | LL | _n += &1; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:167:5 + --> $DIR/arithmetic_side_effects.rs:245:5 | LL | _n -= 1; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:168:5 + --> $DIR/arithmetic_side_effects.rs:246:5 | LL | _n -= &1; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:169:5 + --> $DIR/arithmetic_side_effects.rs:247:5 | LL | _n /= 0; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:170:5 + --> $DIR/arithmetic_side_effects.rs:248:5 | LL | _n /= &0; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:171:5 + --> $DIR/arithmetic_side_effects.rs:249:5 | LL | _n %= 0; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:172:5 + --> $DIR/arithmetic_side_effects.rs:250:5 | LL | _n %= &0; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:173:5 + --> $DIR/arithmetic_side_effects.rs:251:5 | LL | _n *= 2; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:174:5 + --> $DIR/arithmetic_side_effects.rs:252:5 | LL | _n *= &2; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:177:10 + --> $DIR/arithmetic_side_effects.rs:253:5 + | +LL | _n += -1; + | ^^^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:254:5 + | +LL | _n += &-1; + | ^^^^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:255:5 + | +LL | _n -= -1; + | ^^^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:256:5 + | +LL | _n -= &-1; + | ^^^^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:257:5 + | +LL | _n /= -0; + | ^^^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:258:5 + | +LL | _n /= &-0; + | ^^^^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:259:5 + | +LL | _n %= -0; + | ^^^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:260:5 + | +LL | _n %= &-0; + | ^^^^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:261:5 + | +LL | _n *= -2; + | ^^^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:262:5 + | +LL | _n *= &-2; + | ^^^^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:263:5 + | +LL | _custom += Custom; + | ^^^^^^^^^^^^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:264:5 + | +LL | _custom += &Custom; + | ^^^^^^^^^^^^^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:265:5 + | +LL | _custom -= Custom; + | ^^^^^^^^^^^^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:266:5 + | +LL | _custom -= &Custom; + | ^^^^^^^^^^^^^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:267:5 + | +LL | _custom /= Custom; + | ^^^^^^^^^^^^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:268:5 + | +LL | _custom /= &Custom; + | ^^^^^^^^^^^^^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:269:5 + | +LL | _custom %= Custom; + | ^^^^^^^^^^^^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:270:5 + | +LL | _custom %= &Custom; + | ^^^^^^^^^^^^^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:271:5 + | +LL | _custom *= Custom; + | ^^^^^^^^^^^^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:272:5 + | +LL | _custom *= &Custom; + | ^^^^^^^^^^^^^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:273:5 + | +LL | _custom += -Custom; + | ^^^^^^^^^^^^^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:274:5 + | +LL | _custom += &-Custom; + | ^^^^^^^^^^^^^^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:275:5 + | +LL | _custom -= -Custom; + | ^^^^^^^^^^^^^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:276:5 + | +LL | _custom -= &-Custom; + | ^^^^^^^^^^^^^^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:277:5 + | +LL | _custom /= -Custom; + | ^^^^^^^^^^^^^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:278:5 + | +LL | _custom /= &-Custom; + | ^^^^^^^^^^^^^^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:279:5 + | +LL | _custom %= -Custom; + | ^^^^^^^^^^^^^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:280:5 + | +LL | _custom %= &-Custom; + | ^^^^^^^^^^^^^^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:281:5 + | +LL | _custom *= -Custom; + | ^^^^^^^^^^^^^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:282:5 + | +LL | _custom *= &-Custom; + | ^^^^^^^^^^^^^^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:285:10 | LL | _n = _n + 1; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:178:10 + --> $DIR/arithmetic_side_effects.rs:286:10 | LL | _n = _n + &1; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:179:10 + --> $DIR/arithmetic_side_effects.rs:287:10 | LL | _n = 1 + _n; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:180:10 + --> $DIR/arithmetic_side_effects.rs:288:10 | LL | _n = &1 + _n; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:181:10 + --> $DIR/arithmetic_side_effects.rs:289:10 | LL | _n = _n - 1; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:182:10 + --> $DIR/arithmetic_side_effects.rs:290:10 | LL | _n = _n - &1; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:183:10 + --> $DIR/arithmetic_side_effects.rs:291:10 | LL | _n = 1 - _n; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:184:10 + --> $DIR/arithmetic_side_effects.rs:292:10 | LL | _n = &1 - _n; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:185:10 + --> $DIR/arithmetic_side_effects.rs:293:10 | LL | _n = _n / 0; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:186:10 + --> $DIR/arithmetic_side_effects.rs:294:10 | LL | _n = _n / &0; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:187:10 + --> $DIR/arithmetic_side_effects.rs:295:10 | LL | _n = _n % 0; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:188:10 + --> $DIR/arithmetic_side_effects.rs:296:10 | LL | _n = _n % &0; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:189:10 + --> $DIR/arithmetic_side_effects.rs:297:10 | LL | _n = _n * 2; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:190:10 + --> $DIR/arithmetic_side_effects.rs:298:10 | LL | _n = _n * &2; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:191:10 + --> $DIR/arithmetic_side_effects.rs:299:10 | LL | _n = 2 * _n; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:192:10 + --> $DIR/arithmetic_side_effects.rs:300:10 | LL | _n = &2 * _n; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:193:10 + --> $DIR/arithmetic_side_effects.rs:301:10 | LL | _n = 23 + &85; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:194:10 + --> $DIR/arithmetic_side_effects.rs:302:10 | LL | _n = &23 + 85; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:195:10 + --> $DIR/arithmetic_side_effects.rs:303:10 | LL | _n = &23 + &85; | ^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:198:13 + --> $DIR/arithmetic_side_effects.rs:304:15 | -LL | let _ = Custom + 0; - | ^^^^^^^^^^ +LL | _custom = _custom + _custom; + | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:199:13 + --> $DIR/arithmetic_side_effects.rs:305:15 | -LL | let _ = Custom + 1; - | ^^^^^^^^^^ +LL | _custom = _custom + &_custom; + | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:200:13 + --> $DIR/arithmetic_side_effects.rs:306:15 | -LL | let _ = Custom + 2; - | ^^^^^^^^^^ +LL | _custom = Custom + _custom; + | ^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:201:13 + --> $DIR/arithmetic_side_effects.rs:307:15 | -LL | let _ = Custom + 0.0; - | ^^^^^^^^^^^^ +LL | _custom = &Custom + _custom; + | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:202:13 + --> $DIR/arithmetic_side_effects.rs:308:15 | -LL | let _ = Custom + 1.0; - | ^^^^^^^^^^^^ +LL | _custom = _custom - Custom; + | ^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:203:13 + --> $DIR/arithmetic_side_effects.rs:309:15 | -LL | let _ = Custom + 2.0; - | ^^^^^^^^^^^^ +LL | _custom = _custom - &Custom; + | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:204:13 + --> $DIR/arithmetic_side_effects.rs:310:15 | -LL | let _ = Custom - 0; - | ^^^^^^^^^^ +LL | _custom = Custom - _custom; + | ^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:205:13 + --> $DIR/arithmetic_side_effects.rs:311:15 | -LL | let _ = Custom - 1; - | ^^^^^^^^^^ +LL | _custom = &Custom - _custom; + | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:206:13 + --> $DIR/arithmetic_side_effects.rs:312:15 | -LL | let _ = Custom - 2; - | ^^^^^^^^^^ +LL | _custom = _custom / Custom; + | ^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:207:13 + --> $DIR/arithmetic_side_effects.rs:313:15 | -LL | let _ = Custom - 0.0; - | ^^^^^^^^^^^^ +LL | _custom = _custom / &Custom; + | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:208:13 + --> $DIR/arithmetic_side_effects.rs:314:15 | -LL | let _ = Custom - 1.0; - | ^^^^^^^^^^^^ +LL | _custom = _custom % Custom; + | ^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:209:13 + --> $DIR/arithmetic_side_effects.rs:315:15 | -LL | let _ = Custom - 2.0; - | ^^^^^^^^^^^^ +LL | _custom = _custom % &Custom; + | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:210:13 + --> $DIR/arithmetic_side_effects.rs:316:15 | -LL | let _ = Custom / 0; - | ^^^^^^^^^^ +LL | _custom = _custom * Custom; + | ^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:211:13 + --> $DIR/arithmetic_side_effects.rs:317:15 | -LL | let _ = Custom / 1; - | ^^^^^^^^^^ +LL | _custom = _custom * &Custom; + | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:212:13 + --> $DIR/arithmetic_side_effects.rs:318:15 | -LL | let _ = Custom / 2; - | ^^^^^^^^^^ +LL | _custom = Custom * _custom; + | ^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:213:13 + --> $DIR/arithmetic_side_effects.rs:319:15 | -LL | let _ = Custom / 0.0; - | ^^^^^^^^^^^^ +LL | _custom = &Custom * _custom; + | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:214:13 + --> $DIR/arithmetic_side_effects.rs:320:15 | -LL | let _ = Custom / 1.0; - | ^^^^^^^^^^^^ +LL | _custom = Custom + &Custom; + | ^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:215:13 + --> $DIR/arithmetic_side_effects.rs:321:15 | -LL | let _ = Custom / 2.0; - | ^^^^^^^^^^^^ +LL | _custom = &Custom + Custom; + | ^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:216:13 + --> $DIR/arithmetic_side_effects.rs:322:15 | -LL | let _ = Custom * 0; - | ^^^^^^^^^^ +LL | _custom = &Custom + &Custom; + | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:217:13 + --> $DIR/arithmetic_side_effects.rs:325:10 | -LL | let _ = Custom * 1; - | ^^^^^^^^^^ +LL | _n = -_n; + | ^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:218:13 + --> $DIR/arithmetic_side_effects.rs:326:10 | -LL | let _ = Custom * 2; - | ^^^^^^^^^^ +LL | _n = -&_n; + | ^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:219:13 + --> $DIR/arithmetic_side_effects.rs:327:15 | -LL | let _ = Custom * 0.0; - | ^^^^^^^^^^^^ +LL | _custom = -_custom; + | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:220:13 + --> $DIR/arithmetic_side_effects.rs:328:15 | -LL | let _ = Custom * 1.0; - | ^^^^^^^^^^^^ +LL | _custom = -&_custom; + | ^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:221:13 + --> $DIR/arithmetic_side_effects.rs:337:5 | -LL | let _ = Custom * 2.0; - | ^^^^^^^^^^^^ +LL | 1 + i; + | ^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:224:10 + --> $DIR/arithmetic_side_effects.rs:338:5 | -LL | _n = -_n; - | ^^^ +LL | i * 2; + | ^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:225:10 + --> $DIR/arithmetic_side_effects.rs:340:5 | -LL | _n = -&_n; - | ^^^^ +LL | i - 2 + 2 - i; + | ^^^^^^^^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:341:5 + | +LL | -i; + | ^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:342:5 + | +LL | i >> 1; + | ^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:343:5 + | +LL | i << 1; + | ^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:352:5 + | +LL | i += 1; + | ^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:353:5 + | +LL | i -= 1; + | ^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:354:5 + | +LL | i *= 2; + | ^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:356:5 + | +LL | i /= 0; + | ^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:358:5 + | +LL | i /= var1; + | ^^^^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:359:5 + | +LL | i /= var2; + | ^^^^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:361:5 + | +LL | i %= 0; + | ^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:363:5 + | +LL | i %= var1; + | ^^^^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:364:5 + | +LL | i %= var2; + | ^^^^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:365:5 + | +LL | i <<= 3; + | ^^^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:366:5 + | +LL | i >>= 2; + | ^^^^^^^ -error: aborting due to 55 previous errors +error: aborting due to 99 previous errors diff --git a/src/tools/clippy/tests/ui/box_default.fixed b/src/tools/clippy/tests/ui/box_default.fixed index 911fa856aa0..7e9f074fdca 100644 --- a/src/tools/clippy/tests/ui/box_default.fixed +++ b/src/tools/clippy/tests/ui/box_default.fixed @@ -21,16 +21,16 @@ macro_rules! outer { fn main() { let _string: Box<String> = Box::default(); let _byte = Box::<u8>::default(); - let _vec = Box::<std::vec::Vec<u8>>::default(); + let _vec = Box::<Vec<u8>>::default(); let _impl = Box::<ImplementsDefault>::default(); let _impl2 = Box::<ImplementsDefault>::default(); let _impl3: Box<ImplementsDefault> = Box::default(); let _own = Box::new(OwnDefault::default()); // should not lint - let _in_macro = outer!(Box::<std::string::String>::default()); - let _string_default = outer!(Box::<std::string::String>::default()); + let _in_macro = outer!(Box::<String>::default()); + let _string_default = outer!(Box::<String>::default()); let _vec2: Box<Vec<ImplementsDefault>> = Box::default(); let _vec3: Box<Vec<bool>> = Box::default(); - let _vec4: Box<_> = Box::<std::vec::Vec<bool>>::default(); + let _vec4: Box<_> = Box::<Vec<bool>>::default(); let _more = ret_ty_fn(); call_ty_fn(Box::default()); } @@ -54,4 +54,14 @@ impl Read for ImplementsDefault { fn issue_9621_dyn_trait() { let _: Box<dyn Read> = Box::<ImplementsDefault>::default(); + issue_10089(); +} + +fn issue_10089() { + let _closure = || { + #[derive(Default)] + struct WeirdPathed; + + let _ = Box::<WeirdPathed>::default(); + }; } diff --git a/src/tools/clippy/tests/ui/box_default.rs b/src/tools/clippy/tests/ui/box_default.rs index 20019c2ee5a..5c8d0b8354c 100644 --- a/src/tools/clippy/tests/ui/box_default.rs +++ b/src/tools/clippy/tests/ui/box_default.rs @@ -54,4 +54,14 @@ impl Read for ImplementsDefault { fn issue_9621_dyn_trait() { let _: Box<dyn Read> = Box::new(ImplementsDefault::default()); + issue_10089(); +} + +fn issue_10089() { + let _closure = || { + #[derive(Default)] + struct WeirdPathed; + + let _ = Box::new(WeirdPathed::default()); + }; } diff --git a/src/tools/clippy/tests/ui/box_default.stderr b/src/tools/clippy/tests/ui/box_default.stderr index 5ea410331af..249eb340f96 100644 --- a/src/tools/clippy/tests/ui/box_default.stderr +++ b/src/tools/clippy/tests/ui/box_default.stderr @@ -16,7 +16,7 @@ error: `Box::new(_)` of default value --> $DIR/box_default.rs:24:16 | LL | let _vec = Box::new(Vec::<u8>::new()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::<std::vec::Vec<u8>>::default()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::<Vec<u8>>::default()` error: `Box::new(_)` of default value --> $DIR/box_default.rs:25:17 @@ -40,13 +40,13 @@ error: `Box::new(_)` of default value --> $DIR/box_default.rs:29:28 | LL | let _in_macro = outer!(Box::new(String::new())); - | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::<std::string::String>::default()` + | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::<String>::default()` error: `Box::new(_)` of default value --> $DIR/box_default.rs:30:34 | LL | let _string_default = outer!(Box::new(String::from(""))); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::<std::string::String>::default()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::<String>::default()` error: `Box::new(_)` of default value --> $DIR/box_default.rs:31:46 @@ -64,7 +64,7 @@ error: `Box::new(_)` of default value --> $DIR/box_default.rs:33:25 | LL | let _vec4: Box<_> = Box::new(Vec::from([false; 0])); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::<std::vec::Vec<bool>>::default()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::<Vec<bool>>::default()` error: `Box::new(_)` of default value --> $DIR/box_default.rs:35:16 @@ -84,5 +84,11 @@ error: `Box::new(_)` of default value LL | let _: Box<dyn Read> = Box::new(ImplementsDefault::default()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::<ImplementsDefault>::default()` -error: aborting due to 14 previous errors +error: `Box::new(_)` of default value + --> $DIR/box_default.rs:65:17 + | +LL | let _ = Box::new(WeirdPathed::default()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::<WeirdPathed>::default()` + +error: aborting due to 15 previous errors diff --git a/src/tools/clippy/tests/ui/case_sensitive_file_extension_comparisons.fixed b/src/tools/clippy/tests/ui/case_sensitive_file_extension_comparisons.fixed new file mode 100644 index 00000000000..5fbaa64db39 --- /dev/null +++ b/src/tools/clippy/tests/ui/case_sensitive_file_extension_comparisons.fixed @@ -0,0 +1,67 @@ +// run-rustfix +#![warn(clippy::case_sensitive_file_extension_comparisons)] + +use std::string::String; + +struct TestStruct; + +impl TestStruct { + fn ends_with(self, _arg: &str) {} +} + +#[allow(dead_code)] +fn is_rust_file(filename: &str) -> bool { + std::path::Path::new(filename) + .extension() + .map_or(false, |ext| ext.eq_ignore_ascii_case("rs")) +} + +fn main() { + // std::string::String and &str should trigger the lint failure with .ext12 + let _ = std::path::Path::new(&String::new()) + .extension() + .map_or(false, |ext| ext.eq_ignore_ascii_case("ext12")); + let _ = std::path::Path::new("str") + .extension() + .map_or(false, |ext| ext.eq_ignore_ascii_case("ext12")); + + // The fixup should preserve the indentation level + { + let _ = std::path::Path::new("str") + .extension() + .map_or(false, |ext| ext.eq_ignore_ascii_case("ext12")); + } + + // The test struct should not trigger the lint failure with .ext12 + TestStruct {}.ends_with(".ext12"); + + // std::string::String and &str should trigger the lint failure with .EXT12 + let _ = std::path::Path::new(&String::new()) + .extension() + .map_or(false, |ext| ext.eq_ignore_ascii_case("EXT12")); + let _ = std::path::Path::new("str") + .extension() + .map_or(false, |ext| ext.eq_ignore_ascii_case("EXT12")); + + // Should not trigger the lint failure because of the calls to to_lowercase and to_uppercase + let _ = String::new().to_lowercase().ends_with(".EXT12"); + let _ = String::new().to_uppercase().ends_with(".EXT12"); + + // The test struct should not trigger the lint failure with .EXT12 + TestStruct {}.ends_with(".EXT12"); + + // Should not trigger the lint failure with .eXT12 + let _ = String::new().ends_with(".eXT12"); + let _ = "str".ends_with(".eXT12"); + TestStruct {}.ends_with(".eXT12"); + + // Should not trigger the lint failure with .EXT123 (too long) + let _ = String::new().ends_with(".EXT123"); + let _ = "str".ends_with(".EXT123"); + TestStruct {}.ends_with(".EXT123"); + + // Shouldn't fail if it doesn't start with a dot + let _ = String::new().ends_with("a.ext"); + let _ = "str".ends_with("a.extA"); + TestStruct {}.ends_with("a.ext"); +} diff --git a/src/tools/clippy/tests/ui/case_sensitive_file_extension_comparisons.rs b/src/tools/clippy/tests/ui/case_sensitive_file_extension_comparisons.rs index 6f0485b5279..3c0d4821f9f 100644 --- a/src/tools/clippy/tests/ui/case_sensitive_file_extension_comparisons.rs +++ b/src/tools/clippy/tests/ui/case_sensitive_file_extension_comparisons.rs @@ -1,3 +1,4 @@ +// run-rustfix #![warn(clippy::case_sensitive_file_extension_comparisons)] use std::string::String; @@ -5,9 +6,10 @@ use std::string::String; struct TestStruct; impl TestStruct { - fn ends_with(self, arg: &str) {} + fn ends_with(self, _arg: &str) {} } +#[allow(dead_code)] fn is_rust_file(filename: &str) -> bool { filename.ends_with(".rs") } @@ -17,6 +19,11 @@ fn main() { let _ = String::new().ends_with(".ext12"); let _ = "str".ends_with(".ext12"); + // The fixup should preserve the indentation level + { + let _ = "str".ends_with(".ext12"); + } + // The test struct should not trigger the lint failure with .ext12 TestStruct {}.ends_with(".ext12"); @@ -24,6 +31,10 @@ fn main() { let _ = String::new().ends_with(".EXT12"); let _ = "str".ends_with(".EXT12"); + // Should not trigger the lint failure because of the calls to to_lowercase and to_uppercase + let _ = String::new().to_lowercase().ends_with(".EXT12"); + let _ = String::new().to_uppercase().ends_with(".EXT12"); + // The test struct should not trigger the lint failure with .EXT12 TestStruct {}.ends_with(".EXT12"); diff --git a/src/tools/clippy/tests/ui/case_sensitive_file_extension_comparisons.stderr b/src/tools/clippy/tests/ui/case_sensitive_file_extension_comparisons.stderr index a28dd8bd5ad..44c8e3fdf74 100644 --- a/src/tools/clippy/tests/ui/case_sensitive_file_extension_comparisons.stderr +++ b/src/tools/clippy/tests/ui/case_sensitive_file_extension_comparisons.stderr @@ -1,43 +1,87 @@ error: case-sensitive file extension comparison - --> $DIR/case_sensitive_file_extension_comparisons.rs:12:14 + --> $DIR/case_sensitive_file_extension_comparisons.rs:14:5 | LL | filename.ends_with(".rs") - | ^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: consider using a case-insensitive comparison instead = note: `-D clippy::case-sensitive-file-extension-comparisons` implied by `-D warnings` +help: use std::path::Path + | +LL ~ std::path::Path::new(filename) +LL + .extension() +LL + .map_or(false, |ext| ext.eq_ignore_ascii_case("rs")) + | error: case-sensitive file extension comparison - --> $DIR/case_sensitive_file_extension_comparisons.rs:17:27 + --> $DIR/case_sensitive_file_extension_comparisons.rs:19:13 | LL | let _ = String::new().ends_with(".ext12"); - | ^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: consider using a case-insensitive comparison instead +help: use std::path::Path + | +LL ~ let _ = std::path::Path::new(&String::new()) +LL + .extension() +LL ~ .map_or(false, |ext| ext.eq_ignore_ascii_case("ext12")); + | error: case-sensitive file extension comparison - --> $DIR/case_sensitive_file_extension_comparisons.rs:18:19 + --> $DIR/case_sensitive_file_extension_comparisons.rs:20:13 | LL | let _ = "str".ends_with(".ext12"); - | ^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: consider using a case-insensitive comparison instead +help: use std::path::Path + | +LL ~ let _ = std::path::Path::new("str") +LL + .extension() +LL ~ .map_or(false, |ext| ext.eq_ignore_ascii_case("ext12")); + | error: case-sensitive file extension comparison - --> $DIR/case_sensitive_file_extension_comparisons.rs:24:27 + --> $DIR/case_sensitive_file_extension_comparisons.rs:24:17 + | +LL | let _ = "str".ends_with(".ext12"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider using a case-insensitive comparison instead +help: use std::path::Path + | +LL ~ let _ = std::path::Path::new("str") +LL + .extension() +LL ~ .map_or(false, |ext| ext.eq_ignore_ascii_case("ext12")); + | + +error: case-sensitive file extension comparison + --> $DIR/case_sensitive_file_extension_comparisons.rs:31:13 | LL | let _ = String::new().ends_with(".EXT12"); - | ^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: consider using a case-insensitive comparison instead +help: use std::path::Path + | +LL ~ let _ = std::path::Path::new(&String::new()) +LL + .extension() +LL ~ .map_or(false, |ext| ext.eq_ignore_ascii_case("EXT12")); + | error: case-sensitive file extension comparison - --> $DIR/case_sensitive_file_extension_comparisons.rs:25:19 + --> $DIR/case_sensitive_file_extension_comparisons.rs:32:13 | LL | let _ = "str".ends_with(".EXT12"); - | ^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: consider using a case-insensitive comparison instead +help: use std::path::Path + | +LL ~ let _ = std::path::Path::new("str") +LL + .extension() +LL ~ .map_or(false, |ext| ext.eq_ignore_ascii_case("EXT12")); + | -error: aborting due to 5 previous errors +error: aborting due to 6 previous errors diff --git a/src/tools/clippy/tests/ui/clone_on_copy.stderr b/src/tools/clippy/tests/ui/clone_on_copy.stderr index 42ae227777c..862234d204b 100644 --- a/src/tools/clippy/tests/ui/clone_on_copy.stderr +++ b/src/tools/clippy/tests/ui/clone_on_copy.stderr @@ -48,7 +48,7 @@ error: using `clone` on type `i32` which implements the `Copy` trait LL | vec.push(42.clone()); | ^^^^^^^^^^ help: try removing the `clone` call: `42` -error: using `clone` on type `std::option::Option<i32>` which implements the `Copy` trait +error: using `clone` on type `Option<i32>` which implements the `Copy` trait --> $DIR/clone_on_copy.rs:77:17 | LL | let value = opt.clone()?; // operator precedence needed (*opt)? diff --git a/src/tools/clippy/tests/ui/crashes/ice-6252.stderr b/src/tools/clippy/tests/ui/crashes/ice-6252.stderr index 638e4a54849..efdd56dd47d 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-6252.stderr +++ b/src/tools/clippy/tests/ui/crashes/ice-6252.stderr @@ -17,9 +17,12 @@ error[E0412]: cannot find type `VAL` in this scope --> $DIR/ice-6252.rs:10:63 | LL | impl<N, M> TypeVal<usize> for Multiply<N, M> where N: TypeVal<VAL> {} - | - ^^^ not found in this scope - | | - | help: you might be missing a type parameter: `, VAL` + | ^^^ not found in this scope + | +help: you might be missing a type parameter + | +LL | impl<N, M, VAL> TypeVal<usize> for Multiply<N, M> where N: TypeVal<VAL> {} + | +++++ error[E0046]: not all trait items implemented, missing: `VAL` --> $DIR/ice-6252.rs:10:1 diff --git a/src/tools/clippy/tests/ui/dbg_macro.stderr b/src/tools/clippy/tests/ui/dbg_macro.stderr index e6a65b46d97..ddb5f1342e9 100644 --- a/src/tools/clippy/tests/ui/dbg_macro.stderr +++ b/src/tools/clippy/tests/ui/dbg_macro.stderr @@ -1,143 +1,143 @@ -error: `dbg!` macro is intended as a debugging tool +error: the `dbg!` macro is intended as a debugging tool --> $DIR/dbg_macro.rs:5:22 | LL | if let Some(n) = dbg!(n.checked_sub(4)) { n } else { n } | ^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::dbg-macro` implied by `-D warnings` -help: ensure to avoid having uses of it in version control +help: remove the invocation before committing it to a version control system | LL | if let Some(n) = n.checked_sub(4) { n } else { n } | ~~~~~~~~~~~~~~~~ -error: `dbg!` macro is intended as a debugging tool +error: the `dbg!` macro is intended as a debugging tool --> $DIR/dbg_macro.rs:9:8 | LL | if dbg!(n <= 1) { | ^^^^^^^^^^^^ | -help: ensure to avoid having uses of it in version control +help: remove the invocation before committing it to a version control system | LL | if n <= 1 { | ~~~~~~ -error: `dbg!` macro is intended as a debugging tool +error: the `dbg!` macro is intended as a debugging tool --> $DIR/dbg_macro.rs:10:9 | LL | dbg!(1) | ^^^^^^^ | -help: ensure to avoid having uses of it in version control +help: remove the invocation before committing it to a version control system | LL | 1 | -error: `dbg!` macro is intended as a debugging tool +error: the `dbg!` macro is intended as a debugging tool --> $DIR/dbg_macro.rs:12:9 | LL | dbg!(n * factorial(n - 1)) | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | -help: ensure to avoid having uses of it in version control +help: remove the invocation before committing it to a version control system | LL | n * factorial(n - 1) | -error: `dbg!` macro is intended as a debugging tool +error: the `dbg!` macro is intended as a debugging tool --> $DIR/dbg_macro.rs:17:5 | LL | dbg!(42); | ^^^^^^^^ | -help: ensure to avoid having uses of it in version control +help: remove the invocation before committing it to a version control system | LL | 42; | ~~ -error: `dbg!` macro is intended as a debugging tool +error: the `dbg!` macro is intended as a debugging tool --> $DIR/dbg_macro.rs:18:5 | LL | dbg!(dbg!(dbg!(42))); | ^^^^^^^^^^^^^^^^^^^^ | -help: ensure to avoid having uses of it in version control +help: remove the invocation before committing it to a version control system | LL | dbg!(dbg!(42)); | ~~~~~~~~~~~~~~ -error: `dbg!` macro is intended as a debugging tool +error: the `dbg!` macro is intended as a debugging tool --> $DIR/dbg_macro.rs:19:14 | LL | foo(3) + dbg!(factorial(4)); | ^^^^^^^^^^^^^^^^^^ | -help: ensure to avoid having uses of it in version control +help: remove the invocation before committing it to a version control system | LL | foo(3) + factorial(4); | ~~~~~~~~~~~~ -error: `dbg!` macro is intended as a debugging tool +error: the `dbg!` macro is intended as a debugging tool --> $DIR/dbg_macro.rs:20:5 | LL | dbg!(1, 2, dbg!(3, 4)); | ^^^^^^^^^^^^^^^^^^^^^^ | -help: ensure to avoid having uses of it in version control +help: remove the invocation before committing it to a version control system | LL | (1, 2, dbg!(3, 4)); | ~~~~~~~~~~~~~~~~~~ -error: `dbg!` macro is intended as a debugging tool +error: the `dbg!` macro is intended as a debugging tool --> $DIR/dbg_macro.rs:21:5 | LL | dbg!(1, 2, 3, 4, 5); | ^^^^^^^^^^^^^^^^^^^ | -help: ensure to avoid having uses of it in version control +help: remove the invocation before committing it to a version control system | LL | (1, 2, 3, 4, 5); | ~~~~~~~~~~~~~~~ -error: `dbg!` macro is intended as a debugging tool +error: the `dbg!` macro is intended as a debugging tool --> $DIR/dbg_macro.rs:41:9 | LL | dbg!(2); | ^^^^^^^ | -help: ensure to avoid having uses of it in version control +help: remove the invocation before committing it to a version control system | LL | 2; | ~ -error: `dbg!` macro is intended as a debugging tool +error: the `dbg!` macro is intended as a debugging tool --> $DIR/dbg_macro.rs:47:5 | LL | dbg!(1); | ^^^^^^^ | -help: ensure to avoid having uses of it in version control +help: remove the invocation before committing it to a version control system | LL | 1; | ~ -error: `dbg!` macro is intended as a debugging tool +error: the `dbg!` macro is intended as a debugging tool --> $DIR/dbg_macro.rs:52:5 | LL | dbg!(1); | ^^^^^^^ | -help: ensure to avoid having uses of it in version control +help: remove the invocation before committing it to a version control system | LL | 1; | ~ -error: `dbg!` macro is intended as a debugging tool +error: the `dbg!` macro is intended as a debugging tool --> $DIR/dbg_macro.rs:58:9 | LL | dbg!(1); | ^^^^^^^ | -help: ensure to avoid having uses of it in version control +help: remove the invocation before committing it to a version control system | LL | 1; | ~ diff --git a/src/tools/clippy/tests/ui/def_id_nocore.rs b/src/tools/clippy/tests/ui/def_id_nocore.rs index a7da8f89aa3..1af77d1a25b 100644 --- a/src/tools/clippy/tests/ui/def_id_nocore.rs +++ b/src/tools/clippy/tests/ui/def_id_nocore.rs @@ -15,7 +15,7 @@ pub trait Copy {} pub unsafe trait Freeze {} #[lang = "start"] -fn start<T>(_main: fn() -> T, _argc: isize, _argv: *const *const u8) -> isize { +fn start<T>(_main: fn() -> T, _argc: isize, _argv: *const *const u8, _sigpipe: u8) -> isize { 0 } diff --git a/src/tools/clippy/tests/ui/default_trait_access.fixed b/src/tools/clippy/tests/ui/default_trait_access.fixed index eedd4361939..5640599d48a 100644 --- a/src/tools/clippy/tests/ui/default_trait_access.fixed +++ b/src/tools/clippy/tests/ui/default_trait_access.fixed @@ -12,17 +12,17 @@ use std::default::Default as D2; use std::string; fn main() { - let s1: String = std::string::String::default(); + let s1: String = String::default(); let s2 = String::default(); - let s3: String = std::string::String::default(); + let s3: String = String::default(); - let s4: String = std::string::String::default(); + let s4: String = String::default(); let s5 = string::String::default(); - let s6: String = std::string::String::default(); + let s6: String = String::default(); let s7 = std::string::String::default(); diff --git a/src/tools/clippy/tests/ui/default_trait_access.stderr b/src/tools/clippy/tests/ui/default_trait_access.stderr index 49b2dde3f1e..e4f73c08d19 100644 --- a/src/tools/clippy/tests/ui/default_trait_access.stderr +++ b/src/tools/clippy/tests/ui/default_trait_access.stderr @@ -1,8 +1,8 @@ -error: calling `std::string::String::default()` is more clear than this expression +error: calling `String::default()` is more clear than this expression --> $DIR/default_trait_access.rs:15:22 | LL | let s1: String = Default::default(); - | ^^^^^^^^^^^^^^^^^^ help: try: `std::string::String::default()` + | ^^^^^^^^^^^^^^^^^^ help: try: `String::default()` | note: the lint level is defined here --> $DIR/default_trait_access.rs:3:9 @@ -10,23 +10,23 @@ note: the lint level is defined here LL | #![deny(clippy::default_trait_access)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: calling `std::string::String::default()` is more clear than this expression +error: calling `String::default()` is more clear than this expression --> $DIR/default_trait_access.rs:19:22 | LL | let s3: String = D2::default(); - | ^^^^^^^^^^^^^ help: try: `std::string::String::default()` + | ^^^^^^^^^^^^^ help: try: `String::default()` -error: calling `std::string::String::default()` is more clear than this expression +error: calling `String::default()` is more clear than this expression --> $DIR/default_trait_access.rs:21:22 | LL | let s4: String = std::default::Default::default(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::string::String::default()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `String::default()` -error: calling `std::string::String::default()` is more clear than this expression +error: calling `String::default()` is more clear than this expression --> $DIR/default_trait_access.rs:25:22 | LL | let s6: String = default::Default::default(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::string::String::default()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `String::default()` error: calling `GenericDerivedDefault::default()` is more clear than this expression --> $DIR/default_trait_access.rs:35:46 diff --git a/src/tools/clippy/tests/ui/derivable_impls.fixed b/src/tools/clippy/tests/ui/derivable_impls.fixed index 7dcdfb0937e..ee8456f5deb 100644 --- a/src/tools/clippy/tests/ui/derivable_impls.fixed +++ b/src/tools/clippy/tests/ui/derivable_impls.fixed @@ -210,4 +210,25 @@ impl Default for IntOrString { } } +#[derive(Default)] +pub enum SimpleEnum { + Foo, + #[default] + Bar, +} + + + +pub enum NonExhaustiveEnum { + Foo, + #[non_exhaustive] + Bar, +} + +impl Default for NonExhaustiveEnum { + fn default() -> Self { + NonExhaustiveEnum::Bar + } +} + fn main() {} diff --git a/src/tools/clippy/tests/ui/derivable_impls.rs b/src/tools/clippy/tests/ui/derivable_impls.rs index 625cbcdde23..14af419bcad 100644 --- a/src/tools/clippy/tests/ui/derivable_impls.rs +++ b/src/tools/clippy/tests/ui/derivable_impls.rs @@ -244,4 +244,27 @@ impl Default for IntOrString { } } +pub enum SimpleEnum { + Foo, + Bar, +} + +impl Default for SimpleEnum { + fn default() -> Self { + SimpleEnum::Bar + } +} + +pub enum NonExhaustiveEnum { + Foo, + #[non_exhaustive] + Bar, +} + +impl Default for NonExhaustiveEnum { + fn default() -> Self { + NonExhaustiveEnum::Bar + } +} + fn main() {} diff --git a/src/tools/clippy/tests/ui/derivable_impls.stderr b/src/tools/clippy/tests/ui/derivable_impls.stderr index c1db5a58b1f..81963c3be5b 100644 --- a/src/tools/clippy/tests/ui/derivable_impls.stderr +++ b/src/tools/clippy/tests/ui/derivable_impls.stderr @@ -113,5 +113,26 @@ help: ...and instead derive it LL | #[derive(Default)] | -error: aborting due to 7 previous errors +error: this `impl` can be derived + --> $DIR/derivable_impls.rs:252:1 + | +LL | / impl Default for SimpleEnum { +LL | | fn default() -> Self { +LL | | SimpleEnum::Bar +LL | | } +LL | | } + | |_^ + | + = help: remove the manual implementation... +help: ...and instead derive it... + | +LL | #[derive(Default)] + | +help: ...and mark the default variant + | +LL ~ #[default] +LL ~ Bar, + | + +error: aborting due to 8 previous errors diff --git a/src/tools/clippy/tests/ui/derive.rs b/src/tools/clippy/tests/ui/derive.rs index b276c384c04..6e0ce55f57d 100644 --- a/src/tools/clippy/tests/ui/derive.rs +++ b/src/tools/clippy/tests/ui/derive.rs @@ -86,4 +86,15 @@ impl<T: Clone, U> Clone for GenericRef<'_, T, U> { } } +// https://github.com/rust-lang/rust-clippy/issues/10188 +#[repr(packed)] +#[derive(Copy)] +struct Packed<T>(T); + +impl<T: Copy> Clone for Packed<T> { + fn clone(&self) -> Self { + *self + } +} + fn main() {} diff --git a/src/tools/clippy/tests/ui/derive_hash_xor_eq.stderr b/src/tools/clippy/tests/ui/derive_hash_xor_eq.stderr deleted file mode 100644 index 16c92397804..00000000000 --- a/src/tools/clippy/tests/ui/derive_hash_xor_eq.stderr +++ /dev/null @@ -1,59 +0,0 @@ -error: you are deriving `Hash` but have implemented `PartialEq` explicitly - --> $DIR/derive_hash_xor_eq.rs:12:10 - | -LL | #[derive(Hash)] - | ^^^^ - | -note: `PartialEq` implemented here - --> $DIR/derive_hash_xor_eq.rs:15:1 - | -LL | impl PartialEq for Bar { - | ^^^^^^^^^^^^^^^^^^^^^^ - = note: `#[deny(clippy::derive_hash_xor_eq)]` on by default - = note: this error originates in the derive macro `Hash` (in Nightly builds, run with -Z macro-backtrace for more info) - -error: you are deriving `Hash` but have implemented `PartialEq` explicitly - --> $DIR/derive_hash_xor_eq.rs:21:10 - | -LL | #[derive(Hash)] - | ^^^^ - | -note: `PartialEq` implemented here - --> $DIR/derive_hash_xor_eq.rs:24:1 - | -LL | impl PartialEq<Baz> for Baz { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: this error originates in the derive macro `Hash` (in Nightly builds, run with -Z macro-backtrace for more info) - -error: you are implementing `Hash` explicitly but have derived `PartialEq` - --> $DIR/derive_hash_xor_eq.rs:33:1 - | -LL | / impl std::hash::Hash for Bah { -LL | | fn hash<H: std::hash::Hasher>(&self, _: &mut H) {} -LL | | } - | |_^ - | -note: `PartialEq` implemented here - --> $DIR/derive_hash_xor_eq.rs:30:10 - | -LL | #[derive(PartialEq)] - | ^^^^^^^^^ - = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info) - -error: you are implementing `Hash` explicitly but have derived `PartialEq` - --> $DIR/derive_hash_xor_eq.rs:51:5 - | -LL | / impl Hash for Foo3 { -LL | | fn hash<H: std::hash::Hasher>(&self, _: &mut H) {} -LL | | } - | |_____^ - | -note: `PartialEq` implemented here - --> $DIR/derive_hash_xor_eq.rs:48:14 - | -LL | #[derive(PartialEq)] - | ^^^^^^^^^ - = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info) - -error: aborting due to 4 previous errors - diff --git a/src/tools/clippy/tests/ui/derive_hash_xor_eq.rs b/src/tools/clippy/tests/ui/derived_hash_with_manual_eq.rs index 813ddc56646..8ad09a8de43 100644 --- a/src/tools/clippy/tests/ui/derive_hash_xor_eq.rs +++ b/src/tools/clippy/tests/ui/derived_hash_with_manual_eq.rs @@ -27,6 +27,8 @@ impl PartialEq<Baz> for Baz { } } +// Implementing `Hash` with a derived `PartialEq` is fine. See #2627 + #[derive(PartialEq)] struct Bah; @@ -34,23 +36,4 @@ impl std::hash::Hash for Bah { fn hash<H: std::hash::Hasher>(&self, _: &mut H) {} } -#[derive(PartialEq)] -struct Foo2; - -trait Hash {} - -// We don't want to lint on user-defined traits called `Hash` -impl Hash for Foo2 {} - -mod use_hash { - use std::hash::{Hash, Hasher}; - - #[derive(PartialEq)] - struct Foo3; - - impl Hash for Foo3 { - fn hash<H: std::hash::Hasher>(&self, _: &mut H) {} - } -} - fn main() {} diff --git a/src/tools/clippy/tests/ui/derived_hash_with_manual_eq.stderr b/src/tools/clippy/tests/ui/derived_hash_with_manual_eq.stderr new file mode 100644 index 00000000000..230940f25fb --- /dev/null +++ b/src/tools/clippy/tests/ui/derived_hash_with_manual_eq.stderr @@ -0,0 +1,29 @@ +error: you are deriving `Hash` but have implemented `PartialEq` explicitly + --> $DIR/derived_hash_with_manual_eq.rs:12:10 + | +LL | #[derive(Hash)] + | ^^^^ + | +note: `PartialEq` implemented here + --> $DIR/derived_hash_with_manual_eq.rs:15:1 + | +LL | impl PartialEq for Bar { + | ^^^^^^^^^^^^^^^^^^^^^^ + = note: `#[deny(clippy::derived_hash_with_manual_eq)]` on by default + = note: this error originates in the derive macro `Hash` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: you are deriving `Hash` but have implemented `PartialEq` explicitly + --> $DIR/derived_hash_with_manual_eq.rs:21:10 + | +LL | #[derive(Hash)] + | ^^^^ + | +note: `PartialEq` implemented here + --> $DIR/derived_hash_with_manual_eq.rs:24:1 + | +LL | impl PartialEq<Baz> for Baz { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: this error originates in the derive macro `Hash` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 2 previous errors + diff --git a/src/tools/clippy/tests/ui/drop_ref.rs b/src/tools/clippy/tests/ui/drop_ref.rs index 7de0b0bbdf9..10044e65f11 100644 --- a/src/tools/clippy/tests/ui/drop_ref.rs +++ b/src/tools/clippy/tests/ui/drop_ref.rs @@ -72,3 +72,26 @@ fn test_owl_result_2() -> Result<u8, ()> { produce_half_owl_ok().map(drop)?; Ok(1) } + +#[allow(unused)] +#[allow(clippy::unit_cmp)] +fn issue10122(x: u8) { + // This is a function which returns a reference and has a side-effect, which means + // that calling drop() on the function is considered an idiomatic way of achieving the side-effect + // in a match arm. + fn println_and<T>(t: &T) -> &T { + println!("foo"); + t + } + + match x { + 0 => drop(println_and(&12)), // Don't lint (copy type), we only care about side-effects + 1 => drop(println_and(&String::new())), // Don't lint (no copy type), we only care about side-effects + 2 => { + drop(println_and(&13)); // Lint, even if we only care about the side-effect, it's already in a block + }, + 3 if drop(println_and(&14)) == () => (), // Lint, idiomatic use is only in body of `Arm` + 4 => drop(&2), // Lint, not a fn/method call + _ => (), + } +} diff --git a/src/tools/clippy/tests/ui/drop_ref.stderr b/src/tools/clippy/tests/ui/drop_ref.stderr index 4743cf79b5d..293b9f6de83 100644 --- a/src/tools/clippy/tests/ui/drop_ref.stderr +++ b/src/tools/clippy/tests/ui/drop_ref.stderr @@ -107,5 +107,41 @@ note: argument has type `&SomeStruct` LL | std::mem::drop(&SomeStruct); | ^^^^^^^^^^^ -error: aborting due to 9 previous errors +error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing + --> $DIR/drop_ref.rs:91:13 + | +LL | drop(println_and(&13)); // Lint, even if we only care about the side-effect, it's already in a block + | ^^^^^^^^^^^^^^^^^^^^^^ + | +note: argument has type `&i32` + --> $DIR/drop_ref.rs:91:18 + | +LL | drop(println_and(&13)); // Lint, even if we only care about the side-effect, it's already in a block + | ^^^^^^^^^^^^^^^^ + +error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing + --> $DIR/drop_ref.rs:93:14 + | +LL | 3 if drop(println_and(&14)) == () => (), // Lint, idiomatic use is only in body of `Arm` + | ^^^^^^^^^^^^^^^^^^^^^^ + | +note: argument has type `&i32` + --> $DIR/drop_ref.rs:93:19 + | +LL | 3 if drop(println_and(&14)) == () => (), // Lint, idiomatic use is only in body of `Arm` + | ^^^^^^^^^^^^^^^^ + +error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing + --> $DIR/drop_ref.rs:94:14 + | +LL | 4 => drop(&2), // Lint, not a fn/method call + | ^^^^^^^^ + | +note: argument has type `&i32` + --> $DIR/drop_ref.rs:94:19 + | +LL | 4 => drop(&2), // Lint, not a fn/method call + | ^^ + +error: aborting due to 12 previous errors diff --git a/src/tools/clippy/tests/ui/field_reassign_with_default.rs b/src/tools/clippy/tests/ui/field_reassign_with_default.rs index 7367910eaa1..1f989bb1220 100644 --- a/src/tools/clippy/tests/ui/field_reassign_with_default.rs +++ b/src/tools/clippy/tests/ui/field_reassign_with_default.rs @@ -247,3 +247,24 @@ mod issue6312 { } } } + +struct Collection { + items: Vec<i32>, + len: usize, +} + +impl Default for Collection { + fn default() -> Self { + Self { + items: vec![1, 2, 3], + len: 0, + } + } +} + +#[allow(clippy::redundant_closure_call)] +fn issue10136() { + let mut c = Collection::default(); + // don't lint, since c.items was used to calculate this value + c.len = (|| c.items.len())(); +} diff --git a/src/tools/clippy/tests/ui/iter_kv_map.fixed b/src/tools/clippy/tests/ui/iter_kv_map.fixed index 83fee04080f..f2a4c284cb1 100644 --- a/src/tools/clippy/tests/ui/iter_kv_map.fixed +++ b/src/tools/clippy/tests/ui/iter_kv_map.fixed @@ -1,14 +1,15 @@ // run-rustfix #![warn(clippy::iter_kv_map)] -#![allow(clippy::redundant_clone)] -#![allow(clippy::suspicious_map)] -#![allow(clippy::map_identity)] +#![allow(unused_mut, clippy::redundant_clone, clippy::suspicious_map, clippy::map_identity)] use std::collections::{BTreeMap, HashMap}; fn main() { let get_key = |(key, _val)| key; + fn ref_acceptor(v: &u32) -> u32 { + *v + } let map: HashMap<u32, u32> = HashMap::new(); @@ -36,6 +37,20 @@ fn main() { let _ = map.keys().map(|key| key * 9).count(); let _ = map.values().map(|value| value * 17).count(); + // Preserve the ref in the fix. + let _ = map.clone().into_values().map(|ref val| ref_acceptor(val)).count(); + + // Preserve the mut in the fix. + let _ = map + .clone().into_values().map(|mut val| { + val += 2; + val + }) + .count(); + + // Don't let a mut interfere. + let _ = map.clone().into_values().count(); + let map: BTreeMap<u32, u32> = BTreeMap::new(); let _ = map.keys().collect::<Vec<_>>(); @@ -61,4 +76,18 @@ fn main() { // Lint let _ = map.keys().map(|key| key * 9).count(); let _ = map.values().map(|value| value * 17).count(); + + // Preserve the ref in the fix. + let _ = map.clone().into_values().map(|ref val| ref_acceptor(val)).count(); + + // Preserve the mut in the fix. + let _ = map + .clone().into_values().map(|mut val| { + val += 2; + val + }) + .count(); + + // Don't let a mut interfere. + let _ = map.clone().into_values().count(); } diff --git a/src/tools/clippy/tests/ui/iter_kv_map.rs b/src/tools/clippy/tests/ui/iter_kv_map.rs index 7a1f1fb0198..ad6564df408 100644 --- a/src/tools/clippy/tests/ui/iter_kv_map.rs +++ b/src/tools/clippy/tests/ui/iter_kv_map.rs @@ -1,14 +1,15 @@ // run-rustfix #![warn(clippy::iter_kv_map)] -#![allow(clippy::redundant_clone)] -#![allow(clippy::suspicious_map)] -#![allow(clippy::map_identity)] +#![allow(unused_mut, clippy::redundant_clone, clippy::suspicious_map, clippy::map_identity)] use std::collections::{BTreeMap, HashMap}; fn main() { let get_key = |(key, _val)| key; + fn ref_acceptor(v: &u32) -> u32 { + *v + } let map: HashMap<u32, u32> = HashMap::new(); @@ -36,6 +37,22 @@ fn main() { let _ = map.iter().map(|(key, _value)| key * 9).count(); let _ = map.iter().map(|(_key, value)| value * 17).count(); + // Preserve the ref in the fix. + let _ = map.clone().into_iter().map(|(_, ref val)| ref_acceptor(val)).count(); + + // Preserve the mut in the fix. + let _ = map + .clone() + .into_iter() + .map(|(_, mut val)| { + val += 2; + val + }) + .count(); + + // Don't let a mut interfere. + let _ = map.clone().into_iter().map(|(_, mut val)| val).count(); + let map: BTreeMap<u32, u32> = BTreeMap::new(); let _ = map.iter().map(|(key, _)| key).collect::<Vec<_>>(); @@ -61,4 +78,20 @@ fn main() { // Lint let _ = map.iter().map(|(key, _value)| key * 9).count(); let _ = map.iter().map(|(_key, value)| value * 17).count(); + + // Preserve the ref in the fix. + let _ = map.clone().into_iter().map(|(_, ref val)| ref_acceptor(val)).count(); + + // Preserve the mut in the fix. + let _ = map + .clone() + .into_iter() + .map(|(_, mut val)| { + val += 2; + val + }) + .count(); + + // Don't let a mut interfere. + let _ = map.clone().into_iter().map(|(_, mut val)| val).count(); } diff --git a/src/tools/clippy/tests/ui/iter_kv_map.stderr b/src/tools/clippy/tests/ui/iter_kv_map.stderr index 9b9b04c97d8..e00da223b4d 100644 --- a/src/tools/clippy/tests/ui/iter_kv_map.stderr +++ b/src/tools/clippy/tests/ui/iter_kv_map.stderr @@ -1,5 +1,5 @@ error: iterating on a map's keys - --> $DIR/iter_kv_map.rs:15:13 + --> $DIR/iter_kv_map.rs:16:13 | LL | let _ = map.iter().map(|(key, _)| key).collect::<Vec<_>>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.keys()` @@ -7,130 +7,198 @@ LL | let _ = map.iter().map(|(key, _)| key).collect::<Vec<_>>(); = note: `-D clippy::iter-kv-map` implied by `-D warnings` error: iterating on a map's values - --> $DIR/iter_kv_map.rs:16:13 + --> $DIR/iter_kv_map.rs:17:13 | LL | let _ = map.iter().map(|(_, value)| value).collect::<Vec<_>>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values()` error: iterating on a map's values - --> $DIR/iter_kv_map.rs:17:13 + --> $DIR/iter_kv_map.rs:18:13 | LL | let _ = map.iter().map(|(_, v)| v + 2).collect::<Vec<_>>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values().map(|v| v + 2)` error: iterating on a map's keys - --> $DIR/iter_kv_map.rs:19:13 + --> $DIR/iter_kv_map.rs:20:13 | LL | let _ = map.clone().into_iter().map(|(key, _)| key).collect::<Vec<_>>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_keys()` error: iterating on a map's keys - --> $DIR/iter_kv_map.rs:20:13 + --> $DIR/iter_kv_map.rs:21:13 | LL | let _ = map.clone().into_iter().map(|(key, _)| key + 2).collect::<Vec<_>>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_keys().map(|key| key + 2)` error: iterating on a map's values - --> $DIR/iter_kv_map.rs:22:13 + --> $DIR/iter_kv_map.rs:23:13 | LL | let _ = map.clone().into_iter().map(|(_, val)| val).collect::<Vec<_>>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_values()` error: iterating on a map's values - --> $DIR/iter_kv_map.rs:23:13 + --> $DIR/iter_kv_map.rs:24:13 | LL | let _ = map.clone().into_iter().map(|(_, val)| val + 2).collect::<Vec<_>>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_values().map(|val| val + 2)` error: iterating on a map's values - --> $DIR/iter_kv_map.rs:25:13 + --> $DIR/iter_kv_map.rs:26:13 | LL | let _ = map.clone().iter().map(|(_, val)| val).collect::<Vec<_>>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().values()` error: iterating on a map's keys - --> $DIR/iter_kv_map.rs:26:13 + --> $DIR/iter_kv_map.rs:27:13 | LL | let _ = map.iter().map(|(key, _)| key).filter(|x| *x % 2 == 0).count(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.keys()` error: iterating on a map's keys - --> $DIR/iter_kv_map.rs:36:13 + --> $DIR/iter_kv_map.rs:37:13 | LL | let _ = map.iter().map(|(key, _value)| key * 9).count(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.keys().map(|key| key * 9)` error: iterating on a map's values - --> $DIR/iter_kv_map.rs:37:13 + --> $DIR/iter_kv_map.rs:38:13 | LL | let _ = map.iter().map(|(_key, value)| value * 17).count(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values().map(|value| value * 17)` -error: iterating on a map's keys +error: iterating on a map's values --> $DIR/iter_kv_map.rs:41:13 | +LL | let _ = map.clone().into_iter().map(|(_, ref val)| ref_acceptor(val)).count(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_values().map(|ref val| ref_acceptor(val))` + +error: iterating on a map's values + --> $DIR/iter_kv_map.rs:44:13 + | +LL | let _ = map + | _____________^ +LL | | .clone() +LL | | .into_iter() +LL | | .map(|(_, mut val)| { +LL | | val += 2; +LL | | val +LL | | }) + | |__________^ + | +help: try + | +LL ~ let _ = map +LL + .clone().into_values().map(|mut val| { +LL + val += 2; +LL + val +LL + }) + | + +error: iterating on a map's values + --> $DIR/iter_kv_map.rs:54:13 + | +LL | let _ = map.clone().into_iter().map(|(_, mut val)| val).count(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_values()` + +error: iterating on a map's keys + --> $DIR/iter_kv_map.rs:58:13 + | LL | let _ = map.iter().map(|(key, _)| key).collect::<Vec<_>>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.keys()` error: iterating on a map's values - --> $DIR/iter_kv_map.rs:42:13 + --> $DIR/iter_kv_map.rs:59:13 | LL | let _ = map.iter().map(|(_, value)| value).collect::<Vec<_>>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values()` error: iterating on a map's values - --> $DIR/iter_kv_map.rs:43:13 + --> $DIR/iter_kv_map.rs:60:13 | LL | let _ = map.iter().map(|(_, v)| v + 2).collect::<Vec<_>>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values().map(|v| v + 2)` error: iterating on a map's keys - --> $DIR/iter_kv_map.rs:45:13 + --> $DIR/iter_kv_map.rs:62:13 | LL | let _ = map.clone().into_iter().map(|(key, _)| key).collect::<Vec<_>>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_keys()` error: iterating on a map's keys - --> $DIR/iter_kv_map.rs:46:13 + --> $DIR/iter_kv_map.rs:63:13 | LL | let _ = map.clone().into_iter().map(|(key, _)| key + 2).collect::<Vec<_>>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_keys().map(|key| key + 2)` error: iterating on a map's values - --> $DIR/iter_kv_map.rs:48:13 + --> $DIR/iter_kv_map.rs:65:13 | LL | let _ = map.clone().into_iter().map(|(_, val)| val).collect::<Vec<_>>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_values()` error: iterating on a map's values - --> $DIR/iter_kv_map.rs:49:13 + --> $DIR/iter_kv_map.rs:66:13 | LL | let _ = map.clone().into_iter().map(|(_, val)| val + 2).collect::<Vec<_>>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_values().map(|val| val + 2)` error: iterating on a map's values - --> $DIR/iter_kv_map.rs:51:13 + --> $DIR/iter_kv_map.rs:68:13 | LL | let _ = map.clone().iter().map(|(_, val)| val).collect::<Vec<_>>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().values()` error: iterating on a map's keys - --> $DIR/iter_kv_map.rs:52:13 + --> $DIR/iter_kv_map.rs:69:13 | LL | let _ = map.iter().map(|(key, _)| key).filter(|x| *x % 2 == 0).count(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.keys()` error: iterating on a map's keys - --> $DIR/iter_kv_map.rs:62:13 + --> $DIR/iter_kv_map.rs:79:13 | LL | let _ = map.iter().map(|(key, _value)| key * 9).count(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.keys().map(|key| key * 9)` error: iterating on a map's values - --> $DIR/iter_kv_map.rs:63:13 + --> $DIR/iter_kv_map.rs:80:13 | LL | let _ = map.iter().map(|(_key, value)| value * 17).count(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values().map(|value| value * 17)` -error: aborting due to 22 previous errors +error: iterating on a map's values + --> $DIR/iter_kv_map.rs:83:13 + | +LL | let _ = map.clone().into_iter().map(|(_, ref val)| ref_acceptor(val)).count(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_values().map(|ref val| ref_acceptor(val))` + +error: iterating on a map's values + --> $DIR/iter_kv_map.rs:86:13 + | +LL | let _ = map + | _____________^ +LL | | .clone() +LL | | .into_iter() +LL | | .map(|(_, mut val)| { +LL | | val += 2; +LL | | val +LL | | }) + | |__________^ + | +help: try + | +LL ~ let _ = map +LL + .clone().into_values().map(|mut val| { +LL + val += 2; +LL + val +LL + }) + | + +error: iterating on a map's values + --> $DIR/iter_kv_map.rs:96:13 + | +LL | let _ = map.clone().into_iter().map(|(_, mut val)| val).count(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_values()` + +error: aborting due to 28 previous errors diff --git a/src/tools/clippy/tests/ui/needless_borrow.fixed b/src/tools/clippy/tests/ui/needless_borrow.fixed index 31e1cb6c3d7..4cb7f6b687f 100644 --- a/src/tools/clippy/tests/ui/needless_borrow.fixed +++ b/src/tools/clippy/tests/ui/needless_borrow.fixed @@ -1,5 +1,5 @@ // run-rustfix -#![feature(custom_inner_attributes, lint_reasons, rustc_private)] +#![feature(lint_reasons)] #![allow( unused, clippy::uninlined_format_args, @@ -491,14 +491,3 @@ mod issue_9782_method_variant { S.foo::<&[u8; 100]>(&a); } } - -extern crate rustc_lint; -extern crate rustc_span; - -#[allow(dead_code)] -mod span_lint { - use rustc_lint::{LateContext, Lint, LintContext}; - fn foo(cx: &LateContext<'_>, lint: &'static Lint) { - cx.struct_span_lint(lint, rustc_span::Span::default(), "", |diag| diag.note(String::new())); - } -} diff --git a/src/tools/clippy/tests/ui/needless_borrow.rs b/src/tools/clippy/tests/ui/needless_borrow.rs index 55c2738fcf2..9a01190ed8d 100644 --- a/src/tools/clippy/tests/ui/needless_borrow.rs +++ b/src/tools/clippy/tests/ui/needless_borrow.rs @@ -1,5 +1,5 @@ // run-rustfix -#![feature(custom_inner_attributes, lint_reasons, rustc_private)] +#![feature(lint_reasons)] #![allow( unused, clippy::uninlined_format_args, @@ -491,14 +491,3 @@ mod issue_9782_method_variant { S.foo::<&[u8; 100]>(&a); } } - -extern crate rustc_lint; -extern crate rustc_span; - -#[allow(dead_code)] -mod span_lint { - use rustc_lint::{LateContext, Lint, LintContext}; - fn foo(cx: &LateContext<'_>, lint: &'static Lint) { - cx.struct_span_lint(lint, rustc_span::Span::default(), "", |diag| diag.note(&String::new())); - } -} diff --git a/src/tools/clippy/tests/ui/needless_borrow.stderr b/src/tools/clippy/tests/ui/needless_borrow.stderr index 98a48d68317..d26c317124b 100644 --- a/src/tools/clippy/tests/ui/needless_borrow.stderr +++ b/src/tools/clippy/tests/ui/needless_borrow.stderr @@ -216,11 +216,5 @@ error: the borrowed expression implements the required traits LL | foo(&a); | ^^ help: change this to: `a` -error: the borrowed expression implements the required traits - --> $DIR/needless_borrow.rs:502:85 - | -LL | cx.struct_span_lint(lint, rustc_span::Span::default(), "", |diag| diag.note(&String::new())); - | ^^^^^^^^^^^^^^ help: change this to: `String::new()` - -error: aborting due to 37 previous errors +error: aborting due to 36 previous errors diff --git a/src/tools/clippy/tests/ui/needless_return.fixed b/src/tools/clippy/tests/ui/needless_return.fixed index d451be1f389..ab1c0e590bb 100644 --- a/src/tools/clippy/tests/ui/needless_return.fixed +++ b/src/tools/clippy/tests/ui/needless_return.fixed @@ -277,4 +277,14 @@ fn issue9947() -> Result<(), String> { do yeet "hello"; } +// without anyhow, but triggers the same bug I believe +#[expect(clippy::useless_format)] +fn issue10051() -> Result<String, String> { + if true { + Ok(format!("ok!")) + } else { + Err(format!("err!")) + } +} + fn main() {} diff --git a/src/tools/clippy/tests/ui/needless_return.rs b/src/tools/clippy/tests/ui/needless_return.rs index e1a1bea2c0b..abed338bb9b 100644 --- a/src/tools/clippy/tests/ui/needless_return.rs +++ b/src/tools/clippy/tests/ui/needless_return.rs @@ -287,4 +287,14 @@ fn issue9947() -> Result<(), String> { do yeet "hello"; } +// without anyhow, but triggers the same bug I believe +#[expect(clippy::useless_format)] +fn issue10051() -> Result<String, String> { + if true { + return Ok(format!("ok!")); + } else { + return Err(format!("err!")); + } +} + fn main() {} diff --git a/src/tools/clippy/tests/ui/needless_return.stderr b/src/tools/clippy/tests/ui/needless_return.stderr index ca2253e6586..52eabf6e137 100644 --- a/src/tools/clippy/tests/ui/needless_return.stderr +++ b/src/tools/clippy/tests/ui/needless_return.stderr @@ -386,5 +386,21 @@ LL | let _ = 42; return; | = help: remove `return` -error: aborting due to 46 previous errors +error: unneeded `return` statement + --> $DIR/needless_return.rs:294:9 + | +LL | return Ok(format!("ok!")); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: remove `return` + +error: unneeded `return` statement + --> $DIR/needless_return.rs:296:9 + | +LL | return Err(format!("err!")); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: remove `return` + +error: aborting due to 48 previous errors diff --git a/src/tools/clippy/tests/ui/redundant_clone.fixed b/src/tools/clippy/tests/ui/redundant_clone.fixed index a157b6a6f9a..00b42745093 100644 --- a/src/tools/clippy/tests/ui/redundant_clone.fixed +++ b/src/tools/clippy/tests/ui/redundant_clone.fixed @@ -239,9 +239,3 @@ fn false_negative_5707() { let _z = x.clone(); // pr 7346 can't lint on `x` drop(y); } - -#[allow(unused, clippy::manual_retain)] -fn possible_borrower_improvements() { - let mut s = String::from("foobar"); - s = s.chars().filter(|&c| c != 'o').collect(); -} diff --git a/src/tools/clippy/tests/ui/redundant_clone.rs b/src/tools/clippy/tests/ui/redundant_clone.rs index 430672e8b8d..f899127db8d 100644 --- a/src/tools/clippy/tests/ui/redundant_clone.rs +++ b/src/tools/clippy/tests/ui/redundant_clone.rs @@ -239,9 +239,3 @@ fn false_negative_5707() { let _z = x.clone(); // pr 7346 can't lint on `x` drop(y); } - -#[allow(unused, clippy::manual_retain)] -fn possible_borrower_improvements() { - let mut s = String::from("foobar"); - s = s.chars().filter(|&c| c != 'o').to_owned().collect(); -} diff --git a/src/tools/clippy/tests/ui/redundant_clone.stderr b/src/tools/clippy/tests/ui/redundant_clone.stderr index 1bacc2c76af..782590034d0 100644 --- a/src/tools/clippy/tests/ui/redundant_clone.stderr +++ b/src/tools/clippy/tests/ui/redundant_clone.stderr @@ -179,17 +179,5 @@ note: this value is dropped without further use LL | foo(&x.clone(), move || { | ^ -error: redundant clone - --> $DIR/redundant_clone.rs:246:40 - | -LL | s = s.chars().filter(|&c| c != 'o').to_owned().collect(); - | ^^^^^^^^^^^ help: remove this - | -note: this value is dropped without further use - --> $DIR/redundant_clone.rs:246:9 - | -LL | s = s.chars().filter(|&c| c != 'o').to_owned().collect(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 16 previous errors +error: aborting due to 15 previous errors diff --git a/src/tools/clippy/tests/ui/rename.fixed b/src/tools/clippy/tests/ui/rename.fixed index 2f76b575296..5076f61334d 100644 --- a/src/tools/clippy/tests/ui/rename.fixed +++ b/src/tools/clippy/tests/ui/rename.fixed @@ -10,6 +10,7 @@ #![allow(clippy::box_collection)] #![allow(clippy::redundant_static_lifetimes)] #![allow(clippy::cognitive_complexity)] +#![allow(clippy::derived_hash_with_manual_eq)] #![allow(clippy::disallowed_methods)] #![allow(clippy::disallowed_types)] #![allow(clippy::mixed_read_write_in_expression)] @@ -45,6 +46,7 @@ #![warn(clippy::box_collection)] #![warn(clippy::redundant_static_lifetimes)] #![warn(clippy::cognitive_complexity)] +#![warn(clippy::derived_hash_with_manual_eq)] #![warn(clippy::disallowed_methods)] #![warn(clippy::disallowed_types)] #![warn(clippy::mixed_read_write_in_expression)] diff --git a/src/tools/clippy/tests/ui/rename.rs b/src/tools/clippy/tests/ui/rename.rs index 699c0ff464e..64bc1ca7116 100644 --- a/src/tools/clippy/tests/ui/rename.rs +++ b/src/tools/clippy/tests/ui/rename.rs @@ -10,6 +10,7 @@ #![allow(clippy::box_collection)] #![allow(clippy::redundant_static_lifetimes)] #![allow(clippy::cognitive_complexity)] +#![allow(clippy::derived_hash_with_manual_eq)] #![allow(clippy::disallowed_methods)] #![allow(clippy::disallowed_types)] #![allow(clippy::mixed_read_write_in_expression)] @@ -45,6 +46,7 @@ #![warn(clippy::box_vec)] #![warn(clippy::const_static_lifetime)] #![warn(clippy::cyclomatic_complexity)] +#![warn(clippy::derive_hash_xor_eq)] #![warn(clippy::disallowed_method)] #![warn(clippy::disallowed_type)] #![warn(clippy::eval_order_dependence)] diff --git a/src/tools/clippy/tests/ui/rename.stderr b/src/tools/clippy/tests/ui/rename.stderr index 9af58dc75a6..27a0263292e 100644 --- a/src/tools/clippy/tests/ui/rename.stderr +++ b/src/tools/clippy/tests/ui/rename.stderr @@ -1,5 +1,5 @@ error: lint `clippy::almost_complete_letter_range` has been renamed to `clippy::almost_complete_range` - --> $DIR/rename.rs:41:9 + --> $DIR/rename.rs:42:9 | LL | #![warn(clippy::almost_complete_letter_range)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::almost_complete_range` @@ -7,244 +7,250 @@ LL | #![warn(clippy::almost_complete_letter_range)] = note: `-D renamed-and-removed-lints` implied by `-D warnings` error: lint `clippy::blacklisted_name` has been renamed to `clippy::disallowed_names` - --> $DIR/rename.rs:42:9 + --> $DIR/rename.rs:43:9 | LL | #![warn(clippy::blacklisted_name)] | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_names` error: lint `clippy::block_in_if_condition_expr` has been renamed to `clippy::blocks_in_if_conditions` - --> $DIR/rename.rs:43:9 + --> $DIR/rename.rs:44:9 | LL | #![warn(clippy::block_in_if_condition_expr)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_if_conditions` error: lint `clippy::block_in_if_condition_stmt` has been renamed to `clippy::blocks_in_if_conditions` - --> $DIR/rename.rs:44:9 + --> $DIR/rename.rs:45:9 | LL | #![warn(clippy::block_in_if_condition_stmt)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_if_conditions` error: lint `clippy::box_vec` has been renamed to `clippy::box_collection` - --> $DIR/rename.rs:45:9 + --> $DIR/rename.rs:46:9 | LL | #![warn(clippy::box_vec)] | ^^^^^^^^^^^^^^^ help: use the new name: `clippy::box_collection` error: lint `clippy::const_static_lifetime` has been renamed to `clippy::redundant_static_lifetimes` - --> $DIR/rename.rs:46:9 + --> $DIR/rename.rs:47:9 | LL | #![warn(clippy::const_static_lifetime)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::redundant_static_lifetimes` error: lint `clippy::cyclomatic_complexity` has been renamed to `clippy::cognitive_complexity` - --> $DIR/rename.rs:47:9 + --> $DIR/rename.rs:48:9 | LL | #![warn(clippy::cyclomatic_complexity)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::cognitive_complexity` +error: lint `clippy::derive_hash_xor_eq` has been renamed to `clippy::derived_hash_with_manual_eq` + --> $DIR/rename.rs:49:9 + | +LL | #![warn(clippy::derive_hash_xor_eq)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::derived_hash_with_manual_eq` + error: lint `clippy::disallowed_method` has been renamed to `clippy::disallowed_methods` - --> $DIR/rename.rs:48:9 + --> $DIR/rename.rs:50:9 | LL | #![warn(clippy::disallowed_method)] | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_methods` error: lint `clippy::disallowed_type` has been renamed to `clippy::disallowed_types` - --> $DIR/rename.rs:49:9 + --> $DIR/rename.rs:51:9 | LL | #![warn(clippy::disallowed_type)] | ^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_types` error: lint `clippy::eval_order_dependence` has been renamed to `clippy::mixed_read_write_in_expression` - --> $DIR/rename.rs:50:9 + --> $DIR/rename.rs:52:9 | LL | #![warn(clippy::eval_order_dependence)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::mixed_read_write_in_expression` error: lint `clippy::identity_conversion` has been renamed to `clippy::useless_conversion` - --> $DIR/rename.rs:51:9 + --> $DIR/rename.rs:53:9 | LL | #![warn(clippy::identity_conversion)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::useless_conversion` error: lint `clippy::if_let_some_result` has been renamed to `clippy::match_result_ok` - --> $DIR/rename.rs:52:9 + --> $DIR/rename.rs:54:9 | LL | #![warn(clippy::if_let_some_result)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::match_result_ok` error: lint `clippy::logic_bug` has been renamed to `clippy::overly_complex_bool_expr` - --> $DIR/rename.rs:53:9 + --> $DIR/rename.rs:55:9 | LL | #![warn(clippy::logic_bug)] | ^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::overly_complex_bool_expr` error: lint `clippy::new_without_default_derive` has been renamed to `clippy::new_without_default` - --> $DIR/rename.rs:54:9 + --> $DIR/rename.rs:56:9 | LL | #![warn(clippy::new_without_default_derive)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::new_without_default` error: lint `clippy::option_and_then_some` has been renamed to `clippy::bind_instead_of_map` - --> $DIR/rename.rs:55:9 + --> $DIR/rename.rs:57:9 | LL | #![warn(clippy::option_and_then_some)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::bind_instead_of_map` error: lint `clippy::option_expect_used` has been renamed to `clippy::expect_used` - --> $DIR/rename.rs:56:9 + --> $DIR/rename.rs:58:9 | LL | #![warn(clippy::option_expect_used)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used` error: lint `clippy::option_map_unwrap_or` has been renamed to `clippy::map_unwrap_or` - --> $DIR/rename.rs:57:9 + --> $DIR/rename.rs:59:9 | LL | #![warn(clippy::option_map_unwrap_or)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or` error: lint `clippy::option_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or` - --> $DIR/rename.rs:58:9 + --> $DIR/rename.rs:60:9 | LL | #![warn(clippy::option_map_unwrap_or_else)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or` error: lint `clippy::option_unwrap_used` has been renamed to `clippy::unwrap_used` - --> $DIR/rename.rs:59:9 + --> $DIR/rename.rs:61:9 | LL | #![warn(clippy::option_unwrap_used)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used` error: lint `clippy::ref_in_deref` has been renamed to `clippy::needless_borrow` - --> $DIR/rename.rs:60:9 + --> $DIR/rename.rs:62:9 | LL | #![warn(clippy::ref_in_deref)] | ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::needless_borrow` error: lint `clippy::result_expect_used` has been renamed to `clippy::expect_used` - --> $DIR/rename.rs:61:9 + --> $DIR/rename.rs:63:9 | LL | #![warn(clippy::result_expect_used)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used` error: lint `clippy::result_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or` - --> $DIR/rename.rs:62:9 + --> $DIR/rename.rs:64:9 | LL | #![warn(clippy::result_map_unwrap_or_else)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or` error: lint `clippy::result_unwrap_used` has been renamed to `clippy::unwrap_used` - --> $DIR/rename.rs:63:9 + --> $DIR/rename.rs:65:9 | LL | #![warn(clippy::result_unwrap_used)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used` error: lint `clippy::single_char_push_str` has been renamed to `clippy::single_char_add_str` - --> $DIR/rename.rs:64:9 + --> $DIR/rename.rs:66:9 | LL | #![warn(clippy::single_char_push_str)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::single_char_add_str` error: lint `clippy::stutter` has been renamed to `clippy::module_name_repetitions` - --> $DIR/rename.rs:65:9 + --> $DIR/rename.rs:67:9 | LL | #![warn(clippy::stutter)] | ^^^^^^^^^^^^^^^ help: use the new name: `clippy::module_name_repetitions` error: lint `clippy::to_string_in_display` has been renamed to `clippy::recursive_format_impl` - --> $DIR/rename.rs:66:9 + --> $DIR/rename.rs:68:9 | LL | #![warn(clippy::to_string_in_display)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::recursive_format_impl` error: lint `clippy::zero_width_space` has been renamed to `clippy::invisible_characters` - --> $DIR/rename.rs:67:9 + --> $DIR/rename.rs:69:9 | LL | #![warn(clippy::zero_width_space)] | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::invisible_characters` error: lint `clippy::drop_bounds` has been renamed to `drop_bounds` - --> $DIR/rename.rs:68:9 + --> $DIR/rename.rs:70:9 | LL | #![warn(clippy::drop_bounds)] | ^^^^^^^^^^^^^^^^^^^ help: use the new name: `drop_bounds` error: lint `clippy::for_loop_over_option` has been renamed to `for_loops_over_fallibles` - --> $DIR/rename.rs:69:9 + --> $DIR/rename.rs:71:9 | LL | #![warn(clippy::for_loop_over_option)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles` error: lint `clippy::for_loop_over_result` has been renamed to `for_loops_over_fallibles` - --> $DIR/rename.rs:70:9 + --> $DIR/rename.rs:72:9 | LL | #![warn(clippy::for_loop_over_result)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles` error: lint `clippy::for_loops_over_fallibles` has been renamed to `for_loops_over_fallibles` - --> $DIR/rename.rs:71:9 + --> $DIR/rename.rs:73:9 | LL | #![warn(clippy::for_loops_over_fallibles)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles` error: lint `clippy::into_iter_on_array` has been renamed to `array_into_iter` - --> $DIR/rename.rs:72:9 + --> $DIR/rename.rs:74:9 | LL | #![warn(clippy::into_iter_on_array)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `array_into_iter` error: lint `clippy::invalid_atomic_ordering` has been renamed to `invalid_atomic_ordering` - --> $DIR/rename.rs:73:9 + --> $DIR/rename.rs:75:9 | LL | #![warn(clippy::invalid_atomic_ordering)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_atomic_ordering` error: lint `clippy::invalid_ref` has been renamed to `invalid_value` - --> $DIR/rename.rs:74:9 + --> $DIR/rename.rs:76:9 | LL | #![warn(clippy::invalid_ref)] | ^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_value` error: lint `clippy::let_underscore_drop` has been renamed to `let_underscore_drop` - --> $DIR/rename.rs:75:9 + --> $DIR/rename.rs:77:9 | LL | #![warn(clippy::let_underscore_drop)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `let_underscore_drop` error: lint `clippy::mem_discriminant_non_enum` has been renamed to `enum_intrinsics_non_enums` - --> $DIR/rename.rs:76:9 + --> $DIR/rename.rs:78:9 | LL | #![warn(clippy::mem_discriminant_non_enum)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `enum_intrinsics_non_enums` error: lint `clippy::panic_params` has been renamed to `non_fmt_panics` - --> $DIR/rename.rs:77:9 + --> $DIR/rename.rs:79:9 | LL | #![warn(clippy::panic_params)] | ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `non_fmt_panics` error: lint `clippy::positional_named_format_parameters` has been renamed to `named_arguments_used_positionally` - --> $DIR/rename.rs:78:9 + --> $DIR/rename.rs:80:9 | LL | #![warn(clippy::positional_named_format_parameters)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `named_arguments_used_positionally` error: lint `clippy::temporary_cstring_as_ptr` has been renamed to `temporary_cstring_as_ptr` - --> $DIR/rename.rs:79:9 + --> $DIR/rename.rs:81:9 | LL | #![warn(clippy::temporary_cstring_as_ptr)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `temporary_cstring_as_ptr` error: lint `clippy::unknown_clippy_lints` has been renamed to `unknown_lints` - --> $DIR/rename.rs:80:9 + --> $DIR/rename.rs:82:9 | LL | #![warn(clippy::unknown_clippy_lints)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unknown_lints` error: lint `clippy::unused_label` has been renamed to `unused_labels` - --> $DIR/rename.rs:81:9 + --> $DIR/rename.rs:83:9 | LL | #![warn(clippy::unused_label)] | ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unused_labels` -error: aborting due to 41 previous errors +error: aborting due to 42 previous errors diff --git a/src/tools/clippy/tests/ui/single_element_loop.fixed b/src/tools/clippy/tests/ui/single_element_loop.fixed index 63d31ff83f9..a0dcc0172e8 100644 --- a/src/tools/clippy/tests/ui/single_element_loop.fixed +++ b/src/tools/clippy/tests/ui/single_element_loop.fixed @@ -33,4 +33,31 @@ fn main() { let item = 0..5; dbg!(item); } + + // should not lint (issue #10018) + for e in [42] { + if e > 0 { + continue; + } + } + + // should not lint (issue #10018) + for e in [42] { + if e > 0 { + break; + } + } + + // should lint (issue #10018) + { + let _ = 42; + let _f = |n: u32| { + for i in 0..n { + if i > 10 { + dbg!(i); + break; + } + } + }; + } } diff --git a/src/tools/clippy/tests/ui/single_element_loop.rs b/src/tools/clippy/tests/ui/single_element_loop.rs index 2cda5a329d2..bc014035c98 100644 --- a/src/tools/clippy/tests/ui/single_element_loop.rs +++ b/src/tools/clippy/tests/ui/single_element_loop.rs @@ -27,4 +27,30 @@ fn main() { for item in [0..5].into_iter() { dbg!(item); } + + // should not lint (issue #10018) + for e in [42] { + if e > 0 { + continue; + } + } + + // should not lint (issue #10018) + for e in [42] { + if e > 0 { + break; + } + } + + // should lint (issue #10018) + for _ in [42] { + let _f = |n: u32| { + for i in 0..n { + if i > 10 { + dbg!(i); + break; + } + } + }; + } } diff --git a/src/tools/clippy/tests/ui/single_element_loop.stderr b/src/tools/clippy/tests/ui/single_element_loop.stderr index 0aeb8da1a2e..14437a59745 100644 --- a/src/tools/clippy/tests/ui/single_element_loop.stderr +++ b/src/tools/clippy/tests/ui/single_element_loop.stderr @@ -95,5 +95,32 @@ LL + dbg!(item); LL + } | -error: aborting due to 6 previous errors +error: for loop over a single element + --> $DIR/single_element_loop.rs:46:5 + | +LL | / for _ in [42] { +LL | | let _f = |n: u32| { +LL | | for i in 0..n { +LL | | if i > 10 { +... | +LL | | }; +LL | | } + | |_____^ + | +help: try + | +LL ~ { +LL + let _ = 42; +LL + let _f = |n: u32| { +LL + for i in 0..n { +LL + if i > 10 { +LL + dbg!(i); +LL + break; +LL + } +LL + } +LL + }; +LL + } + | + +error: aborting due to 7 previous errors diff --git a/src/tools/clippy/tests/ui/suspicious_to_owned.stderr b/src/tools/clippy/tests/ui/suspicious_to_owned.stderr index ae1aec34d82..dec3f50d6f1 100644 --- a/src/tools/clippy/tests/ui/suspicious_to_owned.stderr +++ b/src/tools/clippy/tests/ui/suspicious_to_owned.stderr @@ -1,4 +1,4 @@ -error: this `to_owned` call clones the std::borrow::Cow<'_, str> itself and does not cause the std::borrow::Cow<'_, str> contents to become owned +error: this `to_owned` call clones the Cow<'_, str> itself and does not cause the Cow<'_, str> contents to become owned --> $DIR/suspicious_to_owned.rs:16:13 | LL | let _ = cow.to_owned(); @@ -6,19 +6,19 @@ LL | let _ = cow.to_owned(); | = note: `-D clippy::suspicious-to-owned` implied by `-D warnings` -error: this `to_owned` call clones the std::borrow::Cow<'_, [char; 3]> itself and does not cause the std::borrow::Cow<'_, [char; 3]> contents to become owned +error: this `to_owned` call clones the Cow<'_, [char; 3]> itself and does not cause the Cow<'_, [char; 3]> contents to become owned --> $DIR/suspicious_to_owned.rs:26:13 | LL | let _ = cow.to_owned(); | ^^^^^^^^^^^^^^ help: consider using, depending on intent: `cow.clone()` or `cow.into_owned()` -error: this `to_owned` call clones the std::borrow::Cow<'_, std::vec::Vec<char>> itself and does not cause the std::borrow::Cow<'_, std::vec::Vec<char>> contents to become owned +error: this `to_owned` call clones the Cow<'_, Vec<char>> itself and does not cause the Cow<'_, Vec<char>> contents to become owned --> $DIR/suspicious_to_owned.rs:36:13 | LL | let _ = cow.to_owned(); | ^^^^^^^^^^^^^^ help: consider using, depending on intent: `cow.clone()` or `cow.into_owned()` -error: this `to_owned` call clones the std::borrow::Cow<'_, str> itself and does not cause the std::borrow::Cow<'_, str> contents to become owned +error: this `to_owned` call clones the Cow<'_, str> itself and does not cause the Cow<'_, str> contents to become owned --> $DIR/suspicious_to_owned.rs:46:13 | LL | let _ = cow.to_owned(); diff --git a/src/tools/clippy/tests/ui/unnecessary_clone.stderr b/src/tools/clippy/tests/ui/unnecessary_clone.stderr index 94cc7777aca..6022d9fa4c5 100644 --- a/src/tools/clippy/tests/ui/unnecessary_clone.stderr +++ b/src/tools/clippy/tests/ui/unnecessary_clone.stderr @@ -38,13 +38,13 @@ LL | t.clone(); | = note: `-D clippy::clone-on-copy` implied by `-D warnings` -error: using `clone` on type `std::option::Option<T>` which implements the `Copy` trait +error: using `clone` on type `Option<T>` which implements the `Copy` trait --> $DIR/unnecessary_clone.rs:42:5 | LL | Some(t).clone(); | ^^^^^^^^^^^^^^^ help: try removing the `clone` call: `Some(t)` -error: using `clone` on a double-reference; this will copy the reference of type `&std::vec::Vec<i32>` instead of cloning the inner type +error: using `clone` on a double-reference; this will copy the reference of type `&Vec<i32>` instead of cloning the inner type --> $DIR/unnecessary_clone.rs:48:22 | LL | let z: &Vec<_> = y.clone(); @@ -57,10 +57,10 @@ LL | let z: &Vec<_> = &(*y).clone(); | ~~~~~~~~~~~~~ help: or try being explicit if you are sure, that you want to clone a reference | -LL | let z: &Vec<_> = <&std::vec::Vec<i32>>::clone(y); - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +LL | let z: &Vec<_> = <&Vec<i32>>::clone(y); + | ~~~~~~~~~~~~~~~~~~~~~ -error: using `clone` on type `many_derefs::E` which implements the `Copy` trait +error: using `clone` on type `E` which implements the `Copy` trait --> $DIR/unnecessary_clone.rs:84:20 | LL | let _: E = a.clone(); diff --git a/src/tools/clippy/tests/ui/unused_self.rs b/src/tools/clippy/tests/ui/unused_self.rs index 92e8e1dba69..55bd5607185 100644 --- a/src/tools/clippy/tests/ui/unused_self.rs +++ b/src/tools/clippy/tests/ui/unused_self.rs @@ -60,6 +60,16 @@ mod unused_self_allow { // shouldn't trigger for public methods pub fn unused_self_move(self) {} } + + pub struct E; + + impl E { + // shouldn't trigger if body contains todo!() + pub fn unused_self_todo(self) { + let x = 42; + todo!() + } + } } pub use unused_self_allow::D; diff --git a/src/tools/clippy/tests/ui/unused_self.stderr b/src/tools/clippy/tests/ui/unused_self.stderr index 23186122a9a..919f9b6efda 100644 --- a/src/tools/clippy/tests/ui/unused_self.stderr +++ b/src/tools/clippy/tests/ui/unused_self.stderr @@ -4,7 +4,7 @@ error: unused `self` argument LL | fn unused_self_move(self) {} | ^^^^ | - = help: consider refactoring to a associated function + = help: consider refactoring to an associated function = note: `-D clippy::unused-self` implied by `-D warnings` error: unused `self` argument @@ -13,7 +13,7 @@ error: unused `self` argument LL | fn unused_self_ref(&self) {} | ^^^^^ | - = help: consider refactoring to a associated function + = help: consider refactoring to an associated function error: unused `self` argument --> $DIR/unused_self.rs:13:32 @@ -21,7 +21,7 @@ error: unused `self` argument LL | fn unused_self_mut_ref(&mut self) {} | ^^^^^^^^^ | - = help: consider refactoring to a associated function + = help: consider refactoring to an associated function error: unused `self` argument --> $DIR/unused_self.rs:14:32 @@ -29,7 +29,7 @@ error: unused `self` argument LL | fn unused_self_pin_ref(self: Pin<&Self>) {} | ^^^^ | - = help: consider refactoring to a associated function + = help: consider refactoring to an associated function error: unused `self` argument --> $DIR/unused_self.rs:15:36 @@ -37,7 +37,7 @@ error: unused `self` argument LL | fn unused_self_pin_mut_ref(self: Pin<&mut Self>) {} | ^^^^ | - = help: consider refactoring to a associated function + = help: consider refactoring to an associated function error: unused `self` argument --> $DIR/unused_self.rs:16:35 @@ -45,7 +45,7 @@ error: unused `self` argument LL | fn unused_self_pin_nested(self: Pin<Arc<Self>>) {} | ^^^^ | - = help: consider refactoring to a associated function + = help: consider refactoring to an associated function error: unused `self` argument --> $DIR/unused_self.rs:17:28 @@ -53,7 +53,7 @@ error: unused `self` argument LL | fn unused_self_box(self: Box<Self>) {} | ^^^^ | - = help: consider refactoring to a associated function + = help: consider refactoring to an associated function error: unused `self` argument --> $DIR/unused_self.rs:18:40 @@ -61,7 +61,7 @@ error: unused `self` argument LL | fn unused_with_other_used_args(&self, x: u8, y: u8) -> u8 { | ^^^^^ | - = help: consider refactoring to a associated function + = help: consider refactoring to an associated function error: unused `self` argument --> $DIR/unused_self.rs:21:37 @@ -69,7 +69,7 @@ error: unused `self` argument LL | fn unused_self_class_method(&self) { | ^^^^^ | - = help: consider refactoring to a associated function + = help: consider refactoring to an associated function error: aborting due to 9 previous errors diff --git a/src/tools/miri/src/bin/miri.rs b/src/tools/miri/src/bin/miri.rs index 8c01748613c..6a147de3be2 100644 --- a/src/tools/miri/src/bin/miri.rs +++ b/src/tools/miri/src/bin/miri.rs @@ -61,7 +61,7 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { ) -> Compilation { compiler.session().abort_if_errors(); - queries.global_ctxt().unwrap().peek_mut().enter(|tcx| { + queries.global_ctxt().unwrap().enter(|tcx| { init_late_loggers(tcx); if !tcx.sess.crate_types().contains(&CrateType::Executable) { tcx.sess.fatal("miri only makes sense on bin crates"); diff --git a/src/tools/rustfmt/src/closures.rs b/src/tools/rustfmt/src/closures.rs index 244d4427c56..8fd0fcf8f5c 100644 --- a/src/tools/rustfmt/src/closures.rs +++ b/src/tools/rustfmt/src/closures.rs @@ -26,6 +26,7 @@ use crate::utils::{last_line_width, left_most_sub_expr, stmt_expr, NodeIdExt}; pub(crate) fn rewrite_closure( binder: &ast::ClosureBinder, + constness: ast::Const, capture: ast::CaptureBy, is_async: &ast::Async, movability: ast::Movability, @@ -38,7 +39,7 @@ pub(crate) fn rewrite_closure( debug!("rewrite_closure {:?}", body); let (prefix, extra_offset) = rewrite_closure_fn_decl( - binder, capture, is_async, movability, fn_decl, body, span, context, shape, + binder, constness, capture, is_async, movability, fn_decl, body, span, context, shape, )?; // 1 = space between `|...|` and body. let body_shape = shape.offset_left(extra_offset)?; @@ -230,6 +231,7 @@ fn rewrite_closure_block( // Return type is (prefix, extra_offset) fn rewrite_closure_fn_decl( binder: &ast::ClosureBinder, + constness: ast::Const, capture: ast::CaptureBy, asyncness: &ast::Async, movability: ast::Movability, @@ -250,6 +252,12 @@ fn rewrite_closure_fn_decl( ast::ClosureBinder::NotPresent => "".to_owned(), }; + let const_ = if matches!(constness, ast::Const::Yes(_)) { + "const " + } else { + "" + }; + let immovable = if movability == ast::Movability::Static { "static " } else { @@ -264,7 +272,7 @@ fn rewrite_closure_fn_decl( // 4 = "|| {".len(), which is overconservative when the closure consists of // a single expression. let nested_shape = shape - .shrink_left(binder.len() + immovable.len() + is_async.len() + mover.len())? + .shrink_left(binder.len() + const_.len() + immovable.len() + is_async.len() + mover.len())? .sub_width(4)?; // 1 = | @@ -302,7 +310,10 @@ fn rewrite_closure_fn_decl( .tactic(tactic) .preserve_newline(true); let list_str = write_list(&item_vec, &fmt)?; - let mut prefix = format!("{}{}{}{}|{}|", binder, immovable, is_async, mover, list_str); + let mut prefix = format!( + "{}{}{}{}{}|{}|", + binder, const_, immovable, is_async, mover, list_str + ); if !ret_str.is_empty() { if prefix.contains('\n') { @@ -329,6 +340,7 @@ pub(crate) fn rewrite_last_closure( if let ast::ExprKind::Closure(ref closure) = expr.kind { let ast::Closure { ref binder, + constness, capture_clause, ref asyncness, movability, @@ -349,6 +361,7 @@ pub(crate) fn rewrite_last_closure( }; let (prefix, extra_offset) = rewrite_closure_fn_decl( binder, + constness, capture_clause, asyncness, movability, diff --git a/src/tools/rustfmt/src/expr.rs b/src/tools/rustfmt/src/expr.rs index 414e767690b..868ff045ab7 100644 --- a/src/tools/rustfmt/src/expr.rs +++ b/src/tools/rustfmt/src/expr.rs @@ -205,6 +205,7 @@ pub(crate) fn format_expr( } ast::ExprKind::Closure(ref cl) => closures::rewrite_closure( &cl.binder, + cl.constness, cl.capture_clause, &cl.asyncness, cl.movability, diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index 29501d2d3b6..845eb5af0d6 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -217,7 +217,7 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[ "serde", "serde_derive", "serde_json", - "sha-1", + "sha1", "sha2", "sharded-slab", "smallvec", diff --git a/src/tools/tidy/src/error_codes.rs b/src/tools/tidy/src/error_codes.rs index ac8b5f6834c..bc9fd35ecde 100644 --- a/src/tools/tidy/src/error_codes.rs +++ b/src/tools/tidy/src/error_codes.rs @@ -31,10 +31,8 @@ const IGNORE_DOCTEST_CHECK: &[&str] = &["E0208", "E0464", "E0570", "E0601", "E0602", "E0640", "E0717"]; // Error codes that don't yet have a UI test. This list will eventually be removed. -const IGNORE_UI_TEST_CHECK: &[&str] = &[ - "E0461", "E0465", "E0476", "E0490", "E0514", "E0523", "E0554", "E0640", "E0717", "E0729", - "E0789", -]; +const IGNORE_UI_TEST_CHECK: &[&str] = + &["E0461", "E0465", "E0476", "E0514", "E0523", "E0554", "E0640", "E0717", "E0729", "E0789"]; macro_rules! verbose_print { ($verbose:expr, $($fmt:tt)*) => { diff --git a/tests/codegen/abi-efiapi.rs b/tests/codegen/abi-efiapi.rs index 9061d7432a3..9502ebf59af 100644 --- a/tests/codegen/abi-efiapi.rs +++ b/tests/codegen/abi-efiapi.rs @@ -14,7 +14,7 @@ // compile-flags: -C no-prepopulate-passes #![crate_type = "lib"] -#![feature(no_core, lang_items, abi_efiapi)] +#![feature(no_core, lang_items)] #![no_core] #[lang="sized"] diff --git a/tests/run-make-fulldeps/obtain-borrowck/driver.rs b/tests/run-make-fulldeps/obtain-borrowck/driver.rs index a6c60df83a6..9cd504f004d 100644 --- a/tests/run-make-fulldeps/obtain-borrowck/driver.rs +++ b/tests/run-make-fulldeps/obtain-borrowck/driver.rs @@ -62,7 +62,7 @@ impl rustc_driver::Callbacks for CompilerCalls { queries: &'tcx Queries<'tcx>, ) -> Compilation { compiler.session().abort_if_errors(); - queries.global_ctxt().unwrap().peek_mut().enter(|tcx| { + queries.global_ctxt().unwrap().enter(|tcx| { // Collect definition ids of MIR bodies. let hir = tcx.hir(); let mut bodies = Vec::new(); diff --git a/tests/run-make-fulldeps/target-specs/foo.rs b/tests/run-make-fulldeps/target-specs/foo.rs index d576a1dd281..22939e87912 100644 --- a/tests/run-make-fulldeps/target-specs/foo.rs +++ b/tests/run-make-fulldeps/target-specs/foo.rs @@ -11,7 +11,7 @@ trait Sized {} auto trait Freeze {} #[lang = "start"] -fn start<T>(_main: fn() -> T, _argc: isize, _argv: *const *const u8) -> isize { +fn start<T>(_main: fn() -> T, _argc: isize, _argv: *const *const u8, _sigpipe: u8) -> isize { 0 } diff --git a/tests/rustdoc-gui/method-margins.goml b/tests/rustdoc-gui/method-margins.goml index ed36bcdec17..720268a9e7e 100644 --- a/tests/rustdoc-gui/method-margins.goml +++ b/tests/rustdoc-gui/method-margins.goml @@ -1,18 +1,18 @@ // This test ensures that the margins on methods are coherent inside an impl block. goto: "file://" + |DOC_PATH| + "/test_docs/trait_members/struct.HasTrait.html#impl-TraitMembers-for-HasTrait" -assert-count: ("#trait-implementations-list > .rustdoc-toggle", 1) +assert-count: ("#trait-implementations-list > .toggle", 1) compare-elements-css: ( // compare margin on type with margin on method - "#trait-implementations-list .impl-items > .rustdoc-toggle:nth-child(1) > summary", - "#trait-implementations-list .impl-items > .rustdoc-toggle:nth-child(2) > summary", + "#trait-implementations-list .impl-items > .toggle:nth-child(1) > summary", + "#trait-implementations-list .impl-items > .toggle:nth-child(2) > summary", ["margin"] ) compare-elements-css: ( // compare margin on type with margin on method - "#trait-implementations-list .impl-items > .rustdoc-toggle:nth-child(1)", - "#trait-implementations-list .impl-items > .rustdoc-toggle:nth-child(2)", + "#trait-implementations-list .impl-items > .toggle:nth-child(1)", + "#trait-implementations-list .impl-items > .toggle:nth-child(2)", ["margin"] ) diff --git a/tests/rustdoc-gui/settings.goml b/tests/rustdoc-gui/settings.goml index fc3beaa53fa..f236dc3e0fe 100644 --- a/tests/rustdoc-gui/settings.goml +++ b/tests/rustdoc-gui/settings.goml @@ -159,7 +159,7 @@ assert-text: ("#preferred-light-theme .setting-name", "Preferred light theme") // We now check that clicking on the toggles' text is like clicking on the checkbox. // To test it, we use the "Disable keyboard shortcuts". local-storage: {"rustdoc-disable-shortcuts": "false"} -click: ".setting-line:last-child .toggle .label" +click: ".setting-line:last-child .settings-toggle .label" assert-local-storage: {"rustdoc-disable-shortcuts": "true"} // Make sure that "Disable keyboard shortcuts" actually took effect. @@ -169,7 +169,7 @@ assert-false: "#help-button .popover" wait-for-css: ("#settings-menu .popover", {"display": "block"}) // Now turn keyboard shortcuts back on, and see if they work. -click: ".setting-line:last-child .toggle .label" +click: ".setting-line:last-child .settings-toggle .label" assert-local-storage: {"rustdoc-disable-shortcuts": "false"} press-key: "Escape" press-key: "?" diff --git a/tests/rustdoc-gui/toggle-click-deadspace.goml b/tests/rustdoc-gui/toggle-click-deadspace.goml index 029403ee13e..689e562f730 100644 --- a/tests/rustdoc-gui/toggle-click-deadspace.goml +++ b/tests/rustdoc-gui/toggle-click-deadspace.goml @@ -1,14 +1,14 @@ // This test ensures that clicking on a method summary, but not on the "[-]", // doesn't toggle the <details>. goto: "file://" + |DOC_PATH| + "/lib2/struct.Foo.html" -assert-attribute: (".impl-items .rustdoc-toggle", {"open": ""}) +assert-attribute: (".impl-items .toggle", {"open": ""}) click: "h4.code-header" // This is the position of "pub" in "pub fn a_method" -assert-attribute: (".impl-items .rustdoc-toggle", {"open": ""}) +assert-attribute: (".impl-items .toggle", {"open": ""}) click-with-offset: ( - ".impl-items .rustdoc-toggle summary", + ".impl-items .toggle summary", {"x": -24, "y": 8}, // This is the position of "[-]" next to that pub fn. ) -assert-attribute-false: (".impl-items .rustdoc-toggle", {"open": ""}) +assert-attribute-false: (".impl-items .toggle", {"open": ""}) // Click the "Trait" part of "impl Trait" and verify it navigates. click: "#impl-Trait-for-Foo h3 a:first-of-type" diff --git a/tests/rustdoc-gui/toggle-docs.goml b/tests/rustdoc-gui/toggle-docs.goml index 89ce78e3aab..c9d236e9bba 100644 --- a/tests/rustdoc-gui/toggle-docs.goml +++ b/tests/rustdoc-gui/toggle-docs.goml @@ -20,10 +20,10 @@ assert-text: ("#toggle-all-docs", "[−]") goto: "file://" + |DOC_PATH| + "/test_docs/struct.Foo.html" // We first check that everything is visible. assert-text: ("#toggle-all-docs", "[−]") -assert-attribute: ("#implementations-list details.rustdoc-toggle", {"open": ""}, ALL) -assert-attribute: ("#trait-implementations-list details.rustdoc-toggle", {"open": ""}, ALL) +assert-attribute: ("#implementations-list details.toggle", {"open": ""}, ALL) +assert-attribute: ("#trait-implementations-list details.toggle", {"open": ""}, ALL) assert-attribute-false: ( - "#blanket-implementations-list > details.rustdoc-toggle", + "#blanket-implementations-list > details.toggle", {"open": ""}, ALL, ) @@ -32,18 +32,18 @@ assert-attribute-false: ( click: "#toggle-all-docs" wait-for-text: ("#toggle-all-docs", "[+]") // We check that all <details> are collapsed (except for the impl block ones). -assert-attribute-false: ("details.rustdoc-toggle:not(.implementors-toggle)", {"open": ""}, ALL) +assert-attribute-false: ("details.toggle:not(.implementors-toggle)", {"open": ""}, ALL) assert-attribute: ("#implementations-list > details.implementors-toggle", {"open": ""}) // We now check that the other impl blocks are collapsed. assert-attribute-false: ( - "#blanket-implementations-list > details.rustdoc-toggle.implementors-toggle", + "#blanket-implementations-list > details.toggle.implementors-toggle", {"open": ""}, ALL, ) // We open them all again. click: "#toggle-all-docs" wait-for-text: ("#toggle-all-docs", "[−]") -assert-attribute: ("details.rustdoc-toggle", {"open": ""}, ALL) +assert-attribute: ("details.toggle", {"open": ""}, ALL) // Checking the toggles style. show-text: true @@ -56,12 +56,12 @@ define-function: ( // We reload the page so the local storage settings are being used. reload: - assert-css: ("details.rustdoc-toggle > summary::before", { + assert-css: ("details.toggle > summary::before", { "opacity": "0.5", "filter": |filter|, }, ALL) - move-cursor-to: "details.rustdoc-toggle summary" - assert-css: ("details.rustdoc-toggle > summary:hover::before", { + move-cursor-to: "details.toggle summary" + assert-css: ("details.toggle > summary:hover::before", { "opacity": "1", "filter": |filter|, }) diff --git a/tests/rustdoc-gui/toggled-open-implementations.goml b/tests/rustdoc-gui/toggled-open-implementations.goml index e4d59b5d728..000293b555f 100644 --- a/tests/rustdoc-gui/toggled-open-implementations.goml +++ b/tests/rustdoc-gui/toggled-open-implementations.goml @@ -2,4 +2,4 @@ // has all the implementations toggled open by default, so users can // find method names in those implementations with Ctrl-F. goto: "file://" + |DOC_PATH| + "/test_docs/struct.Foo.html" -assert-attribute: (".rustdoc-toggle.implementors-toggle", {"open": ""}) +assert-attribute: (".toggle.implementors-toggle", {"open": ""}) diff --git a/tests/rustdoc-ui/z-help.stdout b/tests/rustdoc-ui/z-help.stdout index 43f30f3d6e8..4bdecdc1b79 100644 --- a/tests/rustdoc-ui/z-help.stdout +++ b/tests/rustdoc-ui/z-help.stdout @@ -76,6 +76,7 @@ -Z llvm-plugins=val -- a list LLVM plugins to enable (space separated) -Z llvm-time-trace=val -- generate JSON tracing data file from LLVM data (default: no) -Z location-detail=val -- what location details should be tracked when using caller_location, either `none`, or a comma separated list of location details, for which valid options are `file`, `line`, and `column` (default: `file,line,column`) + -Z log-backtrace=val -- add a backtrace along with logging -Z ls=val -- list the symbols defined by a library crate (default: no) -Z macro-backtrace=val -- show macro backtraces (default: no) -Z maximal-hir-to-mir-coverage=val -- save as much information as possible about the correspondence between MIR and HIR as source scopes (default: no) diff --git a/tests/rustdoc/const-intrinsic.rs b/tests/rustdoc/const-intrinsic.rs new file mode 100644 index 00000000000..2fc486d01da --- /dev/null +++ b/tests/rustdoc/const-intrinsic.rs @@ -0,0 +1,25 @@ +#![feature(intrinsics)] +#![feature(staged_api)] + +#![crate_name = "foo"] +#![stable(since="1.0.0", feature="rust1")] + +extern "rust-intrinsic" { + // @has 'foo/fn.transmute.html' + // @has - '//pre[@class="rust fn"]' 'pub const unsafe extern "rust-intrinsic" fn transmute<T, U>(_: T) -> U' + #[stable(since="1.0.0", feature="rust1")] + #[rustc_const_stable(feature = "const_transmute", since = "1.56.0")] + pub fn transmute<T, U>(_: T) -> U; + + // @has 'foo/fn.unreachable.html' + // @has - '//pre[@class="rust fn"]' 'pub unsafe extern "rust-intrinsic" fn unreachable() -> !' + #[stable(since="1.0.0", feature="rust1")] + pub fn unreachable() -> !; +} + +extern "C" { + // @has 'foo/fn.needs_drop.html' + // @has - '//pre[@class="rust fn"]' 'pub unsafe extern "C" fn needs_drop() -> !' + #[stable(since="1.0.0", feature="rust1")] + pub fn needs_drop() -> !; +} diff --git a/tests/rustdoc/issue-41783.rs b/tests/rustdoc/issue-41783.rs index 769f984a274..7578d49daa5 100644 --- a/tests/rustdoc/issue-41783.rs +++ b/tests/rustdoc/issue-41783.rs @@ -5,7 +5,7 @@ // @!hasraw - '<span class="attr">#[outer]</span>' // @hasraw - '#![inner]</span>' // @!hasraw - '<span class="attr">#![inner]</span>' -// @snapshot 'codeblock' - '//*[@class="rustdoc-toggle top-doc"]/*[@class="docblock"]//pre/code' +// @snapshot 'codeblock' - '//*[@class="toggle top-doc"]/*[@class="docblock"]//pre/code' /// ```no_run /// # # space diff --git a/tests/rustdoc/local-reexport-doc.rs b/tests/rustdoc/local-reexport-doc.rs index 1c8468008dd..5dc857773a3 100644 --- a/tests/rustdoc/local-reexport-doc.rs +++ b/tests/rustdoc/local-reexport-doc.rs @@ -4,7 +4,7 @@ #![crate_name = "foo"] // @has 'foo/fn.g.html' -// @has - '//*[@class="rustdoc-toggle top-doc"]/*[@class="docblock"]' \ +// @has - '//*[@class="toggle top-doc"]/*[@class="docblock"]' \ // 'outer module inner module' mod inner_mod { diff --git a/tests/rustdoc/mixing-doc-comments-and-attrs.rs b/tests/rustdoc/mixing-doc-comments-and-attrs.rs index a27c5ae6d01..010058361fa 100644 --- a/tests/rustdoc/mixing-doc-comments-and-attrs.rs +++ b/tests/rustdoc/mixing-doc-comments-and-attrs.rs @@ -1,7 +1,7 @@ #![crate_name = "foo"] // @has 'foo/struct.S1.html' -// @snapshot S1_top-doc - '//details[@class="rustdoc-toggle top-doc"]/div[@class="docblock"]' +// @snapshot S1_top-doc - '//details[@class="toggle top-doc"]/div[@class="docblock"]' #[doc = "Hello world!\n\n"] /// Goodbye! @@ -9,7 +9,7 @@ pub struct S1; // @has 'foo/struct.S2.html' -// @snapshot S2_top-doc - '//details[@class="rustdoc-toggle top-doc"]/div[@class="docblock"]' +// @snapshot S2_top-doc - '//details[@class="toggle top-doc"]/div[@class="docblock"]' /// Hello world! /// @@ -18,7 +18,7 @@ pub struct S1; pub struct S2; // @has 'foo/struct.S3.html' -// @snapshot S3_top-doc - '//details[@class="rustdoc-toggle top-doc"]/div[@class="docblock"]' +// @snapshot S3_top-doc - '//details[@class="toggle top-doc"]/div[@class="docblock"]' /** Par 1 */ /// /// Par 2 diff --git a/tests/rustdoc/multiple-import-levels.rs b/tests/rustdoc/multiple-import-levels.rs index 1daae49cde9..29b67c6b2b1 100644 --- a/tests/rustdoc/multiple-import-levels.rs +++ b/tests/rustdoc/multiple-import-levels.rs @@ -21,14 +21,14 @@ mod c { } // @has 'foo/struct.Type.html' -// @has - '//*[@class="rustdoc-toggle top-doc"]/*[@class="docblock"]' 'foo 2 1' +// @has - '//*[@class="toggle top-doc"]/*[@class="docblock"]' 'foo 2 1' /// foo pub use b::Type; // @has 'foo/struct.Whatever.html' -// @has - '//*[@class="rustdoc-toggle top-doc"]/*[@class="docblock"]' 'whatever 3 2 1' +// @has - '//*[@class="toggle top-doc"]/*[@class="docblock"]' 'whatever 3 2 1' /// whatever pub use c::Type as Whatever; // @has 'foo/struct.Woof.html' -// @has - '//*[@class="rustdoc-toggle top-doc"]/*[@class="docblock"]' 'a dog 4 2 1' +// @has - '//*[@class="toggle top-doc"]/*[@class="docblock"]' 'a dog 4 2 1' /// a dog pub use c::Woof; diff --git a/tests/rustdoc/reexport-doc-hidden.rs b/tests/rustdoc/reexport-doc-hidden.rs new file mode 100644 index 00000000000..3ea5fde72f7 --- /dev/null +++ b/tests/rustdoc/reexport-doc-hidden.rs @@ -0,0 +1,26 @@ +// Part of <https://github.com/rust-lang/rust/issues/59368>. +// This test ensures that reexporting a `doc(hidden)` item will +// still show the reexport. + +#![crate_name = "foo"] + +#[doc(hidden)] +pub type Type = u32; + +// @has 'foo/index.html' +// @has - '//*[@id="reexport.Type2"]/code' 'pub use crate::Type as Type2;' +pub use crate::Type as Type2; + +// @count - '//*[@id="reexport.Type3"]' 0 +#[doc(hidden)] +pub use crate::Type as Type3; + +#[macro_export] +#[doc(hidden)] +macro_rules! foo { + () => {}; +} + +// This is a bug: https://github.com/rust-lang/rust/issues/59368 +// @!has - '//*[@id="reexport.Macro"]/code' 'pub use crate::foo as Macro;' +pub use crate::foo as Macro; diff --git a/tests/rustdoc/strip-block-doc-comments-stars.rs b/tests/rustdoc/strip-block-doc-comments-stars.rs index ea28d84f1ff..ca4c93f92e0 100644 --- a/tests/rustdoc/strip-block-doc-comments-stars.rs +++ b/tests/rustdoc/strip-block-doc-comments-stars.rs @@ -4,7 +4,7 @@ // block doc comments can have their lines starting with a star. // @has foo/fn.foo.html -// @snapshot docblock - '//*[@class="rustdoc-toggle top-doc"]//*[@class="docblock"]' +// @snapshot docblock - '//*[@class="toggle top-doc"]//*[@class="docblock"]' /** * a */ diff --git a/tests/rustdoc/toggle-item-contents.rs b/tests/rustdoc/toggle-item-contents.rs index 47a1d62f5a7..87240f233ff 100644 --- a/tests/rustdoc/toggle-item-contents.rs +++ b/tests/rustdoc/toggle-item-contents.rs @@ -1,15 +1,15 @@ #![allow(unused)] // @has 'toggle_item_contents/struct.PubStruct.html' -// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 0 +// @count - '//details[@class="toggle type-contents-toggle"]' 0 pub struct PubStruct { pub a: usize, pub b: usize, } // @has 'toggle_item_contents/struct.BigPubStruct.html' -// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 1 -// @has - '//details[@class="rustdoc-toggle type-contents-toggle"]' 'Show 13 fields' +// @count - '//details[@class="toggle type-contents-toggle"]' 1 +// @has - '//details[@class="toggle type-contents-toggle"]' 'Show 13 fields' pub struct BigPubStruct { pub a: usize, pub b: usize, @@ -27,8 +27,8 @@ pub struct BigPubStruct { } // @has 'toggle_item_contents/union.BigUnion.html' -// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 1 -// @has - '//details[@class="rustdoc-toggle type-contents-toggle"]' 'Show 13 fields' +// @count - '//details[@class="toggle type-contents-toggle"]' 1 +// @has - '//details[@class="toggle type-contents-toggle"]' 'Show 13 fields' pub union BigUnion { pub a: usize, pub b: usize, @@ -46,7 +46,7 @@ pub union BigUnion { } // @has 'toggle_item_contents/union.Union.html' -// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 0 +// @count - '//details[@class="toggle type-contents-toggle"]' 0 pub union Union { pub a: usize, pub b: usize, @@ -54,7 +54,7 @@ pub union Union { } // @has 'toggle_item_contents/struct.PrivStruct.html' -// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 0 +// @count - '//details[@class="toggle type-contents-toggle"]' 0 // @has - '//div[@class="item-decl"]' '/* private fields */' pub struct PrivStruct { a: usize, @@ -62,7 +62,7 @@ pub struct PrivStruct { } // @has 'toggle_item_contents/enum.Enum.html' -// @!has - '//details[@class="rustdoc-toggle type-contents-toggle"]' '' +// @!has - '//details[@class="toggle type-contents-toggle"]' '' pub enum Enum { A, B, C, D { @@ -72,7 +72,7 @@ pub enum Enum { } // @has 'toggle_item_contents/enum.EnumStructVariant.html' -// @!has - '//details[@class="rustdoc-toggle type-contents-toggle"]' '' +// @!has - '//details[@class="toggle type-contents-toggle"]' '' pub enum EnumStructVariant { A, B, C, D { @@ -81,14 +81,14 @@ pub enum EnumStructVariant { } // @has 'toggle_item_contents/enum.LargeEnum.html' -// @count - '//*[@class="rust enum"]//details[@class="rustdoc-toggle type-contents-toggle"]' 1 -// @has - '//*[@class="rust enum"]//details[@class="rustdoc-toggle type-contents-toggle"]' 'Show 13 variants' +// @count - '//*[@class="rust enum"]//details[@class="toggle type-contents-toggle"]' 1 +// @has - '//*[@class="rust enum"]//details[@class="toggle type-contents-toggle"]' 'Show 13 variants' pub enum LargeEnum { A, B, C, D, E, F(u8), G, H, I, J, K, L, M } // @has 'toggle_item_contents/trait.Trait.html' -// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 0 +// @count - '//details[@class="toggle type-contents-toggle"]' 0 pub trait Trait { type A; #[must_use] @@ -97,8 +97,8 @@ pub trait Trait { } // @has 'toggle_item_contents/trait.GinormousTrait.html' -// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 1 -// @has - '//details[@class="rustdoc-toggle type-contents-toggle"]' 'Show 16 associated items' +// @count - '//details[@class="toggle type-contents-toggle"]' 1 +// @has - '//details[@class="toggle type-contents-toggle"]' 'Show 16 associated items' pub trait GinormousTrait { type A; type B; @@ -120,8 +120,8 @@ pub trait GinormousTrait { } // @has 'toggle_item_contents/trait.HugeTrait.html' -// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 1 -// @has - '//details[@class="rustdoc-toggle type-contents-toggle"]' 'Show 12 associated constants and 2 methods' +// @count - '//details[@class="toggle type-contents-toggle"]' 1 +// @has - '//details[@class="toggle type-contents-toggle"]' 'Show 12 associated constants and 2 methods' pub trait HugeTrait { type A; const M: usize = 1; @@ -142,8 +142,8 @@ pub trait HugeTrait { } // @has 'toggle_item_contents/trait.GiganticTrait.html' -// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 1 -// @has - '//details[@class="rustdoc-toggle type-contents-toggle"]' 'Show 1 associated constant and 1 method' +// @count - '//details[@class="toggle type-contents-toggle"]' 1 +// @has - '//details[@class="toggle type-contents-toggle"]' 'Show 1 associated constant and 1 method' pub trait GiganticTrait { type A; type B; @@ -163,8 +163,8 @@ pub trait GiganticTrait { } // @has 'toggle_item_contents/trait.BigTrait.html' -// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 1 -// @has - '//details[@class="rustdoc-toggle type-contents-toggle"]' 'Show 14 methods' +// @count - '//details[@class="toggle type-contents-toggle"]' 1 +// @has - '//details[@class="toggle type-contents-toggle"]' 'Show 14 methods' pub trait BigTrait { type A; #[must_use] diff --git a/tests/rustdoc/toggle-method.rs b/tests/rustdoc/toggle-method.rs index 1aa74e59659..ebc316ca8ad 100644 --- a/tests/rustdoc/toggle-method.rs +++ b/tests/rustdoc/toggle-method.rs @@ -4,9 +4,9 @@ // summary. Struct methods with no documentation should not be wrapped. // // @has foo/struct.Foo.html -// @has - '//details[@class="rustdoc-toggle method-toggle"]//summary//h4[@class="code-header"]' 'is_documented()' -// @has - '//details[@class="rustdoc-toggle method-toggle"]//*[@class="docblock"]' 'is_documented is documented' -// @!has - '//details[@class="rustdoc-toggle method-toggle"]//summary//h4[@class="code-header"]' 'not_documented()' +// @has - '//details[@class="toggle method-toggle"]//summary//h4[@class="code-header"]' 'is_documented()' +// @has - '//details[@class="toggle method-toggle"]//*[@class="docblock"]' 'is_documented is documented' +// @!has - '//details[@class="toggle method-toggle"]//summary//h4[@class="code-header"]' 'not_documented()' pub struct Foo { } diff --git a/tests/rustdoc/toggle-trait-fn.rs b/tests/rustdoc/toggle-trait-fn.rs index 0a1f088b9ab..686a174fc8f 100644 --- a/tests/rustdoc/toggle-trait-fn.rs +++ b/tests/rustdoc/toggle-trait-fn.rs @@ -4,14 +4,14 @@ // summary. Trait methods with no documentation should not be wrapped. // // @has foo/trait.Foo.html -// @has - '//details[@class="rustdoc-toggle"]//summary//h4[@class="code-header"]' 'type Item' -// @!has - '//details[@class="rustdoc-toggle"]//summary//h4[@class="code-header"]' 'type Item2' -// @has - '//details[@class="rustdoc-toggle method-toggle"]//summary//h4[@class="code-header"]' 'is_documented()' -// @!has - '//details[@class="rustdoc-toggle method-toggle"]//summary//h4[@class="code-header"]' 'not_documented()' -// @has - '//details[@class="rustdoc-toggle method-toggle"]//*[@class="docblock"]' 'is_documented is documented' -// @has - '//details[@class="rustdoc-toggle method-toggle"]//summary//h4[@class="code-header"]' 'is_documented_optional()' -// @!has - '//details[@class="rustdoc-toggle method-toggle"]//summary//h4[@class="code-header"]' 'not_documented_optional()' -// @has - '//details[@class="rustdoc-toggle method-toggle"]//*[@class="docblock"]' 'is_documented_optional is documented' +// @has - '//details[@class="toggle"]//summary//h4[@class="code-header"]' 'type Item' +// @!has - '//details[@class="toggle"]//summary//h4[@class="code-header"]' 'type Item2' +// @has - '//details[@class="toggle method-toggle"]//summary//h4[@class="code-header"]' 'is_documented()' +// @!has - '//details[@class="toggle method-toggle"]//summary//h4[@class="code-header"]' 'not_documented()' +// @has - '//details[@class="toggle method-toggle"]//*[@class="docblock"]' 'is_documented is documented' +// @has - '//details[@class="toggle method-toggle"]//summary//h4[@class="code-header"]' 'is_documented_optional()' +// @!has - '//details[@class="toggle method-toggle"]//summary//h4[@class="code-header"]' 'not_documented_optional()' +// @has - '//details[@class="toggle method-toggle"]//*[@class="docblock"]' 'is_documented_optional is documented' pub trait Foo { /// is documented type Item; diff --git a/tests/ui-fulldeps/pprust-expr-roundtrip.rs b/tests/ui-fulldeps/pprust-expr-roundtrip.rs index 6dbabc8eb34..7a91dcf0dad 100644 --- a/tests/ui-fulldeps/pprust-expr-roundtrip.rs +++ b/tests/ui-fulldeps/pprust-expr-roundtrip.rs @@ -126,6 +126,7 @@ fn iter_exprs(depth: usize, f: &mut dyn FnMut(P<Expr>)) { g(ExprKind::Closure(Box::new(Closure { binder: ClosureBinder::NotPresent, capture_clause: CaptureBy::Value, + constness: Const::No, asyncness: Async::No, movability: Movability::Movable, fn_decl: decl.clone(), diff --git a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.rs b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.rs index c19b639a8d5..65d9601e78a 100644 --- a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.rs +++ b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.rs @@ -723,7 +723,6 @@ struct SubdiagnosticEagerLint { #[diag(compiletest_example)] struct SubdiagnosticEagerCorrect { #[subdiagnostic(eager)] - //~^ ERROR `#[subdiagnostic(...)]` is not a valid attribute note: Note, } @@ -744,7 +743,6 @@ pub(crate) struct SubdiagnosticWithSuggestion { #[diag(compiletest_example)] struct SubdiagnosticEagerSuggestion { #[subdiagnostic(eager)] - //~^ ERROR `#[subdiagnostic(...)]` is not a valid attribute sub: SubdiagnosticWithSuggestion, } diff --git a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr index f39d32a221c..13e806a434f 100644 --- a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr +++ b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr @@ -539,7 +539,7 @@ error: `#[subdiagnostic(...)]` is not a valid attribute LL | #[subdiagnostic(bad)] | ^^^^^^^^^^^^^^^^^^^^^ | - = help: `subdiagnostic` does not support nested attributes + = help: `eager` is the only supported nested attribute for `subdiagnostic` error: `#[subdiagnostic = ...]` is not a valid attribute --> $DIR/diagnostic-derive.rs:693:5 @@ -553,7 +553,7 @@ error: `#[subdiagnostic(...)]` is not a valid attribute LL | #[subdiagnostic(bad, bad)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: `subdiagnostic` does not support nested attributes + = help: `eager` is the only supported nested attribute for `subdiagnostic` error: `#[subdiagnostic(...)]` is not a valid attribute --> $DIR/diagnostic-derive.rs:709:5 @@ -561,7 +561,7 @@ error: `#[subdiagnostic(...)]` is not a valid attribute LL | #[subdiagnostic("bad")] | ^^^^^^^^^^^^^^^^^^^^^^^ | - = help: `subdiagnostic` does not support nested attributes + = help: `eager` is the only supported nested attribute for `subdiagnostic` error: `#[subdiagnostic(...)]` is not a valid attribute --> $DIR/diagnostic-derive.rs:717:5 @@ -569,38 +569,22 @@ error: `#[subdiagnostic(...)]` is not a valid attribute LL | #[subdiagnostic(eager)] | ^^^^^^^^^^^^^^^^^^^^^^^ | - = help: `subdiagnostic` does not support nested attributes - -error: `#[subdiagnostic(...)]` is not a valid attribute - --> $DIR/diagnostic-derive.rs:725:5 - | -LL | #[subdiagnostic(eager)] - | ^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: `subdiagnostic` does not support nested attributes - -error: `#[subdiagnostic(...)]` is not a valid attribute - --> $DIR/diagnostic-derive.rs:746:5 - | -LL | #[subdiagnostic(eager)] - | ^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: `subdiagnostic` does not support nested attributes + = help: eager subdiagnostics are not supported on lints error: expected at least one string literal for `code(...)` - --> $DIR/diagnostic-derive.rs:777:18 + --> $DIR/diagnostic-derive.rs:775:18 | LL | #[suggestion(code())] | ^^^^^^ error: `code(...)` must contain only string literals - --> $DIR/diagnostic-derive.rs:785:23 + --> $DIR/diagnostic-derive.rs:783:23 | LL | #[suggestion(code(foo))] | ^^^ error: `code = "..."`/`code(...)` must contain only string literals - --> $DIR/diagnostic-derive.rs:793:18 + --> $DIR/diagnostic-derive.rs:791:18 | LL | #[suggestion(code = 3)] | ^^^^^^^^ @@ -676,7 +660,7 @@ note: required by a bound in `DiagnosticBuilder::<'a, G>::set_arg` --> $COMPILER_DIR/rustc_errors/src/diagnostic_builder.rs:LL:CC = note: this error originates in the derive macro `Diagnostic` which comes from the expansion of the macro `forward` (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 85 previous errors +error: aborting due to 83 previous errors Some errors have detailed explanations: E0277, E0425. For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/associated-item/ambiguous-associated-type-with-generics.fixed b/tests/ui/associated-item/ambiguous-associated-type-with-generics.fixed new file mode 100644 index 00000000000..23f71520040 --- /dev/null +++ b/tests/ui/associated-item/ambiguous-associated-type-with-generics.fixed @@ -0,0 +1,14 @@ +// run-rustfix +trait Trait<A> {} + +trait Assoc { + type Ty; +} + +impl<A> Assoc for dyn Trait<A> { + type Ty = i32; +} + +fn main() { + let _x: <dyn Trait<i32> as Assoc>::Ty; //~ ERROR ambiguous associated type +} diff --git a/tests/ui/associated-item/ambiguous-associated-type-with-generics.rs b/tests/ui/associated-item/ambiguous-associated-type-with-generics.rs new file mode 100644 index 00000000000..9c26e339a44 --- /dev/null +++ b/tests/ui/associated-item/ambiguous-associated-type-with-generics.rs @@ -0,0 +1,14 @@ +// run-rustfix +trait Trait<A> {} + +trait Assoc { + type Ty; +} + +impl<A> Assoc for dyn Trait<A> { + type Ty = i32; +} + +fn main() { + let _x: <dyn Trait<i32>>::Ty; //~ ERROR ambiguous associated type +} diff --git a/tests/ui/associated-item/ambiguous-associated-type-with-generics.stderr b/tests/ui/associated-item/ambiguous-associated-type-with-generics.stderr new file mode 100644 index 00000000000..97088b79fd6 --- /dev/null +++ b/tests/ui/associated-item/ambiguous-associated-type-with-generics.stderr @@ -0,0 +1,9 @@ +error[E0223]: ambiguous associated type + --> $DIR/ambiguous-associated-type-with-generics.rs:13:13 + | +LL | let _x: <dyn Trait<i32>>::Ty; + | ^^^^^^^^^^^^^^^^^^^^ help: use the fully-qualified path: `<dyn Trait<i32> as Assoc>::Ty` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0223`. diff --git a/tests/ui/associated-item/associated-item-duplicate-names-3.stderr b/tests/ui/associated-item/associated-item-duplicate-names-3.stderr index bf4bd634cf1..d0c17062076 100644 --- a/tests/ui/associated-item/associated-item-duplicate-names-3.stderr +++ b/tests/ui/associated-item/associated-item-duplicate-names-3.stderr @@ -13,7 +13,7 @@ error[E0223]: ambiguous associated type --> $DIR/associated-item-duplicate-names-3.rs:18:12 | LL | let x: Baz::Bar = 5; - | ^^^^^^^^ help: use fully-qualified syntax: `<Baz as Trait>::Bar` + | ^^^^^^^^ help: use the fully-qualified path: `<Baz as Foo>::Bar` error: aborting due to 2 previous errors diff --git a/tests/ui/associated-types/associated-types-in-ambiguous-context.stderr b/tests/ui/associated-types/associated-types-in-ambiguous-context.stderr index 289911779ff..00856b55df5 100644 --- a/tests/ui/associated-types/associated-types-in-ambiguous-context.stderr +++ b/tests/ui/associated-types/associated-types-in-ambiguous-context.stderr @@ -2,31 +2,46 @@ error[E0223]: ambiguous associated type --> $DIR/associated-types-in-ambiguous-context.rs:6:36 | LL | fn get<T:Get,U:Get>(x: T, y: U) -> Get::Value {} - | ^^^^^^^^^^ help: use fully-qualified syntax: `<Type as Get>::Value` + | ^^^^^^^^^^ + | +help: if there were a type named `Example` that implemented `Get`, you could use the fully-qualified path + | +LL | fn get<T:Get,U:Get>(x: T, y: U) -> <Example as Get>::Value {} + | ~~~~~~~~~~~~~~~~~~~~~~~ error[E0223]: ambiguous associated type --> $DIR/associated-types-in-ambiguous-context.rs:20:17 | LL | trait Foo where Foo::Assoc: Bar { - | ^^^^^^^^^^ help: use fully-qualified syntax: `<Self as Foo>::Assoc` + | ^^^^^^^^^^ help: use the fully-qualified path: `<Self as Foo>::Assoc` error[E0223]: ambiguous associated type --> $DIR/associated-types-in-ambiguous-context.rs:25:10 | LL | type X = std::ops::Deref::Target; - | ^^^^^^^^^^^^^^^^^^^^^^^ help: use fully-qualified syntax: `<Type as Deref>::Target` + | ^^^^^^^^^^^^^^^^^^^^^^^ + | +help: if there were a type named `Example` that implemented `Deref`, you could use the fully-qualified path + | +LL | type X = <Example as Deref>::Target; + | ~~~~~~~~~~~~~~~~~~~~~~~~~~ error[E0223]: ambiguous associated type --> $DIR/associated-types-in-ambiguous-context.rs:11:23 | LL | fn grab(&self) -> Grab::Value; - | ^^^^^^^^^^^ help: use fully-qualified syntax: `<Self as Grab>::Value` + | ^^^^^^^^^^^ help: use the fully-qualified path: `<Self as Grab>::Value` error[E0223]: ambiguous associated type --> $DIR/associated-types-in-ambiguous-context.rs:14:22 | LL | fn get(&self) -> Get::Value; - | ^^^^^^^^^^ help: use fully-qualified syntax: `<Type as Get>::Value` + | ^^^^^^^^^^ + | +help: if there were a type named `Example` that implemented `Get`, you could use the fully-qualified path + | +LL | fn get(&self) -> <Example as Get>::Value; + | ~~~~~~~~~~~~~~~~~~~~~~~ error: aborting due to 5 previous errors diff --git a/tests/ui/async-await/in-trait/nested-rpit.rs b/tests/ui/async-await/in-trait/nested-rpit.rs index ae8e0aed0cc..41d72ebb4d4 100644 --- a/tests/ui/async-await/in-trait/nested-rpit.rs +++ b/tests/ui/async-await/in-trait/nested-rpit.rs @@ -1,5 +1,7 @@ -// check-pass // edition: 2021 +// known-bug: #105197 +// failure-status:101 +// dont-check-compiler-stderr #![feature(async_fn_in_trait)] #![feature(return_position_impl_trait_in_trait)] diff --git a/tests/ui/attributes/log-backtrace.rs b/tests/ui/attributes/log-backtrace.rs new file mode 100644 index 00000000000..3979d2001fc --- /dev/null +++ b/tests/ui/attributes/log-backtrace.rs @@ -0,0 +1,9 @@ +// run-pass +// +// This test makes sure that log-backtrace option doesn't give a compilation error. +// +// dont-check-compiler-stdout +// dont-check-compiler-stderr +// rustc-env:RUSTC_LOG=info +// compile-flags: -Zlog-backtrace=rustc_metadata::creader +fn main() {} diff --git a/tests/ui/builtin-superkinds/builtin-superkinds-double-superkind.stderr b/tests/ui/builtin-superkinds/builtin-superkinds-double-superkind.stderr index 492316f0027..592aa4369ce 100644 --- a/tests/ui/builtin-superkinds/builtin-superkinds-double-superkind.stderr +++ b/tests/ui/builtin-superkinds/builtin-superkinds-double-superkind.stderr @@ -1,8 +1,8 @@ error[E0277]: `T` cannot be sent between threads safely - --> $DIR/builtin-superkinds-double-superkind.rs:6:24 + --> $DIR/builtin-superkinds-double-superkind.rs:6:32 | LL | impl <T: Sync+'static> Foo for (T,) { } - | ^^^ `T` cannot be sent between threads safely + | ^^^^ `T` cannot be sent between threads safely | = note: required because it appears within the type `(T,)` note: required by a bound in `Foo` @@ -16,10 +16,10 @@ LL | impl <T: Sync+'static + std::marker::Send> Foo for (T,) { } | +++++++++++++++++++ error[E0277]: `T` cannot be shared between threads safely - --> $DIR/builtin-superkinds-double-superkind.rs:9:16 + --> $DIR/builtin-superkinds-double-superkind.rs:9:24 | LL | impl <T: Send> Foo for (T,T) { } - | ^^^ `T` cannot be shared between threads safely + | ^^^^^ `T` cannot be shared between threads safely | = note: required because it appears within the type `(T, T)` note: required by a bound in `Foo` diff --git a/tests/ui/builtin-superkinds/builtin-superkinds-in-metadata.stderr b/tests/ui/builtin-superkinds/builtin-superkinds-in-metadata.stderr index a46e4b2337c..f9d548bb8fb 100644 --- a/tests/ui/builtin-superkinds/builtin-superkinds-in-metadata.stderr +++ b/tests/ui/builtin-superkinds/builtin-superkinds-in-metadata.stderr @@ -1,8 +1,8 @@ error[E0277]: `T` cannot be sent between threads safely - --> $DIR/builtin-superkinds-in-metadata.rs:13:23 + --> $DIR/builtin-superkinds-in-metadata.rs:13:56 | LL | impl <T:Sync+'static> RequiresRequiresShareAndSend for X<T> { } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `T` cannot be sent between threads safely + | ^^^^ `T` cannot be sent between threads safely | note: required because it appears within the type `X<T>` --> $DIR/builtin-superkinds-in-metadata.rs:9:8 diff --git a/tests/ui/builtin-superkinds/builtin-superkinds-simple.stderr b/tests/ui/builtin-superkinds/builtin-superkinds-simple.stderr index 9db9cbfdb91..8b19170b0f1 100644 --- a/tests/ui/builtin-superkinds/builtin-superkinds-simple.stderr +++ b/tests/ui/builtin-superkinds/builtin-superkinds-simple.stderr @@ -1,8 +1,8 @@ error[E0277]: `Rc<i8>` cannot be sent between threads safely - --> $DIR/builtin-superkinds-simple.rs:6:6 + --> $DIR/builtin-superkinds-simple.rs:6:14 | LL | impl Foo for std::rc::Rc<i8> { } - | ^^^ `Rc<i8>` cannot be sent between threads safely + | ^^^^^^^^^^^^^^^ `Rc<i8>` cannot be sent between threads safely | = help: the trait `Send` is not implemented for `Rc<i8>` note: required by a bound in `Foo` diff --git a/tests/ui/builtin-superkinds/builtin-superkinds-typaram-not-send.stderr b/tests/ui/builtin-superkinds/builtin-superkinds-typaram-not-send.stderr index 3ec0b907d0c..0cfea72d5f1 100644 --- a/tests/ui/builtin-superkinds/builtin-superkinds-typaram-not-send.stderr +++ b/tests/ui/builtin-superkinds/builtin-superkinds-typaram-not-send.stderr @@ -1,8 +1,8 @@ error[E0277]: `T` cannot be sent between threads safely - --> $DIR/builtin-superkinds-typaram-not-send.rs:5:24 + --> $DIR/builtin-superkinds-typaram-not-send.rs:5:32 | LL | impl <T: Sync+'static> Foo for T { } - | ^^^ `T` cannot be sent between threads safely + | ^ `T` cannot be sent between threads safely | note: required by a bound in `Foo` --> $DIR/builtin-superkinds-typaram-not-send.rs:3:13 diff --git a/tests/ui/c-variadic/feature-gate-extended_varargs_abi_support.rs b/tests/ui/c-variadic/feature-gate-extended_varargs_abi_support.rs index 087743e505d..fce6210b2f4 100644 --- a/tests/ui/c-variadic/feature-gate-extended_varargs_abi_support.rs +++ b/tests/ui/c-variadic/feature-gate-extended_varargs_abi_support.rs @@ -1,5 +1,3 @@ -#![feature(abi_efiapi)] - fn efiapi(f: extern "efiapi" fn(usize, ...)) { //~^ ERROR: C-variadic function must have a compatible calling convention, like `C` or `cdecl` //~^^ ERROR: using calling conventions other than `C` or `cdecl` for varargs functions is unstable diff --git a/tests/ui/c-variadic/feature-gate-extended_varargs_abi_support.stderr b/tests/ui/c-variadic/feature-gate-extended_varargs_abi_support.stderr index 007d7d7953c..5b97b396fb1 100644 --- a/tests/ui/c-variadic/feature-gate-extended_varargs_abi_support.stderr +++ b/tests/ui/c-variadic/feature-gate-extended_varargs_abi_support.stderr @@ -1,5 +1,5 @@ error[E0658]: using calling conventions other than `C` or `cdecl` for varargs functions is unstable - --> $DIR/feature-gate-extended_varargs_abi_support.rs:3:14 + --> $DIR/feature-gate-extended_varargs_abi_support.rs:1:14 | LL | fn efiapi(f: extern "efiapi" fn(usize, ...)) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -8,13 +8,13 @@ LL | fn efiapi(f: extern "efiapi" fn(usize, ...)) { = help: add `#![feature(extended_varargs_abi_support)]` to the crate attributes to enable error[E0045]: C-variadic function must have a compatible calling convention, like `C` or `cdecl` - --> $DIR/feature-gate-extended_varargs_abi_support.rs:3:14 + --> $DIR/feature-gate-extended_varargs_abi_support.rs:1:14 | LL | fn efiapi(f: extern "efiapi" fn(usize, ...)) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ C-variadic function must have a compatible calling convention error[E0658]: using calling conventions other than `C` or `cdecl` for varargs functions is unstable - --> $DIR/feature-gate-extended_varargs_abi_support.rs:8:12 + --> $DIR/feature-gate-extended_varargs_abi_support.rs:6:12 | LL | fn sysv(f: extern "sysv64" fn(usize, ...)) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -23,13 +23,13 @@ LL | fn sysv(f: extern "sysv64" fn(usize, ...)) { = help: add `#![feature(extended_varargs_abi_support)]` to the crate attributes to enable error[E0045]: C-variadic function must have a compatible calling convention, like `C` or `cdecl` - --> $DIR/feature-gate-extended_varargs_abi_support.rs:8:12 + --> $DIR/feature-gate-extended_varargs_abi_support.rs:6:12 | LL | fn sysv(f: extern "sysv64" fn(usize, ...)) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ C-variadic function must have a compatible calling convention error[E0658]: using calling conventions other than `C` or `cdecl` for varargs functions is unstable - --> $DIR/feature-gate-extended_varargs_abi_support.rs:13:11 + --> $DIR/feature-gate-extended_varargs_abi_support.rs:11:11 | LL | fn win(f: extern "win64" fn(usize, ...)) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -38,7 +38,7 @@ LL | fn win(f: extern "win64" fn(usize, ...)) { = help: add `#![feature(extended_varargs_abi_support)]` to the crate attributes to enable error[E0045]: C-variadic function must have a compatible calling convention, like `C` or `cdecl` - --> $DIR/feature-gate-extended_varargs_abi_support.rs:13:11 + --> $DIR/feature-gate-extended_varargs_abi_support.rs:11:11 | LL | fn win(f: extern "win64" fn(usize, ...)) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ C-variadic function must have a compatible calling convention diff --git a/tests/ui/c-variadic/variadic-ffi-2.rs b/tests/ui/c-variadic/variadic-ffi-2.rs index 96cea87546e..c34b7e55f6a 100644 --- a/tests/ui/c-variadic/variadic-ffi-2.rs +++ b/tests/ui/c-variadic/variadic-ffi-2.rs @@ -1,6 +1,5 @@ // ignore-arm stdcall isn't supported #![feature(extended_varargs_abi_support)] -#![feature(abi_efiapi)] fn baz(f: extern "stdcall" fn(usize, ...)) { //~^ ERROR: C-variadic function must have a compatible calling convention, diff --git a/tests/ui/c-variadic/variadic-ffi-2.stderr b/tests/ui/c-variadic/variadic-ffi-2.stderr index 4e74c9d9227..e21001ecaf8 100644 --- a/tests/ui/c-variadic/variadic-ffi-2.stderr +++ b/tests/ui/c-variadic/variadic-ffi-2.stderr @@ -1,5 +1,5 @@ error[E0045]: C-variadic function must have a compatible calling convention, like `C`, `cdecl`, `win64`, `sysv64` or `efiapi` - --> $DIR/variadic-ffi-2.rs:5:11 + --> $DIR/variadic-ffi-2.rs:4:11 | LL | fn baz(f: extern "stdcall" fn(usize, ...)) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ C-variadic function must have a compatible calling convention diff --git a/tests/ui/chalkify/bugs/async.rs b/tests/ui/chalkify/bugs/async.rs index 86ce42631b4..1c69b07e3d4 100644 --- a/tests/ui/chalkify/bugs/async.rs +++ b/tests/ui/chalkify/bugs/async.rs @@ -2,12 +2,21 @@ // known-bug // unset-rustc-env:RUST_BACKTRACE // compile-flags:-Z trait-solver=chalk --edition=2021 -// error-pattern:stack backtrace: +// error-pattern:internal compiler error // failure-status:101 -// normalize-stderr-test "note: .*" -> "" -// normalize-stderr-test "thread 'rustc' .*" -> "" -// normalize-stderr-test " .*\n" -> "" // normalize-stderr-test "DefId([^)]*)" -> "..." +// normalize-stderr-test "\nerror: internal compiler error.*\n\n" -> "" +// normalize-stderr-test "note:.*unexpectedly panicked.*\n\n" -> "" +// normalize-stderr-test "note: we would appreciate a bug report.*\n\n" -> "" +// normalize-stderr-test "note: compiler flags.*\n\n" -> "" +// normalize-stderr-test "note: rustc.*running on.*\n\n" -> "" +// normalize-stderr-test "thread.*panicked.*\n" -> "" +// normalize-stderr-test "stack backtrace:\n" -> "" +// normalize-stderr-test "\s\d{1,}: .*\n" -> "" +// normalize-stderr-test "\s at .*\n" -> "" +// normalize-stderr-test ".*note: Some details.*\n" -> "" +// normalize-stderr-test "\n\n[ ]*\n" -> "" +// normalize-stderr-test "compiler/.*: projection" -> "projection" fn main() -> () {} diff --git a/tests/ui/chalkify/bugs/async.stderr b/tests/ui/chalkify/bugs/async.stderr index 7e2466dece4..d1508cb1700 100644 --- a/tests/ui/chalkify/bugs/async.stderr +++ b/tests/ui/chalkify/bugs/async.stderr @@ -1,29 +1,47 @@ -error[E0277]: `[async fn body@$DIR/async.rs:14:29: 16:2]` is not a future -LL |LL | |LL | | } - - -error[E0277]: the size for values of type `<[async fn body@$DIR/async.rs:14:29: 16:2] as Future>::Output` cannot be known at compilation time -LL |LL | |LL | | } - - -error[E0277]: `[async fn body@$DIR/async.rs:14:29: 16:2]` is not a future +error[E0277]: `[async fn body@$DIR/async.rs:23:29: 25:2]` is not a future + --> $DIR/async.rs:23:29 + | +LL | async fn foo(x: u32) -> u32 { + | _____________________________- +LL | | x +LL | | } + | | ^ + | | | + | |_`[async fn body@$DIR/async.rs:23:29: 25:2]` is not a future + | required by a bound introduced by this call + | + = help: the trait `Future` is not implemented for `[async fn body@$DIR/async.rs:23:29: 25:2]` + = note: [async fn body@$DIR/async.rs:23:29: 25:2] must be a future or must implement `IntoFuture` to be awaited +note: required by a bound in `identity_future` + --> $SRC_DIR/core/src/future/mod.rs:LL:COL + +error[E0277]: the size for values of type `<[async fn body@$DIR/async.rs:23:29: 25:2] as Future>::Output` cannot be known at compilation time + --> $DIR/async.rs:23:29 + | +LL | async fn foo(x: u32) -> u32 { + | _____________________________^ +LL | | x +LL | | } + | |_^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `<[async fn body@$DIR/async.rs:23:29: 25:2] as Future>::Output` +note: required by a bound in `identity_future` + --> $SRC_DIR/core/src/future/mod.rs:LL:COL + +error[E0277]: `[async fn body@$DIR/async.rs:23:29: 25:2]` is not a future + --> $DIR/async.rs:23:25 + | LL | async fn foo(x: u32) -> u32 { - -error: internal compiler error: compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs:1114:25: projection clauses should be implied from elsewhere. obligation: `Obligation(predicate=Binder(ProjectionPredicate(AliasTy { substs: [[async fn body@$DIR/async.rs:14:29: 16:2]], def_id: ...), _use_mk_alias_ty_instead: () }, Term::Ty(u32)), []), depth=0)` + | ^^^ `[async fn body@$DIR/async.rs:23:29: 25:2]` is not a future + | + = help: the trait `Future` is not implemented for `[async fn body@$DIR/async.rs:23:29: 25:2]` + = note: [async fn body@$DIR/async.rs:23:29: 25:2] must be a future or must implement `IntoFuture` to be awaited + +error: internal compiler error: projection clauses should be implied from elsewhere. obligation: `Obligation(predicate=Binder(ProjectionPredicate(AliasTy { substs: [[async fn body@$DIR/async.rs:23:29: 25:2]], def_id: ...), _use_mk_alias_ty_instead: () }, Term::Ty(u32)), []), depth=0)` + --> $DIR/async.rs:23:25 + | LL | async fn foo(x: u32) -> u32 { - - -stack backtrace: - - - - - - - - - -query stack during panic: + | ^^^query stack during panic: #0 [typeck] type-checking `foo` #1 [thir_body] building THIR for `foo` #2 [mir_built] building MIR for `foo` diff --git a/tests/ui/chalkify/impl_wf.stderr b/tests/ui/chalkify/impl_wf.stderr index a142459bcb4..84c32fa3771 100644 --- a/tests/ui/chalkify/impl_wf.stderr +++ b/tests/ui/chalkify/impl_wf.stderr @@ -1,8 +1,8 @@ error[E0277]: the size for values of type `str` cannot be known at compilation time - --> $DIR/impl_wf.rs:11:6 + --> $DIR/impl_wf.rs:11:14 | LL | impl Foo for 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` note: required by a bound in `Foo` @@ -12,10 +12,10 @@ LL | trait Foo: Sized { } | ^^^^^ required by this bound in `Foo` error[E0277]: the trait bound `f32: Foo` is not satisfied - --> $DIR/impl_wf.rs:22:6 + --> $DIR/impl_wf.rs:22:19 | LL | impl Baz<f32> for f32 { } - | ^^^^^^^^ the trait `Foo` is not implemented for `f32` + | ^^^ the trait `Foo` is not implemented for `f32` | = help: the trait `Foo` is implemented for `i32` note: required by a bound in `Baz` diff --git a/tests/ui/check-static-values-constraints.stderr b/tests/ui/check-static-values-constraints.stderr index b13700a4ea5..49056678448 100644 --- a/tests/ui/check-static-values-constraints.stderr +++ b/tests/ui/check-static-values-constraints.stderr @@ -22,6 +22,7 @@ LL | field2: SafeEnum::Variant4("str".to_string()) | ^^^^^^^^^^^ | = note: calls in statics are limited to constant functions, tuple structs and tuple variants + = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable = note: consider wrapping this expression in `Lazy::new(|| ...)` from the `once_cell` crate: https://crates.io/crates/once_cell error[E0010]: allocations are not allowed in statics diff --git a/tests/ui/coherence/coherence-overlap-trait-alias.stderr b/tests/ui/coherence/coherence-overlap-trait-alias.stderr index e324c1e799f..668b8319b38 100644 --- a/tests/ui/coherence/coherence-overlap-trait-alias.stderr +++ b/tests/ui/coherence/coherence-overlap-trait-alias.stderr @@ -1,8 +1,8 @@ error[E0283]: type annotations needed: cannot satisfy `u32: C` - --> $DIR/coherence-overlap-trait-alias.rs:15:6 + --> $DIR/coherence-overlap-trait-alias.rs:15:12 | LL | impl C for u32 {} - | ^ + | ^^^ | note: multiple `impl`s satisfying `u32: C` found --> $DIR/coherence-overlap-trait-alias.rs:14:1 diff --git a/tests/ui/const-generics/issue-93647.stderr b/tests/ui/const-generics/issue-93647.stderr index e2048ecd60f..18370eea571 100644 --- a/tests/ui/const-generics/issue-93647.stderr +++ b/tests/ui/const-generics/issue-93647.stderr @@ -6,6 +6,7 @@ LL | (||1usize)() | = note: closures need an RFC before allowed to be called in constants = note: calls in constants are limited to constant functions, tuple structs and tuple variants + = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable error: aborting due to previous error diff --git a/tests/ui/consts/const-fn-error.stderr b/tests/ui/consts/const-fn-error.stderr index f6b532fb658..f735b3d53ce 100644 --- a/tests/ui/consts/const-fn-error.stderr +++ b/tests/ui/consts/const-fn-error.stderr @@ -22,6 +22,7 @@ LL | for i in 0..x { note: impl defined here, but it is not `const` --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants + = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable error[E0658]: mutable references are not allowed in constant functions --> $DIR/const-fn-error.rs:5:14 @@ -39,6 +40,7 @@ LL | for i in 0..x { | ^^^^ | = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants + = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable error: aborting due to 4 previous errors diff --git a/tests/ui/consts/const-for.stderr b/tests/ui/consts/const-for.stderr index 294ea627d85..3fb9787c0d8 100644 --- a/tests/ui/consts/const-for.stderr +++ b/tests/ui/consts/const-for.stderr @@ -7,6 +7,7 @@ LL | for _ in 0..5 {} note: impl defined here, but it is not `const` --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL = note: calls in constants are limited to constant functions, tuple structs and tuple variants + = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable error[E0015]: cannot call non-const fn `<std::ops::Range<i32> as Iterator>::next` in constants --> $DIR/const-for.rs:5:14 @@ -15,6 +16,7 @@ LL | for _ in 0..5 {} | ^^^^ | = note: calls in constants are limited to constant functions, tuple structs and tuple variants + = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable error: aborting due to 2 previous errors diff --git a/tests/ui/consts/ct-var-in-collect_all_mismatches.rs b/tests/ui/consts/ct-var-in-collect_all_mismatches.rs new file mode 100644 index 00000000000..5fb633de983 --- /dev/null +++ b/tests/ui/consts/ct-var-in-collect_all_mismatches.rs @@ -0,0 +1,20 @@ +struct Foo<T, const N: usize> { + array: [T; N], +} + +trait Bar<const N: usize> {} + +impl<T, const N: usize> Foo<T, N> { + fn trigger(self) { + self.unsatisfied() + //~^ ERROR the trait bound `T: Bar<N>` is not satisfied + } + + fn unsatisfied(self) + where + T: Bar<N>, + { + } +} + +fn main() {} diff --git a/tests/ui/consts/ct-var-in-collect_all_mismatches.stderr b/tests/ui/consts/ct-var-in-collect_all_mismatches.stderr new file mode 100644 index 00000000000..43fba2573ff --- /dev/null +++ b/tests/ui/consts/ct-var-in-collect_all_mismatches.stderr @@ -0,0 +1,22 @@ +error[E0277]: the trait bound `T: Bar<N>` is not satisfied + --> $DIR/ct-var-in-collect_all_mismatches.rs:9:14 + | +LL | self.unsatisfied() + | ^^^^^^^^^^^ the trait `Bar<N>` is not implemented for `T` + | +note: required by a bound in `Foo::<T, N>::unsatisfied` + --> $DIR/ct-var-in-collect_all_mismatches.rs:15:12 + | +LL | fn unsatisfied(self) + | ----------- required by a bound in this +LL | where +LL | T: Bar<N>, + | ^^^^^^ required by this bound in `Foo::<T, N>::unsatisfied` +help: consider restricting type parameter `T` + | +LL | impl<T: Bar<N>, const N: usize> Foo<T, N> { + | ++++++++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/consts/invalid-inline-const-in-match-arm.stderr b/tests/ui/consts/invalid-inline-const-in-match-arm.stderr index ab594c921f9..257ecd7f3cf 100644 --- a/tests/ui/consts/invalid-inline-const-in-match-arm.stderr +++ b/tests/ui/consts/invalid-inline-const-in-match-arm.stderr @@ -6,6 +6,7 @@ LL | const { (|| {})() } => {} | = note: closures need an RFC before allowed to be called in constants = note: calls in constants are limited to constant functions, tuple structs and tuple variants + = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable error: aborting due to previous error diff --git a/tests/ui/consts/issue-28113.stderr b/tests/ui/consts/issue-28113.stderr index 7ad1f752eb0..1294cc99bf7 100644 --- a/tests/ui/consts/issue-28113.stderr +++ b/tests/ui/consts/issue-28113.stderr @@ -6,6 +6,7 @@ LL | || -> u8 { 5 }() | = note: closures need an RFC before allowed to be called in constants = note: calls in constants are limited to constant functions, tuple structs and tuple variants + = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable error: aborting due to previous error diff --git a/tests/ui/consts/issue-56164.stderr b/tests/ui/consts/issue-56164.stderr index 2579b3e7827..845b23d5d87 100644 --- a/tests/ui/consts/issue-56164.stderr +++ b/tests/ui/consts/issue-56164.stderr @@ -6,6 +6,7 @@ LL | const fn foo() { (||{})() } | = note: closures need an RFC before allowed to be called in constant functions = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants + = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable error: function pointer calls are not allowed in constant functions --> $DIR/issue-56164.rs:5:5 diff --git a/tests/ui/consts/issue-68542-closure-in-array-len.stderr b/tests/ui/consts/issue-68542-closure-in-array-len.stderr index 74fbbc680f7..d23513ed7ff 100644 --- a/tests/ui/consts/issue-68542-closure-in-array-len.stderr +++ b/tests/ui/consts/issue-68542-closure-in-array-len.stderr @@ -6,6 +6,7 @@ LL | a: [(); (|| { 0 })()] | = note: closures need an RFC before allowed to be called in constants = note: calls in constants are limited to constant functions, tuple structs and tuple variants + = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable error: aborting due to previous error diff --git a/tests/ui/consts/issue-90870.fixed b/tests/ui/consts/issue-90870.fixed index 0d28e06e532..df44689efed 100644 --- a/tests/ui/consts/issue-90870.fixed +++ b/tests/ui/consts/issue-90870.fixed @@ -8,12 +8,14 @@ const fn f(a: &u8, b: &u8) -> bool { *a == *b //~^ ERROR: cannot call non-const operator in constant functions [E0015] //~| HELP: consider dereferencing here + //~| HELP: add `#![feature(const_trait_impl)]` } const fn g(a: &&&&i64, b: &&&&i64) -> bool { ****a == ****b //~^ ERROR: cannot call non-const operator in constant functions [E0015] //~| HELP: consider dereferencing here + //~| HELP: add `#![feature(const_trait_impl)]` } const fn h(mut a: &[u8], mut b: &[u8]) -> bool { @@ -21,6 +23,7 @@ const fn h(mut a: &[u8], mut b: &[u8]) -> bool { if *l == *r { //~^ ERROR: cannot call non-const operator in constant functions [E0015] //~| HELP: consider dereferencing here + //~| HELP: add `#![feature(const_trait_impl)]` a = at; b = bt; } else { diff --git a/tests/ui/consts/issue-90870.rs b/tests/ui/consts/issue-90870.rs index c6bfffd2c5c..676ac73c64d 100644 --- a/tests/ui/consts/issue-90870.rs +++ b/tests/ui/consts/issue-90870.rs @@ -8,12 +8,14 @@ const fn f(a: &u8, b: &u8) -> bool { a == b //~^ ERROR: cannot call non-const operator in constant functions [E0015] //~| HELP: consider dereferencing here + //~| HELP: add `#![feature(const_trait_impl)]` } const fn g(a: &&&&i64, b: &&&&i64) -> bool { a == b //~^ ERROR: cannot call non-const operator in constant functions [E0015] //~| HELP: consider dereferencing here + //~| HELP: add `#![feature(const_trait_impl)]` } const fn h(mut a: &[u8], mut b: &[u8]) -> bool { @@ -21,6 +23,7 @@ const fn h(mut a: &[u8], mut b: &[u8]) -> bool { if l == r { //~^ ERROR: cannot call non-const operator in constant functions [E0015] //~| HELP: consider dereferencing here + //~| HELP: add `#![feature(const_trait_impl)]` a = at; b = bt; } else { diff --git a/tests/ui/consts/issue-90870.stderr b/tests/ui/consts/issue-90870.stderr index 478445cfb39..8825efd1449 100644 --- a/tests/ui/consts/issue-90870.stderr +++ b/tests/ui/consts/issue-90870.stderr @@ -5,30 +5,33 @@ LL | a == b | ^^^^^^ | = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants + = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable help: consider dereferencing here | LL | *a == *b | + + error[E0015]: cannot call non-const operator in constant functions - --> $DIR/issue-90870.rs:14:5 + --> $DIR/issue-90870.rs:15:5 | LL | a == b | ^^^^^^ | = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants + = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable help: consider dereferencing here | LL | ****a == ****b | ++++ ++++ error[E0015]: cannot call non-const operator in constant functions - --> $DIR/issue-90870.rs:21:12 + --> $DIR/issue-90870.rs:23:12 | LL | if l == r { | ^^^^^^ | = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants + = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable help: consider dereferencing here | LL | if *l == *r { diff --git a/tests/ui/did_you_mean/bad-assoc-ty.stderr b/tests/ui/did_you_mean/bad-assoc-ty.stderr index 21f957ab549..55096e95df7 100644 --- a/tests/ui/did_you_mean/bad-assoc-ty.stderr +++ b/tests/ui/did_you_mean/bad-assoc-ty.stderr @@ -61,25 +61,45 @@ error[E0223]: ambiguous associated type --> $DIR/bad-assoc-ty.rs:1:10 | LL | type A = [u8; 4]::AssocTy; - | ^^^^^^^^^^^^^^^^ help: use fully-qualified syntax: `<[u8; 4] as Trait>::AssocTy` + | ^^^^^^^^^^^^^^^^ + | +help: if there were a trait named `Example` with associated type `AssocTy` implemented for `[u8; 4]`, you could use the fully-qualified path + | +LL | type A = <[u8; 4] as Example>::AssocTy; + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error[E0223]: ambiguous associated type --> $DIR/bad-assoc-ty.rs:5:10 | LL | type B = [u8]::AssocTy; - | ^^^^^^^^^^^^^ help: use fully-qualified syntax: `<[u8] as Trait>::AssocTy` + | ^^^^^^^^^^^^^ + | +help: if there were a trait named `Example` with associated type `AssocTy` implemented for `[u8]`, you could use the fully-qualified path + | +LL | type B = <[u8] as Example>::AssocTy; + | ~~~~~~~~~~~~~~~~~~~~~~~~~~ error[E0223]: ambiguous associated type --> $DIR/bad-assoc-ty.rs:9:10 | LL | type C = (u8)::AssocTy; - | ^^^^^^^^^^^^^ help: use fully-qualified syntax: `<u8 as Trait>::AssocTy` + | ^^^^^^^^^^^^^ + | +help: if there were a trait named `Example` with associated type `AssocTy` implemented for `u8`, you could use the fully-qualified path + | +LL | type C = <u8 as Example>::AssocTy; + | ~~~~~~~~~~~~~~~~~~~~~~~~ error[E0223]: ambiguous associated type --> $DIR/bad-assoc-ty.rs:13:10 | LL | type D = (u8, u8)::AssocTy; - | ^^^^^^^^^^^^^^^^^ help: use fully-qualified syntax: `<(u8, u8) as Trait>::AssocTy` + | ^^^^^^^^^^^^^^^^^ + | +help: if there were a trait named `Example` with associated type `AssocTy` implemented for `(u8, u8)`, you could use the fully-qualified path + | +LL | type D = <(u8, u8) as Example>::AssocTy; + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error[E0121]: the placeholder `_` is not allowed within types on item signatures for type aliases --> $DIR/bad-assoc-ty.rs:17:10 @@ -91,13 +111,23 @@ error[E0223]: ambiguous associated type --> $DIR/bad-assoc-ty.rs:21:19 | LL | type F = &'static (u8)::AssocTy; - | ^^^^^^^^^^^^^ help: use fully-qualified syntax: `<u8 as Trait>::AssocTy` + | ^^^^^^^^^^^^^ + | +help: if there were a trait named `Example` with associated type `AssocTy` implemented for `u8`, you could use the fully-qualified path + | +LL | type F = &'static <u8 as Example>::AssocTy; + | ~~~~~~~~~~~~~~~~~~~~~~~~ error[E0223]: ambiguous associated type --> $DIR/bad-assoc-ty.rs:27:10 | LL | type G = dyn 'static + (Send)::AssocTy; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use fully-qualified syntax: `<(dyn Send + 'static) as Trait>::AssocTy` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: if there were a trait named `Example` with associated type `AssocTy` implemented for `(dyn Send + 'static)`, you could use the fully-qualified path + | +LL | type G = <(dyn Send + 'static) as Example>::AssocTy; + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ warning: trait objects without an explicit `dyn` are deprecated --> $DIR/bad-assoc-ty.rs:33:10 @@ -117,24 +147,33 @@ error[E0223]: ambiguous associated type --> $DIR/bad-assoc-ty.rs:33:10 | LL | type H = Fn(u8) -> (u8)::Output; - | ^^^^^^^^^^^^^^^^^^^^^^ help: use fully-qualified syntax: `<(dyn Fn(u8) -> u8 + 'static) as Trait>::Output` + | ^^^^^^^^^^^^^^^^^^^^^^ help: use the fully-qualified path: `<(dyn Fn(u8) -> u8 + 'static) as IntoFuture>::Output` error[E0223]: ambiguous associated type --> $DIR/bad-assoc-ty.rs:39:19 | LL | ($ty: ty) => ($ty::AssocTy); - | ^^^^^^^^^^^^ help: use fully-qualified syntax: `<u8 as Trait>::AssocTy` + | ^^^^^^^^^^^^ ... LL | type J = ty!(u8); | ------- in this macro invocation | = note: this error originates in the macro `ty` (in Nightly builds, run with -Z macro-backtrace for more info) +help: if there were a trait named `Example` with associated type `AssocTy` implemented for `u8`, you could use the fully-qualified path + | +LL | ($ty: ty) => (<u8 as Example>::AssocTy); + | ~~~~~~~~~~~~~~~~~~~~~~~~ error[E0223]: ambiguous associated type --> $DIR/bad-assoc-ty.rs:46:10 | LL | type I = ty!()::AssocTy; - | ^^^^^^^^^^^^^^ help: use fully-qualified syntax: `<u8 as Trait>::AssocTy` + | ^^^^^^^^^^^^^^ + | +help: if there were a trait named `Example` with associated type `AssocTy` implemented for `u8`, you could use the fully-qualified path + | +LL | type I = <u8 as Example>::AssocTy; + | ~~~~~~~~~~~~~~~~~~~~~~~~ error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions --> $DIR/bad-assoc-ty.rs:51:13 diff --git a/tests/ui/dst/dst-sized-trait-param.stderr b/tests/ui/dst/dst-sized-trait-param.stderr index 8ec94f5a3c0..60e9de90332 100644 --- a/tests/ui/dst/dst-sized-trait-param.stderr +++ b/tests/ui/dst/dst-sized-trait-param.stderr @@ -16,10 +16,10 @@ LL | trait Foo<T: ?Sized> : Sized { fn take(self, x: &T) { } } // Note: T is siz | ++++++++ error[E0277]: the size for values of type `[usize]` cannot be known at compilation time - --> $DIR/dst-sized-trait-param.rs:10:6 + --> $DIR/dst-sized-trait-param.rs:10:21 | LL | impl Foo<isize> for [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 `[usize]` note: required by a bound in `Foo` diff --git a/tests/ui/error-codes/E0223.rs b/tests/ui/error-codes/E0223.rs index 6031b682d72..2fe252de256 100644 --- a/tests/ui/error-codes/E0223.rs +++ b/tests/ui/error-codes/E0223.rs @@ -1,4 +1,8 @@ trait MyTrait { type X; } +struct MyStruct; +impl MyTrait for MyStruct { + type X = (); +} fn main() { let foo: MyTrait::X; diff --git a/tests/ui/error-codes/E0223.stderr b/tests/ui/error-codes/E0223.stderr index 726f39e11f1..42945e42f6e 100644 --- a/tests/ui/error-codes/E0223.stderr +++ b/tests/ui/error-codes/E0223.stderr @@ -1,8 +1,8 @@ error[E0223]: ambiguous associated type - --> $DIR/E0223.rs:4:14 + --> $DIR/E0223.rs:8:14 | LL | let foo: MyTrait::X; - | ^^^^^^^^^^ help: use fully-qualified syntax: `<Type as MyTrait>::X` + | ^^^^^^^^^^ help: use the fully-qualified path: `<MyStruct as MyTrait>::X` error: aborting due to previous error diff --git a/tests/ui/error-codes/E0308-2.stderr b/tests/ui/error-codes/E0308-2.stderr index de54a417253..3a8a81a73a6 100644 --- a/tests/ui/error-codes/E0308-2.stderr +++ b/tests/ui/error-codes/E0308-2.stderr @@ -1,8 +1,8 @@ error[E0308]: mismatched types - --> $DIR/E0308-2.rs:9:6 + --> $DIR/E0308-2.rs:9:13 | LL | impl Eq for &dyn DynEq {} - | ^^ lifetime mismatch + | ^^^^^^^^^^ lifetime mismatch | = note: expected trait `<&dyn DynEq as PartialEq>` found trait `<&(dyn DynEq + 'static) as PartialEq>` diff --git a/tests/ui/feature-gates/feature-gate-abi-efiapi.rs b/tests/ui/feature-gates/feature-gate-abi-efiapi.rs deleted file mode 100644 index 0c0d736acd0..00000000000 --- a/tests/ui/feature-gates/feature-gate-abi-efiapi.rs +++ /dev/null @@ -1,33 +0,0 @@ -// needs-llvm-components: x86 -// compile-flags: --target=x86_64-unknown-linux-gnu --crate-type=rlib -#![no_core] -#![feature(no_core, lang_items)] -#[lang="sized"] -trait Sized { } - -// Functions -extern "efiapi" fn f1() {} //~ ERROR efiapi ABI is experimental - -// Methods in trait defintion -trait Tr { - extern "efiapi" fn f2(); //~ ERROR efiapi ABI is experimental - extern "efiapi" fn f3() {} //~ ERROR efiapi ABI is experimental -} - -struct S; - -// Methods in trait impl -impl Tr for S { - extern "efiapi" fn f2() {} //~ ERROR efiapi ABI is experimental -} - -// Methods in inherent impl -impl S { - extern "efiapi" fn f4() {} //~ ERROR efiapi ABI is experimental -} - -// Function pointer types -type A = extern "efiapi" fn(); //~ ERROR efiapi ABI is experimental - -// Foreign modules -extern "efiapi" {} //~ ERROR efiapi ABI is experimental diff --git a/tests/ui/feature-gates/feature-gate-abi-efiapi.stderr b/tests/ui/feature-gates/feature-gate-abi-efiapi.stderr deleted file mode 100644 index 5b01dcc6d85..00000000000 --- a/tests/ui/feature-gates/feature-gate-abi-efiapi.stderr +++ /dev/null @@ -1,66 +0,0 @@ -error[E0658]: efiapi ABI is experimental and subject to change - --> $DIR/feature-gate-abi-efiapi.rs:9:8 - | -LL | extern "efiapi" fn f1() {} - | ^^^^^^^^ - | - = note: see issue #65815 <https://github.com/rust-lang/rust/issues/65815> for more information - = help: add `#![feature(abi_efiapi)]` to the crate attributes to enable - -error[E0658]: efiapi ABI is experimental and subject to change - --> $DIR/feature-gate-abi-efiapi.rs:13:12 - | -LL | extern "efiapi" fn f2(); - | ^^^^^^^^ - | - = note: see issue #65815 <https://github.com/rust-lang/rust/issues/65815> for more information - = help: add `#![feature(abi_efiapi)]` to the crate attributes to enable - -error[E0658]: efiapi ABI is experimental and subject to change - --> $DIR/feature-gate-abi-efiapi.rs:14:12 - | -LL | extern "efiapi" fn f3() {} - | ^^^^^^^^ - | - = note: see issue #65815 <https://github.com/rust-lang/rust/issues/65815> for more information - = help: add `#![feature(abi_efiapi)]` to the crate attributes to enable - -error[E0658]: efiapi ABI is experimental and subject to change - --> $DIR/feature-gate-abi-efiapi.rs:21:12 - | -LL | extern "efiapi" fn f2() {} - | ^^^^^^^^ - | - = note: see issue #65815 <https://github.com/rust-lang/rust/issues/65815> for more information - = help: add `#![feature(abi_efiapi)]` to the crate attributes to enable - -error[E0658]: efiapi ABI is experimental and subject to change - --> $DIR/feature-gate-abi-efiapi.rs:26:12 - | -LL | extern "efiapi" fn f4() {} - | ^^^^^^^^ - | - = note: see issue #65815 <https://github.com/rust-lang/rust/issues/65815> for more information - = help: add `#![feature(abi_efiapi)]` to the crate attributes to enable - -error[E0658]: efiapi ABI is experimental and subject to change - --> $DIR/feature-gate-abi-efiapi.rs:30:17 - | -LL | type A = extern "efiapi" fn(); - | ^^^^^^^^ - | - = note: see issue #65815 <https://github.com/rust-lang/rust/issues/65815> for more information - = help: add `#![feature(abi_efiapi)]` to the crate attributes to enable - -error[E0658]: efiapi ABI is experimental and subject to change - --> $DIR/feature-gate-abi-efiapi.rs:33:8 - | -LL | extern "efiapi" {} - | ^^^^^^^^ - | - = note: see issue #65815 <https://github.com/rust-lang/rust/issues/65815> for more information - = help: add `#![feature(abi_efiapi)]` to the crate attributes to enable - -error: aborting due to 7 previous errors - -For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/functions-closures/fn-help-with-err-generic-is-not-function.stderr b/tests/ui/functions-closures/fn-help-with-err-generic-is-not-function.stderr index 26bdf460f5e..9d4ea01152c 100644 --- a/tests/ui/functions-closures/fn-help-with-err-generic-is-not-function.stderr +++ b/tests/ui/functions-closures/fn-help-with-err-generic-is-not-function.stderr @@ -2,9 +2,12 @@ error[E0412]: cannot find type `T` in this scope --> $DIR/fn-help-with-err-generic-is-not-function.rs:2:13 | LL | impl Struct<T> - | - ^ not found in this scope - | | - | help: you might be missing a type parameter: `<T>` + | ^ not found in this scope + | +help: you might be missing a type parameter + | +LL | impl<T> Struct<T> + | +++ error[E0412]: cannot find type `T` in this scope --> $DIR/fn-help-with-err-generic-is-not-function.rs:7:5 diff --git a/tests/ui/impl-trait/impl_trait_projections.rs b/tests/ui/impl-trait/impl_trait_projections.rs index fd0986d7c0a..b3ff2ce5a7b 100644 --- a/tests/ui/impl-trait/impl_trait_projections.rs +++ b/tests/ui/impl-trait/impl_trait_projections.rs @@ -11,7 +11,7 @@ fn path_parametrized_type_is_allowed() -> option::Option<impl Debug> { fn projection_is_disallowed(x: impl Iterator) -> <impl Iterator>::Item { //~^ ERROR `impl Trait` is not allowed in path parameters -//~^^ ERROR ambiguous associated type +//~| ERROR `impl Trait` is not allowed in path parameters x.next().unwrap() } diff --git a/tests/ui/impl-trait/impl_trait_projections.stderr b/tests/ui/impl-trait/impl_trait_projections.stderr index 82d2422c407..4deb24731bc 100644 --- a/tests/ui/impl-trait/impl_trait_projections.stderr +++ b/tests/ui/impl-trait/impl_trait_projections.stderr @@ -22,13 +22,12 @@ error[E0667]: `impl Trait` is not allowed in path parameters LL | -> <dyn Iterator<Item = impl Debug> as Iterator>::Item | ^^^^^^^^^^ -error[E0223]: ambiguous associated type - --> $DIR/impl_trait_projections.rs:12:50 +error[E0667]: `impl Trait` is not allowed in path parameters + --> $DIR/impl_trait_projections.rs:12:51 | LL | fn projection_is_disallowed(x: impl Iterator) -> <impl Iterator>::Item { - | ^^^^^^^^^^^^^^^^^^^^^ help: use fully-qualified syntax: `<impl Iterator as Trait>::Item` + | ^^^^^^^^^^^^^ error: aborting due to 5 previous errors -Some errors have detailed explanations: E0223, E0667. -For more information about an error, try `rustc --explain E0223`. +For more information about this error, try `rustc --explain E0667`. diff --git a/tests/ui/implied-bounds/impl-implied-bounds-compatibility-unnormalized.stderr b/tests/ui/implied-bounds/impl-implied-bounds-compatibility-unnormalized.stderr index 0ac31c642eb..ebe07027d2f 100644 --- a/tests/ui/implied-bounds/impl-implied-bounds-compatibility-unnormalized.stderr +++ b/tests/ui/implied-bounds/impl-implied-bounds-compatibility-unnormalized.stderr @@ -1,8 +1,8 @@ error: impl method assumes more implied bounds than the corresponding trait method - --> $DIR/impl-implied-bounds-compatibility-unnormalized.rs:13:5 + --> $DIR/impl-implied-bounds-compatibility-unnormalized.rs:13:31 | LL | fn get<'s>(s: &'s str, _: <&'static &'s () as Project>::Ty) -> &'static str { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace this type to make the impl signature compatible: `()` | = 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 #105572 <https://github.com/rust-lang/rust/issues/105572> @@ -14,3 +14,18 @@ LL | #![deny(implied_bounds_entailment)] error: aborting due to previous error +Future incompatibility report: Future breakage diagnostic: +error: impl method assumes more implied bounds than the corresponding trait method + --> $DIR/impl-implied-bounds-compatibility-unnormalized.rs:13:31 + | +LL | fn get<'s>(s: &'s str, _: <&'static &'s () as Project>::Ty) -> &'static str { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace this type to make the impl signature compatible: `()` + | + = 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 #105572 <https://github.com/rust-lang/rust/issues/105572> +note: the lint level is defined here + --> $DIR/impl-implied-bounds-compatibility-unnormalized.rs:1:9 + | +LL | #![deny(implied_bounds_entailment)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + diff --git a/tests/ui/implied-bounds/impl-implied-bounds-compatibility.stderr b/tests/ui/implied-bounds/impl-implied-bounds-compatibility.stderr index 0dfa8167a99..43d3e058ffe 100644 --- a/tests/ui/implied-bounds/impl-implied-bounds-compatibility.stderr +++ b/tests/ui/implied-bounds/impl-implied-bounds-compatibility.stderr @@ -1,8 +1,8 @@ error: impl method assumes more implied bounds than the corresponding trait method - --> $DIR/impl-implied-bounds-compatibility.rs:14:5 + --> $DIR/impl-implied-bounds-compatibility.rs:14:35 | LL | fn listeners<'b>(&'b self) -> &'a MessageListeners<'b> { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: replace this type to make the impl signature compatible: `&'b MessageListeners<'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 #105572 <https://github.com/rust-lang/rust/issues/105572> @@ -14,3 +14,18 @@ LL | #![deny(implied_bounds_entailment)] error: aborting due to previous error +Future incompatibility report: Future breakage diagnostic: +error: impl method assumes more implied bounds than the corresponding trait method + --> $DIR/impl-implied-bounds-compatibility.rs:14:35 + | +LL | fn listeners<'b>(&'b self) -> &'a MessageListeners<'b> { + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: replace this type to make the impl signature compatible: `&'b MessageListeners<'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 #105572 <https://github.com/rust-lang/rust/issues/105572> +note: the lint level is defined here + --> $DIR/impl-implied-bounds-compatibility.rs:1:9 + | +LL | #![deny(implied_bounds_entailment)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + diff --git a/tests/ui/issues/issue-23073.stderr b/tests/ui/issues/issue-23073.stderr index 3a10a1ab11a..3a9f49ef167 100644 --- a/tests/ui/issues/issue-23073.stderr +++ b/tests/ui/issues/issue-23073.stderr @@ -2,7 +2,12 @@ error[E0223]: ambiguous associated type --> $DIR/issue-23073.rs:6:17 | LL | type FooT = <<Self as Bar>::Foo>::T; - | ^^^^^^^^^^^^^^^^^^^^^^^ help: use fully-qualified syntax: `<<Self as Bar>::Foo as Trait>::T` + | ^^^^^^^^^^^^^^^^^^^^^^^ + | +help: if there were a trait named `Example` with associated type `T` implemented for `<Self as Bar>::Foo`, you could use the fully-qualified path + | +LL | type FooT = <<Self as Bar>::Foo as Example>::T; + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: aborting due to previous error diff --git a/tests/ui/issues/issue-58712.stderr b/tests/ui/issues/issue-58712.stderr index 87c16aa993b..f4bd4d1e826 100644 --- a/tests/ui/issues/issue-58712.stderr +++ b/tests/ui/issues/issue-58712.stderr @@ -2,9 +2,12 @@ error[E0412]: cannot find type `DeviceId` in this scope --> $DIR/issue-58712.rs:6:20 | LL | impl<H> AddrVec<H, DeviceId> { - | - ^^^^^^^^ not found in this scope - | | - | help: you might be missing a type parameter: `, DeviceId` + | ^^^^^^^^ not found in this scope + | +help: you might be missing a type parameter + | +LL | impl<H, DeviceId> AddrVec<H, DeviceId> { + | ++++++++++ error[E0412]: cannot find type `DeviceId` in this scope --> $DIR/issue-58712.rs:8:29 diff --git a/tests/ui/issues/issue-65230.stderr b/tests/ui/issues/issue-65230.stderr index fcabcdea74f..7ccab889483 100644 --- a/tests/ui/issues/issue-65230.stderr +++ b/tests/ui/issues/issue-65230.stderr @@ -1,8 +1,8 @@ error[E0308]: mismatched types - --> $DIR/issue-65230.rs:8:6 + --> $DIR/issue-65230.rs:8:13 | LL | impl T1 for &dyn T2 {} - | ^^ lifetime mismatch + | ^^^^^^^ lifetime mismatch | = note: expected trait `<&dyn T2 as T0>` found trait `<&(dyn T2 + 'static) as T0>` diff --git a/tests/ui/issues/issue-77919.stderr b/tests/ui/issues/issue-77919.stderr index ca256847b1f..d154bfe0cb5 100644 --- a/tests/ui/issues/issue-77919.stderr +++ b/tests/ui/issues/issue-77919.stderr @@ -13,9 +13,12 @@ error[E0412]: cannot find type `VAL` in this scope --> $DIR/issue-77919.rs:11:63 | LL | impl<N, M> TypeVal<usize> for Multiply<N, M> where N: TypeVal<VAL> {} - | - ^^^ not found in this scope - | | - | help: you might be missing a type parameter: `, VAL` + | ^^^ not found in this scope + | +help: you might be missing a type parameter + | +LL | impl<N, M, VAL> TypeVal<usize> for Multiply<N, M> where N: TypeVal<VAL> {} + | +++++ error[E0046]: not all trait items implemented, missing: `VAL` --> $DIR/issue-77919.rs:11:1 diff --git a/tests/ui/issues/issue-78622.stderr b/tests/ui/issues/issue-78622.stderr index f7d44f21d3b..70daf8a2f1a 100644 --- a/tests/ui/issues/issue-78622.stderr +++ b/tests/ui/issues/issue-78622.stderr @@ -2,7 +2,12 @@ error[E0223]: ambiguous associated type --> $DIR/issue-78622.rs:5:5 | LL | S::A::<f> {} - | ^^^^ help: use fully-qualified syntax: `<S as Trait>::A` + | ^^^^ + | +help: if there were a trait named `Example` with associated type `A` implemented for `S`, you could use the fully-qualified path + | +LL | <S as Example>::A::<f> {} + | ~~~~~~~~~~~~~~~~~ error: aborting due to previous error diff --git a/tests/ui/issues/issue-86756.stderr b/tests/ui/issues/issue-86756.stderr index 6c5917bdf6e..bfa7459ab4a 100644 --- a/tests/ui/issues/issue-86756.stderr +++ b/tests/ui/issues/issue-86756.stderr @@ -9,8 +9,6 @@ LL | trait Foo<T, T = T> {} error[E0412]: cannot find type `dyn` in this scope --> $DIR/issue-86756.rs:5:10 | -LL | fn eq<A, B>() { - | - help: you might be missing a type parameter: `, dyn` LL | eq::<dyn, Foo> | ^^^ not found in this scope diff --git a/tests/ui/iterators/float_iterator_hint.rs b/tests/ui/iterators/float_iterator_hint.rs new file mode 100644 index 00000000000..a3335ca41f7 --- /dev/null +++ b/tests/ui/iterators/float_iterator_hint.rs @@ -0,0 +1,15 @@ +// #106728 + +fn main() { + for i in 0.2 { + //~^ ERROR `{float}` is not an iterator + //~| `{float}` is not an iterator + //~| NOTE in this expansion of desugaring of `for` loop + //~| NOTE in this expansion of desugaring of `for` loop + //~| NOTE in this expansion of desugaring of `for` loop + //~| NOTE in this expansion of desugaring of `for` loop + //~| NOTE if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end` + //~| NOTE required for `{float}` to implement `IntoIterator` + println!(); + } +} diff --git a/tests/ui/iterators/float_iterator_hint.stderr b/tests/ui/iterators/float_iterator_hint.stderr new file mode 100644 index 00000000000..bae23a1f8ff --- /dev/null +++ b/tests/ui/iterators/float_iterator_hint.stderr @@ -0,0 +1,13 @@ +error[E0277]: `{float}` is not an iterator + --> $DIR/float_iterator_hint.rs:4:14 + | +LL | for i in 0.2 { + | ^^^ `{float}` is not an iterator + | + = help: the trait `Iterator` is not implemented for `{float}` + = note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end` + = note: required for `{float}` to implement `IntoIterator` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/iterators/integral.stderr b/tests/ui/iterators/integral.stderr index 047a71f98d9..c142fec8da0 100644 --- a/tests/ui/iterators/integral.stderr +++ b/tests/ui/iterators/integral.stderr @@ -115,6 +115,7 @@ LL | for _ in 42.0 {} | ^^^^ `{float}` is not an iterator | = help: the trait `Iterator` is not implemented for `{float}` + = note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end` = note: required for `{float}` to implement `IntoIterator` error: aborting due to 12 previous errors diff --git a/tests/ui/iterators/invalid-iterator-chain-with-int-infer.rs b/tests/ui/iterators/invalid-iterator-chain-with-int-infer.rs new file mode 100644 index 00000000000..882a1d13954 --- /dev/null +++ b/tests/ui/iterators/invalid-iterator-chain-with-int-infer.rs @@ -0,0 +1,4 @@ +fn main() { + let x = Some(()).iter().map(|()| 1).sum::<f32>(); + //~^ ERROR a value of type `f32` cannot be made by summing an iterator over elements of type `{integer}` +} diff --git a/tests/ui/iterators/invalid-iterator-chain-with-int-infer.stderr b/tests/ui/iterators/invalid-iterator-chain-with-int-infer.stderr new file mode 100644 index 00000000000..3cb5e44c711 --- /dev/null +++ b/tests/ui/iterators/invalid-iterator-chain-with-int-infer.stderr @@ -0,0 +1,24 @@ +error[E0277]: a value of type `f32` cannot be made by summing an iterator over elements of type `{integer}` + --> $DIR/invalid-iterator-chain-with-int-infer.rs:2:41 + | +LL | let x = Some(()).iter().map(|()| 1).sum::<f32>(); + | ^^^ value of type `f32` cannot be made by summing a `std::iter::Iterator<Item={integer}>` + | + = help: the trait `Sum<{integer}>` is not implemented for `f32` + = help: the following other types implement trait `Sum<A>`: + <f32 as Sum<&'a f32>> + <f32 as Sum> +note: the method call chain might not have had the expected associated types + --> $DIR/invalid-iterator-chain-with-int-infer.rs:2:29 + | +LL | let x = Some(()).iter().map(|()| 1).sum::<f32>(); + | -------- ------ ^^^^^^^^^^^ `Iterator::Item` changed to `{integer}` here + | | | + | | `Iterator::Item` is `&()` here + | this expression has type `Option<()>` +note: required by a bound in `std::iter::Iterator::sum` + --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/lang-items/start_lang_item_args.argc.stderr b/tests/ui/lang-items/start_lang_item_args.argc.stderr new file mode 100644 index 00000000000..65c99a93c75 --- /dev/null +++ b/tests/ui/lang-items/start_lang_item_args.argc.stderr @@ -0,0 +1,8 @@ +error: parameter 2 of the `start` lang item is incorrect + --> $DIR/start_lang_item_args.rs:75:38 + | +LL | fn start<T>(_main: fn() -> T, _argc: i8, _argv: *const *const u8, _sigpipe: u8) -> isize { + | ^^ help: change the type from `i8` to `isize` + +error: aborting due to previous error + diff --git a/tests/ui/lang-items/start_lang_item_args.argv.stderr b/tests/ui/lang-items/start_lang_item_args.argv.stderr new file mode 100644 index 00000000000..f0947a9b3e9 --- /dev/null +++ b/tests/ui/lang-items/start_lang_item_args.argv.stderr @@ -0,0 +1,8 @@ +error: parameter 3 of the `start` lang item is incorrect + --> $DIR/start_lang_item_args.rs:89:52 + | +LL | fn start<T>(_main: fn() -> T, _argc: isize, _argv: u8, _sigpipe: u8) -> isize { + | ^^ help: change the type from `u8` to `*const *const u8` + +error: aborting due to previous error + diff --git a/tests/ui/lang-items/start_lang_item_args.argv_inner_ptr.stderr b/tests/ui/lang-items/start_lang_item_args.argv_inner_ptr.stderr new file mode 100644 index 00000000000..08efd5088f9 --- /dev/null +++ b/tests/ui/lang-items/start_lang_item_args.argv_inner_ptr.stderr @@ -0,0 +1,13 @@ +error: parameter 3 of the `start` lang item is incorrect + --> $DIR/start_lang_item_args.rs:82:52 + | +LL | fn start<T>(_main: fn() -> T, _argc: isize, _argv: *const *const usize, _sigpipe: u8) -> isize { + | ^^^^^^^^^^^^^^^^^^^ + | +help: change the type from `*const *const usize` to `*const *const u8` + | +LL | fn start<T>(_main: fn() -> T, _argc: isize, _argv: *const *const u8, _sigpipe: u8) -> isize { + | ~~~~~~~~~~~~~~~~ + +error: aborting due to previous error + diff --git a/tests/ui/lang-items/start_lang_item_args.main_args.stderr b/tests/ui/lang-items/start_lang_item_args.main_args.stderr new file mode 100644 index 00000000000..c20a744661d --- /dev/null +++ b/tests/ui/lang-items/start_lang_item_args.main_args.stderr @@ -0,0 +1,13 @@ +error: parameter 1 of the `start` lang item is incorrect + --> $DIR/start_lang_item_args.rs:61:20 + | +LL | fn start<T>(_main: fn(i32) -> T, _argc: isize, _argv: *const *const u8, _sigpipe: u8) -> isize { + | ^^^^^^^^^^^^ + | +help: change the type from `fn(i32) -> T` to `fn() -> T` + | +LL | fn start<T>(_main: fn() -> T, _argc: isize, _argv: *const *const u8, _sigpipe: u8) -> isize { + | ~~~~~~~~~ + +error: aborting due to previous error + diff --git a/tests/ui/lang-items/start_lang_item_args.main_ret.stderr b/tests/ui/lang-items/start_lang_item_args.main_ret.stderr new file mode 100644 index 00000000000..8f967252f49 --- /dev/null +++ b/tests/ui/lang-items/start_lang_item_args.main_ret.stderr @@ -0,0 +1,13 @@ +error: parameter 1 of the `start` lang item is incorrect + --> $DIR/start_lang_item_args.rs:68:20 + | +LL | fn start<T>(_main: fn() -> u16, _argc: isize, _argv: *const *const u8, _sigpipe: u8) -> isize { + | ^^^^^^^^^^^ + | +help: change the type from `fn() -> u16` to `fn() -> T` + | +LL | fn start<T>(_main: fn() -> T, _argc: isize, _argv: *const *const u8, _sigpipe: u8) -> isize { + | ~~~~~~~~~ + +error: aborting due to previous error + diff --git a/tests/ui/lang-items/start_lang_item_args.main_ty.stderr b/tests/ui/lang-items/start_lang_item_args.main_ty.stderr new file mode 100644 index 00000000000..deb37b868ea --- /dev/null +++ b/tests/ui/lang-items/start_lang_item_args.main_ty.stderr @@ -0,0 +1,8 @@ +error: parameter 1 of the `start` lang item is incorrect + --> $DIR/start_lang_item_args.rs:54:20 + | +LL | fn start<T>(_main: u64, _argc: isize, _argv: *const *const u8, _sigpipe: u8) -> isize { + | ^^^ help: change the type from `u64` to `fn() -> T` + +error: aborting due to previous error + diff --git a/tests/ui/lang-items/start_lang_item_args.missing_all_args.stderr b/tests/ui/lang-items/start_lang_item_args.missing_all_args.stderr new file mode 100644 index 00000000000..004c2a67f62 --- /dev/null +++ b/tests/ui/lang-items/start_lang_item_args.missing_all_args.stderr @@ -0,0 +1,11 @@ +error: incorrect number of parameters for the `start` lang item + --> $DIR/start_lang_item_args.rs:15:1 + | +LL | fn start<T>() -> isize { + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = note: the `start` lang item should have four parameters, but found 0 + = note: the `start` lang item should have the signature `fn(fn() -> T, isize, *const *const u8, u8) -> isize` + +error: aborting due to previous error + diff --git a/tests/ui/lang-items/start_lang_item_args.missing_ret.stderr b/tests/ui/lang-items/start_lang_item_args.missing_ret.stderr new file mode 100644 index 00000000000..1d8285b5900 --- /dev/null +++ b/tests/ui/lang-items/start_lang_item_args.missing_ret.stderr @@ -0,0 +1,8 @@ +error: the return type of the `start` lang item is incorrect + --> $DIR/start_lang_item_args.rs:29:84 + | +LL | fn start<T>(_main: fn() -> T, _argc: isize, _argv: *const *const u8, _sigpipe: u8) {} + | ^ help: change the type from `()` to `isize` + +error: aborting due to previous error + diff --git a/tests/ui/lang-items/start_lang_item_args.missing_sigpipe_arg.stderr b/tests/ui/lang-items/start_lang_item_args.missing_sigpipe_arg.stderr new file mode 100644 index 00000000000..e545a750f24 --- /dev/null +++ b/tests/ui/lang-items/start_lang_item_args.missing_sigpipe_arg.stderr @@ -0,0 +1,11 @@ +error: incorrect number of parameters for the `start` lang item + --> $DIR/start_lang_item_args.rs:22:1 + | +LL | fn start<T>(_main: fn() -> T, _argc: isize, _argv: *const *const u8) -> isize { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: the `start` lang item should have four parameters, but found 3 + = note: the `start` lang item should have the signature `fn(fn() -> T, isize, *const *const u8, u8) -> isize` + +error: aborting due to previous error + diff --git a/tests/ui/lang-items/start_lang_item_args.rs b/tests/ui/lang-items/start_lang_item_args.rs new file mode 100644 index 00000000000..0dbfba39cb6 --- /dev/null +++ b/tests/ui/lang-items/start_lang_item_args.rs @@ -0,0 +1,101 @@ +// check-fail +// revisions: missing_all_args missing_sigpipe_arg missing_ret start_ret too_many_args +// revisions: main_ty main_args main_ret argc argv_inner_ptr argv sigpipe + +#![feature(lang_items, no_core)] +#![no_core] + +#[lang = "copy"] +pub trait Copy {} +#[lang = "sized"] +pub trait Sized {} + +#[cfg(missing_all_args)] +#[lang = "start"] +fn start<T>() -> isize { + //[missing_all_args]~^ ERROR incorrect number of parameters + 100 +} + +#[cfg(missing_sigpipe_arg)] +#[lang = "start"] +fn start<T>(_main: fn() -> T, _argc: isize, _argv: *const *const u8) -> isize { + //[missing_sigpipe_arg]~^ ERROR incorrect number of parameters + 100 +} + +#[cfg(missing_ret)] +#[lang = "start"] +fn start<T>(_main: fn() -> T, _argc: isize, _argv: *const *const u8, _sigpipe: u8) {} +//[missing_ret]~^ ERROR the return type of the `start` lang item is incorrect + +#[cfg(start_ret)] +#[lang = "start"] +fn start<T>(_main: fn() -> T, _argc: isize, _argv: *const *const u8, _sigpipe: u8) -> u8 { + //[start_ret]~^ ERROR the return type of the `start` lang item is incorrect + 100 +} + +#[cfg(too_many_args)] +#[lang = "start"] +fn start<T>( + //[too_many_args]~^ ERROR incorrect number of parameters + _main: fn() -> T, + _argc: isize, + _argv: *const *const u8, + _sigpipe: u8, + _extra_arg: (), +) -> isize { + 100 +} + +#[cfg(main_ty)] +#[lang = "start"] +fn start<T>(_main: u64, _argc: isize, _argv: *const *const u8, _sigpipe: u8) -> isize { + //[main_ty]~^ ERROR parameter 1 of the `start` lang item is incorrect + 100 +} + +#[cfg(main_args)] +#[lang = "start"] +fn start<T>(_main: fn(i32) -> T, _argc: isize, _argv: *const *const u8, _sigpipe: u8) -> isize { + //[main_args]~^ ERROR parameter 1 of the `start` lang item is incorrect + 100 +} + +#[cfg(main_ret)] +#[lang = "start"] +fn start<T>(_main: fn() -> u16, _argc: isize, _argv: *const *const u8, _sigpipe: u8) -> isize { + //[main_ret]~^ ERROR parameter 1 of the `start` lang item is incorrect + 100 +} + +#[cfg(argc)] +#[lang = "start"] +fn start<T>(_main: fn() -> T, _argc: i8, _argv: *const *const u8, _sigpipe: u8) -> isize { + //[argc]~^ ERROR parameter 2 of the `start` lang item is incorrect + 100 +} + +#[cfg(argv_inner_ptr)] +#[lang = "start"] +fn start<T>(_main: fn() -> T, _argc: isize, _argv: *const *const usize, _sigpipe: u8) -> isize { + //[argv_inner_ptr]~^ ERROR parameter 3 of the `start` lang item is incorrect + 100 +} + +#[cfg(argv)] +#[lang = "start"] +fn start<T>(_main: fn() -> T, _argc: isize, _argv: u8, _sigpipe: u8) -> isize { + //[argv]~^ ERROR parameter 3 of the `start` lang item is incorrect + 100 +} + +#[cfg(sigpipe)] +#[lang = "start"] +fn start<T>(_main: fn() -> T, _argc: isize, _argv: *const *const u8, _sigpipe: i64) -> isize { + //[sigpipe]~^ ERROR parameter 4 of the `start` lang item is incorrect + 100 +} + +fn main() {} diff --git a/tests/ui/lang-items/start_lang_item_args.sigpipe.stderr b/tests/ui/lang-items/start_lang_item_args.sigpipe.stderr new file mode 100644 index 00000000000..b20ae312801 --- /dev/null +++ b/tests/ui/lang-items/start_lang_item_args.sigpipe.stderr @@ -0,0 +1,8 @@ +error: parameter 4 of the `start` lang item is incorrect + --> $DIR/start_lang_item_args.rs:96:80 + | +LL | fn start<T>(_main: fn() -> T, _argc: isize, _argv: *const *const u8, _sigpipe: i64) -> isize { + | ^^^ help: change the type from `i64` to `u8` + +error: aborting due to previous error + diff --git a/tests/ui/lang-items/start_lang_item_args.start_ret.stderr b/tests/ui/lang-items/start_lang_item_args.start_ret.stderr new file mode 100644 index 00000000000..935d5f3c8b4 --- /dev/null +++ b/tests/ui/lang-items/start_lang_item_args.start_ret.stderr @@ -0,0 +1,8 @@ +error: the return type of the `start` lang item is incorrect + --> $DIR/start_lang_item_args.rs:34:87 + | +LL | fn start<T>(_main: fn() -> T, _argc: isize, _argv: *const *const u8, _sigpipe: u8) -> u8 { + | ^^ help: change the type from `u8` to `isize` + +error: aborting due to previous error + diff --git a/tests/ui/lang-items/start_lang_item_args.too_many_args.stderr b/tests/ui/lang-items/start_lang_item_args.too_many_args.stderr new file mode 100644 index 00000000000..30a7ed18a3d --- /dev/null +++ b/tests/ui/lang-items/start_lang_item_args.too_many_args.stderr @@ -0,0 +1,17 @@ +error: incorrect number of parameters for the `start` lang item + --> $DIR/start_lang_item_args.rs:41:1 + | +LL | / fn start<T>( +LL | | +LL | | _main: fn() -> T, +LL | | _argc: isize, +... | +LL | | _extra_arg: (), +LL | | ) -> isize { + | |__________^ + | + = note: the `start` lang item should have four parameters, but found 5 + = note: the `start` lang item should have the signature `fn(fn() -> T, isize, *const *const u8, u8) -> isize` + +error: aborting due to previous error + diff --git a/tests/ui/lint/bare-trait-objects-path.stderr b/tests/ui/lint/bare-trait-objects-path.stderr index 8ed303ca606..a19f4963c23 100644 --- a/tests/ui/lint/bare-trait-objects-path.stderr +++ b/tests/ui/lint/bare-trait-objects-path.stderr @@ -16,7 +16,7 @@ error[E0223]: ambiguous associated type --> $DIR/bare-trait-objects-path.rs:23:12 | LL | let _: Dyn::Ty; - | ^^^^^^^ help: use fully-qualified syntax: `<dyn Dyn as Trait>::Ty` + | ^^^^^^^ help: use the fully-qualified path: `<dyn Dyn as Assoc>::Ty` warning: trait objects without an explicit `dyn` are deprecated --> $DIR/bare-trait-objects-path.rs:14:5 diff --git a/tests/ui/lint/lint-ffi-safety-all-phantom.rs b/tests/ui/lint/lint-ffi-safety-all-phantom.rs new file mode 100644 index 00000000000..7419d345800 --- /dev/null +++ b/tests/ui/lint/lint-ffi-safety-all-phantom.rs @@ -0,0 +1,22 @@ +// This is a regression test for issue https://github.com/rust-lang/rust/issues/106629. +// It ensures that transparent types where all fields are PhantomData are marked as +// FFI-safe. + +// check-pass + +#[repr(transparent)] +#[derive(Copy, Clone)] +struct MyPhantom(core::marker::PhantomData<u8>); + +#[repr(C)] +#[derive(Copy, Clone)] +pub struct Bar { + pub x: i32, + _marker: MyPhantom, +} + +extern "C" { + pub fn foo(bar: *mut Bar); +} + +fn main() {} diff --git a/tests/ui/marker_trait_attr/overlap-marker-trait-with-underscore-lifetime.stderr b/tests/ui/marker_trait_attr/overlap-marker-trait-with-underscore-lifetime.stderr index 235c89e200a..3cd59d6926e 100644 --- a/tests/ui/marker_trait_attr/overlap-marker-trait-with-underscore-lifetime.stderr +++ b/tests/ui/marker_trait_attr/overlap-marker-trait-with-underscore-lifetime.stderr @@ -1,8 +1,8 @@ error[E0283]: type annotations needed: cannot satisfy `&(): Marker` - --> $DIR/overlap-marker-trait-with-underscore-lifetime.rs:6:6 + --> $DIR/overlap-marker-trait-with-underscore-lifetime.rs:6:17 | LL | impl Marker for &'_ () {} - | ^^^^^^ + | ^^^^^^ | note: multiple `impl`s satisfying `&(): Marker` found --> $DIR/overlap-marker-trait-with-underscore-lifetime.rs:6:1 @@ -13,10 +13,10 @@ LL | impl Marker for &'_ () {} | ^^^^^^^^^^^^^^^^^^^^^^ error[E0283]: type annotations needed: cannot satisfy `&(): Marker` - --> $DIR/overlap-marker-trait-with-underscore-lifetime.rs:7:6 + --> $DIR/overlap-marker-trait-with-underscore-lifetime.rs:7:17 | LL | impl Marker for &'_ () {} - | ^^^^^^ + | ^^^^^^ | note: multiple `impl`s satisfying `&(): Marker` found --> $DIR/overlap-marker-trait-with-underscore-lifetime.rs:6:1 diff --git a/tests/ui/marker_trait_attr/region-overlap.stderr b/tests/ui/marker_trait_attr/region-overlap.stderr index 6631fe987e2..c6497b4669d 100644 --- a/tests/ui/marker_trait_attr/region-overlap.stderr +++ b/tests/ui/marker_trait_attr/region-overlap.stderr @@ -1,8 +1,8 @@ error[E0283]: type annotations needed: cannot satisfy `(&'static (), &'a ()): A` - --> $DIR/region-overlap.rs:5:10 + --> $DIR/region-overlap.rs:5:16 | LL | impl<'a> A for (&'static (), &'a ()) {} - | ^ + | ^^^^^^^^^^^^^^^^^^^^^ | note: multiple `impl`s satisfying `(&'static (), &'a ()): A` found --> $DIR/region-overlap.rs:5:1 @@ -13,10 +13,10 @@ LL | impl<'a> A for (&'a (), &'static ()) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0283]: type annotations needed: cannot satisfy `(&'a (), &'static ()): A` - --> $DIR/region-overlap.rs:6:10 + --> $DIR/region-overlap.rs:6:16 | LL | impl<'a> A for (&'a (), &'static ()) {} - | ^ + | ^^^^^^^^^^^^^^^^^^^^^ | note: multiple `impl`s satisfying `(&'a (), &'static ()): A` found --> $DIR/region-overlap.rs:5:1 diff --git a/tests/ui/never_type/issue-52443.stderr b/tests/ui/never_type/issue-52443.stderr index de5c9c56016..33b7a9185d0 100644 --- a/tests/ui/never_type/issue-52443.stderr +++ b/tests/ui/never_type/issue-52443.stderr @@ -47,6 +47,7 @@ LL | [(); { for _ in 0usize.. {}; 0}]; note: impl defined here, but it is not `const` --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL = note: calls in constants are limited to constant functions, tuple structs and tuple variants + = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable error[E0658]: mutable references are not allowed in constants --> $DIR/issue-52443.rs:9:21 @@ -64,6 +65,7 @@ LL | [(); { for _ in 0usize.. {}; 0}]; | ^^^^^^^^ | = note: calls in constants are limited to constant functions, tuple structs and tuple variants + = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable error: aborting due to 6 previous errors; 1 warning emitted diff --git a/tests/ui/parser/dyn-trait-compatibility.stderr b/tests/ui/parser/dyn-trait-compatibility.stderr index 9218ae9d5da..0cae01bd1e3 100644 --- a/tests/ui/parser/dyn-trait-compatibility.stderr +++ b/tests/ui/parser/dyn-trait-compatibility.stderr @@ -26,17 +26,13 @@ error[E0412]: cannot find type `dyn` in this scope --> $DIR/dyn-trait-compatibility.rs:5:15 | LL | type A2 = dyn<dyn, dyn>; - | - ^^^ not found in this scope - | | - | help: you might be missing a type parameter: `<dyn>` + | ^^^ not found in this scope error[E0412]: cannot find type `dyn` in this scope --> $DIR/dyn-trait-compatibility.rs:5:20 | LL | type A2 = dyn<dyn, dyn>; - | - ^^^ not found in this scope - | | - | help: you might be missing a type parameter: `<dyn>` + | ^^^ not found in this scope error[E0412]: cannot find type `dyn` in this scope --> $DIR/dyn-trait-compatibility.rs:9:11 @@ -48,9 +44,7 @@ error[E0412]: cannot find type `dyn` in this scope --> $DIR/dyn-trait-compatibility.rs:9:16 | LL | type A3 = dyn<<dyn as dyn>::dyn>; - | - ^^^ not found in this scope - | | - | help: you might be missing a type parameter: `<dyn>` + | ^^^ not found in this scope error: aborting due to 8 previous errors diff --git a/tests/ui/parser/recover-quantified-closure.rs b/tests/ui/parser/recover-quantified-closure.rs index 10af39b7007..df22f5e065c 100644 --- a/tests/ui/parser/recover-quantified-closure.rs +++ b/tests/ui/parser/recover-quantified-closure.rs @@ -7,6 +7,6 @@ fn main() { enum Foo { Bar } fn foo(x: impl Iterator<Item = Foo>) { for <Foo>::Bar in x {} - //~^ ERROR expected one of `move`, `static`, `|` + //~^ ERROR expected one of `const`, `move`, `static`, `|` //~^^ ERROR `for<...>` binders for closures are experimental } diff --git a/tests/ui/parser/recover-quantified-closure.stderr b/tests/ui/parser/recover-quantified-closure.stderr index 39eec80f658..9ec4d2c034d 100644 --- a/tests/ui/parser/recover-quantified-closure.stderr +++ b/tests/ui/parser/recover-quantified-closure.stderr @@ -1,8 +1,8 @@ -error: expected one of `move`, `static`, `|`, or `||`, found `::` +error: expected one of `const`, `move`, `static`, `|`, or `||`, found `::` --> $DIR/recover-quantified-closure.rs:9:14 | LL | for <Foo>::Bar in x {} - | ^^ expected one of `move`, `static`, `|`, or `||` + | ^^ expected one of `const`, `move`, `static`, `|`, or `||` error[E0658]: `for<...>` binders for closures are experimental --> $DIR/recover-quantified-closure.rs:2:5 diff --git a/tests/ui/privacy/issue-75906.stderr b/tests/ui/privacy/issue-75906.stderr index 4c6a68646ad..600dc7c876f 100644 --- a/tests/ui/privacy/issue-75906.stderr +++ b/tests/ui/privacy/issue-75906.stderr @@ -9,6 +9,10 @@ note: constructor is not visible here due to private fields | LL | pub struct Bar(u8); | ^^ private field +help: consider making the field publicly accessible + | +LL | pub struct Bar(pub u8); + | +++ error: aborting due to previous error diff --git a/tests/ui/privacy/issue-75907.rs b/tests/ui/privacy/issue-75907.rs index 6da99cf6435..3bed841d13e 100644 --- a/tests/ui/privacy/issue-75907.rs +++ b/tests/ui/privacy/issue-75907.rs @@ -2,7 +2,7 @@ mod foo { pub(crate) struct Foo(u8); - pub(crate) struct Bar(pub u8, u8, Foo); + pub(crate) struct Bar(pub u8, pub(in crate::foo) u8, Foo); pub(crate) fn make_bar() -> Bar { Bar(1, 12, Foo(10)) diff --git a/tests/ui/privacy/issue-75907.stderr b/tests/ui/privacy/issue-75907.stderr index 2f89e31a31a..f7cb874c2cc 100644 --- a/tests/ui/privacy/issue-75907.stderr +++ b/tests/ui/privacy/issue-75907.stderr @@ -11,6 +11,10 @@ LL | let Bar(x, y, Foo(z)) = make_bar(); | ^ ^^^^^^ private field | | | private field +help: consider making the fields publicly accessible + | +LL | pub(crate) struct Bar(pub u8, pub u8, pub Foo); + | ~~~ ~~~ +++ error[E0532]: cannot match against a tuple struct which contains private fields --> $DIR/issue-75907.rs:15:19 @@ -23,6 +27,10 @@ note: constructor is not visible here due to private fields | LL | let Bar(x, y, Foo(z)) = make_bar(); | ^ private field +help: consider making the field publicly accessible + | +LL | pub(crate) struct Foo(pub u8); + | +++ error: aborting due to 2 previous errors diff --git a/tests/ui/privacy/privacy5.stderr b/tests/ui/privacy/privacy5.stderr index 680161272ce..615b0af2762 100644 --- a/tests/ui/privacy/privacy5.stderr +++ b/tests/ui/privacy/privacy5.stderr @@ -12,6 +12,10 @@ note: the tuple struct constructor `A` is defined here | LL | pub struct A(()); | ^^^^^^^^^^^^^^^^^ +help: consider making the field publicly accessible + | +LL | pub struct A(pub ()); + | +++ error[E0603]: tuple struct constructor `B` is private --> $DIR/privacy5.rs:52:16 @@ -27,6 +31,10 @@ note: the tuple struct constructor `B` is defined here | LL | pub struct B(isize); | ^^^^^^^^^^^^^^^^^^^^ +help: consider making the field publicly accessible + | +LL | pub struct B(pub isize); + | +++ error[E0603]: tuple struct constructor `C` is private --> $DIR/privacy5.rs:53:16 @@ -42,6 +50,10 @@ note: the tuple struct constructor `C` is defined here | LL | pub struct C(pub isize, isize); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: consider making the fields publicly accessible + | +LL | pub struct C(pub isize, pub isize); + | ~~~ +++ error[E0603]: tuple struct constructor `A` is private --> $DIR/privacy5.rs:56:12 @@ -57,6 +69,10 @@ note: the tuple struct constructor `A` is defined here | LL | pub struct A(()); | ^^^^^^^^^^^^^^^^^ +help: consider making the field publicly accessible + | +LL | pub struct A(pub ()); + | +++ error[E0603]: tuple struct constructor `A` is private --> $DIR/privacy5.rs:57:12 @@ -72,6 +88,10 @@ note: the tuple struct constructor `A` is defined here | LL | pub struct A(()); | ^^^^^^^^^^^^^^^^^ +help: consider making the field publicly accessible + | +LL | pub struct A(pub ()); + | +++ error[E0603]: tuple struct constructor `A` is private --> $DIR/privacy5.rs:58:18 @@ -87,6 +107,10 @@ note: the tuple struct constructor `A` is defined here | LL | pub struct A(()); | ^^^^^^^^^^^^^^^^^ +help: consider making the field publicly accessible + | +LL | pub struct A(pub ()); + | +++ error[E0603]: tuple struct constructor `A` is private --> $DIR/privacy5.rs:59:18 @@ -102,6 +126,10 @@ note: the tuple struct constructor `A` is defined here | LL | pub struct A(()); | ^^^^^^^^^^^^^^^^^ +help: consider making the field publicly accessible + | +LL | pub struct A(pub ()); + | +++ error[E0603]: tuple struct constructor `B` is private --> $DIR/privacy5.rs:61:12 @@ -117,6 +145,10 @@ note: the tuple struct constructor `B` is defined here | LL | pub struct B(isize); | ^^^^^^^^^^^^^^^^^^^^ +help: consider making the field publicly accessible + | +LL | pub struct B(pub isize); + | +++ error[E0603]: tuple struct constructor `B` is private --> $DIR/privacy5.rs:62:12 @@ -132,6 +164,10 @@ note: the tuple struct constructor `B` is defined here | LL | pub struct B(isize); | ^^^^^^^^^^^^^^^^^^^^ +help: consider making the field publicly accessible + | +LL | pub struct B(pub isize); + | +++ error[E0603]: tuple struct constructor `B` is private --> $DIR/privacy5.rs:63:18 @@ -147,6 +183,10 @@ note: the tuple struct constructor `B` is defined here | LL | pub struct B(isize); | ^^^^^^^^^^^^^^^^^^^^ +help: consider making the field publicly accessible + | +LL | pub struct B(pub isize); + | +++ error[E0603]: tuple struct constructor `B` is private --> $DIR/privacy5.rs:64:18 @@ -162,6 +202,10 @@ note: the tuple struct constructor `B` is defined here | LL | pub struct B(isize); | ^^^^^^^^^^^^^^^^^^^^ +help: consider making the field publicly accessible + | +LL | pub struct B(pub isize); + | +++ error[E0603]: tuple struct constructor `B` is private --> $DIR/privacy5.rs:65:18 @@ -177,6 +221,10 @@ note: the tuple struct constructor `B` is defined here | LL | pub struct B(isize); | ^^^^^^^^^^^^^^^^^^^^ +help: consider making the field publicly accessible + | +LL | pub struct B(pub isize); + | +++ error[E0603]: tuple struct constructor `B` is private --> $DIR/privacy5.rs:65:32 @@ -192,6 +240,10 @@ note: the tuple struct constructor `B` is defined here | LL | pub struct B(isize); | ^^^^^^^^^^^^^^^^^^^^ +help: consider making the field publicly accessible + | +LL | pub struct B(pub isize); + | +++ error[E0603]: tuple struct constructor `C` is private --> $DIR/privacy5.rs:68:12 @@ -207,6 +259,10 @@ note: the tuple struct constructor `C` is defined here | LL | pub struct C(pub isize, isize); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: consider making the fields publicly accessible + | +LL | pub struct C(pub isize, pub isize); + | ~~~ +++ error[E0603]: tuple struct constructor `C` is private --> $DIR/privacy5.rs:69:12 @@ -222,6 +278,10 @@ note: the tuple struct constructor `C` is defined here | LL | pub struct C(pub isize, isize); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: consider making the fields publicly accessible + | +LL | pub struct C(pub isize, pub isize); + | ~~~ +++ error[E0603]: tuple struct constructor `C` is private --> $DIR/privacy5.rs:70:12 @@ -237,6 +297,10 @@ note: the tuple struct constructor `C` is defined here | LL | pub struct C(pub isize, isize); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: consider making the fields publicly accessible + | +LL | pub struct C(pub isize, pub isize); + | ~~~ +++ error[E0603]: tuple struct constructor `C` is private --> $DIR/privacy5.rs:71:12 @@ -252,6 +316,10 @@ note: the tuple struct constructor `C` is defined here | LL | pub struct C(pub isize, isize); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: consider making the fields publicly accessible + | +LL | pub struct C(pub isize, pub isize); + | ~~~ +++ error[E0603]: tuple struct constructor `C` is private --> $DIR/privacy5.rs:72:18 @@ -267,6 +335,10 @@ note: the tuple struct constructor `C` is defined here | LL | pub struct C(pub isize, isize); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: consider making the fields publicly accessible + | +LL | pub struct C(pub isize, pub isize); + | ~~~ +++ error[E0603]: tuple struct constructor `C` is private --> $DIR/privacy5.rs:73:18 @@ -282,6 +354,10 @@ note: the tuple struct constructor `C` is defined here | LL | pub struct C(pub isize, isize); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: consider making the fields publicly accessible + | +LL | pub struct C(pub isize, pub isize); + | ~~~ +++ error[E0603]: tuple struct constructor `C` is private --> $DIR/privacy5.rs:74:18 @@ -297,6 +373,10 @@ note: the tuple struct constructor `C` is defined here | LL | pub struct C(pub isize, isize); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: consider making the fields publicly accessible + | +LL | pub struct C(pub isize, pub isize); + | ~~~ +++ error[E0603]: tuple struct constructor `C` is private --> $DIR/privacy5.rs:75:18 @@ -312,6 +392,10 @@ note: the tuple struct constructor `C` is defined here | LL | pub struct C(pub isize, isize); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: consider making the fields publicly accessible + | +LL | pub struct C(pub isize, pub isize); + | ~~~ +++ error[E0603]: tuple struct constructor `A` is private --> $DIR/privacy5.rs:83:17 @@ -327,6 +411,10 @@ note: the tuple struct constructor `A` is defined here | LL | pub struct A(()); | ^^^^^^^^^^^^^^^^^ +help: consider making the field publicly accessible + | +LL | pub struct A(pub ()); + | +++ error[E0603]: tuple struct constructor `B` is private --> $DIR/privacy5.rs:84:17 @@ -342,6 +430,10 @@ note: the tuple struct constructor `B` is defined here | LL | pub struct B(isize); | ^^^^^^^^^^^^^^^^^^^^ +help: consider making the field publicly accessible + | +LL | pub struct B(pub isize); + | +++ error[E0603]: tuple struct constructor `C` is private --> $DIR/privacy5.rs:85:17 @@ -357,6 +449,10 @@ note: the tuple struct constructor `C` is defined here | LL | pub struct C(pub isize, isize); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: consider making the fields publicly accessible + | +LL | pub struct C(pub isize, pub isize); + | ~~~ +++ error[E0603]: tuple struct constructor `A` is private --> $DIR/privacy5.rs:90:20 diff --git a/tests/ui/privacy/suggest-making-field-public.fixed b/tests/ui/privacy/suggest-making-field-public.fixed new file mode 100644 index 00000000000..78e335b3db1 --- /dev/null +++ b/tests/ui/privacy/suggest-making-field-public.fixed @@ -0,0 +1,15 @@ +// run-rustfix +mod a { + pub struct A(pub String); +} + +mod b { + use crate::a::A; + pub fn x() { + A("".into()); //~ ERROR cannot initialize a tuple struct which contains private fields + } +} +fn main() { + a::A("a".into()); //~ ERROR tuple struct constructor `A` is private + b::x(); +} diff --git a/tests/ui/privacy/suggest-making-field-public.rs b/tests/ui/privacy/suggest-making-field-public.rs new file mode 100644 index 00000000000..b65c801d10e --- /dev/null +++ b/tests/ui/privacy/suggest-making-field-public.rs @@ -0,0 +1,15 @@ +// run-rustfix +mod a { + pub struct A(pub(self)String); +} + +mod b { + use crate::a::A; + pub fn x() { + A("".into()); //~ ERROR cannot initialize a tuple struct which contains private fields + } +} +fn main() { + a::A("a".into()); //~ ERROR tuple struct constructor `A` is private + b::x(); +} diff --git a/tests/ui/privacy/suggest-making-field-public.stderr b/tests/ui/privacy/suggest-making-field-public.stderr new file mode 100644 index 00000000000..e92e9aae310 --- /dev/null +++ b/tests/ui/privacy/suggest-making-field-public.stderr @@ -0,0 +1,39 @@ +error[E0603]: tuple struct constructor `A` is private + --> $DIR/suggest-making-field-public.rs:13:8 + | +LL | pub struct A(pub(self)String); + | --------------- a constructor is private if any of the fields is private +... +LL | a::A("a".into()); + | ^ private tuple struct constructor + | +note: the tuple struct constructor `A` is defined here + --> $DIR/suggest-making-field-public.rs:3:5 + | +LL | pub struct A(pub(self)String); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: consider making the field publicly accessible + | +LL | pub struct A(pub String); + | ~~~ + +error[E0423]: cannot initialize a tuple struct which contains private fields + --> $DIR/suggest-making-field-public.rs:9:9 + | +LL | A("".into()); + | ^ + | +note: constructor is not visible here due to private fields + --> $DIR/suggest-making-field-public.rs:3:18 + | +LL | pub struct A(pub(self)String); + | ^^^^^^^^^^^^^^^ private field +help: consider making the field publicly accessible + | +LL | pub struct A(pub String); + | ~~~ + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0423, E0603. +For more information about an error, try `rustc --explain E0423`. diff --git a/tests/ui/proc-macro/panic-abort.rs b/tests/ui/proc-macro/panic-abort.rs new file mode 100644 index 00000000000..ad312a875e3 --- /dev/null +++ b/tests/ui/proc-macro/panic-abort.rs @@ -0,0 +1,4 @@ +// error-pattern: building proc macro crate with `panic=abort` may crash the compiler should the proc-macro panic +// compile-flags: --crate-type proc-macro -Cpanic=abort +// force-host +// check-pass diff --git a/tests/ui/proc-macro/panic-abort.stderr b/tests/ui/proc-macro/panic-abort.stderr new file mode 100644 index 00000000000..a6e18614f8f --- /dev/null +++ b/tests/ui/proc-macro/panic-abort.stderr @@ -0,0 +1,4 @@ +warning: building proc macro crate with `panic=abort` may crash the compiler should the proc-macro panic + +warning: 1 warning emitted + diff --git a/tests/ui/qualified/qualified-path-params-2.stderr b/tests/ui/qualified/qualified-path-params-2.stderr index 948f21fce4b..b6cf19b8286 100644 --- a/tests/ui/qualified/qualified-path-params-2.stderr +++ b/tests/ui/qualified/qualified-path-params-2.stderr @@ -2,7 +2,12 @@ error[E0223]: ambiguous associated type --> $DIR/qualified-path-params-2.rs:18:10 | LL | type A = <S as Tr>::A::f<u8>; - | ^^^^^^^^^^^^^^^^^^^ help: use fully-qualified syntax: `<<S as Tr>::A as Trait>::f` + | ^^^^^^^^^^^^^^^^^^^ + | +help: if there were a trait named `Example` with associated type `f` implemented for `<S as Tr>::A`, you could use the fully-qualified path + | +LL | type A = <<S as Tr>::A as Example>::f; + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: aborting due to previous error diff --git a/tests/ui/resolve/issue-103202.stderr b/tests/ui/resolve/issue-103202.stderr index 880389371ef..d4d141fb06f 100644 --- a/tests/ui/resolve/issue-103202.stderr +++ b/tests/ui/resolve/issue-103202.stderr @@ -2,7 +2,12 @@ error[E0223]: ambiguous associated type --> $DIR/issue-103202.rs:4:17 | LL | fn f(self: &S::x) {} - | ^^^^ help: use fully-qualified syntax: `<S as Trait>::x` + | ^^^^ + | +help: if there were a trait named `Example` with associated type `x` implemented for `S`, you could use the fully-qualified path + | +LL | fn f(self: &<S as Example>::x) {} + | ~~~~~~~~~~~~~~~~~ error: aborting due to previous error diff --git a/tests/ui/resolve/issue-39559-2.stderr b/tests/ui/resolve/issue-39559-2.stderr index ea27e7bd250..e9d8eb0835b 100644 --- a/tests/ui/resolve/issue-39559-2.stderr +++ b/tests/ui/resolve/issue-39559-2.stderr @@ -5,6 +5,7 @@ LL | let array: [usize; Dim3::dim()] | ^^^^^^^^^^^ | = note: calls in constants are limited to constant functions, tuple structs and tuple variants + = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable error[E0015]: cannot call non-const fn `<Dim3 as Dim>::dim` in constants --> $DIR/issue-39559-2.rs:16:15 @@ -13,6 +14,7 @@ LL | = [0; Dim3::dim()]; | ^^^^^^^^^^^ | = note: calls in constants are limited to constant functions, tuple structs and tuple variants + = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable error: aborting due to 2 previous errors diff --git a/tests/ui/resolve/issue-42944.rs b/tests/ui/resolve/issue-42944.rs index a4404857a56..7e439c10b7b 100644 --- a/tests/ui/resolve/issue-42944.rs +++ b/tests/ui/resolve/issue-42944.rs @@ -1,5 +1,5 @@ mod foo { - pub struct Bx(()); + pub struct Bx(pub(in crate::foo) ()); } mod bar { diff --git a/tests/ui/resolve/issue-42944.stderr b/tests/ui/resolve/issue-42944.stderr index 0ee9fd391fe..4ffa9402c66 100644 --- a/tests/ui/resolve/issue-42944.stderr +++ b/tests/ui/resolve/issue-42944.stderr @@ -7,8 +7,8 @@ LL | Bx(()); note: tuple struct `foo::Bx` exists but is inaccessible --> $DIR/issue-42944.rs:2:5 | -LL | pub struct Bx(()); - | ^^^^^^^^^^^^^^^^^^ not accessible +LL | pub struct Bx(pub(in crate::foo) ()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not accessible error[E0423]: cannot initialize a tuple struct which contains private fields --> $DIR/issue-42944.rs:9:9 @@ -19,8 +19,12 @@ LL | Bx(()); note: constructor is not visible here due to private fields --> $DIR/issue-42944.rs:2:19 | -LL | pub struct Bx(()); - | ^^ private field +LL | pub struct Bx(pub(in crate::foo) ()); + | ^^^^^^^^^^^^^^^^^^^^^ private field +help: consider making the field publicly accessible + | +LL | pub struct Bx(pub ()); + | ~~~ error: aborting due to 2 previous errors diff --git a/tests/ui/resolve/privacy-struct-ctor.stderr b/tests/ui/resolve/privacy-struct-ctor.stderr index 17a666a401c..c1fcaaf0573 100644 --- a/tests/ui/resolve/privacy-struct-ctor.stderr +++ b/tests/ui/resolve/privacy-struct-ctor.stderr @@ -53,6 +53,10 @@ note: the tuple struct constructor `Z` is defined here | LL | pub(in m) struct Z(pub(in m::n) u8); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: consider making the field publicly accessible + | +LL | pub(in m) struct Z(pub u8); + | ~~~ error[E0603]: tuple struct constructor `S` is private --> $DIR/privacy-struct-ctor.rs:29:8 @@ -68,6 +72,10 @@ note: the tuple struct constructor `S` is defined here | LL | pub struct S(u8); | ^^^^^^^^^^^^^^^^^ +help: consider making the field publicly accessible + | +LL | pub struct S(pub u8); + | +++ error[E0603]: tuple struct constructor `S` is private --> $DIR/privacy-struct-ctor.rs:31:19 @@ -83,6 +91,10 @@ note: the tuple struct constructor `S` is defined here | LL | pub struct S(u8); | ^^^^^^^^^^^^^^^^^ +help: consider making the field publicly accessible + | +LL | pub struct S(pub u8); + | +++ error[E0603]: tuple struct constructor `Z` is private --> $DIR/privacy-struct-ctor.rs:35:11 @@ -98,6 +110,10 @@ note: the tuple struct constructor `Z` is defined here | LL | pub(in m) struct Z(pub(in m::n) u8); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: consider making the field publicly accessible + | +LL | pub(in m) struct Z(pub u8); + | ~~~ error[E0603]: tuple struct constructor `S` is private --> $DIR/privacy-struct-ctor.rs:41:16 diff --git a/tests/ui/rfc-2397-do-not-recommend/incorrect-locations.rs b/tests/ui/rfc-2397-do-not-recommend/incorrect-locations.rs new file mode 100644 index 00000000000..91863f5e497 --- /dev/null +++ b/tests/ui/rfc-2397-do-not-recommend/incorrect-locations.rs @@ -0,0 +1,45 @@ +#![feature(do_not_recommend)] + +#[do_not_recommend] +//~^ `#[do_not_recommend]` can only be placed +const CONST: () = (); + +#[do_not_recommend] +//~^ `#[do_not_recommend]` can only be placed +static Static: () = (); + +#[do_not_recommend] +//~^ `#[do_not_recommend]` can only be placed +type Type = (); + +#[do_not_recommend] +//~^ `#[do_not_recommend]` can only be placed +enum Enum { +} + +#[do_not_recommend] +//~^ `#[do_not_recommend]` can only be placed +extern { +} + +#[do_not_recommend] +//~^ `#[do_not_recommend]` can only be placed +fn fun() { +} + +#[do_not_recommend] +//~^ `#[do_not_recommend]` can only be placed +struct Struct { +} + +#[do_not_recommend] +//~^ `#[do_not_recommend]` can only be placed +trait Trait { +} + +#[do_not_recommend] +impl Trait for i32 { +} + +fn main() { +} diff --git a/tests/ui/rfc-2397-do-not-recommend/incorrect-locations.stderr b/tests/ui/rfc-2397-do-not-recommend/incorrect-locations.stderr new file mode 100644 index 00000000000..01ebc23c86e --- /dev/null +++ b/tests/ui/rfc-2397-do-not-recommend/incorrect-locations.stderr @@ -0,0 +1,50 @@ +error: `#[do_not_recommend]` can only be placed on trait implementations + --> $DIR/incorrect-locations.rs:3:1 + | +LL | #[do_not_recommend] + | ^^^^^^^^^^^^^^^^^^^ + +error: `#[do_not_recommend]` can only be placed on trait implementations + --> $DIR/incorrect-locations.rs:7:1 + | +LL | #[do_not_recommend] + | ^^^^^^^^^^^^^^^^^^^ + +error: `#[do_not_recommend]` can only be placed on trait implementations + --> $DIR/incorrect-locations.rs:11:1 + | +LL | #[do_not_recommend] + | ^^^^^^^^^^^^^^^^^^^ + +error: `#[do_not_recommend]` can only be placed on trait implementations + --> $DIR/incorrect-locations.rs:15:1 + | +LL | #[do_not_recommend] + | ^^^^^^^^^^^^^^^^^^^ + +error: `#[do_not_recommend]` can only be placed on trait implementations + --> $DIR/incorrect-locations.rs:20:1 + | +LL | #[do_not_recommend] + | ^^^^^^^^^^^^^^^^^^^ + +error: `#[do_not_recommend]` can only be placed on trait implementations + --> $DIR/incorrect-locations.rs:25:1 + | +LL | #[do_not_recommend] + | ^^^^^^^^^^^^^^^^^^^ + +error: `#[do_not_recommend]` can only be placed on trait implementations + --> $DIR/incorrect-locations.rs:30:1 + | +LL | #[do_not_recommend] + | ^^^^^^^^^^^^^^^^^^^ + +error: `#[do_not_recommend]` can only be placed on trait implementations + --> $DIR/incorrect-locations.rs:35:1 + | +LL | #[do_not_recommend] + | ^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 8 previous errors + diff --git a/tests/ui/rfc-2397-do-not-recommend/unstable-feature.rs b/tests/ui/rfc-2397-do-not-recommend/unstable-feature.rs index b816c4a19da..f0c5c222e78 100644 --- a/tests/ui/rfc-2397-do-not-recommend/unstable-feature.rs +++ b/tests/ui/rfc-2397-do-not-recommend/unstable-feature.rs @@ -1,6 +1,9 @@ +trait Foo { +} + #[do_not_recommend] //~^ ERROR the `#[do_not_recommend]` attribute is an experimental feature -trait Foo { +impl Foo for i32 { } fn main() { diff --git a/tests/ui/rfc-2397-do-not-recommend/unstable-feature.stderr b/tests/ui/rfc-2397-do-not-recommend/unstable-feature.stderr index 425d7e4bca0..1597e5be45f 100644 --- a/tests/ui/rfc-2397-do-not-recommend/unstable-feature.stderr +++ b/tests/ui/rfc-2397-do-not-recommend/unstable-feature.stderr @@ -1,5 +1,5 @@ error[E0658]: the `#[do_not_recommend]` attribute is an experimental feature - --> $DIR/unstable-feature.rs:1:1 + --> $DIR/unstable-feature.rs:4:1 | LL | #[do_not_recommend] | ^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/rfc-2632-const-trait-impl/call.rs b/tests/ui/rfc-2632-const-trait-impl/call.rs new file mode 100644 index 00000000000..5f48c235373 --- /dev/null +++ b/tests/ui/rfc-2632-const-trait-impl/call.rs @@ -0,0 +1,10 @@ +// check-pass + +#![feature(const_closures, const_trait_impl)] +#![allow(incomplete_features)] + +pub const _: () = { + assert!((const || true)()); +}; + +fn main() {} diff --git a/tests/ui/rfc-2632-const-trait-impl/const_derives/derive-const-non-const-type.stderr b/tests/ui/rfc-2632-const-trait-impl/const_derives/derive-const-non-const-type.stderr index d463c774e28..96e0c78b9c7 100644 --- a/tests/ui/rfc-2632-const-trait-impl/const_derives/derive-const-non-const-type.stderr +++ b/tests/ui/rfc-2632-const-trait-impl/const_derives/derive-const-non-const-type.stderr @@ -7,6 +7,7 @@ LL | pub struct S(A); | ^ | = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants + = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable = note: this error originates in the derive macro `Default` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to previous error diff --git a/tests/ui/rfc-2632-const-trait-impl/cross-crate.stock.stderr b/tests/ui/rfc-2632-const-trait-impl/cross-crate.stock.stderr index 086547542bb..22f13a7416e 100644 --- a/tests/ui/rfc-2632-const-trait-impl/cross-crate.stock.stderr +++ b/tests/ui/rfc-2632-const-trait-impl/cross-crate.stock.stderr @@ -5,6 +5,7 @@ LL | Const.func(); | ^^^^^^ | = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants + = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable error: aborting due to previous error diff --git a/tests/ui/rfc-2632-const-trait-impl/gate.rs b/tests/ui/rfc-2632-const-trait-impl/gate.rs new file mode 100644 index 00000000000..f2cd26c91b6 --- /dev/null +++ b/tests/ui/rfc-2632-const-trait-impl/gate.rs @@ -0,0 +1,5 @@ +// gate-test-const_closures +fn main() { + (const || {})(); + //~^ ERROR: const closures are experimental +} diff --git a/tests/ui/rfc-2632-const-trait-impl/gate.stderr b/tests/ui/rfc-2632-const-trait-impl/gate.stderr new file mode 100644 index 00000000000..30edc4127e1 --- /dev/null +++ b/tests/ui/rfc-2632-const-trait-impl/gate.stderr @@ -0,0 +1,12 @@ +error[E0658]: const closures are experimental + --> $DIR/gate.rs:3:6 + | +LL | (const || {})(); + | ^^^^^^^^^^^ + | + = note: see issue #106003 <https://github.com/rust-lang/rust/issues/106003> for more information + = help: add `#![feature(const_closures)]` to the crate attributes to enable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/rfc-2632-const-trait-impl/non-const-op-const-closure-non-const-outer.rs b/tests/ui/rfc-2632-const-trait-impl/non-const-op-const-closure-non-const-outer.rs new file mode 100644 index 00000000000..cd8bb5963ad --- /dev/null +++ b/tests/ui/rfc-2632-const-trait-impl/non-const-op-const-closure-non-const-outer.rs @@ -0,0 +1,15 @@ +#![feature(const_closures, const_trait_impl)] +#![allow(incomplete_features)] + +trait Foo { + fn foo(&self); +} + +impl Foo for () { + fn foo(&self) {} +} + +fn main() { + (const || { (()).foo() })(); + //~^ ERROR: cannot call non-const fn +} diff --git a/tests/ui/rfc-2632-const-trait-impl/non-const-op-const-closure-non-const-outer.stderr b/tests/ui/rfc-2632-const-trait-impl/non-const-op-const-closure-non-const-outer.stderr new file mode 100644 index 00000000000..979d7febbca --- /dev/null +++ b/tests/ui/rfc-2632-const-trait-impl/non-const-op-const-closure-non-const-outer.stderr @@ -0,0 +1,11 @@ +error[E0015]: cannot call non-const fn `<() as Foo>::foo` in constant functions + --> $DIR/non-const-op-const-closure-non-const-outer.rs:13:22 + | +LL | (const || { (()).foo() })(); + | ^^^^^ + | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0015`. diff --git a/tests/ui/rfc-2632-const-trait-impl/staged-api-user-crate.stderr b/tests/ui/rfc-2632-const-trait-impl/staged-api-user-crate.stderr index 61f9840e0d0..d7aa0d95cfc 100644 --- a/tests/ui/rfc-2632-const-trait-impl/staged-api-user-crate.stderr +++ b/tests/ui/rfc-2632-const-trait-impl/staged-api-user-crate.stderr @@ -5,6 +5,7 @@ LL | Unstable::func(); | ^^^^^^^^^^^^^^^^ | = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants + = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable error: aborting due to previous error diff --git a/tests/ui/rfc-2632-const-trait-impl/std-impl-gate.stock.stderr b/tests/ui/rfc-2632-const-trait-impl/std-impl-gate.stock.stderr index 0b450a94742..6a3396401d2 100644 --- a/tests/ui/rfc-2632-const-trait-impl/std-impl-gate.stock.stderr +++ b/tests/ui/rfc-2632-const-trait-impl/std-impl-gate.stock.stderr @@ -5,6 +5,7 @@ LL | Default::default() | ^^^^^^^^^^^^^^^^^^ | = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants + = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable error: aborting due to previous error diff --git a/tests/ui/rfc-2632-const-trait-impl/super-traits-fail.stderr b/tests/ui/rfc-2632-const-trait-impl/super-traits-fail.stderr index 1f8f312df01..bf12ef1ca77 100644 --- a/tests/ui/rfc-2632-const-trait-impl/super-traits-fail.stderr +++ b/tests/ui/rfc-2632-const-trait-impl/super-traits-fail.stderr @@ -1,14 +1,14 @@ error[E0277]: the trait bound `S: ~const Foo` is not satisfied - --> $DIR/super-traits-fail.rs:15:12 + --> $DIR/super-traits-fail.rs:15:20 | LL | impl const Bar for S {} - | ^^^ the trait `~const Foo` is not implemented for `S` + | ^ the trait `~const Foo` is not implemented for `S` | note: the trait `Foo` is implemented for `S`, but that implementation is not `const` - --> $DIR/super-traits-fail.rs:15:12 + --> $DIR/super-traits-fail.rs:15:20 | LL | impl const Bar for S {} - | ^^^ + | ^ note: required by a bound in `Bar` --> $DIR/super-traits-fail.rs:8:12 | diff --git a/tests/ui/self/self-impl.stderr b/tests/ui/self/self-impl.stderr index fb47f27e022..36372b644d6 100644 --- a/tests/ui/self/self-impl.stderr +++ b/tests/ui/self/self-impl.stderr @@ -2,13 +2,13 @@ error[E0223]: ambiguous associated type --> $DIR/self-impl.rs:23:16 | LL | let _: <Self>::Baz = true; - | ^^^^^^^^^^^ help: use fully-qualified syntax: `<Bar as Trait>::Baz` + | ^^^^^^^^^^^ help: use the fully-qualified path: `<Bar as Foo>::Baz` error[E0223]: ambiguous associated type --> $DIR/self-impl.rs:25:16 | LL | let _: Self::Baz = true; - | ^^^^^^^^^ help: use fully-qualified syntax: `<Bar as Trait>::Baz` + | ^^^^^^^^^ help: use the fully-qualified path: `<Bar as Foo>::Baz` error: aborting due to 2 previous errors diff --git a/tests/ui/span/issue-71363.stderr b/tests/ui/span/issue-71363.stderr index 6c7ea007ee0..cb5cc320276 100644 --- a/tests/ui/span/issue-71363.stderr +++ b/tests/ui/span/issue-71363.stderr @@ -1,8 +1,8 @@ error[E0277]: `MyError` doesn't implement `std::fmt::Display` - --> $DIR/issue-71363.rs:4:6 + --> $DIR/issue-71363.rs:4:28 | 4 | impl std::error::Error for MyError {} - | ^^^^^^^^^^^^^^^^^ `MyError` cannot be formatted with the default formatter + | ^^^^^^^ `MyError` cannot be formatted with the default formatter | = help: the trait `std::fmt::Display` is not implemented for `MyError` = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead @@ -10,10 +10,10 @@ note: required by a bound in `std::error::Error` --> $SRC_DIR/core/src/error.rs:LL:COL error[E0277]: `MyError` doesn't implement `Debug` - --> $DIR/issue-71363.rs:4:6 + --> $DIR/issue-71363.rs:4:28 | 4 | impl std::error::Error for MyError {} - | ^^^^^^^^^^^^^^^^^ `MyError` cannot be formatted using `{:?}` + | ^^^^^^^ `MyError` cannot be formatted using `{:?}` | = help: the trait `Debug` is not implemented for `MyError` = note: add `#[derive(Debug)]` to `MyError` or manually `impl Debug for MyError` diff --git a/tests/ui/specialization/min_specialization/issue-79224.stderr b/tests/ui/specialization/min_specialization/issue-79224.stderr index be6f04ae62a..505baa23ca3 100644 --- a/tests/ui/specialization/min_specialization/issue-79224.stderr +++ b/tests/ui/specialization/min_specialization/issue-79224.stderr @@ -1,8 +1,8 @@ error[E0277]: the trait bound `B: Clone` is not satisfied - --> $DIR/issue-79224.rs:18:17 + --> $DIR/issue-79224.rs:18:29 | LL | impl<B: ?Sized> Display for Cow<'_, B> { - | ^^^^^^^ the trait `Clone` is not implemented for `B` + | ^^^^^^^^^^ the trait `Clone` is not implemented for `B` | = note: required for `B` to implement `ToOwned` help: consider further restricting this bound diff --git a/tests/ui/structs/struct-path-associated-type.stderr b/tests/ui/structs/struct-path-associated-type.stderr index abb445214f3..ca5f0b7e21e 100644 --- a/tests/ui/structs/struct-path-associated-type.stderr +++ b/tests/ui/structs/struct-path-associated-type.stderr @@ -48,19 +48,19 @@ error[E0223]: ambiguous associated type --> $DIR/struct-path-associated-type.rs:32:13 | LL | let s = S::A {}; - | ^^^^ help: use fully-qualified syntax: `<S as Trait>::A` + | ^^^^ help: use the fully-qualified path: `<S as Tr>::A` error[E0223]: ambiguous associated type --> $DIR/struct-path-associated-type.rs:33:13 | LL | let z = S::A::<u8> {}; - | ^^^^ help: use fully-qualified syntax: `<S as Trait>::A` + | ^^^^ help: use the fully-qualified path: `<S as Tr>::A` error[E0223]: ambiguous associated type --> $DIR/struct-path-associated-type.rs:35:9 | LL | S::A {} => {} - | ^^^^ help: use fully-qualified syntax: `<S as Trait>::A` + | ^^^^ help: use the fully-qualified path: `<S as Tr>::A` error: aborting due to 8 previous errors diff --git a/tests/ui/suggestions/issue-105761-suggest-self-for-closure.fixed b/tests/ui/suggestions/issue-105761-suggest-self-for-closure.fixed new file mode 100644 index 00000000000..78e48364bba --- /dev/null +++ b/tests/ui/suggestions/issue-105761-suggest-self-for-closure.fixed @@ -0,0 +1,28 @@ +//run-rustfix +#![allow(unused)] + +struct S; +impl S { + fn foo(&mut self) { + let x = |this: &Self, v: i32| { + this.bar(); + this.hel(); + }; + self.qux(); //~ ERROR cannot borrow `*self` as mutable because it is also borrowed as immutable + x(self, 1); + x(self, 3); + } + fn bar(&self) {} + fn hel(&self) {} + fn qux(&mut self) {} + + fn hello(&mut self) { + let y = |this: &Self| { + this.bar(); + }; + self.qux(); //~ ERROR cannot borrow `*self` as mutable because it is also borrowed as immutable + y(self); + } +} + +fn main() {} diff --git a/tests/ui/suggestions/issue-105761-suggest-self-for-closure.rs b/tests/ui/suggestions/issue-105761-suggest-self-for-closure.rs new file mode 100644 index 00000000000..6d8a9ffc12d --- /dev/null +++ b/tests/ui/suggestions/issue-105761-suggest-self-for-closure.rs @@ -0,0 +1,28 @@ +//run-rustfix +#![allow(unused)] + +struct S; +impl S { + fn foo(&mut self) { + let x = |v: i32| { + self.bar(); + self.hel(); + }; + self.qux(); //~ ERROR cannot borrow `*self` as mutable because it is also borrowed as immutable + x(1); + x(3); + } + fn bar(&self) {} + fn hel(&self) {} + fn qux(&mut self) {} + + fn hello(&mut self) { + let y = || { + self.bar(); + }; + self.qux(); //~ ERROR cannot borrow `*self` as mutable because it is also borrowed as immutable + y(); + } +} + +fn main() {} diff --git a/tests/ui/suggestions/issue-105761-suggest-self-for-closure.stderr b/tests/ui/suggestions/issue-105761-suggest-self-for-closure.stderr new file mode 100644 index 00000000000..bc97d32ebb6 --- /dev/null +++ b/tests/ui/suggestions/issue-105761-suggest-self-for-closure.stderr @@ -0,0 +1,49 @@ +error[E0502]: cannot borrow `*self` as mutable because it is also borrowed as immutable + --> $DIR/issue-105761-suggest-self-for-closure.rs:11:9 + | +LL | let x = |v: i32| { + | -------- immutable borrow occurs here +LL | self.bar(); + | ---- first borrow occurs due to use of `self` in closure +... +LL | self.qux(); + | ^^^^^^^^^^ mutable borrow occurs here +LL | x(1); + | - immutable borrow later used here + | +help: try explicitly pass `&Self` into the Closure as an argument + | +LL ~ let x = |this: &Self, v: i32| { +LL ~ this.bar(); +LL ~ this.hel(); +LL | }; +LL | self.qux(); +LL ~ x(self, 1); +LL ~ x(self, 3); + | + +error[E0502]: cannot borrow `*self` as mutable because it is also borrowed as immutable + --> $DIR/issue-105761-suggest-self-for-closure.rs:23:9 + | +LL | let y = || { + | -- immutable borrow occurs here +LL | self.bar(); + | ---- first borrow occurs due to use of `self` in closure +LL | }; +LL | self.qux(); + | ^^^^^^^^^^ mutable borrow occurs here +LL | y(); + | - immutable borrow later used here + | +help: try explicitly pass `&Self` into the Closure as an argument + | +LL ~ let y = |this: &Self| { +LL ~ this.bar(); +LL | }; +LL | self.qux(); +LL ~ y(self); + | + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0502`. diff --git a/tests/ui/suggestions/let-binding-init-expr-as-ty.stderr b/tests/ui/suggestions/let-binding-init-expr-as-ty.stderr index 2bf072ef521..b90ae051fb7 100644 --- a/tests/ui/suggestions/let-binding-init-expr-as-ty.stderr +++ b/tests/ui/suggestions/let-binding-init-expr-as-ty.stderr @@ -21,7 +21,12 @@ error[E0223]: ambiguous associated type --> $DIR/let-binding-init-expr-as-ty.rs:2:14 | LL | let foo: i32::from_be(num); - | ^^^^^^^^^^^^^^^^^ help: use fully-qualified syntax: `<i32 as Trait>::from_be` + | ^^^^^^^^^^^^^^^^^ + | +help: if there were a trait named `Example` with associated type `from_be` implemented for `i32`, you could use the fully-qualified path + | +LL | let foo: <i32 as Example>::from_be; + | ~~~~~~~~~~~~~~~~~~~~~~~~~ error: aborting due to 3 previous errors diff --git a/tests/ui/suggestions/type-not-found-in-adt-field.stderr b/tests/ui/suggestions/type-not-found-in-adt-field.stderr index e990fb5ba12..934ba87bbaa 100644 --- a/tests/ui/suggestions/type-not-found-in-adt-field.stderr +++ b/tests/ui/suggestions/type-not-found-in-adt-field.stderr @@ -7,10 +7,13 @@ LL | m: Vec<Someunknownname<String, ()>>, error[E0412]: cannot find type `K` in this scope --> $DIR/type-not-found-in-adt-field.rs:6:8 | -LL | struct OtherStruct { - | - help: you might be missing a type parameter: `<K>` LL | m: K, | ^ not found in this scope + | +help: you might be missing a type parameter + | +LL | struct OtherStruct<K> { + | +++ error: aborting due to 2 previous errors diff --git a/tests/ui/trait-bounds/unsized-bound.stderr b/tests/ui/trait-bounds/unsized-bound.stderr index ec85ada7a8d..da27ba1c58d 100644 --- a/tests/ui/trait-bounds/unsized-bound.stderr +++ b/tests/ui/trait-bounds/unsized-bound.stderr @@ -1,8 +1,8 @@ error[E0277]: the size for values of type `B` cannot be known at compilation time - --> $DIR/unsized-bound.rs:2:12 + --> $DIR/unsized-bound.rs:2:30 | LL | impl<A, B> Trait<(A, B)> for (A, B) where A: ?Sized, B: ?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 `std::marker::Sized` | @@ -38,10 +38,10 @@ LL + impl<A, B> Trait<(A, B)> for (A, B) where B: ?Sized, {} | error[E0277]: the size for values of type `C` cannot be known at compilation time - --> $DIR/unsized-bound.rs:5:31 + --> $DIR/unsized-bound.rs:5:52 | LL | impl<A, B: ?Sized, C: ?Sized> Trait<(A, B, C)> for (A, B, C) where A: ?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 `std::marker::Sized` | @@ -92,10 +92,10 @@ LL + impl<A, B, C: ?Sized> Trait<(A, B, C)> for (A, B, C) where A: ?Sized, {} | error[E0277]: the size for values of type `B` cannot be known at compilation time - --> $DIR/unsized-bound.rs:10:28 + --> $DIR/unsized-bound.rs:10:47 | LL | impl<A: ?Sized, B: ?Sized> Trait2<(A, B)> for (A, B) {} - | - ^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | - ^^^^^^ doesn't have a size known at compile-time | | | this type parameter needs to be `std::marker::Sized` | @@ -131,10 +131,10 @@ LL + impl<A, B: ?Sized> Trait2<(A, B)> for (A, B) {} | error[E0277]: the size for values of type `A` cannot be known at compilation time - --> $DIR/unsized-bound.rs:14:9 + --> $DIR/unsized-bound.rs:14:23 | LL | impl<A> Trait3<A> for A where A: ?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 `std::marker::Sized` | @@ -154,10 +154,10 @@ LL | trait Trait3<A: ?Sized> {} | ++++++++ error[E0277]: the size for values of type `A` cannot be known at compilation time - --> $DIR/unsized-bound.rs:17:17 + --> $DIR/unsized-bound.rs:17:31 | LL | impl<A: ?Sized> Trait4<A> for A {} - | - ^^^^^^^^^ doesn't have a size known at compile-time + | - ^ doesn't have a size known at compile-time | | | this type parameter needs to be `std::marker::Sized` | @@ -177,10 +177,10 @@ LL | trait Trait4<A: ?Sized> {} | ++++++++ error[E0277]: the size for values of type `X` cannot be known at compilation time - --> $DIR/unsized-bound.rs:20:12 + --> $DIR/unsized-bound.rs:20:29 | LL | impl<X, Y> Trait5<X, Y> for X where X: ?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 `std::marker::Sized` | @@ -200,10 +200,10 @@ LL | trait Trait5<A: ?Sized, B> {} | ++++++++ error[E0277]: the size for values of type `X` cannot be known at compilation time - --> $DIR/unsized-bound.rs:23:20 + --> $DIR/unsized-bound.rs:23:37 | LL | impl<X: ?Sized, Y> Trait6<X, Y> for 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 `std::marker::Sized` | diff --git a/tests/ui/traits/ignore-err-impls.stderr b/tests/ui/traits/ignore-err-impls.stderr index 1390106a291..45bd533b5c6 100644 --- a/tests/ui/traits/ignore-err-impls.stderr +++ b/tests/ui/traits/ignore-err-impls.stderr @@ -2,9 +2,12 @@ error[E0412]: cannot find type `Type` in this scope --> $DIR/ignore-err-impls.rs:6:14 | LL | impl Generic<Type> for S {} - | - ^^^^ not found in this scope - | | - | help: you might be missing a type parameter: `<Type>` + | ^^^^ not found in this scope + | +help: you might be missing a type parameter + | +LL | impl<Type> Generic<Type> for S {} + | ++++++ error: aborting due to previous error diff --git a/tests/ui/traits/impl-bounds-checking.stderr b/tests/ui/traits/impl-bounds-checking.stderr index b01bacdb87d..1f969efe114 100644 --- a/tests/ui/traits/impl-bounds-checking.stderr +++ b/tests/ui/traits/impl-bounds-checking.stderr @@ -1,8 +1,8 @@ error[E0277]: the trait bound `isize: Clone2` is not satisfied - --> $DIR/impl-bounds-checking.rs:10:6 + --> $DIR/impl-bounds-checking.rs:10:24 | LL | impl Getter<isize> for isize { - | ^^^^^^^^^^^^^ the trait `Clone2` is not implemented for `isize` + | ^^^^^ the trait `Clone2` is not implemented for `isize` | note: required by a bound in `Getter` --> $DIR/impl-bounds-checking.rs:6:17 diff --git a/tests/ui/traits/impl-of-supertrait-has-wrong-lifetime-parameters.stderr b/tests/ui/traits/impl-of-supertrait-has-wrong-lifetime-parameters.stderr index 5572c6515ff..1bace8ab286 100644 --- a/tests/ui/traits/impl-of-supertrait-has-wrong-lifetime-parameters.stderr +++ b/tests/ui/traits/impl-of-supertrait-has-wrong-lifetime-parameters.stderr @@ -1,8 +1,8 @@ error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'b` due to conflicting requirements - --> $DIR/impl-of-supertrait-has-wrong-lifetime-parameters.rs:24:13 + --> $DIR/impl-of-supertrait-has-wrong-lifetime-parameters.rs:24:28 | LL | impl<'a,'b> T2<'a, 'b> for S<'a, 'b> { - | ^^^^^^^^^^ + | ^^^^^^^^^ | note: first, the lifetime cannot outlive the lifetime `'a` as defined here... --> $DIR/impl-of-supertrait-has-wrong-lifetime-parameters.rs:24:6 @@ -15,10 +15,10 @@ note: ...but the lifetime must also be valid for the lifetime `'b` as defined he LL | impl<'a,'b> T2<'a, 'b> for S<'a, 'b> { | ^^ note: ...so that the types are compatible - --> $DIR/impl-of-supertrait-has-wrong-lifetime-parameters.rs:24:13 + --> $DIR/impl-of-supertrait-has-wrong-lifetime-parameters.rs:24:28 | LL | impl<'a,'b> T2<'a, 'b> for S<'a, 'b> { - | ^^^^^^^^^^ + | ^^^^^^^^^ = note: expected `T1<'a>` found `T1<'_>` diff --git a/tests/ui/traits/issue-43784-supertrait.stderr b/tests/ui/traits/issue-43784-supertrait.stderr index bb890cb99ee..4fe12731475 100644 --- a/tests/ui/traits/issue-43784-supertrait.stderr +++ b/tests/ui/traits/issue-43784-supertrait.stderr @@ -1,8 +1,8 @@ error[E0277]: the trait bound `T: Copy` is not satisfied - --> $DIR/issue-43784-supertrait.rs:8:9 + --> $DIR/issue-43784-supertrait.rs:8:22 | LL | impl<T> Complete for T {} - | ^^^^^^^^ the trait `Copy` is not implemented for `T` + | ^ the trait `Copy` is not implemented for `T` | note: required by a bound in `Complete` --> $DIR/issue-43784-supertrait.rs:4:21 diff --git a/tests/ui/traits/issue-50480.stderr b/tests/ui/traits/issue-50480.stderr index 0bb1f9ae035..aa8384e9805 100644 --- a/tests/ui/traits/issue-50480.stderr +++ b/tests/ui/traits/issue-50480.stderr @@ -2,9 +2,12 @@ error[E0412]: cannot find type `N` in this scope --> $DIR/issue-50480.rs:3:12 | LL | struct Foo(N, NotDefined, <i32 as Iterator>::Item, Vec<i32>, String); - | -^ not found in this scope - | | - | help: you might be missing a type parameter: `<N>` + | ^ not found in this scope + | +help: you might be missing a type parameter + | +LL | struct Foo<N>(N, NotDefined, <i32 as Iterator>::Item, Vec<i32>, String); + | +++ error[E0412]: cannot find type `NotDefined` in this scope --> $DIR/issue-50480.rs:3:15 @@ -16,17 +19,23 @@ error[E0412]: cannot find type `N` in this scope --> $DIR/issue-50480.rs:3:12 | LL | struct Foo(N, NotDefined, <i32 as Iterator>::Item, Vec<i32>, String); - | -^ not found in this scope - | | - | help: you might be missing a type parameter: `<N>` + | ^ not found in this scope + | +help: you might be missing a type parameter + | +LL | struct Foo<N>(N, NotDefined, <i32 as Iterator>::Item, Vec<i32>, String); + | +++ error[E0412]: cannot find type `NotDefined` in this scope --> $DIR/issue-50480.rs:3:15 | LL | struct Foo(N, NotDefined, <i32 as Iterator>::Item, Vec<i32>, String); - | - ^^^^^^^^^^ not found in this scope - | | - | help: you might be missing a type parameter: `<NotDefined>` + | ^^^^^^^^^^ not found in this scope + | +help: you might be missing a type parameter + | +LL | struct Foo<NotDefined>(N, NotDefined, <i32 as Iterator>::Item, Vec<i32>, String); + | ++++++++++++ error[E0412]: cannot find type `N` in this scope --> $DIR/issue-50480.rs:12:18 diff --git a/tests/ui/traits/issue-75627.stderr b/tests/ui/traits/issue-75627.stderr index 432ddf2dcdb..1675edc9ff0 100644 --- a/tests/ui/traits/issue-75627.stderr +++ b/tests/ui/traits/issue-75627.stderr @@ -2,9 +2,12 @@ error[E0412]: cannot find type `T` in this scope --> $DIR/issue-75627.rs:3:26 | LL | unsafe impl Send for Foo<T> {} - | - ^ not found in this scope - | | - | help: you might be missing a type parameter: `<T>` + | ^ not found in this scope + | +help: you might be missing a type parameter + | +LL | unsafe impl<T> Send for Foo<T> {} + | +++ error: aborting due to previous error diff --git a/tests/ui/traits/issue-78372.stderr b/tests/ui/traits/issue-78372.stderr index 7e781016e1f..8e7fd5f2557 100644 --- a/tests/ui/traits/issue-78372.stderr +++ b/tests/ui/traits/issue-78372.stderr @@ -30,9 +30,12 @@ error[E0412]: cannot find type `MISC` in this scope --> $DIR/issue-78372.rs:3:34 | LL | impl<T> DispatchFromDyn<Smaht<U, MISC>> for T {} - | - ^^^^ not found in this scope - | | - | help: you might be missing a type parameter: `, MISC` + | ^^^^ not found in this scope + | +help: you might be missing a type parameter + | +LL | impl<T, MISC> DispatchFromDyn<Smaht<U, MISC>> for T {} + | ++++++ error[E0658]: use of unstable library feature 'dispatch_from_dyn' --> $DIR/issue-78372.rs:1:5 diff --git a/tests/ui/traits/issue-91594.stderr b/tests/ui/traits/issue-91594.stderr index 6b314fa586d..85d903fadd1 100644 --- a/tests/ui/traits/issue-91594.stderr +++ b/tests/ui/traits/issue-91594.stderr @@ -1,8 +1,8 @@ error[E0277]: the trait bound `Foo: HasComponent<()>` is not satisfied - --> $DIR/issue-91594.rs:10:6 + --> $DIR/issue-91594.rs:10:19 | LL | impl HasComponent<<Foo as Component<Foo>>::Interface> for Foo {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `HasComponent<()>` is not implemented for `Foo` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `HasComponent<()>` is not implemented for `Foo` | = help: the trait `HasComponent<<Foo as Component<Foo>>::Interface>` is implemented for `Foo` note: required for `Foo` to implement `Component<Foo>` diff --git a/tests/ui/traits/item-privacy.stderr b/tests/ui/traits/item-privacy.stderr index f137a298a7f..293cfbda86c 100644 --- a/tests/ui/traits/item-privacy.stderr +++ b/tests/ui/traits/item-privacy.stderr @@ -148,19 +148,24 @@ error[E0223]: ambiguous associated type --> $DIR/item-privacy.rs:115:12 | LL | let _: S::A; - | ^^^^ help: use fully-qualified syntax: `<S as Trait>::A` + | ^^^^ + | +help: if there were a trait named `Example` with associated type `A` implemented for `S`, you could use the fully-qualified path + | +LL | let _: <S as Example>::A; + | ~~~~~~~~~~~~~~~~~ error[E0223]: ambiguous associated type --> $DIR/item-privacy.rs:116:12 | LL | let _: S::B; - | ^^^^ help: use fully-qualified syntax: `<S as Trait>::B` + | ^^^^ help: use the fully-qualified path: `<S as assoc_ty::B>::B` error[E0223]: ambiguous associated type --> $DIR/item-privacy.rs:117:12 | LL | let _: S::C; - | ^^^^ help: use fully-qualified syntax: `<S as Trait>::C` + | ^^^^ help: use the fully-qualified path: `<S as assoc_ty::C>::C` error[E0624]: associated type `A` is private --> $DIR/item-privacy.rs:119:12 diff --git a/tests/ui/transmutability/malformed-program-gracefulness/unknown_dst.stderr b/tests/ui/transmutability/malformed-program-gracefulness/unknown_dst.stderr index 85087282d3a..b4591778f8e 100644 --- a/tests/ui/transmutability/malformed-program-gracefulness/unknown_dst.stderr +++ b/tests/ui/transmutability/malformed-program-gracefulness/unknown_dst.stderr @@ -1,11 +1,13 @@ error[E0412]: cannot find type `Dst` in this scope --> $DIR/unknown_dst.rs:20:36 | -LL | fn should_gracefully_handle_unknown_dst() { - | - help: you might be missing a type parameter: `<Dst>` -... LL | assert::is_transmutable::<Src, Dst, Context>(); | ^^^ not found in this scope + | +help: you might be missing a type parameter + | +LL | fn should_gracefully_handle_unknown_dst<Dst>() { + | +++++ error: aborting due to previous error diff --git a/tests/ui/transmutability/malformed-program-gracefulness/unknown_src.stderr b/tests/ui/transmutability/malformed-program-gracefulness/unknown_src.stderr index 9bedbe87c3f..a55d71d8068 100644 --- a/tests/ui/transmutability/malformed-program-gracefulness/unknown_src.stderr +++ b/tests/ui/transmutability/malformed-program-gracefulness/unknown_src.stderr @@ -1,11 +1,13 @@ error[E0412]: cannot find type `Src` in this scope --> $DIR/unknown_src.rs:20:31 | -LL | fn should_gracefully_handle_unknown_src() { - | - help: you might be missing a type parameter: `<Src>` -... LL | assert::is_transmutable::<Src, Dst, Context>(); | ^^^ not found in this scope + | +help: you might be missing a type parameter + | +LL | fn should_gracefully_handle_unknown_src<Src>() { + | +++++ error: aborting due to previous error diff --git a/tests/ui/typeck/autoderef-with-param-env-error.stderr b/tests/ui/typeck/autoderef-with-param-env-error.stderr index cde800336dd..182612d5ee7 100644 --- a/tests/ui/typeck/autoderef-with-param-env-error.stderr +++ b/tests/ui/typeck/autoderef-with-param-env-error.stderr @@ -1,11 +1,13 @@ error[E0412]: cannot find type `T` in this scope --> $DIR/autoderef-with-param-env-error.rs:3:5 | -LL | fn foo() - | - help: you might be missing a type parameter: `<T>` -LL | where LL | T: Send, | ^ not found in this scope + | +help: you might be missing a type parameter + | +LL | fn foo<T>() + | +++ error: aborting due to previous error diff --git a/tests/ui/typeck/issue-104513-ice.stderr b/tests/ui/typeck/issue-104513-ice.stderr index 2b3b1b9efdf..5561673f3c6 100644 --- a/tests/ui/typeck/issue-104513-ice.stderr +++ b/tests/ui/typeck/issue-104513-ice.stderr @@ -1,10 +1,13 @@ error[E0405]: cannot find trait `Oops` in this scope --> $DIR/issue-104513-ice.rs:3:19 | -LL | fn f() { - | - help: you might be missing a type parameter: `<Oops>` LL | let _: S<impl Oops> = S; | ^^^^ not found in this scope + | +help: you might be missing a type parameter + | +LL | fn f<Oops>() { + | ++++++ error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in variable binding --> $DIR/issue-104513-ice.rs:3:14 diff --git a/tests/ui/ufcs/ufcs-partially-resolved.stderr b/tests/ui/ufcs/ufcs-partially-resolved.stderr index 5f7f6aa9f6e..72fccea8ae3 100644 --- a/tests/ui/ufcs/ufcs-partially-resolved.stderr +++ b/tests/ui/ufcs/ufcs-partially-resolved.stderr @@ -205,7 +205,12 @@ error[E0223]: ambiguous associated type --> $DIR/ufcs-partially-resolved.rs:36:12 | LL | let _: <u8 as Tr>::Y::NN; - | ^^^^^^^^^^^^^^^^^ help: use fully-qualified syntax: `<<u8 as Tr>::Y as Trait>::NN` + | ^^^^^^^^^^^^^^^^^ + | +help: if there were a trait named `Example` with associated type `NN` implemented for `<u8 as Tr>::Y`, you could use the fully-qualified path + | +LL | let _: <<u8 as Tr>::Y as Example>::NN; + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error[E0599]: no associated item named `NN` found for type `u16` in the current scope --> $DIR/ufcs-partially-resolved.rs:38:20 diff --git a/triagebot.toml b/triagebot.toml index 1f1b1f1110d..914b52cf041 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -471,6 +471,7 @@ compiler-team = [ "@lcnr", "@nagisa", "@wesleywiser", + "@michaelwoerister", ] compiler-team-contributors = [ "@compiler-errors", @@ -478,6 +479,7 @@ compiler-team-contributors = [ "@jackh726", "@TaKO8Ki", "@Nilstrieb", + "@WaffleLapkin", ] compiler = [ "compiler-team", |
