diff options
279 files changed, 4777 insertions, 2012 deletions
diff --git a/Cargo.lock b/Cargo.lock index 98c030b3996..dbe5b2ec6b7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -598,7 +598,7 @@ dependencies = [ "itertools", "quine-mc_cluskey", "regex", - "regex-syntax 0.7.2", + "regex-syntax 0.8.2", "rustc-semver", "semver", "serde", @@ -3196,6 +3196,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "436b050e76ed2903236f032a59761c1eb99e1b0aead2c257922771dab1fc8c78" [[package]] +name = "regex-syntax" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" + +[[package]] name = "remote-test-client" version = "0.1.0" diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 5755ae8a8bc..9d543563c0f 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -2845,6 +2845,28 @@ impl Item { pub fn span_with_attributes(&self) -> Span { self.attrs.iter().fold(self.span, |acc, attr| acc.to(attr.span)) } + + pub fn opt_generics(&self) -> Option<&Generics> { + match &self.kind { + ItemKind::ExternCrate(_) + | ItemKind::Use(_) + | ItemKind::Mod(_, _) + | ItemKind::ForeignMod(_) + | ItemKind::GlobalAsm(_) + | ItemKind::MacCall(_) + | ItemKind::MacroDef(_) => None, + ItemKind::Static(_) => None, + ItemKind::Const(i) => Some(&i.generics), + ItemKind::Fn(i) => Some(&i.generics), + ItemKind::TyAlias(i) => Some(&i.generics), + ItemKind::TraitAlias(generics, _) + | ItemKind::Enum(_, generics) + | ItemKind::Struct(_, generics) + | ItemKind::Union(_, generics) => Some(&generics), + ItemKind::Trait(i) => Some(&i.generics), + ItemKind::Impl(i) => Some(&i.generics), + } + } } /// `extern` qualifier on a function item or function type. diff --git a/compiler/rustc_ast/src/util/literal.rs b/compiler/rustc_ast/src/util/literal.rs index 50eb92125b9..92b9adf1db7 100644 --- a/compiler/rustc_ast/src/util/literal.rs +++ b/compiler/rustc_ast/src/util/literal.rs @@ -77,6 +77,8 @@ impl LitKind { // new symbol because the string in the LitKind is different to the // string in the token. let s = symbol.as_str(); + // Vanilla strings are so common we optimize for the common case where no chars + // requiring special behaviour are present. let symbol = if s.contains(['\\', '\r']) { let mut buf = String::with_capacity(s.len()); let mut error = Ok(()); @@ -104,27 +106,20 @@ impl LitKind { LitKind::Str(symbol, ast::StrStyle::Cooked) } token::StrRaw(n) => { - // Ditto. - let s = symbol.as_str(); - let symbol = - if s.contains('\r') { - let mut buf = String::with_capacity(s.len()); - let mut error = Ok(()); - unescape_literal(s, Mode::RawStr, &mut |_, unescaped_char| { - match unescaped_char { - Ok(c) => buf.push(c), - Err(err) => { - if err.is_fatal() { - error = Err(LitError::LexerError); - } - } + // Raw strings have no escapes, so we only need to check for invalid chars, and we + // can reuse the symbol on success. + let mut error = Ok(()); + unescape_literal(symbol.as_str(), Mode::RawStr, &mut |_, unescaped_char| { + match unescaped_char { + Ok(_) => {} + Err(err) => { + if err.is_fatal() { + error = Err(LitError::LexerError); } - }); - error?; - Symbol::intern(&buf) - } else { - symbol - }; + } + } + }); + error?; LitKind::Str(symbol, ast::StrStyle::Raw(n)) } token::ByteStr => { @@ -143,25 +138,19 @@ impl LitKind { LitKind::ByteStr(buf.into(), StrStyle::Cooked) } token::ByteStrRaw(n) => { + // Raw strings have no escapes, so we only need to check for invalid chars, and we + // can convert the symbol directly to a `Lrc<u8>` on success. let s = symbol.as_str(); - let bytes = if s.contains('\r') { - let mut buf = Vec::with_capacity(s.len()); - let mut error = Ok(()); - unescape_literal(s, Mode::RawByteStr, &mut |_, c| match c { - Ok(c) => buf.push(byte_from_char(c)), - Err(err) => { - if err.is_fatal() { - error = Err(LitError::LexerError); - } + let mut error = Ok(()); + unescape_literal(s, Mode::RawByteStr, &mut |_, c| match c { + Ok(_) => {} + Err(err) => { + if err.is_fatal() { + error = Err(LitError::LexerError); } - }); - error?; - buf - } else { - symbol.to_string().into_bytes() - }; - - LitKind::ByteStr(bytes.into(), StrStyle::Raw(n)) + } + }); + LitKind::ByteStr(s.to_owned().into_bytes().into(), StrStyle::Raw(n)) } token::CStr => { let s = symbol.as_str(); @@ -172,7 +161,6 @@ impl LitKind { error = Err(LitError::NulInCStr(span)); } Ok(CStrUnit::Byte(b)) => buf.push(b), - Ok(CStrUnit::Char(c)) if c.len_utf8() == 1 => buf.push(c as u8), Ok(CStrUnit::Char(c)) => { buf.extend_from_slice(c.encode_utf8(&mut [0; 4]).as_bytes()) } @@ -187,18 +175,15 @@ impl LitKind { LitKind::CStr(buf.into(), StrStyle::Cooked) } token::CStrRaw(n) => { + // Raw strings have no escapes, so we only need to check for invalid chars, and we + // can convert the symbol directly to a `Lrc<u8>` on success. let s = symbol.as_str(); - let mut buf = Vec::with_capacity(s.len()); let mut error = Ok(()); unescape_c_string(s, Mode::RawCStr, &mut |span, c| match c { Ok(CStrUnit::Byte(0) | CStrUnit::Char('\0')) => { error = Err(LitError::NulInCStr(span)); } - Ok(CStrUnit::Byte(b)) => buf.push(b), - Ok(CStrUnit::Char(c)) if c.len_utf8() == 1 => buf.push(c as u8), - Ok(CStrUnit::Char(c)) => { - buf.extend_from_slice(c.encode_utf8(&mut [0; 4]).as_bytes()) - } + Ok(_) => {} Err(err) => { if err.is_fatal() { error = Err(LitError::LexerError); @@ -206,6 +191,7 @@ impl LitKind { } }); error?; + let mut buf = s.to_owned().into_bytes(); buf.push(0); LitKind::CStr(buf.into(), StrStyle::Raw(n)) } diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 0bbdcb7f09e..11b5131b8d7 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -1260,9 +1260,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ); // `a = lhs1; b = lhs2;`. - let stmts = self - .arena - .alloc_from_iter(std::iter::once(destructure_let).chain(assignments.into_iter())); + let stmts = self.arena.alloc_from_iter(std::iter::once(destructure_let).chain(assignments)); // Wrap everything in a block. hir::ExprKind::Block(self.block_all(whole_span, stmts, None), None) diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index d9663d50c59..5c9e43f1e06 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -453,6 +453,7 @@ pub fn lower_to_hir(tcx: TyCtxt<'_>, (): ()) -> hir::Crate<'_> { tcx.ensure_with_value().output_filenames(()); tcx.ensure_with_value().early_lint_checks(()); tcx.ensure_with_value().debugger_visualizers(LOCAL_CRATE); + tcx.ensure_with_value().get_lang_items(()); let (mut resolver, krate) = tcx.resolver_for_lowering(()).steal(); let ast_index = index_crate(&resolver.node_id_to_def_id, &krate); @@ -765,6 +766,28 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { self.resolver.get_import_res(id).present_items() } + fn make_lang_item_path( + &mut self, + lang_item: hir::LangItem, + span: Span, + args: Option<&'hir hir::GenericArgs<'hir>>, + ) -> &'hir hir::Path<'hir> { + let def_id = self.tcx.require_lang_item(lang_item, Some(span)); + let def_kind = self.tcx.def_kind(def_id); + let res = Res::Def(def_kind, def_id); + self.arena.alloc(hir::Path { + span, + res, + segments: self.arena.alloc_from_iter([hir::PathSegment { + ident: Ident::new(lang_item.name(), span), + hir_id: self.next_id(), + res, + args, + infer_args: false, + }]), + }) + } + /// Reuses the span but adds information like the kind of the desugaring and features that are /// allowed inside this span. fn mark_span_with_reason( @@ -1976,18 +1999,27 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { CoroutineKind::AsyncGen { .. } => (sym::Item, hir::LangItem::AsyncIterator), }; - let future_args = self.arena.alloc(hir::GenericArgs { + let bound_args = self.arena.alloc(hir::GenericArgs { args: &[], bindings: arena_vec![self; self.assoc_ty_binding(assoc_ty_name, opaque_ty_span, output_ty)], parenthesized: hir::GenericArgsParentheses::No, span_ext: DUMMY_SP, }); - hir::GenericBound::LangItemTrait( - trait_lang_item, - opaque_ty_span, - self.next_id(), - future_args, + hir::GenericBound::Trait( + hir::PolyTraitRef { + bound_generic_params: &[], + trait_ref: hir::TraitRef { + path: self.make_lang_item_path( + trait_lang_item, + opaque_ty_span, + Some(bound_args), + ), + hir_ref_id: self.next_id(), + }, + span: opaque_ty_span, + }, + hir::TraitBoundModifier::None, ) } diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs index 4c3cef2e763..8441dfaa7df 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs @@ -788,28 +788,18 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { }; let opaque_ty = hir.item(id); if let hir::ItemKind::OpaqueTy(hir::OpaqueTy { - bounds: - [ - hir::GenericBound::LangItemTrait( - hir::LangItem::Future, - _, - _, - hir::GenericArgs { - bindings: - [ - hir::TypeBinding { - ident: Ident { name: sym::Output, .. }, - kind: - hir::TypeBindingKind::Equality { term: hir::Term::Ty(ty) }, - .. - }, - ], - .. - }, - ), - ], + bounds: [hir::GenericBound::Trait(trait_ref, _)], .. }) = opaque_ty.kind + && let Some(segment) = trait_ref.trait_ref.path.segments.last() + && let Some(args) = segment.args + && let [ + hir::TypeBinding { + ident: Ident { name: sym::Output, .. }, + kind: hir::TypeBindingKind::Equality { term: hir::Term::Ty(ty) }, + .. + }, + ] = args.bindings { ty } else { diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index f4b9296dbbd..8f60175a603 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -353,7 +353,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { let new_kind = match ty.kind() { Int(t @ Isize) => Int(t.normalize(self.tcx.sess.target.pointer_width)), Uint(t @ Usize) => Uint(t.normalize(self.tcx.sess.target.pointer_width)), - t @ (Uint(_) | Int(_)) => t.clone(), + t @ (Uint(_) | Int(_)) => *t, _ => panic!("tried to get overflow intrinsic for op applied to non-int type"), }; diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index 7968f238b40..883f82caa80 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -607,7 +607,7 @@ pub fn file_metadata<'ll>(cx: &CodegenCx<'ll, '_>, source_file: &SourceFile) -> if let Ok(rel_path) = abs_path.strip_prefix(working_directory) { ( - working_directory.to_string_lossy().into(), + working_directory.to_string_lossy(), rel_path.to_string_lossy().into_owned(), ) } else { @@ -977,6 +977,27 @@ fn build_field_di_node<'ll, 'tcx>( } } +/// Returns the `DIFlags` corresponding to the visibility of the item identified by `did`. +/// +/// `DIFlags::Flag{Public,Protected,Private}` correspond to `DW_AT_accessibility` +/// (public/protected/private) aren't exactly right for Rust, but neither is `DW_AT_visibility` +/// (local/exported/qualified), and there's no way to set `DW_AT_visibility` in LLVM's API. +fn visibility_di_flags<'ll, 'tcx>( + cx: &CodegenCx<'ll, 'tcx>, + did: DefId, + type_did: DefId, +) -> DIFlags { + let parent_did = cx.tcx.parent(type_did); + let visibility = cx.tcx.visibility(did); + match visibility { + Visibility::Public => DIFlags::FlagPublic, + // Private fields have a restricted visibility of the module containing the type. + Visibility::Restricted(did) if did == parent_did => DIFlags::FlagPrivate, + // `pub(crate)`/`pub(super)` visibilities are any other restricted visibility. + Visibility::Restricted(..) => DIFlags::FlagProtected, + } +} + /// Creates the debuginfo node for a Rust struct type. Maybe be a regular struct or a tuple-struct. fn build_struct_type_di_node<'ll, 'tcx>( cx: &CodegenCx<'ll, 'tcx>, @@ -1000,7 +1021,7 @@ fn build_struct_type_di_node<'ll, 'tcx>( &compute_debuginfo_type_name(cx.tcx, struct_type, false), size_and_align_of(struct_type_and_layout), Some(containing_scope), - DIFlags::FlagZero, + visibility_di_flags(cx, adt_def.did(), adt_def.did()), ), // Fields: |cx, owner| { @@ -1023,7 +1044,7 @@ fn build_struct_type_di_node<'ll, 'tcx>( &field_name[..], (field_layout.size, field_layout.align.abi), struct_type_and_layout.fields.offset(i), - DIFlags::FlagZero, + visibility_di_flags(cx, f.did, adt_def.did()), type_di_node(cx, field_layout.ty), ) }) diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs index 7ef185250a3..4a2861af44c 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs @@ -26,8 +26,8 @@ use crate::{ enums::{tag_base_type, DiscrResult}, file_metadata, size_and_align_of, type_di_node, type_map::{self, Stub, UniqueTypeId}, - unknown_file_metadata, DINodeCreationResult, SmallVec, NO_GENERICS, NO_SCOPE_METADATA, - UNKNOWN_LINE_NUMBER, + unknown_file_metadata, visibility_di_flags, DINodeCreationResult, SmallVec, + NO_GENERICS, NO_SCOPE_METADATA, UNKNOWN_LINE_NUMBER, }, utils::DIB, }, @@ -215,7 +215,7 @@ pub(super) fn build_enum_type_di_node<'ll, 'tcx>( &enum_type_name, cx.size_and_align_of(enum_type), NO_SCOPE_METADATA, - DIFlags::FlagZero, + visibility_di_flags(cx, enum_adt_def.did(), enum_adt_def.did()), ), |cx, enum_type_di_node| { match enum_type_and_layout.variants { @@ -320,6 +320,7 @@ fn build_single_variant_union_fields<'ll, 'tcx>( variant_index: VariantIdx, ) -> SmallVec<&'ll DIType> { let variant_layout = enum_type_and_layout.for_variant(cx, variant_index); + let visibility_flags = visibility_di_flags(cx, enum_adt_def.did(), enum_adt_def.did()); let variant_struct_type_di_node = super::build_enum_variant_struct_type_di_node( cx, enum_type_and_layout, @@ -327,6 +328,7 @@ fn build_single_variant_union_fields<'ll, 'tcx>( variant_index, enum_adt_def.variant(variant_index), variant_layout, + visibility_flags, ); let tag_base_type = cx.tcx.types.u32; @@ -364,7 +366,7 @@ fn build_single_variant_union_fields<'ll, 'tcx>( // since the later is sometimes smaller (if it has fewer fields). size_and_align_of(enum_type_and_layout), Size::ZERO, - DIFlags::FlagZero, + visibility_flags, variant_struct_type_wrapper_di_node, ), unsafe { @@ -376,7 +378,7 @@ fn build_single_variant_union_fields<'ll, 'tcx>( unknown_file_metadata(cx), UNKNOWN_LINE_NUMBER, variant_names_type_di_node, - DIFlags::FlagZero, + visibility_flags, Some(cx.const_u64(SINGLE_VARIANT_VIRTUAL_DISR)), tag_base_type_align.bits() as u32, ) @@ -403,6 +405,7 @@ fn build_union_fields_for_enum<'ll, 'tcx>( (variant_index, variant_name) }), ); + let visibility_flags = visibility_di_flags(cx, enum_adt_def.did(), enum_adt_def.did()); let variant_field_infos: SmallVec<VariantFieldInfo<'ll>> = variant_indices .map(|variant_index| { @@ -417,6 +420,7 @@ fn build_union_fields_for_enum<'ll, 'tcx>( variant_index, variant_def, variant_layout, + visibility_flags, ); VariantFieldInfo { @@ -437,6 +441,7 @@ fn build_union_fields_for_enum<'ll, 'tcx>( tag_base_type, tag_field, untagged_variant_index, + visibility_flags, ) } @@ -744,6 +749,7 @@ fn build_union_fields_for_direct_tag_coroutine<'ll, 'tcx>( tag_base_type, tag_field, None, + DIFlags::FlagZero, ) } @@ -758,6 +764,7 @@ fn build_union_fields_for_direct_tag_enum_or_coroutine<'ll, 'tcx>( tag_base_type: Ty<'tcx>, tag_field: usize, untagged_variant_index: Option<VariantIdx>, + di_flags: DIFlags, ) -> SmallVec<&'ll DIType> { let tag_base_type_di_node = type_di_node(cx, tag_base_type); let mut unions_fields = SmallVec::with_capacity(variant_field_infos.len() + 1); @@ -801,7 +808,7 @@ fn build_union_fields_for_direct_tag_enum_or_coroutine<'ll, 'tcx>( align.bits() as u32, // Union fields are always at offset zero Size::ZERO.bits(), - DIFlags::FlagZero, + di_flags, variant_struct_type_wrapper, ) } @@ -835,7 +842,7 @@ fn build_union_fields_for_direct_tag_enum_or_coroutine<'ll, 'tcx>( TAG_FIELD_NAME_128_LO, size_and_align, lo_offset, - DIFlags::FlagZero, + di_flags, type_di_node, )); @@ -855,7 +862,7 @@ fn build_union_fields_for_direct_tag_enum_or_coroutine<'ll, 'tcx>( TAG_FIELD_NAME, cx.size_and_align_of(enum_type_and_layout.field(cx, tag_field).ty), enum_type_and_layout.fields.offset(tag_field), - DIFlags::FlagZero, + di_flags, tag_base_type_di_node, )); } diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs index df1df6d197e..eef8dbb33b4 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs @@ -250,6 +250,7 @@ fn build_enum_variant_struct_type_di_node<'ll, 'tcx>( variant_index: VariantIdx, variant_def: &VariantDef, variant_layout: TyAndLayout<'tcx>, + di_flags: DIFlags, ) -> &'ll DIType { debug_assert_eq!(variant_layout.ty, enum_type_and_layout.ty); @@ -267,7 +268,7 @@ fn build_enum_variant_struct_type_di_node<'ll, 'tcx>( // NOTE: We use size and align of enum_type, not from variant_layout: size_and_align_of(enum_type_and_layout), Some(enum_type_di_node), - DIFlags::FlagZero, + di_flags, ), |cx, struct_type_di_node| { (0..variant_layout.fields.count()) @@ -289,7 +290,7 @@ fn build_enum_variant_struct_type_di_node<'ll, 'tcx>( &field_name, (field_layout.size, field_layout.align.abi), variant_layout.fields.offset(field_index), - DIFlags::FlagZero, + di_flags, type_di_node(cx, field_layout.ty), ) }) @@ -395,7 +396,7 @@ pub fn build_coroutine_variant_struct_type_di_node<'ll, 'tcx>( }) .collect(); - state_specific_fields.into_iter().chain(common_fields.into_iter()).collect() + state_specific_fields.into_iter().chain(common_fields).collect() }, |cx| build_generic_type_param_di_nodes(cx, coroutine_type_and_layout.ty), ) diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs index 130ca2727e4..cba4e3811d5 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs @@ -7,8 +7,8 @@ use crate::{ enums::tag_base_type, file_metadata, size_and_align_of, type_di_node, type_map::{self, Stub, StubInfo, UniqueTypeId}, - unknown_file_metadata, DINodeCreationResult, SmallVec, NO_GENERICS, - UNKNOWN_LINE_NUMBER, + unknown_file_metadata, visibility_di_flags, DINodeCreationResult, SmallVec, + NO_GENERICS, UNKNOWN_LINE_NUMBER, }, utils::{create_DIArray, get_namespace_for_item, DIB}, }, @@ -63,6 +63,8 @@ pub(super) fn build_enum_type_di_node<'ll, 'tcx>( let enum_type_and_layout = cx.layout_of(enum_type); let enum_type_name = compute_debuginfo_type_name(cx.tcx, enum_type, false); + let visibility_flags = visibility_di_flags(cx, enum_adt_def.did(), enum_adt_def.did()); + debug_assert!(!wants_c_like_enum_debuginfo(enum_type_and_layout)); type_map::build_type_with_children( @@ -74,7 +76,7 @@ pub(super) fn build_enum_type_di_node<'ll, 'tcx>( &enum_type_name, size_and_align_of(enum_type_and_layout), Some(containing_scope), - DIFlags::FlagZero, + visibility_flags, ), |cx, enum_type_di_node| { // Build the struct type for each variant. These will be referenced by the @@ -92,6 +94,7 @@ pub(super) fn build_enum_type_di_node<'ll, 'tcx>( variant_index, enum_adt_def.variant(variant_index), enum_type_and_layout.for_variant(cx, variant_index), + visibility_flags, ), source_info: None, }) diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index 40a985cf255..015ea10d721 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -578,7 +578,9 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { hir_id, no_sanitize_span, "`no_sanitize` will have no effect after inlining", - |lint| lint.span_note(inline_span, "inlining requested here"), + |lint| { + lint.span_note(inline_span, "inlining requested here"); + }, ) } } diff --git a/compiler/rustc_data_structures/src/sorted_map.rs b/compiler/rustc_data_structures/src/sorted_map.rs index 60b343afbed..ed2e558bffa 100644 --- a/compiler/rustc_data_structures/src/sorted_map.rs +++ b/compiler/rustc_data_structures/src/sorted_map.rs @@ -198,7 +198,7 @@ impl<K: Ord, V> SortedMap<K, V> { if index == self.data.len() || elements.last().unwrap().0 < self.data[index].0 { // We can copy the whole range without having to mix with // existing elements. - self.data.splice(index..index, elements.into_iter()); + self.data.splice(index..index, elements); return; } diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs index 4fb63d67e78..403e0ec7950 100644 --- a/compiler/rustc_errors/src/diagnostic.rs +++ b/compiler/rustc_errors/src/diagnostic.rs @@ -91,10 +91,7 @@ where #[rustc_diagnostic_item = "DecorateLint"] pub trait DecorateLint<'a, G: EmissionGuarantee> { /// Decorate and emit a lint. - fn decorate_lint<'b>( - self, - diag: &'b mut DiagnosticBuilder<'a, G>, - ) -> &'b mut DiagnosticBuilder<'a, G>; + fn decorate_lint<'b>(self, diag: &'b mut DiagnosticBuilder<'a, G>); fn msg(&self) -> DiagnosticMessage; } diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index 379883a0c18..ec37240e394 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -2677,10 +2677,7 @@ fn from_stderr(color: ColorConfig) -> Destination { /// On Windows, BRIGHT_BLUE is hard to read on black. Use cyan instead. /// /// See #36178. -#[cfg(windows)] -const BRIGHT_BLUE: Color = Color::Cyan; -#[cfg(not(windows))] -const BRIGHT_BLUE: Color = Color::Blue; +const BRIGHT_BLUE: Color = if cfg!(windows) { Color::Cyan } else { Color::Blue }; impl Style { fn color_spec(&self, lvl: Level) -> ColorSpec { diff --git a/compiler/rustc_expand/src/proc_macro_server.rs b/compiler/rustc_expand/src/proc_macro_server.rs index d2c26668ea8..4f439c15fbb 100644 --- a/compiler/rustc_expand/src/proc_macro_server.rs +++ b/compiler/rustc_expand/src/proc_macro_server.rs @@ -426,6 +426,10 @@ impl server::Types for Rustc<'_, '_> { } impl server::FreeFunctions for Rustc<'_, '_> { + fn injected_env_var(&mut self, var: &str) -> Option<String> { + self.ecx.sess.opts.logical_env.get(var).cloned() + } + fn track_env_var(&mut self, var: &str, value: Option<&str>) { self.sess() .env_depinfo diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 5c252c3f9f2..760945554f0 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -435,8 +435,6 @@ pub enum TraitBoundModifier { #[derive(Clone, Copy, Debug, HashStable_Generic)] pub enum GenericBound<'hir> { Trait(PolyTraitRef<'hir>, TraitBoundModifier), - // FIXME(davidtwco): Introduce `PolyTraitRef::LangItem` - LangItemTrait(LangItem, Span, HirId, &'hir GenericArgs<'hir>), Outlives(&'hir Lifetime), } @@ -451,7 +449,6 @@ impl GenericBound<'_> { pub fn span(&self) -> Span { match self { GenericBound::Trait(t, ..) => t.span, - GenericBound::LangItemTrait(_, span, ..) => *span, GenericBound::Outlives(l) => l.ident.span, } } @@ -1560,7 +1557,7 @@ impl Expr<'_> { ExprKind::Call(..) => ExprPrecedence::Call, ExprKind::MethodCall(..) => ExprPrecedence::MethodCall, ExprKind::Tup(_) => ExprPrecedence::Tup, - ExprKind::Binary(op, ..) => ExprPrecedence::Binary(op.node.into()), + ExprKind::Binary(op, ..) => ExprPrecedence::Binary(op.node), ExprKind::Unary(..) => ExprPrecedence::Unary, ExprKind::Lit(_) => ExprPrecedence::Lit, ExprKind::Type(..) | ExprKind::Cast(..) => ExprPrecedence::Cast, @@ -1700,11 +1697,9 @@ impl Expr<'_> { // them being used only for its side-effects. base.can_have_side_effects() } - ExprKind::Struct(_, fields, init) => fields - .iter() - .map(|field| field.expr) - .chain(init.into_iter()) - .any(|e| e.can_have_side_effects()), + ExprKind::Struct(_, fields, init) => { + fields.iter().map(|field| field.expr).chain(init).any(|e| e.can_have_side_effects()) + } ExprKind::Array(args) | ExprKind::Tup(args) diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 9cf1db166a5..67e058a3219 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -1075,10 +1075,6 @@ pub fn walk_param_bound<'v, V: Visitor<'v>>(visitor: &mut V, bound: &'v GenericB GenericBound::Trait(ref typ, _modifier) => { visitor.visit_poly_trait_ref(typ); } - GenericBound::LangItemTrait(_, _span, hir_id, args) => { - visitor.visit_id(hir_id); - visitor.visit_generic_args(args); - } GenericBound::Outlives(ref lifetime) => visitor.visit_lifetime(lifetime), } } diff --git a/compiler/rustc_hir/src/target.rs b/compiler/rustc_hir/src/target.rs index 0d65ddb5642..8948a03e4a6 100644 --- a/compiler/rustc_hir/src/target.rs +++ b/compiler/rustc_hir/src/target.rs @@ -67,6 +67,42 @@ impl Display for Target { } impl Target { + pub fn is_associated_item(self) -> bool { + match self { + Target::AssocConst | Target::AssocTy | Target::Method(_) => true, + Target::ExternCrate + | Target::Use + | Target::Static + | Target::Const + | Target::Fn + | Target::Closure + | Target::Mod + | Target::ForeignMod + | Target::GlobalAsm + | Target::TyAlias + | Target::OpaqueTy + | Target::Enum + | Target::Variant + | Target::Struct + | Target::Field + | Target::Union + | Target::Trait + | Target::TraitAlias + | Target::Impl + | Target::Expression + | Target::Statement + | Target::Arm + | Target::ForeignFn + | Target::ForeignStatic + | Target::ForeignTy + | Target::GenericParam(_) + | Target::MacroDef + | Target::Param + | Target::PatField + | Target::ExprField => false, + } + } + pub fn from_item(item: &Item<'_>) -> Target { match item.kind { ItemKind::ExternCrate(..) => Target::ExternCrate, diff --git a/compiler/rustc_hir_analysis/src/astconv/bounds.rs b/compiler/rustc_hir_analysis/src/astconv/bounds.rs index dfec3c5e829..0748644cc0a 100644 --- a/compiler/rustc_hir_analysis/src/astconv/bounds.rs +++ b/compiler/rustc_hir_analysis/src/astconv/bounds.rs @@ -134,17 +134,6 @@ impl<'tcx> dyn AstConv<'tcx> + '_ { only_self_bounds, ); } - &hir::GenericBound::LangItemTrait(lang_item, span, hir_id, args) => { - self.instantiate_lang_item_trait_ref( - lang_item, - span, - hir_id, - args, - param_ty, - bounds, - only_self_bounds, - ); - } hir::GenericBound::Outlives(lifetime) => { let region = self.ast_region_to_region(lifetime, None); bounds.push_region_bound( diff --git a/compiler/rustc_hir_analysis/src/astconv/generics.rs b/compiler/rustc_hir_analysis/src/astconv/generics.rs index 47fbed45b91..be73c027fdc 100644 --- a/compiler/rustc_hir_analysis/src/astconv/generics.rs +++ b/compiler/rustc_hir_analysis/src/astconv/generics.rs @@ -661,7 +661,7 @@ pub(crate) fn prohibit_explicit_late_bound_lifetimes( args.args[0].hir_id(), multispan, msg, - |lint| lint, + |_| {}, ); } diff --git a/compiler/rustc_hir_analysis/src/astconv/lint.rs b/compiler/rustc_hir_analysis/src/astconv/lint.rs index 43d4248ab74..9afb04b7470 100644 --- a/compiler/rustc_hir_analysis/src/astconv/lint.rs +++ b/compiler/rustc_hir_analysis/src/astconv/lint.rs @@ -122,7 +122,6 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { Applicability::MachineApplicable, ); self.maybe_lint_blanket_trait_impl(self_ty, lint); - lint }, ); } diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs index 2ae9f87f296..6f8e80172dd 100644 --- a/compiler/rustc_hir_analysis/src/astconv/mod.rs +++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs @@ -678,36 +678,57 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { ) } - fn instantiate_poly_trait_ref_inner( + /// Given a trait bound like `Debug`, applies that trait bound the given self-type to construct + /// a full trait reference. The resulting trait reference is returned. This may also generate + /// auxiliary bounds, which are added to `bounds`. + /// + /// Example: + /// + /// ```ignore (illustrative) + /// poly_trait_ref = Iterator<Item = u32> + /// self_ty = Foo + /// ``` + /// + /// this would return `Foo: Iterator` and add `<Foo as Iterator>::Item = u32` into `bounds`. + /// + /// **A note on binders:** against our usual convention, there is an implied binder around + /// the `self_ty` and `poly_trait_ref` parameters here. So they may reference bound regions. + /// If for example you had `for<'a> Foo<'a>: Bar<'a>`, then the `self_ty` would be `Foo<'a>` + /// where `'a` is a bound region at depth 0. Similarly, the `poly_trait_ref` would be + /// `Bar<'a>`. The returned poly-trait-ref will have this binder instantiated explicitly, + /// however. + #[instrument(level = "debug", skip(self, span, constness, bounds, speculative))] + pub(crate) fn instantiate_poly_trait_ref( &self, - hir_id: hir::HirId, + trait_ref: &hir::TraitRef<'_>, span: Span, - binding_span: Option<Span>, constness: ty::BoundConstness, polarity: ty::ImplPolarity, + self_ty: Ty<'tcx>, bounds: &mut Bounds<'tcx>, speculative: bool, - trait_ref_span: Span, - trait_def_id: DefId, - trait_segment: &hir::PathSegment<'_>, - args: &GenericArgs<'_>, - infer_args: bool, - self_ty: Ty<'tcx>, only_self_bounds: OnlySelfBounds, ) -> GenericArgCountResult { + let trait_def_id = trait_ref.trait_def_id().unwrap_or_else(|| FatalError.raise()); + let trait_segment = trait_ref.path.segments.last().unwrap(); + let args = trait_segment.args(); + + self.prohibit_generics(trait_ref.path.segments.split_last().unwrap().1.iter(), |_| {}); + self.complain_about_internal_fn_trait(span, trait_def_id, trait_segment, false); + let (generic_args, arg_count) = self.create_args_for_ast_path( - trait_ref_span, + trait_ref.path.span, trait_def_id, &[], trait_segment, args, - infer_args, + trait_segment.infer_args, Some(self_ty), constness, ); let tcx = self.tcx(); - let bound_vars = tcx.late_bound_vars(hir_id); + let bound_vars = tcx.late_bound_vars(trait_ref.hir_ref_id); debug!(?bound_vars); let assoc_bindings = self.create_assoc_bindings_for_generic_args(args); @@ -735,13 +756,13 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // Specify type to assert that error was already reported in `Err` case. let _: Result<_, ErrorGuaranteed> = self.add_predicates_for_ast_type_binding( - hir_id, + trait_ref.hir_ref_id, poly_trait_ref, binding, bounds, speculative, &mut dup_bindings, - binding_span.unwrap_or(binding.span), + binding.span, constness, only_self_bounds, polarity, @@ -752,102 +773,6 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { arg_count } - /// Given a trait bound like `Debug`, applies that trait bound the given self-type to construct - /// a full trait reference. The resulting trait reference is returned. This may also generate - /// auxiliary bounds, which are added to `bounds`. - /// - /// Example: - /// - /// ```ignore (illustrative) - /// poly_trait_ref = Iterator<Item = u32> - /// self_ty = Foo - /// ``` - /// - /// this would return `Foo: Iterator` and add `<Foo as Iterator>::Item = u32` into `bounds`. - /// - /// **A note on binders:** against our usual convention, there is an implied bounder around - /// the `self_ty` and `poly_trait_ref` parameters here. So they may reference bound regions. - /// If for example you had `for<'a> Foo<'a>: Bar<'a>`, then the `self_ty` would be `Foo<'a>` - /// where `'a` is a bound region at depth 0. Similarly, the `poly_trait_ref` would be - /// `Bar<'a>`. The returned poly-trait-ref will have this binder instantiated explicitly, - /// however. - #[instrument(level = "debug", skip(self, span, constness, bounds, speculative))] - pub(crate) fn instantiate_poly_trait_ref( - &self, - trait_ref: &hir::TraitRef<'_>, - span: Span, - constness: ty::BoundConstness, - polarity: ty::ImplPolarity, - self_ty: Ty<'tcx>, - bounds: &mut Bounds<'tcx>, - speculative: bool, - only_self_bounds: OnlySelfBounds, - ) -> GenericArgCountResult { - let hir_id = trait_ref.hir_ref_id; - let binding_span = None; - let trait_ref_span = trait_ref.path.span; - let trait_def_id = trait_ref.trait_def_id().unwrap_or_else(|| FatalError.raise()); - let trait_segment = trait_ref.path.segments.last().unwrap(); - let args = trait_segment.args(); - let infer_args = trait_segment.infer_args; - - self.prohibit_generics(trait_ref.path.segments.split_last().unwrap().1.iter(), |_| {}); - self.complain_about_internal_fn_trait(span, trait_def_id, trait_segment, false); - - self.instantiate_poly_trait_ref_inner( - hir_id, - span, - binding_span, - constness, - polarity, - bounds, - speculative, - trait_ref_span, - trait_def_id, - trait_segment, - args, - infer_args, - self_ty, - only_self_bounds, - ) - } - - pub(crate) fn instantiate_lang_item_trait_ref( - &self, - lang_item: hir::LangItem, - span: Span, - hir_id: hir::HirId, - args: &GenericArgs<'_>, - self_ty: Ty<'tcx>, - bounds: &mut Bounds<'tcx>, - only_self_bounds: OnlySelfBounds, - ) { - let binding_span = Some(span); - let constness = ty::BoundConstness::NotConst; - let speculative = false; - let trait_ref_span = span; - let trait_def_id = self.tcx().require_lang_item(lang_item, Some(span)); - let trait_segment = &hir::PathSegment::invalid(); - let infer_args = false; - - self.instantiate_poly_trait_ref_inner( - hir_id, - span, - binding_span, - constness, - ty::ImplPolarity::Positive, - bounds, - speculative, - trait_ref_span, - trait_def_id, - trait_segment, - args, - infer_args, - self_ty, - only_self_bounds, - ); - } - fn ast_path_to_mono_trait_ref( &self, span: Span, @@ -1509,8 +1434,6 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { format!("<{} as {}>::{}", qself_ty, tcx.item_name(trait_did), assoc_ident), Applicability::MachineApplicable, ); - - lint }, ); } diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index e6245e4d0b1..8413a1cc0db 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -51,7 +51,7 @@ pub fn check_abi(tcx: TyCtxt<'_>, hir_id: hir::HirId, span: Span, abi: Abi) { hir_id, span, "use of calling convention not supported on this target", - |lint| lint, + |_| {}, ); } } @@ -190,7 +190,7 @@ fn check_static_inhabited(tcx: TyCtxt<'_>, def_id: LocalDefId) { "static of uninhabited type", |lint| { lint - .note("uninhabited statics cannot be initialized, and any access would be an immediate error") + .note("uninhabited statics cannot be initialized, and any access would be an immediate error"); }, ); } @@ -1093,7 +1093,7 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>) "this {descr} contains `{field_ty}`, which {note}, \ and makes it not a breaking change to become \ non-zero-sized in the future." - )) + )); }, ) } else { diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index 4705d9350b0..264868fdfc7 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -2,9 +2,7 @@ use super::potentially_plural_count; use crate::errors::LifetimesOrBoundsMismatchOnTrait; use hir::def_id::{DefId, LocalDefId}; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet}; -use rustc_errors::{ - pluralize, struct_span_err, Applicability, DiagnosticId, ErrorGuaranteed, MultiSpan, -}; +use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticId, ErrorGuaranteed}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::intravisit; @@ -50,13 +48,7 @@ pub(super) fn compare_impl_method<'tcx>( let _: Result<_, ErrorGuaranteed> = try { check_method_is_structurally_compatible(tcx, impl_m, trait_m, impl_trait_ref, false)?; - compare_method_predicate_entailment( - tcx, - impl_m, - trait_m, - impl_trait_ref, - CheckImpliedWfMode::Check, - )?; + compare_method_predicate_entailment(tcx, impl_m, trait_m, impl_trait_ref)?; refine::check_refining_return_position_impl_trait_in_trait( tcx, impl_m, @@ -170,7 +162,6 @@ fn compare_method_predicate_entailment<'tcx>( impl_m: ty::AssocItem, trait_m: ty::AssocItem, impl_trait_ref: ty::TraitRef<'tcx>, - check_implied_wf: CheckImpliedWfMode, ) -> Result<(), ErrorGuaranteed> { let trait_to_impl_args = impl_trait_ref.args; @@ -317,7 +308,7 @@ fn compare_method_predicate_entailment<'tcx>( return Err(emitted); } - if check_implied_wf == CheckImpliedWfMode::Check && !(impl_sig, trait_sig).references_error() { + if !(impl_sig, trait_sig).references_error() { // Select obligations to make progress on inference before processing // the wf obligation below. // FIXME(-Znext-solver): Not needed when the hack below is removed. @@ -333,8 +324,9 @@ fn compare_method_predicate_entailment<'tcx>( // trigger the lint. Instead, let's only consider type outlives and // region outlives obligations. // - // FIXME(-Znext-solver): Try removing this hack again once - // the new solver is stable. + // FIXME(-Znext-solver): Try removing this hack again once the new + // solver is stable. We should just be able to register a WF pred for + // the fn sig. let mut wf_args: smallvec::SmallVec<[_; 4]> = unnormalized_impl_sig.inputs_and_output.iter().map(|ty| ty.into()).collect(); // Annoyingly, asking for the WF predicates of an array (with an unevaluated const (only?)) @@ -357,7 +349,7 @@ fn compare_method_predicate_entailment<'tcx>( // We need to register Projection oblgiations too, because we may end up with // an implied `X::Item: 'a`, which gets desugared into `X::Item = ?0`, `?0: 'a`. // If we only register the region outlives obligation, this leads to an unconstrained var. - // See `implied_bounds_entailment_alias_var` test. + // See `implied_bounds_entailment_alias_var.rs` test. ty::PredicateKind::Clause( ty::ClauseKind::RegionOutlives(..) | ty::ClauseKind::TypeOutlives(..) @@ -378,26 +370,8 @@ fn compare_method_predicate_entailment<'tcx>( // version. let errors = ocx.select_all_or_error(); if !errors.is_empty() { - match check_implied_wf { - CheckImpliedWfMode::Check => { - let impl_m_hir_id = tcx.local_def_id_to_hir_id(impl_m_def_id); - return compare_method_predicate_entailment( - tcx, - impl_m, - trait_m, - impl_trait_ref, - CheckImpliedWfMode::Skip, - ) - .map(|()| { - // If the skip-mode was successful, emit a lint. - emit_implied_wf_lint(infcx.tcx, impl_m, impl_m_hir_id, vec![]); - }); - } - CheckImpliedWfMode::Skip => { - let reported = infcx.err_ctxt().report_fulfillment_errors(errors); - return Err(reported); - } - } + let reported = infcx.err_ctxt().report_fulfillment_errors(errors); + return Err(reported); } // Finally, resolve all regions. This catches wily misuses of @@ -408,119 +382,14 @@ fn compare_method_predicate_entailment<'tcx>( ); let errors = infcx.resolve_regions(&outlives_env); if !errors.is_empty() { - // FIXME(compiler-errors): This can be simplified when IMPLIED_BOUNDS_ENTAILMENT - // becomes a hard error (i.e. ideally we'd just call `resolve_regions_and_report_errors` - let impl_m_hir_id = tcx.local_def_id_to_hir_id(impl_m_def_id); - match check_implied_wf { - CheckImpliedWfMode::Check => { - return compare_method_predicate_entailment( - tcx, - impl_m, - trait_m, - impl_trait_ref, - CheckImpliedWfMode::Skip, - ) - .map(|()| { - let bad_args = extract_bad_args_for_implies_lint( - tcx, - &errors, - (trait_m, trait_sig), - // Unnormalized impl sig corresponds to the HIR types written - (impl_m, unnormalized_impl_sig), - impl_m_hir_id, - ); - // If the skip-mode was successful, emit a lint. - emit_implied_wf_lint(tcx, impl_m, impl_m_hir_id, bad_args); - }); - } - CheckImpliedWfMode::Skip => { - if infcx.tainted_by_errors().is_none() { - infcx.err_ctxt().report_region_errors(impl_m_def_id, &errors); - } - return Err(tcx - .sess - .span_delayed_bug(rustc_span::DUMMY_SP, "error should have been emitted")); - } - } + return Err(infcx + .tainted_by_errors() + .unwrap_or_else(|| infcx.err_ctxt().report_region_errors(impl_m_def_id, &errors))); } Ok(()) } -fn extract_bad_args_for_implies_lint<'tcx>( - tcx: TyCtxt<'tcx>, - errors: &[infer::RegionResolutionError<'tcx>], - (trait_m, trait_sig): (ty::AssocItem, ty::FnSig<'tcx>), - (impl_m, impl_sig): (ty::AssocItem, ty::FnSig<'tcx>), - hir_id: hir::HirId, -) -> Vec<(Span, Option<String>)> { - let mut blame_generics = vec![]; - for error in errors { - // Look for the subregion origin that contains an input/output type - let origin = match error { - infer::RegionResolutionError::ConcreteFailure(o, ..) => o, - infer::RegionResolutionError::GenericBoundFailure(o, ..) => o, - infer::RegionResolutionError::SubSupConflict(_, _, o, ..) => o, - infer::RegionResolutionError::UpperBoundUniverseConflict(.., o, _) => o, - }; - // Extract (possible) input/output types from origin - match origin { - infer::SubregionOrigin::Subtype(trace) => { - if let Some((a, b)) = trace.values.ty() { - blame_generics.extend([a, b]); - } - } - infer::SubregionOrigin::RelateParamBound(_, ty, _) => blame_generics.push(*ty), - infer::SubregionOrigin::ReferenceOutlivesReferent(ty, _) => blame_generics.push(*ty), - _ => {} - } - } - - let fn_decl = tcx.hir().fn_decl_by_hir_id(hir_id).unwrap(); - let opt_ret_ty = match fn_decl.output { - hir::FnRetTy::DefaultReturn(_) => None, - hir::FnRetTy::Return(ty) => Some(ty), - }; - - // Map late-bound regions from trait to impl, so the names are right. - let mapping = std::iter::zip( - tcx.fn_sig(trait_m.def_id).skip_binder().bound_vars(), - tcx.fn_sig(impl_m.def_id).skip_binder().bound_vars(), - ) - .filter_map(|(impl_bv, trait_bv)| { - if let ty::BoundVariableKind::Region(impl_bv) = impl_bv - && let ty::BoundVariableKind::Region(trait_bv) = trait_bv - { - Some((impl_bv, trait_bv)) - } else { - None - } - }) - .collect(); - - // For each arg, see if it was in the "blame" of any of the region errors. - // If so, then try to produce a suggestion to replace the argument type with - // one from the trait. - let mut bad_args = vec![]; - for (idx, (ty, hir_ty)) in - std::iter::zip(impl_sig.inputs_and_output, fn_decl.inputs.iter().chain(opt_ret_ty)) - .enumerate() - { - let expected_ty = trait_sig.inputs_and_output[idx] - .fold_with(&mut RemapLateBound { tcx, mapping: &mapping }); - if blame_generics.iter().any(|blame| ty.contains(*blame)) { - let expected_ty_sugg = expected_ty.to_string(); - bad_args.push(( - hir_ty.span, - // Only suggest something if it actually changed. - (expected_ty_sugg != ty.to_string()).then_some(expected_ty_sugg), - )); - } - } - - bad_args -} - struct RemapLateBound<'a, 'tcx> { tcx: TyCtxt<'tcx>, mapping: &'a FxHashMap<ty::BoundRegionKind, ty::BoundRegionKind>, @@ -544,53 +413,6 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for RemapLateBound<'_, 'tcx> { } } -fn emit_implied_wf_lint<'tcx>( - tcx: TyCtxt<'tcx>, - impl_m: ty::AssocItem, - hir_id: hir::HirId, - bad_args: Vec<(Span, Option<String>)>, -) { - let span: MultiSpan = if bad_args.is_empty() { - tcx.def_span(impl_m.def_id).into() - } else { - bad_args.iter().map(|(span, _)| *span).collect::<Vec<_>>().into() - }; - tcx.struct_span_lint_hir( - rustc_session::lint::builtin::IMPLIED_BOUNDS_ENTAILMENT, - hir_id, - span, - "impl method assumes more implied bounds than the corresponding trait method", - |lint| { - let bad_args: Vec<_> = - bad_args.into_iter().filter_map(|(span, sugg)| Some((span, sugg?))).collect(); - if !bad_args.is_empty() { - lint.multipart_suggestion( - format!( - "replace {} type{} to make the impl signature compatible", - pluralize!("this", bad_args.len()), - pluralize!(bad_args.len()) - ), - bad_args, - Applicability::MaybeIncorrect, - ); - } - lint - }, - ); -} - -#[derive(Debug, PartialEq, Eq)] -enum CheckImpliedWfMode { - /// Checks implied well-formedness of the impl method. If it fails, we will - /// re-check with `Skip`, and emit a lint if it succeeds. - Check, - /// Skips checking implied well-formedness of the impl method, but will emit - /// a lint if the `compare_method_predicate_entailment` succeeded. This means that - /// the reason that we had failed earlier during `Check` was due to the impl - /// having stronger requirements than the trait. - Skip, -} - fn compare_asyncness<'tcx>( tcx: TyCtxt<'tcx>, impl_m: ty::AssocItem, diff --git a/compiler/rustc_hir_analysis/src/check/intrinsicck.rs b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs index 7c9624206e5..d86ebc2c9c3 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsicck.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs @@ -276,7 +276,6 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { lint.help(format!( "or use `{{{idx}:{default_modifier}}}` to keep the default formatting of `{default_result}`", )); - lint }, ); } diff --git a/compiler/rustc_hir_analysis/src/check_unused.rs b/compiler/rustc_hir_analysis/src/check_unused.rs index 9ad73eeffc6..36cb8f7a202 100644 --- a/compiler/rustc_hir_analysis/src/check_unused.rs +++ b/compiler/rustc_hir_analysis/src/check_unused.rs @@ -45,7 +45,7 @@ fn check_unused_traits(tcx: TyCtxt<'_>, (): ()) { item.hir_id(), path.span, msg, - |lint| lint, + |_| {}, ); } } diff --git a/compiler/rustc_hir_analysis/src/coherence/orphan.rs b/compiler/rustc_hir_analysis/src/coherence/orphan.rs index 45100457629..88128d22a3d 100644 --- a/compiler/rustc_hir_analysis/src/coherence/orphan.rs +++ b/compiler/rustc_hir_analysis/src/coherence/orphan.rs @@ -522,7 +522,7 @@ fn lint_auto_trait_impl<'tcx>( format!( "try using the same sequence of generic parameters as the {self_descr} definition", ), - ) + ); }, ); } diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs index c1c2bb62c66..3ee2822edd8 100644 --- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs @@ -279,7 +279,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { param.hir_id, param.span, TYPE_DEFAULT_NOT_ALLOWED, - |lint| lint, + |_| {}, ); } Defaults::Deny => { diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs index 5769fc5fe64..9f0742dade8 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -350,7 +350,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { // Nested poly trait refs have the binders concatenated let mut full_binders = self.map.late_bound_vars.entry(*hir_id).or_default().clone(); - full_binders.extend(supertrait_bound_vars.into_iter()); + full_binders.extend(supertrait_bound_vars); break (full_binders, BinderScopeType::Concatenating); } } @@ -925,7 +925,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { "you can use the `'static` lifetime directly, in place of `{}`", lifetime.ident, ); - lint.help(help) + lint.help(help); }, ); } @@ -938,32 +938,6 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { } } - fn visit_param_bound(&mut self, bound: &'tcx hir::GenericBound<'tcx>) { - match bound { - hir::GenericBound::LangItemTrait(_, _, hir_id, _) => { - // FIXME(jackh726): This is pretty weird. `LangItemTrait` doesn't go - // through the regular poly trait ref code, so we don't get another - // chance to introduce a binder. For now, I'm keeping the existing logic - // of "if there isn't a Binder scope above us, add one", but I - // imagine there's a better way to go about this. - let (binders, scope_type) = self.poly_trait_ref_binder_info(); - - self.record_late_bound_vars(*hir_id, binders); - let scope = Scope::Binder { - hir_id: *hir_id, - bound_vars: FxIndexMap::default(), - s: self.scope, - scope_type, - where_bound_origin: None, - }; - self.with(scope, |this| { - intravisit::walk_param_bound(this, bound); - }); - } - _ => intravisit::walk_param_bound(self, bound), - } - } - fn visit_poly_trait_ref(&mut self, trait_ref: &'tcx hir::PolyTraitRef<'tcx>) { self.visit_poly_trait_ref_inner(trait_ref, NonLifetimeBinderAllowed::Allow); } diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 82e687135eb..21a50b94a37 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -2084,11 +2084,6 @@ impl<'a> State<'a> { } self.print_poly_trait_ref(tref); } - GenericBound::LangItemTrait(lang_item, span, ..) => { - self.word("#[lang = \""); - self.print_ident(Ident::new(lang_item.name(), *span)); - self.word("\"]"); - } GenericBound::Outlives(lt) => { self.print_lifetime(lt); } diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs index 74aec897f95..ff03cf16a27 100644 --- a/compiler/rustc_hir_typeck/src/errors.rs +++ b/compiler/rustc_hir_typeck/src/errors.rs @@ -573,13 +573,13 @@ impl rustc_errors::AddToDiagnostic for CastUnknownPointerSub { { match self { CastUnknownPointerSub::To(span) => { - let msg = f(diag, crate::fluent_generated::hir_typeck_label_to.into()); + let msg = f(diag, crate::fluent_generated::hir_typeck_label_to); diag.span_label(span, msg); - let msg = f(diag, crate::fluent_generated::hir_typeck_note.into()); + let msg = f(diag, crate::fluent_generated::hir_typeck_note); diag.note(msg); } CastUnknownPointerSub::From(span) => { - let msg = f(diag, crate::fluent_generated::hir_typeck_label_from.into()); + let msg = f(diag, crate::fluent_generated::hir_typeck_label_from); diag.span_label(span, msg); } } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index 7744f75121e..3bee42eb89c 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -72,7 +72,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { orig_span, custom_note .unwrap_or("any code following this expression is unreachable"), - ) + ); }, ) } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index 1650aaeb495..668e547571f 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -825,9 +825,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { && let hir::Node::Item(hir::Item { kind: hir::ItemKind::OpaqueTy(op_ty), .. }) = self.tcx.hir_node(item_id.hir_id()) - && let [ - hir::GenericBound::LangItemTrait(hir::LangItem::Future, _, _, generic_args), - ] = op_ty.bounds + && let [hir::GenericBound::Trait(trait_ref, _)] = op_ty.bounds + && let Some(hir::PathSegment { args: Some(generic_args), .. }) = + trait_ref.trait_ref.path.segments.last() && let hir::GenericArgs { bindings: [ty_binding], .. } = generic_args && let hir::TypeBindingKind::Equality { term: hir::Term::Ty(term) } = ty_binding.kind diff --git a/compiler/rustc_hir_typeck/src/method/prelude2021.rs b/compiler/rustc_hir_typeck/src/method/prelude2021.rs index 3f1dca5b1de..43d258de6ca 100644 --- a/compiler/rustc_hir_typeck/src/method/prelude2021.rs +++ b/compiler/rustc_hir_typeck/src/method/prelude2021.rs @@ -122,8 +122,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { format!("disambiguate the method call with `({self_adjusted})`",), ); } - - lint }, ); } else { @@ -187,8 +185,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ), ); } - - lint }, ); } @@ -307,8 +303,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { format!("<{} as {}>::{}", self_ty_name, trait_name, method_name.name,), Applicability::MachineApplicable, ); - - lint }, ); } diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index 4243bce377f..fe2d43a3c92 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -445,7 +445,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { scope_expr_id, span, "type annotations needed", - |lint| lint, + |_| {}, ); } } else { @@ -1427,8 +1427,6 @@ impl<'tcx> Pick<'tcx> { )); } } - - lint }, ); } @@ -1548,9 +1546,9 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { ); let candidate_obligations = impl_obligations - .chain(norm_obligations.into_iter()) + .chain(norm_obligations) .chain(ref_obligations.iter().cloned()) - .chain(normalization_obligations.into_iter()); + .chain(normalization_obligations); // Evaluate those obligations to see if they might possibly hold. for o in candidate_obligations { diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index be21fd5f0a6..56a420fab4f 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -1849,8 +1849,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { lint.note(format!( "the pattern is of type `{ty}` and the `non_exhaustive_omitted_patterns` attribute was found", )); - - lint }); } diff --git a/compiler/rustc_hir_typeck/src/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs index 998ee339ae2..69d6fb8e2ea 100644 --- a/compiler/rustc_hir_typeck/src/upvar.rs +++ b/compiler/rustc_hir_typeck/src/upvar.rs @@ -912,8 +912,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Applicability::HasPlaceholders ); } - - lint }, ); } diff --git a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs index b762778122b..bbe07b8ed72 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs @@ -668,26 +668,16 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { ( hir::ItemKind::OpaqueTy(hir::OpaqueTy { bounds: last_bounds, .. }), hir::ItemKind::OpaqueTy(hir::OpaqueTy { bounds: exp_bounds, .. }), - ) if std::iter::zip(*last_bounds, *exp_bounds).all(|(left, right)| { - match (left, right) { - ( - hir::GenericBound::Trait(tl, ml), - hir::GenericBound::Trait(tr, mr), - ) if tl.trait_ref.trait_def_id() == tr.trait_ref.trait_def_id() + ) if std::iter::zip(*last_bounds, *exp_bounds).all(|(left, right)| match ( + left, right, + ) { + (hir::GenericBound::Trait(tl, ml), hir::GenericBound::Trait(tr, mr)) + if tl.trait_ref.trait_def_id() == tr.trait_ref.trait_def_id() && ml == mr => - { - true - } - ( - hir::GenericBound::LangItemTrait(langl, _, _, argsl), - hir::GenericBound::LangItemTrait(langr, _, _, argsr), - ) if langl == langr => { - // FIXME: consider the bounds! - debug!("{:?} {:?}", argsl, argsr); - true - } - _ => false, + { + true } + _ => false, }) => { StatementAsExpression::NeedsBoxing diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index e8a8808428c..3de269da22d 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -5,7 +5,7 @@ pub use self::BoundRegionConversionTime::*; pub use self::RegionVariableOrigin::*; pub use self::SubregionOrigin::*; pub use self::ValuePairs::*; -pub use combine::ObligationEmittingRelation; +pub use relate::combine::ObligationEmittingRelation; use rustc_data_structures::captures::Captures; use rustc_data_structures::undo_log::UndoLogs; use rustc_middle::infer::unify_key::{ConstVidKey, EffectVidKey}; @@ -43,7 +43,6 @@ use rustc_span::{Span, DUMMY_SP}; use std::cell::{Cell, RefCell}; use std::fmt; -use self::combine::CombineFields; use self::error_reporting::TypeErrCtxt; use self::free_regions::RegionRelations; use self::lexical_region_resolve::LexicalRegionResolutions; @@ -51,29 +50,23 @@ use self::region_constraints::{GenericKind, VarInfos, VerifyBound}; use self::region_constraints::{ RegionConstraintCollector, RegionConstraintStorage, RegionSnapshot, }; +pub use self::relate::combine::CombineFields; +pub use self::relate::nll as nll_relate; use self::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; pub mod at; pub mod canonical; -mod combine; -mod equate; pub mod error_reporting; pub mod free_regions; mod freshen; mod fudge; -mod generalize; -mod glb; -mod higher_ranked; -pub mod lattice; mod lexical_region_resolve; -mod lub; -pub mod nll_relate; pub mod opaque_types; pub mod outlives; mod projection; pub mod region_constraints; +mod relate; pub mod resolve; -mod sub; pub mod type_variable; mod undo_log; diff --git a/compiler/rustc_infer/src/infer/outlives/verify.rs b/compiler/rustc_infer/src/infer/outlives/verify.rs index ce619ae8a0d..bb578a482e4 100644 --- a/compiler/rustc_infer/src/infer/outlives/verify.rs +++ b/compiler/rustc_infer/src/infer/outlives/verify.rs @@ -130,12 +130,7 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { // see the extensive comment in projection_must_outlive let recursive_bound = { let mut components = smallvec![]; - compute_alias_components_recursive( - self.tcx, - alias_ty_as_ty.into(), - &mut components, - visited, - ); + compute_alias_components_recursive(self.tcx, alias_ty_as_ty, &mut components, visited); self.bound_from_components(&components, visited) }; diff --git a/compiler/rustc_infer/src/infer/combine.rs b/compiler/rustc_infer/src/infer/relate/combine.rs index fe58fc7122c..dfaca3458d6 100644 --- a/compiler/rustc_infer/src/infer/combine.rs +++ b/compiler/rustc_infer/src/infer/relate/combine.rs @@ -3,7 +3,7 @@ //! combining two instances of various things and yielding a new instance. //! These combiner methods always yield a `Result<T>`. To relate two //! types, you can use `infcx.at(cause, param_env)` which then allows -//! you to use the relevant methods of [At](super::at::At). +//! you to use the relevant methods of [At](crate::infer::at::At). //! //! Combiners mostly do their specific behavior and then hand off the //! bulk of the work to [InferCtxt::super_combine_tys] and @@ -23,11 +23,11 @@ //! this should be correctly updated. use super::equate::Equate; +use super::generalize::{self, CombineDelegate, Generalization}; use super::glb::Glb; use super::lub::Lub; use super::sub::Sub; -use super::{DefineOpaqueTypes, InferCtxt, TypeTrace}; -use crate::infer::generalize::{self, CombineDelegate, Generalization}; +use crate::infer::{DefineOpaqueTypes, InferCtxt, TypeTrace}; use crate::traits::{Obligation, PredicateObligations}; use rustc_middle::infer::canonical::OriginalQueryValues; use rustc_middle::infer::unify_key::{ConstVarValue, ConstVariableValue, EffectVarValue}; @@ -552,7 +552,7 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> { } pub fn register_obligations(&mut self, obligations: PredicateObligations<'tcx>) { - self.obligations.extend(obligations.into_iter()); + self.obligations.extend(obligations); } pub fn register_predicates(&mut self, obligations: impl IntoIterator<Item: ToPredicate<'tcx>>) { diff --git a/compiler/rustc_infer/src/infer/equate.rs b/compiler/rustc_infer/src/infer/relate/equate.rs index 5d929394eb0..9943c638a91 100644 --- a/compiler/rustc_infer/src/infer/equate.rs +++ b/compiler/rustc_infer/src/infer/relate/equate.rs @@ -1,8 +1,6 @@ -use crate::infer::DefineOpaqueTypes; -use crate::traits::PredicateObligations; - use super::combine::{CombineFields, ObligationEmittingRelation}; -use super::Subtype; +use crate::infer::{DefineOpaqueTypes, SubregionOrigin}; +use crate::traits::PredicateObligations; use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation}; use rustc_middle::ty::GenericArgsRef; @@ -133,7 +131,7 @@ impl<'tcx> TypeRelation<'tcx> for Equate<'_, '_, 'tcx> { b: ty::Region<'tcx>, ) -> RelateResult<'tcx, ty::Region<'tcx>> { debug!("{}.regions({:?}, {:?})", self.tag(), a, b); - let origin = Subtype(Box::new(self.fields.trace.clone())); + let origin = SubregionOrigin::Subtype(Box::new(self.fields.trace.clone())); self.fields .infcx .inner diff --git a/compiler/rustc_infer/src/infer/generalize.rs b/compiler/rustc_infer/src/infer/relate/generalize.rs index 383f3bdbe23..66f7b08ee12 100644 --- a/compiler/rustc_infer/src/infer/generalize.rs +++ b/compiler/rustc_infer/src/infer/relate/generalize.rs @@ -16,7 +16,7 @@ use crate::infer::{InferCtxt, RegionVariableOrigin}; /// Attempts to generalize `term` for the type variable `for_vid`. /// This checks for cycles -- that is, whether the type `term` /// references `for_vid`. -pub(super) fn generalize<'tcx, D: GeneralizerDelegate<'tcx>, T: Into<Term<'tcx>> + Relate<'tcx>>( +pub fn generalize<'tcx, D: GeneralizerDelegate<'tcx>, T: Into<Term<'tcx>> + Relate<'tcx>>( infcx: &InferCtxt<'tcx>, delegate: &mut D, term: T, @@ -54,7 +54,7 @@ pub(super) fn generalize<'tcx, D: GeneralizerDelegate<'tcx>, T: Into<Term<'tcx>> /// Abstracts the handling of region vars between HIR and MIR/NLL typechecking /// in the generalizer code. -pub(super) trait GeneralizerDelegate<'tcx> { +pub trait GeneralizerDelegate<'tcx> { fn param_env(&self) -> ty::ParamEnv<'tcx>; fn forbid_inference_vars() -> bool; @@ -64,7 +64,7 @@ pub(super) trait GeneralizerDelegate<'tcx> { fn generalize_region(&mut self, universe: ty::UniverseIndex) -> ty::Region<'tcx>; } -pub(super) struct CombineDelegate<'cx, 'tcx> { +pub struct CombineDelegate<'cx, 'tcx> { pub infcx: &'cx InferCtxt<'tcx>, pub param_env: ty::ParamEnv<'tcx>, pub span: Span, @@ -515,7 +515,7 @@ where /// not only the generalized type, but also a bool flag /// indicating whether further WF checks are needed. #[derive(Debug)] -pub(super) struct Generalization<T> { +pub struct Generalization<T> { /// When generalizing `<?0 as Trait>::Assoc` or /// `<T as Bar<<?0 as Foo>::Assoc>>::Assoc` /// for `?0` generalization returns an inference @@ -524,7 +524,7 @@ pub(super) struct Generalization<T> { /// This has to be handled wotj care as it can /// otherwise very easily result in infinite /// recursion. - pub(super) value_may_be_infer: T, + pub value_may_be_infer: T, /// If true, then the generalized type may not be well-formed, /// even if the source type is well-formed, so we should add an @@ -551,5 +551,5 @@ pub(super) struct Generalization<T> { /// will force the calling code to check that `WF(Foo<?C, ?D>)` /// holds, which in turn implies that `?C::Item == ?D`. So once /// `?C` is constrained, that should suffice to restrict `?D`. - pub(super) needs_wf: bool, + pub needs_wf: bool, } diff --git a/compiler/rustc_infer/src/infer/glb.rs b/compiler/rustc_infer/src/infer/relate/glb.rs index 2f659d9a665..6a3413879c4 100644 --- a/compiler/rustc_infer/src/infer/glb.rs +++ b/compiler/rustc_infer/src/infer/relate/glb.rs @@ -1,13 +1,12 @@ //! Greatest lower bound. See [`lattice`]. +use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation}; +use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt}; + use super::combine::{CombineFields, ObligationEmittingRelation}; use super::lattice::{self, LatticeDir}; -use super::Subtype; -use super::{DefineOpaqueTypes, InferCtxt}; - +use crate::infer::{DefineOpaqueTypes, InferCtxt, SubregionOrigin}; use crate::traits::{ObligationCause, PredicateObligations}; -use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation}; -use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt}; /// "Greatest lower bound" (common subtype) pub struct Glb<'combine, 'infcx, 'tcx> { @@ -68,7 +67,7 @@ impl<'tcx> TypeRelation<'tcx> for Glb<'_, '_, 'tcx> { ) -> RelateResult<'tcx, ty::Region<'tcx>> { debug!("{}.regions({:?}, {:?})", self.tag(), a, b); - let origin = Subtype(Box::new(self.fields.trace.clone())); + let origin = SubregionOrigin::Subtype(Box::new(self.fields.trace.clone())); // GLB(&'static u8, &'a u8) == &RegionLUB('static, 'a) u8 == &'static u8 Ok(self.fields.infcx.inner.borrow_mut().unwrap_region_constraints().lub_regions( self.tcx(), diff --git a/compiler/rustc_infer/src/infer/higher_ranked/mod.rs b/compiler/rustc_infer/src/infer/relate/higher_ranked.rs index 510b1797d3c..440df8c8936 100644 --- a/compiler/rustc_infer/src/infer/higher_ranked/mod.rs +++ b/compiler/rustc_infer/src/infer/relate/higher_ranked.rs @@ -2,8 +2,8 @@ //! the end of the file for details. use super::combine::CombineFields; -use super::{HigherRankedType, InferCtxt}; use crate::infer::CombinedSnapshot; +use crate::infer::{HigherRankedType, InferCtxt}; use rustc_middle::ty::fold::FnMutDelegate; use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation}; use rustc_middle::ty::{self, Binder, Ty, TyCtxt, TypeFoldable}; diff --git a/compiler/rustc_infer/src/infer/lattice.rs b/compiler/rustc_infer/src/infer/relate/lattice.rs index 9ef35429fe3..744e2dfa380 100644 --- a/compiler/rustc_infer/src/infer/lattice.rs +++ b/compiler/rustc_infer/src/infer/relate/lattice.rs @@ -18,10 +18,10 @@ //! [lattices]: https://en.wikipedia.org/wiki/Lattice_(order) use super::combine::ObligationEmittingRelation; -use super::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; -use super::{DefineOpaqueTypes, InferCtxt}; - +use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; +use crate::infer::{DefineOpaqueTypes, InferCtxt}; use crate::traits::ObligationCause; + use rustc_middle::ty::relate::RelateResult; use rustc_middle::ty::TyVar; use rustc_middle::ty::{self, Ty}; diff --git a/compiler/rustc_infer/src/infer/lub.rs b/compiler/rustc_infer/src/infer/relate/lub.rs index e41ec7e6c01..41cd98ed0cf 100644 --- a/compiler/rustc_infer/src/infer/lub.rs +++ b/compiler/rustc_infer/src/infer/relate/lub.rs @@ -2,10 +2,9 @@ use super::combine::{CombineFields, ObligationEmittingRelation}; use super::lattice::{self, LatticeDir}; -use super::Subtype; -use super::{DefineOpaqueTypes, InferCtxt}; - +use crate::infer::{DefineOpaqueTypes, InferCtxt, SubregionOrigin}; use crate::traits::{ObligationCause, PredicateObligations}; + use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation}; use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt}; @@ -68,7 +67,7 @@ impl<'tcx> TypeRelation<'tcx> for Lub<'_, '_, 'tcx> { ) -> RelateResult<'tcx, ty::Region<'tcx>> { debug!("{}.regions({:?}, {:?})", self.tag(), a, b); - let origin = Subtype(Box::new(self.fields.trace.clone())); + let origin = SubregionOrigin::Subtype(Box::new(self.fields.trace.clone())); // LUB(&'static u8, &'a u8) == &RegionGLB('static, 'a) u8 == &'a u8 Ok(self.fields.infcx.inner.borrow_mut().unwrap_region_constraints().glb_regions( self.tcx(), diff --git a/compiler/rustc_infer/src/infer/relate/mod.rs b/compiler/rustc_infer/src/infer/relate/mod.rs new file mode 100644 index 00000000000..f688c2b74a6 --- /dev/null +++ b/compiler/rustc_infer/src/infer/relate/mod.rs @@ -0,0 +1,12 @@ +//! This module contains the definitions of most `TypeRelation`s in the type system +//! (except for some relations used for diagnostics and heuristics in the compiler). + +pub(super) mod combine; +mod equate; +pub(super) mod generalize; +mod glb; +mod higher_ranked; +mod lattice; +mod lub; +pub mod nll; +mod sub; diff --git a/compiler/rustc_infer/src/infer/nll_relate/mod.rs b/compiler/rustc_infer/src/infer/relate/nll.rs index ab3c976a351..afc2a8b2f62 100644 --- a/compiler/rustc_infer/src/infer/nll_relate/mod.rs +++ b/compiler/rustc_infer/src/infer/relate/nll.rs @@ -30,8 +30,8 @@ use rustc_middle::ty::{self, InferConst, Ty, TyCtxt}; use rustc_span::{Span, Symbol}; use std::fmt::Debug; -use crate::infer::combine::ObligationEmittingRelation; -use crate::infer::generalize::{self, Generalization}; +use super::combine::ObligationEmittingRelation; +use super::generalize::{self, Generalization}; use crate::infer::InferCtxt; use crate::infer::{TypeVariableOrigin, TypeVariableOriginKind}; use crate::traits::{Obligation, PredicateObligations}; diff --git a/compiler/rustc_infer/src/infer/sub.rs b/compiler/rustc_infer/src/infer/relate/sub.rs index 0c3bb633b53..5a623e48c93 100644 --- a/compiler/rustc_infer/src/infer/sub.rs +++ b/compiler/rustc_infer/src/infer/relate/sub.rs @@ -1,7 +1,7 @@ use super::combine::CombineFields; -use super::{DefineOpaqueTypes, ObligationEmittingRelation, SubregionOrigin}; - +use crate::infer::{DefineOpaqueTypes, ObligationEmittingRelation, SubregionOrigin}; use crate::traits::{Obligation, PredicateObligations}; + use rustc_middle::ty::relate::{Cause, Relate, RelateResult, TypeRelation}; use rustc_middle::ty::visit::TypeVisitableExt; use rustc_middle::ty::TyVar; diff --git a/compiler/rustc_lexer/src/unescape.rs b/compiler/rustc_lexer/src/unescape.rs index 249126a269e..abec12f52a6 100644 --- a/compiler/rustc_lexer/src/unescape.rs +++ b/compiler/rustc_lexer/src/unescape.rs @@ -92,8 +92,8 @@ where let res = unescape_char_or_byte(&mut chars, mode); callback(0..(src.len() - chars.as_str().len()), res); } - Str | ByteStr => unescape_str_common(src, mode, callback), - RawStr | RawByteStr => unescape_raw_str_or_raw_byte_str(src, mode, callback), + Str | ByteStr => unescape_non_raw_common(src, mode, callback), + RawStr | RawByteStr => check_raw_common(src, mode, callback), CStr | RawCStr => unreachable!(), } } @@ -122,12 +122,10 @@ where { match mode { CStr => { - unescape_str_common(src, mode, callback); + unescape_non_raw_common(src, mode, callback); } RawCStr => { - unescape_raw_str_or_raw_byte_str(src, mode, &mut |r, result| { - callback(r, result.map(CStrUnit::Char)) - }); + check_raw_common(src, mode, &mut |r, result| callback(r, result.map(CStrUnit::Char))); } Char | Byte | Str | RawStr | ByteStr | RawByteStr => unreachable!(), } @@ -191,8 +189,9 @@ impl Mode { /// Byte literals do not allow unicode escape. fn is_unicode_escape_disallowed(self) -> bool { match self { - Byte | ByteStr | RawByteStr => true, - Char | Str | RawStr | CStr | RawCStr => false, + Byte | ByteStr => true, + Char | Str | CStr => false, + RawByteStr | RawStr | RawCStr => unreachable!(), } } @@ -324,7 +323,7 @@ fn unescape_char_or_byte(chars: &mut Chars<'_>, mode: Mode) -> Result<char, Esca /// Takes a contents of a string literal (without quotes) and produces a /// sequence of escaped characters or errors. -fn unescape_str_common<F, T: From<u8> + From<char>>(src: &str, mode: Mode, callback: &mut F) +fn unescape_non_raw_common<F, T: From<u8> + From<char>>(src: &str, mode: Mode, callback: &mut F) where F: FnMut(Range<usize>, Result<T, EscapeError>), { @@ -391,7 +390,7 @@ where /// sequence of characters or errors. /// NOTE: Raw strings do not perform any explicit character escaping, here we /// only produce errors on bare CR. -fn unescape_raw_str_or_raw_byte_str<F>(src: &str, mode: Mode, callback: &mut F) +fn check_raw_common<F>(src: &str, mode: Mode, callback: &mut F) where F: FnMut(Range<usize>, Result<char, EscapeError>), { @@ -399,7 +398,7 @@ where let chars_should_be_ascii = mode.chars_should_be_ascii(); // get this outside the loop // The `start` and `end` computation here matches the one in - // `unescape_str_common` for consistency, even though this function + // `unescape_non_raw_common` for consistency, even though this function // doesn't have to worry about skipping any chars. while let Some(c) = chars.next() { let start = src.len() - chars.as_str().len() - c.len_utf8(); diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 32eb67ba3a1..045ff38c056 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -2800,7 +2800,7 @@ impl<'tcx> LateLintPass<'tcx> for NamedAsmLabels { NAMED_ASM_LABELS, Some(target_spans), fluent::lint_builtin_asm_labels, - |lint| lint, + |_| {}, BuiltinLintDiagnostics::NamedAsmLabel( "only local labels of the form `<number>:` should be used in inline asm" .to_string(), diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index 0911fa70f97..c7a9d5e80ac 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -520,9 +520,6 @@ pub trait LintContext { /// Emit a lint at the appropriate level, with an optional associated span and an existing /// diagnostic. /// - /// Return value of the `decorate` closure is ignored, see [`struct_lint_level`] for a detailed - /// explanation. - /// /// [`struct_lint_level`]: rustc_middle::lint::struct_lint_level#decorate-signature #[rustc_lint_diagnostics] fn lookup_with_diagnostics( @@ -530,9 +527,7 @@ pub trait LintContext { lint: &'static Lint, span: Option<impl Into<MultiSpan>>, msg: impl Into<DiagnosticMessage>, - decorate: impl for<'a, 'b> FnOnce( - &'b mut DiagnosticBuilder<'a, ()>, - ) -> &'b mut DiagnosticBuilder<'a, ()>, + decorate: impl for<'a, 'b> FnOnce(&'b mut DiagnosticBuilder<'a, ()>), diagnostic: BuiltinLintDiagnostics, ) { // We first generate a blank diagnostic. @@ -986,8 +981,6 @@ pub trait LintContext { // set the span in their `decorate` function (preferably using set_span). /// Emit a lint at the appropriate level, with an optional associated span. /// - /// Return value of the `decorate` closure is ignored, see [`struct_lint_level`] for a detailed explanation. - /// /// [`struct_lint_level`]: rustc_middle::lint::struct_lint_level#decorate-signature #[rustc_lint_diagnostics] fn lookup<S: Into<MultiSpan>>( @@ -995,9 +988,7 @@ pub trait LintContext { lint: &'static Lint, span: Option<S>, msg: impl Into<DiagnosticMessage>, - decorate: impl for<'a, 'b> FnOnce( - &'b mut DiagnosticBuilder<'a, ()>, - ) -> &'b mut DiagnosticBuilder<'a, ()>, + decorate: impl for<'a, 'b> FnOnce(&'b mut DiagnosticBuilder<'a, ()>), ); /// Emit a lint at `span` from a lint struct (some type that implements `DecorateLint`, @@ -1008,13 +999,13 @@ pub trait LintContext { span: S, decorator: impl for<'a> DecorateLint<'a, ()>, ) { - self.lookup(lint, Some(span), decorator.msg(), |diag| decorator.decorate_lint(diag)); + self.lookup(lint, Some(span), decorator.msg(), |diag| { + decorator.decorate_lint(diag); + }); } /// Emit a lint at the appropriate level, with an associated span. /// - /// Return value of the `decorate` closure is ignored, see [`struct_lint_level`] for a detailed explanation. - /// /// [`struct_lint_level`]: rustc_middle::lint::struct_lint_level#decorate-signature #[rustc_lint_diagnostics] fn struct_span_lint<S: Into<MultiSpan>>( @@ -1022,9 +1013,7 @@ pub trait LintContext { lint: &'static Lint, span: S, msg: impl Into<DiagnosticMessage>, - decorate: impl for<'a, 'b> FnOnce( - &'b mut DiagnosticBuilder<'a, ()>, - ) -> &'b mut DiagnosticBuilder<'a, ()>, + decorate: impl for<'a, 'b> FnOnce(&'b mut DiagnosticBuilder<'a, ()>), ) { self.lookup(lint, Some(span), msg, decorate); } @@ -1033,23 +1022,19 @@ pub trait LintContext { /// generated by `#[derive(LintDiagnostic)]`). fn emit_lint(&self, lint: &'static Lint, decorator: impl for<'a> DecorateLint<'a, ()>) { self.lookup(lint, None as Option<Span>, decorator.msg(), |diag| { - decorator.decorate_lint(diag) + decorator.decorate_lint(diag); }); } /// Emit a lint at the appropriate level, with no associated span. /// - /// Return value of the `decorate` closure is ignored, see [`struct_lint_level`] for a detailed explanation. - /// /// [`struct_lint_level`]: rustc_middle::lint::struct_lint_level#decorate-signature #[rustc_lint_diagnostics] fn lint( &self, lint: &'static Lint, msg: impl Into<DiagnosticMessage>, - decorate: impl for<'a, 'b> FnOnce( - &'b mut DiagnosticBuilder<'a, ()>, - ) -> &'b mut DiagnosticBuilder<'a, ()>, + decorate: impl for<'a, 'b> FnOnce(&'b mut DiagnosticBuilder<'a, ()>), ) { self.lookup(lint, None as Option<Span>, msg, decorate); } @@ -1113,9 +1098,7 @@ impl<'tcx> LintContext for LateContext<'tcx> { lint: &'static Lint, span: Option<S>, msg: impl Into<DiagnosticMessage>, - decorate: impl for<'a, 'b> FnOnce( - &'b mut DiagnosticBuilder<'a, ()>, - ) -> &'b mut DiagnosticBuilder<'a, ()>, + decorate: impl for<'a, 'b> FnOnce(&'b mut DiagnosticBuilder<'a, ()>), ) { let hir_id = self.last_node_with_lint_attrs; @@ -1142,9 +1125,7 @@ impl LintContext for EarlyContext<'_> { lint: &'static Lint, span: Option<S>, msg: impl Into<DiagnosticMessage>, - decorate: impl for<'a, 'b> FnOnce( - &'b mut DiagnosticBuilder<'a, ()>, - ) -> &'b mut DiagnosticBuilder<'a, ()>, + decorate: impl for<'a, 'b> FnOnce(&'b mut DiagnosticBuilder<'a, ()>), ) { self.builder.struct_lint(lint, span.map(|s| s.into()), msg, decorate) } diff --git a/compiler/rustc_lint/src/early.rs b/compiler/rustc_lint/src/early.rs index 4c7f9eeff8c..b9add9e9f06 100644 --- a/compiler/rustc_lint/src/early.rs +++ b/compiler/rustc_lint/src/early.rs @@ -45,13 +45,7 @@ impl<'a, T: EarlyLintPass> EarlyContextAndPass<'a, T> { fn inlined_check_id(&mut self, id: ast::NodeId) { for early_lint in self.context.buffered.take(id) { let BufferedEarlyLint { span, msg, node_id: _, lint_id, diagnostic } = early_lint; - self.context.lookup_with_diagnostics( - lint_id.lint, - Some(span), - msg, - |lint| lint, - diagnostic, - ); + self.context.lookup_with_diagnostics(lint_id.lint, Some(span), msg, |_| {}, diagnostic); } } diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs index c1d4ed37627..8c8ff3fc650 100644 --- a/compiler/rustc_lint/src/levels.rs +++ b/compiler/rustc_lint/src/levels.rs @@ -1077,7 +1077,6 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> { GateIssue::Language, lint_from_cli, ); - lint }, ); return false; @@ -1094,8 +1093,6 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> { /// Used to emit a lint-related diagnostic based on the current state of /// this lint context. /// - /// Return value of the `decorate` closure is ignored, see [`struct_lint_level`] for a detailed explanation. - /// /// [`struct_lint_level`]: rustc_middle::lint::struct_lint_level#decorate-signature #[rustc_lint_diagnostics] #[track_caller] @@ -1104,9 +1101,7 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> { lint: &'static Lint, span: Option<MultiSpan>, msg: impl Into<DiagnosticMessage>, - decorate: impl for<'a, 'b> FnOnce( - &'b mut DiagnosticBuilder<'a, ()>, - ) -> &'b mut DiagnosticBuilder<'a, ()>, + decorate: impl for<'a, 'b> FnOnce(&'b mut DiagnosticBuilder<'a, ()>), ) { let (level, src) = self.lint_level(lint); struct_lint_level(self.sess, lint, level, src, span, msg, decorate) @@ -1121,7 +1116,7 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> { ) { let (level, src) = self.lint_level(lint); struct_lint_level(self.sess, lint, level, src, Some(span), decorate.msg(), |lint| { - decorate.decorate_lint(lint) + decorate.decorate_lint(lint); }); } @@ -1129,7 +1124,7 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> { pub fn emit_lint(&self, lint: &'static Lint, decorate: impl for<'a> DecorateLint<'a, ()>) { let (level, src) = self.lint_level(lint); struct_lint_level(self.sess, lint, level, src, None, decorate.msg(), |lint| { - decorate.decorate_lint(lint) + decorate.decorate_lint(lint); }); } } diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 83414ee702f..a4ab5527e3f 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -509,6 +509,11 @@ fn register_builtins(store: &mut LintStore) { "converted into hard error, see PR #104616 \ <https://github.com/rust-lang/rust/pull/104616> for more information", ); + store.register_removed( + "implied_bounds_entailment", + "converted into hard error, see PR #117984 \ + <https://github.com/rust-lang/rust/pull/117984> for more information", + ); } fn register_internals(store: &mut LintStore) { diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index d0b895f7354..ca6408bdf3d 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -134,12 +134,8 @@ pub struct BuiltinMissingDebugImpl<'a> { // Needed for def_path_str impl<'a> DecorateLint<'a, ()> for BuiltinMissingDebugImpl<'_> { - fn decorate_lint<'b>( - self, - diag: &'b mut rustc_errors::DiagnosticBuilder<'a, ()>, - ) -> &'b mut rustc_errors::DiagnosticBuilder<'a, ()> { + fn decorate_lint<'b>(self, diag: &'b mut rustc_errors::DiagnosticBuilder<'a, ()>) { diag.set_arg("debug", self.tcx.def_path_str(self.def_id)); - diag } fn msg(&self) -> DiagnosticMessage { @@ -243,17 +239,13 @@ pub struct BuiltinUngatedAsyncFnTrackCaller<'a> { } impl<'a> DecorateLint<'a, ()> for BuiltinUngatedAsyncFnTrackCaller<'_> { - fn decorate_lint<'b>( - self, - diag: &'b mut rustc_errors::DiagnosticBuilder<'a, ()>, - ) -> &'b mut rustc_errors::DiagnosticBuilder<'a, ()> { + fn decorate_lint<'b>(self, diag: &'b mut rustc_errors::DiagnosticBuilder<'a, ()>) { diag.span_label(self.label, fluent::lint_label); rustc_session::parse::add_feature_diagnostics( diag, self.parse_sess, sym::async_fn_track_caller, ); - diag } fn msg(&self) -> DiagnosticMessage { @@ -433,10 +425,7 @@ pub struct BuiltinUnpermittedTypeInit<'a> { } impl<'a> DecorateLint<'a, ()> for BuiltinUnpermittedTypeInit<'_> { - fn decorate_lint<'b>( - self, - diag: &'b mut rustc_errors::DiagnosticBuilder<'a, ()>, - ) -> &'b mut rustc_errors::DiagnosticBuilder<'a, ()> { + fn decorate_lint<'b>(self, diag: &'b mut rustc_errors::DiagnosticBuilder<'a, ()>) { diag.set_arg("ty", self.ty); diag.span_label(self.label, fluent::lint_builtin_unpermitted_type_init_label); if let InhabitedPredicate::True = self.ty.inhabited_predicate(self.tcx) { @@ -447,7 +436,6 @@ impl<'a> DecorateLint<'a, ()> for BuiltinUnpermittedTypeInit<'_> { ); } self.sub.add_to_diagnostic(diag); - diag } fn msg(&self) -> rustc_errors::DiagnosticMessage { @@ -1159,10 +1147,7 @@ pub struct NonFmtPanicUnused { // Used because of two suggestions based on one Option<Span> impl<'a> DecorateLint<'a, ()> for NonFmtPanicUnused { - fn decorate_lint<'b>( - self, - diag: &'b mut rustc_errors::DiagnosticBuilder<'a, ()>, - ) -> &'b mut rustc_errors::DiagnosticBuilder<'a, ()> { + fn decorate_lint<'b>(self, diag: &'b mut rustc_errors::DiagnosticBuilder<'a, ()>) { diag.set_arg("count", self.count); diag.note(fluent::lint_note); if let Some(span) = self.suggestion { @@ -1179,7 +1164,6 @@ impl<'a> DecorateLint<'a, ()> for NonFmtPanicUnused { Applicability::MachineApplicable, ); } - diag } fn msg(&self) -> rustc_errors::DiagnosticMessage { @@ -1358,12 +1342,9 @@ pub struct DropTraitConstraintsDiag<'a> { // Needed for def_path_str impl<'a> DecorateLint<'a, ()> for DropTraitConstraintsDiag<'_> { - fn decorate_lint<'b>( - self, - diag: &'b mut rustc_errors::DiagnosticBuilder<'a, ()>, - ) -> &'b mut rustc_errors::DiagnosticBuilder<'a, ()> { + fn decorate_lint<'b>(self, diag: &'b mut rustc_errors::DiagnosticBuilder<'a, ()>) { diag.set_arg("predicate", self.predicate); - diag.set_arg("needs_drop", self.tcx.def_path_str(self.def_id)) + diag.set_arg("needs_drop", self.tcx.def_path_str(self.def_id)); } fn msg(&self) -> rustc_errors::DiagnosticMessage { @@ -1378,11 +1359,8 @@ pub struct DropGlue<'a> { // Needed for def_path_str impl<'a> DecorateLint<'a, ()> for DropGlue<'_> { - fn decorate_lint<'b>( - self, - diag: &'b mut rustc_errors::DiagnosticBuilder<'a, ()>, - ) -> &'b mut rustc_errors::DiagnosticBuilder<'a, ()> { - diag.set_arg("needs_drop", self.tcx.def_path_str(self.def_id)) + fn decorate_lint<'b>(self, diag: &'b mut rustc_errors::DiagnosticBuilder<'a, ()>) { + diag.set_arg("needs_drop", self.tcx.def_path_str(self.def_id)); } fn msg(&self) -> rustc_errors::DiagnosticMessage { @@ -1655,10 +1633,7 @@ pub struct ImproperCTypes<'a> { // Used because of the complexity of Option<DiagnosticMessage>, DiagnosticMessage, and Option<Span> impl<'a> DecorateLint<'a, ()> for ImproperCTypes<'_> { - fn decorate_lint<'b>( - self, - diag: &'b mut rustc_errors::DiagnosticBuilder<'a, ()>, - ) -> &'b mut rustc_errors::DiagnosticBuilder<'a, ()> { + fn decorate_lint<'b>(self, diag: &'b mut rustc_errors::DiagnosticBuilder<'a, ()>) { diag.set_arg("ty", self.ty); diag.set_arg("desc", self.desc); diag.span_label(self.label, fluent::lint_label); @@ -1669,7 +1644,6 @@ impl<'a> DecorateLint<'a, ()> for ImproperCTypes<'_> { if let Some(note) = self.span_note { diag.span_note(note, fluent::lint_note); } - diag } fn msg(&self) -> rustc_errors::DiagnosticMessage { @@ -1802,10 +1776,7 @@ pub enum UnusedDefSuggestion { // Needed because of def_path_str impl<'a> DecorateLint<'a, ()> for UnusedDef<'_, '_> { - fn decorate_lint<'b>( - self, - diag: &'b mut rustc_errors::DiagnosticBuilder<'a, ()>, - ) -> &'b mut rustc_errors::DiagnosticBuilder<'a, ()> { + fn decorate_lint<'b>(self, diag: &'b mut rustc_errors::DiagnosticBuilder<'a, ()>) { diag.set_arg("pre", self.pre); diag.set_arg("post", self.post); diag.set_arg("def", self.cx.tcx.def_path_str(self.def_id)); @@ -1816,7 +1787,6 @@ impl<'a> DecorateLint<'a, ()> for UnusedDef<'_, '_> { if let Some(sugg) = self.suggestion { diag.subdiagnostic(sugg); } - diag } fn msg(&self) -> rustc_errors::DiagnosticMessage { @@ -1889,15 +1859,11 @@ pub struct AsyncFnInTraitDiag { } impl<'a> DecorateLint<'a, ()> for AsyncFnInTraitDiag { - fn decorate_lint<'b>( - self, - diag: &'b mut rustc_errors::DiagnosticBuilder<'a, ()>, - ) -> &'b mut rustc_errors::DiagnosticBuilder<'a, ()> { + fn decorate_lint<'b>(self, diag: &'b mut rustc_errors::DiagnosticBuilder<'a, ()>) { diag.note(fluent::lint_note); if let Some(sugg) = self.sugg { diag.multipart_suggestion(fluent::lint_suggestion, sugg, Applicability::MaybeIncorrect); } - diag } fn msg(&self) -> rustc_errors::DiagnosticMessage { diff --git a/compiler/rustc_lint/src/non_fmt_panic.rs b/compiler/rustc_lint/src/non_fmt_panic.rs index f0e415492ae..9fcd70ba0b5 100644 --- a/compiler/rustc_lint/src/non_fmt_panic.rs +++ b/compiler/rustc_lint/src/non_fmt_panic.rs @@ -126,7 +126,7 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc lint.note(fluent::lint_more_info_note); if !is_arg_inside_call(arg_span, span) { // No clue where this argument is coming from. - return lint; + return; } if arg_macro.is_some_and(|id| cx.tcx.is_diagnostic_item(sym::format_macro, id)) { // A case of `panic!(format!(..))`. @@ -207,7 +207,6 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc } } } - lint }); } diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index e6e445c54b1..f9b66239bf9 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -47,7 +47,6 @@ declare_lint_pass! { HIDDEN_GLOB_REEXPORTS, ILL_FORMED_ATTRIBUTE_INPUT, ILLEGAL_FLOATING_POINT_LITERAL_PATTERN, - IMPLIED_BOUNDS_ENTAILMENT, INCOMPLETE_INCLUDE, INDIRECT_STRUCTURAL_MATCH, INEFFECTIVE_UNSTABLE_TRAIT_IMPL, @@ -4236,47 +4235,6 @@ declare_lint! { } declare_lint! { - /// The `implied_bounds_entailment` lint detects cases where the arguments of an impl method - /// have stronger implied bounds than those from the trait method it's implementing. - /// - /// ### Example - /// - /// ```rust,compile_fail - /// #![deny(implied_bounds_entailment)] - /// - /// trait Trait { - /// fn get<'s>(s: &'s str, _: &'static &'static ()) -> &'static str; - /// } - /// - /// impl Trait for () { - /// fn get<'s>(s: &'s str, _: &'static &'s ()) -> &'static str { - /// s - /// } - /// } - /// - /// let val = <() as Trait>::get(&String::from("blah blah blah"), &&()); - /// println!("{}", val); - /// ``` - /// - /// {{produces}} - /// - /// ### Explanation - /// - /// Neither the trait method, which provides no implied bounds about `'s`, nor the impl, - /// requires the main function to prove that 's: 'static, but the impl method is allowed - /// to assume that `'s: 'static` within its own body. - /// - /// This can be used to implement an unsound API if used incorrectly. - pub IMPLIED_BOUNDS_ENTAILMENT, - Deny, - "impl method assumes more implied bounds than its corresponding trait method", - @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::FutureReleaseErrorReportInDeps, - reference: "issue #105572 <https://github.com/rust-lang/rust/issues/105572>", - }; -} - -declare_lint! { /// The `byte_slice_in_packed_struct_with_derive` lint detects cases where a byte slice field /// (`[u8]`) or string slice field (`str`) is used in a `packed` struct that derives one or /// more built-in traits. diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp index 556dc890a84..cf3f526400d 100644 --- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp @@ -468,6 +468,14 @@ extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine( // it prevents control flow from "falling through" into whatever code // happens to be laid out next in memory. Options.TrapUnreachable = true; + // But don't emit traps after other traps or no-returns unnecessarily. + // ...except for when targeting WebAssembly, because the NoTrapAfterNoreturn + // option causes bugs in the LLVM WebAssembly backend. You should be able to + // remove this check when Rust's minimum supported LLVM version is >= 18 + // https://github.com/llvm/llvm-project/pull/65876 + if (!Trip.isWasm()) { + Options.NoTrapAfterNoreturn = true; + } } if (Singlethread) { diff --git a/compiler/rustc_macros/src/diagnostics/diagnostic.rs b/compiler/rustc_macros/src/diagnostics/diagnostic.rs index 31ad9cdb216..cd61544f69d 100644 --- a/compiler/rustc_macros/src/diagnostics/diagnostic.rs +++ b/compiler/rustc_macros/src/diagnostics/diagnostic.rs @@ -175,9 +175,9 @@ impl<'a> LintDiagnosticDerive<'a> { fn decorate_lint<'__b>( self, #diag: &'__b mut rustc_errors::DiagnosticBuilder<'__a, ()> - ) -> &'__b mut rustc_errors::DiagnosticBuilder<'__a, ()> { + ) { use rustc_errors::IntoDiagnosticArg; - #implementation + #implementation; } fn msg(&self) -> rustc_errors::DiagnosticMessage { diff --git a/compiler/rustc_middle/src/infer/canonical.rs b/compiler/rustc_middle/src/infer/canonical.rs index 59593ae1c63..e544c2a26e8 100644 --- a/compiler/rustc_middle/src/infer/canonical.rs +++ b/compiler/rustc_middle/src/infer/canonical.rs @@ -341,13 +341,13 @@ impl<'tcx> CanonicalParamEnvCache<'tcx> { Entry::Occupied(e) => { let (canonical, var_values) = e.get(); state.var_values.extend_from_slice(var_values); - canonical.clone() + *canonical } Entry::Vacant(e) => { let canonical = canonicalize_op(tcx, key, state); let OriginalQueryValues { var_values, universe_map } = state; assert_eq!(universe_map.len(), 1); - e.insert((canonical.clone(), tcx.arena.alloc_slice(var_values))); + e.insert((canonical, tcx.arena.alloc_slice(var_values))); canonical } } diff --git a/compiler/rustc_middle/src/lint.rs b/compiler/rustc_middle/src/lint.rs index eada116f896..4c4f38d1ad8 100644 --- a/compiler/rustc_middle/src/lint.rs +++ b/compiler/rustc_middle/src/lint.rs @@ -253,29 +253,10 @@ pub fn explain_lint_level_source( /// - [`TyCtxt::struct_lint_node`] /// - `LintContext::lookup` /// -/// ## `decorate` signature +/// ## `decorate` /// -/// The return value of `decorate` is ignored by this function. So what is the -/// point of returning `&'b mut DiagnosticBuilder<'a, ()>`? -/// -/// There are 2 reasons for this signature. -/// -/// First of all, it prevents accidental use of `.emit()` -- it's clear that the -/// builder will be later used and shouldn't be emitted right away (this is -/// especially important because the old API expected you to call `.emit()` in -/// the closure). -/// -/// Second of all, it makes the most common case of adding just a single label -/// /suggestion much nicer, since [`DiagnosticBuilder`] methods return -/// `&mut DiagnosticBuilder`, you can just chain methods, without needed -/// awkward `{ ...; }`: -/// ```ignore pseudo-code -/// struct_lint_level( -/// ..., -/// |lint| lint.span_label(sp, "lbl") -/// // ^^^^^^^^^^^^^^^^^^^^^ returns `&mut DiagnosticBuilder` by default -/// ) -/// ``` +/// It is not intended to call `emit`/`cancel` on the `DiagnosticBuilder` passed +/// in the `decorate` callback. #[track_caller] pub fn struct_lint_level( sess: &Session, @@ -284,9 +265,7 @@ pub fn struct_lint_level( src: LintLevelSource, span: Option<MultiSpan>, msg: impl Into<DiagnosticMessage>, - decorate: impl for<'a, 'b> FnOnce( - &'b mut DiagnosticBuilder<'a, ()>, - ) -> &'b mut DiagnosticBuilder<'a, ()>, + decorate: impl for<'a, 'b> FnOnce(&'b mut DiagnosticBuilder<'a, ()>), ) { // Avoid codegen bloat from monomorphization by immediately doing dyn dispatch of `decorate` to // the "real" work. @@ -298,12 +277,7 @@ pub fn struct_lint_level( src: LintLevelSource, span: Option<MultiSpan>, msg: impl Into<DiagnosticMessage>, - decorate: Box< - dyn '_ - + for<'a, 'b> FnOnce( - &'b mut DiagnosticBuilder<'a, ()>, - ) -> &'b mut DiagnosticBuilder<'a, ()>, - >, + decorate: Box<dyn '_ + for<'a, 'b> FnOnce(&'b mut DiagnosticBuilder<'a, ()>)>, ) { // Check for future incompatibility lints and issue a stronger warning. let future_incompatible = lint.future_incompatible; diff --git a/compiler/rustc_middle/src/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs index 564a1fad14d..0cba6d5b52a 100644 --- a/compiler/rustc_middle/src/middle/stability.rs +++ b/compiler/rustc_middle/src/middle/stability.rs @@ -223,7 +223,6 @@ fn late_report_deprecation( let kind = tcx.def_descr(def_id); deprecation_suggestion(diag, kind, suggestion, method_span); } - diag }); } @@ -587,7 +586,7 @@ impl<'tcx> TyCtxt<'tcx> { unmarked: impl FnOnce(Span, DefId), ) -> bool { let soft_handler = |lint, span, msg: String| { - self.struct_span_lint_hir(lint, id.unwrap_or(hir::CRATE_HIR_ID), span, msg, |lint| lint) + self.struct_span_lint_hir(lint, id.unwrap_or(hir::CRATE_HIR_ID), span, msg, |_| {}) }; let eval_result = self.eval_stability_allow_unstable(def_id, id, span, method_span, allow_unstable); diff --git a/compiler/rustc_middle/src/mir/interpret/queries.rs b/compiler/rustc_middle/src/mir/interpret/queries.rs index 34068a9da37..092b59deeff 100644 --- a/compiler/rustc_middle/src/mir/interpret/queries.rs +++ b/compiler/rustc_middle/src/mir/interpret/queries.rs @@ -113,7 +113,7 @@ impl<'tcx> TyCtxt<'tcx> { self.local_def_id_to_hir_id(local_def_id), self.def_span(ct.def), "cannot use constants which depend on generic parameters in types", - |err| err, + |_| {}, ) } } diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs index a3fa568114f..2d3ee33489e 100644 --- a/compiler/rustc_middle/src/ty/consts.rs +++ b/compiler/rustc_middle/src/ty/consts.rs @@ -59,7 +59,7 @@ impl<'tcx> Const<'tcx> { #[inline] pub fn kind(self) -> ConstKind<'tcx> { - self.0.kind.clone() + self.0.kind } #[inline] diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 5e61847a37a..6a6ed59fabf 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -2030,14 +2030,12 @@ impl<'tcx> TyCtxt<'tcx> { let msg = decorator.msg(); let (level, src) = self.lint_level_at_node(lint, hir_id); struct_lint_level(self.sess, lint, level, src, Some(span.into()), msg, |diag| { - decorator.decorate_lint(diag) + decorator.decorate_lint(diag); }) } /// Emit a lint at the appropriate level for a hir node, with an associated span. /// - /// Return value of the `decorate` closure is ignored, see [`struct_lint_level`] for a detailed explanation. - /// /// [`struct_lint_level`]: rustc_middle::lint::struct_lint_level#decorate-signature #[rustc_lint_diagnostics] #[track_caller] @@ -2047,9 +2045,7 @@ impl<'tcx> TyCtxt<'tcx> { hir_id: HirId, span: impl Into<MultiSpan>, msg: impl Into<DiagnosticMessage>, - decorate: impl for<'a, 'b> FnOnce( - &'b mut DiagnosticBuilder<'a, ()>, - ) -> &'b mut DiagnosticBuilder<'a, ()>, + decorate: impl for<'a, 'b> FnOnce(&'b mut DiagnosticBuilder<'a, ()>), ) { let (level, src) = self.lint_level_at_node(lint, hir_id); struct_lint_level(self.sess, lint, level, src, Some(span.into()), msg, decorate); @@ -2064,13 +2060,13 @@ impl<'tcx> TyCtxt<'tcx> { id: HirId, decorator: impl for<'a> DecorateLint<'a, ()>, ) { - self.struct_lint_node(lint, id, decorator.msg(), |diag| decorator.decorate_lint(diag)) + self.struct_lint_node(lint, id, decorator.msg(), |diag| { + decorator.decorate_lint(diag); + }) } /// Emit a lint at the appropriate level for a hir node. /// - /// Return value of the `decorate` closure is ignored, see [`struct_lint_level`] for a detailed explanation. - /// /// [`struct_lint_level`]: rustc_middle::lint::struct_lint_level#decorate-signature #[rustc_lint_diagnostics] #[track_caller] @@ -2079,9 +2075,7 @@ impl<'tcx> TyCtxt<'tcx> { lint: &'static Lint, id: HirId, msg: impl Into<DiagnosticMessage>, - decorate: impl for<'a, 'b> FnOnce( - &'b mut DiagnosticBuilder<'a, ()>, - ) -> &'b mut DiagnosticBuilder<'a, ()>, + decorate: impl for<'a, 'b> FnOnce(&'b mut DiagnosticBuilder<'a, ()>), ) { let (level, src) = self.lint_level_at_node(lint, id); struct_lint_level(self.sess, lint, level, src, None, msg, decorate); diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index a09a5115386..febab23ea35 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -473,7 +473,7 @@ impl<'tcx> IntoKind for Ty<'tcx> { type Kind = TyKind<'tcx>; fn kind(self) -> TyKind<'tcx> { - self.kind().clone() + *self.kind() } } diff --git a/compiler/rustc_mir_dataflow/src/value_analysis.rs b/compiler/rustc_mir_dataflow/src/value_analysis.rs index 071024a0fa3..2802f5491be 100644 --- a/compiler/rustc_mir_dataflow/src/value_analysis.rs +++ b/compiler/rustc_mir_dataflow/src/value_analysis.rs @@ -956,11 +956,7 @@ impl Map { // The local is not tracked at all, so it does not alias anything. return; }; - let elems = place - .projection - .iter() - .map(|&elem| elem.try_into()) - .chain(tail_elem.map(Ok).into_iter()); + let elems = place.projection.iter().map(|&elem| elem.try_into()).chain(tail_elem.map(Ok)); for elem in elems { // A field aliases the parent place. if let Some(vi) = self.places[index].value_index { diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs index 146cc33e8c6..ad12bce9b02 100644 --- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs +++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs @@ -496,7 +496,7 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> { FlatSet::Elem(scalar) => { let ty = op.ty(self.local_decls, self.tcx); self.tcx.layout_of(self.param_env.and(ty)).map_or(FlatSet::Top, |layout| { - FlatSet::Elem(ImmTy::from_scalar(scalar.into(), layout)) + FlatSet::Elem(ImmTy::from_scalar(scalar, layout)) }) } FlatSet::Bottom => FlatSet::Bottom, diff --git a/compiler/rustc_mir_transform/src/errors.rs b/compiler/rustc_mir_transform/src/errors.rs index dbf27ea60f8..928db471298 100644 --- a/compiler/rustc_mir_transform/src/errors.rs +++ b/compiler/rustc_mir_transform/src/errors.rs @@ -180,10 +180,7 @@ pub(crate) struct UnsafeOpInUnsafeFn { impl<'a> DecorateLint<'a, ()> for UnsafeOpInUnsafeFn { #[track_caller] - fn decorate_lint<'b>( - self, - diag: &'b mut DiagnosticBuilder<'a, ()>, - ) -> &'b mut DiagnosticBuilder<'a, ()> { + fn decorate_lint<'b>(self, diag: &'b mut DiagnosticBuilder<'a, ()>) { let handler = diag.handler().expect("lint should not yet be emitted"); let desc = handler.eagerly_translate_to_string(self.details.label(), [].into_iter()); diag.set_arg("details", desc); @@ -198,8 +195,6 @@ impl<'a> DecorateLint<'a, ()> for UnsafeOpInUnsafeFn { Applicability::MaybeIncorrect, ); } - - diag } fn msg(&self) -> DiagnosticMessage { @@ -213,10 +208,7 @@ pub(crate) enum AssertLint<P> { } impl<'a, P: std::fmt::Debug> DecorateLint<'a, ()> for AssertLint<P> { - fn decorate_lint<'b>( - self, - diag: &'b mut DiagnosticBuilder<'a, ()>, - ) -> &'b mut DiagnosticBuilder<'a, ()> { + fn decorate_lint<'b>(self, diag: &'b mut DiagnosticBuilder<'a, ()>) { let span = self.span(); let assert_kind = self.panic(); let message = assert_kind.diagnostic_message(); @@ -224,8 +216,6 @@ impl<'a, P: std::fmt::Debug> DecorateLint<'a, ()> for AssertLint<P> { diag.set_arg(name, value); }); diag.span_label(span, message); - - diag } fn msg(&self) -> DiagnosticMessage { @@ -284,10 +274,7 @@ pub(crate) struct MustNotSupend<'tcx, 'a> { // Needed for def_path_str impl<'a> DecorateLint<'a, ()> for MustNotSupend<'_, '_> { - fn decorate_lint<'b>( - self, - diag: &'b mut rustc_errors::DiagnosticBuilder<'a, ()>, - ) -> &'b mut rustc_errors::DiagnosticBuilder<'a, ()> { + fn decorate_lint<'b>(self, diag: &'b mut rustc_errors::DiagnosticBuilder<'a, ()>) { diag.span_label(self.yield_sp, fluent::_subdiag::label); if let Some(reason) = self.reason { diag.subdiagnostic(reason); @@ -296,7 +283,6 @@ impl<'a> DecorateLint<'a, ()> for MustNotSupend<'_, '_> { diag.set_arg("pre", self.pre); diag.set_arg("def_path", self.tcx.def_path_str(self.def_id)); diag.set_arg("post", self.post); - diag } fn msg(&self) -> rustc_errors::DiagnosticMessage { diff --git a/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs b/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs index b659c40b233..2b4c2e3c250 100644 --- a/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs +++ b/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs @@ -11,12 +11,12 @@ use crate::errors::{MoreThanOneCharNote, MoreThanOneCharSugg, NoBraceUnicodeSub, pub(crate) fn emit_unescape_error( handler: &Handler, - // interior part of the literal, without quotes + // interior part of the literal, between quotes lit: &str, - // full span of the literal, including quotes - span_with_quotes: Span, - // interior span of the literal, without quotes - span: Span, + // full span of the literal, including quotes and any prefix + full_lit_span: Span, + // span of the error part of the literal + err_span: Span, mode: Mode, // range of the error inside `lit` range: Range<usize>, @@ -24,19 +24,21 @@ pub(crate) fn emit_unescape_error( ) { debug!( "emit_unescape_error: {:?}, {:?}, {:?}, {:?}, {:?}", - lit, span_with_quotes, mode, range, error + lit, full_lit_span, mode, range, error ); let last_char = || { let c = lit[range.clone()].chars().next_back().unwrap(); - let span = span.with_lo(span.hi() - BytePos(c.len_utf8() as u32)); + let span = err_span.with_lo(err_span.hi() - BytePos(c.len_utf8() as u32)); (c, span) }; match error { EscapeError::LoneSurrogateUnicodeEscape => { - handler.emit_err(UnescapeError::InvalidUnicodeEscape { span, surrogate: true }); + handler + .emit_err(UnescapeError::InvalidUnicodeEscape { span: err_span, surrogate: true }); } EscapeError::OutOfRangeUnicodeEscape => { - handler.emit_err(UnescapeError::InvalidUnicodeEscape { span, surrogate: false }); + handler + .emit_err(UnescapeError::InvalidUnicodeEscape { span: err_span, surrogate: false }); } EscapeError::MoreThanOneChar => { use unicode_normalization::{char::is_combining_mark, UnicodeNormalization}; @@ -49,12 +51,16 @@ pub(crate) fn emit_unescape_error( let normalized = lit.nfc().to_string(); if normalized.chars().count() == 1 { let ch = normalized.chars().next().unwrap().escape_default().to_string(); - sugg = Some(MoreThanOneCharSugg::NormalizedForm { span, ch, normalized }); + sugg = Some(MoreThanOneCharSugg::NormalizedForm { + span: err_span, + ch, + normalized, + }); } let escaped_marks = rest.iter().map(|c| c.escape_default().to_string()).collect::<Vec<_>>(); note = Some(MoreThanOneCharNote::AllCombining { - span, + span: err_span, chr: format!("{first}"), len: escaped_marks.len(), escaped_marks: escaped_marks.join(""), @@ -69,10 +75,12 @@ pub(crate) fn emit_unescape_error( .collect(); if let &[ch] = printable.as_slice() { - sugg = - Some(MoreThanOneCharSugg::RemoveNonPrinting { span, ch: ch.to_string() }); + sugg = Some(MoreThanOneCharSugg::RemoveNonPrinting { + span: err_span, + ch: ch.to_string(), + }); note = Some(MoreThanOneCharNote::NonPrinting { - span, + span: err_span, escaped: lit.escape_default().to_string(), }); } @@ -91,13 +99,13 @@ pub(crate) fn emit_unescape_error( } let sugg = format!("{prefix}\"{escaped}\""); MoreThanOneCharSugg::Quotes { - span: span_with_quotes, + span: full_lit_span, is_byte: mode == Mode::Byte, sugg, } }); handler.emit_err(UnescapeError::MoreThanOneChar { - span: span_with_quotes, + span: full_lit_span, note, suggestion: sugg, }); @@ -105,7 +113,7 @@ pub(crate) fn emit_unescape_error( EscapeError::EscapeOnlyChar => { let (c, char_span) = last_char(); handler.emit_err(UnescapeError::EscapeOnlyChar { - span, + span: err_span, char_span, escaped_sugg: c.escape_default().to_string(), escaped_msg: escaped_char(c), @@ -114,11 +122,11 @@ pub(crate) fn emit_unescape_error( } EscapeError::BareCarriageReturn => { let double_quotes = mode.in_double_quotes(); - handler.emit_err(UnescapeError::BareCr { span, double_quotes }); + handler.emit_err(UnescapeError::BareCr { span: err_span, double_quotes }); } EscapeError::BareCarriageReturnInRawString => { assert!(mode.in_double_quotes()); - handler.emit_err(UnescapeError::BareCrRawString(span)); + handler.emit_err(UnescapeError::BareCrRawString(err_span)); } EscapeError::InvalidEscape => { let (c, span) = last_char(); @@ -143,7 +151,7 @@ pub(crate) fn emit_unescape_error( } else { if mode == Mode::Str || mode == Mode::Char { diag.span_suggestion( - span_with_quotes, + full_lit_span, "if you meant to write a literal backslash (perhaps escaping in a regular expression), consider a raw string literal", format!("r\"{lit}\""), Applicability::MaybeIncorrect, @@ -158,7 +166,7 @@ pub(crate) fn emit_unescape_error( diag.emit(); } EscapeError::TooShortHexEscape => { - handler.emit_err(UnescapeError::TooShortHexEscape(span)); + handler.emit_err(UnescapeError::TooShortHexEscape(err_span)); } EscapeError::InvalidCharInHexEscape | EscapeError::InvalidCharInUnicodeEscape => { let (c, span) = last_char(); @@ -210,7 +218,7 @@ pub(crate) fn emit_unescape_error( err.emit(); } EscapeError::OutOfRangeHexEscape => { - handler.emit_err(UnescapeError::OutOfRangeHexEscape(span)); + handler.emit_err(UnescapeError::OutOfRangeHexEscape(err_span)); } EscapeError::LeadingUnderscoreUnicodeEscape => { let (c, span) = last_char(); @@ -220,10 +228,11 @@ pub(crate) fn emit_unescape_error( }); } EscapeError::OverlongUnicodeEscape => { - handler.emit_err(UnescapeError::OverlongUnicodeEscape(span)); + handler.emit_err(UnescapeError::OverlongUnicodeEscape(err_span)); } EscapeError::UnclosedUnicodeEscape => { - handler.emit_err(UnescapeError::UnclosedUnicodeEscape(span, span.shrink_to_hi())); + handler + .emit_err(UnescapeError::UnclosedUnicodeEscape(err_span, err_span.shrink_to_hi())); } EscapeError::NoBraceInUnicodeEscape => { let mut suggestion = "\\u{".to_owned(); @@ -238,34 +247,34 @@ pub(crate) fn emit_unescape_error( let (label, sub) = if suggestion_len > 0 { suggestion.push('}'); let hi = char_span.lo() + BytePos(suggestion_len as u32); - (None, NoBraceUnicodeSub::Suggestion { span: span.with_hi(hi), suggestion }) + (None, NoBraceUnicodeSub::Suggestion { span: err_span.with_hi(hi), suggestion }) } else { - (Some(span), NoBraceUnicodeSub::Help) + (Some(err_span), NoBraceUnicodeSub::Help) }; - handler.emit_err(UnescapeError::NoBraceInUnicodeEscape { span, label, sub }); + handler.emit_err(UnescapeError::NoBraceInUnicodeEscape { span: err_span, label, sub }); } EscapeError::UnicodeEscapeInByte => { - handler.emit_err(UnescapeError::UnicodeEscapeInByte(span)); + handler.emit_err(UnescapeError::UnicodeEscapeInByte(err_span)); } EscapeError::EmptyUnicodeEscape => { - handler.emit_err(UnescapeError::EmptyUnicodeEscape(span)); + handler.emit_err(UnescapeError::EmptyUnicodeEscape(err_span)); } EscapeError::ZeroChars => { - handler.emit_err(UnescapeError::ZeroChars(span)); + handler.emit_err(UnescapeError::ZeroChars(err_span)); } EscapeError::LoneSlash => { - handler.emit_err(UnescapeError::LoneSlash(span)); + handler.emit_err(UnescapeError::LoneSlash(err_span)); } EscapeError::UnskippedWhitespaceWarning => { let (c, char_span) = last_char(); handler.emit_warning(UnescapeError::UnskippedWhitespace { - span, + span: err_span, ch: escaped_char(c), char_span, }); } EscapeError::MultipleSkippedLinesWarning => { - handler.emit_warning(UnescapeError::MultipleSkippedLinesWarning(span)); + handler.emit_warning(UnescapeError::MultipleSkippedLinesWarning(err_span)); } } } diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 89919247e82..fd7dad36c9d 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -923,7 +923,7 @@ impl<'a> Parser<'a> { ); let where_predicates_split = before_where_clause.predicates.len(); let mut predicates = before_where_clause.predicates; - predicates.extend(after_where_clause.predicates.into_iter()); + predicates.extend(after_where_clause.predicates); let where_clause = WhereClause { has_where_token: before_where_clause.has_where_token || after_where_clause.has_where_token, diff --git a/compiler/rustc_parse/src/validate_attr.rs b/compiler/rustc_parse/src/validate_attr.rs index 81055431f64..d10c8c92257 100644 --- a/compiler/rustc_parse/src/validate_attr.rs +++ b/compiler/rustc_parse/src/validate_attr.rs @@ -215,7 +215,7 @@ fn emit_malformed_attribute( } else { "the following are the possible correct uses" }, - suggestions.into_iter(), + suggestions, Applicability::HasPlaceholders, ) .emit(); diff --git a/compiler/rustc_passes/src/hir_stats.rs b/compiler/rustc_passes/src/hir_stats.rs index 85969b72d23..c2392620cb2 100644 --- a/compiler/rustc_passes/src/hir_stats.rs +++ b/compiler/rustc_passes/src/hir_stats.rs @@ -429,7 +429,7 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> { fn visit_param_bound(&mut self, b: &'v hir::GenericBound<'v>) { record_variants!( (self, b, b, Id::None, hir, GenericBound, GenericBound), - [Trait, LangItemTrait, Outlives] + [Trait, Outlives] ); hir_visit::walk_param_bound(self, b) } diff --git a/compiler/rustc_passes/src/lang_items.rs b/compiler/rustc_passes/src/lang_items.rs index 83b7d8d71bc..6d14a14096d 100644 --- a/compiler/rustc_passes/src/lang_items.rs +++ b/compiler/rustc_passes/src/lang_items.rs @@ -7,18 +7,18 @@ //! * Traits that represent operators; e.g., `Add`, `Sub`, `Index`. //! * Functions called by the compiler itself. -use crate::check_attr::target_from_impl_item; use crate::errors::{ DuplicateLangItem, IncorrectTarget, LangItemOnIncorrectTarget, UnknownLangItem, }; use crate::weak_lang_items; -use rustc_hir as hir; -use rustc_hir::def::DefKind; +use rustc_ast as ast; +use rustc_ast::visit; +use rustc_data_structures::fx::FxHashMap; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::lang_items::{extract, GenericRequirement}; -use rustc_hir::{LangItem, LanguageItems, Target}; -use rustc_middle::ty::TyCtxt; +use rustc_hir::{LangItem, LanguageItems, MethodKind, Target}; +use rustc_middle::ty::{ResolverAstLowering, TyCtxt}; use rustc_session::cstore::ExternCrate; use rustc_span::symbol::kw::Empty; use rustc_span::Span; @@ -31,28 +31,55 @@ pub(crate) enum Duplicate { CrateDepends, } -struct LanguageItemCollector<'tcx> { +struct LanguageItemCollector<'ast, 'tcx> { items: LanguageItems, tcx: TyCtxt<'tcx>, + resolver: &'ast ResolverAstLowering, + // FIXME(#118552): We should probably feed def_span eagerly on def-id creation + // so we can avoid constructing this map for local def-ids. + item_spans: FxHashMap<DefId, Span>, + parent_item: Option<&'ast ast::Item>, } -impl<'tcx> LanguageItemCollector<'tcx> { - fn new(tcx: TyCtxt<'tcx>) -> LanguageItemCollector<'tcx> { - LanguageItemCollector { tcx, items: LanguageItems::new() } +impl<'ast, 'tcx> LanguageItemCollector<'ast, 'tcx> { + fn new( + tcx: TyCtxt<'tcx>, + resolver: &'ast ResolverAstLowering, + ) -> LanguageItemCollector<'ast, 'tcx> { + LanguageItemCollector { + tcx, + resolver, + items: LanguageItems::new(), + item_spans: FxHashMap::default(), + parent_item: None, + } } - fn check_for_lang(&mut self, actual_target: Target, def_id: LocalDefId) { - let attrs = self.tcx.hir().attrs(self.tcx.local_def_id_to_hir_id(def_id)); - if let Some((name, span)) = extract(attrs) { + fn check_for_lang( + &mut self, + actual_target: Target, + def_id: LocalDefId, + attrs: &'ast [ast::Attribute], + item_span: Span, + generics: Option<&'ast ast::Generics>, + ) { + if let Some((name, attr_span)) = extract(attrs) { match LangItem::from_name(name) { // Known lang item with attribute on correct target. Some(lang_item) if actual_target == lang_item.target() => { - self.collect_item_extended(lang_item, def_id, span); + self.collect_item_extended( + lang_item, + def_id, + item_span, + attr_span, + generics, + actual_target, + ); } // Known lang item with attribute on incorrect target. Some(lang_item) => { self.tcx.sess.emit_err(LangItemOnIncorrectTarget { - span, + span: attr_span, name, expected_target: lang_item.target(), actual_target, @@ -60,127 +87,131 @@ impl<'tcx> LanguageItemCollector<'tcx> { } // Unknown lang item. _ => { - self.tcx.sess.emit_err(UnknownLangItem { span, name }); + self.tcx.sess.emit_err(UnknownLangItem { span: attr_span, name }); } } } } - fn collect_item(&mut self, lang_item: LangItem, item_def_id: DefId) { + fn collect_item(&mut self, lang_item: LangItem, item_def_id: DefId, item_span: Option<Span>) { // Check for duplicates. - if let Some(original_def_id) = self.items.get(lang_item) { - if original_def_id != item_def_id { - let local_span = self.tcx.hir().span_if_local(item_def_id); - let lang_item_name = lang_item.name(); - let crate_name = self.tcx.crate_name(item_def_id.krate); - let mut dependency_of = Empty; - let is_local = item_def_id.is_local(); - let path = if is_local { - String::new() - } else { - self.tcx - .crate_extern_paths(item_def_id.krate) - .iter() - .map(|p| p.display().to_string()) - .collect::<Vec<_>>() - .join(", ") - }; - let first_defined_span = self.tcx.hir().span_if_local(original_def_id); - let mut orig_crate_name = Empty; - let mut orig_dependency_of = Empty; - let orig_is_local = original_def_id.is_local(); - let orig_path = if orig_is_local { - String::new() - } else { - self.tcx - .crate_extern_paths(original_def_id.krate) - .iter() - .map(|p| p.display().to_string()) - .collect::<Vec<_>>() - .join(", ") - }; - if first_defined_span.is_none() { - orig_crate_name = self.tcx.crate_name(original_def_id.krate); - if let Some(ExternCrate { dependency_of: inner_dependency_of, .. }) = - self.tcx.extern_crate(original_def_id) - { - orig_dependency_of = self.tcx.crate_name(*inner_dependency_of); - } + if let Some(original_def_id) = self.items.get(lang_item) + && original_def_id != item_def_id + { + let lang_item_name = lang_item.name(); + let crate_name = self.tcx.crate_name(item_def_id.krate); + let mut dependency_of = Empty; + let is_local = item_def_id.is_local(); + let path = if is_local { + String::new() + } else { + self.tcx + .crate_extern_paths(item_def_id.krate) + .iter() + .map(|p| p.display().to_string()) + .collect::<Vec<_>>() + .join(", ") + }; + + let first_defined_span = self.item_spans.get(&original_def_id).copied(); + let mut orig_crate_name = Empty; + let mut orig_dependency_of = Empty; + let orig_is_local = original_def_id.is_local(); + let orig_path = if orig_is_local { + String::new() + } else { + self.tcx + .crate_extern_paths(original_def_id.krate) + .iter() + .map(|p| p.display().to_string()) + .collect::<Vec<_>>() + .join(", ") + }; + + if first_defined_span.is_none() { + orig_crate_name = self.tcx.crate_name(original_def_id.krate); + if let Some(ExternCrate { dependency_of: inner_dependency_of, .. }) = + self.tcx.extern_crate(original_def_id) + { + orig_dependency_of = self.tcx.crate_name(*inner_dependency_of); } + } - let duplicate = if local_span.is_some() { - Duplicate::Plain - } else { - match self.tcx.extern_crate(item_def_id) { - Some(ExternCrate { dependency_of: inner_dependency_of, .. }) => { - dependency_of = self.tcx.crate_name(*inner_dependency_of); - Duplicate::CrateDepends - } - _ => Duplicate::Crate, + let duplicate = if item_span.is_some() { + Duplicate::Plain + } else { + match self.tcx.extern_crate(item_def_id) { + Some(ExternCrate { dependency_of: inner_dependency_of, .. }) => { + dependency_of = self.tcx.crate_name(*inner_dependency_of); + Duplicate::CrateDepends } - }; - - self.tcx.sess.emit_err(DuplicateLangItem { - local_span, - lang_item_name, - crate_name, - dependency_of, - is_local, - path, - first_defined_span, - orig_crate_name, - orig_dependency_of, - orig_is_local, - orig_path, - duplicate, - }); + _ => Duplicate::Crate, + } + }; + + self.tcx.sess.emit_err(DuplicateLangItem { + local_span: item_span, + lang_item_name, + crate_name, + dependency_of, + is_local, + path, + first_defined_span, + orig_crate_name, + orig_dependency_of, + orig_is_local, + orig_path, + duplicate, + }); + } else { + // Matched. + self.items.set(lang_item, item_def_id); + // Collect span for error later + if let Some(item_span) = item_span { + self.item_spans.insert(item_def_id, item_span); } } - - // Matched. - self.items.set(lang_item, item_def_id); } // Like collect_item() above, but also checks whether the lang item is declared // with the right number of generic arguments. - fn collect_item_extended(&mut self, lang_item: LangItem, item_def_id: LocalDefId, span: Span) { + fn collect_item_extended( + &mut self, + lang_item: LangItem, + item_def_id: LocalDefId, + item_span: Span, + attr_span: Span, + generics: Option<&'ast ast::Generics>, + target: Target, + ) { let name = lang_item.name(); - // Now check whether the lang_item has the expected number of generic - // arguments. Generally speaking, binary and indexing operations have - // one (for the RHS/index), unary operations have none, the closure - // traits have one for the argument list, coroutines have one for the - // resume argument, and ordering/equality relations have one for the RHS - // Some other types like Box and various functions like drop_in_place - // have minimum requirements. + if let Some(generics) = generics { + // Now check whether the lang_item has the expected number of generic + // arguments. Generally speaking, binary and indexing operations have + // one (for the RHS/index), unary operations have none, the closure + // traits have one for the argument list, coroutines have one for the + // resume argument, and ordering/equality relations have one for the RHS + // Some other types like Box and various functions like drop_in_place + // have minimum requirements. - if let hir::Node::Item(hir::Item { kind, span: item_span, .. }) = - self.tcx.hir_node_by_def_id(item_def_id) - { - let (actual_num, generics_span) = match kind.generics() { - Some(generics) => ( - generics - .params - .iter() - .filter(|p| { - !matches!( - p.kind, - hir::GenericParamKind::Const { is_host_effect: true, .. } - ) - }) - .count(), - generics.span, - ), - None => (0, *item_span), - }; + // FIXME: This still doesn't count, e.g., elided lifetimes and APITs. + let mut actual_num = generics.params.len(); + if target.is_associated_item() { + actual_num += self + .parent_item + .unwrap() + .opt_generics() + .map_or(0, |generics| generics.params.len()); + } let mut at_least = false; let required = match lang_item.required_generics() { GenericRequirement::Exact(num) if num != actual_num => Some(num), GenericRequirement::Minimum(num) if actual_num < num => { at_least = true; - Some(num)} - , + Some(num) + } // If the number matches, or there is no requirement, handle it normally _ => None, }; @@ -190,10 +221,10 @@ impl<'tcx> LanguageItemCollector<'tcx> { // item kind of the target is correct, the target is still wrong // because of the wrong number of generic arguments. self.tcx.sess.emit_err(IncorrectTarget { - span, - generics_span, + span: attr_span, + generics_span: generics.span, name: name.as_str(), - kind: kind.descr(), + kind: target.name(), num, actual_num, at_least, @@ -204,58 +235,117 @@ impl<'tcx> LanguageItemCollector<'tcx> { } } - self.collect_item(lang_item, item_def_id.to_def_id()); + self.collect_item(lang_item, item_def_id.to_def_id(), Some(item_span)); } } /// Traverses and collects all the lang items in all crates. fn get_lang_items(tcx: TyCtxt<'_>, (): ()) -> LanguageItems { + let resolver = tcx.resolver_for_lowering(()).borrow(); + let (resolver, krate) = &*resolver; + // Initialize the collector. - let mut collector = LanguageItemCollector::new(tcx); + let mut collector = LanguageItemCollector::new(tcx, resolver); // Collect lang items in other crates. for &cnum in tcx.crates(()).iter() { for &(def_id, lang_item) in tcx.defined_lang_items(cnum).iter() { - collector.collect_item(lang_item, def_id); + collector.collect_item(lang_item, def_id, None); } } - // Collect lang items in this crate. - let crate_items = tcx.hir_crate_items(()); + // Collect lang items local to this crate. + visit::Visitor::visit_crate(&mut collector, krate); - for id in crate_items.items() { - collector - .check_for_lang(Target::from_def_kind(tcx.def_kind(id.owner_id)), id.owner_id.def_id); + // Find all required but not-yet-defined lang items. + weak_lang_items::check_crate(tcx, &mut collector.items, krate); - if matches!(tcx.def_kind(id.owner_id), DefKind::Enum) { - let item = tcx.hir().item(id); - if let hir::ItemKind::Enum(def, ..) = &item.kind { - for variant in def.variants { - collector.check_for_lang(Target::Variant, variant.def_id); - } - } - } - } + // Return all the lang items that were found. + collector.items +} + +impl<'ast, 'tcx> visit::Visitor<'ast> for LanguageItemCollector<'ast, 'tcx> { + fn visit_item(&mut self, i: &'ast ast::Item) { + let target = match &i.kind { + ast::ItemKind::ExternCrate(_) => Target::ExternCrate, + ast::ItemKind::Use(_) => Target::Use, + ast::ItemKind::Static(_) => Target::Static, + ast::ItemKind::Const(_) => Target::Const, + ast::ItemKind::Fn(_) => Target::Fn, + ast::ItemKind::Mod(_, _) => Target::Mod, + ast::ItemKind::ForeignMod(_) => Target::ForeignFn, + ast::ItemKind::GlobalAsm(_) => Target::GlobalAsm, + ast::ItemKind::TyAlias(_) => Target::TyAlias, + ast::ItemKind::Enum(_, _) => Target::Enum, + ast::ItemKind::Struct(_, _) => Target::Struct, + ast::ItemKind::Union(_, _) => Target::Union, + ast::ItemKind::Trait(_) => Target::Trait, + ast::ItemKind::TraitAlias(_, _) => Target::TraitAlias, + ast::ItemKind::Impl(_) => Target::Impl, + ast::ItemKind::MacroDef(_) => Target::MacroDef, + ast::ItemKind::MacCall(_) => unreachable!("macros should have been expanded"), + }; - // FIXME: avoid calling trait_item() when possible - for id in crate_items.trait_items() { - let item = tcx.hir().trait_item(id); - collector.check_for_lang(Target::from_trait_item(item), item.owner_id.def_id) + self.check_for_lang( + target, + self.resolver.node_id_to_def_id[&i.id], + &i.attrs, + i.span, + i.opt_generics(), + ); + + let parent_item = self.parent_item.replace(i); + visit::walk_item(self, i); + self.parent_item = parent_item; } - // FIXME: avoid calling impl_item() when possible - for id in crate_items.impl_items() { - let item = tcx.hir().impl_item(id); - collector.check_for_lang(target_from_impl_item(tcx, item), item.owner_id.def_id) + fn visit_enum_def(&mut self, enum_definition: &'ast ast::EnumDef) { + for variant in &enum_definition.variants { + self.check_for_lang( + Target::Variant, + self.resolver.node_id_to_def_id[&variant.id], + &variant.attrs, + variant.span, + None, + ); + } + + visit::walk_enum_def(self, enum_definition); } - // Extract out the found lang items. - let LanguageItemCollector { mut items, .. } = collector; + fn visit_assoc_item(&mut self, i: &'ast ast::AssocItem, ctxt: visit::AssocCtxt) { + let (target, generics) = match &i.kind { + ast::AssocItemKind::Fn(fun) => ( + match &self.parent_item.unwrap().kind { + ast::ItemKind::Impl(i) => { + if i.of_trait.is_some() { + Target::Method(MethodKind::Trait { body: fun.body.is_some() }) + } else { + Target::Method(MethodKind::Inherent) + } + } + ast::ItemKind::Trait(_) => { + Target::Method(MethodKind::Trait { body: fun.body.is_some() }) + } + _ => unreachable!(), + }, + &fun.generics, + ), + ast::AssocItemKind::Const(ct) => (Target::AssocConst, &ct.generics), + ast::AssocItemKind::Type(ty) => (Target::AssocTy, &ty.generics), + ast::AssocItemKind::MacCall(_) => unreachable!("macros should have been expanded"), + }; - // Find all required but not-yet-defined lang items. - weak_lang_items::check_crate(tcx, &mut items); + self.check_for_lang( + target, + self.resolver.node_id_to_def_id[&i.id], + &i.attrs, + i.span, + Some(generics), + ); - items + visit::walk_assoc_item(self, i, ctxt); + } } pub fn provide(providers: &mut Providers) { diff --git a/compiler/rustc_passes/src/weak_lang_items.rs b/compiler/rustc_passes/src/weak_lang_items.rs index 9a6fb88c281..b226c65e96c 100644 --- a/compiler/rustc_passes/src/weak_lang_items.rs +++ b/compiler/rustc_passes/src/weak_lang_items.rs @@ -1,5 +1,7 @@ //! Validity checking for weak lang items +use rustc_ast as ast; +use rustc_ast::visit; use rustc_data_structures::fx::FxHashSet; use rustc_hir::lang_items::{self, LangItem}; use rustc_hir::weak_lang_items::WEAK_LANG_ITEMS; @@ -11,7 +13,7 @@ use crate::errors::{MissingLangItem, MissingPanicHandler, UnknownExternLangItem} /// Checks the crate for usage of weak lang items, returning a vector of all the /// language items required by this crate, but not defined yet. -pub fn check_crate(tcx: TyCtxt<'_>, items: &mut lang_items::LanguageItems) { +pub fn check_crate(tcx: TyCtxt<'_>, items: &mut lang_items::LanguageItems, krate: &ast::Crate) { // These are never called by user code, they're generated by the compiler. // They will never implicitly be added to the `missing` array unless we do // so here. @@ -22,24 +24,30 @@ pub fn check_crate(tcx: TyCtxt<'_>, items: &mut lang_items::LanguageItems) { items.missing.push(LangItem::EhCatchTypeinfo); } - let crate_items = tcx.hir_crate_items(()); - for id in crate_items.foreign_items() { - let attrs = tcx.hir().attrs(id.hir_id()); - if let Some((lang_item, _)) = lang_items::extract(attrs) { + visit::Visitor::visit_crate(&mut WeakLangItemVisitor { tcx, items }, krate); + + verify(tcx, items); +} + +struct WeakLangItemVisitor<'a, 'tcx> { + tcx: TyCtxt<'tcx>, + items: &'a mut lang_items::LanguageItems, +} + +impl<'ast> visit::Visitor<'ast> for WeakLangItemVisitor<'_, '_> { + fn visit_foreign_item(&mut self, i: &'ast ast::ForeignItem) { + if let Some((lang_item, _)) = lang_items::extract(&i.attrs) { if let Some(item) = LangItem::from_name(lang_item) && item.is_weak() { - if items.get(item).is_none() { - items.missing.push(item); + if self.items.get(item).is_none() { + self.items.missing.push(item); } } else { - let span = tcx.def_span(id.owner_id); - tcx.sess.emit_err(UnknownExternLangItem { span, lang_item }); + self.tcx.sess.emit_err(UnknownExternLangItem { span: i.span, lang_item }); } } } - - verify(tcx, items); } fn verify(tcx: TyCtxt<'_>, items: &lang_items::LanguageItems) { diff --git a/compiler/rustc_pattern_analysis/src/constructor.rs b/compiler/rustc_pattern_analysis/src/constructor.rs index 3bca7894a29..6486ad8b483 100644 --- a/compiler/rustc_pattern_analysis/src/constructor.rs +++ b/compiler/rustc_pattern_analysis/src/constructor.rs @@ -923,7 +923,7 @@ impl ConstructorSet { } ConstructorSet::Integers { range_1, range_2 } => { let seen_ranges: Vec<_> = - seen.iter().map(|ctor| ctor.as_int_range().unwrap().clone()).collect(); + seen.iter().map(|ctor| *ctor.as_int_range().unwrap()).collect(); for (seen, splitted_range) in range_1.split(seen_ranges.iter().cloned()) { match seen { Presence::Unseen => missing.push(IntRange(splitted_range)), diff --git a/compiler/rustc_resolve/src/rustdoc.rs b/compiler/rustc_resolve/src/rustdoc.rs index f95c0acd750..4ff4ccf5e98 100644 --- a/compiler/rustc_resolve/src/rustdoc.rs +++ b/compiler/rustc_resolve/src/rustdoc.rs @@ -407,8 +407,7 @@ fn parse_links<'md>(doc: &'md str) -> Vec<Box<str>> { doc, main_body_opts(), Some(&mut broken_link_callback), - ) - .into_iter(); + ); let mut links = Vec::new(); while let Some(event) = event_iter.next() { diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index d46a309df55..20d18fa4b83 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -1579,7 +1579,7 @@ impl CheckCfg { pub fn build_configuration(sess: &Session, mut user_cfg: Cfg) -> Cfg { // Combine the configuration requested by the session (command line) with // some default and generated configuration items. - user_cfg.extend(default_configuration(sess).into_iter()); + user_cfg.extend(default_configuration(sess)); user_cfg } diff --git a/compiler/rustc_smir/src/rustc_smir/context.rs b/compiler/rustc_smir/src/rustc_smir/context.rs index 70313cc021e..3a8289f38bd 100644 --- a/compiler/rustc_smir/src/rustc_smir/context.rs +++ b/compiler/rustc_smir/src/rustc_smir/context.rs @@ -158,7 +158,6 @@ impl<'tcx> Context for TablesWrapper<'tcx> { let crate_name = tables.tcx.crate_name(*crate_num).to_string(); (name == crate_name).then(|| smir_crate(tables.tcx, *crate_num)) }) - .into_iter() .flatten() .collect(); crates diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index 818d1436659..533fe32f70d 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -273,7 +273,6 @@ fn overlap<'tcx>( causing the impls to overlap", infcx.resolve_vars_if_possible(failing_obligation.predicate) )); - lint }, ); } diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 9073cd6ac47..a1b896d2251 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -4665,7 +4665,7 @@ pub trait NextTypeParamName { impl NextTypeParamName for &[hir::GenericParam<'_>] { fn next_type_param_name(&self, name: Option<&str>) -> String { // This is the list of possible parameter names that we might suggest. - let name = name.and_then(|n| n.chars().next()).map(|c| c.to_string().to_uppercase()); + let name = name.and_then(|n| n.chars().next()).map(|c| c.to_uppercase().to_string()); let name = name.as_deref(); let possible_names = [name.unwrap_or("T"), "T", "U", "V", "X", "Y", "Z", "A", "B", "C"]; let used_names = self @@ -4783,8 +4783,14 @@ pub fn suggest_desugaring_async_fn_to_impl_future_in_trait<'tcx>( }; let future = tcx.hir_node_by_def_id(opaque_def_id).expect_item().expect_opaque_ty(); - let Some(hir::GenericBound::LangItemTrait(_, _, _, generics)) = future.bounds.get(0) else { - // `async fn` should always lower to a lang item bound... but don't ICE. + let [hir::GenericBound::Trait(trait_ref, _)] = future.bounds else { + // `async fn` should always lower to a single bound... but don't ICE. + return None; + }; + let Some(hir::PathSegment { args: Some(generics), .. }) = + trait_ref.trait_ref.path.segments.last() + else { + // desugaring to a single path segment for `Future<...>`. return None; }; let Some(hir::TypeBindingKind::Equality { term: hir::Term::Ty(future_output_ty) }) = diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs index fbde7455145..47a79bfa9ab 100644 --- a/compiler/rustc_trait_selection/src/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -194,7 +194,6 @@ fn lint_object_unsafe_trait( // Only provide the help if its a local trait, otherwise it's not violation.solution().add_to(err); } - err }, ); } @@ -345,7 +344,7 @@ fn generics_require_sized_self(tcx: TyCtxt<'_>, def_id: DefId) -> bool { // Search for a predicate like `Self : Sized` amongst the trait bounds. let predicates = tcx.predicates_of(def_id); let predicates = predicates.instantiate_identity(tcx).predicates; - elaborate(tcx, predicates.into_iter()).any(|pred| match pred.kind().skip_binder() { + elaborate(tcx, predicates).any(|pred| match pred.kind().skip_binder() { ty::ClauseKind::Trait(ref trait_pred) => { trait_pred.def_id() == sized_def_id && trait_pred.self_ty().is_param(0) } diff --git a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs index 39f5ff52eba..71a88f5f07c 100644 --- a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs @@ -450,7 +450,6 @@ fn report_conflicting_impls<'tcx>( msg, |err| { decorate(tcx, &overlap, impl_span, err); - err }, ); } diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs index 98da3bc2fe9..575010ff46d 100644 --- a/compiler/rustc_trait_selection/src/traits/util.rs +++ b/compiler/rustc_trait_selection/src/traits/util.rs @@ -220,9 +220,8 @@ pub fn impl_subject_and_oblig<'a, 'tcx>( selcx.infcx.at(&ObligationCause::dummy(), param_env).normalize(predicates); let impl_obligations = super::predicates_for_generics(cause, param_env, predicates); - let impl_obligations = impl_obligations - .chain(normalization_obligations1.into_iter()) - .chain(normalization_obligations2.into_iter()); + let impl_obligations = + impl_obligations.chain(normalization_obligations1).chain(normalization_obligations2); (subject, impl_obligations) } diff --git a/library/alloc/src/ffi/c_str.rs b/library/alloc/src/ffi/c_str.rs index 62856fc9a49..4a4a3abd47f 100644 --- a/library/alloc/src/ffi/c_str.rs +++ b/library/alloc/src/ffi/c_str.rs @@ -421,7 +421,7 @@ impl CString { /// Failure to call [`CString::from_raw`] will lead to a memory leak. /// /// The C side must **not** modify the length of the string (by writing a - /// `null` somewhere inside the string or removing the final one) before + /// nul byte somewhere inside the string or removing the final one) before /// it makes it back into Rust using [`CString::from_raw`]. See the safety section /// in [`CString::from_raw`]. /// @@ -797,7 +797,7 @@ impl From<Box<CStr>> for CString { #[stable(feature = "cstring_from_vec_of_nonzerou8", since = "1.43.0")] impl From<Vec<NonZeroU8>> for CString { /// Converts a <code>[Vec]<[NonZeroU8]></code> into a [`CString`] without - /// copying nor checking for inner null bytes. + /// copying nor checking for inner nul bytes. #[inline] fn from(v: Vec<NonZeroU8>) -> CString { unsafe { @@ -809,7 +809,7 @@ impl From<Vec<NonZeroU8>> for CString { let (ptr, len, cap): (*mut NonZeroU8, _, _) = Vec::into_raw_parts(v); Vec::from_raw_parts(ptr.cast::<u8>(), len, cap) }; - // SAFETY: `v` cannot contain null bytes, given the type-level + // SAFETY: `v` cannot contain nul bytes, given the type-level // invariant of `NonZeroU8`. Self::_from_vec_unchecked(v) } diff --git a/library/core/src/any.rs b/library/core/src/any.rs index 22777fb078a..c82984d5c6b 100644 --- a/library/core/src/any.rs +++ b/library/core/src/any.rs @@ -695,44 +695,41 @@ pub const fn type_name<T: ?Sized>() -> &'static str { intrinsics::type_name::<T>() } -/// Returns the name of the type of the pointed-to value as a string slice. +/// Returns the type name of the pointed-to value as a string slice. +/// /// This is the same as `type_name::<T>()`, but can be used where the type of a /// variable is not easily available. /// /// # Note /// -/// This is intended for diagnostic use. The exact contents and format of the -/// string are not specified, other than being a best-effort description of the -/// type. For example, `type_name_of_val::<Option<String>>(None)` could return -/// `"Option<String>"` or `"std::option::Option<std::string::String>"`, but not -/// `"foobar"`. In addition, the output may change between versions of the -/// compiler. -/// -/// This function does not resolve trait objects, -/// meaning that `type_name_of_val(&7u32 as &dyn Debug)` -/// may return `"dyn Debug"`, but not `"u32"`. +/// Like [`type_name`], this is intended for diagnostic use and the exact output is not +/// guaranteed. It provides a best-effort description, but the output may change between +/// versions of the compiler. /// -/// The type name should not be considered a unique identifier of a type; -/// multiple types may share the same type name. +/// In short: use this for debugging, avoid using the output to affect program behavior. More +/// information is available at [`type_name`]. /// -/// The current implementation uses the same infrastructure as compiler -/// diagnostics and debuginfo, but this is not guaranteed. +/// Additionally, this function does not resolve trait objects. This means that +/// `type_name_of_val(&7u32 as &dyn Debug)` may return `"dyn Debug"`, but will not return `"u32"` +/// at this time. /// /// # Examples /// /// Prints the default integer and float types. /// /// ```rust -/// #![feature(type_name_of_val)] /// use std::any::type_name_of_val; /// -/// let x = 1; -/// println!("{}", type_name_of_val(&x)); -/// let y = 1.0; -/// println!("{}", type_name_of_val(&y)); +/// let s = "foo"; +/// let x: i32 = 1; +/// let y: f32 = 1.0; +/// +/// assert!(type_name_of_val(&s).contains("str")); +/// assert!(type_name_of_val(&x).contains("i32")); +/// assert!(type_name_of_val(&y).contains("f32")); /// ``` #[must_use] -#[unstable(feature = "type_name_of_val", issue = "66359")] +#[stable(feature = "type_name_of_val", since = "CURRENT_RUSTC_VERSION")] #[rustc_const_unstable(feature = "const_type_name", issue = "63084")] pub const fn type_name_of_val<T: ?Sized>(_val: &T) -> &'static str { type_name::<T>() diff --git a/library/core/src/ffi/c_str.rs b/library/core/src/ffi/c_str.rs index e7ec1fb73cd..bb839a71e90 100644 --- a/library/core/src/ffi/c_str.rs +++ b/library/core/src/ffi/c_str.rs @@ -205,7 +205,7 @@ impl CStr { /// * The memory pointed to by `ptr` must contain a valid nul terminator at the /// end of the string. /// - /// * `ptr` must be [valid] for reads of bytes up to and including the null terminator. + /// * `ptr` must be [valid] for reads of bytes up to and including the nul terminator. /// This means in particular: /// /// * The entire memory range of this `CStr` must be contained within a single allocated object! @@ -415,7 +415,7 @@ impl CStr { let mut i = bytes.len().saturating_sub(1); assert!(!bytes.is_empty() && bytes[i] == 0, "input was not nul-terminated"); - // Ending null byte exists, skip to the rest. + // Ending nul byte exists, skip to the rest. while i != 0 { i -= 1; let byte = bytes[i]; diff --git a/library/core/src/net/ip_addr.rs b/library/core/src/net/ip_addr.rs index dafc58d3a7d..8bf15c736c3 100644 --- a/library/core/src/net/ip_addr.rs +++ b/library/core/src/net/ip_addr.rs @@ -1437,7 +1437,7 @@ impl Ipv6Addr { /// - The [unspecified address] ([`is_unspecified`](Ipv6Addr::is_unspecified)) /// - The [loopback address] ([`is_loopback`](Ipv6Addr::is_loopback)) /// - IPv4-mapped addresses - /// - Addresses reserved for benchmarking + /// - Addresses reserved for benchmarking ([`is_benchmarking`](Ipv6Addr::is_benchmarking)) /// - Addresses reserved for documentation ([`is_documentation`](Ipv6Addr::is_documentation)) /// - Unique local addresses ([`is_unique_local`](Ipv6Addr::is_unique_local)) /// - Unicast addresses with link-local scope ([`is_unicast_link_local`](Ipv6Addr::is_unicast_link_local)) diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs index d6603681a0b..eed793186b9 100644 --- a/library/core/src/ptr/mod.rs +++ b/library/core/src/ptr/mod.rs @@ -720,7 +720,8 @@ where /// type or mutability, in particular if the code is refactored. #[inline(always)] #[must_use] -#[unstable(feature = "ptr_from_ref", issue = "106116")] +#[stable(feature = "ptr_from_ref", since = "CURRENT_RUSTC_VERSION")] +#[rustc_const_stable(feature = "ptr_from_ref", since = "CURRENT_RUSTC_VERSION")] #[rustc_never_returns_null_ptr] #[rustc_diagnostic_item = "ptr_from_ref"] pub const fn from_ref<T: ?Sized>(r: &T) -> *const T { @@ -733,7 +734,9 @@ pub const fn from_ref<T: ?Sized>(r: &T) -> *const T { /// type or mutability, in particular if the code is refactored. #[inline(always)] #[must_use] -#[unstable(feature = "ptr_from_ref", issue = "106116")] +#[stable(feature = "ptr_from_ref", since = "CURRENT_RUSTC_VERSION")] +#[rustc_const_stable(feature = "ptr_from_ref", since = "CURRENT_RUSTC_VERSION")] +#[rustc_allow_const_fn_unstable(const_mut_refs)] #[rustc_never_returns_null_ptr] pub const fn from_mut<T: ?Sized>(r: &mut T) -> *mut T { r diff --git a/library/core/src/slice/ascii.rs b/library/core/src/slice/ascii.rs index 4cfccd2e3ce..ce04a9f4089 100644 --- a/library/core/src/slice/ascii.rs +++ b/library/core/src/slice/ascii.rs @@ -125,6 +125,7 @@ impl [u8] { /// assert_eq!(b"".trim_ascii_start(), b""); /// ``` #[unstable(feature = "byte_slice_trim_ascii", issue = "94035")] + #[inline] pub const fn trim_ascii_start(&self) -> &[u8] { let mut bytes = self; // Note: A pattern matching based approach (instead of indexing) allows @@ -154,6 +155,7 @@ impl [u8] { /// assert_eq!(b"".trim_ascii_end(), b""); /// ``` #[unstable(feature = "byte_slice_trim_ascii", issue = "94035")] + #[inline] pub const fn trim_ascii_end(&self) -> &[u8] { let mut bytes = self; // Note: A pattern matching based approach (instead of indexing) allows @@ -184,6 +186,7 @@ impl [u8] { /// assert_eq!(b"".trim_ascii(), b""); /// ``` #[unstable(feature = "byte_slice_trim_ascii", issue = "94035")] + #[inline] pub const fn trim_ascii(&self) -> &[u8] { self.trim_ascii_start().trim_ascii_end() } diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs index 27178328be5..a22c46edce2 100644 --- a/library/core/src/str/mod.rs +++ b/library/core/src/str/mod.rs @@ -2423,6 +2423,85 @@ impl str { me.make_ascii_lowercase() } + /// Returns a string slice with leading ASCII whitespace removed. + /// + /// 'Whitespace' refers to the definition used by + /// [`u8::is_ascii_whitespace`]. + /// + /// [`u8::is_ascii_whitespace`]: u8::is_ascii_whitespace + /// + /// # Examples + /// + /// ``` + /// #![feature(byte_slice_trim_ascii)] + /// + /// assert_eq!(" \t \u{3000}hello world\n".trim_ascii_start(), "\u{3000}hello world\n"); + /// assert_eq!(" ".trim_ascii_start(), ""); + /// assert_eq!("".trim_ascii_start(), ""); + /// ``` + #[unstable(feature = "byte_slice_trim_ascii", issue = "94035")] + #[must_use = "this returns the trimmed string as a new slice, \ + without modifying the original"] + #[inline] + pub const fn trim_ascii_start(&self) -> &str { + // SAFETY: Removing ASCII characters from a `&str` does not invalidate + // UTF-8. + unsafe { core::str::from_utf8_unchecked(self.as_bytes().trim_ascii_start()) } + } + + /// Returns a string slice with trailing ASCII whitespace removed. + /// + /// 'Whitespace' refers to the definition used by + /// [`u8::is_ascii_whitespace`]. + /// + /// [`u8::is_ascii_whitespace`]: u8::is_ascii_whitespace + /// + /// # Examples + /// + /// ``` + /// #![feature(byte_slice_trim_ascii)] + /// + /// assert_eq!("\r hello world\u{3000}\n ".trim_ascii_end(), "\r hello world\u{3000}"); + /// assert_eq!(" ".trim_ascii_end(), ""); + /// assert_eq!("".trim_ascii_end(), ""); + /// ``` + #[unstable(feature = "byte_slice_trim_ascii", issue = "94035")] + #[must_use = "this returns the trimmed string as a new slice, \ + without modifying the original"] + #[inline] + pub const fn trim_ascii_end(&self) -> &str { + // SAFETY: Removing ASCII characters from a `&str` does not invalidate + // UTF-8. + unsafe { core::str::from_utf8_unchecked(self.as_bytes().trim_ascii_end()) } + } + + /// Returns a string slice with leading and trailing ASCII whitespace + /// removed. + /// + /// 'Whitespace' refers to the definition used by + /// [`u8::is_ascii_whitespace`]. + /// + /// [`u8::is_ascii_whitespace`]: u8::is_ascii_whitespace + /// + /// # Examples + /// + /// ``` + /// #![feature(byte_slice_trim_ascii)] + /// + /// assert_eq!("\r hello world\n ".trim_ascii(), "hello world"); + /// assert_eq!(" ".trim_ascii(), ""); + /// assert_eq!("".trim_ascii(), ""); + /// ``` + #[unstable(feature = "byte_slice_trim_ascii", issue = "94035")] + #[must_use = "this returns the trimmed string as a new slice, \ + without modifying the original"] + #[inline] + pub const fn trim_ascii(&self) -> &str { + // SAFETY: Removing ASCII characters from a `&str` does not invalidate + // UTF-8. + unsafe { core::str::from_utf8_unchecked(self.as_bytes().trim_ascii()) } + } + /// Return an iterator that escapes each char in `self` with [`char::escape_debug`]. /// /// Note: only extended grapheme codepoints that begin the string will be diff --git a/library/proc_macro/src/bridge/mod.rs b/library/proc_macro/src/bridge/mod.rs index 86ce5d9c6d5..75bf3329786 100644 --- a/library/proc_macro/src/bridge/mod.rs +++ b/library/proc_macro/src/bridge/mod.rs @@ -55,6 +55,7 @@ macro_rules! with_api { $m! { FreeFunctions { fn drop($self: $S::FreeFunctions); + fn injected_env_var(var: &str) -> Option<String>; fn track_env_var(var: &str, value: Option<&str>); fn track_path(path: &str); fn literal_from_str(s: &str) -> Result<Literal<$S::Span, $S::Symbol>, ()>; diff --git a/library/proc_macro/src/lib.rs b/library/proc_macro/src/lib.rs index 7ebb6810b3e..6e664a162df 100644 --- a/library/proc_macro/src/lib.rs +++ b/library/proc_macro/src/lib.rs @@ -1503,7 +1503,8 @@ pub mod tracked_env { #[unstable(feature = "proc_macro_tracked_env", issue = "99515")] pub fn var<K: AsRef<OsStr> + AsRef<str>>(key: K) -> Result<String, VarError> { let key: &str = key.as_ref(); - let value = env::var(key); + let value = crate::bridge::client::FreeFunctions::injected_env_var(key) + .map_or_else(|| env::var(key), Ok); crate::bridge::client::FreeFunctions::track_env_var(key, value.as_deref().ok()); value } diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index f666b18887c..fe66788b564 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -30,8 +30,13 @@ rustc-demangle = { version = "0.1.21", features = ['rustc-dep-of-std'] } [target.'cfg(not(all(windows, target_env = "msvc", not(target_vendor = "uwp"))))'.dependencies] miniz_oxide = { version = "0.7.0", optional = true, default-features = false } addr2line = { version = "0.21.0", optional = true, default-features = false } + +[target.'cfg(all(not(target_os = "aix"), not(all(windows, target_env = "msvc", not(target_vendor = "uwp")))))'.dependencies] object = { version = "0.32.0", default-features = false, optional = true, features = ['read_core', 'elf', 'macho', 'pe', 'unaligned', 'archive'] } +[target.'cfg(target_os = "aix")'.dependencies] +object = { version = "0.32.0", default-features = false, optional = true, features = ['read_core', 'xcoff', 'unaligned', 'archive'] } + [dev-dependencies] rand = { version = "0.8.5", default-features = false, features = ["alloc"] } rand_xorshift = "0.3.0" diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index d08f0b1c9d0..76081833e05 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -338,7 +338,6 @@ #![feature(portable_simd)] #![feature(prelude_2024)] #![feature(ptr_as_uninit)] -#![feature(ptr_from_ref)] #![feature(raw_os_nonzero)] #![feature(round_ties_even)] #![feature(slice_internals)] diff --git a/library/std/src/panicking.rs b/library/std/src/panicking.rs index 55f4917a937..66b4ec37c8e 100644 --- a/library/std/src/panicking.rs +++ b/library/std/src/panicking.rs @@ -588,7 +588,7 @@ pub fn panicking() -> bool { } /// Entry point of panics from the core crate (`panic_impl` lang item). -#[cfg(not(test))] +#[cfg(not(any(test, doctest)))] #[panic_handler] pub fn begin_panic_handler(info: &PanicInfo<'_>) -> ! { struct FormatStringPayload<'a> { @@ -669,7 +669,7 @@ pub fn begin_panic_handler(info: &PanicInfo<'_>) -> ! { /// panic!() and assert!(). In particular, this is the only entry point that supports /// arbitrary payloads, not just format strings. #[unstable(feature = "libstd_sys_internals", reason = "used by the panic! macro", issue = "none")] -#[cfg_attr(not(test), lang = "begin_panic")] +#[cfg_attr(not(any(test, doctest)), lang = "begin_panic")] // lang item for CTFE panic support // never inline unless panic_immediate_abort to avoid code // bloat at the call sites as much as possible diff --git a/library/std/src/process.rs b/library/std/src/process.rs index 6004ed51bd1..4a7f5d8e0be 100644 --- a/library/std/src/process.rs +++ b/library/std/src/process.rs @@ -2311,7 +2311,7 @@ pub fn id() -> u32 { /// of the `main` function, this trait is likely to be available only on /// standard library's runtime for convenience. Other runtimes are not required /// to provide similar functionality. -#[cfg_attr(not(test), lang = "termination")] +#[cfg_attr(not(any(test, doctest)), lang = "termination")] #[stable(feature = "termination_trait_lib", since = "1.61.0")] #[rustc_on_unimplemented(on( cause = "MainFunctionType", diff --git a/library/std/src/rt.rs b/library/std/src/rt.rs index f1eeb75be7c..335944845ae 100644 --- a/library/std/src/rt.rs +++ b/library/std/src/rt.rs @@ -154,7 +154,7 @@ fn lang_start_internal( ret_code } -#[cfg(not(test))] +#[cfg(not(any(test, doctest)))] #[lang = "start"] fn lang_start<T: crate::process::Termination + 'static>( main: fn() -> T, diff --git a/library/std/src/sys/personality/mod.rs b/library/std/src/sys/personality/mod.rs index 0fff53f1887..d37b8ce6346 100644 --- a/library/std/src/sys/personality/mod.rs +++ b/library/std/src/sys/personality/mod.rs @@ -12,7 +12,7 @@ mod dwarf; -#[cfg(not(test))] +#[cfg(not(any(test, doctest)))] cfg_if::cfg_if! { if #[cfg(target_os = "emscripten")] { mod emcc; diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index 2328dd822af..fea194a80ef 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -616,22 +616,6 @@ class RustBuild(object): with output(self.rustc_stamp()) as rust_stamp: rust_stamp.write(key) - def _download_component_helper( - self, filename, pattern, tarball_suffix, rustc_cache, - ): - key = self.stage0_compiler.date - - tarball = os.path.join(rustc_cache, filename) - if not os.path.exists(tarball): - get( - self.download_url, - "dist/{}/{}".format(key, filename), - tarball, - self.checksums_sha256, - verbose=self.verbose, - ) - unpack(tarball, tarball_suffix, self.bin_root(), match=pattern, verbose=self.verbose) - def should_fix_bins_and_dylibs(self): """Whether or not `fix_bin_or_dylib` needs to be run; can only be True on NixOS or if config.toml has `build.patch-binaries-for-nix` set. diff --git a/src/bootstrap/src/bin/rustc.rs b/src/bootstrap/src/bin/rustc.rs index 18136635c42..38c55b20344 100644 --- a/src/bootstrap/src/bin/rustc.rs +++ b/src/bootstrap/src/bin/rustc.rs @@ -16,11 +16,11 @@ //! never get replaced. use std::env; -use std::path::PathBuf; +use std::path::{Path, PathBuf}; use std::process::{Child, Command}; use std::time::Instant; -use dylib_util::{dylib_path, dylib_path_var}; +use dylib_util::{dylib_path, dylib_path_var, exe}; #[path = "../utils/bin_helpers.rs"] mod bin_helpers; @@ -29,8 +29,10 @@ mod bin_helpers; mod dylib_util; fn main() { - let args = env::args_os().skip(1).collect::<Vec<_>>(); - let arg = |name| args.windows(2).find(|args| args[0] == name).and_then(|args| args[1].to_str()); + let orig_args = env::args_os().skip(1).collect::<Vec<_>>(); + let mut args = orig_args.clone(); + let arg = + |name| orig_args.windows(2).find(|args| args[0] == name).and_then(|args| args[1].to_str()); let stage = bin_helpers::parse_rustc_stage(); let verbose = bin_helpers::parse_rustc_verbose(); @@ -45,7 +47,8 @@ fn main() { // determine the version of the compiler, the real compiler needs to be // used. Currently, these two states are differentiated based on whether // --target and -vV is/isn't passed. - let (rustc, libdir) = if target.is_none() && version.is_none() { + let is_build_script = target.is_none() && version.is_none(); + let (rustc, libdir) = if is_build_script { ("RUSTC_SNAPSHOT", "RUSTC_SNAPSHOT_LIBDIR") } else { ("RUSTC_REAL", "RUSTC_LIBDIR") @@ -54,12 +57,47 @@ fn main() { let sysroot = env::var_os("RUSTC_SYSROOT").expect("RUSTC_SYSROOT was not set"); let on_fail = env::var_os("RUSTC_ON_FAIL").map(Command::new); - let rustc = env::var_os(rustc).unwrap_or_else(|| panic!("{:?} was not set", rustc)); + let rustc_real = env::var_os(rustc).unwrap_or_else(|| panic!("{:?} was not set", rustc)); let libdir = env::var_os(libdir).unwrap_or_else(|| panic!("{:?} was not set", libdir)); let mut dylib_path = dylib_path(); dylib_path.insert(0, PathBuf::from(&libdir)); - let mut cmd = Command::new(rustc); + // if we're running clippy, trust cargo-clippy to set clippy-driver appropriately (and don't override it with rustc). + // otherwise, substitute whatever cargo thinks rustc should be with RUSTC_REAL. + // NOTE: this means we ignore RUSTC in the environment. + // FIXME: We might want to consider removing RUSTC_REAL and setting RUSTC directly? + // NOTE: we intentionally pass the name of the host, not the target. + let host = env::var("CFG_COMPILER_BUILD_TRIPLE").unwrap(); + let is_clippy = args[0].to_string_lossy().ends_with(&exe("clippy-driver", &host)); + let rustc_driver = if is_clippy { + if is_build_script { + // Don't run clippy on build scripts (for one thing, we may not have libstd built with + // the appropriate version yet, e.g. for stage 1 std). + // Also remove the `clippy-driver` param in addition to the RUSTC param. + args.drain(..2); + rustc_real + } else { + args.remove(0) + } + } else { + // Cargo doesn't respect RUSTC_WRAPPER for version information >:( + // don't remove the first arg if we're being run as RUSTC instead of RUSTC_WRAPPER. + // Cargo also sometimes doesn't pass the `.exe` suffix on Windows - add it manually. + let current_exe = env::current_exe().expect("couldn't get path to rustc shim"); + let arg0 = exe(args[0].to_str().expect("only utf8 paths are supported"), &host); + if Path::new(&arg0) == current_exe { + args.remove(0); + } + rustc_real + }; + + let mut cmd = if let Some(wrapper) = env::var_os("RUSTC_WRAPPER_REAL") { + let mut cmd = Command::new(wrapper); + cmd.arg(rustc_driver); + cmd + } else { + Command::new(rustc_driver) + }; cmd.args(&args).env(dylib_path_var(), env::join_paths(&dylib_path).unwrap()); // Get the name of the crate we're compiling, if any. diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index 11e789a996a..df4d1a43dab 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -1809,10 +1809,6 @@ pub fn run_cargo( is_check: bool, rlib_only_metadata: bool, ) -> Vec<PathBuf> { - if builder.config.dry_run() { - return Vec::new(); - } - // `target_root_dir` looks like $dir/$target/release let target_root_dir = stamp.parent().unwrap(); // `target_deps_dir` looks like $dir/$target/release/deps @@ -1919,6 +1915,10 @@ pub fn run_cargo( crate::exit!(1); } + if builder.config.dry_run() { + return Vec::new(); + } + // Ok now we need to actually find all the files listed in `toplevel`. We've // got a list of prefix/extensions and we basically just need to find the // most recent file in the `deps` folder corresponding to each one. @@ -1974,9 +1974,6 @@ pub fn stream_cargo( cb: &mut dyn FnMut(CargoMessage<'_>), ) -> bool { let mut cargo = Command::from(cargo); - if builder.config.dry_run() { - return true; - } // Instruct Cargo to give us json messages on stdout, critically leaving // stderr as piped so we can get those pretty colors. let mut message_format = if builder.config.json_output { @@ -1995,6 +1992,11 @@ pub fn stream_cargo( } builder.verbose(&format!("running: {cargo:?}")); + + if builder.config.dry_run() { + return true; + } + let mut child = match cargo.spawn() { Ok(child) => child, Err(e) => panic!("failed to execute command: {cargo:?}\nERROR: {e}"), diff --git a/src/bootstrap/src/core/builder.rs b/src/bootstrap/src/core/builder.rs index 28761a7ee4b..e1809644350 100644 --- a/src/bootstrap/src/core/builder.rs +++ b/src/bootstrap/src/core/builder.rs @@ -1152,6 +1152,44 @@ impl<'a> Builder<'a> { self.ensure(tool::Rustdoc { compiler }) } + pub fn cargo_clippy_cmd(&self, run_compiler: Compiler) -> Command { + let initial_sysroot_bin = self.initial_rustc.parent().unwrap(); + // Set PATH to include the sysroot bin dir so clippy can find cargo. + // FIXME: once rust-clippy#11944 lands on beta, set `CARGO` directly instead. + let path = t!(env::join_paths( + // The sysroot comes first in PATH to avoid using rustup's cargo. + std::iter::once(PathBuf::from(initial_sysroot_bin)) + .chain(env::split_paths(&t!(env::var("PATH")))) + )); + + if run_compiler.stage == 0 { + // `ensure(Clippy { stage: 0 })` *builds* clippy with stage0, it doesn't use the beta clippy. + let cargo_clippy = self.build.config.download_clippy(); + let mut cmd = Command::new(cargo_clippy); + cmd.env("PATH", &path); + return cmd; + } + + let build_compiler = self.compiler(run_compiler.stage - 1, self.build.build); + self.ensure(tool::Clippy { + compiler: build_compiler, + target: self.build.build, + extra_features: vec![], + }); + let cargo_clippy = self.ensure(tool::CargoClippy { + compiler: build_compiler, + target: self.build.build, + extra_features: vec![], + }); + let mut dylib_path = helpers::dylib_path(); + dylib_path.insert(0, self.sysroot(run_compiler).join("lib")); + + let mut cmd = Command::new(cargo_clippy.unwrap()); + cmd.env(helpers::dylib_path_var(), env::join_paths(&dylib_path).unwrap()); + cmd.env("PATH", path); + cmd + } + pub fn rustdoc_cmd(&self, compiler: Compiler) -> Command { let mut cmd = Command::new(&self.bootstrap_out.join("rustdoc")); cmd.env("RUSTC_STAGE", compiler.stage.to_string()) @@ -1200,7 +1238,12 @@ impl<'a> Builder<'a> { target: TargetSelection, cmd: &str, ) -> Command { - let mut cargo = Command::new(&self.initial_cargo); + let mut cargo = if cmd == "clippy" { + self.cargo_clippy_cmd(compiler) + } else { + Command::new(&self.initial_cargo) + }; + // Run cargo from the source root so it can find .cargo/config. // This matters when using vendoring and the working directory is outside the repository. cargo.current_dir(&self.src); @@ -1324,6 +1367,23 @@ impl<'a> Builder<'a> { compiler.stage }; + // We synthetically interpret a stage0 compiler used to build tools as a + // "raw" compiler in that it's the exact snapshot we download. Normally + // the stage0 build means it uses libraries build by the stage0 + // compiler, but for tools we just use the precompiled libraries that + // we've downloaded + let use_snapshot = mode == Mode::ToolBootstrap; + assert!(!use_snapshot || stage == 0 || self.local_rebuild); + + let maybe_sysroot = self.sysroot(compiler); + let sysroot = if use_snapshot { self.rustc_snapshot_sysroot() } else { &maybe_sysroot }; + let libdir = self.rustc_libdir(compiler); + + let sysroot_str = sysroot.as_os_str().to_str().expect("sysroot should be UTF-8"); + if !matches!(self.config.dry_run, DryRun::SelfCheck) { + self.verbose_than(0, &format!("using sysroot {sysroot_str}")); + } + let mut rustflags = Rustflags::new(target); if stage != 0 { if let Ok(s) = env::var("CARGOFLAGS_NOT_BOOTSTRAP") { @@ -1335,41 +1395,16 @@ impl<'a> Builder<'a> { cargo.args(s.split_whitespace()); } rustflags.env("RUSTFLAGS_BOOTSTRAP"); - if cmd == "clippy" { - // clippy overwrites sysroot if we pass it to cargo. - // Pass it directly to clippy instead. - // NOTE: this can't be fixed in clippy because we explicitly don't set `RUSTC`, - // so it has no way of knowing the sysroot. - rustflags.arg("--sysroot"); - rustflags.arg( - self.sysroot(compiler) - .as_os_str() - .to_str() - .expect("sysroot must be valid UTF-8"), - ); - // Only run clippy on a very limited subset of crates (in particular, not build scripts). - cargo.arg("-Zunstable-options"); - // Explicitly does *not* set `--cfg=bootstrap`, since we're using a nightly clippy. - let host_version = Command::new("rustc").arg("--version").output().map_err(|_| ()); - let output = host_version.and_then(|output| { - if output.status.success() { - Ok(output) - } else { - Err(()) - } - }).unwrap_or_else(|_| { - eprintln!( - "ERROR: `x.py clippy` requires a host `rustc` toolchain with the `clippy` component" - ); - eprintln!("HELP: try `rustup component add clippy`"); - crate::exit!(1); - }); - if !t!(std::str::from_utf8(&output.stdout)).contains("nightly") { - rustflags.arg("--cfg=bootstrap"); - } - } else { - rustflags.arg("--cfg=bootstrap"); - } + rustflags.arg("--cfg=bootstrap"); + } + + if cmd == "clippy" { + // clippy overwrites sysroot if we pass it to cargo. + // Pass it directly to clippy instead. + // NOTE: this can't be fixed in clippy because we explicitly don't set `RUSTC`, + // so it has no way of knowing the sysroot. + rustflags.arg("--sysroot"); + rustflags.arg(sysroot_str); } let use_new_symbol_mangling = match self.config.rust_new_symbol_mangling { @@ -1564,18 +1599,6 @@ impl<'a> Builder<'a> { let want_rustdoc = self.doc_tests != DocTests::No; - // We synthetically interpret a stage0 compiler used to build tools as a - // "raw" compiler in that it's the exact snapshot we download. Normally - // the stage0 build means it uses libraries build by the stage0 - // compiler, but for tools we just use the precompiled libraries that - // we've downloaded - let use_snapshot = mode == Mode::ToolBootstrap; - assert!(!use_snapshot || stage == 0 || self.local_rebuild); - - let maybe_sysroot = self.sysroot(compiler); - let sysroot = if use_snapshot { self.rustc_snapshot_sysroot() } else { &maybe_sysroot }; - let libdir = self.rustc_libdir(compiler); - // Clear the output directory if the real rustc we're using has changed; // Cargo cannot detect this as it thinks rustc is bootstrap/debug/rustc. // @@ -1611,10 +1634,19 @@ impl<'a> Builder<'a> { ) .env("RUSTC_ERROR_METADATA_DST", self.extended_error_dir()) .env("RUSTC_BREAK_ON_ICE", "1"); - // Clippy support is a hack and uses the default `cargo-clippy` in path. - // Don't override RUSTC so that the `cargo-clippy` in path will be run. - if cmd != "clippy" { - cargo.env("RUSTC", self.bootstrap_out.join("rustc")); + + // Set RUSTC_WRAPPER to the bootstrap shim, which switches between beta and in-tree + // sysroot depending on whether we're building build scripts. + // NOTE: we intentionally use RUSTC_WRAPPER so that we can support clippy - RUSTC is not + // respected by clippy-driver; RUSTC_WRAPPER happens earlier, before clippy runs. + cargo.env("RUSTC_WRAPPER", self.bootstrap_out.join("rustc")); + // NOTE: we also need to set RUSTC so cargo can run `rustc -vV`; apparently that ignores RUSTC_WRAPPER >:( + cargo.env("RUSTC", self.bootstrap_out.join("rustc")); + + // Someone might have set some previous rustc wrapper (e.g. + // sccache) before bootstrap overrode it. Respect that variable. + if let Some(existing_wrapper) = env::var_os("RUSTC_WRAPPER") { + cargo.env("RUSTC_WRAPPER_REAL", existing_wrapper); } // Dealing with rpath here is a little special, so let's go into some @@ -1991,7 +2023,11 @@ impl<'a> Builder<'a> { // Environment variables *required* throughout the build // // FIXME: should update code to not require this env var + + // The host this new compiler will *run* on. cargo.env("CFG_COMPILER_HOST_TRIPLE", target.triple); + // The host this new compiler is being *built* on. + cargo.env("CFG_COMPILER_BUILD_TRIPLE", compiler.host.triple); // Set this for all builds to make sure doc builds also get it. cargo.env("CFG_RELEASE_CHANNEL", &self.config.channel); diff --git a/src/bootstrap/src/core/download.rs b/src/bootstrap/src/core/download.rs index 0a5844a6859..1f2ee6a6b73 100644 --- a/src/bootstrap/src/core/download.rs +++ b/src/bootstrap/src/core/download.rs @@ -208,7 +208,10 @@ impl Config { Some(other) => panic!("unsupported protocol {other} in {url}"), None => panic!("no protocol in {url}"), } - t!(std::fs::rename(&tempfile, dest_path)); + t!( + std::fs::rename(&tempfile, dest_path), + format!("failed to rename {tempfile:?} to {dest_path:?}") + ); } fn download_http_with_retries(&self, tempfile: &Path, url: &str, help_on_error: &str) { @@ -375,6 +378,32 @@ enum DownloadSource { /// Functions that are only ever called once, but named for clarify and to avoid thousand-line functions. impl Config { + pub(crate) fn download_clippy(&self) -> PathBuf { + self.verbose("downloading stage0 clippy artifacts"); + + let date = &self.stage0_metadata.compiler.date; + let version = &self.stage0_metadata.compiler.version; + let host = self.build; + + let bin_root = self.out.join(host.triple).join("stage0"); + let clippy_stamp = bin_root.join(".clippy-stamp"); + let cargo_clippy = bin_root.join("bin").join(exe("cargo-clippy", host)); + if cargo_clippy.exists() && !program_out_of_date(&clippy_stamp, &date) { + return cargo_clippy; + } + + let filename = format!("clippy-{version}-{host}.tar.xz"); + self.download_component(DownloadSource::Dist, filename, "clippy-preview", date, "stage0"); + if self.should_fix_bins_and_dylibs() { + self.fix_bin_or_dylib(&cargo_clippy); + self.fix_bin_or_dylib(&cargo_clippy.with_file_name(exe("clippy-driver", host))); + } + + cargo_clippy + } + + /// NOTE: rustfmt is a completely different toolchain than the bootstrap compiler, so it can't + /// reuse target directories or artifacts pub(crate) fn maybe_download_rustfmt(&self) -> Option<PathBuf> { let RustfmtMetadata { date, version } = self.stage0_metadata.rustfmt.as_ref()?; let channel = format!("{version}-{date}"); @@ -544,6 +573,10 @@ impl Config { key: &str, destination: &str, ) { + if self.dry_run() { + return; + } + let cache_dst = self.out.join("cache"); let cache_dir = cache_dst.join(key); if !cache_dir.exists() { diff --git a/src/bootstrap/src/utils/dylib.rs b/src/bootstrap/src/utils/dylib.rs index 279a6a010f1..b6e7aec1756 100644 --- a/src/bootstrap/src/utils/dylib.rs +++ b/src/bootstrap/src/utils/dylib.rs @@ -25,3 +25,16 @@ pub fn dylib_path() -> Vec<std::path::PathBuf> { }; std::env::split_paths(&var).collect() } + +/// Given an executable called `name`, return the filename for the +/// executable for a particular target. +#[allow(dead_code)] +pub fn exe(name: &str, target: &str) -> String { + if target.contains("windows") { + format!("{name}.exe") + } else if target.contains("uefi") { + format!("{name}.efi") + } else { + name.to_string() + } +} diff --git a/src/bootstrap/src/utils/helpers.rs b/src/bootstrap/src/utils/helpers.rs index d96608db22c..031d56beb67 100644 --- a/src/bootstrap/src/utils/helpers.rs +++ b/src/bootstrap/src/utils/helpers.rs @@ -46,16 +46,8 @@ macro_rules! t { } pub use t; -/// Given an executable called `name`, return the filename for the -/// executable for a particular target. pub fn exe(name: &str, target: TargetSelection) -> String { - if target.is_windows() { - format!("{name}.exe") - } else if target.contains("uefi") { - format!("{name}.efi") - } else { - name.to_string() - } + crate::utils::dylib::exe(name, &target.triple) } /// Returns `true` if the file name given looks like a dynamic library. diff --git a/src/ci/docker/host-x86_64/mingw-check/Dockerfile b/src/ci/docker/host-x86_64/mingw-check/Dockerfile index 82d37f0f633..f8fcda5070f 100644 --- a/src/ci/docker/host-x86_64/mingw-check/Dockerfile +++ b/src/ci/docker/host-x86_64/mingw-check/Dockerfile @@ -39,8 +39,14 @@ COPY host-x86_64/mingw-check/validate-toolstate.sh /scripts/ COPY host-x86_64/mingw-check/validate-error-codes.sh /scripts/ ENV RUN_CHECK_WITH_PARALLEL_QUERIES 1 + +# Run clippy just to make sure it doesn't error out; we don't actually want to gate on the warnings +# though. +# Ideally we'd use stage 1, but that ICEs: https://github.com/rust-lang/rust-clippy/issues/11230 + ENV SCRIPT python3 ../x.py --stage 2 test src/tools/expand-yaml-anchors && \ python3 ../x.py check --target=i686-pc-windows-gnu --host=i686-pc-windows-gnu && \ + python3 ../x.py clippy --stage 0 -Awarnings && \ python3 ../x.py build --stage 0 src/tools/build-manifest && \ python3 ../x.py test --stage 0 src/tools/compiletest && \ python3 ../x.py test --stage 0 core alloc std test proc_macro && \ diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 6631c427270..828e7f959b4 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -184,22 +184,6 @@ fn clean_generic_bound<'tcx>( ) -> Option<GenericBound> { Some(match *bound { hir::GenericBound::Outlives(lt) => GenericBound::Outlives(clean_lifetime(lt, cx)), - hir::GenericBound::LangItemTrait(lang_item, span, _, generic_args) => { - let def_id = cx.tcx.require_lang_item(lang_item, Some(span)); - - let trait_ref = ty::Binder::dummy(ty::TraitRef::identity(cx.tcx, def_id)); - - let generic_args = clean_generic_args(generic_args, cx); - let GenericArgs::AngleBracketed { bindings, .. } = generic_args else { - bug!("clean: parenthesized `GenericBound::LangItemTrait`"); - }; - - let trait_ = clean_trait_ref_with_bindings(cx, trait_ref, bindings); - GenericBound::TraitBound( - PolyTrait { trait_, generic_params: vec![] }, - hir::TraitBoundModifier::None, - ) - } hir::GenericBound::Trait(ref t, modifier) => { // `T: ~const Destruct` is hidden because `T: Destruct` is a no-op. if modifier == hir::TraitBoundModifier::MaybeConst @@ -743,7 +727,7 @@ pub(crate) fn clean_generics<'tcx>( .into_iter() .map(|(lifetime, bounds)| WherePredicate::RegionPredicate { lifetime, bounds }), ) - .chain(eq_predicates.into_iter()) + .chain(eq_predicates) .collect(), } } diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 8215926ee33..0150496990d 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -380,7 +380,9 @@ pub(crate) fn run_global_ctxt( crate::lint::MISSING_CRATE_LEVEL_DOCS, DocContext::as_local_hir_id(tcx, krate.module.item_id).unwrap(), "no documentation found for this crate's top-level module", - |lint| lint.help(help), + |lint| { + lint.help(help); + }, ); } diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index dbd78ea0dc9..642265f5f6b 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -835,7 +835,7 @@ impl<'tcx> ExtraInfo<'tcx> { self.tcx.local_def_id_to_hir_id(def_id), self.sp, msg, - |l| l, + |_| {}, ); } } @@ -843,9 +843,7 @@ impl<'tcx> ExtraInfo<'tcx> { fn error_invalid_codeblock_attr_with_help( &self, msg: impl Into<DiagnosticMessage>, - f: impl for<'a, 'b> FnOnce( - &'b mut DiagnosticBuilder<'a, ()>, - ) -> &'b mut DiagnosticBuilder<'a, ()>, + f: impl for<'a, 'b> FnOnce(&'b mut DiagnosticBuilder<'a, ()>), ) { if let Some(def_id) = self.def_id.as_local() { self.tcx.struct_span_lint_hir( @@ -1296,7 +1294,7 @@ impl LangString { lint.help(format!( "there is an attribute with a similar name: `edition{}`", &x[4..], - )) + )); }, ); } @@ -1350,7 +1348,7 @@ impl LangString { lint.help(format!( "there is an attribute with a similar name: `{flag}`" )) - .help(help) + .help(help); }, ); } @@ -1383,7 +1381,7 @@ impl LangString { }; if custom_code_classes_in_docs { - call(&mut TagIterator::new(string, extra).into_iter()) + call(&mut TagIterator::new(string, extra)) } else { call(&mut tokens(string)) } diff --git a/src/librustdoc/html/render/write_shared.rs b/src/librustdoc/html/render/write_shared.rs index c4a6e920031..6408e97df50 100644 --- a/src/librustdoc/html/render/write_shared.rs +++ b/src/librustdoc/html/render/write_shared.rs @@ -328,8 +328,8 @@ pub(super) fn write_shared( v.push_str( r#"\ ]')); -if (typeof window !== 'undefined' && window.initSearch) {window.initSearch(searchIndex)}; -if (typeof exports !== 'undefined') {exports.searchIndex = searchIndex}; +if (typeof exports !== 'undefined') exports.searchIndex = searchIndex; +else if (window.initSearch) window.initSearch(searchIndex); "#, ); Ok(v.into_bytes()) diff --git a/src/librustdoc/html/static/js/src-script.js b/src/librustdoc/html/static/js/src-script.js index bbb0527a833..fc1d2d37845 100644 --- a/src/librustdoc/html/static/js/src-script.js +++ b/src/librustdoc/html/static/js/src-script.js @@ -146,12 +146,8 @@ function createSrcSidebar() { } } -const lineNumbersRegex = /^#?(\d+)(?:-(\d+))?$/; - -function highlightSrcLines(match) { - if (typeof match === "undefined") { - match = window.location.hash.match(lineNumbersRegex); - } +function highlightSrcLines() { + const match = window.location.hash.match(/^#?(\d+)(?:-(\d+))?$/); if (!match) { return; } @@ -233,12 +229,7 @@ const handleSrcHighlight = (function() { }; }()); -window.addEventListener("hashchange", () => { - const match = window.location.hash.match(lineNumbersRegex); - if (match) { - return highlightSrcLines(match); - } -}); +window.addEventListener("hashchange", highlightSrcLines); onEachLazy(document.getElementsByClassName("src-line-numbers"), el => { el.addEventListener("click", handleSrcHighlight); diff --git a/src/librustdoc/lint.rs b/src/librustdoc/lint.rs index d45040e348a..267f1cb0b72 100644 --- a/src/librustdoc/lint.rs +++ b/src/librustdoc/lint.rs @@ -33,7 +33,7 @@ where let lints = || { lint::builtin::HardwiredLints::get_lints() .into_iter() - .chain(rustc_lint::SoftLints::get_lints().into_iter()) + .chain(rustc_lint::SoftLints::get_lints()) }; let lint_opts = lints() @@ -46,7 +46,7 @@ where filter_call(lint) } }) - .chain(lint_opts.into_iter()) + .chain(lint_opts) .collect::<Vec<_>>(); let lint_caps = lints() diff --git a/src/librustdoc/passes/check_custom_code_classes.rs b/src/librustdoc/passes/check_custom_code_classes.rs index 6266d3ff51d..f246e2962fe 100644 --- a/src/librustdoc/passes/check_custom_code_classes.rs +++ b/src/librustdoc/passes/check_custom_code_classes.rs @@ -48,7 +48,7 @@ struct TestsWithCustomClasses { impl crate::doctest::Tester for TestsWithCustomClasses { fn add_test(&mut self, _: String, config: LangString, _: usize) { - self.custom_classes_found.extend(config.added_classes.into_iter()); + self.custom_classes_found.extend(config.added_classes); } } diff --git a/src/librustdoc/passes/check_doc_test_visibility.rs b/src/librustdoc/passes/check_doc_test_visibility.rs index 8d5b17f43cd..a931e8804d9 100644 --- a/src/librustdoc/passes/check_doc_test_visibility.rs +++ b/src/librustdoc/passes/check_doc_test_visibility.rs @@ -131,7 +131,7 @@ pub(crate) fn look_for_tests<'tcx>(cx: &DocContext<'tcx>, dox: &str, item: &Item hir_id, sp, "missing code example in this documentation", - |lint| lint, + |_| {}, ); } } else if tests.found_tests > 0 @@ -142,7 +142,7 @@ pub(crate) fn look_for_tests<'tcx>(cx: &DocContext<'tcx>, dox: &str, item: &Item hir_id, item.attr_span(cx.tcx), "documentation test in private item", - |lint| lint, + |_| {}, ); } } diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 6b536e97c43..ee185ab9892 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -1755,8 +1755,6 @@ fn report_diagnostic( } decorate(lint, span, link_range); - - lint }); } diff --git a/src/librustdoc/passes/lint/bare_urls.rs b/src/librustdoc/passes/lint/bare_urls.rs index 0c5cfffe1be..bffa17da3b4 100644 --- a/src/librustdoc/passes/lint/bare_urls.rs +++ b/src/librustdoc/passes/lint/bare_urls.rs @@ -31,7 +31,7 @@ pub(super) fn visit_item(cx: &DocContext<'_>, item: &Item) { "use an automatic link instead", format!("<{url}>"), Applicability::MachineApplicable, - ) + ); }); }; diff --git a/src/librustdoc/passes/lint/check_code_block_syntax.rs b/src/librustdoc/passes/lint/check_code_block_syntax.rs index e9b9e36a530..b5583ae4520 100644 --- a/src/librustdoc/passes/lint/check_code_block_syntax.rs +++ b/src/librustdoc/passes/lint/check_code_block_syntax.rs @@ -131,8 +131,6 @@ fn check_rust_syntax( for message in buffer.messages.iter() { lint.note(message.clone()); } - - lint }); } diff --git a/src/librustdoc/passes/lint/html_tags.rs b/src/librustdoc/passes/lint/html_tags.rs index 4a80c22ed08..90874c01102 100644 --- a/src/librustdoc/passes/lint/html_tags.rs +++ b/src/librustdoc/passes/lint/html_tags.rs @@ -89,7 +89,7 @@ pub(crate) fn visit_item(cx: &DocContext<'_>, item: &Item) { if (generics_start > 0 && dox.as_bytes()[generics_start - 1] == b'<') || (generics_end < dox.len() && dox.as_bytes()[generics_end] == b'>') { - return lint; + return; } // multipart form is chosen here because ``Vec<i32>`` would be confusing. lint.multipart_suggestion( @@ -101,8 +101,6 @@ pub(crate) fn visit_item(cx: &DocContext<'_>, item: &Item) { Applicability::MaybeIncorrect, ); } - - lint }); }; diff --git a/src/librustdoc/passes/lint/redundant_explicit_links.rs b/src/librustdoc/passes/lint/redundant_explicit_links.rs index 472781e7d22..4491d20b478 100644 --- a/src/librustdoc/passes/lint/redundant_explicit_links.rs +++ b/src/librustdoc/passes/lint/redundant_explicit_links.rs @@ -181,8 +181,6 @@ fn check_inline_or_reference_unknown_redundancy( .span_label(display_span, "because label contains path that resolves to same destination") .note("when a link's destination is not specified,\nthe label is used to resolve intra-doc links") .span_suggestion_with_style(link_span, "remove explicit link target", format!("[{}]", link_data.display_link), Applicability::MaybeIncorrect, SuggestionStyle::ShowAlways); - - lint }); } @@ -234,8 +232,6 @@ fn check_reference_redundancy( .span_note(def_span, "referenced explicit link target defined here") .note("when a link's destination is not specified,\nthe label is used to resolve intra-doc links") .span_suggestion_with_style(link_span, "remove explicit link target", format!("[{}]", link_data.display_link), Applicability::MaybeIncorrect, SuggestionStyle::ShowAlways); - - lint }); } diff --git a/src/librustdoc/passes/lint/unescaped_backticks.rs b/src/librustdoc/passes/lint/unescaped_backticks.rs index 8b7fdd6ab1f..0893cd0b40b 100644 --- a/src/librustdoc/passes/lint/unescaped_backticks.rs +++ b/src/librustdoc/passes/lint/unescaped_backticks.rs @@ -111,8 +111,6 @@ pub(crate) fn visit_item(cx: &DocContext<'_>, item: &Item) { } suggest_insertion(cx, item, &dox, lint, backtick_index, '\\', "if you meant to use a literal backtick, escape it"); - - lint }); } Event::Code(_) => { diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index bbc7e5b48d1..42ff1210f23 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -168,10 +168,11 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { }) .collect::<Vec<_>>() }) - .chain( - [Cfg::Cfg(sym::test, None), Cfg::Cfg(sym::doc, None), Cfg::Cfg(sym::doctest, None)] - .into_iter(), - ) + .chain([ + Cfg::Cfg(sym::test, None), + Cfg::Cfg(sym::doc, None), + Cfg::Cfg(sym::doctest, None), + ]) .collect(); self.cx.cache.exact_paths = self.exact_paths; diff --git a/src/stage0.json b/src/stage0.json index 3fb6a0d4ed0..5625e7219f8 100644 --- a/src/stage0.json +++ b/src/stage0.json @@ -74,6 +74,54 @@ "dist/2023-11-13/cargo-beta-x86_64-unknown-linux-musl.tar.xz": "790a859eaf49da5fdef1ea1ebf8b7f1f001bdaa62798a745d791bc915d886094", "dist/2023-11-13/cargo-beta-x86_64-unknown-netbsd.tar.gz": "f14395b57c0eca7c8ac9012b303c3781e16a2287698f68705fcbbc5c7c5916c9", "dist/2023-11-13/cargo-beta-x86_64-unknown-netbsd.tar.xz": "2c759c8bfc9cc556eb3464ac7e5589b573c46bd3938ac288ba52549121d3333d", + "dist/2023-11-13/clippy-beta-aarch64-apple-darwin.tar.gz": "258b55f0db78c93f14952fc3e2d9fc49f1121de5268ec49d03d4f197bd7c9773", + "dist/2023-11-13/clippy-beta-aarch64-apple-darwin.tar.xz": "554bd9488a9887c4acfb7c24775365108aef049feb15c93926128f805183f5e1", + "dist/2023-11-13/clippy-beta-aarch64-pc-windows-msvc.tar.gz": "d120adaec65b5f44f40fba38fa10a0cda33769756ac7fc2878d64154acc7e06c", + "dist/2023-11-13/clippy-beta-aarch64-pc-windows-msvc.tar.xz": "1dd23152a87fb8fa60569c304a3bbfd93f97c52d533fe53c8d9a5a4a72912938", + "dist/2023-11-13/clippy-beta-aarch64-unknown-linux-gnu.tar.gz": "41198264d015ccf624e0fca876bee16f8c3cbb07596f5f4d4f271b9843b10e30", + "dist/2023-11-13/clippy-beta-aarch64-unknown-linux-gnu.tar.xz": "1c889aad06c73dd2212403ff2aa5f256eba490cb8f1c81d7c75199a267052648", + "dist/2023-11-13/clippy-beta-aarch64-unknown-linux-musl.tar.gz": "db784d117c156d0e8854518a5df6e9adbf0b2d24f3504358b1a371b8e7954eef", + "dist/2023-11-13/clippy-beta-aarch64-unknown-linux-musl.tar.xz": "a946d40d32be1c5477f1740648e18af5792ceed38fe255e8cf09160acb27d02f", + "dist/2023-11-13/clippy-beta-arm-unknown-linux-gnueabi.tar.gz": "1b760fadecb9f4c4c1780b36d9bd651fa6c8a8fb6b48dc0dfbfb2ecd9359ca92", + "dist/2023-11-13/clippy-beta-arm-unknown-linux-gnueabi.tar.xz": "9e21f778eee57b067f411faa15425317158abd22f7c60dd4fc24214536ff7415", + "dist/2023-11-13/clippy-beta-arm-unknown-linux-gnueabihf.tar.gz": "fbe3d7776b9353782d2690ff1c98a0ce5d8d23de2381ecd3d4eff4ce165b66d5", + "dist/2023-11-13/clippy-beta-arm-unknown-linux-gnueabihf.tar.xz": "bfabf9e2419065173bf709166b0c81db66e1b2514003b28d08ec4410e04525a3", + "dist/2023-11-13/clippy-beta-armv7-unknown-linux-gnueabihf.tar.gz": "5371c798687aece2b98e22cf5bca02e568913011393a86a1aa3b0ff79eeabb57", + "dist/2023-11-13/clippy-beta-armv7-unknown-linux-gnueabihf.tar.xz": "82723066f2ec52fb5854a397f71df79db54976f4c03113034627c1a5c92ceffb", + "dist/2023-11-13/clippy-beta-i686-pc-windows-gnu.tar.gz": "0214eee5dc37f3a780ca62f1e7a66c5e19d583542dbfca047e383dfacca604b3", + "dist/2023-11-13/clippy-beta-i686-pc-windows-gnu.tar.xz": "cee7d7039b1ee909fa4a188d7fd0bae14d718bad98209d8df2dc087cc28d7a9c", + "dist/2023-11-13/clippy-beta-i686-pc-windows-msvc.tar.gz": "b6f1042f0d4652e941d975af8aeb4a61e335c585c1cd6dad7f85ba5b03c6face", + "dist/2023-11-13/clippy-beta-i686-pc-windows-msvc.tar.xz": "a31c1951abdff06c3709472acede08cd000b940a7a65f9afd664ca276fc724c1", + "dist/2023-11-13/clippy-beta-i686-unknown-linux-gnu.tar.gz": "1e0f2f2ea38988cd0012ceedacfa9828b4b6c6dfd3dca9eee5a98483fd90f439", + "dist/2023-11-13/clippy-beta-i686-unknown-linux-gnu.tar.xz": "f19b56068a40af2aee7c828a4688289a8142f98a81b80d66d12ddc6725209628", + "dist/2023-11-13/clippy-beta-loongarch64-unknown-linux-gnu.tar.gz": "e0f02e3ba303bef68a7cd1ea5effaa126eedbdc892b01dac85f4b3e6d4b2f522", + "dist/2023-11-13/clippy-beta-loongarch64-unknown-linux-gnu.tar.xz": "17a01e484f238bff790ad6cfededa8d9c7df0f6f36af336a1e8a7414a43271f5", + "dist/2023-11-13/clippy-beta-powerpc-unknown-linux-gnu.tar.gz": "ea4bc3aed8739bcecaa97f01972bbbba45e838c811ca0c408824b1409f9ac7c6", + "dist/2023-11-13/clippy-beta-powerpc-unknown-linux-gnu.tar.xz": "9ddb71b1f35f6953aedc6a1f93dde4a9b014255b5bd7d4448e4dd9b1a65c7f5a", + "dist/2023-11-13/clippy-beta-powerpc64-unknown-linux-gnu.tar.gz": "ccb95c3ce3dd4ee2776201ce1bd79122e97916c555126393f1839d301824e746", + "dist/2023-11-13/clippy-beta-powerpc64-unknown-linux-gnu.tar.xz": "9aad65fcefe5789670bc85cd177bd72eac469eb0a33db54685132a7ce5115a83", + "dist/2023-11-13/clippy-beta-powerpc64le-unknown-linux-gnu.tar.gz": "eb50e6349423c963fdce3193f361572a47e4d7fe5b90f8a297471c0a5df31feb", + "dist/2023-11-13/clippy-beta-powerpc64le-unknown-linux-gnu.tar.xz": "aa72d573b344953b9224ceb6eff484b6f012febfc009bc7773d398a3ffa69ea0", + "dist/2023-11-13/clippy-beta-riscv64gc-unknown-linux-gnu.tar.gz": "8546ac9a9e5081384d7ef889254e41998f60c04bbdca319128039e8a4e7cbc68", + "dist/2023-11-13/clippy-beta-riscv64gc-unknown-linux-gnu.tar.xz": "15fa574f7f7de2d8fcd124f44b1880a78bdd6a2ba77fe6b392299dd746ea9c63", + "dist/2023-11-13/clippy-beta-s390x-unknown-linux-gnu.tar.gz": "ee27937b85c142ebf46bb59ad9e113414cc9d631179a2f8df2b32980aa57b515", + "dist/2023-11-13/clippy-beta-s390x-unknown-linux-gnu.tar.xz": "e6e99e486418cb23a0cb80a2b145413bfeb62746b60fd9a0ff3959424b7ee07e", + "dist/2023-11-13/clippy-beta-x86_64-apple-darwin.tar.gz": "8a37545cef25abdd3c722a21385b843cb9d8d06fed8f302880beecbcb9373f98", + "dist/2023-11-13/clippy-beta-x86_64-apple-darwin.tar.xz": "f572586fc28bb5b2b77464d89b41c374de4002b453c297a8fc1468cee10db972", + "dist/2023-11-13/clippy-beta-x86_64-pc-windows-gnu.tar.gz": "5add2dab913488a482be6849887d9fa8c3cd197d3c423595a7133b511efcefca", + "dist/2023-11-13/clippy-beta-x86_64-pc-windows-gnu.tar.xz": "1d0d97a6b8703166616b6ae56d2b344e85dfa1db36976585d21cda65362cfff8", + "dist/2023-11-13/clippy-beta-x86_64-pc-windows-msvc.tar.gz": "4069dc9296cdc54af7e14d4ba5fc12ee5e6445be74f39c39526e4ed77378112f", + "dist/2023-11-13/clippy-beta-x86_64-pc-windows-msvc.tar.xz": "fdf4dfaef5f8fb24075bf8b24bdbd71804a49acda40921de84c61bc2250ade6c", + "dist/2023-11-13/clippy-beta-x86_64-unknown-freebsd.tar.gz": "4554eee1b1bd7e5575eaf5e7a815686da88fb395a80084c7a0fad3f338ac83b1", + "dist/2023-11-13/clippy-beta-x86_64-unknown-freebsd.tar.xz": "b0f1718df2a1e88ff4aa239bf4b9dc7a971fbc64cfa1ef8f399760fe09117097", + "dist/2023-11-13/clippy-beta-x86_64-unknown-illumos.tar.gz": "035400e01edb1a91ddcac72fe3ca1ea94465c4fe9047546d057f6867d8b068d1", + "dist/2023-11-13/clippy-beta-x86_64-unknown-illumos.tar.xz": "3ad1b06c3bc1e327ea7a3b30908b48bf6b59b7222101e5a30fb054b1be579087", + "dist/2023-11-13/clippy-beta-x86_64-unknown-linux-gnu.tar.gz": "88d611c40a30922515d09425ecd1a8b87f46131ab61f3c4bf841a41f281134b3", + "dist/2023-11-13/clippy-beta-x86_64-unknown-linux-gnu.tar.xz": "9908227c8a684aa5c24f3272997fc9688044580f792375ec9fc8f775e394953f", + "dist/2023-11-13/clippy-beta-x86_64-unknown-linux-musl.tar.gz": "10a7b2427ee8a4e83d271023e6bd00573266f317789cff3b75e68d7bddc41cbc", + "dist/2023-11-13/clippy-beta-x86_64-unknown-linux-musl.tar.xz": "cb1f3c2be55e11920340344d2f2f796098b7f13c9ddd2fb8a38ac1b29c5d6925", + "dist/2023-11-13/clippy-beta-x86_64-unknown-netbsd.tar.gz": "2b29461b085f0af1bb50d10ef8bf6448550c9b5867a364da3d921daea8e0a13d", + "dist/2023-11-13/clippy-beta-x86_64-unknown-netbsd.tar.xz": "e9d2ff4c8c63a9cfb7d8b12df4942f5b90c33c4fa3f755bbdc3c5df1b2b877fe", "dist/2023-11-13/rust-std-beta-aarch64-apple-darwin.tar.gz": "818e3554a6bd82c3533e68f8597c09563af1dc08d6b23bbd2323b8ebcce251f6", "dist/2023-11-13/rust-std-beta-aarch64-apple-darwin.tar.xz": "6f9333c281859e40b1c1c20e9f07ac1633ca2c99e86268b521945b8ed6cf6a50", "dist/2023-11-13/rust-std-beta-aarch64-apple-ios-sim.tar.gz": "fa4bb7a5d4dcecb2dfd8596e3ad442a5fe05468c939de3b36e44a43e10ea9d30", diff --git a/src/tools/bump-stage0/src/main.rs b/src/tools/bump-stage0/src/main.rs index b007f9a22c3..bd97b4eaa3e 100644 --- a/src/tools/bump-stage0/src/main.rs +++ b/src/tools/bump-stage0/src/main.rs @@ -4,7 +4,7 @@ use indexmap::IndexMap; use std::collections::HashMap; const PATH: &str = "src/stage0.json"; -const COMPILER_COMPONENTS: &[&str] = &["rustc", "rust-std", "cargo"]; +const COMPILER_COMPONENTS: &[&str] = &["rustc", "rust-std", "cargo", "clippy-preview"]; const RUSTFMT_COMPONENTS: &[&str] = &["rustfmt-preview", "rustc"]; struct Tool { diff --git a/src/tools/clippy/.github/workflows/clippy_bors.yml b/src/tools/clippy/.github/workflows/clippy_bors.yml index f67233dec62..73c25550742 100644 --- a/src/tools/clippy/.github/workflows/clippy_bors.yml +++ b/src/tools/clippy/.github/workflows/clippy_bors.yml @@ -206,6 +206,7 @@ jobs: max-parallel: 6 matrix: integration: + - 'matthiaskrgr/clippy_ci_panic_test' - 'rust-lang/cargo' - 'rust-lang/chalk' - 'rust-lang/rustfmt' @@ -220,7 +221,6 @@ jobs: - 'rust-itertools/itertools' - 'rust-lang-nursery/failure' - 'rust-lang/log' - - 'matthiaskrgr/clippy_ci_panic_test' runs-on: ubuntu-latest diff --git a/src/tools/clippy/CHANGELOG.md b/src/tools/clippy/CHANGELOG.md index 2e9b755caa0..70aff7f60e0 100644 --- a/src/tools/clippy/CHANGELOG.md +++ b/src/tools/clippy/CHANGELOG.md @@ -4946,6 +4946,7 @@ Released 2018-09-13 [`blanket_clippy_restriction_lints`]: https://rust-lang.github.io/rust-clippy/master/index.html#blanket_clippy_restriction_lints [`block_in_if_condition_expr`]: https://rust-lang.github.io/rust-clippy/master/index.html#block_in_if_condition_expr [`block_in_if_condition_stmt`]: https://rust-lang.github.io/rust-clippy/master/index.html#block_in_if_condition_stmt +[`blocks_in_conditions`]: https://rust-lang.github.io/rust-clippy/master/index.html#blocks_in_conditions [`blocks_in_if_conditions`]: https://rust-lang.github.io/rust-clippy/master/index.html#blocks_in_if_conditions [`bool_assert_comparison`]: https://rust-lang.github.io/rust-clippy/master/index.html#bool_assert_comparison [`bool_comparison`]: https://rust-lang.github.io/rust-clippy/master/index.html#bool_comparison @@ -5145,9 +5146,11 @@ Released 2018-09-13 [`index_refutable_slice`]: https://rust-lang.github.io/rust-clippy/master/index.html#index_refutable_slice [`indexing_slicing`]: https://rust-lang.github.io/rust-clippy/master/index.html#indexing_slicing [`ineffective_bit_mask`]: https://rust-lang.github.io/rust-clippy/master/index.html#ineffective_bit_mask +[`ineffective_open_options`]: https://rust-lang.github.io/rust-clippy/master/index.html#ineffective_open_options [`inefficient_to_string`]: https://rust-lang.github.io/rust-clippy/master/index.html#inefficient_to_string [`infallible_destructuring_match`]: https://rust-lang.github.io/rust-clippy/master/index.html#infallible_destructuring_match [`infinite_iter`]: https://rust-lang.github.io/rust-clippy/master/index.html#infinite_iter +[`infinite_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#infinite_loop [`inherent_to_string`]: https://rust-lang.github.io/rust-clippy/master/index.html#inherent_to_string [`inherent_to_string_shadow_display`]: https://rust-lang.github.io/rust-clippy/master/index.html#inherent_to_string_shadow_display [`init_numbered_fields`]: https://rust-lang.github.io/rust-clippy/master/index.html#init_numbered_fields @@ -5462,6 +5465,7 @@ Released 2018-09-13 [`ref_patterns`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_patterns [`regex_macro`]: https://rust-lang.github.io/rust-clippy/master/index.html#regex_macro [`repeat_once`]: https://rust-lang.github.io/rust-clippy/master/index.html#repeat_once +[`repeat_vec_with_capacity`]: https://rust-lang.github.io/rust-clippy/master/index.html#repeat_vec_with_capacity [`replace_consts`]: https://rust-lang.github.io/rust-clippy/master/index.html#replace_consts [`reserve_after_initialization`]: https://rust-lang.github.io/rust-clippy/master/index.html#reserve_after_initialization [`rest_pat_in_fully_bound_structs`]: https://rust-lang.github.io/rust-clippy/master/index.html#rest_pat_in_fully_bound_structs @@ -5582,6 +5586,7 @@ Released 2018-09-13 [`undropped_manually_drops`]: https://rust-lang.github.io/rust-clippy/master/index.html#undropped_manually_drops [`unicode_not_nfc`]: https://rust-lang.github.io/rust-clippy/master/index.html#unicode_not_nfc [`unimplemented`]: https://rust-lang.github.io/rust-clippy/master/index.html#unimplemented +[`uninhabited_references`]: https://rust-lang.github.io/rust-clippy/master/index.html#uninhabited_references [`uninit_assumed_init`]: https://rust-lang.github.io/rust-clippy/master/index.html#uninit_assumed_init [`uninit_vec`]: https://rust-lang.github.io/rust-clippy/master/index.html#uninit_vec [`uninlined_format_args`]: https://rust-lang.github.io/rust-clippy/master/index.html#uninlined_format_args diff --git a/src/tools/clippy/clippy_dev/src/lint.rs b/src/tools/clippy/clippy_dev/src/lint.rs index a19be1bca6c..906a9727810 100644 --- a/src/tools/clippy/clippy_dev/src/lint.rs +++ b/src/tools/clippy/clippy_dev/src/lint.rs @@ -1,6 +1,6 @@ use crate::{cargo_clippy_path, exit_if_err}; -use std::fs; use std::process::{self, Command}; +use std::{env, fs}; pub fn run<'a>(path: &str, args: impl Iterator<Item = &'a String>) { let is_file = match fs::metadata(path) { @@ -13,7 +13,7 @@ pub fn run<'a>(path: &str, args: impl Iterator<Item = &'a String>) { if is_file { exit_if_err( - Command::new("cargo") + Command::new(env::var("CARGO").unwrap_or("cargo".into())) .args(["run", "--bin", "clippy-driver", "--"]) .args(["-L", "./target/debug"]) .args(["-Z", "no-codegen"]) @@ -23,7 +23,11 @@ pub fn run<'a>(path: &str, args: impl Iterator<Item = &'a String>) { .status(), ); } else { - exit_if_err(Command::new("cargo").arg("build").status()); + exit_if_err( + Command::new(env::var("CARGO").unwrap_or("cargo".into())) + .arg("build") + .status(), + ); let status = Command::new(cargo_clippy_path()) .arg("clippy") diff --git a/src/tools/clippy/clippy_dev/src/serve.rs b/src/tools/clippy/clippy_dev/src/serve.rs index 535c25e69f1..ea925f6709f 100644 --- a/src/tools/clippy/clippy_dev/src/serve.rs +++ b/src/tools/clippy/clippy_dev/src/serve.rs @@ -2,8 +2,8 @@ use std::ffi::OsStr; use std::num::ParseIntError; use std::path::Path; use std::process::Command; -use std::thread; use std::time::{Duration, SystemTime}; +use std::{env, thread}; /// # Panics /// @@ -16,7 +16,7 @@ pub fn run(port: u16, lint: Option<&String>) -> ! { loop { if mtime("util/gh-pages/lints.json") < mtime("clippy_lints/src") { - Command::new("cargo") + Command::new(env::var("CARGO").unwrap_or("cargo".into())) .arg("collect-metadata") .spawn() .unwrap() diff --git a/src/tools/clippy/clippy_lints/Cargo.toml b/src/tools/clippy/clippy_lints/Cargo.toml index a9375214be4..ad8b7ded46b 100644 --- a/src/tools/clippy/clippy_lints/Cargo.toml +++ b/src/tools/clippy/clippy_lints/Cargo.toml @@ -16,7 +16,7 @@ clippy_utils = { path = "../clippy_utils" } declare_clippy_lint = { path = "../declare_clippy_lint" } itertools = "0.11" quine-mc_cluskey = "0.2" -regex-syntax = "0.7" +regex-syntax = "0.8" serde = { version = "1.0", features = ["derive"] } serde_json = { version = "1.0", optional = true } tempfile = { version = "3.3.0", optional = true } diff --git a/src/tools/clippy/clippy_lints/src/as_conversions.rs b/src/tools/clippy/clippy_lints/src/as_conversions.rs index e052d36f115..e3daf75c3eb 100644 --- a/src/tools/clippy/clippy_lints/src/as_conversions.rs +++ b/src/tools/clippy/clippy_lints/src/as_conversions.rs @@ -48,11 +48,10 @@ declare_lint_pass!(AsConversions => [AS_CONVERSIONS]); impl<'tcx> LateLintPass<'tcx> for AsConversions { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) { - if in_external_macro(cx.sess(), expr.span) || is_from_proc_macro(cx, expr) { - return; - } - - if let ExprKind::Cast(_, _) = expr.kind { + if let ExprKind::Cast(_, _) = expr.kind + && !in_external_macro(cx.sess(), expr.span) + && !is_from_proc_macro(cx, expr) + { span_lint_and_help( cx, AS_CONVERSIONS, diff --git a/src/tools/clippy/clippy_lints/src/blocks_in_conditions.rs b/src/tools/clippy/clippy_lints/src/blocks_in_conditions.rs new file mode 100644 index 00000000000..1417e230aee --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/blocks_in_conditions.rs @@ -0,0 +1,137 @@ +use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg}; +use clippy_utils::source::snippet_block_with_applicability; +use clippy_utils::ty::implements_trait; +use clippy_utils::visitors::{for_each_expr, Descend}; +use clippy_utils::{get_parent_expr, higher}; +use core::ops::ControlFlow; +use rustc_errors::Applicability; +use rustc_hir::{BlockCheckMode, Expr, ExprKind, MatchSource}; +use rustc_lint::{LateContext, LateLintPass, LintContext}; +use rustc_middle::lint::in_external_macro; +use rustc_session::declare_lint_pass; +use rustc_span::sym; + +declare_clippy_lint! { + /// ### What it does + /// Checks for `if` conditions that use blocks containing an + /// expression, statements or conditions that use closures with blocks. + /// + /// ### Why is this bad? + /// Style, using blocks in the condition makes it hard to read. + /// + /// ### Examples + /// ```no_run + /// # fn somefunc() -> bool { true }; + /// if { true } { /* ... */ } + /// + /// if { let x = somefunc(); x } { /* ... */ } + /// ``` + /// + /// Use instead: + /// ```no_run + /// # fn somefunc() -> bool { true }; + /// if true { /* ... */ } + /// + /// let res = { let x = somefunc(); x }; + /// if res { /* ... */ } + /// ``` + #[clippy::version = "1.45.0"] + pub BLOCKS_IN_CONDITIONS, + style, + "useless or complex blocks that can be eliminated in conditions" +} + +declare_lint_pass!(BlocksInConditions => [BLOCKS_IN_CONDITIONS]); + +const BRACED_EXPR_MESSAGE: &str = "omit braces around single expression condition"; + +impl<'tcx> LateLintPass<'tcx> for BlocksInConditions { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { + if in_external_macro(cx.sess(), expr.span) { + return; + } + + let Some((cond, keyword, desc)) = higher::If::hir(expr) + .map(|hif| (hif.cond, "if", "an `if` condition")) + .or(if let ExprKind::Match(match_ex, _, MatchSource::Normal) = expr.kind { + Some((match_ex, "match", "a `match` scrutinee")) + } else { + None + }) + else { + return; + }; + let complex_block_message = &format!( + "in {desc}, avoid complex blocks or closures with blocks; \ + instead, move the block or closure higher and bind it with a `let`", + ); + + if let ExprKind::Block(block, _) = &cond.kind { + if block.rules == BlockCheckMode::DefaultBlock { + if block.stmts.is_empty() { + if let Some(ex) = &block.expr { + // don't dig into the expression here, just suggest that they remove + // the block + if expr.span.from_expansion() || ex.span.from_expansion() { + return; + } + let mut applicability = Applicability::MachineApplicable; + span_lint_and_sugg( + cx, + BLOCKS_IN_CONDITIONS, + cond.span, + BRACED_EXPR_MESSAGE, + "try", + snippet_block_with_applicability(cx, ex.span, "..", Some(expr.span), &mut applicability) + .to_string(), + applicability, + ); + } + } else { + let span = block.expr.as_ref().map_or_else(|| block.stmts[0].span, |e| e.span); + if span.from_expansion() || expr.span.from_expansion() { + return; + } + // move block higher + let mut applicability = Applicability::MachineApplicable; + span_lint_and_sugg( + cx, + BLOCKS_IN_CONDITIONS, + expr.span.with_hi(cond.span.hi()), + complex_block_message, + "try", + format!( + "let res = {}; {keyword} res", + snippet_block_with_applicability(cx, block.span, "..", Some(expr.span), &mut applicability), + ), + applicability, + ); + } + } + } else { + let _: Option<!> = for_each_expr(cond, |e| { + if let ExprKind::Closure(closure) = e.kind { + // do not lint if the closure is called using an iterator (see #1141) + if let Some(parent) = get_parent_expr(cx, e) + && let ExprKind::MethodCall(_, self_arg, _, _) = &parent.kind + && let caller = cx.typeck_results().expr_ty(self_arg) + && let Some(iter_id) = cx.tcx.get_diagnostic_item(sym::Iterator) + && implements_trait(cx, caller, iter_id, &[]) + { + return ControlFlow::Continue(Descend::No); + } + + let body = cx.tcx.hir().body(closure.body); + let ex = &body.value; + if let ExprKind::Block(block, _) = ex.kind { + if !body.value.span.from_expansion() && !block.stmts.is_empty() { + span_lint(cx, BLOCKS_IN_CONDITIONS, ex.span, complex_block_message); + return ControlFlow::Continue(Descend::No); + } + } + } + ControlFlow::Continue(Descend::Yes) + }); + } + } +} diff --git a/src/tools/clippy/clippy_lints/src/blocks_in_if_conditions.rs b/src/tools/clippy/clippy_lints/src/blocks_in_if_conditions.rs deleted file mode 100644 index 692309629b7..00000000000 --- a/src/tools/clippy/clippy_lints/src/blocks_in_if_conditions.rs +++ /dev/null @@ -1,139 +0,0 @@ -use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg}; -use clippy_utils::source::snippet_block_with_applicability; -use clippy_utils::ty::implements_trait; -use clippy_utils::visitors::{for_each_expr, Descend}; -use clippy_utils::{get_parent_expr, higher}; -use core::ops::ControlFlow; -use rustc_errors::Applicability; -use rustc_hir::{BlockCheckMode, Expr, ExprKind}; -use rustc_lint::{LateContext, LateLintPass, LintContext}; -use rustc_middle::lint::in_external_macro; -use rustc_session::declare_lint_pass; -use rustc_span::sym; - -declare_clippy_lint! { - /// ### What it does - /// Checks for `if` conditions that use blocks containing an - /// expression, statements or conditions that use closures with blocks. - /// - /// ### Why is this bad? - /// Style, using blocks in the condition makes it hard to read. - /// - /// ### Examples - /// ```no_run - /// # fn somefunc() -> bool { true }; - /// if { true } { /* ... */ } - /// - /// if { let x = somefunc(); x } { /* ... */ } - /// ``` - /// - /// Use instead: - /// ```no_run - /// # fn somefunc() -> bool { true }; - /// if true { /* ... */ } - /// - /// let res = { let x = somefunc(); x }; - /// if res { /* ... */ } - /// ``` - #[clippy::version = "1.45.0"] - pub BLOCKS_IN_IF_CONDITIONS, - style, - "useless or complex blocks that can be eliminated in conditions" -} - -declare_lint_pass!(BlocksInIfConditions => [BLOCKS_IN_IF_CONDITIONS]); - -const BRACED_EXPR_MESSAGE: &str = "omit braces around single expression condition"; -const COMPLEX_BLOCK_MESSAGE: &str = "in an `if` condition, avoid complex blocks or closures with blocks; \ - instead, move the block or closure higher and bind it with a `let`"; - -impl<'tcx> LateLintPass<'tcx> for BlocksInIfConditions { - fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if in_external_macro(cx.sess(), expr.span) { - return; - } - if let Some(higher::If { cond, .. }) = higher::If::hir(expr) { - if let ExprKind::Block(block, _) = &cond.kind { - if block.rules == BlockCheckMode::DefaultBlock { - if block.stmts.is_empty() { - if let Some(ex) = &block.expr { - // don't dig into the expression here, just suggest that they remove - // the block - if expr.span.from_expansion() || ex.span.from_expansion() { - return; - } - let mut applicability = Applicability::MachineApplicable; - span_lint_and_sugg( - cx, - BLOCKS_IN_IF_CONDITIONS, - cond.span, - BRACED_EXPR_MESSAGE, - "try", - format!( - "{}", - snippet_block_with_applicability( - cx, - ex.span, - "..", - Some(expr.span), - &mut applicability - ) - ), - applicability, - ); - } - } else { - let span = block.expr.as_ref().map_or_else(|| block.stmts[0].span, |e| e.span); - if span.from_expansion() || expr.span.from_expansion() { - return; - } - // move block higher - let mut applicability = Applicability::MachineApplicable; - span_lint_and_sugg( - cx, - BLOCKS_IN_IF_CONDITIONS, - expr.span.with_hi(cond.span.hi()), - COMPLEX_BLOCK_MESSAGE, - "try", - format!( - "let res = {}; if res", - snippet_block_with_applicability( - cx, - block.span, - "..", - Some(expr.span), - &mut applicability - ), - ), - applicability, - ); - } - } - } else { - let _: Option<!> = for_each_expr(cond, |e| { - if let ExprKind::Closure(closure) = e.kind { - // do not lint if the closure is called using an iterator (see #1141) - if let Some(parent) = get_parent_expr(cx, e) - && let ExprKind::MethodCall(_, self_arg, _, _) = &parent.kind - && let caller = cx.typeck_results().expr_ty(self_arg) - && let Some(iter_id) = cx.tcx.get_diagnostic_item(sym::Iterator) - && implements_trait(cx, caller, iter_id, &[]) - { - return ControlFlow::Continue(Descend::No); - } - - let body = cx.tcx.hir().body(closure.body); - let ex = &body.value; - if let ExprKind::Block(block, _) = ex.kind { - if !body.value.span.from_expansion() && !block.stmts.is_empty() { - span_lint(cx, BLOCKS_IN_IF_CONDITIONS, ex.span, COMPLEX_BLOCK_MESSAGE); - return ControlFlow::Continue(Descend::No); - } - } - } - ControlFlow::Continue(Descend::Yes) - }); - } - } - } -} diff --git a/src/tools/clippy/clippy_lints/src/borrow_deref_ref.rs b/src/tools/clippy/clippy_lints/src/borrow_deref_ref.rs index d3d4f3c41c8..0ca4a0e067d 100644 --- a/src/tools/clippy/clippy_lints/src/borrow_deref_ref.rs +++ b/src/tools/clippy/clippy_lints/src/borrow_deref_ref.rs @@ -57,7 +57,6 @@ impl<'tcx> LateLintPass<'tcx> for BorrowDerefRef { && !matches!(deref_target.kind, ExprKind::Unary(UnOp::Deref, ..)) && let ref_ty = cx.typeck_results().expr_ty(deref_target) && let ty::Ref(_, inner_ty, Mutability::Not) = ref_ty.kind() - && !is_from_proc_macro(cx, e) { if let Some(parent_expr) = get_parent_expr(cx, e) { if matches!(parent_expr.kind, ExprKind::Unary(UnOp::Deref, ..)) @@ -75,6 +74,9 @@ impl<'tcx> LateLintPass<'tcx> for BorrowDerefRef { return; } } + if is_from_proc_macro(cx, e) { + return; + } span_lint_and_then( cx, diff --git a/src/tools/clippy/clippy_lints/src/casts/as_ptr_cast_mut.rs b/src/tools/clippy/clippy_lints/src/casts/as_ptr_cast_mut.rs index b55cd8833b7..8bfb7383f14 100644 --- a/src/tools/clippy/clippy_lints/src/casts/as_ptr_cast_mut.rs +++ b/src/tools/clippy/clippy_lints/src/casts/as_ptr_cast_mut.rs @@ -9,11 +9,10 @@ use rustc_middle::ty::{self, Ty, TypeAndMut}; use super::AS_PTR_CAST_MUT; pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, cast_to: Ty<'_>) { - if let ty::RawPtr( - TypeAndMut { - mutbl: Mutability::Mut, ty: ptrty, - }, - ) = cast_to.kind() + if let ty::RawPtr(TypeAndMut { + mutbl: Mutability::Mut, + ty: ptrty, + }) = cast_to.kind() && let ty::RawPtr(TypeAndMut { mutbl: Mutability::Not, .. }) = cx.typeck_results().node_type(cast_expr.hir_id).kind() diff --git a/src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs b/src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs index 0c555c1acc5..35e36e9ef3f 100644 --- a/src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs +++ b/src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs @@ -3,12 +3,29 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; use clippy_utils::sugg::Sugg; use rustc_errors::Applicability; -use rustc_hir::{Expr, ExprKind, Mutability, TyKind}; +use rustc_hir::{Expr, ExprKind, Mutability, QPath, TyKind}; +use rustc_hir_pretty::qpath_to_string; use rustc_lint::LateContext; use rustc_middle::ty::{self, TypeAndMut}; +use rustc_span::sym; use super::PTR_AS_PTR; +enum OmitFollowedCastReason<'a> { + None, + Null(&'a QPath<'a>), + NullMut(&'a QPath<'a>), +} + +impl OmitFollowedCastReason<'_> { + fn corresponding_item(&self) -> Option<&QPath<'_>> { + match self { + OmitFollowedCastReason::None => None, + OmitFollowedCastReason::Null(x) | OmitFollowedCastReason::NullMut(x) => Some(*x), + } + } +} + pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, msrv: &Msrv) { if !msrv.meets(msrvs::POINTER_CAST) { return; @@ -25,7 +42,6 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, msrv: &Msrv) { && to_pointee_ty.is_sized(cx.tcx, cx.param_env) { let mut app = Applicability::MachineApplicable; - let cast_expr_sugg = Sugg::hir_with_applicability(cx, cast_expr, "_", &mut app); let turbofish = match &cast_to_hir_ty.kind { TyKind::Infer => String::new(), TyKind::Ptr(mut_ty) => { @@ -41,13 +57,44 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, msrv: &Msrv) { _ => return, }; + // following `cast` does not compile because it fails to infer what type is expected + // as type argument to `std::ptr::ptr_null` or `std::ptr::ptr_null_mut`, so + // we omit following `cast`: + let omit_cast = if let ExprKind::Call(func, []) = cast_expr.kind + && let ExprKind::Path(ref qpath @ QPath::Resolved(None, path)) = func.kind + { + let method_defid = path.res.def_id(); + if cx.tcx.is_diagnostic_item(sym::ptr_null, method_defid) { + OmitFollowedCastReason::Null(qpath) + } else if cx.tcx.is_diagnostic_item(sym::ptr_null_mut, method_defid) { + OmitFollowedCastReason::NullMut(qpath) + } else { + OmitFollowedCastReason::None + } + } else { + OmitFollowedCastReason::None + }; + + let (help, final_suggestion) = if let Some(method) = omit_cast.corresponding_item() { + // don't force absolute path + let method = qpath_to_string(method); + ("try call directly", format!("{method}{turbofish}()")) + } else { + let cast_expr_sugg = Sugg::hir_with_applicability(cx, cast_expr, "_", &mut app); + + ( + "try `pointer::cast`, a safer alternative", + format!("{}.cast{turbofish}()", cast_expr_sugg.maybe_par()), + ) + }; + span_lint_and_sugg( cx, PTR_AS_PTR, expr.span, "`as` casting between raw pointers without changing its mutability", - "try `pointer::cast`, a safer alternative", - format!("{}.cast{turbofish}()", cast_expr_sugg.maybe_par()), + help, + final_suggestion, app, ); } diff --git a/src/tools/clippy/clippy_lints/src/declared_lints.rs b/src/tools/clippy/clippy_lints/src/declared_lints.rs index 3627096ed91..1220eb89013 100644 --- a/src/tools/clippy/clippy_lints/src/declared_lints.rs +++ b/src/tools/clippy/clippy_lints/src/declared_lints.rs @@ -63,7 +63,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::await_holding_invalid::AWAIT_HOLDING_INVALID_TYPE_INFO, crate::await_holding_invalid::AWAIT_HOLDING_LOCK_INFO, crate::await_holding_invalid::AWAIT_HOLDING_REFCELL_REF_INFO, - crate::blocks_in_if_conditions::BLOCKS_IN_IF_CONDITIONS_INFO, + crate::blocks_in_conditions::BLOCKS_IN_CONDITIONS_INFO, crate::bool_assert_comparison::BOOL_ASSERT_COMPARISON_INFO, crate::bool_to_int_with_if::BOOL_TO_INT_WITH_IF_INFO, crate::booleans::NONMINIMAL_BOOL_INFO, @@ -215,6 +215,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::index_refutable_slice::INDEX_REFUTABLE_SLICE_INFO, crate::indexing_slicing::INDEXING_SLICING_INFO, crate::indexing_slicing::OUT_OF_BOUNDS_INDEXING_INFO, + crate::ineffective_open_options::INEFFECTIVE_OPEN_OPTIONS_INFO, crate::infinite_iter::INFINITE_ITER_INFO, crate::infinite_iter::MAYBE_INFINITE_ITER_INFO, crate::inherent_impl::MULTIPLE_INHERENT_IMPL_INFO, @@ -265,6 +266,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::loops::EXPLICIT_INTO_ITER_LOOP_INFO, crate::loops::EXPLICIT_ITER_LOOP_INFO, crate::loops::FOR_KV_MAP_INFO, + crate::loops::INFINITE_LOOP_INFO, crate::loops::ITER_NEXT_LOOP_INFO, crate::loops::MANUAL_FIND_INFO, crate::loops::MANUAL_FLATTEN_INFO, @@ -598,6 +600,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::reference::DEREF_ADDROF_INFO, crate::regex::INVALID_REGEX_INFO, crate::regex::TRIVIAL_REGEX_INFO, + crate::repeat_vec_with_capacity::REPEAT_VEC_WITH_CAPACITY_INFO, crate::reserve_after_initialization::RESERVE_AFTER_INITIALIZATION_INFO, crate::return_self_not_must_use::RETURN_SELF_NOT_MUST_USE_INFO, crate::returns::LET_AND_RETURN_INFO, @@ -678,6 +681,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::unicode::INVISIBLE_CHARACTERS_INFO, crate::unicode::NON_ASCII_LITERAL_INFO, crate::unicode::UNICODE_NOT_NFC_INFO, + crate::uninhabited_references::UNINHABITED_REFERENCES_INFO, crate::uninit_vec::UNINIT_VEC_INFO, crate::unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD_INFO, crate::unit_types::LET_UNIT_VALUE_INFO, diff --git a/src/tools/clippy/clippy_lints/src/doc/markdown.rs b/src/tools/clippy/clippy_lints/src/doc/markdown.rs index c0b11eb0dd1..a58219c2946 100644 --- a/src/tools/clippy/clippy_lints/src/doc/markdown.rs +++ b/src/tools/clippy/clippy_lints/src/doc/markdown.rs @@ -9,11 +9,21 @@ use url::Url; use crate::doc::DOC_MARKDOWN; pub fn check(cx: &LateContext<'_>, valid_idents: &FxHashSet<String>, text: &str, span: Span) { - for word in text.split(|c: char| c.is_whitespace() || c == '\'') { + for orig_word in text.split(|c: char| c.is_whitespace() || c == '\'') { // Trim punctuation as in `some comment (see foo::bar).` // ^^ // Or even as in `_foo bar_` which is emphasized. Also preserve `::` as a prefix/suffix. - let mut word = word.trim_matches(|c: char| !c.is_alphanumeric() && c != ':'); + let trim_pattern = |c: char| !c.is_alphanumeric() && c != ':'; + let mut word = orig_word.trim_end_matches(trim_pattern); + + // If word is immediately followed by `()`, claw it back. + if let Some(tmp_word) = orig_word.get(..word.len() + 2) + && tmp_word.ends_with("()") + { + word = tmp_word; + } + + word = word.trim_start_matches(trim_pattern); // Remove leading or trailing single `:` which may be part of a sentence. if word.starts_with(':') && !word.starts_with("::") { @@ -84,7 +94,7 @@ fn check_word(cx: &LateContext<'_>, word: &str, span: Span) { return; } - if has_underscore(word) || word.contains("::") || is_camel_case(word) { + if has_underscore(word) || word.contains("::") || is_camel_case(word) || word.ends_with("()") { let mut applicability = Applicability::MachineApplicable; span_lint_and_then( diff --git a/src/tools/clippy/clippy_lints/src/explicit_write.rs b/src/tools/clippy/clippy_lints/src/explicit_write.rs index f1366c434f4..e8c1e5db35e 100644 --- a/src/tools/clippy/clippy_lints/src/explicit_write.rs +++ b/src/tools/clippy/clippy_lints/src/explicit_write.rs @@ -15,7 +15,7 @@ declare_clippy_lint! { /// replaced with `(e)print!()` / `(e)println!()` /// /// ### Why is this bad? - /// Using `(e)println! is clearer and more concise + /// Using `(e)println!` is clearer and more concise /// /// ### Example /// ```no_run diff --git a/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs b/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs index 4811691c80d..0f5a9ea5d84 100644 --- a/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs +++ b/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs @@ -194,7 +194,12 @@ fn is_same_generics<'tcx>( .enumerate() .skip(1) // skip `Self` implicit arg .all(|(arg_index, arg)| { - if [implied_by_generics.host_effect_index, implied_generics.host_effect_index].contains(&Some(arg_index)) { + if [ + implied_by_generics.host_effect_index, + implied_generics.host_effect_index, + ] + .contains(&Some(arg_index)) + { // skip host effect params in determining whether generics are same return true; } diff --git a/src/tools/clippy/clippy_lints/src/ineffective_open_options.rs b/src/tools/clippy/clippy_lints/src/ineffective_open_options.rs new file mode 100644 index 00000000000..955f90d4262 --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/ineffective_open_options.rs @@ -0,0 +1,95 @@ +use crate::methods::method_call; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::peel_blocks; +use rustc_ast::LitKind; +use rustc_errors::Applicability; +use rustc_hir::{Expr, ExprKind}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty; +use rustc_session::declare_lint_pass; +use rustc_span::{sym, BytePos, Span}; + +declare_clippy_lint! { + /// ### What it does + /// Checks if both `.write(true)` and `.append(true)` methods are called + /// on a same `OpenOptions`. + /// + /// ### Why is this bad? + /// `.append(true)` already enables `write(true)`, making this one + /// superflous. + /// + /// ### Example + /// ```no_run + /// # use std::fs::OpenOptions; + /// let _ = OpenOptions::new() + /// .write(true) + /// .append(true) + /// .create(true) + /// .open("file.json"); + /// ``` + /// Use instead: + /// ```no_run + /// # use std::fs::OpenOptions; + /// let _ = OpenOptions::new() + /// .append(true) + /// .create(true) + /// .open("file.json"); + /// ``` + #[clippy::version = "1.76.0"] + pub INEFFECTIVE_OPEN_OPTIONS, + suspicious, + "usage of both `write(true)` and `append(true)` on same `OpenOptions`" +} + +declare_lint_pass!(IneffectiveOpenOptions => [INEFFECTIVE_OPEN_OPTIONS]); + +fn index_if_arg_is_boolean(args: &[Expr<'_>], call_span: Span) -> Option<Span> { + if let [arg] = args + && let ExprKind::Lit(lit) = peel_blocks(arg).kind + && lit.node == LitKind::Bool(true) + { + // The `.` is not included in the span so we cheat a little bit to include it as well. + Some(call_span.with_lo(call_span.lo() - BytePos(1))) + } else { + None + } +} + +impl<'tcx> LateLintPass<'tcx> for IneffectiveOpenOptions { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { + let Some(("open", mut receiver, [_arg], _, _)) = method_call(expr) else { + return; + }; + let receiver_ty = cx.typeck_results().expr_ty(receiver); + match receiver_ty.peel_refs().kind() { + ty::Adt(adt, _) if cx.tcx.is_diagnostic_item(sym::FsOpenOptions, adt.did()) => {}, + _ => return, + } + + let mut append = None; + let mut write = None; + + while let Some((name, recv, args, _, span)) = method_call(receiver) { + if name == "append" { + append = index_if_arg_is_boolean(args, span); + } else if name == "write" { + write = index_if_arg_is_boolean(args, span); + } + receiver = recv; + } + + if let Some(write_span) = write + && append.is_some() + { + span_lint_and_sugg( + cx, + INEFFECTIVE_OPEN_OPTIONS, + write_span, + "unnecessary use of `.write(true)` because there is `.append(true)`", + "remove `.write(true)`", + String::new(), + Applicability::MachineApplicable, + ); + } + } +} diff --git a/src/tools/clippy/clippy_lints/src/len_zero.rs b/src/tools/clippy/clippy_lints/src/len_zero.rs index 83af551fcd3..8c032b17023 100644 --- a/src/tools/clippy/clippy_lints/src/len_zero.rs +++ b/src/tools/clippy/clippy_lints/src/len_zero.rs @@ -8,8 +8,8 @@ use rustc_hir::def::Res; use rustc_hir::def_id::{DefId, DefIdSet}; use rustc_hir::{ AssocItemKind, BinOpKind, Expr, ExprKind, FnRetTy, GenericArg, GenericBound, ImplItem, ImplItemKind, - ImplicitSelfKind, Item, ItemKind, LangItem, Mutability, Node, PatKind, PathSegment, PrimTy, QPath, TraitItemRef, - TyKind, TypeBindingKind, + ImplicitSelfKind, Item, ItemKind, Mutability, Node, PatKind, PathSegment, PrimTy, QPath, TraitItemRef, + TyKind, TypeBindingKind, OpaqueTyOrigin, }; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{self, AssocKind, FnSig, Ty}; @@ -289,8 +289,10 @@ fn extract_future_output<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<& kind: ItemKind::OpaqueTy(opaque), .. } = item - && opaque.bounds.len() == 1 - && let GenericBound::LangItemTrait(LangItem::Future, _, _, generic_args) = &opaque.bounds[0] + && let OpaqueTyOrigin::AsyncFn(_) = opaque.origin + && let [GenericBound::Trait(trait_ref, _)] = &opaque.bounds + && let Some(segment) = trait_ref.trait_ref.path.segments.last() + && let Some(generic_args) = segment.args && generic_args.bindings.len() == 1 && let TypeBindingKind::Equality { term: diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs index 1c59b2df853..7758d6a58e6 100644 --- a/src/tools/clippy/clippy_lints/src/lib.rs +++ b/src/tools/clippy/clippy_lints/src/lib.rs @@ -50,6 +50,8 @@ extern crate clippy_utils; #[macro_use] extern crate declare_clippy_lint; +use std::collections::BTreeMap; + use rustc_data_structures::fx::FxHashSet; use rustc_lint::{Lint, LintId}; @@ -74,7 +76,7 @@ mod assertions_on_result_states; mod async_yields_async; mod attrs; mod await_holding_invalid; -mod blocks_in_if_conditions; +mod blocks_in_conditions; mod bool_assert_comparison; mod bool_to_int_with_if; mod booleans; @@ -153,6 +155,7 @@ mod implied_bounds_in_impls; mod inconsistent_struct_constructor; mod index_refutable_slice; mod indexing_slicing; +mod ineffective_open_options; mod infinite_iter; mod inherent_impl; mod inherent_to_string; @@ -289,6 +292,7 @@ mod ref_option_ref; mod ref_patterns; mod reference; mod regex; +mod repeat_vec_with_capacity; mod reserve_after_initialization; mod return_self_not_must_use; mod returns; @@ -325,6 +329,7 @@ mod tuple_array_conversions; mod types; mod undocumented_unsafe_blocks; mod unicode; +mod uninhabited_references; mod uninit_vec; mod unit_return_expecting_ord; mod unit_types; @@ -653,7 +658,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { store.register_late_pass(|_| Box::<significant_drop_tightening::SignificantDropTightening<'_>>::default()); store.register_late_pass(|_| Box::new(len_zero::LenZero)); store.register_late_pass(|_| Box::new(attrs::Attributes)); - store.register_late_pass(|_| Box::new(blocks_in_if_conditions::BlocksInIfConditions)); + store.register_late_pass(|_| Box::new(blocks_in_conditions::BlocksInConditions)); store.register_late_pass(|_| Box::new(unicode::Unicode)); store.register_late_pass(|_| Box::new(uninit_vec::UninitVec)); store.register_late_pass(|_| Box::new(unit_return_expecting_ord::UnitReturnExpectingOrd)); @@ -722,6 +727,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { Box::new(vec::UselessVec { too_large_for_stack, msrv: msrv(), + span_to_lint_map: BTreeMap::new(), }) }); store.register_late_pass(|_| Box::new(panic_unimplemented::PanicUnimplemented)); @@ -1069,6 +1075,9 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { store.register_late_pass(|_| Box::new(iter_without_into_iter::IterWithoutIntoIter)); store.register_late_pass(|_| Box::new(iter_over_hash_type::IterOverHashType)); store.register_late_pass(|_| Box::new(impl_hash_with_borrow_str_and_bytes::ImplHashWithBorrowStrBytes)); + store.register_late_pass(|_| Box::new(repeat_vec_with_capacity::RepeatVecWithCapacity)); + store.register_late_pass(|_| Box::new(uninhabited_references::UninhabitedReferences)); + store.register_late_pass(|_| Box::new(ineffective_open_options::IneffectiveOpenOptions)); // add lints here, do not remove this comment, it's used in `new_lint` } diff --git a/src/tools/clippy/clippy_lints/src/loops/infinite_loop.rs b/src/tools/clippy/clippy_lints/src/loops/infinite_loop.rs new file mode 100644 index 00000000000..9b88dd76e5c --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/loops/infinite_loop.rs @@ -0,0 +1,125 @@ +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::{fn_def_id, is_lint_allowed}; +use hir::intravisit::{walk_expr, Visitor}; +use hir::{Expr, ExprKind, FnRetTy, FnSig, Node}; +use rustc_ast::Label; +use rustc_errors::Applicability; +use rustc_hir as hir; +use rustc_lint::LateContext; + +use super::INFINITE_LOOP; + +pub(super) fn check<'tcx>( + cx: &LateContext<'tcx>, + expr: &Expr<'_>, + loop_block: &'tcx hir::Block<'_>, + label: Option<Label>, +) { + if is_lint_allowed(cx, INFINITE_LOOP, expr.hir_id) { + return; + } + + // Skip check if this loop is not in a function/method/closure. (In some weird case) + let Some(parent_fn_ret) = get_parent_fn_ret_ty(cx, expr) else { + return; + }; + // Or, its parent function is already returning `Never` + if matches!( + parent_fn_ret, + FnRetTy::Return(hir::Ty { + kind: hir::TyKind::Never, + .. + }) + ) { + return; + } + + let mut loop_visitor = LoopVisitor { + cx, + label, + is_finite: false, + loop_depth: 0, + }; + loop_visitor.visit_block(loop_block); + + let is_finite_loop = loop_visitor.is_finite; + + if !is_finite_loop { + span_lint_and_then(cx, INFINITE_LOOP, expr.span, "infinite loop detected", |diag| { + if let FnRetTy::DefaultReturn(ret_span) = parent_fn_ret { + diag.span_suggestion( + ret_span, + "if this is intentional, consider specifing `!` as function return", + " -> !", + Applicability::MaybeIncorrect, + ); + } else { + diag.help("if this is not intended, try adding a `break` or `return` condition in the loop"); + } + }); + } +} + +fn get_parent_fn_ret_ty<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>) -> Option<FnRetTy<'tcx>> { + for (_, parent_node) in cx.tcx.hir().parent_iter(expr.hir_id) { + match parent_node { + Node::Item(hir::Item { + kind: hir::ItemKind::Fn(FnSig { decl, .. }, _, _), + .. + }) + | Node::TraitItem(hir::TraitItem { + kind: hir::TraitItemKind::Fn(FnSig { decl, .. }, _), + .. + }) + | Node::ImplItem(hir::ImplItem { + kind: hir::ImplItemKind::Fn(FnSig { decl, .. }, _), + .. + }) + | Node::Expr(Expr { + kind: ExprKind::Closure(hir::Closure { fn_decl: decl, .. }), + .. + }) => return Some(decl.output), + _ => (), + } + } + None +} + +struct LoopVisitor<'hir, 'tcx> { + cx: &'hir LateContext<'tcx>, + label: Option<Label>, + loop_depth: usize, + is_finite: bool, +} + +impl<'hir> Visitor<'hir> for LoopVisitor<'hir, '_> { + fn visit_expr(&mut self, ex: &'hir Expr<'_>) { + match &ex.kind { + ExprKind::Break(hir::Destination { label, .. }, ..) => { + // Assuming breaks the loop when `loop_depth` is 0, + // as it could only means this `break` breaks current loop or any of its upper loop. + // Or, the depth is not zero but the label is matched. + if self.loop_depth == 0 || (label.is_some() && *label == self.label) { + self.is_finite = true; + } + }, + ExprKind::Ret(..) => self.is_finite = true, + ExprKind::Loop(..) => { + self.loop_depth += 1; + walk_expr(self, ex); + self.loop_depth = self.loop_depth.saturating_sub(1); + }, + _ => { + // Calls to a function that never return + if let Some(did) = fn_def_id(self.cx, ex) { + let fn_ret_ty = self.cx.tcx.fn_sig(did).skip_binder().output().skip_binder(); + if fn_ret_ty.is_never() { + self.is_finite = true; + return; + } + } + walk_expr(self, ex); + }, + } + } +} diff --git a/src/tools/clippy/clippy_lints/src/loops/mod.rs b/src/tools/clippy/clippy_lints/src/loops/mod.rs index 892336878c7..3c9bde86bb6 100644 --- a/src/tools/clippy/clippy_lints/src/loops/mod.rs +++ b/src/tools/clippy/clippy_lints/src/loops/mod.rs @@ -3,6 +3,7 @@ mod explicit_counter_loop; mod explicit_into_iter_loop; mod explicit_iter_loop; mod for_kv_map; +mod infinite_loop; mod iter_next_loop; mod manual_find; mod manual_flatten; @@ -635,6 +636,48 @@ declare_clippy_lint! { "checking for emptiness of a `Vec` in the loop condition and popping an element in the body" } +declare_clippy_lint! { + /// ### What it does + /// Checks for infinite loops in a function where the return type is not `!` + /// and lint accordingly. + /// + /// ### Why is this bad? + /// A loop should be gently exited somewhere, or at least mark its parent function as + /// never return (`!`). + /// + /// ### Example + /// ```no_run,ignore + /// fn run_forever() { + /// loop { + /// // do something + /// } + /// } + /// ``` + /// If infinite loops are as intended: + /// ```no_run,ignore + /// fn run_forever() -> ! { + /// loop { + /// // do something + /// } + /// } + /// ``` + /// Otherwise add a `break` or `return` condition: + /// ```no_run,ignore + /// fn run_forever() { + /// loop { + /// // do something + /// if condition { + /// break; + /// } + /// } + /// } + /// ``` + #[clippy::version = "1.75.0"] + pub INFINITE_LOOP, + restriction, + "possibly unintended infinite loop" +} + pub struct Loops { msrv: Msrv, enforce_iter_loop_reborrow: bool, @@ -669,6 +712,7 @@ impl_lint_pass!(Loops => [ MANUAL_FIND, MANUAL_WHILE_LET_SOME, UNUSED_ENUMERATE_INDEX, + INFINITE_LOOP, ]); impl<'tcx> LateLintPass<'tcx> for Loops { @@ -707,10 +751,11 @@ impl<'tcx> LateLintPass<'tcx> for Loops { // check for `loop { if let {} else break }` that could be `while let` // (also matches an explicit "match" instead of "if let") // (even if the "match" or "if let" is used for declaration) - if let ExprKind::Loop(block, _, LoopSource::Loop, _) = expr.kind { + if let ExprKind::Loop(block, label, LoopSource::Loop, _) = expr.kind { // also check for empty `loop {}` statements, skipping those in #[panic_handler] empty_loop::check(cx, expr, block); while_let_loop::check(cx, expr, block); + infinite_loop::check(cx, expr, block, label); } while_let_on_iterator::check(cx, expr); diff --git a/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs b/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs index 28abecd0429..4acf46f73c9 100644 --- a/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs +++ b/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs @@ -13,8 +13,7 @@ use rustc_lint::LateContext; use rustc_middle::middle::region; use rustc_middle::ty::{self, Ty}; use rustc_span::symbol::{sym, Symbol}; -use std::iter::{self}; -use std::mem; +use std::{iter, mem}; /// Checks for looping over a range and then indexing a sequence with it. /// The iteratee must be a range literal. diff --git a/src/tools/clippy/clippy_lints/src/manual_float_methods.rs b/src/tools/clippy/clippy_lints/src/manual_float_methods.rs index 31cfb41640d..72cf1d7a354 100644 --- a/src/tools/clippy/clippy_lints/src/manual_float_methods.rs +++ b/src/tools/clippy/clippy_lints/src/manual_float_methods.rs @@ -105,7 +105,6 @@ impl<'tcx> LateLintPass<'tcx> for ManualFloatMethods { // case somebody does that for some reason && (is_infinity(const_1) && is_neg_infinity(const_2) || is_neg_infinity(const_1) && is_infinity(const_2)) - && !is_from_proc_macro(cx, expr) && let Some(local_snippet) = snippet_opt(cx, first.span) { let variant = match (kind.node, lhs_kind.node, rhs_kind.node) { @@ -113,6 +112,9 @@ impl<'tcx> LateLintPass<'tcx> for ManualFloatMethods { (BinOpKind::And, BinOpKind::Ne, BinOpKind::Ne) => Variant::ManualIsFinite, _ => return, }; + if is_from_proc_macro(cx, expr) { + return; + } span_lint_and_then(cx, variant.lint(), expr.span, variant.msg(), |diag| { match variant { diff --git a/src/tools/clippy/clippy_lints/src/manual_string_new.rs b/src/tools/clippy/clippy_lints/src/manual_string_new.rs index 737c70496c2..781db4b97f0 100644 --- a/src/tools/clippy/clippy_lints/src/manual_string_new.rs +++ b/src/tools/clippy/clippy_lints/src/manual_string_new.rs @@ -108,18 +108,16 @@ fn parse_call(cx: &LateContext<'_>, span: Span, func: &Expr<'_>, args: &[Expr<'_ let arg_kind = &args[0].kind; if let ExprKind::Path(qpath) = &func.kind { - if let QPath::TypeRelative(_, _) = qpath { - // String::from(...) or String::try_from(...) - if let QPath::TypeRelative(ty, path_seg) = qpath - && [sym::from, sym::try_from].contains(&path_seg.ident.name) - && let TyKind::Path(qpath) = &ty.kind - && let QPath::Resolved(_, path) = qpath - && let [path_seg] = path.segments - && path_seg.ident.name == sym::String - && is_expr_kind_empty_str(arg_kind) - { - warn_then_suggest(cx, span); - } + // String::from(...) or String::try_from(...) + if let QPath::TypeRelative(ty, path_seg) = qpath + && [sym::from, sym::try_from].contains(&path_seg.ident.name) + && let TyKind::Path(qpath) = &ty.kind + && let QPath::Resolved(_, path) = qpath + && let [path_seg] = path.segments + && path_seg.ident.name == sym::String + && is_expr_kind_empty_str(arg_kind) + { + warn_then_suggest(cx, span); } else if let QPath::Resolved(_, path) = qpath { // From::from(...) or TryFrom::try_from(...) if let [path_seg1, path_seg2] = path.segments diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs index 25c681bb9d9..b4f60ffadd7 100644 --- a/src/tools/clippy/clippy_lints/src/methods/mod.rs +++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs @@ -3906,7 +3906,7 @@ impl_lint_pass!(Methods => [ ]); /// Extracts a method call name, args, and `Span` of the method name. -fn method_call<'tcx>( +pub fn method_call<'tcx>( recv: &'tcx hir::Expr<'tcx>, ) -> Option<(&'tcx str, &'tcx hir::Expr<'tcx>, &'tcx [hir::Expr<'tcx>], Span, Span)> { if let ExprKind::MethodCall(path, receiver, args, call_span) = recv.kind { diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_lazy_eval.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_lazy_eval.rs index 4a651396f14..4429f032605 100644 --- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_lazy_eval.rs +++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_lazy_eval.rs @@ -19,10 +19,6 @@ pub(super) fn check<'tcx>( arg: &'tcx hir::Expr<'_>, simplify_using: &str, ) { - if is_from_proc_macro(cx, expr) { - return; - } - let is_option = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Option); let is_result = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Result); let is_bool = cx.typeck_results().expr_ty(recv).is_bool(); @@ -32,7 +28,7 @@ pub(super) fn check<'tcx>( let body = cx.tcx.hir().body(body); let body_expr = &body.value; - if usage::BindingUsageFinder::are_params_used(cx, body) { + if usage::BindingUsageFinder::are_params_used(cx, body) || is_from_proc_macro(cx, expr) { return; } diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs index 395b22ebc5d..c4775b6bd04 100644 --- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs +++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs @@ -15,8 +15,7 @@ use rustc_lint::LateContext; use rustc_middle::mir::Mutability; use rustc_middle::ty::adjustment::{Adjust, Adjustment, OverloadedDeref}; use rustc_middle::ty::{ - self, ClauseKind, EarlyBinder, GenericArg, GenericArgKind, GenericArgsRef, ParamTy, ProjectionPredicate, - TraitPredicate, Ty, + self, ClauseKind, GenericArg, GenericArgKind, GenericArgsRef, ParamTy, ProjectionPredicate, TraitPredicate, Ty, }; use rustc_span::{sym, Symbol}; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _; @@ -359,6 +358,7 @@ fn get_input_traits_and_projections<'tcx>( (trait_predicates, projection_predicates) } +#[expect(clippy::too_many_lines)] fn can_change_type<'a>(cx: &LateContext<'a>, mut expr: &'a Expr<'a>, mut ty: Ty<'a>) -> bool { for (_, node) in cx.tcx.hir().parent_iter(expr.hir_id) { match node { @@ -387,22 +387,21 @@ fn can_change_type<'a>(cx: &LateContext<'a>, mut expr: &'a Expr<'a>, mut ty: Ty< if let Some((callee_def_id, call_generic_args, recv, call_args)) = get_callee_generic_args_and_args(cx, parent_expr) { - // FIXME: the `instantiate_identity()` below seems incorrect, since we eventually - // call `tcx.try_instantiate_and_normalize_erasing_regions` further down - // (i.e., we are explicitly not in the identity context). - let fn_sig = cx.tcx.fn_sig(callee_def_id).instantiate_identity().skip_binder(); + let bound_fn_sig = cx.tcx.fn_sig(callee_def_id); + let fn_sig = bound_fn_sig.skip_binder(); if let Some(arg_index) = recv.into_iter().chain(call_args).position(|arg| arg.hir_id == expr.hir_id) - && let Some(param_ty) = fn_sig.inputs().get(arg_index) - && let ty::Param(ParamTy { index: param_index , ..}) = param_ty.kind() + && let param_ty = fn_sig.input(arg_index).skip_binder() + && let ty::Param(ParamTy { index: param_index , ..}) = *param_ty.kind() // https://github.com/rust-lang/rust-clippy/issues/9504 and https://github.com/rust-lang/rust-clippy/issues/10021 - && (*param_index as usize) < call_generic_args.len() + && (param_index as usize) < call_generic_args.len() { if fn_sig + .skip_binder() .inputs() .iter() .enumerate() .filter(|(i, _)| *i != arg_index) - .any(|(_, ty)| ty.contains(*param_ty)) + .any(|(_, ty)| ty.contains(param_ty)) { return false; } @@ -414,7 +413,7 @@ fn can_change_type<'a>(cx: &LateContext<'a>, mut expr: &'a Expr<'a>, mut ty: Ty< .iter() .filter(|predicate| { if let ClauseKind::Trait(trait_predicate) = predicate.kind().skip_binder() - && trait_predicate.trait_ref.self_ty() == *param_ty + && trait_predicate.trait_ref.self_ty() == param_ty { true } else { @@ -425,7 +424,7 @@ fn can_change_type<'a>(cx: &LateContext<'a>, mut expr: &'a Expr<'a>, mut ty: Ty< let new_subst = cx .tcx .mk_args_from_iter(call_generic_args.iter().enumerate().map(|(i, t)| { - if i == (*param_index as usize) { + if i == param_index as usize { GenericArg::from(ty) } else { t @@ -433,7 +432,7 @@ fn can_change_type<'a>(cx: &LateContext<'a>, mut expr: &'a Expr<'a>, mut ty: Ty< })); if trait_predicates.any(|predicate| { - let predicate = EarlyBinder::bind(predicate).instantiate(cx.tcx, new_subst); + let predicate = bound_fn_sig.rebind(predicate).instantiate(cx.tcx, new_subst); let obligation = Obligation::new(cx.tcx, ObligationCause::dummy(), cx.param_env, predicate); !cx.tcx .infer_ctxt() @@ -443,12 +442,12 @@ fn can_change_type<'a>(cx: &LateContext<'a>, mut expr: &'a Expr<'a>, mut ty: Ty< return false; } - let output_ty = fn_sig.output(); - if output_ty.contains(*param_ty) { + let output_ty = cx.tcx.instantiate_bound_regions_with_erased(fn_sig.output()); + if output_ty.contains(param_ty) { if let Ok(new_ty) = cx.tcx.try_instantiate_and_normalize_erasing_regions( new_subst, cx.param_env, - EarlyBinder::bind(output_ty), + bound_fn_sig.rebind(output_ty), ) { expr = parent_expr; ty = new_ty; diff --git a/src/tools/clippy/clippy_lints/src/missing_asserts_for_indexing.rs b/src/tools/clippy/clippy_lints/src/missing_asserts_for_indexing.rs index 8f2a5390781..0f18e943451 100644 --- a/src/tools/clippy/clippy_lints/src/missing_asserts_for_indexing.rs +++ b/src/tools/clippy/clippy_lints/src/missing_asserts_for_indexing.rs @@ -52,7 +52,7 @@ declare_clippy_lint! { /// Use instead: /// ```no_run /// fn sum(v: &[u8]) -> u8 { - /// assert!(v.len() > 4); + /// assert!(v.len() > 3); /// // no bounds checks /// v[0] + v[1] + v[2] + v[3] /// } @@ -87,11 +87,14 @@ enum LengthComparison { LengthLessThanOrEqualInt, /// `5 <= v.len()` IntLessThanOrEqualLength, + /// `5 == v.len()` + /// `v.len() == 5` + LengthEqualInt, } /// Extracts parts out of a length comparison expression. /// -/// E.g. for `v.len() > 5` this returns `Some((LengthComparison::IntLessThanLength, 5, `v.len()`))` +/// E.g. for `v.len() > 5` this returns `Some((LengthComparison::IntLessThanLength, 5, v.len()))` fn len_comparison<'hir>( bin_op: BinOp, left: &'hir Expr<'hir>, @@ -114,6 +117,8 @@ fn len_comparison<'hir>( (Rel::Lt, _, int_lit_pat!(right)) => Some((LengthComparison::LengthLessThanInt, *right as usize, left)), (Rel::Le, int_lit_pat!(left), _) => Some((LengthComparison::IntLessThanOrEqualLength, *left as usize, right)), (Rel::Le, _, int_lit_pat!(right)) => Some((LengthComparison::LengthLessThanOrEqualInt, *right as usize, left)), + (Rel::Eq, int_lit_pat!(left), _) => Some((LengthComparison::LengthEqualInt, *left as usize, right)), + (Rel::Eq, _, int_lit_pat!(right)) => Some((LengthComparison::LengthEqualInt, *right as usize, left)), _ => None, } } @@ -316,11 +321,11 @@ fn report_indexes(cx: &LateContext<'_>, map: &UnhashMap<u64, Vec<IndexEntry<'_>> continue; }; - match entry { + match *entry { IndexEntry::AssertWithIndex { highest_index, asserted_len, - indexes, + ref indexes, comparison, assert_span, slice, @@ -343,6 +348,12 @@ fn report_indexes(cx: &LateContext<'_>, map: &UnhashMap<u64, Vec<IndexEntry<'_>> "assert!({}.len() > {highest_index})", snippet(cx, slice.span, "..") )), + // `highest_index` here is rather a length, so we need to add 1 to it + LengthComparison::LengthEqualInt if asserted_len < highest_index + 1 => Some(format!( + "assert!({}.len() == {})", + snippet(cx, slice.span, ".."), + highest_index + 1 + )), _ => None, }; @@ -354,7 +365,7 @@ fn report_indexes(cx: &LateContext<'_>, map: &UnhashMap<u64, Vec<IndexEntry<'_>> indexes, |diag| { diag.span_suggestion( - *assert_span, + assert_span, "provide the highest index that is indexed with", sugg, Applicability::MachineApplicable, @@ -364,7 +375,7 @@ fn report_indexes(cx: &LateContext<'_>, map: &UnhashMap<u64, Vec<IndexEntry<'_>> } }, IndexEntry::IndexWithoutAssert { - indexes, + ref indexes, highest_index, slice, } if indexes.len() > 1 => { diff --git a/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs b/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs index 34119c6911c..3ff40081c47 100644 --- a/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs +++ b/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs @@ -213,7 +213,9 @@ fn check_for_unsequenced_reads(vis: &mut ReadVisitor<'_, '_>) { if parent_id == cur_id { break; } - let Some(parent_node) = vis.cx.tcx.opt_hir_node(parent_id) else { break }; + let Some(parent_node) = vis.cx.tcx.opt_hir_node(parent_id) else { + break; + }; let stop_early = match parent_node { Node::Expr(expr) => check_expr(vis, expr), diff --git a/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs b/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs index 85166b0dd95..a32bca3d038 100644 --- a/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs +++ b/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs @@ -2,7 +2,7 @@ use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::mir::{enclosing_mir, expr_local, local_assignments, used_exactly_once, PossibleBorrowerMap}; use clippy_utils::source::snippet_with_context; -use clippy_utils::ty::is_copy; +use clippy_utils::ty::{implements_trait, is_copy}; use clippy_utils::{expr_use_ctxt, peel_n_hir_expr_refs, DefinedTy, ExprUseNode}; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; @@ -169,6 +169,7 @@ fn needless_borrow_count<'tcx>( ) -> usize { let destruct_trait_def_id = cx.tcx.lang_items().destruct_trait(); let sized_trait_def_id = cx.tcx.lang_items().sized_trait(); + let drop_trait_def_id = cx.tcx.lang_items().drop_trait(); let fn_sig = cx.tcx.fn_sig(fn_id).instantiate_identity().skip_binder(); let predicates = cx.tcx.param_env(fn_id).caller_bounds(); @@ -223,7 +224,14 @@ fn needless_borrow_count<'tcx>( // elements are modified each time `check_referent` is called. let mut args_with_referent_ty = callee_args.to_vec(); - let mut check_reference_and_referent = |reference, referent| { + let mut check_reference_and_referent = |reference: &Expr<'tcx>, referent: &Expr<'tcx>| { + if let ExprKind::Field(base, _) = &referent.kind { + let base_ty = cx.typeck_results().expr_ty(base); + if drop_trait_def_id.map_or(false, |id| implements_trait(cx, base_ty, id, &[])) { + return false; + } + } + let referent_ty = cx.typeck_results().expr_ty(referent); if !is_copy(cx, referent_ty) diff --git a/src/tools/clippy/clippy_lints/src/needless_if.rs b/src/tools/clippy/clippy_lints/src/needless_if.rs index 41d05d72284..51bee4b51f6 100644 --- a/src/tools/clippy/clippy_lints/src/needless_if.rs +++ b/src/tools/clippy/clippy_lints/src/needless_if.rs @@ -44,7 +44,6 @@ impl LateLintPass<'_> for NeedlessIf { && block.stmts.is_empty() && block.expr.is_none() && !in_external_macro(cx.sess(), expr.span) - && !is_from_proc_macro(cx, expr) && let Some(then_snippet) = snippet_opt(cx, then.span) // Ignore // - empty macro expansions @@ -53,6 +52,7 @@ impl LateLintPass<'_> for NeedlessIf { // - #[cfg]'d out code && then_snippet.chars().all(|ch| matches!(ch, '{' | '}') || ch.is_ascii_whitespace()) && let Some(cond_snippet) = snippet_opt(cx, cond.span) + && !is_from_proc_macro(cx, expr) { span_lint_and_sugg( cx, diff --git a/src/tools/clippy/clippy_lints/src/no_effect.rs b/src/tools/clippy/clippy_lints/src/no_effect.rs index 6e65dd628a4..5978da83199 100644 --- a/src/tools/clippy/clippy_lints/src/no_effect.rs +++ b/src/tools/clippy/clippy_lints/src/no_effect.rs @@ -87,6 +87,17 @@ impl<'tcx> LateLintPass<'tcx> for NoEffect { fn check_no_effect(cx: &LateContext<'_>, stmt: &Stmt<'_>) -> bool { if let StmtKind::Semi(expr) = stmt.kind { + // move `expr.span.from_expansion()` ahead + if expr.span.from_expansion() { + return false; + } + let expr = peel_blocks(expr); + + if is_operator_overridden(cx, expr) { + // Return `true`, to prevent `check_unnecessary_operation` from + // linting on this statement as well. + return true; + } if has_no_effect(cx, expr) { span_lint_hir_and_then( cx, @@ -153,11 +164,26 @@ fn check_no_effect(cx: &LateContext<'_>, stmt: &Stmt<'_>) -> bool { false } -fn has_no_effect(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { - if expr.span.from_expansion() { - return false; +fn is_operator_overridden(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { + // It's very hard or impossable to check whether overridden operator have side-effect this lint. + // So, this function assume user-defined operator is overridden with an side-effect. + // The definition of user-defined structure here is ADT-type, + // Althrough this will weaken the ability of this lint, less error lint-fix happen. + match expr.kind { + ExprKind::Binary(..) | ExprKind::Unary(..) => { + // No need to check type of `lhs` and `rhs` + // because if the operator is overridden, at least one operand is ADT type + + // reference: rust/compiler/rustc_middle/src/ty/typeck_results.rs: `is_method_call`. + // use this function to check whether operator is overridden in `ExprKind::{Binary, Unary}`. + cx.typeck_results().is_method_call(expr) + }, + _ => false, } - match peel_blocks(expr).kind { +} + +fn has_no_effect(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { + match expr.kind { ExprKind::Lit(..) | ExprKind::Closure { .. } => true, ExprKind::Path(..) => !has_drop(cx, cx.typeck_results().expr_ty(expr)), ExprKind::Index(a, b, _) | ExprKind::Binary(_, a, b) => has_no_effect(cx, a) && has_no_effect(cx, b), diff --git a/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs b/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs index 1a2b20bf438..c081dec9b6b 100644 --- a/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs +++ b/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs @@ -132,7 +132,11 @@ impl ArithmeticSideEffects { } // Common entry-point to avoid code duplication. - fn issue_lint(&mut self, cx: &LateContext<'_>, expr: &hir::Expr<'_>) { + fn issue_lint<'tcx>(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) { + if is_from_proc_macro(cx, expr) { + return; + } + let msg = "arithmetic operation that can potentially result in unexpected side-effects"; span_lint(cx, ARITHMETIC_SIDE_EFFECTS, expr.span, msg); self.expr_span = Some(expr.span); @@ -160,10 +164,10 @@ impl ArithmeticSideEffects { fn manage_bin_ops<'tcx>( &mut self, cx: &LateContext<'tcx>, - expr: &hir::Expr<'tcx>, + expr: &'tcx hir::Expr<'_>, op: &Spanned<hir::BinOpKind>, - lhs: &hir::Expr<'tcx>, - rhs: &hir::Expr<'tcx>, + lhs: &'tcx hir::Expr<'_>, + rhs: &'tcx hir::Expr<'_>, ) { if constant_simple(cx, cx.typeck_results(), expr).is_some() { return; @@ -236,10 +240,10 @@ impl ArithmeticSideEffects { /// provided input. fn manage_method_call<'tcx>( &mut self, - args: &[hir::Expr<'tcx>], + args: &'tcx [hir::Expr<'_>], cx: &LateContext<'tcx>, - ps: &hir::PathSegment<'tcx>, - receiver: &hir::Expr<'tcx>, + ps: &'tcx hir::PathSegment<'_>, + receiver: &'tcx hir::Expr<'_>, ) { let Some(arg) = args.first() else { return; @@ -264,8 +268,8 @@ impl ArithmeticSideEffects { fn manage_unary_ops<'tcx>( &mut self, cx: &LateContext<'tcx>, - expr: &hir::Expr<'tcx>, - un_expr: &hir::Expr<'tcx>, + expr: &'tcx hir::Expr<'_>, + un_expr: &'tcx hir::Expr<'_>, un_op: hir::UnOp, ) { let hir::UnOp::Neg = un_op else { @@ -287,14 +291,13 @@ impl ArithmeticSideEffects { fn should_skip_expr<'tcx>(&mut self, cx: &LateContext<'tcx>, expr: &hir::Expr<'tcx>) -> bool { is_lint_allowed(cx, ARITHMETIC_SIDE_EFFECTS, expr.hir_id) - || is_from_proc_macro(cx, expr) || self.expr_span.is_some() || self.const_span.map_or(false, |sp| sp.contains(expr.span)) } } impl<'tcx> LateLintPass<'tcx> for ArithmeticSideEffects { - fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &hir::Expr<'tcx>) { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) { if self.should_skip_expr(cx, expr) { return; } diff --git a/src/tools/clippy/clippy_lints/src/renamed_lints.rs b/src/tools/clippy/clippy_lints/src/renamed_lints.rs index 9f5897d2ca7..85979903b58 100644 --- a/src/tools/clippy/clippy_lints/src/renamed_lints.rs +++ b/src/tools/clippy/clippy_lints/src/renamed_lints.rs @@ -4,8 +4,9 @@ pub static RENAMED_LINTS: &[(&str, &str)] = &[ ("clippy::almost_complete_letter_range", "clippy::almost_complete_range"), ("clippy::blacklisted_name", "clippy::disallowed_names"), - ("clippy::block_in_if_condition_expr", "clippy::blocks_in_if_conditions"), - ("clippy::block_in_if_condition_stmt", "clippy::blocks_in_if_conditions"), + ("clippy::block_in_if_condition_expr", "clippy::blocks_in_conditions"), + ("clippy::block_in_if_condition_stmt", "clippy::blocks_in_conditions"), + ("clippy::blocks_in_if_conditions", "clippy::blocks_in_conditions"), ("clippy::box_vec", "clippy::box_collection"), ("clippy::const_static_lifetime", "clippy::redundant_static_lifetimes"), ("clippy::cyclomatic_complexity", "clippy::cognitive_complexity"), diff --git a/src/tools/clippy/clippy_lints/src/repeat_vec_with_capacity.rs b/src/tools/clippy/clippy_lints/src/repeat_vec_with_capacity.rs new file mode 100644 index 00000000000..5a4933a3fce --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/repeat_vec_with_capacity.rs @@ -0,0 +1,114 @@ +use clippy_utils::consts::{constant, Constant}; +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::higher::VecArgs; +use clippy_utils::macros::root_macro_call; +use clippy_utils::source::snippet; +use clippy_utils::{expr_or_init, fn_def_id, match_def_path, paths}; +use rustc_errors::Applicability; +use rustc_hir::{Expr, ExprKind}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_session::declare_lint_pass; +use rustc_span::{sym, Span}; + +declare_clippy_lint! { + /// ### What it does + /// Looks for patterns such as `vec![Vec::with_capacity(x); n]` or `iter::repeat(Vec::with_capacity(x))`. + /// + /// ### Why is this bad? + /// These constructs work by cloning the element, but cloning a `Vec<_>` does not + /// respect the old vector's capacity and effectively discards it. + /// + /// This makes `iter::repeat(Vec::with_capacity(x))` especially suspicious because the user most certainly + /// expected that the yielded `Vec<_>` will have the requested capacity, otherwise one can simply write + /// `iter::repeat(Vec::new())` instead and it will have the same effect. + /// + /// Similarly for `vec![x; n]`, the element `x` is cloned to fill the vec. + /// Unlike `iter::repeat` however, the vec repeat macro does not have to clone the value `n` times + /// but just `n - 1` times, because it can reuse the passed value for the last slot. + /// That means that the last `Vec<_>` gets the requested capacity but all other ones do not. + /// + /// ### Example + /// ```rust + /// # use std::iter; + /// + /// let _: Vec<Vec<u8>> = vec![Vec::with_capacity(42); 123]; + /// let _: Vec<Vec<u8>> = iter::repeat(Vec::with_capacity(42)).take(123).collect(); + /// ``` + /// Use instead: + /// ```rust + /// # use std::iter; + /// + /// let _: Vec<Vec<u8>> = iter::repeat_with(|| Vec::with_capacity(42)).take(123).collect(); + /// // ^^^ this closure executes 123 times + /// // and the vecs will have the expected capacity + /// ``` + #[clippy::version = "1.74.0"] + pub REPEAT_VEC_WITH_CAPACITY, + suspicious, + "repeating a `Vec::with_capacity` expression which does not retain capacity" +} + +declare_lint_pass!(RepeatVecWithCapacity => [REPEAT_VEC_WITH_CAPACITY]); + +fn emit_lint(cx: &LateContext<'_>, span: Span, kind: &str, note: &'static str, sugg_msg: &'static str, sugg: String) { + span_lint_and_then( + cx, + REPEAT_VEC_WITH_CAPACITY, + span, + &format!("repeating `Vec::with_capacity` using `{kind}`, which does not retain capacity"), + |diag| { + diag.note(note); + diag.span_suggestion_verbose(span, sugg_msg, sugg, Applicability::MaybeIncorrect); + }, + ); +} + +/// Checks `vec![Vec::with_capacity(x); n]` +fn check_vec_macro(cx: &LateContext<'_>, expr: &Expr<'_>) { + if let Some(mac_call) = root_macro_call(expr.span) + && cx.tcx.is_diagnostic_item(sym::vec_macro, mac_call.def_id) + && let Some(VecArgs::Repeat(repeat_expr, len_expr)) = VecArgs::hir(cx, expr) + && fn_def_id(cx, repeat_expr).is_some_and(|did| match_def_path(cx, did, &paths::VEC_WITH_CAPACITY)) + && !len_expr.span.from_expansion() + && let Some(Constant::Int(2..)) = constant(cx, cx.typeck_results(), expr_or_init(cx, len_expr)) + { + emit_lint( + cx, + expr.span.source_callsite(), + "vec![x; n]", + "only the last `Vec` will have the capacity", + "if you intended to initialize multiple `Vec`s with an initial capacity, try", + format!( + "(0..{}).map(|_| {}).collect::<Vec<_>>()", + snippet(cx, len_expr.span, ""), + snippet(cx, repeat_expr.span, "..") + ), + ); + } +} + +/// Checks `iter::repeat(Vec::with_capacity(x))` +fn check_repeat_fn(cx: &LateContext<'_>, expr: &Expr<'_>) { + if !expr.span.from_expansion() + && fn_def_id(cx, expr).is_some_and(|did| cx.tcx.is_diagnostic_item(sym::iter_repeat, did)) + && let ExprKind::Call(_, [repeat_expr]) = expr.kind + && fn_def_id(cx, repeat_expr).is_some_and(|did| match_def_path(cx, did, &paths::VEC_WITH_CAPACITY)) + && !repeat_expr.span.from_expansion() + { + emit_lint( + cx, + expr.span, + "iter::repeat", + "none of the yielded `Vec`s will have the requested capacity", + "if you intended to create an iterator that yields `Vec`s with an initial capacity, try", + format!("std::iter::repeat_with(|| {})", snippet(cx, repeat_expr.span, "..")), + ); + } +} + +impl LateLintPass<'_> for RepeatVecWithCapacity { + fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { + check_vec_macro(cx, expr); + check_repeat_fn(cx, expr); + } +} diff --git a/src/tools/clippy/clippy_lints/src/same_name_method.rs b/src/tools/clippy/clippy_lints/src/same_name_method.rs index 1316343e0c2..7a351dab2d4 100644 --- a/src/tools/clippy/clippy_lints/src/same_name_method.rs +++ b/src/tools/clippy/clippy_lints/src/same_name_method.rs @@ -55,11 +55,11 @@ impl<'tcx> LateLintPass<'tcx> for SameNameMethod { if matches!(cx.tcx.def_kind(id.owner_id), DefKind::Impl { .. }) && let item = cx.tcx.hir().item(id) && let ItemKind::Impl(Impl { - items, - of_trait, - self_ty, - .. - }) = &item.kind + items, + of_trait, + self_ty, + .. + }) = &item.kind && let TyKind::Path(QPath::Resolved(_, Path { res, .. })) = self_ty.kind { if !map.contains_key(res) { @@ -75,24 +75,24 @@ impl<'tcx> LateLintPass<'tcx> for SameNameMethod { match of_trait { Some(trait_ref) => { - let mut methods_in_trait: BTreeSet<Symbol> = if let Some(Node::TraitRef(TraitRef { - path, .. - })) = cx.tcx.opt_hir_node(trait_ref.hir_ref_id) - && let Res::Def(DefKind::Trait, did) = path.res - { - // FIXME: if - // `rustc_middle::ty::assoc::AssocItems::items` is public, - // we can iterate its keys instead of `in_definition_order`, - // which's more efficient - cx.tcx - .associated_items(did) - .in_definition_order() - .filter(|assoc_item| matches!(assoc_item.kind, AssocKind::Fn)) - .map(|assoc_item| assoc_item.name) - .collect() - } else { - BTreeSet::new() - }; + let mut methods_in_trait: BTreeSet<Symbol> = + if let Some(Node::TraitRef(TraitRef { path, .. })) = + cx.tcx.opt_hir_node(trait_ref.hir_ref_id) + && let Res::Def(DefKind::Trait, did) = path.res + { + // FIXME: if + // `rustc_middle::ty::assoc::AssocItems::items` is public, + // we can iterate its keys instead of `in_definition_order`, + // which's more efficient + cx.tcx + .associated_items(did) + .in_definition_order() + .filter(|assoc_item| matches!(assoc_item.kind, AssocKind::Fn)) + .map(|assoc_item| assoc_item.name) + .collect() + } else { + BTreeSet::new() + }; let mut check_trait_method = |method_name: Symbol, trait_method_span: Span| { if let Some((impl_span, hir_id)) = existing_name.impl_methods.get(&method_name) { diff --git a/src/tools/clippy/clippy_lints/src/single_call_fn.rs b/src/tools/clippy/clippy_lints/src/single_call_fn.rs index 396d2717a13..8e181c3ccc7 100644 --- a/src/tools/clippy/clippy_lints/src/single_call_fn.rs +++ b/src/tools/clippy/clippy_lints/src/single_call_fn.rs @@ -72,8 +72,8 @@ impl<'tcx> LateLintPass<'tcx> for SingleCallFn { ) { if self.avoid_breaking_exported_api && cx.effective_visibilities.is_exported(def_id) || in_external_macro(cx.sess(), span) - || is_from_proc_macro(cx, &(&kind, body, cx.tcx.local_def_id_to_hir_id(def_id), span)) || is_in_test_function(cx.tcx, body.value.hir_id) + || is_from_proc_macro(cx, &(&kind, body, cx.tcx.local_def_id_to_hir_id(def_id), span)) { return; } diff --git a/src/tools/clippy/clippy_lints/src/uninhabited_references.rs b/src/tools/clippy/clippy_lints/src/uninhabited_references.rs new file mode 100644 index 00000000000..d41576cadad --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/uninhabited_references.rs @@ -0,0 +1,84 @@ +use clippy_utils::diagnostics::span_lint; +use rustc_hir::intravisit::FnKind; +use rustc_hir::{Body, Expr, ExprKind, FnDecl, FnRetTy, TyKind, UnOp}; +use rustc_hir_analysis::hir_ty_to_ty; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::lint::in_external_macro; +use rustc_session::declare_lint_pass; +use rustc_span::def_id::LocalDefId; +use rustc_span::Span; + +declare_clippy_lint! { + /// ### What it does + /// It detects references to uninhabited types, such as `!` and + /// warns when those are either dereferenced or returned from a function. + /// + /// ### Why is this bad? + /// Dereferencing a reference to an uninhabited type would create + /// an instance of such a type, which cannot exist. This constitutes + /// undefined behaviour. Such a reference could have been created + /// by `unsafe` code. + /// + /// ### Example + /// The following function can return a reference to an uninhabited type + /// (`Infallible`) because it uses `unsafe` code to create it. However, + /// the user of such a function could dereference the return value and + /// trigger an undefined behavior from safe code. + /// + /// ```no_run + /// fn create_ref() -> &'static std::convert::Infallible { + /// unsafe { std::mem::transmute(&()) } + /// } + /// ``` + #[clippy::version = "1.76.0"] + pub UNINHABITED_REFERENCES, + suspicious, + "reference to uninhabited type" +} + +declare_lint_pass!(UninhabitedReferences => [UNINHABITED_REFERENCES]); + +impl LateLintPass<'_> for UninhabitedReferences { + fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'_ Expr<'_>) { + if in_external_macro(cx.tcx.sess, expr.span) { + return; + } + + if let ExprKind::Unary(UnOp::Deref, _) = expr.kind { + let ty = cx.typeck_results().expr_ty_adjusted(expr); + if ty.is_privately_uninhabited(cx.tcx, cx.param_env) { + span_lint( + cx, + UNINHABITED_REFERENCES, + expr.span, + "dereferencing a reference to an uninhabited type is undefined behavior", + ); + } + } + } + + fn check_fn( + &mut self, + cx: &LateContext<'_>, + kind: FnKind<'_>, + fndecl: &'_ FnDecl<'_>, + _: &'_ Body<'_>, + span: Span, + _: LocalDefId, + ) { + if in_external_macro(cx.tcx.sess, span) || matches!(kind, FnKind::Closure) { + return; + } + if let FnRetTy::Return(hir_ty) = fndecl.output + && let TyKind::Ref(_, mut_ty) = hir_ty.kind + && hir_ty_to_ty(cx.tcx, mut_ty.ty).is_privately_uninhabited(cx.tcx, cx.param_env) + { + span_lint( + cx, + UNINHABITED_REFERENCES, + hir_ty.span, + "dereferencing a reference to an uninhabited type would be undefined behavior", + ); + } + } +} diff --git a/src/tools/clippy/clippy_lints/src/unnecessary_map_on_constructor.rs b/src/tools/clippy/clippy_lints/src/unnecessary_map_on_constructor.rs index 9979e02297e..2b0d2d61d20 100644 --- a/src/tools/clippy/clippy_lints/src/unnecessary_map_on_constructor.rs +++ b/src/tools/clippy/clippy_lints/src/unnecessary_map_on_constructor.rs @@ -66,7 +66,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryMapOnConstructor { }; match constructor_symbol { sym::Some | sym::Ok if path.ident.name == rustc_span::sym::map => (), - sym::Err if path.ident.name == sym!(map_err) => (), + sym::Err if path.ident.name == sym::map_err => (), _ => return, } diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs index 373b076f92c..fae1b90ace2 100644 --- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs +++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs @@ -28,12 +28,12 @@ use rustc_span::{sym, Loc, Span, Symbol}; use serde::ser::SerializeStruct; use serde::{Serialize, Serializer}; use std::collections::{BTreeSet, BinaryHeap}; -use std::fmt; use std::fmt::Write as _; use std::fs::{self, File}; use std::io::prelude::*; use std::path::{Path, PathBuf}; use std::process::Command; +use std::{env, fmt}; /// This is the json output file of the lint collector. const JSON_OUTPUT_FILE: &str = "../util/gh-pages/lints.json"; @@ -415,7 +415,7 @@ fn get_lint_output(lint_name: &str, example: &[&mut String], clippy_project_root let prefixed_name = format!("{CLIPPY_LINT_GROUP_PREFIX}{lint_name}"); - let mut cmd = Command::new("cargo"); + let mut cmd = Command::new(env::var("CARGO").unwrap_or("cargo".into())); cmd.current_dir(clippy_project_root) .env("CARGO_INCREMENTAL", "0") diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs index 31a81a52497..6e449dc9806 100644 --- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs +++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs @@ -218,7 +218,7 @@ fn path_to_matched_type(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option<Ve ExprKind::Path(ref qpath) => match cx.qpath_res(qpath, expr.hir_id) { Res::Local(hir_id) => { let parent_id = cx.tcx.hir().parent_id(hir_id); - if let Some(Node::Local(Local { init: Some(init), .. })) = cx.tcx.hir_node(parent_id) { + if let Node::Local(Local { init: Some(init), .. }) = cx.tcx.hir_node(parent_id) { path_to_matched_type(cx, init) } else { None @@ -246,7 +246,7 @@ fn path_to_matched_type(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option<Ve fn read_mir_alloc_def_path<'tcx>(cx: &LateContext<'tcx>, alloc: &'tcx Allocation, ty: Ty<'_>) -> Option<Vec<String>> { let (alloc, ty) = if let ty::Ref(_, ty, Mutability::Not) = *ty.kind() { let &alloc = alloc.provenance().ptrs().values().next()?; - if let GlobalAlloc::Memory(alloc) = cx.tcx.global_alloc(alloc) { + if let GlobalAlloc::Memory(alloc) = cx.tcx.global_alloc(alloc.alloc_id()) { (alloc.inner(), ty) } else { return None; @@ -264,7 +264,7 @@ fn read_mir_alloc_def_path<'tcx>(cx: &LateContext<'tcx>, alloc: &'tcx Allocation .ptrs() .values() .map(|&alloc| { - if let GlobalAlloc::Memory(alloc) = cx.tcx.global_alloc(alloc) { + if let GlobalAlloc::Memory(alloc) = cx.tcx.global_alloc(alloc.alloc_id()) { let alloc = alloc.inner(); str::from_utf8(alloc.inspect_with_uninit_and_ptr_outside_interpreter(0..alloc.len())) .ok() diff --git a/src/tools/clippy/clippy_lints/src/vec.rs b/src/tools/clippy/clippy_lints/src/vec.rs index ba958c5b392..5e13c73f035 100644 --- a/src/tools/clippy/clippy_lints/src/vec.rs +++ b/src/tools/clippy/clippy_lints/src/vec.rs @@ -1,25 +1,27 @@ +use std::collections::BTreeMap; use std::ops::ControlFlow; use clippy_config::msrvs::{self, Msrv}; use clippy_utils::consts::{constant, Constant}; -use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::diagnostics::span_lint_hir_and_then; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::is_copy; use clippy_utils::visitors::for_each_local_use_after_expr; use clippy_utils::{get_parent_expr, higher, is_trait_method}; use rustc_errors::Applicability; -use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability, Node, PatKind}; +use rustc_hir::{BorrowKind, Expr, ExprKind, HirId, Mutability, Node, PatKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::{self, Ty}; use rustc_session::impl_lint_pass; -use rustc_span::{sym, Span}; +use rustc_span::{sym, DesugaringKind, Span}; #[expect(clippy::module_name_repetitions)] #[derive(Clone)] pub struct UselessVec { pub too_large_for_stack: u64, pub msrv: Msrv, + pub span_to_lint_map: BTreeMap<Span, Option<(HirId, SuggestedType, String, Applicability)>>, } declare_clippy_lint! { @@ -69,64 +71,88 @@ pub fn is_allowed_vec_method(cx: &LateContext<'_>, e: &Expr<'_>) -> bool { impl<'tcx> LateLintPass<'tcx> for UselessVec { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - // search for `&vec![_]` or `vec![_]` expressions where the adjusted type is `&[_]` - if adjusts_to_slice(cx, expr) - && let Some(vec_args) = higher::VecArgs::hir(cx, expr.peel_borrows()) - { - let (suggest_slice, span) = if let ExprKind::AddrOf(BorrowKind::Ref, mutability, _) = expr.kind { - // `expr` is `&vec![_]`, so suggest `&[_]` (or `&mut[_]` resp.) - (SuggestedType::SliceRef(mutability), expr.span) - } else { - // `expr` is the `vec![_]` expansion, so suggest `[_]` - // and also use the span of the actual `vec![_]` expression - (SuggestedType::Array, expr.span.ctxt().outer_expn_data().call_site) - }; - - self.check_vec_macro(cx, &vec_args, span, suggest_slice); - } + if let Some(vec_args) = higher::VecArgs::hir(cx, expr.peel_borrows()) { + // search for `let foo = vec![_]` expressions where all uses of `foo` + // adjust to slices or call a method that exist on slices (e.g. len) + if let Node::Local(local) = cx.tcx.hir().get_parent(expr.hir_id) + // for now ignore locals with type annotations. + // this is to avoid compile errors when doing the suggestion here: let _: Vec<_> = vec![..]; + && local.ty.is_none() + && let PatKind::Binding(_, id, ..) = local.pat.kind + && is_copy(cx, vec_type(cx.typeck_results().expr_ty_adjusted(expr.peel_borrows()))) + { + let only_slice_uses = for_each_local_use_after_expr(cx, id, expr.hir_id, |expr| { + // allow indexing into a vec and some set of allowed method calls that exist on slices, too + if let Some(parent) = get_parent_expr(cx, expr) + && (adjusts_to_slice(cx, expr) + || matches!(parent.kind, ExprKind::Index(..)) + || is_allowed_vec_method(cx, parent)) + { + ControlFlow::Continue(()) + } else { + ControlFlow::Break(()) + } + }) + .is_continue(); - // search for `let foo = vec![_]` expressions where all uses of `foo` - // adjust to slices or call a method that exist on slices (e.g. len) - if let Some(vec_args) = higher::VecArgs::hir(cx, expr) - && let Node::Local(local) = cx.tcx.hir().get_parent(expr.hir_id) - // for now ignore locals with type annotations. - // this is to avoid compile errors when doing the suggestion here: let _: Vec<_> = vec![..]; - && local.ty.is_none() - && let PatKind::Binding(_, id, ..) = local.pat.kind - && is_copy(cx, vec_type(cx.typeck_results().expr_ty_adjusted(expr))) - { - let only_slice_uses = for_each_local_use_after_expr(cx, id, expr.hir_id, |expr| { - // allow indexing into a vec and some set of allowed method calls that exist on slices, too - if let Some(parent) = get_parent_expr(cx, expr) - && (adjusts_to_slice(cx, expr) - || matches!(parent.kind, ExprKind::Index(..)) - || is_allowed_vec_method(cx, parent)) - { - ControlFlow::Continue(()) + let span = expr.span.ctxt().outer_expn_data().call_site; + if only_slice_uses { + self.check_vec_macro(cx, &vec_args, span, expr.hir_id, SuggestedType::Array); } else { - ControlFlow::Break(()) + self.span_to_lint_map.insert(span, None); + } + } + // if the local pattern has a specified type, do not lint. + else if let Some(_) = higher::VecArgs::hir(cx, expr) + && let Node::Local(local) = cx.tcx.hir().get_parent(expr.hir_id) + && local.ty.is_some() + { + let span = expr.span.ctxt().outer_expn_data().call_site; + self.span_to_lint_map.insert(span, None); + } + // search for `for _ in vec![...]` + else if let Some(parent) = get_parent_expr(cx, expr) + && parent.span.is_desugaring(DesugaringKind::ForLoop) + && self.msrv.meets(msrvs::ARRAY_INTO_ITERATOR) + { + // report the error around the `vec!` not inside `<std macros>:` + let span = expr.span.ctxt().outer_expn_data().call_site; + self.check_vec_macro(cx, &vec_args, span, expr.hir_id, SuggestedType::Array); + } + // search for `&vec![_]` or `vec![_]` expressions where the adjusted type is `&[_]` + else { + let (suggest_slice, span) = if let ExprKind::AddrOf(BorrowKind::Ref, mutability, _) = expr.kind { + // `expr` is `&vec![_]`, so suggest `&[_]` (or `&mut[_]` resp.) + (SuggestedType::SliceRef(mutability), expr.span) + } else { + // `expr` is the `vec![_]` expansion, so suggest `[_]` + // and also use the span of the actual `vec![_]` expression + (SuggestedType::Array, expr.span.ctxt().outer_expn_data().call_site) + }; + + if adjusts_to_slice(cx, expr) { + self.check_vec_macro(cx, &vec_args, span, expr.hir_id, suggest_slice); + } else { + self.span_to_lint_map.insert(span, None); } - }) - .is_continue(); - - if only_slice_uses { - self.check_vec_macro( - cx, - &vec_args, - expr.span.ctxt().outer_expn_data().call_site, - SuggestedType::Array, - ); } } + } - // search for `for _ in vec![…]` - if let Some(higher::ForLoop { arg, .. }) = higher::ForLoop::hir(expr) - && let Some(vec_args) = higher::VecArgs::hir(cx, arg) - && self.msrv.meets(msrvs::ARRAY_INTO_ITERATOR) - { - // report the error around the `vec!` not inside `<std macros>:` - let span = arg.span.ctxt().outer_expn_data().call_site; - self.check_vec_macro(cx, &vec_args, span, SuggestedType::Array); + fn check_crate_post(&mut self, cx: &LateContext<'tcx>) { + for (span, lint_opt) in &self.span_to_lint_map { + if let Some((hir_id, suggest_slice, snippet, applicability)) = lint_opt { + let help_msg = format!( + "you can use {} directly", + match suggest_slice { + SuggestedType::SliceRef(_) => "a slice", + SuggestedType::Array => "an array", + } + ); + span_lint_hir_and_then(cx, USELESS_VEC, *hir_id, *span, "useless use of `vec!`", |diag| { + diag.span_suggestion(*span, help_msg, snippet, *applicability); + }); + } } } @@ -134,7 +160,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessVec { } #[derive(Copy, Clone)] -enum SuggestedType { +pub(crate) enum SuggestedType { /// Suggest using a slice `&[..]` / `&mut [..]` SliceRef(Mutability), /// Suggest using an array: `[..]` @@ -147,6 +173,7 @@ impl UselessVec { cx: &LateContext<'tcx>, vec_args: &higher::VecArgs<'tcx>, span: Span, + hir_id: HirId, suggest_slice: SuggestedType, ) { if span.from_expansion() { @@ -204,21 +231,9 @@ impl UselessVec { }, }; - span_lint_and_sugg( - cx, - USELESS_VEC, - span, - "useless use of `vec!`", - &format!( - "you can use {} directly", - match suggest_slice { - SuggestedType::SliceRef(_) => "a slice", - SuggestedType::Array => "an array", - } - ), - snippet, - applicability, - ); + self.span_to_lint_map + .entry(span) + .or_insert(Some((hir_id, suggest_slice, snippet, applicability))); } } diff --git a/src/tools/clippy/clippy_utils/src/ast_utils.rs b/src/tools/clippy/clippy_utils/src/ast_utils.rs index 47237de4fef..e36f2fa87a7 100644 --- a/src/tools/clippy/clippy_utils/src/ast_utils.rs +++ b/src/tools/clippy/clippy_utils/src/ast_utils.rs @@ -206,7 +206,7 @@ pub fn eq_expr(l: &Expr, r: &Expr) -> bool { ) => { eq_closure_binder(lb, rb) && lc == rc - && la.map_or(false, |la| la.is_async()) == ra.map_or(false, |ra| ra.is_async()) + && la.map_or(false, CoroutineKind::is_async) == ra.map_or(false, CoroutineKind::is_async) && lm == rm && eq_fn_decl(lf, rf) && eq_expr(le, re) @@ -564,13 +564,16 @@ pub fn eq_fn_sig(l: &FnSig, r: &FnSig) -> bool { } fn eq_opt_coroutine_kind(l: Option<CoroutineKind>, r: Option<CoroutineKind>) -> bool { - match (l, r) { + matches!( + (l, r), (Some(CoroutineKind::Async { .. }), Some(CoroutineKind::Async { .. })) - | (Some(CoroutineKind::Gen { .. }), Some(CoroutineKind::Gen { .. })) - | (Some(CoroutineKind::AsyncGen { .. }), Some(CoroutineKind::AsyncGen { .. })) => true, - (None, None) => true, - _ => false, - } + | (Some(CoroutineKind::Gen { .. }), Some(CoroutineKind::Gen { .. })) + | ( + Some(CoroutineKind::AsyncGen { .. }), + Some(CoroutineKind::AsyncGen { .. }) + ) + | (None, None) + ) } pub fn eq_fn_header(l: &FnHeader, r: &FnHeader) -> bool { diff --git a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs index 3f68b6d75b5..470d31fa3e1 100644 --- a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs +++ b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs @@ -12,14 +12,14 @@ //! code was written, and check if the span contains that text. Note this will only work correctly //! if the span is not from a `macro_rules` based macro. -use rustc_ast::ast::{AttrKind, Attribute, IntTy, LitIntType, LitKind, StrStyle, UintTy}; +use rustc_ast::ast::{AttrKind, Attribute, IntTy, LitIntType, LitKind, StrStyle, TraitObjectSyntax, UintTy}; use rustc_ast::token::CommentKind; use rustc_ast::AttrStyle; use rustc_hir::intravisit::FnKind; use rustc_hir::{ - Block, BlockCheckMode, Body, Closure, Destination, Expr, ExprKind, FieldDef, FnHeader, HirId, Impl, ImplItem, - ImplItemKind, IsAuto, Item, ItemKind, LoopSource, MatchSource, MutTy, Node, QPath, TraitItem, TraitItemKind, Ty, - TyKind, UnOp, UnsafeSource, Unsafety, Variant, VariantData, YieldSource, + Block, BlockCheckMode, Body, Closure, Destination, Expr, ExprKind, FieldDef, FnHeader, FnRetTy, HirId, Impl, + ImplItem, ImplItemKind, IsAuto, Item, ItemKind, LoopSource, MatchSource, MutTy, Node, QPath, TraitItem, + TraitItemKind, Ty, TyKind, UnOp, UnsafeSource, Unsafety, Variant, VariantData, YieldSource, }; use rustc_lint::{LateContext, LintContext}; use rustc_middle::ty::TyCtxt; @@ -33,8 +33,6 @@ use rustc_target::spec::abi::Abi; pub enum Pat { /// A single string. Str(&'static str), - /// A single string. - OwnedStr(String), /// Any of the given strings. MultiStr(&'static [&'static str]), /// Any of the given strings. @@ -59,14 +57,12 @@ fn span_matches_pat(sess: &Session, span: Span, start_pat: Pat, end_pat: Pat) -> let end_str = s.trim_end_matches(|c: char| c.is_whitespace() || c == ')' || c == ','); (match start_pat { Pat::Str(text) => start_str.starts_with(text), - Pat::OwnedStr(text) => start_str.starts_with(&text), Pat::MultiStr(texts) => texts.iter().any(|s| start_str.starts_with(s)), Pat::OwnedMultiStr(texts) => texts.iter().any(|s| start_str.starts_with(s)), Pat::Sym(sym) => start_str.starts_with(sym.as_str()), Pat::Num => start_str.as_bytes().first().map_or(false, u8::is_ascii_digit), } && match end_pat { Pat::Str(text) => end_str.ends_with(text), - Pat::OwnedStr(text) => end_str.starts_with(&text), Pat::MultiStr(texts) => texts.iter().any(|s| start_str.ends_with(s)), Pat::OwnedMultiStr(texts) => texts.iter().any(|s| start_str.starts_with(s)), Pat::Sym(sym) => end_str.ends_with(sym.as_str()), @@ -125,6 +121,8 @@ fn qpath_search_pat(path: &QPath<'_>) -> (Pat, Pat) { fn expr_search_pat(tcx: TyCtxt<'_>, e: &Expr<'_>) -> (Pat, Pat) { match e.kind { ExprKind::ConstBlock(_) => (Pat::Str("const"), Pat::Str("}")), + // Parenthesis are trimmed from the text before the search patterns are matched. + // See: `span_matches_pat` ExprKind::Tup([]) => (Pat::Str(")"), Pat::Str("(")), ExprKind::Unary(UnOp::Deref, e) => (Pat::Str("*"), expr_search_pat(tcx, e).1), ExprKind::Unary(UnOp::Not, e) => (Pat::Str("!"), expr_search_pat(tcx, e).1), @@ -286,23 +284,17 @@ fn fn_kind_pat(tcx: TyCtxt<'_>, kind: &FnKind<'_>, body: &Body<'_>, hir_id: HirI fn attr_search_pat(attr: &Attribute) -> (Pat, Pat) { match attr.kind { AttrKind::Normal(..) => { - let mut pat = if matches!(attr.style, AttrStyle::Outer) { - (Pat::Str("#["), Pat::Str("]")) - } else { - (Pat::Str("#!["), Pat::Str("]")) - }; - - if let Some(ident) = attr.ident() - && let Pat::Str(old_pat) = pat.0 - { + if let Some(ident) = attr.ident() { // TODO: I feel like it's likely we can use `Cow` instead but this will require quite a bit of // refactoring // NOTE: This will likely have false positives, like `allow = 1` - pat.0 = Pat::OwnedMultiStr(vec![ident.to_string(), old_pat.to_owned()]); - pat.1 = Pat::Str(""); + ( + Pat::OwnedMultiStr(vec![ident.to_string(), "#".to_owned()]), + Pat::Str(""), + ) + } else { + (Pat::Str("#"), Pat::Str("]")) } - - pat }, AttrKind::DocComment(_kind @ CommentKind::Line, ..) => { if matches!(attr.style, AttrStyle::Outer) { @@ -324,32 +316,42 @@ fn attr_search_pat(attr: &Attribute) -> (Pat, Pat) { fn ty_search_pat(ty: &Ty<'_>) -> (Pat, Pat) { match ty.kind { TyKind::Slice(..) | TyKind::Array(..) => (Pat::Str("["), Pat::Str("]")), - TyKind::Ptr(MutTy { mutbl, ty }) => ( - if mutbl.is_mut() { - Pat::Str("*const") - } else { - Pat::Str("*mut") - }, - ty_search_pat(ty).1, - ), + TyKind::Ptr(MutTy { ty, .. }) => (Pat::Str("*"), ty_search_pat(ty).1), TyKind::Ref(_, MutTy { ty, .. }) => (Pat::Str("&"), ty_search_pat(ty).1), TyKind::BareFn(bare_fn) => ( - Pat::OwnedStr(format!("{}{} fn", bare_fn.unsafety.prefix_str(), bare_fn.abi.name())), - ty_search_pat(ty).1, + if bare_fn.unsafety == Unsafety::Unsafe { + Pat::Str("unsafe") + } else if bare_fn.abi != Abi::Rust { + Pat::Str("extern") + } else { + Pat::MultiStr(&["fn", "extern"]) + }, + match bare_fn.decl.output { + FnRetTy::DefaultReturn(_) => { + if let [.., ty] = bare_fn.decl.inputs { + ty_search_pat(ty).1 + } else { + Pat::Str("(") + } + }, + FnRetTy::Return(ty) => ty_search_pat(ty).1, + }, ), - TyKind::Never => (Pat::Str("!"), Pat::Str("")), - TyKind::Tup(..) => (Pat::Str("("), Pat::Str(")")), + TyKind::Never => (Pat::Str("!"), Pat::Str("!")), + // Parenthesis are trimmed from the text before the search patterns are matched. + // See: `span_matches_pat` + TyKind::Tup([]) => (Pat::Str(")"), Pat::Str("(")), + TyKind::Tup([ty]) => ty_search_pat(ty), + TyKind::Tup([head, .., tail]) => (ty_search_pat(head).0, ty_search_pat(tail).1), TyKind::OpaqueDef(..) => (Pat::Str("impl"), Pat::Str("")), TyKind::Path(qpath) => qpath_search_pat(&qpath), - // NOTE: This is missing `TraitObject`. It will always return true then. + TyKind::Infer => (Pat::Str("_"), Pat::Str("_")), + TyKind::TraitObject(_, _, TraitObjectSyntax::Dyn) => (Pat::Str("dyn"), Pat::Str("")), + // NOTE: `TraitObject` is incomplete. It will always return true then. _ => (Pat::Str(""), Pat::Str("")), } } -fn ident_search_pat(ident: Ident) -> (Pat, Pat) { - (Pat::OwnedStr(ident.name.as_str().to_owned()), Pat::Str("")) -} - pub trait WithSearchPat<'cx> { type Context: LintContext; fn search_pat(&self, cx: &Self::Context) -> (Pat, Pat); @@ -408,7 +410,7 @@ impl<'cx> WithSearchPat<'cx> for Ident { type Context = LateContext<'cx>; fn search_pat(&self, _cx: &Self::Context) -> (Pat, Pat) { - ident_search_pat(*self) + (Pat::Sym(self.name), Pat::Sym(self.name)) } fn span(&self) -> Span { diff --git a/src/tools/clippy/clippy_utils/src/diagnostics.rs b/src/tools/clippy/clippy_utils/src/diagnostics.rs index fa56e5b0ba2..7562961538e 100644 --- a/src/tools/clippy/clippy_utils/src/diagnostics.rs +++ b/src/tools/clippy/clippy_utils/src/diagnostics.rs @@ -49,7 +49,6 @@ pub fn span_lint<T: LintContext>(cx: &T, lint: &'static Lint, sp: impl Into<Mult #[expect(clippy::disallowed_methods)] cx.struct_span_lint(lint, sp, msg.to_string(), |diag| { docs_link(diag, lint); - diag }); } @@ -90,7 +89,6 @@ pub fn span_lint_and_help<T: LintContext>( diag.help(help.to_string()); } docs_link(diag, lint); - diag }); } @@ -134,7 +132,6 @@ pub fn span_lint_and_note<T: LintContext>( diag.note(note); } docs_link(diag, lint); - diag }); } @@ -152,7 +149,6 @@ where cx.struct_span_lint(lint, sp, msg.to_string(), |diag| { f(diag); docs_link(diag, lint); - diag }); } @@ -160,7 +156,6 @@ pub fn span_lint_hir(cx: &LateContext<'_>, lint: &'static Lint, hir_id: HirId, s #[expect(clippy::disallowed_methods)] cx.tcx.struct_span_lint_hir(lint, hir_id, sp, msg.to_string(), |diag| { docs_link(diag, lint); - diag }); } @@ -176,7 +171,6 @@ pub fn span_lint_hir_and_then( cx.tcx.struct_span_lint_hir(lint, hir_id, sp, msg.to_string(), |diag| { f(diag); docs_link(diag, lint); - diag }); } diff --git a/src/tools/clippy/clippy_utils/src/ty.rs b/src/tools/clippy/clippy_utils/src/ty.rs index 868c92f2f54..61d0663aa83 100644 --- a/src/tools/clippy/clippy_utils/src/ty.rs +++ b/src/tools/clippy/clippy_utils/src/ty.rs @@ -214,8 +214,17 @@ pub fn implements_trait<'tcx>( trait_id: DefId, args: &[GenericArg<'tcx>], ) -> bool { - let callee_id = cx.enclosing_body.map(|body| cx.tcx.hir().body_owner(body).owner.to_def_id()); - implements_trait_with_env_from_iter(cx.tcx, cx.param_env, ty, trait_id, callee_id, args.iter().map(|&x| Some(x))) + let callee_id = cx + .enclosing_body + .map(|body| cx.tcx.hir().body_owner(body).owner.to_def_id()); + implements_trait_with_env_from_iter( + cx.tcx, + cx.param_env, + ty, + trait_id, + callee_id, + args.iter().map(|&x| Some(x)), + ) } /// Same as `implements_trait` but allows using a `ParamEnv` different from the lint context. @@ -227,7 +236,14 @@ pub fn implements_trait_with_env<'tcx>( callee_id: DefId, args: &[GenericArg<'tcx>], ) -> bool { - implements_trait_with_env_from_iter(tcx, param_env, ty, trait_id, Some(callee_id), args.iter().map(|&x| Some(x))) + implements_trait_with_env_from_iter( + tcx, + param_env, + ty, + trait_id, + Some(callee_id), + args.iter().map(|&x| Some(x)), + ) } /// Same as `implements_trait_from_env` but takes the arguments as an iterator. @@ -248,19 +264,28 @@ pub fn implements_trait_with_env_from_iter<'tcx>( } let infcx = tcx.infer_ctxt().build(); - let args = args.into_iter().map(|arg| { - arg.into().unwrap_or_else(|| { - let orig = TypeVariableOrigin { - kind: TypeVariableOriginKind::MiscVariable, - span: DUMMY_SP, - }; - infcx.next_ty_var(orig).into() + let args = args + .into_iter() + .map(|arg| { + arg.into().unwrap_or_else(|| { + let orig = TypeVariableOrigin { + kind: TypeVariableOriginKind::MiscVariable, + span: DUMMY_SP, + }; + infcx.next_ty_var(orig).into() + }) }) - }).collect::<Vec<_>>(); + .collect::<Vec<_>>(); // If an effect arg was not specified, we need to specify it. - let effect_arg = if tcx.generics_of(trait_id).host_effect_index.is_some_and(|x| args.get(x - 1).is_none()) { - Some(GenericArg::from(callee_id.map(|def_id| tcx.expected_host_effect_param_for_body(def_id)).unwrap_or(tcx.consts.true_))) + let effect_arg = if tcx + .generics_of(trait_id) + .host_effect_index + .is_some_and(|x| args.get(x - 1).is_none()) + { + Some(GenericArg::from(callee_id.map_or(tcx.consts.true_, |def_id| { + tcx.expected_host_effect_param_for_body(def_id) + }))) } else { None }; @@ -268,9 +293,7 @@ pub fn implements_trait_with_env_from_iter<'tcx>( let trait_ref = TraitRef::new( tcx, trait_id, - Some(GenericArg::from(ty)) - .into_iter() - .chain(args).chain(effect_arg), + Some(GenericArg::from(ty)).into_iter().chain(args).chain(effect_arg), ); debug_assert_matches!( diff --git a/src/tools/clippy/lintcheck/src/main.rs b/src/tools/clippy/lintcheck/src/main.rs index 841b605f5fb..88966b41f69 100644 --- a/src/tools/clippy/lintcheck/src/main.rs +++ b/src/tools/clippy/lintcheck/src/main.rs @@ -367,7 +367,7 @@ impl Crate { // // The wrapper is set to the `lintcheck` so we can force enable linting and ignore certain crates // (see `crate::driver`) - let status = Command::new("cargo") + let status = Command::new(env::var("CARGO").unwrap_or("cargo".into())) .arg("check") .arg("--quiet") .current_dir(&self.path) @@ -441,7 +441,7 @@ impl Crate { /// Builds clippy inside the repo to make sure we have a clippy executable we can use. fn build_clippy() { - let status = Command::new("cargo") + let status = Command::new(env::var("CARGO").unwrap_or("cargo".into())) .arg("build") .status() .expect("Failed to build clippy!"); @@ -816,7 +816,7 @@ fn lintcheck_test() { "--crates-toml", "lintcheck/test_sources.toml", ]; - let status = std::process::Command::new("cargo") + let status = std::process::Command::new(env::var("CARGO").unwrap_or("cargo".into())) .args(args) .current_dir("..") // repo root .status(); diff --git a/src/tools/clippy/rust-toolchain b/src/tools/clippy/rust-toolchain index 684cf4574b9..d575da6dece 100644 --- a/src/tools/clippy/rust-toolchain +++ b/src/tools/clippy/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2023-12-01" +channel = "nightly-2023-12-16" components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"] diff --git a/src/tools/clippy/src/main.rs b/src/tools/clippy/src/main.rs index bbf7d22c850..dffa854177b 100644 --- a/src/tools/clippy/src/main.rs +++ b/src/tools/clippy/src/main.rs @@ -105,7 +105,7 @@ impl ClippyCmd { } fn into_std_cmd(self) -> Command { - let mut cmd = Command::new("cargo"); + let mut cmd = Command::new(env::var("CARGO").unwrap_or("cargo".into())); let clippy_args: String = self .clippy_args .iter() diff --git a/src/tools/clippy/tests/headers.rs b/src/tools/clippy/tests/headers.rs index 7eec9a9cdd2..d1f986ef526 100644 --- a/src/tools/clippy/tests/headers.rs +++ b/src/tools/clippy/tests/headers.rs @@ -12,7 +12,12 @@ fn old_test_headers() { for entry in WalkDir::new("tests") { let entry = entry.unwrap(); - if !entry.file_type().is_file() { + let is_hidden_file = entry + .file_name() + .to_str() + .expect("non-UTF-8 file name") + .starts_with('.'); + if is_hidden_file || !entry.file_type().is_file() { continue; } diff --git a/src/tools/clippy/tests/ui-cargo/module_style/fail_mod_remap/Cargo.stderr b/src/tools/clippy/tests/ui-cargo/module_style/fail_mod_remap/Cargo.stderr index d776feb7f2e..bdceb752608 100644 --- a/src/tools/clippy/tests/ui-cargo/module_style/fail_mod_remap/Cargo.stderr +++ b/src/tools/clippy/tests/ui-cargo/module_style/fail_mod_remap/Cargo.stderr @@ -8,4 +8,4 @@ error: `mod.rs` files are required, found `src/bad.rs` = note: `-D clippy::self-named-module-files` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::self_named_module_files)]` -error: could not compile `fail-mod-remap` (bin "fail-mod-remap") due to previous error +error: could not compile `fail-mod-remap` (bin "fail-mod-remap") due to 1 previous error diff --git a/src/tools/clippy/tests/ui-cargo/module_style/fail_no_mod/Cargo.stderr b/src/tools/clippy/tests/ui-cargo/module_style/fail_no_mod/Cargo.stderr index 22558bc4ce8..06eaa071e82 100644 --- a/src/tools/clippy/tests/ui-cargo/module_style/fail_no_mod/Cargo.stderr +++ b/src/tools/clippy/tests/ui-cargo/module_style/fail_no_mod/Cargo.stderr @@ -8,4 +8,4 @@ error: `mod.rs` files are not allowed, found `src/bad/mod.rs` = note: `-D clippy::mod-module-files` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::mod_module_files)]` -error: could not compile `fail-no-mod` (bin "fail-no-mod") due to previous error +error: could not compile `fail-no-mod` (bin "fail-no-mod") due to 1 previous error diff --git a/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/fail/Cargo.stderr b/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/fail/Cargo.stderr index 4beedc10830..39f7176ade2 100644 --- a/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/fail/Cargo.stderr +++ b/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/fail/Cargo.stderr @@ -3,4 +3,4 @@ error: multiple versions for dependency `winapi`: 0.2.8, 0.3.9 = note: `-D clippy::multiple-crate-versions` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::multiple_crate_versions)]` -error: could not compile `multiple_crate_versions` (bin "multiple_crate_versions") due to previous error +error: could not compile `multiple_crate_versions` (bin "multiple_crate_versions") due to 1 previous error diff --git a/src/tools/clippy/tests/ui-cargo/wildcard_dependencies/fail/Cargo.stderr b/src/tools/clippy/tests/ui-cargo/wildcard_dependencies/fail/Cargo.stderr index 65a19bb0718..a3539051b4d 100644 --- a/src/tools/clippy/tests/ui-cargo/wildcard_dependencies/fail/Cargo.stderr +++ b/src/tools/clippy/tests/ui-cargo/wildcard_dependencies/fail/Cargo.stderr @@ -3,4 +3,4 @@ error: wildcard dependency for `regex` = note: `-D clippy::wildcard-dependencies` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::wildcard_dependencies)]` -error: could not compile `wildcard_dependencies` (bin "wildcard_dependencies") due to previous error +error: could not compile `wildcard_dependencies` (bin "wildcard_dependencies") due to 1 previous error diff --git a/src/tools/clippy/tests/ui-toml/excessive_nesting/excessive_nesting.rs b/src/tools/clippy/tests/ui-toml/excessive_nesting/excessive_nesting.rs index d737a832dd1..4375f324aca 100644 --- a/src/tools/clippy/tests/ui-toml/excessive_nesting/excessive_nesting.rs +++ b/src/tools/clippy/tests/ui-toml/excessive_nesting/excessive_nesting.rs @@ -9,7 +9,7 @@ #![allow(clippy::never_loop)] #![allow(clippy::needless_if)] #![warn(clippy::excessive_nesting)] -#![allow(clippy::collapsible_if)] +#![allow(clippy::collapsible_if, clippy::blocks_in_conditions)] #[macro_use] extern crate proc_macros; diff --git a/src/tools/clippy/tests/ui/bind_instead_of_map_multipart.fixed b/src/tools/clippy/tests/ui/bind_instead_of_map_multipart.fixed index 8cbadc67d71..8c77039b3c0 100644 --- a/src/tools/clippy/tests/ui/bind_instead_of_map_multipart.fixed +++ b/src/tools/clippy/tests/ui/bind_instead_of_map_multipart.fixed @@ -1,5 +1,5 @@ #![deny(clippy::bind_instead_of_map)] -#![allow(clippy::blocks_in_if_conditions)] +#![allow(clippy::blocks_in_conditions)] pub fn main() { let _ = Some("42").map(|s| if s.len() < 42 { 0 } else { s.len() }); diff --git a/src/tools/clippy/tests/ui/bind_instead_of_map_multipart.rs b/src/tools/clippy/tests/ui/bind_instead_of_map_multipart.rs index 91d9d11e3c1..44257f3a469 100644 --- a/src/tools/clippy/tests/ui/bind_instead_of_map_multipart.rs +++ b/src/tools/clippy/tests/ui/bind_instead_of_map_multipart.rs @@ -1,5 +1,5 @@ #![deny(clippy::bind_instead_of_map)] -#![allow(clippy::blocks_in_if_conditions)] +#![allow(clippy::blocks_in_conditions)] pub fn main() { let _ = Some("42").and_then(|s| if s.len() < 42 { Some(0) } else { Some(s.len()) }); diff --git a/src/tools/clippy/tests/ui/blocks_in_if_conditions.fixed b/src/tools/clippy/tests/ui/blocks_in_conditions.fixed index f89c465047e..2ab441bbd0c 100644 --- a/src/tools/clippy/tests/ui/blocks_in_if_conditions.fixed +++ b/src/tools/clippy/tests/ui/blocks_in_conditions.fixed @@ -1,4 +1,4 @@ -#![warn(clippy::blocks_in_if_conditions)] +#![warn(clippy::blocks_in_conditions)] #![allow(unused, clippy::let_and_return, clippy::needless_if)] #![warn(clippy::nonminimal_bool)] @@ -21,6 +21,7 @@ fn macro_if() { fn condition_has_block() -> i32 { let res = { + //~^ ERROR: in an `if` condition, avoid complex blocks or closures with blocks; instead, move the block or closure higher and bind it with a `let` let x = 3; x == 3 }; if res { @@ -32,6 +33,7 @@ fn condition_has_block() -> i32 { fn condition_has_block_with_single_expression() -> i32 { if true { 6 } else { 10 } + //~^ ERROR: omit braces around single expression condition } fn condition_is_normal() -> i32 { @@ -61,4 +63,26 @@ fn block_in_assert() { ); } +// issue #11814 +fn block_in_match_expr(num: i32) -> i32 { + let res = { + //~^ ERROR: in a `match` scrutinee, avoid complex blocks or closures with blocks; instead, move the block or closure higher and bind it with a `let` + let opt = Some(2); + opt + }; match res { + Some(0) => 1, + Some(n) => num * 2, + None => 0, + }; + + match unsafe { + let hearty_hearty_hearty = vec![240, 159, 146, 150]; + String::from_utf8_unchecked(hearty_hearty_hearty).as_str() + } { + "💖" => 1, + "what" => 2, + _ => 3, + } +} + fn main() {} diff --git a/src/tools/clippy/tests/ui/blocks_in_if_conditions.rs b/src/tools/clippy/tests/ui/blocks_in_conditions.rs index 34febc5fa2c..dd5ae4fb486 100644 --- a/src/tools/clippy/tests/ui/blocks_in_if_conditions.rs +++ b/src/tools/clippy/tests/ui/blocks_in_conditions.rs @@ -1,4 +1,4 @@ -#![warn(clippy::blocks_in_if_conditions)] +#![warn(clippy::blocks_in_conditions)] #![allow(unused, clippy::let_and_return, clippy::needless_if)] #![warn(clippy::nonminimal_bool)] @@ -21,6 +21,7 @@ fn macro_if() { fn condition_has_block() -> i32 { if { + //~^ ERROR: in an `if` condition, avoid complex blocks or closures with blocks; instead, move the block or closure higher and bind it with a `let` let x = 3; x == 3 } { @@ -32,6 +33,7 @@ fn condition_has_block() -> i32 { fn condition_has_block_with_single_expression() -> i32 { if { true } { 6 } else { 10 } + //~^ ERROR: omit braces around single expression condition } fn condition_is_normal() -> i32 { @@ -61,4 +63,26 @@ fn block_in_assert() { ); } +// issue #11814 +fn block_in_match_expr(num: i32) -> i32 { + match { + //~^ ERROR: in a `match` scrutinee, avoid complex blocks or closures with blocks; instead, move the block or closure higher and bind it with a `let` + let opt = Some(2); + opt + } { + Some(0) => 1, + Some(n) => num * 2, + None => 0, + }; + + match unsafe { + let hearty_hearty_hearty = vec![240, 159, 146, 150]; + String::from_utf8_unchecked(hearty_hearty_hearty).as_str() + } { + "💖" => 1, + "what" => 2, + _ => 3, + } +} + fn main() {} diff --git a/src/tools/clippy/tests/ui/blocks_in_if_conditions.stderr b/src/tools/clippy/tests/ui/blocks_in_conditions.stderr index d80ef9c0fd8..b00fe2f632c 100644 --- a/src/tools/clippy/tests/ui/blocks_in_if_conditions.stderr +++ b/src/tools/clippy/tests/ui/blocks_in_conditions.stderr @@ -1,30 +1,32 @@ error: in an `if` condition, avoid complex blocks or closures with blocks; instead, move the block or closure higher and bind it with a `let` - --> $DIR/blocks_in_if_conditions.rs:23:5 + --> $DIR/blocks_in_conditions.rs:23:5 | LL | / if { +LL | | LL | | let x = 3; LL | | x == 3 LL | | } { | |_____^ | - = note: `-D clippy::blocks-in-if-conditions` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::blocks_in_if_conditions)]` + = note: `-D clippy::blocks-in-conditions` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::blocks_in_conditions)]` help: try | LL ~ let res = { +LL + LL + let x = 3; LL + x == 3 LL ~ }; if res { | error: omit braces around single expression condition - --> $DIR/blocks_in_if_conditions.rs:34:8 + --> $DIR/blocks_in_conditions.rs:35:8 | LL | if { true } { 6 } else { 10 } | ^^^^^^^^ help: try: `true` error: this boolean expression can be simplified - --> $DIR/blocks_in_if_conditions.rs:39:8 + --> $DIR/blocks_in_conditions.rs:41:8 | LL | if true && x == 3 { 6 } else { 10 } | ^^^^^^^^^^^^^^ help: try: `x == 3` @@ -32,5 +34,24 @@ LL | if true && x == 3 { 6 } else { 10 } = note: `-D clippy::nonminimal-bool` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::nonminimal_bool)]` -error: aborting due to 3 previous errors +error: in a `match` scrutinee, avoid complex blocks or closures with blocks; instead, move the block or closure higher and bind it with a `let` + --> $DIR/blocks_in_conditions.rs:68:5 + | +LL | / match { +LL | | +LL | | let opt = Some(2); +LL | | opt +LL | | } { + | |_____^ + | +help: try + | +LL ~ let res = { +LL + +LL + let opt = Some(2); +LL + opt +LL ~ }; match res { + | + +error: aborting due to 4 previous errors diff --git a/src/tools/clippy/tests/ui/blocks_in_if_conditions_closure.rs b/src/tools/clippy/tests/ui/blocks_in_conditions_closure.rs index 539f2df15bd..db31e4ae1a9 100644 --- a/src/tools/clippy/tests/ui/blocks_in_if_conditions_closure.rs +++ b/src/tools/clippy/tests/ui/blocks_in_conditions_closure.rs @@ -1,4 +1,4 @@ -#![warn(clippy::blocks_in_if_conditions)] +#![warn(clippy::blocks_in_conditions)] #![allow( unused, clippy::let_and_return, @@ -22,7 +22,7 @@ fn pred_test() { && predicate( |x| { //~^ ERROR: in an `if` condition, avoid complex blocks or closures with blocks - //~| NOTE: `-D clippy::blocks-in-if-conditions` implied by `-D warnings` + //~| NOTE: `-D clippy::blocks-in-conditions` implied by `-D warnings` let target = 3; x == target }, @@ -60,6 +60,23 @@ fn function_with_empty_closure() { if closure(|| {}) {} } +// issue #11814 +fn match_with_pred() { + let v = 3; + match Some(predicate( + |x| { + //~^ ERROR: in a `match` scrutinee, avoid complex blocks or closures with blocks + let target = 3; + x == target + }, + v, + )) { + Some(true) => 1, + Some(false) => 2, + None => 3, + }; +} + #[rustfmt::skip] fn main() { let mut range = 0..10; diff --git a/src/tools/clippy/tests/ui/blocks_in_if_conditions_closure.stderr b/src/tools/clippy/tests/ui/blocks_in_conditions_closure.stderr index ab68997d477..08b98f1b4fc 100644 --- a/src/tools/clippy/tests/ui/blocks_in_if_conditions_closure.stderr +++ b/src/tools/clippy/tests/ui/blocks_in_conditions_closure.stderr @@ -1,5 +1,5 @@ error: in an `if` condition, avoid complex blocks or closures with blocks; instead, move the block or closure higher and bind it with a `let` - --> $DIR/blocks_in_if_conditions_closure.rs:23:17 + --> $DIR/blocks_in_conditions_closure.rs:23:17 | LL | |x| { | _________________^ @@ -10,11 +10,11 @@ LL | | x == target LL | | }, | |_____________^ | - = note: `-D clippy::blocks-in-if-conditions` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::blocks_in_if_conditions)]` + = note: `-D clippy::blocks-in-conditions` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::blocks_in_conditions)]` error: in an `if` condition, avoid complex blocks or closures with blocks; instead, move the block or closure higher and bind it with a `let` - --> $DIR/blocks_in_if_conditions_closure.rs:34:13 + --> $DIR/blocks_in_conditions_closure.rs:34:13 | LL | |x| { | _____________^ @@ -24,5 +24,16 @@ LL | | x == target LL | | }, | |_________^ -error: aborting due to 2 previous errors +error: in a `match` scrutinee, avoid complex blocks or closures with blocks; instead, move the block or closure higher and bind it with a `let` + --> $DIR/blocks_in_conditions_closure.rs:67:13 + | +LL | |x| { + | _____________^ +LL | | +LL | | let target = 3; +LL | | x == target +LL | | }, + | |_________^ + +error: aborting due to 3 previous errors diff --git a/src/tools/clippy/tests/ui/doc/doc-fixable.fixed b/src/tools/clippy/tests/ui/doc/doc-fixable.fixed index aee89719728..708ac666675 100644 --- a/src/tools/clippy/tests/ui/doc/doc-fixable.fixed +++ b/src/tools/clippy/tests/ui/doc/doc-fixable.fixed @@ -227,3 +227,6 @@ where [(); N.checked_next_power_of_two().unwrap()]: { /// this checks if the lowerCamelCase issue is fixed fn issue_11568() {} + +/// There is no try (`do()` or `do_not()`). +fn parenthesized_word() {} diff --git a/src/tools/clippy/tests/ui/doc/doc-fixable.rs b/src/tools/clippy/tests/ui/doc/doc-fixable.rs index b6346b881ad..040d6352c52 100644 --- a/src/tools/clippy/tests/ui/doc/doc-fixable.rs +++ b/src/tools/clippy/tests/ui/doc/doc-fixable.rs @@ -227,3 +227,6 @@ where [(); N.checked_next_power_of_two().unwrap()]: { /// this checks if the lowerCamelCase issue is fixed fn issue_11568() {} + +/// There is no try (do() or do_not()). +fn parenthesized_word() {} diff --git a/src/tools/clippy/tests/ui/doc/doc-fixable.stderr b/src/tools/clippy/tests/ui/doc/doc-fixable.stderr index 4c9ff41d918..033604e030a 100644 --- a/src/tools/clippy/tests/ui/doc/doc-fixable.stderr +++ b/src/tools/clippy/tests/ui/doc/doc-fixable.stderr @@ -319,5 +319,27 @@ help: try LL | /// Foo \[bar\] \[baz\] \[qux\]. `DocMarkdownLint` | ~~~~~~~~~~~~~~~~~ -error: aborting due to 29 previous errors +error: item in documentation is missing backticks + --> $DIR/doc-fixable.rs:231:22 + | +LL | /// There is no try (do() or do_not()). + | ^^^^ + | +help: try + | +LL | /// There is no try (`do()` or do_not()). + | ~~~~~~ + +error: item in documentation is missing backticks + --> $DIR/doc-fixable.rs:231:30 + | +LL | /// There is no try (do() or do_not()). + | ^^^^^^^^ + | +help: try + | +LL | /// There is no try (do() or `do_not()`). + | ~~~~~~~~~~ + +error: aborting due to 31 previous errors diff --git a/src/tools/clippy/tests/ui/doc_unsafe.rs b/src/tools/clippy/tests/ui/doc_unsafe.rs index 0c8eac5ccff..f7f41c915e3 100644 --- a/src/tools/clippy/tests/ui/doc_unsafe.rs +++ b/src/tools/clippy/tests/ui/doc_unsafe.rs @@ -1,6 +1,6 @@ //@aux-build:proc_macros.rs -#![allow(clippy::let_unit_value)] +#![allow(clippy::let_unit_value, clippy::needless_pass_by_ref_mut)] extern crate proc_macros; use proc_macros::external; diff --git a/src/tools/clippy/tests/ui/ineffective_open_options.fixed b/src/tools/clippy/tests/ui/ineffective_open_options.fixed new file mode 100644 index 00000000000..3af8f3c5aaa --- /dev/null +++ b/src/tools/clippy/tests/ui/ineffective_open_options.fixed @@ -0,0 +1,41 @@ +#![warn(clippy::ineffective_open_options)] + +use std::fs::OpenOptions; + +fn main() { + let file = OpenOptions::new() + .create(true) + //~ ERROR: unnecessary use of `.write(true)` + .append(true) + .open("dump.json") + .unwrap(); + + let file = OpenOptions::new() + .create(true) + .append(true) + //~ ERROR: unnecessary use of `.write(true)` + .open("dump.json") + .unwrap(); + + // All the next calls are ok. + let file = OpenOptions::new() + .create(true) + .write(false) + .append(true) + .open("dump.json") + .unwrap(); + let file = OpenOptions::new() + .create(true) + .write(true) + .append(false) + .open("dump.json") + .unwrap(); + let file = OpenOptions::new() + .create(true) + .write(false) + .append(false) + .open("dump.json") + .unwrap(); + let file = OpenOptions::new().create(true).append(true).open("dump.json").unwrap(); + let file = OpenOptions::new().create(true).write(true).open("dump.json").unwrap(); +} diff --git a/src/tools/clippy/tests/ui/ineffective_open_options.rs b/src/tools/clippy/tests/ui/ineffective_open_options.rs new file mode 100644 index 00000000000..4eaf6293c40 --- /dev/null +++ b/src/tools/clippy/tests/ui/ineffective_open_options.rs @@ -0,0 +1,41 @@ +#![warn(clippy::ineffective_open_options)] + +use std::fs::OpenOptions; + +fn main() { + let file = OpenOptions::new() + .create(true) + .write(true) //~ ERROR: unnecessary use of `.write(true)` + .append(true) + .open("dump.json") + .unwrap(); + + let file = OpenOptions::new() + .create(true) + .append(true) + .write(true) //~ ERROR: unnecessary use of `.write(true)` + .open("dump.json") + .unwrap(); + + // All the next calls are ok. + let file = OpenOptions::new() + .create(true) + .write(false) + .append(true) + .open("dump.json") + .unwrap(); + let file = OpenOptions::new() + .create(true) + .write(true) + .append(false) + .open("dump.json") + .unwrap(); + let file = OpenOptions::new() + .create(true) + .write(false) + .append(false) + .open("dump.json") + .unwrap(); + let file = OpenOptions::new().create(true).append(true).open("dump.json").unwrap(); + let file = OpenOptions::new().create(true).write(true).open("dump.json").unwrap(); +} diff --git a/src/tools/clippy/tests/ui/ineffective_open_options.stderr b/src/tools/clippy/tests/ui/ineffective_open_options.stderr new file mode 100644 index 00000000000..7dc5322232c --- /dev/null +++ b/src/tools/clippy/tests/ui/ineffective_open_options.stderr @@ -0,0 +1,17 @@ +error: unnecessary use of `.write(true)` because there is `.append(true)` + --> $DIR/ineffective_open_options.rs:8:9 + | +LL | .write(true) + | ^^^^^^^^^^^^ help: remove `.write(true)` + | + = note: `-D clippy::ineffective-open-options` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::ineffective_open_options)]` + +error: unnecessary use of `.write(true)` because there is `.append(true)` + --> $DIR/ineffective_open_options.rs:16:9 + | +LL | .write(true) + | ^^^^^^^^^^^^ help: remove `.write(true)` + +error: aborting due to 2 previous errors + diff --git a/src/tools/clippy/tests/ui/infallible_destructuring_match.fixed b/src/tools/clippy/tests/ui/infallible_destructuring_match.fixed index 60304177b42..ecf1b14e5b6 100644 --- a/src/tools/clippy/tests/ui/infallible_destructuring_match.fixed +++ b/src/tools/clippy/tests/ui/infallible_destructuring_match.fixed @@ -1,6 +1,6 @@ #![feature(exhaustive_patterns, never_type)] #![allow(dead_code, unreachable_code, unused_variables)] -#![allow(clippy::let_and_return)] +#![allow(clippy::let_and_return, clippy::uninhabited_references)] enum SingleVariantEnum { Variant(i32), diff --git a/src/tools/clippy/tests/ui/infallible_destructuring_match.rs b/src/tools/clippy/tests/ui/infallible_destructuring_match.rs index b77aac4a16c..7cc7cb9d687 100644 --- a/src/tools/clippy/tests/ui/infallible_destructuring_match.rs +++ b/src/tools/clippy/tests/ui/infallible_destructuring_match.rs @@ -1,6 +1,6 @@ #![feature(exhaustive_patterns, never_type)] #![allow(dead_code, unreachable_code, unused_variables)] -#![allow(clippy::let_and_return)] +#![allow(clippy::let_and_return, clippy::uninhabited_references)] enum SingleVariantEnum { Variant(i32), diff --git a/src/tools/clippy/tests/ui/infinite_loops.rs b/src/tools/clippy/tests/ui/infinite_loops.rs new file mode 100644 index 00000000000..646f1eca56d --- /dev/null +++ b/src/tools/clippy/tests/ui/infinite_loops.rs @@ -0,0 +1,366 @@ +//@no-rustfix +#![allow(clippy::never_loop)] +#![warn(clippy::infinite_loop)] + +fn do_something() {} + +fn no_break() { + loop { + //~^ ERROR: infinite loop detected + do_something(); + } +} + +fn all_inf() { + loop { + //~^ ERROR: infinite loop detected + loop { + //~^ ERROR: infinite loop detected + loop { + //~^ ERROR: infinite loop detected + do_something(); + } + } + do_something(); + } +} + +fn no_break_return_some_ty() -> Option<u8> { + loop { + do_something(); + return None; + } + loop { + //~^ ERROR: infinite loop detected + do_something(); + } +} + +fn no_break_never_ret() -> ! { + loop { + do_something(); + } +} + +fn no_break_never_ret_noise() { + loop { + fn inner_fn() -> ! { + std::process::exit(0); + } + do_something(); + } +} + +fn has_direct_break_1() { + loop { + do_something(); + break; + } +} + +fn has_direct_break_2() { + 'outer: loop { + do_something(); + break 'outer; + } +} + +fn has_indirect_break_1(cond: bool) { + 'outer: loop { + loop { + if cond { + break 'outer; + } + } + } +} + +fn has_indirect_break_2(stop_num: i32) { + 'outer: loop { + for x in 0..5 { + if x == stop_num { + break 'outer; + } + } + } +} + +fn break_inner_but_not_outer_1(cond: bool) { + loop { + //~^ ERROR: infinite loop detected + loop { + if cond { + break; + } + } + } +} + +fn break_inner_but_not_outer_2(cond: bool) { + loop { + //~^ ERROR: infinite loop detected + 'inner: loop { + loop { + if cond { + break 'inner; + } + } + } + } +} + +fn break_outer_but_not_inner() { + loop { + loop { + //~^ ERROR: infinite loop detected + do_something(); + } + break; + } +} + +fn can_break_both_inner_and_outer(cond: bool) { + 'outer: loop { + loop { + if cond { + break 'outer; + } else { + break; + } + } + } +} + +fn break_wrong_loop(cond: bool) { + // 'inner has statement to break 'outer loop, but it was breaked early by a labeled child loop + 'outer: loop { + loop { + //~^ ERROR: infinite loop detected + 'inner: loop { + loop { + loop { + break 'inner; + } + break 'outer; + } + } + } + } +} + +fn has_direct_return(cond: bool) { + loop { + if cond { + return; + } + } +} + +fn ret_in_inner(cond: bool) { + loop { + loop { + if cond { + return; + } + } + } +} + +enum Foo { + A, + B, + C, +} + +fn match_like() { + let opt: Option<u8> = Some(1); + loop { + //~^ ERROR: infinite loop detected + match opt { + Some(v) => { + println!("{v}"); + }, + None => { + do_something(); + }, + } + } + + loop { + match opt { + Some(v) => { + println!("{v}"); + }, + None => { + do_something(); + break; + }, + } + } + + let result: Result<u8, u16> = Ok(1); + loop { + let _val = match result { + Ok(1) => 1 + 1, + Ok(v) => v / 2, + Err(_) => return, + }; + } + + loop { + let Ok(_val) = result else { return }; + } + + loop { + let Ok(_val) = result.map(|v| 10) else { break }; + } + + loop { + //~^ ERROR: infinite loop detected + let _x = matches!(result, Ok(v) if v != 0).then_some(0); + } + + loop { + //~^ ERROR: infinite loop detected + // This `return` does not return the function, so it doesn't count + let _x = matches!(result, Ok(v) if v != 0).then(|| { + if true { + return; + } + do_something(); + }); + } + + let mut val = 0; + let mut fooc = Foo::C; + + loop { + val = match fooc { + Foo::A => 0, + Foo::B => { + fooc = Foo::C; + 1 + }, + Foo::C => break, + }; + } + + loop { + val = match fooc { + Foo::A => 0, + Foo::B => 1, + Foo::C => { + break; + }, + }; + } +} + +macro_rules! set_or_ret { + ($opt:expr, $a:expr) => {{ + match $opt { + Some(val) => $a = val, + None => return, + } + }}; +} + +fn ret_in_macro(opt: Option<u8>) { + let opt: Option<u8> = Some(1); + let mut a: u8 = 0; + loop { + set_or_ret!(opt, a); + } + + let res: Result<bool, u8> = Ok(true); + loop { + match res { + Ok(true) => set_or_ret!(opt, a), + _ => do_something(), + } + } +} + +fn panic_like_macros_1() { + loop { + do_something(); + panic!(); + } +} + +fn panic_like_macros_2() { + let mut x = 0; + + loop { + do_something(); + if true { + todo!(); + } + } + loop { + do_something(); + x += 1; + assert_eq!(x, 0); + } + loop { + do_something(); + assert!(x % 2 == 0); + } + loop { + do_something(); + match Some(1) { + Some(n) => println!("{n}"), + None => unreachable!("It won't happen"), + } + } +} + +fn exit_directly(cond: bool) { + loop { + if cond { + std::process::exit(0); + } + } +} + +trait MyTrait { + fn problematic_trait_method() { + loop { + //~^ ERROR: infinite loop detected + do_something(); + } + } + fn could_be_problematic(); +} + +impl MyTrait for String { + fn could_be_problematic() { + loop { + //~^ ERROR: infinite loop detected + do_something(); + } + } +} + +fn inf_loop_in_closure() { + let _loop_forever = || { + loop { + //~^ ERROR: infinite loop detected + do_something(); + } + }; + + let _somehow_ok = || -> ! { + loop { + do_something(); + } + }; +} + +fn inf_loop_in_res() -> Result<(), i32> { + Ok(loop { + do_something() + }) +} + +fn main() {} diff --git a/src/tools/clippy/tests/ui/infinite_loops.stderr b/src/tools/clippy/tests/ui/infinite_loops.stderr new file mode 100644 index 00000000000..f58b3cebbc3 --- /dev/null +++ b/src/tools/clippy/tests/ui/infinite_loops.stderr @@ -0,0 +1,259 @@ +error: infinite loop detected + --> $DIR/infinite_loops.rs:8:5 + | +LL | / loop { +LL | | +LL | | do_something(); +LL | | } + | |_____^ + | + = note: `-D clippy::infinite-loop` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::infinite_loop)]` +help: if this is intentional, consider specifing `!` as function return + | +LL | fn no_break() -> ! { + | ++++ + +error: infinite loop detected + --> $DIR/infinite_loops.rs:15:5 + | +LL | / loop { +LL | | +LL | | loop { +LL | | +... | +LL | | do_something(); +LL | | } + | |_____^ + | +help: if this is intentional, consider specifing `!` as function return + | +LL | fn all_inf() -> ! { + | ++++ + +error: infinite loop detected + --> $DIR/infinite_loops.rs:17:9 + | +LL | / loop { +LL | | +LL | | loop { +LL | | +LL | | do_something(); +LL | | } +LL | | } + | |_________^ + | +help: if this is intentional, consider specifing `!` as function return + | +LL | fn all_inf() -> ! { + | ++++ + +error: infinite loop detected + --> $DIR/infinite_loops.rs:19:13 + | +LL | / loop { +LL | | +LL | | do_something(); +LL | | } + | |_____________^ + | +help: if this is intentional, consider specifing `!` as function return + | +LL | fn all_inf() -> ! { + | ++++ + +error: infinite loop detected + --> $DIR/infinite_loops.rs:33:5 + | +LL | / loop { +LL | | +LL | | do_something(); +LL | | } + | |_____^ + | + = help: if this is not intended, try adding a `break` or `return` condition in the loop + +error: infinite loop detected + --> $DIR/infinite_loops.rs:46:5 + | +LL | / loop { +LL | | fn inner_fn() -> ! { +LL | | std::process::exit(0); +LL | | } +LL | | do_something(); +LL | | } + | |_____^ + | +help: if this is intentional, consider specifing `!` as function return + | +LL | fn no_break_never_ret_noise() -> ! { + | ++++ + +error: infinite loop detected + --> $DIR/infinite_loops.rs:89:5 + | +LL | / loop { +LL | | +LL | | loop { +LL | | if cond { +... | +LL | | } +LL | | } + | |_____^ + | +help: if this is intentional, consider specifing `!` as function return + | +LL | fn break_inner_but_not_outer_1(cond: bool) -> ! { + | ++++ + +error: infinite loop detected + --> $DIR/infinite_loops.rs:100:5 + | +LL | / loop { +LL | | +LL | | 'inner: loop { +LL | | loop { +... | +LL | | } +LL | | } + | |_____^ + | +help: if this is intentional, consider specifing `!` as function return + | +LL | fn break_inner_but_not_outer_2(cond: bool) -> ! { + | ++++ + +error: infinite loop detected + --> $DIR/infinite_loops.rs:114:9 + | +LL | / loop { +LL | | +LL | | do_something(); +LL | | } + | |_________^ + | +help: if this is intentional, consider specifing `!` as function return + | +LL | fn break_outer_but_not_inner() -> ! { + | ++++ + +error: infinite loop detected + --> $DIR/infinite_loops.rs:137:9 + | +LL | / loop { +LL | | +LL | | 'inner: loop { +LL | | loop { +... | +LL | | } +LL | | } + | |_________^ + | +help: if this is intentional, consider specifing `!` as function return + | +LL | fn break_wrong_loop(cond: bool) -> ! { + | ++++ + +error: infinite loop detected + --> $DIR/infinite_loops.rs:177:5 + | +LL | / loop { +LL | | +LL | | match opt { +LL | | Some(v) => { +... | +LL | | } +LL | | } + | |_____^ + | +help: if this is intentional, consider specifing `!` as function return + | +LL | fn match_like() -> ! { + | ++++ + +error: infinite loop detected + --> $DIR/infinite_loops.rs:218:5 + | +LL | / loop { +LL | | +LL | | let _x = matches!(result, Ok(v) if v != 0).then_some(0); +LL | | } + | |_____^ + | +help: if this is intentional, consider specifing `!` as function return + | +LL | fn match_like() -> ! { + | ++++ + +error: infinite loop detected + --> $DIR/infinite_loops.rs:223:5 + | +LL | / loop { +LL | | +LL | | // This `return` does not return the function, so it doesn't count +LL | | let _x = matches!(result, Ok(v) if v != 0).then(|| { +... | +LL | | }); +LL | | } + | |_____^ + | +help: if this is intentional, consider specifing `!` as function return + | +LL | fn match_like() -> ! { + | ++++ + +error: infinite loop detected + --> $DIR/infinite_loops.rs:328:9 + | +LL | / loop { +LL | | +LL | | do_something(); +LL | | } + | |_________^ + | +help: if this is intentional, consider specifing `!` as function return + | +LL | fn problematic_trait_method() -> ! { + | ++++ + +error: infinite loop detected + --> $DIR/infinite_loops.rs:338:9 + | +LL | / loop { +LL | | +LL | | do_something(); +LL | | } + | |_________^ + | +help: if this is intentional, consider specifing `!` as function return + | +LL | fn could_be_problematic() -> ! { + | ++++ + +error: infinite loop detected + --> $DIR/infinite_loops.rs:347:9 + | +LL | / loop { +LL | | +LL | | do_something(); +LL | | } + | |_________^ + | +help: if this is intentional, consider specifing `!` as function return + | +LL | let _loop_forever = || -> ! { + | ++++ + +error: infinite loop detected + --> $DIR/infinite_loops.rs:361:8 + | +LL | Ok(loop { + | ________^ +LL | | do_something() +LL | | }) + | |_____^ + | + = help: if this is not intended, try adding a `break` or `return` condition in the loop + +error: aborting due to 17 previous errors + diff --git a/src/tools/clippy/tests/ui/manual_filter.fixed b/src/tools/clippy/tests/ui/manual_filter.fixed index c1bc4aae92e..a0fb0e32d60 100644 --- a/src/tools/clippy/tests/ui/manual_filter.fixed +++ b/src/tools/clippy/tests/ui/manual_filter.fixed @@ -40,7 +40,7 @@ fn main() { }; } - #[allow(clippy::blocks_in_if_conditions)] + #[allow(clippy::blocks_in_conditions)] Some(11).filter(|&x| { println!("foo"); x > 10 && x < 100 diff --git a/src/tools/clippy/tests/ui/manual_filter.rs b/src/tools/clippy/tests/ui/manual_filter.rs index ee44909f37e..0ac6cbefc4e 100644 --- a/src/tools/clippy/tests/ui/manual_filter.rs +++ b/src/tools/clippy/tests/ui/manual_filter.rs @@ -135,7 +135,7 @@ fn main() { }; } - #[allow(clippy::blocks_in_if_conditions)] + #[allow(clippy::blocks_in_conditions)] match Some(11) { // Lint, statement is preserved by `.filter` Some(x) => { diff --git a/src/tools/clippy/tests/ui/missing_asserts_for_indexing.fixed b/src/tools/clippy/tests/ui/missing_asserts_for_indexing.fixed index a96827259f5..ac44a6f3fdb 100644 --- a/src/tools/clippy/tests/ui/missing_asserts_for_indexing.fixed +++ b/src/tools/clippy/tests/ui/missing_asserts_for_indexing.fixed @@ -118,4 +118,19 @@ fn index_different_slice_in_same_expr(v1: &[u8], v2: &[u8]) { let _ = v1[0] + v2[1]; } +fn issue11835(v1: &[u8], v2: &[u8], v3: &[u8], v4: &[u8]) { + assert!(v1.len() == 3); + assert!(v2.len() == 4); + assert!(v3.len() == 3); + assert!(4 == v4.len()); + + let _ = v1[0] + v1[1] + v1[2]; + //~^ ERROR: indexing into a slice multiple times with an `assert` that does not cover the + let _ = v2[0] + v2[1] + v2[2]; + + let _ = v3[0] + v3[1] + v3[2]; + //~^ ERROR: indexing into a slice multiple times with an `assert` that does not cover the + let _ = v4[0] + v4[1] + v4[2]; +} + fn main() {} diff --git a/src/tools/clippy/tests/ui/missing_asserts_for_indexing.rs b/src/tools/clippy/tests/ui/missing_asserts_for_indexing.rs index 0b4b883acf8..f05d5fea57d 100644 --- a/src/tools/clippy/tests/ui/missing_asserts_for_indexing.rs +++ b/src/tools/clippy/tests/ui/missing_asserts_for_indexing.rs @@ -118,4 +118,19 @@ fn index_different_slice_in_same_expr(v1: &[u8], v2: &[u8]) { let _ = v1[0] + v2[1]; } +fn issue11835(v1: &[u8], v2: &[u8], v3: &[u8], v4: &[u8]) { + assert!(v1.len() == 2); + assert!(v2.len() == 4); + assert!(2 == v3.len()); + assert!(4 == v4.len()); + + let _ = v1[0] + v1[1] + v1[2]; + //~^ ERROR: indexing into a slice multiple times with an `assert` that does not cover the + let _ = v2[0] + v2[1] + v2[2]; + + let _ = v3[0] + v3[1] + v3[2]; + //~^ ERROR: indexing into a slice multiple times with an `assert` that does not cover the + let _ = v4[0] + v4[1] + v4[2]; +} + fn main() {} diff --git a/src/tools/clippy/tests/ui/missing_asserts_for_indexing.stderr b/src/tools/clippy/tests/ui/missing_asserts_for_indexing.stderr index a3e66d7958e..61dce6ccc6c 100644 --- a/src/tools/clippy/tests/ui/missing_asserts_for_indexing.stderr +++ b/src/tools/clippy/tests/ui/missing_asserts_for_indexing.stderr @@ -249,5 +249,57 @@ LL | let _ = v1[0] + v1[12]; | ^^^^^^ = note: asserting the length before indexing will elide bounds checks -error: aborting due to 9 previous errors +error: indexing into a slice multiple times with an `assert` that does not cover the highest index + --> $DIR/missing_asserts_for_indexing.rs:127:13 + | +LL | assert!(v1.len() == 2); + | ---------------------- help: provide the highest index that is indexed with: `assert!(v1.len() == 3)` +... +LL | let _ = v1[0] + v1[1] + v1[2]; + | ^^^^^^^^^^^^^^^^^^^^^ + | +note: slice indexed here + --> $DIR/missing_asserts_for_indexing.rs:127:13 + | +LL | let _ = v1[0] + v1[1] + v1[2]; + | ^^^^^ +note: slice indexed here + --> $DIR/missing_asserts_for_indexing.rs:127:21 + | +LL | let _ = v1[0] + v1[1] + v1[2]; + | ^^^^^ +note: slice indexed here + --> $DIR/missing_asserts_for_indexing.rs:127:29 + | +LL | let _ = v1[0] + v1[1] + v1[2]; + | ^^^^^ + = note: asserting the length before indexing will elide bounds checks + +error: indexing into a slice multiple times with an `assert` that does not cover the highest index + --> $DIR/missing_asserts_for_indexing.rs:131:13 + | +LL | assert!(2 == v3.len()); + | ---------------------- help: provide the highest index that is indexed with: `assert!(v3.len() == 3)` +... +LL | let _ = v3[0] + v3[1] + v3[2]; + | ^^^^^^^^^^^^^^^^^^^^^ + | +note: slice indexed here + --> $DIR/missing_asserts_for_indexing.rs:131:13 + | +LL | let _ = v3[0] + v3[1] + v3[2]; + | ^^^^^ +note: slice indexed here + --> $DIR/missing_asserts_for_indexing.rs:131:21 + | +LL | let _ = v3[0] + v3[1] + v3[2]; + | ^^^^^ +note: slice indexed here + --> $DIR/missing_asserts_for_indexing.rs:131:29 + | +LL | let _ = v3[0] + v3[1] + v3[2]; + | ^^^^^ + = note: asserting the length before indexing will elide bounds checks + +error: aborting due to 11 previous errors diff --git a/src/tools/clippy/tests/ui/needless_borrows_for_generic_args.fixed b/src/tools/clippy/tests/ui/needless_borrows_for_generic_args.fixed index 2a335516f51..bd7a9a0b984 100644 --- a/src/tools/clippy/tests/ui/needless_borrows_for_generic_args.fixed +++ b/src/tools/clippy/tests/ui/needless_borrows_for_generic_args.fixed @@ -284,4 +284,19 @@ fn main() { { } } + // address of field when operand impl Drop + { + struct CustomDrop(String); + + impl Drop for CustomDrop { + fn drop(&mut self) {} + } + + fn check_str<P: AsRef<str>>(_to: P) {} + + fn test() { + let owner = CustomDrop(String::default()); + check_str(&owner.0); // Don't lint. `owner` can't be partially moved because it impl Drop + } + } } diff --git a/src/tools/clippy/tests/ui/needless_borrows_for_generic_args.rs b/src/tools/clippy/tests/ui/needless_borrows_for_generic_args.rs index f0567f486ac..5cfd4ce30cc 100644 --- a/src/tools/clippy/tests/ui/needless_borrows_for_generic_args.rs +++ b/src/tools/clippy/tests/ui/needless_borrows_for_generic_args.rs @@ -284,4 +284,19 @@ fn main() { { } } + // address of field when operand impl Drop + { + struct CustomDrop(String); + + impl Drop for CustomDrop { + fn drop(&mut self) {} + } + + fn check_str<P: AsRef<str>>(_to: P) {} + + fn test() { + let owner = CustomDrop(String::default()); + check_str(&owner.0); // Don't lint. `owner` can't be partially moved because it impl Drop + } + } } diff --git a/src/tools/clippy/tests/ui/needless_if.fixed b/src/tools/clippy/tests/ui/needless_if.fixed index be35dcddbe6..1086ae2c984 100644 --- a/src/tools/clippy/tests/ui/needless_if.fixed +++ b/src/tools/clippy/tests/ui/needless_if.fixed @@ -1,7 +1,7 @@ //@aux-build:proc_macros.rs #![feature(let_chains)] #![allow( - clippy::blocks_in_if_conditions, + clippy::blocks_in_conditions, clippy::if_same_then_else, clippy::ifs_same_cond, clippy::let_unit_value, diff --git a/src/tools/clippy/tests/ui/needless_if.rs b/src/tools/clippy/tests/ui/needless_if.rs index e2ad17e69a8..131cceaf712 100644 --- a/src/tools/clippy/tests/ui/needless_if.rs +++ b/src/tools/clippy/tests/ui/needless_if.rs @@ -1,7 +1,7 @@ //@aux-build:proc_macros.rs #![feature(let_chains)] #![allow( - clippy::blocks_in_if_conditions, + clippy::blocks_in_conditions, clippy::if_same_then_else, clippy::ifs_same_cond, clippy::let_unit_value, diff --git a/src/tools/clippy/tests/ui/needless_late_init.fixed b/src/tools/clippy/tests/ui/needless_late_init.fixed index 891b2b01437..6db87049044 100644 --- a/src/tools/clippy/tests/ui/needless_late_init.fixed +++ b/src/tools/clippy/tests/ui/needless_late_init.fixed @@ -3,7 +3,7 @@ #![allow(unused)] #![allow( clippy::assign_op_pattern, - clippy::blocks_in_if_conditions, + clippy::blocks_in_conditions, clippy::let_and_return, clippy::let_unit_value, clippy::nonminimal_bool, diff --git a/src/tools/clippy/tests/ui/needless_late_init.rs b/src/tools/clippy/tests/ui/needless_late_init.rs index 55399511639..c1e86212a08 100644 --- a/src/tools/clippy/tests/ui/needless_late_init.rs +++ b/src/tools/clippy/tests/ui/needless_late_init.rs @@ -3,7 +3,7 @@ #![allow(unused)] #![allow( clippy::assign_op_pattern, - clippy::blocks_in_if_conditions, + clippy::blocks_in_conditions, clippy::let_and_return, clippy::let_unit_value, clippy::nonminimal_bool, diff --git a/src/tools/clippy/tests/ui/needless_pass_by_ref_mut.rs b/src/tools/clippy/tests/ui/needless_pass_by_ref_mut.rs index 25a02bdd2f2..a92197fb0af 100644 --- a/src/tools/clippy/tests/ui/needless_pass_by_ref_mut.rs +++ b/src/tools/clippy/tests/ui/needless_pass_by_ref_mut.rs @@ -307,6 +307,19 @@ fn filter_copy<T: Copy>(predicate: &mut impl FnMut(T) -> bool) -> impl FnMut(&T) move |&item| predicate(item) } +// `is_from_proc_macro` stress tests +fn _empty_tup(x: &mut (())) {} +fn _single_tup(x: &mut ((i32,))) {} +fn _multi_tup(x: &mut ((i32, u32))) {} +fn _fn(x: &mut (fn())) {} +#[rustfmt::skip] +fn _extern_rust_fn(x: &mut extern "Rust" fn()) {} +fn _extern_c_fn(x: &mut extern "C" fn()) {} +fn _unsafe_fn(x: &mut unsafe fn()) {} +fn _unsafe_extern_fn(x: &mut unsafe extern "C" fn()) {} +fn _fn_with_arg(x: &mut unsafe extern "C" fn(i32)) {} +fn _fn_with_ret(x: &mut unsafe extern "C" fn() -> (i32)) {} + fn main() { let mut u = 0; let mut v = vec![0]; diff --git a/src/tools/clippy/tests/ui/needless_pass_by_ref_mut.stderr b/src/tools/clippy/tests/ui/needless_pass_by_ref_mut.stderr index 92b753276ac..5d1e9515de1 100644 --- a/src/tools/clippy/tests/ui/needless_pass_by_ref_mut.stderr +++ b/src/tools/clippy/tests/ui/needless_pass_by_ref_mut.stderr @@ -139,5 +139,65 @@ LL | pub async fn closure4(n: &mut usize) { | = warning: changing this function will impact semver compatibility -error: aborting due to 21 previous errors +error: this argument is a mutable reference, but not used mutably + --> $DIR/needless_pass_by_ref_mut.rs:311:18 + | +LL | fn _empty_tup(x: &mut (())) {} + | ^^^^^^^^^ help: consider changing to: `&()` + +error: this argument is a mutable reference, but not used mutably + --> $DIR/needless_pass_by_ref_mut.rs:312:19 + | +LL | fn _single_tup(x: &mut ((i32,))) {} + | ^^^^^^^^^^^^^ help: consider changing to: `&(i32,)` + +error: this argument is a mutable reference, but not used mutably + --> $DIR/needless_pass_by_ref_mut.rs:313:18 + | +LL | fn _multi_tup(x: &mut ((i32, u32))) {} + | ^^^^^^^^^^^^^^^^^ help: consider changing to: `&(i32, u32)` + +error: this argument is a mutable reference, but not used mutably + --> $DIR/needless_pass_by_ref_mut.rs:314:11 + | +LL | fn _fn(x: &mut (fn())) {} + | ^^^^^^^^^^^ help: consider changing to: `&fn()` + +error: this argument is a mutable reference, but not used mutably + --> $DIR/needless_pass_by_ref_mut.rs:316:23 + | +LL | fn _extern_rust_fn(x: &mut extern "Rust" fn()) {} + | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing to: `&extern "Rust" fn()` + +error: this argument is a mutable reference, but not used mutably + --> $DIR/needless_pass_by_ref_mut.rs:317:20 + | +LL | fn _extern_c_fn(x: &mut extern "C" fn()) {} + | ^^^^^^^^^^^^^^^^^^^^ help: consider changing to: `&extern "C" fn()` + +error: this argument is a mutable reference, but not used mutably + --> $DIR/needless_pass_by_ref_mut.rs:318:18 + | +LL | fn _unsafe_fn(x: &mut unsafe fn()) {} + | ^^^^^^^^^^^^^^^^ help: consider changing to: `&unsafe fn()` + +error: this argument is a mutable reference, but not used mutably + --> $DIR/needless_pass_by_ref_mut.rs:319:25 + | +LL | fn _unsafe_extern_fn(x: &mut unsafe extern "C" fn()) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing to: `&unsafe extern "C" fn()` + +error: this argument is a mutable reference, but not used mutably + --> $DIR/needless_pass_by_ref_mut.rs:320:20 + | +LL | fn _fn_with_arg(x: &mut unsafe extern "C" fn(i32)) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing to: `&unsafe extern "C" fn(i32)` + +error: this argument is a mutable reference, but not used mutably + --> $DIR/needless_pass_by_ref_mut.rs:321:20 + | +LL | fn _fn_with_ret(x: &mut unsafe extern "C" fn() -> (i32)) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing to: `&unsafe extern "C" fn() -> (i32)` + +error: aborting due to 31 previous errors diff --git a/src/tools/clippy/tests/ui/no_effect.rs b/src/tools/clippy/tests/ui/no_effect.rs index c52f4389192..777b1e52c2d 100644 --- a/src/tools/clippy/tests/ui/no_effect.rs +++ b/src/tools/clippy/tests/ui/no_effect.rs @@ -9,6 +9,30 @@ clippy::useless_vec )] +use std::fmt::Display; +use std::ops::{Neg, Shl}; + +struct Cout; + +impl<T> Shl<T> for Cout +where + T: Display, +{ + type Output = Self; + fn shl(self, rhs: T) -> Self::Output { + println!("{}", rhs); + self + } +} + +impl Neg for Cout { + type Output = Self; + fn neg(self) -> Self::Output { + println!("hello world"); + self + } +} + struct Unit; struct Tuple(i32); struct Struct { @@ -174,4 +198,11 @@ fn main() { GreetStruct1("world"); GreetStruct2()("world"); GreetStruct3 {}("world"); + + fn n() -> i32 { + 42 + } + + Cout << 142; + -Cout; } diff --git a/src/tools/clippy/tests/ui/no_effect.stderr b/src/tools/clippy/tests/ui/no_effect.stderr index feba35697f5..f5ba234b4cb 100644 --- a/src/tools/clippy/tests/ui/no_effect.stderr +++ b/src/tools/clippy/tests/ui/no_effect.stderr @@ -1,5 +1,5 @@ error: statement with no effect - --> $DIR/no_effect.rs:98:5 + --> $DIR/no_effect.rs:122:5 | LL | 0; | ^^ @@ -8,151 +8,151 @@ LL | 0; = help: to override `-D warnings` add `#[allow(clippy::no_effect)]` error: statement with no effect - --> $DIR/no_effect.rs:101:5 + --> $DIR/no_effect.rs:125:5 | LL | s2; | ^^^ error: statement with no effect - --> $DIR/no_effect.rs:103:5 + --> $DIR/no_effect.rs:127:5 | LL | Unit; | ^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:105:5 + --> $DIR/no_effect.rs:129:5 | LL | Tuple(0); | ^^^^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:107:5 + --> $DIR/no_effect.rs:131:5 | LL | Struct { field: 0 }; | ^^^^^^^^^^^^^^^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:109:5 + --> $DIR/no_effect.rs:133:5 | LL | Struct { ..s }; | ^^^^^^^^^^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:111:5 + --> $DIR/no_effect.rs:135:5 | LL | Union { a: 0 }; | ^^^^^^^^^^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:113:5 + --> $DIR/no_effect.rs:137:5 | LL | Enum::Tuple(0); | ^^^^^^^^^^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:115:5 + --> $DIR/no_effect.rs:139:5 | LL | Enum::Struct { field: 0 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:117:5 + --> $DIR/no_effect.rs:141:5 | LL | 5 + 6; | ^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:119:5 + --> $DIR/no_effect.rs:143:5 | LL | *&42; | ^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:121:5 + --> $DIR/no_effect.rs:145:5 | LL | &6; | ^^^ error: statement with no effect - --> $DIR/no_effect.rs:123:5 + --> $DIR/no_effect.rs:147:5 | LL | (5, 6, 7); | ^^^^^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:125:5 + --> $DIR/no_effect.rs:149:5 | LL | ..; | ^^^ error: statement with no effect - --> $DIR/no_effect.rs:127:5 + --> $DIR/no_effect.rs:151:5 | LL | 5..; | ^^^^ error: statement with no effect - --> $DIR/no_effect.rs:129:5 + --> $DIR/no_effect.rs:153:5 | LL | ..5; | ^^^^ error: statement with no effect - --> $DIR/no_effect.rs:131:5 + --> $DIR/no_effect.rs:155:5 | LL | 5..6; | ^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:133:5 + --> $DIR/no_effect.rs:157:5 | LL | 5..=6; | ^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:135:5 + --> $DIR/no_effect.rs:159:5 | LL | [42, 55]; | ^^^^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:137:5 + --> $DIR/no_effect.rs:161:5 | LL | [42, 55][1]; | ^^^^^^^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:139:5 + --> $DIR/no_effect.rs:163:5 | LL | (42, 55).1; | ^^^^^^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:141:5 + --> $DIR/no_effect.rs:165:5 | LL | [42; 55]; | ^^^^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:143:5 + --> $DIR/no_effect.rs:167:5 | LL | [42; 55][13]; | ^^^^^^^^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:146:5 + --> $DIR/no_effect.rs:170:5 | LL | || x += 5; | ^^^^^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:149:5 + --> $DIR/no_effect.rs:173:5 | LL | FooString { s: s }; | ^^^^^^^^^^^^^^^^^^^ error: binding to `_` prefixed variable with no side-effect - --> $DIR/no_effect.rs:151:5 + --> $DIR/no_effect.rs:175:5 | LL | let _unused = 1; | ^^^^^^^^^^^^^^^^ @@ -161,19 +161,19 @@ LL | let _unused = 1; = help: to override `-D warnings` add `#[allow(clippy::no_effect_underscore_binding)]` error: binding to `_` prefixed variable with no side-effect - --> $DIR/no_effect.rs:154:5 + --> $DIR/no_effect.rs:178:5 | LL | let _penguin = || println!("Some helpful closure"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: binding to `_` prefixed variable with no side-effect - --> $DIR/no_effect.rs:156:5 + --> $DIR/no_effect.rs:180:5 | LL | let _duck = Struct { field: 0 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: binding to `_` prefixed variable with no side-effect - --> $DIR/no_effect.rs:158:5 + --> $DIR/no_effect.rs:182:5 | LL | let _cat = [2, 4, 6, 8][2]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/ptr_as_ptr.fixed b/src/tools/clippy/tests/ui/ptr_as_ptr.fixed index ca13b52ae3b..fa15c323540 100644 --- a/src/tools/clippy/tests/ui/ptr_as_ptr.fixed +++ b/src/tools/clippy/tests/ui/ptr_as_ptr.fixed @@ -71,3 +71,118 @@ fn _msrv_1_38() { let _ = ptr.cast::<i32>(); let _ = mut_ptr.cast::<i32>(); } + +#[allow(clippy::unnecessary_cast)] +mod null { + fn use_path_mut() -> *mut u32 { + use std::ptr; + ptr::null_mut::<u32>() + } + + fn full_path_mut() -> *mut u32 { + std::ptr::null_mut::<u32>() + } + + fn core_path_mut() -> *mut u32 { + use core::ptr; + ptr::null_mut::<u32>() + } + + fn full_core_path_mut() -> *mut u32 { + core::ptr::null_mut::<u32>() + } + + fn use_path() -> *const u32 { + use std::ptr; + ptr::null::<u32>() + } + + fn full_path() -> *const u32 { + std::ptr::null::<u32>() + } + + fn core_path() -> *const u32 { + use core::ptr; + ptr::null::<u32>() + } + + fn full_core_path() -> *const u32 { + core::ptr::null::<u32>() + } +} + +mod null_ptr_infer { + fn use_path_mut() -> *mut u32 { + use std::ptr; + ptr::null_mut() + } + + fn full_path_mut() -> *mut u32 { + std::ptr::null_mut() + } + + fn core_path_mut() -> *mut u32 { + use core::ptr; + ptr::null_mut() + } + + fn full_core_path_mut() -> *mut u32 { + core::ptr::null_mut() + } + + fn use_path() -> *const u32 { + use std::ptr; + ptr::null() + } + + fn full_path() -> *const u32 { + std::ptr::null() + } + + fn core_path() -> *const u32 { + use core::ptr; + ptr::null() + } + + fn full_core_path() -> *const u32 { + core::ptr::null() + } +} + +mod null_entire_infer { + fn use_path_mut() -> *mut u32 { + use std::ptr; + ptr::null_mut() + } + + fn full_path_mut() -> *mut u32 { + std::ptr::null_mut() + } + + fn core_path_mut() -> *mut u32 { + use core::ptr; + ptr::null_mut() + } + + fn full_core_path_mut() -> *mut u32 { + core::ptr::null_mut() + } + + fn use_path() -> *const u32 { + use std::ptr; + ptr::null() + } + + fn full_path() -> *const u32 { + std::ptr::null() + } + + fn core_path() -> *const u32 { + use core::ptr; + ptr::null() + } + + fn full_core_path() -> *const u32 { + core::ptr::null() + } +} diff --git a/src/tools/clippy/tests/ui/ptr_as_ptr.rs b/src/tools/clippy/tests/ui/ptr_as_ptr.rs index 942c8734444..7ab52e63da5 100644 --- a/src/tools/clippy/tests/ui/ptr_as_ptr.rs +++ b/src/tools/clippy/tests/ui/ptr_as_ptr.rs @@ -71,3 +71,118 @@ fn _msrv_1_38() { let _ = ptr as *const i32; let _ = mut_ptr as *mut i32; } + +#[allow(clippy::unnecessary_cast)] +mod null { + fn use_path_mut() -> *mut u32 { + use std::ptr; + ptr::null_mut() as *mut u32 + } + + fn full_path_mut() -> *mut u32 { + std::ptr::null_mut() as *mut u32 + } + + fn core_path_mut() -> *mut u32 { + use core::ptr; + ptr::null_mut() as *mut u32 + } + + fn full_core_path_mut() -> *mut u32 { + core::ptr::null_mut() as *mut u32 + } + + fn use_path() -> *const u32 { + use std::ptr; + ptr::null() as *const u32 + } + + fn full_path() -> *const u32 { + std::ptr::null() as *const u32 + } + + fn core_path() -> *const u32 { + use core::ptr; + ptr::null() as *const u32 + } + + fn full_core_path() -> *const u32 { + core::ptr::null() as *const u32 + } +} + +mod null_ptr_infer { + fn use_path_mut() -> *mut u32 { + use std::ptr; + ptr::null_mut() as *mut _ + } + + fn full_path_mut() -> *mut u32 { + std::ptr::null_mut() as *mut _ + } + + fn core_path_mut() -> *mut u32 { + use core::ptr; + ptr::null_mut() as *mut _ + } + + fn full_core_path_mut() -> *mut u32 { + core::ptr::null_mut() as *mut _ + } + + fn use_path() -> *const u32 { + use std::ptr; + ptr::null() as *const _ + } + + fn full_path() -> *const u32 { + std::ptr::null() as *const _ + } + + fn core_path() -> *const u32 { + use core::ptr; + ptr::null() as *const _ + } + + fn full_core_path() -> *const u32 { + core::ptr::null() as *const _ + } +} + +mod null_entire_infer { + fn use_path_mut() -> *mut u32 { + use std::ptr; + ptr::null_mut() as _ + } + + fn full_path_mut() -> *mut u32 { + std::ptr::null_mut() as _ + } + + fn core_path_mut() -> *mut u32 { + use core::ptr; + ptr::null_mut() as _ + } + + fn full_core_path_mut() -> *mut u32 { + core::ptr::null_mut() as _ + } + + fn use_path() -> *const u32 { + use std::ptr; + ptr::null() as _ + } + + fn full_path() -> *const u32 { + std::ptr::null() as _ + } + + fn core_path() -> *const u32 { + use core::ptr; + ptr::null() as _ + } + + fn full_core_path() -> *const u32 { + core::ptr::null() as _ + } +} diff --git a/src/tools/clippy/tests/ui/ptr_as_ptr.stderr b/src/tools/clippy/tests/ui/ptr_as_ptr.stderr index c0ce69b4357..ef64347e935 100644 --- a/src/tools/clippy/tests/ui/ptr_as_ptr.stderr +++ b/src/tools/clippy/tests/ui/ptr_as_ptr.stderr @@ -57,5 +57,149 @@ error: `as` casting between raw pointers without changing its mutability LL | let _ = mut_ptr as *mut i32; | ^^^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `mut_ptr.cast::<i32>()` -error: aborting due to 9 previous errors +error: `as` casting between raw pointers without changing its mutability + --> $DIR/ptr_as_ptr.rs:79:9 + | +LL | ptr::null_mut() as *mut u32 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null_mut::<u32>()` + +error: `as` casting between raw pointers without changing its mutability + --> $DIR/ptr_as_ptr.rs:83:9 + | +LL | std::ptr::null_mut() as *mut u32 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `std::ptr::null_mut::<u32>()` + +error: `as` casting between raw pointers without changing its mutability + --> $DIR/ptr_as_ptr.rs:88:9 + | +LL | ptr::null_mut() as *mut u32 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null_mut::<u32>()` + +error: `as` casting between raw pointers without changing its mutability + --> $DIR/ptr_as_ptr.rs:92:9 + | +LL | core::ptr::null_mut() as *mut u32 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `core::ptr::null_mut::<u32>()` + +error: `as` casting between raw pointers without changing its mutability + --> $DIR/ptr_as_ptr.rs:97:9 + | +LL | ptr::null() as *const u32 + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null::<u32>()` + +error: `as` casting between raw pointers without changing its mutability + --> $DIR/ptr_as_ptr.rs:101:9 + | +LL | std::ptr::null() as *const u32 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `std::ptr::null::<u32>()` + +error: `as` casting between raw pointers without changing its mutability + --> $DIR/ptr_as_ptr.rs:106:9 + | +LL | ptr::null() as *const u32 + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null::<u32>()` + +error: `as` casting between raw pointers without changing its mutability + --> $DIR/ptr_as_ptr.rs:110:9 + | +LL | core::ptr::null() as *const u32 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `core::ptr::null::<u32>()` + +error: `as` casting between raw pointers without changing its mutability + --> $DIR/ptr_as_ptr.rs:117:9 + | +LL | ptr::null_mut() as *mut _ + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null_mut()` + +error: `as` casting between raw pointers without changing its mutability + --> $DIR/ptr_as_ptr.rs:121:9 + | +LL | std::ptr::null_mut() as *mut _ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `std::ptr::null_mut()` + +error: `as` casting between raw pointers without changing its mutability + --> $DIR/ptr_as_ptr.rs:126:9 + | +LL | ptr::null_mut() as *mut _ + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null_mut()` + +error: `as` casting between raw pointers without changing its mutability + --> $DIR/ptr_as_ptr.rs:130:9 + | +LL | core::ptr::null_mut() as *mut _ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `core::ptr::null_mut()` + +error: `as` casting between raw pointers without changing its mutability + --> $DIR/ptr_as_ptr.rs:135:9 + | +LL | ptr::null() as *const _ + | ^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null()` + +error: `as` casting between raw pointers without changing its mutability + --> $DIR/ptr_as_ptr.rs:139:9 + | +LL | std::ptr::null() as *const _ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `std::ptr::null()` + +error: `as` casting between raw pointers without changing its mutability + --> $DIR/ptr_as_ptr.rs:144:9 + | +LL | ptr::null() as *const _ + | ^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null()` + +error: `as` casting between raw pointers without changing its mutability + --> $DIR/ptr_as_ptr.rs:148:9 + | +LL | core::ptr::null() as *const _ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `core::ptr::null()` + +error: `as` casting between raw pointers without changing its mutability + --> $DIR/ptr_as_ptr.rs:155:9 + | +LL | ptr::null_mut() as _ + | ^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null_mut()` + +error: `as` casting between raw pointers without changing its mutability + --> $DIR/ptr_as_ptr.rs:159:9 + | +LL | std::ptr::null_mut() as _ + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `std::ptr::null_mut()` + +error: `as` casting between raw pointers without changing its mutability + --> $DIR/ptr_as_ptr.rs:164:9 + | +LL | ptr::null_mut() as _ + | ^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null_mut()` + +error: `as` casting between raw pointers without changing its mutability + --> $DIR/ptr_as_ptr.rs:168:9 + | +LL | core::ptr::null_mut() as _ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `core::ptr::null_mut()` + +error: `as` casting between raw pointers without changing its mutability + --> $DIR/ptr_as_ptr.rs:173:9 + | +LL | ptr::null() as _ + | ^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null()` + +error: `as` casting between raw pointers without changing its mutability + --> $DIR/ptr_as_ptr.rs:177:9 + | +LL | std::ptr::null() as _ + | ^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `std::ptr::null()` + +error: `as` casting between raw pointers without changing its mutability + --> $DIR/ptr_as_ptr.rs:182:9 + | +LL | ptr::null() as _ + | ^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null()` + +error: `as` casting between raw pointers without changing its mutability + --> $DIR/ptr_as_ptr.rs:186:9 + | +LL | core::ptr::null() as _ + | ^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `core::ptr::null()` + +error: aborting due to 33 previous errors diff --git a/src/tools/clippy/tests/ui/regex.rs b/src/tools/clippy/tests/ui/regex.rs index 094d9574ae9..1ea0d65bf1e 100644 --- a/src/tools/clippy/tests/ui/regex.rs +++ b/src/tools/clippy/tests/ui/regex.rs @@ -112,6 +112,10 @@ fn trivial_regex() { // #6005: unicode classes in bytes::Regex let a_byte_of_unicode = BRegex::new(r"\p{C}"); + + // start and end word boundry, introduced in regex 0.10 + let _ = BRegex::new(r"\<word\>"); + let _ = BRegex::new(r"\b{start}word\b{end}"); } fn main() { diff --git a/src/tools/clippy/tests/ui/rename.fixed b/src/tools/clippy/tests/ui/rename.fixed index 31f1ee6a86d..f4ff0f0b88b 100644 --- a/src/tools/clippy/tests/ui/rename.fixed +++ b/src/tools/clippy/tests/ui/rename.fixed @@ -4,7 +4,7 @@ #![allow(clippy::almost_complete_range)] #![allow(clippy::disallowed_names)] -#![allow(clippy::blocks_in_if_conditions)] +#![allow(clippy::blocks_in_conditions)] #![allow(clippy::box_collection)] #![allow(clippy::redundant_static_lifetimes)] #![allow(clippy::cognitive_complexity)] @@ -54,8 +54,9 @@ #![allow(ambiguous_wide_pointer_comparisons)] #![warn(clippy::almost_complete_range)] #![warn(clippy::disallowed_names)] -#![warn(clippy::blocks_in_if_conditions)] -#![warn(clippy::blocks_in_if_conditions)] +#![warn(clippy::blocks_in_conditions)] +#![warn(clippy::blocks_in_conditions)] +#![warn(clippy::blocks_in_conditions)] #![warn(clippy::box_collection)] #![warn(clippy::redundant_static_lifetimes)] #![warn(clippy::cognitive_complexity)] diff --git a/src/tools/clippy/tests/ui/rename.rs b/src/tools/clippy/tests/ui/rename.rs index 325bc356c15..0df1098f5fb 100644 --- a/src/tools/clippy/tests/ui/rename.rs +++ b/src/tools/clippy/tests/ui/rename.rs @@ -4,7 +4,7 @@ #![allow(clippy::almost_complete_range)] #![allow(clippy::disallowed_names)] -#![allow(clippy::blocks_in_if_conditions)] +#![allow(clippy::blocks_in_conditions)] #![allow(clippy::box_collection)] #![allow(clippy::redundant_static_lifetimes)] #![allow(clippy::cognitive_complexity)] @@ -56,6 +56,7 @@ #![warn(clippy::blacklisted_name)] #![warn(clippy::block_in_if_condition_expr)] #![warn(clippy::block_in_if_condition_stmt)] +#![warn(clippy::blocks_in_if_conditions)] #![warn(clippy::box_vec)] #![warn(clippy::const_static_lifetime)] #![warn(clippy::cyclomatic_complexity)] diff --git a/src/tools/clippy/tests/ui/rename.stderr b/src/tools/clippy/tests/ui/rename.stderr index a6164338c20..f63ad82a757 100644 --- a/src/tools/clippy/tests/ui/rename.stderr +++ b/src/tools/clippy/tests/ui/rename.stderr @@ -13,335 +13,341 @@ error: lint `clippy::blacklisted_name` has been renamed to `clippy::disallowed_n LL | #![warn(clippy::blacklisted_name)] | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_names` -error: lint `clippy::block_in_if_condition_expr` has been renamed to `clippy::blocks_in_if_conditions` +error: lint `clippy::block_in_if_condition_expr` has been renamed to `clippy::blocks_in_conditions` --> $DIR/rename.rs:57:9 | LL | #![warn(clippy::block_in_if_condition_expr)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_if_conditions` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_conditions` -error: lint `clippy::block_in_if_condition_stmt` has been renamed to `clippy::blocks_in_if_conditions` +error: lint `clippy::block_in_if_condition_stmt` has been renamed to `clippy::blocks_in_conditions` --> $DIR/rename.rs:58:9 | LL | #![warn(clippy::block_in_if_condition_stmt)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_if_conditions` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_conditions` -error: lint `clippy::box_vec` has been renamed to `clippy::box_collection` +error: lint `clippy::blocks_in_if_conditions` has been renamed to `clippy::blocks_in_conditions` --> $DIR/rename.rs:59:9 | +LL | #![warn(clippy::blocks_in_if_conditions)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_conditions` + +error: lint `clippy::box_vec` has been renamed to `clippy::box_collection` + --> $DIR/rename.rs:60:9 + | LL | #![warn(clippy::box_vec)] | ^^^^^^^^^^^^^^^ help: use the new name: `clippy::box_collection` error: lint `clippy::const_static_lifetime` has been renamed to `clippy::redundant_static_lifetimes` - --> $DIR/rename.rs:60:9 + --> $DIR/rename.rs:61:9 | LL | #![warn(clippy::const_static_lifetime)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::redundant_static_lifetimes` error: lint `clippy::cyclomatic_complexity` has been renamed to `clippy::cognitive_complexity` - --> $DIR/rename.rs:61:9 + --> $DIR/rename.rs:62:9 | LL | #![warn(clippy::cyclomatic_complexity)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::cognitive_complexity` error: lint `clippy::derive_hash_xor_eq` has been renamed to `clippy::derived_hash_with_manual_eq` - --> $DIR/rename.rs:62:9 + --> $DIR/rename.rs:63:9 | LL | #![warn(clippy::derive_hash_xor_eq)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::derived_hash_with_manual_eq` error: lint `clippy::disallowed_method` has been renamed to `clippy::disallowed_methods` - --> $DIR/rename.rs:63:9 + --> $DIR/rename.rs:64:9 | LL | #![warn(clippy::disallowed_method)] | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_methods` error: lint `clippy::disallowed_type` has been renamed to `clippy::disallowed_types` - --> $DIR/rename.rs:64:9 + --> $DIR/rename.rs:65:9 | LL | #![warn(clippy::disallowed_type)] | ^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_types` error: lint `clippy::eval_order_dependence` has been renamed to `clippy::mixed_read_write_in_expression` - --> $DIR/rename.rs:65:9 + --> $DIR/rename.rs:66:9 | LL | #![warn(clippy::eval_order_dependence)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::mixed_read_write_in_expression` error: lint `clippy::identity_conversion` has been renamed to `clippy::useless_conversion` - --> $DIR/rename.rs:66:9 + --> $DIR/rename.rs:67:9 | LL | #![warn(clippy::identity_conversion)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::useless_conversion` error: lint `clippy::if_let_some_result` has been renamed to `clippy::match_result_ok` - --> $DIR/rename.rs:67:9 + --> $DIR/rename.rs:68:9 | LL | #![warn(clippy::if_let_some_result)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::match_result_ok` error: lint `clippy::incorrect_clone_impl_on_copy_type` has been renamed to `clippy::non_canonical_clone_impl` - --> $DIR/rename.rs:68:9 + --> $DIR/rename.rs:69:9 | LL | #![warn(clippy::incorrect_clone_impl_on_copy_type)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::non_canonical_clone_impl` error: lint `clippy::incorrect_partial_ord_impl_on_ord_type` has been renamed to `clippy::non_canonical_partial_ord_impl` - --> $DIR/rename.rs:69:9 + --> $DIR/rename.rs:70:9 | LL | #![warn(clippy::incorrect_partial_ord_impl_on_ord_type)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::non_canonical_partial_ord_impl` error: lint `clippy::integer_arithmetic` has been renamed to `clippy::arithmetic_side_effects` - --> $DIR/rename.rs:70:9 + --> $DIR/rename.rs:71:9 | LL | #![warn(clippy::integer_arithmetic)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::arithmetic_side_effects` error: lint `clippy::logic_bug` has been renamed to `clippy::overly_complex_bool_expr` - --> $DIR/rename.rs:71:9 + --> $DIR/rename.rs:72:9 | LL | #![warn(clippy::logic_bug)] | ^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::overly_complex_bool_expr` error: lint `clippy::new_without_default_derive` has been renamed to `clippy::new_without_default` - --> $DIR/rename.rs:72:9 + --> $DIR/rename.rs:73:9 | LL | #![warn(clippy::new_without_default_derive)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::new_without_default` error: lint `clippy::option_and_then_some` has been renamed to `clippy::bind_instead_of_map` - --> $DIR/rename.rs:73:9 + --> $DIR/rename.rs:74:9 | LL | #![warn(clippy::option_and_then_some)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::bind_instead_of_map` error: lint `clippy::option_expect_used` has been renamed to `clippy::expect_used` - --> $DIR/rename.rs:74:9 + --> $DIR/rename.rs:75:9 | LL | #![warn(clippy::option_expect_used)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used` error: lint `clippy::option_map_unwrap_or` has been renamed to `clippy::map_unwrap_or` - --> $DIR/rename.rs:75:9 + --> $DIR/rename.rs:76:9 | LL | #![warn(clippy::option_map_unwrap_or)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or` error: lint `clippy::option_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or` - --> $DIR/rename.rs:76:9 + --> $DIR/rename.rs:77:9 | LL | #![warn(clippy::option_map_unwrap_or_else)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or` error: lint `clippy::option_unwrap_used` has been renamed to `clippy::unwrap_used` - --> $DIR/rename.rs:77:9 + --> $DIR/rename.rs:78:9 | LL | #![warn(clippy::option_unwrap_used)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used` error: lint `clippy::ref_in_deref` has been renamed to `clippy::needless_borrow` - --> $DIR/rename.rs:78:9 + --> $DIR/rename.rs:79:9 | LL | #![warn(clippy::ref_in_deref)] | ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::needless_borrow` error: lint `clippy::result_expect_used` has been renamed to `clippy::expect_used` - --> $DIR/rename.rs:79:9 + --> $DIR/rename.rs:80:9 | LL | #![warn(clippy::result_expect_used)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used` error: lint `clippy::result_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or` - --> $DIR/rename.rs:80:9 + --> $DIR/rename.rs:81:9 | LL | #![warn(clippy::result_map_unwrap_or_else)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or` error: lint `clippy::result_unwrap_used` has been renamed to `clippy::unwrap_used` - --> $DIR/rename.rs:81:9 + --> $DIR/rename.rs:82:9 | LL | #![warn(clippy::result_unwrap_used)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used` error: lint `clippy::single_char_push_str` has been renamed to `clippy::single_char_add_str` - --> $DIR/rename.rs:82:9 + --> $DIR/rename.rs:83:9 | LL | #![warn(clippy::single_char_push_str)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::single_char_add_str` error: lint `clippy::stutter` has been renamed to `clippy::module_name_repetitions` - --> $DIR/rename.rs:83:9 + --> $DIR/rename.rs:84:9 | LL | #![warn(clippy::stutter)] | ^^^^^^^^^^^^^^^ help: use the new name: `clippy::module_name_repetitions` error: lint `clippy::to_string_in_display` has been renamed to `clippy::recursive_format_impl` - --> $DIR/rename.rs:84:9 + --> $DIR/rename.rs:85:9 | LL | #![warn(clippy::to_string_in_display)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::recursive_format_impl` error: lint `clippy::unwrap_or_else_default` has been renamed to `clippy::unwrap_or_default` - --> $DIR/rename.rs:85:9 + --> $DIR/rename.rs:86:9 | LL | #![warn(clippy::unwrap_or_else_default)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_or_default` error: lint `clippy::zero_width_space` has been renamed to `clippy::invisible_characters` - --> $DIR/rename.rs:86:9 + --> $DIR/rename.rs:87:9 | LL | #![warn(clippy::zero_width_space)] | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::invisible_characters` error: lint `clippy::cast_ref_to_mut` has been renamed to `invalid_reference_casting` - --> $DIR/rename.rs:87:9 + --> $DIR/rename.rs:88:9 | LL | #![warn(clippy::cast_ref_to_mut)] | ^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_reference_casting` error: lint `clippy::clone_double_ref` has been renamed to `suspicious_double_ref_op` - --> $DIR/rename.rs:88:9 + --> $DIR/rename.rs:89:9 | LL | #![warn(clippy::clone_double_ref)] | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `suspicious_double_ref_op` error: lint `clippy::cmp_nan` has been renamed to `invalid_nan_comparisons` - --> $DIR/rename.rs:89:9 + --> $DIR/rename.rs:90:9 | LL | #![warn(clippy::cmp_nan)] | ^^^^^^^^^^^^^^^ help: use the new name: `invalid_nan_comparisons` error: lint `clippy::drop_bounds` has been renamed to `drop_bounds` - --> $DIR/rename.rs:90:9 + --> $DIR/rename.rs:91:9 | LL | #![warn(clippy::drop_bounds)] | ^^^^^^^^^^^^^^^^^^^ help: use the new name: `drop_bounds` error: lint `clippy::drop_copy` has been renamed to `dropping_copy_types` - --> $DIR/rename.rs:91:9 + --> $DIR/rename.rs:92:9 | LL | #![warn(clippy::drop_copy)] | ^^^^^^^^^^^^^^^^^ help: use the new name: `dropping_copy_types` error: lint `clippy::drop_ref` has been renamed to `dropping_references` - --> $DIR/rename.rs:92:9 + --> $DIR/rename.rs:93:9 | LL | #![warn(clippy::drop_ref)] | ^^^^^^^^^^^^^^^^ help: use the new name: `dropping_references` error: lint `clippy::fn_null_check` has been renamed to `useless_ptr_null_checks` - --> $DIR/rename.rs:93:9 + --> $DIR/rename.rs:94:9 | LL | #![warn(clippy::fn_null_check)] | ^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `useless_ptr_null_checks` error: lint `clippy::for_loop_over_option` has been renamed to `for_loops_over_fallibles` - --> $DIR/rename.rs:94:9 + --> $DIR/rename.rs:95:9 | LL | #![warn(clippy::for_loop_over_option)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles` error: lint `clippy::for_loop_over_result` has been renamed to `for_loops_over_fallibles` - --> $DIR/rename.rs:95:9 + --> $DIR/rename.rs:96:9 | LL | #![warn(clippy::for_loop_over_result)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles` error: lint `clippy::for_loops_over_fallibles` has been renamed to `for_loops_over_fallibles` - --> $DIR/rename.rs:96:9 + --> $DIR/rename.rs:97:9 | LL | #![warn(clippy::for_loops_over_fallibles)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles` error: lint `clippy::forget_copy` has been renamed to `forgetting_copy_types` - --> $DIR/rename.rs:97:9 + --> $DIR/rename.rs:98:9 | LL | #![warn(clippy::forget_copy)] | ^^^^^^^^^^^^^^^^^^^ help: use the new name: `forgetting_copy_types` error: lint `clippy::forget_ref` has been renamed to `forgetting_references` - --> $DIR/rename.rs:98:9 + --> $DIR/rename.rs:99:9 | LL | #![warn(clippy::forget_ref)] | ^^^^^^^^^^^^^^^^^^ help: use the new name: `forgetting_references` error: lint `clippy::into_iter_on_array` has been renamed to `array_into_iter` - --> $DIR/rename.rs:99:9 + --> $DIR/rename.rs:100:9 | LL | #![warn(clippy::into_iter_on_array)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `array_into_iter` error: lint `clippy::invalid_atomic_ordering` has been renamed to `invalid_atomic_ordering` - --> $DIR/rename.rs:100:9 + --> $DIR/rename.rs:101:9 | LL | #![warn(clippy::invalid_atomic_ordering)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_atomic_ordering` error: lint `clippy::invalid_ref` has been renamed to `invalid_value` - --> $DIR/rename.rs:101:9 + --> $DIR/rename.rs:102:9 | LL | #![warn(clippy::invalid_ref)] | ^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_value` error: lint `clippy::invalid_utf8_in_unchecked` has been renamed to `invalid_from_utf8_unchecked` - --> $DIR/rename.rs:102:9 + --> $DIR/rename.rs:103:9 | LL | #![warn(clippy::invalid_utf8_in_unchecked)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_from_utf8_unchecked` error: lint `clippy::let_underscore_drop` has been renamed to `let_underscore_drop` - --> $DIR/rename.rs:103:9 + --> $DIR/rename.rs:104:9 | LL | #![warn(clippy::let_underscore_drop)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `let_underscore_drop` error: lint `clippy::mem_discriminant_non_enum` has been renamed to `enum_intrinsics_non_enums` - --> $DIR/rename.rs:104:9 + --> $DIR/rename.rs:105:9 | LL | #![warn(clippy::mem_discriminant_non_enum)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `enum_intrinsics_non_enums` error: lint `clippy::panic_params` has been renamed to `non_fmt_panics` - --> $DIR/rename.rs:105:9 + --> $DIR/rename.rs:106:9 | LL | #![warn(clippy::panic_params)] | ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `non_fmt_panics` error: lint `clippy::positional_named_format_parameters` has been renamed to `named_arguments_used_positionally` - --> $DIR/rename.rs:106:9 + --> $DIR/rename.rs:107:9 | LL | #![warn(clippy::positional_named_format_parameters)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `named_arguments_used_positionally` error: lint `clippy::temporary_cstring_as_ptr` has been renamed to `temporary_cstring_as_ptr` - --> $DIR/rename.rs:107:9 + --> $DIR/rename.rs:108:9 | LL | #![warn(clippy::temporary_cstring_as_ptr)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `temporary_cstring_as_ptr` error: lint `clippy::undropped_manually_drops` has been renamed to `undropped_manually_drops` - --> $DIR/rename.rs:108:9 + --> $DIR/rename.rs:109:9 | LL | #![warn(clippy::undropped_manually_drops)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `undropped_manually_drops` error: lint `clippy::unknown_clippy_lints` has been renamed to `unknown_lints` - --> $DIR/rename.rs:109:9 + --> $DIR/rename.rs:110:9 | LL | #![warn(clippy::unknown_clippy_lints)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unknown_lints` error: lint `clippy::unused_label` has been renamed to `unused_labels` - --> $DIR/rename.rs:110:9 + --> $DIR/rename.rs:111:9 | LL | #![warn(clippy::unused_label)] | ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unused_labels` error: lint `clippy::vtable_address_comparisons` has been renamed to `ambiguous_wide_pointer_comparisons` - --> $DIR/rename.rs:111:9 + --> $DIR/rename.rs:112:9 | LL | #![warn(clippy::vtable_address_comparisons)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `ambiguous_wide_pointer_comparisons` -error: aborting due to 57 previous errors +error: aborting due to 58 previous errors diff --git a/src/tools/clippy/tests/ui/repeat_vec_with_capacity.fixed b/src/tools/clippy/tests/ui/repeat_vec_with_capacity.fixed new file mode 100644 index 00000000000..2afe2f43325 --- /dev/null +++ b/src/tools/clippy/tests/ui/repeat_vec_with_capacity.fixed @@ -0,0 +1,38 @@ +#![warn(clippy::repeat_vec_with_capacity)] + +fn main() { + { + (0..123).map(|_| Vec::<()>::with_capacity(42)).collect::<Vec<_>>(); + //~^ ERROR: repeating `Vec::with_capacity` using `vec![x; n]`, which does not retain capacity + } + + { + let n = 123; + (0..n).map(|_| Vec::<()>::with_capacity(42)).collect::<Vec<_>>(); + //~^ ERROR: repeating `Vec::with_capacity` using `vec![x; n]`, which does not retain capacity + } + + { + macro_rules! from_macro { + ($x:expr) => { + vec![$x; 123]; + }; + } + // vec expansion is from another macro, don't lint + from_macro!(Vec::<()>::with_capacity(42)); + } + + { + std::iter::repeat_with(|| Vec::<()>::with_capacity(42)); + //~^ ERROR: repeating `Vec::with_capacity` using `iter::repeat`, which does not retain capacity + } + + { + macro_rules! from_macro { + ($x:expr) => { + std::iter::repeat($x) + }; + } + from_macro!(Vec::<()>::with_capacity(42)); + } +} diff --git a/src/tools/clippy/tests/ui/repeat_vec_with_capacity.rs b/src/tools/clippy/tests/ui/repeat_vec_with_capacity.rs new file mode 100644 index 00000000000..659f2a3953d --- /dev/null +++ b/src/tools/clippy/tests/ui/repeat_vec_with_capacity.rs @@ -0,0 +1,38 @@ +#![warn(clippy::repeat_vec_with_capacity)] + +fn main() { + { + vec![Vec::<()>::with_capacity(42); 123]; + //~^ ERROR: repeating `Vec::with_capacity` using `vec![x; n]`, which does not retain capacity + } + + { + let n = 123; + vec![Vec::<()>::with_capacity(42); n]; + //~^ ERROR: repeating `Vec::with_capacity` using `vec![x; n]`, which does not retain capacity + } + + { + macro_rules! from_macro { + ($x:expr) => { + vec![$x; 123]; + }; + } + // vec expansion is from another macro, don't lint + from_macro!(Vec::<()>::with_capacity(42)); + } + + { + std::iter::repeat(Vec::<()>::with_capacity(42)); + //~^ ERROR: repeating `Vec::with_capacity` using `iter::repeat`, which does not retain capacity + } + + { + macro_rules! from_macro { + ($x:expr) => { + std::iter::repeat($x) + }; + } + from_macro!(Vec::<()>::with_capacity(42)); + } +} diff --git a/src/tools/clippy/tests/ui/repeat_vec_with_capacity.stderr b/src/tools/clippy/tests/ui/repeat_vec_with_capacity.stderr new file mode 100644 index 00000000000..10b5f121420 --- /dev/null +++ b/src/tools/clippy/tests/ui/repeat_vec_with_capacity.stderr @@ -0,0 +1,40 @@ +error: repeating `Vec::with_capacity` using `vec![x; n]`, which does not retain capacity + --> $DIR/repeat_vec_with_capacity.rs:5:9 + | +LL | vec![Vec::<()>::with_capacity(42); 123]; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: only the last `Vec` will have the capacity + = note: `-D clippy::repeat-vec-with-capacity` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::repeat_vec_with_capacity)]` +help: if you intended to initialize multiple `Vec`s with an initial capacity, try + | +LL | (0..123).map(|_| Vec::<()>::with_capacity(42)).collect::<Vec<_>>(); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: repeating `Vec::with_capacity` using `vec![x; n]`, which does not retain capacity + --> $DIR/repeat_vec_with_capacity.rs:11:9 + | +LL | vec![Vec::<()>::with_capacity(42); n]; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: only the last `Vec` will have the capacity +help: if you intended to initialize multiple `Vec`s with an initial capacity, try + | +LL | (0..n).map(|_| Vec::<()>::with_capacity(42)).collect::<Vec<_>>(); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: repeating `Vec::with_capacity` using `iter::repeat`, which does not retain capacity + --> $DIR/repeat_vec_with_capacity.rs:26:9 + | +LL | std::iter::repeat(Vec::<()>::with_capacity(42)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: none of the yielded `Vec`s will have the requested capacity +help: if you intended to create an iterator that yields `Vec`s with an initial capacity, try + | +LL | std::iter::repeat_with(|| Vec::<()>::with_capacity(42)); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: aborting due to 3 previous errors + diff --git a/src/tools/clippy/tests/ui/uninhabited_references.rs b/src/tools/clippy/tests/ui/uninhabited_references.rs new file mode 100644 index 00000000000..cd07b590a61 --- /dev/null +++ b/src/tools/clippy/tests/ui/uninhabited_references.rs @@ -0,0 +1,22 @@ +#![warn(clippy::uninhabited_references)] +#![feature(never_type)] + +fn ret_uninh_ref() -> &'static std::convert::Infallible { + unsafe { std::mem::transmute(&()) } +} + +macro_rules! ret_something { + ($name:ident, $ty:ty) => { + fn $name(x: &$ty) -> &$ty { + &*x + } + }; +} + +ret_something!(id_u32, u32); +ret_something!(id_never, !); + +fn main() { + let x = ret_uninh_ref(); + let _ = *x; +} diff --git a/src/tools/clippy/tests/ui/uninhabited_references.stderr b/src/tools/clippy/tests/ui/uninhabited_references.stderr new file mode 100644 index 00000000000..2cdf320b809 --- /dev/null +++ b/src/tools/clippy/tests/ui/uninhabited_references.stderr @@ -0,0 +1,39 @@ +error: dereferencing a reference to an uninhabited type would be undefined behavior + --> $DIR/uninhabited_references.rs:4:23 + | +LL | fn ret_uninh_ref() -> &'static std::convert::Infallible { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::uninhabited-references` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::uninhabited_references)]` + +error: dereferencing a reference to an uninhabited type would be undefined behavior + --> $DIR/uninhabited_references.rs:10:30 + | +LL | fn $name(x: &$ty) -> &$ty { + | ^^^^ +... +LL | ret_something!(id_never, !); + | --------------------------- in this macro invocation + | + = note: this error originates in the macro `ret_something` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: dereferencing a reference to an uninhabited type is undefined behavior + --> $DIR/uninhabited_references.rs:11:14 + | +LL | &*x + | ^^ +... +LL | ret_something!(id_never, !); + | --------------------------- in this macro invocation + | + = note: this error originates in the macro `ret_something` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: dereferencing a reference to an uninhabited type is undefined behavior + --> $DIR/uninhabited_references.rs:21:13 + | +LL | let _ = *x; + | ^^ + +error: aborting due to 4 previous errors + diff --git a/src/tools/clippy/tests/ui/unnecessary_operation.fixed b/src/tools/clippy/tests/ui/unnecessary_operation.fixed index d0c0298ef4c..463412daec0 100644 --- a/src/tools/clippy/tests/ui/unnecessary_operation.fixed +++ b/src/tools/clippy/tests/ui/unnecessary_operation.fixed @@ -7,6 +7,9 @@ )] #![warn(clippy::unnecessary_operation)] +use std::fmt::Display; +use std::ops::Shl; + struct Tuple(i32); struct Struct { field: i32, @@ -50,6 +53,19 @@ fn get_drop_struct() -> DropStruct { DropStruct { field: 0 } } +struct Cout; + +impl<T> Shl<T> for Cout +where + T: Display, +{ + type Output = Self; + fn shl(self, rhs: T) -> Self::Output { + println!("{}", rhs); + self + } +} + fn main() { get_number(); get_number(); @@ -87,4 +103,7 @@ fn main() { ($($e:expr),*) => {{ $($e;)* }} } use_expr!(isize::MIN / -(one() as isize), i8::MIN / -one()); + + // Issue #11885 + Cout << 16; } diff --git a/src/tools/clippy/tests/ui/unnecessary_operation.rs b/src/tools/clippy/tests/ui/unnecessary_operation.rs index e8e3a2d5657..f0d28e28902 100644 --- a/src/tools/clippy/tests/ui/unnecessary_operation.rs +++ b/src/tools/clippy/tests/ui/unnecessary_operation.rs @@ -7,6 +7,9 @@ )] #![warn(clippy::unnecessary_operation)] +use std::fmt::Display; +use std::ops::Shl; + struct Tuple(i32); struct Struct { field: i32, @@ -50,6 +53,19 @@ fn get_drop_struct() -> DropStruct { DropStruct { field: 0 } } +struct Cout; + +impl<T> Shl<T> for Cout +where + T: Display, +{ + type Output = Self; + fn shl(self, rhs: T) -> Self::Output { + println!("{}", rhs); + self + } +} + fn main() { Tuple(get_number()); Struct { field: get_number() }; @@ -91,4 +107,7 @@ fn main() { ($($e:expr),*) => {{ $($e;)* }} } use_expr!(isize::MIN / -(one() as isize), i8::MIN / -one()); + + // Issue #11885 + Cout << 16; } diff --git a/src/tools/clippy/tests/ui/unnecessary_operation.stderr b/src/tools/clippy/tests/ui/unnecessary_operation.stderr index fbe495f518f..eeee9ad6006 100644 --- a/src/tools/clippy/tests/ui/unnecessary_operation.stderr +++ b/src/tools/clippy/tests/ui/unnecessary_operation.stderr @@ -1,5 +1,5 @@ error: unnecessary operation - --> $DIR/unnecessary_operation.rs:54:5 + --> $DIR/unnecessary_operation.rs:70:5 | LL | Tuple(get_number()); | ^^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `get_number();` @@ -8,103 +8,103 @@ LL | Tuple(get_number()); = help: to override `-D warnings` add `#[allow(clippy::unnecessary_operation)]` error: unnecessary operation - --> $DIR/unnecessary_operation.rs:55:5 + --> $DIR/unnecessary_operation.rs:71:5 | LL | Struct { field: get_number() }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `get_number();` error: unnecessary operation - --> $DIR/unnecessary_operation.rs:56:5 + --> $DIR/unnecessary_operation.rs:72:5 | LL | Struct { ..get_struct() }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `get_struct();` error: unnecessary operation - --> $DIR/unnecessary_operation.rs:57:5 + --> $DIR/unnecessary_operation.rs:73:5 | LL | Enum::Tuple(get_number()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `get_number();` error: unnecessary operation - --> $DIR/unnecessary_operation.rs:58:5 + --> $DIR/unnecessary_operation.rs:74:5 | LL | Enum::Struct { field: get_number() }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `get_number();` error: unnecessary operation - --> $DIR/unnecessary_operation.rs:59:5 + --> $DIR/unnecessary_operation.rs:75:5 | LL | 5 + get_number(); | ^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `5;get_number();` error: unnecessary operation - --> $DIR/unnecessary_operation.rs:60:5 + --> $DIR/unnecessary_operation.rs:76:5 | LL | *&get_number(); | ^^^^^^^^^^^^^^^ help: statement can be reduced to: `get_number();` error: unnecessary operation - --> $DIR/unnecessary_operation.rs:61:5 + --> $DIR/unnecessary_operation.rs:77:5 | LL | &get_number(); | ^^^^^^^^^^^^^^ help: statement can be reduced to: `get_number();` error: unnecessary operation - --> $DIR/unnecessary_operation.rs:62:5 + --> $DIR/unnecessary_operation.rs:78:5 | LL | (5, 6, get_number()); | ^^^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `5;6;get_number();` error: unnecessary operation - --> $DIR/unnecessary_operation.rs:63:5 + --> $DIR/unnecessary_operation.rs:79:5 | LL | get_number()..; | ^^^^^^^^^^^^^^^ help: statement can be reduced to: `get_number();` error: unnecessary operation - --> $DIR/unnecessary_operation.rs:64:5 + --> $DIR/unnecessary_operation.rs:80:5 | LL | ..get_number(); | ^^^^^^^^^^^^^^^ help: statement can be reduced to: `get_number();` error: unnecessary operation - --> $DIR/unnecessary_operation.rs:65:5 + --> $DIR/unnecessary_operation.rs:81:5 | LL | 5..get_number(); | ^^^^^^^^^^^^^^^^ help: statement can be reduced to: `5;get_number();` error: unnecessary operation - --> $DIR/unnecessary_operation.rs:66:5 + --> $DIR/unnecessary_operation.rs:82:5 | LL | [42, get_number()]; | ^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `42;get_number();` error: unnecessary operation - --> $DIR/unnecessary_operation.rs:67:5 + --> $DIR/unnecessary_operation.rs:83:5 | LL | [42, 55][get_usize()]; | ^^^^^^^^^^^^^^^^^^^^^^ help: statement can be written as: `assert!([42, 55].len() > get_usize());` error: unnecessary operation - --> $DIR/unnecessary_operation.rs:68:5 + --> $DIR/unnecessary_operation.rs:84:5 | LL | (42, get_number()).1; | ^^^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `42;get_number();` error: unnecessary operation - --> $DIR/unnecessary_operation.rs:69:5 + --> $DIR/unnecessary_operation.rs:85:5 | LL | [get_number(); 55]; | ^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `get_number();` error: unnecessary operation - --> $DIR/unnecessary_operation.rs:70:5 + --> $DIR/unnecessary_operation.rs:86:5 | LL | [42; 55][get_usize()]; | ^^^^^^^^^^^^^^^^^^^^^^ help: statement can be written as: `assert!([42; 55].len() > get_usize());` error: unnecessary operation - --> $DIR/unnecessary_operation.rs:71:5 + --> $DIR/unnecessary_operation.rs:87:5 | LL | / { LL | | get_number() @@ -112,7 +112,7 @@ LL | | }; | |______^ help: statement can be reduced to: `get_number();` error: unnecessary operation - --> $DIR/unnecessary_operation.rs:74:5 + --> $DIR/unnecessary_operation.rs:90:5 | LL | / FooString { LL | | s: String::from("blah"), diff --git a/src/tools/clippy/tests/ui/unnecessary_to_owned.fixed b/src/tools/clippy/tests/ui/unnecessary_to_owned.fixed index 67faabc53cb..2dd1d746626 100644 --- a/src/tools/clippy/tests/ui/unnecessary_to_owned.fixed +++ b/src/tools/clippy/tests/ui/unnecessary_to_owned.fixed @@ -1,4 +1,10 @@ -#![allow(clippy::needless_borrow, clippy::needless_borrows_for_generic_args, clippy::ptr_arg)] +#![allow( + clippy::needless_borrow, + clippy::needless_borrows_for_generic_args, + clippy::ptr_arg, + clippy::manual_async_fn, + clippy::needless_lifetimes +)] #![warn(clippy::unnecessary_to_owned, clippy::redundant_clone)] use std::borrow::Cow; @@ -506,3 +512,18 @@ mod issue_10033 { } } } + +mod issue_11952 { + use core::future::{Future, IntoFuture}; + + fn foo<'a, T: AsRef<[u8]>>(x: T, y: &'a i32) -> impl 'a + Future<Output = Result<(), ()>> { + async move { + let _y = y; + Ok(()) + } + } + + fn bar() { + IntoFuture::into_future(foo([], &0)); + } +} diff --git a/src/tools/clippy/tests/ui/unnecessary_to_owned.rs b/src/tools/clippy/tests/ui/unnecessary_to_owned.rs index 99f9136427d..17fad33402b 100644 --- a/src/tools/clippy/tests/ui/unnecessary_to_owned.rs +++ b/src/tools/clippy/tests/ui/unnecessary_to_owned.rs @@ -1,4 +1,10 @@ -#![allow(clippy::needless_borrow, clippy::needless_borrows_for_generic_args, clippy::ptr_arg)] +#![allow( + clippy::needless_borrow, + clippy::needless_borrows_for_generic_args, + clippy::ptr_arg, + clippy::manual_async_fn, + clippy::needless_lifetimes +)] #![warn(clippy::unnecessary_to_owned, clippy::redundant_clone)] use std::borrow::Cow; @@ -506,3 +512,18 @@ mod issue_10033 { } } } + +mod issue_11952 { + use core::future::{Future, IntoFuture}; + + fn foo<'a, T: AsRef<[u8]>>(x: T, y: &'a i32) -> impl 'a + Future<Output = Result<(), ()>> { + async move { + let _y = y; + Ok(()) + } + } + + fn bar() { + IntoFuture::into_future(foo([].to_vec(), &0)); + } +} diff --git a/src/tools/clippy/tests/ui/unnecessary_to_owned.stderr b/src/tools/clippy/tests/ui/unnecessary_to_owned.stderr index d8971b51dca..ad6fa422b8c 100644 --- a/src/tools/clippy/tests/ui/unnecessary_to_owned.stderr +++ b/src/tools/clippy/tests/ui/unnecessary_to_owned.stderr @@ -1,11 +1,11 @@ error: redundant clone - --> $DIR/unnecessary_to_owned.rs:148:64 + --> $DIR/unnecessary_to_owned.rs:154:64 | LL | require_c_str(&CString::from_vec_with_nul(vec![0]).unwrap().to_owned()); | ^^^^^^^^^^^ help: remove this | note: this value is dropped without further use - --> $DIR/unnecessary_to_owned.rs:148:20 + --> $DIR/unnecessary_to_owned.rs:154:20 | LL | require_c_str(&CString::from_vec_with_nul(vec![0]).unwrap().to_owned()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -13,55 +13,55 @@ LL | require_c_str(&CString::from_vec_with_nul(vec![0]).unwrap().to_owned()) = help: to override `-D warnings` add `#[allow(clippy::redundant_clone)]` error: redundant clone - --> $DIR/unnecessary_to_owned.rs:149:40 + --> $DIR/unnecessary_to_owned.rs:155:40 | LL | require_os_str(&OsString::from("x").to_os_string()); | ^^^^^^^^^^^^^^^ help: remove this | note: this value is dropped without further use - --> $DIR/unnecessary_to_owned.rs:149:21 + --> $DIR/unnecessary_to_owned.rs:155:21 | LL | require_os_str(&OsString::from("x").to_os_string()); | ^^^^^^^^^^^^^^^^^^^ error: redundant clone - --> $DIR/unnecessary_to_owned.rs:150:48 + --> $DIR/unnecessary_to_owned.rs:156:48 | LL | require_path(&std::path::PathBuf::from("x").to_path_buf()); | ^^^^^^^^^^^^^^ help: remove this | note: this value is dropped without further use - --> $DIR/unnecessary_to_owned.rs:150:19 + --> $DIR/unnecessary_to_owned.rs:156:19 | LL | require_path(&std::path::PathBuf::from("x").to_path_buf()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: redundant clone - --> $DIR/unnecessary_to_owned.rs:151:35 + --> $DIR/unnecessary_to_owned.rs:157:35 | LL | require_str(&String::from("x").to_string()); | ^^^^^^^^^^^^ help: remove this | note: this value is dropped without further use - --> $DIR/unnecessary_to_owned.rs:151:18 + --> $DIR/unnecessary_to_owned.rs:157:18 | LL | require_str(&String::from("x").to_string()); | ^^^^^^^^^^^^^^^^^ error: redundant clone - --> $DIR/unnecessary_to_owned.rs:152:39 + --> $DIR/unnecessary_to_owned.rs:158:39 | LL | require_slice(&[String::from("x")].to_owned()); | ^^^^^^^^^^^ help: remove this | note: this value is dropped without further use - --> $DIR/unnecessary_to_owned.rs:152:20 + --> $DIR/unnecessary_to_owned.rs:158:20 | LL | require_slice(&[String::from("x")].to_owned()); | ^^^^^^^^^^^^^^^^^^^ error: unnecessary use of `into_owned` - --> $DIR/unnecessary_to_owned.rs:57:36 + --> $DIR/unnecessary_to_owned.rs:63:36 | LL | require_c_str(&Cow::from(c_str).into_owned()); | ^^^^^^^^^^^^^ help: remove this @@ -70,415 +70,415 @@ LL | require_c_str(&Cow::from(c_str).into_owned()); = help: to override `-D warnings` add `#[allow(clippy::unnecessary_to_owned)]` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:58:19 + --> $DIR/unnecessary_to_owned.rs:64:19 | LL | require_c_str(&c_str.to_owned()); | ^^^^^^^^^^^^^^^^^ help: use: `c_str` error: unnecessary use of `to_os_string` - --> $DIR/unnecessary_to_owned.rs:60:20 + --> $DIR/unnecessary_to_owned.rs:66:20 | LL | require_os_str(&os_str.to_os_string()); | ^^^^^^^^^^^^^^^^^^^^^^ help: use: `os_str` error: unnecessary use of `into_owned` - --> $DIR/unnecessary_to_owned.rs:61:38 + --> $DIR/unnecessary_to_owned.rs:67:38 | LL | require_os_str(&Cow::from(os_str).into_owned()); | ^^^^^^^^^^^^^ help: remove this error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:62:20 + --> $DIR/unnecessary_to_owned.rs:68:20 | LL | require_os_str(&os_str.to_owned()); | ^^^^^^^^^^^^^^^^^^ help: use: `os_str` error: unnecessary use of `to_path_buf` - --> $DIR/unnecessary_to_owned.rs:64:18 + --> $DIR/unnecessary_to_owned.rs:70:18 | LL | require_path(&path.to_path_buf()); | ^^^^^^^^^^^^^^^^^^^ help: use: `path` error: unnecessary use of `into_owned` - --> $DIR/unnecessary_to_owned.rs:65:34 + --> $DIR/unnecessary_to_owned.rs:71:34 | LL | require_path(&Cow::from(path).into_owned()); | ^^^^^^^^^^^^^ help: remove this error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:66:18 + --> $DIR/unnecessary_to_owned.rs:72:18 | LL | require_path(&path.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `path` error: unnecessary use of `to_string` - --> $DIR/unnecessary_to_owned.rs:68:17 + --> $DIR/unnecessary_to_owned.rs:74:17 | LL | require_str(&s.to_string()); | ^^^^^^^^^^^^^^ help: use: `s` error: unnecessary use of `into_owned` - --> $DIR/unnecessary_to_owned.rs:69:30 + --> $DIR/unnecessary_to_owned.rs:75:30 | LL | require_str(&Cow::from(s).into_owned()); | ^^^^^^^^^^^^^ help: remove this error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:70:17 + --> $DIR/unnecessary_to_owned.rs:76:17 | LL | require_str(&s.to_owned()); | ^^^^^^^^^^^^^ help: use: `s` error: unnecessary use of `to_string` - --> $DIR/unnecessary_to_owned.rs:71:17 + --> $DIR/unnecessary_to_owned.rs:77:17 | LL | require_str(&x_ref.to_string()); | ^^^^^^^^^^^^^^^^^^ help: use: `x_ref.as_ref()` error: unnecessary use of `to_vec` - --> $DIR/unnecessary_to_owned.rs:73:19 + --> $DIR/unnecessary_to_owned.rs:79:19 | LL | require_slice(&slice.to_vec()); | ^^^^^^^^^^^^^^^ help: use: `slice` error: unnecessary use of `into_owned` - --> $DIR/unnecessary_to_owned.rs:74:36 + --> $DIR/unnecessary_to_owned.rs:80:36 | LL | require_slice(&Cow::from(slice).into_owned()); | ^^^^^^^^^^^^^ help: remove this error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:75:19 + --> $DIR/unnecessary_to_owned.rs:81:19 | LL | require_slice(&array.to_owned()); | ^^^^^^^^^^^^^^^^^ help: use: `array.as_ref()` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:76:19 + --> $DIR/unnecessary_to_owned.rs:82:19 | LL | require_slice(&array_ref.to_owned()); | ^^^^^^^^^^^^^^^^^^^^^ help: use: `array_ref.as_ref()` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:77:19 + --> $DIR/unnecessary_to_owned.rs:83:19 | LL | require_slice(&slice.to_owned()); | ^^^^^^^^^^^^^^^^^ help: use: `slice` error: unnecessary use of `into_owned` - --> $DIR/unnecessary_to_owned.rs:80:42 + --> $DIR/unnecessary_to_owned.rs:86:42 | LL | require_x(&Cow::<X>::Owned(x.clone()).into_owned()); | ^^^^^^^^^^^^^ help: remove this error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:83:25 + --> $DIR/unnecessary_to_owned.rs:89:25 | LL | require_deref_c_str(c_str.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `c_str` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:84:26 + --> $DIR/unnecessary_to_owned.rs:90:26 | LL | require_deref_os_str(os_str.to_owned()); | ^^^^^^^^^^^^^^^^^ help: use: `os_str` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:85:24 + --> $DIR/unnecessary_to_owned.rs:91:24 | LL | require_deref_path(path.to_owned()); | ^^^^^^^^^^^^^^^ help: use: `path` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:86:23 + --> $DIR/unnecessary_to_owned.rs:92:23 | LL | require_deref_str(s.to_owned()); | ^^^^^^^^^^^^ help: use: `s` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:87:25 + --> $DIR/unnecessary_to_owned.rs:93:25 | LL | require_deref_slice(slice.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `slice` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:89:30 + --> $DIR/unnecessary_to_owned.rs:95:30 | LL | require_impl_deref_c_str(c_str.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `c_str` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:90:31 + --> $DIR/unnecessary_to_owned.rs:96:31 | LL | require_impl_deref_os_str(os_str.to_owned()); | ^^^^^^^^^^^^^^^^^ help: use: `os_str` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:91:29 + --> $DIR/unnecessary_to_owned.rs:97:29 | LL | require_impl_deref_path(path.to_owned()); | ^^^^^^^^^^^^^^^ help: use: `path` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:92:28 + --> $DIR/unnecessary_to_owned.rs:98:28 | LL | require_impl_deref_str(s.to_owned()); | ^^^^^^^^^^^^ help: use: `s` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:93:30 + --> $DIR/unnecessary_to_owned.rs:99:30 | LL | require_impl_deref_slice(slice.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `slice` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:95:29 + --> $DIR/unnecessary_to_owned.rs:101:29 | LL | require_deref_str_slice(s.to_owned(), slice.to_owned()); | ^^^^^^^^^^^^ help: use: `s` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:95:43 + --> $DIR/unnecessary_to_owned.rs:101:43 | LL | require_deref_str_slice(s.to_owned(), slice.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `slice` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:96:29 + --> $DIR/unnecessary_to_owned.rs:102:29 | LL | require_deref_slice_str(slice.to_owned(), s.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `slice` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:96:47 + --> $DIR/unnecessary_to_owned.rs:102:47 | LL | require_deref_slice_str(slice.to_owned(), s.to_owned()); | ^^^^^^^^^^^^ help: use: `s` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:98:26 + --> $DIR/unnecessary_to_owned.rs:104:26 | LL | require_as_ref_c_str(c_str.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `c_str` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:99:27 + --> $DIR/unnecessary_to_owned.rs:105:27 | LL | require_as_ref_os_str(os_str.to_owned()); | ^^^^^^^^^^^^^^^^^ help: use: `os_str` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:100:25 + --> $DIR/unnecessary_to_owned.rs:106:25 | LL | require_as_ref_path(path.to_owned()); | ^^^^^^^^^^^^^^^ help: use: `path` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:101:24 + --> $DIR/unnecessary_to_owned.rs:107:24 | LL | require_as_ref_str(s.to_owned()); | ^^^^^^^^^^^^ help: use: `s` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:102:24 + --> $DIR/unnecessary_to_owned.rs:108:24 | LL | require_as_ref_str(x.to_owned()); | ^^^^^^^^^^^^ help: use: `&x` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:103:26 + --> $DIR/unnecessary_to_owned.rs:109:26 | LL | require_as_ref_slice(array.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `array` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:104:26 + --> $DIR/unnecessary_to_owned.rs:110:26 | LL | require_as_ref_slice(array_ref.to_owned()); | ^^^^^^^^^^^^^^^^^^^^ help: use: `array_ref` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:105:26 + --> $DIR/unnecessary_to_owned.rs:111:26 | LL | require_as_ref_slice(slice.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `slice` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:107:31 + --> $DIR/unnecessary_to_owned.rs:113:31 | LL | require_impl_as_ref_c_str(c_str.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `c_str` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:108:32 + --> $DIR/unnecessary_to_owned.rs:114:32 | LL | require_impl_as_ref_os_str(os_str.to_owned()); | ^^^^^^^^^^^^^^^^^ help: use: `os_str` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:109:30 + --> $DIR/unnecessary_to_owned.rs:115:30 | LL | require_impl_as_ref_path(path.to_owned()); | ^^^^^^^^^^^^^^^ help: use: `path` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:110:29 + --> $DIR/unnecessary_to_owned.rs:116:29 | LL | require_impl_as_ref_str(s.to_owned()); | ^^^^^^^^^^^^ help: use: `s` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:111:29 + --> $DIR/unnecessary_to_owned.rs:117:29 | LL | require_impl_as_ref_str(x.to_owned()); | ^^^^^^^^^^^^ help: use: `&x` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:112:31 + --> $DIR/unnecessary_to_owned.rs:118:31 | LL | require_impl_as_ref_slice(array.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `array` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:113:31 + --> $DIR/unnecessary_to_owned.rs:119:31 | LL | require_impl_as_ref_slice(array_ref.to_owned()); | ^^^^^^^^^^^^^^^^^^^^ help: use: `array_ref` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:114:31 + --> $DIR/unnecessary_to_owned.rs:120:31 | LL | require_impl_as_ref_slice(slice.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `slice` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:116:30 + --> $DIR/unnecessary_to_owned.rs:122:30 | LL | require_as_ref_str_slice(s.to_owned(), array.to_owned()); | ^^^^^^^^^^^^ help: use: `s` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:116:44 + --> $DIR/unnecessary_to_owned.rs:122:44 | LL | require_as_ref_str_slice(s.to_owned(), array.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `array` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:117:30 + --> $DIR/unnecessary_to_owned.rs:123:30 | LL | require_as_ref_str_slice(s.to_owned(), array_ref.to_owned()); | ^^^^^^^^^^^^ help: use: `s` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:117:44 + --> $DIR/unnecessary_to_owned.rs:123:44 | LL | require_as_ref_str_slice(s.to_owned(), array_ref.to_owned()); | ^^^^^^^^^^^^^^^^^^^^ help: use: `array_ref` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:118:30 + --> $DIR/unnecessary_to_owned.rs:124:30 | LL | require_as_ref_str_slice(s.to_owned(), slice.to_owned()); | ^^^^^^^^^^^^ help: use: `s` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:118:44 + --> $DIR/unnecessary_to_owned.rs:124:44 | LL | require_as_ref_str_slice(s.to_owned(), slice.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `slice` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:119:30 + --> $DIR/unnecessary_to_owned.rs:125:30 | LL | require_as_ref_slice_str(array.to_owned(), s.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `array` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:119:48 + --> $DIR/unnecessary_to_owned.rs:125:48 | LL | require_as_ref_slice_str(array.to_owned(), s.to_owned()); | ^^^^^^^^^^^^ help: use: `s` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:120:30 + --> $DIR/unnecessary_to_owned.rs:126:30 | LL | require_as_ref_slice_str(array_ref.to_owned(), s.to_owned()); | ^^^^^^^^^^^^^^^^^^^^ help: use: `array_ref` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:120:52 + --> $DIR/unnecessary_to_owned.rs:126:52 | LL | require_as_ref_slice_str(array_ref.to_owned(), s.to_owned()); | ^^^^^^^^^^^^ help: use: `s` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:121:30 + --> $DIR/unnecessary_to_owned.rs:127:30 | LL | require_as_ref_slice_str(slice.to_owned(), s.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `slice` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:121:48 + --> $DIR/unnecessary_to_owned.rs:127:48 | LL | require_as_ref_slice_str(slice.to_owned(), s.to_owned()); | ^^^^^^^^^^^^ help: use: `s` error: unnecessary use of `to_string` - --> $DIR/unnecessary_to_owned.rs:123:20 + --> $DIR/unnecessary_to_owned.rs:129:20 | LL | let _ = x.join(&x_ref.to_string()); | ^^^^^^^^^^^^^^^^^^ help: use: `x_ref` error: unnecessary use of `to_vec` - --> $DIR/unnecessary_to_owned.rs:125:13 + --> $DIR/unnecessary_to_owned.rs:131:13 | LL | let _ = slice.to_vec().into_iter(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `slice.iter().copied()` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:126:13 + --> $DIR/unnecessary_to_owned.rs:132:13 | LL | let _ = slice.to_owned().into_iter(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `slice.iter().copied()` error: unnecessary use of `to_vec` - --> $DIR/unnecessary_to_owned.rs:127:13 + --> $DIR/unnecessary_to_owned.rs:133:13 | LL | let _ = [std::path::PathBuf::new()][..].to_vec().into_iter(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `[std::path::PathBuf::new()][..].iter().cloned()` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:128:13 + --> $DIR/unnecessary_to_owned.rs:134:13 | LL | let _ = [std::path::PathBuf::new()][..].to_owned().into_iter(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `[std::path::PathBuf::new()][..].iter().cloned()` error: unnecessary use of `to_vec` - --> $DIR/unnecessary_to_owned.rs:130:13 + --> $DIR/unnecessary_to_owned.rs:136:13 | LL | let _ = IntoIterator::into_iter(slice.to_vec()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `slice.iter().copied()` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:131:13 + --> $DIR/unnecessary_to_owned.rs:137:13 | LL | let _ = IntoIterator::into_iter(slice.to_owned()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `slice.iter().copied()` error: unnecessary use of `to_vec` - --> $DIR/unnecessary_to_owned.rs:132:13 + --> $DIR/unnecessary_to_owned.rs:138:13 | LL | let _ = IntoIterator::into_iter([std::path::PathBuf::new()][..].to_vec()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `[std::path::PathBuf::new()][..].iter().cloned()` error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:133:13 + --> $DIR/unnecessary_to_owned.rs:139:13 | LL | let _ = IntoIterator::into_iter([std::path::PathBuf::new()][..].to_owned()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `[std::path::PathBuf::new()][..].iter().cloned()` error: unnecessary use of `to_vec` - --> $DIR/unnecessary_to_owned.rs:195:14 + --> $DIR/unnecessary_to_owned.rs:201:14 | LL | for t in file_types.to_vec() { | ^^^^^^^^^^^^^^^^^^^ @@ -494,28 +494,34 @@ LL + let path = match get_file_path(t) { | error: unnecessary use of `to_vec` - --> $DIR/unnecessary_to_owned.rs:218:14 + --> $DIR/unnecessary_to_owned.rs:224:14 | LL | let _ = &["x"][..].to_vec().into_iter(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `["x"][..].iter().cloned()` error: unnecessary use of `to_vec` - --> $DIR/unnecessary_to_owned.rs:223:14 + --> $DIR/unnecessary_to_owned.rs:229:14 | LL | let _ = &["x"][..].to_vec().into_iter(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `["x"][..].iter().copied()` error: unnecessary use of `to_string` - --> $DIR/unnecessary_to_owned.rs:270:24 + --> $DIR/unnecessary_to_owned.rs:276:24 | LL | Box::new(build(y.to_string())) | ^^^^^^^^^^^^^ help: use: `y` error: unnecessary use of `to_string` - --> $DIR/unnecessary_to_owned.rs:378:12 + --> $DIR/unnecessary_to_owned.rs:384:12 | LL | id("abc".to_string()) | ^^^^^^^^^^^^^^^^^ help: use: `"abc"` -error: aborting due to 79 previous errors +error: unnecessary use of `to_vec` + --> $DIR/unnecessary_to_owned.rs:527:37 + | +LL | IntoFuture::into_future(foo([].to_vec(), &0)); + | ^^^^^^^^^^^ help: use: `[]` + +error: aborting due to 80 previous errors diff --git a/src/tools/clippy/tests/ui/unnecessary_unsafety_doc.rs b/src/tools/clippy/tests/ui/unnecessary_unsafety_doc.rs index 373b18470f6..5ad117eb8db 100644 --- a/src/tools/clippy/tests/ui/unnecessary_unsafety_doc.rs +++ b/src/tools/clippy/tests/ui/unnecessary_unsafety_doc.rs @@ -1,6 +1,6 @@ //@aux-build:proc_macros.rs -#![allow(clippy::let_unit_value)] +#![allow(clippy::let_unit_value, clippy::needless_pass_by_ref_mut)] #![warn(clippy::unnecessary_safety_doc)] extern crate proc_macros; diff --git a/src/tools/clippy/tests/ui/vec.fixed b/src/tools/clippy/tests/ui/vec.fixed index bcbca971a78..81b8bd7da77 100644 --- a/src/tools/clippy/tests/ui/vec.fixed +++ b/src/tools/clippy/tests/ui/vec.fixed @@ -176,3 +176,37 @@ fn below() { let _: String = a; } } + +fn func_needing_vec(_bar: usize, _baz: Vec<usize>) {} +fn func_not_needing_vec(_bar: usize, _baz: usize) {} + +fn issue11861() { + macro_rules! this_macro_needs_vec { + ($x:expr) => {{ + func_needing_vec($x.iter().sum(), $x); + for _ in $x {} + }}; + } + macro_rules! this_macro_doesnt_need_vec { + ($x:expr) => {{ func_not_needing_vec($x.iter().sum(), $x.iter().sum()) }}; + } + + // Do not lint the next line + this_macro_needs_vec!(vec![1]); + this_macro_doesnt_need_vec!([1]); //~ ERROR: useless use of `vec!` + + macro_rules! m { + ($x:expr) => { + fn f2() { + let _x: Vec<i32> = $x; + } + fn f() { + let _x = $x; + $x.starts_with(&[]); + } + }; + } + + // should not lint + m!(vec![1]); +} diff --git a/src/tools/clippy/tests/ui/vec.rs b/src/tools/clippy/tests/ui/vec.rs index 087425585de..5aca9b2925c 100644 --- a/src/tools/clippy/tests/ui/vec.rs +++ b/src/tools/clippy/tests/ui/vec.rs @@ -176,3 +176,37 @@ fn below() { let _: String = a; } } + +fn func_needing_vec(_bar: usize, _baz: Vec<usize>) {} +fn func_not_needing_vec(_bar: usize, _baz: usize) {} + +fn issue11861() { + macro_rules! this_macro_needs_vec { + ($x:expr) => {{ + func_needing_vec($x.iter().sum(), $x); + for _ in $x {} + }}; + } + macro_rules! this_macro_doesnt_need_vec { + ($x:expr) => {{ func_not_needing_vec($x.iter().sum(), $x.iter().sum()) }}; + } + + // Do not lint the next line + this_macro_needs_vec!(vec![1]); + this_macro_doesnt_need_vec!(vec![1]); //~ ERROR: useless use of `vec!` + + macro_rules! m { + ($x:expr) => { + fn f2() { + let _x: Vec<i32> = $x; + } + fn f() { + let _x = $x; + $x.starts_with(&[]); + } + }; + } + + // should not lint + m!(vec![1]); +} diff --git a/src/tools/clippy/tests/ui/vec.stderr b/src/tools/clippy/tests/ui/vec.stderr index fc261838fe3..c9018f94f9d 100644 --- a/src/tools/clippy/tests/ui/vec.stderr +++ b/src/tools/clippy/tests/ui/vec.stderr @@ -115,5 +115,11 @@ error: useless use of `vec!` LL | for a in vec![String::new(), String::new()] { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can use an array directly: `[String::new(), String::new()]` -error: aborting due to 19 previous errors +error: useless use of `vec!` + --> $DIR/vec.rs:196:33 + | +LL | this_macro_doesnt_need_vec!(vec![1]); + | ^^^^^^^ help: you can use an array directly: `[1]` + +error: aborting due to 20 previous errors diff --git a/src/tools/clippy/triagebot.toml b/src/tools/clippy/triagebot.toml index ab2fb1a3291..96085bcf9ee 100644 --- a/src/tools/clippy/triagebot.toml +++ b/src/tools/clippy/triagebot.toml @@ -19,6 +19,7 @@ new_pr = true [assign] contributing_url = "https://github.com/rust-lang/rust-clippy/blob/master/CONTRIBUTING.md" +users_on_vacation = ["blyxyas"] [assign.owners] "/.github" = ["@flip1995"] diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server.rs index 54430e0d190..917d8a6e26a 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server.rs @@ -58,6 +58,10 @@ impl server::Types for RustAnalyzer { } impl server::FreeFunctions for RustAnalyzer { + fn injected_env_var(&mut self, _var: &str) -> Option<String> { + None + } + fn track_env_var(&mut self, _var: &str, _value: Option<&str>) { // FIXME: track env var accesses // https://github.com/rust-lang/rust/pull/71858 diff --git a/tests/codegen/debug-accessibility/crate-enum.rs b/tests/codegen/debug-accessibility/crate-enum.rs new file mode 100644 index 00000000000..eeea18dd815 --- /dev/null +++ b/tests/codegen/debug-accessibility/crate-enum.rs @@ -0,0 +1,26 @@ +// compile-flags: -C debuginfo=2 +// ignore-tidy-linelength + +#![allow(dead_code)] + +// Checks that visibility information is present in the debuginfo for crate-visibility enums. + +mod module { + use std::hint::black_box; + + pub(crate) enum CrateFooEnum { + A, + B(u32), + C { x: u32 }, + } + + // NONMSVC: {{!.*}} = !DICompositeType(tag: DW_TAG_structure_type, name: "CrateFooEnum"{{.*}}flags: DIFlagProtected{{.*}}) + // MSVC: {{!.*}} = !DICompositeType(tag: DW_TAG_union_type, name: "enum2$<crate_enum::module::CrateFooEnum>"{{.*}}flags: DIFlagProtected{{.*}}) + pub fn use_everything() { + black_box(CrateFooEnum::A); + } +} + +fn main() { + module::use_everything(); +} diff --git a/tests/codegen/debug-accessibility/crate-struct.rs b/tests/codegen/debug-accessibility/crate-struct.rs new file mode 100644 index 00000000000..68d126a3478 --- /dev/null +++ b/tests/codegen/debug-accessibility/crate-struct.rs @@ -0,0 +1,23 @@ +// compile-flags: -C debuginfo=2 + +#![allow(dead_code)] + +// Checks that visibility information is present in the debuginfo for crate-visibility structs. + +mod module { + use std::hint::black_box; + + pub(crate) struct CrateFooStruct { + x: u32, + } + + // CHECK: {{!.*}} = !DICompositeType(tag: DW_TAG_structure_type, name: "CrateFooStruct"{{.*}}flags: DIFlagProtected{{.*}}) + + pub fn use_everything() { + black_box(CrateFooStruct { x: 2 }); + } +} + +fn main() { + module::use_everything(); +} diff --git a/tests/codegen/debug-accessibility/private-enum.rs b/tests/codegen/debug-accessibility/private-enum.rs new file mode 100644 index 00000000000..7f81026ddec --- /dev/null +++ b/tests/codegen/debug-accessibility/private-enum.rs @@ -0,0 +1,21 @@ +// compile-flags: -C debuginfo=2 +// ignore-tidy-linelength + +#![allow(dead_code)] + +// Checks that visibility information is present in the debuginfo for private enums. + +use std::hint::black_box; + +enum PrivateFooEnum { + A, + B(u32), + C { x: u32 }, +} + +// NONMSVC: {{!.*}} = !DICompositeType(tag: DW_TAG_structure_type, name: "PrivateFooEnum"{{.*}}flags: DIFlagPrivate{{.*}}) +// MSVC: {{!.*}} = !DICompositeType(tag: DW_TAG_union_type, name: "enum2$<private_enum::PrivateFooEnum>"{{.*}}flags: DIFlagPrivate{{.*}}) + +fn main() { + black_box(PrivateFooEnum::A); +} diff --git a/tests/codegen/debug-accessibility/private-struct.rs b/tests/codegen/debug-accessibility/private-struct.rs new file mode 100644 index 00000000000..43b260f9024 --- /dev/null +++ b/tests/codegen/debug-accessibility/private-struct.rs @@ -0,0 +1,17 @@ +// compile-flags: -C debuginfo=2 + +#![allow(dead_code)] + +// Checks that visibility information is present in the debuginfo for private structs. + +use std::hint::black_box; + +struct PrivateFooStruct { + x: u32, +} + +// CHECK: {{!.*}} = !DICompositeType(tag: DW_TAG_structure_type, name: "PrivateFooStruct"{{.*}}flags: DIFlagPrivate{{.*}}) + +fn main() { + black_box(PrivateFooStruct { x: 1 }); +} diff --git a/tests/codegen/debug-accessibility/public-enum.rs b/tests/codegen/debug-accessibility/public-enum.rs new file mode 100644 index 00000000000..29ae5fd6421 --- /dev/null +++ b/tests/codegen/debug-accessibility/public-enum.rs @@ -0,0 +1,21 @@ +// compile-flags: -C debuginfo=2 +// ignore-tidy-linelength + +#![allow(dead_code)] + +// Checks that visibility information is present in the debuginfo for types and their fields. + +use std::hint::black_box; + +pub enum PublicFooEnum { + A, + B(u32), + C { x: u32 }, +} + +// NONMSVC: {{!.*}} = !DICompositeType(tag: DW_TAG_structure_type, name: "PublicFooEnum"{{.*}}flags: DIFlagPublic{{.*}}) +// MSVC: {{!.*}} = !DICompositeType(tag: DW_TAG_union_type, name: "enum2$<public_enum::PublicFooEnum>"{{.*}}flags: DIFlagPublic{{.*}}) + +fn main() { + black_box(PublicFooEnum::A); +} diff --git a/tests/codegen/debug-accessibility/public-struct.rs b/tests/codegen/debug-accessibility/public-struct.rs new file mode 100644 index 00000000000..e7cd9b40d09 --- /dev/null +++ b/tests/codegen/debug-accessibility/public-struct.rs @@ -0,0 +1,17 @@ +// compile-flags: -C debuginfo=2 + +#![allow(dead_code)] + +// Checks that visibility information is present in the debuginfo for public structs. + +use std::hint::black_box; + +pub struct PublicFooStruct { + x: u32, +} + +// CHECK: {{!.*}} = !DICompositeType(tag: DW_TAG_structure_type, name: "PublicFooStruct"{{.*}}flags: DIFlagPublic{{.*}}) + +fn main() { + black_box(PublicFooStruct { x: 4 }); +} diff --git a/tests/codegen/debug-accessibility/struct-fields.rs b/tests/codegen/debug-accessibility/struct-fields.rs new file mode 100644 index 00000000000..76831bdc6c6 --- /dev/null +++ b/tests/codegen/debug-accessibility/struct-fields.rs @@ -0,0 +1,30 @@ +// compile-flags: -C debuginfo=2 + +#![allow(dead_code)] + +// Checks that visibility information is present in the debuginfo for struct fields. + +mod module { + use std::hint::black_box; + + struct StructFields { + a: u32, + pub(crate) b: u32, + pub(super) c: u32, + pub d: u32, + } + + // CHECK: [[StructFields:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "StructFields"{{.*}}flags: DIFlagPrivate{{.*}}) + // CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: [[StructFields]]{{.*}}flags: DIFlagPrivate{{.*}}) + // CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "b", scope: [[StructFields]]{{.*}}flags: DIFlagProtected{{.*}}) + // CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "c", scope: [[StructFields]]{{.*}}flags: DIFlagProtected{{.*}}) + // CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "d", scope: [[StructFields]]{{.*}}flags: DIFlagPublic{{.*}}) + + pub fn use_everything() { + black_box(StructFields { a: 1, b: 2, c: 3, d: 4 }); + } +} + +fn main() { + module::use_everything(); +} diff --git a/tests/codegen/debug-accessibility/super-enum.rs b/tests/codegen/debug-accessibility/super-enum.rs new file mode 100644 index 00000000000..9d83fb45bd0 --- /dev/null +++ b/tests/codegen/debug-accessibility/super-enum.rs @@ -0,0 +1,27 @@ +// compile-flags: -C debuginfo=2 +// ignore-tidy-linelength + +#![allow(dead_code)] + +// Checks that visibility information is present in the debuginfo for super-visibility enums. + +mod module { + use std::hint::black_box; + + pub(super) enum SuperFooEnum { + A, + B(u32), + C { x: u32 }, + } + + // NONMSVC: {{!.*}} = !DICompositeType(tag: DW_TAG_structure_type, name: "SuperFooEnum"{{.*}}flags: DIFlagProtected{{.*}}) + // MSVC: {{!.*}} = !DICompositeType(tag: DW_TAG_union_type, name: "enum2$<super_enum::module::SuperFooEnum>"{{.*}}flags: DIFlagProtected{{.*}}) + + pub fn use_everything() { + black_box(SuperFooEnum::A); + } +} + +fn main() { + module::use_everything(); +} diff --git a/tests/codegen/debug-accessibility/super-struct.rs b/tests/codegen/debug-accessibility/super-struct.rs new file mode 100644 index 00000000000..481006c3965 --- /dev/null +++ b/tests/codegen/debug-accessibility/super-struct.rs @@ -0,0 +1,23 @@ +// compile-flags: -C debuginfo=2 + +#![allow(dead_code)] + +// Checks that visibility information is present in the debuginfo for super-visibility structs. + +mod module { + use std::hint::black_box; + + pub(super) struct SuperFooStruct { + x: u32, + } + + // CHECK: {{!.*}} = !DICompositeType(tag: DW_TAG_structure_type, name: "SuperFooStruct"{{.*}}flags: DIFlagProtected{{.*}}) + + pub fn use_everything() { + black_box(SuperFooStruct { x: 3 }); + } +} + +fn main() { + module::use_everything(); +} diff --git a/tests/codegen/debug-accessibility/tuple-fields.rs b/tests/codegen/debug-accessibility/tuple-fields.rs new file mode 100644 index 00000000000..1163ba2c7c3 --- /dev/null +++ b/tests/codegen/debug-accessibility/tuple-fields.rs @@ -0,0 +1,24 @@ +// compile-flags: -C debuginfo=2 + +#![allow(dead_code)] + +// Checks that visibility information is present in the debuginfo for tuple struct fields. + +mod module { + use std::hint::black_box; + + struct TupleFields(u32, pub(crate) u32, pub(super) u32, pub u32); + + // CHECK: [[TupleFields:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "TupleFields"{{.*}}flags: DIFlagPrivate{{.*}}) + // CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "__0", scope: [[TupleFields]]{{.*}}flags: DIFlagPrivate{{.*}}) + // CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "__1", scope: [[TupleFields]]{{.*}}flags: DIFlagProtected{{.*}}) + // CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "__2", scope: [[TupleFields]]{{.*}}flags: DIFlagProtected{{.*}}) + // CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "__3", scope: [[TupleFields]]{{.*}}flags: DIFlagPublic{{.*}}) + pub fn use_everything() { + black_box(TupleFields(1, 2, 3, 4)); + } +} + +fn main() { + module::use_everything(); +} diff --git a/tests/coverage/assert_not.cov-map b/tests/coverage/assert_not.cov-map new file mode 100644 index 00000000000..788bc5dbf58 --- /dev/null +++ b/tests/coverage/assert_not.cov-map @@ -0,0 +1,16 @@ +Function name: assert_not::main +Raw bytes (33): 0x[01, 01, 02, 05, 00, 0d, 00, 05, 01, 06, 01, 01, 12, 05, 02, 05, 00, 14, 02, 01, 05, 00, 14, 0d, 01, 05, 00, 16, 06, 01, 01, 00, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 2 +- expression 0 operands: lhs = Counter(1), rhs = Zero +- expression 1 operands: lhs = Counter(3), rhs = Zero +Number of file 0 mappings: 5 +- Code(Counter(0)) at (prev + 6, 1) to (start + 1, 18) +- Code(Counter(1)) at (prev + 2, 5) to (start + 0, 20) +- Code(Expression(0, Sub)) at (prev + 1, 5) to (start + 0, 20) + = (c1 - Zero) +- Code(Counter(3)) at (prev + 1, 5) to (start + 0, 22) +- Code(Expression(1, Sub)) at (prev + 1, 1) to (start + 0, 2) + = (c3 - Zero) + diff --git a/tests/coverage/assert_not.coverage b/tests/coverage/assert_not.coverage new file mode 100644 index 00000000000..4cfdab974ed --- /dev/null +++ b/tests/coverage/assert_not.coverage @@ -0,0 +1,12 @@ + LL| |// edition: 2021 + LL| | + LL| |// Regression test for <https://github.com/rust-lang/rust/issues/118904>. + LL| |// `assert!(true)` and `assert!(!false)` should have similar coverage spans. + LL| | + LL| 1|fn main() { + LL| 1| assert!(true); + LL| 1| assert!(!false); + LL| 1| assert!(!!true); + LL| 1| assert!(!!!false); + LL| 1|} + diff --git a/tests/coverage/assert_not.rs b/tests/coverage/assert_not.rs new file mode 100644 index 00000000000..95204fcadd1 --- /dev/null +++ b/tests/coverage/assert_not.rs @@ -0,0 +1,11 @@ +// edition: 2021 + +// Regression test for <https://github.com/rust-lang/rust/issues/118904>. +// `assert!(true)` and `assert!(!false)` should have similar coverage spans. + +fn main() { + assert!(true); + assert!(!false); + assert!(!!true); + assert!(!!!false); +} diff --git a/tests/rustdoc-gui/globals.goml b/tests/rustdoc-gui/globals.goml new file mode 100644 index 00000000000..53f96ff086e --- /dev/null +++ b/tests/rustdoc-gui/globals.goml @@ -0,0 +1,24 @@ +// Make sure search stores its data in `window` +// It needs to use a global to avoid racing on search-index.js and search.js +// https://github.com/rust-lang/rust/pull/118961 + +// URL query +go-to: "file://" + |DOC_PATH| + "/test_docs/index.html?search=sa'%3Bda'%3Bds" +wait-for: "#search-tabs" +assert-window-property-false: {"searchIndex": null} +assert-window-property: {"srcIndex": null} + +// Form input +go-to: "file://" + |DOC_PATH| + "/test_docs/index.html" +write: (".search-input", "Foo") +press-key: 'Enter' +wait-for: "#search-tabs" +assert-window-property-false: {"searchIndex": null} +assert-window-property: {"srcIndex": null} + +// source sidebar +go-to: "file://" + |DOC_PATH| + "/src/test_docs/lib.rs.html" +click: "#src-sidebar-toggle" +wait-for: "#src-sidebar details" +assert-window-property-false: {"srcIndex": null} +assert-window-property: {"searchIndex": null} diff --git a/tests/ui/coherence/occurs-check/associated-type.next.stderr b/tests/ui/coherence/occurs-check/associated-type.next.stderr index 69f541cba05..f64e8b39798 100644 --- a/tests/ui/coherence/occurs-check/associated-type.next.stderr +++ b/tests/ui/coherence/occurs-check/associated-type.next.stderr @@ -1,11 +1,11 @@ -WARN rustc_infer::infer::generalize may incompletely handle alias type: Alias(Projection, AliasTy { args: [*const ?1t, ReBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), 'a) })], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) }) -WARN rustc_infer::infer::generalize may incompletely handle alias type: Alias(Projection, AliasTy { args: [*const ?1t, RePlaceholder(!2_BoundRegion { var: 0, kind: BrNamed(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), 'a) })], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) }) -WARN rustc_infer::infer::generalize may incompletely handle alias type: Alias(Projection, AliasTy { args: [*const ?1t, ReBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), 'a) })], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) }) -WARN rustc_infer::infer::generalize may incompletely handle alias type: Alias(Projection, AliasTy { args: [*const ?1t, RePlaceholder(!2_BoundRegion { var: 0, kind: BrNamed(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), 'a) })], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) }) -WARN rustc_infer::infer::generalize may incompletely handle alias type: Alias(Projection, AliasTy { args: [*const ?1t, ReBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), 'a) })], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) }) -WARN rustc_infer::infer::generalize may incompletely handle alias type: Alias(Projection, AliasTy { args: [*const ?1t, RePlaceholder(!2_BoundRegion { var: 0, kind: BrNamed(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), 'a) })], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) }) -WARN rustc_infer::infer::generalize may incompletely handle alias type: Alias(Projection, AliasTy { args: [*const ?1t, ReBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), 'a) })], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) }) -WARN rustc_infer::infer::generalize may incompletely handle alias type: Alias(Projection, AliasTy { args: [*const ?1t, RePlaceholder(!2_BoundRegion { var: 0, kind: BrNamed(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), 'a) })], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) }) +WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: Alias(Projection, AliasTy { args: [*const ?1t, ReBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), 'a) })], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) }) +WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: Alias(Projection, AliasTy { args: [*const ?1t, RePlaceholder(!2_BoundRegion { var: 0, kind: BrNamed(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), 'a) })], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) }) +WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: Alias(Projection, AliasTy { args: [*const ?1t, ReBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), 'a) })], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) }) +WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: Alias(Projection, AliasTy { args: [*const ?1t, RePlaceholder(!2_BoundRegion { var: 0, kind: BrNamed(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), 'a) })], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) }) +WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: Alias(Projection, AliasTy { args: [*const ?1t, ReBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), 'a) })], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) }) +WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: Alias(Projection, AliasTy { args: [*const ?1t, RePlaceholder(!2_BoundRegion { var: 0, kind: BrNamed(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), 'a) })], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) }) +WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: Alias(Projection, AliasTy { args: [*const ?1t, ReBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), 'a) })], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) }) +WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: Alias(Projection, AliasTy { args: [*const ?1t, RePlaceholder(!2_BoundRegion { var: 0, kind: BrNamed(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), 'a) })], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) }) error[E0119]: conflicting implementations of trait `Overlap<for<'a> fn(&'a (), ())>` for type `for<'a> fn(&'a (), ())` --> $DIR/associated-type.rs:31:1 | diff --git a/tests/ui/coherence/occurs-check/associated-type.old.stderr b/tests/ui/coherence/occurs-check/associated-type.old.stderr index c2c951af0db..8e852ec796e 100644 --- a/tests/ui/coherence/occurs-check/associated-type.old.stderr +++ b/tests/ui/coherence/occurs-check/associated-type.old.stderr @@ -1,11 +1,11 @@ -WARN rustc_infer::infer::generalize may incompletely handle alias type: Alias(Projection, AliasTy { args: [*const ?1t, ReBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), 'a) })], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) }) -WARN rustc_infer::infer::generalize may incompletely handle alias type: Alias(Projection, AliasTy { args: [*const ?1t, RePlaceholder(!3_BoundRegion { var: 0, kind: BrNamed(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), 'a) })], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) }) -WARN rustc_infer::infer::generalize may incompletely handle alias type: Alias(Projection, AliasTy { args: [*const ?1t, ReBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), 'a) })], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) }) -WARN rustc_infer::infer::generalize may incompletely handle alias type: Alias(Projection, AliasTy { args: [*const ?1t, RePlaceholder(!3_BoundRegion { var: 0, kind: BrNamed(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), 'a) })], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) }) -WARN rustc_infer::infer::generalize may incompletely handle alias type: Alias(Projection, AliasTy { args: [*const ?1t, ReBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), 'a) })], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) }) -WARN rustc_infer::infer::generalize may incompletely handle alias type: Alias(Projection, AliasTy { args: [*const ?1t, RePlaceholder(!3_BoundRegion { var: 0, kind: BrNamed(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), 'a) })], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) }) -WARN rustc_infer::infer::generalize may incompletely handle alias type: Alias(Projection, AliasTy { args: [*const ?1t, ReBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), 'a) })], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) }) -WARN rustc_infer::infer::generalize may incompletely handle alias type: Alias(Projection, AliasTy { args: [*const ?1t, RePlaceholder(!3_BoundRegion { var: 0, kind: BrNamed(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), 'a) })], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) }) +WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: Alias(Projection, AliasTy { args: [*const ?1t, ReBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), 'a) })], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) }) +WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: Alias(Projection, AliasTy { args: [*const ?1t, RePlaceholder(!3_BoundRegion { var: 0, kind: BrNamed(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), 'a) })], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) }) +WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: Alias(Projection, AliasTy { args: [*const ?1t, ReBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), 'a) })], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) }) +WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: Alias(Projection, AliasTy { args: [*const ?1t, RePlaceholder(!3_BoundRegion { var: 0, kind: BrNamed(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), 'a) })], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) }) +WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: Alias(Projection, AliasTy { args: [*const ?1t, ReBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), 'a) })], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) }) +WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: Alias(Projection, AliasTy { args: [*const ?1t, RePlaceholder(!3_BoundRegion { var: 0, kind: BrNamed(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), 'a) })], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) }) +WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: Alias(Projection, AliasTy { args: [*const ?1t, ReBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), 'a) })], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) }) +WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: Alias(Projection, AliasTy { args: [*const ?1t, RePlaceholder(!3_BoundRegion { var: 0, kind: BrNamed(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), 'a) })], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) }) error[E0119]: conflicting implementations of trait `Overlap<for<'a> fn(&'a (), _)>` for type `for<'a> fn(&'a (), _)` --> $DIR/associated-type.rs:31:1 | diff --git a/tests/ui/duplicate_entry_error.stderr b/tests/ui/duplicate_entry_error.stderr index 592640a884c..3b5998df353 100644 --- a/tests/ui/duplicate_entry_error.stderr +++ b/tests/ui/duplicate_entry_error.stderr @@ -1,8 +1,11 @@ error[E0152]: found duplicate lang item `panic_impl` --> $DIR/duplicate_entry_error.rs:11:1 | -LL | fn panic_impl(info: &PanicInfo) -> ! { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | / fn panic_impl(info: &PanicInfo) -> ! { +LL | | +LL | | loop {} +LL | | } + | |_^ | = note: the lang item is first defined in crate `std` (which `duplicate_entry_error` depends on) = note: first definition in `std` loaded from SYSROOT/libstd-*.rlib diff --git a/tests/ui/error-codes/E0152.stderr b/tests/ui/error-codes/E0152.stderr index 816ba2d569b..dbea7e6d27f 100644 --- a/tests/ui/error-codes/E0152.stderr +++ b/tests/ui/error-codes/E0152.stderr @@ -2,7 +2,7 @@ error[E0152]: found duplicate lang item `owned_box` --> $DIR/E0152.rs:5:1 | LL | struct Foo<T>(T); - | ^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^ | = note: the lang item is first defined in crate `alloc` (which `std` depends on) = note: first definition in `alloc` loaded from SYSROOT/liballoc-*.rlib diff --git a/tests/ui/error-codes/E0264.stderr b/tests/ui/error-codes/E0264.stderr index 14a4ffbe316..3503fb229e4 100644 --- a/tests/ui/error-codes/E0264.stderr +++ b/tests/ui/error-codes/E0264.stderr @@ -2,7 +2,7 @@ error[E0264]: unknown external lang item: `cake` --> $DIR/E0264.rs:5:5 | LL | fn cake(); - | ^^^^^^^^^ + | ^^^^^^^^^^ error: aborting due to 1 previous error diff --git a/tests/ui/hygiene/cross-crate-define-and-use.rs b/tests/ui/hygiene/cross-crate-define-and-use.rs index 94f1adff626..62b1820235c 100644 --- a/tests/ui/hygiene/cross-crate-define-and-use.rs +++ b/tests/ui/hygiene/cross-crate-define-and-use.rs @@ -6,7 +6,6 @@ // check-pass // aux-build:use_by_macro.rs -#![feature(type_name_of_val)] extern crate use_by_macro; use use_by_macro::*; diff --git a/tests/ui/implied-bounds/impl-implied-bounds-compatibility-unnormalized.rs b/tests/ui/implied-bounds/impl-implied-bounds-compatibility-unnormalized.rs index 6ccbb5bb266..280856805e5 100644 --- a/tests/ui/implied-bounds/impl-implied-bounds-compatibility-unnormalized.rs +++ b/tests/ui/implied-bounds/impl-implied-bounds-compatibility-unnormalized.rs @@ -1,5 +1,3 @@ -#![deny(implied_bounds_entailment)] - trait Project { type Ty; } @@ -11,8 +9,7 @@ trait Trait { } impl Trait for () { fn get<'s>(s: &'s str, _: <&'static &'s () as Project>::Ty) -> &'static str { - //~^ ERROR impl method assumes more implied bounds than the corresponding trait method - //~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + //~^ ERROR cannot infer an appropriate lifetime for lifetime parameter 's in generic type due to conflicting requirements s } } diff --git a/tests/ui/implied-bounds/impl-implied-bounds-compatibility-unnormalized.stderr b/tests/ui/implied-bounds/impl-implied-bounds-compatibility-unnormalized.stderr index 86b12cf8fa2..c8d1614a7f3 100644 --- a/tests/ui/implied-bounds/impl-implied-bounds-compatibility-unnormalized.stderr +++ b/tests/ui/implied-bounds/impl-implied-bounds-compatibility-unnormalized.stderr @@ -1,31 +1,28 @@ -error: impl method assumes more implied bounds than the corresponding trait method - --> $DIR/impl-implied-bounds-compatibility-unnormalized.rs:13:31 +error[E0495]: cannot infer an appropriate lifetime for lifetime parameter 's in generic type due to conflicting requirements + --> $DIR/impl-implied-bounds-compatibility-unnormalized.rs:11:5 | LL | fn get<'s>(s: &'s str, _: <&'static &'s () as Project>::Ty) -> &'static str { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace this type to make the impl signature compatible: `()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #105572 <https://github.com/rust-lang/rust/issues/105572> -note: the lint level is defined here - --> $DIR/impl-implied-bounds-compatibility-unnormalized.rs:1:9 - | -LL | #![deny(implied_bounds_entailment)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 1 previous error - -Future incompatibility report: Future breakage diagnostic: -error: impl method assumes more implied bounds than the corresponding trait method - --> $DIR/impl-implied-bounds-compatibility-unnormalized.rs:13:31 +note: first, the lifetime cannot outlive the lifetime `'s` as defined here... + --> $DIR/impl-implied-bounds-compatibility-unnormalized.rs:11:12 | LL | fn get<'s>(s: &'s str, _: <&'static &'s () as Project>::Ty) -> &'static str { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace this type to make the impl signature compatible: `()` + | ^^ +note: ...so that the method type is compatible with trait + --> $DIR/impl-implied-bounds-compatibility-unnormalized.rs:11:5 | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #105572 <https://github.com/rust-lang/rust/issues/105572> -note: the lint level is defined here - --> $DIR/impl-implied-bounds-compatibility-unnormalized.rs:1:9 +LL | fn get<'s>(s: &'s str, _: <&'static &'s () as Project>::Ty) -> &'static str { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: expected `fn(&'s _, ()) -> &'static _` + found `fn(&_, ()) -> &'static _` + = note: but, the lifetime must be valid for the static lifetime... +note: ...so that the reference type `&'static &()` does not outlive the data it points at + --> $DIR/impl-implied-bounds-compatibility-unnormalized.rs:11:5 | -LL | #![deny(implied_bounds_entailment)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn get<'s>(s: &'s str, _: <&'static &'s () as Project>::Ty) -> &'static str { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error +For more information about this error, try `rustc --explain E0495`. diff --git a/tests/ui/implied-bounds/impl-implied-bounds-compatibility.rs b/tests/ui/implied-bounds/impl-implied-bounds-compatibility.rs index d097bc16a22..7f3817b326a 100644 --- a/tests/ui/implied-bounds/impl-implied-bounds-compatibility.rs +++ b/tests/ui/implied-bounds/impl-implied-bounds-compatibility.rs @@ -1,5 +1,3 @@ -#![deny(implied_bounds_entailment)] - use std::cell::RefCell; pub struct MessageListeners<'a> { @@ -12,8 +10,7 @@ pub trait MessageListenersInterface { impl<'a> MessageListenersInterface for MessageListeners<'a> { fn listeners<'b>(&'b self) -> &'a MessageListeners<'b> { - //~^ ERROR impl method assumes more implied bounds than the corresponding trait method - //~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + //~^ ERROR cannot infer an appropriate lifetime for lifetime parameter 'b in generic type due to conflicting requirements self } } diff --git a/tests/ui/implied-bounds/impl-implied-bounds-compatibility.stderr b/tests/ui/implied-bounds/impl-implied-bounds-compatibility.stderr index a89645c128b..6a412eb5e4b 100644 --- a/tests/ui/implied-bounds/impl-implied-bounds-compatibility.stderr +++ b/tests/ui/implied-bounds/impl-implied-bounds-compatibility.stderr @@ -1,31 +1,32 @@ -error: impl method assumes more implied bounds than the corresponding trait method - --> $DIR/impl-implied-bounds-compatibility.rs:14:35 +error[E0495]: cannot infer an appropriate lifetime for lifetime parameter 'b in generic type due to conflicting requirements + --> $DIR/impl-implied-bounds-compatibility.rs:12:5 | LL | fn listeners<'b>(&'b self) -> &'a MessageListeners<'b> { - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: replace this type to make the impl signature compatible: `&'b MessageListeners<'b>` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #105572 <https://github.com/rust-lang/rust/issues/105572> -note: the lint level is defined here - --> $DIR/impl-implied-bounds-compatibility.rs:1:9 +note: first, the lifetime cannot outlive the lifetime `'c` as defined here... + --> $DIR/impl-implied-bounds-compatibility.rs:12:5 | -LL | #![deny(implied_bounds_entailment)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 1 previous error - -Future incompatibility report: Future breakage diagnostic: -error: impl method assumes more implied bounds than the corresponding trait method - --> $DIR/impl-implied-bounds-compatibility.rs:14:35 +LL | fn listeners<'b>(&'b self) -> &'a MessageListeners<'b> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...so that the method type is compatible with trait + --> $DIR/impl-implied-bounds-compatibility.rs:12:5 | LL | fn listeners<'b>(&'b self) -> &'a MessageListeners<'b> { - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: replace this type to make the impl signature compatible: `&'b MessageListeners<'b>` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: expected `fn(&'c MessageListeners<'_>) -> &'c MessageListeners<'c>` + found `fn(&MessageListeners<'_>) -> &'a MessageListeners<'_>` +note: but, the lifetime must be valid for the lifetime `'a` as defined here... + --> $DIR/impl-implied-bounds-compatibility.rs:11:6 | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #105572 <https://github.com/rust-lang/rust/issues/105572> -note: the lint level is defined here - --> $DIR/impl-implied-bounds-compatibility.rs:1:9 +LL | impl<'a> MessageListenersInterface for MessageListeners<'a> { + | ^^ +note: ...so that the reference type `&'a MessageListeners<'_>` does not outlive the data it points at + --> $DIR/impl-implied-bounds-compatibility.rs:12:5 | -LL | #![deny(implied_bounds_entailment)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn listeners<'b>(&'b self) -> &'a MessageListeners<'b> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error +For more information about this error, try `rustc --explain E0495`. diff --git a/tests/ui/lang-items/lang-item-generic-requirements.rs b/tests/ui/lang-items/lang-item-generic-requirements.rs index 3d33adf6831..21bd7187e15 100644 --- a/tests/ui/lang-items/lang-item-generic-requirements.rs +++ b/tests/ui/lang-items/lang-item-generic-requirements.rs @@ -22,6 +22,8 @@ trait MyIndex<'a, T> {} #[lang = "phantom_data"] //~^ ERROR `phantom_data` language item must be applied to a struct with 1 generic argument struct MyPhantomData<T, U>; +//~^ ERROR parameter `T` is never used +//~| ERROR parameter `U` is never used #[lang = "owned_box"] //~^ ERROR `owned_box` language item must be applied to a struct with at least 1 generic argument @@ -40,6 +42,7 @@ fn ice() { let r = 5; let a = 6; r + a; + //~^ ERROR cannot add `{integer}` to `{integer}` // Use drop in place my_ptr_drop(); diff --git a/tests/ui/lang-items/lang-item-generic-requirements.stderr b/tests/ui/lang-items/lang-item-generic-requirements.stderr index 4d349a25f9c..8072e6797e4 100644 --- a/tests/ui/lang-items/lang-item-generic-requirements.stderr +++ b/tests/ui/lang-items/lang-item-generic-requirements.stderr @@ -33,7 +33,7 @@ LL | struct MyPhantomData<T, U>; | ------ this struct has 2 generic arguments error[E0718]: `owned_box` language item must be applied to a struct with at least 1 generic argument - --> $DIR/lang-item-generic-requirements.rs:26:1 + --> $DIR/lang-item-generic-requirements.rs:28:1 | LL | #[lang = "owned_box"] | ^^^^^^^^^^^^^^^^^^^^^ @@ -42,7 +42,7 @@ LL | struct Foo; | - this struct has 0 generic arguments error[E0718]: `start` language item must be applied to a function with 1 generic argument - --> $DIR/lang-item-generic-requirements.rs:32:1 + --> $DIR/lang-item-generic-requirements.rs:34:1 | LL | #[lang = "start"] | ^^^^^^^^^^^^^^^^^ @@ -50,6 +50,35 @@ LL | LL | fn start(_: *const u8, _: isize, _: *const *const u8) -> isize { | - this function has 0 generic arguments -error: aborting due to 6 previous errors +error[E0392]: parameter `T` is never used + --> $DIR/lang-item-generic-requirements.rs:24:22 + | +LL | struct MyPhantomData<T, U>; + | ^ unused parameter + | + = help: consider removing `T` or referring to it in a field + = help: if you intended `T` to be a const parameter, use `const T: usize` instead + +error[E0392]: parameter `U` is never used + --> $DIR/lang-item-generic-requirements.rs:24:25 + | +LL | struct MyPhantomData<T, U>; + | ^ unused parameter + | + = help: consider removing `U` or referring to it in a field + = help: if you intended `U` to be a const parameter, use `const U: usize` instead + +error[E0369]: cannot add `{integer}` to `{integer}` + --> $DIR/lang-item-generic-requirements.rs:44:7 + | +LL | r + a; + | - ^ - {integer} + | | + | {integer} + +error: requires `copy` lang_item + +error: aborting due to 10 previous errors -For more information about this error, try `rustc --explain E0718`. +Some errors have detailed explanations: E0369, E0392, E0718. +For more information about an error, try `rustc --explain E0369`. diff --git a/tests/ui/lint/ptr_null_checks.rs b/tests/ui/lint/ptr_null_checks.rs index 3028084e962..4925019be1e 100644 --- a/tests/ui/lint/ptr_null_checks.rs +++ b/tests/ui/lint/ptr_null_checks.rs @@ -1,7 +1,5 @@ // check-pass -#![feature(ptr_from_ref)] - use std::ptr; extern "C" fn c_fn() {} diff --git a/tests/ui/lint/ptr_null_checks.stderr b/tests/ui/lint/ptr_null_checks.stderr index 0edc1b86536..70a27790c5b 100644 --- a/tests/ui/lint/ptr_null_checks.stderr +++ b/tests/ui/lint/ptr_null_checks.stderr @@ -1,5 +1,5 @@ warning: function pointers are not nullable, so checking them for null will always return false - --> $DIR/ptr_null_checks.rs:14:8 + --> $DIR/ptr_null_checks.rs:12:8 | LL | if (fn_ptr as *mut ()).is_null() {} | ^------^^^^^^^^^^^^^^^^^^^^^^ @@ -10,7 +10,7 @@ LL | if (fn_ptr as *mut ()).is_null() {} = note: `#[warn(useless_ptr_null_checks)]` on by default warning: function pointers are not nullable, so checking them for null will always return false - --> $DIR/ptr_null_checks.rs:16:8 + --> $DIR/ptr_null_checks.rs:14:8 | LL | if (fn_ptr as *const u8).is_null() {} | ^------^^^^^^^^^^^^^^^^^^^^^^^^ @@ -20,7 +20,7 @@ LL | if (fn_ptr as *const u8).is_null() {} = help: wrap the function pointer inside an `Option` and use `Option::is_none` to check for null pointer value warning: function pointers are not nullable, so checking them for null will always return false - --> $DIR/ptr_null_checks.rs:18:8 + --> $DIR/ptr_null_checks.rs:16:8 | LL | if (fn_ptr as *const ()) == std::ptr::null() {} | ^------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -30,7 +30,7 @@ LL | if (fn_ptr as *const ()) == std::ptr::null() {} = help: wrap the function pointer inside an `Option` and use `Option::is_none` to check for null pointer value warning: function pointers are not nullable, so checking them for null will always return false - --> $DIR/ptr_null_checks.rs:20:8 + --> $DIR/ptr_null_checks.rs:18:8 | LL | if (fn_ptr as *mut ()) == std::ptr::null_mut() {} | ^------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -40,7 +40,7 @@ LL | if (fn_ptr as *mut ()) == std::ptr::null_mut() {} = help: wrap the function pointer inside an `Option` and use `Option::is_none` to check for null pointer value warning: function pointers are not nullable, so checking them for null will always return false - --> $DIR/ptr_null_checks.rs:22:8 + --> $DIR/ptr_null_checks.rs:20:8 | LL | if (fn_ptr as *const ()) == (0 as *const ()) {} | ^------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -50,7 +50,7 @@ LL | if (fn_ptr as *const ()) == (0 as *const ()) {} = help: wrap the function pointer inside an `Option` and use `Option::is_none` to check for null pointer value warning: function pointers are not nullable, so checking them for null will always return false - --> $DIR/ptr_null_checks.rs:24:8 + --> $DIR/ptr_null_checks.rs:22:8 | LL | if <*const _>::is_null(fn_ptr as *const ()) {} | ^^^^^^^^^^^^^^^^^^^^------^^^^^^^^^^^^^^ @@ -60,7 +60,7 @@ LL | if <*const _>::is_null(fn_ptr as *const ()) {} = help: wrap the function pointer inside an `Option` and use `Option::is_none` to check for null pointer value warning: function pointers are not nullable, so checking them for null will always return false - --> $DIR/ptr_null_checks.rs:26:8 + --> $DIR/ptr_null_checks.rs:24:8 | LL | if (fn_ptr as *mut fn() as *const fn() as *const ()).is_null() {} | ^------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -70,7 +70,7 @@ LL | if (fn_ptr as *mut fn() as *const fn() as *const ()).is_null() {} = help: wrap the function pointer inside an `Option` and use `Option::is_none` to check for null pointer value warning: function pointers are not nullable, so checking them for null will always return false - --> $DIR/ptr_null_checks.rs:28:8 + --> $DIR/ptr_null_checks.rs:26:8 | LL | if (fn_ptr as *mut fn() as *const fn()).cast_mut().is_null() {} | ^------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -80,7 +80,7 @@ LL | if (fn_ptr as *mut fn() as *const fn()).cast_mut().is_null() {} = help: wrap the function pointer inside an `Option` and use `Option::is_none` to check for null pointer value warning: function pointers are not nullable, so checking them for null will always return false - --> $DIR/ptr_null_checks.rs:30:8 + --> $DIR/ptr_null_checks.rs:28:8 | LL | if ((fn_ptr as *mut fn()).cast() as *const fn()).cast_mut().is_null() {} | ^^------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -90,7 +90,7 @@ LL | if ((fn_ptr as *mut fn()).cast() as *const fn()).cast_mut().is_null() { = help: wrap the function pointer inside an `Option` and use `Option::is_none` to check for null pointer value warning: function pointers are not nullable, so checking them for null will always return false - --> $DIR/ptr_null_checks.rs:32:8 + --> $DIR/ptr_null_checks.rs:30:8 | LL | if (fn_ptr as fn() as *const ()).is_null() {} | ^--------------^^^^^^^^^^^^^^^^^^^^^^^^ @@ -100,7 +100,7 @@ LL | if (fn_ptr as fn() as *const ()).is_null() {} = help: wrap the function pointer inside an `Option` and use `Option::is_none` to check for null pointer value warning: function pointers are not nullable, so checking them for null will always return false - --> $DIR/ptr_null_checks.rs:34:8 + --> $DIR/ptr_null_checks.rs:32:8 | LL | if (c_fn as *const fn()).is_null() {} | ^----^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -110,7 +110,7 @@ LL | if (c_fn as *const fn()).is_null() {} = help: wrap the function pointer inside an `Option` and use `Option::is_none` to check for null pointer value warning: references are not nullable, so checking them for null will always return false - --> $DIR/ptr_null_checks.rs:38:8 + --> $DIR/ptr_null_checks.rs:36:8 | LL | if (&mut 8 as *mut i32).is_null() {} | ^------^^^^^^^^^^^^^^^^^^^^^^^ @@ -118,13 +118,13 @@ LL | if (&mut 8 as *mut i32).is_null() {} | expression has type `&mut i32` warning: returned pointer of `from_mut` call is never null, so checking it for null will always return false - --> $DIR/ptr_null_checks.rs:40:8 + --> $DIR/ptr_null_checks.rs:38:8 | LL | if ptr::from_mut(&mut 8).is_null() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: references are not nullable, so checking them for null will always return false - --> $DIR/ptr_null_checks.rs:42:8 + --> $DIR/ptr_null_checks.rs:40:8 | LL | if (&8 as *const i32).is_null() {} | ^--^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -132,25 +132,25 @@ LL | if (&8 as *const i32).is_null() {} | expression has type `&i32` warning: returned pointer of `from_ref` call is never null, so checking it for null will always return false - --> $DIR/ptr_null_checks.rs:44:8 + --> $DIR/ptr_null_checks.rs:42:8 | LL | if ptr::from_ref(&8).is_null() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: returned pointer of `from_ref` call is never null, so checking it for null will always return false - --> $DIR/ptr_null_checks.rs:46:8 + --> $DIR/ptr_null_checks.rs:44:8 | LL | if ptr::from_ref(&8).cast_mut().is_null() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: returned pointer of `from_ref` call is never null, so checking it for null will always return false - --> $DIR/ptr_null_checks.rs:48:8 + --> $DIR/ptr_null_checks.rs:46:8 | LL | if (ptr::from_ref(&8).cast_mut() as *mut i32).is_null() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: references are not nullable, so checking them for null will always return false - --> $DIR/ptr_null_checks.rs:50:8 + --> $DIR/ptr_null_checks.rs:48:8 | LL | if (&8 as *const i32) == std::ptr::null() {} | ^--^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -158,7 +158,7 @@ LL | if (&8 as *const i32) == std::ptr::null() {} | expression has type `&i32` warning: references are not nullable, so checking them for null will always return false - --> $DIR/ptr_null_checks.rs:53:8 + --> $DIR/ptr_null_checks.rs:51:8 | LL | if (ref_num as *const i32) == std::ptr::null() {} | ^-------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -166,7 +166,7 @@ LL | if (ref_num as *const i32) == std::ptr::null() {} | expression has type `&i32` warning: references are not nullable, so checking them for null will always return false - --> $DIR/ptr_null_checks.rs:55:8 + --> $DIR/ptr_null_checks.rs:53:8 | LL | if (b"\0" as *const u8).is_null() {} | ^-----^^^^^^^^^^^^^^^^^^^^^^^^ @@ -174,7 +174,7 @@ LL | if (b"\0" as *const u8).is_null() {} | expression has type `&[u8; 1]` warning: references are not nullable, so checking them for null will always return false - --> $DIR/ptr_null_checks.rs:57:8 + --> $DIR/ptr_null_checks.rs:55:8 | LL | if ("aa" as *const str).is_null() {} | ^----^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -182,7 +182,7 @@ LL | if ("aa" as *const str).is_null() {} | expression has type `&str` warning: references are not nullable, so checking them for null will always return false - --> $DIR/ptr_null_checks.rs:59:8 + --> $DIR/ptr_null_checks.rs:57:8 | LL | if (&[1, 2] as *const i32).is_null() {} | ^-------^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -190,7 +190,7 @@ LL | if (&[1, 2] as *const i32).is_null() {} | expression has type `&[i32; 2]` warning: references are not nullable, so checking them for null will always return false - --> $DIR/ptr_null_checks.rs:61:8 + --> $DIR/ptr_null_checks.rs:59:8 | LL | if (&mut [1, 2] as *mut i32) == std::ptr::null_mut() {} | ^-----------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -198,7 +198,7 @@ LL | if (&mut [1, 2] as *mut i32) == std::ptr::null_mut() {} | expression has type `&mut [i32; 2]` warning: references are not nullable, so checking them for null will always return false - --> $DIR/ptr_null_checks.rs:63:8 + --> $DIR/ptr_null_checks.rs:61:8 | LL | if (static_i32() as *const i32).is_null() {} | ^------------^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -206,7 +206,7 @@ LL | if (static_i32() as *const i32).is_null() {} | expression has type `&i32` warning: references are not nullable, so checking them for null will always return false - --> $DIR/ptr_null_checks.rs:65:8 + --> $DIR/ptr_null_checks.rs:63:8 | LL | if (&*{ static_i32() } as *const i32).is_null() {} | ^------------------^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -214,13 +214,13 @@ LL | if (&*{ static_i32() } as *const i32).is_null() {} | expression has type `&i32` warning: returned pointer of `as_ptr` call is never null, so checking it for null will always return false - --> $DIR/ptr_null_checks.rs:69:8 + --> $DIR/ptr_null_checks.rs:67:8 | LL | if ptr::NonNull::new(&mut 8).unwrap().as_ptr().is_null() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: returned pointer of `as_ptr` call is never null, so checking it for null will always return false - --> $DIR/ptr_null_checks.rs:71:8 + --> $DIR/ptr_null_checks.rs:69:8 | LL | if ptr::NonNull::<u8>::dangling().as_ptr().is_null() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/lint/reference_casting.rs b/tests/ui/lint/reference_casting.rs index fe8c6e3ff23..84267c0af03 100644 --- a/tests/ui/lint/reference_casting.rs +++ b/tests/ui/lint/reference_casting.rs @@ -1,7 +1,5 @@ // check-fail -#![feature(ptr_from_ref)] - extern "C" { // N.B., mutability can be easily incorrect in FFI calls -- as // in C, the default is mutable pointers. diff --git a/tests/ui/lint/reference_casting.stderr b/tests/ui/lint/reference_casting.stderr index 2820696508a..374a58d7b7b 100644 --- a/tests/ui/lint/reference_casting.stderr +++ b/tests/ui/lint/reference_casting.stderr @@ -1,5 +1,5 @@ error: casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell` - --> $DIR/reference_casting.rs:19:16 + --> $DIR/reference_casting.rs:17:16 | LL | let _num = &mut *(num as *const i32 as *mut i32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -8,7 +8,7 @@ LL | let _num = &mut *(num as *const i32 as *mut i32); = note: `#[deny(invalid_reference_casting)]` on by default error: casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell` - --> $DIR/reference_casting.rs:21:16 + --> $DIR/reference_casting.rs:19:16 | LL | let _num = &mut *(num as *const i32).cast_mut(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -16,7 +16,7 @@ LL | let _num = &mut *(num as *const i32).cast_mut(); = note: for more information, visit <https://doc.rust-lang.org/book/ch15-05-interior-mutability.html> error: casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell` - --> $DIR/reference_casting.rs:23:16 + --> $DIR/reference_casting.rs:21:16 | LL | let _num = &mut *std::ptr::from_ref(num).cast_mut(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -24,7 +24,7 @@ LL | let _num = &mut *std::ptr::from_ref(num).cast_mut(); = note: for more information, visit <https://doc.rust-lang.org/book/ch15-05-interior-mutability.html> error: casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell` - --> $DIR/reference_casting.rs:25:16 + --> $DIR/reference_casting.rs:23:16 | LL | let _num = &mut *std::ptr::from_ref({ num }).cast_mut(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -32,7 +32,7 @@ LL | let _num = &mut *std::ptr::from_ref({ num }).cast_mut(); = note: for more information, visit <https://doc.rust-lang.org/book/ch15-05-interior-mutability.html> error: casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell` - --> $DIR/reference_casting.rs:27:16 + --> $DIR/reference_casting.rs:25:16 | LL | let _num = &mut *{ std::ptr::from_ref(num) }.cast_mut(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -40,7 +40,7 @@ LL | let _num = &mut *{ std::ptr::from_ref(num) }.cast_mut(); = note: for more information, visit <https://doc.rust-lang.org/book/ch15-05-interior-mutability.html> error: casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell` - --> $DIR/reference_casting.rs:29:16 + --> $DIR/reference_casting.rs:27:16 | LL | let _num = &mut *(std::ptr::from_ref({ num }) as *mut i32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -48,7 +48,7 @@ LL | let _num = &mut *(std::ptr::from_ref({ num }) as *mut i32); = note: for more information, visit <https://doc.rust-lang.org/book/ch15-05-interior-mutability.html> error: casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell` - --> $DIR/reference_casting.rs:31:16 + --> $DIR/reference_casting.rs:29:16 | LL | let _num = &mut *(num as *const i32).cast::<i32>().cast_mut(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -56,7 +56,7 @@ LL | let _num = &mut *(num as *const i32).cast::<i32>().cast_mut(); = note: for more information, visit <https://doc.rust-lang.org/book/ch15-05-interior-mutability.html> error: casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell` - --> $DIR/reference_casting.rs:33:16 + --> $DIR/reference_casting.rs:31:16 | LL | let _num = &mut *(num as *const i32).cast::<i32>().cast_mut().cast_const().cast_mut(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -64,7 +64,7 @@ LL | let _num = &mut *(num as *const i32).cast::<i32>().cast_mut().cast_cons = note: for more information, visit <https://doc.rust-lang.org/book/ch15-05-interior-mutability.html> error: casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell` - --> $DIR/reference_casting.rs:35:16 + --> $DIR/reference_casting.rs:33:16 | LL | let _num = &mut *(std::ptr::from_ref(static_u8()) as *mut i32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -72,7 +72,7 @@ LL | let _num = &mut *(std::ptr::from_ref(static_u8()) as *mut i32); = note: for more information, visit <https://doc.rust-lang.org/book/ch15-05-interior-mutability.html> error: casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell` - --> $DIR/reference_casting.rs:37:16 + --> $DIR/reference_casting.rs:35:16 | LL | let _num = &mut *std::mem::transmute::<_, *mut i32>(num); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -80,7 +80,7 @@ LL | let _num = &mut *std::mem::transmute::<_, *mut i32>(num); = note: for more information, visit <https://doc.rust-lang.org/book/ch15-05-interior-mutability.html> error: casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell` - --> $DIR/reference_casting.rs:39:16 + --> $DIR/reference_casting.rs:37:16 | LL | let _num = &mut *(std::mem::transmute::<_, *mut i32>(num) as *mut i32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -88,7 +88,7 @@ LL | let _num = &mut *(std::mem::transmute::<_, *mut i32>(num) as *mut i32); = note: for more information, visit <https://doc.rust-lang.org/book/ch15-05-interior-mutability.html> error: casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell` - --> $DIR/reference_casting.rs:41:16 + --> $DIR/reference_casting.rs:39:16 | LL | let _num = &mut *std::cell::UnsafeCell::raw_get( | ________________^ @@ -100,7 +100,7 @@ LL | | ); = note: for more information, visit <https://doc.rust-lang.org/book/ch15-05-interior-mutability.html> error: casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell` - --> $DIR/reference_casting.rs:47:16 + --> $DIR/reference_casting.rs:45:16 | LL | let deferred = num as *const i32 as *mut i32; | ----------------------------- casting happend here @@ -110,7 +110,7 @@ LL | let _num = &mut *deferred; = note: for more information, visit <https://doc.rust-lang.org/book/ch15-05-interior-mutability.html> error: casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell` - --> $DIR/reference_casting.rs:50:16 + --> $DIR/reference_casting.rs:48:16 | LL | let deferred = (std::ptr::from_ref(num) as *const i32 as *const i32).cast_mut() as *mut i32; | ---------------------------------------------------------------------------- casting happend here @@ -120,7 +120,7 @@ LL | let _num = &mut *deferred; = note: for more information, visit <https://doc.rust-lang.org/book/ch15-05-interior-mutability.html> error: casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell` - --> $DIR/reference_casting.rs:53:16 + --> $DIR/reference_casting.rs:51:16 | LL | let deferred = (std::ptr::from_ref(num) as *const i32 as *const i32).cast_mut() as *mut i32; | ---------------------------------------------------------------------------- casting happend here @@ -131,7 +131,7 @@ LL | let _num = &mut *deferred_rebind; = note: for more information, visit <https://doc.rust-lang.org/book/ch15-05-interior-mutability.html> error: casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell` - --> $DIR/reference_casting.rs:55:16 + --> $DIR/reference_casting.rs:53:16 | LL | let _num = &mut *(num as *const _ as usize as *mut i32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -139,7 +139,7 @@ LL | let _num = &mut *(num as *const _ as usize as *mut i32); = note: for more information, visit <https://doc.rust-lang.org/book/ch15-05-interior-mutability.html> error: casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell` - --> $DIR/reference_casting.rs:57:16 + --> $DIR/reference_casting.rs:55:16 | LL | let _num = &mut *(std::mem::transmute::<_, *mut _>(num as *const i32) as *mut i32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -147,7 +147,7 @@ LL | let _num = &mut *(std::mem::transmute::<_, *mut _>(num as *const i32) a = note: for more information, visit <https://doc.rust-lang.org/book/ch15-05-interior-mutability.html> error: casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell` - --> $DIR/reference_casting.rs:64:16 + --> $DIR/reference_casting.rs:62:16 | LL | let num = NUM as *const i32 as *mut i32; | ----------------------------- casting happend here @@ -158,7 +158,7 @@ LL | let _num = &mut *num; = note: for more information, visit <https://doc.rust-lang.org/book/ch15-05-interior-mutability.html> error: casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell` - --> $DIR/reference_casting.rs:68:16 + --> $DIR/reference_casting.rs:66:16 | LL | let _num = &mut *(cell as *const _ as *mut i32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -167,7 +167,7 @@ LL | let _num = &mut *(cell as *const _ as *mut i32); = note: even for types with interior mutability, the only legal way to obtain a mutable pointer from a shared reference is through `UnsafeCell::get` error: casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell` - --> $DIR/reference_casting.rs:72:9 + --> $DIR/reference_casting.rs:70:9 | LL | &mut *((this as *const _) as *mut _) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -175,7 +175,7 @@ LL | &mut *((this as *const _) as *mut _) = note: for more information, visit <https://doc.rust-lang.org/book/ch15-05-interior-mutability.html> error: casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell` - --> $DIR/reference_casting.rs:77:18 + --> $DIR/reference_casting.rs:75:18 | LL | unsafe { &mut *std::cell::UnsafeCell::raw_get(x as *const _ as *const _) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -183,7 +183,7 @@ LL | unsafe { &mut *std::cell::UnsafeCell::raw_get(x as *const _ as *con = note: for more information, visit <https://doc.rust-lang.org/book/ch15-05-interior-mutability.html> error: casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell` - --> $DIR/reference_casting.rs:82:18 + --> $DIR/reference_casting.rs:80:18 | LL | unsafe { &mut *std::cell::UnsafeCell::raw_get(x as *const _ as *const _) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -191,7 +191,7 @@ LL | unsafe { &mut *std::cell::UnsafeCell::raw_get(x as *const _ as *con = note: for more information, visit <https://doc.rust-lang.org/book/ch15-05-interior-mutability.html> error: assigning to `&T` is undefined behavior, consider using an `UnsafeCell` - --> $DIR/reference_casting.rs:92:5 + --> $DIR/reference_casting.rs:90:5 | LL | *(a as *const _ as *mut _) = String::from("Replaced"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -199,7 +199,7 @@ LL | *(a as *const _ as *mut _) = String::from("Replaced"); = note: for more information, visit <https://doc.rust-lang.org/book/ch15-05-interior-mutability.html> error: assigning to `&T` is undefined behavior, consider using an `UnsafeCell` - --> $DIR/reference_casting.rs:94:5 + --> $DIR/reference_casting.rs:92:5 | LL | *(a as *const _ as *mut String) += " world"; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -207,7 +207,7 @@ LL | *(a as *const _ as *mut String) += " world"; = note: for more information, visit <https://doc.rust-lang.org/book/ch15-05-interior-mutability.html> error: assigning to `&T` is undefined behavior, consider using an `UnsafeCell` - --> $DIR/reference_casting.rs:96:5 + --> $DIR/reference_casting.rs:94:5 | LL | *std::ptr::from_ref(num).cast_mut() += 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -215,7 +215,7 @@ LL | *std::ptr::from_ref(num).cast_mut() += 1; = note: for more information, visit <https://doc.rust-lang.org/book/ch15-05-interior-mutability.html> error: assigning to `&T` is undefined behavior, consider using an `UnsafeCell` - --> $DIR/reference_casting.rs:98:5 + --> $DIR/reference_casting.rs:96:5 | LL | *std::ptr::from_ref({ num }).cast_mut() += 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -223,7 +223,7 @@ LL | *std::ptr::from_ref({ num }).cast_mut() += 1; = note: for more information, visit <https://doc.rust-lang.org/book/ch15-05-interior-mutability.html> error: assigning to `&T` is undefined behavior, consider using an `UnsafeCell` - --> $DIR/reference_casting.rs:100:5 + --> $DIR/reference_casting.rs:98:5 | LL | *{ std::ptr::from_ref(num) }.cast_mut() += 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -231,7 +231,7 @@ LL | *{ std::ptr::from_ref(num) }.cast_mut() += 1; = note: for more information, visit <https://doc.rust-lang.org/book/ch15-05-interior-mutability.html> error: assigning to `&T` is undefined behavior, consider using an `UnsafeCell` - --> $DIR/reference_casting.rs:102:5 + --> $DIR/reference_casting.rs:100:5 | LL | *(std::ptr::from_ref({ num }) as *mut i32) += 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -239,7 +239,7 @@ LL | *(std::ptr::from_ref({ num }) as *mut i32) += 1; = note: for more information, visit <https://doc.rust-lang.org/book/ch15-05-interior-mutability.html> error: assigning to `&T` is undefined behavior, consider using an `UnsafeCell` - --> $DIR/reference_casting.rs:104:5 + --> $DIR/reference_casting.rs:102:5 | LL | *std::mem::transmute::<_, *mut i32>(num) += 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -247,7 +247,7 @@ LL | *std::mem::transmute::<_, *mut i32>(num) += 1; = note: for more information, visit <https://doc.rust-lang.org/book/ch15-05-interior-mutability.html> error: assigning to `&T` is undefined behavior, consider using an `UnsafeCell` - --> $DIR/reference_casting.rs:106:5 + --> $DIR/reference_casting.rs:104:5 | LL | *(std::mem::transmute::<_, *mut i32>(num) as *mut i32) += 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -255,7 +255,7 @@ LL | *(std::mem::transmute::<_, *mut i32>(num) as *mut i32) += 1; = note: for more information, visit <https://doc.rust-lang.org/book/ch15-05-interior-mutability.html> error: assigning to `&T` is undefined behavior, consider using an `UnsafeCell` - --> $DIR/reference_casting.rs:108:5 + --> $DIR/reference_casting.rs:106:5 | LL | / std::ptr::write( LL | | @@ -267,7 +267,7 @@ LL | | ); = note: for more information, visit <https://doc.rust-lang.org/book/ch15-05-interior-mutability.html> error: assigning to `&T` is undefined behavior, consider using an `UnsafeCell` - --> $DIR/reference_casting.rs:113:5 + --> $DIR/reference_casting.rs:111:5 | LL | *((&std::cell::UnsafeCell::new(0)) as *const _ as *mut i32) = 5; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -276,7 +276,7 @@ LL | *((&std::cell::UnsafeCell::new(0)) as *const _ as *mut i32) = 5; = note: even for types with interior mutability, the only legal way to obtain a mutable pointer from a shared reference is through `UnsafeCell::get` error: assigning to `&T` is undefined behavior, consider using an `UnsafeCell` - --> $DIR/reference_casting.rs:117:5 + --> $DIR/reference_casting.rs:115:5 | LL | let value = num as *const i32 as *mut i32; | ----------------------------- casting happend here @@ -286,7 +286,7 @@ LL | *value = 1; = note: for more information, visit <https://doc.rust-lang.org/book/ch15-05-interior-mutability.html> error: assigning to `&T` is undefined behavior, consider using an `UnsafeCell` - --> $DIR/reference_casting.rs:121:5 + --> $DIR/reference_casting.rs:119:5 | LL | let value = value as *mut i32; | ----------------- casting happend here @@ -296,7 +296,7 @@ LL | *value = 1; = note: for more information, visit <https://doc.rust-lang.org/book/ch15-05-interior-mutability.html> error: assigning to `&T` is undefined behavior, consider using an `UnsafeCell` - --> $DIR/reference_casting.rs:124:5 + --> $DIR/reference_casting.rs:122:5 | LL | let value = num as *const i32 as *mut i32; | ----------------------------- casting happend here @@ -306,7 +306,7 @@ LL | *value = 1; = note: for more information, visit <https://doc.rust-lang.org/book/ch15-05-interior-mutability.html> error: assigning to `&T` is undefined behavior, consider using an `UnsafeCell` - --> $DIR/reference_casting.rs:127:5 + --> $DIR/reference_casting.rs:125:5 | LL | let value = num as *const i32 as *mut i32; | ----------------------------- casting happend here @@ -317,7 +317,7 @@ LL | *value_rebind = 1; = note: for more information, visit <https://doc.rust-lang.org/book/ch15-05-interior-mutability.html> error: assigning to `&T` is undefined behavior, consider using an `UnsafeCell` - --> $DIR/reference_casting.rs:129:5 + --> $DIR/reference_casting.rs:127:5 | LL | *(num as *const i32).cast::<i32>().cast_mut() = 2; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -325,7 +325,7 @@ LL | *(num as *const i32).cast::<i32>().cast_mut() = 2; = note: for more information, visit <https://doc.rust-lang.org/book/ch15-05-interior-mutability.html> error: assigning to `&T` is undefined behavior, consider using an `UnsafeCell` - --> $DIR/reference_casting.rs:131:5 + --> $DIR/reference_casting.rs:129:5 | LL | *(num as *const _ as usize as *mut i32) = 2; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -333,7 +333,7 @@ LL | *(num as *const _ as usize as *mut i32) = 2; = note: for more information, visit <https://doc.rust-lang.org/book/ch15-05-interior-mutability.html> error: assigning to `&T` is undefined behavior, consider using an `UnsafeCell` - --> $DIR/reference_casting.rs:133:5 + --> $DIR/reference_casting.rs:131:5 | LL | let value = num as *const i32 as *mut i32; | ----------------------------- casting happend here @@ -344,7 +344,7 @@ LL | std::ptr::write(value, 2); = note: for more information, visit <https://doc.rust-lang.org/book/ch15-05-interior-mutability.html> error: assigning to `&T` is undefined behavior, consider using an `UnsafeCell` - --> $DIR/reference_casting.rs:135:5 + --> $DIR/reference_casting.rs:133:5 | LL | let value = num as *const i32 as *mut i32; | ----------------------------- casting happend here @@ -355,7 +355,7 @@ LL | std::ptr::write_unaligned(value, 2); = note: for more information, visit <https://doc.rust-lang.org/book/ch15-05-interior-mutability.html> error: assigning to `&T` is undefined behavior, consider using an `UnsafeCell` - --> $DIR/reference_casting.rs:137:5 + --> $DIR/reference_casting.rs:135:5 | LL | let value = num as *const i32 as *mut i32; | ----------------------------- casting happend here @@ -366,7 +366,7 @@ LL | std::ptr::write_volatile(value, 2); = note: for more information, visit <https://doc.rust-lang.org/book/ch15-05-interior-mutability.html> error: assigning to `&T` is undefined behavior, consider using an `UnsafeCell` - --> $DIR/reference_casting.rs:141:9 + --> $DIR/reference_casting.rs:139:9 | LL | *(this as *const _ as *mut _) = a; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/panic-handler/panic-handler-duplicate.stderr b/tests/ui/panic-handler/panic-handler-duplicate.stderr index 5c50b7016b2..299847474cd 100644 --- a/tests/ui/panic-handler/panic-handler-duplicate.stderr +++ b/tests/ui/panic-handler/panic-handler-duplicate.stderr @@ -1,14 +1,18 @@ error[E0152]: found duplicate lang item `panic_impl` --> $DIR/panic-handler-duplicate.rs:15:1 | -LL | fn panic2(info: &PanicInfo) -> ! { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | / fn panic2(info: &PanicInfo) -> ! { +LL | | loop {} +LL | | } + | |_^ | note: the lang item is first defined here --> $DIR/panic-handler-duplicate.rs:10:1 | -LL | fn panic(info: &PanicInfo) -> ! { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | / fn panic(info: &PanicInfo) -> ! { +LL | | loop {} +LL | | } + | |_^ error: aborting due to 1 previous error diff --git a/tests/ui/panic-handler/panic-handler-std.stderr b/tests/ui/panic-handler/panic-handler-std.stderr index ad9addec8eb..48c216ce27e 100644 --- a/tests/ui/panic-handler/panic-handler-std.stderr +++ b/tests/ui/panic-handler/panic-handler-std.stderr @@ -1,8 +1,10 @@ error[E0152]: found duplicate lang item `panic_impl` --> $DIR/panic-handler-std.rs:8:1 | -LL | fn panic(info: PanicInfo) -> ! { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | / fn panic(info: PanicInfo) -> ! { +LL | | loop {} +LL | | } + | |_^ | = note: the lang item is first defined in crate `std` (which `panic_handler_std` depends on) = note: first definition in `std` loaded from SYSROOT/libstd-*.rlib diff --git a/tests/ui/proc-macro/auxiliary/env.rs b/tests/ui/proc-macro/auxiliary/env.rs new file mode 100644 index 00000000000..58bcb08bf06 --- /dev/null +++ b/tests/ui/proc-macro/auxiliary/env.rs @@ -0,0 +1,28 @@ +// force-host +// no-prefer-dynamic + +#![crate_type = "proc-macro"] +#![feature(proc_macro_tracked_env)] + +extern crate proc_macro; + +use proc_macro::TokenStream; +use proc_macro::tracked_env::var; + +#[proc_macro] +pub fn generate_const(input: TokenStream) -> TokenStream { + let the_const = match var("THE_CONST") { + Ok(x) if x == "12" => { + "const THE_CONST: u32 = 12;" + } + _ => { + "const THE_CONST: u32 = 0;" + } + }; + let another = if var("ANOTHER").is_ok() { + "const ANOTHER: u32 = 1;" + } else { + "const ANOTHER: u32 = 2;" + }; + format!("{the_const}{another}").parse().unwrap() +} diff --git a/tests/ui/proc-macro/env.rs b/tests/ui/proc-macro/env.rs new file mode 100644 index 00000000000..1b1d1873eb3 --- /dev/null +++ b/tests/ui/proc-macro/env.rs @@ -0,0 +1,17 @@ +// aux-build:env.rs +// run-pass +// rustc-env: THE_CONST=1 +// compile-flags: -Zunstable-options --env THE_CONST=12 --env ANOTHER=4 + +#![crate_name = "foo"] + +extern crate env; + +use env::generate_const; + +generate_const!(); + +fn main() { + assert_eq!(THE_CONST, 12); + assert_eq!(ANOTHER, 1); +} diff --git a/tests/ui/regions/resolve-re-error-ice.rs b/tests/ui/regions/resolve-re-error-ice.rs index f37b27a82b3..bf6defb9bae 100644 --- a/tests/ui/regions/resolve-re-error-ice.rs +++ b/tests/ui/regions/resolve-re-error-ice.rs @@ -1,8 +1,3 @@ -// check-pass - -// Allow this for now, can remove this UI test when this becomes a hard error. -#![allow(implied_bounds_entailment)] - use std::collections::hash_map::{Keys, HashMap}; use std::marker::PhantomData; @@ -15,6 +10,7 @@ struct Subject<'a, T, V, R>(PhantomData<(&'a T, V, R)>); impl<'a, K, V, R> MapAssertion<'a, K, V, R> for Subject<'a, HashMap<K, V>, (), R> { fn key_set(&self) -> Subject<'a, Keys<K, V>, (), R> { + //~^ ERROR cannot infer an appropriate lifetime for lifetime parameter '_ in generic type due to conflicting requirements todo!() } } diff --git a/tests/ui/regions/resolve-re-error-ice.stderr b/tests/ui/regions/resolve-re-error-ice.stderr index e7003e1c32f..41c5f0fa92e 100644 --- a/tests/ui/regions/resolve-re-error-ice.stderr +++ b/tests/ui/regions/resolve-re-error-ice.stderr @@ -1,15 +1,37 @@ -Future incompatibility report: Future breakage diagnostic: -warning: impl method assumes more implied bounds than the corresponding trait method - --> $DIR/resolve-re-error-ice.rs:17:16 +error[E0495]: cannot infer an appropriate lifetime for lifetime parameter '_ in generic type due to conflicting requirements + --> $DIR/resolve-re-error-ice.rs:12:5 | LL | fn key_set(&self) -> Subject<'a, Keys<K, V>, (), R> { - | ^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace this type to make the impl signature compatible: `Subject<'_, std::collections::hash_map::Keys<'_, K, V>, (), R>` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #105572 <https://github.com/rust-lang/rust/issues/105572> -note: the lint level is defined here - --> $DIR/resolve-re-error-ice.rs:4:10 +note: first, the lifetime cannot outlive the anonymous lifetime defined here... + --> $DIR/resolve-re-error-ice.rs:5:16 | -LL | #![allow(implied_bounds_entailment)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn key_set(&self) -> Subject<Keys<K, V>, (), R>; + | ^^^^^ +note: ...so that the method type is compatible with trait + --> $DIR/resolve-re-error-ice.rs:12:5 + | +LL | fn key_set(&self) -> Subject<'a, Keys<K, V>, (), R> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: expected `fn(&Subject<'_, _, _, _>) -> Subject<'_, std::collections::hash_map::Keys<'_, _, _>, _, _>` + found `fn(&Subject<'_, _, _, _>) -> Subject<'a, std::collections::hash_map::Keys<'_, _, _>, _, _>` +note: but, the lifetime must be valid for the lifetime `'a` as defined here... + --> $DIR/resolve-re-error-ice.rs:10:6 + | +LL | impl<'a, K, V, R> MapAssertion<'a, K, V, R> for Subject<'a, HashMap<K, V>, (), R> + | ^^ +note: ...so that the type `std::collections::hash_map::Keys<'_, K, V>` will meet its required lifetime bounds... + --> $DIR/resolve-re-error-ice.rs:12:5 + | +LL | fn key_set(&self) -> Subject<'a, Keys<K, V>, (), R> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...that is required by this bound + --> $DIR/resolve-re-error-ice.rs:8:29 + | +LL | struct Subject<'a, T, V, R>(PhantomData<(&'a T, V, R)>); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error +For more information about this error, try `rustc --explain E0495`. diff --git a/tests/ui/structs-enums/type-sizes.rs b/tests/ui/structs-enums/type-sizes.rs index 406e5c8441e..490d6a2f918 100644 --- a/tests/ui/structs-enums/type-sizes.rs +++ b/tests/ui/structs-enums/type-sizes.rs @@ -4,7 +4,6 @@ #![allow(dead_code)] #![feature(never_type)] #![feature(pointer_is_aligned)] -#![feature(ptr_from_ref)] #![feature(strict_provenance)] use std::mem::size_of; diff --git a/tests/ui/traits/issue-102989.rs b/tests/ui/traits/issue-102989.rs index 216cd78e56f..f1ecee0a552 100644 --- a/tests/ui/traits/issue-102989.rs +++ b/tests/ui/traits/issue-102989.rs @@ -7,6 +7,7 @@ trait Sized { } //~ ERROR found duplicate lang item `sized` fn ref_Struct(self: &Struct, f: &u32) -> &u32 { //~^ ERROR `self` parameter is only allowed in associated functions //~| ERROR cannot find type `Struct` in this scope + //~| ERROR mismatched types let x = x << 1; //~^ ERROR cannot find value `x` in this scope } diff --git a/tests/ui/traits/issue-102989.stderr b/tests/ui/traits/issue-102989.stderr index 7d0098fe885..40e49df2b2d 100644 --- a/tests/ui/traits/issue-102989.stderr +++ b/tests/ui/traits/issue-102989.stderr @@ -13,7 +13,7 @@ LL | fn ref_Struct(self: &Struct, f: &u32) -> &u32 { | ^^^^^^ not found in this scope error[E0425]: cannot find value `x` in this scope - --> $DIR/issue-102989.rs:10:13 + --> $DIR/issue-102989.rs:11:13 | LL | let x = x << 1; | ^ help: a local variable with a similar name exists: `f` @@ -22,13 +22,27 @@ error[E0152]: found duplicate lang item `sized` --> $DIR/issue-102989.rs:5:1 | LL | trait Sized { } - | ^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^ | = note: the lang item is first defined in crate `core` (which `std` depends on) = note: first definition in `core` loaded from SYSROOT/libcore-*.rlib = note: second definition in the local crate (`issue_102989`) -error: aborting due to 4 previous errors +error[E0308]: mismatched types + --> $DIR/issue-102989.rs:7:42 + | +LL | fn ref_Struct(self: &Struct, f: &u32) -> &u32 { + | ---------- ^^^^ expected `&u32`, found `()` + | | + | implicitly returns `()` as its body has no tail or `return` expression + | +help: consider returning the local binding `f` + | +LL ~ let x = x << 1; +LL + f + | + +error: aborting due to 5 previous errors -Some errors have detailed explanations: E0152, E0412, E0425. +Some errors have detailed explanations: E0152, E0308, E0412, E0425. For more information about an error, try `rustc --explain E0152`. diff --git a/tests/ui/traits/next-solver/issue-118950-root-region.stderr b/tests/ui/traits/next-solver/issue-118950-root-region.stderr index 6b43b95fef3..c16a48d5f15 100644 --- a/tests/ui/traits/next-solver/issue-118950-root-region.stderr +++ b/tests/ui/traits/next-solver/issue-118950-root-region.stderr @@ -13,14 +13,14 @@ LL | #![feature(lazy_type_alias)] = note: see issue #112792 <https://github.com/rust-lang/rust/issues/112792> for more information = note: `#[warn(incomplete_features)]` on by default -WARN rustc_infer::infer::generalize may incompletely handle alias type: Alias(Weak, AliasTy { args: [ReBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed(DefId(0:15 ~ issue_118950_root_region[d54f]::{impl#1}::'a), 'a) }), ?1t], def_id: DefId(0:8 ~ issue_118950_root_region[d54f]::Assoc) }) -WARN rustc_infer::infer::generalize may incompletely handle alias type: Alias(Weak, AliasTy { args: [RePlaceholder(!1_BoundRegion { var: 0, kind: BrNamed(DefId(0:15 ~ issue_118950_root_region[d54f]::{impl#1}::'a), 'a) }), ?1t], def_id: DefId(0:8 ~ issue_118950_root_region[d54f]::Assoc) }) -WARN rustc_infer::infer::generalize may incompletely handle alias type: Alias(Weak, AliasTy { args: [ReBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed(DefId(0:15 ~ issue_118950_root_region[d54f]::{impl#1}::'a), 'a) }), ?1t], def_id: DefId(0:8 ~ issue_118950_root_region[d54f]::Assoc) }) -WARN rustc_infer::infer::generalize may incompletely handle alias type: Alias(Weak, AliasTy { args: [RePlaceholder(!1_BoundRegion { var: 0, kind: BrNamed(DefId(0:15 ~ issue_118950_root_region[d54f]::{impl#1}::'a), 'a) }), ?1t], def_id: DefId(0:8 ~ issue_118950_root_region[d54f]::Assoc) }) -WARN rustc_infer::infer::generalize may incompletely handle alias type: Alias(Weak, AliasTy { args: [ReBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed(DefId(0:15 ~ issue_118950_root_region[d54f]::{impl#1}::'a), 'a) }), ?1t], def_id: DefId(0:8 ~ issue_118950_root_region[d54f]::Assoc) }) -WARN rustc_infer::infer::generalize may incompletely handle alias type: Alias(Weak, AliasTy { args: [RePlaceholder(!1_BoundRegion { var: 0, kind: BrNamed(DefId(0:15 ~ issue_118950_root_region[d54f]::{impl#1}::'a), 'a) }), ?1t], def_id: DefId(0:8 ~ issue_118950_root_region[d54f]::Assoc) }) -WARN rustc_infer::infer::generalize may incompletely handle alias type: Alias(Weak, AliasTy { args: [ReBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed(DefId(0:15 ~ issue_118950_root_region[d54f]::{impl#1}::'a), 'a) }), ?1t], def_id: DefId(0:8 ~ issue_118950_root_region[d54f]::Assoc) }) -WARN rustc_infer::infer::generalize may incompletely handle alias type: Alias(Weak, AliasTy { args: [RePlaceholder(!1_BoundRegion { var: 0, kind: BrNamed(DefId(0:15 ~ issue_118950_root_region[d54f]::{impl#1}::'a), 'a) }), ?1t], def_id: DefId(0:8 ~ issue_118950_root_region[d54f]::Assoc) }) +WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: Alias(Weak, AliasTy { args: [ReBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed(DefId(0:15 ~ issue_118950_root_region[d54f]::{impl#1}::'a), 'a) }), ?1t], def_id: DefId(0:8 ~ issue_118950_root_region[d54f]::Assoc) }) +WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: Alias(Weak, AliasTy { args: [RePlaceholder(!1_BoundRegion { var: 0, kind: BrNamed(DefId(0:15 ~ issue_118950_root_region[d54f]::{impl#1}::'a), 'a) }), ?1t], def_id: DefId(0:8 ~ issue_118950_root_region[d54f]::Assoc) }) +WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: Alias(Weak, AliasTy { args: [ReBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed(DefId(0:15 ~ issue_118950_root_region[d54f]::{impl#1}::'a), 'a) }), ?1t], def_id: DefId(0:8 ~ issue_118950_root_region[d54f]::Assoc) }) +WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: Alias(Weak, AliasTy { args: [RePlaceholder(!1_BoundRegion { var: 0, kind: BrNamed(DefId(0:15 ~ issue_118950_root_region[d54f]::{impl#1}::'a), 'a) }), ?1t], def_id: DefId(0:8 ~ issue_118950_root_region[d54f]::Assoc) }) +WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: Alias(Weak, AliasTy { args: [ReBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed(DefId(0:15 ~ issue_118950_root_region[d54f]::{impl#1}::'a), 'a) }), ?1t], def_id: DefId(0:8 ~ issue_118950_root_region[d54f]::Assoc) }) +WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: Alias(Weak, AliasTy { args: [RePlaceholder(!1_BoundRegion { var: 0, kind: BrNamed(DefId(0:15 ~ issue_118950_root_region[d54f]::{impl#1}::'a), 'a) }), ?1t], def_id: DefId(0:8 ~ issue_118950_root_region[d54f]::Assoc) }) +WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: Alias(Weak, AliasTy { args: [ReBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed(DefId(0:15 ~ issue_118950_root_region[d54f]::{impl#1}::'a), 'a) }), ?1t], def_id: DefId(0:8 ~ issue_118950_root_region[d54f]::Assoc) }) +WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: Alias(Weak, AliasTy { args: [RePlaceholder(!1_BoundRegion { var: 0, kind: BrNamed(DefId(0:15 ~ issue_118950_root_region[d54f]::{impl#1}::'a), 'a) }), ?1t], def_id: DefId(0:8 ~ issue_118950_root_region[d54f]::Assoc) }) error[E0119]: conflicting implementations of trait `Overlap<fn(_)>` for type `fn(_)` --> $DIR/issue-118950-root-region.rs:18:1 | diff --git a/triagebot.toml b/triagebot.toml index 30f049c79d6..2867bbc8171 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -441,6 +441,14 @@ cc = ["@rust-lang/miri"] message = "Some changes occurred in need_type_info.rs" cc = ["@lcnr"] +[mentions."compiler/rustc_middle/src/ty/relate.rs"] +message = "Type relation code was changed" +cc = ["@compiler-errors", "@lcnr"] + +[mentions."compiler/rustc_infer/src/infer/relate"] +message = "Type relation code was changed" +cc = ["@compiler-errors", "@lcnr"] + [mentions."compiler/rustc_middle/src/mir/interpret"] message = "Some changes occurred to the CTFE / Miri engine" cc = ["@rust-lang/miri"] @@ -555,15 +563,15 @@ cc = ["@oli-obk", "@RalfJung", "@JakobDegen", "@davidtwco", "@celinval", "@vakar [mentions."compiler/rustc_error_messages"] message = "`rustc_error_messages` was changed" -cc = ["@davidtwco", "@compiler-errors", "@JohnTitor", "@TaKO8Ki"] +cc = ["@davidtwco", "@compiler-errors", "@TaKO8Ki"] [mentions."compiler/rustc_errors/src/translation.rs"] message = "`rustc_errors::translation` was changed" -cc = ["@davidtwco", "@compiler-errors", "@JohnTitor", "@TaKO8Ki"] +cc = ["@davidtwco", "@compiler-errors", "@TaKO8Ki"] [mentions."compiler/rustc_macros/src/diagnostics"] message = "`rustc_macros::diagnostics` was changed" -cc = ["@davidtwco", "@compiler-errors", "@JohnTitor", "@TaKO8Ki"] +cc = ["@davidtwco", "@compiler-errors", "@TaKO8Ki"] [mentions."compiler/stable_mir"] message = "This PR changes Stable MIR" |
