From 9d9b55cd2b14bce066cef83d9d85ba798a2ba95c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 15 Jul 2024 21:25:03 +0200 Subject: [PATCH 01/36] 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 f13aa506c1e..a78ae0d6993 100644 --- a/compiler/rustc_feature/src/removed.rs +++ b/compiler/rustc_feature/src/removed.rs @@ -75,6 +75,9 @@ macro_rules! 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 948499fb38f..407800ce60d 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -428,8 +428,6 @@ pub fn internal(&self, feature: Symbol) -> bool { (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 22d465c8e62..398a496a373 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 @@ enum Defaults { 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 aa7844f4012..276a507d3e8 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -1241,7 +1241,7 @@ 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 308de269293..00000000000 --- 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 f0d259d01de..1fb69db98c1 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 3391ea4b350..e0723e016b3 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 c2a3d4b83d5..4a18b23fd8b 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 70f06b4be60..3f97ae6c5bd 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 dc0bea58a70..bf8829c0925 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 00000000000..a3205cd3c29 --- /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/36] 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 ba289f9552e..fc1cf71a130 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 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 @@ fn create_struct_field_access_fields( ), ); 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 4e83ef0c629..7f4904bb48a 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -537,7 +537,7 @@ macro_rules! add_lint_group { ); 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 @@ macro_rules! add_lint_group { "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 aa7844f4012..f37d3d402df 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -25,7 +25,6 @@ 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 @@ 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 58be4519720..d17b52842ce 100644 --- a/tests/ui/derives/deriving-with-repr-packed.rs +++ b/tests/ui/derives/deriving-with-repr-packed.rs @@ -22,25 +22,22 @@ 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 a8523d25cab..321ffb27eeb 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 | - = 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) -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[E0161]: cannot move a value of type `str` + --> $DIR/deriving-with-repr-packed.rs:38:5 + | +LL | data: str, + | ^^^^^^^^^ the size of `str` cannot be statically determined + +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 6fa4f74f2a5..eab2b4f1f53 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 503f0cae73b..00000000000 --- 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 6b69b57c516..6503c870990 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 571f7b658964e5781546e8ea4a2d1466e8b0a611 Mon Sep 17 00:00:00 2001 From: Folkert Date: Sun, 28 Jul 2024 15:11:14 +0200 Subject: [PATCH 03/36] improve error message when global asm uses inline asm operands --- compiler/rustc_builtin_macros/messages.ftl | 3 ++ compiler/rustc_builtin_macros/src/asm.rs | 39 +++++++++++++++----- compiler/rustc_builtin_macros/src/errors.rs | 9 +++++ tests/ui/asm/parse-error.rs | 15 ++++++-- tests/ui/asm/parse-error.stderr | 40 ++++++++++++++++++--- 5 files changed, 91 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_builtin_macros/messages.ftl b/compiler/rustc_builtin_macros/messages.ftl index a30ab236213..2d9f6b974d2 100644 --- a/compiler/rustc_builtin_macros/messages.ftl +++ b/compiler/rustc_builtin_macros/messages.ftl @@ -199,6 +199,9 @@ builtin_macros_format_use_positional = consider using a positional formatting ar builtin_macros_global_asm_clobber_abi = `clobber_abi` cannot be used with `global_asm!` +builtin_macros_global_asm_unsupported_operand = the `{$symbol}` operand cannot be used with `global_asm!` + .label = the `{$symbol}` operand is not meaningful for global-scoped inline assembly, remove it + builtin_macros_global_asm_unsupported_option = the `{$symbol}` option cannot be used with `global_asm!` .label = the `{$symbol}` option is not meaningful for global-scoped inline assembly .suggestion = remove this option diff --git a/compiler/rustc_builtin_macros/src/asm.rs b/compiler/rustc_builtin_macros/src/asm.rs index 62e59f1f4d4..7a5cabfce6a 100644 --- a/compiler/rustc_builtin_macros/src/asm.rs +++ b/compiler/rustc_builtin_macros/src/asm.rs @@ -29,6 +29,29 @@ pub struct AsmArgs { pub options_spans: Vec, } +/// Used for better error messages when operand types are used that are not +/// supported by the current macro (e.g. `in` or `out` for `global_asm!`) +/// +/// returns +/// +/// - `Ok(true)` if the current token matches the keyword, and was expected +/// - `Ok(false)` if the current token does not match the keyword +/// - `Err(_)` if the current token matches the keyword, but was not expected +fn eat_operand_keyword<'a>(p: &mut Parser<'a>, symbol: Symbol, expect: bool) -> PResult<'a, bool> { + if expect { + Ok(p.eat_keyword(symbol)) + } else { + let span = p.token.span; + if p.eat_keyword_noexpect(symbol) { + // in gets printed as `r#in` otherwise + let symbol = if symbol == kw::In { "in" } else { symbol.as_str() }; + Err(p.dcx().create_err(errors::GlobalAsmUnsupportedOperand { span, symbol })) + } else { + Ok(false) + } + } +} + fn parse_args<'a>( ecx: &ExtCtxt<'a>, sp: Span, @@ -106,7 +129,7 @@ pub fn parse_asm_args<'a>( }; let mut explicit_reg = false; - let op = if !is_global_asm && p.eat_keyword(kw::In) { + let op = if eat_operand_keyword(p, kw::In, !is_global_asm)? { let reg = parse_reg(p, &mut explicit_reg)?; if p.eat_keyword(kw::Underscore) { let err = dcx.create_err(errors::AsmUnderscoreInput { span: p.token.span }); @@ -114,15 +137,15 @@ pub fn parse_asm_args<'a>( } let expr = p.parse_expr()?; ast::InlineAsmOperand::In { reg, expr } - } else if !is_global_asm && p.eat_keyword(sym::out) { + } else if eat_operand_keyword(p, sym::out, !is_global_asm)? { let reg = parse_reg(p, &mut explicit_reg)?; let expr = if p.eat_keyword(kw::Underscore) { None } else { Some(p.parse_expr()?) }; ast::InlineAsmOperand::Out { reg, expr, late: false } - } else if !is_global_asm && p.eat_keyword(sym::lateout) { + } else if eat_operand_keyword(p, sym::lateout, !is_global_asm)? { let reg = parse_reg(p, &mut explicit_reg)?; let expr = if p.eat_keyword(kw::Underscore) { None } else { Some(p.parse_expr()?) }; ast::InlineAsmOperand::Out { reg, expr, late: true } - } else if !is_global_asm && p.eat_keyword(sym::inout) { + } else if eat_operand_keyword(p, sym::inout, !is_global_asm)? { let reg = parse_reg(p, &mut explicit_reg)?; if p.eat_keyword(kw::Underscore) { let err = dcx.create_err(errors::AsmUnderscoreInput { span: p.token.span }); @@ -136,7 +159,7 @@ pub fn parse_asm_args<'a>( } else { ast::InlineAsmOperand::InOut { reg, expr, late: false } } - } else if !is_global_asm && p.eat_keyword(sym::inlateout) { + } else if eat_operand_keyword(p, sym::inlateout, !is_global_asm)? { let reg = parse_reg(p, &mut explicit_reg)?; if p.eat_keyword(kw::Underscore) { let err = dcx.create_err(errors::AsmUnderscoreInput { span: p.token.span }); @@ -150,6 +173,9 @@ pub fn parse_asm_args<'a>( } else { ast::InlineAsmOperand::InOut { reg, expr, late: true } } + } else if eat_operand_keyword(p, sym::label, !is_global_asm)? { + let block = p.parse_block()?; + ast::InlineAsmOperand::Label { block } } else if p.eat_keyword(kw::Const) { let anon_const = p.parse_expr_anon_const()?; ast::InlineAsmOperand::Const { anon_const } @@ -165,9 +191,6 @@ pub fn parse_asm_args<'a>( path: path.clone(), }; ast::InlineAsmOperand::Sym { sym } - } else if !is_global_asm && p.eat_keyword(sym::label) { - let block = p.parse_block()?; - ast::InlineAsmOperand::Label { block } } else if allow_templates { let template = p.parse_expr()?; // If it can't possibly expand to a string, provide diagnostics here to include other diff --git a/compiler/rustc_builtin_macros/src/errors.rs b/compiler/rustc_builtin_macros/src/errors.rs index f17819474ad..1c5d98a0897 100644 --- a/compiler/rustc_builtin_macros/src/errors.rs +++ b/compiler/rustc_builtin_macros/src/errors.rs @@ -856,6 +856,15 @@ pub(crate) struct GlobalAsmUnsupportedOption { pub(crate) full_span: Span, } +#[derive(Diagnostic)] +#[diag(builtin_macros_global_asm_unsupported_operand)] +pub(crate) struct GlobalAsmUnsupportedOperand<'a> { + #[primary_span] + #[label] + pub(crate) span: Span, + pub(crate) symbol: &'a str, +} + #[derive(Diagnostic)] #[diag(builtin_macros_test_runner_invalid)] pub(crate) struct TestRunnerInvalid { diff --git a/tests/ui/asm/parse-error.rs b/tests/ui/asm/parse-error.rs index 9dec3a1c394..16ae0282864 100644 --- a/tests/ui/asm/parse-error.rs +++ b/tests/ui/asm/parse-error.rs @@ -146,5 +146,16 @@ fn main() { //~^ ERROR asm template must be a string literal global_asm!("{1}", format!("{{{}}}", 0), const FOO, const BAR); //~^ ERROR asm template must be a string literal -global_asm!("{}", label {}); -//~^ ERROR expected operand, options, or additional template string + +global_asm!("{}", in(reg)); +//~^ ERROR the `in` operand cannot be used with `global_asm!` +global_asm!("{}", out(reg)); +//~^ ERROR the `out` operand cannot be used with `global_asm!` +global_asm!("{}", lateout(reg)); +//~^ ERROR the `lateout` operand cannot be used with `global_asm!` +global_asm!("{}", inout(reg)); +//~^ ERROR the `inout` operand cannot be used with `global_asm!` +global_asm!("{}", inlateout(reg)); +//~^ ERROR the `inlateout` operand cannot be used with `global_asm!` +global_asm!("{}", label(reg)); +//~^ ERROR the `label` operand cannot be used with `global_asm!` diff --git a/tests/ui/asm/parse-error.stderr b/tests/ui/asm/parse-error.stderr index e9ecd712bc3..f5f8d537d86 100644 --- a/tests/ui/asm/parse-error.stderr +++ b/tests/ui/asm/parse-error.stderr @@ -380,11 +380,41 @@ LL | global_asm!("{1}", format!("{{{}}}", 0), const FOO, const BAR); | = note: this error originates in the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info) -error: expected operand, options, or additional template string - --> $DIR/parse-error.rs:149:19 +error: the `in` operand cannot be used with `global_asm!` + --> $DIR/parse-error.rs:150:19 | -LL | global_asm!("{}", label {}); - | ^^^^^^^^ expected operand, options, or additional template string +LL | global_asm!("{}", in(reg)); + | ^^ the `in` operand is not meaningful for global-scoped inline assembly, remove it + +error: the `out` operand cannot be used with `global_asm!` + --> $DIR/parse-error.rs:152:19 + | +LL | global_asm!("{}", out(reg)); + | ^^^ the `out` operand is not meaningful for global-scoped inline assembly, remove it + +error: the `lateout` operand cannot be used with `global_asm!` + --> $DIR/parse-error.rs:154:19 + | +LL | global_asm!("{}", lateout(reg)); + | ^^^^^^^ the `lateout` operand is not meaningful for global-scoped inline assembly, remove it + +error: the `inout` operand cannot be used with `global_asm!` + --> $DIR/parse-error.rs:156:19 + | +LL | global_asm!("{}", inout(reg)); + | ^^^^^ the `inout` operand is not meaningful for global-scoped inline assembly, remove it + +error: the `inlateout` operand cannot be used with `global_asm!` + --> $DIR/parse-error.rs:158:19 + | +LL | global_asm!("{}", inlateout(reg)); + | ^^^^^^^^^ the `inlateout` operand is not meaningful for global-scoped inline assembly, remove it + +error: the `label` operand cannot be used with `global_asm!` + --> $DIR/parse-error.rs:160:19 + | +LL | global_asm!("{}", label(reg)); + | ^^^^^ the `label` operand is not meaningful for global-scoped inline assembly, remove it error[E0435]: attempt to use a non-constant value in a constant --> $DIR/parse-error.rs:39:37 @@ -441,6 +471,6 @@ help: consider using `const` instead of `let` LL | const bar: /* Type */ = 0; | ~~~~~ ++++++++++++ -error: aborting due to 67 previous errors +error: aborting due to 72 previous errors For more information about this error, try `rustc --explain E0435`. From 9b165a16009980545a864eb5899c3b3279f58f37 Mon Sep 17 00:00:00 2001 From: Ken Micklas Date: Sun, 28 Jul 2024 15:03:07 +0100 Subject: [PATCH 04/36] 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 b0bd6ef2d3c..6f23d686bcf 100644 --- a/library/alloc/src/collections/btree/set.rs +++ b/library/alloc/src/collections/btree/set.rs @@ -2,11 +2,12 @@ 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 @@ pub const fn len(&self) -> usize { 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 @@ fn min(mut self) -> Option<&'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 05/36] 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 268e89c7f60..c09180e542f 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::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 06/36] 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 45faa66ec11..1a7bdc4737f 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 9b097b2d44a8f953640ba42122a804485d651ea9 Mon Sep 17 00:00:00 2001 From: Bryanskiy Date: Wed, 31 Jul 2024 18:58:04 +0300 Subject: [PATCH 07/36] Delegation: second attempt to improve perf --- compiler/rustc_hir/src/hir.rs | 11 +++++++++++ .../src/collect/generics_of.rs | 17 ++++++++++------- .../src/collect/predicates_of.rs | 17 ++++++++++------- compiler/rustc_hir_analysis/src/delegation.rs | 2 +- compiler/rustc_middle/src/hir/map/mod.rs | 13 +------------ 5 files changed, 33 insertions(+), 27 deletions(-) diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 3b9aea08791..9257be86471 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -2952,6 +2952,17 @@ pub struct FnDecl<'hir> { pub lifetime_elision_allowed: bool, } +impl<'hir> FnDecl<'hir> { + pub fn opt_delegation_sig_id(&self) -> Option { + if let FnRetTy::Return(ty) = self.output + && let TyKind::InferDelegation(sig_id, _) = ty.kind + { + return Some(sig_id); + } + None + } +} + /// Represents what type of implicit self a function has, if any. #[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Debug, HashStable_Generic)] pub enum ImplicitSelfKind { diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs index 80a65aa2988..71a6501de8b 100644 --- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs @@ -54,13 +54,6 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { }; } - // For a delegation item inherit generics from callee. - if let Some(sig_id) = tcx.hir().opt_delegation_sig_id(def_id) - && let Some(generics) = inherit_generics_for_delegation_item(tcx, def_id, sig_id) - { - return generics; - } - let hir_id = tcx.local_def_id_to_hir_id(def_id); let node = tcx.hir_node(hir_id); @@ -234,6 +227,16 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { // inherit the generics of the item. Some(parent.to_def_id()) } + ItemKind::Fn(sig, _, _) => { + // For a delegation item inherit generics from callee. + if let Some(sig_id) = sig.decl.opt_delegation_sig_id() + && let Some(generics) = + inherit_generics_for_delegation_item(tcx, def_id, sig_id) + { + return generics; + } + None + } _ => None, }, _ => None, diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index ae52dbd56f9..a5a56cb845d 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -115,13 +115,6 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen None => {} } - // For a delegation item inherit predicates from callee. - if let Some(sig_id) = tcx.hir().opt_delegation_sig_id(def_id) - && let Some(predicates) = inherit_predicates_for_delegation_item(tcx, def_id, sig_id) - { - return predicates; - } - let hir_id = tcx.local_def_id_to_hir_id(def_id); let node = tcx.hir_node(hir_id); @@ -151,6 +144,16 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen ItemKind::Trait(_, _, _, self_bounds, ..) | ItemKind::TraitAlias(_, self_bounds) => { is_trait = Some(self_bounds); } + + ItemKind::Fn(sig, _, _) => { + // For a delegation item inherit predicates from callee. + if let Some(sig_id) = sig.decl.opt_delegation_sig_id() + && let Some(predicates) = + inherit_predicates_for_delegation_item(tcx, def_id, sig_id) + { + return predicates; + } + } _ => {} } }; diff --git a/compiler/rustc_hir_analysis/src/delegation.rs b/compiler/rustc_hir_analysis/src/delegation.rs index e21ed55bce3..ca62ef92b83 100644 --- a/compiler/rustc_hir_analysis/src/delegation.rs +++ b/compiler/rustc_hir_analysis/src/delegation.rs @@ -242,7 +242,7 @@ pub(crate) fn inherit_sig_for_delegation_item<'tcx>( tcx: TyCtxt<'tcx>, def_id: LocalDefId, ) -> &'tcx [Ty<'tcx>] { - let sig_id = tcx.hir().delegation_sig_id(def_id); + let sig_id = tcx.hir().opt_delegation_sig_id(def_id).unwrap(); let caller_sig = tcx.fn_sig(sig_id); if let Err(err) = check_constraints(tcx, def_id, sig_id) { let sig_len = caller_sig.instantiate_identity().skip_binder().inputs().len() + 1; diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index 1705c016437..4c243e6330b 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -747,18 +747,7 @@ pub fn expect_expr(self, id: HirId) -> &'hir Expr<'hir> { } pub fn opt_delegation_sig_id(self, def_id: LocalDefId) -> Option { - if let Some(ret) = self.get_fn_output(def_id) - && let FnRetTy::Return(ty) = ret - && let TyKind::InferDelegation(sig_id, _) = ty.kind - { - return Some(sig_id); - } - None - } - - #[inline] - pub fn delegation_sig_id(self, def_id: LocalDefId) -> DefId { - self.opt_delegation_sig_id(def_id).unwrap() + self.tcx.opt_hir_owner_node(def_id)?.fn_decl()?.opt_delegation_sig_id() } #[inline] From 020476296b1aa60f79c2f671c48542afe99cc428 Mon Sep 17 00:00:00 2001 From: Ken Micklas Date: Thu, 1 Aug 2024 19:23:18 +0100 Subject: [PATCH 08/36] 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 6f23d686bcf..0fc892eec65 100644 --- a/library/alloc/src/collections/btree/set.rs +++ b/library/alloc/src/collections/btree/set.rs @@ -2,7 +2,6 @@ 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 @@ pub unsafe fn insert_before_unchecked(&mut self, value: T) { /// /// 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 @@ pub fn insert_after(&mut self, value: T) -> Result<(), UnorderedError> { /// /// 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 @@ pub fn remove_prev(&mut self) -> Option { } } -/// 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 09/36] 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 0fc892eec65..47b7e56ddf0 100644 --- a/library/alloc/src/collections/btree/set.rs +++ b/library/alloc/src/collections/btree/set.rs @@ -1194,7 +1194,7 @@ pub const fn is_empty(&self) -> bool { /// 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 @@ pub fn lower_bound(&self, bound: Bound<&Q>) -> Cursor<'_, T> /// 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 @@ pub unsafe fn lower_bound_mut(&mut self, bound: Bound<&Q>) -> CursorM /// 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 @@ pub fn upper_bound(&self, bound: Bound<&Q>) -> Cursor<'_, T> /// 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 10/36] 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 47b7e56ddf0..86401714639 100644 --- a/library/alloc/src/collections/btree/set.rs +++ b/library/alloc/src/collections/btree/set.rs @@ -1249,25 +1249,25 @@ pub fn lower_bound(&self, bound: Bound<&Q>) -> Cursor<'_, T> /// /// 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 @@ pub unsafe fn upper_bound_mut(&mut self, bound: Bound<&Q>) -> CursorM 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 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { } } +/// 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 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { /// 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 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { /// * 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,6 +2117,70 @@ 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<&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<&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<&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<&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() } + } + + /// 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) } @@ -2105,7 +2197,7 @@ pub fn prev(&mut self) -> Option<&mut T> { /// 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. + /// 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) @@ -2120,11 +2212,11 @@ pub fn peek_prev(&mut self) -> Option<&mut T> { } /// Returns a read-only cursor pointing to the same location as the - /// `CursorMut`. + /// `CursorMutKey`. /// /// 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`. + /// `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() } @@ -2217,6 +2309,92 @@ pub fn remove_prev(&mut self) -> Option { } } +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 11/36] 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 86401714639..362e32cc8f4 100644 --- a/library/alloc/src/collections/btree/set.rs +++ b/library/alloc/src/collections/btree/set.rs @@ -1250,16 +1250,16 @@ pub fn lower_bound(&self, bound: Bound<&Q>) -> Cursor<'_, T> /// 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 @@ pub fn upper_bound(&self, bound: Bound<&Q>) -> Cursor<'_, T> /// 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 af79a6396c4175fcdacc18d7448bcde94c3f0363 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Fri, 2 Aug 2024 05:16:01 +0200 Subject: [PATCH 12/36] time.rs: remove "Basic usage text" Only one example is given (for each method) --- library/core/src/time.rs | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/library/core/src/time.rs b/library/core/src/time.rs index 179fbabadde..0390bb59a89 100644 --- a/library/core/src/time.rs +++ b/library/core/src/time.rs @@ -617,8 +617,6 @@ pub const fn as_nanos(&self) -> u128 { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// use std::time::Duration; /// @@ -640,8 +638,6 @@ pub const fn abs_diff(self, other: Duration) -> Duration { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// use std::time::Duration; /// @@ -700,8 +696,6 @@ pub const fn saturating_add(self, rhs: Duration) -> Duration { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// use std::time::Duration; /// @@ -758,8 +752,6 @@ pub const fn saturating_sub(self, rhs: Duration) -> Duration { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// use std::time::Duration; /// @@ -814,8 +806,6 @@ pub const fn saturating_mul(self, rhs: u32) -> Duration { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// use std::time::Duration; /// From 7742be0095391591c7063465d82f836bdd4787b7 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 1 Aug 2024 20:10:19 +0000 Subject: [PATCH 13/36] Handle virtual workspaces in the tidy edition check --- src/tools/tidy/src/edition.rs | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/tools/tidy/src/edition.rs b/src/tools/tidy/src/edition.rs index d658fe13d36..6a58d58dbde 100644 --- a/src/tools/tidy/src/edition.rs +++ b/src/tools/tidy/src/edition.rs @@ -4,11 +4,6 @@ use crate::walk::{filter_dirs, walk}; -fn is_edition_2021(mut line: &str) -> bool { - line = line.trim(); - line == "edition = \"2021\"" -} - pub fn check(path: &Path, bad: &mut bool) { walk(path, |path, _is_dir| filter_dirs(path), &mut |entry, contents| { let file = entry.path(); @@ -17,8 +12,15 @@ pub fn check(path: &Path, bad: &mut bool) { return; } - let is_2021 = contents.lines().any(is_edition_2021); - if !is_2021 { + let is_2021 = contents.lines().any(|line| line.trim() == "edition = \"2021\""); + + let is_workspace = contents.lines().any(|line| line.trim() == "[workspace]"); + let is_package = contents.lines().any(|line| line.trim() == "[package]"); + assert!(is_workspace || is_package); + + // Check that all packages use the 2021 edition. Virtual workspaces don't allow setting an + // edition, so these shouldn't be checked. + if is_package && !is_2021 { tidy_error!( bad, "{} doesn't have `edition = \"2021\"` on a separate line", From 1f3be75f56bfa7520b86eada306ad66455b4fd6e Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 1 Aug 2024 20:09:50 +0000 Subject: [PATCH 14/36] Move the standard library to a separate workspace This ensures that the Cargo.lock packaged for it in the rust-src component is up-to-date, allowing rust-analyzer to run cargo metadata on the standard library even when the rust-src component is stored in a read-only location as is necessary for loading crates.io dependencies of the standard library. This also simplifies tidy's license check for runtime dependencies as it can now look at all entries in library/Cargo.lock without having to filter for just the dependencies of runtime crates. In addition this allows removing an exception in check_runtime_license_exceptions that was necessary due to the compiler enabling a feature on the object crate which pulls in a dependency not allowed for the standard library. While cargo workspaces normally enable dependencies of multiple targets to be reused, for the standard library we do not want this reusing to prevent conflicts between dependencies of the sysroot and of tools that are built using this sysroot. For this reason we already use an unstable cargo feature to ensure that any dependencies which would otherwise be shared get a different -Cmetadata argument as well as using separate build dirs. This doesn't change the situation around vendoring. We already have several cargo workspaces that need to be vendored. Adding another one doesn't change much. There are also no cargo profiles that are shared between the root workspace and the library workspace anyway, so it doesn't add any extra work when changing cargo profiles. --- .gitignore | 1 + Cargo.lock | 304 +----------- Cargo.toml | 37 -- library/Cargo.lock | 489 +++++++++++++++++++ library/Cargo.toml | 44 ++ src/bootstrap/src/core/build_steps/dist.rs | 2 + src/bootstrap/src/core/build_steps/vendor.rs | 1 + src/bootstrap/src/core/metadata.rs | 5 +- src/tools/tidy/src/deps.rs | 104 ++-- 9 files changed, 598 insertions(+), 389 deletions(-) create mode 100644 library/Cargo.lock create mode 100644 library/Cargo.toml diff --git a/.gitignore b/.gitignore index 87d02563ed0..aabec0988a9 100644 --- a/.gitignore +++ b/.gitignore @@ -48,6 +48,7 @@ build/ /dist/ /unicode-downloads /target +/library/target /src/bootstrap/target /src/tools/x/target # Created by default with `src/ci/docker/run.sh` diff --git a/Cargo.lock b/Cargo.lock index 1a7d7e3f5d7..b47a21355db 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -11,27 +11,11 @@ dependencies = [ "gimli 0.28.1", ] -[[package]] -name = "addr2line" -version = "0.22.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678" -dependencies = [ - "compiler_builtins", - "gimli 0.29.0", - "rustc-std-workspace-alloc", - "rustc-std-workspace-core", -] - [[package]] name = "adler" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" -dependencies = [ - "compiler_builtins", - "rustc-std-workspace-core", -] [[package]] name = "aes" @@ -66,16 +50,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "alloc" -version = "0.0.0" -dependencies = [ - "compiler_builtins", - "core", - "rand", - "rand_xorshift", -] - [[package]] name = "allocator-api2" version = "0.2.18" @@ -256,7 +230,7 @@ version = "0.3.71" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d" dependencies = [ - "addr2line 0.21.0", + "addr2line", "cc", "cfg-if", "libc", @@ -455,10 +429,6 @@ name = "cfg-if" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" -dependencies = [ - "compiler_builtins", - "rustc-std-workspace-core", -] [[package]] name = "cfg_aliases" @@ -737,16 +707,6 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "55b672471b4e9f9e95499ea597ff64941a309b2cdbffcc46f2cc5e2d971fd335" -[[package]] -name = "compiler_builtins" -version = "0.1.114" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb58b199190fcfe0846f55a3b545cd6b07a34bdd5930a476ff856f3ebcc5558a" -dependencies = [ - "cc", - "rustc-std-workspace-core", -] - [[package]] name = "compiletest" version = "0.0.0" @@ -787,14 +747,6 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "core" -version = "0.0.0" -dependencies = [ - "rand", - "rand_xorshift", -] - [[package]] name = "core-foundation-sys" version = "0.8.6" @@ -1134,19 +1086,6 @@ version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "59f8e79d1fbf76bdfbde321e902714bf6c49df88a7dda6fc682fc2979226962d" -[[package]] -name = "dlmalloc" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3264b043b8e977326c1ee9e723da2c1f8d09a99df52cacf00b4dbce5ac54414d" -dependencies = [ - "cfg-if", - "compiler_builtins", - "libc", - "rustc-std-workspace-core", - "windows-sys 0.52.0", -] - [[package]] name = "either" version = "1.12.0" @@ -1348,16 +1287,6 @@ dependencies = [ "percent-encoding", ] -[[package]] -name = "fortanix-sgx-abi" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57cafc2274c10fab234f176b25903ce17e690fca7597090d50880e047a0389c5" -dependencies = [ - "compiler_builtins", - "rustc-std-workspace-core", -] - [[package]] name = "fs-err" version = "2.11.0" @@ -1504,8 +1433,6 @@ version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5" dependencies = [ - "rustc-std-workspace-core", - "rustc-std-workspace-std", "unicode-width", ] @@ -1526,25 +1453,11 @@ version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" dependencies = [ - "compiler_builtins", "fallible-iterator", "indexmap", - "rustc-std-workspace-alloc", - "rustc-std-workspace-core", "stable_deref_trait", ] -[[package]] -name = "gimli" -version = "0.29.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" -dependencies = [ - "compiler_builtins", - "rustc-std-workspace-alloc", - "rustc-std-workspace-core", -] - [[package]] name = "gimli" version = "0.31.0" @@ -1606,9 +1519,6 @@ checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" dependencies = [ "ahash", "allocator-api2", - "compiler_builtins", - "rustc-std-workspace-alloc", - "rustc-std-workspace-core", "serde", ] @@ -1630,17 +1540,6 @@ version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" -[[package]] -name = "hermit-abi" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" -dependencies = [ - "compiler_builtins", - "rustc-std-workspace-alloc", - "rustc-std-workspace-core", -] - [[package]] name = "hex" version = "0.4.3" @@ -2065,9 +1964,6 @@ name = "libc" version = "0.2.155" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" -dependencies = [ - "rustc-std-workspace-core", -] [[package]] name = "libdbus-sys" @@ -2299,10 +2195,6 @@ name = "memchr" version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" -dependencies = [ - "compiler_builtins", - "rustc-std-workspace-core", -] [[package]] name = "memmap2" @@ -2357,9 +2249,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" dependencies = [ "adler", - "compiler_builtins", - "rustc-std-workspace-alloc", - "rustc-std-workspace-core", ] [[package]] @@ -2549,7 +2438,7 @@ version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" dependencies = [ - "hermit-abi 0.3.9", + "hermit-abi", "libc", ] @@ -2588,14 +2477,11 @@ version = "0.36.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f203fa8daa7bb185f760ae12bd8e097f63d17041dcdcaf675ac54cdf863170e" dependencies = [ - "compiler_builtins", "crc32fast", "flate2", "hashbrown", "indexmap", "memchr", - "rustc-std-workspace-alloc", - "rustc-std-workspace-core", "ruzstd 0.7.0", "wasmparser 0.214.0", ] @@ -2719,29 +2605,6 @@ dependencies = [ "unicode-width", ] -[[package]] -name = "panic_abort" -version = "0.0.0" -dependencies = [ - "alloc", - "cfg-if", - "compiler_builtins", - "core", - "libc", -] - -[[package]] -name = "panic_unwind" -version = "0.0.0" -dependencies = [ - "alloc", - "cfg-if", - "compiler_builtins", - "core", - "libc", - "unwind", -] - [[package]] name = "papergrid" version = "0.11.0" @@ -2996,23 +2859,6 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "proc_macro" -version = "0.0.0" -dependencies = [ - "core", - "std", -] - -[[package]] -name = "profiler_builtins" -version = "0.0.0" -dependencies = [ - "cc", - "compiler_builtins", - "core", -] - [[package]] name = "psm" version = "0.1.21" @@ -3090,27 +2936,6 @@ dependencies = [ "proc-macro2", ] -[[package]] -name = "r-efi" -version = "4.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9e935efc5854715dfc0a4c9ef18dc69dee0ec3bf9cc3ab740db831c0fdd86a3" -dependencies = [ - "compiler_builtins", - "rustc-std-workspace-core", -] - -[[package]] -name = "r-efi-alloc" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31d6f09fe2b6ad044bc3d2c34ce4979796581afd2f1ebc185837e02421e02fd7" -dependencies = [ - "compiler_builtins", - "r-efi", - "rustc-std-workspace-core", -] - [[package]] name = "rand" version = "0.8.5" @@ -3141,15 +2966,6 @@ dependencies = [ "getrandom", ] -[[package]] -name = "rand_xorshift" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f" -dependencies = [ - "rand_core", -] - [[package]] name = "rand_xoshiro" version = "0.6.0" @@ -3361,10 +3177,6 @@ name = "rustc-demangle" version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" -dependencies = [ - "compiler_builtins", - "rustc-std-workspace-core", -] [[package]] name = "rustc-hash" @@ -3425,27 +3237,6 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5c9f15eec8235d7cb775ee6f81891db79b98fd54ba1ad8fae565b88ef1ae4e2" -[[package]] -name = "rustc-std-workspace-alloc" -version = "1.99.0" -dependencies = [ - "alloc", -] - -[[package]] -name = "rustc-std-workspace-core" -version = "1.99.0" -dependencies = [ - "core", -] - -[[package]] -name = "rustc-std-workspace-std" -version = "1.99.0" -dependencies = [ - "std", -] - [[package]] name = "rustc_abi" version = "0.0.0" @@ -5231,46 +5022,6 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" -[[package]] -name = "std" -version = "0.0.0" -dependencies = [ - "addr2line 0.22.0", - "alloc", - "cfg-if", - "compiler_builtins", - "core", - "dlmalloc", - "fortanix-sgx-abi", - "hashbrown", - "hermit-abi 0.4.0", - "libc", - "miniz_oxide", - "object 0.36.2", - "panic_abort", - "panic_unwind", - "profiler_builtins", - "r-efi", - "r-efi-alloc", - "rand", - "rand_xorshift", - "rustc-demangle", - "std_detect", - "unwind", - "wasi", -] - -[[package]] -name = "std_detect" -version = "0.1.5" -dependencies = [ - "cfg-if", - "compiler_builtins", - "libc", - "rustc-std-workspace-alloc", - "rustc-std-workspace-core", -] - [[package]] name = "string_cache" version = "0.8.7" @@ -5377,15 +5128,6 @@ dependencies = [ "windows", ] -[[package]] -name = "sysroot" -version = "0.0.0" -dependencies = [ - "proc_macro", - "std", - "test", -] - [[package]] name = "tabled" version = "0.15.0" @@ -5470,16 +5212,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "test" -version = "0.0.0" -dependencies = [ - "core", - "getopts", - "libc", - "std", -] - [[package]] name = "test-float-parse" version = "0.1.0" @@ -5978,11 +5710,6 @@ name = "unicode-width" version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d" -dependencies = [ - "compiler_builtins", - "rustc-std-workspace-core", - "rustc-std-workspace-std", -] [[package]] name = "unicode-xid" @@ -6007,28 +5734,6 @@ dependencies = [ "tidy", ] -[[package]] -name = "unwind" -version = "0.0.0" -dependencies = [ - "cfg-if", - "compiler_builtins", - "core", - "libc", - "unwinding", -] - -[[package]] -name = "unwinding" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37a19a21a537f635c16c7576f22d0f2f7d63353c1337ad4ce0d8001c7952a25b" -dependencies = [ - "compiler_builtins", - "gimli 0.28.1", - "rustc-std-workspace-core", -] - [[package]] name = "url" version = "2.5.2" @@ -6100,11 +5805,6 @@ name = "wasi" version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" -dependencies = [ - "compiler_builtins", - "rustc-std-workspace-alloc", - "rustc-std-workspace-core", -] [[package]] name = "wasm-bindgen" diff --git a/Cargo.toml b/Cargo.toml index 178a5ab9408..131feec70ab 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,8 +2,6 @@ resolver = "1" members = [ "compiler/rustc", - "library/std", - "library/sysroot", "src/etc/test-float-parse", "src/rustdoc-json-types", "src/tools/build_helper", @@ -61,23 +59,8 @@ exclude = [ # not all `Cargo.toml` files are available, so we exclude the `x` binary, # so it can be invoked before the current checkout is set up. "src/tools/x", - # stdarch has its own Cargo workspace - "library/stdarch", ] -[profile.release.package.compiler_builtins] -# For compiler-builtins we always use a high number of codegen units. -# The goal here is to place every single intrinsic into its own object -# file to avoid symbol clashes with the system libgcc if possible. Note -# that this number doesn't actually produce this many object files, we -# just don't create more than this number of object files. -# -# It's a bit of a bummer that we have to pass this here, unfortunately. -# Ideally this would be specified through an env var to Cargo so Cargo -# knows how many CGUs are for this specific crate, but for now -# per-crate configuration isn't specifiable in the environment. -codegen-units = 10000 - [profile.release.package.rustc-rayon-core] # The rustc fork of Rayon has deadlock detection code which intermittently # causes overflows in the CI (see https://github.com/rust-lang/rust/issues/90227) @@ -85,19 +68,6 @@ codegen-units = 10000 # FIXME: This workaround should be removed once #90227 is fixed. overflow-checks = false -# These dependencies of the standard library implement symbolication for -# backtraces on most platforms. Their debuginfo causes both linking to be slower -# (more data to chew through) and binaries to be larger without really all that -# much benefit. This section turns them all to down to have no debuginfo which -# helps to improve link times a little bit. -[profile.release.package] -addr2line.debug = 0 -adler.debug = 0 -gimli.debug = 0 -miniz_oxide.debug = 0 -object.debug = 0 -rustc-demangle.debug = 0 - # These are very thin wrappers around executing lld with the right binary name. # Basically nothing within them can go wrong without having been explicitly logged anyway. # We ship these in every rustc tarball and even after compression they add up @@ -120,10 +90,3 @@ codegen-units = 1 # FIXME: LTO cannot be enabled for binaries in a workspace # # lto = true - -[patch.crates-io] -# See comments in `library/rustc-std-workspace-core/README.md` for what's going on -# here -rustc-std-workspace-core = { path = 'library/rustc-std-workspace-core' } -rustc-std-workspace-alloc = { path = 'library/rustc-std-workspace-alloc' } -rustc-std-workspace-std = { path = 'library/rustc-std-workspace-std' } diff --git a/library/Cargo.lock b/library/Cargo.lock new file mode 100644 index 00000000000..223b61456c2 --- /dev/null +++ b/library/Cargo.lock @@ -0,0 +1,489 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "addr2line" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678" +dependencies = [ + "compiler_builtins", + "gimli 0.29.0", + "rustc-std-workspace-alloc", + "rustc-std-workspace-core", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +dependencies = [ + "compiler_builtins", + "rustc-std-workspace-core", +] + +[[package]] +name = "alloc" +version = "0.0.0" +dependencies = [ + "compiler_builtins", + "core", + "rand", + "rand_xorshift", +] + +[[package]] +name = "allocator-api2" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" + +[[package]] +name = "cc" +version = "1.0.99" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96c51067fd44124faa7f870b4b1c969379ad32b2ba805aa959430ceaa384f695" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +dependencies = [ + "compiler_builtins", + "rustc-std-workspace-core", +] + +[[package]] +name = "compiler_builtins" +version = "0.1.114" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb58b199190fcfe0846f55a3b545cd6b07a34bdd5930a476ff856f3ebcc5558a" +dependencies = [ + "cc", + "rustc-std-workspace-core", +] + +[[package]] +name = "core" +version = "0.0.0" +dependencies = [ + "rand", + "rand_xorshift", +] + +[[package]] +name = "dlmalloc" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3264b043b8e977326c1ee9e723da2c1f8d09a99df52cacf00b4dbce5ac54414d" +dependencies = [ + "cfg-if", + "compiler_builtins", + "libc", + "rustc-std-workspace-core", + "windows-sys", +] + +[[package]] +name = "fortanix-sgx-abi" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57cafc2274c10fab234f176b25903ce17e690fca7597090d50880e047a0389c5" +dependencies = [ + "compiler_builtins", + "rustc-std-workspace-core", +] + +[[package]] +name = "getopts" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5" +dependencies = [ + "rustc-std-workspace-core", + "rustc-std-workspace-std", + "unicode-width", +] + +[[package]] +name = "gimli" +version = "0.28.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" +dependencies = [ + "compiler_builtins", + "rustc-std-workspace-alloc", + "rustc-std-workspace-core", +] + +[[package]] +name = "gimli" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" +dependencies = [ + "compiler_builtins", + "rustc-std-workspace-alloc", + "rustc-std-workspace-core", +] + +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +dependencies = [ + "allocator-api2", + "compiler_builtins", + "rustc-std-workspace-alloc", + "rustc-std-workspace-core", +] + +[[package]] +name = "hermit-abi" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" +dependencies = [ + "compiler_builtins", + "rustc-std-workspace-alloc", + "rustc-std-workspace-core", +] + +[[package]] +name = "libc" +version = "0.2.155" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" +dependencies = [ + "rustc-std-workspace-core", +] + +[[package]] +name = "memchr" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +dependencies = [ + "compiler_builtins", + "rustc-std-workspace-core", +] + +[[package]] +name = "miniz_oxide" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" +dependencies = [ + "adler", + "compiler_builtins", + "rustc-std-workspace-alloc", + "rustc-std-workspace-core", +] + +[[package]] +name = "object" +version = "0.36.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f203fa8daa7bb185f760ae12bd8e097f63d17041dcdcaf675ac54cdf863170e" +dependencies = [ + "compiler_builtins", + "memchr", + "rustc-std-workspace-alloc", + "rustc-std-workspace-core", +] + +[[package]] +name = "panic_abort" +version = "0.0.0" +dependencies = [ + "alloc", + "cfg-if", + "compiler_builtins", + "core", + "libc", +] + +[[package]] +name = "panic_unwind" +version = "0.0.0" +dependencies = [ + "alloc", + "cfg-if", + "compiler_builtins", + "core", + "libc", + "unwind", +] + +[[package]] +name = "proc_macro" +version = "0.0.0" +dependencies = [ + "core", + "std", +] + +[[package]] +name = "profiler_builtins" +version = "0.0.0" +dependencies = [ + "cc", + "compiler_builtins", + "core", +] + +[[package]] +name = "r-efi" +version = "4.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9e935efc5854715dfc0a4c9ef18dc69dee0ec3bf9cc3ab740db831c0fdd86a3" +dependencies = [ + "compiler_builtins", + "rustc-std-workspace-core", +] + +[[package]] +name = "r-efi-alloc" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31d6f09fe2b6ad044bc3d2c34ce4979796581afd2f1ebc185837e02421e02fd7" +dependencies = [ + "compiler_builtins", + "r-efi", + "rustc-std-workspace-core", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" + +[[package]] +name = "rand_xorshift" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f" +dependencies = [ + "rand_core", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" +dependencies = [ + "compiler_builtins", + "rustc-std-workspace-core", +] + +[[package]] +name = "rustc-std-workspace-alloc" +version = "1.99.0" +dependencies = [ + "alloc", +] + +[[package]] +name = "rustc-std-workspace-core" +version = "1.99.0" +dependencies = [ + "core", +] + +[[package]] +name = "rustc-std-workspace-std" +version = "1.99.0" +dependencies = [ + "std", +] + +[[package]] +name = "std" +version = "0.0.0" +dependencies = [ + "addr2line", + "alloc", + "cfg-if", + "compiler_builtins", + "core", + "dlmalloc", + "fortanix-sgx-abi", + "hashbrown", + "hermit-abi", + "libc", + "miniz_oxide", + "object", + "panic_abort", + "panic_unwind", + "profiler_builtins", + "r-efi", + "r-efi-alloc", + "rand", + "rand_xorshift", + "rustc-demangle", + "std_detect", + "unwind", + "wasi", +] + +[[package]] +name = "std_detect" +version = "0.1.5" +dependencies = [ + "cfg-if", + "compiler_builtins", + "libc", + "rustc-std-workspace-alloc", + "rustc-std-workspace-core", +] + +[[package]] +name = "sysroot" +version = "0.0.0" +dependencies = [ + "proc_macro", + "std", + "test", +] + +[[package]] +name = "test" +version = "0.0.0" +dependencies = [ + "core", + "getopts", + "libc", + "std", +] + +[[package]] +name = "unicode-width" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d" +dependencies = [ + "compiler_builtins", + "rustc-std-workspace-core", + "rustc-std-workspace-std", +] + +[[package]] +name = "unwind" +version = "0.0.0" +dependencies = [ + "cfg-if", + "compiler_builtins", + "core", + "libc", + "unwinding", +] + +[[package]] +name = "unwinding" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37a19a21a537f635c16c7576f22d0f2f7d63353c1337ad4ce0d8001c7952a25b" +dependencies = [ + "compiler_builtins", + "gimli 0.28.1", + "rustc-std-workspace-core", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +dependencies = [ + "compiler_builtins", + "rustc-std-workspace-alloc", + "rustc-std-workspace-core", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" diff --git a/library/Cargo.toml b/library/Cargo.toml new file mode 100644 index 00000000000..c4513b4c127 --- /dev/null +++ b/library/Cargo.toml @@ -0,0 +1,44 @@ +[workspace] +resolver = "1" +members = [ + "std", + "sysroot", +] + +exclude = [ + # stdarch has its own Cargo workspace + "stdarch", +] + +[profile.release.package.compiler_builtins] +# For compiler-builtins we always use a high number of codegen units. +# The goal here is to place every single intrinsic into its own object +# file to avoid symbol clashes with the system libgcc if possible. Note +# that this number doesn't actually produce this many object files, we +# just don't create more than this number of object files. +# +# It's a bit of a bummer that we have to pass this here, unfortunately. +# Ideally this would be specified through an env var to Cargo so Cargo +# knows how many CGUs are for this specific crate, but for now +# per-crate configuration isn't specifiable in the environment. +codegen-units = 10000 + +# These dependencies of the standard library implement symbolication for +# backtraces on most platforms. Their debuginfo causes both linking to be slower +# (more data to chew through) and binaries to be larger without really all that +# much benefit. This section turns them all to down to have no debuginfo which +# helps to improve link times a little bit. +[profile.release.package] +addr2line.debug = 0 +adler.debug = 0 +gimli.debug = 0 +miniz_oxide.debug = 0 +object.debug = 0 +rustc-demangle.debug = 0 + +[patch.crates-io] +# See comments in `library/rustc-std-workspace-core/README.md` for what's going on +# here +rustc-std-workspace-core = { path = 'rustc-std-workspace-core' } +rustc-std-workspace-alloc = { path = 'rustc-std-workspace-alloc' } +rustc-std-workspace-std = { path = 'rustc-std-workspace-std' } diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs index 58f86aa996d..c14709ffb63 100644 --- a/src/bootstrap/src/core/build_steps/dist.rs +++ b/src/bootstrap/src/core/build_steps/dist.rs @@ -1034,6 +1034,8 @@ fn run(self, builder: &Builder<'_>) -> GeneratedTarball { .arg("--sync") .arg(builder.src.join("./compiler/rustc_codegen_gcc/Cargo.toml")) .arg("--sync") + .arg(builder.src.join("./library/Cargo.toml")) + .arg("--sync") .arg(builder.src.join("./src/bootstrap/Cargo.toml")) .arg("--sync") .arg(builder.src.join("./src/tools/opt-dist/Cargo.toml")) diff --git a/src/bootstrap/src/core/build_steps/vendor.rs b/src/bootstrap/src/core/build_steps/vendor.rs index 81770036d71..33768465225 100644 --- a/src/bootstrap/src/core/build_steps/vendor.rs +++ b/src/bootstrap/src/core/build_steps/vendor.rs @@ -47,6 +47,7 @@ fn run(self, builder: &Builder<'_>) -> Self::Output { "src/tools/rust-analyzer/Cargo.toml", "compiler/rustc_codegen_cranelift/Cargo.toml", "compiler/rustc_codegen_gcc/Cargo.toml", + "library/Cargo.toml", "src/bootstrap/Cargo.toml", "src/tools/rustbook/Cargo.toml", ] { diff --git a/src/bootstrap/src/core/metadata.rs b/src/bootstrap/src/core/metadata.rs index 9b4c85e6d34..c11230744c3 100644 --- a/src/bootstrap/src/core/metadata.rs +++ b/src/bootstrap/src/core/metadata.rs @@ -87,5 +87,8 @@ fn workspace_members(build: &Build) -> Vec { }; // Collects `metadata.packages` from all workspaces. - collect_metadata("Cargo.toml") + let mut packages = vec![]; + packages.extend(collect_metadata("Cargo.toml")); + packages.extend(collect_metadata("library/Cargo.toml")); + packages } diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index de59d7d89f9..e23e931b0eb 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -54,6 +54,7 @@ pub(crate) const WORKSPACES: &[(&str, ExceptionList, Option<(&[&str], &[&str])>, &[&str])] = &[ // The root workspace has to be first for check_rustfix to work. (".", EXCEPTIONS, Some((&["rustc-main"], PERMITTED_RUSTC_DEPENDENCIES)), &[]), + ("library", EXCEPTIONS_STDLIB, Some((&["sysroot"], PERMITTED_STDLIB_DEPENDENCIES)), &[]), // Outside of the alphabetical section because rustfmt formats it using multiple lines. ( "compiler/rustc_codegen_cranelift", @@ -90,7 +91,6 @@ ("colored", "MPL-2.0"), // rustfmt ("dissimilar", "Apache-2.0"), // rustdoc, rustc_lexer (few tests) via expect-test, (dev deps) ("fluent-langneg", "Apache-2.0"), // rustc (fluent translations) - ("fortanix-sgx-abi", "MPL-2.0"), // libstd but only for `sgx` target. FIXME: this dependency violates the documentation comment above. ("instant", "BSD-3-Clause"), // rustc_driver/tracing-subscriber/parking_lot ("mdbook", "MPL-2.0"), // mdbook ("option-ext", "MPL-2.0"), // cargo-miri (via `directories`) @@ -108,6 +108,17 @@ // tidy-alphabetical-end ]; +/// These are exceptions to Rust's permissive licensing policy, and +/// should be considered bugs. Exceptions are only allowed in Rust +/// tooling. It is _crucial_ that no exception crates be dependencies +/// of the Rust runtime (std/test). +#[rustfmt::skip] +const EXCEPTIONS_STDLIB: ExceptionList = &[ + // tidy-alphabetical-start + ("fortanix-sgx-abi", "MPL-2.0"), // libstd but only for `sgx` target. FIXME: this dependency violates the documentation comment above. + // tidy-alphabetical-end +]; + // FIXME uncomment once rust-lang/stdarch#1462 lands /* const EXCEPTIONS_STDARCH: ExceptionList = &[ @@ -228,10 +239,6 @@ "ring", ]; -/// These are the root crates that are part of the runtime. The licenses for -/// these and all their dependencies *must not* be in the exception list. -const RUNTIME_CRATES: &[&str] = &["std", "core", "alloc", "test", "panic_abort", "panic_unwind"]; - const PERMITTED_DEPS_LOCATION: &str = concat!(file!(), ":", line!()); /// Crates rustc is allowed to depend on. Avoid adding to the list if possible. @@ -240,7 +247,6 @@ /// rustc. Please check with the compiler team before adding an entry. const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[ // tidy-alphabetical-start - "addr2line", "adler", "ahash", "aho-corasick", @@ -256,7 +262,6 @@ "cc", "cfg-if", "cfg_aliases", - "compiler_builtins", "cpufeatures", "crc32fast", "crossbeam-channel", @@ -276,7 +281,6 @@ "digest", "displaydoc", "dissimilar", - "dlmalloc", "either", "elsa", "ena", @@ -291,7 +295,6 @@ "fluent-langneg", "fluent-syntax", "fnv", - "fortanix-sgx-abi", "generic-array", "getopts", "getrandom", @@ -354,12 +357,9 @@ "pulldown-cmark-escape", "punycode", "quote", - "r-efi", - "r-efi-alloc", "rand", "rand_chacha", "rand_core", - "rand_xorshift", "rand_xoshiro", "redox_syscall", "regex", @@ -429,7 +429,6 @@ "unicode-security", "unicode-width", "unicode-xid", - "unwinding", "valuable", "version_check", "wasi", @@ -463,6 +462,46 @@ // tidy-alphabetical-end ]; +const PERMITTED_STDLIB_DEPENDENCIES: &[&str] = &[ + // tidy-alphabetical-start + "addr2line", + "adler", + "allocator-api2", + "cc", + "cfg-if", + "compiler_builtins", + "dlmalloc", + "fortanix-sgx-abi", + "getopts", + "gimli", + "hashbrown", + "hermit-abi", + "libc", + "memchr", + "miniz_oxide", + "object", + "r-efi", + "r-efi-alloc", + "rand", + "rand_core", + "rand_xorshift", + "rustc-demangle", + "unicode-width", + "unwinding", + "wasi", + "windows-sys", + "windows-targets", + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", + // tidy-alphabetical-end +]; + const PERMITTED_CRANELIFT_DEPENDENCIES: &[&str] = &[ // tidy-alphabetical-start "ahash", @@ -556,9 +595,8 @@ pub fn check(root: &Path, cargo: &Path, bad: &mut bool) { check_permitted_dependencies(&metadata, workspace, permitted_deps, crates, bad); } - if workspace == "." { - let runtime_ids = compute_runtime_crates(&metadata); - check_runtime_license_exceptions(&metadata, runtime_ids, bad); + if workspace == "library" { + check_runtime_license_exceptions(&metadata, bad); checked_runtime_licenses = true; } } @@ -583,16 +621,8 @@ pub fn has_missing_submodule(root: &Path, submodules: &[&str]) -> bool { /// /// Unlike for tools we don't allow exceptions to the `LICENSES` list for the runtime with the sole /// exception of `fortanix-sgx-abi` which is only used on x86_64-fortanix-unknown-sgx. -fn check_runtime_license_exceptions( - metadata: &Metadata, - runtime_ids: HashSet<&PackageId>, - bad: &mut bool, -) { +fn check_runtime_license_exceptions(metadata: &Metadata, bad: &mut bool) { for pkg in &metadata.packages { - if !runtime_ids.contains(&pkg.id) { - // Only checking dependencies of runtime libraries here. - continue; - } if pkg.source.is_none() { // No need to check local packages. continue; @@ -613,20 +643,6 @@ fn check_runtime_license_exceptions( continue; } - // This exception is due to the fact that the feature set of the - // `object` crate is different between rustc and libstd. In the - // standard library only a conservative set of features are enabled - // which notably does not include the `wasm` feature which pulls in - // this dependency. In the compiler, however, the `wasm` feature is - // enabled. This exception is intended to be here so long as the - // `EXCEPTIONS` above contains `wasmparser`, but once that goes away - // this can be removed. - if pkg.name == "wasmparser" - && pkg.license.as_deref() == Some("Apache-2.0 WITH LLVM-exception") - { - continue; - } - tidy_error!(bad, "invalid license `{}` in `{}`", license, pkg.id); } } @@ -758,16 +774,6 @@ fn pkg_from_id<'a>(metadata: &'a Metadata, id: &PackageId) -> &'a Package { metadata.packages.iter().find(|p| &p.id == id).unwrap() } -/// Finds all the packages that are in the rust runtime. -fn compute_runtime_crates<'a>(metadata: &'a Metadata) -> HashSet<&'a PackageId> { - let mut result = HashSet::new(); - for name in RUNTIME_CRATES { - let id = &pkg_from_name(metadata, name).id; - deps_of(metadata, id, &mut result); - } - result -} - /// Recursively find all dependencies. fn deps_of<'a>(metadata: &'a Metadata, pkg_id: &'a PackageId, result: &mut HashSet<&'a PackageId>) { if !result.insert(pkg_id) { From feeeb5c48ea8cd7a9379091ce3f6f15797cf762f Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 2 Aug 2024 11:34:54 +0000 Subject: [PATCH 15/36] Bless tests --- tests/ui/extern/extern-types-field-offset.run.stderr | 2 +- tests/ui/extern/extern-types-size_of_val.align.run.stderr | 2 +- tests/ui/extern/extern-types-size_of_val.size.run.stderr | 2 +- tests/ui/hygiene/panic-location.run.stderr | 2 +- tests/ui/panics/panic-in-cleanup.run.stderr | 2 +- tests/ui/panics/panic-in-ffi.run.stderr | 2 +- tests/ui/process/println-with-broken-pipe.run.stderr | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/ui/extern/extern-types-field-offset.run.stderr b/tests/ui/extern/extern-types-field-offset.run.stderr index 1b04b860db5..f1407398980 100644 --- a/tests/ui/extern/extern-types-field-offset.run.stderr +++ b/tests/ui/extern/extern-types-field-offset.run.stderr @@ -1,4 +1,4 @@ -thread 'main' panicked at library/core/src/panicking.rs:$LINE:$COL: +thread 'main' panicked at core/src/panicking.rs:$LINE:$COL: attempted to compute the size or alignment of extern type `Opaque` note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace thread caused non-unwinding panic. aborting. diff --git a/tests/ui/extern/extern-types-size_of_val.align.run.stderr b/tests/ui/extern/extern-types-size_of_val.align.run.stderr index 20c4d8785e8..faad1aa13fa 100644 --- a/tests/ui/extern/extern-types-size_of_val.align.run.stderr +++ b/tests/ui/extern/extern-types-size_of_val.align.run.stderr @@ -1,4 +1,4 @@ -thread 'main' panicked at library/core/src/panicking.rs:$LINE:$COL: +thread 'main' panicked at core/src/panicking.rs:$LINE:$COL: attempted to compute the size or alignment of extern type `A` note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace thread caused non-unwinding panic. aborting. diff --git a/tests/ui/extern/extern-types-size_of_val.size.run.stderr b/tests/ui/extern/extern-types-size_of_val.size.run.stderr index 20c4d8785e8..faad1aa13fa 100644 --- a/tests/ui/extern/extern-types-size_of_val.size.run.stderr +++ b/tests/ui/extern/extern-types-size_of_val.size.run.stderr @@ -1,4 +1,4 @@ -thread 'main' panicked at library/core/src/panicking.rs:$LINE:$COL: +thread 'main' panicked at core/src/panicking.rs:$LINE:$COL: attempted to compute the size or alignment of extern type `A` note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace thread caused non-unwinding panic. aborting. diff --git a/tests/ui/hygiene/panic-location.run.stderr b/tests/ui/hygiene/panic-location.run.stderr index 5c1778bc485..bfed4cd6650 100644 --- a/tests/ui/hygiene/panic-location.run.stderr +++ b/tests/ui/hygiene/panic-location.run.stderr @@ -1,3 +1,3 @@ -thread 'main' panicked at library/alloc/src/raw_vec.rs:LL:CC: +thread 'main' panicked at alloc/src/raw_vec.rs:LL:CC: capacity overflow note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace diff --git a/tests/ui/panics/panic-in-cleanup.run.stderr b/tests/ui/panics/panic-in-cleanup.run.stderr index e7def11b0e9..3417d4bf1a3 100644 --- a/tests/ui/panics/panic-in-cleanup.run.stderr +++ b/tests/ui/panics/panic-in-cleanup.run.stderr @@ -4,6 +4,6 @@ note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace thread 'main' panicked at $DIR/panic-in-cleanup.rs:16:9: BOOM stack backtrace: -thread 'main' panicked at library/core/src/panicking.rs:$LINE:$COL: +thread 'main' panicked at core/src/panicking.rs:$LINE:$COL: panic in a destructor during cleanup thread caused non-unwinding panic. aborting. diff --git a/tests/ui/panics/panic-in-ffi.run.stderr b/tests/ui/panics/panic-in-ffi.run.stderr index 596355399c8..fc70847ad9a 100644 --- a/tests/ui/panics/panic-in-ffi.run.stderr +++ b/tests/ui/panics/panic-in-ffi.run.stderr @@ -1,7 +1,7 @@ thread 'main' panicked at $DIR/panic-in-ffi.rs:12:5: Test note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace -thread 'main' panicked at library/core/src/panicking.rs:$LINE:$COL: +thread 'main' panicked at core/src/panicking.rs:$LINE:$COL: panic in a function that cannot unwind stack backtrace: thread caused non-unwinding panic. aborting. diff --git a/tests/ui/process/println-with-broken-pipe.run.stderr b/tests/ui/process/println-with-broken-pipe.run.stderr index a334c0ad204..f9d138a0424 100644 --- a/tests/ui/process/println-with-broken-pipe.run.stderr +++ b/tests/ui/process/println-with-broken-pipe.run.stderr @@ -1,3 +1,3 @@ -thread 'main' panicked at library/std/src/io/stdio.rs:LL:CC: +thread 'main' panicked at std/src/io/stdio.rs:LL:CC: failed printing to stdout: Broken pipe (os error 32) note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace From f850e37119eac6489ae6d9983631f2c702a4887f Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 2 Aug 2024 09:46:10 -0400 Subject: [PATCH 16/36] Check divergence value first before doing span operations in warn_if_unreachable --- .../rustc_hir_typeck/src/fn_ctxt/_impl.rs | 38 +++++++++---------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index 40d9a2985da..8c1aa66332f 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -48,29 +48,29 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Produces warning on the given node, if the current point in the /// function is unreachable, and there hasn't been another warning. pub(crate) fn warn_if_unreachable(&self, id: HirId, span: Span, kind: &str) { - // If span arose from a desugaring of `if` or `while`, then it is the condition itself, - // which diverges, that we are about to lint on. This gives suboptimal diagnostics. - // Instead, stop here so that the `if`- or `while`-expression's block is linted instead. - if span.is_desugaring(DesugaringKind::CondTemporary) { - return; - } - - // Don't lint if the result of an async block or async function is `!`. - // This does not affect the unreachable lints *within* the body. - if span.is_desugaring(DesugaringKind::Async) { - return; - } - - // Don't lint *within* the `.await` operator, since that's all just desugaring junk. - // We only want to lint if there is a subsequent expression after the `.await`. - if span.is_desugaring(DesugaringKind::Await) { - return; - } - let Diverges::Always { span: orig_span, custom_note } = self.diverges.get() else { return; }; + match span.desugaring_kind() { + // If span arose from a desugaring of `if` or `while`, then it is the condition + // itself, which diverges, that we are about to lint on. This gives suboptimal + // diagnostics. Instead, stop here so that the `if`- or `while`-expression's + // block is linted instead. + Some(DesugaringKind::CondTemporary) => return, + + // Don't lint if the result of an async block or async function is `!`. + // This does not affect the unreachable lints *within* the body. + Some(DesugaringKind::Async) => return, + + // Don't lint *within* the `.await` operator, since that's all just desugaring + // junk. We only want to lint if there is a subsequent expression after the + // `.await` operator. + Some(DesugaringKind::Await) => return, + + _ => {} + } + // Don't warn twice. self.diverges.set(Diverges::WarnedAlways); From 7dd5ad282c4aab165236c8ba9404929d7dd337ac Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Thu, 1 Aug 2024 22:54:22 -0700 Subject: [PATCH 17/36] rustdoc: Extract helper function to add item to search index --- src/librustdoc/formats/cache.rs | 272 ++++++++++++++++---------------- 1 file changed, 135 insertions(+), 137 deletions(-) diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs index 9f284486616..8c0ed6cddf0 100644 --- a/src/librustdoc/formats/cache.rs +++ b/src/librustdoc/formats/cache.rs @@ -260,7 +260,7 @@ fn is_from_private_dep(tcx: TyCtxt<'_>, cache: &Cache, def_id: DefId) -> bool { } // Index this method for searching later on. - if let Some(s) = item.name.or_else(|| { + if let Some(name) = item.name.or_else(|| { if item.is_stripped() { None } else if let clean::ImportItem(ref i) = *item.kind @@ -271,142 +271,7 @@ fn is_from_private_dep(tcx: TyCtxt<'_>, cache: &Cache, def_id: DefId) -> bool { None } }) { - let (parent, is_inherent_impl_item) = match *item.kind { - clean::StrippedItem(..) => ((None, None), false), - clean::AssocConstItem(..) | clean::AssocTypeItem(..) - if self - .cache - .parent_stack - .last() - .is_some_and(|parent| parent.is_trait_impl()) => - { - // skip associated items in trait impls - ((None, None), false) - } - clean::TyMethodItem(..) - | clean::TyAssocConstItem(..) - | clean::TyAssocTypeItem(..) - | clean::StructFieldItem(..) - | clean::VariantItem(..) => ( - ( - Some( - self.cache - .parent_stack - .last() - .expect("parent_stack is empty") - .item_id() - .expect_def_id(), - ), - Some(&self.cache.stack[..self.cache.stack.len() - 1]), - ), - false, - ), - clean::MethodItem(..) | clean::AssocConstItem(..) | clean::AssocTypeItem(..) => { - if self.cache.parent_stack.is_empty() { - ((None, None), false) - } else { - let last = self.cache.parent_stack.last().expect("parent_stack is empty 2"); - let did = match &*last { - ParentStackItem::Impl { - // impl Trait for &T { fn method(self); } - // - // When generating a function index with the above shape, we want it - // associated with `T`, not with the primitive reference type. It should - // show up as `T::method`, rather than `reference::method`, in the search - // results page. - for_: clean::Type::BorrowedRef { type_, .. }, - .. - } => type_.def_id(&self.cache), - ParentStackItem::Impl { for_, .. } => for_.def_id(&self.cache), - ParentStackItem::Type(item_id) => item_id.as_def_id(), - }; - let path = did - .and_then(|did| self.cache.paths.get(&did)) - // The current stack not necessarily has correlation - // for where the type was defined. On the other - // hand, `paths` always has the right - // information if present. - .map(|(fqp, _)| &fqp[..fqp.len() - 1]); - ((did, path), true) - } - } - _ => ((None, Some(&*self.cache.stack)), false), - }; - - match parent { - (parent, Some(path)) if is_inherent_impl_item || !self.cache.stripped_mod => { - debug_assert!(!item.is_stripped()); - - // A crate has a module at its root, containing all items, - // which should not be indexed. The crate-item itself is - // inserted later on when serializing the search-index. - if item.item_id.as_def_id().is_some_and(|idx| !idx.is_crate_root()) - && let ty = item.type_() - && (ty != ItemType::StructField - || u16::from_str_radix(s.as_str(), 10).is_err()) - { - let desc = - short_markdown_summary(&item.doc_value(), &item.link_names(self.cache)); - // For searching purposes, a re-export is a duplicate if: - // - // - It's either an inline, or a true re-export - // - It's got the same name - // - Both of them have the same exact path - let defid = (match &*item.kind { - &clean::ItemKind::ImportItem(ref import) => import.source.did, - _ => None, - }) - .or_else(|| item.item_id.as_def_id()); - // In case this is a field from a tuple struct, we don't add it into - // the search index because its name is something like "0", which is - // not useful for rustdoc search. - self.cache.search_index.push(IndexItem { - ty, - defid, - name: s, - path: join_with_double_colon(path), - desc, - parent, - parent_idx: None, - exact_path: None, - impl_id: if let Some(ParentStackItem::Impl { item_id, .. }) = - self.cache.parent_stack.last() - { - item_id.as_def_id() - } else { - None - }, - search_type: get_function_type_for_search( - &item, - self.tcx, - clean_impl_generics(self.cache.parent_stack.last()).as_ref(), - parent, - self.cache, - ), - aliases: item.attrs.get_doc_aliases(), - deprecation: item.deprecation(self.tcx), - }); - } - } - (Some(parent), None) if is_inherent_impl_item => { - // We have a parent, but we don't know where they're - // defined yet. Wait for later to index this item. - let impl_generics = clean_impl_generics(self.cache.parent_stack.last()); - self.cache.orphan_impl_items.push(OrphanImplItem { - parent, - item: item.clone(), - impl_generics, - impl_id: if let Some(ParentStackItem::Impl { item_id, .. }) = - self.cache.parent_stack.last() - { - item_id.as_def_id() - } else { - None - }, - }); - } - _ => {} - } + add_item_to_search_index(self.tcx, &mut self.cache, &item, name) } // Keep track of the fully qualified path for this item. @@ -573,6 +438,139 @@ fn is_from_private_dep(tcx: TyCtxt<'_>, cache: &Cache, def_id: DefId) -> bool { } } +fn add_item_to_search_index(tcx: TyCtxt<'_>, cache: &mut Cache, item: &clean::Item, name: Symbol) { + let (parent, is_inherent_impl_item) = match *item.kind { + clean::StrippedItem(..) => ((None, None), false), + clean::AssocConstItem(..) | clean::AssocTypeItem(..) + if cache.parent_stack.last().is_some_and(|parent| parent.is_trait_impl()) => + { + // skip associated items in trait impls + ((None, None), false) + } + clean::TyMethodItem(..) + | clean::TyAssocConstItem(..) + | clean::TyAssocTypeItem(..) + | clean::StructFieldItem(..) + | clean::VariantItem(..) => ( + ( + Some( + cache + .parent_stack + .last() + .expect("parent_stack is empty") + .item_id() + .expect_def_id(), + ), + Some(&cache.stack[..cache.stack.len() - 1]), + ), + false, + ), + clean::MethodItem(..) | clean::AssocConstItem(..) | clean::AssocTypeItem(..) => { + if cache.parent_stack.is_empty() { + ((None, None), false) + } else { + let last = cache.parent_stack.last().expect("parent_stack is empty 2"); + let did = match &*last { + ParentStackItem::Impl { + // impl Trait for &T { fn method(self); } + // + // When generating a function index with the above shape, we want it + // associated with `T`, not with the primitive reference type. It should + // show up as `T::method`, rather than `reference::method`, in the search + // results page. + for_: clean::Type::BorrowedRef { type_, .. }, + .. + } => type_.def_id(&cache), + ParentStackItem::Impl { for_, .. } => for_.def_id(&cache), + ParentStackItem::Type(item_id) => item_id.as_def_id(), + }; + let path = did + .and_then(|did| cache.paths.get(&did)) + // The current stack not necessarily has correlation + // for where the type was defined. On the other + // hand, `paths` always has the right + // information if present. + .map(|(fqp, _)| &fqp[..fqp.len() - 1]); + ((did, path), true) + } + } + _ => ((None, Some(&*cache.stack)), false), + }; + + match parent { + (parent, Some(path)) if is_inherent_impl_item || !cache.stripped_mod => { + debug_assert!(!item.is_stripped()); + + // A crate has a module at its root, containing all items, + // which should not be indexed. The crate-item itself is + // inserted later on when serializing the search-index. + if item.item_id.as_def_id().is_some_and(|idx| !idx.is_crate_root()) + && let ty = item.type_() + && (ty != ItemType::StructField || u16::from_str_radix(name.as_str(), 10).is_err()) + { + let desc = short_markdown_summary(&item.doc_value(), &item.link_names(cache)); + // For searching purposes, a re-export is a duplicate if: + // + // - It's either an inline, or a true re-export + // - It's got the same name + // - Both of them have the same exact path + let defid = (match &*item.kind { + &clean::ItemKind::ImportItem(ref import) => import.source.did, + _ => None, + }) + .or_else(|| item.item_id.as_def_id()); + // In case this is a field from a tuple struct, we don't add it into + // the search index because its name is something like "0", which is + // not useful for rustdoc search. + cache.search_index.push(IndexItem { + ty, + defid, + name, + path: join_with_double_colon(path), + desc, + parent, + parent_idx: None, + exact_path: None, + impl_id: if let Some(ParentStackItem::Impl { item_id, .. }) = + cache.parent_stack.last() + { + item_id.as_def_id() + } else { + None + }, + search_type: get_function_type_for_search( + &item, + tcx, + clean_impl_generics(cache.parent_stack.last()).as_ref(), + parent, + cache, + ), + aliases: item.attrs.get_doc_aliases(), + deprecation: item.deprecation(tcx), + }); + } + } + (Some(parent), None) if is_inherent_impl_item => { + // We have a parent, but we don't know where they're + // defined yet. Wait for later to index this item. + let impl_generics = clean_impl_generics(cache.parent_stack.last()); + cache.orphan_impl_items.push(OrphanImplItem { + parent, + item: item.clone(), + impl_generics, + impl_id: if let Some(ParentStackItem::Impl { item_id, .. }) = + cache.parent_stack.last() + { + item_id.as_def_id() + } else { + None + }, + }); + } + _ => {} + } +} + pub(crate) struct OrphanImplItem { pub(crate) parent: DefId, pub(crate) impl_id: Option, From 2721e97c5d9a4e5a001461e499a751e81e10df4c Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Thu, 1 Aug 2024 23:20:20 -0700 Subject: [PATCH 18/36] rustdoc: Clarify construction of name for search index --- src/librustdoc/formats/cache.rs | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs index 8c0ed6cddf0..13b91f483eb 100644 --- a/src/librustdoc/formats/cache.rs +++ b/src/librustdoc/formats/cache.rs @@ -260,17 +260,20 @@ fn is_from_private_dep(tcx: TyCtxt<'_>, cache: &Cache, def_id: DefId) -> bool { } // Index this method for searching later on. - if let Some(name) = item.name.or_else(|| { - if item.is_stripped() { - None - } else if let clean::ImportItem(ref i) = *item.kind - && let clean::ImportKind::Simple(s) = i.kind - { - Some(s) - } else { - None - } - }) { + let search_name = if !item.is_stripped() { + item.name.or_else(|| { + if let clean::ImportItem(ref i) = *item.kind + && let clean::ImportKind::Simple(s) = i.kind + { + Some(s) + } else { + None + } + }) + } else { + None + }; + if let Some(name) = search_name { add_item_to_search_index(self.tcx, &mut self.cache, &item, name) } From 4e2084769b8e6de0dd43453315b7466305e9d312 Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Thu, 1 Aug 2024 23:33:42 -0700 Subject: [PATCH 19/36] rustdoc: Simplify some search index code --- src/librustdoc/clean/types.rs | 20 +++++------ src/librustdoc/formats/cache.rs | 60 +++++++++++++++------------------ 2 files changed, 36 insertions(+), 44 deletions(-) diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 1ec5f38b6ec..cf01ffb2e75 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -1680,13 +1680,16 @@ pub(crate) fn projection(&self) -> Option<(&Type, DefId, PathSegment)> { } } - fn inner_def_id(&self, cache: Option<&Cache>) -> Option { + /// Use this method to get the [DefId] of a [clean] AST node, including [PrimitiveType]s. + /// + /// [clean]: crate::clean + pub(crate) fn def_id(&self, cache: &Cache) -> Option { let t: PrimitiveType = match *self { Type::Path { ref path } => return Some(path.def_id()), DynTrait(ref bounds, _) => return bounds.get(0).map(|b| b.trait_.def_id()), - Primitive(p) => return cache.and_then(|c| c.primitive_locations.get(&p).cloned()), + Primitive(p) => return cache.primitive_locations.get(&p).cloned(), BorrowedRef { type_: box Generic(..), .. } => PrimitiveType::Reference, - BorrowedRef { ref type_, .. } => return type_.inner_def_id(cache), + BorrowedRef { ref type_, .. } => return type_.def_id(cache), Tuple(ref tys) => { if tys.is_empty() { PrimitiveType::Unit @@ -1699,17 +1702,10 @@ fn inner_def_id(&self, cache: Option<&Cache>) -> Option { Array(..) => PrimitiveType::Array, Type::Pat(..) => PrimitiveType::Pat, RawPointer(..) => PrimitiveType::RawPointer, - QPath(box QPathData { ref self_type, .. }) => return self_type.inner_def_id(cache), + QPath(box QPathData { ref self_type, .. }) => return self_type.def_id(cache), Generic(_) | Infer | ImplTrait(_) => return None, }; - cache.and_then(|c| Primitive(t).def_id(c)) - } - - /// Use this method to get the [DefId] of a [clean] AST node, including [PrimitiveType]s. - /// - /// [clean]: crate::clean - pub(crate) fn def_id(&self, cache: &Cache) -> Option { - self.inner_def_id(Some(cache)) + Primitive(t).def_id(cache) } } diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs index 13b91f483eb..0788543d89a 100644 --- a/src/librustdoc/formats/cache.rs +++ b/src/librustdoc/formats/cache.rs @@ -442,13 +442,13 @@ fn is_from_private_dep(tcx: TyCtxt<'_>, cache: &Cache, def_id: DefId) -> bool { } fn add_item_to_search_index(tcx: TyCtxt<'_>, cache: &mut Cache, item: &clean::Item, name: Symbol) { - let (parent, is_inherent_impl_item) = match *item.kind { - clean::StrippedItem(..) => ((None, None), false), + let (parent, is_impl_child) = match *item.kind { + clean::StrippedItem(..) => return, clean::AssocConstItem(..) | clean::AssocTypeItem(..) if cache.parent_stack.last().is_some_and(|parent| parent.is_trait_impl()) => { // skip associated items in trait impls - ((None, None), false) + return; } clean::TyMethodItem(..) | clean::TyAssocConstItem(..) @@ -469,39 +469,35 @@ fn add_item_to_search_index(tcx: TyCtxt<'_>, cache: &mut Cache, item: &clean::It false, ), clean::MethodItem(..) | clean::AssocConstItem(..) | clean::AssocTypeItem(..) => { - if cache.parent_stack.is_empty() { - ((None, None), false) - } else { - let last = cache.parent_stack.last().expect("parent_stack is empty 2"); - let did = match &*last { - ParentStackItem::Impl { - // impl Trait for &T { fn method(self); } - // - // When generating a function index with the above shape, we want it - // associated with `T`, not with the primitive reference type. It should - // show up as `T::method`, rather than `reference::method`, in the search - // results page. - for_: clean::Type::BorrowedRef { type_, .. }, - .. - } => type_.def_id(&cache), - ParentStackItem::Impl { for_, .. } => for_.def_id(&cache), - ParentStackItem::Type(item_id) => item_id.as_def_id(), - }; - let path = did - .and_then(|did| cache.paths.get(&did)) - // The current stack not necessarily has correlation - // for where the type was defined. On the other - // hand, `paths` always has the right - // information if present. - .map(|(fqp, _)| &fqp[..fqp.len() - 1]); - ((did, path), true) - } + let last = cache.parent_stack.last().expect("parent_stack is empty 2"); + let did = match &*last { + ParentStackItem::Impl { + // impl Trait for &T { fn method(self); } + // + // When generating a function index with the above shape, we want it + // associated with `T`, not with the primitive reference type. It should + // show up as `T::method`, rather than `reference::method`, in the search + // results page. + for_: clean::Type::BorrowedRef { type_, .. }, + .. + } => type_.def_id(&cache), + ParentStackItem::Impl { for_, .. } => for_.def_id(&cache), + ParentStackItem::Type(item_id) => item_id.as_def_id(), + }; + let path = did + .and_then(|did| cache.paths.get(&did)) + // The current stack not necessarily has correlation + // for where the type was defined. On the other + // hand, `paths` always has the right + // information if present. + .map(|(fqp, _)| &fqp[..fqp.len() - 1]); + ((did, path), true) } _ => ((None, Some(&*cache.stack)), false), }; match parent { - (parent, Some(path)) if is_inherent_impl_item || !cache.stripped_mod => { + (parent, Some(path)) if is_impl_child || !cache.stripped_mod => { debug_assert!(!item.is_stripped()); // A crate has a module at its root, containing all items, @@ -553,7 +549,7 @@ fn add_item_to_search_index(tcx: TyCtxt<'_>, cache: &mut Cache, item: &clean::It }); } } - (Some(parent), None) if is_inherent_impl_item => { + (Some(parent), None) if is_impl_child => { // We have a parent, but we don't know where they're // defined yet. Wait for later to index this item. let impl_generics = clean_impl_generics(cache.parent_stack.last()); From 015aa8d0fba2247da33967a93fad9a2bea16037f Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Fri, 2 Aug 2024 12:58:59 -0700 Subject: [PATCH 20/36] Restructure a confusing `match` --- src/librustdoc/formats/cache.rs | 124 ++++++++++++++++---------------- 1 file changed, 62 insertions(+), 62 deletions(-) diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs index 0788543d89a..5c18cebb965 100644 --- a/src/librustdoc/formats/cache.rs +++ b/src/librustdoc/formats/cache.rs @@ -442,7 +442,7 @@ fn is_from_private_dep(tcx: TyCtxt<'_>, cache: &Cache, def_id: DefId) -> bool { } fn add_item_to_search_index(tcx: TyCtxt<'_>, cache: &mut Cache, item: &clean::Item, name: Symbol) { - let (parent, is_impl_child) = match *item.kind { + let ((parent_did, parent_path), is_impl_child) = match *item.kind { clean::StrippedItem(..) => return, clean::AssocConstItem(..) | clean::AssocTypeItem(..) if cache.parent_stack.last().is_some_and(|parent| parent.is_trait_impl()) => @@ -496,67 +496,59 @@ fn add_item_to_search_index(tcx: TyCtxt<'_>, cache: &mut Cache, item: &clean::It _ => ((None, Some(&*cache.stack)), false), }; - match parent { - (parent, Some(path)) if is_impl_child || !cache.stripped_mod => { - debug_assert!(!item.is_stripped()); - - // A crate has a module at its root, containing all items, - // which should not be indexed. The crate-item itself is - // inserted later on when serializing the search-index. - if item.item_id.as_def_id().is_some_and(|idx| !idx.is_crate_root()) - && let ty = item.type_() - && (ty != ItemType::StructField || u16::from_str_radix(name.as_str(), 10).is_err()) + if let Some(parent_did) = parent_did + && parent_path.is_none() + && is_impl_child + { + // We have a parent, but we don't know where they're + // defined yet. Wait for later to index this item. + let impl_generics = clean_impl_generics(cache.parent_stack.last()); + cache.orphan_impl_items.push(OrphanImplItem { + parent: parent_did, + item: item.clone(), + impl_generics, + impl_id: if let Some(ParentStackItem::Impl { item_id, .. }) = cache.parent_stack.last() { - let desc = short_markdown_summary(&item.doc_value(), &item.link_names(cache)); - // For searching purposes, a re-export is a duplicate if: - // - // - It's either an inline, or a true re-export - // - It's got the same name - // - Both of them have the same exact path - let defid = (match &*item.kind { - &clean::ItemKind::ImportItem(ref import) => import.source.did, - _ => None, - }) - .or_else(|| item.item_id.as_def_id()); - // In case this is a field from a tuple struct, we don't add it into - // the search index because its name is something like "0", which is - // not useful for rustdoc search. - cache.search_index.push(IndexItem { - ty, - defid, - name, - path: join_with_double_colon(path), - desc, - parent, - parent_idx: None, - exact_path: None, - impl_id: if let Some(ParentStackItem::Impl { item_id, .. }) = - cache.parent_stack.last() - { - item_id.as_def_id() - } else { - None - }, - search_type: get_function_type_for_search( - &item, - tcx, - clean_impl_generics(cache.parent_stack.last()).as_ref(), - parent, - cache, - ), - aliases: item.attrs.get_doc_aliases(), - deprecation: item.deprecation(tcx), - }); - } - } - (Some(parent), None) if is_impl_child => { - // We have a parent, but we don't know where they're - // defined yet. Wait for later to index this item. - let impl_generics = clean_impl_generics(cache.parent_stack.last()); - cache.orphan_impl_items.push(OrphanImplItem { - parent, - item: item.clone(), - impl_generics, + item_id.as_def_id() + } else { + None + }, + }); + } else if let Some(path) = parent_path + && (is_impl_child || !cache.stripped_mod) + { + debug_assert!(!item.is_stripped()); + + // A crate has a module at its root, containing all items, + // which should not be indexed. The crate-item itself is + // inserted later on when serializing the search-index. + if item.item_id.as_def_id().is_some_and(|idx| !idx.is_crate_root()) + && let ty = item.type_() + && (ty != ItemType::StructField || u16::from_str_radix(name.as_str(), 10).is_err()) + { + let desc = short_markdown_summary(&item.doc_value(), &item.link_names(cache)); + // For searching purposes, a re-export is a duplicate if: + // + // - It's either an inline, or a true re-export + // - It's got the same name + // - Both of them have the same exact path + let defid = (match &*item.kind { + &clean::ItemKind::ImportItem(ref import) => import.source.did, + _ => None, + }) + .or_else(|| item.item_id.as_def_id()); + // In case this is a field from a tuple struct, we don't add it into + // the search index because its name is something like "0", which is + // not useful for rustdoc search. + cache.search_index.push(IndexItem { + ty, + defid, + name, + path: join_with_double_colon(path), + desc, + parent: parent_did, + parent_idx: None, + exact_path: None, impl_id: if let Some(ParentStackItem::Impl { item_id, .. }) = cache.parent_stack.last() { @@ -564,9 +556,17 @@ fn add_item_to_search_index(tcx: TyCtxt<'_>, cache: &mut Cache, item: &clean::It } else { None }, + search_type: get_function_type_for_search( + &item, + tcx, + clean_impl_generics(cache.parent_stack.last()).as_ref(), + parent_did, + cache, + ), + aliases: item.attrs.get_doc_aliases(), + deprecation: item.deprecation(tcx), }); } - _ => {} } } From 08f4d54ea91b1092161e9bb77b5b6aa3f9d48714 Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Fri, 2 Aug 2024 14:01:38 -0700 Subject: [PATCH 21/36] Extract local variables --- src/librustdoc/formats/cache.rs | 63 +++++++++++++++++---------------- 1 file changed, 33 insertions(+), 30 deletions(-) diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs index 5c18cebb965..effdce54015 100644 --- a/src/librustdoc/formats/cache.rs +++ b/src/librustdoc/formats/cache.rs @@ -503,17 +503,15 @@ fn add_item_to_search_index(tcx: TyCtxt<'_>, cache: &mut Cache, item: &clean::It // We have a parent, but we don't know where they're // defined yet. Wait for later to index this item. let impl_generics = clean_impl_generics(cache.parent_stack.last()); - cache.orphan_impl_items.push(OrphanImplItem { - parent: parent_did, - item: item.clone(), - impl_generics, - impl_id: if let Some(ParentStackItem::Impl { item_id, .. }) = cache.parent_stack.last() - { - item_id.as_def_id() - } else { - None - }, - }); + let impl_id = if let Some(ParentStackItem::Impl { item_id, .. }) = cache.parent_stack.last() + { + item_id.as_def_id() + } else { + None + }; + let orphan_item = + OrphanImplItem { parent: parent_did, item: item.clone(), impl_generics, impl_id }; + cache.orphan_impl_items.push(orphan_item); } else if let Some(path) = parent_path && (is_impl_child || !cache.stripped_mod) { @@ -540,32 +538,37 @@ fn add_item_to_search_index(tcx: TyCtxt<'_>, cache: &mut Cache, item: &clean::It // In case this is a field from a tuple struct, we don't add it into // the search index because its name is something like "0", which is // not useful for rustdoc search. - cache.search_index.push(IndexItem { + let path = join_with_double_colon(path); + let impl_id = + if let Some(ParentStackItem::Impl { item_id, .. }) = cache.parent_stack.last() { + item_id.as_def_id() + } else { + None + }; + let search_type = get_function_type_for_search( + &item, + tcx, + clean_impl_generics(cache.parent_stack.last()).as_ref(), + parent_did, + cache, + ); + let aliases = item.attrs.get_doc_aliases(); + let deprecation = item.deprecation(tcx); + let index_item = IndexItem { ty, defid, name, - path: join_with_double_colon(path), + path, desc, parent: parent_did, parent_idx: None, exact_path: None, - impl_id: if let Some(ParentStackItem::Impl { item_id, .. }) = - cache.parent_stack.last() - { - item_id.as_def_id() - } else { - None - }, - search_type: get_function_type_for_search( - &item, - tcx, - clean_impl_generics(cache.parent_stack.last()).as_ref(), - parent_did, - cache, - ), - aliases: item.attrs.get_doc_aliases(), - deprecation: item.deprecation(tcx), - }); + impl_id, + search_type, + aliases, + deprecation, + }; + cache.search_index.push(index_item); } } } From 220c2d8c9bc07d0a7b81104edb14f892e0a5f0aa Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Fri, 2 Aug 2024 14:48:36 -0700 Subject: [PATCH 22/36] Restructure `add_item_to_search_index` to eliminate code paths Many of the code paths it handled were actually impossible. In other cases, the various checks and transformations were spread around in such a way that it was hard to tell what was going on. --- src/librustdoc/formats/cache.rs | 211 +++++++++++++++----------------- 1 file changed, 102 insertions(+), 109 deletions(-) diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs index effdce54015..d2d0f5a4380 100644 --- a/src/librustdoc/formats/cache.rs +++ b/src/librustdoc/formats/cache.rs @@ -442,7 +442,9 @@ fn is_from_private_dep(tcx: TyCtxt<'_>, cache: &Cache, def_id: DefId) -> bool { } fn add_item_to_search_index(tcx: TyCtxt<'_>, cache: &mut Cache, item: &clean::Item, name: Symbol) { - let ((parent_did, parent_path), is_impl_child) = match *item.kind { + // Item has a name, so it must also have a DefId (can't be an impl, let alone a blanket or auto impl). + let item_def_id = item.item_id.as_def_id().unwrap(); + let (parent_did, parent_path) = match *item.kind { clean::StrippedItem(..) => return, clean::AssocConstItem(..) | clean::AssocTypeItem(..) if cache.parent_stack.last().is_some_and(|parent| parent.is_trait_impl()) => @@ -454,123 +456,114 @@ fn add_item_to_search_index(tcx: TyCtxt<'_>, cache: &mut Cache, item: &clean::It | clean::TyAssocConstItem(..) | clean::TyAssocTypeItem(..) | clean::StructFieldItem(..) - | clean::VariantItem(..) => ( - ( - Some( - cache - .parent_stack - .last() - .expect("parent_stack is empty") - .item_id() - .expect_def_id(), - ), - Some(&cache.stack[..cache.stack.len() - 1]), - ), - false, - ), + | clean::VariantItem(..) => { + // Don't index if containing module is stripped (i.e., private), + // or if item is tuple struct/variant field (name is a number -> not useful for search). + if cache.stripped_mod + || item.type_() == ItemType::StructField + && name.as_str().chars().all(|c| c.is_digit(10)) + { + return; + } + let parent_did = + cache.parent_stack.last().expect("parent_stack is empty").item_id().expect_def_id(); + let parent_path = &cache.stack[..cache.stack.len() - 1]; + (Some(parent_did), parent_path) + } clean::MethodItem(..) | clean::AssocConstItem(..) | clean::AssocTypeItem(..) => { let last = cache.parent_stack.last().expect("parent_stack is empty 2"); - let did = match &*last { - ParentStackItem::Impl { - // impl Trait for &T { fn method(self); } - // - // When generating a function index with the above shape, we want it - // associated with `T`, not with the primitive reference type. It should - // show up as `T::method`, rather than `reference::method`, in the search - // results page. - for_: clean::Type::BorrowedRef { type_, .. }, - .. - } => type_.def_id(&cache), + let parent_did = match &*last { + // impl Trait for &T { fn method(self); } + // + // When generating a function index with the above shape, we want it + // associated with `T`, not with the primitive reference type. It should + // show up as `T::method`, rather than `reference::method`, in the search + // results page. + ParentStackItem::Impl { for_: clean::Type::BorrowedRef { type_, .. }, .. } => { + type_.def_id(&cache) + } ParentStackItem::Impl { for_, .. } => for_.def_id(&cache), ParentStackItem::Type(item_id) => item_id.as_def_id(), }; - let path = did - .and_then(|did| cache.paths.get(&did)) - // The current stack not necessarily has correlation - // for where the type was defined. On the other - // hand, `paths` always has the right - // information if present. - .map(|(fqp, _)| &fqp[..fqp.len() - 1]); - ((did, path), true) + let Some(parent_did) = parent_did else { return }; + // The current stack not necessarily has correlation + // for where the type was defined. On the other + // hand, `paths` always has the right + // information if present. + match cache.paths.get(&parent_did) { + Some((fqp, _)) => (Some(parent_did), &fqp[..fqp.len() - 1]), + None => { + handle_orphan_impl_child(cache, item, parent_did); + return; + } + } + } + _ => { + // Don't index if item is crate root, which is inserted later on when serializing the index. + if item_def_id.is_crate_root() { + return; + } + (None, &*cache.stack) } - _ => ((None, Some(&*cache.stack)), false), }; - if let Some(parent_did) = parent_did - && parent_path.is_none() - && is_impl_child - { - // We have a parent, but we don't know where they're - // defined yet. Wait for later to index this item. - let impl_generics = clean_impl_generics(cache.parent_stack.last()); - let impl_id = if let Some(ParentStackItem::Impl { item_id, .. }) = cache.parent_stack.last() - { - item_id.as_def_id() - } else { - None - }; - let orphan_item = - OrphanImplItem { parent: parent_did, item: item.clone(), impl_generics, impl_id }; - cache.orphan_impl_items.push(orphan_item); - } else if let Some(path) = parent_path - && (is_impl_child || !cache.stripped_mod) - { - debug_assert!(!item.is_stripped()); + debug_assert!(!item.is_stripped()); - // A crate has a module at its root, containing all items, - // which should not be indexed. The crate-item itself is - // inserted later on when serializing the search-index. - if item.item_id.as_def_id().is_some_and(|idx| !idx.is_crate_root()) - && let ty = item.type_() - && (ty != ItemType::StructField || u16::from_str_radix(name.as_str(), 10).is_err()) - { - let desc = short_markdown_summary(&item.doc_value(), &item.link_names(cache)); - // For searching purposes, a re-export is a duplicate if: - // - // - It's either an inline, or a true re-export - // - It's got the same name - // - Both of them have the same exact path - let defid = (match &*item.kind { - &clean::ItemKind::ImportItem(ref import) => import.source.did, - _ => None, - }) - .or_else(|| item.item_id.as_def_id()); - // In case this is a field from a tuple struct, we don't add it into - // the search index because its name is something like "0", which is - // not useful for rustdoc search. - let path = join_with_double_colon(path); - let impl_id = - if let Some(ParentStackItem::Impl { item_id, .. }) = cache.parent_stack.last() { - item_id.as_def_id() - } else { - None - }; - let search_type = get_function_type_for_search( - &item, - tcx, - clean_impl_generics(cache.parent_stack.last()).as_ref(), - parent_did, - cache, - ); - let aliases = item.attrs.get_doc_aliases(); - let deprecation = item.deprecation(tcx); - let index_item = IndexItem { - ty, - defid, - name, - path, - desc, - parent: parent_did, - parent_idx: None, - exact_path: None, - impl_id, - search_type, - aliases, - deprecation, - }; - cache.search_index.push(index_item); - } - } + let desc = short_markdown_summary(&item.doc_value(), &item.link_names(cache)); + // For searching purposes, a re-export is a duplicate if: + // + // - It's either an inline, or a true re-export + // - It's got the same name + // - Both of them have the same exact path + let defid = match &*item.kind { + clean::ItemKind::ImportItem(import) => import.source.did.unwrap_or(item_def_id), + _ => item_def_id, + }; + let path = join_with_double_colon(parent_path); + let impl_id = if let Some(ParentStackItem::Impl { item_id, .. }) = cache.parent_stack.last() { + item_id.as_def_id() + } else { + None + }; + let search_type = get_function_type_for_search( + &item, + tcx, + clean_impl_generics(cache.parent_stack.last()).as_ref(), + parent_did, + cache, + ); + let aliases = item.attrs.get_doc_aliases(); + let deprecation = item.deprecation(tcx); + let index_item = IndexItem { + ty: item.type_(), + defid: Some(defid), + name, + path, + desc, + parent: parent_did, + parent_idx: None, + exact_path: None, + impl_id, + search_type, + aliases, + deprecation, + }; + cache.search_index.push(index_item); +} + +/// We have a parent, but we don't know where they're +/// defined yet. Wait for later to index this item. +/// See [`Cache::orphan_impl_items`]. +fn handle_orphan_impl_child(cache: &mut Cache, item: &clean::Item, parent_did: DefId) { + let impl_generics = clean_impl_generics(cache.parent_stack.last()); + let impl_id = if let Some(ParentStackItem::Impl { item_id, .. }) = cache.parent_stack.last() { + item_id.as_def_id() + } else { + None + }; + let orphan_item = + OrphanImplItem { parent: parent_did, item: item.clone(), impl_generics, impl_id }; + cache.orphan_impl_items.push(orphan_item); } pub(crate) struct OrphanImplItem { From 5ce554f4ecaffe1161eaecc9111a06da3a95cc12 Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Sat, 3 Aug 2024 09:31:21 +0300 Subject: [PATCH 23/36] allow setting `link-shared` and `static-libstdcpp` with CI LLVM These options also affect `compiler/rustc_llvm` builds. They should be configurable even when using CI LLVM. Signed-off-by: onur-ozkan --- src/bootstrap/src/core/config/config.rs | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index 1343e257efe..39a17754c4f 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -1840,6 +1840,23 @@ fn get_table(option: &str) -> Result { config.llvm_from_ci = config.parse_download_ci_llvm(download_ci_llvm, asserts); if config.llvm_from_ci { + let warn = |option: &str| { + println!( + "WARNING: `{option}` will only be used on `compiler/rustc_llvm` build, not for the LLVM build." + ); + println!( + "HELP: To use `{option}` for LLVM builds, set `download-ci-llvm` option to false." + ); + }; + + if static_libstdcpp.is_some() { + warn("static-libstdcpp"); + } + + if link_shared.is_some() { + warn("link-shared"); + } + // None of the LLVM options, except assertions, are supported // when using downloaded LLVM. We could just ignore these but // that's potentially confusing, so force them to not be @@ -1849,9 +1866,6 @@ fn get_table(option: &str) -> Result { check_ci_llvm!(optimize_toml); check_ci_llvm!(thin_lto); check_ci_llvm!(release_debuginfo); - // CI-built LLVM can be either dynamic or static. We won't know until we download it. - check_ci_llvm!(link_shared); - check_ci_llvm!(static_libstdcpp); check_ci_llvm!(targets); check_ci_llvm!(experimental_targets); check_ci_llvm!(clang_cl); From 21c02517c31e90ec1c001f3997abcea2caa36f0c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 2 Aug 2024 10:29:52 +0200 Subject: [PATCH 24/36] Miri: add a flag to do recursive validity checking --- .../src/const_eval/eval_queries.rs | 2 +- .../rustc_const_eval/src/interpret/machine.rs | 7 + .../rustc_const_eval/src/interpret/memory.rs | 5 +- .../rustc_const_eval/src/interpret/place.rs | 15 +- .../src/interpret/validity.rs | 176 +++++++++++------- .../src/util/check_validity_requirement.rs | 2 +- src/tools/miri/README.md | 2 + src/tools/miri/src/bin/miri.rs | 6 +- src/tools/miri/src/eval.rs | 16 +- src/tools/miri/src/intrinsics/mod.rs | 2 +- src/tools/miri/src/lib.rs | 1 + src/tools/miri/src/machine.rs | 36 ++-- .../validity/recursive-validity-ref-bool.rs | 8 + .../recursive-validity-ref-bool.stderr | 15 ++ 14 files changed, 186 insertions(+), 107 deletions(-) create mode 100644 src/tools/miri/tests/fail/validity/recursive-validity-ref-bool.rs create mode 100644 src/tools/miri/tests/fail/validity/recursive-validity-ref-bool.stderr diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs index ba4b80d1026..6d5bca57313 100644 --- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs @@ -396,7 +396,7 @@ fn const_validate_mplace<'tcx>( let alloc_id = mplace.ptr().provenance.unwrap().alloc_id(); let mut ref_tracking = RefTracking::new(mplace.clone()); let mut inner = false; - while let Some((mplace, path)) = ref_tracking.todo.pop() { + while let Some((mplace, path)) = ref_tracking.next() { let mode = match ecx.tcx.static_mutability(cid.instance.def_id()) { _ if cid.promoted.is_some() => CtfeValidationMode::Promoted, Some(mutbl) => CtfeValidationMode::Static { mutbl }, // a `static` diff --git a/compiler/rustc_const_eval/src/interpret/machine.rs b/compiler/rustc_const_eval/src/interpret/machine.rs index 4620b15d8d9..bdce8253b2e 100644 --- a/compiler/rustc_const_eval/src/interpret/machine.rs +++ b/compiler/rustc_const_eval/src/interpret/machine.rs @@ -165,6 +165,13 @@ fn alignment_check( /// Whether to enforce the validity invariant for a specific layout. fn enforce_validity(ecx: &InterpCx<'tcx, Self>, layout: TyAndLayout<'tcx>) -> bool; + /// Whether to enforce the validity invariant *recursively*. + fn enforce_validity_recursively( + _ecx: &InterpCx<'tcx, Self>, + _layout: TyAndLayout<'tcx>, + ) -> bool { + false + } /// Whether function calls should be [ABI](CallAbi)-checked. fn enforce_abi(_ecx: &InterpCx<'tcx, Self>) -> bool { diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs index b71e6ed8d2b..2e5d0ae7736 100644 --- a/compiler/rustc_const_eval/src/interpret/memory.rs +++ b/compiler/rustc_const_eval/src/interpret/memory.rs @@ -1006,8 +1006,11 @@ pub fn find_leaked_allocations( }) } - /// Runs the close in "validation" mode, which means the machine's memory read hooks will be + /// Runs the closure in "validation" mode, which means the machine's memory read hooks will be /// suppressed. Needless to say, this must only be set with great care! Cannot be nested. + /// + /// We do this so Miri's allocation access tracking does not show the validation + /// reads as spurious accesses. pub(super) fn run_for_validation(&self, f: impl FnOnce() -> R) -> R { // This deliberately uses `==` on `bool` to follow the pattern // `assert!(val.replace(new) == old)`. diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs index 242f36363a5..470a62026b9 100644 --- a/compiler/rustc_const_eval/src/interpret/place.rs +++ b/compiler/rustc_const_eval/src/interpret/place.rs @@ -572,7 +572,10 @@ pub fn write_immediate( if M::enforce_validity(self, dest.layout()) { // Data got changed, better make sure it matches the type! - self.validate_operand(&dest.to_op(self)?)?; + self.validate_operand( + &dest.to_op(self)?, + M::enforce_validity_recursively(self, dest.layout()), + )?; } Ok(()) @@ -811,7 +814,10 @@ fn copy_op_inner( // Generally for transmutation, data must be valid both at the old and new type. // But if the types are the same, the 2nd validation below suffices. if src.layout().ty != dest.layout().ty && M::enforce_validity(self, src.layout()) { - self.validate_operand(&src.to_op(self)?)?; + self.validate_operand( + &src.to_op(self)?, + M::enforce_validity_recursively(self, src.layout()), + )?; } // Do the actual copy. @@ -819,7 +825,10 @@ fn copy_op_inner( if validate_dest && M::enforce_validity(self, dest.layout()) { // Data got changed, better make sure it matches the type! - self.validate_operand(&dest.to_op(self)?)?; + self.validate_operand( + &dest.to_op(self)?, + M::enforce_validity_recursively(self, dest.layout()), + )?; } Ok(()) diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs index c8d59c5648d..460f5448634 100644 --- a/compiler/rustc_const_eval/src/interpret/validity.rs +++ b/compiler/rustc_const_eval/src/interpret/validity.rs @@ -155,8 +155,8 @@ fn allow_immutable_unsafe_cell(self) -> bool { /// State for tracking recursive validation of references pub struct RefTracking { - pub seen: FxHashSet, - pub todo: Vec<(T, PATH)>, + seen: FxHashSet, + todo: Vec<(T, PATH)>, } impl RefTracking { @@ -169,8 +169,11 @@ pub fn new(op: T) -> Self { ref_tracking_for_consts.seen.insert(op); ref_tracking_for_consts } + pub fn next(&mut self) -> Option<(T, PATH)> { + self.todo.pop() + } - pub fn track(&mut self, op: T, path: impl FnOnce() -> PATH) { + fn track(&mut self, op: T, path: impl FnOnce() -> PATH) { if self.seen.insert(op.clone()) { trace!("Recursing below ptr {:#?}", op); let path = path(); @@ -435,88 +438,96 @@ fn check_safe_pointer( if self.ecx.scalar_may_be_null(Scalar::from_maybe_pointer(place.ptr(), self.ecx))? { throw_validation_failure!(self.path, NullPtr { ptr_kind }) } - // Do not allow pointers to uninhabited types. + // Do not allow references to uninhabited types. if place.layout.abi.is_uninhabited() { let ty = place.layout.ty; throw_validation_failure!(self.path, PtrToUninhabited { ptr_kind, ty }) } // Recursive checking if let Some(ref_tracking) = self.ref_tracking.as_deref_mut() { - // Determine whether this pointer expects to be pointing to something mutable. - let ptr_expected_mutbl = match ptr_kind { - PointerKind::Box => Mutability::Mut, - PointerKind::Ref(mutbl) => { - // We do not take into account interior mutability here since we cannot know if - // there really is an `UnsafeCell` inside `Option` -- so we check - // that in the recursive descent behind this reference (controlled by - // `allow_immutable_unsafe_cell`). - mutbl - } - }; // Proceed recursively even for ZST, no reason to skip them! // `!` is a ZST and we want to validate it. - if let Ok((alloc_id, _offset, _prov)) = self.ecx.ptr_try_get_alloc_id(place.ptr(), 0) { + if let Some(ctfe_mode) = self.ctfe_mode { let mut skip_recursive_check = false; - if let Some(GlobalAlloc::Static(did)) = self.ecx.tcx.try_get_global_alloc(alloc_id) + // CTFE imposes restrictions on what references can point to. + if let Ok((alloc_id, _offset, _prov)) = + self.ecx.ptr_try_get_alloc_id(place.ptr(), 0) { - let DefKind::Static { nested, .. } = self.ecx.tcx.def_kind(did) else { bug!() }; - // Special handling for pointers to statics (irrespective of their type). - assert!(!self.ecx.tcx.is_thread_local_static(did)); - assert!(self.ecx.tcx.is_static(did)); - // Mode-specific checks - match self.ctfe_mode { - Some( - CtfeValidationMode::Static { .. } | CtfeValidationMode::Promoted { .. }, - ) => { - // We skip recursively checking other statics. These statics must be sound by - // themselves, and the only way to get broken statics here is by using - // unsafe code. - // The reasons we don't check other statics is twofold. For one, in all - // sound cases, the static was already validated on its own, and second, we - // trigger cycle errors if we try to compute the value of the other static - // and that static refers back to us (potentially through a promoted). - // This could miss some UB, but that's fine. - // We still walk nested allocations, as they are fundamentally part of this validation run. - // This means we will also recurse into nested statics of *other* - // statics, even though we do not recurse into other statics directly. - // That's somewhat inconsistent but harmless. - skip_recursive_check = !nested; - } - Some(CtfeValidationMode::Const { .. }) => { - // We can't recursively validate `extern static`, so we better reject them. - if self.ecx.tcx.is_foreign_item(did) { - throw_validation_failure!(self.path, ConstRefToExtern); + if let Some(GlobalAlloc::Static(did)) = + self.ecx.tcx.try_get_global_alloc(alloc_id) + { + let DefKind::Static { nested, .. } = self.ecx.tcx.def_kind(did) else { + bug!() + }; + // Special handling for pointers to statics (irrespective of their type). + assert!(!self.ecx.tcx.is_thread_local_static(did)); + assert!(self.ecx.tcx.is_static(did)); + // Mode-specific checks + match ctfe_mode { + CtfeValidationMode::Static { .. } + | CtfeValidationMode::Promoted { .. } => { + // We skip recursively checking other statics. These statics must be sound by + // themselves, and the only way to get broken statics here is by using + // unsafe code. + // The reasons we don't check other statics is twofold. For one, in all + // sound cases, the static was already validated on its own, and second, we + // trigger cycle errors if we try to compute the value of the other static + // and that static refers back to us (potentially through a promoted). + // This could miss some UB, but that's fine. + // We still walk nested allocations, as they are fundamentally part of this validation run. + // This means we will also recurse into nested statics of *other* + // statics, even though we do not recurse into other statics directly. + // That's somewhat inconsistent but harmless. + skip_recursive_check = !nested; + } + CtfeValidationMode::Const { .. } => { + // We can't recursively validate `extern static`, so we better reject them. + if self.ecx.tcx.is_foreign_item(did) { + throw_validation_failure!(self.path, ConstRefToExtern); + } } } - None => {} } - } - // Dangling and Mutability check. - let (size, _align, alloc_kind) = self.ecx.get_alloc_info(alloc_id); - if alloc_kind == AllocKind::Dead { - // This can happen for zero-sized references. We can't have *any* references to non-existing - // allocations though, interning rejects them all as the rest of rustc isn't happy with them... - // so we throw an error, even though this isn't really UB. - // A potential future alternative would be to resurrect this as a zero-sized allocation - // (which codegen will then compile to an aligned dummy pointer anyway). - throw_validation_failure!(self.path, DanglingPtrUseAfterFree { ptr_kind }); - } - // If this allocation has size zero, there is no actual mutability here. - if size != Size::ZERO { - let alloc_actual_mutbl = mutability(self.ecx, alloc_id); - // Mutable pointer to immutable memory is no good. - if ptr_expected_mutbl == Mutability::Mut - && alloc_actual_mutbl == Mutability::Not - { - throw_validation_failure!(self.path, MutableRefToImmutable); + // Dangling and Mutability check. + let (size, _align, alloc_kind) = self.ecx.get_alloc_info(alloc_id); + if alloc_kind == AllocKind::Dead { + // This can happen for zero-sized references. We can't have *any* references to + // non-existing allocations in const-eval though, interning rejects them all as + // the rest of rustc isn't happy with them... so we throw an error, even though + // this isn't really UB. + // A potential future alternative would be to resurrect this as a zero-sized allocation + // (which codegen will then compile to an aligned dummy pointer anyway). + throw_validation_failure!(self.path, DanglingPtrUseAfterFree { ptr_kind }); } - // In a const, everything must be completely immutable. - if matches!(self.ctfe_mode, Some(CtfeValidationMode::Const { .. })) { + // If this allocation has size zero, there is no actual mutability here. + if size != Size::ZERO { + // Determine whether this pointer expects to be pointing to something mutable. + let ptr_expected_mutbl = match ptr_kind { + PointerKind::Box => Mutability::Mut, + PointerKind::Ref(mutbl) => { + // We do not take into account interior mutability here since we cannot know if + // there really is an `UnsafeCell` inside `Option` -- so we check + // that in the recursive descent behind this reference (controlled by + // `allow_immutable_unsafe_cell`). + mutbl + } + }; + // Determine what it actually points to. + let alloc_actual_mutbl = mutability(self.ecx, alloc_id); + // Mutable pointer to immutable memory is no good. if ptr_expected_mutbl == Mutability::Mut - || alloc_actual_mutbl == Mutability::Mut + && alloc_actual_mutbl == Mutability::Not { - throw_validation_failure!(self.path, ConstRefToMutable); + throw_validation_failure!(self.path, MutableRefToImmutable); + } + // In a const, everything must be completely immutable. + if matches!(self.ctfe_mode, Some(CtfeValidationMode::Const { .. })) { + if ptr_expected_mutbl == Mutability::Mut + || alloc_actual_mutbl == Mutability::Mut + { + throw_validation_failure!(self.path, ConstRefToMutable); + } } } } @@ -524,6 +535,15 @@ fn check_safe_pointer( if skip_recursive_check { return Ok(()); } + } else { + // This is not CTFE, so it's Miri with recursive checking. + // FIXME: we do *not* check behind boxes, since creating a new box first creates it uninitialized + // and then puts the value in there, so briefly we have a box with uninit contents. + // FIXME: should we also skip `UnsafeCell` behind shared references? Currently that is not + // needed since validation reads bypass Stacked Borrows and data race checks. + if matches!(ptr_kind, PointerKind::Box) { + return Ok(()); + } } let path = &self.path; ref_tracking.track(place, || { @@ -1072,11 +1092,23 @@ pub(crate) fn const_validate_operand( /// `op` is assumed to cover valid memory if it is an indirect operand. /// It will error if the bits at the destination do not match the ones described by the layout. #[inline(always)] - pub fn validate_operand(&self, op: &OpTy<'tcx, M::Provenance>) -> InterpResult<'tcx> { + pub fn validate_operand( + &self, + op: &OpTy<'tcx, M::Provenance>, + recursive: bool, + ) -> InterpResult<'tcx> { // Note that we *could* actually be in CTFE here with `-Zextra-const-ub-checks`, but it's // still correct to not use `ctfe_mode`: that mode is for validation of the final constant - // value, it rules out things like `UnsafeCell` in awkward places. It also can make checking - // recurse through references which, for now, we don't want here, either. - self.validate_operand_internal(op, vec![], None, None) + // value, it rules out things like `UnsafeCell` in awkward places. + if !recursive { + return self.validate_operand_internal(op, vec![], None, None); + } + // Do a recursive check. + let mut ref_tracking = RefTracking::empty(); + self.validate_operand_internal(op, vec![], Some(&mut ref_tracking), None)?; + while let Some((mplace, path)) = ref_tracking.todo.pop() { + self.validate_operand_internal(&mplace.into(), path, Some(&mut ref_tracking), None)?; + } + Ok(()) } } diff --git a/compiler/rustc_const_eval/src/util/check_validity_requirement.rs b/compiler/rustc_const_eval/src/util/check_validity_requirement.rs index daf57285ebe..4b6b1e453b8 100644 --- a/compiler/rustc_const_eval/src/util/check_validity_requirement.rs +++ b/compiler/rustc_const_eval/src/util/check_validity_requirement.rs @@ -67,7 +67,7 @@ fn might_permit_raw_init_strict<'tcx>( // This does *not* actually check that references are dereferenceable, but since all types that // require dereferenceability also require non-null, we don't actually get any false negatives // due to this. - Ok(cx.validate_operand(&ot).is_ok()) + Ok(cx.validate_operand(&ot, /*recursive*/ false).is_ok()) } /// Implements the 'lax' (default) version of the `might_permit_raw_init` checks; see that function for diff --git a/src/tools/miri/README.md b/src/tools/miri/README.md index b1be596c006..ff0f162822c 100644 --- a/src/tools/miri/README.md +++ b/src/tools/miri/README.md @@ -398,6 +398,8 @@ to Miri failing to detect cases of undefined behavior in a program. application instead of raising an error within the context of Miri (and halting execution). Note that code might not expect these operations to ever panic, so this flag can lead to strange (mis)behavior. +* `-Zmiri-recursive-validation` is a *highly experimental* flag that makes validity checking + recurse below references. * `-Zmiri-retag-fields[=]` controls when Stacked Borrows retagging recurses into fields. `all` means it always recurses (the default, and equivalent to `-Zmiri-retag-fields` without an explicit value), `none` means it never recurses, `scalar` means it only recurses for diff --git a/src/tools/miri/src/bin/miri.rs b/src/tools/miri/src/bin/miri.rs index 25b154a8206..4b3c97e248f 100644 --- a/src/tools/miri/src/bin/miri.rs +++ b/src/tools/miri/src/bin/miri.rs @@ -44,7 +44,7 @@ use rustc_session::search_paths::PathKind; use rustc_session::{CtfeBacktrace, EarlyDiagCtxt}; -use miri::{BacktraceStyle, BorrowTrackerMethod, ProvenanceMode, RetagFields}; +use miri::{BacktraceStyle, BorrowTrackerMethod, ProvenanceMode, RetagFields, ValidationMode}; struct MiriCompilerCalls { miri_config: miri::MiriConfig, @@ -421,7 +421,9 @@ fn main() { } else if arg == "--" { after_dashdash = true; } else if arg == "-Zmiri-disable-validation" { - miri_config.validate = false; + miri_config.validation = ValidationMode::No; + } else if arg == "-Zmiri-recursive-validation" { + miri_config.validation = ValidationMode::Deep; } else if arg == "-Zmiri-disable-stacked-borrows" { miri_config.borrow_tracker = None; } else if arg == "-Zmiri-tree-borrows" { diff --git a/src/tools/miri/src/eval.rs b/src/tools/miri/src/eval.rs index 2184a4426c8..53e87751708 100644 --- a/src/tools/miri/src/eval.rs +++ b/src/tools/miri/src/eval.rs @@ -68,7 +68,7 @@ pub enum IsolatedOp { Allow, } -#[derive(Copy, Clone, PartialEq, Eq)] +#[derive(Debug, Copy, Clone, PartialEq, Eq)] pub enum BacktraceStyle { /// Prints a terser backtrace which ideally only contains relevant information. Short, @@ -78,6 +78,16 @@ pub enum BacktraceStyle { Off, } +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub enum ValidationMode { + /// Do not perform any kind of validation. + No, + /// Validate the interior of the value, but not things behind references. + Shallow, + /// Fully recursively validate references. + Deep, +} + /// Configuration needed to spawn a Miri instance. #[derive(Clone)] pub struct MiriConfig { @@ -85,7 +95,7 @@ pub struct MiriConfig { /// (This is still subject to isolation as well as `forwarded_env_vars`.) pub env: Vec<(OsString, OsString)>, /// Determine if validity checking is enabled. - pub validate: bool, + pub validation: ValidationMode, /// Determines if Stacked Borrows or Tree Borrows is enabled. pub borrow_tracker: Option, /// Whether `core::ptr::Unique` receives special treatment. @@ -162,7 +172,7 @@ impl Default for MiriConfig { fn default() -> MiriConfig { MiriConfig { env: vec![], - validate: true, + validation: ValidationMode::Shallow, borrow_tracker: Some(BorrowTrackerMethod::StackedBorrows), unique_is_unique: false, check_alignment: AlignmentCheck::Int, diff --git a/src/tools/miri/src/intrinsics/mod.rs b/src/tools/miri/src/intrinsics/mod.rs index 9cd776c9371..d60119e75f1 100644 --- a/src/tools/miri/src/intrinsics/mod.rs +++ b/src/tools/miri/src/intrinsics/mod.rs @@ -153,7 +153,7 @@ fn emulate_intrinsic_by_name( // Would not be considered UB, or the other way around (`is_val_statically_known(0)`). "is_val_statically_known" => { let [arg] = check_arg_count(args)?; - this.validate_operand(arg)?; + this.validate_operand(arg, /*recursive*/ false)?; let branch: bool = this.machine.rng.get_mut().gen(); this.write_scalar(Scalar::from_bool(branch), dest)?; } diff --git a/src/tools/miri/src/lib.rs b/src/tools/miri/src/lib.rs index 24909f21eb2..2b3ae6df5de 100644 --- a/src/tools/miri/src/lib.rs +++ b/src/tools/miri/src/lib.rs @@ -142,6 +142,7 @@ }; pub use crate::eval::{ create_ecx, eval_entry, AlignmentCheck, BacktraceStyle, IsolatedOp, MiriConfig, RejectOpWith, + ValidationMode, }; pub use crate::helpers::{AccessKind, EvalContextExt as _}; pub use crate::machine::{ diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs index 5f4aa9d2f5d..fec345c8de1 100644 --- a/src/tools/miri/src/machine.rs +++ b/src/tools/miri/src/machine.rs @@ -187,7 +187,11 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { pub type MemoryKind = interpret::MemoryKind; /// Pointer provenance. -#[derive(Clone, Copy)] +// This needs to be `Eq`+`Hash` because the `Machine` trait needs that because validity checking +// *might* be recursive and then it has to track which places have already been visited. +// These implementations are a bit questionable, and it means we may check the same place multiple +// times with different provenance, but that is in general not wrong. +#[derive(Clone, Copy, PartialEq, Eq, Hash)] pub enum Provenance { /// For pointers with concrete provenance. we exactly know which allocation they are attached to /// and what their borrow tag is. @@ -215,24 +219,6 @@ pub enum Provenance { Wildcard, } -// This needs to be `Eq`+`Hash` because the `Machine` trait needs that because validity checking -// *might* be recursive and then it has to track which places have already been visited. -// However, comparing provenance is meaningless, since `Wildcard` might be any provenance -- and of -// course we don't actually do recursive checking. -// We could change `RefTracking` to strip provenance for its `seen` set but that type is generic so that is quite annoying. -// Instead owe add the required instances but make them panic. -impl PartialEq for Provenance { - fn eq(&self, _other: &Self) -> bool { - panic!("Provenance must not be compared") - } -} -impl Eq for Provenance {} -impl std::hash::Hash for Provenance { - fn hash(&self, _state: &mut H) { - panic!("Provenance must not be hashed") - } -} - /// The "extra" information a pointer has over a regular AllocId. #[derive(Copy, Clone, PartialEq)] pub enum ProvenanceExtra { @@ -460,7 +446,7 @@ pub struct MiriMachine<'tcx> { pub(crate) isolated_op: IsolatedOp, /// Whether to enforce the validity invariant. - pub(crate) validate: bool, + pub(crate) validation: ValidationMode, /// The table of file descriptors. pub(crate) fds: shims::FdTable, @@ -659,7 +645,7 @@ pub(crate) fn new(config: &MiriConfig, layout_cx: LayoutCx<'tcx, TyCtxt<'tcx>>) cmd_line: None, tls: TlsData::default(), isolated_op: config.isolated_op, - validate: config.validate, + validation: config.validation, fds: shims::FdTable::init(config.mute_stdout_stderr), dirs: Default::default(), layouts, @@ -801,7 +787,7 @@ fn visit_provenance(&self, visit: &mut VisitWith<'_>) { fds, tcx: _, isolated_op: _, - validate: _, + validation: _, clock: _, layouts: _, static_roots: _, @@ -943,7 +929,11 @@ fn alignment_check( #[inline(always)] fn enforce_validity(ecx: &MiriInterpCx<'tcx>, _layout: TyAndLayout<'tcx>) -> bool { - ecx.machine.validate + ecx.machine.validation != ValidationMode::No + } + #[inline(always)] + fn enforce_validity_recursively(ecx: &InterpCx<'tcx, Self>, _layout: TyAndLayout<'tcx>) -> bool { + ecx.machine.validation == ValidationMode::Deep } #[inline(always)] diff --git a/src/tools/miri/tests/fail/validity/recursive-validity-ref-bool.rs b/src/tools/miri/tests/fail/validity/recursive-validity-ref-bool.rs new file mode 100644 index 00000000000..17b81f29cfe --- /dev/null +++ b/src/tools/miri/tests/fail/validity/recursive-validity-ref-bool.rs @@ -0,0 +1,8 @@ +//@compile-flags: -Zmiri-recursive-validation + +fn main() { + let x = 3u8; + let xref = &x; + let xref_wrong_type: &bool = unsafe { std::mem::transmute(xref) }; //~ERROR: encountered 0x03, but expected a boolean + let _val = *xref_wrong_type; +} diff --git a/src/tools/miri/tests/fail/validity/recursive-validity-ref-bool.stderr b/src/tools/miri/tests/fail/validity/recursive-validity-ref-bool.stderr new file mode 100644 index 00000000000..2b2fa9b8a20 --- /dev/null +++ b/src/tools/miri/tests/fail/validity/recursive-validity-ref-bool.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: constructing invalid value at .: encountered 0x03, but expected a boolean + --> $DIR/recursive-validity-ref-bool.rs:LL:CC + | +LL | let xref_wrong_type: &bool = unsafe { std::mem::transmute(xref) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .: encountered 0x03, but expected a boolean + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: BACKTRACE: + = note: inside `main` at $DIR/recursive-validity-ref-bool.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + From 8497800abde9214041e11f35efdbfa437f761001 Mon Sep 17 00:00:00 2001 From: clubby789 Date: Thu, 1 Aug 2024 15:41:17 +0000 Subject: [PATCH 25/36] 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 00000000000..4b520a62069 --- /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 eb2de64aa1cb0d3eded99458566e8eee8333a751 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Sat, 3 Aug 2024 12:30:38 -0700 Subject: [PATCH 26/36] rustdoc: make the hover trail for doc anchors a bit bigger https://rust-lang.zulipchat.com/#narrow/stream/266220-t-rustdoc/topic/Weird.20markdown.20heading.20rendering.3F --- src/librustdoc/html/static/css/rustdoc.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index f4e231327a8..02a6bb8f548 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -930,7 +930,7 @@ a.doc-anchor { left: -17px; /* We add this padding so that when the cursor moves from the heading's text to the anchor, the anchor doesn't disappear. */ - padding-right: 5px; + padding-right: 10px; /* And this padding is used to make the anchor larger and easier to click on. */ padding-left: 3px; } From 2cde11f2d145d031b26fe22a3e7d2e278bc0e6ba Mon Sep 17 00:00:00 2001 From: sayantn Date: Sun, 4 Aug 2024 02:32:03 +0530 Subject: [PATCH 27/36] Chore: add `x86_amx_intrinsics` feature flag to `core/lib.rs` and remove `issue-120720-reduce-nan.rs` --- library/core/src/lib.rs | 1 + tests/codegen/simd/issue-120720-reduce-nan.rs | 21 ------------------- 2 files changed, 1 insertion(+), 21 deletions(-) delete mode 100644 tests/codegen/simd/issue-120720-reduce-nan.rs diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 9306581dca9..e74900ff747 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -264,6 +264,7 @@ #![feature(sse4a_target_feature)] #![feature(tbm_target_feature)] #![feature(wasm_target_feature)] +#![feature(x86_amx_intrinsics)] // tidy-alphabetical-end // allow using `core::` in intra-doc links diff --git a/tests/codegen/simd/issue-120720-reduce-nan.rs b/tests/codegen/simd/issue-120720-reduce-nan.rs deleted file mode 100644 index 13af0bb076e..00000000000 --- a/tests/codegen/simd/issue-120720-reduce-nan.rs +++ /dev/null @@ -1,21 +0,0 @@ -//@ compile-flags: -C opt-level=3 -C target-cpu=cannonlake -//@ only-x86_64 - -// In a previous implementation, _mm512_reduce_add_pd did the reduction with all fast-math flags -// enabled, making it UB to reduce a vector containing a NaN. - -#![crate_type = "lib"] -#![feature(stdarch_x86_avx512, avx512_target_feature)] -use std::arch::x86_64::*; - -// CHECK-LABEL: @demo( -#[no_mangle] -#[target_feature(enable = "avx512f")] // Function-level target feature mismatches inhibit inlining -pub unsafe fn demo() -> bool { - // CHECK: %0 = tail call reassoc double @llvm.vector.reduce.fadd.v8f64( - // CHECK: %_0.i = fcmp uno double %0, 0.000000e+00 - // CHECK: ret i1 %_0.i - let res = - unsafe { _mm512_reduce_add_pd(_mm512_set_pd(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, f64::NAN)) }; - res.is_nan() -} From 01bda01e3374d73e98806f8e27cbb7f6ceb9ad98 Mon Sep 17 00:00:00 2001 From: sayantn Date: Sun, 4 Aug 2024 03:07:12 +0530 Subject: [PATCH 28/36] Update stdarch --- library/stdarch | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/stdarch b/library/stdarch index df3618d9f35..47b929ddc52 160000 --- a/library/stdarch +++ b/library/stdarch @@ -1 +1 @@ -Subproject commit df3618d9f35165f4bc548114e511c49c29e1fd9b +Subproject commit 47b929ddc521a78b0f699ba8d5c274d28593448a From cb7c596681c3c5718c7fd0fbe15c487cd36c65c3 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sun, 4 Aug 2024 01:08:10 +0200 Subject: [PATCH 29/36] Update rinja version to 0.3.0 --- Cargo.lock | 15 +++++++++------ src/librustdoc/Cargo.toml | 2 +- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0b5aa7db319..13b8eaea068 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3282,20 +3282,22 @@ dependencies = [ [[package]] name = "rinja" -version = "0.2.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2d47a46d7729e891c8accf260e9daa02ae6d570aa2a94fb1fb27eb5364a2323" +checksum = "6d3762e3740cdbf2fd2be465cc2c26d643ad17353cc2e0223d211c1b096118bd" dependencies = [ + "itoa", "rinja_derive", ] [[package]] name = "rinja_derive" -version = "0.2.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44dae9afe59d58ed8d988d67d1945f3638125d2fd2104058399382e11bd3ea2a" +checksum = "fd01fd8e15e7d19c8b8052c1d428325131e02ff1633cdcf695190c2e56ab682c" dependencies = [ "basic-toml", + "memchr", "mime", "mime_guess", "once_map", @@ -3308,10 +3310,11 @@ dependencies = [ [[package]] name = "rinja_parser" -version = "0.2.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b1771c78cd5d3b1646ef8d8f2ed100db936e8b291d3cc06e92a339ff346858c" +checksum = "a2f6bf7cef118c6de21206edf0b3f19f5ede60006be674a58ca21b6e003a1b57" dependencies = [ + "memchr", "nom", ] diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml index dfd7414652f..b3fccbf6456 100644 --- a/src/librustdoc/Cargo.toml +++ b/src/librustdoc/Cargo.toml @@ -8,7 +8,7 @@ path = "lib.rs" [dependencies] arrayvec = { version = "0.7", default-features = false } -rinja = { version = "0.2", default-features = false, features = ["config"] } +rinja = { version = "0.3", default-features = false, features = ["config"] } base64 = "0.21.7" itertools = "0.12" indexmap = "2" From 3a41a11a8f8af11867c0401027235215cac643ca Mon Sep 17 00:00:00 2001 From: Jerry Wang Date: Wed, 17 Jul 2024 16:40:01 -0400 Subject: [PATCH 30/36] Migrate `run-make/print-calling-conventions` to ui-test --- .../tidy/src/allowed_run_make_makefiles.txt | 1 - .../print-calling-conventions/Makefile | 4 --- tests/ui/print-calling-conventions.rs | 2 ++ tests/ui/print-calling-conventions.stdout | 34 +++++++++++++++++++ 4 files changed, 36 insertions(+), 5 deletions(-) delete mode 100644 tests/run-make/print-calling-conventions/Makefile create mode 100644 tests/ui/print-calling-conventions.rs create mode 100644 tests/ui/print-calling-conventions.stdout diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt index a04e239abb0..93226c41a23 100644 --- a/src/tools/tidy/src/allowed_run_make_makefiles.txt +++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt @@ -23,7 +23,6 @@ run-make/no-alloc-shim/Makefile run-make/pdb-buildinfo-cl-cmd/Makefile run-make/pgo-gen-lto/Makefile run-make/pgo-indirect-call-promotion/Makefile -run-make/print-calling-conventions/Makefile run-make/print-target-list/Makefile run-make/raw-dylib-alt-calling-convention/Makefile run-make/raw-dylib-c/Makefile diff --git a/tests/run-make/print-calling-conventions/Makefile b/tests/run-make/print-calling-conventions/Makefile deleted file mode 100644 index 27b87e61086..00000000000 --- a/tests/run-make/print-calling-conventions/Makefile +++ /dev/null @@ -1,4 +0,0 @@ -include ../tools.mk - -all: - $(RUSTC) --print calling-conventions diff --git a/tests/ui/print-calling-conventions.rs b/tests/ui/print-calling-conventions.rs new file mode 100644 index 00000000000..302ed088142 --- /dev/null +++ b/tests/ui/print-calling-conventions.rs @@ -0,0 +1,2 @@ +//@ compile-flags: --print calling-conventions +//@ build-pass diff --git a/tests/ui/print-calling-conventions.stdout b/tests/ui/print-calling-conventions.stdout new file mode 100644 index 00000000000..da67a57f420 --- /dev/null +++ b/tests/ui/print-calling-conventions.stdout @@ -0,0 +1,34 @@ +C +C-cmse-nonsecure-call +C-unwind +Rust +aapcs +aapcs-unwind +avr-interrupt +avr-non-blocking-interrupt +cdecl +cdecl-unwind +efiapi +fastcall +fastcall-unwind +msp430-interrupt +ptx-kernel +riscv-interrupt-m +riscv-interrupt-s +rust-call +rust-cold +rust-intrinsic +stdcall +stdcall-unwind +system +system-unwind +sysv64 +sysv64-unwind +thiscall +thiscall-unwind +unadjusted +vectorcall +vectorcall-unwind +win64 +win64-unwind +x86-interrupt From 1ca959e3f00fcf01395b18bb6e3b9dd86b3e478c Mon Sep 17 00:00:00 2001 From: Jerry Wang Date: Wed, 17 Jul 2024 16:55:13 -0400 Subject: [PATCH 31/36] Migrate `print-target-list` to `rmake` --- .../tidy/src/allowed_run_make_makefiles.txt | 1 - tests/run-make/print-target-list/Makefile | 8 ------- tests/run-make/print-target-list/rmake.rs | 21 +++++++++++++++++++ 3 files changed, 21 insertions(+), 9 deletions(-) delete mode 100644 tests/run-make/print-target-list/Makefile create mode 100644 tests/run-make/print-target-list/rmake.rs diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt index 93226c41a23..088d5ba0c2b 100644 --- a/src/tools/tidy/src/allowed_run_make_makefiles.txt +++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt @@ -23,7 +23,6 @@ run-make/no-alloc-shim/Makefile run-make/pdb-buildinfo-cl-cmd/Makefile run-make/pgo-gen-lto/Makefile run-make/pgo-indirect-call-promotion/Makefile -run-make/print-target-list/Makefile run-make/raw-dylib-alt-calling-convention/Makefile run-make/raw-dylib-c/Makefile run-make/redundant-libs/Makefile diff --git a/tests/run-make/print-target-list/Makefile b/tests/run-make/print-target-list/Makefile deleted file mode 100644 index f23c40d4281..00000000000 --- a/tests/run-make/print-target-list/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -include ../tools.mk - -# Checks that all the targets returned by `rustc --print target-list` are valid -# target specifications -all: - for target in $(shell $(BARE_RUSTC) --print target-list); do \ - $(BARE_RUSTC) --target $$target --print sysroot; \ - done diff --git a/tests/run-make/print-target-list/rmake.rs b/tests/run-make/print-target-list/rmake.rs new file mode 100644 index 00000000000..743ed52069d --- /dev/null +++ b/tests/run-make/print-target-list/rmake.rs @@ -0,0 +1,21 @@ +// Checks that all the targets returned by `rustc --print target-list` are valid +// target specifications + +use run_make_support::bare_rustc; + +// FIXME(127877): certain experimental targets fail with creating a 'LLVM TargetMachine' +// in CI, so we skip them +const EXPERIMENTAL_TARGETS: &[&str] = &["avr", "m68k", "csky", "xtensa"]; + +fn main() { + let targets = bare_rustc().print("target-list").run().stdout_utf8(); + + for target in targets.lines() { + // skip experimental targets that would otherwise fail + if EXPERIMENTAL_TARGETS.iter().any(|experimental| target.contains(experimental)) { + continue; + } + + bare_rustc().target(target).print("sysroot").run(); + } +} From 36cf385e886da13b5b1f98a8b62b1aa63f7e1722 Mon Sep 17 00:00:00 2001 From: Jerry Wang Date: Wed, 17 Jul 2024 17:54:06 -0400 Subject: [PATCH 32/36] Ensure `Rustc::print` use in `rmake` tests --- tests/run-make/print-cfg/rmake.rs | 5 +---- tests/run-make/print-check-cfg/rmake.rs | 2 +- tests/run-make/print-to-output/rmake.rs | 5 +---- tests/run-make/rustdoc-scrape-examples-macros/rmake.rs | 3 +-- 4 files changed, 4 insertions(+), 11 deletions(-) diff --git a/tests/run-make/print-cfg/rmake.rs b/tests/run-make/print-cfg/rmake.rs index d83e8a36f2c..471a99b90d9 100644 --- a/tests/run-make/print-cfg/rmake.rs +++ b/tests/run-make/print-cfg/rmake.rs @@ -6,7 +6,6 @@ //! It also checks that some targets have the correct set cfgs. use std::collections::HashSet; -use std::ffi::OsString; use std::iter::FromIterator; use std::path::PathBuf; @@ -91,10 +90,8 @@ fn check_(output: &str, includes: &[&str], disallow: &[&str]) { // --print=cfg=PATH { let tmp_path = PathBuf::from(format!("{target}.cfg")); - let mut print_arg = OsString::from("--print=cfg="); - print_arg.push(tmp_path.as_os_str()); - rustc().target(target).arg(print_arg).run(); + rustc().target(target).print(&format!("cfg={}", tmp_path.display())).run(); let output = rfs::read_to_string(&tmp_path); diff --git a/tests/run-make/print-check-cfg/rmake.rs b/tests/run-make/print-check-cfg/rmake.rs index 4a79910c8e0..b10336f88c6 100644 --- a/tests/run-make/print-check-cfg/rmake.rs +++ b/tests/run-make/print-check-cfg/rmake.rs @@ -87,7 +87,7 @@ fn main() { fn check(CheckCfg { args, contains }: CheckCfg) { let output = - rustc().input("lib.rs").arg("-Zunstable-options").arg("--print=check-cfg").args(args).run(); + rustc().input("lib.rs").arg("-Zunstable-options").print("check-cfg").args(args).run(); let stdout = output.stdout_utf8(); diff --git a/tests/run-make/print-to-output/rmake.rs b/tests/run-make/print-to-output/rmake.rs index d0cba725b36..db2a291f8e7 100644 --- a/tests/run-make/print-to-output/rmake.rs +++ b/tests/run-make/print-to-output/rmake.rs @@ -1,7 +1,6 @@ //! This checks the output of some `--print` options when //! output to a file (instead of stdout) -use std::ffi::OsString; use std::path::PathBuf; use run_make_support::{rfs, rustc, target}; @@ -44,10 +43,8 @@ fn check_(output: &str, includes: &[&str]) { // --print={option}=PATH let output = { let tmp_path = PathBuf::from(format!("{}.txt", args.option)); - let mut print_arg = OsString::from(format!("--print={}=", args.option)); - print_arg.push(tmp_path.as_os_str()); - rustc().target(args.target).arg(print_arg).run(); + rustc().target(args.target).print(&format!("{}={}", args.option, tmp_path.display())).run(); rfs::read_to_string(&tmp_path) }; diff --git a/tests/run-make/rustdoc-scrape-examples-macros/rmake.rs b/tests/run-make/rustdoc-scrape-examples-macros/rmake.rs index bfe4a1df456..b77df7adc8d 100644 --- a/tests/run-make/rustdoc-scrape-examples-macros/rmake.rs +++ b/tests/run-make/rustdoc-scrape-examples-macros/rmake.rs @@ -11,8 +11,7 @@ fn main() { let dylib_name = rustc() .crate_name(proc_crate_name) .crate_type("dylib") - .arg("--print") - .arg("file-names") + .print("file-names") .arg("-") .run() .stdout_utf8(); From 007d9e1c26da1e509ff7887604e6685f1445982a Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Sat, 3 Aug 2024 20:51:28 -0700 Subject: [PATCH 33/36] rustdoc: Re-add missing `stripped_mod` check; explain orphan impls Co-authored-by: Michael Howell --- src/librustdoc/formats/cache.rs | 31 ++++++++++++++++++++++++++----- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs index d2d0f5a4380..3fdc8786471 100644 --- a/src/librustdoc/formats/cache.rs +++ b/src/librustdoc/formats/cache.rs @@ -486,10 +486,30 @@ fn add_item_to_search_index(tcx: TyCtxt<'_>, cache: &mut Cache, item: &clean::It ParentStackItem::Type(item_id) => item_id.as_def_id(), }; let Some(parent_did) = parent_did else { return }; - // The current stack not necessarily has correlation - // for where the type was defined. On the other - // hand, `paths` always has the right - // information if present. + // The current stack reflects the CacheBuilder's recursive + // walk over HIR. For associated items, this is the module + // where the `impl` block is defined. That's an implementation + // detail that we don't want to affect the search engine. + // + // In particular, you can arrange things like this: + // + // #![crate_name="me"] + // mod private_mod { + // impl Clone for MyThing { fn clone(&self) -> MyThing { MyThing } } + // } + // pub struct MyThing; + // + // When that happens, we need to: + // - ignore the `cache.stripped_mod` flag, since the Clone impl is actually + // part of the public API even though it's defined in a private module + // - present the method as `me::MyThing::clone`, its publicly-visible path + // - deal with the fact that the recursive walk hasn't actually reached `MyThing` + // until it's already past `private_mod`, since that's first, and doesn't know + // yet if `MyThing` will actually be public or not (it could be re-exported) + // + // We accomplish the last two points by recording children of "orphan impls" + // in a field of the cache whose elements are added to the search index later, + // after cache building is complete (see `handle_orphan_impl_child`). match cache.paths.get(&parent_did) { Some((fqp, _)) => (Some(parent_did), &fqp[..fqp.len() - 1]), None => { @@ -500,7 +520,8 @@ fn add_item_to_search_index(tcx: TyCtxt<'_>, cache: &mut Cache, item: &clean::It } _ => { // Don't index if item is crate root, which is inserted later on when serializing the index. - if item_def_id.is_crate_root() { + // Don't index if containing module is stripped (i.e., private), + if item_def_id.is_crate_root() || cache.stripped_mod { return; } (None, &*cache.stack) From 178886e923058327900f945b26afb3759872839e Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 4 Aug 2024 15:25:59 +0000 Subject: [PATCH 34/36] Update incorrect comment --- src/bootstrap/src/core/metadata.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bootstrap/src/core/metadata.rs b/src/bootstrap/src/core/metadata.rs index c11230744c3..1016607fc83 100644 --- a/src/bootstrap/src/core/metadata.rs +++ b/src/bootstrap/src/core/metadata.rs @@ -86,7 +86,7 @@ fn workspace_members(build: &Build) -> Vec { packages }; - // Collects `metadata.packages` from all workspaces. + // Collects `metadata.packages` from the root and library workspaces. let mut packages = vec![]; packages.extend(collect_metadata("Cargo.toml")); packages.extend(collect_metadata("library/Cargo.toml")); From d28083728d493533a72e5a7fe9b9820b824cfcac Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 5 Aug 2024 10:49:01 +0200 Subject: [PATCH 35/36] Preparing for merge from rustc --- src/tools/miri/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index f03fe70aa21..b74f9759ebe 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -1df0458781d6fd753a68c4cdc4de5313b1635dbd +29e924841f06bb181d87494eba2783761bc1ddec From 61463fd042520b1454fecfca0437180535ea8497 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 5 Aug 2024 11:04:40 +0200 Subject: [PATCH 36/36] fmt --- src/tools/miri/src/machine.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs index fec345c8de1..3e45a3a7e1a 100644 --- a/src/tools/miri/src/machine.rs +++ b/src/tools/miri/src/machine.rs @@ -932,7 +932,10 @@ fn enforce_validity(ecx: &MiriInterpCx<'tcx>, _layout: TyAndLayout<'tcx>) -> boo ecx.machine.validation != ValidationMode::No } #[inline(always)] - fn enforce_validity_recursively(ecx: &InterpCx<'tcx, Self>, _layout: TyAndLayout<'tcx>) -> bool { + fn enforce_validity_recursively( + ecx: &InterpCx<'tcx, Self>, + _layout: TyAndLayout<'tcx>, + ) -> bool { ecx.machine.validation == ValidationMode::Deep }