348 lines
7.7 KiB
Rust
348 lines
7.7 KiB
Rust
#![feature(closure_lifetime_binder)]
|
|
#![warn(clippy::explicit_auto_deref)]
|
|
#![allow(
|
|
dead_code,
|
|
unused_braces,
|
|
clippy::borrowed_box,
|
|
clippy::needless_borrow,
|
|
clippy::needless_return,
|
|
clippy::ptr_arg,
|
|
clippy::redundant_field_names,
|
|
clippy::too_many_arguments,
|
|
clippy::borrow_deref_ref,
|
|
clippy::let_unit_value
|
|
)]
|
|
|
|
trait CallableStr {
|
|
type T: Fn(&str);
|
|
fn callable_str(&self) -> Self::T;
|
|
}
|
|
impl CallableStr for () {
|
|
type T = fn(&str);
|
|
fn callable_str(&self) -> Self::T {
|
|
fn f(_: &str) {}
|
|
f
|
|
}
|
|
}
|
|
impl CallableStr for i32 {
|
|
type T = <() as CallableStr>::T;
|
|
fn callable_str(&self) -> Self::T {
|
|
().callable_str()
|
|
}
|
|
}
|
|
|
|
trait CallableT<U: ?Sized> {
|
|
type T: Fn(&U);
|
|
fn callable_t(&self) -> Self::T;
|
|
}
|
|
impl<U: ?Sized> CallableT<U> for () {
|
|
type T = fn(&U);
|
|
fn callable_t(&self) -> Self::T {
|
|
fn f<U: ?Sized>(_: &U) {}
|
|
f::<U>
|
|
}
|
|
}
|
|
impl<U: ?Sized> CallableT<U> for i32 {
|
|
type T = <() as CallableT<U>>::T;
|
|
fn callable_t(&self) -> Self::T {
|
|
().callable_t()
|
|
}
|
|
}
|
|
|
|
fn f_str(_: &str) {}
|
|
fn f_string(_: &String) {}
|
|
fn f_t<T>(_: T) {}
|
|
fn f_ref_t<T: ?Sized>(_: &T) {}
|
|
|
|
fn f_str_t<T>(_: &str, _: T) {}
|
|
|
|
fn f_box_t<T>(_: &Box<T>) {}
|
|
|
|
extern "C" {
|
|
fn var(_: u32, ...);
|
|
}
|
|
|
|
fn main() {
|
|
let s = String::new();
|
|
|
|
let _: &str = &s;
|
|
let _: &str = &{ String::new() };
|
|
let _: &str = &mut { String::new() };
|
|
let _ = &*s; // Don't lint. Inferred type would change.
|
|
let _: &_ = &*s; // Don't lint. Inferred type would change.
|
|
|
|
f_str(&s);
|
|
f_t(&*s); // Don't lint. Inferred type would change.
|
|
f_ref_t(&*s); // Don't lint. Inferred type would change.
|
|
|
|
f_str_t(&s, &*s); // Don't lint second param.
|
|
|
|
let b = Box::new(Box::new(Box::new(5)));
|
|
let _: &Box<i32> = &b;
|
|
let _: &Box<_> = &**b; // Don't lint. Inferred type would change.
|
|
|
|
f_box_t(&**b); // Don't lint. Inferred type would change.
|
|
|
|
let c = |_x: &str| ();
|
|
c(&s);
|
|
|
|
let c = |_x| ();
|
|
c(&*s); // Don't lint. Inferred type would change.
|
|
|
|
fn _f(x: &String) -> &str {
|
|
x
|
|
}
|
|
|
|
fn _f1(x: &String) -> &str {
|
|
{ x }
|
|
}
|
|
|
|
fn _f2(x: &String) -> &str {
|
|
{ x }
|
|
}
|
|
|
|
fn _f3(x: &Box<Box<Box<i32>>>) -> &Box<i32> {
|
|
x
|
|
}
|
|
|
|
fn _f4(
|
|
x: String,
|
|
f1: impl Fn(&str),
|
|
f2: &dyn Fn(&str),
|
|
f3: fn(&str),
|
|
f4: impl CallableStr,
|
|
f5: <() as CallableStr>::T,
|
|
f6: <i32 as CallableStr>::T,
|
|
f7: &dyn CallableStr<T = fn(&str)>,
|
|
f8: impl CallableT<str>,
|
|
f9: <() as CallableT<str>>::T,
|
|
f10: <i32 as CallableT<str>>::T,
|
|
f11: &dyn CallableT<str, T = fn(&str)>,
|
|
) {
|
|
f1(&x);
|
|
f2(&x);
|
|
f3(&x);
|
|
f4.callable_str()(&x);
|
|
f5(&x);
|
|
f6(&x);
|
|
f7.callable_str()(&x);
|
|
f8.callable_t()(&x);
|
|
f9(&x);
|
|
f10(&x);
|
|
f11.callable_t()(&x);
|
|
}
|
|
|
|
struct S1<'a>(&'a str);
|
|
let _ = S1(&s);
|
|
|
|
struct S2<'a> {
|
|
s: &'a str,
|
|
}
|
|
let _ = S2 { s: &s };
|
|
|
|
struct S3<'a, T: ?Sized>(&'a T);
|
|
let _ = S3(&*s); // Don't lint. Inferred type would change.
|
|
|
|
struct S4<'a, T: ?Sized> {
|
|
s: &'a T,
|
|
}
|
|
let _ = S4 { s: &*s }; // Don't lint. Inferred type would change.
|
|
|
|
enum E1<'a> {
|
|
S1(&'a str),
|
|
S2 { s: &'a str },
|
|
}
|
|
impl<'a> E1<'a> {
|
|
fn m1(s: &'a String) {
|
|
let _ = Self::S1(s);
|
|
let _ = Self::S2 { s: s };
|
|
}
|
|
}
|
|
let _ = E1::S1(&s);
|
|
let _ = E1::S2 { s: &s };
|
|
|
|
enum E2<'a, T: ?Sized> {
|
|
S1(&'a T),
|
|
S2 { s: &'a T },
|
|
}
|
|
let _ = E2::S1(&*s); // Don't lint. Inferred type would change.
|
|
let _ = E2::S2 { s: &*s }; // Don't lint. Inferred type would change.
|
|
|
|
let ref_s = &s;
|
|
let _: &String = &*ref_s; // Don't lint reborrow.
|
|
f_string(&*ref_s); // Don't lint reborrow.
|
|
|
|
struct S5 {
|
|
foo: u32,
|
|
}
|
|
let b = Box::new(Box::new(S5 { foo: 5 }));
|
|
let _ = b.foo;
|
|
let _ = b.foo;
|
|
let _ = b.foo;
|
|
|
|
struct S6 {
|
|
foo: S5,
|
|
}
|
|
impl core::ops::Deref for S6 {
|
|
type Target = S5;
|
|
fn deref(&self) -> &Self::Target {
|
|
&self.foo
|
|
}
|
|
}
|
|
let s6 = S6 { foo: S5 { foo: 5 } };
|
|
let _ = (*s6).foo; // Don't lint. `S6` also has a field named `foo`
|
|
|
|
let ref_str = &"foo";
|
|
let _ = f_str(ref_str);
|
|
let ref_ref_str = &ref_str;
|
|
let _ = f_str(ref_ref_str);
|
|
|
|
fn _f5(x: &u32) -> u32 {
|
|
if true {
|
|
*x
|
|
} else {
|
|
return *x;
|
|
}
|
|
}
|
|
|
|
f_str(&ref_str); // `needless_borrow` will suggest removing both references
|
|
f_str(&ref_str); // `needless_borrow` will suggest removing only one reference
|
|
|
|
let x = &&40;
|
|
unsafe {
|
|
var(0, &**x);
|
|
}
|
|
|
|
let s = &"str";
|
|
let _ = || return *s;
|
|
let _ = || -> &'static str { return s };
|
|
|
|
struct X;
|
|
struct Y(X);
|
|
impl core::ops::Deref for Y {
|
|
type Target = X;
|
|
fn deref(&self) -> &Self::Target {
|
|
&self.0
|
|
}
|
|
}
|
|
let _: &X = &*{ Y(X) };
|
|
let _: &X = &*match 0 {
|
|
#[rustfmt::skip]
|
|
0 => { Y(X) },
|
|
_ => panic!(),
|
|
};
|
|
let _: &X = &*if true { Y(X) } else { panic!() };
|
|
|
|
fn deref_to_u<U, T: core::ops::Deref<Target = U>>(x: &T) -> &U {
|
|
x
|
|
}
|
|
|
|
let _ = |x: &'static Box<dyn Iterator<Item = u32>>| -> &'static dyn Iterator<Item = u32> { &**x };
|
|
fn ret_any(x: &Box<dyn std::any::Any>) -> &dyn std::any::Any {
|
|
&**x
|
|
}
|
|
|
|
let x = String::new();
|
|
let _: *const str = &*x;
|
|
|
|
struct S7([u32; 1]);
|
|
impl core::ops::Deref for S7 {
|
|
type Target = [u32; 1];
|
|
fn deref(&self) -> &Self::Target {
|
|
&self.0
|
|
}
|
|
}
|
|
let x = S7([0]);
|
|
let _: &[u32] = &*x;
|
|
|
|
let c1 = |_: &Vec<&u32>| {};
|
|
let x = &&vec![&1u32];
|
|
c1(x);
|
|
let _ = for<'a, 'b> |x: &'a &'a Vec<&'b u32>, b: bool| -> &'a Vec<&'b u32> {
|
|
if b {
|
|
return x;
|
|
}
|
|
x
|
|
};
|
|
|
|
trait WithAssoc {
|
|
type Assoc: ?Sized;
|
|
fn to_assoc(&self) -> &Self::Assoc {
|
|
panic!()
|
|
}
|
|
}
|
|
impl WithAssoc for String {
|
|
type Assoc = str;
|
|
}
|
|
fn takes_assoc<T: WithAssoc>(_: &T::Assoc) -> T {
|
|
unimplemented!()
|
|
}
|
|
let _: String = takes_assoc(&*String::new());
|
|
|
|
// Issue #9901
|
|
fn takes_ref(_: &i32) {}
|
|
takes_ref(*Box::new(&0i32));
|
|
|
|
// Issue #10384
|
|
impl<'a> WithAssoc for &'a u32 {
|
|
type Assoc = dyn core::fmt::Display;
|
|
fn to_assoc(&self) -> &Self::Assoc {
|
|
*self
|
|
}
|
|
}
|
|
fn return_dyn_assoc<'a>(x: &'a &'a u32) -> &'a <&'a u32 as WithAssoc>::Assoc {
|
|
*x
|
|
}
|
|
|
|
// Issue #11366
|
|
let _: &mut u32 = match &mut Some(&mut 0u32) {
|
|
Some(x) => x,
|
|
None => panic!(),
|
|
};
|
|
|
|
// Issue #11474
|
|
#[derive(Clone, Copy)]
|
|
struct Wrap<T>(T);
|
|
impl<T> core::ops::Deref for Wrap<T> {
|
|
type Target = T;
|
|
fn deref(&self) -> &T {
|
|
&self.0
|
|
}
|
|
}
|
|
impl<T> core::ops::DerefMut for Wrap<T> {
|
|
fn deref_mut(&mut self) -> &mut T {
|
|
&mut self.0
|
|
}
|
|
}
|
|
|
|
union U<T: Copy> {
|
|
u: T,
|
|
}
|
|
|
|
#[derive(Clone, Copy)]
|
|
struct S8 {
|
|
x: &'static str,
|
|
}
|
|
|
|
unsafe {
|
|
let mut x = U {
|
|
u: core::mem::ManuallyDrop::new(S8 { x: "" }),
|
|
};
|
|
let _ = &mut (*x.u).x;
|
|
let _ = &mut { x.u }.x;
|
|
let _ = &mut ({ *x.u }).x;
|
|
|
|
let mut x = U {
|
|
u: Wrap(core::mem::ManuallyDrop::new(S8 { x: "" })),
|
|
};
|
|
let _ = &mut (*x.u).x;
|
|
let _ = &mut { x.u }.x;
|
|
let _ = &mut ({ **x.u }).x;
|
|
|
|
let mut x = U { u: Wrap(S8 { x: "" }) };
|
|
let _ = &mut x.u.x;
|
|
let _ = &mut { x.u }.x;
|
|
let _ = &mut ({ *x.u }).x;
|
|
}
|
|
}
|