Rollup merge of #92646 - mdibaiee:76935/pass-by-value, r=lcnr

feat: rustc_pass_by_value lint attribute

Useful for thin wrapper attributes that are best passed as value instead
of reference.

Fixes #76935
This commit is contained in:
Matthias Krüger 2022-01-16 16:58:15 +01:00 committed by GitHub
commit c5041f88ea
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 372 additions and 138 deletions

View file

@ -623,6 +623,11 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
lang, Normal, template!(NameValueStr: "name"), DuplicatesOk, lang_items,
"language items are subject to change",
),
rustc_attr!(
rustc_pass_by_value, Normal,
template!(Word), WarnFollowing,
"#[rustc_pass_by_value] is used to mark types that must be passed by value instead of reference."
),
BuiltinAttribute {
name: sym::rustc_diagnostic_item,
type_: Normal,

View file

@ -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};
@ -58,13 +55,6 @@ declare_tool_lint! {
report_in_external_macro: true
}
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,
@ -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();
})
}
}
_ => {}
}
}

View file

@ -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),
],

View file

@ -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()
}

View file

@ -961,6 +961,7 @@ pub struct FreeRegionInfo {
/// [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/ty.html
#[derive(Copy, Clone)]
#[rustc_diagnostic_item = "TyCtxt"]
#[cfg_attr(not(bootstrap), rustc_pass_by_value)]
pub struct TyCtxt<'tcx> {
gcx: &'tcx GlobalCtxt<'tcx>,
}

View file

@ -464,6 +464,7 @@ impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for TyS<'tcx> {
}
#[rustc_diagnostic_item = "Ty"]
#[cfg_attr(not(bootstrap), rustc_pass_by_value)]
pub type Ty<'tcx> = &'tcx TyS<'tcx>;
impl ty::EarlyBoundRegion {

View file

@ -114,6 +114,7 @@ impl CheckAttrVisitor<'_> {
}
sym::must_not_suspend => self.check_must_not_suspend(&attr, span, target),
sym::must_use => self.check_must_use(hir_id, &attr, span, target),
sym::rustc_pass_by_value => self.check_pass_by_value(&attr, span, target),
sym::rustc_const_unstable
| sym::rustc_const_stable
| sym::unstable
@ -1066,6 +1067,24 @@ impl CheckAttrVisitor<'_> {
is_valid
}
/// Warns against some misuses of `#[pass_by_value]`
fn check_pass_by_value(&self, attr: &Attribute, span: &Span, target: Target) -> bool {
match target {
Target::Struct | Target::Enum | Target::TyAlias => true,
_ => {
self.tcx
.sess
.struct_span_err(
attr.span,
"`pass_by_value` attribute should be applied to a struct, enum or type alias.",
)
.span_label(*span, "is not a struct, enum or type alias")
.emit();
false
}
}
}
/// Warns against some misuses of `#[must_use]`
fn check_must_use(
&self,

View file

@ -1170,6 +1170,7 @@ symbols! {
rustc_paren_sugar,
rustc_partition_codegened,
rustc_partition_reused,
rustc_pass_by_value,
rustc_peek,
rustc_peek_definite_init,
rustc_peek_liveness,

View file

@ -1,80 +0,0 @@
error: passing `Ty<'_>` by reference
--> $DIR/pass_ty_by_ref.rs:13:13
|
LL | ty_ref: &Ty<'_>,
| ^^^^^^^ help: try passing by value: `Ty<'_>`
|
note: the lint level is defined here
--> $DIR/pass_ty_by_ref.rs:4:9
|
LL | #![deny(rustc::ty_pass_by_reference)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: passing `TyCtxt<'_>` by reference
--> $DIR/pass_ty_by_ref.rs:15:18
|
LL | ty_ctxt_ref: &TyCtxt<'_>,
| ^^^^^^^^^^^ help: try passing by value: `TyCtxt<'_>`
error: passing `Ty<'_>` by reference
--> $DIR/pass_ty_by_ref.rs:19:28
|
LL | fn ty_multi_ref(ty_multi: &&Ty<'_>, ty_ctxt_multi: &&&&TyCtxt<'_>) {}
| ^^^^^^^ help: try passing by value: `Ty<'_>`
error: passing `TyCtxt<'_>` by reference
--> $DIR/pass_ty_by_ref.rs:19:55
|
LL | fn ty_multi_ref(ty_multi: &&Ty<'_>, ty_ctxt_multi: &&&&TyCtxt<'_>) {}
| ^^^^^^^^^^^ help: try passing by value: `TyCtxt<'_>`
error: passing `Ty<'_>` by reference
--> $DIR/pass_ty_by_ref.rs:26:17
|
LL | ty_ref: &Ty<'_>,
| ^^^^^^^ help: try passing by value: `Ty<'_>`
error: passing `TyCtxt<'_>` by reference
--> $DIR/pass_ty_by_ref.rs:28:22
|
LL | ty_ctxt_ref: &TyCtxt<'_>,
| ^^^^^^^^^^^ help: try passing by value: `TyCtxt<'_>`
error: passing `Ty<'_>` by reference
--> $DIR/pass_ty_by_ref.rs:31:41
|
LL | fn ty_multi_ref_in_trait(ty_multi: &&Ty<'_>, ty_ctxt_multi: &&&&TyCtxt<'_>);
| ^^^^^^^ help: try passing by value: `Ty<'_>`
error: passing `TyCtxt<'_>` by reference
--> $DIR/pass_ty_by_ref.rs:31:68
|
LL | fn ty_multi_ref_in_trait(ty_multi: &&Ty<'_>, ty_ctxt_multi: &&&&TyCtxt<'_>);
| ^^^^^^^^^^^ help: try passing by value: `TyCtxt<'_>`
error: passing `Ty<'_>` by reference
--> $DIR/pass_ty_by_ref.rs:53:17
|
LL | ty_ref: &Ty<'_>,
| ^^^^^^^ help: try passing by value: `Ty<'_>`
error: passing `TyCtxt<'_>` by reference
--> $DIR/pass_ty_by_ref.rs:55:22
|
LL | ty_ctxt_ref: &TyCtxt<'_>,
| ^^^^^^^^^^^ help: try passing by value: `TyCtxt<'_>`
error: passing `Ty<'_>` by reference
--> $DIR/pass_ty_by_ref.rs:59:38
|
LL | fn ty_multi_ref_assoc(ty_multi: &&Ty<'_>, ty_ctxt_multi: &&&&TyCtxt<'_>) {}
| ^^^^^^^ help: try passing by value: `Ty<'_>`
error: passing `TyCtxt<'_>` by reference
--> $DIR/pass_ty_by_ref.rs:59:65
|
LL | fn ty_multi_ref_assoc(ty_multi: &&Ty<'_>, ty_ctxt_multi: &&&&TyCtxt<'_>) {}
| ^^^^^^^^^^^ help: try passing by value: `TyCtxt<'_>`
error: aborting due to 12 previous errors

View file

@ -1,20 +0,0 @@
error: passing `TyCtxt<'tcx>` by reference
--> $DIR/pass_ty_by_ref_self.rs:18: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:8:9
|
LL | #![deny(rustc::ty_pass_by_reference)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: passing `Ty<'tcx>` by reference
--> $DIR/pass_ty_by_ref_self.rs:31:21
|
LL | fn by_ref(self: &Ty<'tcx>) {}
| ^^^^^^^^^ help: try passing by value: `Ty<'tcx>`
error: aborting due to 2 previous errors

View file

@ -1,7 +1,8 @@
// compile-flags: -Z unstable-options
#![feature(rustc_attrs)]
#![feature(rustc_private)]
#![deny(rustc::ty_pass_by_reference)]
#![deny(rustc::pass_by_value)]
#![allow(unused)]
extern crate rustc_middle;
@ -61,4 +62,57 @@ impl Foo {
//~^^ ERROR passing `TyCtxt<'_>` by reference
}
#[rustc_pass_by_value]
enum CustomEnum {
A,
B,
}
impl CustomEnum {
fn test(
value: CustomEnum,
reference: &CustomEnum, //~ ERROR passing `CustomEnum` by reference
) {
}
}
#[rustc_pass_by_value]
struct CustomStruct {
s: u8,
}
#[rustc_pass_by_value]
type CustomAlias<'a> = &'a CustomStruct; //~ ERROR passing `CustomStruct` by reference
impl CustomStruct {
fn test(
value: CustomStruct,
reference: &CustomStruct, //~ ERROR passing `CustomStruct` by reference
) {
}
fn test_alias(
value: CustomAlias,
reference: &CustomAlias, //~ ERROR passing `CustomAlias<>` by reference
) {
}
}
#[rustc_pass_by_value]
struct WithParameters<T, const N: usize, M = u32> {
slice: [T; N],
m: M,
}
impl<T> WithParameters<T, 1> {
fn test<'a>(
value: WithParameters<T, 1>,
reference: &'a WithParameters<T, 1>, //~ ERROR passing `WithParameters<T, 1>` by reference
reference_with_m: &WithParameters<T, 1, u32>, //~ ERROR passing `WithParameters<T, 1, u32>` by reference
) -> &'a WithParameters<T, 1> {
//~^ ERROR passing `WithParameters<T, 1>` by reference
reference as &WithParameters<_, 1> //~ ERROR passing `WithParameters<_, 1>` by reference
}
}
fn main() {}

View file

@ -0,0 +1,128 @@
error: passing `Ty<'_>` by reference
--> $DIR/rustc_pass_by_value.rs:14:13
|
LL | ty_ref: &Ty<'_>,
| ^^^^^^^ help: try passing by value: `Ty<'_>`
|
note: the lint level is defined here
--> $DIR/rustc_pass_by_value.rs:5:9
|
LL | #![deny(rustc::pass_by_value)]
| ^^^^^^^^^^^^^^^^^^^^
error: passing `TyCtxt<'_>` by reference
--> $DIR/rustc_pass_by_value.rs:16:18
|
LL | ty_ctxt_ref: &TyCtxt<'_>,
| ^^^^^^^^^^^ help: try passing by value: `TyCtxt<'_>`
error: passing `Ty<'_>` by reference
--> $DIR/rustc_pass_by_value.rs:20:28
|
LL | fn ty_multi_ref(ty_multi: &&Ty<'_>, ty_ctxt_multi: &&&&TyCtxt<'_>) {}
| ^^^^^^^ help: try passing by value: `Ty<'_>`
error: passing `TyCtxt<'_>` by reference
--> $DIR/rustc_pass_by_value.rs:20:55
|
LL | fn ty_multi_ref(ty_multi: &&Ty<'_>, ty_ctxt_multi: &&&&TyCtxt<'_>) {}
| ^^^^^^^^^^^ help: try passing by value: `TyCtxt<'_>`
error: passing `Ty<'_>` by reference
--> $DIR/rustc_pass_by_value.rs:27:17
|
LL | ty_ref: &Ty<'_>,
| ^^^^^^^ help: try passing by value: `Ty<'_>`
error: passing `TyCtxt<'_>` by reference
--> $DIR/rustc_pass_by_value.rs:29:22
|
LL | ty_ctxt_ref: &TyCtxt<'_>,
| ^^^^^^^^^^^ help: try passing by value: `TyCtxt<'_>`
error: passing `Ty<'_>` by reference
--> $DIR/rustc_pass_by_value.rs:32:41
|
LL | fn ty_multi_ref_in_trait(ty_multi: &&Ty<'_>, ty_ctxt_multi: &&&&TyCtxt<'_>);
| ^^^^^^^ help: try passing by value: `Ty<'_>`
error: passing `TyCtxt<'_>` by reference
--> $DIR/rustc_pass_by_value.rs:32:68
|
LL | fn ty_multi_ref_in_trait(ty_multi: &&Ty<'_>, ty_ctxt_multi: &&&&TyCtxt<'_>);
| ^^^^^^^^^^^ help: try passing by value: `TyCtxt<'_>`
error: passing `Ty<'_>` by reference
--> $DIR/rustc_pass_by_value.rs:54:17
|
LL | ty_ref: &Ty<'_>,
| ^^^^^^^ help: try passing by value: `Ty<'_>`
error: passing `TyCtxt<'_>` by reference
--> $DIR/rustc_pass_by_value.rs:56:22
|
LL | ty_ctxt_ref: &TyCtxt<'_>,
| ^^^^^^^^^^^ help: try passing by value: `TyCtxt<'_>`
error: passing `Ty<'_>` by reference
--> $DIR/rustc_pass_by_value.rs:60:38
|
LL | fn ty_multi_ref_assoc(ty_multi: &&Ty<'_>, ty_ctxt_multi: &&&&TyCtxt<'_>) {}
| ^^^^^^^ help: try passing by value: `Ty<'_>`
error: passing `TyCtxt<'_>` by reference
--> $DIR/rustc_pass_by_value.rs:60:65
|
LL | fn ty_multi_ref_assoc(ty_multi: &&Ty<'_>, ty_ctxt_multi: &&&&TyCtxt<'_>) {}
| ^^^^^^^^^^^ help: try passing by value: `TyCtxt<'_>`
error: passing `CustomEnum` by reference
--> $DIR/rustc_pass_by_value.rs:74:20
|
LL | reference: &CustomEnum,
| ^^^^^^^^^^^ help: try passing by value: `CustomEnum`
error: passing `CustomStruct` by reference
--> $DIR/rustc_pass_by_value.rs:85:24
|
LL | type CustomAlias<'a> = &'a CustomStruct;
| ^^^^^^^^^^^^^^^^ help: try passing by value: `CustomStruct`
error: passing `CustomStruct` by reference
--> $DIR/rustc_pass_by_value.rs:90:20
|
LL | reference: &CustomStruct,
| ^^^^^^^^^^^^^ help: try passing by value: `CustomStruct`
error: passing `CustomAlias<>` by reference
--> $DIR/rustc_pass_by_value.rs:96:20
|
LL | reference: &CustomAlias,
| ^^^^^^^^^^^^ help: try passing by value: `CustomAlias<>`
error: passing `WithParameters<T, 1>` by reference
--> $DIR/rustc_pass_by_value.rs:110:20
|
LL | reference: &'a WithParameters<T, 1>,
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: try passing by value: `WithParameters<T, 1>`
error: passing `WithParameters<T, 1, u32>` by reference
--> $DIR/rustc_pass_by_value.rs:111:27
|
LL | reference_with_m: &WithParameters<T, 1, u32>,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try passing by value: `WithParameters<T, 1, u32>`
error: passing `WithParameters<T, 1>` by reference
--> $DIR/rustc_pass_by_value.rs:112:10
|
LL | ) -> &'a WithParameters<T, 1> {
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: try passing by value: `WithParameters<T, 1>`
error: passing `WithParameters<_, 1>` by reference
--> $DIR/rustc_pass_by_value.rs:114:22
|
LL | reference as &WithParameters<_, 1>
| ^^^^^^^^^^^^^^^^^^^^^ help: try passing by value: `WithParameters<_, 1>`
error: aborting due to 20 previous errors

View file

@ -5,10 +5,10 @@
// 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)]
#![deny(rustc::pass_by_value)]
#![allow(unused)]
#[rustc_diagnostic_item = "TyCtxt"]
#[rustc_pass_by_value]
struct TyCtxt<'tcx> {
inner: &'tcx (),
}
@ -18,12 +18,11 @@ impl<'tcx> TyCtxt<'tcx> {
fn by_ref(&self) {} //~ ERROR passing `TyCtxt<'tcx>` by reference
}
struct TyS<'tcx> {
inner: &'tcx (),
}
#[rustc_diagnostic_item = "Ty"]
#[rustc_pass_by_value]
type Ty<'tcx> = &'tcx TyS<'tcx>;
impl<'tcx> TyS<'tcx> {
@ -31,4 +30,25 @@ impl<'tcx> TyS<'tcx> {
fn by_ref(self: &Ty<'tcx>) {} //~ ERROR passing `Ty<'tcx>` by reference
}
#[rustc_pass_by_value]
struct Foo;
impl Foo {
fn with_ref(&self) {} //~ ERROR passing `Foo` by reference
}
#[rustc_pass_by_value]
struct WithParameters<T, const N: usize, M = u32> {
slice: [T; N],
m: M,
}
impl<T> WithParameters<T, 1> {
fn with_ref(&self) {} //~ ERROR passing `WithParameters<T, 1_usize>` by reference
}
impl<T> WithParameters<T, 1, u8> {
fn with_ref(&self) {} //~ ERROR passing `WithParameters<T, 1_usize, u8>` by reference
}
fn main() {}

View file

@ -0,0 +1,38 @@
error: passing `TyCtxt<'tcx>` by reference
--> $DIR/rustc_pass_by_value_self.rs:18:15
|
LL | fn by_ref(&self) {}
| ^^^^^ help: try passing by value: `TyCtxt<'tcx>`
|
note: the lint level is defined here
--> $DIR/rustc_pass_by_value_self.rs:8:9
|
LL | #![deny(rustc::pass_by_value)]
| ^^^^^^^^^^^^^^^^^^^^
error: passing `Ty<'tcx>` by reference
--> $DIR/rustc_pass_by_value_self.rs:30:21
|
LL | fn by_ref(self: &Ty<'tcx>) {}
| ^^^^^^^^^ help: try passing by value: `Ty<'tcx>`
error: passing `Foo` by reference
--> $DIR/rustc_pass_by_value_self.rs:37:17
|
LL | fn with_ref(&self) {}
| ^^^^^ help: try passing by value: `Foo`
error: passing `WithParameters<T, 1_usize>` by reference
--> $DIR/rustc_pass_by_value_self.rs:47:17
|
LL | fn with_ref(&self) {}
| ^^^^^ help: try passing by value: `WithParameters<T, 1_usize>`
error: passing `WithParameters<T, 1_usize, u8>` by reference
--> $DIR/rustc_pass_by_value_self.rs:51:17
|
LL | fn with_ref(&self) {}
| ^^^^^ help: try passing by value: `WithParameters<T, 1_usize, u8>`
error: aborting due to 5 previous errors