Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/ide-diagnostics/src/handlers/invalid_cast.rs')
| -rw-r--r-- | crates/ide-diagnostics/src/handlers/invalid_cast.rs | 1114 |
1 files changed, 1114 insertions, 0 deletions
diff --git a/crates/ide-diagnostics/src/handlers/invalid_cast.rs b/crates/ide-diagnostics/src/handlers/invalid_cast.rs new file mode 100644 index 0000000000..ad4baf5e3a --- /dev/null +++ b/crates/ide-diagnostics/src/handlers/invalid_cast.rs @@ -0,0 +1,1114 @@ +use hir::{CastError, ClosureStyle, HirDisplay}; + +use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext}; + +macro_rules! format_ty { + ($ctx:expr, $fmt:literal, $($arg:expr),* $(,)?) => {{ + std::format!( + $fmt, + $( + $arg + .display($ctx.sema.db, $ctx.edition) + .with_closure_style(ClosureStyle::ClosureWithId) + ),* + ) + }} +} + +// Diagnostic: invalid-cast +// +// This diagnostic is triggered if the code contains an illegal cast +pub(crate) fn invalid_cast(ctx: &DiagnosticsContext<'_>, d: &hir::InvalidCast) -> Diagnostic { + let display_range = ctx.sema.diagnostics_display_range(d.expr.map(|it| it.into())); + let (code, message) = match d.error { + CastError::CastToBool => ( + DiagnosticCode::RustcHardError("E0054"), + format_ty!(ctx, "cannot cast `{}` as `bool`", d.expr_ty), + ), + CastError::CastToChar => ( + DiagnosticCode::RustcHardError("E0604"), + format_ty!(ctx, "only `u8` can be cast as `char`, not {}", d.expr_ty), + ), + CastError::DifferingKinds => ( + DiagnosticCode::RustcHardError("E0606"), + format_ty!( + ctx, + "casting `{}` as `{}` is invalid: vtable kinds may not match", + d.expr_ty, + d.cast_ty + ), + ), + CastError::SizedUnsizedCast => ( + DiagnosticCode::RustcHardError("E0607"), + format_ty!( + ctx, + "cannot cast thin pointer `{}` to fat pointer `{}`", + d.expr_ty, + d.cast_ty + ), + ), + CastError::Unknown | CastError::IllegalCast => ( + DiagnosticCode::RustcHardError("E0606"), + format_ty!(ctx, "casting `{}` as `{}` is invalid", d.expr_ty, d.cast_ty), + ), + CastError::IntToFatCast => ( + DiagnosticCode::RustcHardError("E0606"), + format_ty!(ctx, "cannot cast `{}` to a fat pointer `{}`", d.expr_ty, d.cast_ty), + ), + CastError::NeedDeref => ( + DiagnosticCode::RustcHardError("E0606"), + format_ty!( + ctx, + "casting `{}` as `{}` is invalid: needs defererence or removal of unneeded borrow", + d.expr_ty, + d.cast_ty + ), + ), + CastError::NeedViaPtr => ( + DiagnosticCode::RustcHardError("E0606"), + format_ty!( + ctx, + "casting `{}` as `{}` is invalid: needs casting through a raw pointer first", + d.expr_ty, + d.cast_ty + ), + ), + CastError::NeedViaThinPtr => ( + DiagnosticCode::RustcHardError("E0606"), + format_ty!( + ctx, + "casting `{}` as `{}` is invalid: needs casting through a thin pointer first", + d.expr_ty, + d.cast_ty + ), + ), + CastError::NeedViaInt => ( + DiagnosticCode::RustcHardError("E0606"), + format_ty!( + ctx, + "casting `{}` as `{}` is invalid: needs casting through an integer first", + d.expr_ty, + d.cast_ty + ), + ), + CastError::NonScalar => ( + DiagnosticCode::RustcHardError("E0605"), + format_ty!(ctx, "non-primitive cast: `{}` as `{}`", d.expr_ty, d.cast_ty), + ), + CastError::UnknownCastPtrKind | CastError::UnknownExprPtrKind => ( + DiagnosticCode::RustcHardError("E0641"), + "cannot cast to a pointer of an unknown kind".to_owned(), + ), + }; + Diagnostic::new(code, message, display_range) +} + +// Diagnostic: cast-to-unsized +// +// This diagnostic is triggered when casting to an unsized type +pub(crate) fn cast_to_unsized(ctx: &DiagnosticsContext<'_>, d: &hir::CastToUnsized) -> Diagnostic { + let display_range = ctx.sema.diagnostics_display_range(d.expr.map(|it| it.into())); + Diagnostic::new( + DiagnosticCode::RustcHardError("E0620"), + format_ty!(ctx, "cast to unsized type: `{}`", d.cast_ty), + display_range, + ) +} + +#[cfg(test)] +mod tests { + use crate::tests::{check_diagnostics, check_diagnostics_with_disabled}; + + #[test] + fn cast_as_bool() { + check_diagnostics( + r#" +//- minicore: sized +fn main() { + let u = 5 as bool; + //^^^^^^^^^ error: cannot cast `i32` as `bool` + + let t = (1 + 2) as bool; + //^^^^^^^^^^^^^^^ error: cannot cast `i32` as `bool` + + let _ = 5_u32 as bool; + //^^^^^^^^^^^^^ error: cannot cast `u32` as `bool` + + let _ = 64.0_f64 as bool; + //^^^^^^^^^^^^^^^^ error: cannot cast `f64` as `bool` + + enum IntEnum { + Zero, + One, + Two + } + let _ = IntEnum::One as bool; + //^^^^^^^^^^^^^^^^^^^^ error: cannot cast `IntEnum` as `bool` + + fn uwu(_: u8) -> i32 { + 5 + } + + unsafe fn owo() {} + + let _ = uwu as bool; + //^^^^^^^^^^^ error: cannot cast `fn uwu(u8) -> i32` as `bool` + let _ = owo as bool; + //^^^^^^^^^^^ error: cannot cast `unsafe fn owo()` as `bool` + + let _ = uwu as fn(u8) -> i32 as bool; + //^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: cannot cast `fn(u8) -> i32` as `bool` + let _ = 'x' as bool; + //^^^^^^^^^^^ error: cannot cast `char` as `bool` + + let ptr = 1 as *const (); + + let _ = ptr as bool; + //^^^^^^^^^^^ error: cannot cast `*const ()` as `bool` + let v = "hello" as bool; + //^^^^^^^^^^^^^^^ error: casting `&str` as `bool` is invalid: needs casting through a raw pointer first +} +"#, + ); + } + + #[test] + fn cast_pointee_projection() { + check_diagnostics( + r#" +//- minicore: sized +trait Tag<'a> { + type Type: ?Sized; +} + +trait IntoRaw: for<'a> Tag<'a> { + fn into_raw(this: *const <Self as Tag<'_>>::Type) -> *mut <Self as Tag<'_>>::Type; +} + +impl<T: for<'a> Tag<'a>> IntoRaw for T { + fn into_raw(this: *const <Self as Tag<'_>>::Type) -> *mut <Self as Tag<'_>>::Type { + this as *mut T::Type + } +} + +fn main() {} +"#, + ); + } + + #[test] + fn cast_region_to_int() { + check_diagnostics( + r#" +//- minicore: sized +fn main() { + let x: isize = 3; + let _ = &x as *const isize as usize; +} +"#, + ); + } + + #[test] + fn cast_to_bare_fn() { + check_diagnostics( + r#" +//- minicore: sized +fn foo(_x: isize) { } + +fn main() { + let v: u64 = 5; + let x = foo as extern "C" fn() -> isize; + //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: non-primitive cast: `fn foo(isize)` as `fn() -> isize` + let y = v as extern "Rust" fn(isize) -> (isize, isize); + //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: non-primitive cast: `u64` as `fn(isize) -> (isize, isize)` + y(x()); +} +"#, + ); + } + + #[test] + fn cast_to_unit() { + check_diagnostics( + r#" +//- minicore: sized +fn main() { + let _ = 0u32 as (); + //^^^^^^^^^^ error: non-primitive cast: `u32` as `()` +} +"#, + ); + } + + #[test] + fn cast_to_slice() { + check_diagnostics_with_disabled( + r#" +//- minicore: sized +fn as_bytes(_: &str) -> &[u8] { + loop {} +} + +fn main() { + as_bytes("example") as [char]; + //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: cast to unsized type: `[char]` + + let arr: &[u8] = &[0, 2, 3]; + arr as [char]; + //^^^^^^^^^^^^^ error: cast to unsized type: `[char]` +} +"#, + &["E0308"], + ); + } + + #[test] + fn cast() { + check_diagnostics( + r#" +//- minicore: sized +fn null_mut<T: ?Sized>() -> *mut T { + loop {} +} + +pub fn main() { + let i: isize = 'Q' as isize; + let _u: u32 = i as u32; + + // Test that `_` is correctly inferred. + let x = &"hello"; + let mut y = x as *const _; + y = null_mut(); +} +"#, + ); + } + + #[test] + fn dyn_tail_need_normalization() { + check_diagnostics( + r#" +//- minicore: dispatch_from_dyn +trait Trait { + type Associated; +} + +impl Trait for i32 { + type Associated = i64; +} + +trait Generic<T> {} + +type TraitObject = dyn Generic<<i32 as Trait>::Associated>; + +struct Wrap(TraitObject); + +fn cast(x: *mut TraitObject) { + x as *mut Wrap; +} +"#, + ); + } + + #[test] + fn enum_to_numeric_cast() { + check_diagnostics( + r#" +//- minicore: sized +pub enum UnitOnly { + Foo, + Bar, + Baz, +} + +pub enum Fieldless { + Tuple(), + Struct{}, + Unit, +} + +pub enum NotUnitOnlyOrFieldless { + Foo, + Bar(u8), + Baz +} + +fn main() { + let unit_only = UnitOnly::Foo; + + let _ = unit_only as isize; + let _ = unit_only as i32; + let _ = unit_only as usize; + let _ = unit_only as u32; + + + let fieldless = Fieldless::Struct{}; + + let _ = fieldless as isize; + let _ = fieldless as i32; + let _ = fieldless as usize; + let _ = fieldless as u32; + + + let not_unit_only_or_fieldless = NotUnitOnlyOrFieldless::Foo; + + let _ = not_unit_only_or_fieldless as isize; + //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: non-primitive cast: `NotUnitOnlyOrFieldless` as `isize` + let _ = not_unit_only_or_fieldless as i32; + //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: non-primitive cast: `NotUnitOnlyOrFieldless` as `i32` + let _ = not_unit_only_or_fieldless as usize; + //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: non-primitive cast: `NotUnitOnlyOrFieldless` as `usize` + let _ = not_unit_only_or_fieldless as u32; + //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: non-primitive cast: `NotUnitOnlyOrFieldless` as `u32` +} +"#, + ); + } + + #[test] + fn fat_ptr_cast() { + check_diagnostics_with_disabled( + r#" +//- minicore: sized +trait Foo { + fn foo(&self) {} //~ WARN method `foo` is never used +} + +struct Bar; + +impl Foo for Bar {} + +fn to_raw<T>(_: *mut T) -> *mut () { + loop {} +} + +fn main() { + // Test we can turn a fat pointer to array back into a thin pointer. + let a: *const [i32] = &[1, 2, 3]; + let b = a as *const [i32; 2]; + + // Test conversion to an address (usize). + let a: *const [i32; 3] = &[1, 2, 3]; + let b: *const [i32] = a; + + // And conversion to a void pointer/address for trait objects too. + let a: *mut dyn Foo = &mut Bar; + let b = a as *mut () as usize; + let c = a as *const () as usize; + let d = to_raw(a) as usize; +} +"#, + &["E0308"], + ); + + check_diagnostics_with_disabled( + r#" +//- minicore: sized +trait Trait {} + +struct Box<T: ?Sized>; + +impl<T: ?Sized> Box<T> { + fn new(_: T) -> Self { + loop {} + } +} + +fn as_ptr(_: &[i32]) -> *const i32 { + loop {} +} + +fn main() { + let a: &[i32] = &[1, 2, 3]; + let b: Box<[i32]> = Box::new([1, 2, 3]); + let p = a as *const [i32]; + let q = as_ptr(a); + + a as usize; + //^^^^^^^^^^ error: casting `&[i32]` as `usize` is invalid: needs casting through a raw pointer first + a as isize; + //^^^^^^^^^^ error: casting `&[i32]` as `isize` is invalid: needs casting through a raw pointer first + a as i16; + //^^^^^^^^ error: casting `&[i32]` as `i16` is invalid: needs casting through a raw pointer first + a as u32; + //^^^^^^^^ error: casting `&[i32]` as `u32` is invalid: needs casting through a raw pointer first + b as usize; + //^^^^^^^^^^ error: non-primitive cast: `Box<[i32]>` as `usize` + p as usize; + //^^^^^^^^^^ error: casting `*const [i32]` as `usize` is invalid: needs casting through a thin pointer first + q as *const [i32]; + //^^^^^^^^^^^^^^^^^ error: cannot cast thin pointer `*const i32` to fat pointer `*const [i32]` + + let t: *mut (dyn Trait + 'static) = 0 as *mut _; + //^^^^^^^^^^^ error: cannot cast `usize` to a fat pointer `*mut _` + let mut fail: *const str = 0 as *const str; + //^^^^^^^^^^^^^^^ error: cannot cast `usize` to a fat pointer `*const str` + let mut fail2: *const str = 0isize as *const str; + //^^^^^^^^^^^^^^^^^^^^ error: cannot cast `isize` to a fat pointer `*const str` +} + +fn foo<T: ?Sized>() { + let s = 0 as *const T; + //^^^^^^^^^^^^^ error: cannot cast `usize` to a fat pointer `*const T` +} +"#, + &["E0308", "unused_variables"], + ); + } + + #[test] + fn order_dependent_cast_inference() { + check_diagnostics( + r#" +//- minicore: sized +fn main() { + let x = &"hello"; + let mut y = 0 as *const _; + //^^^^^^^^^^^^^ error: cannot cast to a pointer of an unknown kind + y = x as *const _; +} +"#, + ); + } + + #[test] + fn ptr_to_ptr_different_regions() { + check_diagnostics( + r#" +//- minicore: sized +struct Foo<'a> { a: &'a () } + +fn extend_lifetime_very_very_safely<'a>(v: *const Foo<'a>) -> *const Foo<'static> { + // This should pass because raw pointer casts can do anything they want. + v as *const Foo<'static> +} + +trait Trait {} + +fn assert_static<'a>(ptr: *mut (dyn Trait + 'a)) -> *mut (dyn Trait + 'static) { + ptr as _ +} + +fn main() { + let unit = (); + let foo = Foo { a: &unit }; + let _long: *const Foo<'static> = extend_lifetime_very_very_safely(&foo); +} +"#, + ); + } + + #[test] + fn ptr_to_trait_obj_add_auto() { + check_diagnostics( + r#" +//- minicore: pointee +trait Trait<'a> {} + +fn add_auto<'a>(x: *mut dyn Trait<'a>) -> *mut (dyn Trait<'a> + Send) { + x as _ +} + +// (to test diagnostic list formatting) +fn add_multiple_auto<'a>(x: *mut dyn Trait<'a>) -> *mut (dyn Trait<'a> + Send + Sync + Unpin) { + x as _ +} +"#, + ); + } + + #[test] + fn ptr_to_trait_obj_add_super_auto() { + check_diagnostics( + r#" +//- minicore: pointee +trait Trait: Send {} +impl Trait for () {} + +fn main() { + // This is OK: `Trait` has `Send` super trait. + &() as *const dyn Trait as *const (dyn Trait + Send); +} +"#, + ); + } + + #[test] + fn ptr_to_trait_obj_ok() { + check_diagnostics( + r#" +//- minicore: pointee +trait Trait<'a> {} + +fn remove_auto<'a>(x: *mut (dyn Trait<'a> + Send)) -> *mut dyn Trait<'a> { + x as _ +} + +fn cast_inherent_lt<'a, 'b>(x: *mut (dyn Trait<'static> + 'a)) -> *mut (dyn Trait<'static> + 'b) { + x as _ +} + +fn unprincipled<'a, 'b>(x: *mut (dyn Send + 'a)) -> *mut (dyn Sync + 'b) { + x as _ +} +"#, + ); + } + + #[ignore = "issue #18047"] + #[test] + fn ptr_to_trait_obj_wrap_upcast() { + check_diagnostics( + r#" +//- minicore: sized +trait Super {} +trait Sub: Super {} + +struct Wrapper<T: ?Sized>(T); + +// This cast should not compile. +// Upcasting can't work here, because we are also changing the type (`Wrapper`), +// and reinterpreting would be confusing/surprising. +// See <https://github.com/rust-lang/rust/pull/120248#discussion_r1487739518> +fn cast(ptr: *const dyn Sub) -> *const Wrapper<dyn Super> { + ptr as _ + //^^^^^^^^ error: casting `*const dyn Sub` as `*const Wrapper<dyn Super>` is invalid: vtable kinds may not match +} +"#, + ); + } + + #[test] + fn supported_cast() { + check_diagnostics( + r#" +//- minicore: sized +pub fn main() { + struct String; + + let f = 1_usize as *const String; + + let _ = f as isize; + let _ = f as usize; + let _ = f as i8; + let _ = f as i16; + let _ = f as i32; + let _ = f as i64; + let _ = f as u8; + let _ = f as u16; + let _ = f as u32; + let _ = f as u64; + + let _ = 1 as isize; + let _ = 1 as usize; + let _ = 1 as *const String; + let _ = 1 as i8; + let _ = 1 as i16; + let _ = 1 as i32; + let _ = 1 as i64; + let _ = 1 as u8; + let _ = 1 as u16; + let _ = 1 as u32; + let _ = 1 as u64; + let _ = 1 as f32; + let _ = 1 as f64; + + let _ = 1_usize as isize; + let _ = 1_usize as usize; + let _ = 1_usize as *const String; + let _ = 1_usize as i8; + let _ = 1_usize as i16; + let _ = 1_usize as i32; + let _ = 1_usize as i64; + let _ = 1_usize as u8; + let _ = 1_usize as u16; + let _ = 1_usize as u32; + let _ = 1_usize as u64; + let _ = 1_usize as f32; + let _ = 1_usize as f64; + + let _ = 1i8 as isize; + let _ = 1i8 as usize; + let _ = 1i8 as *const String; + let _ = 1i8 as i8; + let _ = 1i8 as i16; + let _ = 1i8 as i32; + let _ = 1i8 as i64; + let _ = 1i8 as u8; + let _ = 1i8 as u16; + let _ = 1i8 as u32; + let _ = 1i8 as u64; + let _ = 1i8 as f32; + let _ = 1i8 as f64; + + let _ = 1u8 as isize; + let _ = 1u8 as usize; + let _ = 1u8 as *const String; + let _ = 1u8 as i8; + let _ = 1u8 as i16; + let _ = 1u8 as i32; + let _ = 1u8 as i64; + let _ = 1u8 as u8; + let _ = 1u8 as u16; + let _ = 1u8 as u32; + let _ = 1u8 as u64; + let _ = 1u8 as f32; + let _ = 1u8 as f64; + + let _ = 1i16 as isize; + let _ = 1i16 as usize; + let _ = 1i16 as *const String; + let _ = 1i16 as i8; + let _ = 1i16 as i16; + let _ = 1i16 as i32; + let _ = 1i16 as i64; + let _ = 1i16 as u8; + let _ = 1i16 as u16; + let _ = 1i16 as u32; + let _ = 1i16 as u64; + let _ = 1i16 as f32; + let _ = 1i16 as f64; + + let _ = 1u16 as isize; + let _ = 1u16 as usize; + let _ = 1u16 as *const String; + let _ = 1u16 as i8; + let _ = 1u16 as i16; + let _ = 1u16 as i32; + let _ = 1u16 as i64; + let _ = 1u16 as u8; + let _ = 1u16 as u16; + let _ = 1u16 as u32; + let _ = 1u16 as u64; + let _ = 1u16 as f32; + let _ = 1u16 as f64; + + let _ = 1i32 as isize; + let _ = 1i32 as usize; + let _ = 1i32 as *const String; + let _ = 1i32 as i8; + let _ = 1i32 as i16; + let _ = 1i32 as i32; + let _ = 1i32 as i64; + let _ = 1i32 as u8; + let _ = 1i32 as u16; + let _ = 1i32 as u32; + let _ = 1i32 as u64; + let _ = 1i32 as f32; + let _ = 1i32 as f64; + + let _ = 1u32 as isize; + let _ = 1u32 as usize; + let _ = 1u32 as *const String; + let _ = 1u32 as i8; + let _ = 1u32 as i16; + let _ = 1u32 as i32; + let _ = 1u32 as i64; + let _ = 1u32 as u8; + let _ = 1u32 as u16; + let _ = 1u32 as u32; + let _ = 1u32 as u64; + let _ = 1u32 as f32; + let _ = 1u32 as f64; + + let _ = 1i64 as isize; + let _ = 1i64 as usize; + let _ = 1i64 as *const String; + let _ = 1i64 as i8; + let _ = 1i64 as i16; + let _ = 1i64 as i32; + let _ = 1i64 as i64; + let _ = 1i64 as u8; + let _ = 1i64 as u16; + let _ = 1i64 as u32; + let _ = 1i64 as u64; + let _ = 1i64 as f32; + let _ = 1i64 as f64; + + let _ = 1u64 as isize; + let _ = 1u64 as usize; + let _ = 1u64 as *const String; + let _ = 1u64 as i8; + let _ = 1u64 as i16; + let _ = 1u64 as i32; + let _ = 1u64 as i64; + let _ = 1u64 as u8; + let _ = 1u64 as u16; + let _ = 1u64 as u32; + let _ = 1u64 as u64; + let _ = 1u64 as f32; + let _ = 1u64 as f64; + + let _ = 1u64 as isize; + let _ = 1u64 as usize; + let _ = 1u64 as *const String; + let _ = 1u64 as i8; + let _ = 1u64 as i16; + let _ = 1u64 as i32; + let _ = 1u64 as i64; + let _ = 1u64 as u8; + let _ = 1u64 as u16; + let _ = 1u64 as u32; + let _ = 1u64 as u64; + let _ = 1u64 as f32; + let _ = 1u64 as f64; + + let _ = true as isize; + let _ = true as usize; + let _ = true as i8; + let _ = true as i16; + let _ = true as i32; + let _ = true as i64; + let _ = true as u8; + let _ = true as u16; + let _ = true as u32; + let _ = true as u64; + + let _ = 1f32 as isize; + let _ = 1f32 as usize; + let _ = 1f32 as i8; + let _ = 1f32 as i16; + let _ = 1f32 as i32; + let _ = 1f32 as i64; + let _ = 1f32 as u8; + let _ = 1f32 as u16; + let _ = 1f32 as u32; + let _ = 1f32 as u64; + let _ = 1f32 as f32; + let _ = 1f32 as f64; + + let _ = 1f64 as isize; + let _ = 1f64 as usize; + let _ = 1f64 as i8; + let _ = 1f64 as i16; + let _ = 1f64 as i32; + let _ = 1f64 as i64; + let _ = 1f64 as u8; + let _ = 1f64 as u16; + let _ = 1f64 as u32; + let _ = 1f64 as u64; + let _ = 1f64 as f32; + let _ = 1f64 as f64; +} +"#, + ); + } + + #[test] + fn unsized_struct_cast() { + check_diagnostics( + r#" +//- minicore: sized +pub struct Data([u8]); + +fn foo(x: &[u8]) { + let _: *const Data = x as *const Data; + //^^^^^^^^^^^^^^^^ error: casting `&[u8]` as `*const Data` is invalid +} +"#, + ); + } + + #[test] + fn unsupported_cast() { + check_diagnostics( + r#" +//- minicore: sized +struct A; + +fn main() { + let _ = 1.0 as *const A; + //^^^^^^^^^^^^^^^ error: casting `f64` as `*const A` is invalid +} +"#, + ); + } + + #[test] + fn issue_17897() { + check_diagnostics( + r#" +//- minicore: sized +fn main() { + _ = ((), ()) as (); + //^^^^^^^^^^^^^^ error: non-primitive cast: `((), ())` as `()` +} +"#, + ); + } + + #[test] + fn rustc_issue_10991() { + check_diagnostics( + r#" +//- minicore: sized +fn main() { + let nil = (); + let _t = nil as usize; + //^^^^^^^^^^^^ error: non-primitive cast: `()` as `usize` +} +"#, + ); + } + + #[test] + fn rustc_issue_17444() { + check_diagnostics( + r#" +//- minicore: sized +enum Test { + Foo = 0 +} + +fn main() { + let _x = Test::Foo as *const isize; + //^^^^^^^^^^^^^^^^^^^^^^^^^ error: casting `Test` as `*const isize` is invalid +} +"#, + ); + } + + #[test] + fn rustc_issue_43825() { + check_diagnostics( + r#" +//- minicore: sized +fn main() { + let error = error; + //^^^^^ error: no such value in this scope + + 0 as f32; + 0.0 as u32; +} +"#, + ); + } + + #[test] + fn rustc_issue_84213() { + check_diagnostics( + r#" +//- minicore: sized +struct Something { + pub field: u32, +} + +fn main() { + let mut something = Something { field: 1337 }; + let _ = something.field; + + let _pointer_to_something = something as *const Something; + //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: non-primitive cast: `Something` as `*const Something` + + let _mut_pointer_to_something = something as *mut Something; + //^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: non-primitive cast: `Something` as `*mut Something` +} +"#, + ); + + // Fixed + check_diagnostics( + r#" +//- minicore: sized +struct Something { + pub field: u32, +} + +fn main() { + let mut something = Something { field: 1337 }; + let _ = something.field; + + let _pointer_to_something = &something as *const Something; + + let _mut_pointer_to_something = &mut something as *mut Something; +} +"#, + ); + } + + #[test] + fn rustc_issue_88621() { + check_diagnostics( + r#" +//- minicore: sized +#[repr(u8)] +enum Kind2 { + Foo() = 1, + Bar{} = 2, + Baz = 3, +} + +fn main() { + let _ = Kind2::Foo() as u8; + //^^^^^^^^^^^^^^^^^^ error: non-primitive cast: `Kind2` as `u8` +} +"#, + ); + } + + #[test] + fn rustc_issue_89497() { + check_diagnostics( + r#" +//- minicore: sized +fn main() { + let pointer: usize = &1_i32 as *const i32 as usize; + let _reference: &'static i32 = unsafe { pointer as *const i32 as &'static i32 }; + //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: non-primitive cast: `*const i32` as `&i32` +} +"#, + ); + + // Fixed + check_diagnostics( + r#" +//- minicore: sized +fn main() { + let pointer: usize = &1_i32 as *const i32 as usize; + let _reference: &'static i32 = unsafe { &*(pointer as *const i32) }; +} +"#, + ); + } + + #[test] + fn rustc_issue_106883() { + check_diagnostics_with_disabled( + r#" +//- minicore: sized, deref +use core::ops::Deref; + +struct Foo; + +impl Deref for Foo { + type Target = [u8]; + + fn deref(&self) -> &Self::Target { + &[] + } +} + +fn main() { + let _ = "foo" as bool; + //^^^^^^^^^^^^^ error: casting `&str` as `bool` is invalid: needs casting through a raw pointer first + + let _ = Foo as bool; + //^^^^^^^^^^^ error: non-primitive cast: `Foo` as `bool` +} + +fn _slice(bar: &[i32]) -> bool { + bar as bool + //^^^^^^^^^^^ error: casting `&[i32]` as `bool` is invalid: needs casting through a raw pointer first +} +"#, + &["E0308"], + ); + } + + #[test] + fn trait_upcasting() { + check_diagnostics( + r#" +//- minicore: coerce_unsized, dispatch_from_dyn +#![feature(trait_upcasting)] +trait Foo {} +trait Bar: Foo {} + +impl dyn Bar { + fn bar(&self) { + _ = self as &dyn Foo; + } +} +"#, + ); + } + + #[test] + fn issue_18047() { + check_diagnostics( + r#" +//- minicore: coerce_unsized, dispatch_from_dyn +trait LocalFrom<T> { + fn from(_: T) -> Self; +} +trait LocalInto<T> { + fn into(self) -> T; +} + +impl<T, U> LocalInto<U> for T +where + U: LocalFrom<T>, +{ + fn into(self) -> U { + U::from(self) + } +} + +impl<T> LocalFrom<T> for T { + fn from(t: T) -> T { + t + } +} + +trait Foo { + type ErrorType; + type Assoc; +} + +trait Bar { + type ErrorType; +} + +struct ErrorLike; + +impl<E> LocalFrom<E> for ErrorLike +where + E: Trait + 'static, +{ + fn from(_: E) -> Self { + loop {} + } +} + +trait Baz { + type Assoc: Bar; + type Error: LocalInto<ErrorLike>; +} + +impl<T, U> Baz for T +where + T: Foo<Assoc = U>, + T::ErrorType: LocalInto<ErrorLike>, + U: Bar, + <U as Bar>::ErrorType: LocalInto<ErrorLike>, +{ + type Assoc = U; + type Error = T::ErrorType; +} +struct S; +trait Trait {} +impl Trait for S {} + +fn test<T>() +where + T: Baz, + T::Assoc: 'static, +{ + let _ = &S as &dyn Trait; +} +"#, + ); + } + + #[test] + fn cast_literal_to_char() { + check_diagnostics( + r#" +fn foo() { + 0 as char; +} + "#, + ); + } +} |