From 475f867e1bb3c74db0a51276956b2c2bc1e2fb30 Mon Sep 17 00:00:00 2001 From: albab-hasan Date: Fri, 24 Jul 2026 19:12:45 +0600 Subject: [PATCH 1/9] point at closure return expression in non-FnOnce E0271 errors when a closure literal is passed as a function argument and E0271 fires for a projection that isnt FnOnceOutput, the error now points at the closures return expression and labels the closure declaration with "this closure", mirroring the existing FnOnce handling in maybe_detailed_projection_msg, which cant recover the closure from self_ty alone. fixes https://github.com/rust-lang/rust/issues/42390 --- .../traits/fulfillment_errors.rs | 26 ++++++- .../closure-arg-assoc-type-mismatch.rs | 30 ++++++++ .../closure-arg-assoc-type-mismatch.stderr | 72 +++++++++++++++++++ ...-arg-type-mismatch-issue-45727.next.stderr | 14 ++-- 4 files changed, 135 insertions(+), 7 deletions(-) create mode 100644 tests/ui/closures/closure-arg-assoc-type-mismatch.rs create mode 100644 tests/ui/closures/closure-arg-assoc-type-mismatch.stderr diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs index b98c3fab5bcb5..725662619ce78 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs @@ -1660,7 +1660,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { }; let mut file = None; - let (msg, span, closure_span) = values + let (msg, mut span, mut closure_span) = values .and_then(|(predicate, normalized_term, expected_term)| { self.maybe_detailed_projection_msg( obligation.cause.span, @@ -1681,6 +1681,30 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { None, ) }); + + // When the obligation comes from a closure arg and the projection isn't FnOnceOutput + // (which maybe_detailed_projection_msg handles via self_ty), point at the closure's + // return expression and label the closure declaration. + if closure_span.is_none() + && let ObligationCauseCode::FunctionArg { arg_hir_id, .. } = obligation.cause.code() + && let Node::Expr(arg_expr) = self.tcx.hir_node(*arg_hir_id) + && let hir::ExprKind::Closure(closure) = arg_expr.kind + && closure.kind == hir::ClosureKind::Closure + { + let body = self.tcx.hir_body(closure.body); + let ret_span = match body.value.kind { + hir::ExprKind::Block(hir::Block { expr: Some(expr), .. }, _) => expr.span, + hir::ExprKind::Block(hir::Block { expr: None, stmts: [.., last], .. }, _) => { + last.span + } + _ => body.value.span, + }; + if !closure.fn_decl_span.overlaps(ret_span) { + closure_span = Some(closure.fn_decl_span); + span = ret_span; + } + } + let mut diag = struct_span_code_err!(self.dcx(), span, E0271, "{msg}"); *diag.long_ty_path() = file; let mut mention_bounds = true; diff --git a/tests/ui/closures/closure-arg-assoc-type-mismatch.rs b/tests/ui/closures/closure-arg-assoc-type-mismatch.rs new file mode 100644 index 0000000000000..6681b6794543e --- /dev/null +++ b/tests/ui/closures/closure-arg-assoc-type-mismatch.rs @@ -0,0 +1,30 @@ +// When a closure is passed as a function argument and the E0271 projection +// mismatch is about an associated type of the closure's return type, the error +// should point at the return expression inside the closure and label the +// closure declaration — mirroring the FnOnce-output diagnostic. +// https://github.com/rust-lang/rust/issues/42390 + +trait MyTrait { + type Item; +} + +struct S; +impl MyTrait for S { + type Item = u32; +} + +// Bound on the closure's output type's associated type. +fn needs_unit_item S>(_f: F) +where + F::Output: MyTrait, +{ +} + +fn main() { + needs_unit_item(|| S); //~ ERROR type mismatch resolving `::Item == ()` + + needs_unit_item(|| { S }); //~ ERROR type mismatch resolving `::Item == ()` + + let x = S; + needs_unit_item(|| { let _ = 0; x }); //~ ERROR type mismatch resolving `::Item == ()` +} diff --git a/tests/ui/closures/closure-arg-assoc-type-mismatch.stderr b/tests/ui/closures/closure-arg-assoc-type-mismatch.stderr new file mode 100644 index 0000000000000..09ae41b30945b --- /dev/null +++ b/tests/ui/closures/closure-arg-assoc-type-mismatch.stderr @@ -0,0 +1,72 @@ +error[E0271]: type mismatch resolving `::Item == ()` + --> $DIR/closure-arg-assoc-type-mismatch.rs:24:24 + | +LL | needs_unit_item(|| S); + | --------------- -- ^ type mismatch resolving `::Item == ()` + | | | + | | this closure + | required by a bound introduced by this call + | +note: expected this to be `()` + --> $DIR/closure-arg-assoc-type-mismatch.rs:13:17 + | +LL | type Item = u32; + | ^^^ +note: required by a bound in `needs_unit_item` + --> $DIR/closure-arg-assoc-type-mismatch.rs:19:24 + | +LL | fn needs_unit_item S>(_f: F) + | --------------- required by a bound in this function +LL | where +LL | F::Output: MyTrait, + | ^^^^^^^^^ required by this bound in `needs_unit_item` + +error[E0271]: type mismatch resolving `::Item == ()` + --> $DIR/closure-arg-assoc-type-mismatch.rs:26:26 + | +LL | needs_unit_item(|| { S }); + | --------------- -- ^ type mismatch resolving `::Item == ()` + | | | + | | this closure + | required by a bound introduced by this call + | +note: expected this to be `()` + --> $DIR/closure-arg-assoc-type-mismatch.rs:13:17 + | +LL | type Item = u32; + | ^^^ +note: required by a bound in `needs_unit_item` + --> $DIR/closure-arg-assoc-type-mismatch.rs:19:24 + | +LL | fn needs_unit_item S>(_f: F) + | --------------- required by a bound in this function +LL | where +LL | F::Output: MyTrait, + | ^^^^^^^^^ required by this bound in `needs_unit_item` + +error[E0271]: type mismatch resolving `::Item == ()` + --> $DIR/closure-arg-assoc-type-mismatch.rs:29:37 + | +LL | needs_unit_item(|| { let _ = 0; x }); + | --------------- -- ^ type mismatch resolving `::Item == ()` + | | | + | | this closure + | required by a bound introduced by this call + | +note: expected this to be `()` + --> $DIR/closure-arg-assoc-type-mismatch.rs:13:17 + | +LL | type Item = u32; + | ^^^ +note: required by a bound in `needs_unit_item` + --> $DIR/closure-arg-assoc-type-mismatch.rs:19:24 + | +LL | fn needs_unit_item S>(_f: F) + | --------------- required by a bound in this function +LL | where +LL | F::Output: MyTrait, + | ^^^^^^^^^ required by this bound in `needs_unit_item` + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0271`. diff --git a/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.next.stderr b/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.next.stderr index eab9bf1ae34a8..2c51d1e9aec4d 100644 --- a/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.next.stderr +++ b/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.next.stderr @@ -13,11 +13,12 @@ note: required by a bound in `find` --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL error[E0271]: type mismatch resolving `<{closure@closure-arg-type-mismatch-issue-45727.rs:6:29} as FnOnce<(&{integer},)>>::Output == bool` - --> $DIR/closure-arg-type-mismatch-issue-45727.rs:6:29 + --> $DIR/closure-arg-type-mismatch-issue-45727.rs:6:38 | LL | let _ = (-10..=10).find(|x: i32| x.signum() == 0); - | ---- ^^^^^^^^^^^^^^^^^^^^^^^^ types differ - | | + | ---- -------- ^^^^^^^^^^^^^^^ types differ + | | | + | | this closure | required by a bound introduced by this call | note: required by a bound in `find` @@ -38,11 +39,12 @@ note: required by a bound in `find` --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL error[E0271]: type mismatch resolving `<{closure@closure-arg-type-mismatch-issue-45727.rs:10:29} as FnOnce<(&{integer},)>>::Output == bool` - --> $DIR/closure-arg-type-mismatch-issue-45727.rs:10:29 + --> $DIR/closure-arg-type-mismatch-issue-45727.rs:10:41 | LL | let _ = (-10..=10).find(|x: &&&i32| x.signum() == 0); - | ---- ^^^^^^^^^^^^^^^^^^^^^^^^^^^ types differ - | | + | ---- ----------- ^^^^^^^^^^^^^^^ types differ + | | | + | | this closure | required by a bound introduced by this call | note: required by a bound in `find` From b7ebb506dd2bb86d6d686297f26363f4eb5d5fbe Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 8 Aug 2026 22:34:31 +0200 Subject: [PATCH 2/9] interpret: treat pattern and unsafe-binder as ABI-transparent --- compiler/rustc_const_eval/src/interpret/call.rs | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_const_eval/src/interpret/call.rs b/compiler/rustc_const_eval/src/interpret/call.rs index f9c21f42d4e5e..87fafc6db589d 100644 --- a/compiler/rustc_const_eval/src/interpret/call.rs +++ b/compiler/rustc_const_eval/src/interpret/call.rs @@ -101,6 +101,13 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { interp_ok(true) } } + // Types that are considered transparent in `unfold_transparent` should also act + // like transparent types here. + ty::Pat(base, _) => self.has_trivial_abi(self.layout_of(base)?), + ty::UnsafeBinder(bound_ty) => { + let ty = self.tcx.instantiate_bound_regions_with_erased(bound_ty.into()); + self.has_trivial_abi(self.layout_of(ty)?) + } ty::Alias(..) => panic!("non-normalized type"), _ => interp_ok(false), @@ -116,8 +123,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { layout: TyAndLayout<'tcx>, may_unfold: impl Fn(AdtDef<'tcx>) -> bool, ) -> InterpResult<'tcx, TyAndLayout<'tcx>> { - match layout.ty.kind() { - ty::Adt(adt_def, _) if adt_def.repr().transparent() && may_unfold(*adt_def) => { + match *layout.ty.kind() { + ty::Adt(adt_def, _) if adt_def.repr().transparent() && may_unfold(adt_def) => { assert_matches!(layout.variants, rustc_abi::Variants::Single { .. }); // Look for non-trivial-ABI field(s). let mut found = None; @@ -142,7 +149,11 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // Recurse. self.unfold_transparent(field, may_unfold) } - ty::Pat(base, _) => interp_ok(self.layout_of(*base)?), + ty::Pat(base, _) => self.unfold_transparent(self.layout_of(base)?, may_unfold), + ty::UnsafeBinder(bound_ty) => { + let ty = self.tcx.instantiate_bound_regions_with_erased(bound_ty.into()); + self.unfold_transparent(self.layout_of(ty)?, may_unfold) + } // Not a transparent type, no further unfolding. _ => interp_ok(layout), } From f2b31009d4e9d22fdb4c08538a554118546e0571 Mon Sep 17 00:00:00 2001 From: Mahdi Ali-Raihan Date: Sat, 18 Jul 2026 18:47:57 -0400 Subject: [PATCH 3/9] avoid re-initializing the spare buffer if we initialized >PROBE_SIZE unfilled bytes in a previous loop --- library/alloc/src/io/read.rs | 39 +++++++++++++++++++++++++++--------- 1 file changed, 30 insertions(+), 9 deletions(-) diff --git a/library/alloc/src/io/read.rs b/library/alloc/src/io/read.rs index c6b802ef9862a..bd09c40e15d61 100644 --- a/library/alloc/src/io/read.rs +++ b/library/alloc/src/io/read.rs @@ -1,4 +1,3 @@ -use core::cmp; use core::mem::{DropGuard, MaybeUninit}; use crate::io::{ @@ -822,8 +821,9 @@ where /// - avoid allocating unless necessary /// - avoid overallocating if we know the exact size (#89165) /// - avoid passing large buffers to readers that always initialize the free capacity if they perform short reads (#23815, #23820) +/// - avoid re-initializing the spare buffer if we initialized >PROBE_SIZE unfilled bytes in a previous loop (#158008) /// - pass large buffers to readers that do not initialize the spare capacity. this can amortize per-call overheads -/// - and finally pass not-too-small and not-too-large buffers to Windows read APIs because they manage to suffer from both problems +/// - pass not-too-small and not-too-large buffers to Windows read APIs because they manage to suffer from both problems /// at the same time, i.e. small reads suffer from syscall overhead, all reads incur costs proportional to buffer size (#110650) #[doc(hidden)] #[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")] @@ -840,6 +840,9 @@ pub fn default_read_to_end( .and_then(|s| s.checked_add(1024)?.checked_next_multiple_of(DEFAULT_BUF_SIZE)) .unwrap_or(DEFAULT_BUF_SIZE); + // Tracks how many bytes are initialized in the buffer + let mut init_until = buf.len(); + const PROBE_SIZE: usize = 32; fn small_probe_read(r: &mut R, buf: &mut Vec) -> Result { @@ -893,10 +896,10 @@ pub fn default_read_to_end( // unnecessary doubling of the capacity. But if not, append the // probe buffer to the primary buffer and let its capacity grow. let read = small_probe_read(r, buf)?; - if read == 0 { return Ok(buf.len() - start_len); } + init_until = buf.len(); } if buf.len() == buf.capacity() { @@ -904,13 +907,25 @@ pub fn default_read_to_end( buf.try_reserve(PROBE_SIZE)?; } + // We set a threshold of >PROBE_SIZE initialized yet unfilled bytes left in the + // spare buffer before determining that we need to initialize more bytes into + // the spare buffer + let buf_len = if init_until > buf.len() + PROBE_SIZE { + init_until - buf.len() + } else { + usize::min(max_read_size, buf.capacity() - buf.len()) + }; + let was_init = init_until >= buf.len() + buf_len; + let mut spare = buf.spare_capacity_mut(); - let buf_len = cmp::min(spare.len(), max_read_size); spare = &mut spare[..buf_len]; let mut read_buf: BorrowedBuf<'_, u8> = spare.into(); - // Note that we don't track already initialized bytes here, but this is fine - // because we explicitly limit the read size + if was_init { + // SAFETY: These bytes were initialized but not filled in the previous loop + unsafe { read_buf.set_init() }; + } + let mut cursor = read_buf.unfilled(); let result = loop { match r.read_buf(cursor.reborrow()) { @@ -924,6 +939,10 @@ pub fn default_read_to_end( let bytes_read = cursor.written(); let is_init = read_buf.is_init(); + if is_init { + init_until = buf.len() + buf_len; + } + // SAFETY: BorrowedBuf's invariants mean this much memory is initialized. unsafe { let new_len = bytes_read + buf.len(); @@ -948,9 +967,11 @@ pub fn default_read_to_end( if !is_init { max_read_size = usize::MAX; } - // we have passed a larger buffer than previously and the - // reader still hasn't returned a short read - else if buf_len >= max_read_size && bytes_read == buf_len { + // the spare buffer has initialized and read in `max_read_size` bytes. + // it's possible that we have more than `max_read_size` bytes to read + // left, so a larger buffer may be necessary to minimize the number of + // iterations of reading in bytes to the buffer + else if bytes_read == max_read_size { max_read_size = max_read_size.saturating_mul(2); } } From 9ebbabccf402793835de2a46976f6c6a9fea8b78 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Sun, 9 Aug 2026 13:00:02 -0400 Subject: [PATCH 4/9] Avoid unnecessarily short reads in `read_to_end` On Windows, the UTF-16 to UTF-8 translation is made simpler by ensuring we don't split code points.: --- library/alloc/src/io/read.rs | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/library/alloc/src/io/read.rs b/library/alloc/src/io/read.rs index bd09c40e15d61..72e73abe3d6c1 100644 --- a/library/alloc/src/io/read.rs +++ b/library/alloc/src/io/read.rs @@ -821,10 +821,11 @@ where /// - avoid allocating unless necessary /// - avoid overallocating if we know the exact size (#89165) /// - avoid passing large buffers to readers that always initialize the free capacity if they perform short reads (#23815, #23820) -/// - avoid re-initializing the spare buffer if we initialized >PROBE_SIZE unfilled bytes in a previous loop (#158008) +/// - avoid re-initializing unfilled bytes into the spare buffer if we initialized >PROBE_SIZE unfilled bytes in a previous loop (#158008) /// - pass large buffers to readers that do not initialize the spare capacity. this can amortize per-call overheads /// - pass not-too-small and not-too-large buffers to Windows read APIs because they manage to suffer from both problems /// at the same time, i.e. small reads suffer from syscall overhead, all reads incur costs proportional to buffer size (#110650) +/// - also avoid <4 byte reads as this may split UTF-8 code points, which can be a problem for Windows console reads (#142847) #[doc(hidden)] #[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")] pub fn default_read_to_end( @@ -890,22 +891,27 @@ pub fn default_read_to_end( } loop { - if buf.len() == buf.capacity() && buf.capacity() == start_cap { + if buf.spare_capacity_mut().len() < PROBE_SIZE && buf.capacity() == start_cap { // The buffer might be an exact fit. Let's read into a probe buffer // and see if it returns `Ok(0)`. If so, we've avoided an // unnecessary doubling of the capacity. But if not, append the // probe buffer to the primary buffer and let its capacity grow. let read = small_probe_read(r, buf)?; + if read == 0 { return Ok(buf.len() - start_len); } + init_until = buf.len(); + // In the case of very short reads, continue to use the stack buffer + // until either we reach the end or we need to reallocate. + continue; } - if buf.len() == buf.capacity() { - // buf is full, need more space - buf.try_reserve(PROBE_SIZE)?; - } + // Avoid unnecessarily short reads by ensuring there's at least PROBE_SIZE space available. + // And assert that PROBE_SIZE is always at least large enough to fit any UTF-8 encoded code point. + const { assert!(PROBE_SIZE >= char::MAX_LEN_UTF8) } + buf.try_reserve(PROBE_SIZE)?; // We set a threshold of >PROBE_SIZE initialized yet unfilled bytes left in the // spare buffer before determining that we need to initialize more bytes into From 9e13b0a69e35a0ec5ea92c9ab0e5cb5ba9fac530 Mon Sep 17 00:00:00 2001 From: Mahdi Ali-Raihan Date: Mon, 10 Aug 2026 12:28:08 -0400 Subject: [PATCH 5/9] Re-calibrate init_until to how many bytes are actually initialized and filled in the buffer when reallocation occurs --- library/alloc/src/io/read.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/library/alloc/src/io/read.rs b/library/alloc/src/io/read.rs index 72e73abe3d6c1..6ca8ff6319eff 100644 --- a/library/alloc/src/io/read.rs +++ b/library/alloc/src/io/read.rs @@ -911,7 +911,12 @@ pub fn default_read_to_end( // Avoid unnecessarily short reads by ensuring there's at least PROBE_SIZE space available. // And assert that PROBE_SIZE is always at least large enough to fit any UTF-8 encoded code point. const { assert!(PROBE_SIZE >= char::MAX_LEN_UTF8) } - buf.try_reserve(PROBE_SIZE)?; + if buf.spare_capacity_mut().len() < PROBE_SIZE { + buf.try_reserve(PROBE_SIZE)?; + // When reallocation occurs, we have to update init_until accordingly + // to re-calibrate how many bytes are actually initialized in the buffer + init_until = buf.len(); + } // We set a threshold of >PROBE_SIZE initialized yet unfilled bytes left in the // spare buffer before determining that we need to initialize more bytes into From b189f6e09faa34282dbf04e6bd567a25940640f7 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Mon, 3 Aug 2026 21:58:01 +1000 Subject: [PATCH 6/9] Move and rename bootstrap's `main.rs` This intermediate commit helps to preserve line history. --- src/bootstrap/Cargo.toml | 2 +- src/bootstrap/src/{bin/main.rs => cli_main.rs} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename src/bootstrap/src/{bin/main.rs => cli_main.rs} (100%) diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml index bdbdbade90fa4..71b6e1fa5bba1 100644 --- a/src/bootstrap/Cargo.toml +++ b/src/bootstrap/Cargo.toml @@ -15,7 +15,7 @@ doctest = false [[bin]] name = "bootstrap" -path = "src/bin/main.rs" +path = "src/cli_main.rs" test = false [[bin]] diff --git a/src/bootstrap/src/bin/main.rs b/src/bootstrap/src/cli_main.rs similarity index 100% rename from src/bootstrap/src/bin/main.rs rename to src/bootstrap/src/cli_main.rs From d14e7c41d721364a7d9015e077e8fcd734a4f506 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Mon, 3 Aug 2026 21:59:23 +1000 Subject: [PATCH 7/9] Make bootstrap's `main.rs` a stub that calls into the library crate If there is non-trivial code in `main.rs`, then any items it touches need to be publicly exported from the library crate. Those public exports make it harder to identify unused code within bootstrap. --- src/bootstrap/Cargo.toml | 2 +- src/bootstrap/src/bin/main.rs | 8 ++++++++ src/bootstrap/src/cli_main.rs | 6 +++--- src/bootstrap/src/lib.rs | 3 +-- 4 files changed, 13 insertions(+), 6 deletions(-) create mode 100644 src/bootstrap/src/bin/main.rs diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml index 71b6e1fa5bba1..bdbdbade90fa4 100644 --- a/src/bootstrap/Cargo.toml +++ b/src/bootstrap/Cargo.toml @@ -15,7 +15,7 @@ doctest = false [[bin]] name = "bootstrap" -path = "src/cli_main.rs" +path = "src/bin/main.rs" test = false [[bin]] diff --git a/src/bootstrap/src/bin/main.rs b/src/bootstrap/src/bin/main.rs new file mode 100644 index 0000000000000..171ef1811ca40 --- /dev/null +++ b/src/bootstrap/src/bin/main.rs @@ -0,0 +1,8 @@ +//! The `main.rs` for bootstrap is a small stub that delegates to the real +//! entry point within the bootstrap library crate. +//! +//! Don't add more code here! Add it to the inner main instead. + +fn main() { + bootstrap::cli_main::main(); +} diff --git a/src/bootstrap/src/cli_main.rs b/src/bootstrap/src/cli_main.rs index 1310255de3ca4..879cf7159fb6b 100644 --- a/src/bootstrap/src/cli_main.rs +++ b/src/bootstrap/src/cli_main.rs @@ -13,7 +13,7 @@ use std::sync::Once; use std::time::Instant; use std::{env, process}; -use bootstrap::{ +use crate::{ Build, CONFIG_CHANGE_HISTORY, ChangeId, Config, Flags, StepStack, Subcommand, debug, find_recent_config_change_ids, human_readable_changes, t, }; @@ -22,9 +22,9 @@ fn is_tracing_enabled() -> bool { cfg!(feature = "tracing") } -fn main() { +pub fn main() { #[cfg(feature = "tracing")] - let guard = bootstrap::setup_tracing("BOOTSTRAP_TRACING"); + let guard = crate::utils::tracing::setup_tracing("BOOTSTRAP_TRACING"); let _start_time = Instant::now(); diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs index a276f0378f450..7c0f2fc0f2937 100644 --- a/src/bootstrap/src/lib.rs +++ b/src/bootstrap/src/lib.rs @@ -39,6 +39,7 @@ use crate::core::config::{BootstrapOverrideLld, DryRun, LlvmLibunwind, TargetSel use crate::utils::exec::{BootstrapCommand, command}; use crate::utils::helpers::{self, dir_is_empty, exe, libdir, set_file_times, split_debuginfo}; +pub mod cli_main; mod core; mod utils; @@ -54,8 +55,6 @@ pub use utils::change_tracker::{ CONFIG_CHANGE_HISTORY, find_recent_config_change_ids, human_readable_changes, }; pub use utils::helpers::{PanicTracker, symlink_dir}; -#[cfg(feature = "tracing")] -pub use utils::tracing::setup_tracing; use crate::core::build_steps::vendor::VENDOR_DIR; From 55050c13e58a93d104b22e25777686e568898339 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Mon, 10 Aug 2026 12:45:49 +1000 Subject: [PATCH 8/9] Tidy imports in `lib.rs` There is no need to re-export anything, so all `pub use` imports can be simplified to `use` and merged with their siblings. --- src/bootstrap/src/lib.rs | 42 ++++++++++++++++++---------------------- 1 file changed, 19 insertions(+), 23 deletions(-) diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs index 7c0f2fc0f2937..f9b29a155eab1 100644 --- a/src/bootstrap/src/lib.rs +++ b/src/bootstrap/src/lib.rs @@ -28,35 +28,31 @@ use std::{env, fs, io, str}; use build_helper::ci::gha; use cc::Tool; use termcolor::{ColorChoice, StandardStream, WriteColor}; -use utils::build_stamp::BuildStamp; -use utils::channel::GitInfo; -use utils::exec::ExecutionContext; - -use crate::core::build_steps::format::InternalRustfmt; -use crate::core::builder; -use crate::core::builder::Kind; -use crate::core::config::{BootstrapOverrideLld, DryRun, LlvmLibunwind, TargetSelection, flags}; -use crate::utils::exec::{BootstrapCommand, command}; -use crate::utils::helpers::{self, dir_is_empty, exe, libdir, set_file_times, split_debuginfo}; - -pub mod cli_main; -mod core; -mod utils; - #[cfg(feature = "tracing")] -pub use core::builder::STEP_SPAN_TARGET; -pub use core::builder::{PathSet, StepStack}; -pub use core::config::flags::{Flags, Subcommand}; -pub use core::config::{ChangeId, Config}; +use tracing::{instrument, span}; +use crate::core::build_steps::format::InternalRustfmt; +use crate::core::build_steps::vendor::VENDOR_DIR; #[cfg(feature = "tracing")] -use tracing::{instrument, span}; -pub use utils::change_tracker::{ +use crate::core::builder::STEP_SPAN_TARGET; +use crate::core::builder::{self, Kind, StepStack}; +use crate::core::config::flags::{Flags, Subcommand}; +use crate::core::config::{ + BootstrapOverrideLld, ChangeId, Config, DryRun, LlvmLibunwind, TargetSelection, flags, +}; +use crate::utils::build_stamp::BuildStamp; +use crate::utils::change_tracker::{ CONFIG_CHANGE_HISTORY, find_recent_config_change_ids, human_readable_changes, }; -pub use utils::helpers::{PanicTracker, symlink_dir}; +use crate::utils::channel::GitInfo; +use crate::utils::exec::{BootstrapCommand, ExecutionContext, command}; +use crate::utils::helpers::{ + self, PanicTracker, dir_is_empty, exe, libdir, set_file_times, split_debuginfo, symlink_dir, +}; -use crate::core::build_steps::vendor::VENDOR_DIR; +pub mod cli_main; +mod core; +mod utils; const LLVM_TOOLS: &[&str] = &[ "llvm-cov", // used to generate coverage report From 599fbed7fe8024cd0a379db74100d97c68c906d6 Mon Sep 17 00:00:00 2001 From: Pieter-Louis Schoeman Date: Tue, 11 Aug 2026 06:48:53 +0000 Subject: [PATCH 9/9] Implement derives for Reborrow and CoerceShared --- .../rustc_builtin_macros/src/deriving/mod.rs | 1 + .../src/deriving/reborrow.rs | 235 ++++++++++++++++++ compiler/rustc_builtin_macros/src/lib.rs | 2 + compiler/rustc_span/src/symbol.rs | 1 + library/core/src/marker.rs | 18 ++ .../feature-gate-reborrow-coerce-shared.rs | 12 +- ...feature-gate-reborrow-coerce-shared.stderr | 33 ++- .../ui/feature-gates/feature-gate-reborrow.rs | 6 +- .../feature-gate-reborrow.stderr | 23 +- tests/ui/reborrow/custom_marker.rs | 17 -- .../ui/reborrow/custom_marker_assign_deref.rs | 2 +- .../reborrow/custom_marker_coerce_shared.rs | 22 -- .../custom_marker_coerce_shared_copy.rs | 5 +- .../custom_marker_coerce_shared_move.rs | 5 +- .../custom_marker_coerce_shared_move.stderr | 2 +- tests/ui/reborrow/custom_marker_deref.rs | 2 +- tests/ui/reborrow/custom_marker_mut_a_b.rs | 2 +- tests/ui/reborrow/custom_marker_mut_self.rs | 2 +- tests/ui/reborrow/custom_marker_mut_self_a.rs | 2 +- tests/ui/reborrow/custom_marker_mut_self_b.rs | 2 +- .../reborrow/custom_marker_two_lifetimes.rs | 8 - .../custom_marker_two_lifetimes.stderr | 8 - tests/ui/reborrow/derive_coerce_shared.rs | 87 +++++++ .../ui/reborrow/derive_coerce_shared_attr.rs | 33 +++ .../reborrow/derive_coerce_shared_attr.stderr | 45 ++++ tests/ui/reborrow/derive_invalid_coherence.rs | 26 ++ .../reborrow/derive_invalid_coherence.stderr | 33 +++ .../ui/reborrow/derive_manual_equivalence.rs | 42 ++++ .../ui/reborrow/derive_multiple_lifetimes.rs | 69 +++++ .../reborrow/derive_multiple_lifetimes.stderr | 37 +++ tests/ui/reborrow/derive_reborrow.rs | 50 ++++ tests/ui/reborrow/derive_unsupported_items.rs | 33 +++ .../reborrow/derive_unsupported_items.stderr | 27 ++ 33 files changed, 820 insertions(+), 72 deletions(-) create mode 100644 compiler/rustc_builtin_macros/src/deriving/reborrow.rs delete mode 100644 tests/ui/reborrow/custom_marker.rs delete mode 100644 tests/ui/reborrow/custom_marker_coerce_shared.rs delete mode 100644 tests/ui/reborrow/custom_marker_two_lifetimes.rs delete mode 100644 tests/ui/reborrow/custom_marker_two_lifetimes.stderr create mode 100644 tests/ui/reborrow/derive_coerce_shared.rs create mode 100644 tests/ui/reborrow/derive_coerce_shared_attr.rs create mode 100644 tests/ui/reborrow/derive_coerce_shared_attr.stderr create mode 100644 tests/ui/reborrow/derive_invalid_coherence.rs create mode 100644 tests/ui/reborrow/derive_invalid_coherence.stderr create mode 100644 tests/ui/reborrow/derive_manual_equivalence.rs create mode 100644 tests/ui/reborrow/derive_multiple_lifetimes.rs create mode 100644 tests/ui/reborrow/derive_multiple_lifetimes.stderr create mode 100644 tests/ui/reborrow/derive_reborrow.rs create mode 100644 tests/ui/reborrow/derive_unsupported_items.rs create mode 100644 tests/ui/reborrow/derive_unsupported_items.stderr diff --git a/compiler/rustc_builtin_macros/src/deriving/mod.rs b/compiler/rustc_builtin_macros/src/deriving/mod.rs index 9540ade194327..cef45435cb88a 100644 --- a/compiler/rustc_builtin_macros/src/deriving/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/mod.rs @@ -25,6 +25,7 @@ pub(crate) mod debug; pub(crate) mod default; pub(crate) mod from; pub(crate) mod hash; +pub(crate) mod reborrow; #[path = "cmp/eq.rs"] pub(crate) mod eq; diff --git a/compiler/rustc_builtin_macros/src/deriving/reborrow.rs b/compiler/rustc_builtin_macros/src/deriving/reborrow.rs new file mode 100644 index 0000000000000..9dc1ccf4fd8e6 --- /dev/null +++ b/compiler/rustc_builtin_macros/src/deriving/reborrow.rs @@ -0,0 +1,235 @@ +use rustc_ast::{ + self as ast, AttrArgs, GenericArg, GenericParamKind, Generics, ItemKind, MetaItem, token, +}; +use rustc_errors::E0802; +use rustc_expand::base::{Annotatable, ExtCtxt}; +use rustc_macros::Diagnostic; +use rustc_span::{Ident, Span, Symbol, sym}; +use thin_vec::ThinVec; + +macro_rules! path { + ($span:expr, $($part:ident)::*) => { vec![$(Ident::new(sym::$part, $span),)*] } +} + +pub(crate) fn expand_deriving_reborrow( + cx: &ExtCtxt<'_>, + span: Span, + _mitem: &MetaItem, + item: &Annotatable, + push: &mut dyn FnMut(Annotatable), + _is_const: bool, +) { + let Some((ident, generics)) = struct_def(cx, span, item, sym::Reborrow) else { + return; + }; + + push_marker_impl(cx, span, ident, generics, sym::Reborrow, Vec::new(), push); +} + +pub(crate) fn expand_deriving_coerce_shared( + cx: &ExtCtxt<'_>, + span: Span, + _mitem: &MetaItem, + item: &Annotatable, + push: &mut dyn FnMut(Annotatable), + _is_const: bool, +) { + let Some((ident, generics)) = struct_def(cx, span, item, sym::CoerceShared) else { + return; + }; + let Some(target) = coerce_shared_target(cx, span, item) else { + return; + }; + + push_marker_impl( + cx, + span, + ident, + generics, + sym::CoerceShared, + vec![GenericArg::Type(target)], + push, + ); +} + +fn struct_def<'a>( + cx: &ExtCtxt<'_>, + span: Span, + item: &'a Annotatable, + trait_name: Symbol, +) -> Option<(Ident, &'a Generics)> { + match item { + Annotatable::Item(item) => match &item.kind { + ItemKind::Struct(ident, generics, _) => Some((*ident, generics)), + ItemKind::Enum(..) => { + cx.dcx().emit_err(UnsupportedItem { span, trait_name, kind: "enum" }); + None + } + ItemKind::Union(..) => { + cx.dcx().emit_err(UnsupportedItem { span, trait_name, kind: "union" }); + None + } + _ => { + cx.dcx().emit_err(UnsupportedItem { span, trait_name, kind: "item" }); + None + } + }, + _ => { + cx.dcx().emit_err(UnsupportedItem { span, trait_name, kind: "item" }); + None + } + } +} + +fn coerce_shared_target(cx: &ExtCtxt<'_>, span: Span, item: &Annotatable) -> Option> { + let Annotatable::Item(item) = item else { + cx.dcx().emit_err(MissingTarget { span }); + return None; + }; + + let mut attrs = item.attrs.iter().filter(|attr| attr.has_name(sym::coerce_shared)); + let Some(attr) = attrs.next() else { + cx.dcx().emit_err(MissingTarget { span }); + return None; + }; + if let Some(duplicate) = attrs.next() { + cx.dcx().emit_err(DuplicateTarget { first: attr.span, duplicate: duplicate.span }); + return None; + } + + let AttrArgs::Delimited(args) = &attr.get_normal_item().args else { + cx.dcx().emit_err(MalformedTarget { span: attr.span }); + return None; + }; + if args.delim != token::Delimiter::Parenthesis || args.tokens.is_empty() { + cx.dcx().emit_err(MalformedTarget { span: attr.span }); + return None; + } + + let mut parser = cx.new_parser_from_tts(args.tokens.clone()); + let target = match parser.parse_ty() { + Ok(target) => target, + Err(err) => { + err.cancel(); + cx.dcx().emit_err(MalformedTarget { span: attr.span }); + return None; + } + }; + if parser.token != token::Eof { + cx.dcx().emit_err(MalformedTarget { span: attr.span }); + return None; + } + + Some(target) +} + +fn push_marker_impl( + cx: &ExtCtxt<'_>, + span: Span, + ident: Ident, + generics: &Generics, + trait_name: Symbol, + trait_args: Vec, + push: &mut dyn FnMut(Annotatable), +) { + let mut trait_parts = path!(span, core::marker); + trait_parts.push(Ident::new(trait_name, span)); + let trait_path = cx.path_all(span, true, trait_parts, trait_args); + let trait_ref = cx.trait_ref(trait_path); + + let self_params: Vec<_> = generics + .params + .iter() + .map(|param| match param.kind { + GenericParamKind::Lifetime => { + GenericArg::Lifetime(cx.lifetime(param.span(), param.ident)) + } + GenericParamKind::Type { .. } => { + GenericArg::Type(cx.ty_ident(param.span(), param.ident)) + } + GenericParamKind::Const { .. } => { + GenericArg::Const(cx.const_ident(param.span(), param.ident)) + } + }) + .collect(); + let self_ty = cx.ty_path(cx.path_all(span, false, vec![ident], self_params)); + + push(Annotatable::Item(cx.item( + span, + thin_vec::thin_vec![cx.attr_word(sym::automatically_derived, span)], + ast::ItemKind::Impl(ast::Impl { + generics: impl_generics(cx, generics), + of_trait: Some(Box::new(ast::TraitImplHeader { + safety: ast::Safety::Default, + polarity: ast::ImplPolarity::Positive, + defaultness: ast::Defaultness::Implicit, + trait_ref, + })), + constness: ast::Const::No, + self_ty, + items: ThinVec::new(), + }), + ))); +} + +fn impl_generics(cx: &ExtCtxt<'_>, generics: &Generics) -> Generics { + // Rebuild the generic parameter declarations because defaults are allowed on structs but + // rejected on impls. Preserve lifetime, type, and const parameters and their bounds, const + // parameter types, and the where-clause, while omitting type and const defaults. + Generics { + params: generics + .params + .iter() + .map(|param| match ¶m.kind { + GenericParamKind::Lifetime => { + cx.lifetime_param(param.span(), param.ident, param.bounds.clone()) + } + GenericParamKind::Type { default: _ } => { + cx.typaram(param.span(), param.ident, param.bounds.clone(), None) + } + GenericParamKind::Const { ty, span: _, default: _ } => cx.const_param( + param.span(), + param.ident, + param.bounds.clone(), + ty.clone(), + None, + ), + }) + .collect(), + where_clause: generics.where_clause.clone(), + span: generics.span, + } +} + +#[derive(Diagnostic)] +#[diag("`derive({$trait_name})` is only supported for structs, not {$kind}s", code = E0802)] +struct UnsupportedItem { + #[primary_span] + span: Span, + trait_name: Symbol, + kind: &'static str, +} + +#[derive(Diagnostic)] +#[diag("`derive(CoerceShared)` requires exactly one `#[coerce_shared(Target)]` attribute", code = E0802)] +struct MissingTarget { + #[primary_span] + span: Span, +} + +#[derive(Diagnostic)] +#[diag("duplicate `#[coerce_shared(Target)]` attribute for `derive(CoerceShared)`", code = E0802)] +struct DuplicateTarget { + #[primary_span] + duplicate: Span, + #[note("first `#[coerce_shared(Target)]` attribute is here")] + first: Span, +} + +#[derive(Diagnostic)] +#[diag("malformed `#[coerce_shared(Target)]` attribute for `derive(CoerceShared)`", code = E0802)] +#[note("expected a single target type, for example `#[coerce_shared(Target<'a, T>)]`")] +struct MalformedTarget { + #[primary_span] + span: Span, +} diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs index 78bf7d97bd7b8..8f8d8b3149440 100644 --- a/compiler/rustc_builtin_macros/src/lib.rs +++ b/compiler/rustc_builtin_macros/src/lib.rs @@ -130,6 +130,7 @@ pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) { register_derive! { Clone: clone::expand_deriving_clone, + CoerceShared: reborrow::expand_deriving_coerce_shared, Copy: bounds::expand_deriving_copy, ConstParamTy: bounds::expand_deriving_const_param_ty, Debug: debug::expand_deriving_debug, @@ -140,6 +141,7 @@ pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) { PartialEq: partial_eq::expand_deriving_partial_eq, PartialOrd: partial_ord::expand_deriving_partial_ord, CoercePointee: coerce_pointee::expand_deriving_coerce_pointee, + Reborrow: reborrow::expand_deriving_reborrow, From: from::expand_deriving_from, } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 8d6661ca1194b..33142341b15d4 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -188,6 +188,7 @@ symbols! { Clone, CoercePointee, CoercePointeeValidated, + CoerceShared, CoerceUnsized, Const, ConstParamTy, diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs index a1a1ec56d14a1..1eea7adf1a6d5 100644 --- a/library/core/src/marker.rs +++ b/library/core/src/marker.rs @@ -1373,6 +1373,14 @@ pub trait Reborrow { /* compiler built-in */ } +/// Derive macro generating an impl of the trait `Reborrow`. +#[rustc_builtin_macro(Reborrow)] +#[allow_internal_unstable(reborrow)] +#[unstable(feature = "reborrow", issue = "145612")] +pub macro Reborrow($item:item) { + /* compiler built-in */ +} + /// Allows reborrowable value to be reborrowed as shared, creating a copy /// that disables the source for writes for the lifetime of the copy. #[lang = "coerce_shared"] @@ -1380,3 +1388,13 @@ pub trait Reborrow { pub trait CoerceShared: Reborrow { /* compiler built-in */ } + +/// Derive macro generating an impl of the trait `CoerceShared`. +/// +/// The shared target type must be specified with `#[coerce_shared(Target)]`. +#[rustc_builtin_macro(CoerceShared, attributes(coerce_shared))] +#[allow_internal_unstable(reborrow)] +#[unstable(feature = "reborrow", issue = "145612")] +pub macro CoerceShared($item:item) { + /* compiler built-in */ +} diff --git a/tests/ui/feature-gates/feature-gate-reborrow-coerce-shared.rs b/tests/ui/feature-gates/feature-gate-reborrow-coerce-shared.rs index 48a14959d8d64..a79669e817008 100644 --- a/tests/ui/feature-gates/feature-gate-reborrow-coerce-shared.rs +++ b/tests/ui/feature-gates/feature-gate-reborrow-coerce-shared.rs @@ -1,3 +1,13 @@ -use std::marker::CoerceShared; //~ ERROR use of unstable library feature `reborrow` +use std::marker::CoerceShared; //~ ERROR use of unstable library feature `reborrow` +//~^ ERROR use of unstable library feature `reborrow` + +#[derive(Clone, Copy)] +struct CustomRef<'a>(&'a ()); + +#[derive(std::marker::Reborrow, std::marker::CoerceShared)] +//~^ ERROR use of unstable library feature `reborrow` +//~| ERROR use of unstable library feature `reborrow` +#[coerce_shared(CustomRef<'a>)] +struct CustomMut<'a>(&'a mut ()); fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-reborrow-coerce-shared.stderr b/tests/ui/feature-gates/feature-gate-reborrow-coerce-shared.stderr index c4c5e06778af3..36d6a627221fd 100644 --- a/tests/ui/feature-gates/feature-gate-reborrow-coerce-shared.stderr +++ b/tests/ui/feature-gates/feature-gate-reborrow-coerce-shared.stderr @@ -1,3 +1,33 @@ +error[E0658]: use of unstable library feature `reborrow` + --> $DIR/feature-gate-reborrow-coerce-shared.rs:7:10 + | +LL | #[derive(std::marker::Reborrow, std::marker::CoerceShared)] + | ^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #145612 for more information + = help: add `#![feature(reborrow)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: use of unstable library feature `reborrow` + --> $DIR/feature-gate-reborrow-coerce-shared.rs:7:33 + | +LL | #[derive(std::marker::Reborrow, std::marker::CoerceShared)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #145612 for more information + = help: add `#![feature(reborrow)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: use of unstable library feature `reborrow` + --> $DIR/feature-gate-reborrow-coerce-shared.rs:1:5 + | +LL | use std::marker::CoerceShared; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #145612 for more information + = help: add `#![feature(reborrow)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + error[E0658]: use of unstable library feature `reborrow` --> $DIR/feature-gate-reborrow-coerce-shared.rs:1:5 | @@ -7,7 +37,8 @@ LL | use std::marker::CoerceShared; = note: see issue #145612 for more information = help: add `#![feature(reborrow)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error: aborting due to 1 previous error +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/feature-gates/feature-gate-reborrow.rs b/tests/ui/feature-gates/feature-gate-reborrow.rs index f016f6c6bfa59..1b0bfafeae99c 100644 --- a/tests/ui/feature-gates/feature-gate-reborrow.rs +++ b/tests/ui/feature-gates/feature-gate-reborrow.rs @@ -1,3 +1,7 @@ -use std::marker::Reborrow; //~ ERROR use of unstable library feature `reborrow` +use std::marker::Reborrow; //~ ERROR use of unstable library feature `reborrow` +//~^ ERROR use of unstable library feature `reborrow` + +#[derive(std::marker::Reborrow)] //~ ERROR use of unstable library feature `reborrow` +struct CustomMut<'a>(&'a mut ()); fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-reborrow.stderr b/tests/ui/feature-gates/feature-gate-reborrow.stderr index 5e3033f3bf1fe..a5102ac0813ed 100644 --- a/tests/ui/feature-gates/feature-gate-reborrow.stderr +++ b/tests/ui/feature-gates/feature-gate-reborrow.stderr @@ -1,3 +1,23 @@ +error[E0658]: use of unstable library feature `reborrow` + --> $DIR/feature-gate-reborrow.rs:4:10 + | +LL | #[derive(std::marker::Reborrow)] + | ^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #145612 for more information + = help: add `#![feature(reborrow)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: use of unstable library feature `reborrow` + --> $DIR/feature-gate-reborrow.rs:1:5 + | +LL | use std::marker::Reborrow; + | ^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #145612 for more information + = help: add `#![feature(reborrow)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + error[E0658]: use of unstable library feature `reborrow` --> $DIR/feature-gate-reborrow.rs:1:5 | @@ -7,7 +27,8 @@ LL | use std::marker::Reborrow; = note: see issue #145612 for more information = help: add `#![feature(reborrow)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error: aborting due to 1 previous error +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/reborrow/custom_marker.rs b/tests/ui/reborrow/custom_marker.rs deleted file mode 100644 index 80689d81d0cc1..0000000000000 --- a/tests/ui/reborrow/custom_marker.rs +++ /dev/null @@ -1,17 +0,0 @@ -//@ run-pass - -#![feature(reborrow)] -use std::marker::{Reborrow, PhantomData}; - -struct CustomMarker<'a>(PhantomData<&'a ()>); -impl<'a> Reborrow for CustomMarker<'a> {} - -fn method<'a>(_a: CustomMarker<'a>) -> &'a () { - &() -} - -fn main() { - let a = CustomMarker(PhantomData); - let _ = method(a); - let _ = method(a); -} diff --git a/tests/ui/reborrow/custom_marker_assign_deref.rs b/tests/ui/reborrow/custom_marker_assign_deref.rs index 79ea2a35acdaf..9c0501644f83b 100644 --- a/tests/ui/reborrow/custom_marker_assign_deref.rs +++ b/tests/ui/reborrow/custom_marker_assign_deref.rs @@ -3,8 +3,8 @@ #![feature(reborrow)] use std::marker::{Reborrow, PhantomData}; +#[derive(Reborrow)] struct CustomMarker<'a>(PhantomData<&'a ()>); -impl<'a> Reborrow for CustomMarker<'a> {} impl<'a> std::ops::Deref for CustomMarker<'a> { type Target = CustomMarker<'a>; diff --git a/tests/ui/reborrow/custom_marker_coerce_shared.rs b/tests/ui/reborrow/custom_marker_coerce_shared.rs deleted file mode 100644 index 17c7bac98d17a..0000000000000 --- a/tests/ui/reborrow/custom_marker_coerce_shared.rs +++ /dev/null @@ -1,22 +0,0 @@ -//@ run-pass - -#![feature(reborrow)] -use std::marker::{CoerceShared, PhantomData, Reborrow}; - -struct CustomMarker<'a>(PhantomData<&'a ()>); -impl<'a> Reborrow for CustomMarker<'a> {} -#[derive(Debug, Clone, Copy)] -struct CustomMarkerRef<'a>(PhantomData<&'a ()>); -impl<'a> CoerceShared> for CustomMarker<'a> {} - - -fn method<'a>(_a: CustomMarkerRef<'a>) -> &'a () { - &() -} - -fn main() { - let a = CustomMarker(PhantomData); - let b = method(a); - let c = method(a); - let _ = (b, c); -} diff --git a/tests/ui/reborrow/custom_marker_coerce_shared_copy.rs b/tests/ui/reborrow/custom_marker_coerce_shared_copy.rs index 56bc1f896da0f..b84b63234b8c2 100644 --- a/tests/ui/reborrow/custom_marker_coerce_shared_copy.rs +++ b/tests/ui/reborrow/custom_marker_coerce_shared_copy.rs @@ -3,12 +3,11 @@ #![feature(reborrow)] use std::marker::{CoerceShared, PhantomData, Reborrow}; +#[derive(Reborrow, CoerceShared)] +#[coerce_shared(CustomMarkerRef<'a>)] struct CustomMarker<'a>(PhantomData<&'a ()>); -impl<'a> Reborrow for CustomMarker<'a> {} #[derive(Debug, Clone, Copy)] struct CustomMarkerRef<'a>(PhantomData<&'a ()>); -impl<'a> CoerceShared> for CustomMarker<'a> {} - fn method<'a>(_a: CustomMarkerRef<'a>) -> &'a () { &() diff --git a/tests/ui/reborrow/custom_marker_coerce_shared_move.rs b/tests/ui/reborrow/custom_marker_coerce_shared_move.rs index 532d13da258c8..027e45bd5ba49 100644 --- a/tests/ui/reborrow/custom_marker_coerce_shared_move.rs +++ b/tests/ui/reborrow/custom_marker_coerce_shared_move.rs @@ -1,12 +1,11 @@ #![feature(reborrow)] use std::marker::{CoerceShared, PhantomData, Reborrow}; +#[derive(Reborrow, CoerceShared)] +#[coerce_shared(CustomMarkerRef<'a>)] struct CustomMarker<'a>(PhantomData<&'a ()>); -impl<'a> Reborrow for CustomMarker<'a> {} #[derive(Clone, Copy)] struct CustomMarkerRef<'a>(PhantomData<&'a ()>); -impl<'a> CoerceShared> for CustomMarker<'a> {} - fn method<'a>(_a: CustomMarkerRef<'a>) -> &'a () { &() diff --git a/tests/ui/reborrow/custom_marker_coerce_shared_move.stderr b/tests/ui/reborrow/custom_marker_coerce_shared_move.stderr index 90382af3ce30e..0089c03e36c77 100644 --- a/tests/ui/reborrow/custom_marker_coerce_shared_move.stderr +++ b/tests/ui/reborrow/custom_marker_coerce_shared_move.stderr @@ -1,5 +1,5 @@ error[E0505]: cannot move out of `a` because it is borrowed - --> $DIR/custom_marker_coerce_shared_move.rs:19:14 + --> $DIR/custom_marker_coerce_shared_move.rs:18:14 | LL | let a = CustomMarker(PhantomData); | - binding `a` declared here diff --git a/tests/ui/reborrow/custom_marker_deref.rs b/tests/ui/reborrow/custom_marker_deref.rs index 74b9bac22ed0e..3dcf26d6829d1 100644 --- a/tests/ui/reborrow/custom_marker_deref.rs +++ b/tests/ui/reborrow/custom_marker_deref.rs @@ -3,8 +3,8 @@ #![feature(reborrow)] use std::marker::{Reborrow, PhantomData}; +#[derive(Reborrow)] struct CustomMarker<'a>(PhantomData<&'a ()>); -impl<'a> Reborrow for CustomMarker<'a> {} fn method<'a>(_a: CustomMarker<'a>) -> &'a () { &() diff --git a/tests/ui/reborrow/custom_marker_mut_a_b.rs b/tests/ui/reborrow/custom_marker_mut_a_b.rs index 3baf320b583b7..ebed96096b206 100644 --- a/tests/ui/reborrow/custom_marker_mut_a_b.rs +++ b/tests/ui/reborrow/custom_marker_mut_a_b.rs @@ -1,8 +1,8 @@ #![feature(reborrow)] use std::marker::{Reborrow, PhantomData}; +#[derive(Reborrow)] struct CustomMarker<'a>(PhantomData<&'a ()>); -impl<'a> Reborrow for CustomMarker<'a> {} fn method<'a>(_a: CustomMarker<'a>) -> &'a () { &() diff --git a/tests/ui/reborrow/custom_marker_mut_self.rs b/tests/ui/reborrow/custom_marker_mut_self.rs index a688f503517d0..c4c4485f81671 100644 --- a/tests/ui/reborrow/custom_marker_mut_self.rs +++ b/tests/ui/reborrow/custom_marker_mut_self.rs @@ -1,8 +1,8 @@ #![feature(reborrow)] use std::marker::{Reborrow, PhantomData}; +#[derive(Reborrow)] struct CustomMarker<'a>(PhantomData<&'a ()>); -impl<'a> Reborrow for CustomMarker<'a> {} fn method<'a>(_a: CustomMarker<'a>) -> &'a () { &() diff --git a/tests/ui/reborrow/custom_marker_mut_self_a.rs b/tests/ui/reborrow/custom_marker_mut_self_a.rs index f4cc8defb05e6..64cc107eef829 100644 --- a/tests/ui/reborrow/custom_marker_mut_self_a.rs +++ b/tests/ui/reborrow/custom_marker_mut_self_a.rs @@ -1,8 +1,8 @@ #![feature(reborrow)] use std::marker::{Reborrow, PhantomData}; +#[derive(Reborrow)] struct CustomMarker<'a>(PhantomData<&'a ()>); -impl<'a> Reborrow for CustomMarker<'a> {} fn method<'a>(_a: CustomMarker<'a>) -> &'a () { &() diff --git a/tests/ui/reborrow/custom_marker_mut_self_b.rs b/tests/ui/reborrow/custom_marker_mut_self_b.rs index 16356954908b0..3a4baeb241677 100644 --- a/tests/ui/reborrow/custom_marker_mut_self_b.rs +++ b/tests/ui/reborrow/custom_marker_mut_self_b.rs @@ -1,8 +1,8 @@ #![feature(reborrow)] use std::marker::{Reborrow, PhantomData}; +#[derive(Reborrow)] struct CustomMarker<'a>(PhantomData<&'a ()>); -impl<'a> Reborrow for CustomMarker<'a> {} fn method<'a>(_a: CustomMarker<'a>) -> &'a () { &() diff --git a/tests/ui/reborrow/custom_marker_two_lifetimes.rs b/tests/ui/reborrow/custom_marker_two_lifetimes.rs deleted file mode 100644 index d03282145054d..0000000000000 --- a/tests/ui/reborrow/custom_marker_two_lifetimes.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(reborrow)] -use std::marker::{Reborrow, PhantomData}; - -struct CustomMarker<'a, 'b>(PhantomData<&'a mut ()>, PhantomData<&'b ()>); -impl<'a, 'b> Reborrow for CustomMarker<'a, 'b> {} -//~^ ERROR: implementing `Reborrow` requires that a single lifetime parameter is passed between source and target - -fn main() {} diff --git a/tests/ui/reborrow/custom_marker_two_lifetimes.stderr b/tests/ui/reborrow/custom_marker_two_lifetimes.stderr deleted file mode 100644 index ce5c4d09aeb79..0000000000000 --- a/tests/ui/reborrow/custom_marker_two_lifetimes.stderr +++ /dev/null @@ -1,8 +0,0 @@ -error: implementing `Reborrow` requires that a single lifetime parameter is passed between source and target - --> $DIR/custom_marker_two_lifetimes.rs:5:1 - | -LL | impl<'a, 'b> Reborrow for CustomMarker<'a, 'b> {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 1 previous error - diff --git a/tests/ui/reborrow/derive_coerce_shared.rs b/tests/ui/reborrow/derive_coerce_shared.rs new file mode 100644 index 0000000000000..4a4e2d609deee --- /dev/null +++ b/tests/ui/reborrow/derive_coerce_shared.rs @@ -0,0 +1,87 @@ +//@ run-pass + +#![feature(reborrow)] +#![allow(dead_code)] + +use std::marker::{CoerceShared, PhantomData, Reborrow}; + +struct CustomRef<'a, T> { + value: &'a T, +} +impl<'a, T> Clone for CustomRef<'a, T> { + fn clone(&self) -> Self { + *self + } +} +impl<'a, T> Copy for CustomRef<'a, T> {} + +#[derive(Reborrow, CoerceShared)] +#[coerce_shared(CustomRef<'a, T>)] +struct CustomMut<'a, T> { + value: &'a mut T, +} + +struct TupleRef<'a, T>(&'a T); +impl<'a, T> Clone for TupleRef<'a, T> { + fn clone(&self) -> Self { + Self(self.0) + } +} +impl<'a, T> Copy for TupleRef<'a, T> {} + +#[derive(Reborrow, CoerceShared)] +#[coerce_shared(TupleRef<'a, T>)] +struct TupleMut<'a, T>(&'a mut T); + +struct ArrayRef<'a, T, const N: usize>(&'a [T; N]); +impl<'a, T, const N: usize> Clone for ArrayRef<'a, T, N> { + fn clone(&self) -> Self { + Self(self.0) + } +} +impl<'a, T, const N: usize> Copy for ArrayRef<'a, T, N> {} + +#[derive(Reborrow, CoerceShared)] +#[coerce_shared(ArrayRef<'a, T, N>)] +struct ArrayMut<'a, T, const N: usize>(&'a mut [T; N]); + +#[derive(Clone, Copy)] +struct MarkerRef<'a>(PhantomData<&'a ()>); + +#[derive(Reborrow, CoerceShared)] +#[coerce_shared(MarkerRef<'a>)] +struct MarkerMut<'a>(PhantomData<&'a ()>); + +#[derive(Clone, Copy)] +struct SharedOnlyRef<'a>(&'a ()); + +#[derive(CoerceShared)] +#[coerce_shared(SharedOnlyRef<'a>)] +struct SharedOnlyMut<'a>(&'a mut ()); +impl<'a> Reborrow for SharedOnlyMut<'a> {} + +fn take_custom(_: CustomRef<'_, ()>) {} +fn take_tuple(_: TupleRef<'_, ()>) {} +fn take_array(_: ArrayRef<'_, (), 1>) {} +fn take_marker<'a>(_: MarkerRef<'a>) -> &'a () { + &() +} +fn take_shared_only(_: SharedOnlyRef<'_>) {} + +fn main() { + let custom = CustomMut { value: &mut () }; + take_custom(custom); + + let tuple = TupleMut(&mut ()); + take_tuple(tuple); + + let array = ArrayMut(&mut [()]); + take_array(array); + + let marker = MarkerMut(PhantomData); + let _ = take_marker(marker); + let _ = take_marker(marker); + + let shared_only = SharedOnlyMut(&mut ()); + take_shared_only(shared_only); +} diff --git a/tests/ui/reborrow/derive_coerce_shared_attr.rs b/tests/ui/reborrow/derive_coerce_shared_attr.rs new file mode 100644 index 0000000000000..dc9209fe4ba9c --- /dev/null +++ b/tests/ui/reborrow/derive_coerce_shared_attr.rs @@ -0,0 +1,33 @@ +#![feature(reborrow)] + +use std::marker::{CoerceShared, Reborrow}; + +#[derive(Reborrow, CoerceShared)] +//~^ ERROR `derive(CoerceShared)` requires exactly one `#[coerce_shared(Target)]` attribute +struct MissingTarget<'a>(&'a mut ()); + +#[derive(Reborrow, CoerceShared)] +#[coerce_shared(Target<'a>)] +#[coerce_shared(Target<'a>)] +//~^ ERROR duplicate `#[coerce_shared(Target)]` attribute for `derive(CoerceShared)` +struct DuplicateTarget<'a>(&'a mut ()); + +#[derive(Reborrow, CoerceShared)] +#[coerce_shared] +//~^ ERROR malformed `#[coerce_shared(Target)]` attribute for `derive(CoerceShared)` +struct MalformedTargetWord<'a>(&'a mut ()); + +#[derive(Reborrow, CoerceShared)] +#[coerce_shared()] +//~^ ERROR malformed `#[coerce_shared(Target)]` attribute for `derive(CoerceShared)` +struct MalformedTargetEmpty<'a>(&'a mut ()); + +#[derive(Reborrow, CoerceShared)] +#[coerce_shared(Target<'a>, Target<'a>)] +//~^ ERROR malformed `#[coerce_shared(Target)]` attribute for `derive(CoerceShared)` +struct MalformedTargetList<'a>(&'a mut ()); + +#[derive(Clone, Copy)] +struct Target<'a>(&'a ()); + +fn main() {} diff --git a/tests/ui/reborrow/derive_coerce_shared_attr.stderr b/tests/ui/reborrow/derive_coerce_shared_attr.stderr new file mode 100644 index 0000000000000..13f4f498f2189 --- /dev/null +++ b/tests/ui/reborrow/derive_coerce_shared_attr.stderr @@ -0,0 +1,45 @@ +error[E0802]: `derive(CoerceShared)` requires exactly one `#[coerce_shared(Target)]` attribute + --> $DIR/derive_coerce_shared_attr.rs:5:20 + | +LL | #[derive(Reborrow, CoerceShared)] + | ^^^^^^^^^^^^ + +error[E0802]: duplicate `#[coerce_shared(Target)]` attribute for `derive(CoerceShared)` + --> $DIR/derive_coerce_shared_attr.rs:11:1 + | +LL | #[coerce_shared(Target<'a>)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: first `#[coerce_shared(Target)]` attribute is here + --> $DIR/derive_coerce_shared_attr.rs:10:1 + | +LL | #[coerce_shared(Target<'a>)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0802]: malformed `#[coerce_shared(Target)]` attribute for `derive(CoerceShared)` + --> $DIR/derive_coerce_shared_attr.rs:16:1 + | +LL | #[coerce_shared] + | ^^^^^^^^^^^^^^^^ + | + = note: expected a single target type, for example `#[coerce_shared(Target<'a, T>)]` + +error[E0802]: malformed `#[coerce_shared(Target)]` attribute for `derive(CoerceShared)` + --> $DIR/derive_coerce_shared_attr.rs:21:1 + | +LL | #[coerce_shared()] + | ^^^^^^^^^^^^^^^^^^ + | + = note: expected a single target type, for example `#[coerce_shared(Target<'a, T>)]` + +error[E0802]: malformed `#[coerce_shared(Target)]` attribute for `derive(CoerceShared)` + --> $DIR/derive_coerce_shared_attr.rs:26:1 + | +LL | #[coerce_shared(Target<'a>, Target<'a>)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: expected a single target type, for example `#[coerce_shared(Target<'a, T>)]` + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0802`. diff --git a/tests/ui/reborrow/derive_invalid_coherence.rs b/tests/ui/reborrow/derive_invalid_coherence.rs new file mode 100644 index 0000000000000..c1680a964618e --- /dev/null +++ b/tests/ui/reborrow/derive_invalid_coherence.rs @@ -0,0 +1,26 @@ +#![feature(reborrow)] + +use std::marker::{CoerceShared, PhantomData, Reborrow}; + +#[derive(Reborrow)] +//~^ ERROR implementing `Reborrow` requires that a single lifetime parameter is passed between source and target +struct TooManyLifetimes<'a, 'b>(PhantomData<(&'a (), &'b ())>); + +#[derive(Clone, Copy)] +struct BadTarget<'a>(&'a ()); +//~^ ERROR implementing `CoerceShared` requires corresponding fields to match + +#[derive(Reborrow, CoerceShared)] +#[coerce_shared(BadTarget<'a>)] +struct BadSource<'a>(&'a mut u32); + +struct NotCopy; + +#[derive(Reborrow)] +struct NotCopyField<'a> { + field: NotCopy, + //~^ ERROR the trait bound `NotCopy: Copy` is not satisfied + marker: PhantomData<&'a ()>, +} + +fn main() {} diff --git a/tests/ui/reborrow/derive_invalid_coherence.stderr b/tests/ui/reborrow/derive_invalid_coherence.stderr new file mode 100644 index 0000000000000..9bbb5f6395524 --- /dev/null +++ b/tests/ui/reborrow/derive_invalid_coherence.stderr @@ -0,0 +1,33 @@ +error: implementing `Reborrow` requires that a single lifetime parameter is passed between source and target + --> $DIR/derive_invalid_coherence.rs:5:10 + | +LL | #[derive(Reborrow)] + | ^^^^^^^^ + +error[E0277]: the trait bound `NotCopy: Copy` is not satisfied + --> $DIR/derive_invalid_coherence.rs:21:5 + | +LL | field: NotCopy, + | ^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `NotCopy` + | +help: consider annotating `NotCopy` with `#[derive(Copy)]` + | +LL + #[derive(Copy)] +LL | struct NotCopy; + | + +error: implementing `CoerceShared` requires corresponding fields to match, be reborrowable with `CoerceShared`, or coerce a mutable reference field to a shared reference field + --> $DIR/derive_invalid_coherence.rs:10:22 + | +LL | struct BadTarget<'a>(&'a ()); + | ^^^^^^ target field `0` has type `&'a ()` +... +LL | #[derive(Reborrow, CoerceShared)] + | ------------ required by this `CoerceShared` implementation +LL | #[coerce_shared(BadTarget<'a>)] +LL | struct BadSource<'a>(&'a mut u32); + | ----------- source field `0` has type `&'a mut u32` + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/reborrow/derive_manual_equivalence.rs b/tests/ui/reborrow/derive_manual_equivalence.rs new file mode 100644 index 0000000000000..fdf62cc31ab76 --- /dev/null +++ b/tests/ui/reborrow/derive_manual_equivalence.rs @@ -0,0 +1,42 @@ +//@ run-pass + +#![feature(reborrow)] +#![allow(dead_code)] + +use std::marker::{CoerceShared, Reborrow}; + +struct DerivedRef<'a, T>(&'a T); +impl<'a, T> Clone for DerivedRef<'a, T> { + fn clone(&self) -> Self { + Self(self.0) + } +} +impl<'a, T> Copy for DerivedRef<'a, T> {} + +#[derive(Reborrow, CoerceShared)] +#[coerce_shared(DerivedRef<'a, T>)] +struct DerivedMut<'a, T>(&'a mut T); + +struct ManualRef<'a, T>(&'a T); +impl<'a, T> Clone for ManualRef<'a, T> { + fn clone(&self) -> Self { + Self(self.0) + } +} +impl<'a, T> Copy for ManualRef<'a, T> {} + +struct ManualMut<'a, T>(&'a mut T); + +impl<'a, T> Reborrow for ManualMut<'a, T> {} +impl<'a, T> CoerceShared> for ManualMut<'a, T> {} + +fn take_derived(_: DerivedRef<'_, ()>) {} +fn take_manual(_: ManualRef<'_, ()>) {} + +fn main() { + let derived = DerivedMut(&mut ()); + take_derived(derived); + + let manual = ManualMut(&mut ()); + take_manual(manual); +} diff --git a/tests/ui/reborrow/derive_multiple_lifetimes.rs b/tests/ui/reborrow/derive_multiple_lifetimes.rs new file mode 100644 index 0000000000000..2332896d6b03f --- /dev/null +++ b/tests/ui/reborrow/derive_multiple_lifetimes.rs @@ -0,0 +1,69 @@ +//@ normalize-stderr: "\n\n$" -> "\n" + +#![feature(reborrow)] + +use std::marker::{CoerceShared, Reborrow}; + +// This test mirrors manual and derived impls with multiple lifetimes. The derive +// layer preserves both lifetimes; the current underlying trait validation rejects +// both forms with the same experimental one-lifetime limitation. + +struct ManualPair<'a, 'b, T> { + left: &'a mut T, + right: &'b mut T, +} + +impl<'a, 'b, T> Reborrow for ManualPair<'a, 'b, T> {} +//~^ ERROR implementing `Reborrow` requires that a single lifetime parameter is passed between source and target + +#[derive(Reborrow)] +//~^ ERROR implementing `Reborrow` requires that a single lifetime parameter is passed between source and target +struct DerivedPair<'a, 'b, T> { + left: &'a mut T, + right: &'b mut T, +} + +struct ManualShared<'a, 'b, T> { + left: &'a T, + right: &'b T, +} + +impl<'a, 'b, T> Clone for ManualShared<'a, 'b, T> { + fn clone(&self) -> Self { + *self + } +} +impl<'a, 'b, T> Copy for ManualShared<'a, 'b, T> {} + +struct ManualMut<'a, 'b, T> { + left: &'a mut T, + right: &'b mut T, +} + +impl<'a, 'b, T> Reborrow for ManualMut<'a, 'b, T> {} +//~^ ERROR implementing `Reborrow` requires that a single lifetime parameter is passed between source and target +impl<'a, 'b, T> CoerceShared> for ManualMut<'a, 'b, T> {} +//~^ ERROR implementing `CoerceShared` requires that a single lifetime parameter is passed between source and target + +struct DerivedShared<'a, 'b, T> { + left: &'a T, + right: &'b T, +} + +impl<'a, 'b, T> Clone for DerivedShared<'a, 'b, T> { + fn clone(&self) -> Self { + *self + } +} +impl<'a, 'b, T> Copy for DerivedShared<'a, 'b, T> {} + +#[derive(Reborrow, CoerceShared)] +//~^ ERROR implementing `Reborrow` requires that a single lifetime parameter is passed between source and target +//~| ERROR implementing `CoerceShared` requires that a single lifetime parameter is passed between source and target +#[coerce_shared(DerivedShared<'a, 'b, T>)] +struct DerivedMut<'a, 'b, T> { + left: &'a mut T, + right: &'b mut T, +} + +fn main() {} diff --git a/tests/ui/reborrow/derive_multiple_lifetimes.stderr b/tests/ui/reborrow/derive_multiple_lifetimes.stderr new file mode 100644 index 0000000000000..b609ac6e718cb --- /dev/null +++ b/tests/ui/reborrow/derive_multiple_lifetimes.stderr @@ -0,0 +1,37 @@ +error: implementing `Reborrow` requires that a single lifetime parameter is passed between source and target + --> $DIR/derive_multiple_lifetimes.rs:16:1 + | +LL | impl<'a, 'b, T> Reborrow for ManualPair<'a, 'b, T> {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: implementing `Reborrow` requires that a single lifetime parameter is passed between source and target + --> $DIR/derive_multiple_lifetimes.rs:19:10 + | +LL | #[derive(Reborrow)] + | ^^^^^^^^ + +error: implementing `Reborrow` requires that a single lifetime parameter is passed between source and target + --> $DIR/derive_multiple_lifetimes.rs:43:1 + | +LL | impl<'a, 'b, T> Reborrow for ManualMut<'a, 'b, T> {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: implementing `Reborrow` requires that a single lifetime parameter is passed between source and target + --> $DIR/derive_multiple_lifetimes.rs:60:10 + | +LL | #[derive(Reborrow, CoerceShared)] + | ^^^^^^^^ + +error: implementing `CoerceShared` requires that a single lifetime parameter is passed between source and target + --> $DIR/derive_multiple_lifetimes.rs:45:1 + | +LL | impl<'a, 'b, T> CoerceShared> for ManualMut<'a, 'b, T> {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: implementing `CoerceShared` requires that a single lifetime parameter is passed between source and target + --> $DIR/derive_multiple_lifetimes.rs:60:20 + | +LL | #[derive(Reborrow, CoerceShared)] + | ^^^^^^^^^^^^ + +error: aborting due to 6 previous errors diff --git a/tests/ui/reborrow/derive_reborrow.rs b/tests/ui/reborrow/derive_reborrow.rs new file mode 100644 index 0000000000000..6a4f50b82a167 --- /dev/null +++ b/tests/ui/reborrow/derive_reborrow.rs @@ -0,0 +1,50 @@ +//@ run-pass + +#![feature(reborrow)] +#![allow(dead_code)] + +use std::marker::{PhantomData, Reborrow}; + +#[derive(Reborrow)] +struct Named<'a, T> { + value: &'a mut T, +} + +#[derive(Reborrow)] +struct Tuple<'a, T>(&'a mut T); + +#[derive(Reborrow)] +struct Generic<'a, T = (), const N: usize = 1> +where + T: 'a, +{ + value: &'a mut [T; N], +} + +#[derive(Reborrow)] +struct Marker<'a>(PhantomData<&'a ()>); + +fn take_named(_: Named<'_, ()>) {} +fn take_tuple(_: Tuple<'_, ()>) {} +fn take_generic(_: Generic<'_>) {} +fn take_marker<'a>(_: Marker<'a>) -> &'a () { + &() +} + +fn main() { + let named = Named { value: &mut () }; + take_named(named); + take_named(named); + + let tuple = Tuple(&mut ()); + take_tuple(tuple); + take_tuple(tuple); + + let generic = Generic { value: &mut [()] }; + take_generic(generic); + take_generic(generic); + + let marker = Marker(PhantomData); + let _ = take_marker(marker); + let _ = take_marker(marker); +} diff --git a/tests/ui/reborrow/derive_unsupported_items.rs b/tests/ui/reborrow/derive_unsupported_items.rs new file mode 100644 index 0000000000000..5ebd92b5ba358 --- /dev/null +++ b/tests/ui/reborrow/derive_unsupported_items.rs @@ -0,0 +1,33 @@ +#![feature(reborrow)] + +use std::marker::{CoerceShared, Reborrow}; + +#[derive(Reborrow)] //~ ERROR `derive(Reborrow)` is only supported for structs, not enums +enum ReborrowEnum<'a> { + Variant(&'a mut ()), +} + +#[derive(CoerceShared)] //~ ERROR `derive(CoerceShared)` is only supported for structs, not enums +#[coerce_shared(CoerceSharedEnumRef<'a>)] +enum CoerceSharedEnum<'a> { + Variant(&'a mut ()), +} + +#[derive(Clone, Copy)] +struct CoerceSharedEnumRef<'a>(&'a ()); + +#[derive(Reborrow)] //~ ERROR `derive(Reborrow)` is only supported for structs, not unions +union ReborrowUnion<'a> { + field: &'a mut (), +} + +#[derive(CoerceShared)] //~ ERROR `derive(CoerceShared)` is only supported for structs, not unions +#[coerce_shared(CoerceSharedUnionRef<'a>)] +union CoerceSharedUnion<'a> { + field: &'a mut (), +} + +#[derive(Clone, Copy)] +struct CoerceSharedUnionRef<'a>(&'a ()); + +fn main() {} diff --git a/tests/ui/reborrow/derive_unsupported_items.stderr b/tests/ui/reborrow/derive_unsupported_items.stderr new file mode 100644 index 0000000000000..b079a2fbfff40 --- /dev/null +++ b/tests/ui/reborrow/derive_unsupported_items.stderr @@ -0,0 +1,27 @@ +error[E0802]: `derive(Reborrow)` is only supported for structs, not enums + --> $DIR/derive_unsupported_items.rs:5:10 + | +LL | #[derive(Reborrow)] + | ^^^^^^^^ + +error[E0802]: `derive(CoerceShared)` is only supported for structs, not enums + --> $DIR/derive_unsupported_items.rs:10:10 + | +LL | #[derive(CoerceShared)] + | ^^^^^^^^^^^^ + +error[E0802]: `derive(Reborrow)` is only supported for structs, not unions + --> $DIR/derive_unsupported_items.rs:19:10 + | +LL | #[derive(Reborrow)] + | ^^^^^^^^ + +error[E0802]: `derive(CoerceShared)` is only supported for structs, not unions + --> $DIR/derive_unsupported_items.rs:24:10 + | +LL | #[derive(CoerceShared)] + | ^^^^^^^^^^^^ + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0802`.