diff --git a/compiler/rustc_attr_parsing/src/attributes/cfg_select.rs b/compiler/rustc_attr_parsing/src/attributes/cfg_select.rs index f6b49fe6880ed..c786a3774ae81 100644 --- a/compiler/rustc_attr_parsing/src/attributes/cfg_select.rs +++ b/compiler/rustc_attr_parsing/src/attributes/cfg_select.rs @@ -45,25 +45,28 @@ pub struct CfgSelectBranches { impl CfgSelectBranches { /// Removes the top-most branch for which `predicate` returns `true`, /// or the wildcard if none of the reachable branches satisfied the predicate. - pub fn pop_first_match(&mut self, predicate: F) -> Option<(TokenStream, Span)> + pub fn pop_first_match(&mut self, predicate: F) -> Option<(CfgEntry, TokenStream, Span)> where F: Fn(&CfgEntry) -> bool, { for (index, (cfg, _, _)) in self.reachable.iter().enumerate() { if predicate(cfg) { - let matched = self.reachable.remove(index); - return Some((matched.1, matched.2)); + return Some(self.reachable.remove(index)); } } - self.wildcard.take().map(|(_, tts, span)| (tts, span)) + self.wildcard.take().map(|(_, tts, span)| (CfgEntry::Bool(true, span), tts, span)) } /// Consume this value and iterate over all the `TokenStream`s that it stores. - pub fn into_iter_tts(self) -> impl Iterator { - let it1 = self.reachable.into_iter().map(|(_, tts, span)| (tts, span)); - let it2 = self.wildcard.into_iter().map(|(_, tts, span)| (tts, span)); - let it3 = self.unreachable.into_iter().map(|(_, tts, span)| (tts, span)); + pub fn into_iter_tts(self) -> impl Iterator { + let it1 = self.reachable.into_iter(); + let it2 = + self.wildcard.into_iter().map(|(_, tts, span)| (CfgEntry::Bool(true, span), tts, span)); + let it3 = self + .unreachable + .into_iter() + .map(|(_, tts, span)| (CfgEntry::Bool(false, span), tts, span)); it1.chain(it2).chain(it3) } diff --git a/compiler/rustc_borrowck/src/region_infer/values.rs b/compiler/rustc_borrowck/src/region_infer/values.rs index 626b7e1084192..90171cfce6573 100644 --- a/compiler/rustc_borrowck/src/region_infer/values.rs +++ b/compiler/rustc_borrowck/src/region_infer/values.rs @@ -437,14 +437,12 @@ impl ToElementIndex<'_> for RegionVid { impl<'tcx> ToElementIndex<'tcx> for ty::PlaceholderRegion<'tcx> { fn add_to_row(self, values: &mut RegionValues<'tcx, N>, row: N) -> bool { - let placeholder: ty::PlaceholderRegion<'tcx> = self.into(); - let index = values.placeholder_indices.lookup_index(placeholder); + let index = values.placeholder_indices.lookup_index(self); values.placeholders.insert(row, index) } fn contained_in_row(self, values: &RegionValues<'tcx, N>, row: N) -> bool { - let placeholder: ty::PlaceholderRegion<'tcx> = self.into(); - let index = values.placeholder_indices.lookup_index(placeholder); + let index = values.placeholder_indices.lookup_index(self); values.placeholders.contains(row, index) } } diff --git a/compiler/rustc_builtin_macros/src/autodiff.rs b/compiler/rustc_builtin_macros/src/autodiff.rs index 76c43e0df1a24..f7bda717ae825 100644 --- a/compiler/rustc_builtin_macros/src/autodiff.rs +++ b/compiler/rustc_builtin_macros/src/autodiff.rs @@ -567,8 +567,7 @@ mod llvm_enzyme { PatKind::Ident(_, ident, _) => ecx.expr_path(ecx.path_ident(span, ident)), _ => todo!(), }) - .collect::>() - .into(), + .collect::>(), ); let enzyme_path_idents = ecx.std_path(&[sym::intrinsics, sym::autodiff]); diff --git a/compiler/rustc_builtin_macros/src/cfg_select.rs b/compiler/rustc_builtin_macros/src/cfg_select.rs index 35098722a910e..16ec6fa44156d 100644 --- a/compiler/rustc_builtin_macros/src/cfg_select.rs +++ b/compiler/rustc_builtin_macros/src/cfg_select.rs @@ -1,8 +1,13 @@ +use rustc_ast::attr::{AttrIdGenerator, mk_attr_from_item}; use rustc_ast::tokenstream::TokenStream; -use rustc_ast::{Expr, ast}; +use rustc_ast::{ + AttrItem, AttrItemKind, EarlyParsedAttribute, Expr, Path, Safety, ast, tokenstream as tts, +}; use rustc_attr_parsing as attr; use rustc_attr_parsing::{CfgSelectBranches, EvalConfigResult, parse_cfg_select}; use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacResult, MacroExpanderResult}; +use rustc_expand::expand::DeclaredIdents; +use rustc_hir::attrs::CfgEntry; use rustc_span::{Ident, Span, sym}; use smallvec::SmallVec; @@ -17,6 +22,7 @@ struct CfgSelectResult<'cx, 'sess> { selected_tts: TokenStream, selected_span: Span, other_branches: CfgSelectBranches, + cfg_entry: CfgEntry, } fn tts_to_mac_result<'cx, 'sess>( @@ -33,23 +39,78 @@ fn tts_to_mac_result<'cx, 'sess>( } macro_rules! forward_to_parser_any_macro { - ($method_name:ident, $ret_ty:ty) => { + ($method_name:ident, $ret_ty:ty, $other:expr, $selected:expr) => { fn $method_name(self: Box) -> Option<$ret_ty> { - let CfgSelectResult { ecx, site_span, selected_tts, selected_span, .. } = *self; + let CfgSelectResult { ecx, site_span, selected_tts, selected_span, cfg_entry, .. } = + *self; - for (tts, span) in self.other_branches.into_iter_tts() { - let _ = tts_to_mac_result(ecx, site_span, tts, span).$method_name(); + for (cfg_entry, tts, span) in self.other_branches.into_iter_tts() { + let result = tts_to_mac_result(ecx, site_span, tts, span).$method_name(); + $other(&mut *ecx, cfg_entry, span, result); } - tts_to_mac_result(ecx, site_span, selected_tts, selected_span).$method_name() + tts_to_mac_result(ecx, site_span, selected_tts, selected_span) + .$method_name() + .map(|elements| $selected(&mut *ecx, cfg_entry, elements)) } }; + + ($method_name:ident, $ret_ty:ty) => { + forward_to_parser_any_macro!($method_name, $ret_ty, |_, _, _, _| {}, |_, _, elements| { + elements + }); + }; +} + +/// Construct a `#[]` attribute from a `CfgEntry`. This allows us to keep track of items +/// that were behind a `cfg_select!`, which is relevant for some diagnostics. +fn mk_attr(g: &AttrIdGenerator, cfg_entry: CfgEntry) -> ast::Attribute { + let cfg_span = cfg_entry.span(); + let args = AttrItemKind::Parsed(EarlyParsedAttribute::CfgTrace(cfg_entry)); + // This makes the trace attributes unobservable to token-based proc macros. + let tokens = Some(tts::LazyAttrTokenStream::new_direct(tts::AttrTokenStream::default())); + let attr_item = AttrItem { + unsafety: Safety::Default, + path: Path::from_ident(Ident::new(sym::cfg_trace, cfg_span)), + args, + tokens: None, + }; + mk_attr_from_item(g, attr_item, tokens, ast::AttrStyle::Outer, cfg_span) } impl<'cx, 'sess> MacResult for CfgSelectResult<'cx, 'sess> { forward_to_parser_any_macro!(make_expr, Box); forward_to_parser_any_macro!(make_stmts, SmallVec<[ast::Stmt; 1]>); - forward_to_parser_any_macro!(make_items, SmallVec<[Box; 1]>); + forward_to_parser_any_macro!( + make_items, + SmallVec<[Box; 1]>, + |ecx: &mut ExtCtxt<'_>, + cfg_entry: CfgEntry, + span: Span, + items: Option; 1]>>| if let Some(items) = items { + // Register item names that were not selected for error reporting. We do this + // for `#[cfg]` too. + for item in items { + for name in item.declared_idents() { + ecx.resolver.append_stripped_cfg_item( + ecx.current_expansion.lint_node_id, + name, + cfg_entry.clone(), + span, + ); + } + } + }, + |ecx: &mut ExtCtxt<'_>, cfg_entry: CfgEntry, items: SmallVec<[Box; 1]>| { + items + .into_iter() + .map(|mut item| { + item.attrs.push(mk_attr(&ecx.sess.psess.attr_id_generator, cfg_entry.clone())); + item + }) + .collect() + } + ); forward_to_parser_any_macro!(make_impl_items, SmallVec<[Box; 1]>); forward_to_parser_any_macro!(make_trait_impl_items, SmallVec<[Box; 1]>); @@ -73,15 +134,18 @@ pub(super) fn expand_cfg_select<'cx>( ecx.current_expansion.lint_node_id, ) { Ok(mut branches) => { - if let Some((selected_tts, selected_span)) = branches.pop_first_match(|cfg| { - matches!(attr::eval_config_entry(&ecx.sess, cfg), EvalConfigResult::True) - }) { + if let Some((cfg_entry, selected_tts, selected_span)) = + branches.pop_first_match(|cfg| { + matches!(attr::eval_config_entry(&ecx.sess, cfg), EvalConfigResult::True) + }) + { let mac = CfgSelectResult { ecx, selected_tts, selected_span, other_branches: branches, site_span: sp, + cfg_entry, }; return ExpandResult::Ready(Box::new(mac)); } else { diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs index b8e1886b2d3c1..5d7e457b8e1ba 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs @@ -371,7 +371,7 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( } for i in 0..lane_count { - let ret_lane = ret.place_lane(fx, i.into()); + let ret_lane = ret.place_lane(fx, i); ret_lane.write_cvalue(fx, value); } } diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index 3f85e10e5ca94..bd5ff02254c55 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -773,7 +773,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { _ => return interp_ok(false), } - trace!("{:?}", self.dump_place(&dest.clone().into())); + trace!("{:?}", self.dump_place(&dest)); self.return_to_block(ret)?; interp_ok(true) } diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 741c34e0304af..53b75d8d1c8c3 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -1250,7 +1250,7 @@ enum AddSemicolon { /// A trait implemented for all `AstFragment` nodes and providing all pieces /// of functionality used by `InvocationCollector`. -trait InvocationCollectorNode: HasAttrs + HasNodeId + Sized { +trait InvocationCollectorNode: HasAttrs + HasNodeId + Sized + DeclaredIdents { type OutputTy = SmallVec<[Self; 1]>; type ItemKind = ItemKind; const KIND: AstFragmentKind; @@ -1302,13 +1302,43 @@ trait InvocationCollectorNode: HasAttrs + HasNodeId + Sized { collector.cx.dcx().emit_err(RemoveNodeNotSupported { span, descr: Self::descr() }); } + fn as_target(&self) -> Target; +} + +pub trait DeclaredIdents { /// All of the identifiers (items) declared by this node. /// This is an approximation and should only be used for diagnostics. fn declared_idents(&self) -> Vec { vec![] } +} - fn as_target(&self) -> Target; +macro_rules! declared_idents { + ($($ty:ty),*) => { + $(impl DeclaredIdents for $ty {})* + }; +} + +// Use the default "empty" list of idents for the following: +declared_idents! { + AstNodeWrapper, TraitItemTag>, + AstNodeWrapper, ImplItemTag>, + AstNodeWrapper, TraitImplItemTag>, + Box, + ast::Variant, + ast::WherePredicate, + ast::FieldDef, + ast::PatField, + ast::ExprField, + ast::Param, + ast::GenericParam, + ast::Arm, + ast::Stmt, + ast::Crate, + ast::Ty, + ast::Pat, + ast::Expr, + AstNodeWrapper, OptExprTag> } impl InvocationCollectorNode for Box { @@ -1440,6 +1470,12 @@ impl InvocationCollectorNode for Box { res } + fn as_target(&self) -> Target { + Target::from_ast_item(self) + } +} + +impl DeclaredIdents for Box { fn declared_idents(&self) -> Vec { if let ItemKind::Use(ut) = &self.kind { fn collect_use_tree_leaves(ut: &ast::UseTree, idents: &mut Vec) { @@ -1460,10 +1496,6 @@ impl InvocationCollectorNode for Box { self.kind.ident().into_iter().collect() } } - - fn as_target(&self) -> Target { - Target::from_ast_item(self) - } } struct TraitItemTag; @@ -2005,6 +2037,7 @@ impl InvocationCollectorNode for AstNodeWrapper, OptExprTag> { /// It can be removed once that feature is stabilized. struct MethodReceiverTag; +impl DeclaredIdents for AstNodeWrapper {} impl InvocationCollectorNode for AstNodeWrapper { type OutputTy = AstNodeWrapper, MethodReceiverTag>; const KIND: AstFragmentKind = AstFragmentKind::MethodReceiverExpr; diff --git a/compiler/rustc_infer/src/infer/snapshot/undo_log.rs b/compiler/rustc_infer/src/infer/snapshot/undo_log.rs index 09d8eb3bf9232..d1cf26faf49f2 100644 --- a/compiler/rustc_infer/src/infer/snapshot/undo_log.rs +++ b/compiler/rustc_infer/src/infer/snapshot/undo_log.rs @@ -39,6 +39,7 @@ macro_rules! impl_from { $( impl<'tcx> From<$ty> for UndoLog<'tcx> { fn from(x: $ty) -> Self { + #[cfg_attr(not(bootstrap), allow(self_type_conversion))] UndoLog::$ctor(x.into()) } } diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 2c7ccfb25ae9b..1ba8e130a9ea2 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -22,6 +22,7 @@ use rustc_ast::visit::{FnCtxt, FnKind}; use rustc_ast::{self as ast, *}; use rustc_ast_pretty::pprust::expr_to_string; use rustc_attr_parsing::AttributeParser; +use rustc_data_structures::fx::FxHashSet; use rustc_errors::{Applicability, Diagnostic, msg}; use rustc_feature::GateIssue; use rustc_hir::attrs::{AttributeKind, DocAttribute}; @@ -59,6 +60,7 @@ use crate::lints::{ BuiltinUngatedAsyncFnTrackCaller, BuiltinUnpermittedTypeInit, BuiltinUnpermittedTypeInitSub, BuiltinUnreachablePub, BuiltinUnsafe, BuiltinUnstableFeatures, BuiltinUnusedDocComment, BuiltinUnusedDocCommentSub, BuiltinWhileTrue, EqInternalMethodImplemented, InvalidAsmLabel, + SelfTypeConversionDiag, SelfTypeConversionInMacroDiag, }; use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext}; @@ -1599,6 +1601,8 @@ declare_lint_pass!( SoftLints => [ WHILE_TRUE, NON_SHORTHAND_FIELD_PATTERNS, + SELF_TYPE_CONVERSION, + SELF_TYPE_CONVERSION_IN_MACRO, UNSAFE_CODE, MISSING_DOCS, MISSING_COPY_IMPLEMENTATIONS, @@ -3246,3 +3250,198 @@ impl<'tcx> LateLintPass<'tcx> for InternalEqTraitMethodImpls { } } } + +declare_lint! { + /// The `self_type_conversion` lint detects when a call to `.into()` does not have any effect. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// #![deny(self_type_conversion)] + /// fn main() { + /// let _: i32 = 0i32.into(); + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// The standard library provides an `impl Into for T` implementation, which lets you call + /// `.into()` on any type. Relying on that `impl` is a potential semver problem, as a new, more + /// specific `impl` of `Into` for the type could be added in the future, causing an inference + /// error on code that previously compiled successfully. + /// + /// As a way to side-step this potential future failure, it is a good idea to instead use the + /// fully-qualified path to the correct impl, like `>::into(value)`. When + /// calling the method with this syntax, inference does not come into play. + /// + /// ### Limitations + /// + /// The lint as currently implemented has both false negatives *and* false positives. + /// + /// When `use` imports and/or type aliases have `cfg` attributes or are behind a `cfg_select!` + /// macro invocation, their *underlying* type will *not* be considered for the purposes of this + /// lint, in order to avoid complaining about useless conversions for types that are platform + /// dependent. + /// + /// Even then, the analysis for whether a type is different under different platforms isn't + /// exhaustive: if a containing *module* is the one that is gated with a `cfg` attribute, this + /// lint will not detect that. + pub SELF_TYPE_CONVERSION, + Warn, + "unnecessary call to `.into()`", +} + +declare_lint! { + /// The `self_type_conversion_in_macro` lint detects when a call to `.into()` within a macro + /// expansion does not have any effect. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// #![deny(self_type_conversion_in_macro)] + /// macro_rules! foo { + /// ($x:expr) => { + /// $x.into() + /// } + /// } + /// fn main() { + /// let () = foo!(()); + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// The standard library provides an `impl Into for T` implementation, which lets you call + /// `.into()` on any type. Relying on that `impl` is a potential semver problem, as a new, more + /// specific `impl` of `Into` for the type could be added in the future, causing an inference + /// error on code that previously compiled successfully. + /// + /// As a way to side-step this potential future failure, it is a good idea to instead use the + /// fully-qualified path to the correct impl, like `>::into(value)`. When + /// calling the method with this syntax, inference does not come into play. + /// + /// ### Limitations + /// + /// The lint as currently implemented has both false negatives *and* false positives. + /// + /// When `use` imports and/or type aliases have `cfg` attributes or are behind a `cfg_select!` + /// macro invocation, their *underlying* type will *not* be considered for the purposes of this + /// lint, in order to avoid complaining about useless conversions for types that are platform + /// dependent. + /// + /// Even then, the analysis for whether a type is different under different platforms isn't + /// exhaustive: if a containing *module* is the one that is gated with a `cfg` attribute, this + /// lint will not detect that. + pub SELF_TYPE_CONVERSION_IN_MACRO, + Allow, + "unnecessary call to `.into()` within a macro expansion", +} + +pub struct SelfTypeConversion<'tcx> { + ignored_types: FxHashSet>, +} + +impl_lint_pass!(SelfTypeConversion<'_> => [SELF_TYPE_CONVERSION, SELF_TYPE_CONVERSION_IN_MACRO]); + +impl SelfTypeConversion<'_> { + pub fn new() -> Self { + Self { ignored_types: Default::default() } + } +} + +impl<'tcx> LateLintPass<'tcx> for SelfTypeConversion<'tcx> { + fn check_item_post(&mut self, cx: &LateContext<'tcx>, item: &hir::Item<'_>) { + let hir::ItemKind::Use(path, _kind) = item.kind else { return }; + // Look at `cfg`d types as to account for things like `std::io::repr_bitpacked` and + // `std::io::repr_unpacked`. + // + // The compiler currently doesn't track when a type alias has been interacted with in type + // type system, which means that when given `type Alias = i32;` and `let x: i32 = 42;` or + // `let y: Alias = 42`, we can't differentiate between calling `let _: i32 = x.into();` and + // `let _: i32 = y.into();`: as far as the compiler is concerned in both cases the receiver + // type is `i32`. Worse yet, type aliases are often used to select different types in + // different platforms, meaning that `y.into()` might be a no-op in some platforms, while + // being required in others. To avoid some false positives, we keep track of type aliases + // that have `cfg` attributes and will *not* emit the lint against calling `.into()` on the + // underlying type. This *will* cause false negatives. + // + // There are likely other combinations that we should check for in order to avoid false + // positives, like looking at the parent items for the type alias for `cfg` attributes, but + // empirically these two checks seem to account for the majority of the cases in the wild. + // FIXME: verify the above with crater run :) + + // Whether we've encountered `#[cfg(..)] use foo::bar;`. + let import_has_cfg = find_attr!(cx.tcx, item.hir_id(), CfgTrace(..)); + for res in path.res.iter() { + let Some(Res::Def(DefKind::TyAlias, def_id)) = res else { continue }; + let ty = cx.tcx.type_of(*def_id).instantiate_identity().skip_normalization(); + + // Whether we've encountered `#[cfg(..)] type Alias = Ty;`. + let alias_has_cfg = find_attr!(cx.tcx, *def_id, CfgTrace(..)); + if alias_has_cfg || import_has_cfg { + // We have in scope a type alias of type `ty` which is gated behind a `cfg` + // attribute, either at its definition or through its import, which is indicative + // of platform specific code. This kind of code often ends up with `.into()` method + // calls that are useless in some configurations, but *necessary* in others. As a + // first-order approximation, we ignore *all* `val_of_ty.into()` calls. + self.ignored_types.insert(ty); + } + } + } + + /// Look for method calls to `Into::into` that rely on inference and that ends up using the + /// `impl Into for T {}` blanket `impl`. + /// + /// This filters on explicit `foo.into()` method calls (ignoring `<_ as Into<_>>::into(foo)`). + fn check_expr_post(&mut self, cx: &LateContext<'tcx>, expr: &hir::Expr<'_>) { + let hir::ExprKind::MethodCall(_segment, rcvr, args, _) = expr.kind else { return }; + if !args.is_empty() { + // If we have `foo.method(...)` with arguments, we already know that `method` can't be + // `into`, so we bail. + return; + } + + let Some(def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) else { return }; + tracing::debug!(?def_id); + if Some(def_id) != cx.tcx.get_diagnostic_item(sym::into_fn) { + // We don't have `foo.into()` corresponding to `Into::into`. + return; + } + + let ty = cx.typeck_results().expr_ty(expr); + let rcvr_ty = cx.typeck_results().expr_ty(rcvr); + + if ty != rcvr_ty { + // If the type we are converting from and converting towards are different, there's + // nothing to complain about. + return; + } + + if self.ignored_types.contains(&ty) { + // Found `<{ty} as Into<{ty}>::into()` call, but that type has been detected to have + // been annotated with `#[cfg]`, meaning it there are likely configurations in which + // the receiver and target types are different. + tracing::debug!("Skipping linting `<{ty} as Into<{ty}>::into()` call"); + return; + } + + if let Some(expn) = expr.span.macro_backtrace().next() { + if expn.macro_def_id.map_or(false, |did| did.is_local()) { + cx.emit_span_lint( + SELF_TYPE_CONVERSION_IN_MACRO, + expr.span, + SelfTypeConversionInMacroDiag { ty }, + ); + } + // A macro that expands to this code isn't great, but end-users of a macro can't do + // anything about it. + return; + } + + cx.emit_span_lint(SELF_TYPE_CONVERSION, expr.span, SelfTypeConversionDiag { ty }); + } +} diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 1efc8b70ef22d..3a2f588c922dc 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -287,6 +287,9 @@ fn register_builtins(store: &mut LintStore) { store.register_lints(&foreign_modules::get_lints()); store.register_lints(&HardwiredLints::lint_vec()); + store.register_lints(&SelfTypeConversion::lint_vec()); + store.register_late_pass(|_| Box::new(SelfTypeConversion::new())); + add_lint_group!( "nonstandard_style", NON_CAMEL_CASE_TYPES, diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 227a413ea9b07..4326586a777d8 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -65,6 +65,36 @@ pub(crate) enum ShadowedIntoIterDiagSub { }, } +#[derive(Diagnostic)] +#[diag("useless conversion to the same type: `{$ty}`")] +#[note( + "this method call relies on the `impl Into for T` blanket implementation and type \ + inference, which is a semver hazard as a new `impl Into<_>` that affects your type might be \ + added in the future causing type inference errors" +)] +#[note( + "you can instead use the fully-qualified path `<{$ty} as Into<{$ty}>::into(val) to avoid \ + triggering this lint" +)] +pub(crate) struct SelfTypeConversionDiag<'t> { + pub ty: Ty<'t>, +} + +#[derive(Diagnostic)] +#[diag("useless conversion to the same type: `{$ty}`")] +#[note( + "this method call relies on the `impl Into for T` blanket implementation and type \ + inference, which is a semver hazard as a new `impl Into<_>` that affects your type might be \ + added in the future causing type inference errors" +)] +#[note( + "you can instead use the fully-qualified path `<{$ty} as Into<{$ty}>::into(val) to avoid \ + triggering this lint" +)] +pub(crate) struct SelfTypeConversionInMacroDiag<'t> { + pub ty: Ty<'t>, +} + // autorefs.rs #[derive(Diagnostic)] #[diag("implicit autoref creates a reference to the dereference of a raw pointer")] diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index fb433aef68cf8..f43184c3b566f 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1110,6 +1110,7 @@ symbols! { internal_eq_trait_method_impls, internal_features, into_async_iter_into_iter, + into_fn, into_future, into_iter, into_try_type, diff --git a/compiler/rustc_symbol_mangling/src/lib.rs b/compiler/rustc_symbol_mangling/src/lib.rs index c052037f05b39..475b0827a53d3 100644 --- a/compiler/rustc_symbol_mangling/src/lib.rs +++ b/compiler/rustc_symbol_mangling/src/lib.rs @@ -219,7 +219,7 @@ fn compute_symbol_name<'tcx>( // However, we don't have the wasm import module map there yet. tcx.is_foreign_item(def_id) && tcx.sess.target.is_like_wasm - && tcx.wasm_import_module_map(def_id.krate).contains_key(&def_id.into()) + && tcx.wasm_import_module_map(def_id.krate).contains_key(&def_id) }; if !wasm_import_module_exception_force_mangling { diff --git a/compiler/rustc_traits/src/normalize_projection_ty.rs b/compiler/rustc_traits/src/normalize_projection_ty.rs index 96586713aed6f..ccc67ed41d5fa 100644 --- a/compiler/rustc_traits/src/normalize_projection_ty.rs +++ b/compiler/rustc_traits/src/normalize_projection_ty.rs @@ -35,7 +35,7 @@ fn normalize_canonicalized_projection<'tcx>( let normalized_term = traits::normalize_projection_term( selcx, param_env, - goal.into(), + goal, cause, 0, &mut obligations, @@ -111,7 +111,7 @@ fn normalize_canonicalized_inherent_projection<'tcx>( let normalized_term = traits::normalize_inherent_projection( selcx, param_env, - goal.into(), + goal, cause, 0, &mut obligations, diff --git a/library/core/src/convert/mod.rs b/library/core/src/convert/mod.rs index 34cf9c5d0a5b2..aa66dc09dc7bc 100644 --- a/library/core/src/convert/mod.rs +++ b/library/core/src/convert/mod.rs @@ -449,6 +449,7 @@ pub const trait AsMut: PointeeSized { #[rustc_const_unstable(feature = "const_convert", issue = "143773")] pub const trait Into: Sized { /// Converts this type into the (usually inferred) input type. + #[rustc_diagnostic_item = "into_fn"] #[must_use] #[stable(feature = "rust1", since = "1.0.0")] fn into(self) -> T; diff --git a/library/coretests/tests/convert.rs b/library/coretests/tests/convert.rs index 1eb7468e56ea7..c0d1de2f27356 100644 --- a/library/coretests/tests/convert.rs +++ b/library/coretests/tests/convert.rs @@ -8,6 +8,7 @@ fn convert() { assert_eq!(FOO, 42); const fn into(x: Vec) -> Vec { + #[allow(self_type_conversion)] x.into() } diff --git a/library/std/src/sys/process/env.rs b/library/std/src/sys/process/env.rs index 15065c6e2c922..90d3d0df9ddfe 100644 --- a/library/std/src/sys/process/env.rs +++ b/library/std/src/sys/process/env.rs @@ -25,6 +25,7 @@ impl CommandEnv { let mut result = BTreeMap::::new(); if !self.clear { for (k, v) in env::vars_os() { + #[allow(self_type_conversion)] result.insert(k.into(), v); } } @@ -137,6 +138,7 @@ impl Iterator for CommandResolvedEnvs { type Item = (OsString, OsString); fn next(&mut self) -> Option { + #[allow(self_type_conversion)] self.inner.next().map(|(key, value)| (key.into(), value)) } diff --git a/src/tools/clippy/tests/ui/needless_return_with_question_mark.fixed b/src/tools/clippy/tests/ui/needless_return_with_question_mark.fixed index a8e9f09fa5ecf..053cc72d70ef2 100644 --- a/src/tools/clippy/tests/ui/needless_return_with_question_mark.fixed +++ b/src/tools/clippy/tests/ui/needless_return_with_question_mark.fixed @@ -6,6 +6,7 @@ clippy::useless_conversion, clippy::diverging_sub_expression, clippy::let_unit_value, + self_type_conversion, unused )] diff --git a/src/tools/clippy/tests/ui/needless_return_with_question_mark.rs b/src/tools/clippy/tests/ui/needless_return_with_question_mark.rs index aba7ffb273bce..bc44c68a6a51d 100644 --- a/src/tools/clippy/tests/ui/needless_return_with_question_mark.rs +++ b/src/tools/clippy/tests/ui/needless_return_with_question_mark.rs @@ -6,6 +6,7 @@ clippy::useless_conversion, clippy::diverging_sub_expression, clippy::let_unit_value, + self_type_conversion, unused )] diff --git a/src/tools/clippy/tests/ui/needless_return_with_question_mark.stderr b/src/tools/clippy/tests/ui/needless_return_with_question_mark.stderr index d73a0e3fdc896..53141b862fe4e 100644 --- a/src/tools/clippy/tests/ui/needless_return_with_question_mark.stderr +++ b/src/tools/clippy/tests/ui/needless_return_with_question_mark.stderr @@ -1,5 +1,5 @@ error: unneeded `return` statement with `?` operator - --> tests/ui/needless_return_with_question_mark.rs:29:5 + --> tests/ui/needless_return_with_question_mark.rs:30:5 | LL | return Err(())?; | ^^^^^^^ help: remove it @@ -8,25 +8,25 @@ LL | return Err(())?; = help: to override `-D warnings` add `#[allow(clippy::needless_return_with_question_mark)]` error: unneeded `return` statement with `?` operator - --> tests/ui/needless_return_with_question_mark.rs:70:9 + --> tests/ui/needless_return_with_question_mark.rs:71:9 | LL | return Err(())?; | ^^^^^^^ help: remove it error: unneeded `return` statement with `?` operator - --> tests/ui/needless_return_with_question_mark.rs:134:9 + --> tests/ui/needless_return_with_question_mark.rs:135:9 | LL | return Err(())?; | ^^^^^^^ help: remove it error: unneeded `return` statement with `?` operator - --> tests/ui/needless_return_with_question_mark.rs:143:13 + --> tests/ui/needless_return_with_question_mark.rs:144:13 | LL | return Err(())?; | ^^^^^^^ help: remove it error: unneeded `return` statement with `?` operator - --> tests/ui/needless_return_with_question_mark.rs:163:5 + --> tests/ui/needless_return_with_question_mark.rs:164:5 | LL | return Err(())?; | ^^^^^^^ help: remove it diff --git a/src/tools/clippy/tests/ui/useless_conversion.fixed b/src/tools/clippy/tests/ui/useless_conversion.fixed index a22df7013f988..488008ce4adee 100644 --- a/src/tools/clippy/tests/ui/useless_conversion.fixed +++ b/src/tools/clippy/tests/ui/useless_conversion.fixed @@ -1,6 +1,6 @@ #![deny(clippy::useless_conversion)] #![allow(clippy::into_iter_on_ref)] -#![allow(clippy::needless_ifs, clippy::unnecessary_wraps, unused)] +#![allow(clippy::needless_ifs, clippy::unnecessary_wraps, unused, self_type_conversion)] // FIXME(static_mut_refs): Do not allow `static_mut_refs` lint #![allow(static_mut_refs)] diff --git a/src/tools/clippy/tests/ui/useless_conversion.rs b/src/tools/clippy/tests/ui/useless_conversion.rs index 1f170cf87ac58..d1183cd068632 100644 --- a/src/tools/clippy/tests/ui/useless_conversion.rs +++ b/src/tools/clippy/tests/ui/useless_conversion.rs @@ -1,6 +1,6 @@ #![deny(clippy::useless_conversion)] #![allow(clippy::into_iter_on_ref)] -#![allow(clippy::needless_ifs, clippy::unnecessary_wraps, unused)] +#![allow(clippy::needless_ifs, clippy::unnecessary_wraps, unused, self_type_conversion)] // FIXME(static_mut_refs): Do not allow `static_mut_refs` lint #![allow(static_mut_refs)] diff --git a/tests/ui/cfg/auxiliary/cfged_out.rs b/tests/ui/cfg/auxiliary/cfged_out.rs index 564280b24f598..fff8b7bab8cba 100644 --- a/tests/ui/cfg/auxiliary/cfged_out.rs +++ b/tests/ui/cfg/auxiliary/cfged_out.rs @@ -3,10 +3,19 @@ pub mod inner { pub fn uwu() {} #[cfg(false)] - pub mod doesnt_exist { + pub mod cfgd_out { pub fn hello() {} } + cfg_select! { + false => { + pub mod selected_out { + pub fn hello() {} + } + } + _ => {} + } + pub mod wrong { #[cfg(feature = "suggesting me fails the test!!")] pub fn meow() {} diff --git a/tests/ui/cfg/diagnostics-cross-crate.rs b/tests/ui/cfg/diagnostics-cross-crate.rs index c5d8dcdc62f0a..f7b1dd06a8923 100644 --- a/tests/ui/cfg/diagnostics-cross-crate.rs +++ b/tests/ui/cfg/diagnostics-cross-crate.rs @@ -12,10 +12,14 @@ fn main() { //~^ NOTE found an item that was configured out //~| NOTE not found in `cfged_out::inner` - // The module isn't found - we would like to get a diagnostic, but currently don't due to - // the awkward way the resolver diagnostics are currently implemented. - cfged_out::inner::doesnt_exist::hello(); //~ ERROR cannot find - //~^ NOTE could not find `doesnt_exist` in `inner` + // The module isn't found - we mention that `cfgd_out` is `cfg`d out + cfged_out::inner::cfgd_out::hello(); //~ ERROR cannot find + //~^ NOTE could not find `cfgd_out` in `inner` + //~| NOTE found an item that was configured out + + // The module isn't found - we mention that `selected_out` is `cfg_select`d out + cfged_out::inner::selected_out::hello(); //~ ERROR cannot find + //~^ NOTE could not find `selected_out` in `inner` //~| NOTE found an item that was configured out // It should find the one in the right module, not the wrong one. diff --git a/tests/ui/cfg/diagnostics-cross-crate.stderr b/tests/ui/cfg/diagnostics-cross-crate.stderr index 15e60cc43a3c9..5aa00136f3cdb 100644 --- a/tests/ui/cfg/diagnostics-cross-crate.stderr +++ b/tests/ui/cfg/diagnostics-cross-crate.stderr @@ -1,16 +1,33 @@ -error[E0433]: cannot find `doesnt_exist` in `inner` - --> $DIR/diagnostics-cross-crate.rs:17:23 +error[E0433]: cannot find `cfgd_out` in `inner` + --> $DIR/diagnostics-cross-crate.rs:16:23 | -LL | cfged_out::inner::doesnt_exist::hello(); - | ^^^^^^^^^^^^ could not find `doesnt_exist` in `inner` +LL | cfged_out::inner::cfgd_out::hello(); + | ^^^^^^^^ could not find `cfgd_out` in `inner` | note: found an item that was configured out --> $DIR/auxiliary/cfged_out.rs:6:13 | LL | #[cfg(false)] | ----- the item is gated here -LL | pub mod doesnt_exist { - | ^^^^^^^^^^^^ +LL | pub mod cfgd_out { + | ^^^^^^^^ + +error[E0433]: cannot find `selected_out` in `inner` + --> $DIR/diagnostics-cross-crate.rs:21:23 + | +LL | cfged_out::inner::selected_out::hello(); + | ^^^^^^^^^^^^ could not find `selected_out` in `inner` + | +note: found an item that was configured out + --> $DIR/auxiliary/cfged_out.rs:12:21 + | +LL | / false => { +LL | | pub mod selected_out { + | | ^^^^^^^^^^^^ +LL | | pub fn hello() {} +... | +LL | | _ => {} + | |_________- the item is gated here error[E0425]: cannot find function `uwu` in crate `cfged_out` --> $DIR/diagnostics-cross-crate.rs:7:16 @@ -33,13 +50,13 @@ LL | pub fn uwu() {} | ^^^ error[E0425]: cannot find function `meow` in module `cfged_out::inner::right` - --> $DIR/diagnostics-cross-crate.rs:22:30 + --> $DIR/diagnostics-cross-crate.rs:26:30 | LL | cfged_out::inner::right::meow(); | ^^^^ not found in `cfged_out::inner::right` | note: found an item that was configured out - --> $DIR/auxiliary/cfged_out.rs:17:16 + --> $DIR/auxiliary/cfged_out.rs:26:16 | LL | #[cfg(feature = "what-a-cool-feature")] | ------------------------------- the item is gated behind the `what-a-cool-feature` feature @@ -47,20 +64,20 @@ LL | pub fn meow() {} | ^^^^ error[E0425]: cannot find function `vanished` in crate `cfged_out` - --> $DIR/diagnostics-cross-crate.rs:27:16 + --> $DIR/diagnostics-cross-crate.rs:31:16 | LL | cfged_out::vanished(); | ^^^^^^^^ not found in `cfged_out` | note: found an item that was configured out - --> $DIR/auxiliary/cfged_out.rs:22:8 + --> $DIR/auxiliary/cfged_out.rs:31:8 | LL | #[cfg(i_dont_exist_and_you_can_do_nothing_about_it)] | -------------------------------------------- the item is gated here LL | pub fn vanished() {} | ^^^^^^^^ -error: aborting due to 5 previous errors +error: aborting due to 6 previous errors Some errors have detailed explanations: E0425, E0433. For more information about an error, try `rustc --explain E0425`. diff --git a/tests/ui/cfg/diagnostics-same-crate.rs b/tests/ui/cfg/diagnostics-same-crate.rs index 40babaa3d4c9a..00369eb9c8507 100644 --- a/tests/ui/cfg/diagnostics-same-crate.rs +++ b/tests/ui/cfg/diagnostics-same-crate.rs @@ -16,6 +16,21 @@ pub mod inner { pub mod hi {} } + cfg_select! { + false => { //~ NOTE the item is gated here + //~^ NOTE the item is gated here + //~| NOTE the item is gated here + pub mod selected_out { + //~^ NOTE found an item that was configured out + //~| NOTE found an item that was configured out + //~| NOTE found an item that was configured out + pub fn hello() {} + pub mod hi {} + } + } + _ => {} + } + pub mod wrong { #[cfg(feature = "suggesting me fails the test!!")] pub fn meow() {} @@ -35,6 +50,12 @@ mod placeholder { use super::inner::doesnt_exist::hi; //~^ ERROR unresolved import `super::inner::doesnt_exist` //~| NOTE could not find `doesnt_exist` in `inner` + use super::inner::selected_out; + //~^ ERROR unresolved import `super::inner::selected_out` + //~| NOTE no `selected_out` in `inner` + use super::inner::selected_out::hi; + //~^ ERROR unresolved import `super::inner::selected_out` + //~| NOTE could not find `selected_out` in `inner` } #[cfg(i_dont_exist_and_you_can_do_nothing_about_it)] //~ NOTE the item is gated here @@ -53,6 +74,10 @@ fn main() { inner::doesnt_exist::hello(); //~ ERROR cannot find //~| NOTE could not find `doesnt_exist` in `inner` + // The module isn't found - we get a diagnostic. + inner::selected_out::hello(); //~ ERROR cannot find + //~| NOTE could not find `selected_out` in `inner` + // It should find the one in the right module, not the wrong one. inner::right::meow(); //~ ERROR cannot find function //~| NOTE not found in `inner::right diff --git a/tests/ui/cfg/diagnostics-same-crate.stderr b/tests/ui/cfg/diagnostics-same-crate.stderr index c20542e19eaf3..e28075d30cc5d 100644 --- a/tests/ui/cfg/diagnostics-same-crate.stderr +++ b/tests/ui/cfg/diagnostics-same-crate.stderr @@ -1,5 +1,5 @@ error[E0432]: unresolved import `super::inner::doesnt_exist` - --> $DIR/diagnostics-same-crate.rs:32:9 + --> $DIR/diagnostics-same-crate.rs:47:9 | LL | use super::inner::doesnt_exist; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ no `doesnt_exist` in `inner` @@ -14,7 +14,7 @@ LL | pub mod doesnt_exist { | ^^^^^^^^^^^^ error[E0432]: unresolved import `super::inner::doesnt_exist` - --> $DIR/diagnostics-same-crate.rs:35:23 + --> $DIR/diagnostics-same-crate.rs:50:23 | LL | use super::inner::doesnt_exist::hi; | ^^^^^^^^^^^^ could not find `doesnt_exist` in `inner` @@ -28,8 +28,44 @@ LL | #[cfg(false)] LL | pub mod doesnt_exist { | ^^^^^^^^^^^^ +error[E0432]: unresolved import `super::inner::selected_out` + --> $DIR/diagnostics-same-crate.rs:53:9 + | +LL | use super::inner::selected_out; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ no `selected_out` in `inner` + | +note: found an item that was configured out + --> $DIR/diagnostics-same-crate.rs:23:21 + | +LL | / false => { +LL | | +LL | | +LL | | pub mod selected_out { + | | ^^^^^^^^^^^^ +... | +LL | | _ => {} + | |_________- the item is gated here + +error[E0432]: unresolved import `super::inner::selected_out` + --> $DIR/diagnostics-same-crate.rs:56:23 + | +LL | use super::inner::selected_out::hi; + | ^^^^^^^^^^^^ could not find `selected_out` in `inner` + | +note: found an item that was configured out + --> $DIR/diagnostics-same-crate.rs:23:21 + | +LL | / false => { +LL | | +LL | | +LL | | pub mod selected_out { + | | ^^^^^^^^^^^^ +... | +LL | | _ => {} + | |_________- the item is gated here + error[E0433]: cannot find `doesnt_exist` in `inner` - --> $DIR/diagnostics-same-crate.rs:53:12 + --> $DIR/diagnostics-same-crate.rs:74:12 | LL | inner::doesnt_exist::hello(); | ^^^^^^^^^^^^ could not find `doesnt_exist` in `inner` @@ -43,8 +79,26 @@ LL | #[cfg(false)] LL | pub mod doesnt_exist { | ^^^^^^^^^^^^ +error[E0433]: cannot find `selected_out` in `inner` + --> $DIR/diagnostics-same-crate.rs:78:12 + | +LL | inner::selected_out::hello(); + | ^^^^^^^^^^^^ could not find `selected_out` in `inner` + | +note: found an item that was configured out + --> $DIR/diagnostics-same-crate.rs:23:21 + | +LL | / false => { +LL | | +LL | | +LL | | pub mod selected_out { + | | ^^^^^^^^^^^^ +... | +LL | | _ => {} + | |_________- the item is gated here + error[E0425]: cannot find function `uwu` in module `inner` - --> $DIR/diagnostics-same-crate.rs:49:12 + --> $DIR/diagnostics-same-crate.rs:70:12 | LL | inner::uwu(); | ^^^ not found in `inner` @@ -58,13 +112,13 @@ LL | pub fn uwu() {} | ^^^ error[E0425]: cannot find function `meow` in module `inner::right` - --> $DIR/diagnostics-same-crate.rs:57:19 + --> $DIR/diagnostics-same-crate.rs:82:19 | LL | inner::right::meow(); | ^^^^ not found in `inner::right` | note: found an item that was configured out - --> $DIR/diagnostics-same-crate.rs:26:16 + --> $DIR/diagnostics-same-crate.rs:41:16 | LL | #[cfg(feature = "what-a-cool-feature")] | ------------------------------- the item is gated behind the `what-a-cool-feature` feature @@ -72,26 +126,26 @@ LL | pub fn meow() {} | ^^^^ error[E0425]: cannot find function `uwu` in this scope - --> $DIR/diagnostics-same-crate.rs:45:5 + --> $DIR/diagnostics-same-crate.rs:66:5 | LL | uwu(); | ^^^ not found in this scope error[E0425]: cannot find function `vanished` in this scope - --> $DIR/diagnostics-same-crate.rs:62:5 + --> $DIR/diagnostics-same-crate.rs:87:5 | LL | vanished(); | ^^^^^^^^ not found in this scope | note: found an item that was configured out - --> $DIR/diagnostics-same-crate.rs:41:8 + --> $DIR/diagnostics-same-crate.rs:62:8 | LL | #[cfg(i_dont_exist_and_you_can_do_nothing_about_it)] | -------------------------------------------- the item is gated here LL | pub fn vanished() {} | ^^^^^^^^ -error: aborting due to 7 previous errors +error: aborting due to 10 previous errors Some errors have detailed explanations: E0425, E0432, E0433. For more information about an error, try `rustc --explain E0425`. diff --git a/tests/ui/lint/self_type_conversion.rs b/tests/ui/lint/self_type_conversion.rs new file mode 100644 index 0000000000000..46f7307a97e66 --- /dev/null +++ b/tests/ui/lint/self_type_conversion.rs @@ -0,0 +1,81 @@ +#![deny(self_type_conversion)] +mod a { + mod foo { + cfg_select! { + any(target_arch = "avr", target_arch = "msp430") => { + pub type Int = i16; + } + _ => { + pub type Int = i32; + } + } + #[cfg(false)] + pub type Float = f32; + #[cfg(true)] + pub type Float = f64; + + pub type Trigger = u64; + } + + use self::foo::{Int, Float, Trigger}; + + pub fn bar() { + let x: Int = 1; + // Ok, should not lint because the type alias is behind a `cfg_select!` + let _: i32 = x.into(); + let y: Float = 1.; + // Ok, should not lint because the type alias is behind a `cfg` attr + let _: f64 = y.into(); + let z: Trigger = 1; + let _: u64 = z.into(); + //~^ ERROR useless conversion to the same type: `u64` + } +} + +mod b { + #[cfg(any(target_arch = "avr", target_arch = "msp430"))] + mod foo { + pub type Int = i16; + pub type Float = f32; + } + #[cfg(not(any(target_arch = "avr", target_arch = "msp430")))] + mod bar { + pub type Int = i32; + pub type Float = f64; + } + + mod qux { + pub type Trigger = u64; + } + + cfg_select! { + any(target_arch = "avr", target_arch = "msp430") => { + use self::foo::Int; + } + _ => { + use self::bar::Int; + } + } + + #[cfg(any(target_arch = "avr", target_arch = "msp430"))] + use self::foo::Float; + #[cfg(not(any(target_arch = "avr", target_arch = "msp430")))] + use self::bar::Float; + + use self::qux::Trigger; + + pub fn baz() { + let x: Int = 1; + let _: i32 = x.into(); // Ok, should not lint because the import is behind a `cfg_select!` + let y: Float = 1.; + let _: f64 = y.into(); // Ok, should not lint because the import is behind a `cfg` attr + let z: Trigger = 1; + let _: u64 = z.into(); + //~^ ERROR useless conversion to the same type: `u64` + } +} + +fn main() { + a::bar(); + b::baz(); +} diff --git a/tests/ui/lint/self_type_conversion.stderr b/tests/ui/lint/self_type_conversion.stderr new file mode 100644 index 0000000000000..8762a0bf22cba --- /dev/null +++ b/tests/ui/lint/self_type_conversion.stderr @@ -0,0 +1,25 @@ +error: useless conversion to the same type: `u64` + --> $DIR/self_type_conversion.rs:30:22 + | +LL | let _: u64 = z.into(); + | ^^^^^^^^ + | + = note: this method call relies on the `impl Into for T` blanket implementation and type inference, which is a semver hazard as a new `impl Into<_>` that affects your type might be added in the future causing type inference errors + = note: you can instead use the fully-qualified path `::into(val) to avoid triggering this lint +note: the lint level is defined here + --> $DIR/self_type_conversion.rs:1:9 + | +LL | #![deny(self_type_conversion)] + | ^^^^^^^^^^^^^^^^^^^^ + +error: useless conversion to the same type: `u64` + --> $DIR/self_type_conversion.rs:73:22 + | +LL | let _: u64 = z.into(); + | ^^^^^^^^ + | + = note: this method call relies on the `impl Into for T` blanket implementation and type inference, which is a semver hazard as a new `impl Into<_>` that affects your type might be added in the future causing type inference errors + = note: you can instead use the fully-qualified path `::into(val) to avoid triggering this lint + +error: aborting due to 2 previous errors + diff --git a/tests/ui/macros/macro-or-patterns-back-compat.fixed b/tests/ui/macros/macro-or-patterns-back-compat.fixed index 0321a36ae3b07..abb07549fd1a9 100644 --- a/tests/ui/macros/macro-or-patterns-back-compat.fixed +++ b/tests/ui/macros/macro-or-patterns-back-compat.fixed @@ -4,7 +4,7 @@ //@ reference: macro.decl.follow-set.edition2021 #![deny(rust_2021_incompatible_or_patterns)] -#![allow(unused_macros)] +#![allow(unused_macros, self_type_conversion)] #[macro_use] extern crate or_pattern; diff --git a/tests/ui/macros/macro-or-patterns-back-compat.rs b/tests/ui/macros/macro-or-patterns-back-compat.rs index 5d96ad456dc94..381b34eceb40c 100644 --- a/tests/ui/macros/macro-or-patterns-back-compat.rs +++ b/tests/ui/macros/macro-or-patterns-back-compat.rs @@ -4,7 +4,7 @@ //@ reference: macro.decl.follow-set.edition2021 #![deny(rust_2021_incompatible_or_patterns)] -#![allow(unused_macros)] +#![allow(unused_macros, self_type_conversion)] #[macro_use] extern crate or_pattern; diff --git a/tests/ui/macros/macro-pat-pattern-followed-by-or.rs b/tests/ui/macros/macro-pat-pattern-followed-by-or.rs index f5a56a7e8edda..953f8f7360955 100644 --- a/tests/ui/macros/macro-pat-pattern-followed-by-or.rs +++ b/tests/ui/macros/macro-pat-pattern-followed-by-or.rs @@ -2,7 +2,7 @@ //@ run-pass //@ reference: macro.decl.follow-set.token-pat //@ reference: macro.decl.follow-set.edition2021 -#![allow(unused_macros)] +#![allow(unused_macros, self_type_conversion)] macro_rules! foo { ($x:pat | $y:pat) => {} } // should be ok macro_rules! bar { ($($x:pat)+ | $($y:pat)+) => {} } // should be ok macro_rules! qux { ($x:pat, $y:pat) => {} } // should be ok diff --git a/tests/ui/traits/next-solver/closure-signature-inference-hr-ambig-alias-naming-self.rs b/tests/ui/traits/next-solver/closure-signature-inference-hr-ambig-alias-naming-self.rs index 25649d9290326..f04e2565f3ca2 100644 --- a/tests/ui/traits/next-solver/closure-signature-inference-hr-ambig-alias-naming-self.rs +++ b/tests/ui/traits/next-solver/closure-signature-inference-hr-ambig-alias-naming-self.rs @@ -1,6 +1,7 @@ //@ check-pass //@ revisions: current next //@[next] compile-flags: -Znext-solver +#![allow(self_type_conversion)] // When type checking a closure expr we look at the list of unsolved goals // to determine if there are any bounds on the closure type to infer a signature from. diff --git a/tests/ui/traits/next-solver/global-param-env-after-norm.rs b/tests/ui/traits/next-solver/global-param-env-after-norm.rs index 0d098db67d36d..f99a2004fd0fd 100644 --- a/tests/ui/traits/next-solver/global-param-env-after-norm.rs +++ b/tests/ui/traits/next-solver/global-param-env-after-norm.rs @@ -1,5 +1,6 @@ //@ check-pass //@ compile-flags: -Znext-solver +#![allow(self_type_conversion)] struct NewSolver; struct OldSolver; diff --git a/tests/ui/traits/next-solver/method/param-method-from-unnormalized-param-env.rs b/tests/ui/traits/next-solver/method/param-method-from-unnormalized-param-env.rs index dde4f745879e4..624303bde52a6 100644 --- a/tests/ui/traits/next-solver/method/param-method-from-unnormalized-param-env.rs +++ b/tests/ui/traits/next-solver/method/param-method-from-unnormalized-param-env.rs @@ -1,5 +1,6 @@ //@ check-pass //@ compile-flags: -Znext-solver +#![allow(self_type_conversion)] // Regression test for .