blob: 7531e1f87b71baa47b976cde1a9d31ea8b42170b [file] [log] [blame]
#![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) => &mut *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;
}
}