about summary refs log tree commit diff
path: root/compiler/rustc_lint/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2022-01-16 17:22:57 +0000
committerbors <bors@rust-lang.org>2022-01-16 17:22:57 +0000
commitbd3cb52565faab2755ff1bdb54d88bc91f47b4b9 (patch)
tree62cae2960feaabe7d5bd0362032102cd48621b3d /compiler/rustc_lint/src
parent48e89b00caa94829a5f07e0f1ecb33bf37431244 (diff)
parent2b6b49e1d7f1d818b48dbbca11c49f672e25e6ca (diff)
downloadrust-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.rs33
-rw-r--r--compiler/rustc_lint/src/lib.rs6
-rw-r--r--compiler/rustc_lint/src/pass_by_value.rs94
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()
+}