diff --git a/tests/crashes/reborrow/coerce-shared-alias-projection.rs b/tests/crashes/reborrow/coerce-shared-alias-projection.rs new file mode 100644 index 0000000000000..8497455de921a --- /dev/null +++ b/tests/crashes/reborrow/coerce-shared-alias-projection.rs @@ -0,0 +1,110 @@ +//@ known-bug: unknown +#![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/crashes/reborrow/coerce-shared-different-layout.rs b/tests/crashes/reborrow/coerce-shared-different-layout.rs new file mode 100644 index 0000000000000..ad285bf0130d1 --- /dev/null +++ b/tests/crashes/reborrow/coerce-shared-different-layout.rs @@ -0,0 +1,41 @@ +//@ known-bug: unknown +#![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/crashes/reborrow/coerce-shared-marker-no-target-lifetime.rs b/tests/crashes/reborrow/coerce-shared-marker-no-target-lifetime.rs new file mode 100644 index 0000000000000..3cdbf515371f2 --- /dev/null +++ b/tests/crashes/reborrow/coerce-shared-marker-no-target-lifetime.rs @@ -0,0 +1,21 @@ +//@ known-bug: unknown +//@ edition: 2024 + +#![feature(reborrow)] + +use std::marker::{CoerceShared, PhantomData, Reborrow}; + +struct CustomMarker<'a>(PhantomData<&'a ()>); +struct CustomMarkerRef; + +impl<'a> Reborrow for CustomMarker<'a> {} +impl<'a> CoerceShared for CustomMarker<'a> {} +//~^ ERROR + +fn method(_a: CustomMarkerRef) {} + +fn main() { + let a = CustomMarker(PhantomData); + method(a); + //~^ ERROR +} diff --git a/tests/crashes/reborrow/coerce-shared-multi-field.rs b/tests/crashes/reborrow/coerce-shared-multi-field.rs new file mode 100644 index 0000000000000..3bf5b64064d4a --- /dev/null +++ b/tests/crashes/reborrow/coerce-shared-multi-field.rs @@ -0,0 +1,58 @@ +//@ known-bug: unknown +#![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/crashes/reborrow/coerce-shared-nested.rs b/tests/crashes/reborrow/coerce-shared-nested.rs new file mode 100644 index 0000000000000..a916dde881ec5 --- /dev/null +++ b/tests/crashes/reborrow/coerce-shared-nested.rs @@ -0,0 +1,62 @@ +//@ known-bug: unknown +#![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/crashes/reborrow/coerce-shared-tuple-phantom-position.rs b/tests/crashes/reborrow/coerce-shared-tuple-phantom-position.rs new file mode 100644 index 0000000000000..0ada68c9c20f7 --- /dev/null +++ b/tests/crashes/reborrow/coerce-shared-tuple-phantom-position.rs @@ -0,0 +1,86 @@ +//@ known-bug: unknown +#![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/crashes/reborrow/corrected-field-mismatch-coerce-shared-issue-156315.rs b/tests/crashes/reborrow/corrected-field-mismatch-coerce-shared-issue-156315.rs new file mode 100644 index 0000000000000..59e76ec36ab90 --- /dev/null +++ b/tests/crashes/reborrow/corrected-field-mismatch-coerce-shared-issue-156315.rs @@ -0,0 +1,21 @@ +//@ known-bug: unknown + +#![feature(reborrow)] + +use std::marker::{CoerceShared, Reborrow}; + +struct CustomMut<'a, T>(&'a mut T); + +impl<'a, T> Reborrow for CustomMut<'a, T> {} + +struct CustomRef<'a, T>(&'a CustomMut<'a, T>); +//~^ ERROR + +impl<'a, T> CoerceShared> for CustomMut<'a, T> {} + +fn method(_a: CustomRef<'_, ()>) {} + +fn main() { + let a = CustomMut(&mut ()); + method(a); +} diff --git a/tests/crashes/reborrow/malformed-marker-coerce-shared-issue-156309.rs b/tests/crashes/reborrow/malformed-marker-coerce-shared-issue-156309.rs new file mode 100644 index 0000000000000..14b7ec820a180 --- /dev/null +++ b/tests/crashes/reborrow/malformed-marker-coerce-shared-issue-156309.rs @@ -0,0 +1,30 @@ +//@ known-bug: unknown +//@ edition: 2024 + +#![feature(reborrow)] + +// Malformed no-ICE regression: the unrelated name and signature errors are intentional because the +// original issue combined them with CoerceShared validation. + +use std::marker::{CoerceShared, PhantomData, Reborrow}; + +struct CustomMarker<'a>(PhantomData<&'a ()>); + +struct CustomMarkerRef<'a>(PhantomData<(Debug, Clone, Copy)>); +//~^ ERROR +//~| ERROR +//~| ERROR + +impl<'a> Reborrow for CustomMarker<'a> {} +impl<'a> CoerceShared> for CustomMarker<'a> {} +//~^ ERROR + +fn method<'a>(_a: CustomMarkerRef<'a>) -> 'a () { + //~^ ERROR + &() +} + +fn main() { + let a = CustomMarker(PhantomData); + let b = method(a); +} diff --git a/tests/crashes/reborrow/missing-generic-args-coerce-shared-issue-156315.rs b/tests/crashes/reborrow/missing-generic-args-coerce-shared-issue-156315.rs new file mode 100644 index 0000000000000..d365986901fe3 --- /dev/null +++ b/tests/crashes/reborrow/missing-generic-args-coerce-shared-issue-156315.rs @@ -0,0 +1,24 @@ +//@ known-bug: unknown +#![feature(reborrow)] + +// Malformed no-ICE regression: this intentionally keeps the missing generic arguments from the +// original reproducer while the corrected test isolates the CoerceShared field error. + +use std::marker::{CoerceShared, Reborrow}; + +struct CustomMut<'a, T>(&'a mut T); + +impl<'a, T> Reborrow for CustomMut<'a, T> {} +impl<'a, T> CoerceShared> for CustomMut<'a, T> {} + +struct CustomRef<'a, T>(&'a CustomMut); +//~^ ERROR +//~| ERROR +//~| ERROR + +fn method(_a: CustomRef<'_, ()>) {} + +fn main() { + let a = CustomMut(&mut ()); + method(a); +} diff --git a/tests/ui/reborrow/auxiliary/reborrow_foreign_private.rs b/tests/ui/reborrow/auxiliary/reborrow_foreign_private.rs new file mode 100644 index 0000000000000..d9a1029211136 --- /dev/null +++ b/tests/ui/reborrow/auxiliary/reborrow_foreign_private.rs @@ -0,0 +1,6 @@ +#![allow(dead_code)] + +#[derive(Clone, Copy)] +pub struct ForeignRef<'a> { + value: &'a i32, +} diff --git a/tests/ui/reborrow/coerce-shared-associated-type-field.rs b/tests/ui/reborrow/coerce-shared-associated-type-field.rs new file mode 100644 index 0000000000000..df744e9442dd8 --- /dev/null +++ b/tests/ui/reborrow/coerce-shared-associated-type-field.rs @@ -0,0 +1,30 @@ +#![feature(reborrow)] +#![allow(dead_code)] + +use std::marker::{CoerceShared, Reborrow}; + +trait Trait { + type Assoc; +} + +impl Trait for i32 { + type Assoc = i64; +} + +struct MyMut<'a> { + x: &'a (), + y: i64, +} + +#[derive(Copy, Clone)] +struct MyRef<'a> { + x: &'a (), + y: ::Assoc, +} + +impl Reborrow for MyMut<'_> {} + +impl<'a> CoerceShared> for MyMut<'a> {} +//~^ ERROR + +fn main() {} diff --git a/tests/ui/reborrow/coerce-shared-associated-type-field.stderr b/tests/ui/reborrow/coerce-shared-associated-type-field.stderr new file mode 100644 index 0000000000000..d533fa2eb8748 --- /dev/null +++ b/tests/ui/reborrow/coerce-shared-associated-type-field.stderr @@ -0,0 +1,8 @@ +error: implementing `CoerceShared` does not allow multiple lifetimes or fields to be coerced + --> $DIR/coerce-shared-associated-type-field.rs:27:10 + | +LL | impl<'a> CoerceShared> for MyMut<'a> {} + | ^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/reborrow/coerce-shared-decl-macro-hygiene.rs b/tests/ui/reborrow/coerce-shared-decl-macro-hygiene.rs new file mode 100644 index 0000000000000..3b6e9e25d8bb4 --- /dev/null +++ b/tests/ui/reborrow/coerce-shared-decl-macro-hygiene.rs @@ -0,0 +1,26 @@ +#![feature(reborrow, decl_macro)] +#![allow(incomplete_features)] + +use std::marker::{CoerceShared, Reborrow}; + +macro my_macro($field:ident) { + pub struct MyMut<'a> { + $field: &'a i32, + field: &'a i64, + } + + #[derive(Clone, Copy)] + pub struct MyRef<'a> { + $field: &'a i32, + field: &'a i64, + } + + impl Reborrow for MyMut<'_> {} + + impl<'a> CoerceShared> for MyMut<'a> {} + //~^ ERROR +} + +my_macro!(field); + +fn main() {} diff --git a/tests/ui/reborrow/coerce-shared-decl-macro-hygiene.stderr b/tests/ui/reborrow/coerce-shared-decl-macro-hygiene.stderr new file mode 100644 index 0000000000000..0b0b7bf048591 --- /dev/null +++ b/tests/ui/reborrow/coerce-shared-decl-macro-hygiene.stderr @@ -0,0 +1,13 @@ +error: implementing `CoerceShared` does not allow multiple lifetimes or fields to be coerced + --> $DIR/coerce-shared-decl-macro-hygiene.rs:20:14 + | +LL | impl<'a> CoerceShared> for MyMut<'a> {} + | ^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | my_macro!(field); + | ---------------- in this macro invocation + | + = note: this error originates in the macro `my_macro` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 1 previous error + 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); +} diff --git a/tests/ui/reborrow/coerce-shared-field-lifetime-swap.rs b/tests/ui/reborrow/coerce-shared-field-lifetime-swap.rs new file mode 100644 index 0000000000000..d4558dd35d775 --- /dev/null +++ b/tests/ui/reborrow/coerce-shared-field-lifetime-swap.rs @@ -0,0 +1,21 @@ +#![feature(reborrow)] + +use std::marker::{CoerceShared, Reborrow}; + +struct MyMut<'a> { + x: &'static (), + y: &'a (), +} + +impl Reborrow for MyMut<'_> {} + +#[derive(Copy, Clone)] +struct MyRef<'a> { + x: &'a (), + y: &'static (), +} + +impl<'a> CoerceShared> for MyMut<'a> {} +//~^ ERROR + +fn main() {} diff --git a/tests/ui/reborrow/coerce-shared-field-lifetime-swap.stderr b/tests/ui/reborrow/coerce-shared-field-lifetime-swap.stderr new file mode 100644 index 0000000000000..bce87c68eb912 --- /dev/null +++ b/tests/ui/reborrow/coerce-shared-field-lifetime-swap.stderr @@ -0,0 +1,8 @@ +error: implementing `CoerceShared` does not allow multiple lifetimes or fields to be coerced + --> $DIR/coerce-shared-field-lifetime-swap.rs:18:10 + | +LL | impl<'a> CoerceShared> for MyMut<'a> {} + | ^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/reborrow/coerce-shared-field-relations.rs b/tests/ui/reborrow/coerce-shared-field-relations.rs new file mode 100644 index 0000000000000..b2104efb6028d --- /dev/null +++ b/tests/ui/reborrow/coerce-shared-field-relations.rs @@ -0,0 +1,51 @@ +#![feature(reborrow)] + +use std::marker::{CoerceShared, Reborrow}; + +struct CustomMut<'a, T> { + value: &'a mut T, +} + +impl<'a, T> Reborrow for CustomMut<'a, T> {} + +#[derive(Clone, Copy)] +struct CustomRef<'a, T> { + value: &'a T, +} + +impl<'a, T> CoerceShared> for CustomMut<'a, T> {} + +struct RenamedMut<'a, T> { + source: &'a mut T, +} + +impl<'a, T> Reborrow for RenamedMut<'a, T> {} + +#[derive(Clone, Copy)] +struct RenamedRef<'a, T> { + target: &'a T, +} + +impl<'a, T> CoerceShared> for RenamedMut<'a, T> {} + +struct BadMut<'a, T> { + value: &'a mut T, +} + +impl<'a, T> Reborrow for BadMut<'a, T> {} + +#[derive(Clone, Copy)] +struct BadRef<'a, T> { + value: &'a u32, + _marker: std::marker::PhantomData, +} + +impl<'a, T> CoerceShared> for BadMut<'a, T> {} +//~^ ERROR + +fn good(_value: CustomRef<'_, u32>) {} + +fn main() { + let mut value = 1; + good(CustomMut { value: &mut value }); +} diff --git a/tests/ui/reborrow/coerce-shared-field-relations.stderr b/tests/ui/reborrow/coerce-shared-field-relations.stderr new file mode 100644 index 0000000000000..033a29e1e554e --- /dev/null +++ b/tests/ui/reborrow/coerce-shared-field-relations.stderr @@ -0,0 +1,9 @@ +error[E0277]: the trait bound `&'a mut T: CoerceShared<&'a u32>` is not satisfied + --> $DIR/coerce-shared-field-relations.rs:43:1 + | +LL | impl<'a, T> CoerceShared> for BadMut<'a, T> {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the nightly-only, unstable trait `CoerceShared<&'a u32>` is not implemented for `&'a mut T` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/reborrow/coerce-shared-foreign-private-field.rs b/tests/ui/reborrow/coerce-shared-foreign-private-field.rs new file mode 100644 index 0000000000000..3adda6733e16f --- /dev/null +++ b/tests/ui/reborrow/coerce-shared-foreign-private-field.rs @@ -0,0 +1,20 @@ +//@ check-pass + +//@ aux-build: reborrow_foreign_private.rs + +#![feature(reborrow)] + +extern crate reborrow_foreign_private; + +use reborrow_foreign_private::ForeignRef; +use std::marker::{CoerceShared, Reborrow}; + +struct LocalMut<'a> { + value: &'a mut i32, +} + +impl<'a> Reborrow for LocalMut<'a> {} + +impl<'a> CoerceShared> for LocalMut<'a> {} + +fn main() {} diff --git a/tests/ui/reborrow/coerce-shared-foreign-private-tuple-field.rs b/tests/ui/reborrow/coerce-shared-foreign-private-tuple-field.rs new file mode 100644 index 0000000000000..4a70fd49e38ff --- /dev/null +++ b/tests/ui/reborrow/coerce-shared-foreign-private-tuple-field.rs @@ -0,0 +1,22 @@ +//@ check-pass + +#![feature(reborrow)] + +use std::marker::{CoerceShared, PhantomData, Reborrow}; + +mod foreign_ptr { + use std::marker::PhantomData; + + #[derive(Clone, Copy)] + pub struct ForeignPtrRef<'a>(*const i32, PhantomData<&'a ()>); +} + +use foreign_ptr::ForeignPtrRef; + +struct LocalPtrMut<'a>(*const i32, PhantomData<&'a ()>); + +impl<'a> Reborrow for LocalPtrMut<'a> {} + +impl<'a> CoerceShared> for LocalPtrMut<'a> {} + +fn main() {} diff --git a/tests/ui/reborrow/coerce-shared-generics.rs b/tests/ui/reborrow/coerce-shared-generics.rs new file mode 100644 index 0000000000000..9edab02835761 --- /dev/null +++ b/tests/ui/reborrow/coerce-shared-generics.rs @@ -0,0 +1,41 @@ +#![feature(reborrow)] +#![allow(dead_code)] + +use std::marker::{CoerceShared, Reborrow}; + +struct BufferMut<'a, T, U, const N: usize> { + data: &'a mut [T; N], + meta: U, +} + +impl<'a, T, U: Copy, const N: usize> Reborrow for BufferMut<'a, T, U, N> {} + +struct BufferRef<'a, T, U, const N: usize> { + data: &'a [T; N], + meta: U, +} + +impl<'a, T, U: Copy, const N: usize> Clone for BufferRef<'a, T, U, N> { + fn clone(&self) -> Self { + *self + } +} + +impl<'a, T, U: Copy, const N: usize> Copy for BufferRef<'a, T, U, N> {} + +impl<'a, T, U: Copy, const N: usize> CoerceShared> +//~^ ERROR + for BufferMut<'a, T, U, N> +{ +} + +fn inspect(buffer: BufferRef<'_, u8, u16, N>) -> (usize, u16) { + (buffer.data.len(), buffer.meta) +} + +fn main() { + let mut data = [1, 2, 3, 4]; + let buffer = BufferMut { data: &mut data, meta: 9_u16 }; + + assert_eq!(inspect(buffer), (4, 9)); +} diff --git a/tests/ui/reborrow/coerce-shared-generics.stderr b/tests/ui/reborrow/coerce-shared-generics.stderr new file mode 100644 index 0000000000000..72efdd475fc10 --- /dev/null +++ b/tests/ui/reborrow/coerce-shared-generics.stderr @@ -0,0 +1,8 @@ +error: implementing `CoerceShared` does not allow multiple lifetimes or fields to be coerced + --> $DIR/coerce-shared-generics.rs:26:38 + | +LL | impl<'a, T, U: Copy, const N: usize> CoerceShared> + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/reborrow/coerce-shared-lifetime-mismatch.rs b/tests/ui/reborrow/coerce-shared-lifetime-mismatch.rs new file mode 100644 index 0000000000000..90bb4be4c1894 --- /dev/null +++ b/tests/ui/reborrow/coerce-shared-lifetime-mismatch.rs @@ -0,0 +1,23 @@ +#![feature(reborrow)] + +// The impl is accepted, but using it to coerce a local marker into a `'static` +// target still requires the local borrow to live for `'static`. + +use std::marker::{CoerceShared, PhantomData, Reborrow}; + +struct CustomMarker<'a>(PhantomData<&'a ()>); + +impl<'a> Reborrow for CustomMarker<'a> {} + +#[derive(Clone, Copy)] +struct StaticMarkerRef<'a>(PhantomData<&'a ()>); + +impl<'a> CoerceShared> for CustomMarker<'a> {} + +fn method(_a: StaticMarkerRef<'static>) {} + +fn main() { + let a = CustomMarker(PhantomData); + method(a); + //~^ ERROR +} diff --git a/tests/ui/reborrow/coerce-shared-lifetime-mismatch.stderr b/tests/ui/reborrow/coerce-shared-lifetime-mismatch.stderr new file mode 100644 index 0000000000000..337e4b6938944 --- /dev/null +++ b/tests/ui/reborrow/coerce-shared-lifetime-mismatch.stderr @@ -0,0 +1,17 @@ +error[E0597]: `a` does not live long enough + --> $DIR/coerce-shared-lifetime-mismatch.rs:21:12 + | +LL | let a = CustomMarker(PhantomData); + | - binding `a` declared here +LL | method(a); + | -------^- + | | | + | | borrowed value does not live long enough + | argument requires that `a` is borrowed for `'static` +LL | +LL | } + | - `a` dropped here while still borrowed + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0597`. diff --git a/tests/ui/reborrow/coerce-shared-missing-target-field.rs b/tests/ui/reborrow/coerce-shared-missing-target-field.rs new file mode 100644 index 0000000000000..c528fb85340ac --- /dev/null +++ b/tests/ui/reborrow/coerce-shared-missing-target-field.rs @@ -0,0 +1,20 @@ +#![feature(reborrow)] + +use std::marker::{CoerceShared, Reborrow}; + +struct MissingSourceMut<'a, T> { + value: &'a mut T, +} + +impl<'a, T> Reborrow for MissingSourceMut<'a, T> {} + +#[derive(Clone, Copy)] +struct MissingSourceRef<'a, T> { + value: &'a T, + len: usize, +} + +impl<'a, T> CoerceShared> for MissingSourceMut<'a, T> {} +//~^ ERROR + +fn main() {} diff --git a/tests/ui/reborrow/coerce-shared-missing-target-field.stderr b/tests/ui/reborrow/coerce-shared-missing-target-field.stderr new file mode 100644 index 0000000000000..15146341bc56c --- /dev/null +++ b/tests/ui/reborrow/coerce-shared-missing-target-field.stderr @@ -0,0 +1,8 @@ +error: implementing `CoerceShared` does not allow multiple lifetimes or fields to be coerced + --> $DIR/coerce-shared-missing-target-field.rs:17:13 + | +LL | impl<'a, T> CoerceShared> for MissingSourceMut<'a, T> {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/reborrow/coerce-shared-mut-ref-field-validation.rs b/tests/ui/reborrow/coerce-shared-mut-ref-field-validation.rs new file mode 100644 index 0000000000000..9d87ff0bb938a --- /dev/null +++ b/tests/ui/reborrow/coerce-shared-mut-ref-field-validation.rs @@ -0,0 +1,43 @@ +#![feature(reborrow)] + +use std::marker::{CoerceShared, Reborrow}; + +trait Trait { + type Assoc; +} + +impl Trait for i32 { + type Assoc = u32; +} + +type AliasMutField<'a> = &'a mut ::Assoc; +type AliasRefField<'a> = &'a u32; + +struct AliasMut<'a> { + value: AliasMutField<'a>, +} + +impl Reborrow for AliasMut<'_> {} + +#[derive(Copy, Clone)] +struct AliasRef<'a> { + value: AliasRefField<'a>, +} + +impl<'a> CoerceShared> for AliasMut<'a> {} +//~^ ERROR + +struct InnerLifetimeMut<'a> { + value: &'a mut &'static (), +} + +impl Reborrow for InnerLifetimeMut<'_> {} + +#[derive(Copy, Clone)] +struct InnerLifetimeRef<'a> { + value: &'a &'a (), +} + +impl<'a> CoerceShared> for InnerLifetimeMut<'a> {} + +fn main() {} diff --git a/tests/ui/reborrow/coerce-shared-mut-ref-field-validation.stderr b/tests/ui/reborrow/coerce-shared-mut-ref-field-validation.stderr new file mode 100644 index 0000000000000..63a96d65e176d --- /dev/null +++ b/tests/ui/reborrow/coerce-shared-mut-ref-field-validation.stderr @@ -0,0 +1,9 @@ +error[E0277]: the trait bound `&'a mut u32: CoerceShared<&'a u32>` is not satisfied + --> $DIR/coerce-shared-mut-ref-field-validation.rs:27:1 + | +LL | impl<'a> CoerceShared> for AliasMut<'a> {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the nightly-only, unstable trait `CoerceShared<&'a u32>` is not implemented for `&'a mut u32` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/reborrow/coerce-shared-omitted-reborrow-field-after-dead.rs b/tests/ui/reborrow/coerce-shared-omitted-reborrow-field-after-dead.rs new file mode 100644 index 0000000000000..4f066079c749b --- /dev/null +++ b/tests/ui/reborrow/coerce-shared-omitted-reborrow-field-after-dead.rs @@ -0,0 +1,51 @@ +#![feature(reborrow)] +#![allow(dead_code)] + +use std::marker::{CoerceShared, Reborrow}; + +struct ExtraMut<'a, T> { + value: &'a mut T, +} + +impl<'a, T> Reborrow for ExtraMut<'a, T> {} + +struct OmitMut<'a, T> { + value: &'a mut T, + extra: ExtraMut<'a, T>, +} + +impl<'a, T> Reborrow for OmitMut<'a, T> {} + +struct OmitRef<'a, T> { + value: &'a T, +} + +impl<'a, T> Clone for OmitRef<'a, T> { + fn clone(&self) -> Self { + *self + } +} + +impl<'a, T> Copy for OmitRef<'a, T> {} + +impl<'a, T> CoerceShared> for OmitMut<'a, T> {} +//~^ ERROR + +fn read(value: OmitRef<'_, i32>) { + assert_eq!(*value.value, 1); +} + +fn main() { + let mut value = 1; + let mut extra_value = 2; + + { + let extra = ExtraMut { value: &mut extra_value }; + let wrapped = OmitMut { value: &mut value, extra }; + + read(wrapped); + } + + extra_value = 3; + assert_eq!(extra_value, 3); +} diff --git a/tests/ui/reborrow/coerce-shared-omitted-reborrow-field-after-dead.stderr b/tests/ui/reborrow/coerce-shared-omitted-reborrow-field-after-dead.stderr new file mode 100644 index 0000000000000..70a0db88319a7 --- /dev/null +++ b/tests/ui/reborrow/coerce-shared-omitted-reborrow-field-after-dead.stderr @@ -0,0 +1,8 @@ +error: implementing `CoerceShared` does not allow multiple lifetimes or fields to be coerced + --> $DIR/coerce-shared-omitted-reborrow-field-after-dead.rs:31:13 + | +LL | impl<'a, T> CoerceShared> for OmitMut<'a, T> {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/reborrow/coerce-shared-omitted-reborrow-field-locked.rs b/tests/ui/reborrow/coerce-shared-omitted-reborrow-field-locked.rs new file mode 100644 index 0000000000000..ade1890068d76 --- /dev/null +++ b/tests/ui/reborrow/coerce-shared-omitted-reborrow-field-locked.rs @@ -0,0 +1,53 @@ +#![feature(reborrow)] + +use std::marker::{CoerceShared, Reborrow}; + +struct ExtraMut<'a, T> { + value: &'a mut T, +} + +impl<'a, T> Reborrow for ExtraMut<'a, T> {} + +struct OmitMut<'a, T> { + value: &'a mut T, + extra: ExtraMut<'a, T>, +} + +impl<'a, T> Reborrow for OmitMut<'a, T> {} + +struct OmitRef<'a, T> { + value: &'a T, +} + +impl<'a, T> Clone for OmitRef<'a, T> { + fn clone(&self) -> Self { + *self + } +} + +impl<'a, T> Copy for OmitRef<'a, T> {} + +impl<'a, T> CoerceShared> for OmitMut<'a, T> {} +//~^ ERROR + +fn get<'a>(value: OmitRef<'a, i32>) -> &'a i32 { + value.value +} + +fn main() { + let mut value = 1; + let mut extra_value = 2; + let extra = ExtraMut { value: &mut extra_value }; + + let mut wrapped = OmitMut { + value: &mut value, + extra, + }; + + let shared = get(wrapped); + + *wrapped.extra.value = 3; + //~^ ERROR cannot assign to `*wrapped.extra.value` because it is borrowed + + let _ = shared; +} diff --git a/tests/ui/reborrow/coerce-shared-omitted-reborrow-field-locked.stderr b/tests/ui/reborrow/coerce-shared-omitted-reborrow-field-locked.stderr new file mode 100644 index 0000000000000..d718103c80e7f --- /dev/null +++ b/tests/ui/reborrow/coerce-shared-omitted-reborrow-field-locked.stderr @@ -0,0 +1,21 @@ +error: implementing `CoerceShared` does not allow multiple lifetimes or fields to be coerced + --> $DIR/coerce-shared-omitted-reborrow-field-locked.rs:30:13 + | +LL | impl<'a, T> CoerceShared> for OmitMut<'a, T> {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0506]: cannot assign to `*wrapped.extra.value` because it is borrowed + --> $DIR/coerce-shared-omitted-reborrow-field-locked.rs:49:5 + | +LL | let shared = get(wrapped); + | ------- `*wrapped.extra.value` is borrowed here +LL | +LL | *wrapped.extra.value = 3; + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | `*wrapped.extra.value` is assigned to here but it was already borrowed + | borrow later used here + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0506`. diff --git a/tests/ui/reborrow/coerce-shared-omitted-reborrow-field.rs b/tests/ui/reborrow/coerce-shared-omitted-reborrow-field.rs new file mode 100644 index 0000000000000..55cc010c19af4 --- /dev/null +++ b/tests/ui/reborrow/coerce-shared-omitted-reborrow-field.rs @@ -0,0 +1,45 @@ +#![feature(reborrow)] +#![allow(dead_code)] + +use std::marker::{CoerceShared, Reborrow}; + +struct ExtraMut<'a, T> { + value: &'a mut T, +} + +impl<'a, T> Reborrow for ExtraMut<'a, T> {} + +struct OmitMut<'a, T> { + value: &'a mut T, + extra: ExtraMut<'a, T>, +} + +impl<'a, T> Reborrow for OmitMut<'a, T> {} + +struct OmitRef<'a, T> { + value: &'a T, +} + +impl<'a, T> Clone for OmitRef<'a, T> { + fn clone(&self) -> Self { + *self + } +} + +impl<'a, T> Copy for OmitRef<'a, T> {} + +impl<'a, T> CoerceShared> for OmitMut<'a, T> {} +//~^ ERROR + +fn get<'a>(value: OmitRef<'a, i32>) -> &'a i32 { + value.value +} + +fn main() { + let mut value = 1; + let mut extra = 2; + let extra = ExtraMut { value: &mut extra }; + let wrapped = OmitMut { value: &mut value, extra }; + + assert_eq!(*get(wrapped), 1); +} diff --git a/tests/ui/reborrow/coerce-shared-omitted-reborrow-field.stderr b/tests/ui/reborrow/coerce-shared-omitted-reborrow-field.stderr new file mode 100644 index 0000000000000..c663576228f62 --- /dev/null +++ b/tests/ui/reborrow/coerce-shared-omitted-reborrow-field.stderr @@ -0,0 +1,8 @@ +error: implementing `CoerceShared` does not allow multiple lifetimes or fields to be coerced + --> $DIR/coerce-shared-omitted-reborrow-field.rs:31:13 + | +LL | impl<'a, T> CoerceShared> for OmitMut<'a, T> {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/reborrow/coerce-shared-reordered-field.rs b/tests/ui/reborrow/coerce-shared-reordered-field.rs new file mode 100644 index 0000000000000..f4630fe1f7d83 --- /dev/null +++ b/tests/ui/reborrow/coerce-shared-reordered-field.rs @@ -0,0 +1,32 @@ +#![feature(reborrow)] +#![allow(dead_code)] + +use std::marker::{CoerceShared, Reborrow}; + +struct ReorderMut<'a> { + a: &'a mut u8, + b: &'a mut u16, +} + +impl<'a> Reborrow for ReorderMut<'a> {} + +#[derive(Clone, Copy)] +struct ReorderRef<'a> { + b: &'a u16, + a: &'a u8, +} + +impl<'a> CoerceShared> for ReorderMut<'a> {} +//~^ ERROR + +fn read(value: ReorderRef<'_>) -> (u16, u8) { + (*value.b, *value.a) +} + +fn main() { + let mut a = 1; + let mut b = 2; + let wrapped = ReorderMut { a: &mut a, b: &mut b }; + + assert_eq!(read(wrapped), (2, 1)); +} diff --git a/tests/ui/reborrow/coerce-shared-reordered-field.stderr b/tests/ui/reborrow/coerce-shared-reordered-field.stderr new file mode 100644 index 0000000000000..e3cd68547c428 --- /dev/null +++ b/tests/ui/reborrow/coerce-shared-reordered-field.stderr @@ -0,0 +1,8 @@ +error: implementing `CoerceShared` does not allow multiple lifetimes or fields to be coerced + --> $DIR/coerce-shared-reordered-field.rs:19:10 + | +LL | impl<'a> CoerceShared> for ReorderMut<'a> {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/reborrow/coerce-shared-wrong-generic.rs b/tests/ui/reborrow/coerce-shared-wrong-generic.rs new file mode 100644 index 0000000000000..2dc818a7015b2 --- /dev/null +++ b/tests/ui/reborrow/coerce-shared-wrong-generic.rs @@ -0,0 +1,21 @@ +#![feature(reborrow)] + +use std::marker::{CoerceShared, PhantomData, Reborrow}; + +struct GenericMut<'a, T, U> { + value: &'a mut T, + marker: PhantomData, +} + +impl<'a, T, U> Reborrow for GenericMut<'a, T, U> {} + +#[derive(Clone, Copy)] +struct GenericRef<'a, T, U> { + value: &'a U, + marker: PhantomData, +} + +impl<'a, T, U> CoerceShared> for GenericMut<'a, T, U> {} +//~^ ERROR + +fn main() {} diff --git a/tests/ui/reborrow/coerce-shared-wrong-generic.stderr b/tests/ui/reborrow/coerce-shared-wrong-generic.stderr new file mode 100644 index 0000000000000..d0031a7c8a99e --- /dev/null +++ b/tests/ui/reborrow/coerce-shared-wrong-generic.stderr @@ -0,0 +1,9 @@ +error[E0277]: the trait bound `&'a mut T: CoerceShared<&'a U>` is not satisfied + --> $DIR/coerce-shared-wrong-generic.rs:18:1 + | +LL | impl<'a, T, U> CoerceShared> for GenericMut<'a, T, U> {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the nightly-only, unstable trait `CoerceShared<&'a U>` is not implemented for `&'a mut T` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`.