diff options
| author | bors <bors@rust-lang.org> | 2022-01-16 17:22:57 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2022-01-16 17:22:57 +0000 |
| commit | bd3cb52565faab2755ff1bdb54d88bc91f47b4b9 (patch) | |
| tree | 62cae2960feaabe7d5bd0362032102cd48621b3d /compiler/rustc_lint/src | |
| parent | 48e89b00caa94829a5f07e0f1ecb33bf37431244 (diff) | |
| parent | 2b6b49e1d7f1d818b48dbbca11c49f672e25e6ca (diff) | |
| download | rust-bd3cb52565faab2755ff1bdb54d88bc91f47b4b9.tar.gz rust-bd3cb52565faab2755ff1bdb54d88bc91f47b4b9.zip | |
Auto merge of #92970 - matthiaskrgr:rollup-tcx7cfb, r=matthiaskrgr
Rollup of 10 pull requests
Successful merges:
- #92487 (Fix unclosed boxes in pretty printing of TraitAlias)
- #92581 (ARMv6K Horizon - Enable default libraries)
- #92619 (Add diagnostic items for macros)
- #92635 (rustdoc: Yet more intra-doc links cleanup)
- #92646 (feat: rustc_pass_by_value lint attribute)
- #92706 (Clarify explicitly that BTree{Map,Set} are ordered.)
- #92710 (Include Projections when elaborating TypeOutlives)
- #92746 (Parse `Ty?` as `Option<Ty>` and provide structured suggestion)
- #92792 (rustdoc: fix intra-link for generic trait impls)
- #92814 (remove unused FIXME)
Failed merges:
r? `@ghost`
`@rustbot` modify labels: rollup
Diffstat (limited to 'compiler/rustc_lint/src')
| -rw-r--r-- | compiler/rustc_lint/src/internal.rs | 33 | ||||
| -rw-r--r-- | compiler/rustc_lint/src/lib.rs | 6 | ||||
| -rw-r--r-- | compiler/rustc_lint/src/pass_by_value.rs | 94 |
3 files changed, 100 insertions, 33 deletions
diff --git a/compiler/rustc_lint/src/internal.rs b/compiler/rustc_lint/src/internal.rs index c64a67b6b9f..7353cd6b876 100644 --- a/compiler/rustc_lint/src/internal.rs +++ b/compiler/rustc_lint/src/internal.rs @@ -5,10 +5,7 @@ use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext} use rustc_ast as ast; use rustc_errors::Applicability; use rustc_hir::def::Res; -use rustc_hir::{ - GenericArg, HirId, Item, ItemKind, MutTy, Mutability, Node, Path, PathSegment, QPath, Ty, - TyKind, -}; +use rustc_hir::{GenericArg, HirId, Item, ItemKind, Node, Path, PathSegment, QPath, Ty, TyKind}; use rustc_middle::ty; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::hygiene::{ExpnKind, MacroKind}; @@ -59,13 +56,6 @@ declare_tool_lint! { } declare_tool_lint! { - pub rustc::TY_PASS_BY_REFERENCE, - Allow, - "passing `Ty` or `TyCtxt` by reference", - report_in_external_macro: true -} - -declare_tool_lint! { pub rustc::USAGE_OF_QUALIFIED_TY, Allow, "using `ty::{Ty,TyCtxt}` instead of importing it", @@ -74,7 +64,6 @@ declare_tool_lint! { declare_lint_pass!(TyTyKind => [ USAGE_OF_TY_TYKIND, - TY_PASS_BY_REFERENCE, USAGE_OF_QUALIFIED_TY, ]); @@ -131,26 +120,6 @@ impl<'tcx> LateLintPass<'tcx> for TyTyKind { } } } - TyKind::Rptr(_, MutTy { ty: inner_ty, mutbl: Mutability::Not }) => { - if let Some(impl_did) = cx.tcx.impl_of_method(ty.hir_id.owner.to_def_id()) { - if cx.tcx.impl_trait_ref(impl_did).is_some() { - return; - } - } - if let Some(t) = is_ty_or_ty_ctxt(cx, &inner_ty) { - cx.struct_span_lint(TY_PASS_BY_REFERENCE, ty.span, |lint| { - lint.build(&format!("passing `{}` by reference", t)) - .span_suggestion( - ty.span, - "try passing by value", - t, - // Changing type of function argument - Applicability::MaybeIncorrect, - ) - .emit(); - }) - } - } _ => {} } } diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index c6145ae0d51..4aa8505c940 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -56,6 +56,7 @@ mod non_ascii_idents; mod non_fmt_panic; mod nonstandard_style; mod noop_method_call; +mod pass_by_value; mod passes; mod redundant_semicolon; mod traits; @@ -85,6 +86,7 @@ use non_ascii_idents::*; use non_fmt_panic::NonPanicFmt; use nonstandard_style::*; use noop_method_call::*; +use pass_by_value::*; use redundant_semicolon::*; use traits::*; use types::*; @@ -490,6 +492,8 @@ fn register_internals(store: &mut LintStore) { store.register_late_pass(|| Box::new(ExistingDocKeyword)); store.register_lints(&TyTyKind::get_lints()); store.register_late_pass(|| Box::new(TyTyKind)); + store.register_lints(&PassByValue::get_lints()); + store.register_late_pass(|| Box::new(PassByValue)); store.register_group( false, "rustc::internal", @@ -497,8 +501,8 @@ fn register_internals(store: &mut LintStore) { vec![ LintId::of(DEFAULT_HASH_TYPES), LintId::of(USAGE_OF_TY_TYKIND), + LintId::of(PASS_BY_VALUE), LintId::of(LINT_PASS_IMPL_WITHOUT_MACRO), - LintId::of(TY_PASS_BY_REFERENCE), LintId::of(USAGE_OF_QUALIFIED_TY), LintId::of(EXISTING_DOC_KEYWORD), ], diff --git a/compiler/rustc_lint/src/pass_by_value.rs b/compiler/rustc_lint/src/pass_by_value.rs new file mode 100644 index 00000000000..26d0560bf89 --- /dev/null +++ b/compiler/rustc_lint/src/pass_by_value.rs @@ -0,0 +1,94 @@ +use crate::{LateContext, LateLintPass, LintContext}; +use rustc_errors::Applicability; +use rustc_hir as hir; +use rustc_hir::def::Res; +use rustc_hir::{GenericArg, PathSegment, QPath, TyKind}; +use rustc_middle::ty; +use rustc_span::symbol::sym; + +declare_tool_lint! { + /// The `rustc_pass_by_value` lint marks a type with `#[rustc_pass_by_value]` requiring it to always be passed by value. + /// This is usually used for types that are thin wrappers around references, so there is no benefit to an extra + /// layer of indirection. (Example: `Ty` which is a reference to a `TyS`) + pub rustc::PASS_BY_VALUE, + Warn, + "pass by reference of a type flagged as `#[rustc_pass_by_value]`", + report_in_external_macro: true +} + +declare_lint_pass!(PassByValue => [PASS_BY_VALUE]); + +impl<'tcx> LateLintPass<'tcx> for PassByValue { + fn check_ty(&mut self, cx: &LateContext<'_>, ty: &'tcx hir::Ty<'tcx>) { + match &ty.kind { + TyKind::Rptr(_, hir::MutTy { ty: inner_ty, mutbl: hir::Mutability::Not }) => { + if let Some(impl_did) = cx.tcx.impl_of_method(ty.hir_id.owner.to_def_id()) { + if cx.tcx.impl_trait_ref(impl_did).is_some() { + return; + } + } + if let Some(t) = path_for_pass_by_value(cx, &inner_ty) { + cx.struct_span_lint(PASS_BY_VALUE, ty.span, |lint| { + lint.build(&format!("passing `{}` by reference", t)) + .span_suggestion( + ty.span, + "try passing by value", + t, + // Changing type of function argument + Applicability::MaybeIncorrect, + ) + .emit(); + }) + } + } + _ => {} + } + } +} + +fn path_for_pass_by_value(cx: &LateContext<'_>, ty: &hir::Ty<'_>) -> Option<String> { + if let TyKind::Path(QPath::Resolved(_, path)) = &ty.kind { + match path.res { + Res::Def(_, def_id) if cx.tcx.has_attr(def_id, sym::rustc_pass_by_value) => { + let name = cx.tcx.item_name(def_id).to_ident_string(); + let path_segment = path.segments.last().unwrap(); + return Some(format!("{}{}", name, gen_args(cx, path_segment))); + } + Res::SelfTy(None, Some((did, _))) => { + if let ty::Adt(adt, substs) = cx.tcx.type_of(did).kind() { + if cx.tcx.has_attr(adt.did, sym::rustc_pass_by_value) { + return Some(cx.tcx.def_path_str_with_substs(adt.did, substs)); + } + } + } + _ => (), + } + } + + None +} + +fn gen_args(cx: &LateContext<'_>, segment: &PathSegment<'_>) -> String { + if let Some(args) = &segment.args { + let params = args + .args + .iter() + .map(|arg| match arg { + GenericArg::Lifetime(lt) => lt.name.ident().to_string(), + GenericArg::Type(ty) => { + cx.tcx.sess.source_map().span_to_snippet(ty.span).unwrap_or_default() + } + GenericArg::Const(c) => { + cx.tcx.sess.source_map().span_to_snippet(c.span).unwrap_or_default() + } + GenericArg::Infer(_) => String::from("_"), + }) + .collect::<Vec<_>>(); + + if !params.is_empty() { + return format!("<{}>", params.join(", ")); + } + } + + String::new() +} |
