diff --git a/tests/ui/README.md b/tests/ui/README.md index 00afc98a0b55a..b8e09511302cc 100644 --- a/tests/ui/README.md +++ b/tests/ui/README.md @@ -354,6 +354,10 @@ See: Tests for `#![feature(coverage_attribute)]`. See [Tracking issue for function attribute `#[coverage]`](https://github.com/rust-lang/rust/issues/84605). +## `tests/ui/crashes/`: Crash Regressions + +Tests for crash or ICE regressions that still use the UI test harness. + ## `tests/ui/crate-loading/`: Crate Loading Tests for crate resolution and loading behavior, including `extern crate` declarations, `--extern` flags, or the `use` keyword. diff --git a/tests/ui/crashes/reborrow/coerce-shared-alias-projection.rs b/tests/ui/crashes/reborrow/coerce-shared-alias-projection.rs new file mode 100644 index 0000000000000..656b4fbff4676 --- /dev/null +++ b/tests/ui/crashes/reborrow/coerce-shared-alias-projection.rs @@ -0,0 +1,113 @@ +//@ known-bug: #157101 +//@ failure-status: 101 +//@ dont-check-compiler-stderr + +#![feature(reborrow)] +#![allow(dead_code)] + +use std::marker::{CoerceShared, Reborrow}; + +// This test combines alias/projection normalization with the leaf `&mut T` to `&T` +// shared reborrow path. + +struct InnerMut<'a, T> { + value: &'a mut T, +} + +impl<'a, T> Reborrow for InnerMut<'a, T> {} + +struct InnerRef<'a, T> { + value: &'a T, +} + +impl<'a, T> Clone for InnerRef<'a, T> { + fn clone(&self) -> Self { + *self + } +} + +impl<'a, T> Copy for InnerRef<'a, T> {} + +impl<'a, T> CoerceShared> for InnerMut<'a, T> {} + +type DirectInnerRef<'a, T> = InnerRef<'a, T>; + +trait RefFamily<'a, T> { + type Ref; +} + +struct Projected; + +impl<'a, T: 'a> RefFamily<'a, T> for Projected { + type Ref = InnerRef<'a, T>; +} + +type ProjectedInnerRef<'a, T> = >::Ref; + +struct OuterMut<'a, T> { + inner: InnerMut<'a, T>, + tag: usize, +} + +impl<'a, T> Reborrow for OuterMut<'a, T> {} + +struct OuterAliasRef<'a, T> { + inner: DirectInnerRef<'a, T>, + tag: usize, +} + +impl<'a, T> Clone for OuterAliasRef<'a, T> { + fn clone(&self) -> Self { + *self + } +} + +impl<'a, T> Copy for OuterAliasRef<'a, T> {} + +impl<'a, T> CoerceShared> for OuterMut<'a, T> {} + +struct OuterProjectionRef<'a, T: 'a> { + inner: ProjectedInnerRef<'a, T>, + tag: usize, +} + +impl<'a, T: 'a> Clone for OuterProjectionRef<'a, T> { + fn clone(&self) -> Self { + *self + } +} + +impl<'a, T: 'a> Copy for OuterProjectionRef<'a, T> {} + +impl<'a, T: 'a> CoerceShared> for OuterMut<'a, T> {} + +fn read_alias<'a>(outer: OuterAliasRef<'a, u32>) -> (&'a u32, usize) { + (outer.inner.value, outer.tag) +} + +fn read_projection<'a>(outer: OuterProjectionRef<'a, u32>) -> (&'a u32, usize) { + (outer.inner.value, outer.tag) +} + +const fn const_accept_projection(_outer: OuterProjectionRef<'_, u32>) {} + +const fn consteval_projection_reborrow() { + let mut value = 11; + const_accept_projection(OuterMut { + inner: InnerMut { value: &mut value }, + tag: 5, + }); +} + +fn main() { + const { consteval_projection_reborrow(); } + + let mut value = 22; + let outer = OuterMut { inner: InnerMut { value: &mut value }, tag: 7 }; + + let (alias_value, alias_tag) = read_alias(outer); + assert_eq!((*alias_value, alias_tag), (22, 7)); + + let (projection_value, projection_tag) = read_projection(outer); + assert_eq!((*projection_value, projection_tag), (22, 7)); +} diff --git a/tests/ui/crashes/reborrow/coerce-shared-different-layout.rs b/tests/ui/crashes/reborrow/coerce-shared-different-layout.rs new file mode 100644 index 0000000000000..0863dcea346d0 --- /dev/null +++ b/tests/ui/crashes/reborrow/coerce-shared-different-layout.rs @@ -0,0 +1,44 @@ +//@ known-bug: #157101 +//@ failure-status: 101 +//@ dont-check-compiler-stderr + +#![feature(reborrow)] +#![allow(dead_code)] + +use std::marker::{CoerceShared, PhantomData, Reborrow}; +use std::ptr::NonNull; + +struct ImbrisMut<'a, T> { + ptr: NonNull, + metadata: usize, + marker: PhantomData<&'a mut T>, +} + +impl<'a, T> Reborrow for ImbrisMut<'a, T> {} + +struct ImbrisRef<'a, T> { + ptr: NonNull, + marker: PhantomData<&'a T>, +} + +impl<'a, T> Clone for ImbrisRef<'a, T> { + fn clone(&self) -> Self { + *self + } +} + +impl<'a, T> Copy for ImbrisRef<'a, T> {} + +impl<'a, T> CoerceShared> for ImbrisMut<'a, T> {} + +fn ptr(value: ImbrisRef<'_, i32>) -> NonNull { + value.ptr +} + +fn main() { + let mut value = 1; + let raw = NonNull::from(&mut value); + let wrapped = ImbrisMut { ptr: raw, metadata: 32, marker: PhantomData }; + + assert_eq!(ptr(wrapped), raw); +} diff --git a/tests/ui/crashes/reborrow/coerce-shared-multi-field.rs b/tests/ui/crashes/reborrow/coerce-shared-multi-field.rs new file mode 100644 index 0000000000000..05f1150aaffa5 --- /dev/null +++ b/tests/ui/crashes/reborrow/coerce-shared-multi-field.rs @@ -0,0 +1,61 @@ +//@ known-bug: #157101 +//@ failure-status: 101 +//@ dont-check-compiler-stderr + +#![feature(reborrow)] +#![allow(dead_code)] + +use std::marker::{CoerceShared, PhantomData, Reborrow}; +use std::ptr::NonNull; + +struct MatMut<'a, T> { + ptr: NonNull, + rows: usize, + cols: usize, + row_stride: usize, + col_stride: usize, + marker: PhantomData<&'a mut T>, +} + +impl<'a, T> Reborrow for MatMut<'a, T> {} + +struct MatRef<'a, T> { + ptr: NonNull, + rows: usize, + cols: usize, + row_stride: usize, + col_stride: usize, + marker: PhantomData<&'a T>, +} + +impl<'a, T> Clone for MatRef<'a, T> { + fn clone(&self) -> Self { + *self + } +} + +impl<'a, T> Copy for MatRef<'a, T> {} + +impl<'a, T> CoerceShared> for MatMut<'a, T> {} + +fn dims(mat: MatRef<'_, T>) -> (usize, usize, usize, usize) { + let _ = mat.ptr; + (mat.rows, mat.cols, mat.row_stride, mat.col_stride) +} + +fn main() { + let mut value = 0; + let mat = MatMut { + ptr: NonNull::from(&mut value), + rows: 2, + cols: 3, + row_stride: 4, + col_stride: 5, + marker: PhantomData, + }; + + assert_eq!(dims(mat), (2, 3, 4, 5)); + // Reusing the same source proves repeated shared reborrows keep source-only data protected + // without consuming the reborrowable value. + assert_eq!(dims(mat), (2, 3, 4, 5)); +} diff --git a/tests/ui/crashes/reborrow/coerce-shared-nested.rs b/tests/ui/crashes/reborrow/coerce-shared-nested.rs new file mode 100644 index 0000000000000..0957f493fece5 --- /dev/null +++ b/tests/ui/crashes/reborrow/coerce-shared-nested.rs @@ -0,0 +1,65 @@ +//@ known-bug: #157101 +//@ failure-status: 101 +//@ dont-check-compiler-stderr + +#![feature(reborrow)] +#![allow(dead_code)] + +use std::marker::{CoerceShared, Reborrow}; + +struct InnerMut<'a, T> { + value: &'a mut T, +} + +impl<'a, T> Reborrow for InnerMut<'a, T> {} + +struct InnerRef<'a, T> { + value: &'a T, +} + +impl<'a, T> Clone for InnerRef<'a, T> { + fn clone(&self) -> Self { + *self + } +} + +impl<'a, T> Copy for InnerRef<'a, T> {} + +impl<'a, T> CoerceShared> for InnerMut<'a, T> {} + +struct OuterMut<'a, T> { + inner: InnerMut<'a, T>, + tag: usize, +} + +impl<'a, T> Reborrow for OuterMut<'a, T> {} + +struct OuterRef<'a, T> { + inner: InnerRef<'a, T>, + tag: usize, +} + +impl<'a, T> Clone for OuterRef<'a, T> { + fn clone(&self) -> Self { + *self + } +} + +impl<'a, T> Copy for OuterRef<'a, T> {} + +impl<'a, T> CoerceShared> for OuterMut<'a, T> {} + +fn get<'a>(outer: OuterRef<'a, i32>) -> (&'a i32, usize) { + (outer.inner.value, outer.tag) +} + +fn main() { + let mut value = 22; + let outer = OuterMut { inner: InnerMut { value: &mut value }, tag: 7 }; + + let (first, tag) = get(outer); + assert_eq!((*first, tag), (22, 7)); + + let (second, tag) = get(outer); + assert_eq!((*second, tag), (22, 7)); +} diff --git a/tests/ui/crashes/reborrow/coerce-shared-tuple-phantom-position.rs b/tests/ui/crashes/reborrow/coerce-shared-tuple-phantom-position.rs new file mode 100644 index 0000000000000..fae45176f846a --- /dev/null +++ b/tests/ui/crashes/reborrow/coerce-shared-tuple-phantom-position.rs @@ -0,0 +1,89 @@ +//@ known-bug: #157101 +//@ failure-status: 101 +//@ dont-check-compiler-stderr + +#![feature(reborrow)] +#![allow(dead_code)] + +use std::marker::{CoerceShared, PhantomData, Reborrow}; + +struct SourceLeadingMut<'a, T>(PhantomData<&'a mut T>, &'a mut T); + +impl<'a, T> Reborrow for SourceLeadingMut<'a, T> {} + +struct SourceLeadingRef<'a, T>(&'a T); + +impl<'a, T> Clone for SourceLeadingRef<'a, T> { + fn clone(&self) -> Self { + *self + } +} + +impl<'a, T> Copy for SourceLeadingRef<'a, T> {} + +impl<'a, T> CoerceShared> for SourceLeadingMut<'a, T> {} + +struct TargetLeadingMut<'a, T>(&'a mut T); + +impl<'a, T> Reborrow for TargetLeadingMut<'a, T> {} + +struct TargetLeadingRef<'a, T>(PhantomData<&'a T>, &'a T); + +impl<'a, T> Clone for TargetLeadingRef<'a, T> { + fn clone(&self) -> Self { + *self + } +} + +impl<'a, T> Copy for TargetLeadingRef<'a, T> {} + +impl<'a, T> CoerceShared> for TargetLeadingMut<'a, T> {} + +struct InterleavedMut<'a, T, U>( + PhantomData<&'a mut T>, + &'a mut T, + PhantomData<&'a mut U>, + &'a mut U, +); + +impl<'a, T, U> Reborrow for InterleavedMut<'a, T, U> {} + +struct InterleavedRef<'a, T, U>(&'a T, PhantomData<&'a T>, &'a U, PhantomData<&'a U>); + +impl<'a, T, U> Clone for InterleavedRef<'a, T, U> { + fn clone(&self) -> Self { + *self + } +} + +impl<'a, T, U> Copy for InterleavedRef<'a, T, U> {} + +impl<'a, T, U> CoerceShared> for InterleavedMut<'a, T, U> {} + +fn read_source_leading<'a>(value: SourceLeadingRef<'a, i32>) -> &'a i32 { + value.0 +} + +fn read_target_leading<'a>(value: TargetLeadingRef<'a, i32>) -> &'a i32 { + value.1 +} + +fn read_interleaved<'a>(value: InterleavedRef<'a, i32, i64>) -> (&'a i32, &'a i64) { + (value.0, value.2) +} + +fn main() { + let mut source_leading = 10; + let wrapped = SourceLeadingMut(PhantomData, &mut source_leading); + assert_eq!(*read_source_leading(wrapped), 10); + + let mut target_leading = 20; + let wrapped = TargetLeadingMut(&mut target_leading); + assert_eq!(*read_target_leading(wrapped), 20); + + let mut first = 30; + let mut second = 40_i64; + let wrapped = InterleavedMut(PhantomData, &mut first, PhantomData, &mut second); + let (first, second) = read_interleaved(wrapped); + assert_eq!((*first, *second), (30, 40)); +} diff --git a/tests/ui/reborrow/coerce-shared-extra-marker.rs b/tests/ui/reborrow/coerce-shared-extra-marker.rs new file mode 100644 index 0000000000000..40026d68d5dca --- /dev/null +++ b/tests/ui/reborrow/coerce-shared-extra-marker.rs @@ -0,0 +1,37 @@ +//@ run-pass + +#![feature(reborrow)] +#![allow(dead_code)] + +use std::marker::{CoerceShared, PhantomData, Reborrow}; + +struct MarkerExtraMut<'a, T> { + value: &'a mut T, + marker: PhantomData<&'a mut T>, +} + +impl<'a, T> Reborrow for MarkerExtraMut<'a, T> {} + +struct MarkerExtraRef<'a, T> { + value: &'a T, +} + +impl<'a, T> Clone for MarkerExtraRef<'a, T> { + fn clone(&self) -> Self { + *self + } +} + +impl<'a, T> Copy for MarkerExtraRef<'a, T> {} + +impl<'a, T> CoerceShared> for MarkerExtraMut<'a, T> {} + +fn get<'a>(value: MarkerExtraRef<'a, i32>) -> &'a i32 { + value.value +} + +fn main() { + let mut value = 1; + let wrapped = MarkerExtraMut { value: &mut value, marker: PhantomData }; + assert_eq!(*get(wrapped), 1); +}