From 6bd5ab92bd0b407db7ba74d41bf49d900aa887cf Mon Sep 17 00:00:00 2001 From: aerooneqq Date: Thu, 14 May 2026 10:53:17 +0300 Subject: [PATCH 1/8] Emit error when self type is not specified and accessed --- compiler/rustc_hir_analysis/src/delegation.rs | 7 ++ compiler/rustc_hir_analysis/src/errors.rs | 8 +++ .../generics/free-to-trait-static-reuse.rs | 6 ++ .../free-to-trait-static-reuse.stderr | 70 ++++++++++++++----- tests/ui/delegation/self-ty-ice-156388.rs | 8 +++ tests/ui/delegation/self-ty-ice-156388.stderr | 10 +++ tests/ui/delegation/target-expr.rs | 3 + tests/ui/delegation/target-expr.stderr | 25 ++++--- .../ui/delegation/unsupported.current.stderr | 34 +++++---- tests/ui/delegation/unsupported.next.stderr | 34 +++++---- tests/ui/delegation/unsupported.rs | 2 + 11 files changed, 154 insertions(+), 53 deletions(-) create mode 100644 tests/ui/delegation/self-ty-ice-156388.rs create mode 100644 tests/ui/delegation/self-ty-ice-156388.stderr diff --git a/compiler/rustc_hir_analysis/src/delegation.rs b/compiler/rustc_hir_analysis/src/delegation.rs index be8a8e228c47a..2d6d5a5d81f9a 100644 --- a/compiler/rustc_hir_analysis/src/delegation.rs +++ b/compiler/rustc_hir_analysis/src/delegation.rs @@ -14,6 +14,7 @@ use rustc_middle::ty::{ use rustc_span::{ErrorGuaranteed, Span, kw}; use crate::collect::ItemCtxt; +use crate::errors::DelegationSelfTypeNotSpecified; use crate::hir_ty_lowering::HirTyLowerer; type RemapTable = FxHashMap; @@ -284,6 +285,12 @@ fn get_delegation_self_ty_or_err(tcx: TyCtxt<'_>, delegation_id: LocalDefId) -> ctx.lower_ty(tcx.hir_node(id).expect_ty()) }) .unwrap_or_else(|| { + // It is possible to attempt to get self type when it is used in signature + // (i.e., `fn default() -> Self`), so emit error here in addition to possible + // `mismatched types` error (see #156388). + let err = DelegationSelfTypeNotSpecified { span: tcx.def_span(delegation_id) }; + tcx.dcx().emit_err(err); + Ty::new_error_with_message( tcx, tcx.def_span(delegation_id), diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index 9fc26a3b80744..20019aeff3eb8 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -1670,6 +1670,14 @@ pub(crate) struct UnsupportedDelegation<'a> { pub callee_span: Span, } +#[derive(Diagnostic)] +#[diag("delegation self type is not specified")] +#[help("consider explicitly specifying self type: `reuse ::function`")] +pub(crate) struct DelegationSelfTypeNotSpecified { + #[primary_span] + pub span: Span, +} + #[derive(Diagnostic)] #[diag("method should be `async` or return a future, but it is synchronous")] pub(crate) struct MethodShouldReturnFuture { diff --git a/tests/ui/delegation/generics/free-to-trait-static-reuse.rs b/tests/ui/delegation/generics/free-to-trait-static-reuse.rs index abb69e5fc1588..e3d0bdbc7e9b0 100644 --- a/tests/ui/delegation/generics/free-to-trait-static-reuse.rs +++ b/tests/ui/delegation/generics/free-to-trait-static-reuse.rs @@ -1,3 +1,5 @@ +//@ compile-flags: -Z deduplicate-diagnostics=yes + #![feature(fn_delegation)] trait Bound {} @@ -19,12 +21,16 @@ reuse ::static_method::<'static, Vec, false> as bar2; reuse Trait::static_method as error { self - 123 } //~^ ERROR: type annotations needed +//~| ERROR: delegation self type is not specified reuse Trait::<'static, i32, 123>::static_method as error2; //~^ ERROR: type annotations needed +//~| ERROR: delegation self type is not specified reuse Trait::<'static, i32, 123>::static_method::<'static, String, false> as error3; //~^ ERROR: type annotations needed +//~| ERROR: delegation self type is not specified reuse Trait::static_method::<'static, Vec, false> as error4 { self + 4 } //~^ ERROR: type annotations needed +//~| ERROR: delegation self type is not specified reuse ::static_method as error5; //~^ ERROR: the trait bound `String: Trait<'a, T, X>` is not satisfied diff --git a/tests/ui/delegation/generics/free-to-trait-static-reuse.stderr b/tests/ui/delegation/generics/free-to-trait-static-reuse.stderr index 398fa2e5db92a..8d87b9376acd4 100644 --- a/tests/ui/delegation/generics/free-to-trait-static-reuse.stderr +++ b/tests/ui/delegation/generics/free-to-trait-static-reuse.stderr @@ -1,21 +1,53 @@ +error: delegation self type is not specified + --> $DIR/free-to-trait-static-reuse.rs:22:14 + | +LL | reuse Trait::static_method as error { self - 123 } + | ^^^^^^^^^^^^^ + | + = help: consider explicitly specifying self type: `reuse ::function` + +error: delegation self type is not specified + --> $DIR/free-to-trait-static-reuse.rs:25:35 + | +LL | reuse Trait::<'static, i32, 123>::static_method as error2; + | ^^^^^^^^^^^^^ + | + = help: consider explicitly specifying self type: `reuse ::function` + +error: delegation self type is not specified + --> $DIR/free-to-trait-static-reuse.rs:28:35 + | +LL | reuse Trait::<'static, i32, 123>::static_method::<'static, String, false> as error3; + | ^^^^^^^^^^^^^ + | + = help: consider explicitly specifying self type: `reuse ::function` + +error: delegation self type is not specified + --> $DIR/free-to-trait-static-reuse.rs:31:14 + | +LL | reuse Trait::static_method::<'static, Vec, false> as error4 { self + 4 } + | ^^^^^^^^^^^^^ + | + = help: consider explicitly specifying self type: `reuse ::function` + error[E0277]: the trait bound `Struct: Bound` is not satisfied - --> $DIR/free-to-trait-static-reuse.rs:33:49 + --> $DIR/free-to-trait-static-reuse.rs:39:49 | LL | impl<'a, T, const X: usize> Trait<'a, T, X> for Struct {} | ^^^^^^ unsatisfied trait bound | help: the trait `Bound` is not implemented for `Struct` - --> $DIR/free-to-trait-static-reuse.rs:32:1 + --> $DIR/free-to-trait-static-reuse.rs:38:1 | LL | struct Struct; | ^^^^^^^^^^^^^ help: the trait `Bound` is implemented for `usize` - --> $DIR/free-to-trait-static-reuse.rs:13:1 + --> $DIR/free-to-trait-static-reuse.rs:15:1 | LL | impl Bound for usize {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ note: required by a bound in `Trait` - --> $DIR/free-to-trait-static-reuse.rs:7:11 + --> $DIR/free-to-trait-static-reuse.rs:9:11 | LL | trait Trait<'a, T, const X: usize> | ----- required by a bound in this trait @@ -24,13 +56,13 @@ LL | Self: Bound, | ^^^^^^^^ required by this bound in `Trait` error[E0283]: type annotations needed - --> $DIR/free-to-trait-static-reuse.rs:20:14 + --> $DIR/free-to-trait-static-reuse.rs:22:14 | LL | reuse Trait::static_method as error { self - 123 } | ^^^^^^^^^^^^^ cannot infer type | note: multiple `impl`s satisfying `_: Trait<'a, T, X>` found - --> $DIR/free-to-trait-static-reuse.rs:12:1 + --> $DIR/free-to-trait-static-reuse.rs:14:1 | LL | impl<'a, T, const X: usize> Trait<'a, T, X> for usize {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -39,13 +71,13 @@ LL | impl<'a, T, const X: usize> Trait<'a, T, X> for Struct {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0283]: type annotations needed - --> $DIR/free-to-trait-static-reuse.rs:22:35 + --> $DIR/free-to-trait-static-reuse.rs:25:35 | LL | reuse Trait::<'static, i32, 123>::static_method as error2; | ^^^^^^^^^^^^^ cannot infer type | note: multiple `impl`s satisfying `_: Trait<'static, i32, 123>` found - --> $DIR/free-to-trait-static-reuse.rs:12:1 + --> $DIR/free-to-trait-static-reuse.rs:14:1 | LL | impl<'a, T, const X: usize> Trait<'a, T, X> for usize {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -54,13 +86,13 @@ LL | impl<'a, T, const X: usize> Trait<'a, T, X> for Struct {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0283]: type annotations needed - --> $DIR/free-to-trait-static-reuse.rs:24:35 + --> $DIR/free-to-trait-static-reuse.rs:28:35 | LL | reuse Trait::<'static, i32, 123>::static_method::<'static, String, false> as error3; | ^^^^^^^^^^^^^ cannot infer type | note: multiple `impl`s satisfying `_: Trait<'static, i32, 123>` found - --> $DIR/free-to-trait-static-reuse.rs:12:1 + --> $DIR/free-to-trait-static-reuse.rs:14:1 | LL | impl<'a, T, const X: usize> Trait<'a, T, X> for usize {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -69,13 +101,13 @@ LL | impl<'a, T, const X: usize> Trait<'a, T, X> for Struct {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0283]: type annotations needed - --> $DIR/free-to-trait-static-reuse.rs:26:14 + --> $DIR/free-to-trait-static-reuse.rs:31:14 | LL | reuse Trait::static_method::<'static, Vec, false> as error4 { self + 4 } | ^^^^^^^^^^^^^ cannot infer type | note: multiple `impl`s satisfying `_: Trait<'a, T, X>` found - --> $DIR/free-to-trait-static-reuse.rs:12:1 + --> $DIR/free-to-trait-static-reuse.rs:14:1 | LL | impl<'a, T, const X: usize> Trait<'a, T, X> for usize {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -84,13 +116,13 @@ LL | impl<'a, T, const X: usize> Trait<'a, T, X> for Struct {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `String: Trait<'a, T, X>` is not satisfied - --> $DIR/free-to-trait-static-reuse.rs:29:8 + --> $DIR/free-to-trait-static-reuse.rs:35:8 | LL | reuse ::static_method as error5; | ^^^^^^ the trait `Trait<'a, T, X>` is not implemented for `String` | help: the following other types implement trait `Trait<'a, T, X>` - --> $DIR/free-to-trait-static-reuse.rs:12:1 + --> $DIR/free-to-trait-static-reuse.rs:14:1 | LL | impl<'a, T, const X: usize> Trait<'a, T, X> for usize {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `usize` @@ -99,23 +131,23 @@ LL | impl<'a, T, const X: usize> Trait<'a, T, X> for Struct {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `Struct` error[E0277]: the trait bound `Struct: Bound` is not satisfied - --> $DIR/free-to-trait-static-reuse.rs:36:8 + --> $DIR/free-to-trait-static-reuse.rs:42:8 | LL | reuse ::static_method as error6; | ^^^^^^ unsatisfied trait bound | help: the trait `Bound` is not implemented for `Struct` - --> $DIR/free-to-trait-static-reuse.rs:32:1 + --> $DIR/free-to-trait-static-reuse.rs:38:1 | LL | struct Struct; | ^^^^^^^^^^^^^ help: the trait `Bound` is implemented for `usize` - --> $DIR/free-to-trait-static-reuse.rs:13:1 + --> $DIR/free-to-trait-static-reuse.rs:15:1 | LL | impl Bound for usize {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ note: required by a bound in `Trait::static_method` - --> $DIR/free-to-trait-static-reuse.rs:7:11 + --> $DIR/free-to-trait-static-reuse.rs:9:11 | LL | Self: Bound, | ^^^^^^^^ required by this bound in `Trait::static_method` @@ -123,7 +155,7 @@ LL | { LL | fn static_method<'c: 'c, U, const B: bool>(x: usize) {} | ------------- required by a bound in this associated function -error: aborting due to 7 previous errors +error: aborting due to 11 previous errors Some errors have detailed explanations: E0277, E0283. For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/delegation/self-ty-ice-156388.rs b/tests/ui/delegation/self-ty-ice-156388.rs new file mode 100644 index 0000000000000..542f56867b2b2 --- /dev/null +++ b/tests/ui/delegation/self-ty-ice-156388.rs @@ -0,0 +1,8 @@ +//@ compile-flags: -Z deduplicate-diagnostics=yes + +#![feature(fn_delegation)] + +reuse Default::default; +//~^ ERROR: delegation self type is not specified + +fn main() {} diff --git a/tests/ui/delegation/self-ty-ice-156388.stderr b/tests/ui/delegation/self-ty-ice-156388.stderr new file mode 100644 index 0000000000000..c2323cf1c6082 --- /dev/null +++ b/tests/ui/delegation/self-ty-ice-156388.stderr @@ -0,0 +1,10 @@ +error: delegation self type is not specified + --> $DIR/self-ty-ice-156388.rs:5:16 + | +LL | reuse Default::default; + | ^^^^^^^ + | + = help: consider explicitly specifying self type: `reuse ::function` + +error: aborting due to 1 previous error + diff --git a/tests/ui/delegation/target-expr.rs b/tests/ui/delegation/target-expr.rs index 253ce1fffff72..2355decd3d4f7 100644 --- a/tests/ui/delegation/target-expr.rs +++ b/tests/ui/delegation/target-expr.rs @@ -1,3 +1,5 @@ +//@ compile-flags: -Z deduplicate-diagnostics=yes + #![feature(fn_delegation)] trait Trait { @@ -14,6 +16,7 @@ fn foo(x: i32) -> i32 { x } fn bar(_: T) { reuse Trait::static_method { //~^ ERROR mismatched types + //~| ERROR: delegation self type is not specified let _ = T::Default(); //~^ ERROR can't use generic parameters from outer item } diff --git a/tests/ui/delegation/target-expr.stderr b/tests/ui/delegation/target-expr.stderr index 7153fa4178374..8965a1a060786 100644 --- a/tests/ui/delegation/target-expr.stderr +++ b/tests/ui/delegation/target-expr.stderr @@ -1,18 +1,18 @@ error[E0401]: can't use generic parameters from outer item - --> $DIR/target-expr.rs:17:17 + --> $DIR/target-expr.rs:20:17 | LL | fn bar(_: T) { | - type parameter from outer item LL | reuse Trait::static_method { | ------------- generic parameter used in this inner delegated function -LL | +... LL | let _ = T::Default(); | ^ use of generic parameter from outer item | = note: nested items are independent from their parent item for everything except for privacy and name resolution error[E0434]: can't capture dynamic environment in a fn item - --> $DIR/target-expr.rs:25:17 + --> $DIR/target-expr.rs:28:17 | LL | let x = y; | ^ @@ -20,7 +20,7 @@ LL | let x = y; = help: use the `|| { ... }` closure form instead error[E0424]: expected value, found module `self` - --> $DIR/target-expr.rs:32:5 + --> $DIR/target-expr.rs:35:5 | LL | fn main() { | ---- this function can't have a `self` parameter @@ -29,29 +29,38 @@ LL | self.0; | ^^^^ `self` value is a keyword only available in methods with a `self` parameter error[E0425]: cannot find value `x` in this scope - --> $DIR/target-expr.rs:34:13 + --> $DIR/target-expr.rs:37:13 | LL | let z = x; | ^ | help: the binding `x` is available in a different scope in the same function - --> $DIR/target-expr.rs:25:13 + --> $DIR/target-expr.rs:28:13 | LL | let x = y; | ^ +error: delegation self type is not specified + --> $DIR/target-expr.rs:17:18 + | +LL | reuse Trait::static_method { + | ^^^^^^^^^^^^^ + | + = help: consider explicitly specifying self type: `reuse ::function` + error[E0308]: mismatched types - --> $DIR/target-expr.rs:15:32 + --> $DIR/target-expr.rs:17:32 | LL | reuse Trait::static_method { | ________________________________^ LL | | +LL | | LL | | let _ = T::Default(); LL | | LL | | } | |_____^ expected `i32`, found `()` -error: aborting due to 5 previous errors +error: aborting due to 6 previous errors Some errors have detailed explanations: E0308, E0401, E0424, E0425, E0434. For more information about an error, try `rustc --explain E0308`. diff --git a/tests/ui/delegation/unsupported.current.stderr b/tests/ui/delegation/unsupported.current.stderr index 21ea451a2ea5c..88938cd8b362c 100644 --- a/tests/ui/delegation/unsupported.current.stderr +++ b/tests/ui/delegation/unsupported.current.stderr @@ -1,41 +1,49 @@ -error[E0391]: cycle detected when computing type of `opaque::::opaque_ret::{anon_assoc#0}` - --> $DIR/unsupported.rs:29:25 +error[E0391]: cycle detected when computing type of `opaque::::opaque_ret::{anon_assoc#0}` + --> $DIR/unsupported.rs:30:25 | LL | reuse to_reuse::opaque_ret; | ^^^^^^^^^^ | note: ...which requires comparing an impl and trait method signature, inferring any hidden `impl Trait` types in the process... - --> $DIR/unsupported.rs:29:25 + --> $DIR/unsupported.rs:30:25 | LL | reuse to_reuse::opaque_ret; | ^^^^^^^^^^ - = note: ...which again requires computing type of `opaque::::opaque_ret::{anon_assoc#0}`, completing the cycle -note: cycle used when checking assoc item `opaque::::opaque_ret` is compatible with trait definition - --> $DIR/unsupported.rs:29:25 + = note: ...which again requires computing type of `opaque::::opaque_ret::{anon_assoc#0}`, completing the cycle +note: cycle used when checking assoc item `opaque::::opaque_ret` is compatible with trait definition + --> $DIR/unsupported.rs:30:25 | LL | reuse to_reuse::opaque_ret; | ^^^^^^^^^^ = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information -error[E0391]: cycle detected when computing type of `opaque::::opaque_ret::{anon_assoc#0}` - --> $DIR/unsupported.rs:32:24 +error[E0391]: cycle detected when computing type of `opaque::::opaque_ret::{anon_assoc#0}` + --> $DIR/unsupported.rs:33:24 | LL | reuse ToReuse::opaque_ret; | ^^^^^^^^^^ | note: ...which requires comparing an impl and trait method signature, inferring any hidden `impl Trait` types in the process... - --> $DIR/unsupported.rs:32:24 + --> $DIR/unsupported.rs:33:24 | LL | reuse ToReuse::opaque_ret; | ^^^^^^^^^^ - = note: ...which again requires computing type of `opaque::::opaque_ret::{anon_assoc#0}`, completing the cycle -note: cycle used when checking assoc item `opaque::::opaque_ret` is compatible with trait definition - --> $DIR/unsupported.rs:32:24 + = note: ...which again requires computing type of `opaque::::opaque_ret::{anon_assoc#0}`, completing the cycle +note: cycle used when checking assoc item `opaque::::opaque_ret` is compatible with trait definition + --> $DIR/unsupported.rs:33:24 | LL | reuse ToReuse::opaque_ret; | ^^^^^^^^^^ = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information -error: aborting due to 2 previous errors +error: delegation self type is not specified + --> $DIR/unsupported.rs:54:18 + | +LL | reuse Trait::foo; + | ^^^ + | + = help: consider explicitly specifying self type: `reuse ::function` + +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0391`. diff --git a/tests/ui/delegation/unsupported.next.stderr b/tests/ui/delegation/unsupported.next.stderr index 21ea451a2ea5c..88938cd8b362c 100644 --- a/tests/ui/delegation/unsupported.next.stderr +++ b/tests/ui/delegation/unsupported.next.stderr @@ -1,41 +1,49 @@ -error[E0391]: cycle detected when computing type of `opaque::::opaque_ret::{anon_assoc#0}` - --> $DIR/unsupported.rs:29:25 +error[E0391]: cycle detected when computing type of `opaque::::opaque_ret::{anon_assoc#0}` + --> $DIR/unsupported.rs:30:25 | LL | reuse to_reuse::opaque_ret; | ^^^^^^^^^^ | note: ...which requires comparing an impl and trait method signature, inferring any hidden `impl Trait` types in the process... - --> $DIR/unsupported.rs:29:25 + --> $DIR/unsupported.rs:30:25 | LL | reuse to_reuse::opaque_ret; | ^^^^^^^^^^ - = note: ...which again requires computing type of `opaque::::opaque_ret::{anon_assoc#0}`, completing the cycle -note: cycle used when checking assoc item `opaque::::opaque_ret` is compatible with trait definition - --> $DIR/unsupported.rs:29:25 + = note: ...which again requires computing type of `opaque::::opaque_ret::{anon_assoc#0}`, completing the cycle +note: cycle used when checking assoc item `opaque::::opaque_ret` is compatible with trait definition + --> $DIR/unsupported.rs:30:25 | LL | reuse to_reuse::opaque_ret; | ^^^^^^^^^^ = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information -error[E0391]: cycle detected when computing type of `opaque::::opaque_ret::{anon_assoc#0}` - --> $DIR/unsupported.rs:32:24 +error[E0391]: cycle detected when computing type of `opaque::::opaque_ret::{anon_assoc#0}` + --> $DIR/unsupported.rs:33:24 | LL | reuse ToReuse::opaque_ret; | ^^^^^^^^^^ | note: ...which requires comparing an impl and trait method signature, inferring any hidden `impl Trait` types in the process... - --> $DIR/unsupported.rs:32:24 + --> $DIR/unsupported.rs:33:24 | LL | reuse ToReuse::opaque_ret; | ^^^^^^^^^^ - = note: ...which again requires computing type of `opaque::::opaque_ret::{anon_assoc#0}`, completing the cycle -note: cycle used when checking assoc item `opaque::::opaque_ret` is compatible with trait definition - --> $DIR/unsupported.rs:32:24 + = note: ...which again requires computing type of `opaque::::opaque_ret::{anon_assoc#0}`, completing the cycle +note: cycle used when checking assoc item `opaque::::opaque_ret` is compatible with trait definition + --> $DIR/unsupported.rs:33:24 | LL | reuse ToReuse::opaque_ret; | ^^^^^^^^^^ = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information -error: aborting due to 2 previous errors +error: delegation self type is not specified + --> $DIR/unsupported.rs:54:18 + | +LL | reuse Trait::foo; + | ^^^ + | + = help: consider explicitly specifying self type: `reuse ::function` + +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0391`. diff --git a/tests/ui/delegation/unsupported.rs b/tests/ui/delegation/unsupported.rs index 678c93dcd53c0..3349c4ec27ab1 100644 --- a/tests/ui/delegation/unsupported.rs +++ b/tests/ui/delegation/unsupported.rs @@ -1,3 +1,4 @@ +//@ compile-flags: -Z deduplicate-diagnostics=yes //@ revisions: current next //@ ignore-compare-mode-next-solver (explicit revisions) //@[next] compile-flags: -Znext-solver @@ -51,6 +52,7 @@ mod effects { } reuse Trait::foo; + //~^ ERROR: delegation self type is not specified } fn main() {} From 8f221d1084544fd2821fe210a76497b60cca377f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=9D=E5=80=89=E6=B0=B4=E5=B8=8C?= Date: Fri, 15 May 2026 00:06:14 +0800 Subject: [PATCH 2/8] Test EII UI tests with prefer-dynamic --- tests/ui/eii/auxiliary/other_crate_privacy1.rs | 1 - tests/ui/eii/auxiliary/other_crate_privacy2.rs | 1 - tests/ui/eii/default/auxiliary/decl_with_default.rs | 1 - tests/ui/eii/default/auxiliary/decl_with_default_panics.rs | 1 - tests/ui/eii/default/auxiliary/impl1.rs | 1 - tests/ui/eii/default/call_default.rs | 1 - tests/ui/eii/default/call_default_panics.rs | 1 - tests/ui/eii/default/call_impl.rs | 1 - tests/ui/eii/duplicate/auxiliary/decl.rs | 1 - tests/ui/eii/duplicate/auxiliary/impl1.rs | 1 - tests/ui/eii/duplicate/auxiliary/impl2.rs | 1 - tests/ui/eii/duplicate/auxiliary/impl3.rs | 1 - tests/ui/eii/duplicate/auxiliary/impl4.rs | 1 - tests/ui/eii/duplicate/duplicate1.rs | 1 - tests/ui/eii/duplicate/duplicate1.stderr | 4 ++-- tests/ui/eii/duplicate/duplicate2.rs | 1 - tests/ui/eii/duplicate/duplicate2.stderr | 4 ++-- tests/ui/eii/duplicate/duplicate3.rs | 1 - tests/ui/eii/duplicate/duplicate3.stderr | 4 ++-- .../linking/auxiliary/codegen_cross_crate_other_crate.rs | 1 - tests/ui/eii/privacy2.stderr | 6 +++--- tests/ui/eii/static/auxiliary/cross_crate_decl.rs | 1 - tests/ui/eii/static/auxiliary/cross_crate_def.rs | 1 - .../type_checking/auxiliary/cross_crate_eii_declaration.rs | 1 - tests/ui/eii/type_checking/cross_crate_wrong_ty.stderr | 2 +- 25 files changed, 10 insertions(+), 30 deletions(-) diff --git a/tests/ui/eii/auxiliary/other_crate_privacy1.rs b/tests/ui/eii/auxiliary/other_crate_privacy1.rs index 41160cd1fe39f..350fe8c7bfc70 100644 --- a/tests/ui/eii/auxiliary/other_crate_privacy1.rs +++ b/tests/ui/eii/auxiliary/other_crate_privacy1.rs @@ -1,4 +1,3 @@ -//@ no-prefer-dynamic #![crate_type = "rlib"] #![feature(extern_item_impls)] diff --git a/tests/ui/eii/auxiliary/other_crate_privacy2.rs b/tests/ui/eii/auxiliary/other_crate_privacy2.rs index 9fb19298f09f0..4f975178afe68 100644 --- a/tests/ui/eii/auxiliary/other_crate_privacy2.rs +++ b/tests/ui/eii/auxiliary/other_crate_privacy2.rs @@ -1,4 +1,3 @@ -//@ no-prefer-dynamic #![crate_type = "rlib"] #![feature(extern_item_impls)] diff --git a/tests/ui/eii/default/auxiliary/decl_with_default.rs b/tests/ui/eii/default/auxiliary/decl_with_default.rs index 8d962c19c94d9..ba855cb854afd 100644 --- a/tests/ui/eii/default/auxiliary/decl_with_default.rs +++ b/tests/ui/eii/default/auxiliary/decl_with_default.rs @@ -1,4 +1,3 @@ -//@ no-prefer-dynamic #![crate_type = "rlib"] #![feature(extern_item_impls)] diff --git a/tests/ui/eii/default/auxiliary/decl_with_default_panics.rs b/tests/ui/eii/default/auxiliary/decl_with_default_panics.rs index 14778a40cde4a..3867bfb85c9fe 100644 --- a/tests/ui/eii/default/auxiliary/decl_with_default_panics.rs +++ b/tests/ui/eii/default/auxiliary/decl_with_default_panics.rs @@ -1,4 +1,3 @@ -//@ no-prefer-dynamic //@ needs-unwind //@ exec-env:RUST_BACKTRACE=1 #![crate_type = "rlib"] diff --git a/tests/ui/eii/default/auxiliary/impl1.rs b/tests/ui/eii/default/auxiliary/impl1.rs index 3510ea1eb3f27..84edf24e12816 100644 --- a/tests/ui/eii/default/auxiliary/impl1.rs +++ b/tests/ui/eii/default/auxiliary/impl1.rs @@ -1,4 +1,3 @@ -//@ no-prefer-dynamic //@ aux-build: decl_with_default.rs #![crate_type = "rlib"] #![feature(extern_item_impls)] diff --git a/tests/ui/eii/default/call_default.rs b/tests/ui/eii/default/call_default.rs index 8806c7fa7d8ce..07b2a650d3c42 100644 --- a/tests/ui/eii/default/call_default.rs +++ b/tests/ui/eii/default/call_default.rs @@ -1,4 +1,3 @@ -//@ no-prefer-dynamic //@ aux-build: decl_with_default.rs //@ run-pass //@ check-run-results diff --git a/tests/ui/eii/default/call_default_panics.rs b/tests/ui/eii/default/call_default_panics.rs index db664e0cbcb0d..379ba8ea070b6 100644 --- a/tests/ui/eii/default/call_default_panics.rs +++ b/tests/ui/eii/default/call_default_panics.rs @@ -1,4 +1,3 @@ -//@ no-prefer-dynamic //@ aux-build: decl_with_default_panics.rs //@ edition: 2021 //@ run-pass diff --git a/tests/ui/eii/default/call_impl.rs b/tests/ui/eii/default/call_impl.rs index 1a972774beaeb..4553427b8c799 100644 --- a/tests/ui/eii/default/call_impl.rs +++ b/tests/ui/eii/default/call_impl.rs @@ -1,4 +1,3 @@ -//@ no-prefer-dynamic //@ aux-build: decl_with_default.rs //@ aux-build: impl1.rs //@ run-pass diff --git a/tests/ui/eii/duplicate/auxiliary/decl.rs b/tests/ui/eii/duplicate/auxiliary/decl.rs index 2a0661715bfd2..eb29bee66b74b 100644 --- a/tests/ui/eii/duplicate/auxiliary/decl.rs +++ b/tests/ui/eii/duplicate/auxiliary/decl.rs @@ -1,4 +1,3 @@ -//@ no-prefer-dynamic #![crate_type = "rlib"] #![feature(extern_item_impls)] diff --git a/tests/ui/eii/duplicate/auxiliary/impl1.rs b/tests/ui/eii/duplicate/auxiliary/impl1.rs index e99932c69b90b..ffa2cd79818cc 100644 --- a/tests/ui/eii/duplicate/auxiliary/impl1.rs +++ b/tests/ui/eii/duplicate/auxiliary/impl1.rs @@ -1,4 +1,3 @@ -//@ no-prefer-dynamic //@ aux-build: decl.rs #![crate_type = "rlib"] #![feature(extern_item_impls)] diff --git a/tests/ui/eii/duplicate/auxiliary/impl2.rs b/tests/ui/eii/duplicate/auxiliary/impl2.rs index 3a09c824b8292..592234f53fd40 100644 --- a/tests/ui/eii/duplicate/auxiliary/impl2.rs +++ b/tests/ui/eii/duplicate/auxiliary/impl2.rs @@ -1,4 +1,3 @@ -//@ no-prefer-dynamic //@ aux-build: decl.rs #![crate_type = "rlib"] #![feature(extern_item_impls)] diff --git a/tests/ui/eii/duplicate/auxiliary/impl3.rs b/tests/ui/eii/duplicate/auxiliary/impl3.rs index 09bdd8509da29..5e9fdaba0bb6b 100644 --- a/tests/ui/eii/duplicate/auxiliary/impl3.rs +++ b/tests/ui/eii/duplicate/auxiliary/impl3.rs @@ -1,4 +1,3 @@ -//@ no-prefer-dynamic //@ aux-build: decl.rs #![crate_type = "rlib"] #![feature(extern_item_impls)] diff --git a/tests/ui/eii/duplicate/auxiliary/impl4.rs b/tests/ui/eii/duplicate/auxiliary/impl4.rs index fd68a83de1252..068cc18d78e6a 100644 --- a/tests/ui/eii/duplicate/auxiliary/impl4.rs +++ b/tests/ui/eii/duplicate/auxiliary/impl4.rs @@ -1,4 +1,3 @@ -//@ no-prefer-dynamic //@ aux-build: decl.rs #![crate_type = "rlib"] #![feature(extern_item_impls)] diff --git a/tests/ui/eii/duplicate/duplicate1.rs b/tests/ui/eii/duplicate/duplicate1.rs index 2128cac70eb30..3d770232af50f 100644 --- a/tests/ui/eii/duplicate/duplicate1.rs +++ b/tests/ui/eii/duplicate/duplicate1.rs @@ -1,4 +1,3 @@ -//@ no-prefer-dynamic //@ aux-build: impl1.rs //@ aux-build: impl2.rs //@ ignore-backends: gcc diff --git a/tests/ui/eii/duplicate/duplicate1.stderr b/tests/ui/eii/duplicate/duplicate1.stderr index 54cc141f88694..f691043e6a597 100644 --- a/tests/ui/eii/duplicate/duplicate1.stderr +++ b/tests/ui/eii/duplicate/duplicate1.stderr @@ -1,10 +1,10 @@ error: multiple implementations of `#[eii1]` - --> $DIR/auxiliary/impl1.rs:10:1 + --> $DIR/auxiliary/impl1.rs:9:1 | LL | fn other(x: u64) { | ^^^^^^^^^^^^^^^^ first implemented here in crate `impl1` | - ::: $DIR/auxiliary/impl2.rs:10:1 + ::: $DIR/auxiliary/impl2.rs:9:1 | LL | fn other(x: u64) { | ---------------- also implemented here in crate `impl2` diff --git a/tests/ui/eii/duplicate/duplicate2.rs b/tests/ui/eii/duplicate/duplicate2.rs index b0f1b1266e4ca..4311969ed8894 100644 --- a/tests/ui/eii/duplicate/duplicate2.rs +++ b/tests/ui/eii/duplicate/duplicate2.rs @@ -1,4 +1,3 @@ -//@ no-prefer-dynamic //@ aux-build: impl1.rs //@ aux-build: impl2.rs //@ aux-build: impl3.rs diff --git a/tests/ui/eii/duplicate/duplicate2.stderr b/tests/ui/eii/duplicate/duplicate2.stderr index 033e43c8b2fbd..492d2b3e6004b 100644 --- a/tests/ui/eii/duplicate/duplicate2.stderr +++ b/tests/ui/eii/duplicate/duplicate2.stderr @@ -1,10 +1,10 @@ error: multiple implementations of `#[eii1]` - --> $DIR/auxiliary/impl1.rs:10:1 + --> $DIR/auxiliary/impl1.rs:9:1 | LL | fn other(x: u64) { | ^^^^^^^^^^^^^^^^ first implemented here in crate `impl1` | - ::: $DIR/auxiliary/impl2.rs:10:1 + ::: $DIR/auxiliary/impl2.rs:9:1 | LL | fn other(x: u64) { | ---------------- also implemented here in crate `impl2` diff --git a/tests/ui/eii/duplicate/duplicate3.rs b/tests/ui/eii/duplicate/duplicate3.rs index 4b2b0fc111b58..4504ba30c246e 100644 --- a/tests/ui/eii/duplicate/duplicate3.rs +++ b/tests/ui/eii/duplicate/duplicate3.rs @@ -1,4 +1,3 @@ -//@ no-prefer-dynamic //@ aux-build: impl1.rs //@ aux-build: impl2.rs //@ aux-build: impl3.rs diff --git a/tests/ui/eii/duplicate/duplicate3.stderr b/tests/ui/eii/duplicate/duplicate3.stderr index 801d40e69c552..f3ca087a27325 100644 --- a/tests/ui/eii/duplicate/duplicate3.stderr +++ b/tests/ui/eii/duplicate/duplicate3.stderr @@ -1,10 +1,10 @@ error: multiple implementations of `#[eii1]` - --> $DIR/auxiliary/impl1.rs:10:1 + --> $DIR/auxiliary/impl1.rs:9:1 | LL | fn other(x: u64) { | ^^^^^^^^^^^^^^^^ first implemented here in crate `impl1` | - ::: $DIR/auxiliary/impl2.rs:10:1 + ::: $DIR/auxiliary/impl2.rs:9:1 | LL | fn other(x: u64) { | ---------------- also implemented here in crate `impl2` diff --git a/tests/ui/eii/linking/auxiliary/codegen_cross_crate_other_crate.rs b/tests/ui/eii/linking/auxiliary/codegen_cross_crate_other_crate.rs index 7e0ba5f971c35..95fb896bd737d 100644 --- a/tests/ui/eii/linking/auxiliary/codegen_cross_crate_other_crate.rs +++ b/tests/ui/eii/linking/auxiliary/codegen_cross_crate_other_crate.rs @@ -1,4 +1,3 @@ -//@ no-prefer-dynamic #![crate_type = "rlib"] #![feature(extern_item_impls)] diff --git a/tests/ui/eii/privacy2.stderr b/tests/ui/eii/privacy2.stderr index f0a04bf635617..98d0c1600548f 100644 --- a/tests/ui/eii/privacy2.stderr +++ b/tests/ui/eii/privacy2.stderr @@ -11,13 +11,13 @@ LL | codegen::decl1(42); | ^^^^^ private function | note: the function `decl1` is defined here - --> $DIR/auxiliary/other_crate_privacy2.rs:7:1 + --> $DIR/auxiliary/other_crate_privacy2.rs:6:1 | LL | fn decl1(x: u64); | ^^^^^^^^^^^^^^^^^ error: `#[eii2]` required, but not found - --> $DIR/auxiliary/other_crate_privacy2.rs:9:7 + --> $DIR/auxiliary/other_crate_privacy2.rs:8:7 | LL | #[eii(eii2)] | ^^^^ expected because `#[eii2]` was declared here in crate `other_crate_privacy2` @@ -25,7 +25,7 @@ LL | #[eii(eii2)] = help: expected at least one implementation in crate `privacy2` or any of its dependencies error: `#[eii3]` required, but not found - --> $DIR/auxiliary/other_crate_privacy2.rs:13:11 + --> $DIR/auxiliary/other_crate_privacy2.rs:12:11 | LL | #[eii(eii3)] | ^^^^ expected because `#[eii3]` was declared here in crate `other_crate_privacy2` diff --git a/tests/ui/eii/static/auxiliary/cross_crate_decl.rs b/tests/ui/eii/static/auxiliary/cross_crate_decl.rs index 06b7daca22074..f74bf73ba96ef 100644 --- a/tests/ui/eii/static/auxiliary/cross_crate_decl.rs +++ b/tests/ui/eii/static/auxiliary/cross_crate_decl.rs @@ -1,4 +1,3 @@ -//@ no-prefer-dynamic #![crate_type = "rlib"] #![feature(extern_item_impls)] diff --git a/tests/ui/eii/static/auxiliary/cross_crate_def.rs b/tests/ui/eii/static/auxiliary/cross_crate_def.rs index 70933440a62be..56d3f6fcdc557 100644 --- a/tests/ui/eii/static/auxiliary/cross_crate_def.rs +++ b/tests/ui/eii/static/auxiliary/cross_crate_def.rs @@ -1,4 +1,3 @@ -//@ no-prefer-dynamic #![crate_type = "rlib"] #![feature(extern_item_impls)] diff --git a/tests/ui/eii/type_checking/auxiliary/cross_crate_eii_declaration.rs b/tests/ui/eii/type_checking/auxiliary/cross_crate_eii_declaration.rs index 95ae5d923b604..d19229b57390a 100644 --- a/tests/ui/eii/type_checking/auxiliary/cross_crate_eii_declaration.rs +++ b/tests/ui/eii/type_checking/auxiliary/cross_crate_eii_declaration.rs @@ -1,4 +1,3 @@ -//@ no-prefer-dynamic #![crate_type = "rlib"] #![feature(extern_item_impls)] #![feature(decl_macro)] diff --git a/tests/ui/eii/type_checking/cross_crate_wrong_ty.stderr b/tests/ui/eii/type_checking/cross_crate_wrong_ty.stderr index b2190a075b631..5a4947046abb5 100644 --- a/tests/ui/eii/type_checking/cross_crate_wrong_ty.stderr +++ b/tests/ui/eii/type_checking/cross_crate_wrong_ty.stderr @@ -6,7 +6,7 @@ LL | #[unsafe(cross_crate_eii_declaration::foo)] LL | fn other() -> u64 { | ^^^^^^^^^^^^^^^^^ expected 1 parameter, found 0 | - ::: $DIR/auxiliary/cross_crate_eii_declaration.rs:13:5 + ::: $DIR/auxiliary/cross_crate_eii_declaration.rs:12:5 | LL | pub safe fn bar(x: u64) -> u64; | ------------------------------- requires 1 parameter From ca70543ca4e5d499503e23bf0bd42af1b9869a0a Mon Sep 17 00:00:00 2001 From: malezjaa Date: Wed, 15 Apr 2026 23:13:54 +0200 Subject: [PATCH 3/8] map_try_insert changes --- library/Cargo.lock | 4 +-- library/alloc/src/collections/btree/map.rs | 31 +++++++++++++--- .../alloc/src/collections/btree/map/entry.rs | 27 +++----------- library/alloc/src/collections/mod.rs | 1 + library/std/Cargo.toml | 2 +- library/std/src/collections/hash/map.rs | 36 +++++++------------ 6 files changed, 48 insertions(+), 53 deletions(-) diff --git a/library/Cargo.lock b/library/Cargo.lock index d7227def0461d..ae0b1da8396fb 100644 --- a/library/Cargo.lock +++ b/library/Cargo.lock @@ -125,9 +125,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.17.0" +version = "0.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f467dd6dccf739c208452f8014c75c18bb8301b050ad1cfb27153803edb0f51" +checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" dependencies = [ "foldhash", "rustc-std-workspace-alloc", diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs index 8094356910f8c..7d994359ed48b 100644 --- a/library/alloc/src/collections/btree/map.rs +++ b/library/alloc/src/collections/btree/map.rs @@ -1059,7 +1059,7 @@ impl BTreeMap { /// a mutable reference to the value in the entry. /// /// If the map already had this key present, nothing is updated, and - /// an error containing the occupied entry and the value is returned. + /// an error containing the occupied entry, key, and the value is returned. /// /// # Examples /// @@ -1074,6 +1074,7 @@ impl BTreeMap { /// let err = map.try_insert(37, "b").unwrap_err(); /// assert_eq!(err.entry.key(), &37); /// assert_eq!(err.entry.get(), &"a"); + /// assert_eq!(err.key, 37); /// assert_eq!(err.value, "b"); /// ``` #[unstable(feature = "map_try_insert", issue = "82766")] @@ -1081,10 +1082,30 @@ impl BTreeMap { where K: Ord, { - match self.entry(key) { - Occupied(entry) => Err(OccupiedError { entry, value }), - Vacant(entry) => Ok(entry.insert(value)), - } + let (map, dormant_map) = DormantMutRef::new(self); + let handle = match map.root { + Some(ref mut root) => match root.borrow_mut().search_tree(&key) { + Found(handle) => { + let entry = OccupiedEntry { + handle, + dormant_map, + alloc: (*map.alloc).clone(), + _marker: PhantomData, + }; + return Err(OccupiedError { entry, key, value }); + } + GoDown(handle) => Some(handle), + }, + None => None, + }; + let entry = VacantEntry { + key, + handle, + dormant_map, + alloc: (*map.alloc).clone(), + _marker: PhantomData, + }; + Ok(entry.insert(value)) } /// Removes a key from the map, returning the value at the key if the key diff --git a/library/alloc/src/collections/btree/map/entry.rs b/library/alloc/src/collections/btree/map/entry.rs index add8782a9499a..b99fbb5e84bd6 100644 --- a/library/alloc/src/collections/btree/map/entry.rs +++ b/library/alloc/src/collections/btree/map/entry.rs @@ -97,8 +97,9 @@ impl Debug for OccupiedEntry<'_, /// The error returned by [`try_insert`](BTreeMap::try_insert) when the key already exists. /// -/// Contains the occupied entry, and the value that was not inserted. +/// Contains the occupied entry, key, and the value that was not inserted. #[unstable(feature = "map_try_insert", issue = "82766")] +#[non_exhaustive] pub struct OccupiedError< 'a, K: 'a, @@ -107,6 +108,8 @@ pub struct OccupiedError< > { /// The entry in the map that was already occupied. pub entry: OccupiedEntry<'a, K, V, A>, + /// The key which was not inserted, because the entry was already occupied. + pub key: K, /// The value which was not inserted, because the entry was already occupied. pub value: V, } @@ -116,33 +119,13 @@ impl Debug for OccupiedError<'_, fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("OccupiedError") .field("key", self.entry.key()) + .field("uninserted_key", &self.key) .field("old_value", self.entry.get()) .field("new_value", &self.value) .finish() } } -#[unstable(feature = "map_try_insert", issue = "82766")] -impl<'a, K: Debug + Ord, V: Debug, A: Allocator + Clone> fmt::Display - for OccupiedError<'a, K, V, A> -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "failed to insert {:?}, key {:?} already exists with value {:?}", - self.value, - self.entry.key(), - self.entry.get(), - ) - } -} - -#[unstable(feature = "map_try_insert", issue = "82766")] -impl<'a, K: core::fmt::Debug + Ord, V: core::fmt::Debug> core::error::Error - for crate::collections::btree_map::OccupiedError<'a, K, V> -{ -} - impl<'a, K: Ord, V, A: Allocator + Clone> Entry<'a, K, V, A> { /// Ensures a value is in the entry by inserting the default if empty, and returns /// a mutable reference to the value in the entry. diff --git a/library/alloc/src/collections/mod.rs b/library/alloc/src/collections/mod.rs index d306d2016ea28..d11cf5a594148 100644 --- a/library/alloc/src/collections/mod.rs +++ b/library/alloc/src/collections/mod.rs @@ -19,6 +19,7 @@ pub mod vec_deque; pub mod btree_map { //! An ordered map based on a B-Tree. #[stable(feature = "rust1", since = "1.0.0")] + #[cfg(not(test))] pub use super::btree::map::*; } diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index a22ef6c6689c8..4825aa1f5aa7f 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -20,7 +20,7 @@ panic_unwind = { path = "../panic_unwind", optional = true } panic_abort = { path = "../panic_abort" } core = { path = "../core", public = true } unwind = { path = "../unwind" } -hashbrown = { version = "0.17.0", default-features = false, features = [ +hashbrown = { version = "0.17.1", default-features = false, features = [ 'rustc-dep-of-std', ] } std_detect = { path = "../std_detect", public = true } diff --git a/library/std/src/collections/hash/map.rs b/library/std/src/collections/hash/map.rs index 4192254f6c824..50cfe8da150f9 100644 --- a/library/std/src/collections/hash/map.rs +++ b/library/std/src/collections/hash/map.rs @@ -1,13 +1,12 @@ #[cfg(test)] mod tests; -use hashbrown::hash_map as base; +use hashbrown::hash_map::{self as base, RustcOccupiedError}; use self::Entry::*; use crate::alloc::{Allocator, Global}; use crate::borrow::Borrow; use crate::collections::{TryReserveError, TryReserveErrorKind}; -use crate::error::Error; use crate::fmt::{self, Debug}; use crate::hash::{BuildHasher, Hash, RandomState}; use crate::iter::FusedIterator; @@ -1333,7 +1332,7 @@ where /// a mutable reference to the value in the entry. /// /// If the map already had this key present, nothing is updated, and - /// an error containing the occupied entry and the value is returned. + /// an error containing the occupied entry, key, and the value is returned. /// /// # Examples /// @@ -1350,13 +1349,16 @@ where /// let err = map.try_insert(37, "b").unwrap_err(); /// assert_eq!(err.entry.key(), &37); /// assert_eq!(err.entry.get(), &"a"); + /// assert_eq!(err.key, 37); /// assert_eq!(err.value, "b"); /// ``` #[unstable(feature = "map_try_insert", issue = "82766")] pub fn try_insert(&mut self, key: K, value: V) -> Result<&mut V, OccupiedError<'_, K, V, A>> { - match self.entry(key) { - Occupied(entry) => Err(OccupiedError { entry, value }), - Vacant(entry) => Ok(entry.insert(value)), + match self.base.rustc_try_insert(key, value) { + Result::Ok(value) => Ok(value), + Result::Err(RustcOccupiedError { entry, key, value, .. }) => { + Err(OccupiedError { entry: OccupiedEntry { base: entry }, key, value }) + } } } @@ -2007,8 +2009,9 @@ impl Debug for VacantEntry<'_, K, V, A> { /// The error returned by [`try_insert`](HashMap::try_insert) when the key already exists. /// -/// Contains the occupied entry, and the value that was not inserted. +/// Contains the occupied entry, key, and the value that was not inserted. #[unstable(feature = "map_try_insert", issue = "82766")] +#[non_exhaustive] pub struct OccupiedError< 'a, K: 'a, @@ -2017,6 +2020,8 @@ pub struct OccupiedError< > { /// The entry in the map that was already occupied. pub entry: OccupiedEntry<'a, K, V, A>, + /// The key which was not inserted, because the entry was already occupied. + pub key: K, /// The value which was not inserted, because the entry was already occupied. pub value: V, } @@ -2026,28 +2031,13 @@ impl Debug for OccupiedError<'_, K, V, A> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("OccupiedError") .field("key", self.entry.key()) + .field("uninserted_key", &self.key) .field("old_value", self.entry.get()) .field("new_value", &self.value) .finish_non_exhaustive() } } -#[unstable(feature = "map_try_insert", issue = "82766")] -impl<'a, K: Debug, V: Debug, A: Allocator> fmt::Display for OccupiedError<'a, K, V, A> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "failed to insert {:?}, key {:?} already exists with value {:?}", - self.value, - self.entry.key(), - self.entry.get(), - ) - } -} - -#[unstable(feature = "map_try_insert", issue = "82766")] -impl<'a, K: Debug, V: Debug, A: Allocator> Error for OccupiedError<'a, K, V, A> {} - #[stable(feature = "rust1", since = "1.0.0")] impl<'a, K, V, S, A: Allocator> IntoIterator for &'a HashMap { type Item = (&'a K, &'a V); From 9faff71e46e4dd4435529754a347d30a81d87ef4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 12 May 2026 09:40:58 +0200 Subject: [PATCH 4/8] actually run the temp_dir doctest --- library/std/src/env.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/env.rs b/library/std/src/env.rs index d3e4417656e9a..f60c8392785c1 100644 --- a/library/std/src/env.rs +++ b/library/std/src/env.rs @@ -689,7 +689,7 @@ pub fn home_dir() -> Option { /// [GetTempPath]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-gettemppatha /// [appledoc]: https://developer.apple.com/library/archive/documentation/Security/Conceptual/SecureCodingGuide/Articles/RaceConditions.html#//apple_ref/doc/uid/TP40002585-SW10 /// -/// ```no_run +/// ``` /// use std::env; /// /// fn main() { From 5a12d48b62befd848c950da9a74da82cadc36b00 Mon Sep 17 00:00:00 2001 From: Camille Gillot Date: Thu, 14 May 2026 22:12:50 +0000 Subject: [PATCH 5/8] Prefer tracing::instrument. --- .../rustc_mir_transform/src/elaborate_drop.rs | 37 ++++++++----------- 1 file changed, 15 insertions(+), 22 deletions(-) diff --git a/compiler/rustc_mir_transform/src/elaborate_drop.rs b/compiler/rustc_mir_transform/src/elaborate_drop.rs index 9f8a7774327c5..2d92fa8f55ffc 100644 --- a/compiler/rustc_mir_transform/src/elaborate_drop.rs +++ b/compiler/rustc_mir_transform/src/elaborate_drop.rs @@ -207,6 +207,7 @@ where // We keep async drop unexpanded to poll-loop here, to expand it later, at StateTransform - // into states expand. // call_destructor_only - to call only AsyncDrop::drop, not full async_drop_in_place glue + #[instrument(level = "debug", skip(self), ret)] fn build_async_drop( &mut self, place: Place<'tcx>, @@ -565,6 +566,7 @@ where .collect() } + #[instrument(level = "debug", skip(self), ret)] fn drop_subpath( &mut self, place: Place<'tcx>, @@ -574,8 +576,6 @@ where dropline: Option, ) -> BasicBlock { if let Some(path) = path { - debug!("drop_subpath: for std field {:?}", place); - DropCtxt { elaborator: self.elaborator, source_info: self.source_info, @@ -587,8 +587,6 @@ where } .elaborated_drop_block() } else { - debug!("drop_subpath: for rest field {:?}", place); - DropCtxt { elaborator: self.elaborator, source_info: self.source_info, @@ -614,6 +612,7 @@ where /// `dropline_ladder` is a similar list of steps in reverse order, /// which is called if the matching step of the drop glue will contain async drop /// (expanded later to Yield) and the containing coroutine will be dropped at this point. + #[instrument(level = "debug", skip(self), ret)] fn drop_halfladder( &mut self, unwind_ladder: &[Unwind], @@ -679,6 +678,7 @@ where /// /// NOTE: this does not clear the master drop flag, so you need /// to point succ/unwind on a `drop_ladder_bottom`. + #[instrument(level = "debug", skip(self), ret)] fn drop_ladder( &mut self, fields: Vec<(Place<'tcx>, Option)>, @@ -686,7 +686,6 @@ where unwind: Unwind, dropline: Option, ) -> (BasicBlock, Unwind, Option) { - debug!("drop_ladder({:?}, {:?})", self, fields); assert!( if unwind.is_cleanup() { dropline.is_none() } else { true }, "Dropline is set for cleanup drop ladder" @@ -723,9 +722,8 @@ where ) } + #[instrument(level = "debug", skip(self), ret)] fn open_drop_for_tuple(&mut self, tys: &[Ty<'tcx>]) -> BasicBlock { - debug!("open_drop_for_tuple({:?}, {:?})", self, tys); - let fields = tys .iter() .enumerate() @@ -994,8 +992,8 @@ where self.drop_flag_test_block(switch_block, succ, unwind) } + #[instrument(level = "debug", skip(self), ret)] fn destructor_call_block_sync(&mut self, (succ, unwind): (BasicBlock, Unwind)) -> BasicBlock { - debug!("destructor_call_block_sync({:?}, {:?})", self, succ); let tcx = self.tcx(); let drop_trait = tcx.require_lang_item(LangItem::Drop, DUMMY_SP); let drop_fn = tcx.associated_item_def_ids(drop_trait)[0]; @@ -1038,11 +1036,11 @@ where self.elaborator.patch().new_block(result) } + #[instrument(level = "debug", skip(self), ret)] fn destructor_call_block( &mut self, (succ, unwind, dropline): (BasicBlock, Unwind, Option), ) -> BasicBlock { - debug!("destructor_call_block({:?}, {:?})", self, succ); let ty = self.place_ty(self.place); if !unwind.is_cleanup() && self.check_if_can_async_drop(ty, true) { self.build_async_drop(self.place, ty, None, succ, unwind, dropline, true) @@ -1140,13 +1138,13 @@ where loop_block } + #[instrument(level = "debug", skip(self), ret)] fn open_drop_for_array( &mut self, array_ty: Ty<'tcx>, ety: Ty<'tcx>, opt_size: Option, ) -> BasicBlock { - debug!("open_drop_for_array({:?}, {:?}, {:?})", array_ty, ety, opt_size); let tcx = self.tcx(); if let Some(size) = opt_size { @@ -1250,8 +1248,8 @@ where /// Creates a trio of drop-loops of `place`, which drops its contents, even /// in the case of 1 panic or in the case of coroutine drop + #[instrument(level = "debug", skip(self), ret)] fn drop_loop_trio_for_slice(&mut self, ety: Ty<'tcx>) -> BasicBlock { - debug!("drop_loop_trio_for_slice({:?})", ety); let tcx = self.tcx(); let len = self.new_temp(tcx.types.usize); let cur = self.new_temp(tcx.types.usize); @@ -1349,24 +1347,21 @@ where } } + #[instrument(level = "debug", skip(self), ret)] fn complete_drop(&mut self, succ: BasicBlock, unwind: Unwind) -> BasicBlock { - debug!("complete_drop(succ={:?}, unwind={:?})", succ, unwind); - let drop_block = self.drop_block(succ, unwind); - self.drop_flag_test_block(drop_block, succ, unwind) } /// Creates a block that resets the drop flag. If `mode` is deep, all children drop flags will /// also be cleared. + #[instrument(level = "debug", skip(self), ret)] fn drop_flag_reset_block( &mut self, mode: DropFlagMode, succ: BasicBlock, unwind: Unwind, ) -> BasicBlock { - debug!("drop_flag_reset_block({:?},{:?})", self, mode); - if unwind.is_cleanup() { // The drop flag isn't read again on the unwind path, so don't // bother setting it. @@ -1378,8 +1373,8 @@ where block } + #[instrument(level = "debug", skip(self), ret)] fn elaborated_drop_block(&mut self) -> BasicBlock { - debug!("elaborated_drop_block({:?})", self); let blk = self.drop_block_simple(self.succ, self.unwind); self.elaborate_drop(blk); blk @@ -1432,6 +1427,7 @@ where /// Depending on the required `DropStyle`, this might be a generated block with an `if` /// terminator (for dynamic/open drops), or it might be `on_set` or `on_unset` itself, in case /// the drop can be statically determined. + #[instrument(level = "debug", skip(self), ret)] fn drop_flag_test_block( &mut self, on_set: BasicBlock, @@ -1439,11 +1435,6 @@ where unwind: Unwind, ) -> BasicBlock { let style = self.elaborator.drop_style(self.path, DropFlagMode::Shallow); - debug!( - "drop_flag_test_block({:?},{:?},{:?},{:?}) - {:?}", - self, on_set, on_unset, unwind, style - ); - match style { DropStyle::Dead => on_unset, DropStyle::Static => on_set, @@ -1455,6 +1446,7 @@ where } } + #[instrument(level = "trace", skip(self), ret)] fn new_block(&mut self, unwind: Unwind, k: TerminatorKind<'tcx>) -> BasicBlock { self.elaborator.patch().new_block(BasicBlockData::new( Some(Terminator { source_info: self.source_info, kind: k }), @@ -1462,6 +1454,7 @@ where )) } + #[instrument(level = "trace", skip(self, statements), ret)] fn new_block_with_statements( &mut self, unwind: Unwind, From d76d4cd69e0d3c7115a4d63169314ec0d6537cf7 Mon Sep 17 00:00:00 2001 From: Camille Gillot Date: Thu, 14 May 2026 22:13:05 +0000 Subject: [PATCH 6/8] Untuple method parameters. --- .../rustc_mir_transform/src/elaborate_drop.rs | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_mir_transform/src/elaborate_drop.rs b/compiler/rustc_mir_transform/src/elaborate_drop.rs index 2d92fa8f55ffc..2a1c06afe101a 100644 --- a/compiler/rustc_mir_transform/src/elaborate_drop.rs +++ b/compiler/rustc_mir_transform/src/elaborate_drop.rs @@ -798,7 +798,7 @@ where } let skip_contents = adt.is_union() || adt.is_manually_drop(); - let contents_drop = if skip_contents { + let (contents_succ, contents_unwind, contents_dropline) = if skip_contents { if adt.has_dtor(self.tcx()) && self.elaborator.get_drop_flag(self.path).is_some() { // the top-level drop flag is usually cleared by open_drop_for_adt_contents // types with destructors would still need an empty drop ladder to clear it @@ -817,21 +817,19 @@ where if adt.has_dtor(self.tcx()) { let destructor_block = if adt.is_box() { // we need to drop the inside of the box before running the destructor - let succ = self.destructor_call_block_sync((contents_drop.0, contents_drop.1)); - let unwind = contents_drop - .1 - .map(|unwind| self.destructor_call_block_sync((unwind, Unwind::InCleanup))); - let dropline = contents_drop - .2 - .map(|dropline| self.destructor_call_block_sync((dropline, contents_drop.1))); + let succ = self.destructor_call_block_sync(contents_succ, contents_unwind); + let unwind = contents_unwind + .map(|unwind| self.destructor_call_block_sync(unwind, Unwind::InCleanup)); + let dropline = contents_dropline + .map(|dropline| self.destructor_call_block_sync(dropline, contents_unwind)); self.open_drop_for_box_contents(adt, args, succ, unwind, dropline) } else { - self.destructor_call_block(contents_drop) + self.destructor_call_block(contents_succ, contents_unwind, contents_dropline) }; - self.drop_flag_test_block(destructor_block, contents_drop.0, contents_drop.1) + self.drop_flag_test_block(destructor_block, contents_succ, contents_unwind) } else { - contents_drop.0 + contents_succ } } @@ -993,7 +991,7 @@ where } #[instrument(level = "debug", skip(self), ret)] - fn destructor_call_block_sync(&mut self, (succ, unwind): (BasicBlock, Unwind)) -> BasicBlock { + fn destructor_call_block_sync(&mut self, succ: BasicBlock, unwind: Unwind) -> BasicBlock { let tcx = self.tcx(); let drop_trait = tcx.require_lang_item(LangItem::Drop, DUMMY_SP); let drop_fn = tcx.associated_item_def_ids(drop_trait)[0]; @@ -1039,13 +1037,15 @@ where #[instrument(level = "debug", skip(self), ret)] fn destructor_call_block( &mut self, - (succ, unwind, dropline): (BasicBlock, Unwind, Option), + succ: BasicBlock, + unwind: Unwind, + dropline: Option, ) -> BasicBlock { let ty = self.place_ty(self.place); if !unwind.is_cleanup() && self.check_if_can_async_drop(ty, true) { self.build_async_drop(self.place, ty, None, succ, unwind, dropline, true) } else { - self.destructor_call_block_sync((succ, unwind)) + self.destructor_call_block_sync(succ, unwind) } } From 6e7b089cb971aa634e41c6edf31663885ca457d2 Mon Sep 17 00:00:00 2001 From: Camille Gillot Date: Thu, 14 May 2026 18:22:17 +0000 Subject: [PATCH 7/8] Use DropCtxt::new_block and new_block_with_statements systematically. --- .../rustc_mir_transform/src/elaborate_drop.rs | 203 +++++++----------- 1 file changed, 74 insertions(+), 129 deletions(-) diff --git a/compiler/rustc_mir_transform/src/elaborate_drop.rs b/compiler/rustc_mir_transform/src/elaborate_drop.rs index 2a1c06afe101a..c835ff7dbe070 100644 --- a/compiler/rustc_mir_transform/src/elaborate_drop.rs +++ b/compiler/rustc_mir_transform/src/elaborate_drop.rs @@ -222,14 +222,8 @@ where let span = self.source_info.span; let pin_obj_bb = bb.unwrap_or_else(|| { - self.elaborator.patch().new_block(BasicBlockData::new( - Some(Terminator { - // Temporary terminator, will be replaced by patch - source_info: self.source_info, - kind: TerminatorKind::Return, - }), - false, - )) + // Temporary terminator, will be replaced by patch + self.new_block(unwind, TerminatorKind::Return) }); let (fut_ty, drop_fn_def_id, trait_args) = if call_destructor_only { @@ -594,8 +588,7 @@ where succ, unwind, dropline, - // Using `self.path` here to condition the drop on - // our own drop flag. + // Using `self.path` here to condition the drop on our own drop flag. path: self.path, } .complete_drop(succ, unwind) @@ -767,18 +760,14 @@ where let do_drop_bb = self.drop_subpath(interior, interior_path, succ, unwind, dropline); - let setup_bbd = BasicBlockData::new_stmts( + self.new_block_with_statements( + unwind, vec![self.assign( Place::from(ptr_local), Rvalue::Cast(CastKind::Transmute, Operand::Copy(nonnull_place), ptr_ty), )], - Some(Terminator { - kind: TerminatorKind::Goto { target: do_drop_bb }, - source_info: self.source_info, - }), - unwind.is_cleanup(), - ); - self.elaborator.patch().new_block(setup_bbd) + TerminatorKind::Goto { target: do_drop_bb }, + ) } #[instrument(level = "debug", ret)] @@ -788,13 +777,7 @@ where args: GenericArgsRef<'tcx>, ) -> BasicBlock { if adt.variants().is_empty() { - return self.elaborator.patch().new_block(BasicBlockData::new( - Some(Terminator { - source_info: self.source_info, - kind: TerminatorKind::Unreachable, - }), - self.unwind.is_cleanup(), - )); + return self.new_block(self.unwind, TerminatorKind::Unreachable); } let skip_contents = adt.is_union() || adt.is_manually_drop(); @@ -972,21 +955,17 @@ where let discr_ty = adt.repr().discr_type().to_ty(self.tcx()); let discr = Place::from(self.new_temp(discr_ty)); let discr_rv = Rvalue::Discriminant(self.place); - let switch_block = BasicBlockData::new_stmts( + let switch_block = self.new_block_with_statements( + unwind, vec![self.assign(discr, discr_rv)], - Some(Terminator { - source_info: self.source_info, - kind: TerminatorKind::SwitchInt { - discr: Operand::Move(discr), - targets: SwitchTargets::new( - values.iter().copied().zip(blocks.iter().copied()), - *blocks.last().unwrap(), - ), - }, - }), - unwind.is_cleanup(), + TerminatorKind::SwitchInt { + discr: Operand::Move(discr), + targets: SwitchTargets::new( + values.iter().copied().zip(blocks.iter().copied()), + *blocks.last().unwrap(), + ), + }, ); - let switch_block = self.elaborator.patch().new_block(switch_block); self.drop_flag_test_block(switch_block, succ, unwind) } @@ -1001,7 +980,8 @@ where let ref_place = self.new_temp(ref_ty); let unit_temp = Place::from(self.new_temp(tcx.types.unit)); - let result = BasicBlockData::new_stmts( + self.new_block_with_statements( + unwind, vec![self.assign( Place::from(ref_place), Rvalue::Ref( @@ -1010,28 +990,17 @@ where self.place, ), )], - Some(Terminator { - kind: TerminatorKind::Call { - func: Operand::function_handle( - tcx, - drop_fn, - [ty.into()], - self.source_info.span, - ), - args: [Spanned { node: Operand::Move(Place::from(ref_place)), span: DUMMY_SP }] - .into(), - destination: unit_temp, - target: Some(succ), - unwind: unwind.into_action(), - call_source: CallSource::Misc, - fn_span: self.source_info.span, - }, - source_info: self.source_info, - }), - unwind.is_cleanup(), - ); - - self.elaborator.patch().new_block(result) + TerminatorKind::Call { + func: Operand::function_handle(tcx, drop_fn, [ty.into()], self.source_info.span), + args: [Spanned { node: Operand::Move(Place::from(ref_place)), span: DUMMY_SP }] + .into(), + destination: unit_temp, + target: Some(succ), + unwind: unwind.into_action(), + call_source: CallSource::Misc, + fn_span: self.source_info.span, + }, + ) } #[instrument(level = "debug", skip(self), ret)] @@ -1078,7 +1047,8 @@ where let can_go = Place::from(self.new_temp(tcx.types.bool)); let one = self.constant_usize(1); - let drop_block = BasicBlockData::new_stmts( + let drop_block = self.new_block_with_statements( + unwind, vec![ self.assign( ptr, @@ -1089,27 +1059,18 @@ where Rvalue::BinaryOp(BinOp::Add, Box::new((move_(cur.into()), one))), ), ], - Some(Terminator { - source_info: self.source_info, - // this gets overwritten by drop elaboration. - kind: TerminatorKind::Unreachable, - }), - unwind.is_cleanup(), + // this gets overwritten by drop elaboration. + TerminatorKind::Unreachable, ); - let drop_block = self.elaborator.patch().new_block(drop_block); - let loop_block = BasicBlockData::new_stmts( + let loop_block = self.new_block_with_statements( + unwind, vec![self.assign( can_go, Rvalue::BinaryOp(BinOp::Eq, Box::new((copy(Place::from(cur)), copy(len.into())))), )], - Some(Terminator { - source_info: self.source_info, - kind: TerminatorKind::if_(move_(can_go), succ, drop_block), - }), - unwind.is_cleanup(), + TerminatorKind::if_(move_(can_go), succ, drop_block), ); - let loop_block = self.elaborator.patch().new_block(loop_block); let place = tcx.mk_place_deref(ptr); if !unwind.is_cleanup() && self.check_if_can_async_drop(ety, false) { @@ -1213,7 +1174,15 @@ where let slice_ptr_ty = Ty::new_mut_ptr(tcx, slice_ty); let slice_ptr = self.new_temp(slice_ptr_ty); - let mut delegate_block = BasicBlockData::new_stmts( + let array_place = mem::replace( + &mut self.place, + Place::from(slice_ptr).project_deeper(&[PlaceElem::Deref], tcx), + ); + let slice_block = self.drop_loop_trio_for_slice(ety); + self.place = array_place; + + self.new_block_with_statements( + self.unwind, vec![ self.assign(Place::from(array_ptr), Rvalue::RawPtr(RawPtrKind::Mut, self.place)), self.assign( @@ -1228,22 +1197,8 @@ where ), ), ], - None, - self.unwind.is_cleanup(), - ); - - let array_place = mem::replace( - &mut self.place, - Place::from(slice_ptr).project_deeper(&[PlaceElem::Deref], tcx), - ); - let slice_block = self.drop_loop_trio_for_slice(ety); - self.place = array_place; - - delegate_block.terminator = Some(Terminator { - source_info: self.source_info, - kind: TerminatorKind::Goto { target: slice_block }, - }); - self.elaborator.patch().new_block(delegate_block) + TerminatorKind::Goto { target: slice_block }, + ) } /// Creates a trio of drop-loops of `place`, which drops its contents, even @@ -1272,7 +1227,8 @@ where }; let zero = self.constant_usize(0); - let block = BasicBlockData::new_stmts( + let drop_block = self.new_block_with_statements( + unwind, vec![ self.assign( len.into(), @@ -1283,14 +1239,9 @@ where ), self.assign(cur.into(), Rvalue::Use(zero, WithRetag::Yes)), ], - Some(Terminator { - source_info: self.source_info, - kind: TerminatorKind::Goto { target: loop_block }, - }), - unwind.is_cleanup(), + TerminatorKind::Goto { target: loop_block }, ); - let drop_block = self.elaborator.patch().new_block(block); // FIXME(#34708): handle partially-dropped array/slice elements. let reset_block = self.drop_flag_reset_block(DropFlagMode::Deep, drop_block, unwind); self.drop_flag_test_block(reset_block, self.succ, unwind) @@ -1334,13 +1285,7 @@ where self.source_info.span, "open drop for unsafe binder shouldn't be encountered", ); - self.elaborator.patch().new_block(BasicBlockData::new( - Some(Terminator { - source_info: self.source_info, - kind: TerminatorKind::Unreachable, - }), - self.unwind.is_cleanup(), - )) + self.new_block(self.unwind, TerminatorKind::Unreachable) } _ => span_bug!(self.source_info.span, "open drop from non-ADT `{:?}`", ty), @@ -1375,23 +1320,21 @@ where #[instrument(level = "debug", skip(self), ret)] fn elaborated_drop_block(&mut self) -> BasicBlock { - let blk = self.drop_block_simple(self.succ, self.unwind); + let blk = self.new_block( + self.unwind, + TerminatorKind::Drop { + place: self.place, + target: self.succ, + unwind: self.unwind.into_action(), + replace: false, + drop: self.dropline, + async_fut: None, + }, + ); self.elaborate_drop(blk); blk } - fn drop_block_simple(&mut self, target: BasicBlock, unwind: Unwind) -> BasicBlock { - let block = TerminatorKind::Drop { - place: self.place, - target, - unwind: unwind.into_action(), - replace: false, - drop: self.dropline, - async_fut: None, - }; - self.new_block(unwind, block) - } - fn drop_block(&mut self, target: BasicBlock, unwind: Unwind) -> BasicBlock { let drop_ty = self.place_ty(self.place); if !unwind.is_cleanup() && self.check_if_can_async_drop(drop_ty, false) { @@ -1405,15 +1348,17 @@ where false, ) } else { - let block = TerminatorKind::Drop { - place: self.place, - target, - unwind: unwind.into_action(), - replace: false, - drop: None, - async_fut: None, - }; - self.new_block(unwind, block) + self.new_block( + unwind, + TerminatorKind::Drop { + place: self.place, + target, + unwind: unwind.into_action(), + replace: false, + drop: None, + async_fut: None, + }, + ) } } From 8909e794e7122aeca90ccf0ad662514937012260 Mon Sep 17 00:00:00 2001 From: Qai Juang Date: Wed, 13 May 2026 15:00:15 -0400 Subject: [PATCH 8/8] Require UTF-8 in `Utf8Pattern::StringPattern` --- library/alloc/src/str.rs | 5 ++++- library/alloc/src/string.rs | 2 +- library/core/src/str/pattern.rs | 8 +++++--- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/library/alloc/src/str.rs b/library/alloc/src/str.rs index 1efbedf5dc42f..cf04402e3d984 100644 --- a/library/alloc/src/str.rs +++ b/library/alloc/src/str.rs @@ -308,7 +308,10 @@ impl str { pub fn replace(&self, from: P, to: &str) -> String { // Fast path for replacing a single ASCII character with another. if let Some(from_byte) = match from.as_utf8_pattern() { - Some(Utf8Pattern::StringPattern([from_byte])) => Some(*from_byte), + Some(Utf8Pattern::StringPattern(s)) => match s.as_bytes() { + [from_byte] => Some(*from_byte), + _ => None, + }, Some(Utf8Pattern::CharPattern(c)) => c.as_ascii().map(|ascii_char| ascii_char.to_u8()), _ => None, } { diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs index 4e97dfd2d561e..e1285bc596484 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -2654,7 +2654,7 @@ impl<'b> Pattern for &'b String { #[inline] fn as_utf8_pattern(&self) -> Option> { - Some(Utf8Pattern::StringPattern(self.as_bytes())) + Some(Utf8Pattern::StringPattern(self.as_str())) } } diff --git a/library/core/src/str/pattern.rs b/library/core/src/str/pattern.rs index 25202ffd67313..77e0093d3ce84 100644 --- a/library/core/src/str/pattern.rs +++ b/library/core/src/str/pattern.rs @@ -161,7 +161,7 @@ pub trait Pattern: Sized { } } - /// Returns the pattern as utf-8 bytes if possible. + /// Returns the pattern as UTF-8 if possible. fn as_utf8_pattern(&self) -> Option> { None } @@ -172,7 +172,9 @@ pub trait Pattern: Sized { #[derive(Copy, Clone, Eq, PartialEq, Debug)] pub enum Utf8Pattern<'a> { /// Type returned by String and str types. - StringPattern(&'a [u8]), + /// This stores `str` rather than bytes so callers cannot describe + /// non-UTF-8 string patterns through this API. + StringPattern(&'a str), /// Type returned by char types. CharPattern(char), } @@ -1049,7 +1051,7 @@ impl<'b> Pattern for &'b str { #[inline] fn as_utf8_pattern(&self) -> Option> { - Some(Utf8Pattern::StringPattern(self.as_bytes())) + Some(Utf8Pattern::StringPattern(*self)) } }