diff --git a/compiler/rustc_lint/src/internal.rs b/compiler/rustc_lint/src/internal.rs index 100e555f299..c2d98b8e4ad 100644 --- a/compiler/rustc_lint/src/internal.rs +++ b/compiler/rustc_lint/src/internal.rs @@ -5,7 +5,9 @@ use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext} use rustc_ast::{Item, ItemKind}; use rustc_data_structures::fx::FxHashMap; use rustc_errors::Applicability; +use rustc_hir::def::Res; use rustc_hir::{GenericArg, HirId, MutTy, Mutability, Path, PathSegment, QPath, Ty, TyKind}; +use rustc_middle::ty; use rustc_session::{declare_lint_pass, declare_tool_lint, impl_lint_pass}; use rustc_span::hygiene::{ExpnKind, MacroKind}; use rustc_span::symbol::{sym, Ident, Symbol}; @@ -177,11 +179,31 @@ fn lint_ty_kind_usage(cx: &LateContext<'_>, segment: &PathSegment<'_>) -> bool { fn is_ty_or_ty_ctxt(cx: &LateContext<'_>, ty: &Ty<'_>) -> Option { if let TyKind::Path(qpath) = &ty.kind { if let QPath::Resolved(_, path) = qpath { - let did = path.res.opt_def_id()?; - if cx.tcx.is_diagnostic_item(sym::Ty, did) { - return Some(format!("Ty{}", gen_args(path.segments.last().unwrap()))); - } else if cx.tcx.is_diagnostic_item(sym::TyCtxt, did) { - return Some(format!("TyCtxt{}", gen_args(path.segments.last().unwrap()))); + match path.res { + Res::Def(_, did) => { + if cx.tcx.is_diagnostic_item(sym::Ty, did) { + return Some(format!("Ty{}", gen_args(path.segments.last().unwrap()))); + } else if cx.tcx.is_diagnostic_item(sym::TyCtxt, did) { + return Some(format!("TyCtxt{}", gen_args(path.segments.last().unwrap()))); + } + } + // Only lint on `&Ty` and `&TyCtxt` if it is used outside of a trait. + Res::SelfTy(None, Some((did, _))) => { + if let ty::Adt(adt, substs) = cx.tcx.type_of(did).kind() { + if cx.tcx.is_diagnostic_item(sym::Ty, adt.did) { + // NOTE: This path is currently unreachable as `Ty<'tcx>` is + // defined as a type alias meaning that `impl<'tcx> Ty<'tcx>` + // is not actually allowed. + // + // I(@lcnr) still kept this branch in so we don't miss this + // if we ever change it in the future. + return Some(format!("Ty<{}>", substs[0])); + } else if cx.tcx.is_diagnostic_item(sym::TyCtxt, adt.did) { + return Some(format!("TyCtxt<{}>", substs[0])); + } + } + } + _ => (), } } } diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index cd8f12a4f35..ccc8ffd9a9c 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -1179,7 +1179,7 @@ impl<'tcx> TyCtxt<'tcx> { self.mk_const(ty::Const { val: ty::ConstKind::Error(DelaySpanBugEmitted(())), ty }) } - pub fn consider_optimizing String>(&self, msg: T) -> bool { + pub fn consider_optimizing String>(self, msg: T) -> bool { let cname = self.crate_name(LOCAL_CRATE).as_str(); self.sess.consider_optimizing(&cname, msg) } diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs index 8a9d9830cc4..342a37cadba 100644 --- a/compiler/rustc_middle/src/ty/error.rs +++ b/compiler/rustc_middle/src/ty/error.rs @@ -850,7 +850,7 @@ fn foo(&self) -> Self::T { String::new() } /// Given a slice of `hir::GenericBound`s, if any of them corresponds to the `trait_ref` /// requirement, provide a strucuted suggestion to constrain it to a given type `ty`. fn constrain_generic_bound_associated_type_structured_suggestion( - &self, + self, db: &mut DiagnosticBuilder<'_>, trait_ref: &ty::TraitRef<'tcx>, bounds: hir::GenericBounds<'_>, @@ -874,7 +874,7 @@ fn foo(&self) -> Self::T { String::new() } /// Given a span corresponding to a bound, provide a structured suggestion to set an /// associated type to a given type `ty`. fn constrain_associated_type_structured_suggestion( - &self, + self, db: &mut DiagnosticBuilder<'_>, span: Span, assoc: &ty::AssocItem, diff --git a/src/test/ui-fulldeps/internal-lints/pass_ty_by_ref_self.rs b/src/test/ui-fulldeps/internal-lints/pass_ty_by_ref_self.rs new file mode 100644 index 00000000000..f58446d5592 --- /dev/null +++ b/src/test/ui-fulldeps/internal-lints/pass_ty_by_ref_self.rs @@ -0,0 +1,33 @@ +// NOTE: This test doesn't actually require `fulldeps` +// so we could instead use it as an `ui` test. +// +// Considering that all other `internal-lints` are tested here +// this seems like the cleaner solution though. +#![feature(rustc_attrs)] +#![deny(rustc::ty_pass_by_reference)] +#![allow(unused)] + +#[rustc_diagnostic_item = "TyCtxt"] +struct TyCtxt<'tcx> { + inner: &'tcx (), +} + +impl<'tcx> TyCtxt<'tcx> { + fn by_value(self) {} // OK + fn by_ref(&self) {} //~ ERROR passing `TyCtxt<'tcx>` by reference +} + + +struct TyS<'tcx> { + inner: &'tcx (), +} + +#[rustc_diagnostic_item = "Ty"] +type Ty<'tcx> = &'tcx TyS<'tcx>; + +impl<'tcx> TyS<'tcx> { + fn by_value(self: Ty<'tcx>) {} + fn by_ref(self: &Ty<'tcx>) {} //~ ERROR passing `Ty<'tcx>` by reference +} + +fn main() {} diff --git a/src/test/ui-fulldeps/internal-lints/pass_ty_by_ref_self.stderr b/src/test/ui-fulldeps/internal-lints/pass_ty_by_ref_self.stderr new file mode 100644 index 00000000000..b846b30f4ed --- /dev/null +++ b/src/test/ui-fulldeps/internal-lints/pass_ty_by_ref_self.stderr @@ -0,0 +1,20 @@ +error: passing `TyCtxt<'tcx>` by reference + --> $DIR/pass_ty_by_ref_self.rs:17:15 + | +LL | fn by_ref(&self) {} + | ^^^^^ help: try passing by value: `TyCtxt<'tcx>` + | +note: the lint level is defined here + --> $DIR/pass_ty_by_ref_self.rs:7:9 + | +LL | #![deny(rustc::ty_pass_by_reference)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: passing `Ty<'tcx>` by reference + --> $DIR/pass_ty_by_ref_self.rs:30:21 + | +LL | fn by_ref(self: &Ty<'tcx>) {} + | ^^^^^^^^^ help: try passing by value: `Ty<'tcx>` + +error: aborting due to 2 previous errors +