From 9d9b55cd2b14bce066cef83d9d85ba798a2ba95c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 15 Jul 2024 21:25:03 +0200 Subject: [PATCH 01/12] make invalid_type_param_default lint show up in cargo future-compat reports and remove the feature gate that silenced the lint --- compiler/rustc_feature/src/removed.rs | 3 ++ compiler/rustc_feature/src/unstable.rs | 2 - .../src/collect/generics_of.rs | 2 - compiler/rustc_lint_defs/src/builtin.rs | 2 +- ...ate-default_type_parameter_fallback.stderr | 21 --------- tests/ui/impl-trait/where-allowed.stderr | 22 ++++++++++ tests/ui/issues/issue-26812.rs | 4 +- tests/ui/issues/issue-26812.stderr | 25 ++++++++++- .../lifetimes/unusual-rib-combinations.stderr | 11 +++++ ...ed-type-param-in-fn-with-assoc-type.stderr | 10 +++++ .../default_type_parameter_in_fn_or_impl.rs} | 0 ...efault_type_parameter_in_fn_or_impl.stderr | 43 +++++++++++++++++++ 12 files changed, 115 insertions(+), 30 deletions(-) delete mode 100644 tests/ui/feature-gates/feature-gate-default_type_parameter_fallback.stderr rename tests/ui/{feature-gates/feature-gate-default_type_parameter_fallback.rs => type/default_type_parameter_in_fn_or_impl.rs} (100%) create mode 100644 tests/ui/type/default_type_parameter_in_fn_or_impl.stderr diff --git a/compiler/rustc_feature/src/removed.rs b/compiler/rustc_feature/src/removed.rs index f13aa506c1ec0..a78ae0d6993e2 100644 --- a/compiler/rustc_feature/src/removed.rs +++ b/compiler/rustc_feature/src/removed.rs @@ -75,6 +75,9 @@ declare_features! ( /// Allows the use of `#[derive(Anything)]` as sugar for `#[derive_Anything]`. (removed, custom_derive, "1.32.0", Some(29644), Some("subsumed by `#[proc_macro_derive]`")), + /// Allows default type parameters to influence type inference. + (removed, default_type_parameter_fallback, "CURRENT_RUSTC_VERSION", Some(27336), + Some("never properly implemented; requires significant design work")), /// Allows using `#[doc(keyword = "...")]`. (removed, doc_keyword, "1.28.0", Some(51315), Some("merged into `#![feature(rustdoc_internals)]`")), diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 948499fb38fbf..407800ce60d5d 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -428,8 +428,6 @@ declare_features! ( (unstable, custom_test_frameworks, "1.30.0", Some(50297)), /// Allows declarative macros 2.0 (`macro`). (unstable, decl_macro, "1.17.0", Some(39412)), - /// Allows default type parameters to influence type inference. - (unstable, default_type_parameter_fallback, "1.3.0", Some(27336)), /// Allows using `#[deprecated_safe]` to deprecate the safeness of a function or trait (unstable, deprecated_safe, "1.61.0", Some(94978)), /// Allows having using `suggestion` in the `#[deprecated]` attribute. diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs index 22d465c8e62be..398a496a3737f 100644 --- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs @@ -323,8 +323,6 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { if default.is_some() { match allow_defaults { Defaults::Allowed => {} - Defaults::FutureCompatDisallowed - if tcx.features().default_type_parameter_fallback => {} Defaults::FutureCompatDisallowed => { tcx.node_span_lint( lint::builtin::INVALID_TYPE_PARAM_DEFAULT, diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index aa7844f40121b..276a507d3e89b 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -1241,7 +1241,7 @@ declare_lint! { Deny, "type parameter default erroneously allowed in invalid location", @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps, + reason: FutureIncompatibilityReason::FutureReleaseErrorReportInDeps, reference: "issue #36887 ", }; } diff --git a/tests/ui/feature-gates/feature-gate-default_type_parameter_fallback.stderr b/tests/ui/feature-gates/feature-gate-default_type_parameter_fallback.stderr deleted file mode 100644 index 308de2692930d..0000000000000 --- a/tests/ui/feature-gates/feature-gate-default_type_parameter_fallback.stderr +++ /dev/null @@ -1,21 +0,0 @@ -error: defaults for type parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions - --> $DIR/feature-gate-default_type_parameter_fallback.rs:3:8 - | -LL | fn avg(_: T) {} - | ^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #36887 - = note: `#[deny(invalid_type_param_default)]` on by default - -error: defaults for type parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions - --> $DIR/feature-gate-default_type_parameter_fallback.rs:8:6 - | -LL | impl S {} - | ^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #36887 - -error: aborting due to 2 previous errors - diff --git a/tests/ui/impl-trait/where-allowed.stderr b/tests/ui/impl-trait/where-allowed.stderr index f0d259d01de94..1fb69db98c162 100644 --- a/tests/ui/impl-trait/where-allowed.stderr +++ b/tests/ui/impl-trait/where-allowed.stderr @@ -433,3 +433,25 @@ error: aborting due to 50 previous errors Some errors have detailed explanations: E0053, E0118, E0283, E0562, E0599, E0658, E0666. For more information about an error, try `rustc --explain E0053`. +Future incompatibility report: Future breakage diagnostic: +error: defaults for type parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions + --> $DIR/where-allowed.rs:239:7 + | +LL | impl T {} + | ^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #36887 + = note: `#[deny(invalid_type_param_default)]` on by default + +Future breakage diagnostic: +error: defaults for type parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions + --> $DIR/where-allowed.rs:246:36 + | +LL | fn in_method_generic_param_default(_: T) {} + | ^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #36887 + = note: `#[deny(invalid_type_param_default)]` on by default + diff --git a/tests/ui/issues/issue-26812.rs b/tests/ui/issues/issue-26812.rs index 3391ea4b350af..e0723e016b381 100644 --- a/tests/ui/issues/issue-26812.rs +++ b/tests/ui/issues/issue-26812.rs @@ -1,6 +1,6 @@ -#![feature(default_type_parameter_fallback)] - fn avg(_: T) {} //~^ ERROR generic parameters with a default cannot use forward declared identifiers +//~| ERROR defaults for type parameters +//~| WARN previously accepted fn main() {} diff --git a/tests/ui/issues/issue-26812.stderr b/tests/ui/issues/issue-26812.stderr index c2a3d4b83d536..4a18b23fd8b13 100644 --- a/tests/ui/issues/issue-26812.stderr +++ b/tests/ui/issues/issue-26812.stderr @@ -1,9 +1,30 @@ error[E0128]: generic parameters with a default cannot use forward declared identifiers - --> $DIR/issue-26812.rs:3:10 + --> $DIR/issue-26812.rs:1:10 | LL | fn avg(_: T) {} | ^^^^^^^ defaulted generic parameters cannot be forward declared -error: aborting due to 1 previous error +error: defaults for type parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions + --> $DIR/issue-26812.rs:1:8 + | +LL | fn avg(_: T) {} + | ^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #36887 + = note: `#[deny(invalid_type_param_default)]` on by default + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0128`. +Future incompatibility report: Future breakage diagnostic: +error: defaults for type parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions + --> $DIR/issue-26812.rs:1:8 + | +LL | fn avg(_: T) {} + | ^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #36887 + = note: `#[deny(invalid_type_param_default)]` on by default + diff --git a/tests/ui/lifetimes/unusual-rib-combinations.stderr b/tests/ui/lifetimes/unusual-rib-combinations.stderr index 70f06b4be603c..3f97ae6c5bd54 100644 --- a/tests/ui/lifetimes/unusual-rib-combinations.stderr +++ b/tests/ui/lifetimes/unusual-rib-combinations.stderr @@ -68,3 +68,14 @@ error: aborting due to 8 previous errors Some errors have detailed explanations: E0106, E0214, E0308, E0770. For more information about an error, try `rustc --explain E0106`. +Future incompatibility report: Future breakage diagnostic: +error: defaults for type parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions + --> $DIR/unusual-rib-combinations.rs:15:6 + | +LL | fn c() {} + | ^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #36887 + = note: `#[deny(invalid_type_param_default)]` on by default + diff --git a/tests/ui/type-inference/unbounded-type-param-in-fn-with-assoc-type.stderr b/tests/ui/type-inference/unbounded-type-param-in-fn-with-assoc-type.stderr index dc0bea58a70e8..bf8829c09257f 100644 --- a/tests/ui/type-inference/unbounded-type-param-in-fn-with-assoc-type.stderr +++ b/tests/ui/type-inference/unbounded-type-param-in-fn-with-assoc-type.stderr @@ -12,3 +12,13 @@ LL | foo::(); error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0282`. +Future incompatibility report: Future breakage diagnostic: +warning: defaults for type parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions + --> $DIR/unbounded-type-param-in-fn-with-assoc-type.rs:3:11 + | +LL | fn foo() -> (T, U) { + | ^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #36887 + diff --git a/tests/ui/feature-gates/feature-gate-default_type_parameter_fallback.rs b/tests/ui/type/default_type_parameter_in_fn_or_impl.rs similarity index 100% rename from tests/ui/feature-gates/feature-gate-default_type_parameter_fallback.rs rename to tests/ui/type/default_type_parameter_in_fn_or_impl.rs diff --git a/tests/ui/type/default_type_parameter_in_fn_or_impl.stderr b/tests/ui/type/default_type_parameter_in_fn_or_impl.stderr new file mode 100644 index 0000000000000..a3205cd3c29ca --- /dev/null +++ b/tests/ui/type/default_type_parameter_in_fn_or_impl.stderr @@ -0,0 +1,43 @@ +error: defaults for type parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions + --> $DIR/default_type_parameter_in_fn_or_impl.rs:3:8 + | +LL | fn avg(_: T) {} + | ^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #36887 + = note: `#[deny(invalid_type_param_default)]` on by default + +error: defaults for type parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions + --> $DIR/default_type_parameter_in_fn_or_impl.rs:8:6 + | +LL | impl S {} + | ^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #36887 + +error: aborting due to 2 previous errors + +Future incompatibility report: Future breakage diagnostic: +error: defaults for type parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions + --> $DIR/default_type_parameter_in_fn_or_impl.rs:3:8 + | +LL | fn avg(_: T) {} + | ^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #36887 + = note: `#[deny(invalid_type_param_default)]` on by default + +Future breakage diagnostic: +error: defaults for type parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions + --> $DIR/default_type_parameter_in_fn_or_impl.rs:8:6 + | +LL | impl S {} + | ^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #36887 + = note: `#[deny(invalid_type_param_default)]` on by default + From bda31d14f47e49b0aa69173bf8793a9a6e0bead7 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 18 Jul 2024 12:26:19 +0200 Subject: [PATCH 02/12] built-in derive: remove BYTE_SLICE_IN_PACKED_STRUCT_WITH_DERIVE hack and lint --- .../src/deriving/generic/mod.rs | 54 ++------------ compiler/rustc_lint/src/lib.rs | 7 +- compiler/rustc_lint_defs/src/builtin.rs | 34 --------- tests/ui/derives/deriving-with-repr-packed.rs | 11 +-- .../derives/deriving-with-repr-packed.stderr | 74 +++++++------------ tests/ui/deriving/deriving-all-codegen.rs | 10 --- tests/ui/deriving/deriving-all-codegen.stderr | 63 ---------------- tests/ui/deriving/deriving-all-codegen.stdout | 20 ----- 8 files changed, 41 insertions(+), 232 deletions(-) delete mode 100644 tests/ui/deriving/deriving-all-codegen.stderr diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs index ba289f9552e22..fc1cf71a130a2 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs @@ -181,11 +181,10 @@ use crate::{deriving, errors}; use rustc_ast::ptr::P; use rustc_ast::{ self as ast, BindingMode, ByRef, EnumDef, Expr, GenericArg, GenericParamKind, Generics, - Mutability, PatKind, TyKind, VariantData, + Mutability, PatKind, VariantData, }; use rustc_attr as attr; use rustc_expand::base::{Annotatable, ExtCtxt}; -use rustc_session::lint::builtin::BYTE_SLICE_IN_PACKED_STRUCT_WITH_DERIVE; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{Span, DUMMY_SP}; use std::cell::RefCell; @@ -1599,52 +1598,11 @@ impl<'a> TraitDef<'a> { ), ); if is_packed { - // In general, fields in packed structs are copied via a - // block, e.g. `&{self.0}`. The two exceptions are `[u8]` - // and `str` fields, which cannot be copied and also never - // cause unaligned references. These exceptions are allowed - // to handle the `FlexZeroSlice` type in the `zerovec` - // crate within `icu4x-0.9.0`. - // - // Once use of `icu4x-0.9.0` has dropped sufficiently, this - // exception should be removed. - let is_simple_path = |ty: &P, sym| { - if let TyKind::Path(None, ast::Path { segments, .. }) = &ty.kind - && let [seg] = segments.as_slice() - && seg.ident.name == sym - && seg.args.is_none() - { - true - } else { - false - } - }; - - let exception = if let TyKind::Slice(ty) = &struct_field.ty.kind - && is_simple_path(ty, sym::u8) - { - Some("byte") - } else if is_simple_path(&struct_field.ty, sym::str) { - Some("string") - } else { - None - }; - - if let Some(ty) = exception { - cx.sess.psess.buffer_lint( - BYTE_SLICE_IN_PACKED_STRUCT_WITH_DERIVE, - sp, - ast::CRATE_NODE_ID, - rustc_lint_defs::BuiltinLintDiag::ByteSliceInPackedStructWithDerive { - ty: ty.to_string(), - }, - ); - } else { - // Wrap the expression in `{...}`, causing a copy. - field_expr = cx.expr_block( - cx.block(struct_field.span, thin_vec![cx.stmt_expr(field_expr)]), - ); - } + // Fields in packed structs are wrapped in a block, e.g. `&{self.0}`, + // causing a copy instead of a (potentially misaligned) reference. + field_expr = cx.expr_block( + cx.block(struct_field.span, thin_vec![cx.stmt_expr(field_expr)]), + ); } cx.expr_addr_of(sp, field_expr) }) diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 4e83ef0c6291b..7f4904bb48a41 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -537,7 +537,7 @@ fn register_builtins(store: &mut LintStore) { ); store.register_removed( "suspicious_auto_trait_impls", - "no longer needed, see #93367 \ + "no longer needed, see issue #93367 \ for more information", ); store.register_removed( @@ -559,6 +559,11 @@ fn register_builtins(store: &mut LintStore) { "box_pointers", "it does not detect other kinds of allocations, and existed only for historical reasons", ); + store.register_removed( + "byte_slice_in_packed_struct_with_derive", + "converted into hard error, see issue #107457 \ + for more information", + ) } fn register_internals(store: &mut LintStore) { diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index aa7844f40121b..f37d3d402df02 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -25,7 +25,6 @@ declare_lint_pass! { BARE_TRAIT_OBJECTS, BINDINGS_WITH_VARIANT_NAME, BREAK_WITH_LABEL_AND_LOOP, - BYTE_SLICE_IN_PACKED_STRUCT_WITH_DERIVE, CENUM_IMPL_DROP_CAST, COHERENCE_LEAK_CHECK, CONFLICTING_REPR_HINTS, @@ -4246,39 +4245,6 @@ declare_lint! { report_in_external_macro } -declare_lint! { - /// The `byte_slice_in_packed_struct_with_derive` lint detects cases where a byte slice field - /// (`[u8]`) or string slice field (`str`) is used in a `packed` struct that derives one or - /// more built-in traits. - /// - /// ### Example - /// - /// ```rust - /// #[repr(packed)] - /// #[derive(Hash)] - /// struct FlexZeroSlice { - /// width: u8, - /// data: [u8], - /// } - /// ``` - /// - /// {{produces}} - /// - /// ### Explanation - /// - /// This was previously accepted but is being phased out, because fields in packed structs are - /// now required to implement `Copy` for `derive` to work. Byte slices and string slices are a - /// temporary exception because certain crates depended on them. - pub BYTE_SLICE_IN_PACKED_STRUCT_WITH_DERIVE, - Warn, - "`[u8]` or `str` used in a packed struct with `derive`", - @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::FutureReleaseErrorReportInDeps, - reference: "issue #107457 ", - }; - report_in_external_macro -} - declare_lint! { /// The `invalid_macro_export_arguments` lint detects cases where `#[macro_export]` is being used with invalid arguments. /// diff --git a/tests/ui/derives/deriving-with-repr-packed.rs b/tests/ui/derives/deriving-with-repr-packed.rs index 58be451972017..d17b52842cefd 100644 --- a/tests/ui/derives/deriving-with-repr-packed.rs +++ b/tests/ui/derives/deriving-with-repr-packed.rs @@ -22,25 +22,22 @@ struct Y(usize); struct X(Y); //~^ ERROR cannot move out of `self` which is behind a shared reference -// This is currently allowed, but will be phased out at some point. From -// `zerovec` within icu4x-0.9.0. #[derive(Debug)] #[repr(packed)] struct FlexZeroSlice { width: u8, data: [u8], - //~^ WARNING byte slice in a packed struct that derives a built-in trait - //~^^ this was previously accepted + //~^ ERROR cannot move + //~| ERROR cannot move } -// Again, currently allowed, but will be phased out. #[derive(Debug)] #[repr(packed)] struct WithStr { width: u8, data: str, - //~^ WARNING string slice in a packed struct that derives a built-in trait - //~^^ this was previously accepted + //~^ ERROR cannot move + //~| ERROR cannot move } fn main() {} diff --git a/tests/ui/derives/deriving-with-repr-packed.stderr b/tests/ui/derives/deriving-with-repr-packed.stderr index a8523d25cab9b..321ffb27eeb11 100644 --- a/tests/ui/derives/deriving-with-repr-packed.stderr +++ b/tests/ui/derives/deriving-with-repr-packed.stderr @@ -1,32 +1,3 @@ -warning: byte slice in a packed struct that derives a built-in trait - --> $DIR/deriving-with-repr-packed.rs:31:5 - | -LL | #[derive(Debug)] - | ----- in this derive macro expansion -... -LL | data: [u8], - | ^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #107457 - = help: consider implementing the trait by hand, or remove the `packed` attribute - = note: `#[warn(byte_slice_in_packed_struct_with_derive)]` on by default - = note: this warning originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info) - -warning: string slice in a packed struct that derives a built-in trait - --> $DIR/deriving-with-repr-packed.rs:41:5 - | -LL | #[derive(Debug)] - | ----- in this derive macro expansion -... -LL | data: str, - | ^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #107457 - = help: consider implementing the trait by hand, or remove the `packed` attribute - = note: this warning originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info) - error[E0507]: cannot move out of `self` which is behind a shared reference --> $DIR/deriving-with-repr-packed.rs:22:10 | @@ -47,38 +18,43 @@ LL | struct X(Y); = note: `#[derive(Debug)]` triggers a move because taking references to the fields of a packed struct is undefined behaviour = note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 1 previous error; 2 warnings emitted +error[E0161]: cannot move a value of type `[u8]` + --> $DIR/deriving-with-repr-packed.rs:29:5 + | +LL | data: [u8], + | ^^^^^^^^^^ the size of `[u8]` cannot be statically determined -For more information about this error, try `rustc --explain E0507`. -Future incompatibility report: Future breakage diagnostic: -warning: byte slice in a packed struct that derives a built-in trait - --> $DIR/deriving-with-repr-packed.rs:31:5 +error[E0507]: cannot move out of `self.data` which is behind a shared reference + --> $DIR/deriving-with-repr-packed.rs:29:5 | LL | #[derive(Debug)] | ----- in this derive macro expansion ... LL | data: [u8], - | ^^^^^^^^^^ + | ^^^^^^^^^^ move occurs because `self.data` has type `[u8]`, which does not implement the `Copy` trait + | + = note: `#[derive(Debug)]` triggers a move because taking references to the fields of a packed struct is undefined behaviour + = note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0161]: cannot move a value of type `str` + --> $DIR/deriving-with-repr-packed.rs:38:5 | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #107457 - = help: consider implementing the trait by hand, or remove the `packed` attribute - = note: `#[warn(byte_slice_in_packed_struct_with_derive)]` on by default - = note: this warning originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info) +LL | data: str, + | ^^^^^^^^^ the size of `str` cannot be statically determined -Future breakage diagnostic: -warning: string slice in a packed struct that derives a built-in trait - --> $DIR/deriving-with-repr-packed.rs:41:5 +error[E0507]: cannot move out of `self.data` which is behind a shared reference + --> $DIR/deriving-with-repr-packed.rs:38:5 | LL | #[derive(Debug)] | ----- in this derive macro expansion ... LL | data: str, - | ^^^^^^^^^ + | ^^^^^^^^^ move occurs because `self.data` has type `str`, which does not implement the `Copy` trait | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #107457 - = help: consider implementing the trait by hand, or remove the `packed` attribute - = note: `#[warn(byte_slice_in_packed_struct_with_derive)]` on by default - = note: this warning originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: `#[derive(Debug)]` triggers a move because taking references to the fields of a packed struct is undefined behaviour + = note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 5 previous errors +Some errors have detailed explanations: E0161, E0507. +For more information about an error, try `rustc --explain E0161`. diff --git a/tests/ui/deriving/deriving-all-codegen.rs b/tests/ui/deriving/deriving-all-codegen.rs index 6fa4f74f2a508..eab2b4f1f5335 100644 --- a/tests/ui/deriving/deriving-all-codegen.rs +++ b/tests/ui/deriving/deriving-all-codegen.rs @@ -73,16 +73,6 @@ impl Copy for PackedManualCopy {} #[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] struct Unsized([u32]); -// A packed struct with an unsized `[u8]` field. This is currently allowed, but -// causes a warning and will be phased out at some point. -#[derive(Debug, Hash)] -#[repr(packed)] -struct PackedUnsizedU8([u8]); -//~^ WARNING byte slice in a packed struct that derives a built-in trait -//~^^ WARNING byte slice in a packed struct that derives a built-in trait -//~^^^ this was previously accepted -//~^^^^ this was previously accepted - trait Trait { type A; } diff --git a/tests/ui/deriving/deriving-all-codegen.stderr b/tests/ui/deriving/deriving-all-codegen.stderr deleted file mode 100644 index 503f0cae73b69..0000000000000 --- a/tests/ui/deriving/deriving-all-codegen.stderr +++ /dev/null @@ -1,63 +0,0 @@ -warning: byte slice in a packed struct that derives a built-in trait - --> $DIR/deriving-all-codegen.rs:80:24 - | -LL | #[derive(Debug, Hash)] - | ----- in this derive macro expansion -LL | #[repr(packed)] -LL | struct PackedUnsizedU8([u8]); - | ^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #107457 - = help: consider implementing the trait by hand, or remove the `packed` attribute - = note: `#[warn(byte_slice_in_packed_struct_with_derive)]` on by default - = note: this warning originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info) - -warning: byte slice in a packed struct that derives a built-in trait - --> $DIR/deriving-all-codegen.rs:80:24 - | -LL | #[derive(Debug, Hash)] - | ---- in this derive macro expansion -LL | #[repr(packed)] -LL | struct PackedUnsizedU8([u8]); - | ^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #107457 - = help: consider implementing the trait by hand, or remove the `packed` attribute - = note: this warning originates in the derive macro `Hash` (in Nightly builds, run with -Z macro-backtrace for more info) - -warning: 2 warnings emitted - -Future incompatibility report: Future breakage diagnostic: -warning: byte slice in a packed struct that derives a built-in trait - --> $DIR/deriving-all-codegen.rs:80:24 - | -LL | #[derive(Debug, Hash)] - | ----- in this derive macro expansion -LL | #[repr(packed)] -LL | struct PackedUnsizedU8([u8]); - | ^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #107457 - = help: consider implementing the trait by hand, or remove the `packed` attribute - = note: `#[warn(byte_slice_in_packed_struct_with_derive)]` on by default - = note: this warning originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info) - -Future breakage diagnostic: -warning: byte slice in a packed struct that derives a built-in trait - --> $DIR/deriving-all-codegen.rs:80:24 - | -LL | #[derive(Debug, Hash)] - | ---- in this derive macro expansion -LL | #[repr(packed)] -LL | struct PackedUnsizedU8([u8]); - | ^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #107457 - = help: consider implementing the trait by hand, or remove the `packed` attribute - = note: `#[warn(byte_slice_in_packed_struct_with_derive)]` on by default - = note: this warning originates in the derive macro `Hash` (in Nightly builds, run with -Z macro-backtrace for more info) - diff --git a/tests/ui/deriving/deriving-all-codegen.stdout b/tests/ui/deriving/deriving-all-codegen.stdout index 6b69b57c51619..6503c87099040 100644 --- a/tests/ui/deriving/deriving-all-codegen.stdout +++ b/tests/ui/deriving/deriving-all-codegen.stdout @@ -516,26 +516,6 @@ impl ::core::cmp::Ord for Unsized { } } -// A packed struct with an unsized `[u8]` field. This is currently allowed, but -// causes a warning and will be phased out at some point. -#[repr(packed)] -struct PackedUnsizedU8([u8]); -#[automatically_derived] -impl ::core::fmt::Debug for PackedUnsizedU8 { - #[inline] - fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { - ::core::fmt::Formatter::debug_tuple_field1_finish(f, - "PackedUnsizedU8", &&self.0) - } -} -#[automatically_derived] -impl ::core::hash::Hash for PackedUnsizedU8 { - #[inline] - fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () { - ::core::hash::Hash::hash(&self.0, state) - } -} - trait Trait { type A; } From 9b165a16009980545a864eb5899c3b3279f58f37 Mon Sep 17 00:00:00 2001 From: Ken Micklas Date: Sun, 28 Jul 2024 15:03:07 +0100 Subject: [PATCH 03/12] Implement cursors for `BTreeSet` --- library/alloc/src/collections/btree/set.rs | 427 ++++++++++++++++++++- 1 file changed, 426 insertions(+), 1 deletion(-) diff --git a/library/alloc/src/collections/btree/set.rs b/library/alloc/src/collections/btree/set.rs index b0bd6ef2d3c63..6f23d686bcf8e 100644 --- a/library/alloc/src/collections/btree/set.rs +++ b/library/alloc/src/collections/btree/set.rs @@ -2,11 +2,12 @@ use crate::vec::Vec; use core::borrow::Borrow; use core::cmp::Ordering::{self, Equal, Greater, Less}; use core::cmp::{max, min}; +use core::error::Error; use core::fmt::{self, Debug}; use core::hash::{Hash, Hasher}; use core::iter::{FusedIterator, Peekable}; use core::mem::ManuallyDrop; -use core::ops::{BitAnd, BitOr, BitXor, RangeBounds, Sub}; +use core::ops::{BitAnd, BitOr, BitXor, Bound, RangeBounds, Sub}; use super::map::{BTreeMap, Keys}; use super::merge_iter::MergeIterInner; @@ -1183,6 +1184,178 @@ impl BTreeSet { pub const fn is_empty(&self) -> bool { self.len() == 0 } + + /// Returns a [`Cursor`] pointing at the gap before the smallest element + /// greater than the given bound. + /// + /// Passing `Bound::Included(x)` will return a cursor pointing to the + /// gap before the smallest element greater than or equal to `x`. + /// + /// Passing `Bound::Excluded(x)` will return a cursor pointing to the + /// gap before the smallest element greater than `x`. + /// + /// Passing `Bound::Unbounded` will return a cursor pointing to the + /// gap before the smallest element in the map. + /// + /// # Examples + /// + /// ``` + /// #![feature(btree_cursors)] + /// + /// use std::collections::BTreeSet; + /// use std::ops::Bound; + /// + /// let set = BTreeSet::from([1, 2, 3, 4]); + /// + /// let cursor = set.lower_bound(Bound::Included(&2)); + /// assert_eq!(cursor.peek_prev(), Some(&1)); + /// assert_eq!(cursor.peek_next(), Some(&2)); + /// + /// let cursor = set.lower_bound(Bound::Excluded(&2)); + /// assert_eq!(cursor.peek_prev(), Some(&2)); + /// assert_eq!(cursor.peek_next(), Some(&3)); + /// + /// let cursor = set.lower_bound(Bound::Unbounded); + /// assert_eq!(cursor.peek_prev(), None); + /// assert_eq!(cursor.peek_next(), Some(&1)); + /// ``` + #[unstable(feature = "btree_cursors", issue = "107540")] + pub fn lower_bound(&self, bound: Bound<&Q>) -> Cursor<'_, T> + where + T: Borrow + Ord, + Q: Ord, + { + Cursor { inner: self.map.lower_bound(bound) } + } + + /// Returns a [`CursorMut`] pointing at the gap before the smallest element + /// greater than the given bound. + /// + /// Passing `Bound::Included(x)` will return a cursor pointing to the + /// gap before the smallest element greater than or equal to `x`. + /// + /// Passing `Bound::Excluded(x)` will return a cursor pointing to the + /// gap before the smallest element greater than `x`. + /// + /// Passing `Bound::Unbounded` will return a cursor pointing to the + /// gap before the smallest element in the map. + /// + /// # Examples + /// + /// ``` + /// #![feature(btree_cursors)] + /// + /// use std::collections::BTreeSet; + /// use std::ops::Bound; + /// + /// let mut set = BTreeSet::from([1, 2, 3, 4]); + /// + /// let mut cursor = unsafe { set.lower_bound_mut(Bound::Included(&2)) }; + /// assert_eq!(cursor.peek_prev(), Some(&mut 1)); + /// assert_eq!(cursor.peek_next(), Some(&mut 2)); + /// + /// let mut cursor = unsafe { set.lower_bound_mut(Bound::Excluded(&2)) }; + /// assert_eq!(cursor.peek_prev(), Some(&mut 2)); + /// assert_eq!(cursor.peek_next(), Some(&mut 3)); + /// + /// let mut cursor = unsafe { set.lower_bound_mut(Bound::Unbounded) }; + /// assert_eq!(cursor.peek_prev(), None); + /// assert_eq!(cursor.peek_next(), Some(&mut 1)); + /// ``` + #[unstable(feature = "btree_cursors", issue = "107540")] + pub unsafe fn lower_bound_mut(&mut self, bound: Bound<&Q>) -> CursorMut<'_, T, A> + where + T: Borrow + Ord, + Q: Ord, + { + CursorMut { inner: unsafe { self.map.lower_bound_mut(bound).with_mutable_key() } } + } + + /// Returns a [`Cursor`] pointing at the gap after the greatest element + /// smaller than the given bound. + /// + /// Passing `Bound::Included(x)` will return a cursor pointing to the + /// gap after the greatest element smaller than or equal to `x`. + /// + /// Passing `Bound::Excluded(x)` will return a cursor pointing to the + /// gap after the greatest element smaller than `x`. + /// + /// Passing `Bound::Unbounded` will return a cursor pointing to the + /// gap after the greatest element in the map. + /// + /// # Examples + /// + /// ``` + /// #![feature(btree_cursors)] + /// + /// use std::collections::BTreeSet; + /// use std::ops::Bound; + /// + /// let set = BTreeSet::from([1, 2, 3, 4]); + /// + /// let cursor = set.upper_bound(Bound::Included(&3)); + /// assert_eq!(cursor.peek_prev(), Some(&3)); + /// assert_eq!(cursor.peek_next(), Some(&4)); + /// + /// let cursor = set.upper_bound(Bound::Excluded(&3)); + /// assert_eq!(cursor.peek_prev(), Some(&2)); + /// assert_eq!(cursor.peek_next(), Some(&3)); + /// + /// let cursor = set.upper_bound(Bound::Unbounded); + /// assert_eq!(cursor.peek_prev(), Some(&4)); + /// assert_eq!(cursor.peek_next(), None); + /// ``` + #[unstable(feature = "btree_cursors", issue = "107540")] + pub fn upper_bound(&self, bound: Bound<&Q>) -> Cursor<'_, T> + where + T: Borrow + Ord, + Q: Ord, + { + Cursor { inner: self.map.upper_bound(bound) } + } + + /// Returns a [`CursorMut`] pointing at the gap after the greatest element + /// smaller than the given bound. + /// + /// Passing `Bound::Included(x)` will return a cursor pointing to the + /// gap after the greatest element smaller than or equal to `x`. + /// + /// Passing `Bound::Excluded(x)` will return a cursor pointing to the + /// gap after the greatest element smaller than `x`. + /// + /// Passing `Bound::Unbounded` will return a cursor pointing to the + /// gap after the greatest element in the map. + /// + /// # Examples + /// + /// ``` + /// #![feature(btree_cursors)] + /// + /// use std::collections::BTreeSet; + /// use std::ops::Bound; + /// + /// let mut set = BTreeSet::from([1, 2, 3, 4]); + /// + /// let mut cursor = unsafe { set.upper_bound_mut(Bound::Included(&3)) }; + /// assert_eq!(cursor.peek_prev(), Some(&mut 3)); + /// assert_eq!(cursor.peek_next(), Some(&mut 4)); + /// + /// let mut cursor = unsafe { set.upper_bound_mut(Bound::Excluded(&3)) }; + /// assert_eq!(cursor.peek_prev(), Some(&mut 2)); + /// assert_eq!(cursor.peek_next(), Some(&mut 3)); + /// + /// let mut cursor = unsafe { set.upper_bound_mut(Bound::Unbounded) }; + /// assert_eq!(cursor.peek_prev(), Some(&mut 4)); + /// assert_eq!(cursor.peek_next(), None); + /// ``` + #[unstable(feature = "btree_cursors", issue = "107540")] + pub unsafe fn upper_bound_mut(&mut self, bound: Bound<&Q>) -> CursorMut<'_, T, A> + where + T: Borrow + Ord, + Q: Ord, + { + CursorMut { inner: unsafe { self.map.upper_bound_mut(bound).with_mutable_key() } } + } } #[stable(feature = "rust1", since = "1.0.0")] @@ -1817,5 +1990,257 @@ impl<'a, T: Ord> Iterator for Union<'a, T> { #[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for Union<'_, T> {} +/// A cursor over a `BTreeSet`. +/// +/// A `Cursor` is like an iterator, except that it can freely seek back-and-forth. +/// +/// Cursors always point to a gap between two elements in the set, and can +/// operate on the two immediately adjacent elements. +/// +/// A `Cursor` is created with the [`BTreeSet::lower_bound`] and [`BTreeSet::upper_bound`] methods. +#[derive(Clone)] +#[unstable(feature = "btree_cursors", issue = "107540")] +pub struct Cursor<'a, K: 'a> { + inner: super::map::Cursor<'a, K, SetValZST>, +} + +#[unstable(feature = "btree_cursors", issue = "107540")] +impl Debug for Cursor<'_, K> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("Cursor") + } +} + +/// A cursor over a `BTreeSet` with editing operations, and which allows +/// mutating elements. +/// +/// A `Cursor` is like an iterator, except that it can freely seek back-and-forth, and can +/// safely mutate the set during iteration. This is because the lifetime of its yielded +/// references is tied to its own lifetime, instead of just the underlying set. This means +/// cursors cannot yield multiple elements at once. +/// +/// Cursors always point to a gap between two elements in the set, and can +/// operate on the two immediately adjacent elements. +/// +/// A `CursorMut` is created with the [`BTreeSet::lower_bound_mut`] and +/// [`BTreeSet::upper_bound_mut`] methods. +/// +/// # Safety +/// +/// Since this cursor allows mutating elements, you must ensure that the +/// `BTreeSet` invariants are maintained. Specifically: +/// +/// * The newly inserted element must be unique in the tree. +/// * All elements in the tree must remain in sorted order. +#[unstable(feature = "btree_cursors", issue = "107540")] +pub struct CursorMut<'a, K: 'a, #[unstable(feature = "allocator_api", issue = "32838")] A = Global> +{ + inner: super::map::CursorMutKey<'a, K, SetValZST, A>, +} + +#[unstable(feature = "btree_cursors", issue = "107540")] +impl Debug for CursorMut<'_, K, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("CursorMut") + } +} + +impl<'a, K> Cursor<'a, K> { + /// Advances the cursor to the next gap, returning the element that it + /// moved over. + /// + /// If the cursor is already at the end of the set then `None` is returned + /// and the cursor is not moved. + #[unstable(feature = "btree_cursors", issue = "107540")] + pub fn next(&mut self) -> Option<&'a K> { + self.inner.next().map(|(k, _)| k) + } + + /// Advances the cursor to the previous gap, returning the element that it + /// moved over. + /// + /// If the cursor is already at the start of the set then `None` is returned + /// and the cursor is not moved. + #[unstable(feature = "btree_cursors", issue = "107540")] + pub fn prev(&mut self) -> Option<&'a K> { + self.inner.prev().map(|(k, _)| k) + } + + /// Returns a reference to next element without moving the cursor. + /// + /// If the cursor is at the end of the set then `None` is returned + #[unstable(feature = "btree_cursors", issue = "107540")] + pub fn peek_next(&self) -> Option<&'a K> { + self.inner.peek_next().map(|(k, _)| k) + } + + /// Returns a reference to the previous element without moving the cursor. + /// + /// If the cursor is at the start of the set then `None` is returned. + #[unstable(feature = "btree_cursors", issue = "107540")] + pub fn peek_prev(&self) -> Option<&'a K> { + self.inner.peek_prev().map(|(k, _)| k) + } +} + +impl<'a, T, A> CursorMut<'a, T, A> { + /// Advances the cursor to the next gap, returning the element that it + /// moved over. + /// + /// If the cursor is already at the end of the set then `None` is returned + /// and the cursor is not moved. + #[unstable(feature = "btree_cursors", issue = "107540")] + pub fn next(&mut self) -> Option<&mut T> { + self.inner.next().map(|(k, _)| k) + } + + /// Advances the cursor to the previous gap, returning the element that it + /// moved over. + /// + /// If the cursor is already at the start of the set then `None` is returned + /// and the cursor is not moved. + #[unstable(feature = "btree_cursors", issue = "107540")] + pub fn prev(&mut self) -> Option<&mut T> { + self.inner.prev().map(|(k, _)| k) + } + + /// Returns a reference to the next element without moving the cursor. + /// + /// If the cursor is at the end of the set then `None` is returned. + #[unstable(feature = "btree_cursors", issue = "107540")] + pub fn peek_next(&mut self) -> Option<&mut T> { + self.inner.peek_next().map(|(k, _)| k) + } + + /// Returns a reference to the previous element without moving the cursor. + /// + /// If the cursor is at the start of the set then `None` is returned. + #[unstable(feature = "btree_cursors", issue = "107540")] + pub fn peek_prev(&mut self) -> Option<&mut T> { + self.inner.peek_prev().map(|(k, _)| k) + } + + /// Returns a read-only cursor pointing to the same location as the + /// `CursorMut`. + /// + /// The lifetime of the returned `Cursor` is bound to that of the + /// `CursorMut`, which means it cannot outlive the `CursorMut` and that the + /// `CursorMut` is frozen for the lifetime of the `Cursor`. + #[unstable(feature = "btree_cursors", issue = "107540")] + pub fn as_cursor(&self) -> Cursor<'_, T> { + Cursor { inner: self.inner.as_cursor() } + } +} + +impl<'a, T: Ord, A: Allocator + Clone> CursorMut<'a, T, A> { + /// Inserts a new element into the set in the gap that the + /// cursor is currently pointing to. + /// + /// After the insertion the cursor will be pointing at the gap before the + /// newly inserted element. + /// + /// # Safety + /// + /// You must ensure that the `BTreeSet` invariants are maintained. + /// Specifically: + /// + /// * The newly inserted element must be unique in the tree. + /// * All elements in the tree must remain in sorted order. + #[unstable(feature = "btree_cursors", issue = "107540")] + pub unsafe fn insert_after_unchecked(&mut self, value: T) { + unsafe { self.inner.insert_after_unchecked(value, SetValZST) } + } + + /// Inserts a new element into the set in the gap that the + /// cursor is currently pointing to. + /// + /// After the insertion the cursor will be pointing at the gap after the + /// newly inserted element. + /// + /// # Safety + /// + /// You must ensure that the `BTreeSet` invariants are maintained. + /// Specifically: + /// + /// * The newly inserted element must be unique in the tree. + /// * All elements in the tree must remain in sorted order. + #[unstable(feature = "btree_cursors", issue = "107540")] + pub unsafe fn insert_before_unchecked(&mut self, value: T) { + unsafe { self.inner.insert_before_unchecked(value, SetValZST) } + } + + /// Inserts a new element into the set in the gap that the + /// cursor is currently pointing to. + /// + /// After the insertion the cursor will be pointing at the gap before the + /// newly inserted element. + /// + /// If the inserted element is not greater than the element before the + /// cursor (if any), or if it not less than the element after the cursor (if + /// any), then an [`UnorderedError`] is returned since this would + /// invalidate the [`Ord`] invariant between the elements of the set. + #[unstable(feature = "btree_cursors", issue = "107540")] + pub fn insert_after(&mut self, value: T) -> Result<(), UnorderedError> { + self.inner.insert_after(value, SetValZST).map_err(UnorderedError::from_map_error) + } + + /// Inserts a new element into the set in the gap that the + /// cursor is currently pointing to. + /// + /// After the insertion the cursor will be pointing at the gap after the + /// newly inserted element. + /// + /// If the inserted element is not greater than the element before the + /// cursor (if any), or if it not less than the element after the cursor (if + /// any), then an [`UnorderedError`] is returned since this would + /// invalidate the [`Ord`] invariant between the elements of the set. + #[unstable(feature = "btree_cursors", issue = "107540")] + pub fn insert_before(&mut self, value: T) -> Result<(), UnorderedError> { + self.inner.insert_before(value, SetValZST).map_err(UnorderedError::from_map_error) + } + + /// Removes the next element from the `BTreeSet`. + /// + /// The element that was removed is returned. The cursor position is + /// unchanged (before the removed element). + #[unstable(feature = "btree_cursors", issue = "107540")] + pub fn remove_next(&mut self) -> Option { + self.inner.remove_next().map(|(k, _)| k) + } + + /// Removes the precending element from the `BTreeSet`. + /// + /// The element that was removed is returned. The cursor position is + /// unchanged (after the removed element). + #[unstable(feature = "btree_cursors", issue = "107540")] + pub fn remove_prev(&mut self) -> Option { + self.inner.remove_prev().map(|(k, _)| k) + } +} + +/// Error type returned by [`CursorMut::insert_before`] and +/// [`CursorMut::insert_after`] if the element being inserted is not properly +/// ordered with regards to adjacent elements. +#[derive(Clone, PartialEq, Eq, Debug)] +#[unstable(feature = "btree_cursors", issue = "107540")] +pub struct UnorderedError {} + +impl UnorderedError { + fn from_map_error(error: super::map::UnorderedKeyError) -> Self { + let super::map::UnorderedKeyError {} = error; + Self {} + } +} + +#[unstable(feature = "btree_cursors", issue = "107540")] +impl fmt::Display for UnorderedError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "value is not properly ordered relative to neighbors") + } +} + +#[unstable(feature = "btree_cursors", issue = "107540")] +impl Error for UnorderedError {} + #[cfg(test)] mod tests; From bbeff8c7862ad70fada412502324ecd41d1dea14 Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Tue, 30 Jul 2024 16:55:45 +0300 Subject: [PATCH 04/12] set `force_recompile: true` if library is modified This allows the standard library to be compiled even with `download-rustc` enabled. Which means it's no longer a requirement to compile `rustc` in order to compile `std`. Signed-off-by: onur-ozkan --- src/bootstrap/src/core/build_steps/compile.rs | 39 +++++++++++++++---- 1 file changed, 31 insertions(+), 8 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index 268e89c7f6011..c09180e542ff6 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -26,7 +26,8 @@ use crate::core::builder::{ use crate::core::config::{DebuginfoLevel, LlvmLibunwind, RustcLto, TargetSelection}; use crate::utils::exec::command; use crate::utils::helpers::{ - exe, get_clang_cl_resource_dir, is_debug_info, is_dylib, symlink_dir, t, up_to_date, + self, exe, get_clang_cl_resource_dir, get_closest_merge_base_commit, is_debug_info, is_dylib, + symlink_dir, t, up_to_date, }; use crate::{CLang, Compiler, DependencyType, GitRepo, Mode, LLVM_TOOLS}; @@ -114,21 +115,43 @@ impl Step for Std { const DEFAULT: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { - // When downloading stage1, the standard library has already been copied to the sysroot, so - // there's no need to rebuild it. - let builder = run.builder; - run.crate_or_deps("sysroot") - .path("library") - .lazy_default_condition(Box::new(|| !builder.download_rustc())) + run.crate_or_deps("sysroot").path("library") } fn make_run(run: RunConfig<'_>) { let crates = std_crates_for_run_make(&run); + let builder = run.builder; + + // Force compilation of the standard library from source if the `library` is modified. This allows + // library team to compile the standard library without needing to compile the compiler with + // the `rust.download-rustc=true` option. + let force_recompile = + if builder.rust_info().is_managed_git_subrepository() && builder.download_rustc() { + let closest_merge_commit = get_closest_merge_base_commit( + Some(&builder.src), + &builder.config.git_config(), + &builder.config.stage0_metadata.config.git_merge_commit_email, + &[], + ) + .unwrap(); + + // Check if `library` has changes (returns false otherwise) + !t!(helpers::git(Some(&builder.src)) + .args(["diff-index", "--quiet", &closest_merge_commit]) + .arg("--") + .arg(builder.src.join("library")) + .as_command_mut() + .status()) + .success() + } else { + false + }; + run.builder.ensure(Std { compiler: run.builder.compiler(run.builder.top_stage, run.build_triple()), target: run.target, crates, - force_recompile: false, + force_recompile, extra_rust_args: &[], is_for_mir_opt_tests: false, }); From 6fcc630e56263d7d17a37a77202717f1c83c5b2a Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Tue, 30 Jul 2024 16:56:47 +0300 Subject: [PATCH 05/12] update download-rustc documentation Signed-off-by: onur-ozkan --- config.example.toml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/config.example.toml b/config.example.toml index 45faa66ec114f..1a7bdc4737fbf 100644 --- a/config.example.toml +++ b/config.example.toml @@ -472,7 +472,8 @@ # This is mostly useful for tools; if you have changes to `compiler/` or `library/` they will be ignored. # # Set this to "if-unchanged" to only download if the compiler and standard library have not been modified. -# Set this to `true` to download unconditionally (useful if e.g. you are only changing doc-comments). +# Set this to `true` to download unconditionally. This is useful if you are working on tools, doc-comments, +# or library (you will be able to build the standard library without needing to build the compiler). #download-rustc = false # Number of codegen units to use for each compiler invocation. A value of 0 From 020476296b1aa60f79c2f671c48542afe99cc428 Mon Sep 17 00:00:00 2001 From: Ken Micklas Date: Thu, 1 Aug 2024 19:23:18 +0100 Subject: [PATCH 06/12] Share `UnorderedKeyError` with `BTReeMap` for set API --- library/alloc/src/collections/btree/set.rs | 36 +++++----------------- 1 file changed, 7 insertions(+), 29 deletions(-) diff --git a/library/alloc/src/collections/btree/set.rs b/library/alloc/src/collections/btree/set.rs index 6f23d686bcf8e..0fc892eec6504 100644 --- a/library/alloc/src/collections/btree/set.rs +++ b/library/alloc/src/collections/btree/set.rs @@ -2,7 +2,6 @@ use crate::vec::Vec; use core::borrow::Borrow; use core::cmp::Ordering::{self, Equal, Greater, Less}; use core::cmp::{max, min}; -use core::error::Error; use core::fmt::{self, Debug}; use core::hash::{Hash, Hasher}; use core::iter::{FusedIterator, Peekable}; @@ -2177,11 +2176,11 @@ impl<'a, T: Ord, A: Allocator + Clone> CursorMut<'a, T, A> { /// /// If the inserted element is not greater than the element before the /// cursor (if any), or if it not less than the element after the cursor (if - /// any), then an [`UnorderedError`] is returned since this would + /// any), then an [`UnorderedKeyError`] is returned since this would /// invalidate the [`Ord`] invariant between the elements of the set. #[unstable(feature = "btree_cursors", issue = "107540")] - pub fn insert_after(&mut self, value: T) -> Result<(), UnorderedError> { - self.inner.insert_after(value, SetValZST).map_err(UnorderedError::from_map_error) + pub fn insert_after(&mut self, value: T) -> Result<(), UnorderedKeyError> { + self.inner.insert_after(value, SetValZST) } /// Inserts a new element into the set in the gap that the @@ -2192,11 +2191,11 @@ impl<'a, T: Ord, A: Allocator + Clone> CursorMut<'a, T, A> { /// /// If the inserted element is not greater than the element before the /// cursor (if any), or if it not less than the element after the cursor (if - /// any), then an [`UnorderedError`] is returned since this would + /// any), then an [`UnorderedKeyError`] is returned since this would /// invalidate the [`Ord`] invariant between the elements of the set. #[unstable(feature = "btree_cursors", issue = "107540")] - pub fn insert_before(&mut self, value: T) -> Result<(), UnorderedError> { - self.inner.insert_before(value, SetValZST).map_err(UnorderedError::from_map_error) + pub fn insert_before(&mut self, value: T) -> Result<(), UnorderedKeyError> { + self.inner.insert_before(value, SetValZST) } /// Removes the next element from the `BTreeSet`. @@ -2218,29 +2217,8 @@ impl<'a, T: Ord, A: Allocator + Clone> CursorMut<'a, T, A> { } } -/// Error type returned by [`CursorMut::insert_before`] and -/// [`CursorMut::insert_after`] if the element being inserted is not properly -/// ordered with regards to adjacent elements. -#[derive(Clone, PartialEq, Eq, Debug)] #[unstable(feature = "btree_cursors", issue = "107540")] -pub struct UnorderedError {} - -impl UnorderedError { - fn from_map_error(error: super::map::UnorderedKeyError) -> Self { - let super::map::UnorderedKeyError {} = error; - Self {} - } -} - -#[unstable(feature = "btree_cursors", issue = "107540")] -impl fmt::Display for UnorderedError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "value is not properly ordered relative to neighbors") - } -} - -#[unstable(feature = "btree_cursors", issue = "107540")] -impl Error for UnorderedError {} +pub use super::map::UnorderedKeyError; #[cfg(test)] mod tests; From 4560770451a21c3beca5808e362b6fe34c7371ae Mon Sep 17 00:00:00 2001 From: Ken Micklas Date: Thu, 1 Aug 2024 19:47:06 +0100 Subject: [PATCH 07/12] Fix some uses of "map" instead of "set" in `BTreeSet` cursor API docs --- library/alloc/src/collections/btree/set.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/library/alloc/src/collections/btree/set.rs b/library/alloc/src/collections/btree/set.rs index 0fc892eec6504..47b7e56ddf050 100644 --- a/library/alloc/src/collections/btree/set.rs +++ b/library/alloc/src/collections/btree/set.rs @@ -1194,7 +1194,7 @@ impl BTreeSet { /// gap before the smallest element greater than `x`. /// /// Passing `Bound::Unbounded` will return a cursor pointing to the - /// gap before the smallest element in the map. + /// gap before the smallest element in the set. /// /// # Examples /// @@ -1237,7 +1237,7 @@ impl BTreeSet { /// gap before the smallest element greater than `x`. /// /// Passing `Bound::Unbounded` will return a cursor pointing to the - /// gap before the smallest element in the map. + /// gap before the smallest element in the set. /// /// # Examples /// @@ -1280,7 +1280,7 @@ impl BTreeSet { /// gap after the greatest element smaller than `x`. /// /// Passing `Bound::Unbounded` will return a cursor pointing to the - /// gap after the greatest element in the map. + /// gap after the greatest element in the set. /// /// # Examples /// @@ -1323,7 +1323,7 @@ impl BTreeSet { /// gap after the greatest element smaller than `x`. /// /// Passing `Bound::Unbounded` will return a cursor pointing to the - /// gap after the greatest element in the map. + /// gap after the greatest element in the set. /// /// # Examples /// From cbdc3778667c5bad3f9eee4124000a0ca96e4590 Mon Sep 17 00:00:00 2001 From: Ken Micklas Date: Thu, 1 Aug 2024 19:47:28 +0100 Subject: [PATCH 08/12] Introduce `Cursor`/`CursorMut`/`CursorMutKey` thrichotomy for `BTreeSet` like map API --- library/alloc/src/collections/btree/set.rs | 210 +++++++++++++++++++-- 1 file changed, 194 insertions(+), 16 deletions(-) diff --git a/library/alloc/src/collections/btree/set.rs b/library/alloc/src/collections/btree/set.rs index 47b7e56ddf050..86401714639c0 100644 --- a/library/alloc/src/collections/btree/set.rs +++ b/library/alloc/src/collections/btree/set.rs @@ -1249,25 +1249,25 @@ impl BTreeSet { /// /// let mut set = BTreeSet::from([1, 2, 3, 4]); /// - /// let mut cursor = unsafe { set.lower_bound_mut(Bound::Included(&2)) }; + /// let mut cursor = set.lower_bound_mut(Bound::Included(&2)); /// assert_eq!(cursor.peek_prev(), Some(&mut 1)); /// assert_eq!(cursor.peek_next(), Some(&mut 2)); /// - /// let mut cursor = unsafe { set.lower_bound_mut(Bound::Excluded(&2)) }; + /// let mut cursor = set.lower_bound_mut(Bound::Excluded(&2)); /// assert_eq!(cursor.peek_prev(), Some(&mut 2)); /// assert_eq!(cursor.peek_next(), Some(&mut 3)); /// - /// let mut cursor = unsafe { set.lower_bound_mut(Bound::Unbounded) }; + /// let mut cursor = set.lower_bound_mut(Bound::Unbounded); /// assert_eq!(cursor.peek_prev(), None); /// assert_eq!(cursor.peek_next(), Some(&mut 1)); /// ``` #[unstable(feature = "btree_cursors", issue = "107540")] - pub unsafe fn lower_bound_mut(&mut self, bound: Bound<&Q>) -> CursorMut<'_, T, A> + pub fn lower_bound_mut(&mut self, bound: Bound<&Q>) -> CursorMut<'_, T, A> where T: Borrow + Ord, Q: Ord, { - CursorMut { inner: unsafe { self.map.lower_bound_mut(bound).with_mutable_key() } } + CursorMut { inner: self.map.lower_bound_mut(bound) } } /// Returns a [`Cursor`] pointing at the gap after the greatest element @@ -1353,7 +1353,7 @@ impl BTreeSet { T: Borrow + Ord, Q: Ord, { - CursorMut { inner: unsafe { self.map.upper_bound_mut(bound).with_mutable_key() } } + CursorMut { inner: self.map.upper_bound_mut(bound) } } } @@ -2010,6 +2010,31 @@ impl Debug for Cursor<'_, K> { } } +/// A cursor over a `BTreeSet` with editing operations. +/// +/// A `Cursor` is like an iterator, except that it can freely seek back-and-forth, and can +/// safely mutate the set during iteration. This is because the lifetime of its yielded +/// references is tied to its own lifetime, instead of just the underlying map. This means +/// cursors cannot yield multiple elements at once. +/// +/// Cursors always point to a gap between two elements in the set, and can +/// operate on the two immediately adjacent elements. +/// +/// A `CursorMut` is created with the [`BTreeSet::lower_bound_mut`] and [`BTreeSet::upper_bound_mut`] +/// methods. +#[unstable(feature = "btree_cursors", issue = "107540")] +pub struct CursorMut<'a, K: 'a, #[unstable(feature = "allocator_api", issue = "32838")] A = Global> +{ + inner: super::map::CursorMut<'a, K, SetValZST, A>, +} + +#[unstable(feature = "btree_cursors", issue = "107540")] +impl Debug for CursorMut<'_, K, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("CursorMut") + } +} + /// A cursor over a `BTreeSet` with editing operations, and which allows /// mutating elements. /// @@ -2021,8 +2046,8 @@ impl Debug for Cursor<'_, K> { /// Cursors always point to a gap between two elements in the set, and can /// operate on the two immediately adjacent elements. /// -/// A `CursorMut` is created with the [`BTreeSet::lower_bound_mut`] and -/// [`BTreeSet::upper_bound_mut`] methods. +/// A `CursorMutKey` is created from a [`CursorMut`] with the +/// [`CursorMut::with_mutable_key`] method. /// /// # Safety /// @@ -2032,15 +2057,18 @@ impl Debug for Cursor<'_, K> { /// * The newly inserted element must be unique in the tree. /// * All elements in the tree must remain in sorted order. #[unstable(feature = "btree_cursors", issue = "107540")] -pub struct CursorMut<'a, K: 'a, #[unstable(feature = "allocator_api", issue = "32838")] A = Global> -{ +pub struct CursorMutKey< + 'a, + K: 'a, + #[unstable(feature = "allocator_api", issue = "32838")] A = Global, +> { inner: super::map::CursorMutKey<'a, K, SetValZST, A>, } #[unstable(feature = "btree_cursors", issue = "107540")] -impl Debug for CursorMut<'_, K, A> { +impl Debug for CursorMutKey<'_, K, A> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str("CursorMut") + f.write_str("CursorMutKey") } } @@ -2089,7 +2117,7 @@ impl<'a, T, A> CursorMut<'a, T, A> { /// If the cursor is already at the end of the set then `None` is returned /// and the cursor is not moved. #[unstable(feature = "btree_cursors", issue = "107540")] - pub fn next(&mut self) -> Option<&mut T> { + pub fn next(&mut self) -> Option<&T> { self.inner.next().map(|(k, _)| k) } @@ -2099,7 +2127,7 @@ impl<'a, T, A> CursorMut<'a, T, A> { /// If the cursor is already at the start of the set then `None` is returned /// and the cursor is not moved. #[unstable(feature = "btree_cursors", issue = "107540")] - pub fn prev(&mut self) -> Option<&mut T> { + pub fn prev(&mut self) -> Option<&T> { self.inner.prev().map(|(k, _)| k) } @@ -2107,7 +2135,7 @@ impl<'a, T, A> CursorMut<'a, T, A> { /// /// If the cursor is at the end of the set then `None` is returned. #[unstable(feature = "btree_cursors", issue = "107540")] - pub fn peek_next(&mut self) -> Option<&mut T> { + pub fn peek_next(&mut self) -> Option<&T> { self.inner.peek_next().map(|(k, _)| k) } @@ -2115,7 +2143,7 @@ impl<'a, T, A> CursorMut<'a, T, A> { /// /// If the cursor is at the start of the set then `None` is returned. #[unstable(feature = "btree_cursors", issue = "107540")] - pub fn peek_prev(&mut self) -> Option<&mut T> { + pub fn peek_prev(&mut self) -> Option<&T> { self.inner.peek_prev().map(|(k, _)| k) } @@ -2129,6 +2157,70 @@ impl<'a, T, A> CursorMut<'a, T, A> { pub fn as_cursor(&self) -> Cursor<'_, T> { Cursor { inner: self.inner.as_cursor() } } + + /// Converts the cursor into a [`CursorMutKey`], which allows mutating + /// elements in the tree. + /// + /// # Safety + /// + /// Since this cursor allows mutating elements, you must ensure that the + /// `BTreeSet` invariants are maintained. Specifically: + /// + /// * The newly inserted element must be unique in the tree. + /// * All elements in the tree must remain in sorted order. + #[unstable(feature = "btree_cursors", issue = "107540")] + pub unsafe fn with_mutable_key(self) -> CursorMutKey<'a, T, A> { + CursorMutKey { inner: unsafe { self.inner.with_mutable_key() } } + } +} + +impl<'a, T, A> CursorMutKey<'a, T, A> { + /// Advances the cursor to the next gap, returning the element that it + /// moved over. + /// + /// If the cursor is already at the end of the set then `None` is returned + /// and the cursor is not moved. + #[unstable(feature = "btree_cursors", issue = "107540")] + pub fn next(&mut self) -> Option<&mut T> { + self.inner.next().map(|(k, _)| k) + } + + /// Advances the cursor to the previous gap, returning the element that it + /// moved over. + /// + /// If the cursor is already at the start of the set then `None` is returned + /// and the cursor is not moved. + #[unstable(feature = "btree_cursors", issue = "107540")] + pub fn prev(&mut self) -> Option<&mut T> { + self.inner.prev().map(|(k, _)| k) + } + + /// Returns a reference to the next element without moving the cursor. + /// + /// If the cursor is at the end of the set then `None` is returned + #[unstable(feature = "btree_cursors", issue = "107540")] + pub fn peek_next(&mut self) -> Option<&mut T> { + self.inner.peek_next().map(|(k, _)| k) + } + + /// Returns a reference to the previous element without moving the cursor. + /// + /// If the cursor is at the start of the set then `None` is returned. + #[unstable(feature = "btree_cursors", issue = "107540")] + pub fn peek_prev(&mut self) -> Option<&mut T> { + self.inner.peek_prev().map(|(k, _)| k) + } + + /// Returns a read-only cursor pointing to the same location as the + /// `CursorMutKey`. + /// + /// The lifetime of the returned `Cursor` is bound to that of the + /// `CursorMutKey`, which means it cannot outlive the `CursorMutKey` and that the + /// `CursorMutKey` is frozen for the lifetime of the `Cursor`. + #[unstable(feature = "btree_cursors", issue = "107540")] + pub fn as_cursor(&self) -> Cursor<'_, T> { + Cursor { inner: self.inner.as_cursor() } + } } impl<'a, T: Ord, A: Allocator + Clone> CursorMut<'a, T, A> { @@ -2217,6 +2309,92 @@ impl<'a, T: Ord, A: Allocator + Clone> CursorMut<'a, T, A> { } } +impl<'a, T: Ord, A: Allocator + Clone> CursorMutKey<'a, T, A> { + /// Inserts a new element into the set in the gap that the + /// cursor is currently pointing to. + /// + /// After the insertion the cursor will be pointing at the gap before the + /// newly inserted element. + /// + /// # Safety + /// + /// You must ensure that the `BTreeSet` invariants are maintained. + /// Specifically: + /// + /// * The key of the newly inserted element must be unique in the tree. + /// * All elements in the tree must remain in sorted order. + #[unstable(feature = "btree_cursors", issue = "107540")] + pub unsafe fn insert_after_unchecked(&mut self, value: T) { + unsafe { self.inner.insert_after_unchecked(value, SetValZST) } + } + + /// Inserts a new element into the set in the gap that the + /// cursor is currently pointing to. + /// + /// After the insertion the cursor will be pointing at the gap after the + /// newly inserted element. + /// + /// # Safety + /// + /// You must ensure that the `BTreeSet` invariants are maintained. + /// Specifically: + /// + /// * The newly inserted element must be unique in the tree. + /// * All elements in the tree must remain in sorted order. + #[unstable(feature = "btree_cursors", issue = "107540")] + pub unsafe fn insert_before_unchecked(&mut self, value: T) { + unsafe { self.inner.insert_before_unchecked(value, SetValZST) } + } + + /// Inserts a new element into the set in the gap that the + /// cursor is currently pointing to. + /// + /// After the insertion the cursor will be pointing at the gap before the + /// newly inserted element. + /// + /// If the inserted element is not greater than the element before the + /// cursor (if any), or if it not less than the element after the cursor (if + /// any), then an [`UnorderedKeyError`] is returned since this would + /// invalidate the [`Ord`] invariant between the elements of the set. + #[unstable(feature = "btree_cursors", issue = "107540")] + pub fn insert_after(&mut self, value: T) -> Result<(), UnorderedKeyError> { + self.inner.insert_after(value, SetValZST) + } + + /// Inserts a new element into the set in the gap that the + /// cursor is currently pointing to. + /// + /// After the insertion the cursor will be pointing at the gap after the + /// newly inserted element. + /// + /// If the inserted element is not greater than the element before the + /// cursor (if any), or if it not less than the element after the cursor (if + /// any), then an [`UnorderedKeyError`] is returned since this would + /// invalidate the [`Ord`] invariant between the elements of the set. + #[unstable(feature = "btree_cursors", issue = "107540")] + pub fn insert_before(&mut self, value: T) -> Result<(), UnorderedKeyError> { + self.inner.insert_before(value, SetValZST) + } + + /// Removes the next element from the `BTreeSet`. + /// + /// The element that was removed is returned. The cursor position is + /// unchanged (before the removed element). + #[unstable(feature = "btree_cursors", issue = "107540")] + pub fn remove_next(&mut self) -> Option { + self.inner.remove_next().map(|(k, _)| k) + } + + /// Removes the precending element from the `BTreeSet`. + /// + /// The element that was removed is returned. The cursor position is + /// unchanged (after the removed element). + #[unstable(feature = "btree_cursors", issue = "107540")] + pub fn remove_prev(&mut self) -> Option { + self.inner.remove_prev().map(|(k, _)| k) + } +} + #[unstable(feature = "btree_cursors", issue = "107540")] pub use super::map::UnorderedKeyError; From 0bc501e0addf9dec2fe87613c5fdc6180364aceb Mon Sep 17 00:00:00 2001 From: Ken Micklas Date: Thu, 1 Aug 2024 21:02:51 +0100 Subject: [PATCH 09/12] Fix mutability in doc tests for `BTreeSet` cursors --- library/alloc/src/collections/btree/set.rs | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/library/alloc/src/collections/btree/set.rs b/library/alloc/src/collections/btree/set.rs index 86401714639c0..362e32cc8f46a 100644 --- a/library/alloc/src/collections/btree/set.rs +++ b/library/alloc/src/collections/btree/set.rs @@ -1250,16 +1250,16 @@ impl BTreeSet { /// let mut set = BTreeSet::from([1, 2, 3, 4]); /// /// let mut cursor = set.lower_bound_mut(Bound::Included(&2)); - /// assert_eq!(cursor.peek_prev(), Some(&mut 1)); - /// assert_eq!(cursor.peek_next(), Some(&mut 2)); + /// assert_eq!(cursor.peek_prev(), Some(&1)); + /// assert_eq!(cursor.peek_next(), Some(&2)); /// /// let mut cursor = set.lower_bound_mut(Bound::Excluded(&2)); - /// assert_eq!(cursor.peek_prev(), Some(&mut 2)); - /// assert_eq!(cursor.peek_next(), Some(&mut 3)); + /// assert_eq!(cursor.peek_prev(), Some(&2)); + /// assert_eq!(cursor.peek_next(), Some(&3)); /// /// let mut cursor = set.lower_bound_mut(Bound::Unbounded); /// assert_eq!(cursor.peek_prev(), None); - /// assert_eq!(cursor.peek_next(), Some(&mut 1)); + /// assert_eq!(cursor.peek_next(), Some(&1)); /// ``` #[unstable(feature = "btree_cursors", issue = "107540")] pub fn lower_bound_mut(&mut self, bound: Bound<&Q>) -> CursorMut<'_, T, A> @@ -1336,15 +1336,15 @@ impl BTreeSet { /// let mut set = BTreeSet::from([1, 2, 3, 4]); /// /// let mut cursor = unsafe { set.upper_bound_mut(Bound::Included(&3)) }; - /// assert_eq!(cursor.peek_prev(), Some(&mut 3)); - /// assert_eq!(cursor.peek_next(), Some(&mut 4)); + /// assert_eq!(cursor.peek_prev(), Some(&3)); + /// assert_eq!(cursor.peek_next(), Some(&4)); /// /// let mut cursor = unsafe { set.upper_bound_mut(Bound::Excluded(&3)) }; - /// assert_eq!(cursor.peek_prev(), Some(&mut 2)); - /// assert_eq!(cursor.peek_next(), Some(&mut 3)); + /// assert_eq!(cursor.peek_prev(), Some(&2)); + /// assert_eq!(cursor.peek_next(), Some(&3)); /// /// let mut cursor = unsafe { set.upper_bound_mut(Bound::Unbounded) }; - /// assert_eq!(cursor.peek_prev(), Some(&mut 4)); + /// assert_eq!(cursor.peek_prev(), Some(&4)); /// assert_eq!(cursor.peek_next(), None); /// ``` #[unstable(feature = "btree_cursors", issue = "107540")] From 8497800abde9214041e11f35efdbfa437f761001 Mon Sep 17 00:00:00 2001 From: clubby789 Date: Thu, 1 Aug 2024 15:41:17 +0000 Subject: [PATCH 10/12] Add test for updating enum discriminant through pointer --- .../issue-122600-ptr-discriminant-update.rs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 tests/codegen/issues/issue-122600-ptr-discriminant-update.rs diff --git a/tests/codegen/issues/issue-122600-ptr-discriminant-update.rs b/tests/codegen/issues/issue-122600-ptr-discriminant-update.rs new file mode 100644 index 0000000000000..4b520a6206951 --- /dev/null +++ b/tests/codegen/issues/issue-122600-ptr-discriminant-update.rs @@ -0,0 +1,19 @@ +//@ compile-flags: -O +//@ min-llvm-version: 19 + +#![crate_type = "lib"] + +pub enum State { + A([u8; 753]), + B([u8; 753]), +} + +// CHECK-LABEL: @update +#[no_mangle] +pub unsafe fn update(s: *mut State) { + // CHECK-NEXT: start: + // CHECK-NEXT: store i8 + // CHECK-NEXT: ret + let State::A(v) = s.read() else { std::hint::unreachable_unchecked() }; + s.write(State::B(v)); +} From 9e5c9c14c7fb3bc6032fff6e9031e641ed2a104a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=AE=B8=E6=9D=B0=E5=8F=8B=20Jieyou=20Xu=20=28Joe=29?= Date: Sun, 4 Aug 2024 01:42:14 +0000 Subject: [PATCH 11/12] tests: add regression test for incorrect "builtin attribute is checked" assertion ICE See . --- tests/ui/attributes/check-builtin-attr-ice.rs | 58 +++++++++++++++++++ .../attributes/check-builtin-attr-ice.stderr | 21 +++++++ 2 files changed, 79 insertions(+) create mode 100644 tests/ui/attributes/check-builtin-attr-ice.rs create mode 100644 tests/ui/attributes/check-builtin-attr-ice.stderr diff --git a/tests/ui/attributes/check-builtin-attr-ice.rs b/tests/ui/attributes/check-builtin-attr-ice.rs new file mode 100644 index 0000000000000..9ef5890601f6b --- /dev/null +++ b/tests/ui/attributes/check-builtin-attr-ice.rs @@ -0,0 +1,58 @@ +//! Regression test for #128622. +//! +//! PR #128581 introduced an assertion that all builtin attributes are actually checked via +//! `CheckAttrVisitor` and aren't accidentally usable on completely unrelated HIR nodes. +//! Unfortunately, the check had correctness problems. +//! +//! The match on attribute path segments looked like +//! +//! ```rs,ignore +//! [sym::should_panic] => /* check is implemented */ +//! match BUILTIN_ATTRIBUTE_MAP.get(name) { +//! // checked below +//! Some(BuiltinAttribute { type_: AttributeType::CrateLevel, .. }) => {} +//! Some(_) => { +//! if !name.as_str().starts_with("rustc_") { +//! span_bug!( +//! attr.span, +//! "builtin attribute {name:?} not handled by `CheckAttrVisitor`" +//! ) +//! } +//! } +//! None => (), +//! } +//! ``` +//! +//! However, it failed to account for edge cases such as an attribute whose: +//! +//! 1. path segments *starts* with a builtin attribute such as `should_panic` +//! 2. which does not start with `rustc_`, and +//! 3. is also an `AttributeType::Normal` attribute upon registration with the builtin attribute map +//! +//! These conditions when all satisfied cause the span bug to be issued for e.g. +//! `#[should_panic::skip]` because the `[sym::should_panic]` arm is not matched (since it's +//! `[sym::should_panic, sym::skip]`). +//! +//! This test checks that the span bug is not fired for such cases. +//! +//! issue: rust-lang/rust#128622 + +// Notably, `should_panic` is a `AttributeType::Normal` attribute that is checked separately. + +struct Foo { + #[should_panic::skip] + //~^ ERROR failed to resolve + pub field: u8, + + #[should_panic::a::b::c] + //~^ ERROR failed to resolve + pub field2: u8, +} + +fn foo() {} + +fn main() { + #[deny::skip] + //~^ ERROR failed to resolve + foo(); +} diff --git a/tests/ui/attributes/check-builtin-attr-ice.stderr b/tests/ui/attributes/check-builtin-attr-ice.stderr new file mode 100644 index 0000000000000..5a27da565a857 --- /dev/null +++ b/tests/ui/attributes/check-builtin-attr-ice.stderr @@ -0,0 +1,21 @@ +error[E0433]: failed to resolve: use of undeclared crate or module `should_panic` + --> $DIR/check-builtin-attr-ice.rs:43:7 + | +LL | #[should_panic::skip] + | ^^^^^^^^^^^^ use of undeclared crate or module `should_panic` + +error[E0433]: failed to resolve: use of undeclared crate or module `should_panic` + --> $DIR/check-builtin-attr-ice.rs:47:7 + | +LL | #[should_panic::a::b::c] + | ^^^^^^^^^^^^ use of undeclared crate or module `should_panic` + +error[E0433]: failed to resolve: use of undeclared crate or module `deny` + --> $DIR/check-builtin-attr-ice.rs:55:7 + | +LL | #[deny::skip] + | ^^^^ use of undeclared crate or module `deny` + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0433`. From 9d0eaa2ad78ca2995d4f2c4edb61f762ba79846b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=AE=B8=E6=9D=B0=E5=8F=8B=20Jieyou=20Xu=20=28Joe=29?= Date: Sun, 4 Aug 2024 01:39:05 +0000 Subject: [PATCH 12/12] check_attr: cover multi-segment attributes on specific check arms PR #128581 introduced an assertion that all builtin attributes are actually checked via `CheckAttrVisitor` and aren't accidentally usable on completely unrelated HIR nodes. Unfortunately, the check had correctness problems. The match on attribute path segments looked like ```rust,ignore [sym::should_panic] => /* check is implemented */ match BUILTIN_ATTRIBUTE_MAP.get(name) { // checked below Some(BuiltinAttribute { type_: AttributeType::CrateLevel, .. }) => {} Some(_) => { if !name.as_str().starts_with("rustc_") { span_bug!( attr.span, "builtin attribute {name:?} not handled by `CheckAttrVisitor`" ) } } None => (), } ``` However, it failed to account for edge cases such as an attribute whose: 1. path segments *starts* with a builtin attribute such as `should_panic` 2. which does not start with `rustc_`, and 3. is also an `AttributeType::Normal` attribute upon registration with the builtin attribute map These conditions when all satisfied cause the span bug to be issued for e.g. `#[should_panic::skip]` because the `[sym::should_panic]` arm is not matched (since it's `[sym::should_panic, sym::skip]`). See . --- compiler/rustc_passes/src/check_attr.rs | 144 ++++++++++++------------ 1 file changed, 73 insertions(+), 71 deletions(-) diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 755f67b3f4fe0..a0d0d80b9572e 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -116,130 +116,130 @@ impl<'tcx> CheckAttrVisitor<'tcx> { let attrs = self.tcx.hir().attrs(hir_id); for attr in attrs { match attr.path().as_slice() { - [sym::diagnostic, sym::do_not_recommend] => { + [sym::diagnostic, sym::do_not_recommend, ..] => { self.check_do_not_recommend(attr.span, hir_id, target) } - [sym::diagnostic, sym::on_unimplemented] => { + [sym::diagnostic, sym::on_unimplemented, ..] => { self.check_diagnostic_on_unimplemented(attr.span, hir_id, target) } - [sym::inline] => self.check_inline(hir_id, attr, span, target), - [sym::coverage] => self.check_coverage(attr, span, target), - [sym::optimize] => self.check_optimize(hir_id, attr, target), - [sym::non_exhaustive] => self.check_non_exhaustive(hir_id, attr, span, target), - [sym::marker] => self.check_marker(hir_id, attr, span, target), - [sym::target_feature] => { + [sym::inline, ..] => self.check_inline(hir_id, attr, span, target), + [sym::coverage, ..] => self.check_coverage(attr, span, target), + [sym::optimize, ..] => self.check_optimize(hir_id, attr, target), + [sym::non_exhaustive, ..] => self.check_non_exhaustive(hir_id, attr, span, target), + [sym::marker, ..] => self.check_marker(hir_id, attr, span, target), + [sym::target_feature, ..] => { self.check_target_feature(hir_id, attr, span, target, attrs) } - [sym::thread_local] => self.check_thread_local(attr, span, target), - [sym::track_caller] => { + [sym::thread_local, ..] => self.check_thread_local(attr, span, target), + [sym::track_caller, ..] => { self.check_track_caller(hir_id, attr.span, attrs, span, target) } - [sym::doc] => self.check_doc_attrs( + [sym::doc, ..] => self.check_doc_attrs( attr, hir_id, target, &mut specified_inline, &mut doc_aliases, ), - [sym::no_link] => self.check_no_link(hir_id, attr, span, target), - [sym::export_name] => self.check_export_name(hir_id, attr, span, target), - [sym::rustc_layout_scalar_valid_range_start] - | [sym::rustc_layout_scalar_valid_range_end] => { + [sym::no_link, ..] => self.check_no_link(hir_id, attr, span, target), + [sym::export_name, ..] => self.check_export_name(hir_id, attr, span, target), + [sym::rustc_layout_scalar_valid_range_start, ..] + | [sym::rustc_layout_scalar_valid_range_end, ..] => { self.check_rustc_layout_scalar_valid_range(attr, span, target) } - [sym::allow_internal_unstable] => { + [sym::allow_internal_unstable, ..] => { self.check_allow_internal_unstable(hir_id, attr, span, target, attrs) } - [sym::debugger_visualizer] => self.check_debugger_visualizer(attr, target), - [sym::rustc_allow_const_fn_unstable] => { + [sym::debugger_visualizer, ..] => self.check_debugger_visualizer(attr, target), + [sym::rustc_allow_const_fn_unstable, ..] => { self.check_rustc_allow_const_fn_unstable(hir_id, attr, span, target) } - [sym::rustc_std_internal_symbol] => { + [sym::rustc_std_internal_symbol, ..] => { self.check_rustc_std_internal_symbol(attr, span, target) } - [sym::naked] => self.check_naked(hir_id, attr, span, target, attrs), - [sym::rustc_never_returns_null_ptr] => { + [sym::naked, ..] => self.check_naked(hir_id, attr, span, target, attrs), + [sym::rustc_never_returns_null_ptr, ..] => { self.check_applied_to_fn_or_method(hir_id, attr, span, target) } - [sym::rustc_legacy_const_generics] => { + [sym::rustc_legacy_const_generics, ..] => { self.check_rustc_legacy_const_generics(hir_id, attr, span, target, item) } - [sym::rustc_lint_query_instability] => { + [sym::rustc_lint_query_instability, ..] => { self.check_rustc_lint_query_instability(hir_id, attr, span, target) } - [sym::rustc_lint_diagnostics] => { + [sym::rustc_lint_diagnostics, ..] => { self.check_rustc_lint_diagnostics(hir_id, attr, span, target) } - [sym::rustc_lint_opt_ty] => self.check_rustc_lint_opt_ty(attr, span, target), - [sym::rustc_lint_opt_deny_field_access] => { + [sym::rustc_lint_opt_ty, ..] => self.check_rustc_lint_opt_ty(attr, span, target), + [sym::rustc_lint_opt_deny_field_access, ..] => { self.check_rustc_lint_opt_deny_field_access(attr, span, target) } - [sym::rustc_clean] - | [sym::rustc_dirty] - | [sym::rustc_if_this_changed] - | [sym::rustc_then_this_would_need] => self.check_rustc_dirty_clean(attr), - [sym::rustc_coinductive] - | [sym::rustc_must_implement_one_of] - | [sym::rustc_deny_explicit_impl] - | [sym::const_trait] => self.check_must_be_applied_to_trait(attr, span, target), - [sym::cmse_nonsecure_entry] => { + [sym::rustc_clean, ..] + | [sym::rustc_dirty, ..] + | [sym::rustc_if_this_changed, ..] + | [sym::rustc_then_this_would_need, ..] => self.check_rustc_dirty_clean(attr), + [sym::rustc_coinductive, ..] + | [sym::rustc_must_implement_one_of, ..] + | [sym::rustc_deny_explicit_impl, ..] + | [sym::const_trait, ..] => self.check_must_be_applied_to_trait(attr, span, target), + [sym::cmse_nonsecure_entry, ..] => { self.check_cmse_nonsecure_entry(hir_id, attr, span, target) } - [sym::collapse_debuginfo] => self.check_collapse_debuginfo(attr, span, target), - [sym::must_not_suspend] => self.check_must_not_suspend(attr, span, target), - [sym::must_use] => self.check_must_use(hir_id, attr, target), - [sym::rustc_pass_by_value] => self.check_pass_by_value(attr, span, target), - [sym::rustc_allow_incoherent_impl] => { + [sym::collapse_debuginfo, ..] => self.check_collapse_debuginfo(attr, span, target), + [sym::must_not_suspend, ..] => self.check_must_not_suspend(attr, span, target), + [sym::must_use, ..] => self.check_must_use(hir_id, attr, target), + [sym::rustc_pass_by_value, ..] => self.check_pass_by_value(attr, span, target), + [sym::rustc_allow_incoherent_impl, ..] => { self.check_allow_incoherent_impl(attr, span, target) } - [sym::rustc_has_incoherent_inherent_impls] => { + [sym::rustc_has_incoherent_inherent_impls, ..] => { self.check_has_incoherent_inherent_impls(attr, span, target) } - [sym::ffi_pure] => self.check_ffi_pure(attr.span, attrs, target), - [sym::ffi_const] => self.check_ffi_const(attr.span, target), - [sym::rustc_const_unstable] - | [sym::rustc_const_stable] - | [sym::unstable] - | [sym::stable] - | [sym::rustc_allowed_through_unstable_modules] - | [sym::rustc_promotable] => self.check_stability_promotable(attr, target), - [sym::link_ordinal] => self.check_link_ordinal(attr, span, target), - [sym::rustc_confusables] => self.check_confusables(attr, target), - [sym::rustc_safe_intrinsic] => { + [sym::ffi_pure, ..] => self.check_ffi_pure(attr.span, attrs, target), + [sym::ffi_const, ..] => self.check_ffi_const(attr.span, target), + [sym::rustc_const_unstable, ..] + | [sym::rustc_const_stable, ..] + | [sym::unstable, ..] + | [sym::stable, ..] + | [sym::rustc_allowed_through_unstable_modules, ..] + | [sym::rustc_promotable, ..] => self.check_stability_promotable(attr, target), + [sym::link_ordinal, ..] => self.check_link_ordinal(attr, span, target), + [sym::rustc_confusables, ..] => self.check_confusables(attr, target), + [sym::rustc_safe_intrinsic, ..] => { self.check_rustc_safe_intrinsic(hir_id, attr, span, target) } - [sym::cold] => self.check_cold(hir_id, attr, span, target), - [sym::link] => self.check_link(hir_id, attr, span, target), - [sym::link_name] => self.check_link_name(hir_id, attr, span, target), - [sym::link_section] => self.check_link_section(hir_id, attr, span, target), - [sym::no_mangle] => self.check_no_mangle(hir_id, attr, span, target), - [sym::deprecated] => self.check_deprecated(hir_id, attr, span, target), - [sym::macro_use] | [sym::macro_escape] => { + [sym::cold, ..] => self.check_cold(hir_id, attr, span, target), + [sym::link, ..] => self.check_link(hir_id, attr, span, target), + [sym::link_name, ..] => self.check_link_name(hir_id, attr, span, target), + [sym::link_section, ..] => self.check_link_section(hir_id, attr, span, target), + [sym::no_mangle, ..] => self.check_no_mangle(hir_id, attr, span, target), + [sym::deprecated, ..] => self.check_deprecated(hir_id, attr, span, target), + [sym::macro_use, ..] | [sym::macro_escape, ..] => { self.check_macro_use(hir_id, attr, target) } - [sym::path] => self.check_generic_attr(hir_id, attr, target, Target::Mod), - [sym::macro_export] => self.check_macro_export(hir_id, attr, target), - [sym::ignore] | [sym::should_panic] => { + [sym::path, ..] => self.check_generic_attr(hir_id, attr, target, Target::Mod), + [sym::macro_export, ..] => self.check_macro_export(hir_id, attr, target), + [sym::ignore, ..] | [sym::should_panic, ..] => { self.check_generic_attr(hir_id, attr, target, Target::Fn) } - [sym::automatically_derived] => { + [sym::automatically_derived, ..] => { self.check_generic_attr(hir_id, attr, target, Target::Impl) } - [sym::no_implicit_prelude] => { + [sym::no_implicit_prelude, ..] => { self.check_generic_attr(hir_id, attr, target, Target::Mod) } - [sym::rustc_object_lifetime_default] => self.check_object_lifetime_default(hir_id), - [sym::proc_macro] => { + [sym::rustc_object_lifetime_default, ..] => self.check_object_lifetime_default(hir_id), + [sym::proc_macro, ..] => { self.check_proc_macro(hir_id, target, ProcMacroKind::FunctionLike) } - [sym::proc_macro_attribute] => { + [sym::proc_macro_attribute, ..] => { self.check_proc_macro(hir_id, target, ProcMacroKind::Attribute); } - [sym::proc_macro_derive] => { + [sym::proc_macro_derive, ..] => { self.check_generic_attr(hir_id, attr, target, Target::Fn); self.check_proc_macro(hir_id, target, ProcMacroKind::Derive) } - [sym::coroutine] => { + [sym::coroutine, ..] => { self.check_coroutine(attr, target); } [ @@ -273,14 +273,16 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | sym::default_lib_allocator | sym::start | sym::custom_mir, + .. ] => {} [name, ..] => { match BUILTIN_ATTRIBUTE_MAP.get(name) { // checked below Some(BuiltinAttribute { type_: AttributeType::CrateLevel, .. }) => {} Some(_) => { - // FIXME: differentiate between unstable and internal attributes just like we do with features instead - // of just accepting `rustc_` attributes by name. That should allow trimming the above list, too. + // FIXME: differentiate between unstable and internal attributes just + // like we do with features instead of just accepting `rustc_` + // attributes by name. That should allow trimming the above list, too. if !name.as_str().starts_with("rustc_") { span_bug!( attr.span,