diff --git a/Cargo.lock b/Cargo.lock index c717a8f1a9d5b..7491c1712669c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -565,14 +565,14 @@ dependencies = [ "cargo_metadata 0.12.0", "clippy-mini-macro-test", "clippy_lints", - "compiletest_rs", + "compiletest_rs 0.6.0", "derive-new", "rustc-workspace-hack", "rustc_tools_util 0.2.0", "semver 0.11.0", "serde", "tempfile", - "tester", + "tester 0.9.0", ] [[package]] @@ -584,6 +584,7 @@ name = "clippy_lints" version = "0.1.52" dependencies = [ "cargo_metadata 0.12.0", + "clippy_utils", "if_chain", "itertools 0.9.0", "pulldown-cmark 0.8.0", @@ -600,6 +601,20 @@ dependencies = [ "url 2.1.1", ] +[[package]] +name = "clippy_utils" +version = "0.1.52" +dependencies = [ + "if_chain", + "itertools 0.9.0", + "regex-syntax", + "rustc-semver", + "serde", + "smallvec 1.6.1", + "toml", + "unicode-normalization", +] + [[package]] name = "cloudabi" version = "0.1.0" @@ -695,7 +710,30 @@ dependencies = [ "serde_derive", "serde_json", "tempfile", - "tester", + "tester 0.7.0", + "winapi 0.3.9", +] + +[[package]] +name = "compiletest_rs" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0086d6ad78cf409c3061618cd98e2789d5c9ce598fc9651611cf62eae0a599cb" +dependencies = [ + "diff", + "filetime", + "getopts", + "lazy_static", + "libc", + "log", + "miow 0.3.6", + "regex", + "rustfix", + "serde", + "serde_derive", + "serde_json", + "tempfile", + "tester 0.9.0", "winapi 0.3.9", ] @@ -984,6 +1022,16 @@ dependencies = [ "dirs-sys", ] +[[package]] +name = "dirs-next" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" +dependencies = [ + "cfg-if 1.0.0", + "dirs-sys-next", +] + [[package]] name = "dirs-sys" version = "0.3.5" @@ -991,7 +1039,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e93d7f5705de3e49895a2b5e0b8855a1c27f080192ae9c32a6432d50741a57a" dependencies = [ "libc", - "redox_users", + "redox_users 0.3.4", + "winapi 0.3.9", +] + +[[package]] +name = "dirs-sys-next" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" +dependencies = [ + "libc", + "redox_users 0.4.0", "winapi 0.3.9", ] @@ -1115,7 +1174,7 @@ checksum = "3ed85775dcc68644b5c950ac06a2b23768d3bc9390464151aaf27136998dcf9e" dependencies = [ "cfg-if 0.1.10", "libc", - "redox_syscall", + "redox_syscall 0.1.57", "winapi 0.3.9", ] @@ -2226,7 +2285,7 @@ name = "miri" version = "0.1.0" dependencies = [ "colored", - "compiletest_rs", + "compiletest_rs 0.5.0", "env_logger 0.7.1", "getrandom 0.2.0", "hex 0.4.2", @@ -2458,7 +2517,7 @@ dependencies = [ "cloudabi", "instant", "libc", - "redox_syscall", + "redox_syscall 0.1.57", "smallvec 1.6.1", "winapi 0.3.9", ] @@ -2899,6 +2958,15 @@ version = "0.1.57" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" +[[package]] +name = "redox_syscall" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94341e4e44e24f6b591b59e47a8a027df12e008d73fd5672dbea9cc22f4507d9" +dependencies = [ + "bitflags", +] + [[package]] name = "redox_users" version = "0.3.4" @@ -2906,10 +2974,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09b23093265f8d200fa7b4c2c76297f47e681c655f6f1285a8780d6a022f7431" dependencies = [ "getrandom 0.1.14", - "redox_syscall", + "redox_syscall 0.1.57", "rust-argon2", ] +[[package]] +name = "redox_users" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "528532f3d801c87aec9def2add9ca802fe569e44a544afe633765267840abe64" +dependencies = [ + "getrandom 0.2.0", + "redox_syscall 0.2.5", +] + [[package]] name = "regex" version = "1.4.3" @@ -4535,6 +4613,12 @@ dependencies = [ "unicode_categories", ] +[[package]] +name = "rustversion" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb5d2a036dc6d2d8fd16fde3498b04306e29bd193bf306a57427019b823d5acd" + [[package]] name = "ryu" version = "1.0.5" @@ -4812,7 +4896,7 @@ checksum = "7fd8b795c389288baa5f355489c65e71fd48a02104600d15c4cfbc561e9e429d" dependencies = [ "cfg-if 0.1.10", "libc", - "redox_syscall", + "redox_syscall 0.1.57", "winapi 0.3.9", ] @@ -4973,7 +5057,7 @@ checksum = "c8a4c1d0bee3230179544336c15eefb563cf0302955d962e456542323e8c2e8a" dependencies = [ "filetime", "libc", - "redox_syscall", + "redox_syscall 0.1.57", "xattr", ] @@ -4986,7 +5070,7 @@ dependencies = [ "cfg-if 0.1.10", "libc", "rand", - "redox_syscall", + "redox_syscall 0.1.57", "remove_dir_all", "winapi 0.3.9", ] @@ -5020,6 +5104,17 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "term" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c59df8ac95d96ff9bede18eb7300b0fda5e5d8d90960e76f8e14ae765eedbf1f" +dependencies = [ + "dirs-next", + "rustversion", + "winapi 0.3.9", +] + [[package]] name = "termcolor" version = "1.1.0" @@ -5065,6 +5160,19 @@ dependencies = [ "term 0.6.1", ] +[[package]] +name = "tester" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0639d10d8f4615f223a57275cf40f9bdb7cfbb806bcb7f7cc56e3beb55a576eb" +dependencies = [ + "cfg-if 1.0.0", + "getopts", + "libc", + "num_cpus", + "term 0.7.0", +] + [[package]] name = "textwrap" version = "0.11.0" diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 1d2f1f694cf5b..16b4378e7f77f 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -2695,7 +2695,7 @@ pub enum ItemKind { /// A use declaration item (`use`). /// /// E.g., `use foo;`, `use foo::bar;` or `use foo::bar as FooBar;`. - Use(P), + Use(UseTree), /// A static item (`static`). /// /// E.g., `static FOO: i32 = 42;` or `static FOO: &'static str = "bar";`. @@ -2719,7 +2719,7 @@ pub enum ItemKind { /// E.g., `extern {}` or `extern "C" {}`. ForeignMod(ForeignMod), /// Module-level inline assembly (from `global_asm!()`). - GlobalAsm(P), + GlobalAsm(GlobalAsm), /// A type alias (`type`). /// /// E.g., `type Foo = Bar;`. diff --git a/compiler/rustc_builtin_macros/src/global_asm.rs b/compiler/rustc_builtin_macros/src/global_asm.rs index 3689e33be6f0f..76d874529270e 100644 --- a/compiler/rustc_builtin_macros/src/global_asm.rs +++ b/compiler/rustc_builtin_macros/src/global_asm.rs @@ -28,7 +28,7 @@ pub fn expand_global_asm<'cx>( ident: Ident::invalid(), attrs: Vec::new(), id: ast::DUMMY_NODE_ID, - kind: ast::ItemKind::GlobalAsm(P(global_asm)), + kind: ast::ItemKind::GlobalAsm(global_asm), vis: ast::Visibility { span: sp.shrink_to_lo(), kind: ast::VisibilityKind::Inherited, diff --git a/compiler/rustc_builtin_macros/src/standard_library_imports.rs b/compiler/rustc_builtin_macros/src/standard_library_imports.rs index 3a81d076dc52f..f446e6be84ca4 100644 --- a/compiler/rustc_builtin_macros/src/standard_library_imports.rs +++ b/compiler/rustc_builtin_macros/src/standard_library_imports.rs @@ -1,5 +1,4 @@ use rustc_ast as ast; -use rustc_ast::ptr::P; use rustc_expand::base::{ExtCtxt, ResolverExpand}; use rustc_expand::expand::ExpansionConfig; use rustc_session::Session; @@ -72,11 +71,11 @@ pub fn inject( span, Ident::invalid(), vec![cx.attribute(cx.meta_word(span, sym::prelude_import))], - ast::ItemKind::Use(P(ast::UseTree { + ast::ItemKind::Use(ast::UseTree { prefix: cx.path(span, import_path), kind: ast::UseTreeKind::Glob, span, - })), + }), ); krate.items.insert(0, use_item); diff --git a/compiler/rustc_codegen_llvm/src/allocator.rs b/compiler/rustc_codegen_llvm/src/allocator.rs index a5ea0b2a74c5c..068e5e99efead 100644 --- a/compiler/rustc_codegen_llvm/src/allocator.rs +++ b/compiler/rustc_codegen_llvm/src/allocator.rs @@ -93,7 +93,7 @@ pub(crate) unsafe fn codegen( let args = [usize, usize]; // size, align let ty = llvm::LLVMFunctionType(void, args.as_ptr(), args.len() as c_uint, False); - let name = "__rust_alloc_error_handler".to_string(); + let name = "__rust_alloc_error_handler"; let llfn = llvm::LLVMRustGetOrInsertFunction(llmod, name.as_ptr().cast(), name.len(), ty); // -> ! DIFlagNoReturn llvm::Attribute::NoReturn.apply_llfn(llvm::AttributePlace::Function, llfn); diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs index 4aa25aae74760..26815de403fd2 100644 --- a/compiler/rustc_codegen_llvm/src/asm.rs +++ b/compiler/rustc_codegen_llvm/src/asm.rs @@ -61,9 +61,9 @@ impl AsmBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> { // Default per-arch clobbers // Basically what clang does let arch_clobbers = match &self.sess().target.arch[..] { - "x86" | "x86_64" => vec!["~{dirflag}", "~{fpsr}", "~{flags}"], - "mips" | "mips64" => vec!["~{$1}"], - _ => Vec::new(), + "x86" | "x86_64" => &["~{dirflag}", "~{fpsr}", "~{flags}"][..], + "mips" | "mips64" => &["~{$1}"], + _ => &[], }; let all_constraints = ia diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index b93a579df1526..08932e26bf1c7 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -181,16 +181,16 @@ fn get_linker( let original_path = tool.path(); if let Some(ref root_lib_path) = original_path.ancestors().nth(4) { let arch = match t.arch.as_str() { - "x86_64" => Some("x64".to_string()), - "x86" => Some("x86".to_string()), - "aarch64" => Some("arm64".to_string()), - "arm" => Some("arm".to_string()), + "x86_64" => Some("x64"), + "x86" => Some("x86"), + "aarch64" => Some("arm64"), + "arm" => Some("arm"), _ => None, }; if let Some(ref a) = arch { // FIXME: Move this to `fn linker_with_args`. let mut arg = OsString::from("/LIBPATH:"); - arg.push(format!("{}\\lib\\{}\\store", root_lib_path.display(), a.to_string())); + arg.push(format!("{}\\lib\\{}\\store", root_lib_path.display(), a)); cmd.arg(&arg); } else { warn!("arch is not supported"); diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs index ef4a45cab4135..ce5b130dd97fe 100644 --- a/compiler/rustc_errors/src/diagnostic.rs +++ b/compiler/rustc_errors/src/diagnostic.rs @@ -295,6 +295,7 @@ impl Diagnostic { suggestion: Vec<(Span, String)>, applicability: Applicability, ) -> &mut Self { + assert!(!suggestion.is_empty()); self.suggestions.push(CodeSuggestion { substitutions: vec![Substitution { parts: suggestion @@ -318,6 +319,10 @@ impl Diagnostic { suggestions: Vec>, applicability: Applicability, ) -> &mut Self { + assert!(!suggestions.is_empty()); + for s in &suggestions { + assert!(!s.is_empty()); + } self.suggestions.push(CodeSuggestion { substitutions: suggestions .into_iter() @@ -348,6 +353,7 @@ impl Diagnostic { suggestion: Vec<(Span, String)>, applicability: Applicability, ) -> &mut Self { + assert!(!suggestion.is_empty()); self.suggestions.push(CodeSuggestion { substitutions: vec![Substitution { parts: suggestion diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 2fef7c2cc087d..f4402843afcbe 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1577,6 +1577,14 @@ impl Expr<'_> { expr } + pub fn peel_blocks(&self) -> &Self { + let mut expr = self; + while let ExprKind::Block(Block { expr: Some(inner), .. }, _) = &expr.kind { + expr = inner; + } + expr + } + pub fn can_have_side_effects(&self) -> bool { match self.peel_drop_temps().kind { ExprKind::Path(_) | ExprKind::Lit(_) => false, diff --git a/compiler/rustc_middle/src/lint.rs b/compiler/rustc_middle/src/lint.rs index ca73481b21699..26e61ec8cf866 100644 --- a/compiler/rustc_middle/src/lint.rs +++ b/compiler/rustc_middle/src/lint.rs @@ -353,12 +353,12 @@ pub fn struct_lint_level<'s, 'd>( it will become a hard error"; let explanation = if lint_id == LintId::of(builtin::UNSTABLE_NAME_COLLISIONS) { - "once this method is added to the standard library, \ - the ambiguity may cause an error or change in behavior!" + "once this associated item is added to the standard library, the ambiguity may \ + cause an error or change in behavior!" .to_owned() } else if lint_id == LintId::of(builtin::MUTABLE_BORROW_RESERVATION_CONFLICT) { - "this borrowing pattern was not meant to be accepted, \ - and may become a hard error in the future" + "this borrowing pattern was not meant to be accepted, and may become a hard error \ + in the future" .to_owned() } else if let Some(edition) = future_incompatible.edition { format!("{} in the {} edition!", STANDARD_MESSAGE, edition) diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 073a2d8bd5120..9668a24bf8ab6 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -225,7 +225,7 @@ impl<'a> Parser<'a> { return Err(e); } - (Ident::invalid(), ItemKind::Use(P(tree))) + (Ident::invalid(), ItemKind::Use(tree)) } else if self.check_fn_front_matter() { // FUNCTION ITEM let (ident, sig, generics, body) = self.parse_fn(attrs, req_name, lo)?; diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 6457c6cee576f..d60f929cb8f3f 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -319,9 +319,13 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { .collect::>(); let crate_def_id = DefId::local(CRATE_DEF_INDEX); if candidates.is_empty() && is_expected(Res::Def(DefKind::Enum, crate_def_id)) { - let enum_candidates = - self.r.lookup_import_candidates(ident, ns, &self.parent_scope, is_enum_variant); - + let mut enum_candidates: Vec<_> = self + .r + .lookup_import_candidates(ident, ns, &self.parent_scope, is_enum_variant) + .into_iter() + .map(|suggestion| import_candidate_to_enum_paths(&suggestion)) + .filter(|(_, enum_ty_path)| enum_ty_path != "std::prelude::v1") + .collect(); if !enum_candidates.is_empty() { if let (PathSource::Type, Some(span)) = (source, self.diagnostic_metadata.current_type_ascription.last()) @@ -340,10 +344,6 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { } } - let mut enum_candidates = enum_candidates - .iter() - .map(|suggestion| import_candidate_to_enum_paths(&suggestion)) - .collect::>(); enum_candidates.sort(); // Contextualize for E0412 "cannot find type", but don't belabor the point @@ -363,19 +363,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { err.span_suggestions( span, &msg, - enum_candidates - .into_iter() - .map(|(_variant_path, enum_ty_path)| enum_ty_path) - // Variants re-exported in prelude doesn't mean `prelude::v1` is the - // type name! - // FIXME: is there a more principled way to do this that - // would work for other re-exports? - .filter(|enum_ty_path| enum_ty_path != "std::prelude::v1") - // Also write `Option` rather than `std::prelude::v1::Option`. - .map(|enum_ty_path| { - // FIXME #56861: DRY-er prelude filtering. - enum_ty_path.trim_start_matches("std::prelude::v1::").to_owned() - }), + enum_candidates.into_iter().map(|(_variant_path, enum_ty_path)| enum_ty_path), Applicability::MachineApplicable, ); } diff --git a/compiler/rustc_typeck/src/check/callee.rs b/compiler/rustc_typeck/src/check/callee.rs index f2fbb95fc021c..ca1e79fac73e9 100644 --- a/compiler/rustc_typeck/src/check/callee.rs +++ b/compiler/rustc_typeck/src/check/callee.rs @@ -4,7 +4,7 @@ use crate::type_error_struct; use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder}; use rustc_hir as hir; -use rustc_hir::def::Res; +use rustc_hir::def::{Namespace, Res}; use rustc_hir::def_id::{DefId, LOCAL_CRATE}; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_infer::{infer, traits}; @@ -374,7 +374,26 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { |p| format!("`{}` defined here returns `{}`", p, callee_ty), ) } - _ => Some(format!("`{}` defined here", callee_ty)), + _ => { + match def { + // Emit a different diagnostic for local variables, as they are not + // type definitions themselves, but rather variables *of* that type. + Res::Local(hir_id) => Some(format!( + "`{}` has type `{}`", + self.tcx.hir().name(hir_id), + callee_ty + )), + Res::Def(kind, def_id) + if kind.ns() == Some(Namespace::ValueNS) => + { + Some(format!( + "`{}` defined here", + self.tcx.def_path_str(def_id), + )) + } + _ => Some(format!("`{}` defined here", callee_ty)), + } + } }; if let Some(label) = label { err.span_label(span, label); diff --git a/compiler/rustc_typeck/src/check/coercion.rs b/compiler/rustc_typeck/src/check/coercion.rs index 159c97d8bfaa9..792836f666555 100644 --- a/compiler/rustc_typeck/src/check/coercion.rs +++ b/compiler/rustc_typeck/src/check/coercion.rs @@ -42,6 +42,7 @@ use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_infer::infer::{Coercion, InferOk, InferResult}; +use rustc_middle::lint::in_external_macro; use rustc_middle::ty::adjustment::{ Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability, PointerCast, }; @@ -1448,7 +1449,12 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { expected.is_unit(), pointing_at_return_type, ) { - if cond_expr.span.desugaring_kind().is_none() { + // If the block is from an external macro, then do not suggest + // adding a semicolon, because there's nowhere to put it. + // See issue #81943. + if cond_expr.span.desugaring_kind().is_none() + && !in_external_macro(fcx.tcx.sess, cond_expr.span) + { err.span_label(cond_expr.span, "expected this to be `()`"); if expr.can_have_side_effects() { fcx.suggest_semicolon_at_end(cond_expr.span, &mut err); diff --git a/compiler/rustc_typeck/src/check/demand.rs b/compiler/rustc_typeck/src/check/demand.rs index 8d2004a543b7b..39b973ed371ae 100644 --- a/compiler/rustc_typeck/src/check/demand.rs +++ b/compiler/rustc_typeck/src/check/demand.rs @@ -616,10 +616,30 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } _ if sp == expr.span && !is_macro => { if let Some(steps) = self.deref_steps(checked_ty, expected) { + let expr = expr.peel_blocks(); + if steps == 1 { - // For a suggestion to make sense, the type would need to be `Copy`. - if self.infcx.type_is_copy_modulo_regions(self.param_env, expected, sp) { - if let Ok(code) = sm.span_to_snippet(sp) { + if let hir::ExprKind::AddrOf(_, mutbl, inner) = expr.kind { + // If the expression has `&`, removing it would fix the error + let prefix_span = expr.span.with_hi(inner.span.lo()); + let message = match mutbl { + hir::Mutability::Not => "consider removing the `&`", + hir::Mutability::Mut => "consider removing the `&mut`", + }; + let suggestion = String::new(); + return Some(( + prefix_span, + message, + suggestion, + Applicability::MachineApplicable, + )); + } else if self.infcx.type_is_copy_modulo_regions( + self.param_env, + expected, + sp, + ) { + // For this suggestion to make sense, the type would need to be `Copy`. + if let Ok(code) = sm.span_to_snippet(expr.span) { let message = if checked_ty.is_region_ptr() { "consider dereferencing the borrow" } else { @@ -631,7 +651,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { format!("*{}", code) }; return Some(( - sp, + expr.span, message, suggestion, Applicability::MachineApplicable, diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs index 416b75d9e2e0c..1f50ad5779e0f 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs @@ -10,6 +10,7 @@ use rustc_hir::def::{CtorOf, DefKind}; use rustc_hir::lang_items::LangItem; use rustc_hir::{ExprKind, ItemKind, Node}; use rustc_infer::infer; +use rustc_middle::lint::in_external_macro; use rustc_middle::ty::{self, Ty}; use rustc_span::symbol::kw; @@ -44,7 +45,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { blk_id: hir::HirId, ) -> bool { let expr = expr.peel_drop_temps(); - if expr.can_have_side_effects() { + // If the expression is from an external macro, then do not suggest + // adding a semicolon, because there's nowhere to put it. + // See issue #81943. + if expr.can_have_side_effects() && !in_external_macro(self.tcx.sess, cause_span) { self.suggest_missing_semicolon(err, expr, expected, cause_span); } let mut pointing_at_return_type = false; diff --git a/compiler/rustc_typeck/src/check/method/probe.rs b/compiler/rustc_typeck/src/check/method/probe.rs index 158c214759db2..2bfd697e4cdca 100644 --- a/compiler/rustc_typeck/src/check/method/probe.rs +++ b/compiler/rustc_typeck/src/check/method/probe.rs @@ -10,6 +10,7 @@ use crate::hir::def_id::DefId; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::sync::Lrc; +use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::def::Namespace; use rustc_infer::infer::canonical::OriginalQueryValues; @@ -1167,7 +1168,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { // // We suppress warning if we're picking the method only because it is a // suggestion. - self.emit_unstable_name_collision_hint(p, &unstable_candidates); + self.emit_unstable_name_collision_hint(p, &unstable_candidates, self_ty); } } return Some(pick); @@ -1246,24 +1247,46 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { &self, stable_pick: &Pick<'_>, unstable_candidates: &[(&Candidate<'tcx>, Symbol)], + self_ty: Ty<'tcx>, ) { self.tcx.struct_span_lint_hir( lint::builtin::UNSTABLE_NAME_COLLISIONS, self.fcx.body_id, self.span, |lint| { - let mut diag = lint.build( - "a method with this name may be added to the standard library in the future", - ); - // FIXME: This should be a `span_suggestion` instead of `help` - // However `self.span` only - // highlights the method name, so we can't use it. Also consider reusing the code from - // `report_method_error()`. - diag.help(&format!( - "call with fully qualified syntax `{}(...)` to keep using the current method", - self.tcx.def_path_str(stable_pick.item.def_id), + let def_kind = stable_pick.item.kind.as_def_kind(); + let mut diag = lint.build(&format!( + "{} {} with this name may be added to the standard library in the future", + def_kind.article(), + def_kind.descr(stable_pick.item.def_id), )); - + match (stable_pick.item.kind, stable_pick.item.container) { + (ty::AssocKind::Fn, _) => { + // FIXME: This should be a `span_suggestion` instead of `help` + // However `self.span` only + // highlights the method name, so we can't use it. Also consider reusing + // the code from `report_method_error()`. + diag.help(&format!( + "call with fully qualified syntax `{}(...)` to keep using the current \ + method", + self.tcx.def_path_str(stable_pick.item.def_id), + )); + } + (ty::AssocKind::Const, ty::AssocItemContainer::TraitContainer(def_id)) => { + diag.span_suggestion( + self.span, + "use the fully qualified path to the associated const", + format!( + "<{} as {}>::{}", + self_ty, + self.tcx.def_path_str(def_id), + stable_pick.item.ident + ), + Applicability::MachineApplicable, + ); + } + _ => {} + } if self.tcx.sess.is_nightly_build() { for (candidate, feature) in unstable_candidates { diag.help(&format!( diff --git a/library/core/src/char/methods.rs b/library/core/src/char/methods.rs index 4390342134d1d..b3e1becf570a7 100644 --- a/library/core/src/char/methods.rs +++ b/library/core/src/char/methods.rs @@ -569,8 +569,9 @@ impl char { /// assert_eq!(len, tokyo.len()); /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_char_len_utf", since = "1.52.0")] #[inline] - pub fn len_utf8(self) -> usize { + pub const fn len_utf8(self) -> usize { len_utf8(self as u32) } @@ -594,8 +595,9 @@ impl char { /// assert_eq!(len, 2); /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_char_len_utf", since = "1.52.0")] #[inline] - pub fn len_utf16(self) -> usize { + pub const fn len_utf16(self) -> usize { let ch = self as u32; if (ch & 0xFFFF) == ch { 1 } else { 2 } } @@ -1086,8 +1088,9 @@ impl char { /// [`make_ascii_uppercase()`]: #method.make_ascii_uppercase /// [`to_uppercase()`]: #method.to_uppercase #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] + #[rustc_const_stable(feature = "const_ascii_methods_on_intrinsics", since = "1.52.0")] #[inline] - pub fn to_ascii_uppercase(&self) -> char { + pub const fn to_ascii_uppercase(&self) -> char { if self.is_ascii_lowercase() { (*self as u8).ascii_change_case_unchecked() as char } else { @@ -1118,8 +1121,9 @@ impl char { /// [`make_ascii_lowercase()`]: #method.make_ascii_lowercase /// [`to_lowercase()`]: #method.to_lowercase #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] + #[rustc_const_stable(feature = "const_ascii_methods_on_intrinsics", since = "1.52.0")] #[inline] - pub fn to_ascii_lowercase(&self) -> char { + pub const fn to_ascii_lowercase(&self) -> char { if self.is_ascii_uppercase() { (*self as u8).ascii_change_case_unchecked() as char } else { @@ -1143,8 +1147,9 @@ impl char { /// assert!(!upper_a.eq_ignore_ascii_case(&lower_z)); /// ``` #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] + #[rustc_const_stable(feature = "const_ascii_methods_on_intrinsics", since = "1.52.0")] #[inline] - pub fn eq_ignore_ascii_case(&self, other: &char) -> bool { + pub const fn eq_ignore_ascii_case(&self, other: &char) -> bool { self.to_ascii_lowercase() == other.to_ascii_lowercase() } @@ -1561,7 +1566,7 @@ impl char { } #[inline] -fn len_utf8(code: u32) -> usize { +const fn len_utf8(code: u32) -> usize { if code < MAX_ONE_B { 1 } else if code < MAX_TWO_B { diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index a9e2ef4251a16..5274262ded2b2 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -833,6 +833,7 @@ extern "rust-intrinsic" { /// /// This exists solely for [`mem::forget_unsized`]; normal `forget` uses /// `ManuallyDrop` instead. + #[rustc_const_unstable(feature = "const_intrinsic_forget", issue = "none")] pub fn forget(_: T); /// Reinterprets the bits of a value of one type as another type. diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 0d1a09a528db9..64e2a95130999 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -73,10 +73,12 @@ #![feature(const_discriminant)] #![feature(const_cell_into_inner)] #![feature(const_intrinsic_copy)] +#![feature(const_intrinsic_forget)] #![feature(const_float_classify)] #![feature(const_float_bits_conv)] #![feature(const_int_unchecked_arith)] #![feature(const_mut_refs)] +#![feature(const_refs_to_cell)] #![feature(const_cttz)] #![feature(const_panic)] #![feature(const_pin)] @@ -90,6 +92,7 @@ #![feature(const_ptr_offset)] #![feature(const_ptr_offset_from)] #![feature(const_ptr_read)] +#![feature(const_ptr_write)] #![feature(const_raw_ptr_comparison)] #![feature(const_raw_ptr_deref)] #![feature(const_slice_from_raw_parts)] diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs index 41ea2760ec570..9a54921f07b49 100644 --- a/library/core/src/macros/mod.rs +++ b/library/core/src/macros/mod.rs @@ -1,4 +1,4 @@ -#[doc(include = "panic.md")] +#[doc = include_str!("panic.md")] #[macro_export] #[rustc_builtin_macro = "core_panic"] #[allow_internal_unstable(edition_panic)] diff --git a/library/core/src/num/error.rs b/library/core/src/num/error.rs index 9d8c8c862911c..e2cc8faf8547d 100644 --- a/library/core/src/num/error.rs +++ b/library/core/src/num/error.rs @@ -54,10 +54,7 @@ impl From for TryFromIntError { /// /// Among other causes, `ParseIntError` can be thrown because of leading or trailing whitespace /// in the string e.g., when it is obtained from the standard input. -/// Using the [`str.trim()`] method ensures that no whitespace remains before parsing. -/// -/// [`str.trim()`]: ../../std/primitive.str.html#method.trim -/// [`i8::from_str_radix`]: ../../std/primitive.i8.html#method.from_str_radix +/// Using the [`str::trim()`] method ensures that no whitespace remains before parsing. /// /// # Example /// diff --git a/library/core/src/num/f32.rs b/library/core/src/num/f32.rs index 795f94ec03454..80cfb5a0e3aeb 100644 --- a/library/core/src/num/f32.rs +++ b/library/core/src/num/f32.rs @@ -18,7 +18,7 @@ use crate::mem; use crate::num::FpCategory; /// The radix or base of the internal representation of `f32`. -/// Use [`f32::RADIX`](../../std/primitive.f32.html#associatedconstant.RADIX) instead. +/// Use [`f32::RADIX`] instead. /// /// # Examples /// @@ -832,8 +832,8 @@ impl f32 { /// As the target platform's native endianness is used, portable code /// should use [`to_be_bytes`] or [`to_le_bytes`], as appropriate, instead. /// - /// [`to_be_bytes`]: #method.to_be_bytes - /// [`to_le_bytes`]: #method.to_le_bytes + /// [`to_be_bytes`]: f32::to_be_bytes + /// [`to_le_bytes`]: f32::to_le_bytes /// /// # Examples /// @@ -860,7 +860,7 @@ impl f32 { /// /// [`to_ne_bytes`] should be preferred over this whenever possible. /// - /// [`to_ne_bytes`]: #method.to_ne_bytes + /// [`to_ne_bytes`]: f32::to_ne_bytes /// /// # Examples /// @@ -920,8 +920,8 @@ impl f32 { /// likely wants to use [`from_be_bytes`] or [`from_le_bytes`], as /// appropriate instead. /// - /// [`from_be_bytes`]: #method.from_be_bytes - /// [`from_le_bytes`]: #method.from_le_bytes + /// [`from_be_bytes`]: f32::from_be_bytes + /// [`from_le_bytes`]: f32::from_le_bytes /// /// # Examples /// diff --git a/library/core/src/num/f64.rs b/library/core/src/num/f64.rs index 7af968f7fe84b..e365e1b21df10 100644 --- a/library/core/src/num/f64.rs +++ b/library/core/src/num/f64.rs @@ -846,8 +846,8 @@ impl f64 { /// As the target platform's native endianness is used, portable code /// should use [`to_be_bytes`] or [`to_le_bytes`], as appropriate, instead. /// - /// [`to_be_bytes`]: #method.to_be_bytes - /// [`to_le_bytes`]: #method.to_le_bytes + /// [`to_be_bytes`]: f64::to_be_bytes + /// [`to_le_bytes`]: f64::to_le_bytes /// /// # Examples /// @@ -874,7 +874,7 @@ impl f64 { /// /// [`to_ne_bytes`] should be preferred over this whenever possible. /// - /// [`to_ne_bytes`]: #method.to_ne_bytes + /// [`to_ne_bytes`]: f64::to_ne_bytes /// /// # Examples /// @@ -934,8 +934,8 @@ impl f64 { /// likely wants to use [`from_be_bytes`] or [`from_le_bytes`], as /// appropriate instead. /// - /// [`from_be_bytes`]: #method.from_be_bytes - /// [`from_le_bytes`]: #method.from_le_bytes + /// [`from_be_bytes`]: f64::from_be_bytes + /// [`from_le_bytes`]: f64::from_le_bytes /// /// # Examples /// diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs index 709ed26d2a39f..ce9dca39d0ea4 100644 --- a/library/core/src/num/int_macros.rs +++ b/library/core/src/num/int_macros.rs @@ -1067,7 +1067,7 @@ macro_rules! int_impl { /// /// Note that this is *not* the same as a rotate-left; the RHS of a wrapping shift-left is restricted to /// the range of the type, rather than the bits shifted out of the LHS being returned to the other end. - /// The primitive integer types all implement a [`rotate_left`](#method.rotate_left) function, + /// The primitive integer types all implement a [`rotate_left`](Self::rotate_left) function, /// which may be what you want instead. /// /// # Examples @@ -1096,7 +1096,7 @@ macro_rules! int_impl { /// /// Note that this is *not* the same as a rotate-right; the RHS of a wrapping shift-right is restricted /// to the range of the type, rather than the bits shifted out of the LHS being returned to the other - /// end. The primitive integer types all implement a [`rotate_right`](#method.rotate_right) function, + /// end. The primitive integer types all implement a [`rotate_right`](Self::rotate_right) function, /// which may be what you want instead. /// /// # Examples @@ -1812,8 +1812,8 @@ macro_rules! int_impl { /// #[doc = $to_xe_bytes_doc] /// - /// [`to_be_bytes`]: #method.to_be_bytes - /// [`to_le_bytes`]: #method.to_le_bytes + /// [`to_be_bytes`]: Self::to_be_bytes + /// [`to_le_bytes`]: Self::to_le_bytes /// /// # Examples /// @@ -1845,7 +1845,7 @@ macro_rules! int_impl { /// /// [`to_ne_bytes`] should be preferred over this whenever possible. /// - /// [`to_ne_bytes`]: #method.to_ne_bytes + /// [`to_ne_bytes`]: Self::to_ne_bytes /// /// # Examples /// @@ -1937,8 +1937,8 @@ macro_rules! int_impl { /// likely wants to use [`from_be_bytes`] or [`from_le_bytes`], as /// appropriate instead. /// - /// [`from_be_bytes`]: #method.from_be_bytes - /// [`from_le_bytes`]: #method.from_le_bytes + /// [`from_be_bytes`]: Self::from_be_bytes + /// [`from_le_bytes`]: Self::from_le_bytes /// #[doc = $to_xe_bytes_doc] /// @@ -1976,7 +1976,7 @@ macro_rules! int_impl { } /// New code should prefer to use - #[doc = concat!("[`", stringify!($SelfT), "::MIN", "`](#associatedconstant.MIN).")] + #[doc = concat!("[`", stringify!($SelfT), "::MIN", "`] instead.")] /// /// Returns the smallest value that can be represented by this integer type. #[stable(feature = "rust1", since = "1.0.0")] @@ -1989,7 +1989,7 @@ macro_rules! int_impl { } /// New code should prefer to use - #[doc = concat!("[`", stringify!($SelfT), "::MAX", "`](#associatedconstant.MAX).")] + #[doc = concat!("[`", stringify!($SelfT), "::MAX", "`] instead.")] /// /// Returns the largest value that can be represented by this integer type. #[stable(feature = "rust1", since = "1.0.0")] diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs index c13f000a73615..f0bd976ba83d5 100644 --- a/library/core/src/num/mod.rs +++ b/library/core/src/num/mod.rs @@ -193,10 +193,11 @@ impl u8 { /// assert_eq!(65, lowercase_a.to_ascii_uppercase()); /// ``` /// - /// [`make_ascii_uppercase`]: #method.make_ascii_uppercase + /// [`make_ascii_uppercase`]: Self::make_ascii_uppercase #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] + #[rustc_const_stable(feature = "const_ascii_methods_on_intrinsics", since = "1.52.0")] #[inline] - pub fn to_ascii_uppercase(&self) -> u8 { + pub const fn to_ascii_uppercase(&self) -> u8 { // Unset the fifth bit if this is a lowercase letter *self & !((self.is_ascii_lowercase() as u8) * ASCII_CASE_MASK) } @@ -216,17 +217,18 @@ impl u8 { /// assert_eq!(97, uppercase_a.to_ascii_lowercase()); /// ``` /// - /// [`make_ascii_lowercase`]: #method.make_ascii_lowercase + /// [`make_ascii_lowercase`]: Self::make_ascii_lowercase #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] + #[rustc_const_stable(feature = "const_ascii_methods_on_intrinsics", since = "1.52.0")] #[inline] - pub fn to_ascii_lowercase(&self) -> u8 { + pub const fn to_ascii_lowercase(&self) -> u8 { // Set the fifth bit if this is an uppercase letter *self | (self.is_ascii_uppercase() as u8 * ASCII_CASE_MASK) } /// Assumes self is ascii #[inline] - pub(crate) fn ascii_change_case_unchecked(&self) -> u8 { + pub(crate) const fn ascii_change_case_unchecked(&self) -> u8 { *self ^ ASCII_CASE_MASK } @@ -243,8 +245,9 @@ impl u8 { /// assert!(lowercase_a.eq_ignore_ascii_case(&uppercase_a)); /// ``` #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] + #[rustc_const_stable(feature = "const_ascii_methods_on_intrinsics", since = "1.52.0")] #[inline] - pub fn eq_ignore_ascii_case(&self, other: &u8) -> bool { + pub const fn eq_ignore_ascii_case(&self, other: &u8) -> bool { self.to_ascii_lowercase() == other.to_ascii_lowercase() } @@ -266,7 +269,7 @@ impl u8 { /// assert_eq!(b'A', byte); /// ``` /// - /// [`to_ascii_uppercase`]: #method.to_ascii_uppercase + /// [`to_ascii_uppercase`]: Self::to_ascii_uppercase #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] #[inline] pub fn make_ascii_uppercase(&mut self) { @@ -291,7 +294,7 @@ impl u8 { /// assert_eq!(b'a', byte); /// ``` /// - /// [`to_ascii_lowercase`]: #method.to_ascii_lowercase + /// [`to_ascii_lowercase`]: Self::to_ascii_lowercase #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] #[inline] pub fn make_ascii_lowercase(&mut self) { @@ -723,9 +726,6 @@ impl usize { /// This `enum` is used as the return type for [`f32::classify`] and [`f64::classify`]. See /// their documentation for more. /// -/// [`f32::classify`]: ../../std/primitive.f32.html#method.classify -/// [`f64::classify`]: ../../std/primitive.f64.html#method.classify -/// /// # Examples /// /// ``` diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs index bf5331a01d58e..7393e7f923e1f 100644 --- a/library/core/src/num/uint_macros.rs +++ b/library/core/src/num/uint_macros.rs @@ -994,7 +994,7 @@ macro_rules! uint_impl { /// RHS of a wrapping shift-left is restricted to the range /// of the type, rather than the bits shifted out of the LHS /// being returned to the other end. The primitive integer - /// types all implement a [`rotate_left`](#method.rotate_left) function, + /// types all implement a [`rotate_left`](Self::rotate_left) function, /// which may be what you want instead. /// /// # Examples @@ -1026,7 +1026,7 @@ macro_rules! uint_impl { /// RHS of a wrapping shift-right is restricted to the range /// of the type, rather than the bits shifted out of the LHS /// being returned to the other end. The primitive integer - /// types all implement a [`rotate_right`](#method.rotate_right) function, + /// types all implement a [`rotate_right`](Self::rotate_right) function, /// which may be what you want instead. /// /// # Examples @@ -1642,8 +1642,8 @@ macro_rules! uint_impl { /// #[doc = $to_xe_bytes_doc] /// - /// [`to_be_bytes`]: #method.to_be_bytes - /// [`to_le_bytes`]: #method.to_le_bytes + /// [`to_be_bytes`]: Self::to_be_bytes + /// [`to_le_bytes`]: Self::to_le_bytes /// /// # Examples /// @@ -1675,7 +1675,7 @@ macro_rules! uint_impl { /// /// [`to_ne_bytes`] should be preferred over this whenever possible. /// - /// [`to_ne_bytes`]: #method.to_ne_bytes + /// [`to_ne_bytes`]: Self::to_ne_bytes /// /// # Examples /// @@ -1767,8 +1767,8 @@ macro_rules! uint_impl { /// likely wants to use [`from_be_bytes`] or [`from_le_bytes`], as /// appropriate instead. /// - /// [`from_be_bytes`]: #method.from_be_bytes - /// [`from_le_bytes`]: #method.from_le_bytes + /// [`from_be_bytes`]: Self::from_be_bytes + /// [`from_le_bytes`]: Self::from_le_bytes /// #[doc = $from_xe_bytes_doc] /// @@ -1806,8 +1806,7 @@ macro_rules! uint_impl { } /// New code should prefer to use - #[doc = concat!("[`", stringify!($SelfT), "::MIN", "`](#associatedconstant.MIN).")] - /// instead. + #[doc = concat!("[`", stringify!($SelfT), "::MIN", "`] instead.")] /// /// Returns the smallest value that can be represented by this integer type. #[stable(feature = "rust1", since = "1.0.0")] @@ -1818,8 +1817,7 @@ macro_rules! uint_impl { pub const fn min_value() -> Self { Self::MIN } /// New code should prefer to use - #[doc = concat!("[`", stringify!($SelfT), "::MAX", "`](#associatedconstant.MAX).")] - /// instead. + #[doc = concat!("[`", stringify!($SelfT), "::MAX", "`] instead.")] /// /// Returns the largest value that can be represented by this integer type. #[stable(feature = "rust1", since = "1.0.0")] diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs index 9c53430ce3556..481d5d772b4a9 100644 --- a/library/core/src/ptr/mod.rs +++ b/library/core/src/ptr/mod.rs @@ -902,7 +902,8 @@ pub const unsafe fn read_unaligned(src: *const T) -> T { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] -pub unsafe fn write(dst: *mut T, src: T) { +#[rustc_const_unstable(feature = "const_ptr_write", issue = "none")] +pub const unsafe fn write(dst: *mut T, src: T) { // SAFETY: the caller must guarantee that `dst` is valid for writes. // `dst` cannot overlap `src` because the caller has mutable access // to `dst` while `src` is owned by this function. @@ -998,14 +999,16 @@ pub unsafe fn write(dst: *mut T, src: T) { /// ``` #[inline] #[stable(feature = "ptr_unaligned", since = "1.17.0")] -pub unsafe fn write_unaligned(dst: *mut T, src: T) { +#[rustc_const_unstable(feature = "const_ptr_write", issue = "none")] +pub const unsafe fn write_unaligned(dst: *mut T, src: T) { // SAFETY: the caller must guarantee that `dst` is valid for writes. // `dst` cannot overlap `src` because the caller has mutable access // to `dst` while `src` is owned by this function. unsafe { copy_nonoverlapping(&src as *const T as *const u8, dst as *mut u8, mem::size_of::()); + // We are calling the intrinsic directly to avoid function calls in the generated code. + intrinsics::forget(src); } - mem::forget(src); } /// Performs a volatile read of the value from `src` without moving it. This diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index 6651c3dd4e86b..4e3e88b946cd9 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -1003,8 +1003,9 @@ impl *mut T { /// /// [`ptr::write`]: crate::ptr::write() #[stable(feature = "pointer_methods", since = "1.26.0")] + #[rustc_const_unstable(feature = "const_ptr_write", issue = "none")] #[inline] - pub unsafe fn write(self, val: T) + pub const unsafe fn write(self, val: T) where T: Sized, { @@ -1057,8 +1058,9 @@ impl *mut T { /// /// [`ptr::write_unaligned`]: crate::ptr::write_unaligned() #[stable(feature = "pointer_methods", since = "1.26.0")] + #[rustc_const_unstable(feature = "const_ptr_write", issue = "none")] #[inline] - pub unsafe fn write_unaligned(self, val: T) + pub const unsafe fn write_unaligned(self, val: T) where T: Sized, { diff --git a/library/core/tests/const_ptr.rs b/library/core/tests/const_ptr.rs index 4acd059ab03df..152fed803ecdb 100644 --- a/library/core/tests/const_ptr.rs +++ b/library/core/tests/const_ptr.rs @@ -49,3 +49,53 @@ fn mut_ptr_read() { const UNALIGNED: u16 = unsafe { UNALIGNED_PTR.read_unaligned() }; assert_eq!(UNALIGNED, u16::from_ne_bytes([0x23, 0x45])); } + +#[test] +fn write() { + use core::ptr; + + const fn write_aligned() -> i32 { + let mut res = 0; + unsafe { + ptr::write(&mut res as *mut _, 42); + } + res + } + const ALIGNED: i32 = write_aligned(); + assert_eq!(ALIGNED, 42); + + const fn write_unaligned() -> [u16; 2] { + let mut two_aligned = [0u16; 2]; + unsafe { + let unaligned_ptr = (two_aligned.as_mut_ptr() as *mut u8).add(1) as *mut u16; + ptr::write_unaligned(unaligned_ptr, u16::from_ne_bytes([0x23, 0x45])); + } + two_aligned + } + const UNALIGNED: [u16; 2] = write_unaligned(); + assert_eq!(UNALIGNED, [u16::from_ne_bytes([0x00, 0x23]), u16::from_ne_bytes([0x45, 0x00])]); +} + +#[test] +fn mut_ptr_write() { + const fn aligned() -> i32 { + let mut res = 0; + unsafe { + (&mut res as *mut i32).write(42); + } + res + } + const ALIGNED: i32 = aligned(); + assert_eq!(ALIGNED, 42); + + const fn write_unaligned() -> [u16; 2] { + let mut two_aligned = [0u16; 2]; + unsafe { + let unaligned_ptr = (two_aligned.as_mut_ptr() as *mut u8).add(1) as *mut u16; + unaligned_ptr.write_unaligned(u16::from_ne_bytes([0x23, 0x45])); + } + two_aligned + } + const UNALIGNED: [u16; 2] = write_unaligned(); + assert_eq!(UNALIGNED, [u16::from_ne_bytes([0x00, 0x23]), u16::from_ne_bytes([0x45, 0x00])]); +} diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index 9692724545f28..d6d3111e2ffa7 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -14,6 +14,7 @@ #![feature(const_cell_into_inner)] #![feature(const_maybe_uninit_assume_init)] #![feature(const_ptr_read)] +#![feature(const_ptr_write)] #![feature(const_ptr_offset)] #![feature(control_flow_enum)] #![feature(core_intrinsics)] diff --git a/library/std/src/error.rs b/library/std/src/error.rs index 605d953f5da71..94338c7b04d06 100644 --- a/library/std/src/error.rs +++ b/library/std/src/error.rs @@ -30,6 +30,7 @@ use crate::mem::transmute; use crate::num; use crate::str; use crate::string; +use crate::sync::Arc; /// `Error` is a trait representing the basic expectations for error values, /// i.e., values of type `E` in [`Result`]. Errors must describe @@ -507,6 +508,27 @@ impl<'a, T: Error + ?Sized> Error for &'a T { } } +#[stable(feature = "arc_error", since = "1.52.0")] +impl Error for Arc { + #[allow(deprecated, deprecated_in_future)] + fn description(&self) -> &str { + Error::description(&**self) + } + + #[allow(deprecated)] + fn cause(&self) -> Option<&dyn Error> { + Error::cause(&**self) + } + + fn source(&self) -> Option<&(dyn Error + 'static)> { + Error::source(&**self) + } + + fn backtrace(&self) -> Option<&Backtrace> { + Error::backtrace(&**self) + } +} + #[stable(feature = "fmt_error", since = "1.11.0")] impl Error for fmt::Error { #[allow(deprecated)] diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 588bffb57c9c5..32aca8c83924d 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -264,7 +264,6 @@ #![feature(exhaustive_patterns)] #![feature(extend_one)] #![feature(extended_key_value_attributes)] -#![feature(external_doc)] #![feature(fn_traits)] #![feature(format_args_nl)] #![feature(gen_future)] diff --git a/library/std/src/macros.rs b/library/std/src/macros.rs index c0750f8c0d1b0..b729349cf530f 100644 --- a/library/std/src/macros.rs +++ b/library/std/src/macros.rs @@ -4,7 +4,7 @@ //! library. Each macro is available for use when linking against the standard //! library. -#[doc(include = "../../core/src/macros/panic.md")] +#[doc = include_str!("../../core/src/macros/panic.md")] #[macro_export] #[rustc_builtin_macro = "std_panic"] #[stable(feature = "rust1", since = "1.0.0")] diff --git a/library/std/src/os/raw/mod.rs b/library/std/src/os/raw/mod.rs index 22c98d7ade992..50464a050c706 100644 --- a/library/std/src/os/raw/mod.rs +++ b/library/std/src/os/raw/mod.rs @@ -18,7 +18,7 @@ macro_rules! type_alias_no_nz { $Docfile:tt, $Alias:ident = $Real:ty; $( $Cfg:tt )* } => { - #[doc(include = $Docfile)] + #[doc = include_str!($Docfile)] $( $Cfg )* #[stable(feature = "raw_os", since = "1.1.0")] pub type $Alias = $Real; diff --git a/src/librustdoc/html/static/normalize.css b/src/librustdoc/html/static/normalize.css index 0e0426279183f..da9a75e3e85e9 100644 --- a/src/librustdoc/html/static/normalize.css +++ b/src/librustdoc/html/static/normalize.css @@ -1,2 +1,2 @@ /* ignore-tidy-linelength */ -/*! normalize.css v3.0.0 | MIT License | git.io/normalize */html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background:transparent}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:bold}dfn{font-style:italic}h1{font-size:2em;margin:.67em 0}mark{background:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-0.5em}sub{bottom:-0.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{-moz-box-sizing:content-box;box-sizing:content-box;height:0}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}button,input,optgroup,select,textarea{color:inherit;font:inherit;margin:0}button{overflow:visible}button,select{text-transform:none}button,html input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}input{line-height:normal}input[type="checkbox"],input[type="radio"]{box-sizing:border-box;padding:0}input[type="number"]::-webkit-inner-spin-button,input[type="number"]::-webkit-outer-spin-button{height:auto}input[type="search"]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}input[type="search"]::-webkit-search-cancel-button,input[type="search"]::-webkit-search-decoration{-webkit-appearance:none}fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}legend{border:0;padding:0}textarea{overflow:auto}optgroup{font-weight:bold}table{border-collapse:collapse;border-spacing:0}td,th{padding:0} +/*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */html{line-height:1.15;-webkit-text-size-adjust:100%}body{margin:0}main{display:block}h1{font-size:2em;margin:.67em 0}hr{box-sizing:content-box;height:0;overflow:visible}pre{font-family:monospace,monospace;font-size:1em}a{background-color:transparent}abbr[title]{border-bottom:none;text-decoration:underline;text-decoration:underline dotted}b,strong{font-weight:bolder}code,kbd,samp{font-family:monospace,monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}img{border-style:none}button,input,optgroup,select,textarea{font-family:inherit;font-size:100%;line-height:1.15;margin:0}button,input{overflow:visible}button,select{text-transform:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{border-style:none;padding:0}[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring,button:-moz-focusring{outline:1px dotted ButtonText}fieldset{padding:.35em .75em .625em}legend{box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal}progress{vertical-align:baseline}textarea{overflow:auto}[type=checkbox],[type=radio]{box-sizing:border-box;padding:0}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}details{display:block}summary{display:list-item}template{display:none}[hidden]{display:none} diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index c99e1ecac739c..6d9e3d0b9eab0 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -134,15 +134,20 @@ impl TryFrom for Res { } } -#[derive(Debug)] /// A link failed to resolve. +#[derive(Debug)] enum ResolutionFailure<'a> { /// This resolved, but with the wrong namespace. - /// - /// `Namespace` is the namespace specified with a disambiguator - /// (as opposed to the actual namespace of the `Res`). - WrongNamespace(Res, /* disambiguated */ Namespace), - /// The link failed to resolve. `resolution_failure` should look to see if there's + WrongNamespace { + /// What the link resolved to. + res: Res, + /// The expected namespace for the resolution, determined from the link's disambiguator. + /// + /// E.g., for `[fn@Result]` this is [`Namespace::ValueNS`], + /// even though `Result`'s actual namespace is [`Namespace::TypeNS`]. + expected_ns: Namespace, + }, + /// The link failed to resolve. [`resolution_failure`] should look to see if there's /// a more helpful error that can be given. NotResolved { /// The scope the link was resolved in. @@ -157,12 +162,11 @@ enum ResolutionFailure<'a> { unresolved: Cow<'a, str>, }, /// This happens when rustdoc can't determine the parent scope for an item. - /// /// It is always a bug in rustdoc. NoParentItem, /// This link has malformed generic parameters; e.g., the angle brackets are unbalanced. MalformedGenerics(MalformedGenerics), - /// Used to communicate that this should be ignored, but shouldn't be reported to the user + /// Used to communicate that this should be ignored, but shouldn't be reported to the user. /// /// This happens when there is no disambiguator and one of the namespaces /// failed to resolve. @@ -216,7 +220,7 @@ impl ResolutionFailure<'a> { /// Returns the full resolution of the link, if present. fn full_res(&self) -> Option { match self { - Self::WrongNamespace(res, _) => Some(*res), + Self::WrongNamespace { res, expected_ns: _ } => Some(*res), _ => None, } } @@ -1308,20 +1312,20 @@ impl LinkCollector<'_, '_> { let extra_fragment = &key.extra_fragment; match disambiguator.map(Disambiguator::ns) { - Some(ns @ (ValueNS | TypeNS)) => { - match self.resolve(path_str, ns, base_node, extra_fragment) { + Some(expected_ns @ (ValueNS | TypeNS)) => { + match self.resolve(path_str, expected_ns, base_node, extra_fragment) { Ok(res) => Some(res), Err(ErrorKind::Resolve(box mut kind)) => { // We only looked in one namespace. Try to give a better error if possible. if kind.full_res().is_none() { - let other_ns = if ns == ValueNS { TypeNS } else { ValueNS }; + let other_ns = if expected_ns == ValueNS { TypeNS } else { ValueNS }; // FIXME: really it should be `resolution_failure` that does this, not `resolve_with_disambiguator` // See https://github.com/rust-lang/rust/pull/76955#discussion_r493953382 for a good approach for &new_ns in &[other_ns, MacroNS] { if let Some(res) = self.check_full_res(new_ns, path_str, base_node, extra_fragment) { - kind = ResolutionFailure::WrongNamespace(res, ns); + kind = ResolutionFailure::WrongNamespace { res, expected_ns }; break; } } @@ -1396,7 +1400,7 @@ impl LinkCollector<'_, '_> { // Constructors are picked up in the type namespace. match res { Res::Def(DefKind::Ctor(..), _) => { - Err(ResolutionFailure::WrongNamespace(res, TypeNS)) + Err(ResolutionFailure::WrongNamespace { res, expected_ns: TypeNS }) } _ => { match (fragment, extra_fragment.clone()) { @@ -1457,7 +1461,8 @@ impl LinkCollector<'_, '_> { if let Some(res) = self.check_full_res(ns, path_str, base_node, extra_fragment) { - kind = ResolutionFailure::WrongNamespace(res, MacroNS); + kind = + ResolutionFailure::WrongNamespace { res, expected_ns: MacroNS }; break; } } @@ -1889,7 +1894,7 @@ fn resolution_failure( let note = match failure { ResolutionFailure::NotResolved { .. } => unreachable!("handled above"), ResolutionFailure::Dummy => continue, - ResolutionFailure::WrongNamespace(res, expected_ns) => { + ResolutionFailure::WrongNamespace { res, expected_ns } => { if let Res::Def(kind, _) = res { let disambiguator = Disambiguator::Kind(kind); suggest_disambiguator( @@ -1910,7 +1915,7 @@ fn resolution_failure( } ResolutionFailure::NoParentItem => { diag.level = rustc_errors::Level::Bug; - "all intra doc links should have a parent item".to_owned() + "all intra-doc links should have a parent item".to_owned() } ResolutionFailure::MalformedGenerics(variant) => match variant { MalformedGenerics::UnbalancedAngleBrackets => { diff --git a/src/test/ui/consts/const-as-fn.rs b/src/test/ui/consts/const-as-fn.rs new file mode 100644 index 0000000000000..388f907f8d2c3 --- /dev/null +++ b/src/test/ui/consts/const-as-fn.rs @@ -0,0 +1,5 @@ +const FOO: usize = 0; + +fn main() { + FOO(); //~ ERROR expected function, found `usize` +} diff --git a/src/test/ui/consts/const-as-fn.stderr b/src/test/ui/consts/const-as-fn.stderr new file mode 100644 index 0000000000000..b8dd4134b284d --- /dev/null +++ b/src/test/ui/consts/const-as-fn.stderr @@ -0,0 +1,14 @@ +error[E0618]: expected function, found `usize` + --> $DIR/const-as-fn.rs:4:5 + | +LL | const FOO: usize = 0; + | --------------------- `FOO` defined here +... +LL | FOO(); + | ^^^-- + | | + | call expression requires function + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0618`. diff --git a/src/test/ui/error-codes/E0618.stderr b/src/test/ui/error-codes/E0618.stderr index 6ddda3bf8b528..714c8d1e4d75c 100644 --- a/src/test/ui/error-codes/E0618.stderr +++ b/src/test/ui/error-codes/E0618.stderr @@ -18,7 +18,7 @@ error[E0618]: expected function, found `i32` --> $DIR/E0618.rs:9:5 | LL | let x = 0i32; - | - `i32` defined here + | - `x` has type `i32` LL | x(); | ^-- | | diff --git a/src/test/ui/inference/auxiliary/inference_unstable_iterator.rs b/src/test/ui/inference/auxiliary/inference_unstable_iterator.rs index 0dc09704e7fab..91fc398f74183 100644 --- a/src/test/ui/inference/auxiliary/inference_unstable_iterator.rs +++ b/src/test/ui/inference/auxiliary/inference_unstable_iterator.rs @@ -8,7 +8,11 @@ pub trait IpuIterator { fn ipu_flatten(&self) -> u32 { 0 } + #[unstable(feature = "assoc_const_ipu_iter", issue = "99999")] + const C: i32; } #[stable(feature = "ipu_iterator", since = "1.0.0")] -impl IpuIterator for char {} +impl IpuIterator for char { + const C: i32 = 42; +} diff --git a/src/test/ui/inference/auxiliary/inference_unstable_itertools.rs b/src/test/ui/inference/auxiliary/inference_unstable_itertools.rs index 964f35ddadec5..e00adda5c3382 100644 --- a/src/test/ui/inference/auxiliary/inference_unstable_itertools.rs +++ b/src/test/ui/inference/auxiliary/inference_unstable_itertools.rs @@ -2,6 +2,10 @@ pub trait IpuItertools { fn ipu_flatten(&self) -> u32 { 1 } + + const C: i32; } -impl IpuItertools for char {} +impl IpuItertools for char { + const C: i32 = 1; +} diff --git a/src/test/ui/inference/inference_unstable.rs b/src/test/ui/inference/inference_unstable.rs index 0b95770018241..86bb62b8a5f64 100644 --- a/src/test/ui/inference/inference_unstable.rs +++ b/src/test/ui/inference/inference_unstable.rs @@ -14,6 +14,9 @@ use inference_unstable_itertools::IpuItertools; fn main() { assert_eq!('x'.ipu_flatten(), 1); - //~^ WARN a method with this name may be added to the standard library in the future - //~^^ WARN once this method is added to the standard library, the ambiguity may cause an error +//~^ WARN an associated function with this name may be added to the standard library in the future +//~| WARN once this associated item is added to the standard library, the ambiguity may cause an + assert_eq!(char::C, 1); +//~^ WARN an associated constant with this name may be added to the standard library in the future +//~| WARN once this associated item is added to the standard library, the ambiguity may cause an } diff --git a/src/test/ui/inference/inference_unstable.stderr b/src/test/ui/inference/inference_unstable.stderr index df52012463255..2c282e610b29c 100644 --- a/src/test/ui/inference/inference_unstable.stderr +++ b/src/test/ui/inference/inference_unstable.stderr @@ -1,14 +1,24 @@ -warning: a method with this name may be added to the standard library in the future +warning: an associated function with this name may be added to the standard library in the future --> $DIR/inference_unstable.rs:16:20 | LL | assert_eq!('x'.ipu_flatten(), 1); | ^^^^^^^^^^^ | = note: `#[warn(unstable_name_collisions)]` on by default - = warning: once this method is added to the standard library, the ambiguity may cause an error or change in behavior! + = warning: once this associated item is added to the standard library, the ambiguity may cause an error or change in behavior! = note: for more information, see issue #48919 = help: call with fully qualified syntax `inference_unstable_itertools::IpuItertools::ipu_flatten(...)` to keep using the current method = help: add `#![feature(ipu_flatten)]` to the crate attributes to enable `inference_unstable_iterator::IpuIterator::ipu_flatten` -warning: 1 warning emitted +warning: an associated constant with this name may be added to the standard library in the future + --> $DIR/inference_unstable.rs:19:16 + | +LL | assert_eq!(char::C, 1); + | ^^^^^^^ help: use the fully qualified path to the associated const: `::C` + | + = warning: once this associated item is added to the standard library, the ambiguity may cause an error or change in behavior! + = note: for more information, see issue #48919 + = help: add `#![feature(assoc_const_ipu_iter)]` to the crate attributes to enable `inference_unstable_iterator::IpuIterator::C` + +warning: 2 warnings emitted diff --git a/src/test/ui/issues/issue-10969.stderr b/src/test/ui/issues/issue-10969.stderr index 9e28a665e30fb..f64b61aaeb05c 100644 --- a/src/test/ui/issues/issue-10969.stderr +++ b/src/test/ui/issues/issue-10969.stderr @@ -2,7 +2,7 @@ error[E0618]: expected function, found `i32` --> $DIR/issue-10969.rs:2:5 | LL | fn func(i: i32) { - | - `i32` defined here + | - `i` has type `i32` LL | i(); | ^-- | | @@ -12,7 +12,7 @@ error[E0618]: expected function, found `i32` --> $DIR/issue-10969.rs:6:5 | LL | let i = 0i32; - | - `i32` defined here + | - `i` has type `i32` LL | i(); | ^-- | | diff --git a/src/test/ui/issues/issue-21701.stderr b/src/test/ui/issues/issue-21701.stderr index 77bb3802d8603..0405ce551b0ab 100644 --- a/src/test/ui/issues/issue-21701.stderr +++ b/src/test/ui/issues/issue-21701.stderr @@ -2,7 +2,7 @@ error[E0618]: expected function, found `U` --> $DIR/issue-21701.rs:2:13 | LL | fn foo(t: U) { - | - `U` defined here + | - `t` has type `U` LL | let y = t(); | ^-- | | diff --git a/src/test/ui/issues/issue-22468.stderr b/src/test/ui/issues/issue-22468.stderr index 8d8601b311166..3fff91acbc25f 100644 --- a/src/test/ui/issues/issue-22468.stderr +++ b/src/test/ui/issues/issue-22468.stderr @@ -2,7 +2,7 @@ error[E0618]: expected function, found `&str` --> $DIR/issue-22468.rs:3:13 | LL | let foo = "bar"; - | --- `&str` defined here + | --- `foo` has type `&str` LL | let x = foo("baz"); | ^^^------- | | diff --git a/src/test/ui/issues/issue-26237.stderr b/src/test/ui/issues/issue-26237.stderr index f58c1bfe644fc..91d28a5e1e1ef 100644 --- a/src/test/ui/issues/issue-26237.stderr +++ b/src/test/ui/issues/issue-26237.stderr @@ -5,7 +5,7 @@ LL | $not_a_function($some_argument) | ------------------------------- call expression requires function ... LL | let mut value_a = 0; - | ----------- `{integer}` defined here + | ----------- `value_a` has type `{integer}` LL | let mut value_b = 0; LL | macro_panic!(value_a, value_b); | ^^^^^^^ diff --git a/src/test/ui/parser/parse-error-correct.stderr b/src/test/ui/parser/parse-error-correct.stderr index c54baf00b27f2..691df91268b24 100644 --- a/src/test/ui/parser/parse-error-correct.stderr +++ b/src/test/ui/parser/parse-error-correct.stderr @@ -14,7 +14,7 @@ error[E0618]: expected function, found `{integer}` --> $DIR/parse-error-correct.rs:7:13 | LL | let y = 42; - | - `{integer}` defined here + | - `y` has type `{integer}` LL | let x = y.; LL | let x = y.(); | ^--- diff --git a/src/test/ui/structs/80853.rs b/src/test/ui/structs/80853.rs new file mode 100644 index 0000000000000..242d0af959d40 --- /dev/null +++ b/src/test/ui/structs/80853.rs @@ -0,0 +1,7 @@ +struct S; + +fn repro_ref(thing: S) { + thing(); //~ ERROR expected function, found `S` +} + +fn main() {} diff --git a/src/test/ui/structs/80853.stderr b/src/test/ui/structs/80853.stderr new file mode 100644 index 0000000000000..8a38e32c1d0ca --- /dev/null +++ b/src/test/ui/structs/80853.stderr @@ -0,0 +1,13 @@ +error[E0618]: expected function, found `S` + --> $DIR/80853.rs:4:5 + | +LL | fn repro_ref(thing: S) { + | ----- `thing` has type `S` +LL | thing(); + | ^^^^^-- + | | + | call expression requires function + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0618`. diff --git a/src/test/ui/suggestions/do-not-attempt-to-add-suggestions-with-no-changes.rs b/src/test/ui/suggestions/do-not-attempt-to-add-suggestions-with-no-changes.rs new file mode 100644 index 0000000000000..a25be862a5daf --- /dev/null +++ b/src/test/ui/suggestions/do-not-attempt-to-add-suggestions-with-no-changes.rs @@ -0,0 +1,5 @@ +use std::result; +impl result { //~ ERROR expected type, found module `result` + fn into_future() -> Err {} //~ ERROR expected type, found variant `Err` +} +fn main() {} diff --git a/src/test/ui/suggestions/do-not-attempt-to-add-suggestions-with-no-changes.stderr b/src/test/ui/suggestions/do-not-attempt-to-add-suggestions-with-no-changes.stderr new file mode 100644 index 0000000000000..59ccb29e0901a --- /dev/null +++ b/src/test/ui/suggestions/do-not-attempt-to-add-suggestions-with-no-changes.stderr @@ -0,0 +1,20 @@ +error[E0573]: expected type, found module `result` + --> $DIR/do-not-attempt-to-add-suggestions-with-no-changes.rs:2:6 + | +LL | impl result { + | ^^^^^^ help: an enum with a similar name exists: `Result` + | + ::: $SRC_DIR/core/src/result.rs:LL:COL + | +LL | pub enum Result { + | --------------------- similarly named enum `Result` defined here + +error[E0573]: expected type, found variant `Err` + --> $DIR/do-not-attempt-to-add-suggestions-with-no-changes.rs:3:25 + | +LL | fn into_future() -> Err {} + | ^^^ not a type + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0573`. diff --git a/src/test/ui/suggestions/issue-82361.fixed b/src/test/ui/suggestions/issue-82361.fixed new file mode 100644 index 0000000000000..d72de982bf98a --- /dev/null +++ b/src/test/ui/suggestions/issue-82361.fixed @@ -0,0 +1,24 @@ +// run-rustfix + +fn main() { + let a: usize = 123; + let b: &usize = &a; + + if true { + a + } else { + *b //~ ERROR `if` and `else` have incompatible types [E0308] + }; + + if true { + 1 + } else { + 1 //~ ERROR `if` and `else` have incompatible types [E0308] + }; + + if true { + 1 + } else { + 1 //~ ERROR `if` and `else` have incompatible types [E0308] + }; +} diff --git a/src/test/ui/suggestions/issue-82361.rs b/src/test/ui/suggestions/issue-82361.rs new file mode 100644 index 0000000000000..c068f6d22b476 --- /dev/null +++ b/src/test/ui/suggestions/issue-82361.rs @@ -0,0 +1,24 @@ +// run-rustfix + +fn main() { + let a: usize = 123; + let b: &usize = &a; + + if true { + a + } else { + b //~ ERROR `if` and `else` have incompatible types [E0308] + }; + + if true { + 1 + } else { + &1 //~ ERROR `if` and `else` have incompatible types [E0308] + }; + + if true { + 1 + } else { + &mut 1 //~ ERROR `if` and `else` have incompatible types [E0308] + }; +} diff --git a/src/test/ui/suggestions/issue-82361.stderr b/src/test/ui/suggestions/issue-82361.stderr new file mode 100644 index 0000000000000..c19d59ccd4c66 --- /dev/null +++ b/src/test/ui/suggestions/issue-82361.stderr @@ -0,0 +1,48 @@ +error[E0308]: `if` and `else` have incompatible types + --> $DIR/issue-82361.rs:10:9 + | +LL | / if true { +LL | | a + | | - expected because of this +LL | | } else { +LL | | b + | | ^ + | | | + | | expected `usize`, found `&usize` + | | help: consider dereferencing the borrow: `*b` +LL | | }; + | |_____- `if` and `else` have incompatible types + +error[E0308]: `if` and `else` have incompatible types + --> $DIR/issue-82361.rs:16:9 + | +LL | / if true { +LL | | 1 + | | - expected because of this +LL | | } else { +LL | | &1 + | | -^ + | | | + | | expected integer, found `&{integer}` + | | help: consider removing the `&` +LL | | }; + | |_____- `if` and `else` have incompatible types + +error[E0308]: `if` and `else` have incompatible types + --> $DIR/issue-82361.rs:22:9 + | +LL | / if true { +LL | | 1 + | | - expected because of this +LL | | } else { +LL | | &mut 1 + | | -----^ + | | | + | | expected integer, found `&mut {integer}` + | | help: consider removing the `&mut` +LL | | }; + | |_____- `if` and `else` have incompatible types + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/typeck/auxiliary/issue-81943-lib.rs b/src/test/ui/typeck/auxiliary/issue-81943-lib.rs new file mode 100644 index 0000000000000..521c54f899670 --- /dev/null +++ b/src/test/ui/typeck/auxiliary/issue-81943-lib.rs @@ -0,0 +1,7 @@ +pub fn g(t: i32) -> i32 { t } +// This function imitates `dbg!` so that future changes +// to its macro definition won't make this test a dud. +#[macro_export] +macro_rules! d { + ($e:expr) => { match $e { x => { $crate::g(x) } } } +} diff --git a/src/test/ui/typeck/issue-81943.rs b/src/test/ui/typeck/issue-81943.rs new file mode 100644 index 0000000000000..18f5970a350a2 --- /dev/null +++ b/src/test/ui/typeck/issue-81943.rs @@ -0,0 +1,13 @@ +// aux-build:issue-81943-lib.rs +extern crate issue_81943_lib as lib; + +fn f(f: F) { f(0); } +fn g(t: i32) -> i32 { t } +fn main() { + f(|x| lib::d!(x)); //~ERROR + f(|x| match x { tmp => { g(tmp) } }); //~ERROR + macro_rules! d { + ($e:expr) => { match $e { x => { g(x) } } } //~ERROR + } + f(|x| d!(x)); +} diff --git a/src/test/ui/typeck/issue-81943.stderr b/src/test/ui/typeck/issue-81943.stderr new file mode 100644 index 0000000000000..a30facfeb6daa --- /dev/null +++ b/src/test/ui/typeck/issue-81943.stderr @@ -0,0 +1,51 @@ +error[E0308]: mismatched types + --> $DIR/issue-81943.rs:7:9 + | +LL | f(|x| lib::d!(x)); + | ^^^^^^^^^^ expected `()`, found `i32` + | + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0308]: mismatched types + --> $DIR/issue-81943.rs:8:28 + | +LL | f(|x| match x { tmp => { g(tmp) } }); + | -------------------^^^^^^---- + | | | + | | expected `()`, found `i32` + | expected this to be `()` + | +help: consider using a semicolon here + | +LL | f(|x| match x { tmp => { g(tmp); } }); + | ^ +help: consider using a semicolon here + | +LL | f(|x| match x { tmp => { g(tmp) } };); + | ^ + +error[E0308]: mismatched types + --> $DIR/issue-81943.rs:10:38 + | +LL | ($e:expr) => { match $e { x => { g(x) } } } + | ------------------^^^^---- + | | | + | | expected `()`, found `i32` + | expected this to be `()` +LL | } +LL | f(|x| d!(x)); + | ----- in this macro invocation + | + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider using a semicolon here + | +LL | ($e:expr) => { match $e { x => { g(x); } } } + | ^ +help: consider using a semicolon here + | +LL | ($e:expr) => { match $e { x => { g(x) } }; } + | ^ + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/tools/clippy/.github/ISSUE_TEMPLATE/bug_report.md b/src/tools/clippy/.github/ISSUE_TEMPLATE/bug_report.md index d8f0c44148cae..2bc87db123d4d 100644 --- a/src/tools/clippy/.github/ISSUE_TEMPLATE/bug_report.md +++ b/src/tools/clippy/.github/ISSUE_TEMPLATE/bug_report.md @@ -1,7 +1,7 @@ --- name: Bug Report about: Create a bug report for Clippy -labels: L-bug +labels: C-bug --- $DIR/upper_case_acronyms.rs:3:8 + | +LL | struct HTTPResponse; // not linted by default, but with cfg option + | ^^^^^^^^^^^^ help: consider making the acronym lowercase, except the initial letter: `HttpResponse` + | + = note: `-D clippy::upper-case-acronyms` implied by `-D warnings` + +error: name `NS` contains a capitalized acronym + --> $DIR/upper_case_acronyms.rs:8:5 + | +LL | NS, // not linted + | ^^ help: consider making the acronym lowercase, except the initial letter (notice the capitalization): `Ns` + +error: name `CWR` contains a capitalized acronym + --> $DIR/upper_case_acronyms.rs:9:5 + | +LL | CWR, + | ^^^ help: consider making the acronym lowercase, except the initial letter: `Cwr` + +error: name `ECE` contains a capitalized acronym + --> $DIR/upper_case_acronyms.rs:10:5 + | +LL | ECE, + | ^^^ help: consider making the acronym lowercase, except the initial letter: `Ece` + +error: name `URG` contains a capitalized acronym + --> $DIR/upper_case_acronyms.rs:11:5 + | +LL | URG, + | ^^^ help: consider making the acronym lowercase, except the initial letter: `Urg` + +error: name `ACK` contains a capitalized acronym + --> $DIR/upper_case_acronyms.rs:12:5 + | +LL | ACK, + | ^^^ help: consider making the acronym lowercase, except the initial letter (notice the capitalization): `Ack` + +error: name `PSH` contains a capitalized acronym + --> $DIR/upper_case_acronyms.rs:13:5 + | +LL | PSH, + | ^^^ help: consider making the acronym lowercase, except the initial letter: `Psh` + +error: name `RST` contains a capitalized acronym + --> $DIR/upper_case_acronyms.rs:14:5 + | +LL | RST, + | ^^^ help: consider making the acronym lowercase, except the initial letter: `Rst` + +error: name `SYN` contains a capitalized acronym + --> $DIR/upper_case_acronyms.rs:15:5 + | +LL | SYN, + | ^^^ help: consider making the acronym lowercase, except the initial letter: `Syn` + +error: name `FIN` contains a capitalized acronym + --> $DIR/upper_case_acronyms.rs:16:5 + | +LL | FIN, + | ^^^ help: consider making the acronym lowercase, except the initial letter: `Fin` + +error: name `GCCLLVMSomething` contains a capitalized acronym + --> $DIR/upper_case_acronyms.rs:19:8 + | +LL | struct GCCLLVMSomething; // linted with cfg option, beware that lint suggests `GccllvmSomething` instead of + | ^^^^^^^^^^^^^^^^ help: consider making the acronym lowercase, except the initial letter: `GccllvmSomething` + +error: aborting due to 11 previous errors + diff --git a/src/tools/clippy/tests/ui/auxiliary/proc_macro_derive.rs b/src/tools/clippy/tests/ui/auxiliary/proc_macro_derive.rs index 24891682d368d..aebeaf346799d 100644 --- a/src/tools/clippy/tests/ui/auxiliary/proc_macro_derive.rs +++ b/src/tools/clippy/tests/ui/auxiliary/proc_macro_derive.rs @@ -41,3 +41,15 @@ pub fn derive_foo(_input: TokenStream) -> TokenStream { } } } + +#[proc_macro_derive(StructAUseSelf)] +pub fn derive_use_self(_input: TokenStream) -> proc_macro::TokenStream { + quote! { + struct A; + impl A { + fn new() -> A { + A + } + } + } +} diff --git a/src/tools/clippy/tests/ui/blocks_in_if_conditions_closure.rs b/src/tools/clippy/tests/ui/blocks_in_if_conditions_closure.rs index acbabfa20d737..2856943b9be80 100644 --- a/src/tools/clippy/tests/ui/blocks_in_if_conditions_closure.rs +++ b/src/tools/clippy/tests/ui/blocks_in_if_conditions_closure.rs @@ -44,4 +44,13 @@ fn macro_in_closure() { } } -fn main() {} +#[rustfmt::skip] +fn main() { + let mut range = 0..10; + range.all(|i| {i < 10} ); + + let v = vec![1, 2, 3]; + if v.into_iter().any(|x| {x == 4}) { + println!("contains 4!"); + } +} diff --git a/src/tools/clippy/tests/ui/collapsible_else_if.fixed b/src/tools/clippy/tests/ui/collapsible_else_if.fixed index fa4bc30e933a2..c69a46f0a77ee 100644 --- a/src/tools/clippy/tests/ui/collapsible_else_if.fixed +++ b/src/tools/clippy/tests/ui/collapsible_else_if.fixed @@ -65,4 +65,13 @@ fn main() { else { println!("!") } + + if x == "hello" { + print!("Hello "); + } else { + #[cfg(not(roflol))] + if y == "world" { + println!("world!") + } + } } diff --git a/src/tools/clippy/tests/ui/collapsible_else_if.rs b/src/tools/clippy/tests/ui/collapsible_else_if.rs index bf6c1d1f894d7..1359c7eb6278e 100644 --- a/src/tools/clippy/tests/ui/collapsible_else_if.rs +++ b/src/tools/clippy/tests/ui/collapsible_else_if.rs @@ -79,4 +79,13 @@ fn main() { println!("!") } } + + if x == "hello" { + print!("Hello "); + } else { + #[cfg(not(roflol))] + if y == "world" { + println!("world!") + } + } } diff --git a/src/tools/clippy/tests/ui/collapsible_if.fixed b/src/tools/clippy/tests/ui/collapsible_if.fixed index efd4187947b20..e4c088bf6f03f 100644 --- a/src/tools/clippy/tests/ui/collapsible_if.fixed +++ b/src/tools/clippy/tests/ui/collapsible_if.fixed @@ -138,4 +138,11 @@ fn main() { // Fix #5962 if matches!(true, true) && matches!(true, true) {} + + if true { + #[cfg(not(teehee))] + if true { + println!("Hello world!"); + } + } } diff --git a/src/tools/clippy/tests/ui/collapsible_if.rs b/src/tools/clippy/tests/ui/collapsible_if.rs index 657f32d38a32b..d6cf01c831940 100644 --- a/src/tools/clippy/tests/ui/collapsible_if.rs +++ b/src/tools/clippy/tests/ui/collapsible_if.rs @@ -154,4 +154,11 @@ fn main() { if matches!(true, true) { if matches!(true, true) {} } + + if true { + #[cfg(not(teehee))] + if true { + println!("Hello world!"); + } + } } diff --git a/src/tools/clippy/tests/ui/collapsible_match.rs b/src/tools/clippy/tests/ui/collapsible_match.rs index 3294da7e8146f..55467cf4229de 100644 --- a/src/tools/clippy/tests/ui/collapsible_match.rs +++ b/src/tools/clippy/tests/ui/collapsible_match.rs @@ -232,6 +232,14 @@ fn negative_cases(res_opt: Result, String>, res_res: Result match e { + Some(e) => e, + e => e, + }, + // else branch looks the same but the binding is different + e => e, + }; } fn make() -> T { diff --git a/src/tools/clippy/tests/ui/collapsible_match.stderr b/src/tools/clippy/tests/ui/collapsible_match.stderr index 63ac6a1613dc6..7797888490089 100644 --- a/src/tools/clippy/tests/ui/collapsible_match.stderr +++ b/src/tools/clippy/tests/ui/collapsible_match.stderr @@ -1,4 +1,4 @@ -error: Unnecessary nested match +error: unnecessary nested match --> $DIR/collapsible_match.rs:7:20 | LL | Ok(val) => match val { @@ -9,15 +9,15 @@ LL | | }, | |_________^ | = note: `-D clippy::collapsible-match` implied by `-D warnings` -help: The outer pattern can be modified to include the inner pattern. +help: the outer pattern can be modified to include the inner pattern --> $DIR/collapsible_match.rs:7:12 | LL | Ok(val) => match val { - | ^^^ Replace this binding + | ^^^ replace this binding LL | Some(n) => foo(n), | ^^^^^^^ with this pattern -error: Unnecessary nested match +error: unnecessary nested match --> $DIR/collapsible_match.rs:16:20 | LL | Ok(val) => match val { @@ -27,15 +27,15 @@ LL | | _ => return, LL | | }, | |_________^ | -help: The outer pattern can be modified to include the inner pattern. +help: the outer pattern can be modified to include the inner pattern --> $DIR/collapsible_match.rs:16:12 | LL | Ok(val) => match val { - | ^^^ Replace this binding + | ^^^ replace this binding LL | Some(n) => foo(n), | ^^^^^^^ with this pattern -error: Unnecessary nested match +error: unnecessary nested match --> $DIR/collapsible_match.rs:25:9 | LL | / if let Some(n) = val { @@ -43,15 +43,15 @@ LL | | take(n); LL | | } | |_________^ | -help: The outer pattern can be modified to include the inner pattern. +help: the outer pattern can be modified to include the inner pattern --> $DIR/collapsible_match.rs:24:15 | LL | if let Ok(val) = res_opt { - | ^^^ Replace this binding + | ^^^ replace this binding LL | if let Some(n) = val { | ^^^^^^^ with this pattern -error: Unnecessary nested match +error: unnecessary nested match --> $DIR/collapsible_match.rs:32:9 | LL | / if let Some(n) = val { @@ -61,15 +61,15 @@ LL | | return; LL | | } | |_________^ | -help: The outer pattern can be modified to include the inner pattern. +help: the outer pattern can be modified to include the inner pattern --> $DIR/collapsible_match.rs:31:15 | LL | if let Ok(val) = res_opt { - | ^^^ Replace this binding + | ^^^ replace this binding LL | if let Some(n) = val { | ^^^^^^^ with this pattern -error: Unnecessary nested match +error: unnecessary nested match --> $DIR/collapsible_match.rs:43:9 | LL | / match val { @@ -78,16 +78,16 @@ LL | | _ => (), LL | | } | |_________^ | -help: The outer pattern can be modified to include the inner pattern. +help: the outer pattern can be modified to include the inner pattern --> $DIR/collapsible_match.rs:42:15 | LL | if let Ok(val) = res_opt { - | ^^^ Replace this binding + | ^^^ replace this binding LL | match val { LL | Some(n) => foo(n), | ^^^^^^^ with this pattern -error: Unnecessary nested match +error: unnecessary nested match --> $DIR/collapsible_match.rs:52:13 | LL | / if let Some(n) = val { @@ -95,15 +95,15 @@ LL | | take(n); LL | | } | |_____________^ | -help: The outer pattern can be modified to include the inner pattern. +help: the outer pattern can be modified to include the inner pattern --> $DIR/collapsible_match.rs:51:12 | LL | Ok(val) => { - | ^^^ Replace this binding + | ^^^ replace this binding LL | if let Some(n) = val { | ^^^^^^^ with this pattern -error: Unnecessary nested match +error: unnecessary nested match --> $DIR/collapsible_match.rs:61:9 | LL | / match val { @@ -112,16 +112,16 @@ LL | | _ => return, LL | | } | |_________^ | -help: The outer pattern can be modified to include the inner pattern. +help: the outer pattern can be modified to include the inner pattern --> $DIR/collapsible_match.rs:60:15 | LL | if let Ok(val) = res_opt { - | ^^^ Replace this binding + | ^^^ replace this binding LL | match val { LL | Some(n) => foo(n), | ^^^^^^^ with this pattern -error: Unnecessary nested match +error: unnecessary nested match --> $DIR/collapsible_match.rs:72:13 | LL | / if let Some(n) = val { @@ -131,15 +131,15 @@ LL | | return; LL | | } | |_____________^ | -help: The outer pattern can be modified to include the inner pattern. +help: the outer pattern can be modified to include the inner pattern --> $DIR/collapsible_match.rs:71:12 | LL | Ok(val) => { - | ^^^ Replace this binding + | ^^^ replace this binding LL | if let Some(n) = val { | ^^^^^^^ with this pattern -error: Unnecessary nested match +error: unnecessary nested match --> $DIR/collapsible_match.rs:83:20 | LL | Ok(val) => match val { @@ -149,15 +149,15 @@ LL | | None => return, LL | | }, | |_________^ | -help: The outer pattern can be modified to include the inner pattern. +help: the outer pattern can be modified to include the inner pattern --> $DIR/collapsible_match.rs:83:12 | LL | Ok(val) => match val { - | ^^^ Replace this binding + | ^^^ replace this binding LL | Some(n) => foo(n), | ^^^^^^^ with this pattern -error: Unnecessary nested match +error: unnecessary nested match --> $DIR/collapsible_match.rs:92:22 | LL | Some(val) => match val { @@ -167,11 +167,11 @@ LL | | _ => return, LL | | }, | |_________^ | -help: The outer pattern can be modified to include the inner pattern. +help: the outer pattern can be modified to include the inner pattern --> $DIR/collapsible_match.rs:92:14 | LL | Some(val) => match val { - | ^^^ Replace this binding + | ^^^ replace this binding LL | Some(n) => foo(n), | ^^^^^^^ with this pattern diff --git a/src/tools/clippy/tests/ui/collapsible_match2.stderr b/src/tools/clippy/tests/ui/collapsible_match2.stderr index b2eb457d17326..c8a445ef369d9 100644 --- a/src/tools/clippy/tests/ui/collapsible_match2.stderr +++ b/src/tools/clippy/tests/ui/collapsible_match2.stderr @@ -1,4 +1,4 @@ -error: Unnecessary nested match +error: unnecessary nested match --> $DIR/collapsible_match2.rs:8:34 | LL | Ok(val) if make() => match val { @@ -9,15 +9,15 @@ LL | | }, | |_____________^ | = note: `-D clippy::collapsible-match` implied by `-D warnings` -help: The outer pattern can be modified to include the inner pattern. +help: the outer pattern can be modified to include the inner pattern --> $DIR/collapsible_match2.rs:8:16 | LL | Ok(val) if make() => match val { - | ^^^ Replace this binding + | ^^^ replace this binding LL | Some(n) => foo(n), | ^^^^^^^ with this pattern -error: Unnecessary nested match +error: unnecessary nested match --> $DIR/collapsible_match2.rs:15:24 | LL | Ok(val) => match val { @@ -27,15 +27,15 @@ LL | | _ => return, LL | | }, | |_____________^ | -help: The outer pattern can be modified to include the inner pattern. +help: the outer pattern can be modified to include the inner pattern --> $DIR/collapsible_match2.rs:15:16 | LL | Ok(val) => match val { - | ^^^ Replace this binding + | ^^^ replace this binding LL | Some(n) => foo(n), | ^^^^^^^ with this pattern -error: Unnecessary nested match +error: unnecessary nested match --> $DIR/collapsible_match2.rs:29:29 | LL | $pat => match $e { @@ -48,16 +48,16 @@ LL | | }, LL | mac!(res_opt => Ok(val), val => Some(n), foo(n)); | ------------------------------------------------- in this macro invocation | -help: The outer pattern can be modified to include the inner pattern. +help: the outer pattern can be modified to include the inner pattern --> $DIR/collapsible_match2.rs:41:28 | LL | mac!(res_opt => Ok(val), val => Some(n), foo(n)); | ^^^ ^^^^^^^ with this pattern | | - | Replace this binding + | replace this binding = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error: Unnecessary nested match +error: unnecessary nested match --> $DIR/collapsible_match2.rs:46:20 | LL | Some(s) => match *s { @@ -67,15 +67,15 @@ LL | | _ => (), LL | | }, | |_________^ | -help: The outer pattern can be modified to include the inner pattern. +help: the outer pattern can be modified to include the inner pattern --> $DIR/collapsible_match2.rs:46:14 | LL | Some(s) => match *s { - | ^ Replace this binding + | ^ replace this binding LL | [n] => foo(n), | ^^^ with this pattern -error: Unnecessary nested match +error: unnecessary nested match --> $DIR/collapsible_match2.rs:55:24 | LL | Some(ref s) => match &*s { @@ -85,11 +85,11 @@ LL | | _ => (), LL | | }, | |_________^ | -help: The outer pattern can be modified to include the inner pattern. +help: the outer pattern can be modified to include the inner pattern --> $DIR/collapsible_match2.rs:55:14 | LL | Some(ref s) => match &*s { - | ^^^^^ Replace this binding + | ^^^^^ replace this binding LL | [n] => foo(n), | ^^^ with this pattern diff --git a/src/tools/clippy/tests/ui/crashes/ice-6179.rs b/src/tools/clippy/tests/ui/crashes/ice-6179.rs new file mode 100644 index 0000000000000..f8c866a49aa20 --- /dev/null +++ b/src/tools/clippy/tests/ui/crashes/ice-6179.rs @@ -0,0 +1,21 @@ +//! This is a minimal reproducer for the ICE in https://github.com/rust-lang/rust-clippy/pull/6179. +//! The ICE is mainly caused by using `hir_ty_to_ty`. See the discussion in the PR for details. + +#![warn(clippy::use_self)] +#![allow(dead_code)] + +struct Foo {} + +impl Foo { + fn foo() -> Self { + impl Foo { + fn bar() {} + } + + let _: _ = 1; + + Self {} + } +} + +fn main() {} diff --git a/src/tools/clippy/tests/ui/default_numeric_fallback.rs b/src/tools/clippy/tests/ui/default_numeric_fallback.rs new file mode 100644 index 0000000000000..0b3758952ac6d --- /dev/null +++ b/src/tools/clippy/tests/ui/default_numeric_fallback.rs @@ -0,0 +1,135 @@ +#![warn(clippy::default_numeric_fallback)] +#![allow(unused)] +#![allow(clippy::never_loop)] +#![allow(clippy::no_effect)] +#![allow(clippy::unnecessary_operation)] + +mod basic_expr { + fn test() { + // Should lint unsuffixed literals typed `i32`. + let x = 22; + let x = [1, 2, 3]; + let x = if true { (1, 2) } else { (3, 4) }; + let x = match 1 { + 1 => 1, + _ => 2, + }; + + // Should lint unsuffixed literals typed `f64`. + let x = 0.12; + + // Should NOT lint suffixed literals. + let x = 22_i32; + let x = 0.12_f64; + + // Should NOT lint literals in init expr if `Local` has a type annotation. + let x: f64 = 0.1; + let x: [i32; 3] = [1, 2, 3]; + let x: (i32, i32) = if true { (1, 2) } else { (3, 4) }; + let x: _ = 1; + } +} + +mod nested_local { + fn test() { + let x: _ = { + // Should lint this because this literal is not bound to any types. + let y = 1; + + // Should NOT lint this because this literal is bound to `_` of outer `Local`. + 1 + }; + + let x: _ = if true { + // Should lint this because this literal is not bound to any types. + let y = 1; + + // Should NOT lint this because this literal is bound to `_` of outer `Local`. + 1 + } else { + // Should lint this because this literal is not bound to any types. + let y = 1; + + // Should NOT lint this because this literal is bound to `_` of outer `Local`. + 2 + }; + } +} + +mod function_def { + fn ret_i32() -> i32 { + // Even though the output type is specified, + // this unsuffixed literal is linted to reduce heuristics and keep codebase simple. + 1 + } + + fn test() { + // Should lint this because return type is inferred to `i32` and NOT bound to a concrete + // type. + let f = || -> _ { 1 }; + + // Even though the output type is specified, + // this unsuffixed literal is linted to reduce heuristics and keep codebase simple. + let f = || -> i32 { 1 }; + } +} + +mod function_calls { + fn concrete_arg(x: i32) {} + + fn generic_arg(t: T) {} + + fn test() { + // Should NOT lint this because the argument type is bound to a concrete type. + concrete_arg(1); + + // Should lint this because the argument type is inferred to `i32` and NOT bound to a concrete type. + generic_arg(1); + + // Should lint this because the argument type is inferred to `i32` and NOT bound to a concrete type. + let x: _ = generic_arg(1); + } +} + +mod struct_ctor { + struct ConcreteStruct { + x: i32, + } + + struct GenericStruct { + x: T, + } + + fn test() { + // Should NOT lint this because the field type is bound to a concrete type. + ConcreteStruct { x: 1 }; + + // Should lint this because the field type is inferred to `i32` and NOT bound to a concrete type. + GenericStruct { x: 1 }; + + // Should lint this because the field type is inferred to `i32` and NOT bound to a concrete type. + let _ = GenericStruct { x: 1 }; + } +} + +mod method_calls { + struct StructForMethodCallTest {} + + impl StructForMethodCallTest { + fn concrete_arg(&self, x: i32) {} + + fn generic_arg(&self, t: T) {} + } + + fn test() { + let s = StructForMethodCallTest {}; + + // Should NOT lint this because the argument type is bound to a concrete type. + s.concrete_arg(1); + + // Should lint this because the argument type is bound to a concrete type. + s.generic_arg(1); + } +} + +fn main() {} diff --git a/src/tools/clippy/tests/ui/default_numeric_fallback.stderr b/src/tools/clippy/tests/ui/default_numeric_fallback.stderr new file mode 100644 index 0000000000000..b31aa4ebcf8e4 --- /dev/null +++ b/src/tools/clippy/tests/ui/default_numeric_fallback.stderr @@ -0,0 +1,148 @@ +error: default numeric fallback might occur + --> $DIR/default_numeric_fallback.rs:10:17 + | +LL | let x = 22; + | ^^ help: consider adding suffix: `22_i32` + | + = note: `-D clippy::default-numeric-fallback` implied by `-D warnings` + +error: default numeric fallback might occur + --> $DIR/default_numeric_fallback.rs:11:18 + | +LL | let x = [1, 2, 3]; + | ^ help: consider adding suffix: `1_i32` + +error: default numeric fallback might occur + --> $DIR/default_numeric_fallback.rs:11:21 + | +LL | let x = [1, 2, 3]; + | ^ help: consider adding suffix: `2_i32` + +error: default numeric fallback might occur + --> $DIR/default_numeric_fallback.rs:11:24 + | +LL | let x = [1, 2, 3]; + | ^ help: consider adding suffix: `3_i32` + +error: default numeric fallback might occur + --> $DIR/default_numeric_fallback.rs:12:28 + | +LL | let x = if true { (1, 2) } else { (3, 4) }; + | ^ help: consider adding suffix: `1_i32` + +error: default numeric fallback might occur + --> $DIR/default_numeric_fallback.rs:12:31 + | +LL | let x = if true { (1, 2) } else { (3, 4) }; + | ^ help: consider adding suffix: `2_i32` + +error: default numeric fallback might occur + --> $DIR/default_numeric_fallback.rs:12:44 + | +LL | let x = if true { (1, 2) } else { (3, 4) }; + | ^ help: consider adding suffix: `3_i32` + +error: default numeric fallback might occur + --> $DIR/default_numeric_fallback.rs:12:47 + | +LL | let x = if true { (1, 2) } else { (3, 4) }; + | ^ help: consider adding suffix: `4_i32` + +error: default numeric fallback might occur + --> $DIR/default_numeric_fallback.rs:13:23 + | +LL | let x = match 1 { + | ^ help: consider adding suffix: `1_i32` + +error: default numeric fallback might occur + --> $DIR/default_numeric_fallback.rs:14:13 + | +LL | 1 => 1, + | ^ help: consider adding suffix: `1_i32` + +error: default numeric fallback might occur + --> $DIR/default_numeric_fallback.rs:14:18 + | +LL | 1 => 1, + | ^ help: consider adding suffix: `1_i32` + +error: default numeric fallback might occur + --> $DIR/default_numeric_fallback.rs:15:18 + | +LL | _ => 2, + | ^ help: consider adding suffix: `2_i32` + +error: default numeric fallback might occur + --> $DIR/default_numeric_fallback.rs:19:17 + | +LL | let x = 0.12; + | ^^^^ help: consider adding suffix: `0.12_f64` + +error: default numeric fallback might occur + --> $DIR/default_numeric_fallback.rs:37:21 + | +LL | let y = 1; + | ^ help: consider adding suffix: `1_i32` + +error: default numeric fallback might occur + --> $DIR/default_numeric_fallback.rs:45:21 + | +LL | let y = 1; + | ^ help: consider adding suffix: `1_i32` + +error: default numeric fallback might occur + --> $DIR/default_numeric_fallback.rs:51:21 + | +LL | let y = 1; + | ^ help: consider adding suffix: `1_i32` + +error: default numeric fallback might occur + --> $DIR/default_numeric_fallback.rs:63:9 + | +LL | 1 + | ^ help: consider adding suffix: `1_i32` + +error: default numeric fallback might occur + --> $DIR/default_numeric_fallback.rs:69:27 + | +LL | let f = || -> _ { 1 }; + | ^ help: consider adding suffix: `1_i32` + +error: default numeric fallback might occur + --> $DIR/default_numeric_fallback.rs:73:29 + | +LL | let f = || -> i32 { 1 }; + | ^ help: consider adding suffix: `1_i32` + +error: default numeric fallback might occur + --> $DIR/default_numeric_fallback.rs:87:21 + | +LL | generic_arg(1); + | ^ help: consider adding suffix: `1_i32` + +error: default numeric fallback might occur + --> $DIR/default_numeric_fallback.rs:90:32 + | +LL | let x: _ = generic_arg(1); + | ^ help: consider adding suffix: `1_i32` + +error: default numeric fallback might occur + --> $DIR/default_numeric_fallback.rs:108:28 + | +LL | GenericStruct { x: 1 }; + | ^ help: consider adding suffix: `1_i32` + +error: default numeric fallback might occur + --> $DIR/default_numeric_fallback.rs:111:36 + | +LL | let _ = GenericStruct { x: 1 }; + | ^ help: consider adding suffix: `1_i32` + +error: default numeric fallback might occur + --> $DIR/default_numeric_fallback.rs:131:23 + | +LL | s.generic_arg(1); + | ^ help: consider adding suffix: `1_i32` + +error: aborting due to 24 previous errors + diff --git a/src/tools/clippy/tests/ui/doc.rs b/src/tools/clippy/tests/ui/doc.rs index e30970ed95273..d2c666bd2901c 100644 --- a/src/tools/clippy/tests/ui/doc.rs +++ b/src/tools/clippy/tests/ui/doc.rs @@ -50,11 +50,23 @@ fn test_units() { } /// This tests allowed identifiers. +/// KiB MiB GiB TiB PiB EiB /// DirectX /// ECMAScript +/// GPLv2 GPLv3 +/// GitHub GitLab +/// IPv4 IPv6 +/// ClojureScript CoffeeScript JavaScript PureScript TypeScript +/// NaN NaNs /// OAuth GraphQL +/// OCaml +/// OpenGL OpenMP OpenSSH OpenSSL OpenStreetMap OpenDNS /// WebGL +/// TensorFlow +/// TrueType +/// iOS macOS /// TeX LaTeX BibTeX BibLaTeX +/// MinGW /// CamelCase (see also #2395) /// be_sure_we_got_to_the_end_of_it fn test_allowed() { diff --git a/src/tools/clippy/tests/ui/doc.stderr b/src/tools/clippy/tests/ui/doc.stderr index e1c1aa85a60e1..7eab8a85f093d 100644 --- a/src/tools/clippy/tests/ui/doc.stderr +++ b/src/tools/clippy/tests/ui/doc.stderr @@ -55,133 +55,133 @@ LL | /// be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation - --> $DIR/doc.rs:59:5 + --> $DIR/doc.rs:71:5 | LL | /// be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: you should put `link_with_underscores` between ticks in the documentation - --> $DIR/doc.rs:63:22 + --> $DIR/doc.rs:75:22 | LL | /// This test has [a link_with_underscores][chunked-example] inside it. See #823. | ^^^^^^^^^^^^^^^^^^^^^ error: you should put `inline_link2` between ticks in the documentation - --> $DIR/doc.rs:66:21 + --> $DIR/doc.rs:78:21 | LL | /// It can also be [inline_link2]. | ^^^^^^^^^^^^ error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation - --> $DIR/doc.rs:76:5 + --> $DIR/doc.rs:88:5 | LL | /// be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: you should put `CamelCaseThing` between ticks in the documentation - --> $DIR/doc.rs:84:8 + --> $DIR/doc.rs:96:8 | LL | /// ## CamelCaseThing | ^^^^^^^^^^^^^^ error: you should put `CamelCaseThing` between ticks in the documentation - --> $DIR/doc.rs:87:7 + --> $DIR/doc.rs:99:7 | LL | /// # CamelCaseThing | ^^^^^^^^^^^^^^ error: you should put `CamelCaseThing` between ticks in the documentation - --> $DIR/doc.rs:89:22 + --> $DIR/doc.rs:101:22 | LL | /// Not a title #897 CamelCaseThing | ^^^^^^^^^^^^^^ error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation - --> $DIR/doc.rs:90:5 + --> $DIR/doc.rs:102:5 | LL | /// be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation - --> $DIR/doc.rs:97:5 + --> $DIR/doc.rs:109:5 | LL | /// be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation - --> $DIR/doc.rs:110:5 + --> $DIR/doc.rs:122:5 | LL | /// be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: you should put `FooBar` between ticks in the documentation - --> $DIR/doc.rs:121:43 + --> $DIR/doc.rs:133:43 | LL | /** E.g., serialization of an empty list: FooBar | ^^^^^^ error: you should put `BarQuz` between ticks in the documentation - --> $DIR/doc.rs:126:5 + --> $DIR/doc.rs:138:5 | LL | And BarQuz too. | ^^^^^^ error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation - --> $DIR/doc.rs:127:1 + --> $DIR/doc.rs:139:1 | LL | be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: you should put `FooBar` between ticks in the documentation - --> $DIR/doc.rs:132:43 + --> $DIR/doc.rs:144:43 | LL | /** E.g., serialization of an empty list: FooBar | ^^^^^^ error: you should put `BarQuz` between ticks in the documentation - --> $DIR/doc.rs:137:5 + --> $DIR/doc.rs:149:5 | LL | And BarQuz too. | ^^^^^^ error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation - --> $DIR/doc.rs:138:1 + --> $DIR/doc.rs:150:1 | LL | be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation - --> $DIR/doc.rs:149:5 + --> $DIR/doc.rs:161:5 | LL | /// be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: you should put bare URLs between `<`/`>` or make a proper Markdown link - --> $DIR/doc.rs:176:13 + --> $DIR/doc.rs:188:13 | LL | /// Not ok: http://www.unicode.org | ^^^^^^^^^^^^^^^^^^^^^^ error: you should put bare URLs between `<`/`>` or make a proper Markdown link - --> $DIR/doc.rs:177:13 + --> $DIR/doc.rs:189:13 | LL | /// Not ok: https://www.unicode.org | ^^^^^^^^^^^^^^^^^^^^^^^ error: you should put bare URLs between `<`/`>` or make a proper Markdown link - --> $DIR/doc.rs:178:13 + --> $DIR/doc.rs:190:13 | LL | /// Not ok: http://www.unicode.org/ | ^^^^^^^^^^^^^^^^^^^^^^ error: you should put bare URLs between `<`/`>` or make a proper Markdown link - --> $DIR/doc.rs:179:13 + --> $DIR/doc.rs:191:13 | LL | /// Not ok: http://www.unicode.org/reports/tr9/#Reordering_Resolved_Levels | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: you should put `mycrate::Collection` between ticks in the documentation - --> $DIR/doc.rs:182:22 + --> $DIR/doc.rs:194:22 | LL | /// An iterator over mycrate::Collection's values. | ^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/doc_panics.rs b/src/tools/clippy/tests/ui/doc_panics.rs index 7ef932f367b10..3008c2d5b8538 100644 --- a/src/tools/clippy/tests/ui/doc_panics.rs +++ b/src/tools/clippy/tests/ui/doc_panics.rs @@ -28,6 +28,15 @@ pub fn inner_body(opt: Option) { }); } +/// This needs to be documented +pub fn unreachable_and_panic() { + if true { + unreachable!() + } else { + panic!() + } +} + /// This is documented /// /// # Panics @@ -69,6 +78,19 @@ pub fn todo_documented() { todo!() } +/// This is documented +/// +/// # Panics +/// +/// We still need to do this part +pub fn unreachable_amd_panic_documented() { + if true { + unreachable!() + } else { + panic!() + } +} + /// This is okay because it is private fn unwrap_private() { let result = Err("Hi"); @@ -93,3 +115,8 @@ fn inner_body_private(opt: Option) { } }); } + +/// This is okay because unreachable +pub fn unreachable() { + unreachable!("This function panics") +} diff --git a/src/tools/clippy/tests/ui/doc_panics.stderr b/src/tools/clippy/tests/ui/doc_panics.stderr index c0c4e9e4fa7ee..287148690d27a 100644 --- a/src/tools/clippy/tests/ui/doc_panics.stderr +++ b/src/tools/clippy/tests/ui/doc_panics.stderr @@ -63,5 +63,24 @@ LL | panic!() | ^^^^^^^^ = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 4 previous errors +error: docs for function which may panic missing `# Panics` section + --> $DIR/doc_panics.rs:32:1 + | +LL | / pub fn unreachable_and_panic() { +LL | | if true { +LL | | unreachable!() +LL | | } else { +LL | | panic!() +LL | | } +LL | | } + | |_^ + | +note: first possible panic found here + --> $DIR/doc_panics.rs:36:9 + | +LL | panic!() + | ^^^^^^^^ + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 5 previous errors diff --git a/src/tools/clippy/tests/ui/enum_variants.rs b/src/tools/clippy/tests/ui/enum_variants.rs index 89d99dcf0c867..4fefc0b43f1d9 100644 --- a/src/tools/clippy/tests/ui/enum_variants.rs +++ b/src/tools/clippy/tests/ui/enum_variants.rs @@ -133,4 +133,17 @@ pub enum NetworkLayer { Layer3, } +// should lint suggesting `IData`, not only `Data` (see #4639) +enum IDataRequest { + PutIData(String), + GetIData(String), + DeleteUnpubIData(String), +} + +enum HIDataRequest { + PutHIData(String), + GetHIData(String), + DeleteUnpubHIData(String), +} + fn main() {} diff --git a/src/tools/clippy/tests/ui/enum_variants.stderr b/src/tools/clippy/tests/ui/enum_variants.stderr index b1d481190ff53..ab7fff4507aaa 100644 --- a/src/tools/clippy/tests/ui/enum_variants.stderr +++ b/src/tools/clippy/tests/ui/enum_variants.stderr @@ -97,5 +97,29 @@ LL | | } = note: `-D clippy::pub-enum-variant-names` implied by `-D warnings` = help: remove the prefixes and use full paths to the variants instead of glob imports -error: aborting due to 10 previous errors +error: all variants have the same postfix: `IData` + --> $DIR/enum_variants.rs:137:1 + | +LL | / enum IDataRequest { +LL | | PutIData(String), +LL | | GetIData(String), +LL | | DeleteUnpubIData(String), +LL | | } + | |_^ + | + = help: remove the postfixes and use full paths to the variants instead of glob imports + +error: all variants have the same postfix: `HIData` + --> $DIR/enum_variants.rs:143:1 + | +LL | / enum HIDataRequest { +LL | | PutHIData(String), +LL | | GetHIData(String), +LL | | DeleteUnpubHIData(String), +LL | | } + | |_^ + | + = help: remove the postfixes and use full paths to the variants instead of glob imports + +error: aborting due to 12 previous errors diff --git a/src/tools/clippy/tests/ui/from_str_radix_10.rs b/src/tools/clippy/tests/ui/from_str_radix_10.rs new file mode 100644 index 0000000000000..2f2ea04847a98 --- /dev/null +++ b/src/tools/clippy/tests/ui/from_str_radix_10.rs @@ -0,0 +1,52 @@ +#![warn(clippy::from_str_radix_10)] + +mod some_mod { + // fake function that shouldn't trigger the lint + pub fn from_str_radix(_: &str, _: u32) -> Result<(), std::num::ParseIntError> { + unimplemented!() + } +} + +// fake function that shouldn't trigger the lint +fn from_str_radix(_: &str, _: u32) -> Result<(), std::num::ParseIntError> { + unimplemented!() +} + +// to test parenthesis addition +struct Test; + +impl std::ops::Add for Test { + type Output = &'static str; + + fn add(self, _: Self) -> Self::Output { + "304" + } +} + +fn main() -> Result<(), Box> { + // all of these should trigger the lint + u32::from_str_radix("30", 10)?; + i64::from_str_radix("24", 10)?; + isize::from_str_radix("100", 10)?; + u8::from_str_radix("7", 10)?; + u16::from_str_radix(&("10".to_owned() + "5"), 10)?; + i128::from_str_radix(Test + Test, 10)?; + + let string = "300"; + i32::from_str_radix(string, 10)?; + + let stringier = "400".to_string(); + i32::from_str_radix(&stringier, 10)?; + + // none of these should trigger the lint + u16::from_str_radix("20", 3)?; + i32::from_str_radix("45", 12)?; + usize::from_str_radix("10", 16)?; + i128::from_str_radix("10", 13)?; + some_mod::from_str_radix("50", 10)?; + some_mod::from_str_radix("50", 6)?; + from_str_radix("50", 10)?; + from_str_radix("50", 6)?; + + Ok(()) +} diff --git a/src/tools/clippy/tests/ui/from_str_radix_10.stderr b/src/tools/clippy/tests/ui/from_str_radix_10.stderr new file mode 100644 index 0000000000000..471bf52a9a7ed --- /dev/null +++ b/src/tools/clippy/tests/ui/from_str_radix_10.stderr @@ -0,0 +1,52 @@ +error: this call to `from_str_radix` can be replaced with a call to `str::parse` + --> $DIR/from_str_radix_10.rs:28:5 + | +LL | u32::from_str_radix("30", 10)?; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"30".parse::()` + | + = note: `-D clippy::from-str-radix-10` implied by `-D warnings` + +error: this call to `from_str_radix` can be replaced with a call to `str::parse` + --> $DIR/from_str_radix_10.rs:29:5 + | +LL | i64::from_str_radix("24", 10)?; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"24".parse::()` + +error: this call to `from_str_radix` can be replaced with a call to `str::parse` + --> $DIR/from_str_radix_10.rs:30:5 + | +LL | isize::from_str_radix("100", 10)?; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"100".parse::()` + +error: this call to `from_str_radix` can be replaced with a call to `str::parse` + --> $DIR/from_str_radix_10.rs:31:5 + | +LL | u8::from_str_radix("7", 10)?; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"7".parse::()` + +error: this call to `from_str_radix` can be replaced with a call to `str::parse` + --> $DIR/from_str_radix_10.rs:32:5 + | +LL | u16::from_str_radix(&("10".to_owned() + "5"), 10)?; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(("10".to_owned() + "5")).parse::()` + +error: this call to `from_str_radix` can be replaced with a call to `str::parse` + --> $DIR/from_str_radix_10.rs:33:5 + | +LL | i128::from_str_radix(Test + Test, 10)?; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(Test + Test).parse::()` + +error: this call to `from_str_radix` can be replaced with a call to `str::parse` + --> $DIR/from_str_radix_10.rs:36:5 + | +LL | i32::from_str_radix(string, 10)?; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `string.parse::()` + +error: this call to `from_str_radix` can be replaced with a call to `str::parse` + --> $DIR/from_str_radix_10.rs:39:5 + | +LL | i32::from_str_radix(&stringier, 10)?; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `stringier.parse::()` + +error: aborting due to 8 previous errors + diff --git a/src/tools/clippy/tests/ui/if_same_then_else2.rs b/src/tools/clippy/tests/ui/if_same_then_else2.rs index e83ce47e56308..a2ff1b741ca25 100644 --- a/src/tools/clippy/tests/ui/if_same_then_else2.rs +++ b/src/tools/clippy/tests/ui/if_same_then_else2.rs @@ -12,7 +12,7 @@ fn if_same_then_else2() -> Result<&'static str, ()> { if true { for _ in &[42] { let foo: &Option<_> = &Some::(42); - if true { + if foo.is_some() { break; } else { continue; @@ -21,8 +21,8 @@ fn if_same_then_else2() -> Result<&'static str, ()> { } else { //~ ERROR same body as `if` block for _ in &[42] { - let foo: &Option<_> = &Some::(42); - if true { + let bar: &Option<_> = &Some::(42); + if bar.is_some() { break; } else { continue; diff --git a/src/tools/clippy/tests/ui/if_same_then_else2.stderr b/src/tools/clippy/tests/ui/if_same_then_else2.stderr index f98e30fa376fe..454322d8aacda 100644 --- a/src/tools/clippy/tests/ui/if_same_then_else2.stderr +++ b/src/tools/clippy/tests/ui/if_same_then_else2.stderr @@ -5,7 +5,7 @@ LL | } else { | ____________^ LL | | //~ ERROR same body as `if` block LL | | for _ in &[42] { -LL | | let foo: &Option<_> = &Some::(42); +LL | | let bar: &Option<_> = &Some::(42); ... | LL | | } LL | | } @@ -19,7 +19,7 @@ LL | if true { | _____________^ LL | | for _ in &[42] { LL | | let foo: &Option<_> = &Some::(42); -LL | | if true { +LL | | if foo.is_some() { ... | LL | | } LL | | } else { diff --git a/src/tools/clippy/tests/ui/inconsistent_struct_constructor.fixed b/src/tools/clippy/tests/ui/inconsistent_struct_constructor.fixed new file mode 100644 index 0000000000000..8d9c311003508 --- /dev/null +++ b/src/tools/clippy/tests/ui/inconsistent_struct_constructor.fixed @@ -0,0 +1,61 @@ +// run-rustfix +// edition:2018 +#![warn(clippy::inconsistent_struct_constructor)] +#![allow(clippy::redundant_field_names)] +#![allow(clippy::unnecessary_operation)] +#![allow(clippy::no_effect)] +#![allow(dead_code)] + +#[derive(Default)] +struct Foo { + x: i32, + y: i32, + z: i32, +} + +mod without_base { + use super::Foo; + + fn test() { + let x = 1; + let y = 1; + let z = 1; + + // Should lint. + Foo { x, y, z }; + + // Shoule NOT lint because the order is the same as in the definition. + Foo { x, y, z }; + + // Should NOT lint because z is not a shorthand init. + Foo { y, x, z: z }; + } +} + +mod with_base { + use super::Foo; + + fn test() { + let x = 1; + let z = 1; + + // Should lint. + Foo { x, z, ..Default::default() }; + + // Should NOT lint because the order is consistent with the definition. + Foo { + x, + z, + ..Default::default() + }; + + // Should NOT lint because z is not a shorthand init. + Foo { + z: z, + x, + ..Default::default() + }; + } +} + +fn main() {} diff --git a/src/tools/clippy/tests/ui/inconsistent_struct_constructor.rs b/src/tools/clippy/tests/ui/inconsistent_struct_constructor.rs new file mode 100644 index 0000000000000..63fac9105015d --- /dev/null +++ b/src/tools/clippy/tests/ui/inconsistent_struct_constructor.rs @@ -0,0 +1,65 @@ +// run-rustfix +// edition:2018 +#![warn(clippy::inconsistent_struct_constructor)] +#![allow(clippy::redundant_field_names)] +#![allow(clippy::unnecessary_operation)] +#![allow(clippy::no_effect)] +#![allow(dead_code)] + +#[derive(Default)] +struct Foo { + x: i32, + y: i32, + z: i32, +} + +mod without_base { + use super::Foo; + + fn test() { + let x = 1; + let y = 1; + let z = 1; + + // Should lint. + Foo { y, x, z }; + + // Shoule NOT lint because the order is the same as in the definition. + Foo { x, y, z }; + + // Should NOT lint because z is not a shorthand init. + Foo { y, x, z: z }; + } +} + +mod with_base { + use super::Foo; + + fn test() { + let x = 1; + let z = 1; + + // Should lint. + Foo { + z, + x, + ..Default::default() + }; + + // Should NOT lint because the order is consistent with the definition. + Foo { + x, + z, + ..Default::default() + }; + + // Should NOT lint because z is not a shorthand init. + Foo { + z: z, + x, + ..Default::default() + }; + } +} + +fn main() {} diff --git a/src/tools/clippy/tests/ui/inconsistent_struct_constructor.stderr b/src/tools/clippy/tests/ui/inconsistent_struct_constructor.stderr new file mode 100644 index 0000000000000..d7abe44f25408 --- /dev/null +++ b/src/tools/clippy/tests/ui/inconsistent_struct_constructor.stderr @@ -0,0 +1,20 @@ +error: inconsistent struct constructor + --> $DIR/inconsistent_struct_constructor.rs:25:9 + | +LL | Foo { y, x, z }; + | ^^^^^^^^^^^^^^^ help: try: `Foo { x, y, z }` + | + = note: `-D clippy::inconsistent-struct-constructor` implied by `-D warnings` + +error: inconsistent struct constructor + --> $DIR/inconsistent_struct_constructor.rs:43:9 + | +LL | / Foo { +LL | | z, +LL | | x, +LL | | ..Default::default() +LL | | }; + | |_________^ help: try: `Foo { x, z, ..Default::default() }` + +error: aborting due to 2 previous errors + diff --git a/src/tools/clippy/tests/ui/inherent_to_string.rs b/src/tools/clippy/tests/ui/inherent_to_string.rs index e6cf337d1bb1b..6e65fdbd04e7d 100644 --- a/src/tools/clippy/tests/ui/inherent_to_string.rs +++ b/src/tools/clippy/tests/ui/inherent_to_string.rs @@ -14,6 +14,7 @@ struct C; struct D; struct E; struct F; +struct G; impl A { // Should be detected; emit warning @@ -73,6 +74,13 @@ impl F { } } +impl G { + // Should not be detected, as it does not match the function signature + fn to_string(&self) -> String { + "G.to_string()".to_string() + } +} + fn main() { let a = A; a.to_string(); @@ -93,4 +101,7 @@ fn main() { let f = F; f.to_string(1); + + let g = G; + g.to_string::<1>(); } diff --git a/src/tools/clippy/tests/ui/inherent_to_string.stderr b/src/tools/clippy/tests/ui/inherent_to_string.stderr index 4f331f5bec9e6..f5fcc193b4d8a 100644 --- a/src/tools/clippy/tests/ui/inherent_to_string.stderr +++ b/src/tools/clippy/tests/ui/inherent_to_string.stderr @@ -1,5 +1,5 @@ error: implementation of inherent method `to_string(&self) -> String` for type `A` - --> $DIR/inherent_to_string.rs:20:5 + --> $DIR/inherent_to_string.rs:21:5 | LL | / fn to_string(&self) -> String { LL | | "A.to_string()".to_string() @@ -10,7 +10,7 @@ LL | | } = help: implement trait `Display` for type `A` instead error: type `C` implements inherent method `to_string(&self) -> String` which shadows the implementation of `Display` - --> $DIR/inherent_to_string.rs:44:5 + --> $DIR/inherent_to_string.rs:45:5 | LL | / fn to_string(&self) -> String { LL | | "C.to_string()".to_string() diff --git a/src/tools/clippy/tests/ui/manual_map_option.fixed b/src/tools/clippy/tests/ui/manual_map_option.fixed new file mode 100644 index 0000000000000..1935090675825 --- /dev/null +++ b/src/tools/clippy/tests/ui/manual_map_option.fixed @@ -0,0 +1,70 @@ +// run-rustfix + +#![warn(clippy::manual_map)] +#![allow(clippy::no_effect, clippy::map_identity, clippy::unit_arg, clippy::match_ref_pats)] + +fn main() { + Some(0).map(|_| 2); + + Some(0).map(|x| x + 1); + + Some("").map(|x| x.is_empty()); + + Some(0).map(|x| !x); + + #[rustfmt::skip] + Some(0).map(std::convert::identity); + + Some(&String::new()).map(|x| str::len(x)); + + match Some(0) { + Some(x) if false => Some(x + 1), + _ => None, + }; + + Some([0, 1]).as_ref().map(|x| x[0]); + + Some(0).map(|x| x * 2); + + Some(String::new()).as_ref().map(|x| x.is_empty()); + + Some(String::new()).as_ref().map(|x| x.len()); + + Some(0).map(|x| x + x); + + #[warn(clippy::option_map_unit_fn)] + match &mut Some(String::new()) { + Some(x) => Some(x.push_str("")), + None => None, + }; + + #[allow(clippy::option_map_unit_fn)] + { + Some(String::new()).as_mut().map(|x| x.push_str("")); + } + + Some(String::new()).as_ref().map(|x| x.len()); + + Some(String::new()).as_ref().map(|x| x.is_empty()); + + Some((0, 1, 2)).map(|(x, y, z)| x + y + z); + + Some([1, 2, 3]).map(|[first, ..]| first); + + Some((String::new(), "test")).as_ref().map(|(x, y)| (y, x)); + + match Some((String::new(), 0)) { + Some((ref x, y)) => Some((y, x)), + None => None, + }; + + match Some(Some(0)) { + Some(Some(_)) | Some(None) => Some(0), + None => None, + }; + + match Some(Some((0, 1))) { + Some(Some((x, 1))) => Some(x), + _ => None, + }; +} diff --git a/src/tools/clippy/tests/ui/manual_map_option.rs b/src/tools/clippy/tests/ui/manual_map_option.rs new file mode 100644 index 0000000000000..8b8187db0a979 --- /dev/null +++ b/src/tools/clippy/tests/ui/manual_map_option.rs @@ -0,0 +1,122 @@ +// run-rustfix + +#![warn(clippy::manual_map)] +#![allow(clippy::no_effect, clippy::map_identity, clippy::unit_arg, clippy::match_ref_pats)] + +fn main() { + match Some(0) { + Some(_) => Some(2), + None:: => None, + }; + + match Some(0) { + Some(x) => Some(x + 1), + _ => None, + }; + + match Some("") { + Some(x) => Some(x.is_empty()), + None => None, + }; + + if let Some(x) = Some(0) { + Some(!x) + } else { + None + }; + + #[rustfmt::skip] + match Some(0) { + Some(x) => { Some(std::convert::identity(x)) } + None => { None } + }; + + match Some(&String::new()) { + Some(x) => Some(str::len(x)), + None => None, + }; + + match Some(0) { + Some(x) if false => Some(x + 1), + _ => None, + }; + + match &Some([0, 1]) { + Some(x) => Some(x[0]), + &None => None, + }; + + match &Some(0) { + &Some(x) => Some(x * 2), + None => None, + }; + + match Some(String::new()) { + Some(ref x) => Some(x.is_empty()), + _ => None, + }; + + match &&Some(String::new()) { + Some(x) => Some(x.len()), + _ => None, + }; + + match &&Some(0) { + &&Some(x) => Some(x + x), + &&_ => None, + }; + + #[warn(clippy::option_map_unit_fn)] + match &mut Some(String::new()) { + Some(x) => Some(x.push_str("")), + None => None, + }; + + #[allow(clippy::option_map_unit_fn)] + { + match &mut Some(String::new()) { + Some(x) => Some(x.push_str("")), + None => None, + }; + } + + match &mut Some(String::new()) { + Some(ref x) => Some(x.len()), + None => None, + }; + + match &mut &Some(String::new()) { + Some(x) => Some(x.is_empty()), + &mut _ => None, + }; + + match Some((0, 1, 2)) { + Some((x, y, z)) => Some(x + y + z), + None => None, + }; + + match Some([1, 2, 3]) { + Some([first, ..]) => Some(first), + None => None, + }; + + match &Some((String::new(), "test")) { + Some((x, y)) => Some((y, x)), + None => None, + }; + + match Some((String::new(), 0)) { + Some((ref x, y)) => Some((y, x)), + None => None, + }; + + match Some(Some(0)) { + Some(Some(_)) | Some(None) => Some(0), + None => None, + }; + + match Some(Some((0, 1))) { + Some(Some((x, 1))) => Some(x), + _ => None, + }; +} diff --git a/src/tools/clippy/tests/ui/manual_map_option.stderr b/src/tools/clippy/tests/ui/manual_map_option.stderr new file mode 100644 index 0000000000000..210a30d05d40f --- /dev/null +++ b/src/tools/clippy/tests/ui/manual_map_option.stderr @@ -0,0 +1,158 @@ +error: manual implementation of `Option::map` + --> $DIR/manual_map_option.rs:7:5 + | +LL | / match Some(0) { +LL | | Some(_) => Some(2), +LL | | None:: => None, +LL | | }; + | |_____^ help: try this: `Some(0).map(|_| 2)` + | + = note: `-D clippy::manual-map` implied by `-D warnings` + +error: manual implementation of `Option::map` + --> $DIR/manual_map_option.rs:12:5 + | +LL | / match Some(0) { +LL | | Some(x) => Some(x + 1), +LL | | _ => None, +LL | | }; + | |_____^ help: try this: `Some(0).map(|x| x + 1)` + +error: manual implementation of `Option::map` + --> $DIR/manual_map_option.rs:17:5 + | +LL | / match Some("") { +LL | | Some(x) => Some(x.is_empty()), +LL | | None => None, +LL | | }; + | |_____^ help: try this: `Some("").map(|x| x.is_empty())` + +error: manual implementation of `Option::map` + --> $DIR/manual_map_option.rs:22:5 + | +LL | / if let Some(x) = Some(0) { +LL | | Some(!x) +LL | | } else { +LL | | None +LL | | }; + | |_____^ help: try this: `Some(0).map(|x| !x)` + +error: manual implementation of `Option::map` + --> $DIR/manual_map_option.rs:29:5 + | +LL | / match Some(0) { +LL | | Some(x) => { Some(std::convert::identity(x)) } +LL | | None => { None } +LL | | }; + | |_____^ help: try this: `Some(0).map(std::convert::identity)` + +error: manual implementation of `Option::map` + --> $DIR/manual_map_option.rs:34:5 + | +LL | / match Some(&String::new()) { +LL | | Some(x) => Some(str::len(x)), +LL | | None => None, +LL | | }; + | |_____^ help: try this: `Some(&String::new()).map(|x| str::len(x))` + +error: manual implementation of `Option::map` + --> $DIR/manual_map_option.rs:44:5 + | +LL | / match &Some([0, 1]) { +LL | | Some(x) => Some(x[0]), +LL | | &None => None, +LL | | }; + | |_____^ help: try this: `Some([0, 1]).as_ref().map(|x| x[0])` + +error: manual implementation of `Option::map` + --> $DIR/manual_map_option.rs:49:5 + | +LL | / match &Some(0) { +LL | | &Some(x) => Some(x * 2), +LL | | None => None, +LL | | }; + | |_____^ help: try this: `Some(0).map(|x| x * 2)` + +error: manual implementation of `Option::map` + --> $DIR/manual_map_option.rs:54:5 + | +LL | / match Some(String::new()) { +LL | | Some(ref x) => Some(x.is_empty()), +LL | | _ => None, +LL | | }; + | |_____^ help: try this: `Some(String::new()).as_ref().map(|x| x.is_empty())` + +error: manual implementation of `Option::map` + --> $DIR/manual_map_option.rs:59:5 + | +LL | / match &&Some(String::new()) { +LL | | Some(x) => Some(x.len()), +LL | | _ => None, +LL | | }; + | |_____^ help: try this: `Some(String::new()).as_ref().map(|x| x.len())` + +error: manual implementation of `Option::map` + --> $DIR/manual_map_option.rs:64:5 + | +LL | / match &&Some(0) { +LL | | &&Some(x) => Some(x + x), +LL | | &&_ => None, +LL | | }; + | |_____^ help: try this: `Some(0).map(|x| x + x)` + +error: manual implementation of `Option::map` + --> $DIR/manual_map_option.rs:77:9 + | +LL | / match &mut Some(String::new()) { +LL | | Some(x) => Some(x.push_str("")), +LL | | None => None, +LL | | }; + | |_________^ help: try this: `Some(String::new()).as_mut().map(|x| x.push_str(""))` + +error: manual implementation of `Option::map` + --> $DIR/manual_map_option.rs:83:5 + | +LL | / match &mut Some(String::new()) { +LL | | Some(ref x) => Some(x.len()), +LL | | None => None, +LL | | }; + | |_____^ help: try this: `Some(String::new()).as_ref().map(|x| x.len())` + +error: manual implementation of `Option::map` + --> $DIR/manual_map_option.rs:88:5 + | +LL | / match &mut &Some(String::new()) { +LL | | Some(x) => Some(x.is_empty()), +LL | | &mut _ => None, +LL | | }; + | |_____^ help: try this: `Some(String::new()).as_ref().map(|x| x.is_empty())` + +error: manual implementation of `Option::map` + --> $DIR/manual_map_option.rs:93:5 + | +LL | / match Some((0, 1, 2)) { +LL | | Some((x, y, z)) => Some(x + y + z), +LL | | None => None, +LL | | }; + | |_____^ help: try this: `Some((0, 1, 2)).map(|(x, y, z)| x + y + z)` + +error: manual implementation of `Option::map` + --> $DIR/manual_map_option.rs:98:5 + | +LL | / match Some([1, 2, 3]) { +LL | | Some([first, ..]) => Some(first), +LL | | None => None, +LL | | }; + | |_____^ help: try this: `Some([1, 2, 3]).map(|[first, ..]| first)` + +error: manual implementation of `Option::map` + --> $DIR/manual_map_option.rs:103:5 + | +LL | / match &Some((String::new(), "test")) { +LL | | Some((x, y)) => Some((y, x)), +LL | | None => None, +LL | | }; + | |_____^ help: try this: `Some((String::new(), "test")).as_ref().map(|(x, y)| (y, x))` + +error: aborting due to 17 previous errors + diff --git a/src/tools/clippy/tests/ui/result_unit_error.rs b/src/tools/clippy/tests/ui/result_unit_error.rs index 5e57c752b5a03..a4ec803024edf 100644 --- a/src/tools/clippy/tests/ui/result_unit_error.rs +++ b/src/tools/clippy/tests/ui/result_unit_error.rs @@ -1,6 +1,4 @@ -#![allow(clippy::unnecessary_wraps)] -#[warn(clippy::result_unit_err)] -#[allow(unused)] +#![warn(clippy::result_unit_err)] pub fn returns_unit_error() -> Result { Err(()) @@ -36,4 +34,23 @@ impl UnitErrorHolder { } } +// https://github.com/rust-lang/rust-clippy/issues/6546 +pub mod issue_6546 { + type ResInv = Result; + + pub fn should_lint() -> ResInv<(), usize> { + Ok(0) + } + + pub fn should_not_lint() -> ResInv { + Ok(()) + } + + type MyRes = Result<(A, B), Box>; + + pub fn should_not_lint2(x: i32) -> MyRes { + Ok((x, ())) + } +} + fn main() {} diff --git a/src/tools/clippy/tests/ui/result_unit_error.stderr b/src/tools/clippy/tests/ui/result_unit_error.stderr index 12901b354f916..41d8b0a7cb7f8 100644 --- a/src/tools/clippy/tests/ui/result_unit_error.stderr +++ b/src/tools/clippy/tests/ui/result_unit_error.stderr @@ -1,5 +1,5 @@ error: this returns a `Result<_, ()> - --> $DIR/result_unit_error.rs:5:1 + --> $DIR/result_unit_error.rs:3:1 | LL | pub fn returns_unit_error() -> Result { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -8,7 +8,7 @@ LL | pub fn returns_unit_error() -> Result { = help: use a custom Error type instead error: this returns a `Result<_, ()> - --> $DIR/result_unit_error.rs:14:5 + --> $DIR/result_unit_error.rs:12:5 | LL | fn get_that_error(&self) -> Result; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -16,7 +16,7 @@ LL | fn get_that_error(&self) -> Result; = help: use a custom Error type instead error: this returns a `Result<_, ()> - --> $DIR/result_unit_error.rs:16:5 + --> $DIR/result_unit_error.rs:14:5 | LL | fn get_this_one_too(&self) -> Result { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -24,12 +24,20 @@ LL | fn get_this_one_too(&self) -> Result { = help: use a custom Error type instead error: this returns a `Result<_, ()> - --> $DIR/result_unit_error.rs:34:5 + --> $DIR/result_unit_error.rs:32:5 | LL | pub fn unit_error(&self) -> Result { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: use a custom Error type instead -error: aborting due to 4 previous errors +error: this returns a `Result<_, ()> + --> $DIR/result_unit_error.rs:41:5 + | +LL | pub fn should_lint() -> ResInv<(), usize> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use a custom Error type instead + +error: aborting due to 5 previous errors diff --git a/src/tools/clippy/tests/ui/unnecessary_wraps.rs b/src/tools/clippy/tests/ui/unnecessary_wraps.rs index a4570098d7167..a510263e67da1 100644 --- a/src/tools/clippy/tests/ui/unnecessary_wraps.rs +++ b/src/tools/clippy/tests/ui/unnecessary_wraps.rs @@ -116,8 +116,53 @@ fn issue_6384(s: &str) -> Option<&str> { }) } +// should be linted +fn issue_6640_1(a: bool, b: bool) -> Option<()> { + if a && b { + return Some(()); + } + if a { + Some(()); + Some(()) + } else { + return Some(()); + } +} + +// should be linted +fn issue_6640_2(a: bool, b: bool) -> Result<(), i32> { + if a && b { + return Ok(()); + } + if a { + Ok(()) + } else { + return Ok(()); + } +} + +// should not be linted +fn issue_6640_3() -> Option<()> { + if true { + Some(()) + } else { + None + } +} + +// should not be linted +fn issue_6640_4() -> Result<(), ()> { + if true { + Ok(()) + } else { + Err(()) + } +} + fn main() { // method calls are not linted func1(true, true); func2(true, true); + issue_6640_1(true, true); + issue_6640_2(true, true); } diff --git a/src/tools/clippy/tests/ui/unnecessary_wraps.stderr b/src/tools/clippy/tests/ui/unnecessary_wraps.stderr index 410f054b8efca..9a861c61a4679 100644 --- a/src/tools/clippy/tests/ui/unnecessary_wraps.stderr +++ b/src/tools/clippy/tests/ui/unnecessary_wraps.stderr @@ -15,7 +15,7 @@ help: remove `Option` from the return type... | LL | fn func1(a: bool, b: bool) -> i32 { | ^^^ -help: ...and change the returning expressions +help: ...and then change returning expressions | LL | return 42; LL | } @@ -41,7 +41,7 @@ help: remove `Option` from the return type... | LL | fn func2(a: bool, b: bool) -> i32 { | ^^^ -help: ...and change the returning expressions +help: ...and then change returning expressions | LL | return 10; LL | } @@ -63,7 +63,7 @@ help: remove `Option` from the return type... | LL | fn func5() -> i32 { | ^^^ -help: ...and change the returning expressions +help: ...and then change returning expressions | LL | 1 | @@ -80,7 +80,7 @@ help: remove `Result` from the return type... | LL | fn func7() -> i32 { | ^^^ -help: ...and change the returning expressions +help: ...and then change returning expressions | LL | 1 | @@ -97,10 +97,62 @@ help: remove `Option` from the return type... | LL | fn func12() -> i32 { | ^^^ -help: ...and change the returning expressions +help: ...and then change returning expressions | LL | 1 | -error: aborting due to 5 previous errors +error: this function's return value is unnecessary + --> $DIR/unnecessary_wraps.rs:120:1 + | +LL | / fn issue_6640_1(a: bool, b: bool) -> Option<()> { +LL | | if a && b { +LL | | return Some(()); +LL | | } +... | +LL | | } +LL | | } + | |_^ + | +help: remove the return type... + | +LL | fn issue_6640_1(a: bool, b: bool) -> Option<()> { + | ^^^^^^^^^^ +help: ...and then remove returned values + | +LL | return ; +LL | } +LL | if a { +LL | Some(()); +LL | +LL | } else { + ... + +error: this function's return value is unnecessary + --> $DIR/unnecessary_wraps.rs:133:1 + | +LL | / fn issue_6640_2(a: bool, b: bool) -> Result<(), i32> { +LL | | if a && b { +LL | | return Ok(()); +LL | | } +... | +LL | | } +LL | | } + | |_^ + | +help: remove the return type... + | +LL | fn issue_6640_2(a: bool, b: bool) -> Result<(), i32> { + | ^^^^^^^^^^^^^^^ +help: ...and then remove returned values + | +LL | return ; +LL | } +LL | if a { +LL | +LL | } else { +LL | return ; + | + +error: aborting due to 7 previous errors diff --git a/src/tools/clippy/tests/ui/upper_case_acronyms.rs b/src/tools/clippy/tests/ui/upper_case_acronyms.rs index af0b577634863..fdf8905f812f6 100644 --- a/src/tools/clippy/tests/ui/upper_case_acronyms.rs +++ b/src/tools/clippy/tests/ui/upper_case_acronyms.rs @@ -1,11 +1,11 @@ #![warn(clippy::upper_case_acronyms)] -struct HTTPResponse; // linted +struct HTTPResponse; // not linted by default, but with cfg option struct CString; // not linted enum Flags { - NS, // linted + NS, // not linted CWR, ECE, URG, @@ -16,6 +16,7 @@ enum Flags { FIN, } -struct GCCLLVMSomething; // linted, beware that lint suggests `GccllvmSomething` instead of `GccLlvmSomething` +struct GCCLLVMSomething; // linted with cfg option, beware that lint suggests `GccllvmSomething` instead of + // `GccLlvmSomething` fn main() {} diff --git a/src/tools/clippy/tests/ui/upper_case_acronyms.stderr b/src/tools/clippy/tests/ui/upper_case_acronyms.stderr index 2065fe10bb151..bbe38991e5271 100644 --- a/src/tools/clippy/tests/ui/upper_case_acronyms.stderr +++ b/src/tools/clippy/tests/ui/upper_case_acronyms.stderr @@ -1,22 +1,10 @@ -error: name `HTTPResponse` contains a capitalized acronym - --> $DIR/upper_case_acronyms.rs:3:8 - | -LL | struct HTTPResponse; // linted - | ^^^^^^^^^^^^ help: consider making the acronym lowercase, except the initial letter: `HttpResponse` - | - = note: `-D clippy::upper-case-acronyms` implied by `-D warnings` - -error: name `NS` contains a capitalized acronym - --> $DIR/upper_case_acronyms.rs:8:5 - | -LL | NS, // linted - | ^^ help: consider making the acronym lowercase, except the initial letter (notice the capitalization): `Ns` - error: name `CWR` contains a capitalized acronym --> $DIR/upper_case_acronyms.rs:9:5 | LL | CWR, | ^^^ help: consider making the acronym lowercase, except the initial letter: `Cwr` + | + = note: `-D clippy::upper-case-acronyms` implied by `-D warnings` error: name `ECE` contains a capitalized acronym --> $DIR/upper_case_acronyms.rs:10:5 @@ -60,11 +48,5 @@ error: name `FIN` contains a capitalized acronym LL | FIN, | ^^^ help: consider making the acronym lowercase, except the initial letter: `Fin` -error: name `GCCLLVMSomething` contains a capitalized acronym - --> $DIR/upper_case_acronyms.rs:19:8 - | -LL | struct GCCLLVMSomething; // linted, beware that lint suggests `GccllvmSomething` instead of `GccLlvmSomething` - | ^^^^^^^^^^^^^^^^ help: consider making the acronym lowercase, except the initial letter: `GccllvmSomething` - -error: aborting due to 11 previous errors +error: aborting due to 8 previous errors diff --git a/src/tools/clippy/tests/ui/use_self.fixed b/src/tools/clippy/tests/ui/use_self.fixed index bb2012441d90c..95e7bc754310f 100644 --- a/src/tools/clippy/tests/ui/use_self.fixed +++ b/src/tools/clippy/tests/ui/use_self.fixed @@ -1,9 +1,13 @@ // run-rustfix // edition:2018 +// aux-build:proc_macro_derive.rs #![warn(clippy::use_self)] #![allow(dead_code)] -#![allow(clippy::should_implement_trait, clippy::upper_case_acronyms)] +#![allow(clippy::should_implement_trait, clippy::upper_case_acronyms, clippy::from_over_into)] + +#[macro_use] +extern crate proc_macro_derive; fn main() {} @@ -71,13 +75,12 @@ mod lifetimes { mod issue2894 { trait IntoBytes { - #[allow(clippy::wrong_self_convention)] - fn into_bytes(&self) -> Vec; + fn to_bytes(&self) -> Vec; } // This should not be linted impl IntoBytes for u8 { - fn into_bytes(&self) -> Vec { + fn to_bytes(&self) -> Vec { vec![*self] } } @@ -110,8 +113,8 @@ mod tuple_structs { mod macros { macro_rules! use_self_expand { () => { - fn new() -> Self { - Self {} + fn new() -> Foo { + Foo {} } }; } @@ -119,8 +122,11 @@ mod macros { struct Foo {} impl Foo { - use_self_expand!(); // Should lint in local macros + use_self_expand!(); // Should not lint in local macros } + + #[derive(StructAUseSelf)] // Should not lint in derives + struct A; } mod nesting { @@ -177,11 +183,22 @@ mod issue3410 { struct B; trait Trait { - fn a(v: T); + fn a(v: T) -> Self; } impl Trait> for Vec { - fn a(_: Vec) {} + fn a(_: Vec) -> Self { + unimplemented!() + } + } + + impl Trait> for Vec + where + T: Trait, + { + fn a(v: Vec) -> Self { + >::a(v).into_iter().map(Trait::a).collect() + } } } @@ -252,3 +269,192 @@ mod paths_created_by_lowering { } } } + +// reused from #1997 +mod generics { + struct Foo { + value: T, + } + + impl Foo { + // `Self` is applicable here + fn foo(value: T) -> Self { + Self { value } + } + + // `Cannot` use `Self` as a return type as the generic types are different + fn bar(value: i32) -> Foo { + Foo { value } + } + } +} + +mod issue4140 { + pub struct Error { + _from: From, + _too: To, + } + + pub trait From { + type From; + type To; + + fn from(value: T) -> Self; + } + + pub trait TryFrom + where + Self: Sized, + { + type From; + type To; + + fn try_from(value: T) -> Result>; + } + + impl TryFrom for T + where + T: From, + { + type From = Self; + type To = Self; + + fn try_from(value: F) -> Result> { + Ok(From::from(value)) + } + } + + impl From for i64 { + type From = bool; + type To = Self; + + fn from(value: bool) -> Self { + if value { + 100 + } else { + 0 + } + } + } +} + +mod issue2843 { + trait Foo { + type Bar; + } + + impl Foo for usize { + type Bar = u8; + } + + impl Foo for Option { + type Bar = Option; + } +} + +mod issue3859 { + pub struct Foo; + pub struct Bar([usize; 3]); + + impl Foo { + pub const BAR: usize = 3; + + pub fn foo() { + const _X: usize = Foo::BAR; + // const _Y: usize = Self::BAR; + } + } +} + +mod issue4305 { + trait Foo: 'static {} + + struct Bar; + + impl Foo for Bar {} + + impl From for Box { + fn from(t: T) -> Self { + Box::new(t) + } + } +} + +mod lint_at_item_level { + struct Foo {} + + #[allow(clippy::use_self)] + impl Foo { + fn new() -> Foo { + Foo {} + } + } + + #[allow(clippy::use_self)] + impl Default for Foo { + fn default() -> Foo { + Foo::new() + } + } +} + +mod lint_at_impl_item_level { + struct Foo {} + + impl Foo { + #[allow(clippy::use_self)] + fn new() -> Foo { + Foo {} + } + } + + impl Default for Foo { + #[allow(clippy::use_self)] + fn default() -> Foo { + Foo::new() + } + } +} + +mod issue4734 { + #[repr(C, packed)] + pub struct X { + pub x: u32, + } + + impl From for u32 { + fn from(c: X) -> Self { + unsafe { core::mem::transmute(c) } + } + } +} + +mod nested_paths { + use std::convert::Into; + mod submod { + pub struct B {} + pub struct C {} + + impl Into for B { + fn into(self) -> C { + C {} + } + } + } + + struct A { + t: T, + } + + impl A { + fn new>(v: V) -> Self { + Self { t: Into::into(v) } + } + } + + impl A { + fn test() -> Self { + Self::new::(submod::B {}) + } + } +} diff --git a/src/tools/clippy/tests/ui/use_self.rs b/src/tools/clippy/tests/ui/use_self.rs index ddfd2beba3107..75424f341597d 100644 --- a/src/tools/clippy/tests/ui/use_self.rs +++ b/src/tools/clippy/tests/ui/use_self.rs @@ -1,9 +1,13 @@ // run-rustfix // edition:2018 +// aux-build:proc_macro_derive.rs #![warn(clippy::use_self)] #![allow(dead_code)] -#![allow(clippy::should_implement_trait, clippy::upper_case_acronyms)] +#![allow(clippy::should_implement_trait, clippy::upper_case_acronyms, clippy::from_over_into)] + +#[macro_use] +extern crate proc_macro_derive; fn main() {} @@ -71,13 +75,12 @@ mod lifetimes { mod issue2894 { trait IntoBytes { - #[allow(clippy::wrong_self_convention)] - fn into_bytes(&self) -> Vec; + fn to_bytes(&self) -> Vec; } // This should not be linted impl IntoBytes for u8 { - fn into_bytes(&self) -> Vec { + fn to_bytes(&self) -> Vec { vec![*self] } } @@ -87,7 +90,7 @@ mod existential { struct Foo; impl Foo { - fn bad(foos: &[Self]) -> impl Iterator { + fn bad(foos: &[Foo]) -> impl Iterator { foos.iter() } @@ -119,8 +122,11 @@ mod macros { struct Foo {} impl Foo { - use_self_expand!(); // Should lint in local macros + use_self_expand!(); // Should not lint in local macros } + + #[derive(StructAUseSelf)] // Should not lint in derives + struct A; } mod nesting { @@ -177,11 +183,22 @@ mod issue3410 { struct B; trait Trait { - fn a(v: T); + fn a(v: T) -> Self; } impl Trait> for Vec { - fn a(_: Vec) {} + fn a(_: Vec) -> Self { + unimplemented!() + } + } + + impl Trait> for Vec + where + T: Trait, + { + fn a(v: Vec) -> Self { + >::a(v).into_iter().map(Trait::a).collect() + } } } @@ -252,3 +269,192 @@ mod paths_created_by_lowering { } } } + +// reused from #1997 +mod generics { + struct Foo { + value: T, + } + + impl Foo { + // `Self` is applicable here + fn foo(value: T) -> Foo { + Foo { value } + } + + // `Cannot` use `Self` as a return type as the generic types are different + fn bar(value: i32) -> Foo { + Foo { value } + } + } +} + +mod issue4140 { + pub struct Error { + _from: From, + _too: To, + } + + pub trait From { + type From; + type To; + + fn from(value: T) -> Self; + } + + pub trait TryFrom + where + Self: Sized, + { + type From; + type To; + + fn try_from(value: T) -> Result>; + } + + impl TryFrom for T + where + T: From, + { + type From = T::From; + type To = T::To; + + fn try_from(value: F) -> Result> { + Ok(From::from(value)) + } + } + + impl From for i64 { + type From = bool; + type To = Self; + + fn from(value: bool) -> Self { + if value { + 100 + } else { + 0 + } + } + } +} + +mod issue2843 { + trait Foo { + type Bar; + } + + impl Foo for usize { + type Bar = u8; + } + + impl Foo for Option { + type Bar = Option; + } +} + +mod issue3859 { + pub struct Foo; + pub struct Bar([usize; 3]); + + impl Foo { + pub const BAR: usize = 3; + + pub fn foo() { + const _X: usize = Foo::BAR; + // const _Y: usize = Self::BAR; + } + } +} + +mod issue4305 { + trait Foo: 'static {} + + struct Bar; + + impl Foo for Bar {} + + impl From for Box { + fn from(t: T) -> Self { + Box::new(t) + } + } +} + +mod lint_at_item_level { + struct Foo {} + + #[allow(clippy::use_self)] + impl Foo { + fn new() -> Foo { + Foo {} + } + } + + #[allow(clippy::use_self)] + impl Default for Foo { + fn default() -> Foo { + Foo::new() + } + } +} + +mod lint_at_impl_item_level { + struct Foo {} + + impl Foo { + #[allow(clippy::use_self)] + fn new() -> Foo { + Foo {} + } + } + + impl Default for Foo { + #[allow(clippy::use_self)] + fn default() -> Foo { + Foo::new() + } + } +} + +mod issue4734 { + #[repr(C, packed)] + pub struct X { + pub x: u32, + } + + impl From for u32 { + fn from(c: X) -> Self { + unsafe { core::mem::transmute(c) } + } + } +} + +mod nested_paths { + use std::convert::Into; + mod submod { + pub struct B {} + pub struct C {} + + impl Into for B { + fn into(self) -> C { + C {} + } + } + } + + struct A { + t: T, + } + + impl A { + fn new>(v: V) -> Self { + Self { t: Into::into(v) } + } + } + + impl A { + fn test() -> Self { + A::new::(submod::B {}) + } + } +} diff --git a/src/tools/clippy/tests/ui/use_self.stderr b/src/tools/clippy/tests/ui/use_self.stderr index 80e1bfc75e80a..37dfef7cfe0e5 100644 --- a/src/tools/clippy/tests/ui/use_self.stderr +++ b/src/tools/clippy/tests/ui/use_self.stderr @@ -1,5 +1,5 @@ error: unnecessary structure name repetition - --> $DIR/use_self.rs:14:21 + --> $DIR/use_self.rs:18:21 | LL | fn new() -> Foo { | ^^^ help: use the applicable keyword: `Self` @@ -7,158 +7,172 @@ LL | fn new() -> Foo { = note: `-D clippy::use-self` implied by `-D warnings` error: unnecessary structure name repetition - --> $DIR/use_self.rs:15:13 + --> $DIR/use_self.rs:19:13 | LL | Foo {} | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:17:22 + --> $DIR/use_self.rs:21:22 | LL | fn test() -> Foo { | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:18:13 + --> $DIR/use_self.rs:22:13 | LL | Foo::new() | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:23:25 + --> $DIR/use_self.rs:27:25 | LL | fn default() -> Foo { | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:24:13 + --> $DIR/use_self.rs:28:13 | LL | Foo::new() | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:90:56 + --> $DIR/use_self.rs:93:24 | -LL | fn bad(foos: &[Self]) -> impl Iterator { - | ^^^ help: use the applicable keyword: `Self` +LL | fn bad(foos: &[Foo]) -> impl Iterator { + | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:105:13 + --> $DIR/use_self.rs:93:55 + | +LL | fn bad(foos: &[Foo]) -> impl Iterator { + | ^^^ help: use the applicable keyword: `Self` + +error: unnecessary structure name repetition + --> $DIR/use_self.rs:108:13 | LL | TS(0) | ^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:113:25 - | -LL | fn new() -> Foo { - | ^^^ help: use the applicable keyword: `Self` -... -LL | use_self_expand!(); // Should lint in local macros - | ------------------- in this macro invocation + --> $DIR/use_self.rs:143:29 | - = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) +LL | fn bar() -> Bar { + | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:114:17 - | -LL | Foo {} - | ^^^ help: use the applicable keyword: `Self` -... -LL | use_self_expand!(); // Should lint in local macros - | ------------------- in this macro invocation + --> $DIR/use_self.rs:144:21 | - = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) +LL | Bar { foo: Foo {} } + | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:149:21 + --> $DIR/use_self.rs:155:21 | LL | fn baz() -> Foo { | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:150:13 + --> $DIR/use_self.rs:156:13 | LL | Foo {} | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:137:29 - | -LL | fn bar() -> Bar { - | ^^^ help: use the applicable keyword: `Self` - -error: unnecessary structure name repetition - --> $DIR/use_self.rs:138:21 - | -LL | Bar { foo: Foo {} } - | ^^^ help: use the applicable keyword: `Self` - -error: unnecessary structure name repetition - --> $DIR/use_self.rs:167:21 + --> $DIR/use_self.rs:173:21 | LL | let _ = Enum::B(42); | ^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:168:21 + --> $DIR/use_self.rs:174:21 | LL | let _ = Enum::C { field: true }; | ^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:169:21 + --> $DIR/use_self.rs:175:21 | LL | let _ = Enum::A; | ^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:200:13 + --> $DIR/use_self.rs:217:13 | LL | nested::A::fun_1(); | ^^^^^^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:201:13 + --> $DIR/use_self.rs:218:13 | LL | nested::A::A; | ^^^^^^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:203:13 + --> $DIR/use_self.rs:220:13 | LL | nested::A {}; | ^^^^^^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:222:13 + --> $DIR/use_self.rs:239:13 | LL | TestStruct::from_something() | ^^^^^^^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:236:25 + --> $DIR/use_self.rs:253:25 | LL | async fn g() -> S { | ^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:237:13 + --> $DIR/use_self.rs:254:13 | LL | S {} | ^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:241:16 + --> $DIR/use_self.rs:258:16 | LL | &p[S::A..S::B] | ^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:241:22 + --> $DIR/use_self.rs:258:22 | LL | &p[S::A..S::B] | ^ help: use the applicable keyword: `Self` -error: aborting due to 25 previous errors +error: unnecessary structure name repetition + --> $DIR/use_self.rs:281:29 + | +LL | fn foo(value: T) -> Foo { + | ^^^^^^ help: use the applicable keyword: `Self` + +error: unnecessary structure name repetition + --> $DIR/use_self.rs:282:13 + | +LL | Foo { value } + | ^^^ help: use the applicable keyword: `Self` + +error: unnecessary structure name repetition + --> $DIR/use_self.rs:319:21 + | +LL | type From = T::From; + | ^^^^^^^ help: use the applicable keyword: `Self` + +error: unnecessary structure name repetition + --> $DIR/use_self.rs:320:19 + | +LL | type To = T::To; + | ^^^^^ help: use the applicable keyword: `Self` + +error: unnecessary structure name repetition + --> $DIR/use_self.rs:457:13 + | +LL | A::new::(submod::B {}) + | ^ help: use the applicable keyword: `Self` + +error: aborting due to 29 previous errors diff --git a/src/tools/clippy/tests/ui/use_self_trait.fixed b/src/tools/clippy/tests/ui/use_self_trait.fixed index 1582ae114bf4c..9bcd692fb3511 100644 --- a/src/tools/clippy/tests/ui/use_self_trait.fixed +++ b/src/tools/clippy/tests/ui/use_self_trait.fixed @@ -47,7 +47,8 @@ impl Mul for Bad { impl Clone for Bad { fn clone(&self) -> Self { - Self + // FIXME: applicable here + Bad } } diff --git a/src/tools/clippy/tests/ui/use_self_trait.rs b/src/tools/clippy/tests/ui/use_self_trait.rs index 70667b9797e76..de305d40f330b 100644 --- a/src/tools/clippy/tests/ui/use_self_trait.rs +++ b/src/tools/clippy/tests/ui/use_self_trait.rs @@ -47,6 +47,7 @@ impl Mul for Bad { impl Clone for Bad { fn clone(&self) -> Self { + // FIXME: applicable here Bad } } diff --git a/src/tools/clippy/tests/ui/use_self_trait.stderr b/src/tools/clippy/tests/ui/use_self_trait.stderr index 4f2506cc1192f..55af3ff2a93d9 100644 --- a/src/tools/clippy/tests/ui/use_self_trait.stderr +++ b/src/tools/clippy/tests/ui/use_self_trait.stderr @@ -84,11 +84,5 @@ error: unnecessary structure name repetition LL | fn mul(self, rhs: Bad) -> Bad { | ^^^ help: use the applicable keyword: `Self` -error: unnecessary structure name repetition - --> $DIR/use_self_trait.rs:50:9 - | -LL | Bad - | ^^^ help: use the applicable keyword: `Self` - -error: aborting due to 15 previous errors +error: aborting due to 14 previous errors diff --git a/src/tools/clippy/tests/ui/vec_init_then_push.rs b/src/tools/clippy/tests/ui/vec_init_then_push.rs index 642ce5040096e..5099aad83bcbc 100644 --- a/src/tools/clippy/tests/ui/vec_init_then_push.rs +++ b/src/tools/clippy/tests/ui/vec_init_then_push.rs @@ -12,10 +12,35 @@ fn main() { cap_err.push(0); cap_err.push(1); cap_err.push(2); + if true { + // don't include this one + cap_err.push(3); + } let mut cap_ok = Vec::with_capacity(10); cap_ok.push(0); new_err = Vec::new(); new_err.push(0); + + let mut vec = Vec::new(); + // control flow at block final expression + if true { + // no lint + vec.push(1); + } +} + +pub fn no_lint() -> Vec { + let mut p = Some(1); + let mut vec = Vec::new(); + loop { + match p { + None => return vec, + Some(i) => { + vec.push(i); + p = None; + }, + } + } } diff --git a/src/tools/clippy/tests/ui/vec_init_then_push.stderr b/src/tools/clippy/tests/ui/vec_init_then_push.stderr index 819ed47d09919..9ec3e10e62470 100644 --- a/src/tools/clippy/tests/ui/vec_init_then_push.stderr +++ b/src/tools/clippy/tests/ui/vec_init_then_push.stderr @@ -24,7 +24,7 @@ LL | | cap_err.push(2); | |____________________^ help: consider using the `vec![]` macro: `let mut cap_err = vec![..];` error: calls to `push` immediately after creation - --> $DIR/vec_init_then_push.rs:19:5 + --> $DIR/vec_init_then_push.rs:23:5 | LL | / new_err = Vec::new(); LL | | new_err.push(0); diff --git a/src/tools/clippy/tests/versioncheck.rs b/src/tools/clippy/tests/versioncheck.rs index bc5ed0816cc81..922a8207cea86 100644 --- a/src/tools/clippy/tests/versioncheck.rs +++ b/src/tools/clippy/tests/versioncheck.rs @@ -2,21 +2,30 @@ use rustc_tools_util::VersionInfo; #[test] -fn check_that_clippy_lints_has_the_same_version_as_clippy() { +fn check_that_clippy_lints_and_clippy_utils_have_the_same_version_as_clippy() { + // do not run this test inside the upstream rustc repo: + // https://github.com/rust-lang/rust-clippy/issues/6683 + if option_env!("RUSTC_TEST_SUITE").is_some() { + return; + } + let clippy_meta = cargo_metadata::MetadataCommand::new() .no_deps() .exec() .expect("could not obtain cargo metadata"); - std::env::set_current_dir(std::env::current_dir().unwrap().join("clippy_lints")).unwrap(); - let clippy_lints_meta = cargo_metadata::MetadataCommand::new() - .no_deps() - .exec() - .expect("could not obtain cargo metadata"); - assert_eq!(clippy_lints_meta.packages[0].version, clippy_meta.packages[0].version); - for package in &clippy_meta.packages[0].dependencies { - if package.name == "clippy_lints" { - assert!(package.req.matches(&clippy_lints_meta.packages[0].version)); - return; + + for krate in &["clippy_lints", "clippy_utils"] { + let krate_meta = clippy_meta + .packages + .iter() + .find(|package| package.name == *krate) + .expect("could not obtain cargo metadata"); + assert_eq!(krate_meta.version, clippy_meta.packages[0].version); + for package in &clippy_meta.packages[0].dependencies { + if package.name == *krate { + assert!(package.req.matches(&krate_meta.version)); + break; + } } } }