Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions tests/ui/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
113 changes: 113 additions & 0 deletions tests/ui/crashes/reborrow/coerce-shared-alias-projection.rs
Original file line number Diff line number Diff line change
@@ -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<InnerRef<'a, T>> 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> = <Projected as RefFamily<'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<OuterAliasRef<'a, T>> 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<OuterProjectionRef<'a, T>> 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));
}
44 changes: 44 additions & 0 deletions tests/ui/crashes/reborrow/coerce-shared-different-layout.rs
Original file line number Diff line number Diff line change
@@ -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<T>,
metadata: usize,
marker: PhantomData<&'a mut T>,
}

impl<'a, T> Reborrow for ImbrisMut<'a, T> {}

struct ImbrisRef<'a, T> {
ptr: NonNull<T>,
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<ImbrisRef<'a, T>> for ImbrisMut<'a, T> {}

fn ptr(value: ImbrisRef<'_, i32>) -> NonNull<i32> {
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);
}
61 changes: 61 additions & 0 deletions tests/ui/crashes/reborrow/coerce-shared-multi-field.rs
Original file line number Diff line number Diff line change
@@ -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<T>,
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<T>,
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<MatRef<'a, T>> for MatMut<'a, T> {}

fn dims<T>(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));
}
65 changes: 65 additions & 0 deletions tests/ui/crashes/reborrow/coerce-shared-nested.rs
Original file line number Diff line number Diff line change
@@ -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<InnerRef<'a, T>> 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<OuterRef<'a, T>> 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));
}
89 changes: 89 additions & 0 deletions tests/ui/crashes/reborrow/coerce-shared-tuple-phantom-position.rs
Original file line number Diff line number Diff line change
@@ -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<SourceLeadingRef<'a, T>> 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<TargetLeadingRef<'a, T>> 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<InterleavedRef<'a, T, U>> 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));
}
Loading
Loading