diff --git a/.mailmap b/.mailmap index 33673244be6d0..4d93792422c23 100644 --- a/.mailmap +++ b/.mailmap @@ -435,7 +435,7 @@ Nick Platt Niclas Schwarzlose <15schnic@gmail.com> Nicolas Abram Nicole Mazzuca -Nilstrieb <48135649+Nilstrieb@users.noreply.github.com> nils <48135649+Nilstrieb@users.noreply.github.com> +Noratrieb <48135649+Noratrieb@users.noreply.github.com> <48135649+Nilstrieb@users.noreply.github.com> Nif Ward Nika Layzell NODA Kai diff --git a/Cargo.lock b/Cargo.lock index 1dec7d0c11e22..32470c22f29f1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -573,7 +573,7 @@ checksum = "4b82cf0babdbd58558212896d1a4272303a57bdb245c2bf1147185fb45640e70" [[package]] name = "clippy" -version = "0.1.81" +version = "0.1.82" dependencies = [ "anstream", "clippy_config", @@ -594,13 +594,13 @@ dependencies = [ "termize", "tokio", "toml 0.7.8", - "ui_test 0.23.0", + "ui_test 0.24.0", "walkdir", ] [[package]] name = "clippy_config" -version = "0.1.81" +version = "0.1.82" dependencies = [ "rustc-semver", "serde", @@ -623,7 +623,7 @@ dependencies = [ [[package]] name = "clippy_lints" -version = "0.1.81" +version = "0.1.82" dependencies = [ "arrayvec", "cargo_metadata 0.18.1", @@ -648,7 +648,7 @@ dependencies = [ [[package]] name = "clippy_utils" -version = "0.1.81" +version = "0.1.82" dependencies = [ "arrayvec", "clippy_config", @@ -969,7 +969,7 @@ dependencies = [ [[package]] name = "declare_clippy_lint" -version = "0.1.81" +version = "0.1.82" dependencies = [ "itertools", "quote", @@ -2571,18 +2571,6 @@ dependencies = [ "indexmap", "memchr", "ruzstd 0.5.0", - "wasmparser 0.118.2", -] - -[[package]] -name = "object" -version = "0.34.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7090bae93f8585aad99e595b7073c5de9ba89fbd6b4e9f0cdd7a10177273ac8" -dependencies = [ - "flate2", - "memchr", - "ruzstd 0.6.0", ] [[package]] @@ -2596,14 +2584,20 @@ dependencies = [ [[package]] name = "object" -version = "0.36.0" +version = "0.36.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "576dfe1fc8f9df304abb159d767a29d0476f7750fbf8aa7ad07816004a207434" +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", ] [[package]] @@ -2977,6 +2971,16 @@ dependencies = [ "pad", ] +[[package]] +name = "prettydiff" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abec3fb083c10660b3854367697da94c674e9e82aa7511014dc958beeb7215e9" +dependencies = [ + "owo-colors", + "pad", +] + [[package]] name = "proc-macro-hack" version = "0.5.20+deprecated" @@ -3334,10 +3338,10 @@ dependencies = [ "bstr", "build_helper", "gimli 0.31.0", - "object 0.34.0", + "object 0.36.2", "regex", "similar", - "wasmparser 0.118.2", + "wasmparser 0.214.0", ] [[package]] @@ -3643,7 +3647,7 @@ dependencies = [ "itertools", "libc", "measureme", - "object 0.32.2", + "object 0.36.2", "rustc-demangle", "rustc_ast", "rustc_attr", @@ -3682,7 +3686,7 @@ dependencies = [ "itertools", "jobserver", "libc", - "object 0.32.2", + "object 0.36.2", "pathdiff", "regex", "rustc_arena", @@ -3712,7 +3716,7 @@ dependencies = [ "thin-vec", "thorin-dwp", "tracing", - "wasm-encoder 0.200.0", + "wasm-encoder 0.210.0", "windows", ] @@ -4665,7 +4669,7 @@ name = "rustc_target" version = "0.0.0" dependencies = [ "bitflags 2.5.0", - "object 0.32.2", + "object 0.36.2", "rustc_abi", "rustc_data_structures", "rustc_feature", @@ -4950,12 +4954,11 @@ dependencies = [ [[package]] name = "ruzstd" -version = "0.6.0" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5174a470eeb535a721ae9fdd6e291c2411a906b96592182d05217591d5c5cf7b" +checksum = "5022b253619b1ba797f243056276bed8ed1a73b0f5a7ce7225d524067644bf8f" dependencies = [ "byteorder", - "derive_more", "twox-hash", ] @@ -5242,7 +5245,7 @@ dependencies = [ "hermit-abi 0.4.0", "libc", "miniz_oxide", - "object 0.36.0", + "object 0.36.2", "panic_abort", "panic_unwind", "profiler_builtins", @@ -5825,7 +5828,7 @@ dependencies = [ "indicatif", "lazy_static", "levenshtein", - "prettydiff", + "prettydiff 0.6.4", "regex", "rustc_version", "rustfix 0.6.1", @@ -5836,9 +5839,9 @@ dependencies = [ [[package]] name = "ui_test" -version = "0.23.0" +version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29e5f4ffcbab82453958fbf59990e981b8e8a177dcd60c2bd8f9b52c3036a6e1" +checksum = "bc1c6c78d55482388711c8d417b8e547263046a607512278fed274c54633bbe4" dependencies = [ "annotate-snippets 0.11.4", "anyhow", @@ -5852,14 +5855,13 @@ dependencies = [ "indicatif", "lazy_static", "levenshtein", - "prettydiff", + "prettydiff 0.7.0", "regex", "rustc_version", "rustfix 0.8.1", "serde", "serde_json", "spanned", - "tempfile", ] [[package]] @@ -6179,15 +6181,6 @@ dependencies = [ "wasm-component-ld", ] -[[package]] -name = "wasm-encoder" -version = "0.200.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9e3fb0c8fbddd78aa6095b850dfeedbc7506cf5f81e633f69cf8f2333ab84b9" -dependencies = [ - "leb128", -] - [[package]] name = "wasm-encoder" version = "0.210.0" @@ -6224,26 +6217,26 @@ dependencies = [ [[package]] name = "wasmparser" -version = "0.118.2" +version = "0.210.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77f1154f1ab868e2a01d9834a805faca7bf8b50d041b4ca714d005d0dab1c50c" +checksum = "a7bbcd21e7581619d9f6ca00f8c4f08f1cacfe58bf63f83af57cd0476f1026f5" dependencies = [ + "ahash", + "bitflags 2.5.0", + "hashbrown", "indexmap", "semver", + "serde", ] [[package]] name = "wasmparser" -version = "0.210.0" +version = "0.214.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7bbcd21e7581619d9f6ca00f8c4f08f1cacfe58bf63f83af57cd0476f1026f5" +checksum = "5309c1090e3e84dad0d382f42064e9933fdaedb87e468cc239f0eabea73ddcb6" dependencies = [ - "ahash", "bitflags 2.5.0", - "hashbrown", "indexmap", - "semver", - "serde", ] [[package]] diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 564213ee7ee86..628badd6f2349 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -2266,6 +2266,11 @@ bitflags::bitflags! { } impl InlineAsmOptions { + pub const COUNT: usize = Self::all().bits().count_ones() as usize; + + pub const GLOBAL_OPTIONS: Self = Self::ATT_SYNTAX.union(Self::RAW); + pub const NAKED_OPTIONS: Self = Self::ATT_SYNTAX.union(Self::RAW).union(Self::NORETURN); + pub fn human_readable_names(&self) -> Vec<&'static str> { let mut options = vec![]; diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index f990b4ba69b3f..6e6aac1ddfc43 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -172,7 +172,7 @@ impl<'hir> LoweringContext<'_, 'hir> { id: NodeId, hir_id: hir::HirId, ident: &mut Ident, - attrs: Option<&'hir [Attribute]>, + attrs: &'hir [Attribute], vis_span: Span, i: &ItemKind, ) -> hir::ItemKind<'hir> { @@ -488,7 +488,7 @@ impl<'hir> LoweringContext<'_, 'hir> { id: NodeId, vis_span: Span, ident: &mut Ident, - attrs: Option<&'hir [Attribute]>, + attrs: &'hir [Attribute], ) -> hir::ItemKind<'hir> { let path = &tree.prefix; let segments = prefix.segments.iter().chain(path.segments.iter()).cloned().collect(); @@ -566,7 +566,7 @@ impl<'hir> LoweringContext<'_, 'hir> { // `ItemLocalId` and the new owner. (See `lower_node_id`) let kind = this.lower_use_tree(use_tree, &prefix, id, vis_span, &mut ident, attrs); - if let Some(attrs) = attrs { + if !attrs.is_empty() { this.attrs.insert(hir::ItemLocalId::ZERO, attrs); } @@ -1525,8 +1525,14 @@ impl<'hir> LoweringContext<'_, 'hir> { continue; } let is_param = *is_param.get_or_insert_with(compute_is_param); - if !is_param { - self.dcx().emit_err(MisplacedRelaxTraitBound { span: bound.span() }); + if !is_param && !self.tcx.features().more_maybe_bounds { + self.tcx + .sess + .create_feature_err( + MisplacedRelaxTraitBound { span: bound.span() }, + sym::more_maybe_bounds, + ) + .emit(); } } } diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 0f5f4d8023bd1..d44f953010a06 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -913,15 +913,15 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { ret } - fn lower_attrs(&mut self, id: HirId, attrs: &[Attribute]) -> Option<&'hir [Attribute]> { + fn lower_attrs(&mut self, id: HirId, attrs: &[Attribute]) -> &'hir [Attribute] { if attrs.is_empty() { - None + &[] } else { debug_assert_eq!(id.owner, self.current_hir_id_owner); let ret = self.arena.alloc_from_iter(attrs.iter().map(|a| self.lower_attr(a))); debug_assert!(!ret.is_empty()); self.attrs.insert(id.local_id, ret); - Some(ret) + ret } } @@ -1216,6 +1216,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { itctx, TraitBoundModifiers::NONE, ); + let bound = (bound, hir::TraitBoundModifier::None); let bounds = this.arena.alloc_from_iter([bound]); let lifetime_bound = this.elided_dyn_bound(t.span); (bounds, lifetime_bound) @@ -1348,21 +1349,17 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // We can safely ignore constness here since AST validation // takes care of rejecting invalid modifier combinations and // const trait bounds in trait object types. - GenericBound::Trait(ty, modifiers) => match modifiers.polarity { - BoundPolarity::Positive | BoundPolarity::Negative(_) => { - Some(this.lower_poly_trait_ref( - ty, - itctx, - // Still, don't pass along the constness here; we don't want to - // synthesize any host effect args, it'd only cause problems. - TraitBoundModifiers { - constness: BoundConstness::Never, - ..*modifiers - }, - )) - } - BoundPolarity::Maybe(_) => None, - }, + GenericBound::Trait(ty, modifiers) => { + // Still, don't pass along the constness here; we don't want to + // synthesize any host effect args, it'd only cause problems. + let modifiers = TraitBoundModifiers { + constness: BoundConstness::Never, + ..*modifiers + }; + let trait_ref = this.lower_poly_trait_ref(ty, itctx, modifiers); + let polarity = this.lower_trait_bound_modifiers(modifiers); + Some((trait_ref, polarity)) + } GenericBound::Outlives(lifetime) => { if lifetime_bound.is_none() { lifetime_bound = Some(this.lower_lifetime(lifetime)); @@ -2688,6 +2685,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { trait_ref: hir::TraitRef { path, hir_ref_id: hir_id }, span: self.lower_span(span), }; + let principal = (principal, hir::TraitBoundModifier::None); // The original ID is taken by the `PolyTraitRef`, // so the `Ty` itself needs a different one. diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 1088db74cc966..9b063a330b746 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -1345,14 +1345,28 @@ impl<'a> Visitor<'a> for AstValidator<'a> { match bound { GenericBound::Trait(trait_ref, modifiers) => { match (ctxt, modifiers.constness, modifiers.polarity) { - (BoundKind::SuperTraits, BoundConstness::Never, BoundPolarity::Maybe(_)) => { - self.dcx().emit_err(errors::OptionalTraitSupertrait { - span: trait_ref.span, - path_str: pprust::path_to_string(&trait_ref.trait_ref.path), - }); + (BoundKind::SuperTraits, BoundConstness::Never, BoundPolarity::Maybe(_)) + if !self.features.more_maybe_bounds => + { + self.session + .create_feature_err( + errors::OptionalTraitSupertrait { + span: trait_ref.span, + path_str: pprust::path_to_string(&trait_ref.trait_ref.path), + }, + sym::more_maybe_bounds, + ) + .emit(); } - (BoundKind::TraitObject, BoundConstness::Never, BoundPolarity::Maybe(_)) => { - self.dcx().emit_err(errors::OptionalTraitObject { span: trait_ref.span }); + (BoundKind::TraitObject, BoundConstness::Never, BoundPolarity::Maybe(_)) + if !self.features.more_maybe_bounds => + { + self.session + .create_feature_err( + errors::OptionalTraitObject { span: trait_ref.span }, + sym::more_maybe_bounds, + ) + .emit(); } ( BoundKind::TraitObject, diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 2d9bc45ebc823..6fe50ad0d968f 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -1306,37 +1306,6 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> { // result of `foo(...)` won't help. break 'outer; } - - // We're suggesting `.clone()` on an borrowed value. See if the expression we have - // is an argument to a function or method call, and try to suggest cloning the - // *result* of the call, instead of the argument. This is closest to what people - // would actually be looking for in most cases, with maybe the exception of things - // like `fn(T) -> T`, but even then it is reasonable. - let typeck_results = self.infcx.tcx.typeck(self.mir_def_id()); - let mut prev = expr; - while let hir::Node::Expr(parent) = self.infcx.tcx.parent_hir_node(prev.hir_id) { - if let hir::ExprKind::Call(..) | hir::ExprKind::MethodCall(..) = parent.kind - && let Some(call_ty) = typeck_results.node_type_opt(parent.hir_id) - && let call_ty = call_ty.peel_refs() - && (!call_ty - .walk() - .any(|t| matches!(t.unpack(), ty::GenericArgKind::Lifetime(_))) - || if let ty::Alias(ty::Projection, _) = call_ty.kind() { - // FIXME: this isn't quite right with lifetimes on assoc types, - // but ignore for now. We will only suggest cloning if - // `::Assoc: Clone`, which should keep false positives - // down to a managable ammount. - true - } else { - false - }) - && self.implements_clone(call_ty) - && self.suggest_cloning_inner(err, call_ty, parent) - { - return; - } - prev = parent; - } } } let ty = ty.peel_refs(); @@ -1442,9 +1411,14 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> { // See `tests/ui/moves/needs-clone-through-deref.rs` return false; } + // We don't want to suggest `.clone()` in a move closure, since the value has already been captured. if self.in_move_closure(expr) { return false; } + // We also don't want to suggest cloning a closure itself, since the value has already been captured. + if let hir::ExprKind::Closure(_) = expr.kind { + return false; + } // Try to find predicates on *generic params* that would allow copying `ty` let mut suggestion = if let Some(symbol) = tcx.hir().maybe_get_struct_pattern_shorthand_field(expr) { diff --git a/compiler/rustc_builtin_macros/messages.ftl b/compiler/rustc_builtin_macros/messages.ftl index b56bfa98357b3..a30ab236213a0 100644 --- a/compiler/rustc_builtin_macros/messages.ftl +++ b/compiler/rustc_builtin_macros/messages.ftl @@ -199,6 +199,10 @@ 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_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 + builtin_macros_invalid_crate_attribute = invalid crate attribute builtin_macros_multiple_default_attrs = multiple `#[default]` attributes @@ -216,6 +220,11 @@ builtin_macros_multiple_defaults = multiple declared defaults .note = only one variant can be default .suggestion = make `{$ident}` default +builtin_macros_naked_functions_testing_attribute = + cannot use `#[naked]` with testing attributes + .label = function marked with testing attribute here + .naked_attribute = `#[naked]` is incompatible with testing attributes + builtin_macros_no_default_variant = no default declared .help = make a unit variant default by placing `#[default]` above it .suggestion = make `{$ident}` default diff --git a/compiler/rustc_builtin_macros/src/asm.rs b/compiler/rustc_builtin_macros/src/asm.rs index b8fe6338493d0..62e59f1f4d477 100644 --- a/compiler/rustc_builtin_macros/src/asm.rs +++ b/compiler/rustc_builtin_macros/src/asm.rs @@ -310,6 +310,16 @@ fn err_duplicate_option(p: &Parser<'_>, symbol: Symbol, span: Span) { p.dcx().emit_err(errors::AsmOptAlreadyprovided { span, symbol, full_span }); } +/// Report an invalid option error. +/// +/// This function must be called immediately after the option token is parsed. +/// Otherwise, the suggestion will be incorrect. +fn err_unsupported_option(p: &Parser<'_>, symbol: Symbol, span: Span) { + // Tool-only output + let full_span = if p.token.kind == token::Comma { span.to(p.token.span) } else { span }; + p.dcx().emit_err(errors::GlobalAsmUnsupportedOption { span, symbol, full_span }); +} + /// Try to set the provided option in the provided `AsmArgs`. /// If it is already set, report a duplicate option error. /// @@ -318,13 +328,16 @@ fn err_duplicate_option(p: &Parser<'_>, symbol: Symbol, span: Span) { fn try_set_option<'a>( p: &Parser<'a>, args: &mut AsmArgs, + is_global_asm: bool, symbol: Symbol, option: ast::InlineAsmOptions, ) { - if !args.options.contains(option) { - args.options |= option; - } else { + if is_global_asm && !ast::InlineAsmOptions::GLOBAL_OPTIONS.contains(option) { + err_unsupported_option(p, symbol, p.prev_token.span); + } else if args.options.contains(option) { err_duplicate_option(p, symbol, p.prev_token.span); + } else { + args.options |= option; } } @@ -338,25 +351,33 @@ fn parse_options<'a>( p.expect(&token::OpenDelim(Delimiter::Parenthesis))?; while !p.eat(&token::CloseDelim(Delimiter::Parenthesis)) { - if !is_global_asm && p.eat_keyword(sym::pure) { - try_set_option(p, args, sym::pure, ast::InlineAsmOptions::PURE); - } else if !is_global_asm && p.eat_keyword(sym::nomem) { - try_set_option(p, args, sym::nomem, ast::InlineAsmOptions::NOMEM); - } else if !is_global_asm && p.eat_keyword(sym::readonly) { - try_set_option(p, args, sym::readonly, ast::InlineAsmOptions::READONLY); - } else if !is_global_asm && p.eat_keyword(sym::preserves_flags) { - try_set_option(p, args, sym::preserves_flags, ast::InlineAsmOptions::PRESERVES_FLAGS); - } else if !is_global_asm && p.eat_keyword(sym::noreturn) { - try_set_option(p, args, sym::noreturn, ast::InlineAsmOptions::NORETURN); - } else if !is_global_asm && p.eat_keyword(sym::nostack) { - try_set_option(p, args, sym::nostack, ast::InlineAsmOptions::NOSTACK); - } else if !is_global_asm && p.eat_keyword(sym::may_unwind) { - try_set_option(p, args, kw::Raw, ast::InlineAsmOptions::MAY_UNWIND); - } else if p.eat_keyword(sym::att_syntax) { - try_set_option(p, args, sym::att_syntax, ast::InlineAsmOptions::ATT_SYNTAX); - } else if p.eat_keyword(kw::Raw) { - try_set_option(p, args, kw::Raw, ast::InlineAsmOptions::RAW); - } else { + const OPTIONS: [(Symbol, ast::InlineAsmOptions); ast::InlineAsmOptions::COUNT] = [ + (sym::pure, ast::InlineAsmOptions::PURE), + (sym::nomem, ast::InlineAsmOptions::NOMEM), + (sym::readonly, ast::InlineAsmOptions::READONLY), + (sym::preserves_flags, ast::InlineAsmOptions::PRESERVES_FLAGS), + (sym::noreturn, ast::InlineAsmOptions::NORETURN), + (sym::nostack, ast::InlineAsmOptions::NOSTACK), + (sym::may_unwind, ast::InlineAsmOptions::MAY_UNWIND), + (sym::att_syntax, ast::InlineAsmOptions::ATT_SYNTAX), + (kw::Raw, ast::InlineAsmOptions::RAW), + ]; + + 'blk: { + for (symbol, option) in OPTIONS { + let kw_matched = + if !is_global_asm || ast::InlineAsmOptions::GLOBAL_OPTIONS.contains(option) { + p.eat_keyword(symbol) + } else { + p.eat_keyword_noexpect(symbol) + }; + + if kw_matched { + try_set_option(p, args, is_global_asm, symbol, option); + break 'blk; + } + } + return p.unexpected(); } diff --git a/compiler/rustc_builtin_macros/src/errors.rs b/compiler/rustc_builtin_macros/src/errors.rs index 49d640436c2f3..f17819474adcd 100644 --- a/compiler/rustc_builtin_macros/src/errors.rs +++ b/compiler/rustc_builtin_macros/src/errors.rs @@ -845,6 +845,17 @@ pub(crate) struct AsmOptAlreadyprovided { pub(crate) full_span: Span, } +#[derive(Diagnostic)] +#[diag(builtin_macros_global_asm_unsupported_option)] +pub(crate) struct GlobalAsmUnsupportedOption { + #[primary_span] + #[label] + pub(crate) span: Span, + pub(crate) symbol: Symbol, + #[suggestion(code = "", applicability = "machine-applicable", style = "tool-only")] + pub(crate) full_span: Span, +} + #[derive(Diagnostic)] #[diag(builtin_macros_test_runner_invalid)] pub(crate) struct TestRunnerInvalid { @@ -912,3 +923,13 @@ pub(crate) struct ExpectedItem<'a> { pub span: Span, pub token: &'a str, } + +#[derive(Diagnostic)] +#[diag(builtin_macros_naked_functions_testing_attribute, code = E0736)] +pub struct NakedFunctionTestingAttribute { + #[primary_span] + #[label(builtin_macros_naked_attribute)] + pub naked_span: Span, + #[label] + pub testing_span: Span, +} diff --git a/compiler/rustc_builtin_macros/src/test.rs b/compiler/rustc_builtin_macros/src/test.rs index c0310a2f4b003..bb00c8de1b808 100644 --- a/compiler/rustc_builtin_macros/src/test.rs +++ b/compiler/rustc_builtin_macros/src/test.rs @@ -133,6 +133,14 @@ pub(crate) fn expand_test_or_bench( }; }; + if let Some(attr) = attr::find_by_name(&item.attrs, sym::naked) { + cx.dcx().emit_err(errors::NakedFunctionTestingAttribute { + testing_span: attr_sp, + naked_span: attr.span, + }); + return vec![Annotatable::Item(item)]; + } + // check_*_signature will report any errors in the type so compilation // will fail. We shouldn't try to expand in this case because the errors // would be spurious. diff --git a/compiler/rustc_codegen_cranelift/example/std_example.rs b/compiler/rustc_codegen_cranelift/example/std_example.rs index 6cedd84adfe52..e99763e272233 100644 --- a/compiler/rustc_codegen_cranelift/example/std_example.rs +++ b/compiler/rustc_codegen_cranelift/example/std_example.rs @@ -3,7 +3,6 @@ coroutines, stmt_expr_attributes, coroutine_trait, - is_sorted, repr_simd, tuple_trait, unboxed_closures diff --git a/compiler/rustc_codegen_gcc/example/std_example.rs b/compiler/rustc_codegen_gcc/example/std_example.rs index 8ab8fcc525e5c..9e43b4635f0d3 100644 --- a/compiler/rustc_codegen_gcc/example/std_example.rs +++ b/compiler/rustc_codegen_gcc/example/std_example.rs @@ -1,5 +1,5 @@ #![allow(internal_features)] -#![feature(core_intrinsics, coroutines, coroutine_trait, is_sorted, stmt_expr_attributes)] +#![feature(core_intrinsics, coroutines, coroutine_trait, stmt_expr_attributes)] #[cfg(feature="master")] #[cfg(target_arch="x86_64")] diff --git a/compiler/rustc_codegen_llvm/Cargo.toml b/compiler/rustc_codegen_llvm/Cargo.toml index bb5045ec87241..dad4722d620f3 100644 --- a/compiler/rustc_codegen_llvm/Cargo.toml +++ b/compiler/rustc_codegen_llvm/Cargo.toml @@ -12,7 +12,7 @@ bitflags = "2.4.1" itertools = "0.12" libc = "0.2" measureme = "11" -object = { version = "0.32.0", default-features = false, features = ["std", "read"] } +object = { version = "0.36.2", default-features = false, features = ["std", "read"] } rustc-demangle = "0.1.21" rustc_ast = { path = "../rustc_ast" } rustc_attr = { path = "../rustc_attr" } diff --git a/compiler/rustc_codegen_ssa/Cargo.toml b/compiler/rustc_codegen_ssa/Cargo.toml index f7b5b0f310b67..2767ad5ec9ce6 100644 --- a/compiler/rustc_codegen_ssa/Cargo.toml +++ b/compiler/rustc_codegen_ssa/Cargo.toml @@ -41,7 +41,7 @@ tempfile = "3.2" thin-vec = "0.2.12" thorin-dwp = "0.7" tracing = "0.1" -wasm-encoder = "0.200.0" +wasm-encoder = "0.210.0" # tidy-alphabetical-end [target.'cfg(unix)'.dependencies] @@ -50,7 +50,7 @@ libc = "0.2.50" # tidy-alphabetical-end [dependencies.object] -version = "0.32.1" +version = "0.36.2" default-features = false features = ["read_core", "elf", "macho", "pe", "xcoff", "unaligned", "archive", "write", "wasm"] diff --git a/compiler/rustc_codegen_ssa/src/back/archive.rs b/compiler/rustc_codegen_ssa/src/back/archive.rs index ae649cd77c420..eade00d75fdf1 100644 --- a/compiler/rustc_codegen_ssa/src/back/archive.rs +++ b/compiler/rustc_codegen_ssa/src/back/archive.rs @@ -110,13 +110,11 @@ impl<'a> ArArchiveBuilder<'a> { } fn try_filter_fat_archs( - archs: object::read::Result<&[impl FatArch]>, + archs: &[impl FatArch], target_arch: object::Architecture, archive_path: &Path, archive_map_data: &[u8], ) -> io::Result> { - let archs = archs.map_err(|e| io::Error::new(io::ErrorKind::Other, e))?; - let desired = match archs.iter().find(|a| a.architecture() == target_arch) { Some(a) => a, None => return Ok(None), @@ -146,17 +144,15 @@ pub fn try_extract_macho_fat_archive( _ => return Ok(None), }; - match object::macho::FatHeader::parse(&*archive_map) { - Ok(h) if h.magic.get(object::endian::BigEndian) == object::macho::FAT_MAGIC => { - let archs = object::macho::FatHeader::parse_arch32(&*archive_map); - try_filter_fat_archs(archs, target_arch, archive_path, &*archive_map) - } - Ok(h) if h.magic.get(object::endian::BigEndian) == object::macho::FAT_MAGIC_64 => { - let archs = object::macho::FatHeader::parse_arch64(&*archive_map); - try_filter_fat_archs(archs, target_arch, archive_path, &*archive_map) - } + if let Ok(h) = object::read::macho::MachOFatFile32::parse(&*archive_map) { + let archs = h.arches(); + try_filter_fat_archs(archs, target_arch, archive_path, &*archive_map) + } else if let Ok(h) = object::read::macho::MachOFatFile64::parse(&*archive_map) { + let archs = h.arches(); + try_filter_fat_archs(archs, target_arch, archive_path, &*archive_map) + } else { // Not a FatHeader at all, just return None. - _ => Ok(None), + Ok(None) } } diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 8c582fac0d824..f7460a64d0afb 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -700,7 +700,7 @@ fn link_dwarf_object(sess: &Session, cg_results: &CodegenResults, executable_out .truncate(true) .open(dwp_out_filename)?, ); - let mut output_stream = object::write::StreamingBuffer::new(output_stream); + let mut output_stream = thorin::object::write::StreamingBuffer::new(output_stream); package.finish()?.emit(&mut output_stream)?; output_stream.result()?; output_stream.into_inner().flush()?; diff --git a/compiler/rustc_codegen_ssa/src/back/metadata.rs b/compiler/rustc_codegen_ssa/src/back/metadata.rs index 264a98844ad67..31a03a3c94a88 100644 --- a/compiler/rustc_codegen_ssa/src/back/metadata.rs +++ b/compiler/rustc_codegen_ssa/src/back/metadata.rs @@ -656,7 +656,13 @@ pub fn create_metadata_file_for_wasm(sess: &Session, data: &[u8], section_name: imports.import( "env", "__linear_memory", - wasm_encoder::MemoryType { minimum: 0, maximum: None, memory64: true, shared: false }, + wasm_encoder::MemoryType { + minimum: 0, + maximum: None, + memory64: true, + shared: false, + page_size_log2: None, + }, ); } diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index 0cd3e60b0ccbb..491b457358a20 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -8,7 +8,6 @@ use crate::traits::*; use crate::MemFlags; use rustc_middle::mir; -use rustc_middle::ty::cast::{CastTy, IntTy}; use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, TyAndLayout}; use rustc_middle::ty::{self, adjustment::PointerCoercion, Instance, Ty, TyCtxt}; use rustc_middle::{bug, span_bug}; @@ -238,21 +237,21 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } } OperandValue::Immediate(imm) => { - let OperandValueKind::Immediate(in_scalar) = operand_kind else { + let OperandValueKind::Immediate(from_scalar) = operand_kind else { bug!("Found {operand_kind:?} for operand {operand:?}"); }; - if let OperandValueKind::Immediate(out_scalar) = cast_kind - && in_scalar.size(self.cx) == out_scalar.size(self.cx) + if let OperandValueKind::Immediate(to_scalar) = cast_kind + && from_scalar.size(self.cx) == to_scalar.size(self.cx) { - let operand_bty = bx.backend_type(operand.layout); - let cast_bty = bx.backend_type(cast); + let from_backend_ty = bx.backend_type(operand.layout); + let to_backend_ty = bx.backend_type(cast); Some(OperandValue::Immediate(self.transmute_immediate( bx, imm, - in_scalar, - operand_bty, - out_scalar, - cast_bty, + from_scalar, + from_backend_ty, + to_scalar, + to_backend_ty, ))) } else { None @@ -281,6 +280,58 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } } + /// Cast one of the immediates from an [`OperandValue::Immediate`] + /// or an [`OperandValue::Pair`] to an immediate of the target type. + /// + /// Returns `None` if the cast is not possible. + fn cast_immediate( + &self, + bx: &mut Bx, + mut imm: Bx::Value, + from_scalar: abi::Scalar, + from_backend_ty: Bx::Type, + to_scalar: abi::Scalar, + to_backend_ty: Bx::Type, + ) -> Option { + use abi::Primitive::*; + + // When scalars are passed by value, there's no metadata recording their + // valid ranges. For example, `char`s are passed as just `i32`, with no + // way for LLVM to know that they're 0x10FFFF at most. Thus we assume + // the range of the input value too, not just the output range. + self.assume_scalar_range(bx, imm, from_scalar, from_backend_ty); + + imm = match (from_scalar.primitive(), to_scalar.primitive()) { + (Int(_, is_signed), Int(..)) => bx.intcast(imm, to_backend_ty, is_signed), + (Float(_), Float(_)) => { + let srcsz = bx.cx().float_width(from_backend_ty); + let dstsz = bx.cx().float_width(to_backend_ty); + if dstsz > srcsz { + bx.fpext(imm, to_backend_ty) + } else if srcsz > dstsz { + bx.fptrunc(imm, to_backend_ty) + } else { + imm + } + } + (Int(_, is_signed), Float(_)) => { + if is_signed { + bx.sitofp(imm, to_backend_ty) + } else { + bx.uitofp(imm, to_backend_ty) + } + } + (Pointer(..), Pointer(..)) => bx.pointercast(imm, to_backend_ty), + (Int(_, is_signed), Pointer(..)) => { + let usize_imm = bx.intcast(imm, bx.cx().type_isize(), is_signed); + bx.inttoptr(usize_imm, to_backend_ty) + } + (Float(_), Int(_, is_signed)) => bx.cast_float_to_int(is_signed, imm, to_backend_ty), + _ => return None, + }; + Some(imm) + } + /// Transmutes one of the immediates from an [`OperandValue::Immediate`] /// or an [`OperandValue::Pair`] to an immediate of the target type. /// @@ -487,62 +538,33 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { | mir::CastKind::IntToFloat | mir::CastKind::PtrToPtr | mir::CastKind::FnPtrToPtr - // Since int2ptr can have arbitrary integer types as input (so we have to do // sign extension and all that), it is currently best handled in the same code // path as the other integer-to-X casts. | mir::CastKind::PointerWithExposedProvenance => { + let imm = operand.immediate(); + let operand_kind = self.value_kind(operand.layout); + let OperandValueKind::Immediate(from_scalar) = operand_kind else { + bug!("Found {operand_kind:?} for operand {operand:?}"); + }; + let from_backend_ty = bx.cx().immediate_backend_type(operand.layout); + assert!(bx.cx().is_backend_immediate(cast)); - let ll_t_out = bx.cx().immediate_backend_type(cast); + let to_backend_ty = bx.cx().immediate_backend_type(cast); if operand.layout.abi.is_uninhabited() { - let val = OperandValue::Immediate(bx.cx().const_poison(ll_t_out)); + let val = OperandValue::Immediate(bx.cx().const_poison(to_backend_ty)); return OperandRef { val, layout: cast }; } - let r_t_in = - CastTy::from_ty(operand.layout.ty).expect("bad input type for cast"); - let r_t_out = CastTy::from_ty(cast.ty).expect("bad output type for cast"); - let ll_t_in = bx.cx().immediate_backend_type(operand.layout); - let llval = operand.immediate(); - - let newval = match (r_t_in, r_t_out) { - (CastTy::Int(i), CastTy::Int(_)) => { - bx.intcast(llval, ll_t_out, i.is_signed()) - } - (CastTy::Float, CastTy::Float) => { - let srcsz = bx.cx().float_width(ll_t_in); - let dstsz = bx.cx().float_width(ll_t_out); - if dstsz > srcsz { - bx.fpext(llval, ll_t_out) - } else if srcsz > dstsz { - bx.fptrunc(llval, ll_t_out) - } else { - llval - } - } - (CastTy::Int(i), CastTy::Float) => { - if i.is_signed() { - bx.sitofp(llval, ll_t_out) - } else { - bx.uitofp(llval, ll_t_out) - } - } - (CastTy::Ptr(_) | CastTy::FnPtr, CastTy::Ptr(_)) => { - bx.pointercast(llval, ll_t_out) - } - (CastTy::Int(i), CastTy::Ptr(_)) => { - let usize_llval = - bx.intcast(llval, bx.cx().type_isize(), i.is_signed()); - bx.inttoptr(usize_llval, ll_t_out) - } - (CastTy::Float, CastTy::Int(IntTy::I)) => { - bx.cast_float_to_int(true, llval, ll_t_out) - } - (CastTy::Float, CastTy::Int(_)) => { - bx.cast_float_to_int(false, llval, ll_t_out) - } - _ => bug!("unsupported cast: {:?} to {:?}", operand.layout.ty, cast.ty), + let cast_kind = self.value_kind(cast); + let OperandValueKind::Immediate(to_scalar) = cast_kind else { + bug!("Found {cast_kind:?} for operand {cast:?}"); }; - OperandValue::Immediate(newval) + + self.cast_immediate(bx, imm, from_scalar, from_backend_ty, to_scalar, to_backend_ty) + .map(OperandValue::Immediate) + .unwrap_or_else(|| { + bug!("Unsupported cast of {operand:?} to {cast:?}"); + }) } mir::CastKind::Transmute => { self.codegen_transmute_operand(bx, operand, cast).unwrap_or_else(|| { diff --git a/compiler/rustc_error_codes/src/error_codes/E0736.md b/compiler/rustc_error_codes/src/error_codes/E0736.md index 0f3d41ba66dc4..cb7633b7068a3 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0736.md +++ b/compiler/rustc_error_codes/src/error_codes/E0736.md @@ -1,14 +1,20 @@ -`#[track_caller]` and `#[naked]` cannot both be applied to the same function. +Functions marked with the `#[naked]` attribute are restricted in what other +attributes they may be marked with. + +Notable attributes that are incompatible with `#[naked]` are: + +* `#[inline]` +* `#[track_caller]` +* `#[test]`, `#[ignore]`, `#[should_panic]` Erroneous code example: ```compile_fail,E0736 +#[inline] #[naked] -#[track_caller] fn foo() {} ``` -This is primarily due to ABI incompatibilities between the two attributes. -See [RFC 2091] for details on this and other limitations. - -[RFC 2091]: https://github.com/rust-lang/rfcs/blob/master/text/2091-inline-semantic.md +These incompatibilities are due to the fact that naked functions deliberately +impose strict restrictions regarding the code that the compiler is +allowed to produce for this function. diff --git a/compiler/rustc_error_codes/src/error_codes/E0739.md b/compiler/rustc_error_codes/src/error_codes/E0739.md index 8d9039bef93f6..406d3d52779db 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0739.md +++ b/compiler/rustc_error_codes/src/error_codes/E0739.md @@ -1,4 +1,4 @@ -`#[track_caller]` can not be applied on struct. +`#[track_caller]` must be applied to a function Erroneous code example: diff --git a/compiler/rustc_expand/messages.ftl b/compiler/rustc_expand/messages.ftl index cc0b110d2bc6f..18d95a398fd4f 100644 --- a/compiler/rustc_expand/messages.ftl +++ b/compiler/rustc_expand/messages.ftl @@ -105,6 +105,11 @@ expand_meta_var_dif_seq_matchers = {$msg} expand_meta_var_expr_unrecognized_var = variable `{$key}` is not recognized in meta-variable expression +expand_missing_fragment_specifier = missing fragment specifier + .note = fragment specifiers must be specified in the 2024 edition + .suggestion_add_fragspec = try adding a specifier here + .valid = {$valid} + expand_module_circular = circular modules: {$modules} diff --git a/compiler/rustc_expand/src/errors.rs b/compiler/rustc_expand/src/errors.rs index 0be7403f25b17..6f1a0f16c49ff 100644 --- a/compiler/rustc_expand/src/errors.rs +++ b/compiler/rustc_expand/src/errors.rs @@ -416,6 +416,23 @@ pub struct DuplicateMatcherBinding { pub prev: Span, } +#[derive(Diagnostic)] +#[diag(expand_missing_fragment_specifier)] +#[note] +#[help(expand_valid)] +pub struct MissingFragmentSpecifier { + #[primary_span] + pub span: Span, + #[suggestion( + expand_suggestion_add_fragspec, + style = "verbose", + code = ":spec", + applicability = "maybe-incorrect" + )] + pub add_span: Span, + pub valid: &'static str, +} + #[derive(Diagnostic)] #[diag(expand_invalid_fragment_specifier)] #[help] diff --git a/compiler/rustc_expand/src/mbe/macro_check.rs b/compiler/rustc_expand/src/mbe/macro_check.rs index 4b730d307fd6c..161e27fe02c61 100644 --- a/compiler/rustc_expand/src/mbe/macro_check.rs +++ b/compiler/rustc_expand/src/mbe/macro_check.rs @@ -115,6 +115,7 @@ use rustc_errors::MultiSpan; use rustc_lint_defs::BuiltinLintDiag; use rustc_session::lint::builtin::{META_VARIABLE_MISUSE, MISSING_FRAGMENT_SPECIFIER}; use rustc_session::parse::ParseSess; +use rustc_span::edition::Edition; use rustc_span::symbol::kw; use rustc_span::{symbol::MacroRulesNormalizedIdent, ErrorGuaranteed, Span}; @@ -122,6 +123,8 @@ use smallvec::SmallVec; use std::iter; +use super::quoted::VALID_FRAGMENT_NAMES_MSG_2021; + /// Stack represented as linked list. /// /// Those are used for environments because they grow incrementally and are not mutable. @@ -269,12 +272,20 @@ fn check_binders( // FIXME: Report this as a hard error eventually and remove equivalent errors from // `parse_tt_inner` and `nameize`. Until then the error may be reported twice, once // as a hard error and then once as a buffered lint. - psess.buffer_lint( - MISSING_FRAGMENT_SPECIFIER, - span, - node_id, - BuiltinLintDiag::MissingFragmentSpecifier, - ); + if span.edition() >= Edition::Edition2024 { + psess.dcx().emit_err(errors::MissingFragmentSpecifier { + span, + add_span: span.shrink_to_hi(), + valid: VALID_FRAGMENT_NAMES_MSG_2021, + }); + } else { + psess.buffer_lint( + MISSING_FRAGMENT_SPECIFIER, + span, + node_id, + BuiltinLintDiag::MissingFragmentSpecifier, + ); + } } if !macros.is_empty() { psess.dcx().span_bug(span, "unexpected MetaVarDecl in nested lhs"); diff --git a/compiler/rustc_expand/src/mbe/quoted.rs b/compiler/rustc_expand/src/mbe/quoted.rs index 9c480f17b4215..57b6947316d65 100644 --- a/compiler/rustc_expand/src/mbe/quoted.rs +++ b/compiler/rustc_expand/src/mbe/quoted.rs @@ -16,7 +16,7 @@ use rustc_span::Span; const VALID_FRAGMENT_NAMES_MSG: &str = "valid fragment specifiers are \ `ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, \ `literal`, `path`, `meta`, `tt`, `item` and `vis`"; -const VALID_FRAGMENT_NAMES_MSG_2021: &str = "valid fragment specifiers are \ +pub const VALID_FRAGMENT_NAMES_MSG_2021: &str = "valid fragment specifiers are \ `ident`, `block`, `stmt`, `expr`, `expr_2021`, `pat`, \ `ty`, `lifetime`, `literal`, `path`, `meta`, `tt`, \ `item` and `vis`"; diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 9b5ed3b0876a5..d3d071810962b 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -205,6 +205,8 @@ declare_features! ( (unstable, lifetime_capture_rules_2024, "1.76.0", None), /// Allows `#[link(..., cfg(..))]`; perma-unstable per #37406 (unstable, link_cfg, "1.14.0", None), + /// Allows using `?Trait` trait bounds in more contexts. + (internal, more_maybe_bounds, "CURRENT_RUSTC_VERSION", None), /// Allows the `multiple_supertrait_upcastable` lint. (unstable, multiple_supertrait_upcastable, "1.69.0", None), /// Allow negative trait bounds. This is an internal-only feature for testing the trait solver! diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 20b15499234ec..8c8f760bc41dc 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -2832,7 +2832,11 @@ pub enum TyKind<'hir> { OpaqueDef(ItemId, &'hir [GenericArg<'hir>], bool), /// A trait object type `Bound1 + Bound2 + Bound3` /// where `Bound` is a trait or a lifetime. - TraitObject(&'hir [PolyTraitRef<'hir>], &'hir Lifetime, TraitObjectSyntax), + TraitObject( + &'hir [(PolyTraitRef<'hir>, TraitBoundModifier)], + &'hir Lifetime, + TraitObjectSyntax, + ), /// Unused for now. Typeof(&'hir AnonConst), /// `TyKind::Infer` means the type should be inferred instead of it having been diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index c202ee41e3132..696f548f1ba07 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -902,7 +902,9 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty<'v>) -> V::Resul try_visit!(visitor.visit_array_length(length)); } TyKind::TraitObject(bounds, ref lifetime, _syntax) => { - walk_list!(visitor, visit_poly_trait_ref, bounds); + for (bound, _modifier) in bounds { + try_visit!(visitor.visit_poly_trait_ref(bound)); + } try_visit!(visitor.visit_lifetime(lifetime)); } TyKind::Typeof(ref expression) => try_visit!(visitor.visit_anon_const(expression)), diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index 58cc0f6211120..1821387e85f88 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -162,6 +162,7 @@ language_item_table! { StructuralPeq, sym::structural_peq, structural_peq_trait, Target::Trait, GenericRequirement::None; Copy, sym::copy, copy_trait, Target::Trait, GenericRequirement::Exact(0); Clone, sym::clone, clone_trait, Target::Trait, GenericRequirement::None; + CloneFn, sym::clone_fn, clone_fn, Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None; Sync, sym::sync, sync_trait, Target::Trait, GenericRequirement::Exact(0); DiscriminantKind, sym::discriminant_kind, discriminant_kind_trait, Target::Trait, GenericRequirement::None; /// The associated item of the `DiscriminantKind` trait. diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl index cc404daa51f59..367f6e17e7fe6 100644 --- a/compiler/rustc_hir_analysis/messages.ftl +++ b/compiler/rustc_hir_analysis/messages.ftl @@ -1,4 +1,4 @@ -hir_analysis_ambiguous_assoc_item = ambiguous associated {$assoc_kind} `{$assoc_name}` in bounds of `{$ty_param_name}` +hir_analysis_ambiguous_assoc_item = ambiguous associated {$assoc_kind} `{$assoc_name}` in bounds of `{$qself}` .label = ambiguous associated {$assoc_kind} `{$assoc_name}` hir_analysis_ambiguous_lifetime_bound = @@ -12,16 +12,21 @@ hir_analysis_assoc_item_is_private = {$kind} `{$name}` is private .label = private {$kind} .defined_here_label = the {$kind} is defined here -hir_analysis_assoc_item_not_found = associated {$assoc_kind} `{$assoc_name}` not found for `{$ty_param_name}` +hir_analysis_assoc_item_not_found = associated {$assoc_kind} `{$assoc_name}` not found for `{$qself}` hir_analysis_assoc_item_not_found_found_in_other_trait_label = there is {$identically_named -> [true] an *[false] a similarly named } associated {$assoc_kind} `{$suggested_name}` in the trait `{$trait_name}` hir_analysis_assoc_item_not_found_label = associated {$assoc_kind} `{$assoc_name}` not found -hir_analysis_assoc_item_not_found_other_sugg = `{$ty_param_name}` has the following associated {$assoc_kind} +hir_analysis_assoc_item_not_found_other_sugg = `{$qself}` has the following associated {$assoc_kind} +hir_analysis_assoc_item_not_found_similar_in_other_trait_qpath_sugg = + consider fully qualifying{$identically_named -> + [true] {""} + *[false] {" "}and renaming + } the associated {$assoc_kind} hir_analysis_assoc_item_not_found_similar_in_other_trait_sugg = change the associated {$assoc_kind} name to use `{$suggested_name}` from `{$trait_name}` -hir_analysis_assoc_item_not_found_similar_in_other_trait_with_bound_sugg = and also change the associated {$assoc_kind} name +hir_analysis_assoc_item_not_found_similar_in_other_trait_with_bound_sugg = ...and changing the associated {$assoc_kind} name hir_analysis_assoc_item_not_found_similar_sugg = there is an associated {$assoc_kind} with a similar name hir_analysis_assoc_kind_mismatch = expected {$expected}, found {$got} diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 0316ef69bf83e..456dc4e4e0704 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -831,7 +831,7 @@ impl<'tcx> TypeVisitor> for GATArgsCollector<'tcx> { fn could_be_self(trait_def_id: LocalDefId, ty: &hir::Ty<'_>) -> bool { match ty.kind { - hir::TyKind::TraitObject([trait_ref], ..) => match trait_ref.trait_ref.path.segments { + hir::TyKind::TraitObject([(trait_ref, _)], ..) => match trait_ref.trait_ref.path.segments { [s] => s.res.opt_def_id() == Some(trait_def_id.to_def_id()), _ => false, }, diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs index 349dc9ad00ed3..02ea95852f01b 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -652,7 +652,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { debug!(?bounds, ?lifetime, "TraitObject"); let scope = Scope::TraitRefBoundary { s: self.scope }; self.with(scope, |this| { - for bound in bounds { + for (bound, _) in bounds { this.visit_poly_trait_ref_inner( bound, NonLifetimeBinderAllowed::Deny("trait object types"), diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index c83788928a978..c364a56163106 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -22,7 +22,7 @@ pub struct AmbiguousAssocItem<'a> { pub span: Span, pub assoc_kind: &'static str, pub assoc_name: Ident, - pub ty_param_name: &'a str, + pub qself: &'a str, } #[derive(Diagnostic)] @@ -75,7 +75,7 @@ pub struct AssocItemNotFound<'a> { pub span: Span, pub assoc_name: Ident, pub assoc_kind: &'static str, - pub ty_param_name: &'a str, + pub qself: &'a str, #[subdiagnostic] pub label: Option>, #[subdiagnostic] @@ -126,13 +126,32 @@ pub enum AssocItemNotFoundSugg<'a> { assoc_kind: &'static str, suggested_name: Symbol, }, - #[suggestion(hir_analysis_assoc_item_not_found_other_sugg, code = "{suggested_name}")] + #[multipart_suggestion( + hir_analysis_assoc_item_not_found_similar_in_other_trait_qpath_sugg, + style = "verbose" + )] + SimilarInOtherTraitQPath { + #[suggestion_part(code = "<")] + lo: Span, + #[suggestion_part(code = " as {trait_ref}>")] + mi: Span, + #[suggestion_part(code = "{suggested_name}")] + hi: Option, + trait_ref: String, + suggested_name: Symbol, + identically_named: bool, + #[applicability] + applicability: Applicability, + }, + #[suggestion( + hir_analysis_assoc_item_not_found_other_sugg, + code = "{suggested_name}", + applicability = "maybe-incorrect" + )] Other { #[primary_span] span: Span, - #[applicability] - applicability: Applicability, - ty_param_name: &'a str, + qself: &'a str, assoc_kind: &'static str, suggested_name: Symbol, }, diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs index 6f9c481650b21..30c04aa47a358 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs @@ -6,19 +6,17 @@ use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_middle::bug; -use rustc_middle::ty::print::PrintTraitRefExt as _; use rustc_middle::ty::{self as ty, IsSuggestable, Ty, TyCtxt}; use rustc_span::symbol::Ident; -use rustc_span::{ErrorGuaranteed, Span, Symbol}; +use rustc_span::{sym, ErrorGuaranteed, Span, Symbol}; use rustc_trait_selection::traits; use rustc_type_ir::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor}; use smallvec::SmallVec; use crate::bounds::Bounds; use crate::errors; -use crate::hir_ty_lowering::{HirTyLowerer, OnlySelfBounds, PredicateFilter}; - -use super::RegionInferReason; +use crate::hir_ty_lowering::HirTyLowerer; +use crate::hir_ty_lowering::{AssocItemQSelf, OnlySelfBounds, PredicateFilter, RegionInferReason}; impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { /// Add a `Sized` bound to the `bounds` if appropriate. @@ -75,10 +73,22 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } } + let mut unique_bounds = FxIndexSet::default(); + let mut seen_repeat = false; + for unbound in &unbounds { + if let Res::Def(DefKind::Trait, unbound_def_id) = unbound.trait_ref.path.res { + seen_repeat |= !unique_bounds.insert(unbound_def_id); + } + } if unbounds.len() > 1 { - self.dcx().emit_err(errors::MultipleRelaxedDefaultBounds { + let err = errors::MultipleRelaxedDefaultBounds { spans: unbounds.iter().map(|ptr| ptr.span).collect(), - }); + }; + if seen_repeat { + self.dcx().emit_err(err); + } else if !tcx.features().more_maybe_bounds { + self.tcx().sess.create_feature_err(err, sym::more_maybe_bounds).emit(); + }; } let mut seen_sized_unbound = false; @@ -288,8 +298,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { // one that does define it. self.probe_single_bound_for_assoc_item( || traits::supertraits(tcx, trait_ref), - trait_ref.skip_binder().print_only_trait_name(), - None, + AssocItemQSelf::Trait(trait_ref.def_id()), assoc_kind, constraint.ident, path_span, diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs index 8ff6ced8b3983..20f06d7748907 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs @@ -3,7 +3,7 @@ use crate::errors::{ ParenthesizedFnTraitExpansion, TraitObjectDeclaredWithNoTraits, }; use crate::fluent_generated as fluent; -use crate::hir_ty_lowering::HirTyLowerer; +use crate::hir_ty_lowering::{AssocItemQSelf, HirTyLowerer}; use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_data_structures::sorted_map::SortedMap; use rustc_data_structures::unord::UnordMap; @@ -11,9 +11,9 @@ use rustc_errors::MultiSpan; use rustc_errors::{ codes::*, pluralize, struct_span_code_err, Applicability, Diag, ErrorGuaranteed, }; +use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::def_id::{DefId, LocalDefId}; -use rustc_hir::{self as hir, Node}; +use rustc_hir::def_id::DefId; use rustc_middle::bug; use rustc_middle::query::Key; use rustc_middle::ty::print::{PrintPolyTraitRefExt as _, PrintTraitRefExt as _}; @@ -116,8 +116,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { pub(super) fn complain_about_assoc_item_not_found( &self, all_candidates: impl Fn() -> I, - ty_param_name: &str, - ty_param_def_id: Option, + qself: AssocItemQSelf, assoc_kind: ty::AssocKind, assoc_name: Ident, span: Span, @@ -139,7 +138,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { ); } - let assoc_kind_str = super::assoc_kind_str(assoc_kind); + let assoc_kind_str = assoc_kind_str(assoc_kind); + let qself_str = qself.to_string(tcx); // The fallback span is needed because `assoc_name` might be an `Fn()`'s `Output` without a // valid span, so we point at the whole path segment instead. @@ -149,7 +149,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { span: if is_dummy { span } else { assoc_name.span }, assoc_name, assoc_kind: assoc_kind_str, - ty_param_name, + qself: &qself_str, label: None, sugg: None, }; @@ -219,19 +219,28 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { suggested_name, identically_named: suggested_name == assoc_name.name, }); - let hir = tcx.hir(); - if let Some(def_id) = ty_param_def_id - && let parent = hir.get_parent_item(tcx.local_def_id_to_hir_id(def_id)) - && let Some(generics) = hir.get_generics(parent.def_id) + if let AssocItemQSelf::TyParam(ty_param_def_id, ty_param_span) = qself + // Not using `self.item_def_id()` here as that would yield the opaque type itself if we're + // inside an opaque type while we're interested in the overarching type alias (TAIT). + // FIXME: However, for trait aliases, this incorrectly returns the enclosing module... + && let item_def_id = + tcx.hir().get_parent_item(tcx.local_def_id_to_hir_id(ty_param_def_id)) + // FIXME: ...which obviously won't have any generics. + && let Some(generics) = tcx.hir().get_generics(item_def_id.def_id) { - if generics.bounds_for_param(def_id).flat_map(|pred| pred.bounds.iter()).any( - |b| match b { + // FIXME: Suggest adding supertrait bounds if we have a `Self` type param. + // FIXME(trait_alias): Suggest adding `Self: Trait` to + // `trait Alias = where Self::Proj:;` with `trait Trait { type Proj; }`. + if generics + .bounds_for_param(ty_param_def_id) + .flat_map(|pred| pred.bounds.iter()) + .any(|b| match b { hir::GenericBound::Trait(t, ..) => { t.trait_ref.trait_def_id() == Some(best_trait) } _ => false, - }, - ) { + }) + { // The type param already has a bound for `trait_name`, we just need to // change the associated item. err.sugg = Some(errors::AssocItemNotFoundSugg::SimilarInOtherTrait { @@ -242,48 +251,60 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { return self.dcx().emit_err(err); } - let mut err = self.dcx().create_err(err); - if suggest_constraining_type_param( - tcx, - generics, - &mut err, - &ty_param_name, - &trait_name, - None, - None, - ) && suggested_name != assoc_name.name + let trait_args = &ty::GenericArgs::identity_for_item(tcx, best_trait)[1..]; + let mut trait_ref = trait_name.clone(); + let applicability = if let [arg, args @ ..] = trait_args { + use std::fmt::Write; + write!(trait_ref, ""; + Applicability::HasPlaceholders + } else { + Applicability::MaybeIncorrect + }; + + let identically_named = suggested_name == assoc_name.name; + + if let DefKind::TyAlias = tcx.def_kind(item_def_id) + && !tcx.type_alias_is_lazy(item_def_id) { - // We suggested constraining a type parameter, but the associated item on it - // was also not an exact match, so we also suggest changing it. - err.span_suggestion_verbose( - assoc_name.span, - fluent::hir_analysis_assoc_item_not_found_similar_in_other_trait_with_bound_sugg, + err.sugg = Some(errors::AssocItemNotFoundSugg::SimilarInOtherTraitQPath { + lo: ty_param_span.shrink_to_lo(), + mi: ty_param_span.shrink_to_hi(), + hi: (!identically_named).then_some(assoc_name.span), + trait_ref, + identically_named, suggested_name, - Applicability::MaybeIncorrect, - ); + applicability, + }); + } else { + let mut err = self.dcx().create_err(err); + if suggest_constraining_type_param( + tcx, generics, &mut err, &qself_str, &trait_ref, None, None, + ) && !identically_named + { + // We suggested constraining a type parameter, but the associated item on it + // was also not an exact match, so we also suggest changing it. + err.span_suggestion_verbose( + assoc_name.span, + fluent::hir_analysis_assoc_item_not_found_similar_in_other_trait_with_bound_sugg, + suggested_name, + Applicability::MaybeIncorrect, + ); + } + return err.emit(); } - return err.emit(); } return self.dcx().emit_err(err); } } // If we still couldn't find any associated item, and only one associated item exists, - // suggests using it. + // suggest using it. if let [candidate_name] = all_candidate_names.as_slice() { - // This should still compile, except on `#![feature(associated_type_defaults)]` - // where it could suggests `type A = Self::A`, thus recursing infinitely. - let applicability = - if assoc_kind == ty::AssocKind::Type && tcx.features().associated_type_defaults { - Applicability::Unspecified - } else { - Applicability::MaybeIncorrect - }; - err.sugg = Some(errors::AssocItemNotFoundSugg::Other { span: assoc_name.span, - applicability, - ty_param_name, + qself: &qself_str, assoc_kind: assoc_kind_str, suggested_name: *candidate_name, }); @@ -349,10 +370,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { self.dcx().emit_err(errors::AssocKindMismatch { span, - expected: super::assoc_kind_str(expected), - got: super::assoc_kind_str(got), + expected: assoc_kind_str(expected), + got: assoc_kind_str(got), expected_because_label, - assoc_kind: super::assoc_kind_str(assoc_item.kind), + assoc_kind: assoc_kind_str(assoc_item.kind), def_span: tcx.def_span(assoc_item.def_id), bound_on_assoc_const_label, wrap_in_braces_sugg, @@ -698,7 +719,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { &self, associated_types: FxIndexMap>, potential_assoc_types: Vec, - trait_bounds: &[hir::PolyTraitRef<'_>], + trait_bounds: &[(hir::PolyTraitRef<'_>, hir::TraitBoundModifier)], ) { if associated_types.values().all(|v| v.is_empty()) { return; @@ -744,12 +765,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { // related to issue #91997, turbofishes added only when in an expr or pat let mut in_expr_or_pat = false; if let ([], [bound]) = (&potential_assoc_types[..], &trait_bounds) { - let grandparent = tcx.parent_hir_node(tcx.parent_hir_id(bound.trait_ref.hir_ref_id)); + let grandparent = tcx.parent_hir_node(tcx.parent_hir_id(bound.0.trait_ref.hir_ref_id)); in_expr_or_pat = match grandparent { - Node::Expr(_) | Node::Pat(_) => true, + hir::Node::Expr(_) | hir::Node::Pat(_) => true, _ => false, }; - match bound.trait_ref.path.segments { + match bound.0.trait_ref.path.segments { // FIXME: `trait_ref.path.span` can point to a full path with multiple // segments, even though `trait_ref.path.segments` is of length `1`. Work // around that bug here, even though it should be fixed elsewhere. @@ -790,7 +811,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { // and we can then use their span to indicate this to the user. let bound_names = trait_bounds .iter() - .filter_map(|poly_trait_ref| { + .filter_map(|(poly_trait_ref, _)| { let path = poly_trait_ref.trait_ref.path.segments.last()?; let args = path.args?; @@ -1612,3 +1633,11 @@ fn generics_args_err_extend<'a>( _ => {} } } + +pub(super) fn assoc_kind_str(kind: ty::AssocKind) -> &'static str { + match kind { + ty::AssocKind::Fn => "function", + ty::AssocKind::Const => "constant", + ty::AssocKind::Type => "type", + } +} diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs index 29c71c3fa50b5..e7aad0a29c50c 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs @@ -34,7 +34,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { .ok() .is_some_and(|s| s.trim_end().ends_with('<')); - let is_global = poly_trait_ref.trait_ref.path.is_global(); + let is_global = poly_trait_ref.0.trait_ref.path.is_global(); let mut sugg = vec![( self_ty.span.shrink_to_lo(), @@ -176,7 +176,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let mut is_downgradable = true; let is_object_safe = match self_ty.kind { hir::TyKind::TraitObject(objects, ..) => { - objects.iter().all(|o| match o.trait_ref.path.res { + objects.iter().all(|(o, _)| match o.trait_ref.path.res { Res::Def(DefKind::Trait, id) => { if Some(id) == owner { // For recursive traits, don't downgrade the error. (#119652) diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index d6eb1a66902fc..ce298641e6060 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -55,7 +55,6 @@ use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::traits::wf::object_region_bounds; use rustc_trait_selection::traits::{self, ObligationCtxt}; -use std::fmt::Display; use std::slice; /// A path segment that is semantically allowed to have generic arguments. @@ -193,6 +192,25 @@ pub trait HirTyLowerer<'tcx> { } } +/// The "qualified self" of an associated item path. +/// +/// For diagnostic purposes only. +enum AssocItemQSelf { + Trait(DefId), + TyParam(LocalDefId, Span), + SelfTyAlias, +} + +impl AssocItemQSelf { + fn to_string(&self, tcx: TyCtxt<'_>) -> String { + match *self { + Self::Trait(def_id) => tcx.def_path_str(def_id), + Self::TyParam(def_id, _) => tcx.hir().ty_param_name(def_id).to_string(), + Self::SelfTyAlias => kw::SelfUpper.to_string(), + } + } +} + /// New-typed boolean indicating whether explicit late-bound lifetimes /// are present in a set of generic arguments. /// @@ -802,6 +820,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { fn probe_single_ty_param_bound_for_assoc_ty( &self, ty_param_def_id: LocalDefId, + ty_param_span: Span, assoc_name: Ident, span: Span, ) -> Result, ErrorGuaranteed> { @@ -811,19 +830,14 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let predicates = &self.probe_ty_param_bounds(span, ty_param_def_id, assoc_name).predicates; debug!("predicates={:#?}", predicates); - let param_name = tcx.hir().ty_param_name(ty_param_def_id); self.probe_single_bound_for_assoc_item( || { - traits::transitive_bounds_that_define_assoc_item( - tcx, - predicates - .iter() - .filter_map(|(p, _)| Some(p.as_trait_clause()?.map_bound(|t| t.trait_ref))), - assoc_name, - ) + let trait_refs = predicates + .iter() + .filter_map(|(p, _)| Some(p.as_trait_clause()?.map_bound(|t| t.trait_ref))); + traits::transitive_bounds_that_define_assoc_item(tcx, trait_refs, assoc_name) }, - param_name, - Some(ty_param_def_id), + AssocItemQSelf::TyParam(ty_param_def_id, ty_param_span), ty::AssocKind::Type, assoc_name, span, @@ -835,12 +849,11 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { /// /// This fails if there is no such bound in the list of candidates or if there are multiple /// candidates in which case it reports ambiguity. - #[instrument(level = "debug", skip(self, all_candidates, ty_param_name, constraint), ret)] + #[instrument(level = "debug", skip(self, all_candidates, qself, constraint), ret)] fn probe_single_bound_for_assoc_item( &self, all_candidates: impl Fn() -> I, - ty_param_name: impl Display, - ty_param_def_id: Option, + qself: AssocItemQSelf, assoc_kind: ty::AssocKind, assoc_name: Ident, span: Span, @@ -858,8 +871,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let Some(bound) = matching_candidates.next() else { let reported = self.complain_about_assoc_item_not_found( all_candidates, - &ty_param_name.to_string(), - ty_param_def_id, + qself, assoc_kind, assoc_name, span, @@ -872,13 +884,13 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { if let Some(bound2) = matching_candidates.next() { debug!(?bound2); - let assoc_kind_str = assoc_kind_str(assoc_kind); - let ty_param_name = &ty_param_name.to_string(); + let assoc_kind_str = errors::assoc_kind_str(assoc_kind); + let qself_str = qself.to_string(tcx); let mut err = self.dcx().create_err(crate::errors::AmbiguousAssocItem { span, assoc_kind: assoc_kind_str, assoc_name, - ty_param_name, + qself: &qself_str, }); // Provide a more specific error code index entry for equality bindings. err.code( @@ -929,7 +941,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { err.span_suggestion_verbose( span.with_hi(assoc_name.span.lo()), "use fully-qualified syntax to disambiguate", - format!("<{ty_param_name} as {}>::", bound.print_only_trait_path()), + format!("<{qself_str} as {}>::", bound.print_only_trait_path()), Applicability::MaybeIncorrect, ); } @@ -943,7 +955,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { if !where_bounds.is_empty() { err.help(format!( "consider introducing a new type parameter `T` and adding `where` constraints:\ - \n where\n T: {ty_param_name},\n{}", + \n where\n T: {qself_str},\n{}", where_bounds.join(",\n"), )); } @@ -997,11 +1009,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let tcx = self.tcx(); let assoc_ident = assoc_segment.ident; - let qself_res = if let hir::TyKind::Path(hir::QPath::Resolved(_, path)) = &qself.kind { - path.res - } else { - Res::Err - }; // Check if we have an enum variant or an inherent associated type. let mut variant_resolution = None; @@ -1038,6 +1045,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } } + let qself_res = if let hir::TyKind::Path(hir::QPath::Resolved(_, path)) = &qself.kind { + path.res + } else { + Res::Err + }; + // Find the type of the associated item, and the trait where the associated // item is declared. let bound = match (&qself_ty.kind(), qself_res) { @@ -1056,8 +1069,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { ty::Binder::dummy(trait_ref.instantiate_identity()), ) }, - kw::SelfUpper, - None, + AssocItemQSelf::SelfTyAlias, ty::AssocKind::Type, assoc_ident, span, @@ -1069,6 +1081,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { Res::SelfTyParam { trait_: param_did } | Res::Def(DefKind::TyParam, param_did), ) => self.probe_single_ty_param_bound_for_assoc_ty( param_did.expect_local(), + qself.span, assoc_ident, span, )?, @@ -2522,11 +2535,3 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { Some(r) } } - -fn assoc_kind_str(kind: ty::AssocKind) -> &'static str { - match kind { - ty::AssocKind::Fn => "function", - ty::AssocKind::Const => "constant", - ty::AssocKind::Type => "type", - } -} diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/object_safety.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/object_safety.rs index aafadc7f9cbea..b3c7a1ff8a8b5 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/object_safety.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/object_safety.rs @@ -27,7 +27,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { &self, span: Span, hir_id: hir::HirId, - hir_trait_bounds: &[hir::PolyTraitRef<'tcx>], + hir_trait_bounds: &[(hir::PolyTraitRef<'tcx>, hir::TraitBoundModifier)], lifetime: &hir::Lifetime, borrowed: bool, representation: DynKind, @@ -37,7 +37,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let mut bounds = Bounds::default(); let mut potential_assoc_types = Vec::new(); let dummy_self = self.tcx().types.trait_object_dummy_self; - for trait_bound in hir_trait_bounds.iter().rev() { + for (trait_bound, modifier) in hir_trait_bounds.iter().rev() { + if *modifier == hir::TraitBoundModifier::Maybe { + continue; + } if let GenericArgCountResult { correct: Err(GenericArgCountMismatch { invalid_args: cur_potential_assoc_types, .. }), @@ -249,7 +252,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let args = tcx.mk_args(&args); let span = i.bottom().1; - let empty_generic_args = hir_trait_bounds.iter().any(|hir_bound| { + let empty_generic_args = hir_trait_bounds.iter().any(|(hir_bound, _)| { hir_bound.trait_ref.path.res == Res::Def(DefKind::Trait, trait_ref.def_id) && hir_bound.span.contains(span) }); diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index dd7fbba753bdd..89b981ab80dd5 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -64,7 +64,6 @@ This API is completely unstable and subject to change. #![doc(rust_logo)] #![feature(control_flow_enum)] #![feature(if_let_guard)] -#![feature(is_sorted)] #![feature(iter_intersperse)] #![feature(let_chains)] #![feature(never_type)] diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index a982b84e755be..e25f43e169dd7 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -300,13 +300,16 @@ impl<'a> State<'a> { self.word_space("dyn"); } let mut first = true; - for bound in bounds { + for (bound, modifier) in bounds { if first { first = false; } else { self.nbsp(); self.word_space("+"); } + if *modifier == TraitBoundModifier::Maybe { + self.word("?"); + } self.print_poly_trait_ref(bound); } if !lifetime.is_elided() { diff --git a/compiler/rustc_hir_typeck/src/method/prelude_edition_lints.rs b/compiler/rustc_hir_typeck/src/method/prelude_edition_lints.rs index 3ee10f74d98a4..3a902390fcff9 100644 --- a/compiler/rustc_hir_typeck/src/method/prelude_edition_lints.rs +++ b/compiler/rustc_hir_typeck/src/method/prelude_edition_lints.rs @@ -9,7 +9,7 @@ use rustc_hir as hir; use rustc_lint::{ARRAY_INTO_ITER, BOXED_SLICE_INTO_ITER}; use rustc_middle::span_bug; use rustc_middle::ty::{self, Ty}; -use rustc_session::lint::builtin::RUST_2021_PRELUDE_COLLISIONS; +use rustc_session::lint::builtin::{RUST_2021_PRELUDE_COLLISIONS, RUST_2024_PRELUDE_COLLISIONS}; use rustc_span::symbol::kw::{Empty, Underscore}; use rustc_span::symbol::{sym, Ident}; use rustc_span::Span; @@ -35,6 +35,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let (prelude_or_array_lint, edition) = match segment.ident.name { // `try_into` was added to the prelude in Rust 2021. sym::try_into if !span.at_least_rust_2021() => (RUST_2021_PRELUDE_COLLISIONS, "2021"), + // `Future::poll` was added to the prelude in Rust 2024. + sym::poll + // We check that the self type is `Pin<&mut _>` to avoid false positives for this common name. + if !span.at_least_rust_2024() + && let ty::Adt(adt_def, args) = self_ty.kind() + && self.tcx.is_lang_item(adt_def.did(), hir::LangItem::Pin) + && let ty::Ref(_, _, ty::Mutability::Mut) = + args[0].as_type().unwrap().kind() => + { + (RUST_2024_PRELUDE_COLLISIONS, "2024") + } + // `IntoFuture::into_future` was added to the prelude in Rust 2024. + sym::into_future if !span.at_least_rust_2024() => { + (RUST_2024_PRELUDE_COLLISIONS, "2024") + } // `into_iter` wasn't added to the prelude, // but `[T; N].into_iter()` doesn't resolve to IntoIterator::into_iter // before Rust 2021, which results in the same problem. diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index a87b3c2c13597..987dbf6db630a 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -144,13 +144,18 @@ lint_builtin_special_module_name_used_main = found module declaration for main.r lint_builtin_trivial_bounds = {$predicate_kind_name} bound {$predicate} does not depend on any type or lifetime parameters -lint_builtin_type_alias_bounds_help = use fully disambiguated paths (i.e., `::Assoc`) to refer to associated types in type aliases - -lint_builtin_type_alias_generic_bounds = bounds on generic parameters are not enforced in type aliases - .suggestion = the bound will not be checked when the type alias is used, and should be removed - -lint_builtin_type_alias_where_clause = where clauses are not enforced in type aliases - .suggestion = the clause will not be checked when the type alias is used, and should be removed +lint_builtin_type_alias_bounds_enable_feat_help = add `#![feature(lazy_type_alias)]` to the crate attributes to enable the desired semantics +lint_builtin_type_alias_bounds_label = will not be checked at usage sites of the type alias +lint_builtin_type_alias_bounds_limitation_note = this is a known limitation of the type checker that may be lifted in a future edition. + see issue #112792 for more information +lint_builtin_type_alias_bounds_param_bounds = bounds on generic parameters in type aliases are not enforced + .suggestion = remove {$count -> + [one] this bound + *[other] these bounds + } +lint_builtin_type_alias_bounds_qualify_assoc_tys_sugg = fully qualify this associated type +lint_builtin_type_alias_bounds_where_clause = where clauses on type aliases are not enforced + .suggestion = remove this where clause lint_builtin_unpermitted_type_init_label = this code causes undefined behavior when executed lint_builtin_unpermitted_type_init_label_suggestion = help: use `MaybeUninit` instead, and only call `assume_init` after initialization is done diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 9ebada0fff377..ab0b47d48e5b5 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -31,12 +31,11 @@ use crate::{ BuiltinIncompleteFeaturesHelp, BuiltinInternalFeatures, BuiltinKeywordIdents, BuiltinMissingCopyImpl, BuiltinMissingDebugImpl, BuiltinMissingDoc, BuiltinMutablesTransmutes, BuiltinNoMangleGeneric, BuiltinNonShorthandFieldPatterns, - BuiltinSpecialModuleNameUsed, BuiltinTrivialBounds, BuiltinTypeAliasGenericBounds, - BuiltinTypeAliasGenericBoundsSuggestion, BuiltinTypeAliasWhereClause, + BuiltinSpecialModuleNameUsed, BuiltinTrivialBounds, BuiltinTypeAliasBounds, BuiltinUngatedAsyncFnTrackCaller, BuiltinUnpermittedTypeInit, BuiltinUnpermittedTypeInitSub, BuiltinUnreachablePub, BuiltinUnsafe, BuiltinUnstableFeatures, BuiltinUnusedDocComment, BuiltinUnusedDocCommentSub, - BuiltinWhileTrue, InvalidAsmLabel, SuggestChangingAssocTypes, + BuiltinWhileTrue, InvalidAsmLabel, }, EarlyContext, EarlyLintPass, LateContext, LateLintPass, Level, LintContext, }; @@ -1391,64 +1390,80 @@ declare_lint! { /// /// ### Explanation /// - /// The trait bounds in a type alias are currently ignored, and should not - /// be included to avoid confusion. This was previously allowed - /// unintentionally; this may become a hard error in the future. + /// Trait and lifetime bounds on generic parameters and in where clauses of + /// type aliases are not checked at usage sites of the type alias. Moreover, + /// they are not thoroughly checked for correctness at their definition site + /// either similar to the aliased type. + /// + /// This is a known limitation of the type checker that may be lifted in a + /// future edition. Permitting such bounds in light of this was unintentional. + /// + /// While these bounds may have secondary effects such as enabling the use of + /// "shorthand" associated type paths[^1] and affecting the default trait + /// object lifetime[^2] of trait object types passed to the type alias, this + /// should not have been allowed until the aforementioned restrictions of the + /// type checker have been lifted. + /// + /// Using such bounds is highly discouraged as they are actively misleading. + /// + /// [^1]: I.e., paths of the form `T::Assoc` where `T` is a type parameter + /// bounded by trait `Trait` which defines an associated type called `Assoc` + /// as opposed to a fully qualified path of the form `::Assoc`. + /// [^2]: TYPE_ALIAS_BOUNDS, Warn, "bounds in type aliases are not enforced" } -declare_lint_pass!( - /// Lint for trait and lifetime bounds in type aliases being mostly ignored. - /// They are relevant when using associated types, but otherwise neither checked - /// at definition site nor enforced at use site. - TypeAliasBounds => [TYPE_ALIAS_BOUNDS] -); +declare_lint_pass!(TypeAliasBounds => [TYPE_ALIAS_BOUNDS]); impl TypeAliasBounds { - pub(crate) fn is_type_variable_assoc(qpath: &hir::QPath<'_>) -> bool { - match *qpath { - hir::QPath::TypeRelative(ty, _) => { - // If this is a type variable, we found a `T::Assoc`. - match ty.kind { - hir::TyKind::Path(hir::QPath::Resolved(None, path)) => { - matches!(path.res, Res::Def(DefKind::TyParam, _)) - } - _ => false, - } - } - hir::QPath::Resolved(..) | hir::QPath::LangItem(..) => false, + pub(crate) fn affects_object_lifetime_defaults(pred: &hir::WherePredicate<'_>) -> bool { + // Bounds of the form `T: 'a` with `T` type param affect object lifetime defaults. + if let hir::WherePredicate::BoundPredicate(pred) = pred + && pred.bounds.iter().any(|bound| matches!(bound, hir::GenericBound::Outlives(_))) + && pred.bound_generic_params.is_empty() // indeed, even if absent from the RHS + && pred.bounded_ty.as_generic_param().is_some() + { + return true; } + false } } impl<'tcx> LateLintPass<'tcx> for TypeAliasBounds { fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) { - let hir::ItemKind::TyAlias(hir_ty, type_alias_generics) = &item.kind else { return }; + let hir::ItemKind::TyAlias(hir_ty, generics) = item.kind else { return }; - // Bounds of lazy type aliases and TAITs are respected. - if cx.tcx.type_alias_is_lazy(item.owner_id) { + // There must not be a where clause. + if generics.predicates.is_empty() { return; } - let ty = cx.tcx.type_of(item.owner_id).skip_binder(); - if ty.has_inherent_projections() { - // Bounds of type aliases that contain opaque types or inherent projections are - // respected. E.g: `type X = impl Trait;`, `type X = (impl Trait, Y);`, `type X = - // Type::Inherent;`. + // Bounds of lazy type aliases and TAITs are respected. + if cx.tcx.type_alias_is_lazy(item.owner_id) { return; } - // There must not be a where clause - if type_alias_generics.predicates.is_empty() { + // FIXME(generic_const_exprs): Revisit this before stabilization. + // See also `tests/ui/const-generics/generic_const_exprs/type-alias-bounds.rs`. + let ty = cx.tcx.type_of(item.owner_id).instantiate_identity(); + if ty.has_type_flags(ty::TypeFlags::HAS_CT_PROJECTION) + && cx.tcx.features().generic_const_exprs + { return; } + // NOTE(inherent_associated_types): While we currently do take some bounds in type + // aliases into consideration during IAT *selection*, we don't perform full use+def + // site wfchecking for such type aliases. Therefore TAB should still trigger. + // See also `tests/ui/associated-inherent-types/type-alias-bounds.rs`. + let mut where_spans = Vec::new(); let mut inline_spans = Vec::new(); let mut inline_sugg = Vec::new(); - for p in type_alias_generics.predicates { + + for p in generics.predicates { let span = p.span(); if p.in_where_clause() { where_spans.push(span); @@ -1460,37 +1475,57 @@ impl<'tcx> LateLintPass<'tcx> for TypeAliasBounds { } } - let mut suggested_changing_assoc_types = false; - if !where_spans.is_empty() { - let sub = (!suggested_changing_assoc_types).then(|| { - suggested_changing_assoc_types = true; - SuggestChangingAssocTypes { ty: hir_ty } - }); + let mut ty = Some(hir_ty); + let enable_feat_help = cx.tcx.sess.is_nightly_build(); + + if let [.., label_sp] = *where_spans { cx.emit_span_lint( TYPE_ALIAS_BOUNDS, where_spans, - BuiltinTypeAliasWhereClause { - suggestion: type_alias_generics.where_clause_span, - sub, + BuiltinTypeAliasBounds { + in_where_clause: true, + label: label_sp, + enable_feat_help, + suggestions: vec![(generics.where_clause_span, String::new())], + preds: generics.predicates, + ty: ty.take(), }, ); } - - if !inline_spans.is_empty() { - let suggestion = BuiltinTypeAliasGenericBoundsSuggestion { suggestions: inline_sugg }; - let sub = (!suggested_changing_assoc_types).then(|| { - suggested_changing_assoc_types = true; - SuggestChangingAssocTypes { ty: hir_ty } - }); + if let [.., label_sp] = *inline_spans { cx.emit_span_lint( TYPE_ALIAS_BOUNDS, inline_spans, - BuiltinTypeAliasGenericBounds { suggestion, sub }, + BuiltinTypeAliasBounds { + in_where_clause: false, + label: label_sp, + enable_feat_help, + suggestions: inline_sugg, + preds: generics.predicates, + ty, + }, ); } } } +pub(crate) struct ShorthandAssocTyCollector { + pub(crate) qselves: Vec, +} + +impl hir::intravisit::Visitor<'_> for ShorthandAssocTyCollector { + fn visit_qpath(&mut self, qpath: &hir::QPath<'_>, id: hir::HirId, _: Span) { + // Look for "type-parameter shorthand-associated-types". I.e., paths of the + // form `T::Assoc` with `T` type param. These are reliant on trait bounds. + if let hir::QPath::TypeRelative(qself, _) = qpath + && qself.as_generic_param().is_some() + { + self.qselves.push(qself.span); + } + hir::intravisit::walk_qpath(self, qpath, id) + } +} + declare_lint! { /// The `trivial_bounds` lint detects trait bounds that don't depend on /// any type parameters. diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 1f0954c6e9f00..b669a3c6288ba 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -2,14 +2,16 @@ #![allow(rustc::untranslatable_diagnostic)] use std::num::NonZero; -use crate::errors::RequestedLevel; +use crate::builtin::{InitError, ShorthandAssocTyCollector, TypeAliasBounds}; +use crate::errors::{OverruledAttributeSub, RequestedLevel}; use crate::fluent_generated as fluent; +use crate::LateContext; use rustc_errors::{ codes::*, Applicability, Diag, DiagArgValue, DiagMessage, DiagStyledString, ElidedLifetimeInPathSubdiag, EmissionGuarantee, LintDiagnostic, MultiSpan, SubdiagMessageOp, Subdiagnostic, SuggestionStyle, }; -use rustc_hir::{def::Namespace, def_id::DefId}; +use rustc_hir::{self as hir, def::Namespace, def_id::DefId}; use rustc_macros::{LintDiagnostic, Subdiagnostic}; use rustc_middle::ty::{ inhabitedness::InhabitedPredicate, Clause, PolyExistentialTraitRef, Ty, TyCtxt, @@ -22,10 +24,6 @@ use rustc_span::{ Span, Symbol, }; -use crate::{ - builtin::InitError, builtin::TypeAliasBounds, errors::OverruledAttributeSub, LateContext, -}; - // array_into_iter.rs #[derive(LintDiagnostic)] #[diag(lint_shadowed_into_iter)] @@ -263,62 +261,6 @@ pub struct BuiltinUnreachablePub<'a> { pub help: Option<()>, } -pub struct SuggestChangingAssocTypes<'a, 'b> { - pub ty: &'a rustc_hir::Ty<'b>, -} - -impl<'a, 'b> Subdiagnostic for SuggestChangingAssocTypes<'a, 'b> { - fn add_to_diag_with>( - self, - diag: &mut Diag<'_, G>, - _f: &F, - ) { - // Access to associates types should use `::Assoc`, which does not need a - // bound. Let's see if this type does that. - - // We use a HIR visitor to walk the type. - use rustc_hir::intravisit::{self, Visitor}; - struct WalkAssocTypes<'a, 'b, G: EmissionGuarantee> { - err: &'a mut Diag<'b, G>, - } - impl<'a, 'b, G: EmissionGuarantee> Visitor<'_> for WalkAssocTypes<'a, 'b, G> { - fn visit_qpath( - &mut self, - qpath: &rustc_hir::QPath<'_>, - id: rustc_hir::HirId, - span: Span, - ) { - if TypeAliasBounds::is_type_variable_assoc(qpath) { - self.err.span_help(span, fluent::lint_builtin_type_alias_bounds_help); - } - intravisit::walk_qpath(self, qpath, id) - } - } - - // Let's go for a walk! - let mut visitor = WalkAssocTypes { err: diag }; - visitor.visit_ty(self.ty); - } -} - -#[derive(LintDiagnostic)] -#[diag(lint_builtin_type_alias_where_clause)] -pub struct BuiltinTypeAliasWhereClause<'a, 'b> { - #[suggestion(code = "", applicability = "machine-applicable")] - pub suggestion: Span, - #[subdiagnostic] - pub sub: Option>, -} - -#[derive(LintDiagnostic)] -#[diag(lint_builtin_type_alias_generic_bounds)] -pub struct BuiltinTypeAliasGenericBounds<'a, 'b> { - #[subdiagnostic] - pub suggestion: BuiltinTypeAliasGenericBoundsSuggestion, - #[subdiagnostic] - pub sub: Option>, -} - #[derive(LintDiagnostic)] #[diag(lint_macro_expr_fragment_specifier_2024_migration)] pub struct MacroExprFragment2024 { @@ -326,21 +268,72 @@ pub struct MacroExprFragment2024 { pub suggestion: Span, } -pub struct BuiltinTypeAliasGenericBoundsSuggestion { +pub struct BuiltinTypeAliasBounds<'a, 'hir> { + pub in_where_clause: bool, + pub label: Span, + pub enable_feat_help: bool, pub suggestions: Vec<(Span, String)>, + pub preds: &'hir [hir::WherePredicate<'hir>], + pub ty: Option<&'a hir::Ty<'hir>>, } -impl Subdiagnostic for BuiltinTypeAliasGenericBoundsSuggestion { - fn add_to_diag_with>( - self, - diag: &mut Diag<'_, G>, - _f: &F, - ) { - diag.multipart_suggestion( - fluent::lint_suggestion, - self.suggestions, - Applicability::MachineApplicable, - ); +impl<'a> LintDiagnostic<'a, ()> for BuiltinTypeAliasBounds<'_, '_> { + fn decorate_lint<'b>(self, diag: &'b mut Diag<'a, ()>) { + diag.primary_message(if self.in_where_clause { + fluent::lint_builtin_type_alias_bounds_where_clause + } else { + fluent::lint_builtin_type_alias_bounds_param_bounds + }); + diag.span_label(self.label, fluent::lint_builtin_type_alias_bounds_label); + diag.note(fluent::lint_builtin_type_alias_bounds_limitation_note); + if self.enable_feat_help { + diag.help(fluent::lint_builtin_type_alias_bounds_enable_feat_help); + } + + // We perform the walk in here instead of in `` to + // avoid doing throwaway work in case the lint ends up getting suppressed. + let mut collector = ShorthandAssocTyCollector { qselves: Vec::new() }; + if let Some(ty) = self.ty { + hir::intravisit::Visitor::visit_ty(&mut collector, ty); + } + + let affect_object_lifetime_defaults = self + .preds + .iter() + .filter(|pred| pred.in_where_clause() == self.in_where_clause) + .any(|pred| TypeAliasBounds::affects_object_lifetime_defaults(pred)); + + // If there are any shorthand assoc tys, then the bounds can't be removed automatically. + // The user first needs to fully qualify the assoc tys. + let applicability = if !collector.qselves.is_empty() || affect_object_lifetime_defaults { + Applicability::MaybeIncorrect + } else { + Applicability::MachineApplicable + }; + + diag.arg("count", self.suggestions.len()); + diag.multipart_suggestion(fluent::lint_suggestion, self.suggestions, applicability); + + // Suggest fully qualifying paths of the form `T::Assoc` with `T` type param via + // `::Assoc` to remove their reliance on any type param bounds. + // + // Instead of attempting to figure out the necessary trait ref, just use a + // placeholder. Since we don't record type-dependent resolutions for non-body + // items like type aliases, we can't simply deduce the corresp. trait from + // the HIR path alone without rerunning parts of HIR ty lowering here + // (namely `probe_single_ty_param_bound_for_assoc_ty`) which is infeasible. + // + // (We could employ some simple heuristics but that's likely not worth it). + for qself in collector.qselves { + diag.multipart_suggestion( + fluent::lint_builtin_type_alias_bounds_qualify_assoc_tys_sugg, + vec![ + (qself.shrink_to_lo(), "<".into()), + (qself.shrink_to_hi(), " as /* Trait */>".into()), + ], + Applicability::HasPlaceholders, + ); + } } } diff --git a/compiler/rustc_lint/src/non_local_def.rs b/compiler/rustc_lint/src/non_local_def.rs index 2f8eea6cd1816..93c606a954ea4 100644 --- a/compiler/rustc_lint/src/non_local_def.rs +++ b/compiler/rustc_lint/src/non_local_def.rs @@ -429,7 +429,7 @@ fn ty_has_local_parent( path_has_local_parent(ty_path, cx, impl_parent, impl_parent_parent) } TyKind::TraitObject([principle_poly_trait_ref, ..], _, _) => path_has_local_parent( - principle_poly_trait_ref.trait_ref.path, + principle_poly_trait_ref.0.trait_ref.path, cx, impl_parent, impl_parent_parent, @@ -527,7 +527,7 @@ fn self_ty_kind_for_diagnostic(ty: &rustc_hir::Ty<'_>, tcx: TyCtxt<'_>) -> (Span .to_string(), ), TyKind::TraitObject([principle_poly_trait_ref, ..], _, _) => { - let path = &principle_poly_trait_ref.trait_ref.path; + let path = &principle_poly_trait_ref.0.trait_ref.path; ( path_span_without_args(path), path.res diff --git a/compiler/rustc_lint/src/traits.rs b/compiler/rustc_lint/src/traits.rs index 6983e7abbd64e..552245f0cdd93 100644 --- a/compiler/rustc_lint/src/traits.rs +++ b/compiler/rustc_lint/src/traits.rs @@ -113,9 +113,11 @@ impl<'tcx> LateLintPass<'tcx> for DropTraitConstraints { fn check_ty(&mut self, cx: &LateContext<'_>, ty: &'tcx hir::Ty<'tcx>) { let hir::TyKind::TraitObject(bounds, _lifetime, _syntax) = &ty.kind else { return }; - for bound in &bounds[..] { + for (bound, modifier) in &bounds[..] { let def_id = bound.trait_ref.trait_def_id(); - if cx.tcx.lang_items().drop_trait() == def_id { + if cx.tcx.lang_items().drop_trait() == def_id + && *modifier != hir::TraitBoundModifier::Maybe + { let Some(def_id) = cx.tcx.get_diagnostic_item(sym::needs_drop) else { return }; cx.emit_span_lint(DYN_DROP, bound.span, DropGlue { tcx: cx.tcx, def_id }); } diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 5d4cc7561a63d..06d6a6cd612e0 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -91,6 +91,7 @@ declare_lint_pass! { RUST_2021_PREFIXES_INCOMPATIBLE_SYNTAX, RUST_2021_PRELUDE_COLLISIONS, RUST_2024_INCOMPATIBLE_PAT, + RUST_2024_PRELUDE_COLLISIONS, SELF_CONSTRUCTOR_FROM_OUTER_ITEM, SEMICOLON_IN_EXPRESSIONS_FROM_MACROS, SINGLE_USE_LIFETIMES, @@ -1984,14 +1985,18 @@ declare_lint! { /// /// ```rust /// trait MyIterator : Iterator { - /// // is_sorted is an unstable method that already exists on the Iterator trait - /// fn is_sorted(self) -> bool where Self: Sized {true} + /// // is_partitioned is an unstable method that already exists on the Iterator trait + /// fn is_partitioned

(self, predicate: P) -> bool + /// where + /// Self: Sized, + /// P: FnMut(Self::Item) -> bool, + /// {true} /// } /// /// impl MyIterator for T where T: Iterator { } /// /// let x = vec![1, 2, 3]; - /// let _ = x.iter().is_sorted(); + /// let _ = x.iter().is_partitioned(|_| true); /// ``` /// /// {{produces}} @@ -2007,7 +2012,7 @@ declare_lint! { /// is an early-warning to let you know that there may be a collision in /// the future. This can be avoided by adding type annotations to /// disambiguate which trait method you intend to call, such as - /// `MyIterator::is_sorted(my_iter)` or renaming or removing the method. + /// `MyIterator::is_partitioned(my_iter, my_predicate)` or renaming or removing the method. /// /// [nightly channel]: https://doc.rust-lang.org/book/appendix-07-nightly-rust.html /// [`feature` attribute]: https://doc.rust-lang.org/nightly/unstable-book/ @@ -3750,6 +3755,46 @@ declare_lint! { }; } +declare_lint! { + /// The `rust_2024_prelude_collisions` lint detects the usage of trait methods which are ambiguous + /// with traits added to the prelude in future editions. + /// + /// ### Example + /// + /// ```rust,edition2021,compile_fail + /// #![deny(rust_2024_prelude_collisions)] + /// trait Meow { + /// fn poll(&self) {} + /// } + /// impl Meow for T {} + /// + /// fn main() { + /// core::pin::pin!(async {}).poll(); + /// // ^^^^^^ + /// // This call to try_into matches both Future::poll and Meow::poll as + /// // `Future` has been added to the Rust prelude in 2024 edition. + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Rust 2024, introduces two new additions to the standard library's prelude: + /// `Future` and `IntoFuture`. This results in an ambiguity as to which method/function + /// to call when an existing `poll`/`into_future` method is called via dot-call syntax or + /// a `poll`/`into_future` associated function is called directly on a type. + /// + pub RUST_2024_PRELUDE_COLLISIONS, + Allow, + "detects the usage of trait methods which are ambiguous with traits added to the \ + prelude in future editions", + @future_incompatible = FutureIncompatibleInfo { + reason: FutureIncompatibilityReason::EditionError(Edition::Edition2024), + reference: "", + }; +} + declare_lint! { /// The `rust_2021_prefixes_incompatible_syntax` lint detects identifiers that will be parsed as a /// prefix instead in Rust 2021. diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index d2b444a066bcc..da98e3b9f4613 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -1864,9 +1864,9 @@ impl<'tcx> Ty<'tcx> { // Definitely absolutely not copy. ty::Ref(_, _, hir::Mutability::Mut) => false, - // Thin pointers & thin shared references are pure-clone-copy, but for - // anything with custom metadata it might be more complicated. - ty::Ref(_, _, hir::Mutability::Not) | ty::RawPtr(..) => false, + // The standard library has a blanket Copy impl for shared references and raw pointers, + // for all unsized types. + ty::Ref(_, _, hir::Mutability::Not) | ty::RawPtr(..) => true, ty::Coroutine(..) | ty::CoroutineWitness(..) => false, diff --git a/compiler/rustc_mir_build/messages.ftl b/compiler/rustc_mir_build/messages.ftl index 281f3ef6ef35a..dda4debecec67 100644 --- a/compiler/rustc_mir_build/messages.ftl +++ b/compiler/rustc_mir_build/messages.ftl @@ -325,9 +325,16 @@ mir_build_union_field_requires_unsafe_unsafe_op_in_unsafe_fn_allowed = mir_build_union_pattern = cannot use unions in constant patterns +mir_build_unreachable_making_this_unreachable = collectively making this unreachable + +mir_build_unreachable_matches_same_values = matches some of the same values + mir_build_unreachable_pattern = unreachable pattern .label = unreachable pattern - .catchall_label = matches any value + .unreachable_matches_no_values = this pattern matches no values because `{$ty}` is uninhabited + .unreachable_covered_by_catchall = matches any value + .unreachable_covered_by_one = matches all the values already + .unreachable_covered_by_many = these patterns collectively make the last one unreachable mir_build_unsafe_fn_safe_body = an unsafe function restricts its caller, but its body is safe by default mir_build_unsafe_not_inherited = items do not inherit unsafety from separate enclosing items diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs index f6f443b64a63a..bdc4b0ea97d18 100644 --- a/compiler/rustc_mir_build/src/errors.rs +++ b/compiler/rustc_mir_build/src/errors.rs @@ -582,11 +582,23 @@ pub(crate) struct NonConstPath { #[derive(LintDiagnostic)] #[diag(mir_build_unreachable_pattern)] -pub(crate) struct UnreachablePattern { +pub(crate) struct UnreachablePattern<'tcx> { #[label] pub(crate) span: Option, - #[label(mir_build_catchall_label)] - pub(crate) catchall: Option, + #[subdiagnostic] + pub(crate) matches_no_values: Option>, + #[label(mir_build_unreachable_covered_by_catchall)] + pub(crate) covered_by_catchall: Option, + #[label(mir_build_unreachable_covered_by_one)] + pub(crate) covered_by_one: Option, + #[note(mir_build_unreachable_covered_by_many)] + pub(crate) covered_by_many: Option, +} + +#[derive(Subdiagnostic)] +#[note(mir_build_unreachable_matches_no_values)] +pub(crate) struct UnreachableMatchesNoValues<'tcx> { + pub(crate) ty: Ty<'tcx>, } #[derive(Diagnostic)] diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs index 95799cec94b04..5e904057e732c 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -1,4 +1,5 @@ use crate::errors::*; +use crate::fluent_generated as fluent; use rustc_arena::{DroplessArena, TypedArena}; use rustc_ast::Mutability; @@ -16,8 +17,8 @@ use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt}; use rustc_pattern_analysis::errors::Uncovered; use rustc_pattern_analysis::rustc::{ - Constructor, DeconstructedPat, MatchArm, RevealedTy, RustcPatCtxt as PatCtxt, Usefulness, - UsefulnessReport, WitnessPat, + Constructor, DeconstructedPat, MatchArm, RedundancyExplanation, RevealedTy, + RustcPatCtxt as PatCtxt, Usefulness, UsefulnessReport, WitnessPat, }; use rustc_session::lint::builtin::{ BINDINGS_WITH_VARIANT_NAME, IRREFUTABLE_LET_PATTERNS, UNREACHABLE_PATTERNS, @@ -391,12 +392,16 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> { ) -> Result, ErrorGuaranteed> { let pattern_complexity_limit = get_limit_size(cx.tcx.hir().krate_attrs(), cx.tcx.sess, sym::pattern_complexity); - let report = - rustc_pattern_analysis::analyze_match(&cx, &arms, scrut_ty, pattern_complexity_limit) - .map_err(|err| { - self.error = Err(err); - err - })?; + let report = rustc_pattern_analysis::rustc::analyze_match( + &cx, + &arms, + scrut_ty, + pattern_complexity_limit, + ) + .map_err(|err| { + self.error = Err(err); + err + })?; // Warn unreachable subpatterns. for (arm, is_useful) in report.arm_usefulness.iter() { @@ -405,9 +410,9 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> { { let mut redundant_subpats = redundant_subpats.clone(); // Emit lints in the order in which they occur in the file. - redundant_subpats.sort_unstable_by_key(|pat| pat.data().span); - for pat in redundant_subpats { - report_unreachable_pattern(cx, arm.arm_data, pat.data().span, None) + redundant_subpats.sort_unstable_by_key(|(pat, _)| pat.data().span); + for (pat, explanation) in redundant_subpats { + report_unreachable_pattern(cx, arm.arm_data, pat, &explanation) } } } @@ -906,26 +911,60 @@ fn report_irrefutable_let_patterns( fn report_unreachable_pattern<'p, 'tcx>( cx: &PatCtxt<'p, 'tcx>, hir_id: HirId, - span: Span, - catchall: Option, + pat: &DeconstructedPat<'p, 'tcx>, + explanation: &RedundancyExplanation<'p, 'tcx>, ) { - cx.tcx.emit_node_span_lint( - UNREACHABLE_PATTERNS, - hir_id, - span, - UnreachablePattern { span: if catchall.is_some() { Some(span) } else { None }, catchall }, - ); + let pat_span = pat.data().span; + let mut lint = UnreachablePattern { + span: Some(pat_span), + matches_no_values: None, + covered_by_catchall: None, + covered_by_one: None, + covered_by_many: None, + }; + match explanation.covered_by.as_slice() { + [] => { + // Empty pattern; we report the uninhabited type that caused the emptiness. + lint.span = None; // Don't label the pattern itself + pat.walk(&mut |subpat| { + let ty = **subpat.ty(); + if cx.is_uninhabited(ty) { + lint.matches_no_values = Some(UnreachableMatchesNoValues { ty }); + false // No need to dig further. + } else if matches!(subpat.ctor(), Constructor::Ref | Constructor::UnionField) { + false // Don't explore further since they are not by-value. + } else { + true + } + }); + } + [covering_pat] if pat_is_catchall(covering_pat) => { + lint.covered_by_catchall = Some(covering_pat.data().span); + } + [covering_pat] => { + lint.covered_by_one = Some(covering_pat.data().span); + } + covering_pats => { + let mut multispan = MultiSpan::from_span(pat_span); + for p in covering_pats { + multispan.push_span_label( + p.data().span, + fluent::mir_build_unreachable_matches_same_values, + ); + } + multispan + .push_span_label(pat_span, fluent::mir_build_unreachable_making_this_unreachable); + lint.covered_by_many = Some(multispan); + } + } + cx.tcx.emit_node_span_lint(UNREACHABLE_PATTERNS, hir_id, pat_span, lint); } /// Report unreachable arms, if any. fn report_arm_reachability<'p, 'tcx>(cx: &PatCtxt<'p, 'tcx>, report: &UsefulnessReport<'p, 'tcx>) { - let mut catchall = None; for (arm, is_useful) in report.arm_usefulness.iter() { - if matches!(is_useful, Usefulness::Redundant) { - report_unreachable_pattern(cx, arm.arm_data, arm.pat.data().span, catchall) - } - if !arm.has_guard && catchall.is_none() && pat_is_catchall(arm.pat) { - catchall = Some(arm.pat.data().span); + if let Usefulness::Redundant(explanation) = is_useful { + report_unreachable_pattern(cx, arm.arm_data, arm.pat, explanation) } } } diff --git a/compiler/rustc_mir_transform/src/instsimplify.rs b/compiler/rustc_mir_transform/src/instsimplify.rs index 8209e5e27111c..58fdc2d9e4500 100644 --- a/compiler/rustc_mir_transform/src/instsimplify.rs +++ b/compiler/rustc_mir_transform/src/instsimplify.rs @@ -3,6 +3,7 @@ use crate::simplify::simplify_duplicate_switch_targets; use crate::take_array; use rustc_ast::attr; +use rustc_hir::LangItem; use rustc_middle::bug; use rustc_middle::mir::*; use rustc_middle::ty::layout; @@ -271,8 +272,7 @@ impl<'tcx> InstSimplifyContext<'tcx, '_> { return; } - let trait_def_id = self.tcx.trait_of_item(fn_def_id); - if trait_def_id.is_none() || trait_def_id != self.tcx.lang_items().clone_trait() { + if !self.tcx.is_lang_item(fn_def_id, LangItem::CloneFn) { return; } diff --git a/compiler/rustc_mir_transform/src/jump_threading.rs b/compiler/rustc_mir_transform/src/jump_threading.rs index 2100f4b4a1af5..96c52845a4a39 100644 --- a/compiler/rustc_mir_transform/src/jump_threading.rs +++ b/compiler/rustc_mir_transform/src/jump_threading.rs @@ -509,6 +509,13 @@ impl<'tcx, 'a> TOFinder<'tcx, 'a> { BinOp::Ne => ScalarInt::FALSE, _ => return None, }; + if value.const_.ty().is_floating_point() { + // Floating point equality does not follow bit-patterns. + // -0.0 and NaN both have special rules for equality, + // and therefore we cannot use integer comparisons for them. + // Avoid handling them, though this could be extended in the future. + return None; + } let value = value.const_.normalize(self.tcx, self.param_env).try_to_scalar_int()?; let conds = conditions.map(self.arena, |c| Condition { value, diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index 5d253d7384df4..243c9c6a2fd6f 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -6,7 +6,6 @@ #![feature(decl_macro)] #![feature(if_let_guard)] #![feature(impl_trait_in_assoc_type)] -#![feature(is_sorted)] #![feature(let_chains)] #![feature(map_try_insert)] #![feature(never_type)] diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs index 6835a39cf3624..d2f5004082142 100644 --- a/compiler/rustc_mir_transform/src/shim.rs +++ b/compiler/rustc_mir_transform/src/shim.rs @@ -17,7 +17,7 @@ use std::iter; use crate::{ abort_unwinding_calls, add_call_guards, add_moves_for_packed_drops, deref_separator, - mentioned_items, pass_manager as pm, remove_noop_landing_pads, simplify, + instsimplify, mentioned_items, pass_manager as pm, remove_noop_landing_pads, simplify, }; use rustc_middle::mir::patch::MirPatch; use rustc_mir_dataflow::elaborate_drops::{self, DropElaborator, DropFlagMode, DropStyle}; @@ -154,6 +154,7 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceKind<'tcx>) -> Body< &deref_separator::Derefer, &remove_noop_landing_pads::RemoveNoopLandingPads, &simplify::SimplifyCfg::MakeShim, + &instsimplify::InstSimplify, &abort_unwinding_calls::AbortUnwindingCalls, &add_call_guards::CriticalCallEdges, ], @@ -434,6 +435,9 @@ fn build_clone_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, self_ty: Ty<'tcx>) - match self_ty.kind() { ty::FnDef(..) | ty::FnPtr(_) => builder.copy_shim(), ty::Closure(_, args) => builder.tuple_like_shim(dest, src, args.as_closure().upvar_tys()), + ty::CoroutineClosure(_, args) => { + builder.tuple_like_shim(dest, src, args.as_coroutine_closure().upvar_tys()) + } ty::Tuple(..) => builder.tuple_like_shim(dest, src, self_ty.tuple_fields()), ty::Coroutine(coroutine_def_id, args) => { assert_eq!(tcx.coroutine_movability(*coroutine_def_id), hir::Movability::Movable); diff --git a/compiler/rustc_monomorphize/src/lib.rs b/compiler/rustc_monomorphize/src/lib.rs index fc6e8e0d14fd2..3b8f0a91e7463 100644 --- a/compiler/rustc_monomorphize/src/lib.rs +++ b/compiler/rustc_monomorphize/src/lib.rs @@ -1,6 +1,5 @@ // tidy-alphabetical-start #![feature(array_windows)] -#![feature(is_sorted)] // tidy-alphabetical-end use rustc_hir::lang_items::LangItem; diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs index 770ac9a929eae..60beaa0df84ca 100644 --- a/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs +++ b/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs @@ -217,7 +217,10 @@ where // impl Copy/Clone for Closure where Self::TupledUpvars: Copy/Clone ty::Closure(_, args) => Ok(vec![ty::Binder::dummy(args.as_closure().tupled_upvars_ty())]), - ty::CoroutineClosure(..) => Err(NoSolution), + // impl Copy/Clone for CoroutineClosure where Self::TupledUpvars: Copy/Clone + ty::CoroutineClosure(_, args) => { + Ok(vec![ty::Binder::dummy(args.as_coroutine_closure().tupled_upvars_ty())]) + } // only when `coroutine_clone` is enabled and the coroutine is movable // impl Copy/Clone for Coroutine where T: Copy/Clone forall T in (upvars, witnesses) diff --git a/compiler/rustc_parse/src/parser/attr.rs b/compiler/rustc_parse/src/parser/attr.rs index 0b2c304403941..535b53a836e98 100644 --- a/compiler/rustc_parse/src/parser/attr.rs +++ b/compiler/rustc_parse/src/parser/attr.rs @@ -457,14 +457,3 @@ impl<'a> Parser<'a> { Err(self.dcx().create_err(err)) } } - -/// The attributes are complete if all attributes are either a doc comment or a -/// builtin attribute other than `cfg_attr`. -pub fn is_complete(attrs: &[ast::Attribute]) -> bool { - attrs.iter().all(|attr| { - attr.is_doc_comment() - || attr.ident().is_some_and(|ident| { - ident.name != sym::cfg_attr && rustc_feature::is_builtin_attr_name(ident.name) - }) - }) -} diff --git a/compiler/rustc_parse/src/parser/attr_wrapper.rs b/compiler/rustc_parse/src/parser/attr_wrapper.rs index dc5f98f7be8b6..5dc49ea51d1dc 100644 --- a/compiler/rustc_parse/src/parser/attr_wrapper.rs +++ b/compiler/rustc_parse/src/parser/attr_wrapper.rs @@ -60,10 +60,6 @@ impl AttrWrapper { pub fn is_empty(&self) -> bool { self.attrs.is_empty() } - - pub fn is_complete(&self) -> bool { - crate::parser::attr::is_complete(&self.attrs) - } } /// Returns `true` if `attrs` contains a `cfg` or `cfg_attr` attribute @@ -114,17 +110,15 @@ impl ToAttrTokenStream for LazyAttrTokenStreamImpl { replace_ranges.sort_by_key(|(range, _)| range.start); #[cfg(debug_assertions)] - { - for [(range, tokens), (next_range, next_tokens)] in replace_ranges.array_windows() { - assert!( - range.end <= next_range.start || range.end >= next_range.end, - "Replace ranges should either be disjoint or nested: ({:?}, {:?}) ({:?}, {:?})", - range, - tokens, - next_range, - next_tokens, - ); - } + for [(range, tokens), (next_range, next_tokens)] in replace_ranges.array_windows() { + assert!( + range.end <= next_range.start || range.end >= next_range.end, + "Replace ranges should either be disjoint or nested: ({:?}, {:?}) ({:?}, {:?})", + range, + tokens, + next_range, + next_tokens, + ); } // Process the replace ranges, starting from the highest start @@ -137,9 +131,9 @@ impl ToAttrTokenStream for LazyAttrTokenStreamImpl { // `#[cfg(FALSE)] struct Foo { #[cfg(FALSE)] field: bool }` // // By starting processing from the replace range with the greatest - // start position, we ensure that any replace range which encloses - // another replace range will capture the *replaced* tokens for the inner - // range, not the original tokens. + // start position, we ensure that any (outer) replace range which + // encloses another (inner) replace range will fully overwrite the + // inner range's replacement. for (range, target) in replace_ranges.into_iter().rev() { assert!(!range.is_empty(), "Cannot replace an empty range: {range:?}"); @@ -199,20 +193,20 @@ impl<'a> Parser<'a> { force_collect: ForceCollect, f: impl FnOnce(&mut Self, ast::AttrVec) -> PResult<'a, (R, bool)>, ) -> PResult<'a, R> { - // Skip collection when nothing could observe the collected tokens, i.e. - // all of the following conditions hold. - // - We are not force collecting tokens (because force collection - // requires tokens by definition). - if matches!(force_collect, ForceCollect::No) - // - None of our outer attributes require tokens. - && attrs.is_complete() - // - Our target doesn't support custom inner attributes (custom + // We must collect if anything could observe the collected tokens, i.e. + // if any of the following conditions hold. + // - We are force collecting tokens (because force collection requires + // tokens by definition). + let needs_collection = matches!(force_collect, ForceCollect::Yes) + // - Any of our outer attributes require tokens. + || needs_tokens(&attrs.attrs) + // - Our target supports custom inner attributes (custom // inner attribute invocation might require token capturing). - && !R::SUPPORTS_CUSTOM_INNER_ATTRS - // - We are not in `capture_cfg` mode (which requires tokens if + || R::SUPPORTS_CUSTOM_INNER_ATTRS + // - We are in `capture_cfg` mode (which requires tokens if // the parsed node has `#[cfg]` or `#[cfg_attr]` attributes). - && !self.capture_cfg - { + || self.capture_cfg; + if !needs_collection { return Ok(f(self, attrs.attrs)?.0); } @@ -250,28 +244,28 @@ impl<'a> Parser<'a> { return Ok(ret); } - // This is similar to the "skip collection" check at the start of this - // function, but now that we've parsed an AST node we have more + // This is similar to the `needs_collection` check at the start of this + // function, but now that we've parsed an AST node we have complete // information available. (If we return early here that means the // setup, such as cloning the token cursor, was unnecessary. That's // hard to avoid.) // - // Skip collection when nothing could observe the collected tokens, i.e. - // all of the following conditions hold. - // - We are not force collecting tokens. - if matches!(force_collect, ForceCollect::No) - // - None of our outer *or* inner attributes require tokens. - // (`attrs` was just outer attributes, but `ret.attrs()` is outer - // and inner attributes. That makes this check more precise than - // `attrs.is_complete()` at the start of the function, and we can - // skip the subsequent check on `R::SUPPORTS_CUSTOM_INNER_ATTRS`. - && crate::parser::attr::is_complete(ret.attrs()) - // - We are not in `capture_cfg` mode, or we are but there are no - // `#[cfg]` or `#[cfg_attr]` attributes. (During normal - // non-`capture_cfg` parsing, we don't need any special capturing - // for those attributes, because they're builtin.) - && (!self.capture_cfg || !has_cfg_or_cfg_attr(ret.attrs())) - { + // We must collect if anything could observe the collected tokens, i.e. + // if any of the following conditions hold. + // - We are force collecting tokens. + let needs_collection = matches!(force_collect, ForceCollect::Yes) + // - Any of our outer *or* inner attributes require tokens. + // (`attr.attrs` was just outer attributes, but `ret.attrs()` is + // outer and inner attributes. So this check is more precise than + // the earlier `needs_tokens` check, and we don't need to + // check `R::SUPPORTS_CUSTOM_INNER_ATTRS`.) + || needs_tokens(ret.attrs()) + // - We are in `capture_cfg` mode and there are `#[cfg]` or + // `#[cfg_attr]` attributes. (During normal non-`capture_cfg` + // parsing, we don't need any special capturing for those + // attributes, because they're builtin.) + || (self.capture_cfg && has_cfg_or_cfg_attr(ret.attrs())); + if !needs_collection { return Ok(ret); } @@ -297,11 +291,13 @@ impl<'a> Parser<'a> { // with `None`, which means the relevant tokens will be removed. (More // details below.) let mut inner_attr_replace_ranges = Vec::new(); - for inner_attr in ret.attrs().iter().filter(|a| a.style == ast::AttrStyle::Inner) { - if let Some(attr_range) = self.capture_state.inner_attr_ranges.remove(&inner_attr.id) { - inner_attr_replace_ranges.push((attr_range, None)); - } else { - self.dcx().span_delayed_bug(inner_attr.span, "Missing token range for attribute"); + for attr in ret.attrs() { + if attr.style == ast::AttrStyle::Inner { + if let Some(attr_range) = self.capture_state.inner_attr_ranges.remove(&attr.id) { + inner_attr_replace_ranges.push((attr_range, None)); + } else { + self.dcx().span_delayed_bug(attr.span, "Missing token range for attribute"); + } } } @@ -337,8 +333,7 @@ impl<'a> Parser<'a> { // When parsing `m`: // - `start_pos..end_pos` is `0..34` (`mod m`, excluding the `#[cfg_eval]` attribute). // - `inner_attr_replace_ranges` is empty. - // - `replace_range_start..replace_ranges_end` has two entries. - // - One to delete the inner attribute (`17..27`), obtained when parsing `g` (see above). + // - `replace_range_start..replace_ranges_end` has one entry. // - One `AttrsTarget` (added below when parsing `g`) to replace all of `g` (`3..33`, // including its outer attribute), with: // - `attrs`: includes the outer and the inner attr. @@ -369,12 +364,10 @@ impl<'a> Parser<'a> { // What is the status here when parsing the example code at the top of this method? // - // When parsing `g`, we add two entries: + // When parsing `g`, we add one entry: // - The `start_pos..end_pos` (`3..33`) entry has a new `AttrsTarget` with: // - `attrs`: includes the outer and the inner attr. // - `tokens`: lazy tokens for `g` (with its inner attr deleted). - // - `inner_attr_replace_ranges` contains the one entry to delete the inner attr's - // tokens (`17..27`). // // When parsing `m`, we do nothing here. @@ -384,7 +377,6 @@ impl<'a> Parser<'a> { let start_pos = if has_outer_attrs { attrs.start_pos } else { start_pos }; let target = AttrsTarget { attrs: ret.attrs().iter().cloned().collect(), tokens }; self.capture_state.replace_ranges.push((start_pos..end_pos, Some(target))); - self.capture_state.replace_ranges.extend(inner_attr_replace_ranges); } else if matches!(self.capture_state.capturing, Capturing::No) { // Only clear the ranges once we've finished capturing entirely, i.e. we've finished // the outermost call to this method. @@ -461,6 +453,19 @@ fn make_attr_token_stream( AttrTokenStream::new(stack_top.inner) } +/// Tokens are needed if: +/// - any non-single-segment attributes (other than doc comments) are present; or +/// - any `cfg_attr` attributes are present; +/// - any single-segment, non-builtin attributes are present. +fn needs_tokens(attrs: &[ast::Attribute]) -> bool { + attrs.iter().any(|attr| match attr.ident() { + None => !attr.is_doc_comment(), + Some(ident) => { + ident.name == sym::cfg_attr || !rustc_feature::is_builtin_attr_name(ident.name) + } + }) +} + // Some types are used a lot. Make sure they don't unintentionally get bigger. #[cfg(target_pointer_width = "64")] mod size_asserts { diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 9aaf4b99243f5..112855e6d1f5a 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -2483,12 +2483,15 @@ impl<'a> Parser<'a> { /// `check_pub` adds additional `pub` to the checks in case users place it /// wrongly, can be used to ensure `pub` never comes after `default`. pub(super) fn check_fn_front_matter(&mut self, check_pub: bool, case: Case) -> bool { + const ALL_QUALS: &[Symbol] = + &[kw::Pub, kw::Gen, kw::Const, kw::Async, kw::Unsafe, kw::Safe, kw::Extern]; + // We use an over-approximation here. // `const const`, `fn const` won't parse, but we're not stepping over other syntax either. // `pub` is added in case users got confused with the ordering like `async pub fn`, // only if it wasn't preceded by `default` as `default pub` is invalid. let quals: &[Symbol] = if check_pub { - &[kw::Pub, kw::Gen, kw::Const, kw::Async, kw::Unsafe, kw::Safe, kw::Extern] + ALL_QUALS } else { &[kw::Gen, kw::Const, kw::Async, kw::Unsafe, kw::Safe, kw::Extern] }; @@ -2518,9 +2521,9 @@ impl<'a> Parser<'a> { || self.check_keyword_case(kw::Extern, case) && self.look_ahead(1, |t| t.can_begin_string_literal()) && (self.look_ahead(2, |t| t.is_keyword_case(kw::Fn, case)) || - // this branch is only for better diagnostic in later, `pub` is not allowed here + // this branch is only for better diagnostics; `pub`, `unsafe`, etc. are not allowed here (self.may_recover() - && self.look_ahead(2, |t| t.is_keyword(kw::Pub)) + && self.look_ahead(2, |t| ALL_QUALS.iter().any(|&kw| t.is_keyword(kw))) && self.look_ahead(3, |t| t.is_keyword_case(kw::Fn, case)))) } diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 7326b9ec51f2b..e7240869a394a 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -599,7 +599,7 @@ impl<'a> Parser<'a> { /// If the next token is the given keyword, eats it and returns `true`. /// Otherwise, returns `false`. An expectation is also added for diagnostics purposes. - // Public for rustfmt usage. + // Public for rustc_builtin_macros and rustfmt usage. #[inline] pub fn eat_keyword(&mut self, kw: Symbol) -> bool { if self.check_keyword(kw) { @@ -631,8 +631,11 @@ impl<'a> Parser<'a> { false } + /// If the next token is the given keyword, eats it and returns `true`. + /// Otherwise, returns `false`. No expectation is added. + // Public for rustc_builtin_macros usage. #[inline] - fn eat_keyword_noexpect(&mut self, kw: Symbol) -> bool { + pub fn eat_keyword_noexpect(&mut self, kw: Symbol) -> bool { if self.token.is_keyword(kw) { self.bump(); true diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index 1d93cbaddd6fe..bfe0d54e64521 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -69,9 +69,6 @@ passes_break_non_loop = .suggestion = use `break` on its own without a value inside this `{$kind}` loop .break_expr_suggestion = alternatively, you might have meant to use the available loop label -passes_cannot_inline_naked_function = - naked functions cannot be inlined - passes_cannot_stabilize_deprecated = an API can't be stabilized after it is deprecated .label = invalid version @@ -485,6 +482,11 @@ passes_naked_functions_asm_block = passes_naked_functions_asm_options = asm options unsupported in naked functions: {$unsupported_options} +passes_naked_functions_incompatible_attribute = + attribute incompatible with `#[naked]` + .label = the `{$attr}` attribute is incompatible with `#[naked]` + .naked_attribute = function marked with `#[naked]` here + passes_naked_functions_must_use_noreturn = asm in naked functions must use `noreturn` option .suggestion = consider specifying that the asm block is responsible for returning from the function @@ -492,9 +494,6 @@ passes_naked_functions_must_use_noreturn = passes_naked_functions_operands = only `const` and `sym` operands are supported in naked functions -passes_naked_tracked_caller = - cannot use `#[track_caller]` with `#[naked]` - passes_no_link = attribute should be applied to an `extern crate` item .label = not an `extern crate` item diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 9cbd989cc0e9f..e0cf65d3f9830 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -155,7 +155,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { [sym::rustc_std_internal_symbol] => { self.check_rustc_std_internal_symbol(attr, span, target) } - [sym::naked] => self.check_naked(hir_id, attr, span, target), + [sym::naked] => self.check_naked(hir_id, attr, span, target, attrs), [sym::rustc_never_returns_null_ptr] => { self.check_applied_to_fn_or_method(hir_id, attr, span, target) } @@ -410,12 +410,71 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } /// Checks if `#[naked]` is applied to a function definition. - fn check_naked(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) -> bool { + fn check_naked( + &self, + hir_id: HirId, + attr: &Attribute, + span: Span, + target: Target, + attrs: &[Attribute], + ) -> bool { + // many attributes don't make sense in combination with #[naked]. + // Notable attributes that are incompatible with `#[naked]` are: + // + // * `#[inline]` + // * `#[track_caller]` + // * `#[test]`, `#[ignore]`, `#[should_panic]` + // + // NOTE: when making changes to this list, check that `error_codes/E0736.md` remains accurate + const ALLOW_LIST: &[rustc_span::Symbol] = &[ + // conditional compilation + sym::cfg, + sym::cfg_attr, + // testing (allowed here so better errors can be generated in `rustc_builtin_macros::test`) + sym::test, + sym::ignore, + sym::should_panic, + sym::bench, + // diagnostics + sym::allow, + sym::warn, + sym::deny, + sym::forbid, + sym::deprecated, + sym::must_use, + // abi, linking and FFI + sym::export_name, + sym::link_section, + sym::linkage, + sym::no_mangle, + sym::naked, + sym::instruction_set, + // code generation + sym::cold, + sym::target_feature, + // documentation + sym::doc, + ]; + match target { Target::Fn - | Target::Method(MethodKind::Trait { body: true } | MethodKind::Inherent) => true, + | Target::Method(MethodKind::Trait { body: true } | MethodKind::Inherent) => { + for other_attr in attrs { + if !ALLOW_LIST.iter().any(|name| other_attr.has_name(*name)) { + self.dcx().emit_err(errors::NakedFunctionIncompatibleAttribute { + span: other_attr.span, + naked_span: attr.span, + attr: other_attr.name_or_empty(), + }); + + return false; + } + } + + true + } // FIXME(#80564): We permit struct fields, match arms and macro defs to have an - // `#[allow_internal_unstable]` attribute with just a lint, because we previously + // `#[naked]` attribute with just a lint, because we previously // erroneously allowed it and some crates used it accidentally, to be compatible // with crates depending on them, we can't throw an error here. Target::Field | Target::Arm | Target::MacroDef => { @@ -488,7 +547,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } - /// Checks if a `#[track_caller]` is applied to a non-naked function. Returns `true` if valid. + /// Checks if a `#[track_caller]` is applied to a function. Returns `true` if valid. fn check_track_caller( &self, hir_id: HirId, @@ -498,10 +557,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { target: Target, ) -> bool { match target { - _ if attrs.iter().any(|attr| attr.has_name(sym::naked)) => { - self.dcx().emit_err(errors::NakedTrackedCaller { attr_span }); - false - } Target::Fn => { // `#[track_caller]` is not valid on weak lang items because they are called via // `extern` declarations and `#[track_caller]` would alter their ABI. diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index 55514883cb1f8..239bc8e7accfc 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -54,7 +54,24 @@ impl Publicness { } } -fn struct_all_fields_are_public(tcx: TyCtxt<'_>, id: DefId) -> bool { +fn adt_of<'tcx>(ty: &hir::Ty<'tcx>) -> Option<(LocalDefId, DefKind)> { + match ty.kind { + TyKind::Path(hir::QPath::Resolved(_, path)) => { + if let Res::Def(def_kind, def_id) = path.res + && let Some(local_def_id) = def_id.as_local() + { + Some((local_def_id, def_kind)) + } else { + None + } + } + TyKind::Slice(ty) | TyKind::Array(ty, _) => adt_of(ty), + TyKind::Ptr(ty) | TyKind::Ref(_, ty) => adt_of(ty.ty), + _ => None, + } +} + +fn struct_all_fields_are_public(tcx: TyCtxt<'_>, id: LocalDefId) -> bool { // treat PhantomData and positional ZST as public, // we don't want to lint types which only have them, // cause it's a common way to use such types to check things like well-formedness @@ -79,10 +96,7 @@ fn struct_all_fields_are_public(tcx: TyCtxt<'_>, id: DefId) -> bool { /// for enum and union, just check they are public, /// and doesn't solve types like &T for now, just skip them fn ty_ref_to_pub_struct(tcx: TyCtxt<'_>, ty: &hir::Ty<'_>) -> Publicness { - if let TyKind::Path(hir::QPath::Resolved(_, path)) = ty.kind - && let Res::Def(def_kind, def_id) = path.res - && def_id.is_local() - { + if let Some((def_id, def_kind)) = adt_of(ty) { return match def_kind { DefKind::Enum | DefKind::Union => { let ty_is_public = tcx.visibility(def_id).is_public(); @@ -565,10 +579,8 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { } fn impl_item_with_used_self(&mut self, impl_id: hir::ItemId, impl_item_id: LocalDefId) -> bool { - if let TyKind::Path(hir::QPath::Resolved(_, path)) = - self.tcx.hir().item(impl_id).expect_impl().self_ty.kind - && let Res::Def(def_kind, def_id) = path.res - && let Some(local_def_id) = def_id.as_local() + if let Some((local_def_id, def_kind)) = + adt_of(self.tcx.hir().item(impl_id).expect_impl().self_ty) && matches!(def_kind, DefKind::Struct | DefKind::Enum | DefKind::Union) { if let Some(trait_item_id) = self.tcx.associated_item(impl_item_id).trait_item_def_id @@ -915,7 +927,7 @@ fn create_and_seed_worklist( match tcx.def_kind(id) { DefKind::Impl { .. } => false, DefKind::AssocConst | DefKind::AssocTy | DefKind::AssocFn => !matches!(tcx.associated_item(id).container, AssocItemContainer::ImplContainer), - DefKind::Struct => struct_all_fields_are_public(tcx, id.to_def_id()) || has_allow_dead_code_or_lang_attr(tcx, id).is_some(), + DefKind::Struct => struct_all_fields_are_public(tcx, id) || has_allow_dead_code_or_lang_attr(tcx, id).is_some(), _ => true }) .map(|id| (id, ComesFromAllowExpect::No)) diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index 58d27d5b4bbaa..b195ba973ce29 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -79,13 +79,6 @@ pub struct AttrShouldBeAppliedToFn { pub on_crate: bool, } -#[derive(Diagnostic)] -#[diag(passes_naked_tracked_caller, code = E0736)] -pub struct NakedTrackedCaller { - #[primary_span] - pub attr_span: Span, -} - #[derive(Diagnostic)] #[diag(passes_should_be_applied_to_fn, code = E0739)] pub struct TrackedCallerWrongLocation { @@ -1124,13 +1117,6 @@ pub struct UnlabeledCfInWhileCondition<'a> { pub cf_type: &'a str, } -#[derive(Diagnostic)] -#[diag(passes_cannot_inline_naked_function)] -pub struct CannotInlineNakedFunction { - #[primary_span] - pub span: Span, -} - #[derive(LintDiagnostic)] #[diag(passes_undefined_naked_function_abi)] pub struct UndefinedNakedFunctionAbi; @@ -1196,6 +1182,17 @@ pub struct NakedFunctionsMustUseNoreturn { pub last_span: Span, } +#[derive(Diagnostic)] +#[diag(passes_naked_functions_incompatible_attribute, code = E0736)] +pub struct NakedFunctionIncompatibleAttribute { + #[primary_span] + #[label] + pub span: Span, + #[label(passes_naked_attribute)] + pub naked_span: Span, + pub attr: Symbol, +} + #[derive(Diagnostic)] #[diag(passes_attr_only_in_functions)] pub struct AttrOnlyInFunctions { diff --git a/compiler/rustc_passes/src/naked_functions.rs b/compiler/rustc_passes/src/naked_functions.rs index dbbf802c920d4..b72ce239c4a96 100644 --- a/compiler/rustc_passes/src/naked_functions.rs +++ b/compiler/rustc_passes/src/naked_functions.rs @@ -14,9 +14,8 @@ use rustc_span::Span; use rustc_target::spec::abi::Abi; use crate::errors::{ - CannotInlineNakedFunction, NakedFunctionsAsmBlock, NakedFunctionsAsmOptions, - NakedFunctionsMustUseNoreturn, NakedFunctionsOperands, NoPatterns, ParamsNotAllowed, - UndefinedNakedFunctionAbi, + NakedFunctionsAsmBlock, NakedFunctionsAsmOptions, NakedFunctionsMustUseNoreturn, + NakedFunctionsOperands, NoPatterns, ParamsNotAllowed, UndefinedNakedFunctionAbi, }; pub(crate) fn provide(providers: &mut Providers) { @@ -53,15 +52,6 @@ fn check_mod_naked_functions(tcx: TyCtxt<'_>, module_def_id: LocalModDefId) { check_no_patterns(tcx, body.params); check_no_parameters_use(tcx, body); check_asm(tcx, def_id, body); - check_inline(tcx, def_id); - } -} - -/// Check that the function isn't inlined. -fn check_inline(tcx: TyCtxt<'_>, def_id: LocalDefId) { - let attrs = tcx.get_attrs(def_id, sym::inline); - for attr in attrs { - tcx.dcx().emit_err(CannotInlineNakedFunction { span: attr.span }); } } @@ -244,10 +234,7 @@ impl<'tcx> CheckInlineAssembly<'tcx> { self.tcx.dcx().emit_err(NakedFunctionsOperands { unsupported_operands }); } - let supported_options = - InlineAsmOptions::RAW | InlineAsmOptions::NORETURN | InlineAsmOptions::ATT_SYNTAX; - let unsupported_options = asm.options.difference(supported_options); - + let unsupported_options = asm.options.difference(InlineAsmOptions::NAKED_OPTIONS); if !unsupported_options.is_empty() { self.tcx.dcx().emit_err(NakedFunctionsAsmOptions { span, diff --git a/compiler/rustc_pattern_analysis/src/lib.rs b/compiler/rustc_pattern_analysis/src/lib.rs index 1b4bcb789d2da..a5c0b13c90be1 100644 --- a/compiler/rustc_pattern_analysis/src/lib.rs +++ b/compiler/rustc_pattern_analysis/src/lib.rs @@ -1,4 +1,6 @@ -//! Analysis of patterns, notably match exhaustiveness checking. +//! Analysis of patterns, notably match exhaustiveness checking. The main entrypoint for this crate +//! is [`usefulness::compute_match_usefulness`]. For rustc-specific types and entrypoints, see the +//! [`rustc`] module. // tidy-alphabetical-start #![allow(rustc::diagnostic_outside_of_impl)] @@ -23,14 +25,8 @@ use std::fmt; pub use rustc_index::{Idx, IndexVec}; // re-exported to avoid rustc_index version issues -#[cfg(feature = "rustc")] -use rustc_middle::ty::Ty; -#[cfg(feature = "rustc")] -use rustc_span::ErrorGuaranteed; - use crate::constructor::{Constructor, ConstructorSet, IntRange}; use crate::pat::DeconstructedPat; -use crate::pat_column::PatternColumn; pub trait Captures<'a> {} impl<'a, T: ?Sized> Captures<'a> for T {} @@ -128,30 +124,3 @@ impl<'p, Cx: PatCx> Clone for MatchArm<'p, Cx> { } impl<'p, Cx: PatCx> Copy for MatchArm<'p, Cx> {} - -/// The entrypoint for this crate. Computes whether a match is exhaustive and which of its arms are -/// useful, and runs some lints. -#[cfg(feature = "rustc")] -pub fn analyze_match<'p, 'tcx>( - tycx: &rustc::RustcPatCtxt<'p, 'tcx>, - arms: &[rustc::MatchArm<'p, 'tcx>], - scrut_ty: Ty<'tcx>, - pattern_complexity_limit: Option, -) -> Result, ErrorGuaranteed> { - use lints::lint_nonexhaustive_missing_variants; - use usefulness::{compute_match_usefulness, PlaceValidity}; - - let scrut_ty = tycx.reveal_opaque_ty(scrut_ty); - let scrut_validity = PlaceValidity::from_bool(tycx.known_valid_scrutinee); - let report = - compute_match_usefulness(tycx, arms, scrut_ty, scrut_validity, pattern_complexity_limit)?; - - // Run the non_exhaustive_omitted_patterns lint. Only run on refutable patterns to avoid hitting - // `if let`s. Only run if the match is exhaustive otherwise the error is redundant. - if tycx.refutable && report.non_exhaustiveness_witnesses.is_empty() { - let pat_column = PatternColumn::new(arms); - lint_nonexhaustive_missing_variants(tycx, arms, &pat_column, scrut_ty)?; - } - - Ok(report) -} diff --git a/compiler/rustc_pattern_analysis/src/pat.rs b/compiler/rustc_pattern_analysis/src/pat.rs index e8d6c542c5fd4..a591c3c554b52 100644 --- a/compiler/rustc_pattern_analysis/src/pat.rs +++ b/compiler/rustc_pattern_analysis/src/pat.rs @@ -11,7 +11,7 @@ use crate::{PatCx, PrivateUninhabitedField}; use self::Constructor::*; /// A globally unique id to distinguish patterns. -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] pub(crate) struct PatId(u32); impl PatId { fn new() -> Self { @@ -147,6 +147,21 @@ impl fmt::Debug for DeconstructedPat { } } +/// Delegate to `uid`. +impl PartialEq for DeconstructedPat { + fn eq(&self, other: &Self) -> bool { + self.uid == other.uid + } +} +/// Delegate to `uid`. +impl Eq for DeconstructedPat {} +/// Delegate to `uid`. +impl std::hash::Hash for DeconstructedPat { + fn hash(&self, state: &mut H) { + self.uid.hash(state); + } +} + /// Represents either a pattern obtained from user input or a wildcard constructed during the /// algorithm. Do not use `Wild` to represent a wildcard pattern comping from user input. /// diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs index 6ef2d69273ee7..910dd4c6c1a84 100644 --- a/compiler/rustc_pattern_analysis/src/rustc.rs +++ b/compiler/rustc_pattern_analysis/src/rustc.rs @@ -20,6 +20,9 @@ use rustc_target::abi::{FieldIdx, Integer, VariantIdx, FIRST_VARIANT}; use crate::constructor::{ IntRange, MaybeInfiniteInt, OpaqueId, RangeEnd, Slice, SliceKind, VariantVisibility, }; +use crate::lints::lint_nonexhaustive_missing_variants; +use crate::pat_column::PatternColumn; +use crate::usefulness::{compute_match_usefulness, PlaceValidity}; use crate::{errors, Captures, PatCx, PrivateUninhabitedField}; use crate::constructor::Constructor::*; @@ -29,6 +32,8 @@ pub type Constructor<'p, 'tcx> = crate::constructor::Constructor = crate::constructor::ConstructorSet>; pub type DeconstructedPat<'p, 'tcx> = crate::pat::DeconstructedPat>; pub type MatchArm<'p, 'tcx> = crate::MatchArm<'p, RustcPatCtxt<'p, 'tcx>>; +pub type RedundancyExplanation<'p, 'tcx> = + crate::usefulness::RedundancyExplanation<'p, RustcPatCtxt<'p, 'tcx>>; pub type Usefulness<'p, 'tcx> = crate::usefulness::Usefulness<'p, RustcPatCtxt<'p, 'tcx>>; pub type UsefulnessReport<'p, 'tcx> = crate::usefulness::UsefulnessReport<'p, RustcPatCtxt<'p, 'tcx>>; @@ -1058,3 +1063,26 @@ fn expand_or_pat<'p, 'tcx>(pat: &'p Pat<'tcx>) -> Vec<&'p Pat<'tcx>> { expand(pat, &mut pats); pats } + +/// The entrypoint for this crate. Computes whether a match is exhaustive and which of its arms are +/// useful, and runs some lints. +pub fn analyze_match<'p, 'tcx>( + tycx: &RustcPatCtxt<'p, 'tcx>, + arms: &[MatchArm<'p, 'tcx>], + scrut_ty: Ty<'tcx>, + pattern_complexity_limit: Option, +) -> Result, ErrorGuaranteed> { + let scrut_ty = tycx.reveal_opaque_ty(scrut_ty); + let scrut_validity = PlaceValidity::from_bool(tycx.known_valid_scrutinee); + let report = + compute_match_usefulness(tycx, arms, scrut_ty, scrut_validity, pattern_complexity_limit)?; + + // Run the non_exhaustive_omitted_patterns lint. Only run on refutable patterns to avoid hitting + // `if let`s. Only run if the match is exhaustive otherwise the error is redundant. + if tycx.refutable && report.non_exhaustiveness_witnesses.is_empty() { + let pat_column = PatternColumn::new(arms); + lint_nonexhaustive_missing_variants(tycx, arms, &pat_column, scrut_ty)?; + } + + Ok(report) +} diff --git a/compiler/rustc_pattern_analysis/src/usefulness.rs b/compiler/rustc_pattern_analysis/src/usefulness.rs index 8486792b5543f..76dc338e71cd3 100644 --- a/compiler/rustc_pattern_analysis/src/usefulness.rs +++ b/compiler/rustc_pattern_analysis/src/usefulness.rs @@ -713,7 +713,7 @@ use self::PlaceValidity::*; use crate::constructor::{Constructor, ConstructorSet, IntRange}; use crate::pat::{DeconstructedPat, PatId, PatOrWild, WitnessPat}; use crate::{Captures, MatchArm, PatCx, PrivateUninhabitedField}; -use rustc_hash::FxHashSet; +use rustc_hash::{FxHashMap, FxHashSet}; use rustc_index::bit_set::BitSet; use smallvec::{smallvec, SmallVec}; use std::fmt; @@ -726,18 +726,81 @@ pub fn ensure_sufficient_stack(f: impl FnOnce() -> R) -> R { f() } +/// A pattern is a "branch" if it is the immediate child of an or-pattern, or if it is the whole +/// pattern of a match arm. These are the patterns that can be meaningfully considered "redundant", +/// since e.g. `0` in `(0, 1)` cannot be redundant on its own. +/// +/// We track for each branch pattern whether it is useful, and if not why. +struct BranchPatUsefulness<'p, Cx: PatCx> { + /// Whether this pattern is useful. + useful: bool, + /// A set of patterns that: + /// - come before this one in the match; + /// - intersect this one; + /// - at the end of the algorithm, if `!self.useful`, their union covers this pattern. + covered_by: FxHashSet<&'p DeconstructedPat>, +} + +impl<'p, Cx: PatCx> BranchPatUsefulness<'p, Cx> { + /// Update `self` with the usefulness information found in `row`. + fn update(&mut self, row: &MatrixRow<'p, Cx>, matrix: &Matrix<'p, Cx>) { + self.useful |= row.useful; + // This deserves an explanation: `intersects_at_least` does not contain all intersections + // because we skip irrelevant values (see the docs for `intersects_at_least` for an + // example). Yet we claim this suffices to build a covering set. + // + // Let `p` be our pattern. Assume it is found not useful. For a value `v`, if the value was + // relevant then we explored that value and found that there was another pattern `q` before + // `p` that matches it too. We therefore recorded an intersection with `q`. If `v` was + // irrelevant, we know there's another value `v2` that matches strictly fewer rows (while + // still matching our row) and is relevant. Since `p` is not useful, there must have been a + // `q` before `p` that matches `v2`, and we recorded that intersection. Since `v2` matches + // strictly fewer rows than `v`, `q` also matches `v`. In either case, we recorded in + // `intersects_at_least` a pattern that matches `v`. Hence using `intersects_at_least` is + // sufficient to build a covering set. + for row_id in row.intersects_at_least.iter() { + let row = &matrix.rows[row_id]; + if row.useful && !row.is_under_guard { + if let PatOrWild::Pat(intersecting) = row.head() { + self.covered_by.insert(intersecting); + } + } + } + } + + /// Check whether this pattern is redundant, and if so explain why. + fn is_redundant(&self) -> Option> { + if self.useful { + None + } else { + // We avoid instability by sorting by `uid`. The order of `uid`s only depends on the + // pattern structure. + #[cfg_attr(feature = "rustc", allow(rustc::potential_query_instability))] + let mut covered_by: Vec<_> = self.covered_by.iter().copied().collect(); + covered_by.sort_by_key(|pat| pat.uid); // sort to avoid instability + Some(RedundancyExplanation { covered_by }) + } + } +} + +impl<'p, Cx: PatCx> Default for BranchPatUsefulness<'p, Cx> { + fn default() -> Self { + Self { useful: Default::default(), covered_by: Default::default() } + } +} + /// Context that provides information for usefulness checking. -struct UsefulnessCtxt<'a, Cx: PatCx> { +struct UsefulnessCtxt<'a, 'p, Cx: PatCx> { /// The context for type information. tycx: &'a Cx, - /// Collect the patterns found useful during usefulness checking. This is used to lint - /// unreachable (sub)patterns. - useful_subpatterns: FxHashSet, + /// Track information about the usefulness of branch patterns (see definition of "branch + /// pattern" at [`BranchPatUsefulness`]). + branch_usefulness: FxHashMap>, complexity_limit: Option, complexity_level: usize, } -impl<'a, Cx: PatCx> UsefulnessCtxt<'a, Cx> { +impl<'a, 'p, Cx: PatCx> UsefulnessCtxt<'a, 'p, Cx> { fn increase_complexity_level(&mut self, complexity_add: usize) -> Result<(), Cx::Error> { self.complexity_level += complexity_add; if self @@ -1051,14 +1114,40 @@ struct MatrixRow<'p, Cx: PatCx> { /// [`compute_exhaustiveness_and_usefulness`] if the arm is found to be useful. /// This is reset to `false` when specializing. useful: bool, - /// Tracks which rows above this one have an intersection with this one, i.e. such that there is - /// a value that matches both rows. - /// Note: Because of relevancy we may miss some intersections. The intersections we do find are - /// correct. - intersects: BitSet, + /// Tracks some rows above this one that have an intersection with this one, i.e. such that + /// there is a value that matches both rows. + /// Because of relevancy we may miss some intersections. The intersections we do find are + /// correct. In other words, this is an underapproximation of the real set of intersections. + /// + /// For example: + /// ```rust,ignore(illustrative) + /// match ... { + /// (true, _, _) => {} // `intersects_at_least = []` + /// (_, true, 0..=10) => {} // `intersects_at_least = []` + /// (_, true, 5..15) => {} // `intersects_at_least = [1]` + /// } + /// ``` + /// Here the `(true, true)` case is irrelevant. Since we skip it, we will not detect that row 0 + /// intersects rows 1 and 2. + intersects_at_least: BitSet, + /// Whether the head pattern is a branch (see definition of "branch pattern" at + /// [`BranchPatUsefulness`]) + head_is_branch: bool, } impl<'p, Cx: PatCx> MatrixRow<'p, Cx> { + fn new(arm: &MatchArm<'p, Cx>, arm_id: usize) -> Self { + MatrixRow { + pats: PatStack::from_pattern(arm.pat), + parent_row: arm_id, + is_under_guard: arm.has_guard, + useful: false, + intersects_at_least: BitSet::new_empty(0), // Initialized in `Matrix::push`. + // This pattern is a branch because it comes from a match arm. + head_is_branch: true, + } + } + fn len(&self) -> usize { self.pats.len() } @@ -1076,12 +1165,14 @@ impl<'p, Cx: PatCx> MatrixRow<'p, Cx> { &self, parent_row: usize, ) -> impl Iterator> + Captures<'_> { + let is_or_pat = self.pats.head().is_or_pat(); self.pats.expand_or_pat().map(move |patstack| MatrixRow { pats: patstack, parent_row, is_under_guard: self.is_under_guard, useful: false, - intersects: BitSet::new_empty(0), // Initialized in `Matrix::expand_and_push`. + intersects_at_least: BitSet::new_empty(0), // Initialized in `Matrix::push`. + head_is_branch: is_or_pat, }) } @@ -1100,7 +1191,8 @@ impl<'p, Cx: PatCx> MatrixRow<'p, Cx> { parent_row, is_under_guard: self.is_under_guard, useful: false, - intersects: BitSet::new_empty(0), // Initialized in `Matrix::push`. + intersects_at_least: BitSet::new_empty(0), // Initialized in `Matrix::push`. + head_is_branch: false, }) } } @@ -1138,7 +1230,7 @@ struct Matrix<'p, Cx: PatCx> { impl<'p, Cx: PatCx> Matrix<'p, Cx> { /// Pushes a new row to the matrix. Internal method, prefer [`Matrix::new`]. fn push(&mut self, mut row: MatrixRow<'p, Cx>) { - row.intersects = BitSet::new_empty(self.rows.len()); + row.intersects_at_least = BitSet::new_empty(self.rows.len()); self.rows.push(row); } @@ -1156,14 +1248,7 @@ impl<'p, Cx: PatCx> Matrix<'p, Cx> { wildcard_row_is_relevant: true, }; for (arm_id, arm) in arms.iter().enumerate() { - let v = MatrixRow { - pats: PatStack::from_pattern(arm.pat), - parent_row: arm_id, - is_under_guard: arm.has_guard, - useful: false, - intersects: BitSet::new_empty(0), // Initialized in `Matrix::push`. - }; - matrix.push(v); + matrix.push(MatrixRow::new(arm, arm_id)); } matrix } @@ -1242,12 +1327,12 @@ impl<'p, Cx: PatCx> Matrix<'p, Cx> { let parent_row = &mut self.rows[parent_row_id]; // A parent row is useful if any of its children is. parent_row.useful |= child_row.useful; - for child_intersection in child_row.intersects.iter() { + for child_intersection in child_row.intersects_at_least.iter() { // Convert the intersecting ids into ids for the parent matrix. let parent_intersection = specialized.rows[child_intersection].parent_row; // Note: self-intersection can happen with or-patterns. if parent_intersection != parent_row_id { - parent_row.intersects.insert(parent_intersection); + parent_row.intersects_at_least.insert(parent_intersection); } } } @@ -1544,7 +1629,7 @@ fn collect_overlapping_range_endpoints<'p, Cx: PatCx>( let overlaps_with: Vec<_> = prefixes .iter() .filter(|&&(other_child_row_id, _)| { - child_row.intersects.contains(other_child_row_id) + child_row.intersects_at_least.contains(other_child_row_id) }) .map(|&(_, pat)| pat) .collect(); @@ -1560,7 +1645,7 @@ fn collect_overlapping_range_endpoints<'p, Cx: PatCx>( let overlaps_with: Vec<_> = suffixes .iter() .filter(|&&(other_child_row_id, _)| { - child_row.intersects.contains(other_child_row_id) + child_row.intersects_at_least.contains(other_child_row_id) }) .map(|&(_, pat)| pat) .collect(); @@ -1603,8 +1688,8 @@ fn collect_non_contiguous_range_endpoints<'p, Cx: PatCx>( /// The core of the algorithm. /// /// This recursively computes witnesses of the non-exhaustiveness of `matrix` (if any). Also tracks -/// usefulness of each row in the matrix (in `row.useful`). We track usefulness of each subpattern -/// in `mcx.useful_subpatterns`. +/// usefulness of each row in the matrix (in `row.useful`). We track usefulness of subpatterns in +/// `mcx.branch_usefulness`. /// /// The input `Matrix` and the output `WitnessMatrix` together match the type exhaustively. /// @@ -1616,7 +1701,7 @@ fn collect_non_contiguous_range_endpoints<'p, Cx: PatCx>( /// This is all explained at the top of the file. #[instrument(level = "debug", skip(mcx), ret)] fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: PatCx>( - mcx: &mut UsefulnessCtxt<'a, Cx>, + mcx: &mut UsefulnessCtxt<'a, 'p, Cx>, matrix: &mut Matrix<'p, Cx>, ) -> Result, Cx::Error> { debug_assert!(matrix.rows().all(|r| r.len() == matrix.column_count())); @@ -1635,7 +1720,7 @@ fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: PatCx>( let mut useful = true; // Whether the next row is useful. for (i, row) in matrix.rows_mut().enumerate() { row.useful = useful; - row.intersects.insert_range(0..i); + row.intersects_at_least.insert_range(0..i); // The next rows stays useful if this one is under a guard. useful &= row.is_under_guard; } @@ -1677,7 +1762,7 @@ fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: PatCx>( if let Constructor::IntRange(overlap_range) = ctor { if overlap_range.is_singleton() && spec_matrix.rows.len() >= 2 - && spec_matrix.rows.iter().any(|row| !row.intersects.is_empty()) + && spec_matrix.rows.iter().any(|row| !row.intersects_at_least.is_empty()) { collect_overlapping_range_endpoints(mcx.tycx, overlap_range, matrix, &spec_matrix); } @@ -1697,14 +1782,11 @@ fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: PatCx>( } } - // Record usefulness in the patterns. + // Record usefulness of the branch patterns. for row in matrix.rows() { - if row.useful { + if row.head_is_branch { if let PatOrWild::Pat(pat) = row.head() { - let newly_useful = mcx.useful_subpatterns.insert(pat.uid); - if newly_useful { - debug!("newly useful: {pat:?}"); - } + mcx.branch_usefulness.entry(pat.uid).or_default().update(row, matrix); } } } @@ -1712,16 +1794,25 @@ fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: PatCx>( Ok(ret) } +/// Indicates why a given pattern is considered redundant. +#[derive(Clone, Debug)] +pub struct RedundancyExplanation<'p, Cx: PatCx> { + /// All the values matched by this pattern are already matched by the given set of patterns. + /// This list is not guaranteed to be minimal but the contained patterns are at least guaranteed + /// to intersect this pattern. + pub covered_by: Vec<&'p DeconstructedPat>, +} + /// Indicates whether or not a given arm is useful. #[derive(Clone, Debug)] pub enum Usefulness<'p, Cx: PatCx> { /// The arm is useful. This additionally carries a set of or-pattern branches that have been /// found to be redundant despite the overall arm being useful. Used only in the presence of /// or-patterns, otherwise it stays empty. - Useful(Vec<&'p DeconstructedPat>), + Useful(Vec<(&'p DeconstructedPat, RedundancyExplanation<'p, Cx>)>), /// The arm is redundant and can be removed without changing the behavior of the match /// expression. - Redundant, + Redundant(RedundancyExplanation<'p, Cx>), } /// The output of checking a match for exhaustiveness and arm usefulness. @@ -1747,7 +1838,7 @@ pub fn compute_match_usefulness<'p, Cx: PatCx>( ) -> Result, Cx::Error> { let mut cx = UsefulnessCtxt { tycx, - useful_subpatterns: FxHashSet::default(), + branch_usefulness: FxHashMap::default(), complexity_limit, complexity_level: 0, }; @@ -1760,26 +1851,32 @@ pub fn compute_match_usefulness<'p, Cx: PatCx>( .copied() .map(|arm| { debug!(?arm); - let usefulness = if cx.useful_subpatterns.contains(&arm.pat.uid) { + let usefulness = cx.branch_usefulness.get(&arm.pat.uid).unwrap(); + let usefulness = if let Some(explanation) = usefulness.is_redundant() { + Usefulness::Redundant(explanation) + } else { let mut redundant_subpats = Vec::new(); arm.pat.walk(&mut |subpat| { - if cx.useful_subpatterns.contains(&subpat.uid) { - true // keep recursing + if let Some(u) = cx.branch_usefulness.get(&subpat.uid) { + if let Some(explanation) = u.is_redundant() { + redundant_subpats.push((subpat, explanation)); + false // stop recursing + } else { + true // keep recursing + } } else { - redundant_subpats.push(subpat); - false // stop recursing + true // keep recursing } }); Usefulness::Useful(redundant_subpats) - } else { - Usefulness::Redundant }; debug!(?usefulness); (arm, usefulness) }) .collect(); - let arm_intersections: Vec<_> = matrix.rows().map(|row| row.intersects.clone()).collect(); + let arm_intersections: Vec<_> = + matrix.rows().map(|row| row.intersects_at_least.clone()).collect(); Ok(UsefulnessReport { arm_usefulness, non_exhaustiveness_witnesses, arm_intersections }) } diff --git a/compiler/rustc_pattern_analysis/tests/common/mod.rs b/compiler/rustc_pattern_analysis/tests/common/mod.rs index 6e8bb50500554..68ec75b770533 100644 --- a/compiler/rustc_pattern_analysis/tests/common/mod.rs +++ b/compiler/rustc_pattern_analysis/tests/common/mod.rs @@ -25,7 +25,7 @@ pub fn init_tracing() { /// A simple set of types. #[allow(dead_code)] -#[derive(Debug, Copy, Clone)] +#[derive(Debug, Copy, Clone, PartialEq, Eq)] pub enum Ty { /// Booleans Bool, @@ -33,6 +33,8 @@ pub enum Ty { U8, /// Tuples. Tuple(&'static [Ty]), + /// Enum with one variant of each given type. + Enum(&'static [Ty]), /// A struct with `arity` fields of type `ty`. BigStruct { arity: usize, ty: &'static Ty }, /// A enum with `arity` variants of type `ty`. @@ -46,12 +48,23 @@ impl Ty { match (ctor, *self) { (Struct, Ty::Tuple(tys)) => tys.iter().copied().collect(), (Struct, Ty::BigStruct { arity, ty }) => (0..arity).map(|_| *ty).collect(), + (Variant(i), Ty::Enum(tys)) => vec![tys[*i]], (Variant(_), Ty::BigEnum { ty, .. }) => vec![*ty], (Bool(..) | IntRange(..) | NonExhaustive | Missing | Wildcard, _) => vec![], _ => panic!("Unexpected ctor {ctor:?} for type {self:?}"), } } + fn is_empty(&self) -> bool { + match *self { + Ty::Bool | Ty::U8 => false, + Ty::Tuple(tys) => tys.iter().any(|ty| ty.is_empty()), + Ty::Enum(tys) => tys.iter().all(|ty| ty.is_empty()), + Ty::BigStruct { arity, ty } => arity != 0 && ty.is_empty(), + Ty::BigEnum { arity, ty } => arity == 0 || ty.is_empty(), + } + } + pub fn ctor_set(&self) -> ConstructorSet { match *self { Ty::Bool => ConstructorSet::Bool, @@ -64,10 +77,32 @@ impl Ty { range_2: None, }, Ty::Tuple(..) | Ty::BigStruct { .. } => ConstructorSet::Struct { empty: false }, - Ty::BigEnum { arity, .. } => ConstructorSet::Variants { - variants: (0..arity).map(|_| VariantVisibility::Visible).collect(), + Ty::Enum(tys) if tys.is_empty() => ConstructorSet::NoConstructors, + Ty::Enum(tys) => ConstructorSet::Variants { + variants: tys + .iter() + .map(|ty| { + if ty.is_empty() { + VariantVisibility::Empty + } else { + VariantVisibility::Visible + } + }) + .collect(), non_exhaustive: false, }, + Ty::BigEnum { arity: 0, .. } => ConstructorSet::NoConstructors, + Ty::BigEnum { arity, ty } => { + let vis = if ty.is_empty() { + VariantVisibility::Empty + } else { + VariantVisibility::Visible + }; + ConstructorSet::Variants { + variants: (0..arity).map(|_| vis).collect(), + non_exhaustive: false, + } + } } } @@ -79,6 +114,7 @@ impl Ty { match (*self, ctor) { (Ty::Tuple(..), _) => Ok(()), (Ty::BigStruct { .. }, _) => write!(f, "BigStruct"), + (Ty::Enum(..), Constructor::Variant(i)) => write!(f, "Enum::Variant{i}"), (Ty::BigEnum { .. }, Constructor::Variant(i)) => write!(f, "BigEnum::Variant{i}"), _ => write!(f, "{:?}::{:?}", self, ctor), } @@ -119,7 +155,7 @@ impl PatCx for Cx { } fn is_min_exhaustive_patterns_feature_on(&self) -> bool { - false + true } fn ctor_arity(&self, ctor: &Constructor, ty: &Self::Ty) -> usize { diff --git a/compiler/rustc_pattern_analysis/tests/exhaustiveness.rs b/compiler/rustc_pattern_analysis/tests/exhaustiveness.rs index 4f8d68d5514be..205d430d49509 100644 --- a/compiler/rustc_pattern_analysis/tests/exhaustiveness.rs +++ b/compiler/rustc_pattern_analysis/tests/exhaustiveness.rs @@ -76,3 +76,17 @@ fn test_nested() { Struct(Variant.1, Variant.1), )); } + +#[test] +fn test_empty() { + // `TY = Result` + const TY: Ty = Ty::Enum(&[Ty::Bool, Ty::Enum(&[])]); + assert_exhaustive(pats!(TY; + Variant.0, + )); + let ty = Ty::Tuple(&[Ty::Bool, TY]); + assert_exhaustive(pats!(ty; + (true, Variant.0), + (false, Variant.0), + )); +} diff --git a/compiler/rustc_pattern_analysis/tests/intersection.rs b/compiler/rustc_pattern_analysis/tests/intersection.rs index 4a96b7248dae6..8c8cb3c796d8b 100644 --- a/compiler/rustc_pattern_analysis/tests/intersection.rs +++ b/compiler/rustc_pattern_analysis/tests/intersection.rs @@ -67,4 +67,24 @@ fn test_nested() { ), &[&[], &[]], ); + let ty = Ty::Tuple(&[Ty::Bool; 3]); + assert_intersects( + pats!(ty; + (true, true, _), + (true, _, true), + (false, _, _), + ), + &[&[], &[], &[]], + ); + let ty = Ty::Tuple(&[Ty::Bool, Ty::Bool, Ty::U8]); + assert_intersects( + pats!(ty; + (true, _, _), + (_, true, 0..10), + (_, true, 10..), + (_, true, 3), + _, + ), + &[&[], &[], &[], &[1], &[0, 1, 2, 3]], + ); } diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 046ae5fc5933d..df80f4df5b99b 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -1448,7 +1448,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { ); if macro_kind == MacroKind::Bang && ident.name == sym::macro_rules { - err.subdiagnostic(MaybeMissingMacroRulesName { span: ident.span }); + let label_span = ident.span.shrink_to_hi(); + let mut spans = MultiSpan::from_span(label_span); + spans.push_span_label(label_span, "put a macro name here"); + err.subdiagnostic(MaybeMissingMacroRulesName { spans: spans }); return; } diff --git a/compiler/rustc_resolve/src/errors.rs b/compiler/rustc_resolve/src/errors.rs index 0a68231c6fee4..698147765b358 100644 --- a/compiler/rustc_resolve/src/errors.rs +++ b/compiler/rustc_resolve/src/errors.rs @@ -669,7 +669,7 @@ pub(crate) struct MacroSuggMovePosition { #[note(resolve_missing_macro_rules_name)] pub(crate) struct MaybeMissingMacroRulesName { #[primary_span] - pub(crate) span: Span, + pub(crate) spans: MultiSpan, } #[derive(Subdiagnostic)] diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 2b30ca8a89478..cfd263d5951dc 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -557,6 +557,7 @@ symbols! { clobber_abi, clone, clone_closures, + clone_fn, clone_from, closure, closure_lifetime_binder, @@ -1229,6 +1230,7 @@ symbols! { modifiers, module, module_path, + more_maybe_bounds, more_qualified_paths, more_struct_aliases, movbe_target_feature, diff --git a/compiler/rustc_target/Cargo.toml b/compiler/rustc_target/Cargo.toml index 2cb8ac7e8bfb3..c7d24154e8bd4 100644 --- a/compiler/rustc_target/Cargo.toml +++ b/compiler/rustc_target/Cargo.toml @@ -22,5 +22,5 @@ tracing = "0.1" # tidy-alphabetical-start default-features = false features = ["elf", "macho"] -version = "0.32.0" +version = "0.36.2" # tidy-alphabetical-end diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/find_anon_type.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/find_anon_type.rs index b91b755d68370..a892ce5886112 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/find_anon_type.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/find_anon_type.rs @@ -84,7 +84,7 @@ impl<'tcx> Visitor<'tcx> for FindNestedTypeVisitor<'tcx> { } hir::TyKind::TraitObject(bounds, ..) => { - for bound in bounds { + for (bound, _) in bounds { self.current_index.shift_in(1); self.visit_poly_trait_ref(bound); self.current_index.shift_out(1); diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs index ce157ff3dc8d9..e5d97976534e9 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs @@ -607,7 +607,7 @@ impl<'a, 'tcx> Visitor<'tcx> for HirTraitObjectVisitor<'a> { _, ) = t.kind { - for ptr in poly_trait_refs { + for (ptr, _) in poly_trait_refs { if Some(self.1) == ptr.trait_ref.trait_def_id() { self.0.push(ptr.span); } diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs index 87fdc5ddff85c..89ae6f4ccab37 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs @@ -437,7 +437,7 @@ pub fn report_object_safety_error<'tcx>( if tcx.parent_hir_node(hir_id).fn_sig().is_some() { // Do not suggest `impl Trait` when dealing with things like super-traits. err.span_suggestion_verbose( - ty.span.until(trait_ref.span), + ty.span.until(trait_ref.0.span), "consider using an opaque type instead", "impl ", Applicability::MaybeIncorrect, diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs index 885216e62165e..d1381d24764a4 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -3040,11 +3040,11 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { match ty.kind { hir::TyKind::TraitObject(traits, _, _) => { let (span, kw) = match traits { - [first, ..] if first.span.lo() == ty.span.lo() => { + [(first, _), ..] if first.span.lo() == ty.span.lo() => { // Missing `dyn` in front of trait object. (ty.span.shrink_to_lo(), "dyn ") } - [first, ..] => (ty.span.until(first.span), ""), + [(first, _), ..] => (ty.span.until(first.span), ""), [] => span_bug!(ty.span, "trait object with no traits: {ty:?}"), }; let needs_parens = traits.len() != 1; diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index c007cd5314a86..699c05466bd5a 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -2262,8 +2262,21 @@ impl<'tcx> SelectionContext<'_, 'tcx> { } } - // FIXME(async_closures): These are never clone, for now. - ty::CoroutineClosure(_, _) => None, + ty::CoroutineClosure(_, args) => { + // (*) binder moved here + let ty = self.infcx.shallow_resolve(args.as_coroutine_closure().tupled_upvars_ty()); + if let ty::Infer(ty::TyVar(_)) = ty.kind() { + // Not yet resolved. + Ambiguous + } else { + Where( + obligation + .predicate + .rebind(args.as_coroutine_closure().upvar_tys().to_vec()), + ) + } + } + // `Copy` and `Clone` are automatically implemented for an anonymous adt // if all of its fields are `Copy` and `Clone` ty::Adt(adt, args) if adt.is_anonymous() => { diff --git a/compiler/rustc_type_ir/src/canonical.rs b/compiler/rustc_type_ir/src/canonical.rs index 7e93dc248cc12..5285635975cb8 100644 --- a/compiler/rustc_type_ir/src/canonical.rs +++ b/compiler/rustc_type_ir/src/canonical.rs @@ -1,5 +1,3 @@ -#![allow(clippy::derived_hash_with_manual_eq)] - use derive_where::derive_where; #[cfg(feature = "nightly")] use rustc_macros::{HashStable_NoContext, TyDecodable, TyEncodable}; @@ -141,7 +139,7 @@ impl CanonicalVarInfo { /// Describes the "kind" of the canonical variable. This is a "kind" /// in the type-theory sense of the term -- i.e., a "meta" type system /// that analyzes type-like values. -#[derive_where(Clone, Copy, Hash, Eq, Debug; I: Interner)] +#[derive_where(Clone, Copy, Hash, PartialEq, Eq, Debug; I: Interner)] #[derive(TypeVisitable_Generic, TypeFoldable_Generic)] #[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))] pub enum CanonicalVarKind { @@ -169,21 +167,6 @@ pub enum CanonicalVarKind { PlaceholderConst(I::PlaceholderConst), } -// FIXME(GrigorenkoPV): consider not implementing PartialEq manually -impl PartialEq for CanonicalVarKind { - fn eq(&self, other: &Self) -> bool { - match (self, other) { - (Self::Ty(l0), Self::Ty(r0)) => l0 == r0, - (Self::PlaceholderTy(l0), Self::PlaceholderTy(r0)) => l0 == r0, - (Self::Region(l0), Self::Region(r0)) => l0 == r0, - (Self::PlaceholderRegion(l0), Self::PlaceholderRegion(r0)) => l0 == r0, - (Self::Const(l0), Self::Const(r0)) => l0 == r0, - (Self::PlaceholderConst(l0), Self::PlaceholderConst(r0)) => l0 == r0, - _ => std::mem::discriminant(self) == std::mem::discriminant(other), - } - } -} - impl CanonicalVarKind { pub fn universe(self) -> UniverseIndex { match self { diff --git a/compiler/rustc_type_ir/src/const_kind.rs b/compiler/rustc_type_ir/src/const_kind.rs index 458ffdabe94e4..76b70e4ad443f 100644 --- a/compiler/rustc_type_ir/src/const_kind.rs +++ b/compiler/rustc_type_ir/src/const_kind.rs @@ -1,5 +1,3 @@ -#![allow(clippy::derived_hash_with_manual_eq)] - use derive_where::derive_where; #[cfg(feature = "nightly")] use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; @@ -10,10 +8,8 @@ use std::fmt; use crate::{self as ty, DebruijnIndex, Interner}; -use self::ConstKind::*; - /// Represents a constant in Rust. -#[derive_where(Clone, Copy, Hash, Eq; I: Interner)] +#[derive_where(Clone, Copy, Hash, PartialEq, Eq; I: Interner)] #[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))] pub enum ConstKind { /// A const generic parameter. @@ -45,23 +41,6 @@ pub enum ConstKind { Expr(I::ExprConst), } -// FIXME(GrigorenkoPV): consider not implementing PartialEq manually -impl PartialEq for ConstKind { - fn eq(&self, other: &Self) -> bool { - match (self, other) { - (Param(l0), Param(r0)) => l0 == r0, - (Infer(l0), Infer(r0)) => l0 == r0, - (Bound(l0, l1), Bound(r0, r1)) => l0 == r0 && l1 == r1, - (Placeholder(l0), Placeholder(r0)) => l0 == r0, - (Unevaluated(l0), Unevaluated(r0)) => l0 == r0, - (Value(l0, l1), Value(r0, r1)) => l0 == r0 && l1 == r1, - (Error(l0), Error(r0)) => l0 == r0, - (Expr(l0), Expr(r0)) => l0 == r0, - _ => false, - } - } -} - impl fmt::Debug for ConstKind { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { use ConstKind::*; @@ -80,7 +59,7 @@ impl fmt::Debug for ConstKind { } /// An unevaluated (potentially generic) constant used in the type-system. -#[derive_where(Clone, Copy, Hash, PartialEq, Eq; I: Interner)] +#[derive_where(Clone, Copy, Debug, Hash, PartialEq, Eq; I: Interner)] #[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)] #[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))] pub struct UnevaluatedConst { @@ -95,15 +74,6 @@ impl UnevaluatedConst { } } -impl fmt::Debug for UnevaluatedConst { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("UnevaluatedConst") - .field("def", &self.def) - .field("args", &self.args) - .finish() - } -} - rustc_index::newtype_index! { /// A **`const`** **v**ariable **ID**. #[encodable] diff --git a/compiler/rustc_type_ir/src/predicate_kind.rs b/compiler/rustc_type_ir/src/predicate_kind.rs index 70b7c29bdfcc1..acd031432102a 100644 --- a/compiler/rustc_type_ir/src/predicate_kind.rs +++ b/compiler/rustc_type_ir/src/predicate_kind.rs @@ -1,5 +1,3 @@ -#![allow(clippy::derived_hash_with_manual_eq)] - use derive_where::derive_where; #[cfg(feature = "nightly")] use rustc_macros::{Decodable, Encodable, HashStable_NoContext, TyDecodable, TyEncodable}; @@ -10,7 +8,7 @@ use crate::{self as ty, Interner}; /// A clause is something that can appear in where bounds or be inferred /// by implied bounds. -#[derive_where(Clone, Copy, Hash, Eq; I: Interner)] +#[derive_where(Clone, Copy, Hash, PartialEq, Eq; I: Interner)] #[derive(TypeVisitable_Generic, TypeFoldable_Generic)] #[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))] pub enum ClauseKind { @@ -40,22 +38,6 @@ pub enum ClauseKind { ConstEvaluatable(I::Const), } -// FIXME(GrigorenkoPV): consider not implementing PartialEq manually -impl PartialEq for ClauseKind { - fn eq(&self, other: &Self) -> bool { - match (self, other) { - (Self::Trait(l0), Self::Trait(r0)) => l0 == r0, - (Self::RegionOutlives(l0), Self::RegionOutlives(r0)) => l0 == r0, - (Self::TypeOutlives(l0), Self::TypeOutlives(r0)) => l0 == r0, - (Self::Projection(l0), Self::Projection(r0)) => l0 == r0, - (Self::ConstArgHasType(l0, l1), Self::ConstArgHasType(r0, r1)) => l0 == r0 && l1 == r1, - (Self::WellFormed(l0), Self::WellFormed(r0)) => l0 == r0, - (Self::ConstEvaluatable(l0), Self::ConstEvaluatable(r0)) => l0 == r0, - _ => false, - } - } -} - #[derive_where(Clone, Copy, Hash, PartialEq, Eq; I: Interner)] #[derive(TypeVisitable_Generic, TypeFoldable_Generic)] #[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))] diff --git a/compiler/rustc_type_ir/src/region_kind.rs b/compiler/rustc_type_ir/src/region_kind.rs index ef18ef1523552..9c993b3039a9d 100644 --- a/compiler/rustc_type_ir/src/region_kind.rs +++ b/compiler/rustc_type_ir/src/region_kind.rs @@ -1,5 +1,3 @@ -#![allow(clippy::derived_hash_with_manual_eq)] - use derive_where::derive_where; #[cfg(feature = "nightly")] use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; @@ -127,7 +125,7 @@ rustc_index::newtype_index! { /// [1]: https://smallcultfollowing.com/babysteps/blog/2013/10/29/intermingled-parameter-lists/ /// [2]: https://smallcultfollowing.com/babysteps/blog/2013/11/04/intermingled-parameter-lists/ /// [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/traits/hrtb.html -#[derive_where(Clone, Copy, Hash, Eq; I: Interner)] +#[derive_where(Clone, Copy, Hash, PartialEq, Eq; I: Interner)] #[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable))] pub enum RegionKind { /// A region parameter; for example `'a` in `impl<'a> Trait for &'a ()`. @@ -179,48 +177,6 @@ pub enum RegionKind { ReError(I::ErrorGuaranteed), } -// This is manually implemented for `RegionKind` because `std::mem::discriminant` -// returns an opaque value that is `PartialEq` but not `PartialOrd` -#[inline] -const fn regionkind_discriminant(value: &RegionKind) -> usize { - match value { - ReEarlyParam(_) => 0, - ReBound(_, _) => 1, - ReLateParam(_) => 2, - ReStatic => 3, - ReVar(_) => 4, - RePlaceholder(_) => 5, - ReErased => 6, - ReError(_) => 7, - } -} - -// FIXME(GrigorenkoPV): consider not implementing PartialEq manually -// This is manually implemented because a derive would require `I: PartialEq` -impl PartialEq for RegionKind { - #[inline] - fn eq(&self, other: &RegionKind) -> bool { - regionkind_discriminant(self) == regionkind_discriminant(other) - && match (self, other) { - (ReEarlyParam(a_r), ReEarlyParam(b_r)) => a_r == b_r, - (ReBound(a_d, a_r), ReBound(b_d, b_r)) => a_d == b_d && a_r == b_r, - (ReLateParam(a_r), ReLateParam(b_r)) => a_r == b_r, - (ReStatic, ReStatic) => true, - (ReVar(a_r), ReVar(b_r)) => a_r == b_r, - (RePlaceholder(a_r), RePlaceholder(b_r)) => a_r == b_r, - (ReErased, ReErased) => true, - (ReError(_), ReError(_)) => true, - _ => { - debug_assert!( - false, - "This branch must be unreachable, maybe the match is missing an arm? self = {self:?}, other = {other:?}" - ); - true - } - } - } -} - impl fmt::Debug for RegionKind { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { diff --git a/compiler/rustc_type_ir/src/ty_kind.rs b/compiler/rustc_type_ir/src/ty_kind.rs index 4672904ab737f..fcbf4bfcdb7cf 100644 --- a/compiler/rustc_type_ir/src/ty_kind.rs +++ b/compiler/rustc_type_ir/src/ty_kind.rs @@ -1,5 +1,3 @@ -#![allow(clippy::derived_hash_with_manual_eq)] - use derive_where::derive_where; #[cfg(feature = "nightly")] @@ -68,7 +66,7 @@ impl AliasTyKind { /// Types written by the user start out as `hir::TyKind` and get /// converted to this representation using `::lower_ty`. #[cfg_attr(feature = "nightly", rustc_diagnostic_item = "IrTyKind")] -#[derive_where(Clone, Copy, Hash, Eq; I: Interner)] +#[derive_where(Clone, Copy, Hash, PartialEq, Eq; I: Interner)] #[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))] pub enum TyKind { /// The primitive boolean type. Written as `bool`. @@ -259,92 +257,6 @@ impl TyKind { } } -// This is manually implemented for `TyKind` because `std::mem::discriminant` -// returns an opaque value that is `PartialEq` but not `PartialOrd` -#[inline] -const fn tykind_discriminant(value: &TyKind) -> usize { - match value { - Bool => 0, - Char => 1, - Int(_) => 2, - Uint(_) => 3, - Float(_) => 4, - Adt(_, _) => 5, - Foreign(_) => 6, - Str => 7, - Array(_, _) => 8, - Slice(_) => 9, - RawPtr(_, _) => 10, - Ref(_, _, _) => 11, - FnDef(_, _) => 12, - FnPtr(_) => 13, - Dynamic(..) => 14, - Closure(_, _) => 15, - CoroutineClosure(_, _) => 16, - Coroutine(_, _) => 17, - CoroutineWitness(_, _) => 18, - Never => 19, - Tuple(_) => 20, - Pat(_, _) => 21, - Alias(_, _) => 22, - Param(_) => 23, - Bound(_, _) => 24, - Placeholder(_) => 25, - Infer(_) => 26, - Error(_) => 27, - } -} - -// FIXME(GrigorenkoPV): consider not implementing PartialEq manually -// This is manually implemented because a derive would require `I: PartialEq` -impl PartialEq for TyKind { - #[inline] - fn eq(&self, other: &TyKind) -> bool { - // You might expect this `match` to be preceded with this: - // - // tykind_discriminant(self) == tykind_discriminant(other) && - // - // but the data patterns in practice are such that a comparison - // succeeds 99%+ of the time, and it's faster to omit it. - match (self, other) { - (Int(a_i), Int(b_i)) => a_i == b_i, - (Uint(a_u), Uint(b_u)) => a_u == b_u, - (Float(a_f), Float(b_f)) => a_f == b_f, - (Adt(a_d, a_s), Adt(b_d, b_s)) => a_d == b_d && a_s == b_s, - (Foreign(a_d), Foreign(b_d)) => a_d == b_d, - (Array(a_t, a_c), Array(b_t, b_c)) => a_t == b_t && a_c == b_c, - (Pat(a_t, a_c), Pat(b_t, b_c)) => a_t == b_t && a_c == b_c, - (Slice(a_t), Slice(b_t)) => a_t == b_t, - (RawPtr(a_t, a_m), RawPtr(b_t, b_m)) => a_t == b_t && a_m == b_m, - (Ref(a_r, a_t, a_m), Ref(b_r, b_t, b_m)) => a_r == b_r && a_t == b_t && a_m == b_m, - (FnDef(a_d, a_s), FnDef(b_d, b_s)) => a_d == b_d && a_s == b_s, - (FnPtr(a_s), FnPtr(b_s)) => a_s == b_s, - (Dynamic(a_p, a_r, a_repr), Dynamic(b_p, b_r, b_repr)) => { - a_p == b_p && a_r == b_r && a_repr == b_repr - } - (Closure(a_d, a_s), Closure(b_d, b_s)) => a_d == b_d && a_s == b_s, - (CoroutineClosure(a_d, a_s), CoroutineClosure(b_d, b_s)) => a_d == b_d && a_s == b_s, - (Coroutine(a_d, a_s), Coroutine(b_d, b_s)) => a_d == b_d && a_s == b_s, - (CoroutineWitness(a_d, a_s), CoroutineWitness(b_d, b_s)) => a_d == b_d && a_s == b_s, - (Tuple(a_t), Tuple(b_t)) => a_t == b_t, - (Alias(a_i, a_p), Alias(b_i, b_p)) => a_i == b_i && a_p == b_p, - (Param(a_p), Param(b_p)) => a_p == b_p, - (Bound(a_d, a_b), Bound(b_d, b_b)) => a_d == b_d && a_b == b_b, - (Placeholder(a_p), Placeholder(b_p)) => a_p == b_p, - (Infer(a_t), Infer(b_t)) => a_t == b_t, - (Error(a_e), Error(b_e)) => a_e == b_e, - (Bool, Bool) | (Char, Char) | (Str, Str) | (Never, Never) => true, - _ => { - debug_assert!( - tykind_discriminant(self) != tykind_discriminant(other), - "This branch must be unreachable, maybe the match is missing an arm? self = {self:?}, other = {other:?}" - ); - false - } - } - } -} - // This is manually implemented because a derive would require `I: Debug` impl fmt::Debug for TyKind { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { diff --git a/compiler/rustc_type_ir/src/visit.rs b/compiler/rustc_type_ir/src/visit.rs index 6ec38b78fc22a..d5e114b2175c8 100644 --- a/compiler/rustc_type_ir/src/visit.rs +++ b/compiler/rustc_type_ir/src/visit.rs @@ -241,10 +241,6 @@ pub trait TypeVisitableExt: TypeVisitable { self.has_type_flags(TypeFlags::HAS_ALIAS) } - fn has_inherent_projections(&self) -> bool { - self.has_type_flags(TypeFlags::HAS_TY_INHERENT) - } - fn has_opaque_types(&self) -> bool { self.has_type_flags(TypeFlags::HAS_TY_OPAQUE) } diff --git a/config.example.toml b/config.example.toml index 26687bcfb370f..45faa66ec114f 100644 --- a/config.example.toml +++ b/config.example.toml @@ -395,7 +395,7 @@ #metrics = false # Specify the location of the Android NDK. Used when targeting Android. -#android-ndk = "/path/to/android-ndk-r25b" +#android-ndk = "/path/to/android-ndk-r26d" # ============================================================================= # General install configuration options @@ -578,7 +578,10 @@ # The "channel" for the Rust build to produce. The stable/beta channels only # allow using stable features, whereas the nightly and dev channels allow using # nightly features -#channel = "dev" +# +# If using tarball sources, default value for `channel` is taken from the `src/ci/channel` file; +# otherwise, it's "dev". +#channel = if "is a tarball source" { content of `src/ci/channel` file } else { "dev" } # A descriptive string to be appended to `rustc --version` output, which is # also used in places like debuginfo `DW_AT_producer`. This may be useful for diff --git a/library/alloc/src/alloc.rs b/library/alloc/src/alloc.rs index 1833a7f477f00..f7d103396898a 100644 --- a/library/alloc/src/alloc.rs +++ b/library/alloc/src/alloc.rs @@ -57,7 +57,7 @@ pub struct Global; #[cfg(test)] pub use std::alloc::Global; -/// Allocate memory with the global allocator. +/// Allocates memory with the global allocator. /// /// This function forwards calls to the [`GlobalAlloc::alloc`] method /// of the allocator registered with the `#[global_allocator]` attribute @@ -101,7 +101,7 @@ pub unsafe fn alloc(layout: Layout) -> *mut u8 { } } -/// Deallocate memory with the global allocator. +/// Deallocates memory with the global allocator. /// /// This function forwards calls to the [`GlobalAlloc::dealloc`] method /// of the allocator registered with the `#[global_allocator]` attribute @@ -119,7 +119,7 @@ pub unsafe fn dealloc(ptr: *mut u8, layout: Layout) { unsafe { __rust_dealloc(ptr, layout.size(), layout.align()) } } -/// Reallocate memory with the global allocator. +/// Reallocates memory with the global allocator. /// /// This function forwards calls to the [`GlobalAlloc::realloc`] method /// of the allocator registered with the `#[global_allocator]` attribute @@ -138,7 +138,7 @@ pub unsafe fn realloc(ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 unsafe { __rust_realloc(ptr, layout.size(), layout.align(), new_size) } } -/// Allocate zero-initialized memory with the global allocator. +/// Allocates zero-initialized memory with the global allocator. /// /// This function forwards calls to the [`GlobalAlloc::alloc_zeroed`] method /// of the allocator registered with the `#[global_allocator]` attribute @@ -345,7 +345,7 @@ extern "Rust" { fn __rust_alloc_error_handler(size: usize, align: usize) -> !; } -/// Signal a memory allocation error. +/// Signals a memory allocation error. /// /// Callers of memory allocation APIs wishing to cease execution /// in response to an allocation error are encouraged to call this function, diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs index 405430377e551..0fc016aa32bd3 100644 --- a/library/alloc/src/boxed.rs +++ b/library/alloc/src/boxed.rs @@ -1268,9 +1268,11 @@ impl Box { } /// Consumes and leaks the `Box`, returning a mutable reference, - /// `&'a mut T`. Note that the type `T` must outlive the chosen lifetime - /// `'a`. If the type has only static references, or none at all, then this - /// may be chosen to be `'static`. + /// `&'a mut T`. + /// + /// Note that the type `T` must outlive the chosen lifetime `'a`. If the type + /// has only static references, or none at all, then this may be chosen to be + /// `'static`. /// /// This function is mainly useful for data that lives for the remainder of /// the program's life. Dropping the returned reference will cause a memory @@ -1853,7 +1855,7 @@ impl TryFrom> for Box<[T; N]> { } impl Box { - /// Attempt to downcast the box to a concrete type. + /// Attempts to downcast the box to a concrete type. /// /// # Examples /// @@ -1912,7 +1914,7 @@ impl Box { } impl Box { - /// Attempt to downcast the box to a concrete type. + /// Attempts to downcast the box to a concrete type. /// /// # Examples /// @@ -1971,7 +1973,7 @@ impl Box { } impl Box { - /// Attempt to downcast the box to a concrete type. + /// Attempts to downcast the box to a concrete type. /// /// # Examples /// diff --git a/library/alloc/src/collections/binary_heap/mod.rs b/library/alloc/src/collections/binary_heap/mod.rs index fe1ff24139554..11aef5f913e4f 100644 --- a/library/alloc/src/collections/binary_heap/mod.rs +++ b/library/alloc/src/collections/binary_heap/mod.rs @@ -965,6 +965,7 @@ impl BinaryHeap { } /// Returns an iterator which retrieves elements in heap order. + /// /// This method consumes the original heap. /// /// # Examples @@ -1361,7 +1362,7 @@ struct Hole<'a, T: 'a> { } impl<'a, T> Hole<'a, T> { - /// Create a new `Hole` at index `pos`. + /// Creates a new `Hole` at index `pos`. /// /// Unsafe because pos must be within the data slice. #[inline] diff --git a/library/alloc/src/collections/btree/map/entry.rs b/library/alloc/src/collections/btree/map/entry.rs index 66eb991c6d4b8..b5b389bbd25b7 100644 --- a/library/alloc/src/collections/btree/map/entry.rs +++ b/library/alloc/src/collections/btree/map/entry.rs @@ -189,6 +189,7 @@ impl<'a, K: Ord, V, A: Allocator + Clone> Entry<'a, K, V, A> { } /// Ensures a value is in the entry by inserting, if empty, the result of the default function. + /// /// This method allows for generating key-derived values for insertion by providing the default /// function a reference to the key that was moved during the `.entry(key)` method call. /// diff --git a/library/alloc/src/fmt.rs b/library/alloc/src/fmt.rs index c6bba619ae646..4b9b90fc1f157 100644 --- a/library/alloc/src/fmt.rs +++ b/library/alloc/src/fmt.rs @@ -600,8 +600,7 @@ pub use core::fmt::{LowerHex, Pointer, UpperHex}; #[cfg(not(no_global_oom_handling))] use crate::string; -/// The `format` function takes an [`Arguments`] struct and returns the resulting -/// formatted string. +/// Takes an [`Arguments`] struct and returns the resulting formatted string. /// /// The [`Arguments`] instance can be created with the [`format_args!`] macro. /// diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 4491a717dc2ea..3b039786eb5e7 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -92,7 +92,6 @@ // tidy-alphabetical-start #![cfg_attr(not(no_global_oom_handling), feature(const_alloc_error))] #![cfg_attr(not(no_global_oom_handling), feature(const_btree_len))] -#![cfg_attr(test, feature(is_sorted))] #![cfg_attr(test, feature(new_uninit))] #![feature(alloc_layout_extra)] #![feature(allocator_api)] @@ -117,7 +116,6 @@ #![feature(const_pin)] #![feature(const_refs_to_cell)] #![feature(const_size_of_val)] -#![feature(const_waker)] #![feature(core_intrinsics)] #![feature(deprecated_suggestion)] #![feature(deref_pure_trait)] diff --git a/library/alloc/src/raw_vec.rs b/library/alloc/src/raw_vec.rs index 7b7dae5a057f0..2860b88bd83e7 100644 --- a/library/alloc/src/raw_vec.rs +++ b/library/alloc/src/raw_vec.rs @@ -52,7 +52,7 @@ impl Cap { /// * Produces `Unique::dangling()` on zero-length allocations. /// * Avoids freeing `Unique::dangling()`. /// * Catches all overflows in capacity computations (promotes them to "capacity overflow" panics). -/// * Guards against 32-bit systems allocating more than isize::MAX bytes. +/// * Guards against 32-bit systems allocating more than `isize::MAX` bytes. /// * Guards against overflowing your length. /// * Calls `handle_alloc_error` for fallible allocations. /// * Contains a `ptr::Unique` and thus endows the user with all related benefits. @@ -484,7 +484,7 @@ impl RawVec { // `finish_grow` is non-generic over `T`. let ptr = finish_grow(new_layout, self.current_memory(), &mut self.alloc)?; - // SAFETY: finish_grow would have resulted in a capacity overflow if we tried to allocate more than isize::MAX items + // SAFETY: finish_grow would have resulted in a capacity overflow if we tried to allocate more than `isize::MAX` items unsafe { self.set_ptr_and_cap(ptr, cap) }; Ok(()) } @@ -504,7 +504,7 @@ impl RawVec { // `finish_grow` is non-generic over `T`. let ptr = finish_grow(new_layout, self.current_memory(), &mut self.alloc)?; - // SAFETY: finish_grow would have resulted in a capacity overflow if we tried to allocate more than isize::MAX items + // SAFETY: `finish_grow` would have resulted in a capacity overflow if we tried to allocate more than `isize::MAX` items unsafe { self.set_ptr_and_cap(ptr, cap); } diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index bfe3ea2080017..64233d19c5a90 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -439,7 +439,7 @@ impl Rc { /// } /// /// impl Gadget { - /// /// Construct a reference counted Gadget. + /// /// Constructs a reference counted Gadget. /// fn new() -> Rc { /// // `me` is a `Weak` pointing at the new allocation of the /// // `Rc` we're constructing. @@ -449,7 +449,7 @@ impl Rc { /// }) /// } /// - /// /// Return a reference counted pointer to Self. + /// /// Returns a reference counted pointer to Self. /// fn me(&self) -> Rc { /// self.me.upgrade().unwrap() /// } @@ -1900,7 +1900,7 @@ impl Rc { } impl Rc { - /// Attempt to downcast the `Rc` to a concrete type. + /// Attempts to downcast the `Rc` to a concrete type. /// /// # Examples /// @@ -2586,7 +2586,7 @@ impl From<[T; N]> for Rc<[T]> { #[cfg(not(no_global_oom_handling))] #[stable(feature = "shared_from_slice", since = "1.21.0")] impl From<&[T]> for Rc<[T]> { - /// Allocate a reference-counted slice and fill it by cloning `v`'s items. + /// Allocates a reference-counted slice and fills it by cloning `v`'s items. /// /// # Example /// @@ -2605,7 +2605,7 @@ impl From<&[T]> for Rc<[T]> { #[cfg(not(no_global_oom_handling))] #[stable(feature = "shared_from_slice", since = "1.21.0")] impl From<&str> for Rc { - /// Allocate a reference-counted string slice and copy `v` into it. + /// Allocates a reference-counted string slice and copies `v` into it. /// /// # Example /// @@ -2624,7 +2624,7 @@ impl From<&str> for Rc { #[cfg(not(no_global_oom_handling))] #[stable(feature = "shared_from_slice", since = "1.21.0")] impl From for Rc { - /// Allocate a reference-counted string slice and copy `v` into it. + /// Allocates a reference-counted string slice and copies `v` into it. /// /// # Example /// @@ -2662,7 +2662,7 @@ impl From> for Rc { #[cfg(not(no_global_oom_handling))] #[stable(feature = "shared_from_slice", since = "1.21.0")] impl From> for Rc<[T], A> { - /// Allocate a reference-counted slice and move `v`'s items into it. + /// Allocates a reference-counted slice and moves `v`'s items into it. /// /// # Example /// @@ -2695,8 +2695,8 @@ where B: ToOwned + ?Sized, Rc: From<&'a B> + From, { - /// Create a reference-counted pointer from - /// a clone-on-write pointer by copying its content. + /// Creates a reference-counted pointer from a clone-on-write pointer by + /// copying its content. /// /// # Example /// @@ -3526,7 +3526,7 @@ impl AsRef for Rc { #[stable(feature = "pin", since = "1.33.0")] impl Unpin for Rc {} -/// Get the offset within an `RcBox` for the payload behind a pointer. +/// Gets the offset within an `RcBox` for the payload behind a pointer. /// /// # Safety /// @@ -3734,7 +3734,7 @@ struct UniqueRcUninit { #[cfg(not(no_global_oom_handling))] impl UniqueRcUninit { - /// Allocate a RcBox with layout suitable to contain `for_value` or a clone of it. + /// Allocates a RcBox with layout suitable to contain `for_value` or a clone of it. fn new(for_value: &T, alloc: A) -> UniqueRcUninit { let layout = Layout::for_value(for_value); let ptr = unsafe { diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index c36b8f6a1ac8a..f73cd0396cd82 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -428,7 +428,7 @@ impl Arc { /// } /// /// impl Gadget { - /// /// Construct a reference counted Gadget. + /// /// Constructs a reference counted Gadget. /// fn new() -> Arc { /// // `me` is a `Weak` pointing at the new allocation of the /// // `Arc` we're constructing. @@ -438,7 +438,7 @@ impl Arc { /// }) /// } /// - /// /// Return a reference counted pointer to Self. + /// /// Returns a reference counted pointer to Self. /// fn me(&self) -> Arc { /// self.me.upgrade().unwrap() /// } @@ -2531,7 +2531,7 @@ unsafe impl<#[may_dangle] T: ?Sized, A: Allocator> Drop for Arc { } impl Arc { - /// Attempt to downcast the `Arc` to a concrete type. + /// Attempts to downcast the `Arc` to a concrete type. /// /// # Examples /// @@ -3545,7 +3545,7 @@ impl From<[T; N]> for Arc<[T]> { #[cfg(not(no_global_oom_handling))] #[stable(feature = "shared_from_slice", since = "1.21.0")] impl From<&[T]> for Arc<[T]> { - /// Allocate a reference-counted slice and fill it by cloning `v`'s items. + /// Allocates a reference-counted slice and fills it by cloning `v`'s items. /// /// # Example /// @@ -3564,7 +3564,7 @@ impl From<&[T]> for Arc<[T]> { #[cfg(not(no_global_oom_handling))] #[stable(feature = "shared_from_slice", since = "1.21.0")] impl From<&str> for Arc { - /// Allocate a reference-counted `str` and copy `v` into it. + /// Allocates a reference-counted `str` and copies `v` into it. /// /// # Example /// @@ -3583,7 +3583,7 @@ impl From<&str> for Arc { #[cfg(not(no_global_oom_handling))] #[stable(feature = "shared_from_slice", since = "1.21.0")] impl From for Arc { - /// Allocate a reference-counted `str` and copy `v` into it. + /// Allocates a reference-counted `str` and copies `v` into it. /// /// # Example /// @@ -3621,7 +3621,7 @@ impl From> for Arc { #[cfg(not(no_global_oom_handling))] #[stable(feature = "shared_from_slice", since = "1.21.0")] impl From> for Arc<[T], A> { - /// Allocate a reference-counted slice and move `v`'s items into it. + /// Allocates a reference-counted slice and moves `v`'s items into it. /// /// # Example /// @@ -3654,8 +3654,8 @@ where B: ToOwned + ?Sized, Arc: From<&'a B> + From, { - /// Create an atomically reference-counted pointer from - /// a clone-on-write pointer by copying its content. + /// Creates an atomically reference-counted pointer from a clone-on-write + /// pointer by copying its content. /// /// # Example /// @@ -3811,7 +3811,7 @@ impl AsRef for Arc { #[stable(feature = "pin", since = "1.33.0")] impl Unpin for Arc {} -/// Get the offset within an `ArcInner` for the payload behind a pointer. +/// Gets the offset within an `ArcInner` for the payload behind a pointer. /// /// # Safety /// @@ -3833,7 +3833,7 @@ fn data_offset_align(align: usize) -> usize { layout.size() + layout.padding_needed_for(align) } -/// A unique owning pointer to a [`ArcInner`] **that does not imply the contents are initialized,** +/// A unique owning pointer to an [`ArcInner`] **that does not imply the contents are initialized,** /// but will deallocate it (without dropping the value) when dropped. /// /// This is a helper for [`Arc::make_mut()`] to ensure correct cleanup on panic. @@ -3846,7 +3846,7 @@ struct UniqueArcUninit { #[cfg(not(no_global_oom_handling))] impl UniqueArcUninit { - /// Allocate a ArcInner with layout suitable to contain `for_value` or a clone of it. + /// Allocates an ArcInner with layout suitable to contain `for_value` or a clone of it. fn new(for_value: &T, alloc: A) -> UniqueArcUninit { let layout = Layout::for_value(for_value); let ptr = unsafe { diff --git a/library/alloc/src/vec/into_iter.rs b/library/alloc/src/vec/into_iter.rs index 10f62e4bb62d8..c3a8660383dbc 100644 --- a/library/alloc/src/vec/into_iter.rs +++ b/library/alloc/src/vec/into_iter.rs @@ -114,8 +114,9 @@ impl IntoIter { } /// Drops remaining elements and relinquishes the backing allocation. - /// This method guarantees it won't panic before relinquishing - /// the backing allocation. + /// + /// This method guarantees it won't panic before relinquishing the backing + /// allocation. /// /// This is roughly equivalent to the following, but more efficient /// diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 729d5dd4fe4d2..db81fc05c34bb 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -1277,7 +1277,7 @@ impl Vec { /// valid for zero sized reads if the vector didn't allocate. /// /// The caller must ensure that the vector outlives the pointer this - /// function returns, or else it will end up pointing to garbage. + /// function returns, or else it will end up dangling. /// Modifying the vector may cause its buffer to be reallocated, /// which would also make any pointers to it invalid. /// @@ -1337,7 +1337,7 @@ impl Vec { /// raw pointer valid for zero sized reads if the vector didn't allocate. /// /// The caller must ensure that the vector outlives the pointer this - /// function returns, or else it will end up pointing to garbage. + /// function returns, or else it will end up dangling. /// Modifying the vector may cause its buffer to be reallocated, /// which would also make any pointers to it invalid. /// @@ -2373,9 +2373,11 @@ impl Vec { } /// Consumes and leaks the `Vec`, returning a mutable reference to the contents, - /// `&'a mut [T]`. Note that the type `T` must outlive the chosen lifetime - /// `'a`. If the type has only static references, or none at all, then this - /// may be chosen to be `'static`. + /// `&'a mut [T]`. + /// + /// Note that the type `T` must outlive the chosen lifetime `'a`. If the type + /// has only static references, or none at all, then this may be chosen to be + /// `'static`. /// /// As of Rust 1.57, this method does not reallocate or shrink the `Vec`, /// so the leaked allocation may include unused capacity that is not part @@ -3359,7 +3361,7 @@ impl AsMut<[T]> for Vec { #[cfg(not(no_global_oom_handling))] #[stable(feature = "rust1", since = "1.0.0")] impl From<&[T]> for Vec { - /// Allocate a `Vec` and fill it by cloning `s`'s items. + /// Allocates a `Vec` and fills it by cloning `s`'s items. /// /// # Examples /// @@ -3379,7 +3381,7 @@ impl From<&[T]> for Vec { #[cfg(not(no_global_oom_handling))] #[stable(feature = "vec_from_mut", since = "1.19.0")] impl From<&mut [T]> for Vec { - /// Allocate a `Vec` and fill it by cloning `s`'s items. + /// Allocates a `Vec` and fills it by cloning `s`'s items. /// /// # Examples /// @@ -3399,7 +3401,7 @@ impl From<&mut [T]> for Vec { #[cfg(not(no_global_oom_handling))] #[stable(feature = "vec_from_array_ref", since = "1.74.0")] impl From<&[T; N]> for Vec { - /// Allocate a `Vec` and fill it by cloning `s`'s items. + /// Allocates a `Vec` and fills it by cloning `s`'s items. /// /// # Examples /// @@ -3414,7 +3416,7 @@ impl From<&[T; N]> for Vec { #[cfg(not(no_global_oom_handling))] #[stable(feature = "vec_from_array_ref", since = "1.74.0")] impl From<&mut [T; N]> for Vec { - /// Allocate a `Vec` and fill it by cloning `s`'s items. + /// Allocates a `Vec` and fills it by cloning `s`'s items. /// /// # Examples /// @@ -3429,7 +3431,7 @@ impl From<&mut [T; N]> for Vec { #[cfg(not(no_global_oom_handling))] #[stable(feature = "vec_from_array", since = "1.44.0")] impl From<[T; N]> for Vec { - /// Allocate a `Vec` and move `s`'s items into it. + /// Allocates a `Vec` and moves `s`'s items into it. /// /// # Examples /// @@ -3452,7 +3454,7 @@ impl<'a, T> From> for Vec where [T]: ToOwned>, { - /// Convert a clone-on-write slice into a vector. + /// Converts a clone-on-write slice into a vector. /// /// If `s` already owns a `Vec`, it will be returned directly. /// If `s` is borrowing a slice, a new `Vec` will be allocated and @@ -3475,7 +3477,7 @@ where #[cfg(not(test))] #[stable(feature = "vec_from_box", since = "1.18.0")] impl From> for Vec { - /// Convert a boxed slice into a vector by transferring ownership of + /// Converts a boxed slice into a vector by transferring ownership of /// the existing heap allocation. /// /// # Examples @@ -3494,7 +3496,7 @@ impl From> for Vec { #[cfg(not(test))] #[stable(feature = "box_from_vec", since = "1.20.0")] impl From> for Box<[T], A> { - /// Convert a vector into a boxed slice. + /// Converts a vector into a boxed slice. /// /// Before doing the conversion, this method discards excess capacity like [`Vec::shrink_to_fit`]. /// @@ -3522,7 +3524,7 @@ impl From> for Box<[T], A> { #[cfg(not(no_global_oom_handling))] #[stable(feature = "rust1", since = "1.0.0")] impl From<&str> for Vec { - /// Allocate a `Vec` and fill it with a UTF-8 string. + /// Allocates a `Vec` and fills it with a UTF-8 string. /// /// # Examples /// diff --git a/library/core/src/alloc/global.rs b/library/core/src/alloc/global.rs index 8df3ace54ffe1..cf25deacb572e 100644 --- a/library/core/src/alloc/global.rs +++ b/library/core/src/alloc/global.rs @@ -118,7 +118,7 @@ use crate::ptr; /// having side effects. #[stable(feature = "global_alloc", since = "1.28.0")] pub unsafe trait GlobalAlloc { - /// Allocate memory as described by the given `layout`. + /// Allocates memory as described by the given `layout`. /// /// Returns a pointer to newly-allocated memory, /// or null to indicate allocation failure. @@ -153,7 +153,7 @@ pub unsafe trait GlobalAlloc { #[stable(feature = "global_alloc", since = "1.28.0")] unsafe fn alloc(&self, layout: Layout) -> *mut u8; - /// Deallocate the block of memory at the given `ptr` pointer with the given `layout`. + /// Deallocates the block of memory at the given `ptr` pointer with the given `layout`. /// /// # Safety /// @@ -200,7 +200,7 @@ pub unsafe trait GlobalAlloc { ptr } - /// Shrink or grow a block of memory to the given `new_size` in bytes. + /// Shrinks or grows a block of memory to the given `new_size` in bytes. /// The block is described by the given `ptr` pointer and `layout`. /// /// If this returns a non-null pointer, then ownership of the memory block @@ -232,7 +232,7 @@ pub unsafe trait GlobalAlloc { /// * `new_size` must be greater than zero. /// /// * `new_size`, when rounded up to the nearest multiple of `layout.align()`, - /// must not overflow isize (i.e., the rounded value must be less than or + /// must not overflow `isize` (i.e., the rounded value must be less than or /// equal to `isize::MAX`). /// /// (Extension subtraits might provide more specific bounds on diff --git a/library/core/src/alloc/layout.rs b/library/core/src/alloc/layout.rs index e96a41422a2af..431b07035c3c3 100644 --- a/library/core/src/alloc/layout.rs +++ b/library/core/src/alloc/layout.rs @@ -26,7 +26,7 @@ const fn size_align() -> (usize, usize) { /// You build a `Layout` up as an input to give to an allocator. /// /// All layouts have an associated size and a power-of-two alignment. The size, when rounded up to -/// the nearest multiple of `align`, does not overflow isize (i.e., the rounded value will always be +/// the nearest multiple of `align`, does not overflow `isize` (i.e., the rounded value will always be /// less than or equal to `isize::MAX`). /// /// (Note that layouts are *not* required to have non-zero size, @@ -61,7 +61,7 @@ impl Layout { /// * `align` must be a power of two, /// /// * `size`, when rounded up to the nearest multiple of `align`, - /// must not overflow isize (i.e., the rounded value must be + /// must not overflow `isize` (i.e., the rounded value must be /// less than or equal to `isize::MAX`). #[stable(feature = "alloc_layout", since = "1.28.0")] #[rustc_const_stable(feature = "const_alloc_layout_size_align", since = "1.50.0")] diff --git a/library/core/src/array/ascii.rs b/library/core/src/array/ascii.rs index 3fea9a44049fb..05797b042ee4a 100644 --- a/library/core/src/array/ascii.rs +++ b/library/core/src/array/ascii.rs @@ -2,7 +2,7 @@ use crate::ascii; #[cfg(not(test))] impl [u8; N] { - /// Converts this array of bytes into a array of ASCII characters, + /// Converts this array of bytes into an array of ASCII characters, /// or returns `None` if any of the characters is non-ASCII. /// /// # Examples @@ -29,7 +29,7 @@ impl [u8; N] { } } - /// Converts this array of bytes into a array of ASCII characters, + /// Converts this array of bytes into an array of ASCII characters, /// without checking whether they're valid. /// /// # Safety diff --git a/library/core/src/array/iter.rs b/library/core/src/array/iter.rs index 3585bf07b597c..617fd627c9285 100644 --- a/library/core/src/array/iter.rs +++ b/library/core/src/array/iter.rs @@ -47,8 +47,10 @@ impl IntoIterator for [T; N] { type IntoIter = IntoIter; /// Creates a consuming iterator, that is, one that moves each value out of - /// the array (from start to end). The array cannot be used after calling - /// this unless `T` implements `Copy`, so the whole array is copied. + /// the array (from start to end). + /// + /// The array cannot be used after calling this unless `T` implements + /// `Copy`, so the whole array is copied. /// /// Arrays have special behavior when calling `.into_iter()` prior to the /// 2021 edition -- see the [array] Editions section for more information. diff --git a/library/core/src/async_iter/async_iter.rs b/library/core/src/async_iter/async_iter.rs index a0ffb6d47507b..069c50c2531b0 100644 --- a/library/core/src/async_iter/async_iter.rs +++ b/library/core/src/async_iter/async_iter.rs @@ -18,7 +18,7 @@ pub trait AsyncIterator { /// The type of items yielded by the async iterator. type Item; - /// Attempt to pull out the next value of this async iterator, registering the + /// Attempts to pull out the next value of this async iterator, registering the /// current task for wakeup if the value is not yet available, and returning /// `None` if the async iterator is exhausted. /// @@ -139,7 +139,7 @@ impl Poll> { pub const FINISHED: Self = Poll::Ready(None); } -/// Convert something into an async iterator +/// Converts something into an async iterator #[unstable(feature = "async_iterator", issue = "79024")] pub trait IntoAsyncIterator { /// The type of the item yielded by the iterator diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs index b3189f14f9e47..0d66c2b52c84e 100644 --- a/library/core/src/cell.rs +++ b/library/core/src/cell.rs @@ -427,7 +427,9 @@ impl Cell { } /// Swaps the values of two `Cell`s. - /// Difference with `std::mem::swap` is that this function doesn't require `&mut` reference. + /// + /// The difference with `std::mem::swap` is that this function doesn't + /// require a `&mut` reference. /// /// # Panics /// @@ -1579,7 +1581,7 @@ impl<'b, T: ?Sized> Ref<'b, T> { ) } - /// Convert into a reference to the underlying data. + /// Converts into a reference to the underlying data. /// /// The underlying `RefCell` can never be mutably borrowed from again and will always appear /// already immutably borrowed. It is not a good idea to leak more than a constant number of @@ -1747,7 +1749,7 @@ impl<'b, T: ?Sized> RefMut<'b, T> { ) } - /// Convert into a mutable reference to the underlying data. + /// Converts into a mutable reference to the underlying data. /// /// The underlying `RefCell` can not be borrowed from again and will always appear already /// mutably borrowed, making the returned reference the only to the interior. @@ -1879,7 +1881,7 @@ impl fmt::Display for RefMut<'_, T> { /// /// If you have a reference `&T`, then normally in Rust the compiler performs optimizations based on /// the knowledge that `&T` points to immutable data. Mutating that data, for example through an -/// alias or by transmuting an `&T` into an `&mut T`, is considered undefined behavior. +/// alias or by transmuting a `&T` into a `&mut T`, is considered undefined behavior. /// `UnsafeCell` opts-out of the immutability guarantee for `&T`: a shared reference /// `&UnsafeCell` may point to data that is being mutated. This is called "interior mutability". /// @@ -1936,7 +1938,7 @@ impl fmt::Display for RefMut<'_, T> { /// to have multiple `&mut UnsafeCell` aliases. That is, `UnsafeCell` is a wrapper /// designed to have a special interaction with _shared_ accesses (_i.e._, through an /// `&UnsafeCell<_>` reference); there is no magic whatsoever when dealing with _exclusive_ -/// accesses (_e.g._, through an `&mut UnsafeCell<_>`): neither the cell nor the wrapped value +/// accesses (_e.g._, through a `&mut UnsafeCell<_>`): neither the cell nor the wrapped value /// may be aliased for the duration of that `&mut` borrow. /// This is showcased by the [`.get_mut()`] accessor, which is a _safe_ getter that yields /// a `&mut T`. diff --git a/library/core/src/clone.rs b/library/core/src/clone.rs index 939b2be6dfaf1..76a89eaaff86e 100644 --- a/library/core/src/clone.rs +++ b/library/core/src/clone.rs @@ -160,6 +160,9 @@ pub trait Clone: Sized { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[must_use = "cloning is often expensive and is not expected to have side effects"] + // Clone::clone is special because the compiler generates MIR to implement it for some types. + // See InstanceKind::CloneShim. + #[cfg_attr(not(bootstrap), lang = "clone_fn")] fn clone(&self) -> Self; /// Performs copy-assignment from `source`. diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs index cff75870790c5..a1ed993b7d9bf 100644 --- a/library/core/src/cmp.rs +++ b/library/core/src/cmp.rs @@ -246,15 +246,14 @@ use self::Ordering::*; )] #[rustc_diagnostic_item = "PartialEq"] pub trait PartialEq { - /// This method tests for `self` and `other` values to be equal, and is used - /// by `==`. + /// Tests for `self` and `other` values to be equal, and is used by `==`. #[must_use] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_diagnostic_item = "cmp_partialeq_eq"] fn eq(&self, other: &Rhs) -> bool; - /// This method tests for `!=`. The default implementation is almost always - /// sufficient, and should not be overridden without very good reason. + /// Tests for `!=`. The default implementation is almost always sufficient, + /// and should not be overridden without very good reason. #[inline] #[must_use] #[stable(feature = "rust1", since = "1.0.0")] @@ -1163,7 +1162,7 @@ pub trait PartialOrd: PartialEq { #[rustc_diagnostic_item = "cmp_partialord_cmp"] fn partial_cmp(&self, other: &Rhs) -> Option; - /// This method tests less than (for `self` and `other`) and is used by the `<` operator. + /// Tests less than (for `self` and `other`) and is used by the `<` operator. /// /// # Examples /// @@ -1180,8 +1179,8 @@ pub trait PartialOrd: PartialEq { matches!(self.partial_cmp(other), Some(Less)) } - /// This method tests less than or equal to (for `self` and `other`) and is used by the `<=` - /// operator. + /// Tests less than or equal to (for `self` and `other`) and is used by the + /// `<=` operator. /// /// # Examples /// @@ -1198,7 +1197,8 @@ pub trait PartialOrd: PartialEq { matches!(self.partial_cmp(other), Some(Less | Equal)) } - /// This method tests greater than (for `self` and `other`) and is used by the `>` operator. + /// Tests greater than (for `self` and `other`) and is used by the `>` + /// operator. /// /// # Examples /// @@ -1215,8 +1215,8 @@ pub trait PartialOrd: PartialEq { matches!(self.partial_cmp(other), Some(Greater)) } - /// This method tests greater than or equal to (for `self` and `other`) and is used by the `>=` - /// operator. + /// Tests greater than or equal to (for `self` and `other`) and is used by + /// the `>=` operator. /// /// # Examples /// diff --git a/library/core/src/convert/num.rs b/library/core/src/convert/num.rs index 86c4ea9fab088..0246d0627cafe 100644 --- a/library/core/src/convert/num.rs +++ b/library/core/src/convert/num.rs @@ -208,7 +208,7 @@ macro_rules! impl_try_from_unbounded { impl TryFrom<$source> for $target { type Error = TryFromIntError; - /// Try to create the target number type from a source + /// Tries to create the target number type from a source /// number type. This returns an error if the source value /// is outside of the range of the target type. #[inline] @@ -226,7 +226,7 @@ macro_rules! impl_try_from_lower_bounded { impl TryFrom<$source> for $target { type Error = TryFromIntError; - /// Try to create the target number type from a source + /// Tries to create the target number type from a source /// number type. This returns an error if the source value /// is outside of the range of the target type. #[inline] @@ -248,7 +248,7 @@ macro_rules! impl_try_from_upper_bounded { impl TryFrom<$source> for $target { type Error = TryFromIntError; - /// Try to create the target number type from a source + /// Tries to create the target number type from a source /// number type. This returns an error if the source value /// is outside of the range of the target type. #[inline] @@ -270,7 +270,7 @@ macro_rules! impl_try_from_both_bounded { impl TryFrom<$source> for $target { type Error = TryFromIntError; - /// Try to create the target number type from a source + /// Tries to create the target number type from a source /// number type. This returns an error if the source value /// is outside of the range of the target type. #[inline] diff --git a/library/core/src/error.rs b/library/core/src/error.rs index 19b7bb44f855a..4d3b22d4eed8f 100644 --- a/library/core/src/error.rs +++ b/library/core/src/error.rs @@ -30,7 +30,7 @@ use crate::fmt::{Debug, Display, Formatter, Result}; #[rustc_has_incoherent_inherent_impls] #[allow(multiple_supertrait_upcastable)] pub trait Error: Debug + Display { - /// The lower-level source of this error, if any. + /// Returns the lower-level source of this error, if any. /// /// # Examples /// @@ -121,7 +121,7 @@ pub trait Error: Debug + Display { self.source() } - /// Provides type based access to context intended for error reports. + /// Provides type-based access to context intended for error reports. /// /// Used in conjunction with [`Request::provide_value`] and [`Request::provide_ref`] to extract /// references to member variables from `dyn Error` trait objects. @@ -353,7 +353,7 @@ impl dyn Error { } } -/// Request a value of type `T` from the given `impl Error`. +/// Requests a value of type `T` from the given `impl Error`. /// /// # Examples /// @@ -376,7 +376,7 @@ where request_by_type_tag::<'a, tags::Value>(err) } -/// Request a reference of type `T` from the given `impl Error`. +/// Requests a reference of type `T` from the given `impl Error`. /// /// # Examples /// @@ -510,7 +510,7 @@ where pub struct Request<'a>(Tagged + 'a>); impl<'a> Request<'a> { - /// Provide a value or other type with only static lifetimes. + /// Provides a value or other type with only static lifetimes. /// /// # Examples /// @@ -544,7 +544,7 @@ impl<'a> Request<'a> { self.provide::>(value) } - /// Provide a value or other type with only static lifetimes computed using a closure. + /// Provides a value or other type with only static lifetimes computed using a closure. /// /// # Examples /// @@ -578,7 +578,7 @@ impl<'a> Request<'a> { self.provide_with::>(fulfil) } - /// Provide a reference. The referee type must be bounded by `'static`, + /// Provides a reference. The referee type must be bounded by `'static`, /// but may be unsized. /// /// # Examples @@ -610,7 +610,7 @@ impl<'a> Request<'a> { self.provide::>>(value) } - /// Provide a reference computed using a closure. The referee type + /// Provides a reference computed using a closure. The referee type /// must be bounded by `'static`, but may be unsized. /// /// # Examples @@ -652,7 +652,7 @@ impl<'a> Request<'a> { self.provide_with::>>(fulfil) } - /// Provide a value with the given `Type` tag. + /// Provides a value with the given `Type` tag. fn provide(&mut self, value: I::Reified) -> &mut Self where I: tags::Type<'a>, @@ -663,7 +663,7 @@ impl<'a> Request<'a> { self } - /// Provide a value with the given `Type` tag, using a closure to prevent unnecessary work. + /// Provides a value with the given `Type` tag, using a closure to prevent unnecessary work. fn provide_with(&mut self, fulfil: impl FnOnce() -> I::Reified) -> &mut Self where I: tags::Type<'a>, @@ -674,13 +674,13 @@ impl<'a> Request<'a> { self } - /// Check if the `Request` would be satisfied if provided with a + /// Checks if the `Request` would be satisfied if provided with a /// value of the specified type. If the type does not match or has /// already been provided, returns false. /// /// # Examples /// - /// Check if an `u8` still needs to be provided and then provides + /// Checks if a `u8` still needs to be provided and then provides /// it. /// /// ```rust @@ -761,13 +761,14 @@ impl<'a> Request<'a> { self.would_be_satisfied_by::>() } - /// Check if the `Request` would be satisfied if provided with a - /// reference to a value of the specified type. If the type does - /// not match or has already been provided, returns false. + /// Checks if the `Request` would be satisfied if provided with a + /// reference to a value of the specified type. + /// + /// If the type does not match or has already been provided, returns false. /// /// # Examples /// - /// Check if a `&str` still needs to be provided and then provides + /// Checks if a `&str` still needs to be provided and then provides /// it. /// /// ```rust diff --git a/library/core/src/ffi/va_list.rs b/library/core/src/ffi/va_list.rs index f4c746225dc03..dda9e30c24b32 100644 --- a/library/core/src/ffi/va_list.rs +++ b/library/core/src/ffi/va_list.rs @@ -162,7 +162,7 @@ pub struct VaList<'a, 'f: 'a> { windows, ))] impl<'f> VaListImpl<'f> { - /// Convert a `VaListImpl` into a `VaList` that is binary-compatible with C's `va_list`. + /// Converts a `VaListImpl` into a `VaList` that is binary-compatible with C's `va_list`. #[inline] pub fn as_va_list<'a>(&'a mut self) -> VaList<'a, 'f> { VaList { inner: VaListImpl { ..*self }, _marker: PhantomData } @@ -182,7 +182,7 @@ impl<'f> VaListImpl<'f> { not(windows), ))] impl<'f> VaListImpl<'f> { - /// Convert a `VaListImpl` into a `VaList` that is binary-compatible with C's `va_list`. + /// Converts a `VaListImpl` into a `VaList` that is binary-compatible with C's `va_list`. #[inline] pub fn as_va_list<'a>(&'a mut self) -> VaList<'a, 'f> { VaList { inner: self, _marker: PhantomData } diff --git a/library/core/src/fmt/builders.rs b/library/core/src/fmt/builders.rs index 36fae1c15960e..794ca1851b13d 100644 --- a/library/core/src/fmt/builders.rs +++ b/library/core/src/fmt/builders.rs @@ -402,6 +402,7 @@ impl<'a, 'b: 'a> DebugTuple<'a, 'b> { } } +/// A helper used to print list-like items with no special formatting. struct DebugInner<'a, 'b: 'a> { fmt: &'a mut fmt::Formatter<'b>, result: fmt::Result, @@ -578,7 +579,8 @@ impl<'a, 'b: 'a> DebugSet<'a, 'b> { /// ``` #[stable(feature = "debug_builders", since = "1.2.0")] pub fn finish(&mut self) -> fmt::Result { - self.inner.result.and_then(|_| self.inner.fmt.write_str("}")) + self.inner.result = self.inner.result.and_then(|_| self.inner.fmt.write_str("}")); + self.inner.result } } @@ -721,7 +723,8 @@ impl<'a, 'b: 'a> DebugList<'a, 'b> { /// ``` #[stable(feature = "debug_builders", since = "1.2.0")] pub fn finish(&mut self) -> fmt::Result { - self.inner.result.and_then(|_| self.inner.fmt.write_str("]")) + self.inner.result = self.inner.result.and_then(|_| self.inner.fmt.write_str("]")); + self.inner.result } } @@ -1002,11 +1005,12 @@ impl<'a, 'b: 'a> DebugMap<'a, 'b> { /// ``` #[stable(feature = "debug_builders", since = "1.2.0")] pub fn finish(&mut self) -> fmt::Result { - self.result.and_then(|_| { + self.result = self.result.and_then(|_| { assert!(!self.has_key, "attempted to finish a map with a partial entry"); self.fmt.write_str("}") - }) + }); + self.result } fn is_pretty(&self) -> bool { diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs index 25ab5b2db9641..594f26e978ac0 100644 --- a/library/core/src/fmt/mod.rs +++ b/library/core/src/fmt/mod.rs @@ -354,7 +354,7 @@ impl<'a> Arguments<'a> { Arguments { pieces, fmt: None, args } } - /// This function is used to specify nonstandard formatting parameters. + /// Specifies nonstandard formatting parameters. /// /// An `rt::UnsafeArg` is required because the following invariants must be held /// in order for this function to be safe: @@ -396,7 +396,7 @@ impl<'a> Arguments<'a> { } impl<'a> Arguments<'a> { - /// Get the formatted string, if it has no arguments to be formatted at runtime. + /// Gets the formatted string, if it has no arguments to be formatted at runtime. /// /// This can be used to avoid allocations in some cases. /// @@ -1129,8 +1129,8 @@ pub trait UpperExp { fn fmt(&self, f: &mut Formatter<'_>) -> Result; } -/// The `write` function takes an output stream, and an `Arguments` struct -/// that can be precompiled with the `format_args!` macro. +/// Takes an output stream and an `Arguments` struct that can be precompiled with +/// the `format_args!` macro. /// /// The arguments will be formatted according to the specified format string /// into the output stream provided. @@ -1257,7 +1257,7 @@ impl PostPadding { PostPadding { fill, padding } } - /// Write this post padding. + /// Writes this post padding. pub(crate) fn write(self, f: &mut Formatter<'_>) -> Result { for _ in 0..self.padding { f.buf.write_char(self.fill)?; @@ -1398,9 +1398,10 @@ impl<'a> Formatter<'a> { } } - /// This function takes a string slice and emits it to the internal buffer - /// after applying the relevant formatting flags specified. The flags - /// recognized for generic strings are: + /// Takes a string slice and emits it to the internal buffer after applying + /// the relevant formatting flags specified. + /// + /// The flags recognized for generic strings are: /// /// * width - the minimum width of what to emit /// * fill/align - what to emit and where to emit it if the string @@ -1474,9 +1475,10 @@ impl<'a> Formatter<'a> { } } - /// Write the pre-padding and return the unwritten post-padding. Callers are - /// responsible for ensuring post-padding is written after the thing that is - /// being padded. + /// Writes the pre-padding and returns the unwritten post-padding. + /// + /// Callers are responsible for ensuring post-padding is written after the + /// thing that is being padded. pub(crate) fn padding( &mut self, padding: usize, @@ -1503,6 +1505,7 @@ impl<'a> Formatter<'a> { } /// Takes the formatted parts and applies the padding. + /// /// Assumes that the caller already has rendered the parts with required precision, /// so that `self.precision` can be ignored. /// @@ -1655,7 +1658,7 @@ impl<'a> Formatter<'a> { } } - /// Flags for formatting + /// Returns flags for formatting. #[must_use] #[stable(feature = "rust1", since = "1.0.0")] #[deprecated( @@ -1667,7 +1670,7 @@ impl<'a> Formatter<'a> { self.flags } - /// Character used as 'fill' whenever there is alignment. + /// Returns the character used as 'fill' whenever there is alignment. /// /// # Examples /// @@ -1700,7 +1703,7 @@ impl<'a> Formatter<'a> { self.fill } - /// Flag indicating what form of alignment was requested. + /// Returns a flag indicating what form of alignment was requested. /// /// # Examples /// @@ -1740,7 +1743,7 @@ impl<'a> Formatter<'a> { } } - /// Optionally specified integer width that the output should be. + /// Returns the optionally specified integer width that the output should be. /// /// # Examples /// @@ -1770,8 +1773,8 @@ impl<'a> Formatter<'a> { self.width } - /// Optionally specified precision for numeric types. Alternatively, the - /// maximum width for string types. + /// Returns the optionally specified precision for numeric types. + /// Alternatively, the maximum width for string types. /// /// # Examples /// @@ -1967,8 +1970,9 @@ impl<'a> Formatter<'a> { builders::debug_struct_new(self, name) } - /// Used to shrink `derive(Debug)` code, for faster compilation and smaller binaries. - /// `debug_struct_fields_finish` is more general, but this is faster for 1 field. + /// Shrinks `derive(Debug)` code, for faster compilation and smaller + /// binaries. `debug_struct_fields_finish` is more general, but this is + /// faster for 1 field. #[doc(hidden)] #[unstable(feature = "fmt_helpers_for_derive", issue = "none")] pub fn debug_struct_field1_finish<'b>( @@ -1982,8 +1986,9 @@ impl<'a> Formatter<'a> { builder.finish() } - /// Used to shrink `derive(Debug)` code, for faster compilation and smaller binaries. - /// `debug_struct_fields_finish` is more general, but this is faster for 2 fields. + /// Shrinks `derive(Debug)` code, for faster compilation and smaller + /// binaries. `debug_struct_fields_finish` is more general, but this is + /// faster for 2 fields. #[doc(hidden)] #[unstable(feature = "fmt_helpers_for_derive", issue = "none")] pub fn debug_struct_field2_finish<'b>( @@ -2000,8 +2005,9 @@ impl<'a> Formatter<'a> { builder.finish() } - /// Used to shrink `derive(Debug)` code, for faster compilation and smaller binaries. - /// `debug_struct_fields_finish` is more general, but this is faster for 3 fields. + /// Shrinks `derive(Debug)` code, for faster compilation and smaller + /// binaries. `debug_struct_fields_finish` is more general, but this is + /// faster for 3 fields. #[doc(hidden)] #[unstable(feature = "fmt_helpers_for_derive", issue = "none")] pub fn debug_struct_field3_finish<'b>( @@ -2021,8 +2027,9 @@ impl<'a> Formatter<'a> { builder.finish() } - /// Used to shrink `derive(Debug)` code, for faster compilation and smaller binaries. - /// `debug_struct_fields_finish` is more general, but this is faster for 4 fields. + /// Shrinks `derive(Debug)` code, for faster compilation and smaller + /// binaries. `debug_struct_fields_finish` is more general, but this is + /// faster for 4 fields. #[doc(hidden)] #[unstable(feature = "fmt_helpers_for_derive", issue = "none")] pub fn debug_struct_field4_finish<'b>( @@ -2045,8 +2052,9 @@ impl<'a> Formatter<'a> { builder.finish() } - /// Used to shrink `derive(Debug)` code, for faster compilation and smaller binaries. - /// `debug_struct_fields_finish` is more general, but this is faster for 5 fields. + /// Shrinks `derive(Debug)` code, for faster compilation and smaller + /// binaries. `debug_struct_fields_finish` is more general, but this is + /// faster for 5 fields. #[doc(hidden)] #[unstable(feature = "fmt_helpers_for_derive", issue = "none")] pub fn debug_struct_field5_finish<'b>( @@ -2072,7 +2080,7 @@ impl<'a> Formatter<'a> { builder.finish() } - /// Used to shrink `derive(Debug)` code, for faster compilation and smaller binaries. + /// Shrinks `derive(Debug)` code, for faster compilation and smaller binaries. /// For the cases not covered by `debug_struct_field[12345]_finish`. #[doc(hidden)] #[unstable(feature = "fmt_helpers_for_derive", issue = "none")] @@ -2121,8 +2129,9 @@ impl<'a> Formatter<'a> { builders::debug_tuple_new(self, name) } - /// Used to shrink `derive(Debug)` code, for faster compilation and smaller binaries. - /// `debug_tuple_fields_finish` is more general, but this is faster for 1 field. + /// Shrinks `derive(Debug)` code, for faster compilation and smaller + /// binaries. `debug_tuple_fields_finish` is more general, but this is faster + /// for 1 field. #[doc(hidden)] #[unstable(feature = "fmt_helpers_for_derive", issue = "none")] pub fn debug_tuple_field1_finish<'b>(&'b mut self, name: &str, value1: &dyn Debug) -> Result { @@ -2131,8 +2140,9 @@ impl<'a> Formatter<'a> { builder.finish() } - /// Used to shrink `derive(Debug)` code, for faster compilation and smaller binaries. - /// `debug_tuple_fields_finish` is more general, but this is faster for 2 fields. + /// Shrinks `derive(Debug)` code, for faster compilation and smaller + /// binaries. `debug_tuple_fields_finish` is more general, but this is faster + /// for 2 fields. #[doc(hidden)] #[unstable(feature = "fmt_helpers_for_derive", issue = "none")] pub fn debug_tuple_field2_finish<'b>( @@ -2147,8 +2157,9 @@ impl<'a> Formatter<'a> { builder.finish() } - /// Used to shrink `derive(Debug)` code, for faster compilation and smaller binaries. - /// `debug_tuple_fields_finish` is more general, but this is faster for 3 fields. + /// Shrinks `derive(Debug)` code, for faster compilation and smaller + /// binaries. `debug_tuple_fields_finish` is more general, but this is faster + /// for 3 fields. #[doc(hidden)] #[unstable(feature = "fmt_helpers_for_derive", issue = "none")] pub fn debug_tuple_field3_finish<'b>( @@ -2165,8 +2176,9 @@ impl<'a> Formatter<'a> { builder.finish() } - /// Used to shrink `derive(Debug)` code, for faster compilation and smaller binaries. - /// `debug_tuple_fields_finish` is more general, but this is faster for 4 fields. + /// Shrinks `derive(Debug)` code, for faster compilation and smaller + /// binaries. `debug_tuple_fields_finish` is more general, but this is faster + /// for 4 fields. #[doc(hidden)] #[unstable(feature = "fmt_helpers_for_derive", issue = "none")] pub fn debug_tuple_field4_finish<'b>( @@ -2185,8 +2197,9 @@ impl<'a> Formatter<'a> { builder.finish() } - /// Used to shrink `derive(Debug)` code, for faster compilation and smaller binaries. - /// `debug_tuple_fields_finish` is more general, but this is faster for 5 fields. + /// Shrinks `derive(Debug)` code, for faster compilation and smaller + /// binaries. `debug_tuple_fields_finish` is more general, but this is faster + /// for 5 fields. #[doc(hidden)] #[unstable(feature = "fmt_helpers_for_derive", issue = "none")] pub fn debug_tuple_field5_finish<'b>( @@ -2207,8 +2220,8 @@ impl<'a> Formatter<'a> { builder.finish() } - /// Used to shrink `derive(Debug)` code, for faster compilation and smaller binaries. - /// For the cases not covered by `debug_tuple_field[12345]_finish`. + /// Shrinks `derive(Debug)` code, for faster compilation and smaller + /// binaries. For the cases not covered by `debug_tuple_field[12345]_finish`. #[doc(hidden)] #[unstable(feature = "fmt_helpers_for_derive", issue = "none")] pub fn debug_tuple_fields_finish<'b>( @@ -2496,8 +2509,9 @@ impl Pointer for *const T { } } -/// Since the formatting will be identical for all pointer types, use a non-monomorphized -/// implementation for the actual formatting to reduce the amount of codegen work needed. +/// Since the formatting will be identical for all pointer types, uses a +/// non-monomorphized implementation for the actual formatting to reduce the +/// amount of codegen work needed. /// /// This uses `ptr_addr: usize` and not `ptr: *const ()` to be able to use this for /// `fn(...) -> ...` without using [problematic] "Oxford Casts". diff --git a/library/core/src/future/async_drop.rs b/library/core/src/future/async_drop.rs index 63193bbfb35e8..8971a2c0aafd1 100644 --- a/library/core/src/future/async_drop.rs +++ b/library/core/src/future/async_drop.rs @@ -205,7 +205,7 @@ async unsafe fn slice(s: *mut [T]) { } } -/// Construct a chain of two futures, which awaits them sequentially as +/// Constructs a chain of two futures, which awaits them sequentially as /// a future. #[lang = "async_drop_chain"] async fn chain(first: F, last: G) @@ -235,8 +235,8 @@ async unsafe fn defer(to_drop: *mut T) { /// /// # Safety /// -/// User should carefully manage returned future, since it would -/// try creating an immutable referece from `this` and get pointee's +/// Users should carefully manage the returned future, since it would +/// try creating an immutable reference from `this` and get pointee's /// discriminant. // FIXME(zetanumbers): Send and Sync impls #[lang = "async_drop_either"] diff --git a/library/core/src/future/future.rs b/library/core/src/future/future.rs index c80cfdcebf70d..ca1c2d1ca1f2e 100644 --- a/library/core/src/future/future.rs +++ b/library/core/src/future/future.rs @@ -38,7 +38,7 @@ pub trait Future { #[lang = "future_output"] type Output; - /// Attempt to resolve the future to a final value, registering + /// Attempts to resolve the future to a final value, registering /// the current task for wakeup if the value is not yet available. /// /// # Return value diff --git a/library/core/src/future/into_future.rs b/library/core/src/future/into_future.rs index eb5a9b72dd0f2..aa546b940b23a 100644 --- a/library/core/src/future/into_future.rs +++ b/library/core/src/future/into_future.rs @@ -40,7 +40,7 @@ use crate::future::Future; /// } /// /// impl Multiply { -/// /// Construct a new instance of `Multiply`. +/// /// Constructs a new instance of `Multiply`. /// pub fn new(num: u16, factor: u16) -> Self { /// Self { num, factor } /// } @@ -89,7 +89,7 @@ use crate::future::Future; /// ```rust /// use std::future::IntoFuture; /// -/// /// Convert the output of a future to a string. +/// /// Converts the output of a future to a string. /// async fn fut_to_string(fut: Fut) -> String /// where /// Fut: IntoFuture, diff --git a/library/core/src/internal_macros.rs b/library/core/src/internal_macros.rs index bf53b2245ac59..fe4fa80263c28 100644 --- a/library/core/src/internal_macros.rs +++ b/library/core/src/internal_macros.rs @@ -80,7 +80,7 @@ macro_rules! forward_ref_op_assign { } } -/// Create a zero-size type similar to a closure type, but named. +/// Creates a zero-size type similar to a closure type, but named. macro_rules! impl_fn_for_zst { ($( $( #[$attr: meta] )* diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index c4c6388338949..878ab5ad27d7f 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -1252,7 +1252,7 @@ extern "rust-intrinsic" { /// - If the code actually wants to work on the address the pointer points to, it can use `as` /// casts or [`ptr.addr()`][pointer::addr]. /// - /// Turning a `*mut T` into an `&mut T`: + /// Turning a `*mut T` into a `&mut T`: /// /// ``` /// let ptr: *mut i32 = &mut 0; @@ -1264,7 +1264,7 @@ extern "rust-intrinsic" { /// let ref_casted = unsafe { &mut *ptr }; /// ``` /// - /// Turning an `&mut T` into an `&mut U`: + /// Turning a `&mut T` into a `&mut U`: /// /// ``` /// let ptr = &mut 0; @@ -1277,7 +1277,7 @@ extern "rust-intrinsic" { /// let val_casts = unsafe { &mut *(ptr as *mut i32 as *mut u32) }; /// ``` /// - /// Turning an `&str` into a `&[u8]`: + /// Turning a `&str` into a `&[u8]`: /// /// ``` /// // this is not a good way to do this. @@ -1363,7 +1363,7 @@ extern "rust-intrinsic" { /// } /// /// // This gets rid of the type safety problems; `&mut *` will *only* give - /// // you an `&mut T` from an `&mut T` or `*mut T`. + /// // you a `&mut T` from a `&mut T` or `*mut T`. /// fn split_at_mut_casts(slice: &mut [T], mid: usize) /// -> (&mut [T], &mut [T]) { /// let len = slice.len(); @@ -1944,7 +1944,7 @@ extern "rust-intrinsic" { #[rustc_safe_intrinsic] pub fn frem_algebraic(a: T, b: T) -> T; - /// Convert with LLVM’s fptoui/fptosi, which may return undef for values out of range + /// Converts with LLVM’s fptoui/fptosi, which may return undef for values out of range /// () /// /// Stabilized as [`f32::to_int_unchecked`] and [`f64::to_int_unchecked`]. diff --git a/library/core/src/intrinsics/simd.rs b/library/core/src/intrinsics/simd.rs index 0c21e6f31a827..221724d7b4ae9 100644 --- a/library/core/src/intrinsics/simd.rs +++ b/library/core/src/intrinsics/simd.rs @@ -3,7 +3,7 @@ //! In this module, a "vector" is any `repr(simd)` type. extern "rust-intrinsic" { - /// Insert an element into a vector, returning the updated vector. + /// Inserts an element into a vector, returning the updated vector. /// /// `T` must be a vector with element type `U`. /// @@ -13,7 +13,7 @@ extern "rust-intrinsic" { #[rustc_nounwind] pub fn simd_insert(x: T, idx: u32, val: U) -> T; - /// Extract an element from a vector. + /// Extracts an element from a vector. /// /// `T` must be a vector with element type `U`. /// @@ -23,25 +23,25 @@ extern "rust-intrinsic" { #[rustc_nounwind] pub fn simd_extract(x: T, idx: u32) -> U; - /// Add two simd vectors elementwise. + /// Adds two simd vectors elementwise. /// /// `T` must be a vector of integer or floating point primitive types. #[rustc_nounwind] pub fn simd_add(x: T, y: T) -> T; - /// Subtract `rhs` from `lhs` elementwise. + /// Subtracts `rhs` from `lhs` elementwise. /// /// `T` must be a vector of integer or floating point primitive types. #[rustc_nounwind] pub fn simd_sub(lhs: T, rhs: T) -> T; - /// Multiply two simd vectors elementwise. + /// Multiplies two simd vectors elementwise. /// /// `T` must be a vector of integer or floating point primitive types. #[rustc_nounwind] pub fn simd_mul(x: T, y: T) -> T; - /// Divide `lhs` by `rhs` elementwise. + /// Divides `lhs` by `rhs` elementwise. /// /// `T` must be a vector of integer or floating point primitive types. /// @@ -51,7 +51,7 @@ extern "rust-intrinsic" { #[rustc_nounwind] pub fn simd_div(lhs: T, rhs: T) -> T; - /// Remainder of two vectors elementwise + /// Returns remainder of two vectors elementwise. /// /// `T` must be a vector of integer or floating point primitive types. /// @@ -61,9 +61,9 @@ extern "rust-intrinsic" { #[rustc_nounwind] pub fn simd_rem(lhs: T, rhs: T) -> T; - /// Elementwise vector left shift, with UB on overflow. + /// Shifts vector left elementwise, with UB on overflow. /// - /// Shift `lhs` left by `rhs`, shifting in sign bits for signed types. + /// Shifts `lhs` left by `rhs`, shifting in sign bits for signed types. /// /// `T` must be a vector of integer primitive types. /// @@ -73,11 +73,11 @@ extern "rust-intrinsic" { #[rustc_nounwind] pub fn simd_shl(lhs: T, rhs: T) -> T; - /// Elementwise vector right shift, with UB on overflow. + /// Shifts vector right elementwise, with UB on overflow. /// /// `T` must be a vector of integer primitive types. /// - /// Shift `lhs` right by `rhs`, shifting in sign bits for signed types. + /// Shifts `lhs` right by `rhs`, shifting in sign bits for signed types. /// /// # Safety /// @@ -85,25 +85,25 @@ extern "rust-intrinsic" { #[rustc_nounwind] pub fn simd_shr(lhs: T, rhs: T) -> T; - /// Elementwise vector "and". + /// "Ands" vectors elementwise. /// /// `T` must be a vector of integer primitive types. #[rustc_nounwind] pub fn simd_and(x: T, y: T) -> T; - /// Elementwise vector "or". + /// "Ors" vectors elementwise. /// /// `T` must be a vector of integer primitive types. #[rustc_nounwind] pub fn simd_or(x: T, y: T) -> T; - /// Elementwise vector "exclusive or". + /// "Exclusive ors" vectors elementwise. /// /// `T` must be a vector of integer primitive types. #[rustc_nounwind] pub fn simd_xor(x: T, y: T) -> T; - /// Numerically cast a vector, elementwise. + /// Numerically casts a vector, elementwise. /// /// `T` and `U` must be vectors of integer or floating point primitive types, and must have the /// same length. @@ -124,7 +124,7 @@ extern "rust-intrinsic" { #[rustc_nounwind] pub fn simd_cast(x: T) -> U; - /// Numerically cast a vector, elementwise. + /// Numerically casts a vector, elementwise. /// /// `T` and `U` be a vectors of integer or floating point primitive types, and must have the /// same length. @@ -138,7 +138,7 @@ extern "rust-intrinsic" { #[rustc_nounwind] pub fn simd_as(x: T) -> U; - /// Elementwise negation of a vector. + /// Negates a vector elementwise. /// /// `T` must be a vector of integer or floating-point primitive types. /// @@ -146,13 +146,13 @@ extern "rust-intrinsic" { #[rustc_nounwind] pub fn simd_neg(x: T) -> T; - /// Elementwise absolute value of a vector. + /// Returns absolute value of a vector, elementwise. /// /// `T` must be a vector of floating-point primitive types. #[rustc_nounwind] pub fn simd_fabs(x: T) -> T; - /// Elementwise minimum of two vectors. + /// Returns the minimum of two vectors, elementwise. /// /// `T` must be a vector of floating-point primitive types. /// @@ -160,7 +160,7 @@ extern "rust-intrinsic" { #[rustc_nounwind] pub fn simd_fmin(x: T, y: T) -> T; - /// Elementwise maximum of two vectors. + /// Returns the maximum of two vectors, elementwise. /// /// `T` must be a vector of floating-point primitive types. /// @@ -228,7 +228,7 @@ extern "rust-intrinsic" { #[rustc_nounwind] pub fn simd_ge(x: T, y: T) -> U; - /// Shuffle two vectors by const indices. + /// Shuffles two vectors by const indices. /// /// `T` must be a vector. /// @@ -243,7 +243,7 @@ extern "rust-intrinsic" { #[rustc_nounwind] pub fn simd_shuffle(x: T, y: T, idx: U) -> V; - /// Read a vector of pointers. + /// Reads a vector of pointers. /// /// `T` must be a vector. /// @@ -263,7 +263,7 @@ extern "rust-intrinsic" { #[rustc_nounwind] pub fn simd_gather(val: T, ptr: U, mask: V) -> T; - /// Write to a vector of pointers. + /// Writes to a vector of pointers. /// /// `T` must be a vector. /// @@ -286,7 +286,7 @@ extern "rust-intrinsic" { #[rustc_nounwind] pub fn simd_scatter(val: T, ptr: U, mask: V); - /// Read a vector of pointers. + /// Reads a vector of pointers. /// /// `T` must be a vector. /// @@ -308,7 +308,7 @@ extern "rust-intrinsic" { #[rustc_nounwind] pub fn simd_masked_load(mask: V, ptr: U, val: T) -> T; - /// Write to a vector of pointers. + /// Writes to a vector of pointers. /// /// `T` must be a vector. /// @@ -329,13 +329,13 @@ extern "rust-intrinsic" { #[rustc_nounwind] pub fn simd_masked_store(mask: V, ptr: U, val: T); - /// Add two simd vectors elementwise, with saturation. + /// Adds two simd vectors elementwise, with saturation. /// /// `T` must be a vector of integer primitive types. #[rustc_nounwind] pub fn simd_saturating_add(x: T, y: T) -> T; - /// Subtract two simd vectors elementwise, with saturation. + /// Subtracts two simd vectors elementwise, with saturation. /// /// `T` must be a vector of integer primitive types. /// @@ -343,7 +343,7 @@ extern "rust-intrinsic" { #[rustc_nounwind] pub fn simd_saturating_sub(lhs: T, rhs: T) -> T; - /// Add elements within a vector from left to right. + /// Adds elements within a vector from left to right. /// /// `T` must be a vector of integer or floating-point primitive types. /// @@ -353,7 +353,7 @@ extern "rust-intrinsic" { #[rustc_nounwind] pub fn simd_reduce_add_ordered(x: T, y: U) -> U; - /// Add elements within a vector in arbitrary order. May also be re-associated with + /// Adds elements within a vector in arbitrary order. May also be re-associated with /// unordered additions on the inputs/outputs. /// /// `T` must be a vector of integer or floating-point primitive types. @@ -362,7 +362,7 @@ extern "rust-intrinsic" { #[rustc_nounwind] pub fn simd_reduce_add_unordered(x: T) -> U; - /// Multiply elements within a vector from left to right. + /// Multiplies elements within a vector from left to right. /// /// `T` must be a vector of integer or floating-point primitive types. /// @@ -372,7 +372,7 @@ extern "rust-intrinsic" { #[rustc_nounwind] pub fn simd_reduce_mul_ordered(x: T, y: U) -> U; - /// Multiply elements within a vector in arbitrary order. May also be re-associated with + /// Multiplies elements within a vector in arbitrary order. May also be re-associated with /// unordered additions on the inputs/outputs. /// /// `T` must be a vector of integer or floating-point primitive types. @@ -381,7 +381,7 @@ extern "rust-intrinsic" { #[rustc_nounwind] pub fn simd_reduce_mul_unordered(x: T) -> U; - /// Check if all mask values are true. + /// Checks if all mask values are true. /// /// `T` must be a vector of integer primitive types. /// @@ -390,7 +390,7 @@ extern "rust-intrinsic" { #[rustc_nounwind] pub fn simd_reduce_all(x: T) -> bool; - /// Check if any mask value is true. + /// Checks if any mask value is true. /// /// `T` must be a vector of integer primitive types. /// @@ -399,7 +399,7 @@ extern "rust-intrinsic" { #[rustc_nounwind] pub fn simd_reduce_any(x: T) -> bool; - /// Return the maximum element of a vector. + /// Returns the maximum element of a vector. /// /// `T` must be a vector of integer or floating-point primitive types. /// @@ -409,7 +409,7 @@ extern "rust-intrinsic" { #[rustc_nounwind] pub fn simd_reduce_max(x: T) -> U; - /// Return the minimum element of a vector. + /// Returns the minimum element of a vector. /// /// `T` must be a vector of integer or floating-point primitive types. /// @@ -419,7 +419,7 @@ extern "rust-intrinsic" { #[rustc_nounwind] pub fn simd_reduce_min(x: T) -> U; - /// Logical "and" all elements together. + /// Logical "ands" all elements together. /// /// `T` must be a vector of integer or floating-point primitive types. /// @@ -427,7 +427,7 @@ extern "rust-intrinsic" { #[rustc_nounwind] pub fn simd_reduce_and(x: T) -> U; - /// Logical "or" all elements together. + /// Logical "ors" all elements together. /// /// `T` must be a vector of integer or floating-point primitive types. /// @@ -435,7 +435,7 @@ extern "rust-intrinsic" { #[rustc_nounwind] pub fn simd_reduce_or(x: T) -> U; - /// Logical "exclusive or" all elements together. + /// Logical "exclusive ors" all elements together. /// /// `T` must be a vector of integer or floating-point primitive types. /// @@ -443,7 +443,7 @@ extern "rust-intrinsic" { #[rustc_nounwind] pub fn simd_reduce_xor(x: T) -> U; - /// Truncate an integer vector to a bitmask. + /// Truncates an integer vector to a bitmask. /// /// `T` must be an integer vector. /// @@ -479,7 +479,7 @@ extern "rust-intrinsic" { #[rustc_nounwind] pub fn simd_bitmask(x: T) -> U; - /// Select elements from a mask. + /// Selects elements from a mask. /// /// `M` must be an integer vector. /// @@ -494,7 +494,7 @@ extern "rust-intrinsic" { #[rustc_nounwind] pub fn simd_select(mask: M, if_true: T, if_false: T) -> T; - /// Select elements from a bitmask. + /// Selects elements from a bitmask. /// /// `M` must be an unsigned integer or array of `u8`, matching `simd_bitmask`. /// @@ -511,7 +511,8 @@ extern "rust-intrinsic" { #[rustc_nounwind] pub fn simd_select_bitmask(m: M, yes: T, no: T) -> T; - /// Elementwise calculates the offset from a pointer vector, potentially wrapping. + /// Calculates the offset from a pointer vector elementwise, potentially + /// wrapping. /// /// `T` must be a vector of pointers. /// @@ -521,13 +522,13 @@ extern "rust-intrinsic" { #[rustc_nounwind] pub fn simd_arith_offset(ptr: T, offset: U) -> T; - /// Cast a vector of pointers. + /// Casts a vector of pointers. /// /// `T` and `U` must be vectors of pointers with the same number of elements. #[rustc_nounwind] pub fn simd_cast_ptr(ptr: T) -> U; - /// Expose a vector of pointers as a vector of addresses. + /// Exposes a vector of pointers as a vector of addresses. /// /// `T` must be a vector of pointers. /// @@ -535,7 +536,7 @@ extern "rust-intrinsic" { #[rustc_nounwind] pub fn simd_expose_provenance(ptr: T) -> U; - /// Create a vector of pointers from a vector of addresses. + /// Creates a vector of pointers from a vector of addresses. /// /// `T` must be a vector of `usize`. /// @@ -543,56 +544,56 @@ extern "rust-intrinsic" { #[rustc_nounwind] pub fn simd_with_exposed_provenance(addr: T) -> U; - /// Swap bytes of each element. + /// Swaps bytes of each element. /// /// `T` must be a vector of integers. #[rustc_nounwind] pub fn simd_bswap(x: T) -> T; - /// Reverse bits of each element. + /// Reverses bits of each element. /// /// `T` must be a vector of integers. #[rustc_nounwind] pub fn simd_bitreverse(x: T) -> T; - /// Count the leading zeros of each element. + /// Counts the leading zeros of each element. /// /// `T` must be a vector of integers. #[rustc_nounwind] pub fn simd_ctlz(x: T) -> T; - /// Count the number of ones in each element. + /// Counts the number of ones in each element. /// /// `T` must be a vector of integers. #[rustc_nounwind] pub fn simd_ctpop(x: T) -> T; - /// Count the trailing zeros of each element. + /// Counts the trailing zeros of each element. /// /// `T` must be a vector of integers. #[rustc_nounwind] pub fn simd_cttz(x: T) -> T; - /// Round up each element to the next highest integer-valued float. + /// Rounds up each element to the next highest integer-valued float. /// /// `T` must be a vector of floats. #[rustc_nounwind] pub fn simd_ceil(x: T) -> T; - /// Round down each element to the next lowest integer-valued float. + /// Rounds down each element to the next lowest integer-valued float. /// /// `T` must be a vector of floats. #[rustc_nounwind] pub fn simd_floor(x: T) -> T; - /// Round each element to the closest integer-valued float. + /// Rounds each element to the closest integer-valued float. /// Ties are resolved by rounding away from 0. /// /// `T` must be a vector of floats. #[rustc_nounwind] pub fn simd_round(x: T) -> T; - /// Return the integer part of each element as an integer-valued float. + /// Returns the integer part of each element as an integer-valued float. /// In other words, non-integer values are truncated towards zero. /// /// `T` must be a vector of floats. diff --git a/library/core/src/io/borrowed_buf.rs b/library/core/src/io/borrowed_buf.rs index d497da33dd923..dbc60aa8154c6 100644 --- a/library/core/src/io/borrowed_buf.rs +++ b/library/core/src/io/borrowed_buf.rs @@ -44,7 +44,7 @@ impl Debug for BorrowedBuf<'_> { } } -/// Create a new `BorrowedBuf` from a fully initialized slice. +/// Creates a new `BorrowedBuf` from a fully initialized slice. impl<'data> From<&'data mut [u8]> for BorrowedBuf<'data> { #[inline] fn from(slice: &'data mut [u8]) -> BorrowedBuf<'data> { @@ -59,7 +59,7 @@ impl<'data> From<&'data mut [u8]> for BorrowedBuf<'data> { } } -/// Create a new `BorrowedBuf` from an uninitialized buffer. +/// Creates a new `BorrowedBuf` from an uninitialized buffer. /// /// Use `set_init` if part of the buffer is known to be already initialized. impl<'data> From<&'data mut [MaybeUninit]> for BorrowedBuf<'data> { @@ -174,7 +174,7 @@ pub struct BorrowedCursor<'a> { } impl<'a> BorrowedCursor<'a> { - /// Reborrow this cursor by cloning it with a smaller lifetime. + /// Reborrows this cursor by cloning it with a smaller lifetime. /// /// Since a cursor maintains unique access to its underlying buffer, the borrowed cursor is /// not accessible while the new cursor exists. @@ -247,7 +247,7 @@ impl<'a> BorrowedCursor<'a> { unsafe { self.buf.buf.get_unchecked_mut(self.buf.filled..) } } - /// Advance the cursor by asserting that `n` bytes have been filled. + /// Advances the cursor by asserting that `n` bytes have been filled. /// /// After advancing, the `n` bytes are no longer accessible via the cursor and can only be /// accessed via the underlying buffer. I.e., the buffer's filled portion grows by `n` elements @@ -268,7 +268,7 @@ impl<'a> BorrowedCursor<'a> { self } - /// Advance the cursor by asserting that `n` bytes have been filled. + /// Advances the cursor by asserting that `n` bytes have been filled. /// /// After advancing, the `n` bytes are no longer accessible via the cursor and can only be /// accessed via the underlying buffer. I.e., the buffer's filled portion grows by `n` elements diff --git a/library/core/src/iter/adapters/step_by.rs b/library/core/src/iter/adapters/step_by.rs index abdf2f415fe55..d3105e7d88c33 100644 --- a/library/core/src/iter/adapters/step_by.rs +++ b/library/core/src/iter/adapters/step_by.rs @@ -414,9 +414,9 @@ unsafe impl StepByBackImpl for St /// These only work for unsigned types, and will need to be reworked /// if you want to use it to specialize on signed types. /// -/// Currently these are only implemented for integers up to usize due to -/// correctness issues around ExactSizeIterator impls on 16bit platforms. -/// And since ExactSizeIterator is a prerequisite for backwards iteration +/// Currently these are only implemented for integers up to `usize` due to +/// correctness issues around `ExactSizeIterator` impls on 16bit platforms. +/// And since `ExactSizeIterator` is a prerequisite for backwards iteration /// and we must consistently specialize backwards and forwards iteration /// that makes the situation complicated enough that it's not covered /// for now. diff --git a/library/core/src/iter/traits/accum.rs b/library/core/src/iter/traits/accum.rs index f9c7eb8f9383e..c97cd042ab459 100644 --- a/library/core/src/iter/traits/accum.rs +++ b/library/core/src/iter/traits/accum.rs @@ -15,8 +15,8 @@ use crate::num::Wrapping; label = "value of type `{Self}` cannot be made by summing a `std::iter::Iterator`" )] pub trait Sum: Sized { - /// Method which takes an iterator and generates `Self` from the elements by - /// "summing up" the items. + /// Takes an iterator and generates `Self` from the elements by "summing up" + /// the items. #[stable(feature = "iter_arith_traits", since = "1.12.0")] fn sum>(iter: I) -> Self; } @@ -36,8 +36,8 @@ pub trait Sum: Sized { label = "value of type `{Self}` cannot be made by multiplying all elements from a `std::iter::Iterator`" )] pub trait Product: Sized { - /// Method which takes an iterator and generates `Self` from the elements by - /// multiplying the items. + /// Takes an iterator and generates `Self` from the elements by multiplying + /// the items. #[stable(feature = "iter_arith_traits", since = "1.12.0")] fn product>(iter: I) -> Self; } diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index 733d414d44465..c85a61ada3d69 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -823,7 +823,7 @@ pub trait Iterator { /// /// Given an element the closure must return `true` or `false`. The returned /// iterator will yield only the elements for which the closure returns - /// true. + /// `true`. /// /// # Examples /// @@ -3951,8 +3951,6 @@ pub trait Iterator { /// # Examples /// /// ``` - /// #![feature(is_sorted)] - /// /// assert!([1, 2, 2, 9].iter().is_sorted()); /// assert!(![1, 3, 2, 4].iter().is_sorted()); /// assert!([0].iter().is_sorted()); @@ -3960,7 +3958,7 @@ pub trait Iterator { /// assert!(![0.0, 1.0, f32::NAN].iter().is_sorted()); /// ``` #[inline] - #[unstable(feature = "is_sorted", reason = "new API", issue = "53485")] + #[stable(feature = "is_sorted", since = "CURRENT_RUSTC_VERSION")] #[rustc_do_not_const_check] fn is_sorted(self) -> bool where @@ -3978,8 +3976,6 @@ pub trait Iterator { /// # Examples /// /// ``` - /// #![feature(is_sorted)] - /// /// assert!([1, 2, 2, 9].iter().is_sorted_by(|a, b| a <= b)); /// assert!(![1, 2, 2, 9].iter().is_sorted_by(|a, b| a < b)); /// @@ -3989,7 +3985,7 @@ pub trait Iterator { /// assert!(std::iter::empty::().is_sorted_by(|a, b| false)); /// assert!(std::iter::empty::().is_sorted_by(|a, b| true)); /// ``` - #[unstable(feature = "is_sorted", reason = "new API", issue = "53485")] + #[stable(feature = "is_sorted", since = "CURRENT_RUSTC_VERSION")] #[rustc_do_not_const_check] fn is_sorted_by(mut self, compare: F) -> bool where @@ -4030,13 +4026,11 @@ pub trait Iterator { /// # Examples /// /// ``` - /// #![feature(is_sorted)] - /// /// assert!(["c", "bb", "aaa"].iter().is_sorted_by_key(|s| s.len())); /// assert!(![-2i32, -1, 0, 3].iter().is_sorted_by_key(|n| n.abs())); /// ``` #[inline] - #[unstable(feature = "is_sorted", reason = "new API", issue = "53485")] + #[stable(feature = "is_sorted", since = "CURRENT_RUSTC_VERSION")] #[rustc_do_not_const_check] fn is_sorted_by_key(self, f: F) -> bool where diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 02cb02dce1d87..e8f08db94164d 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -127,7 +127,6 @@ #![feature(const_hash)] #![feature(const_heap)] #![feature(const_index_range_slice_index)] -#![feature(const_int_from_str)] #![feature(const_intrinsic_copy)] #![feature(const_intrinsic_forget)] #![feature(const_ipv4)] @@ -163,7 +162,6 @@ #![feature(const_ub_checks)] #![feature(const_unicode_case_lookup)] #![feature(const_unsafecell_get_mut)] -#![feature(const_waker)] #![feature(coverage_attribute)] #![feature(do_not_recommend)] #![feature(duration_consts_float)] diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs index 0d4ca4d5f01e4..ac51a40d9f478 100644 --- a/library/core/src/macros/mod.rs +++ b/library/core/src/macros/mod.rs @@ -14,6 +14,12 @@ macro_rules! panic { /// Asserts that two expressions are equal to each other (using [`PartialEq`]). /// +/// Assertions are always checked in both debug and release builds, and cannot +/// be disabled. See [`debug_assert_eq!`] for assertions that are disabled in +/// release builds by default. +/// +/// [`debug_assert_eq!`]: crate::debug_assert_eq +/// /// On panic, this macro will print the values of the expressions with their /// debug representations. /// @@ -64,6 +70,12 @@ macro_rules! assert_eq { /// Asserts that two expressions are not equal to each other (using [`PartialEq`]). /// +/// Assertions are always checked in both debug and release builds, and cannot +/// be disabled. See [`debug_assert_ne!`] for assertions that are disabled in +/// release builds by default. +/// +/// [`debug_assert_ne!`]: crate::debug_assert_ne +/// /// On panic, this macro will print the values of the expressions with their /// debug representations. /// @@ -122,6 +134,12 @@ macro_rules! assert_ne { /// optional if guard can be used to add additional checks that must be true for the matched value, /// otherwise this macro will panic. /// +/// Assertions are always checked in both debug and release builds, and cannot +/// be disabled. See [`debug_assert_matches!`] for assertions that are disabled in +/// release builds by default. +/// +/// [`debug_assert_matches!`]: crate::assert_matches::debug_assert_matches +/// /// On panic, this macro will print the value of the expression with its debug representation. /// /// Like [`assert!`], this macro has a second form, where a custom panic message can be provided. @@ -633,7 +651,7 @@ macro_rules! write { }; } -/// Write formatted data into a buffer, with a newline appended. +/// Writes formatted data into a buffer, with a newline appended. /// /// On all platforms, the newline is the LINE FEED character (`\n`/`U+000A`) alone /// (no additional CARRIAGE RETURN (`\r`/`U+000D`). diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs index cf428e36ea7a0..ac630df805a57 100644 --- a/library/core/src/marker.rs +++ b/library/core/src/marker.rs @@ -871,7 +871,7 @@ marker_impls! { /// /// *However*, you cannot use [`mem::replace`] on `!Unpin` data which is *pinned* by being wrapped /// inside a [`Pin`] pointing at it. This is because you cannot (safely) use a -/// [`Pin`] to get an `&mut T` to its pointee value, which you would need to call +/// [`Pin`] to get a `&mut T` to its pointee value, which you would need to call /// [`mem::replace`], and *that* is what makes this system work. /// /// So this, for example, can only be done on types implementing `Unpin`: diff --git a/library/core/src/mem/manually_drop.rs b/library/core/src/mem/manually_drop.rs index 997f088c6d687..00c837041b697 100644 --- a/library/core/src/mem/manually_drop.rs +++ b/library/core/src/mem/manually_drop.rs @@ -118,10 +118,12 @@ impl ManuallyDrop { } impl ManuallyDrop { - /// Manually drops the contained value. This is exactly equivalent to calling - /// [`ptr::drop_in_place`] with a pointer to the contained value. As such, unless - /// the contained value is a packed struct, the destructor will be called in-place - /// without moving the value, and thus can be used to safely drop [pinned] data. + /// Manually drops the contained value. + /// + /// This is exactly equivalent to calling [`ptr::drop_in_place`] with a + /// pointer to the contained value. As such, unless the contained value is a + /// packed struct, the destructor will be called in-place without moving the + /// value, and thus can be used to safely drop [pinned] data. /// /// If you have ownership of the value, you can use [`ManuallyDrop::into_inner`] instead. /// diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs index dd40f57dc8707..a3f433fd5ac99 100644 --- a/library/core/src/mem/maybe_uninit.rs +++ b/library/core/src/mem/maybe_uninit.rs @@ -310,7 +310,7 @@ impl MaybeUninit { MaybeUninit { uninit: () } } - /// Create a new array of `MaybeUninit` items, in an uninitialized state. + /// Creates a new array of `MaybeUninit` items, in an uninitialized state. /// /// Note: in a future Rust version this method may become unnecessary /// when Rust allows diff --git a/library/core/src/net/ip_addr.rs b/library/core/src/net/ip_addr.rs index c11a508a135b3..e9abd57b858bc 100644 --- a/library/core/src/net/ip_addr.rs +++ b/library/core/src/net/ip_addr.rs @@ -406,8 +406,8 @@ impl IpAddr { matches!(self, IpAddr::V6(_)) } - /// Converts this address to an `IpAddr::V4` if it is an IPv4-mapped IPv6 address, otherwise it - /// returns `self` as-is. + /// Converts this address to an `IpAddr::V4` if it is an IPv4-mapped IPv6 + /// address, otherwise returns `self` as-is. /// /// # Examples /// @@ -549,7 +549,7 @@ impl Ipv4Addr { #[stable(feature = "ip_constructors", since = "1.30.0")] pub const UNSPECIFIED: Self = Ipv4Addr::new(0, 0, 0, 0); - /// An IPv4 address representing the broadcast address: `255.255.255.255` + /// An IPv4 address representing the broadcast address: `255.255.255.255`. /// /// # Examples /// @@ -686,10 +686,10 @@ impl Ipv4Addr { /// Returns [`true`] if the address appears to be globally reachable /// as specified by the [IANA IPv4 Special-Purpose Address Registry]. - /// Whether or not an address is practically reachable will depend on your network configuration. /// - /// Most IPv4 addresses are globally reachable; - /// unless they are specifically defined as *not* globally reachable. + /// Whether or not an address is practically reachable will depend on your + /// network configuration. Most IPv4 addresses are globally reachable, unless + /// they are specifically defined as *not* globally reachable. /// /// Non-exhaustive list of notable addresses that are not globally reachable: /// @@ -802,8 +802,10 @@ impl Ipv4Addr { } /// Returns [`true`] if this address part of the `198.18.0.0/15` range, which is reserved for - /// network devices benchmarking. This range is defined in [IETF RFC 2544] as `192.18.0.0` - /// through `198.19.255.255` but [errata 423] corrects it to `198.18.0.0/15`. + /// network devices benchmarking. + /// + /// This range is defined in [IETF RFC 2544] as `192.18.0.0` through + /// `198.19.255.255` but [errata 423] corrects it to `198.18.0.0/15`. /// /// [IETF RFC 2544]: https://tools.ietf.org/html/rfc2544 /// [errata 423]: https://www.rfc-editor.org/errata/eid423 @@ -827,10 +829,12 @@ impl Ipv4Addr { self.octets()[0] == 198 && (self.octets()[1] & 0xfe) == 18 } - /// Returns [`true`] if this address is reserved by IANA for future use. [IETF RFC 1112] - /// defines the block of reserved addresses as `240.0.0.0/4`. This range normally includes the - /// broadcast address `255.255.255.255`, but this implementation explicitly excludes it, since - /// it is obviously not reserved for future use. + /// Returns [`true`] if this address is reserved by IANA for future use. + /// + /// [IETF RFC 1112] defines the block of reserved addresses as `240.0.0.0/4`. + /// This range normally includes the broadcast address `255.255.255.255`, but + /// this implementation explicitly excludes it, since it is obviously not + /// reserved for future use. /// /// [IETF RFC 1112]: https://tools.ietf.org/html/rfc1112 /// @@ -1328,7 +1332,7 @@ impl Ipv6Addr { #[stable(feature = "ip_constructors", since = "1.30.0")] pub const LOCALHOST: Self = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1); - /// An IPv6 address representing the unspecified address: `::` + /// An IPv6 address representing the unspecified address: `::`. /// /// This corresponds to constant `IN6ADDR_ANY_INIT` or `in6addr_any` in other languages. /// @@ -1424,10 +1428,10 @@ impl Ipv6Addr { /// Returns [`true`] if the address appears to be globally reachable /// as specified by the [IANA IPv6 Special-Purpose Address Registry]. - /// Whether or not an address is practically reachable will depend on your network configuration. /// - /// Most IPv6 addresses are globally reachable; - /// unless they are specifically defined as *not* globally reachable. + /// Whether or not an address is practically reachable will depend on your + /// network configuration. Most IPv6 addresses are globally reachable, unless + /// they are specifically defined as *not* globally reachable. /// /// Non-exhaustive list of notable addresses that are not globally reachable: /// - The [unspecified address] ([`is_unspecified`](Ipv6Addr::is_unspecified)) @@ -1879,8 +1883,8 @@ impl Ipv6Addr { } } - /// Converts this address to an `IpAddr::V4` if it is an IPv4-mapped address, otherwise it - /// returns self wrapped in an `IpAddr::V6`. + /// Converts this address to an `IpAddr::V4` if it is an IPv4-mapped address, + /// otherwise returns self wrapped in an `IpAddr::V6`. /// /// # Examples /// @@ -1919,7 +1923,7 @@ impl Ipv6Addr { } } -/// Write an Ipv6Addr, conforming to the canonical style described by +/// Writes an Ipv6Addr, conforming to the canonical style described by /// [RFC 5952](https://tools.ietf.org/html/rfc5952). #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Display for Ipv6Addr { @@ -1962,7 +1966,7 @@ impl fmt::Display for Ipv6Addr { longest }; - /// Write a colon-separated part of the address + /// Writes a colon-separated part of the address. #[inline] fn fmt_subslice(f: &mut fmt::Formatter<'_>, chunk: &[u16]) -> fmt::Result { if let Some((first, tail)) = chunk.split_first() { diff --git a/library/core/src/net/parser.rs b/library/core/src/net/parser.rs index deea821244859..a8ec71f0dd801 100644 --- a/library/core/src/net/parser.rs +++ b/library/core/src/net/parser.rs @@ -68,7 +68,7 @@ impl<'a> Parser<'a> { self.state.first().map(|&b| char::from(b)) } - /// Read the next character from the input + /// Reads the next character from the input fn read_char(&mut self) -> Option { self.state.split_first().map(|(&b, tail)| { self.state = tail; @@ -77,7 +77,7 @@ impl<'a> Parser<'a> { } #[must_use] - /// Read the next character from the input if it matches the target. + /// Reads the next character from the input if it matches the target. fn read_given_char(&mut self, target: char) -> Option<()> { self.read_atomically(|p| { p.read_char().and_then(|c| if c == target { Some(()) } else { None }) @@ -165,7 +165,7 @@ impl<'a> Parser<'a> { } } - /// Read an IPv4 address. + /// Reads an IPv4 address. fn read_ipv4_addr(&mut self) -> Option { self.read_atomically(|p| { let mut groups = [0; 4]; @@ -182,7 +182,7 @@ impl<'a> Parser<'a> { }) } - /// Read an IPv6 Address. + /// Reads an IPv6 address. fn read_ipv6_addr(&mut self) -> Option { /// Read a chunk of an IPv6 address into `groups`. Returns the number /// of groups read, along with a bool indicating if an embedded @@ -249,12 +249,12 @@ impl<'a> Parser<'a> { }) } - /// Read an IP Address, either IPv4 or IPv6. + /// Reads an IP address, either IPv4 or IPv6. fn read_ip_addr(&mut self) -> Option { self.read_ipv4_addr().map(IpAddr::V4).or_else(move || self.read_ipv6_addr().map(IpAddr::V6)) } - /// Read a `:` followed by a port in base 10. + /// Reads a `:` followed by a port in base 10. fn read_port(&mut self) -> Option { self.read_atomically(|p| { p.read_given_char(':')?; @@ -262,7 +262,7 @@ impl<'a> Parser<'a> { }) } - /// Read a `%` followed by a scope ID in base 10. + /// Reads a `%` followed by a scope ID in base 10. fn read_scope_id(&mut self) -> Option { self.read_atomically(|p| { p.read_given_char('%')?; @@ -270,7 +270,7 @@ impl<'a> Parser<'a> { }) } - /// Read an IPv4 address with a port. + /// Reads an IPv4 address with a port. fn read_socket_addr_v4(&mut self) -> Option { self.read_atomically(|p| { let ip = p.read_ipv4_addr()?; @@ -279,7 +279,7 @@ impl<'a> Parser<'a> { }) } - /// Read an IPv6 address with a port. + /// Reads an IPv6 address with a port. fn read_socket_addr_v6(&mut self) -> Option { self.read_atomically(|p| { p.read_given_char('[')?; @@ -292,7 +292,7 @@ impl<'a> Parser<'a> { }) } - /// Read an IP address with a port + /// Reads an IP address with a port. fn read_socket_addr(&mut self) -> Option { self.read_socket_addr_v4() .map(SocketAddr::V4) diff --git a/library/core/src/num/dec2flt/common.rs b/library/core/src/num/dec2flt/common.rs index c85727b493816..4dadf406ae8c7 100644 --- a/library/core/src/num/dec2flt/common.rs +++ b/library/core/src/num/dec2flt/common.rs @@ -2,10 +2,10 @@ /// Helper methods to process immutable bytes. pub(crate) trait ByteSlice { - /// Read 8 bytes as a 64-bit integer in little-endian order. + /// Reads 8 bytes as a 64-bit integer in little-endian order. fn read_u64(&self) -> u64; - /// Write a 64-bit integer as 8 bytes in little-endian order. + /// Writes a 64-bit integer as 8 bytes in little-endian order. fn write_u64(&mut self, value: u64); /// Calculate the offset of a slice from another. diff --git a/library/core/src/num/dec2flt/float.rs b/library/core/src/num/dec2flt/float.rs index 1c9d68999d6f8..da57aa9a546af 100644 --- a/library/core/src/num/dec2flt/float.rs +++ b/library/core/src/num/dec2flt/float.rs @@ -81,7 +81,7 @@ pub trait RawFloat: // Maximum mantissa for the fast-path (`1 << 53` for f64). const MAX_MANTISSA_FAST_PATH: u64 = 2_u64 << Self::MANTISSA_EXPLICIT_BITS; - /// Convert integer into float through an as cast. + /// Converts integer into float through an as cast. /// This is only called in the fast-path algorithm, and therefore /// will not lose precision, since the value will always have /// only if the value is <= Self::MAX_MANTISSA_FAST_PATH. @@ -90,7 +90,7 @@ pub trait RawFloat: /// Performs a raw transmutation from an integer. fn from_u64_bits(v: u64) -> Self; - /// Get a small power-of-ten for fast-path multiplication. + /// Gets a small power-of-ten for fast-path multiplication. fn pow10_fast_path(exponent: usize) -> Self; /// Returns the category that this number falls into. diff --git a/library/core/src/num/error.rs b/library/core/src/num/error.rs index a2d7e6f7b0754..b8e22a8aef955 100644 --- a/library/core/src/num/error.rs +++ b/library/core/src/num/error.rs @@ -113,7 +113,7 @@ pub enum IntErrorKind { impl ParseIntError { /// Outputs the detailed cause of parsing an integer failing. #[must_use] - #[rustc_const_unstable(feature = "const_int_from_str", issue = "59133")] + #[rustc_const_stable(feature = "const_int_from_str", since = "CURRENT_RUSTC_VERSION")] #[stable(feature = "int_error_matching", since = "1.55.0")] pub const fn kind(&self) -> &IntErrorKind { &self.kind diff --git a/library/core/src/num/f128.rs b/library/core/src/num/f128.rs index 05dc1e97852e0..0192369c0f9eb 100644 --- a/library/core/src/num/f128.rs +++ b/library/core/src/num/f128.rs @@ -898,7 +898,7 @@ impl f128 { intrinsics::const_eval_select((v,), ct_u128_to_f128, rt_u128_to_f128) } - /// Return the memory representation of this floating point number as a byte array in + /// Returns the memory representation of this floating point number as a byte array in /// big-endian (network) byte order. /// /// See [`from_bits`](Self::from_bits) for some discussion of the @@ -924,7 +924,7 @@ impl f128 { self.to_bits().to_be_bytes() } - /// Return the memory representation of this floating point number as a byte array in + /// Returns the memory representation of this floating point number as a byte array in /// little-endian byte order. /// /// See [`from_bits`](Self::from_bits) for some discussion of the @@ -950,7 +950,7 @@ impl f128 { self.to_bits().to_le_bytes() } - /// Return the memory representation of this floating point number as a byte array in + /// Returns the memory representation of this floating point number as a byte array in /// native byte order. /// /// As the target platform's native endianness is used, portable code @@ -987,7 +987,7 @@ impl f128 { self.to_bits().to_ne_bytes() } - /// Create a floating point value from its representation as a byte array in big endian. + /// Creates a floating point value from its representation as a byte array in big endian. /// /// See [`from_bits`](Self::from_bits) for some discussion of the /// portability of this operation (there are almost no issues). @@ -1014,7 +1014,7 @@ impl f128 { Self::from_bits(u128::from_be_bytes(bytes)) } - /// Create a floating point value from its representation as a byte array in little endian. + /// Creates a floating point value from its representation as a byte array in little endian. /// /// See [`from_bits`](Self::from_bits) for some discussion of the /// portability of this operation (there are almost no issues). @@ -1041,7 +1041,7 @@ impl f128 { Self::from_bits(u128::from_le_bytes(bytes)) } - /// Create a floating point value from its representation as a byte array in native endian. + /// Creates a floating point value from its representation as a byte array in native endian. /// /// As the target platform's native endianness is used, portable code /// likely wants to use [`from_be_bytes`] or [`from_le_bytes`], as @@ -1078,7 +1078,7 @@ impl f128 { Self::from_bits(u128::from_ne_bytes(bytes)) } - /// Return the ordering between `self` and `other`. + /// Returns the ordering between `self` and `other`. /// /// Unlike the standard partial comparison between floating point numbers, /// this comparison always produces an ordering in accordance to diff --git a/library/core/src/num/f16.rs b/library/core/src/num/f16.rs index 2a8ede9383844..e96ffbd8e8ad6 100644 --- a/library/core/src/num/f16.rs +++ b/library/core/src/num/f16.rs @@ -933,7 +933,7 @@ impl f16 { intrinsics::const_eval_select((v,), ct_u16_to_f16, rt_u16_to_f16) } - /// Return the memory representation of this floating point number as a byte array in + /// Returns the memory representation of this floating point number as a byte array in /// big-endian (network) byte order. /// /// See [`from_bits`](Self::from_bits) for some discussion of the @@ -958,7 +958,7 @@ impl f16 { self.to_bits().to_be_bytes() } - /// Return the memory representation of this floating point number as a byte array in + /// Returns the memory representation of this floating point number as a byte array in /// little-endian byte order. /// /// See [`from_bits`](Self::from_bits) for some discussion of the @@ -983,7 +983,7 @@ impl f16 { self.to_bits().to_le_bytes() } - /// Return the memory representation of this floating point number as a byte array in + /// Returns the memory representation of this floating point number as a byte array in /// native byte order. /// /// As the target platform's native endianness is used, portable code @@ -1021,7 +1021,7 @@ impl f16 { self.to_bits().to_ne_bytes() } - /// Create a floating point value from its representation as a byte array in big endian. + /// Creates a floating point value from its representation as a byte array in big endian. /// /// See [`from_bits`](Self::from_bits) for some discussion of the /// portability of this operation (there are almost no issues). @@ -1044,7 +1044,7 @@ impl f16 { Self::from_bits(u16::from_be_bytes(bytes)) } - /// Create a floating point value from its representation as a byte array in little endian. + /// Creates a floating point value from its representation as a byte array in little endian. /// /// See [`from_bits`](Self::from_bits) for some discussion of the /// portability of this operation (there are almost no issues). @@ -1067,7 +1067,7 @@ impl f16 { Self::from_bits(u16::from_le_bytes(bytes)) } - /// Create a floating point value from its representation as a byte array in native endian. + /// Creates a floating point value from its representation as a byte array in native endian. /// /// As the target platform's native endianness is used, portable code /// likely wants to use [`from_be_bytes`] or [`from_le_bytes`], as @@ -1101,7 +1101,7 @@ impl f16 { Self::from_bits(u16::from_ne_bytes(bytes)) } - /// Return the ordering between `self` and `other`. + /// Returns the ordering between `self` and `other`. /// /// Unlike the standard partial comparison between floating point numbers, /// this comparison always produces an ordering in accordance to diff --git a/library/core/src/num/f32.rs b/library/core/src/num/f32.rs index b9c84a66ed138..08d863f17caf7 100644 --- a/library/core/src/num/f32.rs +++ b/library/core/src/num/f32.rs @@ -721,11 +721,13 @@ impl f32 { } /// Returns `true` if `self` has a positive sign, including `+0.0`, NaNs with - /// positive sign bit and positive infinity. Note that IEEE 754 doesn't assign any - /// meaning to the sign bit in case of a NaN, and as Rust doesn't guarantee that - /// the bit pattern of NaNs are conserved over arithmetic operations, the result of - /// `is_sign_positive` on a NaN might produce an unexpected result in some cases. - /// See [explanation of NaN as a special value](f32) for more info. + /// positive sign bit and positive infinity. + /// + /// Note that IEEE 754 doesn't assign any meaning to the sign bit in case of + /// a NaN, and as Rust doesn't guarantee that the bit pattern of NaNs are + /// conserved over arithmetic operations, the result of `is_sign_positive` on + /// a NaN might produce an unexpected result in some cases. See [explanation + /// of NaN as a special value](f32) for more info. /// /// ``` /// let f = 7.0_f32; @@ -743,11 +745,13 @@ impl f32 { } /// Returns `true` if `self` has a negative sign, including `-0.0`, NaNs with - /// negative sign bit and negative infinity. Note that IEEE 754 doesn't assign any - /// meaning to the sign bit in case of a NaN, and as Rust doesn't guarantee that - /// the bit pattern of NaNs are conserved over arithmetic operations, the result of - /// `is_sign_negative` on a NaN might produce an unexpected result in some cases. - /// See [explanation of NaN as a special value](f32) for more info. + /// negative sign bit and negative infinity. + /// + /// Note that IEEE 754 doesn't assign any meaning to the sign bit in case of + /// a NaN, and as Rust doesn't guarantee that the bit pattern of NaNs are + /// conserved over arithmetic operations, the result of `is_sign_negative` on + /// a NaN might produce an unexpected result in some cases. See [explanation + /// of NaN as a special value](f32) for more info. /// /// ``` /// let f = 7.0f32; @@ -1274,7 +1278,7 @@ impl f32 { intrinsics::const_eval_select((v,), ct_u32_to_f32, rt_u32_to_f32) } - /// Return the memory representation of this floating point number as a byte array in + /// Returns the memory representation of this floating point number as a byte array in /// big-endian (network) byte order. /// /// See [`from_bits`](Self::from_bits) for some discussion of the @@ -1295,7 +1299,7 @@ impl f32 { self.to_bits().to_be_bytes() } - /// Return the memory representation of this floating point number as a byte array in + /// Returns the memory representation of this floating point number as a byte array in /// little-endian byte order. /// /// See [`from_bits`](Self::from_bits) for some discussion of the @@ -1316,7 +1320,7 @@ impl f32 { self.to_bits().to_le_bytes() } - /// Return the memory representation of this floating point number as a byte array in + /// Returns the memory representation of this floating point number as a byte array in /// native byte order. /// /// As the target platform's native endianness is used, portable code @@ -1350,7 +1354,7 @@ impl f32 { self.to_bits().to_ne_bytes() } - /// Create a floating point value from its representation as a byte array in big endian. + /// Creates a floating point value from its representation as a byte array in big endian. /// /// See [`from_bits`](Self::from_bits) for some discussion of the /// portability of this operation (there are almost no issues). @@ -1369,7 +1373,7 @@ impl f32 { Self::from_bits(u32::from_be_bytes(bytes)) } - /// Create a floating point value from its representation as a byte array in little endian. + /// Creates a floating point value from its representation as a byte array in little endian. /// /// See [`from_bits`](Self::from_bits) for some discussion of the /// portability of this operation (there are almost no issues). @@ -1388,7 +1392,7 @@ impl f32 { Self::from_bits(u32::from_le_bytes(bytes)) } - /// Create a floating point value from its representation as a byte array in native endian. + /// Creates a floating point value from its representation as a byte array in native endian. /// /// As the target platform's native endianness is used, portable code /// likely wants to use [`from_be_bytes`] or [`from_le_bytes`], as @@ -1418,7 +1422,7 @@ impl f32 { Self::from_bits(u32::from_ne_bytes(bytes)) } - /// Return the ordering between `self` and `other`. + /// Returns the ordering between `self` and `other`. /// /// Unlike the standard partial comparison between floating point numbers, /// this comparison always produces an ordering in accordance to diff --git a/library/core/src/num/f64.rs b/library/core/src/num/f64.rs index f8e4555fc44f2..5d33eea6d011f 100644 --- a/library/core/src/num/f64.rs +++ b/library/core/src/num/f64.rs @@ -711,11 +711,13 @@ impl f64 { } /// Returns `true` if `self` has a positive sign, including `+0.0`, NaNs with - /// positive sign bit and positive infinity. Note that IEEE 754 doesn't assign any - /// meaning to the sign bit in case of a NaN, and as Rust doesn't guarantee that - /// the bit pattern of NaNs are conserved over arithmetic operations, the result of - /// `is_sign_positive` on a NaN might produce an unexpected result in some cases. - /// See [explanation of NaN as a special value](f32) for more info. + /// positive sign bit and positive infinity. + /// + /// Note that IEEE 754 doesn't assign any meaning to the sign bit in case of + /// a NaN, and as Rust doesn't guarantee that the bit pattern of NaNs are + /// conserved over arithmetic operations, the result of `is_sign_positive` on + /// a NaN might produce an unexpected result in some cases. See [explanation + /// of NaN as a special value](f32) for more info. /// /// ``` /// let f = 7.0_f64; @@ -742,11 +744,13 @@ impl f64 { } /// Returns `true` if `self` has a negative sign, including `-0.0`, NaNs with - /// negative sign bit and negative infinity. Note that IEEE 754 doesn't assign any - /// meaning to the sign bit in case of a NaN, and as Rust doesn't guarantee that - /// the bit pattern of NaNs are conserved over arithmetic operations, the result of - /// `is_sign_negative` on a NaN might produce an unexpected result in some cases. - /// See [explanation of NaN as a special value](f32) for more info. + /// negative sign bit and negative infinity. + /// + /// Note that IEEE 754 doesn't assign any meaning to the sign bit in case of + /// a NaN, and as Rust doesn't guarantee that the bit pattern of NaNs are + /// conserved over arithmetic operations, the result of `is_sign_negative` on + /// a NaN might produce an unexpected result in some cases. See [explanation + /// of NaN as a special value](f32) for more info. /// /// ``` /// let f = 7.0_f64; @@ -1252,7 +1256,7 @@ impl f64 { intrinsics::const_eval_select((v,), ct_u64_to_f64, rt_u64_to_f64) } - /// Return the memory representation of this floating point number as a byte array in + /// Returns the memory representation of this floating point number as a byte array in /// big-endian (network) byte order. /// /// See [`from_bits`](Self::from_bits) for some discussion of the @@ -1273,7 +1277,7 @@ impl f64 { self.to_bits().to_be_bytes() } - /// Return the memory representation of this floating point number as a byte array in + /// Returns the memory representation of this floating point number as a byte array in /// little-endian byte order. /// /// See [`from_bits`](Self::from_bits) for some discussion of the @@ -1294,7 +1298,7 @@ impl f64 { self.to_bits().to_le_bytes() } - /// Return the memory representation of this floating point number as a byte array in + /// Returns the memory representation of this floating point number as a byte array in /// native byte order. /// /// As the target platform's native endianness is used, portable code @@ -1328,7 +1332,7 @@ impl f64 { self.to_bits().to_ne_bytes() } - /// Create a floating point value from its representation as a byte array in big endian. + /// Creates a floating point value from its representation as a byte array in big endian. /// /// See [`from_bits`](Self::from_bits) for some discussion of the /// portability of this operation (there are almost no issues). @@ -1347,7 +1351,7 @@ impl f64 { Self::from_bits(u64::from_be_bytes(bytes)) } - /// Create a floating point value from its representation as a byte array in little endian. + /// Creates a floating point value from its representation as a byte array in little endian. /// /// See [`from_bits`](Self::from_bits) for some discussion of the /// portability of this operation (there are almost no issues). @@ -1366,7 +1370,7 @@ impl f64 { Self::from_bits(u64::from_le_bytes(bytes)) } - /// Create a floating point value from its representation as a byte array in native endian. + /// Creates a floating point value from its representation as a byte array in native endian. /// /// As the target platform's native endianness is used, portable code /// likely wants to use [`from_be_bytes`] or [`from_le_bytes`], as @@ -1396,7 +1400,7 @@ impl f64 { Self::from_bits(u64::from_ne_bytes(bytes)) } - /// Return the ordering between `self` and `other`. + /// Returns the ordering between `self` and `other`. /// /// Unlike the standard partial comparison between floating point numbers, /// this comparison always produces an ordering in accordance to diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs index d40e02352a1d0..dd88e859b30e7 100644 --- a/library/core/src/num/int_macros.rs +++ b/library/core/src/num/int_macros.rs @@ -1223,6 +1223,7 @@ macro_rules! int_impl { /// ``` #[doc = concat!("assert_eq!(0x1", stringify!($SelfT), ".checked_shl(4), Some(0x10));")] #[doc = concat!("assert_eq!(0x1", stringify!($SelfT), ".checked_shl(129), None);")] + #[doc = concat!("assert_eq!(0x10", stringify!($SelfT), ".checked_shl(", stringify!($BITS_MINUS_ONE), "), Some(0));")] /// ``` #[stable(feature = "wrapping", since = "1.7.0")] #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")] @@ -2196,10 +2197,11 @@ macro_rules! int_impl { acc.wrapping_mul(base) } - /// Calculates `self` + `rhs` + /// Calculates `self` + `rhs`. /// - /// Returns a tuple of the addition along with a boolean indicating whether an arithmetic overflow would - /// occur. If an overflow would have occurred then the wrapped value is returned. + /// Returns a tuple of the addition along with a boolean indicating + /// whether an arithmetic overflow would occur. If an overflow would have + /// occurred then the wrapped value is returned. /// /// # Examples /// @@ -2277,7 +2279,7 @@ macro_rules! int_impl { (c, b != d) } - /// Calculates `self` + `rhs` with an unsigned `rhs` + /// Calculates `self` + `rhs` with an unsigned `rhs`. /// /// Returns a tuple of the addition along with a boolean indicating /// whether an arithmetic overflow would occur. If an overflow would @@ -2600,6 +2602,7 @@ macro_rules! int_impl { /// ``` #[doc = concat!("assert_eq!(0x1", stringify!($SelfT),".overflowing_shl(4), (0x10, false));")] /// assert_eq!(0x1i32.overflowing_shl(36), (0x10, true)); + #[doc = concat!("assert_eq!(0x10", stringify!($SelfT), ".overflowing_shl(", stringify!($BITS_MINUS_ONE), "), (0, false));")] /// ``` #[stable(feature = "wrapping", since = "1.7.0")] #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] @@ -3389,7 +3392,7 @@ macro_rules! int_impl { #[inline(always)] pub const fn is_negative(self) -> bool { self < 0 } - /// Return the memory representation of this integer as a byte array in + /// Returns the memory representation of this integer as a byte array in /// big-endian (network) byte order. /// #[doc = $to_xe_bytes_doc] @@ -3409,7 +3412,7 @@ macro_rules! int_impl { self.to_be().to_ne_bytes() } - /// Return the memory representation of this integer as a byte array in + /// Returns the memory representation of this integer as a byte array in /// little-endian byte order. /// #[doc = $to_xe_bytes_doc] @@ -3429,7 +3432,7 @@ macro_rules! int_impl { self.to_le().to_ne_bytes() } - /// Return the memory representation of this integer as a byte array in + /// Returns the memory representation of this integer as a byte array in /// native byte order. /// /// As the target platform's native endianness is used, portable code @@ -3467,7 +3470,7 @@ macro_rules! int_impl { unsafe { mem::transmute(self) } } - /// Create an integer value from its representation as a byte array in + /// Creates an integer value from its representation as a byte array in /// big endian. /// #[doc = $from_xe_bytes_doc] @@ -3496,7 +3499,7 @@ macro_rules! int_impl { Self::from_be(Self::from_ne_bytes(bytes)) } - /// Create an integer value from its representation as a byte array in + /// Creates an integer value from its representation as a byte array in /// little endian. /// #[doc = $from_xe_bytes_doc] @@ -3525,7 +3528,7 @@ macro_rules! int_impl { Self::from_le(Self::from_ne_bytes(bytes)) } - /// Create an integer value from its memory representation as a byte + /// Creates an integer value from its memory representation as a byte /// array in native endianness. /// /// As the target platform's native endianness is used, portable code diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs index 4e8e0ecdde998..e342a73d1aee4 100644 --- a/library/core/src/num/mod.rs +++ b/library/core/src/num/mod.rs @@ -483,6 +483,7 @@ impl u8 { ActualT = u8, SignedT = i8, BITS = 8, + BITS_MINUS_ONE = 7, MAX = 255, rot = 2, rot_op = "0x82", @@ -1097,6 +1098,7 @@ impl u16 { ActualT = u16, SignedT = i16, BITS = 16, + BITS_MINUS_ONE = 15, MAX = 65535, rot = 4, rot_op = "0xa003", @@ -1145,6 +1147,7 @@ impl u32 { ActualT = u32, SignedT = i32, BITS = 32, + BITS_MINUS_ONE = 31, MAX = 4294967295, rot = 8, rot_op = "0x10000b3", @@ -1168,6 +1171,7 @@ impl u64 { ActualT = u64, SignedT = i64, BITS = 64, + BITS_MINUS_ONE = 63, MAX = 18446744073709551615, rot = 12, rot_op = "0xaa00000000006e1", @@ -1191,6 +1195,7 @@ impl u128 { ActualT = u128, SignedT = i128, BITS = 128, + BITS_MINUS_ONE = 127, MAX = 340282366920938463463374607431768211455, rot = 16, rot_op = "0x13f40000000000000000000000004f76", @@ -1216,6 +1221,7 @@ impl usize { ActualT = u16, SignedT = isize, BITS = 16, + BITS_MINUS_ONE = 15, MAX = 65535, rot = 4, rot_op = "0xa003", @@ -1240,6 +1246,7 @@ impl usize { ActualT = u32, SignedT = isize, BITS = 32, + BITS_MINUS_ONE = 31, MAX = 4294967295, rot = 8, rot_op = "0x10000b3", @@ -1264,6 +1271,7 @@ impl usize { ActualT = u64, SignedT = isize, BITS = 64, + BITS_MINUS_ONE = 63, MAX = 18446744073709551615, rot = 12, rot_op = "0xaa00000000006e1", @@ -1386,6 +1394,7 @@ from_str_radix_int_impl! { isize i8 i16 i32 i64 i128 usize u8 u16 u32 u64 u128 } #[doc(hidden)] #[inline(always)] #[unstable(issue = "none", feature = "std_internals")] +#[rustc_const_stable(feature = "const_int_from_str", since = "CURRENT_RUSTC_VERSION")] pub const fn can_not_overflow(radix: u32, is_signed_ty: bool, digits: &[u8]) -> bool { radix <= 16 && digits.len() <= mem::size_of::() * 2 - is_signed_ty as usize } @@ -1435,7 +1444,7 @@ macro_rules! from_str_radix { #[doc = concat!("assert_eq!(", stringify!($int_ty), "::from_str_radix(\"A\", 16), Ok(10));")] /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_int_from_str", issue = "59133")] + #[rustc_const_stable(feature = "const_int_from_str", since = "CURRENT_RUSTC_VERSION")] pub const fn from_str_radix(src: &str, radix: u32) -> Result<$int_ty, ParseIntError> { use self::IntErrorKind::*; use self::ParseIntError as PIE; @@ -1565,7 +1574,7 @@ macro_rules! from_str_radix_size_impl { #[doc = concat!("assert_eq!(", stringify!($size), "::from_str_radix(\"A\", 16), Ok(10));")] /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_int_from_str", issue = "59133")] + #[rustc_const_stable(feature = "const_int_from_str", since = "CURRENT_RUSTC_VERSION")] pub const fn from_str_radix(src: &str, radix: u32) -> Result<$size, ParseIntError> { match <$t>::from_str_radix(src, radix) { Ok(x) => Ok(x as $size), diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs index d80d3241b1eee..64985e216c451 100644 --- a/library/core/src/num/nonzero.rs +++ b/library/core/src/num/nonzero.rs @@ -455,6 +455,12 @@ macro_rules! nonzero_integer { UnsignedPrimitive = $Uint:ty, // Used in doc comments. + rot = $rot:literal, + rot_op = $rot_op:literal, + rot_result = $rot_result:literal, + swap_op = $swap_op:literal, + swapped = $swapped:literal, + reversed = $reversed:literal, leading_zeros_test = $leading_zeros_test:expr, ) => { /// An integer that is known not to equal zero. @@ -604,6 +610,270 @@ macro_rules! nonzero_integer { unsafe { NonZero::new_unchecked(self.get().count_ones()) } } + /// Shifts the bits to the left by a specified amount, `n`, + /// wrapping the truncated bits to the end of the resulting integer. + /// + /// Please note this isn't the same operation as the `<<` shifting operator! + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(nonzero_bitwise)] + /// # use std::num::NonZero; + /// # + /// # fn main() { test().unwrap(); } + /// # fn test() -> Option<()> { + #[doc = concat!("let n = NonZero::new(", $rot_op, stringify!($Int), ")?;")] + #[doc = concat!("let m = NonZero::new(", $rot_result, ")?;")] + /// + #[doc = concat!("assert_eq!(n.rotate_left(", $rot, "), m);")] + /// # Some(()) + /// # } + /// ``` + #[unstable(feature = "nonzero_bitwise", issue = "128281")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline(always)] + pub const fn rotate_left(self, n: u32) -> Self { + let result = self.get().rotate_left(n); + // SAFETY: Rotating bits preserves the property int > 0. + unsafe { Self::new_unchecked(result) } + } + + /// Shifts the bits to the right by a specified amount, `n`, + /// wrapping the truncated bits to the beginning of the resulting + /// integer. + /// + /// Please note this isn't the same operation as the `>>` shifting operator! + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(nonzero_bitwise)] + /// # use std::num::NonZero; + /// # + /// # fn main() { test().unwrap(); } + /// # fn test() -> Option<()> { + #[doc = concat!("let n = NonZero::new(", $rot_result, stringify!($Int), ")?;")] + #[doc = concat!("let m = NonZero::new(", $rot_op, ")?;")] + /// + #[doc = concat!("assert_eq!(n.rotate_right(", $rot, "), m);")] + /// # Some(()) + /// # } + /// ``` + #[unstable(feature = "nonzero_bitwise", issue = "128281")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline(always)] + pub const fn rotate_right(self, n: u32) -> Self { + let result = self.get().rotate_right(n); + // SAFETY: Rotating bits preserves the property int > 0. + unsafe { Self::new_unchecked(result) } + } + + /// Reverses the byte order of the integer. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(nonzero_bitwise)] + /// # use std::num::NonZero; + /// # + /// # fn main() { test().unwrap(); } + /// # fn test() -> Option<()> { + #[doc = concat!("let n = NonZero::new(", $swap_op, stringify!($Int), ")?;")] + /// let m = n.swap_bytes(); + /// + #[doc = concat!("assert_eq!(m, NonZero::new(", $swapped, ")?);")] + /// # Some(()) + /// # } + /// ``` + #[unstable(feature = "nonzero_bitwise", issue = "128281")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline(always)] + pub const fn swap_bytes(self) -> Self { + let result = self.get().swap_bytes(); + // SAFETY: Shuffling bytes preserves the property int > 0. + unsafe { Self::new_unchecked(result) } + } + + /// Reverses the order of bits in the integer. The least significant bit becomes the most significant bit, + /// second least-significant bit becomes second most-significant bit, etc. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(nonzero_bitwise)] + /// # use std::num::NonZero; + /// # + /// # fn main() { test().unwrap(); } + /// # fn test() -> Option<()> { + #[doc = concat!("let n = NonZero::new(", $swap_op, stringify!($Int), ")?;")] + /// let m = n.reverse_bits(); + /// + #[doc = concat!("assert_eq!(m, NonZero::new(", $reversed, ")?);")] + /// # Some(()) + /// # } + /// ``` + #[unstable(feature = "nonzero_bitwise", issue = "128281")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline(always)] + pub const fn reverse_bits(self) -> Self { + let result = self.get().reverse_bits(); + // SAFETY: Reversing bits preserves the property int > 0. + unsafe { Self::new_unchecked(result) } + } + + /// Converts an integer from big endian to the target's endianness. + /// + /// On big endian this is a no-op. On little endian the bytes are + /// swapped. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(nonzero_bitwise)] + /// # use std::num::NonZero; + #[doc = concat!("use std::num::", stringify!($Ty), ";")] + /// # + /// # fn main() { test().unwrap(); } + /// # fn test() -> Option<()> { + #[doc = concat!("let n = NonZero::new(0x1A", stringify!($Int), ")?;")] + /// + /// if cfg!(target_endian = "big") { + #[doc = concat!(" assert_eq!(", stringify!($Ty), "::from_be(n), n)")] + /// } else { + #[doc = concat!(" assert_eq!(", stringify!($Ty), "::from_be(n), n.swap_bytes())")] + /// } + /// # Some(()) + /// # } + /// ``` + #[unstable(feature = "nonzero_bitwise", issue = "128281")] + #[must_use] + #[inline(always)] + pub const fn from_be(x: Self) -> Self { + let result = $Int::from_be(x.get()); + // SAFETY: Shuffling bytes preserves the property int > 0. + unsafe { Self::new_unchecked(result) } + } + + /// Converts an integer from little endian to the target's endianness. + /// + /// On little endian this is a no-op. On big endian the bytes are + /// swapped. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(nonzero_bitwise)] + /// # use std::num::NonZero; + #[doc = concat!("use std::num::", stringify!($Ty), ";")] + /// # + /// # fn main() { test().unwrap(); } + /// # fn test() -> Option<()> { + #[doc = concat!("let n = NonZero::new(0x1A", stringify!($Int), ")?;")] + /// + /// if cfg!(target_endian = "little") { + #[doc = concat!(" assert_eq!(", stringify!($Ty), "::from_le(n), n)")] + /// } else { + #[doc = concat!(" assert_eq!(", stringify!($Ty), "::from_le(n), n.swap_bytes())")] + /// } + /// # Some(()) + /// # } + /// ``` + #[unstable(feature = "nonzero_bitwise", issue = "128281")] + #[must_use] + #[inline(always)] + pub const fn from_le(x: Self) -> Self { + let result = $Int::from_le(x.get()); + // SAFETY: Shuffling bytes preserves the property int > 0. + unsafe { Self::new_unchecked(result) } + } + + /// Converts `self` to big endian from the target's endianness. + /// + /// On big endian this is a no-op. On little endian the bytes are + /// swapped. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(nonzero_bitwise)] + /// # use std::num::NonZero; + /// # + /// # fn main() { test().unwrap(); } + /// # fn test() -> Option<()> { + #[doc = concat!("let n = NonZero::new(0x1A", stringify!($Int), ")?;")] + /// + /// if cfg!(target_endian = "big") { + /// assert_eq!(n.to_be(), n) + /// } else { + /// assert_eq!(n.to_be(), n.swap_bytes()) + /// } + /// # Some(()) + /// # } + /// ``` + #[unstable(feature = "nonzero_bitwise", issue = "128281")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline(always)] + pub const fn to_be(self) -> Self { + let result = self.get().to_be(); + // SAFETY: Shuffling bytes preserves the property int > 0. + unsafe { Self::new_unchecked(result) } + } + + /// Converts `self` to little endian from the target's endianness. + /// + /// On little endian this is a no-op. On big endian the bytes are + /// swapped. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(nonzero_bitwise)] + /// # use std::num::NonZero; + /// # + /// # fn main() { test().unwrap(); } + /// # fn test() -> Option<()> { + #[doc = concat!("let n = NonZero::new(0x1A", stringify!($Int), ")?;")] + /// + /// if cfg!(target_endian = "little") { + /// assert_eq!(n.to_le(), n) + /// } else { + /// assert_eq!(n.to_le(), n.swap_bytes()) + /// } + /// # Some(()) + /// # } + /// ``` + #[unstable(feature = "nonzero_bitwise", issue = "128281")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline(always)] + pub const fn to_le(self) -> Self { + let result = self.get().to_le(); + // SAFETY: Shuffling bytes preserves the property int > 0. + unsafe { Self::new_unchecked(result) } + } + nonzero_integer_signedness_dependent_methods! { Primitive = $signedness $Int, UnsignedPrimitive = $Uint, @@ -826,22 +1096,54 @@ macro_rules! nonzero_integer { nonzero_integer_signedness_dependent_impls!($signedness $Int); }; - (Self = $Ty:ident, Primitive = unsigned $Int:ident $(,)?) => { + ( + Self = $Ty:ident, + Primitive = unsigned $Int:ident, + rot = $rot:literal, + rot_op = $rot_op:literal, + rot_result = $rot_result:literal, + swap_op = $swap_op:literal, + swapped = $swapped:literal, + reversed = $reversed:literal, + $(,)? + ) => { nonzero_integer! { #[stable(feature = "nonzero", since = "1.28.0")] Self = $Ty, Primitive = unsigned $Int, UnsignedPrimitive = $Int, + rot = $rot, + rot_op = $rot_op, + rot_result = $rot_result, + swap_op = $swap_op, + swapped = $swapped, + reversed = $reversed, leading_zeros_test = concat!(stringify!($Int), "::MAX"), } }; - (Self = $Ty:ident, Primitive = signed $Int:ident, $($rest:tt)*) => { + ( + Self = $Ty:ident, + Primitive = signed $Int:ident, + UnsignedPrimitive = $UInt:ident, + rot = $rot:literal, + rot_op = $rot_op:literal, + rot_result = $rot_result:literal, + swap_op = $swap_op:literal, + swapped = $swapped:literal, + reversed = $reversed:literal, + ) => { nonzero_integer! { #[stable(feature = "signed_nonzero", since = "1.34.0")] Self = $Ty, Primitive = signed $Int, - $($rest)* + UnsignedPrimitive = $UInt, + rot = $rot, + rot_op = $rot_op, + rot_result = $rot_result, + swap_op = $swap_op, + swapped = $swapped, + reversed = $reversed, leading_zeros_test = concat!("-1", stringify!($Int)), } }; @@ -1241,6 +1543,7 @@ macro_rules! nonzero_integer_signedness_dependent_methods { /// assert_eq!(ten.isqrt(), three); /// # Some(()) /// # } + /// ``` #[unstable(feature = "isqrt", issue = "116226")] #[rustc_const_unstable(feature = "isqrt", issue = "116226")] #[must_use = "this returns the result of the operation, \ @@ -1704,65 +2007,189 @@ macro_rules! sign_dependent_expr { nonzero_integer! { Self = NonZeroU8, Primitive = unsigned u8, + rot = 2, + rot_op = "0x82", + rot_result = "0xa", + swap_op = "0x12", + swapped = "0x12", + reversed = "0x48", } nonzero_integer! { Self = NonZeroU16, Primitive = unsigned u16, + rot = 4, + rot_op = "0xa003", + rot_result = "0x3a", + swap_op = "0x1234", + swapped = "0x3412", + reversed = "0x2c48", } nonzero_integer! { Self = NonZeroU32, Primitive = unsigned u32, + rot = 8, + rot_op = "0x10000b3", + rot_result = "0xb301", + swap_op = "0x12345678", + swapped = "0x78563412", + reversed = "0x1e6a2c48", } nonzero_integer! { Self = NonZeroU64, Primitive = unsigned u64, + rot = 12, + rot_op = "0xaa00000000006e1", + rot_result = "0x6e10aa", + swap_op = "0x1234567890123456", + swapped = "0x5634129078563412", + reversed = "0x6a2c48091e6a2c48", } nonzero_integer! { Self = NonZeroU128, Primitive = unsigned u128, + rot = 16, + rot_op = "0x13f40000000000000000000000004f76", + rot_result = "0x4f7613f4", + swap_op = "0x12345678901234567890123456789012", + swapped = "0x12907856341290785634129078563412", + reversed = "0x48091e6a2c48091e6a2c48091e6a2c48", +} + +#[cfg(target_pointer_width = "16")] +nonzero_integer! { + Self = NonZeroUsize, + Primitive = unsigned usize, + rot = 4, + rot_op = "0xa003", + rot_result = "0x3a", + swap_op = "0x1234", + swapped = "0x3412", + reversed = "0x2c48", } +#[cfg(target_pointer_width = "32")] nonzero_integer! { Self = NonZeroUsize, Primitive = unsigned usize, + rot = 8, + rot_op = "0x10000b3", + rot_result = "0xb301", + swap_op = "0x12345678", + swapped = "0x78563412", + reversed = "0x1e6a2c48", +} + +#[cfg(target_pointer_width = "64")] +nonzero_integer! { + Self = NonZeroUsize, + Primitive = unsigned usize, + rot = 12, + rot_op = "0xaa00000000006e1", + rot_result = "0x6e10aa", + swap_op = "0x1234567890123456", + swapped = "0x5634129078563412", + reversed = "0x6a2c48091e6a2c48", } nonzero_integer! { Self = NonZeroI8, Primitive = signed i8, UnsignedPrimitive = u8, + rot = 2, + rot_op = "-0x7e", + rot_result = "0xa", + swap_op = "0x12", + swapped = "0x12", + reversed = "0x48", } nonzero_integer! { Self = NonZeroI16, Primitive = signed i16, UnsignedPrimitive = u16, + rot = 4, + rot_op = "-0x5ffd", + rot_result = "0x3a", + swap_op = "0x1234", + swapped = "0x3412", + reversed = "0x2c48", } nonzero_integer! { Self = NonZeroI32, Primitive = signed i32, UnsignedPrimitive = u32, + rot = 8, + rot_op = "0x10000b3", + rot_result = "0xb301", + swap_op = "0x12345678", + swapped = "0x78563412", + reversed = "0x1e6a2c48", } nonzero_integer! { Self = NonZeroI64, Primitive = signed i64, UnsignedPrimitive = u64, + rot = 12, + rot_op = "0xaa00000000006e1", + rot_result = "0x6e10aa", + swap_op = "0x1234567890123456", + swapped = "0x5634129078563412", + reversed = "0x6a2c48091e6a2c48", } nonzero_integer! { Self = NonZeroI128, Primitive = signed i128, UnsignedPrimitive = u128, + rot = 16, + rot_op = "0x13f40000000000000000000000004f76", + rot_result = "0x4f7613f4", + swap_op = "0x12345678901234567890123456789012", + swapped = "0x12907856341290785634129078563412", + reversed = "0x48091e6a2c48091e6a2c48091e6a2c48", +} + +#[cfg(target_pointer_width = "16")] +nonzero_integer! { + Self = NonZeroIsize, + Primitive = signed isize, + UnsignedPrimitive = usize, + rot = 4, + rot_op = "-0x5ffd", + rot_result = "0x3a", + swap_op = "0x1234", + swapped = "0x3412", + reversed = "0x2c48", +} + +#[cfg(target_pointer_width = "32")] +nonzero_integer! { + Self = NonZeroIsize, + Primitive = signed isize, + UnsignedPrimitive = usize, + rot = 8, + rot_op = "0x10000b3", + rot_result = "0xb301", + swap_op = "0x12345678", + swapped = "0x78563412", + reversed = "0x1e6a2c48", } +#[cfg(target_pointer_width = "64")] nonzero_integer! { Self = NonZeroIsize, Primitive = signed isize, UnsignedPrimitive = usize, + rot = 12, + rot_op = "0xaa00000000006e1", + rot_result = "0x6e10aa", + swap_op = "0x1234567890123456", + swapped = "0x5634129078563412", + reversed = "0x6a2c48091e6a2c48", } diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs index e6bdc4d450d4a..a2e17fae76873 100644 --- a/library/core/src/num/uint_macros.rs +++ b/library/core/src/num/uint_macros.rs @@ -9,6 +9,7 @@ macro_rules! uint_impl { // literal is fine if they need to be multiple code tokens. // In non-comments, use the associated constants rather than these. BITS = $BITS:literal, + BITS_MINUS_ONE = $BITS_MINUS_ONE:literal, MAX = $MaxV:literal, rot = $rot:literal, rot_op = $rot_op:literal, @@ -949,10 +950,10 @@ macro_rules! uint_impl { } /// Strict integer division. Computes `self / rhs`. - /// Strict division on unsigned types is just normal division. - /// There's no way overflow could ever happen. - /// This function exists, so that all operations - /// are accounted for in the strict operations. + /// + /// Strict division on unsigned types is just normal division. There's no + /// way overflow could ever happen. This function exists so that all + /// operations are accounted for in the strict operations. /// /// # Panics /// @@ -1008,12 +1009,11 @@ macro_rules! uint_impl { } /// Strict Euclidean division. Computes `self.div_euclid(rhs)`. - /// Strict division on unsigned types is just normal division. - /// There's no way overflow could ever happen. - /// This function exists, so that all operations - /// are accounted for in the strict operations. - /// Since, for the positive integers, all common - /// definitions of division are equal, this + /// + /// Strict division on unsigned types is just normal division. There's no + /// way overflow could ever happen. This function exists so that all + /// operations are accounted for in the strict operations. Since, for the + /// positive integers, all common definitions of division are equal, this /// is exactly equal to `self.strict_div(rhs)`. /// /// # Panics @@ -1071,11 +1071,11 @@ macro_rules! uint_impl { } /// Strict integer remainder. Computes `self % rhs`. - /// Strict remainder calculation on unsigned types is - /// just the regular remainder calculation. - /// There's no way overflow could ever happen. - /// This function exists, so that all operations - /// are accounted for in the strict operations. + /// + /// Strict remainder calculation on unsigned types is just the regular + /// remainder calculation. There's no way overflow could ever happen. + /// This function exists so that all operations are accounted for in the + /// strict operations. /// /// # Panics /// @@ -1131,14 +1131,13 @@ macro_rules! uint_impl { } /// Strict Euclidean modulo. Computes `self.rem_euclid(rhs)`. - /// Strict modulo calculation on unsigned types is - /// just the regular remainder calculation. - /// There's no way overflow could ever happen. - /// This function exists, so that all operations - /// are accounted for in the strict operations. - /// Since, for the positive integers, all common - /// definitions of division are equal, this - /// is exactly equal to `self.strict_rem(rhs)`. + /// + /// Strict modulo calculation on unsigned types is just the regular + /// remainder calculation. There's no way overflow could ever happen. + /// This function exists so that all operations are accounted for in the + /// strict operations. Since, for the positive integers, all common + /// definitions of division are equal, this is exactly equal to + /// `self.strict_rem(rhs)`. /// /// # Panics /// @@ -1413,6 +1412,7 @@ macro_rules! uint_impl { /// ``` #[doc = concat!("assert_eq!(0x1", stringify!($SelfT), ".checked_shl(4), Some(0x10));")] #[doc = concat!("assert_eq!(0x10", stringify!($SelfT), ".checked_shl(129), None);")] + #[doc = concat!("assert_eq!(0x10", stringify!($SelfT), ".checked_shl(", stringify!($BITS_MINUS_ONE), "), Some(0));")] /// ``` #[stable(feature = "wrapping", since = "1.7.0")] #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")] @@ -1914,10 +1914,10 @@ macro_rules! uint_impl { } /// Wrapping (modular) division. Computes `self / rhs`. - /// Wrapped division on unsigned types is just normal division. - /// There's no way wrapping could ever happen. - /// This function exists, so that all operations - /// are accounted for in the wrapping operations. + /// + /// Wrapped division on unsigned types is just normal division. There's + /// no way wrapping could ever happen. This function exists so that all + /// operations are accounted for in the wrapping operations. /// /// # Panics /// @@ -1941,13 +1941,12 @@ macro_rules! uint_impl { } /// Wrapping Euclidean division. Computes `self.div_euclid(rhs)`. - /// Wrapped division on unsigned types is just normal division. - /// There's no way wrapping could ever happen. - /// This function exists, so that all operations - /// are accounted for in the wrapping operations. - /// Since, for the positive integers, all common - /// definitions of division are equal, this - /// is exactly equal to `self.wrapping_div(rhs)`. + /// + /// Wrapped division on unsigned types is just normal division. There's + /// no way wrapping could ever happen. This function exists so that all + /// operations are accounted for in the wrapping operations. Since, for + /// the positive integers, all common definitions of division are equal, + /// this is exactly equal to `self.wrapping_div(rhs)`. /// /// # Panics /// @@ -1971,11 +1970,11 @@ macro_rules! uint_impl { } /// Wrapping (modular) remainder. Computes `self % rhs`. - /// Wrapped remainder calculation on unsigned types is - /// just the regular remainder calculation. - /// There's no way wrapping could ever happen. - /// This function exists, so that all operations - /// are accounted for in the wrapping operations. + /// + /// Wrapped remainder calculation on unsigned types is just the regular + /// remainder calculation. There's no way wrapping could ever happen. + /// This function exists so that all operations are accounted for in the + /// wrapping operations. /// /// # Panics /// @@ -1999,14 +1998,13 @@ macro_rules! uint_impl { } /// Wrapping Euclidean modulo. Computes `self.rem_euclid(rhs)`. - /// Wrapped modulo calculation on unsigned types is - /// just the regular remainder calculation. - /// There's no way wrapping could ever happen. - /// This function exists, so that all operations - /// are accounted for in the wrapping operations. - /// Since, for the positive integers, all common - /// definitions of division are equal, this - /// is exactly equal to `self.wrapping_rem(rhs)`. + /// + /// Wrapped modulo calculation on unsigned types is just the regular + /// remainder calculation. There's no way wrapping could ever happen. + /// This function exists so that all operations are accounted for in the + /// wrapping operations. Since, for the positive integers, all common + /// definitions of division are equal, this is exactly equal to + /// `self.wrapping_rem(rhs)`. /// /// # Panics /// @@ -2162,7 +2160,7 @@ macro_rules! uint_impl { acc.wrapping_mul(base) } - /// Calculates `self` + `rhs` + /// Calculates `self` + `rhs`. /// /// Returns a tuple of the addition along with a boolean indicating /// whether an arithmetic overflow would occur. If an overflow would @@ -2236,7 +2234,7 @@ macro_rules! uint_impl { (c, b || d) } - /// Calculates `self` + `rhs` with a signed `rhs` + /// Calculates `self` + `rhs` with a signed `rhs`. /// /// Returns a tuple of the addition along with a boolean indicating /// whether an arithmetic overflow would occur. If an overflow would @@ -2541,6 +2539,7 @@ macro_rules! uint_impl { /// ``` #[doc = concat!("assert_eq!(0x1", stringify!($SelfT), ".overflowing_shl(4), (0x10, false));")] #[doc = concat!("assert_eq!(0x1", stringify!($SelfT), ".overflowing_shl(132), (0x10, true));")] + #[doc = concat!("assert_eq!(0x10", stringify!($SelfT), ".overflowing_shl(", stringify!($BITS_MINUS_ONE), "), (0, false));")] /// ``` #[stable(feature = "wrapping", since = "1.7.0")] #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")] @@ -2854,6 +2853,35 @@ macro_rules! uint_impl { } } + /// Returns `true` if `self` is an integer multiple of `rhs`, and false otherwise. + /// + /// This function is equivalent to `self % rhs == 0`, except that it will not panic + /// for `rhs == 0`. Instead, `0.is_multiple_of(0) == true`, and for any non-zero `n`, + /// `n.is_multiple_of(0) == false`. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(unsigned_is_multiple_of)] + #[doc = concat!("assert!(6_", stringify!($SelfT), ".is_multiple_of(2));")] + #[doc = concat!("assert!(!5_", stringify!($SelfT), ".is_multiple_of(2));")] + /// + #[doc = concat!("assert!(0_", stringify!($SelfT), ".is_multiple_of(0));")] + #[doc = concat!("assert!(!6_", stringify!($SelfT), ".is_multiple_of(0));")] + /// ``` + #[unstable(feature = "unsigned_is_multiple_of", issue = "128101")] + #[must_use] + #[inline] + #[rustc_inherit_overflow_checks] + pub const fn is_multiple_of(self, rhs: Self) -> bool { + match rhs { + 0 => self == 0, + _ => self % rhs == 0, + } + } + /// Returns `true` if and only if `self == 2^k` for some `k`. /// /// # Examples @@ -2967,7 +2995,7 @@ macro_rules! uint_impl { self.one_less_than_next_power_of_two().wrapping_add(1) } - /// Return the memory representation of this integer as a byte array in + /// Returns the memory representation of this integer as a byte array in /// big-endian (network) byte order. /// #[doc = $to_xe_bytes_doc] @@ -2987,7 +3015,7 @@ macro_rules! uint_impl { self.to_be().to_ne_bytes() } - /// Return the memory representation of this integer as a byte array in + /// Returns the memory representation of this integer as a byte array in /// little-endian byte order. /// #[doc = $to_xe_bytes_doc] @@ -3007,7 +3035,7 @@ macro_rules! uint_impl { self.to_le().to_ne_bytes() } - /// Return the memory representation of this integer as a byte array in + /// Returns the memory representation of this integer as a byte array in /// native byte order. /// /// As the target platform's native endianness is used, portable code @@ -3045,7 +3073,7 @@ macro_rules! uint_impl { unsafe { mem::transmute(self) } } - /// Create a native endian integer value from its representation + /// Creates a native endian integer value from its representation /// as a byte array in big endian. /// #[doc = $from_xe_bytes_doc] @@ -3074,7 +3102,7 @@ macro_rules! uint_impl { Self::from_be(Self::from_ne_bytes(bytes)) } - /// Create a native endian integer value from its representation + /// Creates a native endian integer value from its representation /// as a byte array in little endian. /// #[doc = $from_xe_bytes_doc] @@ -3103,7 +3131,7 @@ macro_rules! uint_impl { Self::from_le(Self::from_ne_bytes(bytes)) } - /// Create a native endian integer value from its memory representation + /// Creates a native endian integer value from its memory representation /// as a byte array in native endianness. /// /// As the target platform's native endianness is used, portable code diff --git a/library/core/src/ops/control_flow.rs b/library/core/src/ops/control_flow.rs index e10c438ef4300..a2709c66b06ad 100644 --- a/library/core/src/ops/control_flow.rs +++ b/library/core/src/ops/control_flow.rs @@ -238,7 +238,7 @@ impl ControlFlow { /// They have mediocre names and non-obvious semantics, so aren't /// currently on a path to potential stabilization. impl ControlFlow { - /// Create a `ControlFlow` from any type implementing `Try`. + /// Creates a `ControlFlow` from any type implementing `Try`. #[inline] pub(crate) fn from_try(r: R) -> Self { match R::branch(r) { @@ -247,7 +247,7 @@ impl ControlFlow { } } - /// Convert a `ControlFlow` into any type implementing `Try`; + /// Converts a `ControlFlow` into any type implementing `Try`. #[inline] pub(crate) fn into_try(self) -> R { match self { diff --git a/library/core/src/panic.rs b/library/core/src/panic.rs index 37c338dd9b778..03123450f766e 100644 --- a/library/core/src/panic.rs +++ b/library/core/src/panic.rs @@ -160,7 +160,7 @@ pub unsafe trait PanicPayload: crate::fmt::Display { /// Just borrow the contents. fn get(&mut self) -> &(dyn Any + Send); - /// Try to borrow the contents as `&str`, if possible without doing any allocations. + /// Tries to borrow the contents as `&str`, if possible without doing any allocations. fn as_str(&mut self) -> Option<&str> { None } diff --git a/library/core/src/panic/panic_info.rs b/library/core/src/panic/panic_info.rs index 6bbb9c3017110..961ff6e091695 100644 --- a/library/core/src/panic/panic_info.rs +++ b/library/core/src/panic/panic_info.rs @@ -152,7 +152,7 @@ impl Display for PanicInfo<'_> { } impl<'a> PanicMessage<'a> { - /// Get the formatted message, if it has no arguments to be formatted at runtime. + /// Gets the formatted message, if it has no arguments to be formatted at runtime. /// /// This can be used to avoid allocations in some cases. /// diff --git a/library/core/src/panicking.rs b/library/core/src/panicking.rs index 97fb1d6b7323f..7affe63825719 100644 --- a/library/core/src/panicking.rs +++ b/library/core/src/panicking.rs @@ -294,10 +294,11 @@ fn panic_misaligned_pointer_dereference(required: usize, found: usize) -> ! { ) } -/// Panic because we cannot unwind out of a function. +/// Panics because we cannot unwind out of a function. /// /// This is a separate function to avoid the codesize impact of each crate containing the string to /// pass to `panic_nounwind`. +/// /// This function is called directly by the codegen backend, and must not have /// any extra arguments (including those synthesized by track_caller). #[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)] @@ -309,10 +310,11 @@ fn panic_cannot_unwind() -> ! { panic_nounwind("panic in a function that cannot unwind") } -/// Panic because we are unwinding out of a destructor during cleanup. +/// Panics because we are unwinding out of a destructor during cleanup. /// /// This is a separate function to avoid the codesize impact of each crate containing the string to /// pass to `panic_nounwind`. +/// /// This function is called directly by the codegen backend, and must not have /// any extra arguments (including those synthesized by track_caller). #[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)] diff --git a/library/core/src/pin.rs b/library/core/src/pin.rs index 0d2aa3070a19f..18e1f753defae 100644 --- a/library/core/src/pin.rs +++ b/library/core/src/pin.rs @@ -421,7 +421,7 @@ //! } //! //! impl Unmovable { -//! /// Create a new `Unmovable`. +//! /// Creates a new `Unmovable`. //! /// //! /// To ensure the data doesn't move we place it on the heap behind a pinning Box. //! /// Note that the data is pinned, but the `Pin>` which is pinning it can @@ -1168,7 +1168,7 @@ impl> Hash for Pin { } impl> Pin { - /// Construct a new `Pin` around a pointer to some data of a type that + /// Constructs a new `Pin` around a pointer to some data of a type that /// implements [`Unpin`]. /// /// Unlike `Pin::new_unchecked`, this method is safe because the pointer @@ -1223,7 +1223,7 @@ impl> Pin { } impl Pin { - /// Construct a new `Pin` around a reference to some data of a type that + /// Constructs a new `Pin` around a reference to some data of a type that /// may or may not implement [`Unpin`]. /// /// If `pointer` dereferences to an [`Unpin`] type, [`Pin::new`] should be used @@ -1569,7 +1569,7 @@ impl<'a, T: ?Sized> Pin<&'a mut T> { self.__pointer } - /// Construct a new pin by mapping the interior value. + /// Constructs a new pin by mapping the interior value. /// /// For example, if you wanted to get a `Pin` of a field of something, /// you could use this to get access to that field in one line of code. @@ -1602,7 +1602,7 @@ impl<'a, T: ?Sized> Pin<&'a mut T> { } impl Pin<&'static T> { - /// Get a pinning reference from a `&'static` reference. + /// Gets a pinning reference from a `&'static` reference. /// /// This is safe because `T` is borrowed immutably for the `'static` lifetime, which /// never ends. @@ -1639,8 +1639,8 @@ impl<'a, Ptr: DerefMut> Pin<&'a mut Pin> { // // We need to ensure that two things hold for that to be the case: // - // 1) Once we give out a `Pin<&mut Ptr::Target>`, an `&mut Ptr::Target` will not be given out. - // 2) By giving out a `Pin<&mut Ptr::Target>`, we do not risk of violating + // 1) Once we give out a `Pin<&mut Ptr::Target>`, a `&mut Ptr::Target` will not be given out. + // 2) By giving out a `Pin<&mut Ptr::Target>`, we do not risk violating // `Pin<&mut Pin>` // // The existence of `Pin` is sufficient to guarantee #1: since we already have a @@ -1656,7 +1656,7 @@ impl<'a, Ptr: DerefMut> Pin<&'a mut Pin> { } impl Pin<&'static mut T> { - /// Get a pinning mutable reference from a static mutable reference. + /// Gets a pinning mutable reference from a static mutable reference. /// /// This is safe because `T` is borrowed for the `'static` lifetime, which /// never ends. diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs index 3e7933e9eec86..93bbd92593f2c 100644 --- a/library/core/src/ptr/const_ptr.rs +++ b/library/core/src/ptr/const_ptr.rs @@ -61,7 +61,7 @@ impl *const T { self as _ } - /// Use the pointer value in a new pointer of another type. + /// Uses the pointer value in a new pointer of another type. /// /// In case `meta` is a (fat) pointer to an unsized type, this operation /// will ignore the pointer part, whereas for (thin) pointers to sized diff --git a/library/core/src/ptr/metadata.rs b/library/core/src/ptr/metadata.rs index 06f205c0f2670..84accc3e466d5 100644 --- a/library/core/src/ptr/metadata.rs +++ b/library/core/src/ptr/metadata.rs @@ -81,7 +81,7 @@ pub trait Pointee { // NOTE: don’t stabilize this before trait aliases are stable in the language? pub trait Thin = Pointee; -/// Extract the metadata component of a pointer. +/// Extracts the metadata component of a pointer. /// /// Values of type `*mut T`, `&T`, or `&mut T` can be passed directly to this function /// as they implicitly coerce to `*const T`. diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs index f2247e83ec5c5..da6b541a98700 100644 --- a/library/core/src/ptr/mod.rs +++ b/library/core/src/ptr/mod.rs @@ -196,9 +196,9 @@ //! * The **provenance** it has, defining the memory it has permission to access. //! Provenance can be absent, in which case the pointer does not have permission to access any memory. //! -//! Under Strict Provenance, a usize *cannot* accurately represent a pointer, and converting from -//! a pointer to a usize is generally an operation which *only* extracts the address. It is -//! therefore *impossible* to construct a valid pointer from a usize because there is no way +//! Under Strict Provenance, a `usize` *cannot* accurately represent a pointer, and converting from +//! a pointer to a `usize` is generally an operation which *only* extracts the address. It is +//! therefore *impossible* to construct a valid pointer from a `usize` because there is no way //! to restore the address-space and provenance. In other words, pointer-integer-pointer //! roundtrips are not possible (in the sense that the resulting pointer is not dereferenceable). //! @@ -234,16 +234,16 @@ //! //! Most code needs no changes to conform to strict provenance, as the only really concerning //! operation that *wasn't* obviously already Undefined Behaviour is casts from usize to a -//! pointer. For code which *does* cast a usize to a pointer, the scope of the change depends +//! pointer. For code which *does* cast a `usize` to a pointer, the scope of the change depends //! on exactly what you're doing. //! -//! In general, you just need to make sure that if you want to convert a usize address to a +//! In general, you just need to make sure that if you want to convert a `usize` address to a //! pointer and then use that pointer to read/write memory, you need to keep around a pointer //! that has sufficient provenance to perform that read/write itself. In this way all of your //! casts from an address to a pointer are essentially just applying offsets/indexing. //! //! This is generally trivial to do for simple cases like tagged pointers *as long as you -//! represent the tagged pointer as an actual pointer and not a usize*. For instance: +//! represent the tagged pointer as an actual pointer and not a `usize`*. For instance: //! //! ``` //! #![feature(strict_provenance)] @@ -606,7 +606,7 @@ pub const fn null_mut() -> *mut T { /// Without provenance, this pointer is not associated with any actual allocation. Such a /// no-provenance pointer may be used for zero-sized memory accesses (if suitably aligned), but /// non-zero-sized memory accesses with a no-provenance pointer are UB. No-provenance pointers are -/// little more than a usize address in disguise. +/// little more than a `usize` address in disguise. /// /// This is different from `addr as *const T`, which creates a pointer that picks up a previously /// exposed provenance. See [`with_exposed_provenance`] for more details on that operation. @@ -650,7 +650,7 @@ pub const fn dangling() -> *const T { /// Without provenance, this pointer is not associated with any actual allocation. Such a /// no-provenance pointer may be used for zero-sized memory accesses (if suitably aligned), but /// non-zero-sized memory accesses with a no-provenance pointer are UB. No-provenance pointers are -/// little more than a usize address in disguise. +/// little more than a `usize` address in disguise. /// /// This is different from `addr as *mut T`, which creates a pointer that picks up a previously /// exposed provenance. See [`with_exposed_provenance_mut`] for more details on that operation. @@ -687,7 +687,7 @@ pub const fn dangling_mut() -> *mut T { without_provenance_mut(mem::align_of::()) } -/// Convert an address back to a pointer, picking up a previously 'exposed' provenance. +/// Converts an address back to a pointer, picking up a previously 'exposed' provenance. /// /// This is a more rigorously specified alternative to `addr as *const T`. The provenance of the /// returned pointer is that of *any* pointer that was previously exposed by passing it to @@ -735,7 +735,7 @@ where addr as *const T } -/// Convert an address back to a mutable pointer, picking up a previously 'exposed' provenance. +/// Converts an address back to a mutable pointer, picking up a previously 'exposed' provenance. /// /// This is a more rigorously specified alternative to `addr as *mut T`. The provenance of the /// returned pointer is that of *any* pointer that was previously passed to @@ -775,10 +775,53 @@ where addr as *mut T } -/// Convert a reference to a raw pointer. +/// Converts a reference to a raw pointer. /// -/// This is equivalent to `r as *const T`, but is a bit safer since it will never silently change -/// type or mutability, in particular if the code is refactored. +/// For `r: &T`, `from_ref(r)` is equivalent to `r as *const T` (except for the caveat noted below), +/// but is a bit safer since it will never silently change type or mutability, in particular if the +/// code is refactored. +/// +/// The caller must ensure that the pointee outlives the pointer this function returns, or else it +/// will end up dangling. +/// +/// The caller must also ensure that the memory the pointer (non-transitively) points to is never +/// written to (except inside an `UnsafeCell`) using this pointer or any pointer derived from it. If +/// you need to mutate the pointee, use [`from_mut`]`. Specifically, to turn a mutable reference `m: +/// &mut T` into `*const T`, prefer `from_mut(m).cast_const()` to obtain a pointer that can later be +/// used for mutation. +/// +/// ## Interaction with lifetime extension +/// +/// Note that this has subtle interactions with the rules for lifetime extension of temporaries in +/// tail expressions. This code is valid, albeit in a non-obvious way: +/// ```rust +/// # type T = i32; +/// # fn foo() -> T { 42 } +/// // The temporary holding the return value of `foo` has its lifetime extended, +/// // because the surrounding expression involves no function call. +/// let p = &foo() as *const T; +/// unsafe { p.read() }; +/// ``` +/// Naively replacing the cast with `from_ref` is not valid: +/// ```rust,no_run +/// # use std::ptr; +/// # type T = i32; +/// # fn foo() -> T { 42 } +/// // The temporary holding the return value of `foo` does *not* have its lifetime extended, +/// // because the surrounding expression involves no function call. +/// let p = ptr::from_ref(&foo()); +/// unsafe { p.read() }; // UB! Reading from a dangling pointer ⚠️ +/// ``` +/// The recommended way to write this code is to avoid relying on lifetime extension +/// when raw pointers are involved: +/// ```rust +/// # use std::ptr; +/// # type T = i32; +/// # fn foo() -> T { 42 } +/// let x = foo(); +/// let p = ptr::from_ref(&x); +/// unsafe { p.read() }; +/// ``` #[inline(always)] #[must_use] #[stable(feature = "ptr_from_ref", since = "1.76.0")] @@ -789,10 +832,47 @@ pub const fn from_ref(r: &T) -> *const T { r } -/// Convert a mutable reference to a raw pointer. +/// Converts a mutable reference to a raw pointer. /// -/// This is equivalent to `r as *mut T`, but is a bit safer since it will never silently change -/// type or mutability, in particular if the code is refactored. +/// For `r: &mut T`, `from_mut(r)` is equivalent to `r as *mut T` (except for the caveat noted +/// below), but is a bit safer since it will never silently change type or mutability, in particular +/// if the code is refactored. +/// +/// The caller must ensure that the pointee outlives the pointer this function returns, or else it +/// will end up dangling. +/// +/// ## Interaction with lifetime extension +/// +/// Note that this has subtle interactions with the rules for lifetime extension of temporaries in +/// tail expressions. This code is valid, albeit in a non-obvious way: +/// ```rust +/// # type T = i32; +/// # fn foo() -> T { 42 } +/// // The temporary holding the return value of `foo` has its lifetime extended, +/// // because the surrounding expression involves no function call. +/// let p = &mut foo() as *mut T; +/// unsafe { p.write(T::default()) }; +/// ``` +/// Naively replacing the cast with `from_mut` is not valid: +/// ```rust,no_run +/// # use std::ptr; +/// # type T = i32; +/// # fn foo() -> T { 42 } +/// // The temporary holding the return value of `foo` does *not* have its lifetime extended, +/// // because the surrounding expression involves no function call. +/// let p = ptr::from_mut(&mut foo()); +/// unsafe { p.write(T::default()) }; // UB! Writing to a dangling pointer ⚠️ +/// ``` +/// The recommended way to write this code is to avoid relying on lifetime extension +/// when raw pointers are involved: +/// ```rust +/// # use std::ptr; +/// # type T = i32; +/// # fn foo() -> T { 42 } +/// let mut x = foo(); +/// let p = ptr::from_mut(&mut x); +/// unsafe { p.write(T::default()) }; +/// ``` #[inline(always)] #[must_use] #[stable(feature = "ptr_from_ref", since = "1.76.0")] @@ -1388,7 +1468,7 @@ pub const unsafe fn read(src: *const T) -> T { /// /// # Examples /// -/// Read a usize value from a byte buffer: +/// Read a `usize` value from a byte buffer: /// /// ``` /// use std::mem; @@ -1599,7 +1679,7 @@ pub const unsafe fn write(dst: *mut T, src: T) { /// /// # Examples /// -/// Write a usize value to a byte buffer: +/// Write a `usize` value to a byte buffer: /// /// ``` /// use std::mem; @@ -1934,7 +2014,7 @@ pub(crate) const unsafe fn align_offset(p: *const T, a: usize) -> usiz let y = cttz_nonzero(a); if x < y { x } else { y } }; - // SAFETY: gcdpow has an upper-bound that’s at most the number of bits in a usize. + // SAFETY: gcdpow has an upper-bound that’s at most the number of bits in a `usize`. let gcd = unsafe { unchecked_shl(1usize, gcdpow) }; // SAFETY: gcd is always greater or equal to 1. if addr & unsafe { unchecked_sub(gcd, 1) } == 0 { @@ -2133,7 +2213,7 @@ impl fmt::Debug for F { } } -/// Create a `const` raw pointer to a place, without creating an intermediate reference. +/// Creates a `const` raw pointer to a place, without creating an intermediate reference. /// /// Creating a reference with `&`/`&mut` is only allowed if the pointer is properly aligned /// and points to initialized data. For cases where those requirements do not hold, @@ -2207,7 +2287,7 @@ pub macro addr_of($place:expr) { &raw const $place } -/// Create a `mut` raw pointer to a place, without creating an intermediate reference. +/// Creates a `mut` raw pointer to a place, without creating an intermediate reference. /// /// Creating a reference with `&`/`&mut` is only allowed if the pointer is properly aligned /// and points to initialized data. For cases where those requirements do not hold, diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index 904d6c62dcf1e..bcf9b889182c7 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -60,7 +60,7 @@ impl *mut T { self as _ } - /// Use the pointer value in a new pointer of another type. + /// Uses the pointer value in a new pointer of another type. /// /// In case `meta` is a (fat) pointer to an unsized type, this operation /// will ignore the pointer part, whereas for (thin) pointers to sized diff --git a/library/core/src/range.rs b/library/core/src/range.rs index bfbbf123b1ca5..93400e9b9f071 100644 --- a/library/core/src/range.rs +++ b/library/core/src/range.rs @@ -72,7 +72,7 @@ impl fmt::Debug for Range { } impl Range { - /// Create an iterator over the elements within this range. + /// Creates an iterator over the elements within this range. /// /// Shorthand for `.clone().into_iter()` /// @@ -292,7 +292,7 @@ impl> RangeInclusive { } impl RangeInclusive { - /// Create an iterator over the elements within this range. + /// Creates an iterator over the elements within this range. /// /// Shorthand for `.clone().into_iter()` /// @@ -408,7 +408,7 @@ impl fmt::Debug for RangeFrom { } impl RangeFrom { - /// Create an iterator over the elements within this range. + /// Creates an iterator over the elements within this range. /// /// Shorthand for `.clone().into_iter()` /// diff --git a/library/core/src/slice/index.rs b/library/core/src/slice/index.rs index 2624a44bb4bcb..1591aaf52e592 100644 --- a/library/core/src/slice/index.rs +++ b/library/core/src/slice/index.rs @@ -214,6 +214,7 @@ pub unsafe trait SliceIndex: private_slice_index::Sealed { /// Returns a pointer to the output at this location, without /// performing any bounds checking. + /// /// Calling this method with an out-of-bounds index or a dangling `slice` pointer /// is *[undefined behavior]* even if the resulting pointer is not used. /// @@ -223,6 +224,7 @@ pub unsafe trait SliceIndex: private_slice_index::Sealed { /// Returns a mutable pointer to the output at this location, without /// performing any bounds checking. + /// /// Calling this method with an out-of-bounds index or a dangling `slice` pointer /// is *[undefined behavior]* even if the resulting pointer is not used. /// @@ -802,13 +804,13 @@ unsafe impl SliceIndex<[T]> for ops::RangeToInclusive { } } -/// Performs bounds-checking of a range. +/// Performs bounds checking of a range. /// /// This method is similar to [`Index::index`] for slices, but it returns a /// [`Range`] equivalent to `range`. You can use this method to turn any range /// into `start` and `end` values. /// -/// `bounds` is the range of the slice to use for bounds-checking. It should +/// `bounds` is the range of the slice to use for bounds checking. It should /// be a [`RangeTo`] range that ends at the length of the slice. /// /// The returned [`Range`] is safe to pass to [`slice::get_unchecked`] and @@ -898,7 +900,7 @@ where ops::Range { start, end } } -/// Performs bounds-checking of a range without panicking. +/// Performs bounds checking of a range without panicking. /// /// This is a version of [`range()`] that returns [`None`] instead of panicking. /// @@ -951,7 +953,8 @@ where if start > end || end > len { None } else { Some(ops::Range { start, end }) } } -/// Convert pair of `ops::Bound`s into `ops::Range` without performing any bounds checking and (in debug) overflow checking +/// Converts a pair of `ops::Bound`s into `ops::Range` without performing any +/// bounds checking or (in debug) overflow checking. pub(crate) fn into_range_unchecked( len: usize, (start, end): (ops::Bound, ops::Bound), @@ -970,7 +973,7 @@ pub(crate) fn into_range_unchecked( start..end } -/// Convert pair of `ops::Bound`s into `ops::Range`. +/// Converts pair of `ops::Bound`s into `ops::Range`. /// Returns `None` on overflowing indices. pub(crate) fn into_range( len: usize, @@ -995,7 +998,7 @@ pub(crate) fn into_range( Some(start..end) } -/// Convert pair of `ops::Bound`s into `ops::Range`. +/// Converts pair of `ops::Bound`s into `ops::Range`. /// Panics on overflowing indices. pub(crate) fn into_slice_range( len: usize, diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 6d3e625bef428..5f75e1944122d 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -321,7 +321,7 @@ impl [T] { if let [.., last] = self { Some(last) } else { None } } - /// Return an array reference to the first `N` items in the slice. + /// Returns an array reference to the first `N` items in the slice. /// /// If the slice is not at least `N` in length, this will return `None`. /// @@ -350,7 +350,7 @@ impl [T] { } } - /// Return a mutable array reference to the first `N` items in the slice. + /// Returns a mutable array reference to the first `N` items in the slice. /// /// If the slice is not at least `N` in length, this will return `None`. /// @@ -381,7 +381,7 @@ impl [T] { } } - /// Return an array reference to the first `N` items in the slice and the remaining slice. + /// Returns an array reference to the first `N` items in the slice and the remaining slice. /// /// If the slice is not at least `N` in length, this will return `None`. /// @@ -413,7 +413,7 @@ impl [T] { } } - /// Return a mutable array reference to the first `N` items in the slice and the remaining + /// Returns a mutable array reference to the first `N` items in the slice and the remaining /// slice. /// /// If the slice is not at least `N` in length, this will return `None`. @@ -451,7 +451,7 @@ impl [T] { } } - /// Return an array reference to the last `N` items in the slice and the remaining slice. + /// Returns an array reference to the last `N` items in the slice and the remaining slice. /// /// If the slice is not at least `N` in length, this will return `None`. /// @@ -483,7 +483,7 @@ impl [T] { } } - /// Return a mutable array reference to the last `N` items in the slice and the remaining + /// Returns a mutable array reference to the last `N` items in the slice and the remaining /// slice. /// /// If the slice is not at least `N` in length, this will return `None`. @@ -521,7 +521,7 @@ impl [T] { } } - /// Return an array reference to the last `N` items in the slice. + /// Returns an array reference to the last `N` items in the slice. /// /// If the slice is not at least `N` in length, this will return `None`. /// @@ -554,7 +554,7 @@ impl [T] { } } - /// Return a mutable array reference to the last `N` items in the slice. + /// Returns a mutable array reference to the last `N` items in the slice. /// /// If the slice is not at least `N` in length, this will return `None`. /// @@ -726,7 +726,7 @@ impl [T] { /// Returns a raw pointer to the slice's buffer. /// /// The caller must ensure that the slice outlives the pointer this - /// function returns, or else it will end up pointing to garbage. + /// function returns, or else it will end up dangling. /// /// The caller must also ensure that the memory the pointer (non-transitively) points to /// is never written to (except inside an `UnsafeCell`) using this pointer or any pointer @@ -761,7 +761,7 @@ impl [T] { /// Returns an unsafe mutable pointer to the slice's buffer. /// /// The caller must ensure that the slice outlives the pointer this - /// function returns, or else it will end up pointing to garbage. + /// function returns, or else it will end up dangling. /// /// Modifying the container referenced by this slice may cause its buffer /// to be reallocated, which would also make any pointers to it invalid. @@ -828,7 +828,7 @@ impl [T] { // - Both pointers are part of the same object, as pointing directly // past the object also counts. // - // - The size of the slice is never larger than isize::MAX bytes, as + // - The size of the slice is never larger than `isize::MAX` bytes, as // noted here: // - https://github.com/rust-lang/unsafe-code-guidelines/issues/102#issuecomment-473340447 // - https://doc.rust-lang.org/reference/behavior-considered-undefined.html @@ -839,7 +839,7 @@ impl [T] { // - There is no wrapping around involved, as slices do not wrap past // the end of the address space. // - // See the documentation of pointer::add. + // See the documentation of [`pointer::add`]. let end = unsafe { start.add(self.len()) }; start..end } @@ -3021,7 +3021,7 @@ impl [T] { sort::unstable::sort(self, &mut |a, b| f(a).lt(&f(b))); } - /// Reorder the slice such that the element at `index` after the reordering is at its final + /// Reorders the slice such that the element at `index` after the reordering is at its final /// sorted position. /// /// This reordering has the additional property that any value at position `i < index` will be @@ -3082,7 +3082,7 @@ impl [T] { sort::select::partition_at_index(self, index, T::lt) } - /// Reorder the slice with a comparator function such that the element at `index` after the + /// Reorders the slice with a comparator function such that the element at `index` after the /// reordering is at its final sorted position. /// /// This reordering has the additional property that any value at position `i < index` will be @@ -3147,7 +3147,7 @@ impl [T] { sort::select::partition_at_index(self, index, |a: &T, b: &T| compare(a, b) == Less) } - /// Reorder the slice with a key extraction function such that the element at `index` after the + /// Reorders the slice with a key extraction function such that the element at `index` after the /// reordering is at its final sorted position. /// /// This reordering has the additional property that any value at position `i < index` will be @@ -3405,8 +3405,10 @@ impl [T] { /// Rotates the slice in-place such that the first `mid` elements of the /// slice move to the end while the last `self.len() - mid` elements move to - /// the front. After calling `rotate_left`, the element previously at index - /// `mid` will become the first element in the slice. + /// the front. + /// + /// After calling `rotate_left`, the element previously at index `mid` will + /// become the first element in the slice. /// /// # Panics /// @@ -3448,8 +3450,10 @@ impl [T] { /// Rotates the slice in-place such that the first `self.len() - k` /// elements of the slice move to the end while the last `k` elements move - /// to the front. After calling `rotate_right`, the element previously at - /// index `self.len() - k` will become the first element in the slice. + /// to the front. + /// + /// After calling `rotate_right`, the element previously at index `self.len() + /// - k` will become the first element in the slice. /// /// # Panics /// @@ -3819,7 +3823,7 @@ impl [T] { (us_len, ts_len) } - /// Transmute the slice to a slice of another type, ensuring alignment of the types is + /// Transmutes the slice to a slice of another type, ensuring alignment of the types is /// maintained. /// /// This method splits the slice into three distinct slices: prefix, correctly aligned middle @@ -3884,7 +3888,7 @@ impl [T] { } } - /// Transmute the mutable slice to a mutable slice of another type, ensuring alignment of the + /// Transmutes the mutable slice to a mutable slice of another type, ensuring alignment of the /// types is maintained. /// /// This method splits the slice into three distinct slices: prefix, correctly aligned middle @@ -3957,7 +3961,7 @@ impl [T] { } } - /// Split a slice into a prefix, a middle of aligned SIMD types, and a suffix. + /// Splits a slice into a prefix, a middle of aligned SIMD types, and a suffix. /// /// This is a safe wrapper around [`slice::align_to`], so inherits the same /// guarantees as that method. @@ -4021,7 +4025,7 @@ impl [T] { unsafe { self.align_to() } } - /// Split a mutable slice into a mutable prefix, a middle of aligned SIMD types, + /// Splits a mutable slice into a mutable prefix, a middle of aligned SIMD types, /// and a mutable suffix. /// /// This is a safe wrapper around [`slice::align_to_mut`], so inherits the same @@ -4069,7 +4073,6 @@ impl [T] { /// # Examples /// /// ``` - /// #![feature(is_sorted)] /// let empty: [i32; 0] = []; /// /// assert!([1, 2, 2, 9].is_sorted()); @@ -4079,7 +4082,7 @@ impl [T] { /// assert!(![0.0, 1.0, f32::NAN].is_sorted()); /// ``` #[inline] - #[unstable(feature = "is_sorted", reason = "new API", issue = "53485")] + #[stable(feature = "is_sorted", since = "CURRENT_RUSTC_VERSION")] #[must_use] pub fn is_sorted(&self) -> bool where @@ -4096,8 +4099,6 @@ impl [T] { /// # Examples /// /// ``` - /// #![feature(is_sorted)] - /// /// assert!([1, 2, 2, 9].is_sorted_by(|a, b| a <= b)); /// assert!(![1, 2, 2, 9].is_sorted_by(|a, b| a < b)); /// @@ -4108,7 +4109,7 @@ impl [T] { /// assert!(empty.is_sorted_by(|a, b| false)); /// assert!(empty.is_sorted_by(|a, b| true)); /// ``` - #[unstable(feature = "is_sorted", reason = "new API", issue = "53485")] + #[stable(feature = "is_sorted", since = "CURRENT_RUSTC_VERSION")] #[must_use] pub fn is_sorted_by<'a, F>(&'a self, mut compare: F) -> bool where @@ -4128,13 +4129,11 @@ impl [T] { /// # Examples /// /// ``` - /// #![feature(is_sorted)] - /// /// assert!(["c", "bb", "aaa"].is_sorted_by_key(|s| s.len())); /// assert!(![-2i32, -1, 0, 3].is_sorted_by_key(|n| n.abs())); /// ``` #[inline] - #[unstable(feature = "is_sorted", reason = "new API", issue = "53485")] + #[stable(feature = "is_sorted", since = "CURRENT_RUSTC_VERSION")] #[must_use] pub fn is_sorted_by_key<'a, F, K>(&'a self, f: F) -> bool where diff --git a/library/core/src/slice/sort/select.rs b/library/core/src/slice/sort/select.rs index 6212def30416b..efda993a10353 100644 --- a/library/core/src/slice/sort/select.rs +++ b/library/core/src/slice/sort/select.rs @@ -12,7 +12,7 @@ use crate::slice::sort::shared::pivot::choose_pivot; use crate::slice::sort::shared::smallsort::insertion_sort_shift_left; use crate::slice::sort::unstable::quicksort::partition; -/// Reorder the slice such that the element at `index` is at its final sorted position. +/// Reorders the slice such that the element at `index` is at its final sorted position. pub(crate) fn partition_at_index( v: &mut [T], index: usize, diff --git a/library/core/src/slice/sort/stable/drift.rs b/library/core/src/slice/sort/stable/drift.rs index 2d9c4ac9fcf7c..73dc40cafcf83 100644 --- a/library/core/src/slice/sort/stable/drift.rs +++ b/library/core/src/slice/sort/stable/drift.rs @@ -273,7 +273,7 @@ fn stable_quicksort bool>( } /// Compactly stores the length of a run, and whether or not it is sorted. This -/// can always fit in a usize because the maximum slice length is isize::MAX. +/// can always fit in a `usize` because the maximum slice length is [`isize::MAX`]. #[derive(Copy, Clone)] struct DriftsortRun(usize); diff --git a/library/core/src/slice/sort/stable/quicksort.rs b/library/core/src/slice/sort/stable/quicksort.rs index 181fe603d2325..164314991d0f3 100644 --- a/library/core/src/slice/sort/stable/quicksort.rs +++ b/library/core/src/slice/sort/stable/quicksort.rs @@ -196,7 +196,8 @@ struct PartitionState { impl PartitionState { /// # Safety - /// scan and scratch must point to valid disjoint buffers of length len. The + /// + /// `scan` and `scratch` must point to valid disjoint buffers of length `len`. The /// scan buffer must be initialized. unsafe fn new(scan: *const T, scratch: *mut T, len: usize) -> Self { // SAFETY: See function safety comment. @@ -208,6 +209,7 @@ impl PartitionState { /// branchless core of the partition. /// /// # Safety + /// /// This function may be called at most `len` times. If it is called exactly /// `len` times the scratch buffer then contains a copy of each element from /// the scan buffer exactly once - a permutation, and num_left <= len. diff --git a/library/core/src/str/converts.rs b/library/core/src/str/converts.rs index 397759bd5cae7..b35216eee7b7f 100644 --- a/library/core/src/str/converts.rs +++ b/library/core/src/str/converts.rs @@ -206,7 +206,7 @@ pub const unsafe fn from_utf8_unchecked_mut(v: &mut [u8]) -> &mut str { unsafe { &mut *(v as *mut [u8] as *mut str) } } -/// Creates an `&str` from a pointer and a length. +/// Creates a `&str` from a pointer and a length. /// /// The pointed-to bytes must be valid UTF-8. /// If this might not be the case, use `str::from_utf8(slice::from_raw_parts(ptr, len))`, @@ -225,7 +225,7 @@ pub const unsafe fn from_raw_parts<'a>(ptr: *const u8, len: usize) -> &'a str { unsafe { &*ptr::from_raw_parts(ptr, len) } } -/// Creates an `&mut str` from a pointer and a length. +/// Creates a `&mut str` from a pointer and a length. /// /// The pointed-to bytes must be valid UTF-8. /// If this might not be the case, use `str::from_utf8_mut(slice::from_raw_parts_mut(ptr, len))`, diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs index 6cd029f743639..d861fb2075f53 100644 --- a/library/core/src/str/mod.rs +++ b/library/core/src/str/mod.rs @@ -592,6 +592,7 @@ impl str { /// Creates a string slice from another string slice, bypassing safety /// checks. + /// /// This is generally not recommended, use with caution! For a safe /// alternative see [`str`] and [`IndexMut`]. /// @@ -623,7 +624,7 @@ impl str { unsafe { &mut *(begin..end).get_unchecked_mut(self) } } - /// Divide one string slice into two at an index. + /// Divides one string slice into two at an index. /// /// The argument, `mid`, should be a byte offset from the start of the /// string. It must also be on the boundary of a UTF-8 code point. @@ -662,7 +663,7 @@ impl str { } } - /// Divide one mutable string slice into two at an index. + /// Divides one mutable string slice into two at an index. /// /// The argument, `mid`, should be a byte offset from the start of the /// string. It must also be on the boundary of a UTF-8 code point. @@ -705,7 +706,7 @@ impl str { } } - /// Divide one string slice into two at an index. + /// Divides one string slice into two at an index. /// /// The argument, `mid`, should be a valid byte offset from the start of the /// string. It must also be on the boundary of a UTF-8 code point. The @@ -744,7 +745,7 @@ impl str { } } - /// Divide one mutable string slice into two at an index. + /// Divides one mutable string slice into two at an index. /// /// The argument, `mid`, should be a valid byte offset from the start of the /// string. It must also be on the boundary of a UTF-8 code point. The @@ -784,7 +785,7 @@ impl str { } } - /// Divide one string slice into two at an index. + /// Divides one string slice into two at an index. /// /// # Safety /// @@ -912,7 +913,7 @@ impl str { CharIndices { front_offset: 0, iter: self.chars() } } - /// An iterator over the bytes of a string slice. + /// Returns an iterator over the bytes of a string slice. /// /// As a string slice consists of a sequence of bytes, we can iterate /// through a string slice by byte. This method returns such an iterator. @@ -1038,7 +1039,7 @@ impl str { SplitAsciiWhitespace { inner } } - /// An iterator over the lines of a string, as string slices. + /// Returns an iterator over the lines of a string, as string slices. /// /// Lines are split at line endings that are either newlines (`\n`) or /// sequences of a carriage return followed by a line feed (`\r\n`). @@ -1089,7 +1090,7 @@ impl str { Lines(self.split_inclusive('\n').map(LinesMap)) } - /// An iterator over the lines of a string. + /// Returns an iterator over the lines of a string. #[stable(feature = "rust1", since = "1.0.0")] #[deprecated(since = "1.4.0", note = "use lines() instead now", suggestion = "lines")] #[inline] @@ -1303,7 +1304,7 @@ impl str { pat.into_searcher(self).next_match_back().map(|(i, _)| i) } - /// An iterator over substrings of this string slice, separated by + /// Returns an iterator over substrings of this string slice, separated by /// characters matched by a pattern. /// /// The [pattern] can be a `&str`, [`char`], a slice of [`char`]s, or a @@ -1428,10 +1429,11 @@ impl str { }) } - /// An iterator over substrings of this string slice, separated by - /// characters matched by a pattern. Differs from the iterator produced by - /// `split` in that `split_inclusive` leaves the matched part as the - /// terminator of the substring. + /// Returns an iterator over substrings of this string slice, separated by + /// characters matched by a pattern. + /// + /// Differs from the iterator produced by `split` in that `split_inclusive` + /// leaves the matched part as the terminator of the substring. /// /// The [pattern] can be a `&str`, [`char`], a slice of [`char`]s, or a /// function or closure that determines if a character matches. @@ -1468,8 +1470,8 @@ impl str { }) } - /// An iterator over substrings of the given string slice, separated by - /// characters matched by a pattern and yielded in reverse order. + /// Returns an iterator over substrings of the given string slice, separated + /// by characters matched by a pattern and yielded in reverse order. /// /// The [pattern] can be a `&str`, [`char`], a slice of [`char`]s, or a /// function or closure that determines if a character matches. @@ -1520,8 +1522,8 @@ impl str { RSplit(self.split(pat).0) } - /// An iterator over substrings of the given string slice, separated by - /// characters matched by a pattern. + /// Returns an iterator over substrings of the given string slice, separated + /// by characters matched by a pattern. /// /// The [pattern] can be a `&str`, [`char`], a slice of [`char`]s, or a /// function or closure that determines if a character matches. @@ -1566,7 +1568,7 @@ impl str { SplitTerminator(SplitInternal { allow_trailing_empty: false, ..self.split(pat).0 }) } - /// An iterator over substrings of `self`, separated by characters + /// Returns an iterator over substrings of `self`, separated by characters /// matched by a pattern and yielded in reverse order. /// /// The [pattern] can be a `&str`, [`char`], a slice of [`char`]s, or a @@ -1615,8 +1617,8 @@ impl str { RSplitTerminator(self.split_terminator(pat).0) } - /// An iterator over substrings of the given string slice, separated by a - /// pattern, restricted to returning at most `n` items. + /// Returns an iterator over substrings of the given string slice, separated + /// by a pattern, restricted to returning at most `n` items. /// /// If `n` substrings are returned, the last substring (the `n`th substring) /// will contain the remainder of the string. @@ -1667,9 +1669,9 @@ impl str { SplitN(SplitNInternal { iter: self.split(pat).0, count: n }) } - /// An iterator over substrings of this string slice, separated by a - /// pattern, starting from the end of the string, restricted to returning - /// at most `n` items. + /// Returns an iterator over substrings of this string slice, separated by a + /// pattern, starting from the end of the string, restricted to returning at + /// most `n` items. /// /// If `n` substrings are returned, the last substring (the `n`th substring) /// will contain the remainder of the string. @@ -1759,8 +1761,8 @@ impl str { unsafe { Some((self.get_unchecked(..start), self.get_unchecked(end..))) } } - /// An iterator over the disjoint matches of a pattern within the given string - /// slice. + /// Returns an iterator over the disjoint matches of a pattern within the + /// given string slice. /// /// The [pattern] can be a `&str`, [`char`], a slice of [`char`]s, or a /// function or closure that determines if a character matches. @@ -1794,8 +1796,8 @@ impl str { Matches(MatchesInternal(pat.into_searcher(self))) } - /// An iterator over the disjoint matches of a pattern within this string slice, - /// yielded in reverse order. + /// Returns an iterator over the disjoint matches of a pattern within this + /// string slice, yielded in reverse order. /// /// The [pattern] can be a `&str`, [`char`], a slice of [`char`]s, or a /// function or closure that determines if a character matches. @@ -1831,7 +1833,7 @@ impl str { RMatches(self.matches(pat).0) } - /// An iterator over the disjoint matches of a pattern within this string + /// Returns an iterator over the disjoint matches of a pattern within this string /// slice as well as the index that the match starts at. /// /// For matches of `pat` within `self` that overlap, only the indices @@ -1872,7 +1874,7 @@ impl str { MatchIndices(MatchIndicesInternal(pat.into_searcher(self))) } - /// An iterator over the disjoint matches of a pattern within `self`, + /// Returns an iterator over the disjoint matches of a pattern within `self`, /// yielded in reverse order along with the index of the match. /// /// For matches of `pat` within `self` that overlap, only the indices @@ -2597,7 +2599,7 @@ impl str { unsafe { core::str::from_utf8_unchecked(self.as_bytes().trim_ascii()) } } - /// Return an iterator that escapes each char in `self` with [`char::escape_debug`]. + /// Returns an iterator that escapes each char in `self` with [`char::escape_debug`]. /// /// Note: only extended grapheme codepoints that begin the string will be /// escaped. @@ -2646,7 +2648,7 @@ impl str { } } - /// Return an iterator that escapes each char in `self` with [`char::escape_default`]. + /// Returns an iterator that escapes each char in `self` with [`char::escape_default`]. /// /// # Examples /// @@ -2684,7 +2686,7 @@ impl str { EscapeDefault { inner: self.chars().flat_map(CharEscapeDefault) } } - /// Return an iterator that escapes each char in `self` with [`char::escape_unicode`]. + /// Returns an iterator that escapes each char in `self` with [`char::escape_unicode`]. /// /// # Examples /// diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs index efc07f38f68e0..1769a6dc1012c 100644 --- a/library/core/src/sync/atomic.rs +++ b/library/core/src/sync/atomic.rs @@ -481,7 +481,7 @@ impl AtomicBool { unsafe { &mut *(self.v.get() as *mut bool) } } - /// Get atomic access to a `&mut bool`. + /// Gets atomic access to a `&mut bool`. /// /// # Examples /// @@ -503,7 +503,7 @@ impl AtomicBool { unsafe { &mut *(v as *mut bool as *mut Self) } } - /// Get non-atomic access to a `&mut [AtomicBool]` slice. + /// Gets non-atomic access to a `&mut [AtomicBool]` slice. /// /// This is safe because the mutable reference guarantees that no other threads are /// concurrently accessing the atomic data. @@ -537,7 +537,7 @@ impl AtomicBool { unsafe { &mut *(this as *mut [Self] as *mut [bool]) } } - /// Get atomic access to a `&mut [bool]` slice. + /// Gets atomic access to a `&mut [bool]` slice. /// /// # Examples /// @@ -1276,7 +1276,7 @@ impl AtomicPtr { self.p.get_mut() } - /// Get atomic access to a pointer. + /// Gets atomic access to a pointer. /// /// # Examples /// @@ -1303,7 +1303,7 @@ impl AtomicPtr { unsafe { &mut *(v as *mut *mut T as *mut Self) } } - /// Get non-atomic access to a `&mut [AtomicPtr]` slice. + /// Gets non-atomic access to a `&mut [AtomicPtr]` slice. /// /// This is safe because the mutable reference guarantees that no other threads are /// concurrently accessing the atomic data. @@ -1343,7 +1343,7 @@ impl AtomicPtr { unsafe { &mut *(this as *mut [Self] as *mut [*mut T]) } } - /// Get atomic access to a slice of pointers. + /// Gets atomic access to a slice of pointers. /// /// # Examples /// diff --git a/library/core/src/sync/exclusive.rs b/library/core/src/sync/exclusive.rs index e8170c13ed263..fbf8dafad1869 100644 --- a/library/core/src/sync/exclusive.rs +++ b/library/core/src/sync/exclusive.rs @@ -114,7 +114,7 @@ impl Exclusive { } impl Exclusive { - /// Get exclusive access to the underlying value. + /// Gets exclusive access to the underlying value. #[unstable(feature = "exclusive_wrapper", issue = "98407")] #[must_use] #[inline] @@ -122,7 +122,7 @@ impl Exclusive { &mut self.inner } - /// Get pinned exclusive access to the underlying value. + /// Gets pinned exclusive access to the underlying value. /// /// `Exclusive` is considered to _structurally pin_ the underlying /// value, which means _unpinned_ `Exclusive`s can produce _unpinned_ diff --git a/library/core/src/task/wake.rs b/library/core/src/task/wake.rs index d2b1d74ff6a02..3342fedd926ff 100644 --- a/library/core/src/task/wake.rs +++ b/library/core/src/task/wake.rs @@ -61,7 +61,7 @@ impl RawWaker { RawWaker { data, vtable } } - /// Get the `data` pointer used to create this `RawWaker`. + /// Gets the `data` pointer used to create this `RawWaker`. #[inline] #[must_use] #[unstable(feature = "waker_getters", issue = "96992")] @@ -69,7 +69,7 @@ impl RawWaker { self.data } - /// Get the `vtable` pointer used to create this `RawWaker`. + /// Gets the `vtable` pointer used to create this `RawWaker`. #[inline] #[must_use] #[unstable(feature = "waker_getters", issue = "96992")] @@ -150,7 +150,7 @@ pub struct RawWakerVTable { /// pointer. wake_by_ref: unsafe fn(*const ()), - /// This function gets called when a [`Waker`] gets dropped. + /// This function will be called when a [`Waker`] gets dropped. /// /// The implementation of this function must make sure to release any /// resources that are associated with this instance of a [`RawWaker`] and @@ -203,7 +203,8 @@ impl RawWakerVTable { /// /// # `drop` /// - /// This function gets called when a [`Waker`]/[`LocalWaker`] gets dropped. + /// This function will be called when a [`Waker`]/[`LocalWaker`] gets + /// dropped. /// /// The implementation of this function must make sure to release any /// resources that are associated with this instance of a [`RawWaker`] and @@ -248,9 +249,9 @@ pub struct Context<'a> { } impl<'a> Context<'a> { - /// Create a new `Context` from a [`&Waker`](Waker). + /// Creates a new `Context` from a [`&Waker`](Waker). #[stable(feature = "futures_api", since = "1.36.0")] - #[rustc_const_unstable(feature = "const_waker", issue = "102012")] + #[rustc_const_stable(feature = "const_waker", since = "CURRENT_RUSTC_VERSION")] #[must_use] #[inline] pub const fn from_waker(waker: &'a Waker) -> Self { @@ -261,7 +262,7 @@ impl<'a> Context<'a> { #[inline] #[must_use] #[stable(feature = "futures_api", since = "1.36.0")] - #[rustc_const_unstable(feature = "const_waker", issue = "102012")] + #[rustc_const_stable(feature = "const_waker", since = "CURRENT_RUSTC_VERSION")] pub const fn waker(&self) -> &'a Waker { &self.waker } @@ -269,7 +270,7 @@ impl<'a> Context<'a> { /// Returns a reference to the [`LocalWaker`] for the current task. #[inline] #[unstable(feature = "local_waker", issue = "118959")] - #[rustc_const_unstable(feature = "const_waker", issue = "102012")] + #[rustc_const_unstable(feature = "local_waker", issue = "118959")] pub const fn local_waker(&self) -> &'a LocalWaker { &self.local_waker } @@ -277,7 +278,7 @@ impl<'a> Context<'a> { /// Returns a reference to the extension data for the current task. #[inline] #[unstable(feature = "context_ext", issue = "123392")] - #[rustc_const_unstable(feature = "const_waker", issue = "102012")] + #[rustc_const_unstable(feature = "context_ext", issue = "123392")] pub const fn ext(&mut self) -> &mut dyn Any { // FIXME: this field makes Context extra-weird about unwind safety // can we justify AssertUnwindSafe if we stabilize this? do we care? @@ -334,10 +335,10 @@ pub struct ContextBuilder<'a> { } impl<'a> ContextBuilder<'a> { - /// Create a ContextBuilder from a Waker. + /// Creates a ContextBuilder from a Waker. #[inline] - #[rustc_const_unstable(feature = "const_waker", issue = "102012")] #[unstable(feature = "local_waker", issue = "118959")] + #[rustc_const_stable(feature = "const_waker", since = "CURRENT_RUSTC_VERSION")] pub const fn from_waker(waker: &'a Waker) -> Self { // SAFETY: LocalWaker is just Waker without thread safety let local_waker = unsafe { transmute(waker) }; @@ -350,10 +351,10 @@ impl<'a> ContextBuilder<'a> { } } - /// Create a ContextBuilder from an existing Context. + /// Creates a ContextBuilder from an existing Context. #[inline] - #[rustc_const_unstable(feature = "const_waker", issue = "102012")] #[unstable(feature = "context_ext", issue = "123392")] + #[rustc_const_unstable(feature = "context_ext", issue = "123392")] pub const fn from(cx: &'a mut Context<'_>) -> Self { let ext = match &mut cx.ext.0 { ExtData::Some(ext) => ExtData::Some(*ext), @@ -368,26 +369,26 @@ impl<'a> ContextBuilder<'a> { } } - /// This method is used to set the value for the waker on `Context`. + /// Sets the value for the waker on `Context`. #[inline] #[unstable(feature = "context_ext", issue = "123392")] - #[rustc_const_unstable(feature = "const_waker", issue = "102012")] + #[rustc_const_unstable(feature = "context_ext", issue = "123392")] pub const fn waker(self, waker: &'a Waker) -> Self { Self { waker, ..self } } - /// This method is used to set the value for the local waker on `Context`. + /// Sets the value for the local waker on `Context`. #[inline] #[unstable(feature = "local_waker", issue = "118959")] - #[rustc_const_unstable(feature = "const_waker", issue = "102012")] + #[rustc_const_unstable(feature = "local_waker", issue = "118959")] pub const fn local_waker(self, local_waker: &'a LocalWaker) -> Self { Self { local_waker, ..self } } - /// This method is used to set the value for the extension data on `Context`. + /// Sets the value for the extension data on `Context`. #[inline] #[unstable(feature = "context_ext", issue = "123392")] - #[rustc_const_unstable(feature = "const_waker", issue = "102012")] + #[rustc_const_unstable(feature = "context_ext", issue = "123392")] pub const fn ext(self, data: &'a mut dyn Any) -> Self { Self { ext: ExtData::Some(data), ..self } } @@ -395,7 +396,7 @@ impl<'a> ContextBuilder<'a> { /// Builds the `Context`. #[inline] #[unstable(feature = "local_waker", issue = "118959")] - #[rustc_const_unstable(feature = "const_waker", issue = "102012")] + #[rustc_const_stable(feature = "const_waker", since = "CURRENT_RUSTC_VERSION")] pub const fn build(self) -> Context<'a> { let ContextBuilder { waker, local_waker, ext, _marker, _marker2 } = self; Context { waker, local_waker, ext: AssertUnwindSafe(ext), _marker, _marker2 } @@ -442,7 +443,7 @@ unsafe impl Send for Waker {} unsafe impl Sync for Waker {} impl Waker { - /// Wake up the task associated with this `Waker`. + /// Wakes up the task associated with this `Waker`. /// /// As long as the executor keeps running and the task is not finished, it is /// guaranteed that each invocation of [`wake()`](Self::wake) (or @@ -474,7 +475,7 @@ impl Waker { unsafe { (this.waker.vtable.wake)(this.waker.data) }; } - /// Wake up the task associated with this `Waker` without consuming the `Waker`. + /// Wakes up the task associated with this `Waker` without consuming the `Waker`. /// /// This is similar to [`wake()`](Self::wake), but may be slightly less efficient in /// the case where an owned `Waker` is available. This method should be preferred to @@ -521,7 +522,7 @@ impl Waker { #[inline] #[must_use] #[stable(feature = "futures_api", since = "1.36.0")] - #[rustc_const_unstable(feature = "const_waker", issue = "102012")] + #[rustc_const_stable(feature = "const_waker", since = "CURRENT_RUSTC_VERSION")] pub const unsafe fn from_raw(waker: RawWaker) -> Waker { Waker { waker } } @@ -555,7 +556,7 @@ impl Waker { WAKER } - /// Get a reference to the underlying [`RawWaker`]. + /// Gets a reference to the underlying [`RawWaker`]. #[inline] #[must_use] #[unstable(feature = "waker_getters", issue = "96992")] @@ -701,7 +702,7 @@ pub struct LocalWaker { impl Unpin for LocalWaker {} impl LocalWaker { - /// Wake up the task associated with this `LocalWaker`. + /// Wakes up the task associated with this `LocalWaker`. /// /// As long as the executor keeps running and the task is not finished, it is /// guaranteed that each invocation of [`wake()`](Self::wake) (or @@ -733,7 +734,7 @@ impl LocalWaker { unsafe { (this.waker.vtable.wake)(this.waker.data) }; } - /// Wake up the task associated with this `LocalWaker` without consuming the `LocalWaker`. + /// Wakes up the task associated with this `LocalWaker` without consuming the `LocalWaker`. /// /// This is similar to [`wake()`](Self::wake), but may be slightly less efficient in /// the case where an owned `Waker` is available. This method should be preferred to @@ -772,7 +773,7 @@ impl LocalWaker { #[inline] #[must_use] #[unstable(feature = "local_waker", issue = "118959")] - #[rustc_const_unstable(feature = "const_waker", issue = "102012")] + #[rustc_const_unstable(feature = "local_waker", issue = "118959")] pub const unsafe fn from_raw(waker: RawWaker) -> LocalWaker { Self { waker } } @@ -807,7 +808,7 @@ impl LocalWaker { WAKER } - /// Get a reference to the underlying [`RawWaker`]. + /// Gets a reference to the underlying [`RawWaker`]. #[inline] #[must_use] #[unstable(feature = "waker_getters", issue = "96992")] diff --git a/library/core/src/time.rs b/library/core/src/time.rs index d66f558078ea8..e2693a53bbd8e 100644 --- a/library/core/src/time.rs +++ b/library/core/src/time.rs @@ -1037,7 +1037,7 @@ impl Duration { Duration::from_secs_f32(rhs * self.as_secs_f32()) } - /// Divide `Duration` by `f64`. + /// Divides `Duration` by `f64`. /// /// # Panics /// This method will panic if result is negative, overflows `Duration` or not finite. @@ -1058,7 +1058,7 @@ impl Duration { Duration::from_secs_f64(self.as_secs_f64() / rhs) } - /// Divide `Duration` by `f32`. + /// Divides `Duration` by `f32`. /// /// # Panics /// This method will panic if result is negative, overflows `Duration` or not finite. @@ -1081,7 +1081,7 @@ impl Duration { Duration::from_secs_f32(self.as_secs_f32() / rhs) } - /// Divide `Duration` by `Duration` and return `f64`. + /// Divides `Duration` by `Duration` and returns `f64`. /// /// # Examples /// ``` @@ -1102,7 +1102,7 @@ impl Duration { self_nanos / rhs_nanos } - /// Divide `Duration` by `Duration` and return `f32`. + /// Divides `Duration` by `Duration` and returns `f32`. /// /// # Examples /// ``` diff --git a/library/core/src/ub_checks.rs b/library/core/src/ub_checks.rs index 1aa6a288e7082..cce0665b37d36 100644 --- a/library/core/src/ub_checks.rs +++ b/library/core/src/ub_checks.rs @@ -3,9 +3,11 @@ use crate::intrinsics::{self, const_eval_select}; -/// Check that the preconditions of an unsafe function are followed. The check is enabled at -/// runtime if debug assertions are enabled when the caller is monomorphized. In const-eval/Miri -/// checks implemented with this macro for language UB are always ignored. +/// Checks that the preconditions of an unsafe function are followed. +/// +/// The check is enabled at runtime if debug assertions are enabled when the +/// caller is monomorphized. In const-eval/Miri checks implemented with this +/// macro for language UB are always ignored. /// /// This macro should be called as /// `assert_unsafe_precondition!(check_{library,lang}_ub, "message", (ident: type = expr, ident: type = expr) => check_expr)` diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index 04aaa3f35b7ae..5dad5937a603d 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -16,7 +16,6 @@ #![feature(const_hash)] #![feature(const_heap)] #![feature(const_intrinsic_copy)] -#![feature(const_int_from_str)] #![feature(const_maybe_uninit_as_mut_ptr)] #![feature(const_nonnull_new)] #![feature(const_pointer_is_aligned)] @@ -45,7 +44,6 @@ #![feature(hasher_prefixfree_extras)] #![feature(hashmap_internals)] #![feature(try_find)] -#![feature(is_sorted)] #![feature(layout_for_ptr)] #![feature(pattern)] #![feature(slice_take)] @@ -61,6 +59,7 @@ #![feature(num_midpoint)] #![feature(offset_of_nested)] #![feature(isqrt)] +#![feature(unsigned_is_multiple_of)] #![feature(step_trait)] #![feature(str_internals)] #![feature(std_internals)] @@ -88,7 +87,6 @@ #![feature(const_ipv6)] #![feature(const_mut_refs)] #![feature(const_pin)] -#![feature(const_waker)] #![feature(never_type)] #![feature(unwrap_infallible)] #![feature(pointer_is_aligned_to)] diff --git a/library/core/tests/num/uint_macros.rs b/library/core/tests/num/uint_macros.rs index 955440647eb98..d009ad89d5ce7 100644 --- a/library/core/tests/num/uint_macros.rs +++ b/library/core/tests/num/uint_macros.rs @@ -260,6 +260,14 @@ macro_rules! uint_module { assert_eq!(MAX.checked_next_multiple_of(2), None); } + #[test] + fn test_is_next_multiple_of() { + assert!((12 as $T).is_multiple_of(4)); + assert!(!(12 as $T).is_multiple_of(5)); + assert!((0 as $T).is_multiple_of(0)); + assert!(!(12 as $T).is_multiple_of(0)); + } + #[test] fn test_carrying_add() { assert_eq!($T::MAX.carrying_add(1, false), (0, true)); diff --git a/library/core/tests/ptr.rs b/library/core/tests/ptr.rs index e3830165eda61..bc1940ebf32b5 100644 --- a/library/core/tests/ptr.rs +++ b/library/core/tests/ptr.rs @@ -1050,7 +1050,7 @@ fn nonnull_tagged_pointer_with_provenance() { /// A mask for the non-data-carrying bits of the address. pub const ADDRESS_MASK: usize = usize::MAX << Self::NUM_BITS; - /// Create a new tagged pointer from a possibly null pointer. + /// Creates a new tagged pointer from a possibly null pointer. pub fn new(pointer: *mut T) -> Option> { Some(TaggedPointer(NonNull::new(pointer)?)) } diff --git a/library/core/tests/waker.rs b/library/core/tests/waker.rs index 2c66e0d7ad3a4..f8c91a72593f0 100644 --- a/library/core/tests/waker.rs +++ b/library/core/tests/waker.rs @@ -20,3 +20,35 @@ static WAKER_VTABLE: RawWakerVTable = RawWakerVTable::new( |_| {}, |_| {}, ); + +// https://github.com/rust-lang/rust/issues/102012#issuecomment-1915282956 +mod nop_waker { + use core::{ + future::{ready, Future}, + pin::Pin, + task::{Context, Poll, RawWaker, RawWakerVTable, Waker}, + }; + + const NOP_RAWWAKER: RawWaker = { + fn nop(_: *const ()) {} + const VTAB: RawWakerVTable = RawWakerVTable::new(|_| NOP_RAWWAKER, nop, nop, nop); + RawWaker::new(&() as *const (), &VTAB) + }; + + const NOP_WAKER: &Waker = &unsafe { Waker::from_raw(NOP_RAWWAKER) }; + + const NOP_CONTEXT: Context<'static> = Context::from_waker(NOP_WAKER); + + fn poll_once(f: &mut F) -> Poll + where + F: Future + ?Sized + Unpin, + { + let mut cx = NOP_CONTEXT; + Pin::new(f).as_mut().poll(&mut cx) + } + + #[test] + fn test_const_waker() { + assert_eq!(poll_once(&mut ready(1)), Poll::Ready(1)); + } +} diff --git a/library/portable-simd/crates/core_simd/src/masks.rs b/library/portable-simd/crates/core_simd/src/masks.rs index e6e27c76a5e99..04de3a968276d 100644 --- a/library/portable-simd/crates/core_simd/src/masks.rs +++ b/library/portable-simd/crates/core_simd/src/masks.rs @@ -137,7 +137,7 @@ where T: MaskElement, LaneCount: SupportedLaneCount, { - /// Construct a mask by setting all elements to the given value. + /// Constructs a mask by setting all elements to the given value. #[inline] pub fn splat(value: bool) -> Self { Self(mask_impl::Mask::splat(value)) @@ -288,7 +288,7 @@ where self.0.all() } - /// Create a bitmask from a mask. + /// Creates a bitmask from a mask. /// /// Each bit is set if the corresponding element in the mask is `true`. /// If the mask contains more than 64 elements, the bitmask is truncated to the first 64. @@ -298,7 +298,7 @@ where self.0.to_bitmask_integer() } - /// Create a mask from a bitmask. + /// Creates a mask from a bitmask. /// /// For each bit, if it is set, the corresponding element in the mask is set to `true`. /// If the mask contains more than 64 elements, the remainder are set to `false`. @@ -308,7 +308,7 @@ where Self(mask_impl::Mask::from_bitmask_integer(bitmask)) } - /// Create a bitmask vector from a mask. + /// Creates a bitmask vector from a mask. /// /// Each bit is set if the corresponding element in the mask is `true`. /// The remaining bits are unset. @@ -328,7 +328,7 @@ where self.0.to_bitmask_vector() } - /// Create a mask from a bitmask vector. + /// Creates a mask from a bitmask vector. /// /// For each bit, if it is set, the corresponding element in the mask is set to `true`. /// @@ -350,7 +350,7 @@ where Self(mask_impl::Mask::from_bitmask_vector(bitmask)) } - /// Find the index of the first set element. + /// Finds the index of the first set element. /// /// ``` /// # #![feature(portable_simd)] diff --git a/library/portable-simd/crates/core_simd/src/simd/ptr/const_ptr.rs b/library/portable-simd/crates/core_simd/src/simd/ptr/const_ptr.rs index cbffbc564cfed..be635ea640b86 100644 --- a/library/portable-simd/crates/core_simd/src/simd/ptr/const_ptr.rs +++ b/library/portable-simd/crates/core_simd/src/simd/ptr/const_ptr.rs @@ -54,7 +54,7 @@ pub trait SimdConstPtr: Copy + Sealed { /// [`Self::with_exposed_provenance`] and returns the "address" portion. fn expose_provenance(self) -> Self::Usize; - /// Convert an address back to a pointer, picking up a previously "exposed" provenance. + /// Converts an address back to a pointer, picking up a previously "exposed" provenance. /// /// Equivalent to calling [`core::ptr::with_exposed_provenance`] on each element. fn with_exposed_provenance(addr: Self::Usize) -> Self; diff --git a/library/portable-simd/crates/core_simd/src/simd/ptr/mut_ptr.rs b/library/portable-simd/crates/core_simd/src/simd/ptr/mut_ptr.rs index 6bc6ca3ac42dc..f6823a949e32a 100644 --- a/library/portable-simd/crates/core_simd/src/simd/ptr/mut_ptr.rs +++ b/library/portable-simd/crates/core_simd/src/simd/ptr/mut_ptr.rs @@ -51,7 +51,7 @@ pub trait SimdMutPtr: Copy + Sealed { /// [`Self::with_exposed_provenance`] and returns the "address" portion. fn expose_provenance(self) -> Self::Usize; - /// Convert an address back to a pointer, picking up a previously "exposed" provenance. + /// Converts an address back to a pointer, picking up a previously "exposed" provenance. /// /// Equivalent to calling [`core::ptr::with_exposed_provenance_mut`] on each element. fn with_exposed_provenance(addr: Self::Usize) -> Self; diff --git a/library/portable-simd/crates/core_simd/src/swizzle.rs b/library/portable-simd/crates/core_simd/src/swizzle.rs index 71110bb282018..2f4f777b20e29 100644 --- a/library/portable-simd/crates/core_simd/src/swizzle.rs +++ b/library/portable-simd/crates/core_simd/src/swizzle.rs @@ -69,12 +69,12 @@ pub macro simd_swizzle { } } -/// Create a vector from the elements of another vector. +/// Creates a vector from the elements of another vector. pub trait Swizzle { /// Map from the elements of the input vector to the output vector. const INDEX: [usize; N]; - /// Create a new vector from the elements of `vector`. + /// Creates a new vector from the elements of `vector`. /// /// Lane `i` of the output is `vector[Self::INDEX[i]]`. #[inline] @@ -109,7 +109,7 @@ pub trait Swizzle { } } - /// Create a new vector from the elements of `first` and `second`. + /// Creates a new vector from the elements of `first` and `second`. /// /// Lane `i` of the output is `concat[Self::INDEX[i]]`, where `concat` is the concatenation of /// `first` and `second`. @@ -145,7 +145,7 @@ pub trait Swizzle { } } - /// Create a new mask from the elements of `mask`. + /// Creates a new mask from the elements of `mask`. /// /// Element `i` of the output is `concat[Self::INDEX[i]]`, where `concat` is the concatenation of /// `first` and `second`. @@ -161,7 +161,7 @@ pub trait Swizzle { unsafe { Mask::from_int_unchecked(Self::swizzle(mask.to_int())) } } - /// Create a new mask from the elements of `first` and `second`. + /// Creates a new mask from the elements of `first` and `second`. /// /// Element `i` of the output is `concat[Self::INDEX[i]]`, where `concat` is the concatenation of /// `first` and `second`. diff --git a/library/portable-simd/crates/core_simd/src/to_bytes.rs b/library/portable-simd/crates/core_simd/src/to_bytes.rs index 222526c4ab30a..4833ea9e11362 100644 --- a/library/portable-simd/crates/core_simd/src/to_bytes.rs +++ b/library/portable-simd/crates/core_simd/src/to_bytes.rs @@ -10,7 +10,7 @@ mod sealed { } use sealed::Sealed; -/// Convert SIMD vectors to vectors of bytes +/// Converts SIMD vectors to vectors of bytes pub trait ToBytes: Sealed { /// This type, reinterpreted as bytes. type Bytes: Copy @@ -22,26 +22,26 @@ pub trait ToBytes: Sealed { + SimdUint + 'static; - /// Return the memory representation of this integer as a byte array in native byte + /// Returns the memory representation of this integer as a byte array in native byte /// order. fn to_ne_bytes(self) -> Self::Bytes; - /// Return the memory representation of this integer as a byte array in big-endian + /// Returns the memory representation of this integer as a byte array in big-endian /// (network) byte order. fn to_be_bytes(self) -> Self::Bytes; - /// Return the memory representation of this integer as a byte array in little-endian + /// Returns the memory representation of this integer as a byte array in little-endian /// byte order. fn to_le_bytes(self) -> Self::Bytes; - /// Create a native endian integer value from its memory representation as a byte array + /// Creates a native endian integer value from its memory representation as a byte array /// in native endianness. fn from_ne_bytes(bytes: Self::Bytes) -> Self; - /// Create an integer value from its representation as a byte array in big endian. + /// Creates an integer value from its representation as a byte array in big endian. fn from_be_bytes(bytes: Self::Bytes) -> Self; - /// Create an integer value from its representation as a byte array in little endian. + /// Creates an integer value from its representation as a byte array in little endian. fn from_le_bytes(bytes: Self::Bytes) -> Self; } diff --git a/library/portable-simd/crates/core_simd/src/vector.rs b/library/portable-simd/crates/core_simd/src/vector.rs index 8dbdfc0e1fe03..3e23916914963 100644 --- a/library/portable-simd/crates/core_simd/src/vector.rs +++ b/library/portable-simd/crates/core_simd/src/vector.rs @@ -187,7 +187,7 @@ where unsafe { &mut *(self as *mut Self as *mut [T; N]) } } - /// Load a vector from an array of `T`. + /// Loads a vector from an array of `T`. /// /// This function is necessary since `repr(simd)` has padding for non-power-of-2 vectors (at the time of writing). /// With padding, `read_unaligned` will read past the end of an array of N elements. @@ -567,7 +567,7 @@ where unsafe { Self::gather_select_ptr(ptrs, enable, or) } } - /// Read elementwise from pointers into a SIMD vector. + /// Reads elementwise from pointers into a SIMD vector. /// /// # Safety /// @@ -808,7 +808,7 @@ where } } - /// Write pointers elementwise into a SIMD vector. + /// Writes pointers elementwise into a SIMD vector. /// /// # Safety /// diff --git a/library/proc_macro/src/bridge/server.rs b/library/proc_macro/src/bridge/server.rs index 0dbd4bac85c9f..140519bcb236e 100644 --- a/library/proc_macro/src/bridge/server.rs +++ b/library/proc_macro/src/bridge/server.rs @@ -350,7 +350,7 @@ where /// A message pipe used for communicating between server and client threads. pub trait MessagePipe: Sized { - /// Create a new pair of endpoints for the message pipe. + /// Creates a new pair of endpoints for the message pipe. fn new() -> (Self, Self); /// Send a message to the other endpoint of this pipe. diff --git a/library/proc_macro/src/bridge/symbol.rs b/library/proc_macro/src/bridge/symbol.rs index 86ce2cc189588..37aaee6b21553 100644 --- a/library/proc_macro/src/bridge/symbol.rs +++ b/library/proc_macro/src/bridge/symbol.rs @@ -28,7 +28,7 @@ impl Symbol { INTERNER.with_borrow_mut(|i| i.intern(string)) } - /// Create a new `Symbol` for an identifier. + /// Creates a new `Symbol` for an identifier. /// /// Validates and normalizes before converting it to a symbol. pub(crate) fn new_ident(string: &str, is_raw: bool) -> Self { @@ -63,7 +63,7 @@ impl Symbol { INTERNER.with_borrow_mut(|i| i.clear()); } - /// Check if the ident is a valid ASCII identifier. + /// Checks if the ident is a valid ASCII identifier. /// /// This is a short-circuit which is cheap to implement within the /// proc-macro client to avoid RPC when creating simple idents, but may @@ -177,7 +177,7 @@ impl Interner { name } - /// Read a symbol's value from the store while it is held. + /// Reads a symbol's value from the store while it is held. fn get(&self, symbol: Symbol) -> &str { // NOTE: Subtract out the offset which was added to make the symbol // nonzero and prevent symbol name re-use. diff --git a/library/rtstartup/rsbegin.rs b/library/rtstartup/rsbegin.rs index 14bce2bbeee2b..9a3d95bd8ddfb 100644 --- a/library/rtstartup/rsbegin.rs +++ b/library/rtstartup/rsbegin.rs @@ -29,6 +29,8 @@ trait Copy {} #[lang = "freeze"] auto trait Freeze {} +impl Copy for *mut T {} + #[lang = "drop_in_place"] #[inline] #[allow(unconditional_recursion)] diff --git a/library/rtstartup/rsend.rs b/library/rtstartup/rsend.rs index 714643c83866f..2514eb0034402 100644 --- a/library/rtstartup/rsend.rs +++ b/library/rtstartup/rsend.rs @@ -17,6 +17,8 @@ trait Copy {} #[lang = "freeze"] auto trait Freeze {} +impl Copy for *mut T {} + #[lang = "drop_in_place"] #[inline] #[allow(unconditional_recursion)] diff --git a/library/std/src/backtrace.rs b/library/std/src/backtrace.rs index 4d376753cb6d2..4266da04f9918 100644 --- a/library/std/src/backtrace.rs +++ b/library/std/src/backtrace.rs @@ -271,7 +271,7 @@ impl Backtrace { enabled } - /// Capture a stack backtrace of the current thread. + /// Captures a stack backtrace of the current thread. /// /// This function will capture a stack backtrace of the current OS thread of /// execution, returning a `Backtrace` type which can be later used to print diff --git a/library/std/src/error.rs b/library/std/src/error.rs index 87aad8f764bd0..7d10cbec26d80 100644 --- a/library/std/src/error.rs +++ b/library/std/src/error.rs @@ -234,7 +234,7 @@ impl Report where Report: From, { - /// Create a new `Report` from an input error. + /// Creates a new `Report` from an input error. #[unstable(feature = "error_reporter", issue = "90172")] pub fn new(error: E) -> Report { Self::from(error) diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs index 536d0d1b356a9..65dbf43a42eaf 100644 --- a/library/std/src/fs.rs +++ b/library/std/src/fs.rs @@ -50,7 +50,7 @@ use crate::time::SystemTime; /// } /// ``` /// -/// Read the contents of a file into a [`String`] (you can also use [`read`]): +/// Reads the contents of a file into a [`String`] (you can also use [`read`]): /// /// ```no_run /// use std::fs::File; @@ -229,7 +229,7 @@ pub struct DirBuilder { recursive: bool, } -/// Read the entire contents of a file into a bytes vector. +/// Reads the entire contents of a file into a bytes vector. /// /// This is a convenience function for using [`File::open`] and [`read_to_end`] /// with fewer imports and without an intermediate variable. @@ -268,7 +268,7 @@ pub fn read>(path: P) -> io::Result> { inner(path.as_ref()) } -/// Read the entire contents of a file into a string. +/// Reads the entire contents of a file into a string. /// /// This is a convenience function for using [`File::open`] and [`read_to_string`] /// with fewer imports and without an intermediate variable. @@ -311,7 +311,7 @@ pub fn read_to_string>(path: P) -> io::Result { inner(path.as_ref()) } -/// Write a slice as the entire contents of a file. +/// Writes a slice as the entire contents of a file. /// /// This function will create a file if it does not exist, /// and will entirely replace its contents if it does. @@ -767,7 +767,7 @@ fn buffer_capacity_required(mut file: &File) -> Option { #[stable(feature = "rust1", since = "1.0.0")] impl Read for &File { - /// Read some bytes from the file. + /// Reads some bytes from the file. /// /// See [`Read::read`] docs for more info. /// @@ -835,7 +835,7 @@ impl Read for &File { } #[stable(feature = "rust1", since = "1.0.0")] impl Write for &File { - /// Write some bytes from the file. + /// Writes some bytes from the file. /// /// See [`Write::write`] docs for more info. /// @@ -1526,7 +1526,7 @@ impl FromInner for Metadata { } impl FileTimes { - /// Create a new `FileTimes` with no times set. + /// Creates a new `FileTimes` with no times set. /// /// Using the resulting `FileTimes` in [`File::set_times`] will not modify any timestamps. #[stable(feature = "file_set_times", since = "1.75.0")] @@ -2005,7 +2005,7 @@ pub fn remove_file>(path: P) -> io::Result<()> { fs_imp::unlink(path.as_ref()) } -/// Given a path, query the file system to get information about a file, +/// Given a path, queries the file system to get information about a file, /// directory, etc. /// /// This function will traverse symbolic links to query information about the @@ -2044,7 +2044,7 @@ pub fn metadata>(path: P) -> io::Result { fs_imp::stat(path.as_ref()).map(Metadata) } -/// Query the metadata about a file without following symlinks. +/// Queries the metadata about a file without following symlinks. /// /// # Platform-specific behavior /// @@ -2079,7 +2079,7 @@ pub fn symlink_metadata>(path: P) -> io::Result { fs_imp::lstat(path.as_ref()).map(Metadata) } -/// Rename a file or directory to a new name, replacing the original file if +/// Renames a file or directory to a new name, replacing the original file if /// `to` already exists. /// /// This will not work if the new name is on a different mount point. diff --git a/library/std/src/io/buffered/linewritershim.rs b/library/std/src/io/buffered/linewritershim.rs index c3ac7855d4450..a1f3317bdd806 100644 --- a/library/std/src/io/buffered/linewritershim.rs +++ b/library/std/src/io/buffered/linewritershim.rs @@ -2,6 +2,7 @@ use crate::io::{self, BufWriter, IoSlice, Write}; use core::slice::memchr; /// Private helper struct for implementing the line-buffered writing logic. +/// /// This shim temporarily wraps a BufWriter, and uses its internals to /// implement a line-buffered writer (specifically by using the internal /// methods like write_to_buf and flush_buf). In this way, a more @@ -20,27 +21,27 @@ impl<'a, W: ?Sized + Write> LineWriterShim<'a, W> { Self { buffer } } - /// Get a reference to the inner writer (that is, the writer + /// Gets a reference to the inner writer (that is, the writer /// wrapped by the BufWriter). fn inner(&self) -> &W { self.buffer.get_ref() } - /// Get a mutable reference to the inner writer (that is, the writer + /// Gets a mutable reference to the inner writer (that is, the writer /// wrapped by the BufWriter). Be careful with this writer, as writes to /// it will bypass the buffer. fn inner_mut(&mut self) -> &mut W { self.buffer.get_mut() } - /// Get the content currently buffered in self.buffer + /// Gets the content currently buffered in self.buffer fn buffered(&self) -> &[u8] { self.buffer.buffer() } - /// Flush the buffer iff the last byte is a newline (indicating that an + /// Flushes the buffer iff the last byte is a newline (indicating that an /// earlier write only succeeded partially, and we want to retry flushing - /// the buffered line before continuing with a subsequent write) + /// the buffered line before continuing with a subsequent write). fn flush_if_completed_line(&mut self) -> io::Result<()> { match self.buffered().last().copied() { Some(b'\n') => self.buffer.flush_buf(), @@ -50,10 +51,11 @@ impl<'a, W: ?Sized + Write> LineWriterShim<'a, W> { } impl<'a, W: ?Sized + Write> Write for LineWriterShim<'a, W> { - /// Write some data into this BufReader with line buffering. This means - /// that, if any newlines are present in the data, the data up to the last - /// newline is sent directly to the underlying writer, and data after it - /// is buffered. Returns the number of bytes written. + /// Writes some data into this BufReader with line buffering. + /// + /// This means that, if any newlines are present in the data, the data up to + /// the last newline is sent directly to the underlying writer, and data + /// after it is buffered. Returns the number of bytes written. /// /// This function operates on a "best effort basis"; in keeping with the /// convention of `Write::write`, it makes at most one attempt to write @@ -136,11 +138,12 @@ impl<'a, W: ?Sized + Write> Write for LineWriterShim<'a, W> { self.buffer.flush() } - /// Write some vectored data into this BufReader with line buffering. This - /// means that, if any newlines are present in the data, the data up to - /// and including the buffer containing the last newline is sent directly - /// to the inner writer, and the data after it is buffered. Returns the - /// number of bytes written. + /// Writes some vectored data into this BufReader with line buffering. + /// + /// This means that, if any newlines are present in the data, the data up to + /// and including the buffer containing the last newline is sent directly to + /// the inner writer, and the data after it is buffered. Returns the number + /// of bytes written. /// /// This function operates on a "best effort basis"; in keeping with the /// convention of `Write::write`, it makes at most one attempt to write @@ -245,10 +248,11 @@ impl<'a, W: ?Sized + Write> Write for LineWriterShim<'a, W> { self.inner().is_write_vectored() } - /// Write some data into this BufReader with line buffering. This means - /// that, if any newlines are present in the data, the data up to the last - /// newline is sent directly to the underlying writer, and data after it - /// is buffered. + /// Writes some data into this BufReader with line buffering. + /// + /// This means that, if any newlines are present in the data, the data up to + /// the last newline is sent directly to the underlying writer, and data + /// after it is buffered. /// /// Because this function attempts to send completed lines to the underlying /// writer, it will also flush the existing buffer if it contains any diff --git a/library/std/src/io/buffered/mod.rs b/library/std/src/io/buffered/mod.rs index 100dab1e2493c..d4dc8291131df 100644 --- a/library/std/src/io/buffered/mod.rs +++ b/library/std/src/io/buffered/mod.rs @@ -48,7 +48,7 @@ pub use bufwriter::WriterPanicked; pub struct IntoInnerError(W, Error); impl IntoInnerError { - /// Construct a new IntoInnerError + /// Constructs a new IntoInnerError fn new(writer: W, error: Error) -> Self { Self(writer, error) } diff --git a/library/std/src/io/error.rs b/library/std/src/io/error.rs index 8de27367a3f21..32c0ec53ff25c 100644 --- a/library/std/src/io/error.rs +++ b/library/std/src/io/error.rs @@ -167,7 +167,7 @@ impl SimpleMessage { } } -/// Create and return an `io::Error` for a given `ErrorKind` and constant +/// Creates and returns an `io::Error` for a given `ErrorKind` and constant /// message. This doesn't allocate. pub(crate) macro const_io_error($kind:expr, $message:expr $(,)?) { $crate::io::error::Error::from_static_message({ @@ -852,7 +852,7 @@ impl Error { } } - /// Attempt to downcast the custom boxed error to `E`. + /// Attempts to downcast the custom boxed error to `E`. /// /// If this [`Error`] contains a custom boxed error, /// then it would attempt downcasting on the boxed error, diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index 1345a30361e28..beb88106f1cad 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -782,7 +782,7 @@ pub trait Read { false } - /// Read all bytes until EOF in this source, placing them into `buf`. + /// Reads all bytes until EOF in this source, placing them into `buf`. /// /// All bytes read from this source will be appended to the specified buffer /// `buf`. This function will continuously call [`read()`] to append more data to @@ -866,7 +866,7 @@ pub trait Read { default_read_to_end(self, buf, None) } - /// Read all bytes until EOF in this source, appending them to `buf`. + /// Reads all bytes until EOF in this source, appending them to `buf`. /// /// If successful, this function returns the number of bytes which were read /// and appended to `buf`. @@ -909,7 +909,7 @@ pub trait Read { default_read_to_string(self, buf, None) } - /// Read the exact number of bytes required to fill `buf`. + /// Reads the exact number of bytes required to fill `buf`. /// /// This function reads as many bytes as necessary to completely fill the /// specified buffer `buf`. @@ -973,7 +973,7 @@ pub trait Read { default_read_buf(|b| self.read(b), buf) } - /// Read the exact number of bytes required to fill `cursor`. + /// Reads the exact number of bytes required to fill `cursor`. /// /// This is similar to the [`read_exact`](Read::read_exact) method, except /// that it is passed a [`BorrowedCursor`] rather than `[u8]` to allow use @@ -1159,7 +1159,7 @@ pub trait Read { } } -/// Read all bytes from a [reader][Read] into a new [`String`]. +/// Reads all bytes from a [reader][Read] into a new [`String`]. /// /// This is a convenience function for [`Read::read_to_string`]. Using this /// function avoids having to create a variable first and provides more type @@ -1212,7 +1212,7 @@ pub fn read_to_string(mut reader: R) -> Result { /// A buffer type used with `Read::read_vectored`. /// -/// It is semantically a wrapper around an `&mut [u8]`, but is guaranteed to be +/// It is semantically a wrapper around a `&mut [u8]`, but is guaranteed to be /// ABI compatible with the `iovec` type on Unix platforms and `WSABUF` on /// Windows. #[stable(feature = "iovec", since = "1.36.0")] @@ -1531,7 +1531,7 @@ impl<'a> Deref for IoSlice<'a> { #[doc(notable_trait)] #[cfg_attr(not(test), rustc_diagnostic_item = "IoWrite")] pub trait Write { - /// Write a buffer into this writer, returning how many bytes were written. + /// Writes a buffer into this writer, returning how many bytes were written. /// /// This function will attempt to write the entire contents of `buf`, but /// the entire write might not succeed, or the write may also generate an @@ -1630,7 +1630,7 @@ pub trait Write { false } - /// Flush this output stream, ensuring that all intermediately buffered + /// Flushes this output stream, ensuring that all intermediately buffered /// contents reach their destination. /// /// # Errors @@ -2247,7 +2247,7 @@ pub trait BufRead: Read { #[stable(feature = "rust1", since = "1.0.0")] fn consume(&mut self, amt: usize); - /// Check if the underlying `Read` has any data left to be read. + /// Checks if the underlying `Read` has any data left to be read. /// /// This function may fill the buffer to check for data, /// so this functions returns `Result`, not `bool`. @@ -2278,7 +2278,7 @@ pub trait BufRead: Read { self.fill_buf().map(|b| !b.is_empty()) } - /// Read all bytes into `buf` until the delimiter `byte` or EOF is reached. + /// Reads all bytes into `buf` until the delimiter `byte` or EOF is reached. /// /// This function will read bytes from the underlying stream until the /// delimiter or EOF is found. Once found, all bytes up to, and including, @@ -2337,7 +2337,7 @@ pub trait BufRead: Read { read_until(self, byte, buf) } - /// Skip all bytes until the delimiter `byte` or EOF is reached. + /// Skips all bytes until the delimiter `byte` or EOF is reached. /// /// This function will read (and discard) bytes from the underlying stream until the /// delimiter or EOF is found. @@ -2399,7 +2399,7 @@ pub trait BufRead: Read { skip_until(self, byte) } - /// Read all bytes until a newline (the `0xA` byte) is reached, and append + /// Reads all bytes until a newline (the `0xA` byte) is reached, and append /// them to the provided `String` buffer. /// /// Previous content of the buffer will be preserved. To avoid appending to @@ -3038,7 +3038,7 @@ where } } -/// Read a single byte in a slow, generic way. This is used by the default +/// Reads a single byte in a slow, generic way. This is used by the default /// `spec_read_byte`. #[inline] fn inlined_slow_read_byte(reader: &mut R) -> Option> { diff --git a/library/std/src/io/stdio.rs b/library/std/src/io/stdio.rs index 9aee2bb5e1c5c..10eb8dae48ef4 100644 --- a/library/std/src/io/stdio.rs +++ b/library/std/src/io/stdio.rs @@ -1092,7 +1092,7 @@ pub fn try_set_output_capture( OUTPUT_CAPTURE.try_with(move |slot| slot.replace(sink)) } -/// Write `args` to the capture buffer if enabled and possible, or `global_s` +/// Writes `args` to the capture buffer if enabled and possible, or `global_s` /// otherwise. `label` identifies the stream in a panic message. /// /// This function is used to print error messages, so it takes extra diff --git a/library/std/src/io/tests.rs b/library/std/src/io/tests.rs index a2c1c430863ab..f613626bca843 100644 --- a/library/std/src/io/tests.rs +++ b/library/std/src/io/tests.rs @@ -530,7 +530,7 @@ fn io_slice_advance_slices_beyond_total_length() { assert!(bufs.is_empty()); } -/// Create a new writer that reads from at most `n_bufs` and reads +/// Creates a new writer that reads from at most `n_bufs` and reads /// `per_call` bytes (in total) per call to write. fn test_writer(n_bufs: usize, per_call: usize) -> TestWriter { TestWriter { n_bufs, per_call, written: Vec::new() } diff --git a/library/std/src/keyword_docs.rs b/library/std/src/keyword_docs.rs index 8415f36eba251..c82228fca4bcf 100644 --- a/library/std/src/keyword_docs.rs +++ b/library/std/src/keyword_docs.rs @@ -1175,7 +1175,7 @@ mod ref_keyword {} #[doc(keyword = "return")] // -/// Return a value from a function. +/// Returns a value from a function. /// /// A `return` marks the end of an execution path in a function: /// @@ -2310,7 +2310,7 @@ mod where_keyword {} #[doc(alias = "promise")] #[doc(keyword = "async")] // -/// Return a [`Future`] instead of blocking the current thread. +/// Returns a [`Future`] instead of blocking the current thread. /// /// Use `async` in front of `fn`, `closure`, or a `block` to turn the marked code into a `Future`. /// As such the code will not be run immediately, but will only be evaluated when the returned diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 9fba657d116de..353fd8d2de8c0 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -407,7 +407,6 @@ #![feature(const_ip)] #![feature(const_ipv4)] #![feature(const_ipv6)] -#![feature(const_waker)] #![feature(thread_local_internals)] // tidy-alphabetical-end // diff --git a/library/std/src/os/fd/owned.rs b/library/std/src/os/fd/owned.rs index bbd5093e44c60..3baba14f75e2f 100644 --- a/library/std/src/os/fd/owned.rs +++ b/library/std/src/os/fd/owned.rs @@ -70,7 +70,7 @@ pub struct OwnedFd { } impl BorrowedFd<'_> { - /// Return a `BorrowedFd` holding the given raw file descriptor. + /// Returns a `BorrowedFd` holding the given raw file descriptor. /// /// # Safety /// diff --git a/library/std/src/os/freebsd/net.rs b/library/std/src/os/freebsd/net.rs index b7e0fdc0a9aab..fcfc5c1c83935 100644 --- a/library/std/src/os/freebsd/net.rs +++ b/library/std/src/os/freebsd/net.rs @@ -42,7 +42,7 @@ pub trait UnixSocketExt: Sealed { #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] fn set_local_creds_persistent(&self, local_creds_persistent: bool) -> io::Result<()>; - /// Get a filter name if one had been set previously on the socket. + /// Gets a filter name if one had been set previously on the socket. #[unstable(feature = "acceptfilter", issue = "121891")] fn acceptfilter(&self) -> io::Result<&CStr>; diff --git a/library/std/src/os/netbsd/net.rs b/library/std/src/os/netbsd/net.rs index b9679c7b3af33..e1950d349bf7d 100644 --- a/library/std/src/os/netbsd/net.rs +++ b/library/std/src/os/netbsd/net.rs @@ -42,7 +42,7 @@ pub trait UnixSocketExt: Sealed { #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] fn set_local_creds(&self, local_creds: bool) -> io::Result<()>; - /// Get a filter name if one had been set previously on the socket. + /// Gets a filter name if one had been set previously on the socket. #[unstable(feature = "acceptfilter", issue = "121891")] fn acceptfilter(&self) -> io::Result<&CStr>; diff --git a/library/std/src/os/solid/io.rs b/library/std/src/os/solid/io.rs index bbf7e96d53d95..9834ff6073540 100644 --- a/library/std/src/os/solid/io.rs +++ b/library/std/src/os/solid/io.rs @@ -98,7 +98,7 @@ pub struct OwnedFd { } impl BorrowedFd<'_> { - /// Return a `BorrowedFd` holding the given raw file descriptor. + /// Returns a `BorrowedFd` holding the given raw file descriptor. /// /// # Safety /// diff --git a/library/std/src/os/uefi/env.rs b/library/std/src/os/uefi/env.rs index 5d082e7c11388..3248ff98ff2b9 100644 --- a/library/std/src/os/uefi/env.rs +++ b/library/std/src/os/uefi/env.rs @@ -26,7 +26,7 @@ static BOOT_SERVICES_FLAG: AtomicBool = AtomicBool::new(false); /// standard library is loaded. /// /// # SAFETY -/// Calling this function more than once will panic +/// Calling this function more than once will panic. pub(crate) unsafe fn init_globals(handle: NonNull, system_table: NonNull) { IMAGE_HANDLE .compare_exchange( @@ -47,23 +47,25 @@ pub(crate) unsafe fn init_globals(handle: NonNull, system_table: NonNull BOOT_SERVICES_FLAG.store(true, Ordering::Release) } -/// Get the SystemTable Pointer. +/// Gets the SystemTable Pointer. +/// /// If you want to use `BootServices` then please use [`boot_services`] as it performs some /// additional checks. /// -/// Note: This function panics if the System Table or Image Handle is not initialized +/// Note: This function panics if the System Table or Image Handle is not initialized. pub fn system_table() -> NonNull { try_system_table().unwrap() } -/// Get the ImageHandle Pointer. +/// Gets the ImageHandle Pointer. /// -/// Note: This function panics if the System Table or Image Handle is not initialized +/// Note: This function panics if the System Table or Image Handle is not initialized. pub fn image_handle() -> NonNull { try_image_handle().unwrap() } -/// Get the BootServices Pointer. +/// Gets the BootServices Pointer. +/// /// This function also checks if `ExitBootServices` has already been called. pub fn boot_services() -> Option> { if BOOT_SERVICES_FLAG.load(Ordering::Acquire) { @@ -75,14 +77,16 @@ pub fn boot_services() -> Option> { } } -/// Get the SystemTable Pointer. -/// This function is mostly intended for places where panic is not an option +/// Gets the SystemTable Pointer. +/// +/// This function is mostly intended for places where panic is not an option. pub(crate) fn try_system_table() -> Option> { NonNull::new(SYSTEM_TABLE.load(Ordering::Acquire)) } -/// Get the SystemHandle Pointer. -/// This function is mostly intended for places where panicking is not an option +/// Gets the SystemHandle Pointer. +/// +/// This function is mostly intended for places where panicking is not an option. pub(crate) fn try_image_handle() -> Option> { NonNull::new(IMAGE_HANDLE.load(Ordering::Acquire)) } diff --git a/library/std/src/os/unix/net/ancillary.rs b/library/std/src/os/unix/net/ancillary.rs index fe8e2be93724e..9b487a6298247 100644 --- a/library/std/src/os/unix/net/ancillary.rs +++ b/library/std/src/os/unix/net/ancillary.rs @@ -164,7 +164,7 @@ struct AncillaryDataIter<'a, T> { } impl<'a, T> AncillaryDataIter<'a, T> { - /// Create `AncillaryDataIter` struct to iterate through the data unit in the control message. + /// Creates `AncillaryDataIter` struct to iterate through the data unit in the control message. /// /// # Safety /// @@ -220,7 +220,7 @@ pub struct SocketCred(libc::sockcred2); #[doc(cfg(any(target_os = "android", target_os = "linux")))] #[cfg(any(target_os = "android", target_os = "linux"))] impl SocketCred { - /// Create a Unix credential struct. + /// Creates a Unix credential struct. /// /// PID, UID and GID is set to 0. #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] @@ -235,7 +235,7 @@ impl SocketCred { self.0.pid = pid; } - /// Get the current PID. + /// Gets the current PID. #[must_use] #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub fn get_pid(&self) -> libc::pid_t { @@ -248,7 +248,7 @@ impl SocketCred { self.0.uid = uid; } - /// Get the current UID. + /// Gets the current UID. #[must_use] #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub fn get_uid(&self) -> libc::uid_t { @@ -261,7 +261,7 @@ impl SocketCred { self.0.gid = gid; } - /// Get the current GID. + /// Gets the current GID. #[must_use] #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub fn get_gid(&self) -> libc::gid_t { @@ -271,7 +271,7 @@ impl SocketCred { #[cfg(target_os = "freebsd")] impl SocketCred { - /// Create a Unix credential struct. + /// Creates a Unix credential struct. /// /// PID, UID and GID is set to 0. #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] @@ -295,7 +295,7 @@ impl SocketCred { self.0.sc_pid = pid; } - /// Get the current PID. + /// Gets the current PID. #[must_use] #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub fn get_pid(&self) -> libc::pid_t { @@ -308,7 +308,7 @@ impl SocketCred { self.0.sc_euid = uid; } - /// Get the current UID. + /// Gets the current UID. #[must_use] #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub fn get_uid(&self) -> libc::uid_t { @@ -321,7 +321,7 @@ impl SocketCred { self.0.sc_egid = gid; } - /// Get the current GID. + /// Gets the current GID. #[must_use] #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub fn get_gid(&self) -> libc::gid_t { @@ -331,7 +331,7 @@ impl SocketCred { #[cfg(target_os = "netbsd")] impl SocketCred { - /// Create a Unix credential struct. + /// Creates a Unix credential struct. /// /// PID, UID and GID is set to 0. #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] @@ -353,7 +353,7 @@ impl SocketCred { self.0.sc_pid = pid; } - /// Get the current PID. + /// Gets the current PID. #[must_use] #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub fn get_pid(&self) -> libc::pid_t { @@ -366,7 +366,7 @@ impl SocketCred { self.0.sc_uid = uid; } - /// Get the current UID. + /// Gets the current UID. #[must_use] #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub fn get_uid(&self) -> libc::uid_t { @@ -379,7 +379,7 @@ impl SocketCred { self.0.sc_gid = gid; } - /// Get the current GID. + /// Gets the current GID. #[must_use] #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub fn get_gid(&self) -> libc::gid_t { @@ -466,7 +466,7 @@ pub enum AncillaryData<'a> { } impl<'a> AncillaryData<'a> { - /// Create an `AncillaryData::ScmRights` variant. + /// Creates an `AncillaryData::ScmRights` variant. /// /// # Safety /// @@ -478,7 +478,7 @@ impl<'a> AncillaryData<'a> { AncillaryData::ScmRights(scm_rights) } - /// Create an `AncillaryData::ScmCredentials` variant. + /// Creates an `AncillaryData::ScmCredentials` variant. /// /// # Safety /// @@ -605,7 +605,7 @@ pub struct SocketAncillary<'a> { } impl<'a> SocketAncillary<'a> { - /// Create an ancillary data with the given buffer. + /// Creates an ancillary data with the given buffer. /// /// # Example /// diff --git a/library/std/src/os/unix/net/datagram.rs b/library/std/src/os/unix/net/datagram.rs index b29f9099a1111..f58f9b4d9ab85 100644 --- a/library/std/src/os/unix/net/datagram.rs +++ b/library/std/src/os/unix/net/datagram.rs @@ -20,6 +20,8 @@ use crate::{fmt, io}; target_os = "freebsd", target_os = "openbsd", target_os = "netbsd", + target_os = "solaris", + target_os = "illumos", target_os = "haiku", target_os = "nto", ))] @@ -31,6 +33,8 @@ use libc::MSG_NOSIGNAL; target_os = "freebsd", target_os = "openbsd", target_os = "netbsd", + target_os = "solaris", + target_os = "illumos", target_os = "haiku", target_os = "nto", )))] diff --git a/library/std/src/os/unix/process.rs b/library/std/src/os/unix/process.rs index 72ea54bd77203..d4a35ad3f8642 100644 --- a/library/std/src/os/unix/process.rs +++ b/library/std/src/os/unix/process.rs @@ -444,7 +444,7 @@ impl From for OwnedFd { } } -/// Create a `ChildStdin` from the provided `OwnedFd`. +/// Creates a `ChildStdin` from the provided `OwnedFd`. /// /// The provided file descriptor must point to a pipe /// with the `CLOEXEC` flag set. @@ -475,7 +475,7 @@ impl From for OwnedFd { } } -/// Create a `ChildStdout` from the provided `OwnedFd`. +/// Creates a `ChildStdout` from the provided `OwnedFd`. /// /// The provided file descriptor must point to a pipe /// with the `CLOEXEC` flag set. @@ -506,7 +506,7 @@ impl From for OwnedFd { } } -/// Create a `ChildStderr` from the provided `OwnedFd`. +/// Creates a `ChildStderr` from the provided `OwnedFd`. /// /// The provided file descriptor must point to a pipe /// with the `CLOEXEC` flag set. diff --git a/library/std/src/os/wasi/fs.rs b/library/std/src/os/wasi/fs.rs index 46fc2a50de911..a0920a281990a 100644 --- a/library/std/src/os/wasi/fs.rs +++ b/library/std/src/os/wasi/fs.rs @@ -169,55 +169,55 @@ pub trait FileExt { #[doc(alias = "fd_tell")] fn tell(&self) -> io::Result; - /// Adjust the flags associated with this file. + /// Adjusts the flags associated with this file. /// /// This corresponds to the `fd_fdstat_set_flags` syscall. #[doc(alias = "fd_fdstat_set_flags")] fn fdstat_set_flags(&self, flags: u16) -> io::Result<()>; - /// Adjust the rights associated with this file. + /// Adjusts the rights associated with this file. /// /// This corresponds to the `fd_fdstat_set_rights` syscall. #[doc(alias = "fd_fdstat_set_rights")] fn fdstat_set_rights(&self, rights: u64, inheriting: u64) -> io::Result<()>; - /// Provide file advisory information on a file descriptor. + /// Provides file advisory information on a file descriptor. /// /// This corresponds to the `fd_advise` syscall. #[doc(alias = "fd_advise")] fn advise(&self, offset: u64, len: u64, advice: u8) -> io::Result<()>; - /// Force the allocation of space in a file. + /// Forces the allocation of space in a file. /// /// This corresponds to the `fd_allocate` syscall. #[doc(alias = "fd_allocate")] fn allocate(&self, offset: u64, len: u64) -> io::Result<()>; - /// Create a directory. + /// Creates a directory. /// /// This corresponds to the `path_create_directory` syscall. #[doc(alias = "path_create_directory")] fn create_directory>(&self, dir: P) -> io::Result<()>; - /// Read the contents of a symbolic link. + /// Reads the contents of a symbolic link. /// /// This corresponds to the `path_readlink` syscall. #[doc(alias = "path_readlink")] fn read_link>(&self, path: P) -> io::Result; - /// Return the attributes of a file or directory. + /// Returns the attributes of a file or directory. /// /// This corresponds to the `path_filestat_get` syscall. #[doc(alias = "path_filestat_get")] fn metadata_at>(&self, lookup_flags: u32, path: P) -> io::Result; - /// Unlink a file. + /// Unlinks a file. /// /// This corresponds to the `path_unlink_file` syscall. #[doc(alias = "path_unlink_file")] fn remove_file>(&self, path: P) -> io::Result<()>; - /// Remove a directory. + /// Removes a directory. /// /// This corresponds to the `path_remove_directory` syscall. #[doc(alias = "path_remove_directory")] @@ -501,7 +501,7 @@ impl DirEntryExt for fs::DirEntry { } } -/// Create a hard link. +/// Creates a hard link. /// /// This corresponds to the `path_link` syscall. #[doc(alias = "path_link")] @@ -520,7 +520,7 @@ pub fn link, U: AsRef>( ) } -/// Rename a file or directory. +/// Renames a file or directory. /// /// This corresponds to the `path_rename` syscall. #[doc(alias = "path_rename")] @@ -537,7 +537,7 @@ pub fn rename, U: AsRef>( ) } -/// Create a symbolic link. +/// Creates a symbolic link. /// /// This corresponds to the `path_symlink` syscall. #[doc(alias = "path_symlink")] @@ -551,7 +551,7 @@ pub fn symlink, U: AsRef>( .symlink(osstr2str(old_path.as_ref().as_ref())?, osstr2str(new_path.as_ref().as_ref())?) } -/// Create a symbolic link. +/// Creates a symbolic link. /// /// This is a convenience API similar to `std::os::unix::fs::symlink` and /// `std::os::windows::fs::symlink_file` and `std::os::windows::fs::symlink_dir`. diff --git a/library/std/src/os/windows/fs.rs b/library/std/src/os/windows/fs.rs index 7cac8c39ea89f..8bddeb7310a4d 100644 --- a/library/std/src/os/windows/fs.rs +++ b/library/std/src/os/windows/fs.rs @@ -631,7 +631,7 @@ pub fn symlink_dir, Q: AsRef>(original: P, link: Q) -> io:: sys::fs::symlink_inner(original.as_ref(), link.as_ref(), true) } -/// Create a junction point. +/// Creates a junction point. /// /// The `link` path will be a directory junction pointing to the original path. /// If `link` is a relative path then it will be made absolute prior to creating the junction point. diff --git a/library/std/src/os/windows/io/handle.rs b/library/std/src/os/windows/io/handle.rs index 9865386e753df..21c0f27c5bb91 100644 --- a/library/std/src/os/windows/io/handle.rs +++ b/library/std/src/os/windows/io/handle.rs @@ -135,7 +135,7 @@ unsafe impl Sync for HandleOrInvalid {} unsafe impl Sync for BorrowedHandle<'_> {} impl BorrowedHandle<'_> { - /// Return a `BorrowedHandle` holding the given raw handle. + /// Returns a `BorrowedHandle` holding the given raw handle. /// /// # Safety /// diff --git a/library/std/src/os/windows/io/raw.rs b/library/std/src/os/windows/io/raw.rs index 343cc6e4a8a5a..a1888be5f1d90 100644 --- a/library/std/src/os/windows/io/raw.rs +++ b/library/std/src/os/windows/io/raw.rs @@ -44,7 +44,7 @@ pub trait AsRawHandle { fn as_raw_handle(&self) -> RawHandle; } -/// Construct I/O objects from raw handles. +/// Constructs I/O objects from raw handles. #[stable(feature = "from_raw_os", since = "1.1.0")] pub trait FromRawHandle { /// Constructs a new I/O object from the specified raw handle. diff --git a/library/std/src/os/windows/io/socket.rs b/library/std/src/os/windows/io/socket.rs index df5b56d306205..5a62177e901bc 100644 --- a/library/std/src/os/windows/io/socket.rs +++ b/library/std/src/os/windows/io/socket.rs @@ -63,7 +63,7 @@ pub struct OwnedSocket { } impl BorrowedSocket<'_> { - /// Return a `BorrowedSocket` holding the given raw socket. + /// Returns a `BorrowedSocket` holding the given raw socket. /// /// # Safety /// diff --git a/library/std/src/os/windows/process.rs b/library/std/src/os/windows/process.rs index 3927b2ed9bb5c..af5c13b99e742 100644 --- a/library/std/src/os/windows/process.rs +++ b/library/std/src/os/windows/process.rs @@ -109,7 +109,7 @@ impl IntoRawHandle for process::ChildStderr { } } -/// Create a `ChildStdin` from the provided `OwnedHandle`. +/// Creates a `ChildStdin` from the provided `OwnedHandle`. /// /// The provided handle must be asynchronous, as reading and /// writing from and to it is implemented using asynchronous APIs. @@ -122,7 +122,7 @@ impl From for process::ChildStdin { } } -/// Create a `ChildStdout` from the provided `OwnedHandle`. +/// Creates a `ChildStdout` from the provided `OwnedHandle`. /// /// The provided handle must be asynchronous, as reading and /// writing from and to it is implemented using asynchronous APIs. @@ -135,7 +135,7 @@ impl From for process::ChildStdout { } } -/// Create a `ChildStderr` from the provided `OwnedHandle`. +/// Creates a `ChildStderr` from the provided `OwnedHandle`. /// /// The provided handle must be asynchronous, as reading and /// writing from and to it is implemented using asynchronous APIs. diff --git a/library/std/src/os/xous/ffi.rs b/library/std/src/os/xous/ffi.rs index e9a9f53372026..1a4a940bf358a 100644 --- a/library/std/src/os/xous/ffi.rs +++ b/library/std/src/os/xous/ffi.rs @@ -274,7 +274,7 @@ fn connect_impl(address: ServerAddress, blocking: bool) -> Result Result { connect_impl(address, true) } -/// Attempt to connect to a Xous server represented by the specified `address`. +/// Attempts to connect to a Xous server represented by the specified `address`. /// /// If the server does not exist then None is returned. pub(crate) fn try_connect(address: ServerAddress) -> Result, Error> { @@ -293,7 +293,7 @@ pub(crate) fn try_connect(address: ServerAddress) -> Result, } } -/// Terminate the current process and return the specified code to the parent process. +/// Terminates the current process and returns the specified code to the parent process. pub(crate) fn exit(return_code: u32) -> ! { let a0 = Syscall::TerminateProcess as usize; let a1 = return_code as usize; @@ -320,7 +320,7 @@ pub(crate) fn exit(return_code: u32) -> ! { unreachable!(); } -/// Suspend the current thread and allow another thread to run. This thread may +/// Suspends the current thread and allow another thread to run. This thread may /// continue executing again immediately if there are no other threads available /// to run on the system. pub(crate) fn do_yield() { @@ -348,9 +348,11 @@ pub(crate) fn do_yield() { }; } -/// Allocate memory from the system. An optional physical and/or virtual address -/// may be specified in order to ensure memory is allocated at specific offsets, -/// otherwise the kernel will select an address. +/// Allocates memory from the system. +/// +/// An optional physical and/or virtual address may be specified in order to +/// ensure memory is allocated at specific offsets, otherwise the kernel will +/// select an address. /// /// # Safety /// @@ -400,7 +402,7 @@ pub(crate) unsafe fn map_memory( } } -/// Destroy the given memory, returning it to the compiler. +/// Destroys the given memory, returning it to the compiler. /// /// Safety: The memory pointed to by `range` should not be used after this /// function returns, even if this function returns Err(). @@ -439,9 +441,10 @@ pub(crate) unsafe fn unmap_memory(range: *mut [T]) -> Result<(), Error> { } } -/// Adjust the memory flags for the given range. This can be used to remove flags -/// from a given region in order to harden memory access. Note that flags may -/// only be removed and may never be added. +/// Adjusts the memory flags for the given range. +/// +/// This can be used to remove flags from a given region in order to harden +/// memory access. Note that flags may only be removed and may never be added. /// /// Safety: The memory pointed to by `range` may become inaccessible or have its /// mutability removed. It is up to the caller to ensure that the flags specified @@ -484,7 +487,7 @@ pub(crate) unsafe fn update_memory_flags( } } -/// Create a thread with a given stack and up to four arguments +/// Creates a thread with a given stack and up to four arguments. pub(crate) fn create_thread( start: *mut usize, stack: *mut [u8], @@ -527,7 +530,7 @@ pub(crate) fn create_thread( } } -/// Wait for the given thread to terminate and return the exit code from that thread. +/// Waits for the given thread to terminate and returns the exit code from that thread. pub(crate) fn join_thread(thread_id: ThreadId) -> Result { let mut a0 = Syscall::JoinThread as usize; let mut a1 = thread_id.into(); @@ -567,7 +570,7 @@ pub(crate) fn join_thread(thread_id: ThreadId) -> Result { } } -/// Get the current thread's ID +/// Gets the current thread's ID. pub(crate) fn thread_id() -> Result { let mut a0 = Syscall::GetThreadId as usize; let mut a1 = 0; @@ -603,7 +606,7 @@ pub(crate) fn thread_id() -> Result { } } -/// Adjust the given `knob` limit to match the new value `new`. The current value must +/// Adjusts the given `knob` limit to match the new value `new`. The current value must /// match the `current` in order for this to take effect. /// /// The new value is returned as a result of this call. If the call fails, then the old diff --git a/library/std/src/os/xous/services.rs b/library/std/src/os/xous/services.rs index a75be1b857003..bc4558d9981be 100644 --- a/library/std/src/os/xous/services.rs +++ b/library/std/src/os/xous/services.rs @@ -83,7 +83,7 @@ mod ns { } } -/// Attempt to connect to a server by name. If the server does not exist, this will +/// Attempts to connect to a server by name. If the server does not exist, this will /// block until the server is created. /// /// Note that this is different from connecting to a server by address. Server @@ -94,7 +94,7 @@ pub fn connect(name: &str) -> Option { ns::connect_with_name(name) } -/// Attempt to connect to a server by name. If the server does not exist, this will +/// Attempts to connect to a server by name. If the server does not exist, this will /// immediately return `None`. /// /// Note that this is different from connecting to a server by address. Server @@ -107,7 +107,7 @@ pub fn try_connect(name: &str) -> Option { static NAME_SERVER_CONNECTION: AtomicU32 = AtomicU32::new(0); -/// Return a `Connection` to the name server. If the name server has not been started, +/// Returns a `Connection` to the name server. If the name server has not been started, /// then this call will block until the name server has been started. The `Connection` /// will be shared among all connections in a process, so it is safe to call this /// multiple times. diff --git a/library/std/src/os/xous/services/dns.rs b/library/std/src/os/xous/services/dns.rs index a7d88f4892cda..6ea453e06360b 100644 --- a/library/std/src/os/xous/services/dns.rs +++ b/library/std/src/os/xous/services/dns.rs @@ -13,7 +13,7 @@ impl Into for DnsLendMut { } } -/// Return a `Connection` to the DNS lookup server. This server is used for +/// Returns a `Connection` to the DNS lookup server. This server is used for /// querying domain name values. pub(crate) fn dns_server() -> Connection { static DNS_CONNECTION: AtomicU32 = AtomicU32::new(0); diff --git a/library/std/src/os/xous/services/log.rs b/library/std/src/os/xous/services/log.rs index 55a501dc7d00e..0ecc4bcfd146e 100644 --- a/library/std/src/os/xous/services/log.rs +++ b/library/std/src/os/xous/services/log.rs @@ -1,10 +1,10 @@ use crate::os::xous::ffi::Connection; use core::sync::atomic::{AtomicU32, Ordering}; -/// Group `usize` bytes into a `usize` and return it, beginning -/// from `offset` * sizeof(usize) bytes from the start. For example, -/// `group_or_null([1,2,3,4,5,6,7,8], 1)` on a 32-bit system will -/// return a usize with 5678 packed into it. +/// Group a `usize` worth of bytes into a `usize` and return it, beginning from +/// `offset` * sizeof(usize) bytes from the start. For example, +/// `group_or_null([1,2,3,4,5,6,7,8], 1)` on a 32-bit system will return a +/// `usize` with 5678 packed into it. fn group_or_null(data: &[u8], offset: usize) -> usize { let start = offset * core::mem::size_of::(); let mut out_array = [0u8; core::mem::size_of::()]; @@ -56,10 +56,12 @@ impl Into for LogLend { } } -/// Return a `Connection` to the log server, which is used for printing messages to -/// the console and reporting panics. If the log server has not yet started, this -/// will block until the server is running. It is safe to call this multiple times, -/// because the address is shared among all threads in a process. +/// Returns a `Connection` to the log server, which is used for printing messages to +/// the console and reporting panics. +/// +/// If the log server has not yet started, this will block until the server is +/// running. It is safe to call this multiple times, because the address is +/// shared among all threads in a process. pub(crate) fn log_server() -> Connection { static LOG_SERVER_CONNECTION: AtomicU32 = AtomicU32::new(0); diff --git a/library/std/src/os/xous/services/net.rs b/library/std/src/os/xous/services/net.rs index 26d337dcef168..c7b9ac9f5d59b 100644 --- a/library/std/src/os/xous/services/net.rs +++ b/library/std/src/os/xous/services/net.rs @@ -80,7 +80,7 @@ impl<'a> Into<[usize; 5]> for NetBlockingScalar { } } -/// Return a `Connection` to the Network server. This server provides all +/// Returns a `Connection` to the Network server. This server provides all /// OS-level networking functions. pub(crate) fn net_server() -> Connection { static NET_CONNECTION: AtomicU32 = AtomicU32::new(0); diff --git a/library/std/src/os/xous/services/systime.rs b/library/std/src/os/xous/services/systime.rs index bbb875c69426e..40f70b4db819b 100644 --- a/library/std/src/os/xous/services/systime.rs +++ b/library/std/src/os/xous/services/systime.rs @@ -13,7 +13,7 @@ impl Into<[usize; 5]> for SystimeScalar { } } -/// Return a `Connection` to the systime server. This server is used for reporting the +/// Returns a `Connection` to the systime server. This server is used for reporting the /// realtime clock. pub(crate) fn systime_server() -> Connection { static SYSTIME_SERVER_CONNECTION: AtomicU32 = AtomicU32::new(0); diff --git a/library/std/src/os/xous/services/ticktimer.rs b/library/std/src/os/xous/services/ticktimer.rs index 7759303fdbe23..c94e7710fabd8 100644 --- a/library/std/src/os/xous/services/ticktimer.rs +++ b/library/std/src/os/xous/services/ticktimer.rs @@ -27,7 +27,7 @@ impl Into<[usize; 5]> for TicktimerScalar { } } -/// Return a `Connection` to the ticktimer server. This server is used for synchronization +/// Returns a `Connection` to the ticktimer server. This server is used for synchronization /// primitives such as sleep, Mutex, and Condvar. pub(crate) fn ticktimer_server() -> Connection { static TICKTIMER_SERVER_CONNECTION: AtomicU32 = AtomicU32::new(0); diff --git a/library/std/src/panic.rs b/library/std/src/panic.rs index c5d1a893ee809..b0c7804fd2bed 100644 --- a/library/std/src/panic.rs +++ b/library/std/src/panic.rs @@ -249,7 +249,7 @@ pub use core::panic::Location; #[stable(feature = "catch_unwind", since = "1.9.0")] pub use core::panic::{AssertUnwindSafe, RefUnwindSafe, UnwindSafe}; -/// Panic the current thread with the given message as the panic payload. +/// Panics the current thread with the given message as the panic payload. /// /// The message can be of any (`Any + Send`) type, not just strings. /// @@ -380,7 +380,7 @@ pub fn resume_unwind(payload: Box) -> ! { panicking::rust_panic_without_hook(payload) } -/// Make all future panics abort directly without running the panic hook or unwinding. +/// Makes all future panics abort directly without running the panic hook or unwinding. /// /// There is no way to undo this; the effect lasts until the process exits or /// execs (or the equivalent). @@ -461,7 +461,7 @@ impl BacktraceStyle { // Internally stores equivalent of an Option. static SHOULD_CAPTURE: AtomicU8 = AtomicU8::new(0); -/// Configure whether the default panic hook will capture and display a +/// Configures whether the default panic hook will capture and display a /// backtrace. /// /// The default value for this setting may be set by the `RUST_BACKTRACE` diff --git a/library/std/src/path.rs b/library/std/src/path.rs index 0cef862549c8a..46a1953743ffa 100644 --- a/library/std/src/path.rs +++ b/library/std/src/path.rs @@ -1797,7 +1797,7 @@ impl> From<&T> for PathBuf { #[stable(feature = "rust1", since = "1.0.0")] impl From for PathBuf { - /// Converts an [`OsString`] into a [`PathBuf`] + /// Converts an [`OsString`] into a [`PathBuf`]. /// /// This conversion does not allocate or copy memory. #[inline] diff --git a/library/std/src/process.rs b/library/std/src/process.rs index fc86578a5ff2f..a2222bd11b1d0 100644 --- a/library/std/src/process.rs +++ b/library/std/src/process.rs @@ -2056,7 +2056,7 @@ impl ExitCode { // representation of an ExitCode // // More info: https://internals.rust-lang.org/t/mini-pre-rfc-redesigning-process-exitstatus/5426 - /// Convert an `ExitCode` into an i32 + /// Converts an `ExitCode` into an i32 #[unstable( feature = "process_exitcode_internals", reason = "exposed only for libstd", @@ -2079,7 +2079,7 @@ impl Default for ExitCode { #[stable(feature = "process_exitcode", since = "1.61.0")] impl From for ExitCode { - /// Construct an `ExitCode` from an arbitrary u8 value. + /// Constructs an `ExitCode` from an arbitrary u8 value. fn from(code: u8) -> Self { ExitCode(imp::ExitCode::from(code)) } diff --git a/library/std/src/sync/lazy_lock.rs b/library/std/src/sync/lazy_lock.rs index 18906aceffa30..9fe9ccab4a9f7 100644 --- a/library/std/src/sync/lazy_lock.rs +++ b/library/std/src/sync/lazy_lock.rs @@ -175,7 +175,7 @@ impl T> LazyLock { } impl LazyLock { - /// Get the inner value if it has already been initialized. + /// Gets the inner value if it has already been initialized. fn get(&self) -> Option<&T> { if self.once.is_completed() { // SAFETY: diff --git a/library/std/src/sync/once_lock.rs b/library/std/src/sync/once_lock.rs index 94955beaf37b7..60e43a1cde10e 100644 --- a/library/std/src/sync/once_lock.rs +++ b/library/std/src/sync/once_lock.rs @@ -578,7 +578,7 @@ impl Clone for OnceLock { #[stable(feature = "once_cell", since = "1.70.0")] impl From for OnceLock { - /// Create a new cell with its contents set to `value`. + /// Creates a new cell with its contents set to `value`. /// /// # Example /// diff --git a/library/std/src/sync/poison.rs b/library/std/src/sync/poison.rs index f4975088b372d..d71643b500073 100644 --- a/library/std/src/sync/poison.rs +++ b/library/std/src/sync/poison.rs @@ -31,13 +31,13 @@ impl Flag { } } - /// Check the flag for an unguarded borrow, where we only care about existing poison. + /// Checks the flag for an unguarded borrow, where we only care about existing poison. #[inline] pub fn borrow(&self) -> LockResult<()> { if self.get() { Err(PoisonError::new(())) } else { Ok(()) } } - /// Check the flag for a guarded borrow, where we may also set poison when `done`. + /// Checks the flag for a guarded borrow, where we may also set poison when `done`. #[inline] pub fn guard(&self) -> LockResult { let ret = Guard { diff --git a/library/std/src/sync/rwlock.rs b/library/std/src/sync/rwlock.rs index 761e3e21ede7e..f7e133163a456 100644 --- a/library/std/src/sync/rwlock.rs +++ b/library/std/src/sync/rwlock.rs @@ -589,7 +589,7 @@ impl<'rwlock, T: ?Sized> RwLockReadGuard<'rwlock, T> { } impl<'rwlock, T: ?Sized> RwLockWriteGuard<'rwlock, T> { - /// Create a new instance of `RwLockWriteGuard` from a `RwLock`. + /// Creates a new instance of `RwLockWriteGuard` from a `RwLock`. // SAFETY: if and only if `lock.inner.write()` (or `lock.inner.try_write()`) has been // successfully called from the same thread before instantiating this object. unsafe fn new(lock: &'rwlock RwLock) -> LockResult> { diff --git a/library/std/src/sys/pal/itron/error.rs b/library/std/src/sys/pal/itron/error.rs index fbc822d4eb6e1..dab0aa7b92de3 100644 --- a/library/std/src/sys/pal/itron/error.rs +++ b/library/std/src/sys/pal/itron/error.rs @@ -9,7 +9,7 @@ pub struct ItronError { } impl ItronError { - /// Construct `ItronError` from the specified error code. Returns `None` if the + /// Constructs `ItronError` from the specified error code. Returns `None` if the /// error code does not represent a failure or warning. #[inline] pub fn new(er: abi::ER) -> Option { @@ -22,7 +22,7 @@ impl ItronError { if let Some(error) = Self::new(er) { Err(error) } else { Ok(er) } } - /// Get the raw error code. + /// Gets the raw error code. #[inline] pub fn as_raw(&self) -> abi::ER { self.er diff --git a/library/std/src/sys/pal/itron/task.rs b/library/std/src/sys/pal/itron/task.rs index 94beb50a2541b..82b9b9bfd3ae4 100644 --- a/library/std/src/sys/pal/itron/task.rs +++ b/library/std/src/sys/pal/itron/task.rs @@ -5,19 +5,19 @@ use super::{ use crate::mem::MaybeUninit; -/// Get the ID of the task in Running state. Panics on failure. +/// Gets the ID of the task in Running state. Panics on failure. #[inline] pub fn current_task_id() -> abi::ID { try_current_task_id().unwrap_or_else(|e| fail(e, &"get_tid")) } -/// Get the ID of the task in Running state. Aborts on failure. +/// Gets the ID of the task in Running state. Aborts on failure. #[inline] pub fn current_task_id_aborting() -> abi::ID { try_current_task_id().unwrap_or_else(|e| fail_aborting(e, &"get_tid")) } -/// Get the ID of the task in Running state. +/// Gets the ID of the task in Running state. #[inline] pub fn try_current_task_id() -> Result { unsafe { @@ -27,13 +27,13 @@ pub fn try_current_task_id() -> Result { } } -/// Get the specified task's priority. Panics on failure. +/// Gets the specified task's priority. Panics on failure. #[inline] pub fn task_priority(task: abi::ID) -> abi::PRI { try_task_priority(task).unwrap_or_else(|e| fail(e, &"get_pri")) } -/// Get the specified task's priority. +/// Gets the specified task's priority. #[inline] pub fn try_task_priority(task: abi::ID) -> Result { unsafe { diff --git a/library/std/src/sys/pal/itron/thread.rs b/library/std/src/sys/pal/itron/thread.rs index fd7b5558f7566..83581037706d6 100644 --- a/library/std/src/sys/pal/itron/thread.rs +++ b/library/std/src/sys/pal/itron/thread.rs @@ -308,7 +308,7 @@ impl Drop for Thread { } } -/// Terminate and delete the specified task. +/// Terminates and deletes the specified task. /// /// This function will abort if `deleted_task` refers to the calling task. /// @@ -337,7 +337,7 @@ unsafe fn terminate_and_delete_task(deleted_task: abi::ID) { expect_success_aborting(unsafe { abi::del_tsk(deleted_task) }, &"del_tsk"); } -/// Terminate and delete the calling task. +/// Terminates and deletes the calling task. /// /// Atomicity is not required - i.e., it can be assumed that other threads won't /// `ter_tsk` the calling task while this function is still in progress. (This diff --git a/library/std/src/sys/pal/sgx/abi/usercalls/alloc.rs b/library/std/src/sys/pal/sgx/abi/usercalls/alloc.rs index b625636752cc1..cf3ce60dc3d3c 100644 --- a/library/std/src/sys/pal/sgx/abi/usercalls/alloc.rs +++ b/library/std/src/sys/pal/sgx/abi/usercalls/alloc.rs @@ -67,7 +67,7 @@ pub unsafe trait UserSafe { /// Equivalent to `mem::align_of::`. fn align_of() -> usize; - /// Construct a pointer to `Self` given a memory range in user space. + /// Constructs a pointer to `Self` given a memory range in user space. /// /// N.B., this takes a size, not a length! /// @@ -77,7 +77,7 @@ pub unsafe trait UserSafe { /// correct size and is correctly aligned and points to the right type. unsafe fn from_raw_sized_unchecked(ptr: *mut u8, size: usize) -> *mut Self; - /// Construct a pointer to `Self` given a memory range. + /// Constructs a pointer to `Self` given a memory range. /// /// N.B., this takes a size, not a length! /// @@ -276,7 +276,7 @@ impl User where T: UserSafe, { - /// Allocate space for `T` in user memory. + /// Allocates space for `T` in user memory. pub fn uninitialized() -> Self { Self::new_uninit_bytes(mem::size_of::()) } @@ -287,7 +287,7 @@ impl User<[T]> where [T]: UserSafe, { - /// Allocate space for a `[T]` of `n` elements in user memory. + /// Allocates space for a `[T]` of `n` elements in user memory. pub fn uninitialized(n: usize) -> Self { Self::new_uninit_bytes(n * mem::size_of::()) } diff --git a/library/std/src/sys/pal/sgx/abi/usercalls/mod.rs b/library/std/src/sys/pal/sgx/abi/usercalls/mod.rs index e19e843267a90..def1ccdf81ac0 100644 --- a/library/std/src/sys/pal/sgx/abi/usercalls/mod.rs +++ b/library/std/src/sys/pal/sgx/abi/usercalls/mod.rs @@ -171,10 +171,12 @@ pub fn wait(event_mask: u64, mut timeout: u64) -> IoResult { unsafe { raw::wait(event_mask, timeout).from_sgx_result() } } -/// This function makes an effort to wait for a non-spurious event at least as -/// long as `duration`. Note that in general there is no guarantee about accuracy -/// of time and timeouts in SGX model. The enclave runner serving usercalls may -/// lie about current time and/or ignore timeout values. +/// Makes an effort to wait for a non-spurious event at least as long as +/// `duration`. +/// +/// Note that in general there is no guarantee about accuracy of time and +/// timeouts in SGX model. The enclave runner serving usercalls may lie about +/// current time and/or ignore timeout values. /// /// Once the event is observed, `should_wake_up` will be used to determine /// whether or not the event was spurious. diff --git a/library/std/src/sys/pal/uefi/args.rs b/library/std/src/sys/pal/uefi/args.rs index 18a69afa7d91b..ca6bdfc55eb66 100644 --- a/library/std/src/sys/pal/uefi/args.rs +++ b/library/std/src/sys/pal/uefi/args.rs @@ -76,7 +76,7 @@ impl DoubleEndedIterator for Args { /// This implementation is based on what is defined in Section 3.4 of /// [UEFI Shell Specification](https://uefi.org/sites/default/files/resources/UEFI_Shell_Spec_2_0.pdf) /// -/// Return None in the following cases: +/// Returns None in the following cases: /// - Invalid UTF-16 (unpaired surrogate) /// - Empty/improper arguments fn parse_lp_cmd_line(code_units: &[u16]) -> Option> { diff --git a/library/std/src/sys/pal/uefi/helpers.rs b/library/std/src/sys/pal/uefi/helpers.rs index 29984a915b894..586dbd84af2d4 100644 --- a/library/std/src/sys/pal/uefi/helpers.rs +++ b/library/std/src/sys/pal/uefi/helpers.rs @@ -30,8 +30,9 @@ type BootUninstallMultipleProtocolInterfaces = const BOOT_SERVICES_UNAVAILABLE: io::Error = const_io_error!(io::ErrorKind::Other, "Boot Services are no longer available"); -/// Locate Handles with a particular Protocol GUID -/// Implemented using `EFI_BOOT_SERVICES.LocateHandles()` +/// Locates Handles with a particular Protocol GUID. +/// +/// Implemented using `EFI_BOOT_SERVICES.LocateHandles()`. /// /// Returns an array of [Handles](r_efi::efi::Handle) that support a specified protocol. pub(crate) fn locate_handles(mut guid: Guid) -> io::Result>> { @@ -148,8 +149,9 @@ pub(crate) unsafe fn close_event(evt: NonNull) -> io::Result if r.is_error() { Err(crate::io::Error::from_raw_os_error(r.as_usize())) } else { Ok(()) } } -/// Get the Protocol for current system handle. -/// Note: Some protocols need to be manually freed. It is the callers responsibility to do so. +/// Gets the Protocol for current system handle. +/// +/// Note: Some protocols need to be manually freed. It is the caller's responsibility to do so. pub(crate) fn image_handle_protocol(protocol_guid: Guid) -> io::Result> { let system_handle = uefi::env::try_image_handle().ok_or(io::const_io_error!( io::ErrorKind::NotFound, @@ -220,7 +222,7 @@ pub(crate) fn device_path_to_text(path: NonNull) -> io::R Err(io::const_io_error!(io::ErrorKind::NotFound, "No device path to text protocol found")) } -/// Get RuntimeServices +/// Gets RuntimeServices. pub(crate) fn runtime_services() -> Option> { let system_table: NonNull = crate::os::uefi::env::try_system_table()?.cast(); diff --git a/library/std/src/sys/pal/unix/futex.rs b/library/std/src/sys/pal/unix/futex.rs index b8900da4cddb5..cc725045c4810 100644 --- a/library/std/src/sys/pal/unix/futex.rs +++ b/library/std/src/sys/pal/unix/futex.rs @@ -16,7 +16,7 @@ pub type SmallAtomic = AtomicU32; /// Must be the underlying type of SmallAtomic pub type SmallPrimitive = u32; -/// Wait for a futex_wake operation to wake us. +/// Waits for a `futex_wake` operation to wake us. /// /// Returns directly if the futex doesn't hold the expected value. /// @@ -87,7 +87,7 @@ pub fn futex_wait(futex: &AtomicU32, expected: u32, timeout: Option) - } } -/// Wake up one thread that's blocked on futex_wait on this futex. +/// Wakes up one thread that's blocked on `futex_wait` on this futex. /// /// Returns true if this actually woke up such a thread, /// or false if no thread was waiting on this futex. @@ -100,7 +100,7 @@ pub fn futex_wake(futex: &AtomicU32) -> bool { unsafe { libc::syscall(libc::SYS_futex, ptr, op, 1) > 0 } } -/// Wake up all threads that are waiting on futex_wait on this futex. +/// Wakes up all threads that are waiting on `futex_wait` on this futex. #[cfg(any(target_os = "linux", target_os = "android"))] pub fn futex_wake_all(futex: &AtomicU32) { let ptr = futex as *const AtomicU32; diff --git a/library/std/src/sys/pal/unix/mod.rs b/library/std/src/sys/pal/unix/mod.rs index bdb995876ff2c..7f5a8d0ce852b 100644 --- a/library/std/src/sys/pal/unix/mod.rs +++ b/library/std/src/sys/pal/unix/mod.rs @@ -308,7 +308,7 @@ macro_rules! impl_is_minus_one { impl_is_minus_one! { i8 i16 i32 i64 isize } -/// Convert native return values to Result using the *-1 means error is in `errno`* convention. +/// Converts native return values to Result using the *-1 means error is in `errno`* convention. /// Non-error values are `Ok`-wrapped. pub fn cvt(t: T) -> crate::io::Result { if t.is_minus_one() { Err(crate::io::Error::last_os_error()) } else { Ok(t) } diff --git a/library/std/src/sys/pal/unix/process/process_unix.rs b/library/std/src/sys/pal/unix/process/process_unix.rs index abd4a334783e4..4e4dd3040feeb 100644 --- a/library/std/src/sys/pal/unix/process/process_unix.rs +++ b/library/std/src/sys/pal/unix/process/process_unix.rs @@ -1047,7 +1047,7 @@ impl From for ExitStatus { } } -/// Convert a signal number to a readable, searchable name. +/// Converts a signal number to a readable, searchable name. /// /// This string should be displayed right after the signal number. /// If a signal is unrecognized, it returns the empty string, so that diff --git a/library/std/src/sys/pal/wasm/atomics/futex.rs b/library/std/src/sys/pal/wasm/atomics/futex.rs index 3584138ca0447..42913a99ee9d6 100644 --- a/library/std/src/sys/pal/wasm/atomics/futex.rs +++ b/library/std/src/sys/pal/wasm/atomics/futex.rs @@ -24,7 +24,7 @@ pub fn futex_wait(futex: &AtomicU32, expected: u32, timeout: Option) - } } -/// Wake up one thread that's blocked on futex_wait on this futex. +/// Wakes up one thread that's blocked on `futex_wait` on this futex. /// /// Returns true if this actually woke up such a thread, /// or false if no thread was waiting on this futex. @@ -32,7 +32,7 @@ pub fn futex_wake(futex: &AtomicU32) -> bool { unsafe { wasm::memory_atomic_notify(futex as *const AtomicU32 as *mut i32, 1) > 0 } } -/// Wake up all threads that are waiting on futex_wait on this futex. +/// Wakes up all threads that are waiting on `futex_wait` on this futex. pub fn futex_wake_all(futex: &AtomicU32) { unsafe { wasm::memory_atomic_notify(futex as *const AtomicU32 as *mut i32, i32::MAX as u32); diff --git a/library/std/src/sys/pal/windows/fs.rs b/library/std/src/sys/pal/windows/fs.rs index ea19bd1e96193..a0a48fe759042 100644 --- a/library/std/src/sys/pal/windows/fs.rs +++ b/library/std/src/sys/pal/windows/fs.rs @@ -637,7 +637,7 @@ impl File { Ok(()) } - /// Get only basic file information such as attributes and file times. + /// Gets only basic file information such as attributes and file times. fn basic_info(&self) -> io::Result { unsafe { let mut info: c::FILE_BASIC_INFO = mem::zeroed(); diff --git a/library/std/src/sys/pal/windows/process.rs b/library/std/src/sys/pal/windows/process.rs index 76d2cb77d474c..288ddb3e8011f 100644 --- a/library/std/src/sys/pal/windows/process.rs +++ b/library/std/src/sys/pal/windows/process.rs @@ -549,7 +549,7 @@ where None } -/// Check if a file exists without following symlinks. +/// Checks if a file exists without following symlinks. fn program_exists(path: &Path) -> Option> { unsafe { let path = args::to_user_path(path).ok()?; diff --git a/library/std/src/sys/pal/windows/time.rs b/library/std/src/sys/pal/windows/time.rs index b853daeffebd7..55ff233521acc 100644 --- a/library/std/src/sys/pal/windows/time.rs +++ b/library/std/src/sys/pal/windows/time.rs @@ -230,7 +230,7 @@ pub(super) struct WaitableTimer { handle: c::HANDLE, } impl WaitableTimer { - /// Create a high-resolution timer. Will fail before Windows 10, version 1803. + /// Creates a high-resolution timer. Will fail before Windows 10, version 1803. pub fn high_resolution() -> Result { let handle = unsafe { c::CreateWaitableTimerExW( diff --git a/library/std/src/sys/path/windows.rs b/library/std/src/sys/path/windows.rs index cebc791023115..9bd206ae1bf6e 100644 --- a/library/std/src/sys/path/windows.rs +++ b/library/std/src/sys/path/windows.rs @@ -218,7 +218,7 @@ pub(crate) fn maybe_verbatim(path: &Path) -> io::Result> { get_long_path(path, true) } -/// Get a normalized absolute path that can bypass path length limits. +/// Gets a normalized absolute path that can bypass path length limits. /// /// Setting prefer_verbatim to true suggests a stronger preference for verbatim /// paths even when not strictly necessary. This allows the Windows API to avoid diff --git a/library/std/src/sys/personality/dwarf/eh.rs b/library/std/src/sys/personality/dwarf/eh.rs index ff88ef4e0e1d0..0b81ea9e3d21e 100644 --- a/library/std/src/sys/personality/dwarf/eh.rs +++ b/library/std/src/sys/personality/dwarf/eh.rs @@ -170,7 +170,7 @@ fn round_up(unrounded: usize, align: usize) -> Result { if align.is_power_of_two() { Ok((unrounded + align - 1) & !(align - 1)) } else { Err(()) } } -/// Read a offset (`usize`) from `reader` whose encoding is described by `encoding`. +/// Reads an offset (`usize`) from `reader` whose encoding is described by `encoding`. /// /// `encoding` must be a [DWARF Exception Header Encoding as described by the LSB spec][LSB-dwarf-ext]. /// In addition the upper ("application") part must be zero. @@ -202,7 +202,7 @@ unsafe fn read_encoded_offset(reader: &mut DwarfReader, encoding: u8) -> Result< Ok(result) } -/// Read a pointer from `reader` whose encoding is described by `encoding`. +/// Reads a pointer from `reader` whose encoding is described by `encoding`. /// /// `encoding` must be a [DWARF Exception Header Encoding as described by the LSB spec][LSB-dwarf-ext]. /// diff --git a/library/std/src/sys/sync/mutex/itron.rs b/library/std/src/sys/sync/mutex/itron.rs index b29c7e1d03444..a72c30d1fe373 100644 --- a/library/std/src/sys/sync/mutex/itron.rs +++ b/library/std/src/sys/sync/mutex/itron.rs @@ -13,7 +13,7 @@ pub struct Mutex { mtx: SpinIdOnceCell<()>, } -/// Create a mutex object. This function never panics. +/// Creates a mutex object. This function never panics. fn new_mtx() -> Result { ItronError::err_if_negative(unsafe { abi::acre_mtx(&abi::T_CMTX { @@ -31,7 +31,7 @@ impl Mutex { Mutex { mtx: SpinIdOnceCell::new() } } - /// Get the inner mutex's ID, which is lazily created. + /// Gets the inner mutex's ID, which is lazily created. fn raw(&self) -> abi::ID { match self.mtx.get_or_try_init(|| new_mtx().map(|id| (id, ()))) { Ok((id, ())) => id, diff --git a/library/std/src/sys/sync/rwlock/futex.rs b/library/std/src/sys/sync/rwlock/futex.rs index da4b2fbed7ce7..4b59599b5f2a8 100644 --- a/library/std/src/sys/sync/rwlock/futex.rs +++ b/library/std/src/sys/sync/rwlock/futex.rs @@ -264,7 +264,7 @@ impl RwLock { } } - /// Wake up waiting threads after unlocking. + /// Wakes up waiting threads after unlocking. /// /// If both are waiting, this will wake up only one writer, but will fall /// back to waking up readers if there was no writer to wake up. diff --git a/library/std/src/sys/sync/rwlock/queue.rs b/library/std/src/sys/sync/rwlock/queue.rs index 5bea6268f68a1..5de4421189eb7 100644 --- a/library/std/src/sys/sync/rwlock/queue.rs +++ b/library/std/src/sys/sync/rwlock/queue.rs @@ -186,7 +186,7 @@ struct Node { } impl Node { - /// Create a new queue node. + /// Creates a new queue node. fn new(write: bool) -> Node { Node { next: AtomicLink::new(None), diff --git a/library/std/src/sys/sync/rwlock/solid.rs b/library/std/src/sys/sync/rwlock/solid.rs index f7f399dfdc449..f961d4ed1e0ec 100644 --- a/library/std/src/sys/sync/rwlock/solid.rs +++ b/library/std/src/sys/sync/rwlock/solid.rs @@ -28,7 +28,7 @@ impl RwLock { RwLock { rwl: SpinIdOnceCell::new() } } - /// Get the inner mutex's ID, which is lazily created. + /// Gets the inner mutex's ID, which is lazily created. fn raw(&self) -> abi::ID { match self.rwl.get_or_try_init(|| new_rwl().map(|id| (id, ()))) { Ok((id, ())) => id, diff --git a/library/std/src/sys/sync/thread_parking/futex.rs b/library/std/src/sys/sync/thread_parking/futex.rs index 034eececb2a28..ce852eaadc4d9 100644 --- a/library/std/src/sys/sync/thread_parking/futex.rs +++ b/library/std/src/sys/sync/thread_parking/futex.rs @@ -36,7 +36,7 @@ pub struct Parker { // Ordering::Release when writing NOTIFIED (the 'token') in unpark(), and using // Ordering::Acquire when checking for this state in park(). impl Parker { - /// Construct the futex parker. The UNIX parker implementation + /// Constructs the futex parker. The UNIX parker implementation /// requires this to happen in-place. pub unsafe fn new_in_place(parker: *mut Parker) { unsafe { parker.write(Self { state: Atomic::new(EMPTY) }) }; diff --git a/library/std/src/sys/sync/thread_parking/id.rs b/library/std/src/sys/sync/thread_parking/id.rs index 0466743966034..57c4daefd55f8 100644 --- a/library/std/src/sys/sync/thread_parking/id.rs +++ b/library/std/src/sys/sync/thread_parking/id.rs @@ -30,7 +30,7 @@ impl Parker { Parker { state: AtomicI8::new(EMPTY), tid: UnsafeCell::new(None) } } - /// Create a new thread parker. UNIX requires this to happen in-place. + /// Creates a new thread parker. UNIX requires this to happen in-place. pub unsafe fn new_in_place(parker: *mut Parker) { parker.write(Parker::new()) } diff --git a/library/std/src/sys/sync/thread_parking/pthread.rs b/library/std/src/sys/sync/thread_parking/pthread.rs index fdac1096dbfc1..c64600e9e29c3 100644 --- a/library/std/src/sys/sync/thread_parking/pthread.rs +++ b/library/std/src/sys/sync/thread_parking/pthread.rs @@ -92,7 +92,7 @@ pub struct Parker { } impl Parker { - /// Construct the UNIX parker in-place. + /// Constructs the UNIX parker in-place. /// /// # Safety /// The constructed parker must never be moved. diff --git a/library/std/src/sys/sync/thread_parking/windows7.rs b/library/std/src/sys/sync/thread_parking/windows7.rs index 3a8d40dc5cfac..d19df84774647 100644 --- a/library/std/src/sys/sync/thread_parking/windows7.rs +++ b/library/std/src/sys/sync/thread_parking/windows7.rs @@ -95,7 +95,7 @@ const NOTIFIED: i8 = 1; // Ordering::Release when writing NOTIFIED (the 'token') in unpark(), and using // Ordering::Acquire when reading this state in park() after waking up. impl Parker { - /// Construct the Windows parker. The UNIX parker implementation + /// Constructs the Windows parker. The UNIX parker implementation /// requires this to happen in-place. pub unsafe fn new_in_place(parker: *mut Parker) { parker.write(Self { state: AtomicI8::new(EMPTY) }); diff --git a/library/std/src/sys/thread_local/key/xous.rs b/library/std/src/sys/thread_local/key/xous.rs index 5a837a33e190e..db6dd5a87bac6 100644 --- a/library/std/src/sys/thread_local/key/xous.rs +++ b/library/std/src/sys/thread_local/key/xous.rs @@ -79,7 +79,7 @@ fn tls_ptr_addr() -> *mut *mut u8 { core::ptr::with_exposed_provenance_mut::<*mut u8>(tp) } -/// Create an area of memory that's unique per thread. This area will +/// Creates an area of memory that's unique per thread. This area will /// contain all thread local pointers. fn tls_table() -> &'static mut [*mut u8] { let tp = tls_ptr_addr(); diff --git a/library/std/src/sys/thread_local/native/eager.rs b/library/std/src/sys/thread_local/native/eager.rs index 99e5ae7fb9687..f8cd31613adad 100644 --- a/library/std/src/sys/thread_local/native/eager.rs +++ b/library/std/src/sys/thread_local/native/eager.rs @@ -21,7 +21,7 @@ impl Storage { Storage { state: Cell::new(State::Initial), val: UnsafeCell::new(val) } } - /// Get a pointer to the TLS value. If the TLS variable has been destroyed, + /// Gets a pointer to the TLS value. If the TLS variable has been destroyed, /// a null pointer is returned. /// /// The resulting pointer may not be used after thread destruction has diff --git a/library/std/src/sys/thread_local/native/lazy.rs b/library/std/src/sys/thread_local/native/lazy.rs index 9d47e8ef68975..9c914834d6e07 100644 --- a/library/std/src/sys/thread_local/native/lazy.rs +++ b/library/std/src/sys/thread_local/native/lazy.rs @@ -39,7 +39,7 @@ where Storage { state: UnsafeCell::new(State::Initial) } } - /// Get a pointer to the TLS value, potentially initializing it with the + /// Gets a pointer to the TLS value, potentially initializing it with the /// provided parameters. If the TLS variable has been destroyed, a null /// pointer is returned. /// diff --git a/library/std/src/sys/thread_local/os.rs b/library/std/src/sys/thread_local/os.rs index e06185f00690b..e27b47c3f4536 100644 --- a/library/std/src/sys/thread_local/os.rs +++ b/library/std/src/sys/thread_local/os.rs @@ -60,7 +60,7 @@ impl Storage { Storage { key: LazyKey::new(Some(destroy_value::)), marker: PhantomData } } - /// Get a pointer to the TLS value, potentially initializing it with the + /// Gets a pointer to the TLS value, potentially initializing it with the /// provided parameters. If the TLS variable has been destroyed, a null /// pointer is returned. /// diff --git a/library/std/src/sys/thread_local/statik.rs b/library/std/src/sys/thread_local/statik.rs index 0f08cab1ae4ff..a3451ab74e04f 100644 --- a/library/std/src/sys/thread_local/statik.rs +++ b/library/std/src/sys/thread_local/statik.rs @@ -63,7 +63,7 @@ impl LazyStorage { LazyStorage { value: UnsafeCell::new(None) } } - /// Get a pointer to the TLS value, potentially initializing it with the + /// Gets a pointer to the TLS value, potentially initializing it with the /// provided parameters. /// /// The resulting pointer may not be used after reentrant inialialization diff --git a/library/std/src/sys_common/net.rs b/library/std/src/sys_common/net.rs index 95ca67fc2e0b6..0a82b50ae1ab6 100644 --- a/library/std/src/sys_common/net.rs +++ b/library/std/src/sys_common/net.rs @@ -42,6 +42,7 @@ cfg_if::cfg_if! { target_os = "hurd", target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd", target_os = "netbsd", + target_os = "solaris", target_os = "illumos", target_os = "haiku", target_os = "nto"))] { use libc::MSG_NOSIGNAL; } else { diff --git a/library/std/src/sys_common/wstr.rs b/library/std/src/sys_common/wstr.rs index 8eae160648502..f9a171fb7d8f5 100644 --- a/library/std/src/sys_common/wstr.rs +++ b/library/std/src/sys_common/wstr.rs @@ -15,7 +15,7 @@ pub struct WStrUnits<'a> { } impl WStrUnits<'_> { - /// Create the iterator. Returns `None` if `lpwstr` is null. + /// Creates the iterator. Returns `None` if `lpwstr` is null. /// /// SAFETY: `lpwstr` must point to a null-terminated wide string that lives /// at least as long as the lifetime of this struct. diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs index 40c0d44df900a..ce6a6afdc1914 100644 --- a/library/std/src/thread/mod.rs +++ b/library/std/src/thread/mod.rs @@ -849,7 +849,7 @@ pub fn panicking() -> bool { panicking::panicking() } -/// Use [`sleep`]. +/// Uses [`sleep`]. /// /// Puts the current thread to sleep for at least the specified amount of time. /// @@ -1120,7 +1120,7 @@ pub fn park() { forget(guard); } -/// Use [`park_timeout`]. +/// Uses [`park_timeout`]. /// /// Blocks unless or until the current thread's token is made available or /// the specified duration has been reached (may wake spuriously). diff --git a/library/std/src/thread/scoped.rs b/library/std/src/thread/scoped.rs index e2e22e5194f4a..fbd6f8feecfe7 100644 --- a/library/std/src/thread/scoped.rs +++ b/library/std/src/thread/scoped.rs @@ -67,7 +67,7 @@ impl ScopeData { } } -/// Create a scope for spawning scoped threads. +/// Creates a scope for spawning scoped threads. /// /// The function passed to `scope` will be provided a [`Scope`] object, /// through which scoped threads can be [spawned][`Scope::spawn`]. diff --git a/library/test/src/stats.rs b/library/test/src/stats.rs index b33b080126131..71c944afde8d6 100644 --- a/library/test/src/stats.rs +++ b/library/test/src/stats.rs @@ -116,7 +116,7 @@ pub struct Summary { } impl Summary { - /// Construct a new summary of a sample set. + /// Constructs a new summary of a sample set. pub fn new(samples: &[f64]) -> Summary { Summary { sum: samples.sum(), diff --git a/library/test/src/term/terminfo/searcher.rs b/library/test/src/term/terminfo/searcher.rs index 3e8ccc91ab051..8b8df34b0791e 100644 --- a/library/test/src/term/terminfo/searcher.rs +++ b/library/test/src/term/terminfo/searcher.rs @@ -9,7 +9,7 @@ use std::path::PathBuf; #[cfg(test)] mod tests; -/// Return path to database entry for `term` +/// Returns path to database entry for `term` #[allow(deprecated)] pub(crate) fn get_dbpath_for_term(term: &str) -> Option { let mut dirs_to_search = Vec::new(); diff --git a/src/bootstrap/src/core/build_steps/check.rs b/src/bootstrap/src/core/build_steps/check.rs index ed5b9edc86d64..3e0bb2884cd7d 100644 --- a/src/bootstrap/src/core/build_steps/check.rs +++ b/src/bootstrap/src/core/build_steps/check.rs @@ -9,7 +9,7 @@ use crate::core::builder::{ }; use crate::core::config::TargetSelection; use crate::{Compiler, Mode, Subcommand}; -use std::path::{Path, PathBuf}; +use std::path::PathBuf; pub fn cargo_subcommand(kind: Kind) -> &'static str { match kind { @@ -52,7 +52,7 @@ impl Step for Std { } fn run(self, builder: &Builder<'_>) { - builder.update_submodule(&Path::new("library").join("stdarch")); + builder.require_submodule("library/stdarch", None); let target = self.target; let compiler = builder.compiler(builder.top_stage, builder.config.build); diff --git a/src/bootstrap/src/core/build_steps/clippy.rs b/src/bootstrap/src/core/build_steps/clippy.rs index ee7fb368a8c27..68abf1e464a7a 100644 --- a/src/bootstrap/src/core/build_steps/clippy.rs +++ b/src/bootstrap/src/core/build_steps/clippy.rs @@ -1,7 +1,5 @@ //! Implementation of running clippy on the compiler, standard library and various tools. -use std::path::Path; - use crate::builder::Builder; use crate::builder::ShouldRun; use crate::core::builder; @@ -127,7 +125,7 @@ impl Step for Std { } fn run(self, builder: &Builder<'_>) { - builder.update_submodule(&Path::new("library").join("stdarch")); + builder.require_submodule("library/stdarch", None); let target = self.target; let compiler = builder.compiler(builder.top_stage, builder.config.build); diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index 9bbebf9b87037..23d1e0ffe2d05 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -182,11 +182,16 @@ impl Step for Std { return; } - builder.update_submodule(&Path::new("library").join("stdarch")); + builder.require_submodule("library/stdarch", None); // Profiler information requires LLVM's compiler-rt if builder.config.profiler { - builder.update_submodule(Path::new("src/llvm-project")); + builder.require_submodule( + "src/llvm-project", + Some( + "The `build.profiler` config option requires `compiler-rt` sources from LLVM.", + ), + ); } let mut target_deps = builder.ensure(StartupObjects { compiler, target }); @@ -456,13 +461,15 @@ pub fn std_cargo(builder: &Builder<'_>, target: TargetSelection, stage: u32, car // That's probably ok? At least, the difference wasn't enforced before. There's a comment in // the compiler_builtins build script that makes me nervous, though: // https://github.com/rust-lang/compiler-builtins/blob/31ee4544dbe47903ce771270d6e3bea8654e9e50/build.rs#L575-L579 - builder.update_submodule(&Path::new("src").join("llvm-project")); + builder.require_submodule( + "src/llvm-project", + Some( + "The `build.optimized-compiler-builtins` config option \ + requires `compiler-rt` sources from LLVM.", + ), + ); let compiler_builtins_root = builder.src.join("src/llvm-project/compiler-rt"); - if !compiler_builtins_root.exists() { - panic!( - "need LLVM sources available to build `compiler-rt`, but they weren't present; consider enabling `build.submodules = true` or disabling `optimized-compiler-builtins`" - ); - } + assert!(compiler_builtins_root.exists()); // Note that `libprofiler_builtins/build.rs` also computes this so if // you're changing something here please also change that. cargo.env("RUST_COMPILER_RT_ROOT", &compiler_builtins_root); @@ -1481,7 +1488,7 @@ pub fn compiler_file( let mut cmd = command(compiler); cmd.args(builder.cflags(target, GitRepo::Rustc, c)); cmd.arg(format!("-print-file-name={file}")); - let out = cmd.capture_stdout().run(builder).stdout(); + let out = cmd.run_capture_stdout(builder).stdout(); PathBuf::from(out.trim()) } @@ -1845,7 +1852,7 @@ impl Step for Assemble { builder.ensure(llvm::Llvm { target: target_compiler.host }); if !builder.config.dry_run() && builder.config.llvm_tools_enabled { let llvm_bin_dir = - command(llvm_config).capture_stdout().arg("--bindir").run(builder).stdout(); + command(llvm_config).arg("--bindir").run_capture_stdout(builder).stdout(); let llvm_bin_dir = Path::new(llvm_bin_dir.trim()); // Since we've already built the LLVM tools, install them to the sysroot. @@ -2171,7 +2178,7 @@ pub fn strip_debug(builder: &Builder<'_>, target: TargetSelection, path: &Path) } let previous_mtime = t!(t!(path.metadata()).modified()); - command("strip").capture().arg("--strip-debug").arg(path).run(builder); + command("strip").arg("--strip-debug").arg(path).run_capture(builder); let file = t!(fs::File::open(path)); diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs index 649bcdd873353..cd0661e0edd61 100644 --- a/src/bootstrap/src/core/build_steps/dist.rs +++ b/src/bootstrap/src/core/build_steps/dist.rs @@ -182,7 +182,7 @@ fn make_win_dist( //Ask gcc where it keeps its stuff let mut cmd = command(builder.cc(target)); cmd.arg("-print-search-dirs"); - let gcc_out = cmd.capture_stdout().run(builder).stdout(); + let gcc_out = cmd.run_capture_stdout(builder).stdout(); let mut bin_path: Vec<_> = env::split_paths(&env::var_os("PATH").unwrap_or_default()).collect(); let mut lib_path = Vec::new(); @@ -907,7 +907,7 @@ impl Step for Src { /// Creates the `rust-src` installer component fn run(self, builder: &Builder<'_>) -> GeneratedTarball { if !builder.config.dry_run() { - builder.update_submodule(Path::new("src/llvm-project")); + builder.require_submodule("src/llvm-project", None); } let tarball = Tarball::new_targetless(builder, "rust-src"); @@ -1022,10 +1022,7 @@ impl Step for PlainSourceTarball { // FIXME: This code looks _very_ similar to what we have in `src/core/build_steps/vendor.rs` // perhaps it should be removed in favor of making `dist` perform the `vendor` step? - // Ensure we have all submodules from src and other directories checked out. - for submodule in build_helper::util::parse_gitmodules(&builder.src) { - builder.update_submodule(Path::new(submodule)); - } + builder.require_and_update_all_submodules(); // Vendor all Cargo dependencies let mut cmd = command(&builder.initial_cargo); @@ -1067,7 +1064,7 @@ impl Step for PlainSourceTarball { cmd.arg("--sync").arg(manifest_path); } - let config = cmd.capture().run(builder).stdout(); + let config = cmd.run_capture(builder).stdout(); let cargo_config_dir = plain_dst_src.join(".cargo"); builder.create_dir(&cargo_config_dir); @@ -2075,7 +2072,7 @@ fn maybe_install_llvm( let mut cmd = command(llvm_config); cmd.arg("--libfiles"); builder.verbose(|| println!("running {cmd:?}")); - let files = cmd.capture_stdout().run(builder).stdout(); + let files = cmd.run_capture_stdout(builder).stdout(); let build_llvm_out = &builder.llvm_out(builder.config.build); let target_llvm_out = &builder.llvm_out(target); for file in files.trim_end().split(' ') { diff --git a/src/bootstrap/src/core/build_steps/doc.rs b/src/bootstrap/src/core/build_steps/doc.rs index d8204ea00f7b2..bdd48fa644a8a 100644 --- a/src/bootstrap/src/core/build_steps/doc.rs +++ b/src/bootstrap/src/core/build_steps/doc.rs @@ -9,14 +9,14 @@ use std::io::{self, Write}; use std::path::{Path, PathBuf}; -use std::{fs, mem}; +use std::{env, fs, mem}; use crate::core::build_steps::compile; use crate::core::build_steps::tool::{self, prepare_tool_cargo, SourceType, Tool}; use crate::core::builder::{self, crate_description}; use crate::core::builder::{Alias, Builder, Compiler, Kind, RunConfig, ShouldRun, Step}; use crate::core::config::{Config, TargetSelection}; -use crate::utils::helpers::{dir_is_empty, symlink_dir, t, up_to_date}; +use crate::utils::helpers::{symlink_dir, t, up_to_date}; use crate::Mode; macro_rules! submodule_helper { @@ -53,8 +53,8 @@ macro_rules! book { fn run(self, builder: &Builder<'_>) { $( - let path = Path::new(submodule_helper!( $path, submodule $( = $submodule )? )); - builder.update_submodule(&path); + let path = submodule_helper!( $path, submodule $( = $submodule )? ); + builder.require_submodule(path, None); )? builder.ensure(RustbookSrc { target: self.target, @@ -62,6 +62,7 @@ macro_rules! book { src: builder.src.join($path), parent: Some(self), languages: $lang.into(), + rustdoc: None, }) } } @@ -80,7 +81,6 @@ book!( EditionGuide, "src/doc/edition-guide", "edition-guide", &[], submodule; EmbeddedBook, "src/doc/embedded-book", "embedded-book", &[], submodule; Nomicon, "src/doc/nomicon", "nomicon", &[], submodule; - Reference, "src/doc/reference", "reference", &[], submodule; RustByExample, "src/doc/rust-by-example", "rust-by-example", &["ja"], submodule; RustdocBook, "src/doc/rustdoc", "rustdoc", &[]; StyleGuide, "src/doc/style-guide", "style-guide", &[]; @@ -112,6 +112,7 @@ impl Step for UnstableBook { src: builder.md_doc_out(self.target).join("unstable-book"), parent: Some(self), languages: vec![], + rustdoc: None, }) } } @@ -123,6 +124,7 @@ struct RustbookSrc { src: PathBuf, parent: Option

, languages: Vec<&'static str>, + rustdoc: Option, } impl Step for RustbookSrc

{ @@ -153,13 +155,18 @@ impl Step for RustbookSrc

{ builder.info(&format!("Rustbook ({target}) - {name}")); let _ = fs::remove_dir_all(&out); - builder - .tool_cmd(Tool::Rustbook) - .arg("build") - .arg(&src) - .arg("-d") - .arg(&out) - .run(builder); + let mut rustbook_cmd = builder.tool_cmd(Tool::Rustbook); + if let Some(mut rustdoc) = self.rustdoc { + rustdoc.pop(); + let old_path = env::var_os("PATH").unwrap_or_default(); + let new_path = + env::join_paths(std::iter::once(rustdoc).chain(env::split_paths(&old_path))) + .expect("could not add rustdoc to PATH"); + + rustbook_cmd.env("PATH", new_path); + } + + rustbook_cmd.arg("build").arg(&src).arg("-d").arg(&out).run(builder); for lang in &self.languages { let out = out.join(lang); @@ -217,22 +224,14 @@ impl Step for TheBook { /// * Index page /// * Redirect pages fn run(self, builder: &Builder<'_>) { - let relative_path = Path::new("src").join("doc").join("book"); - builder.update_submodule(&relative_path); + builder.require_submodule("src/doc/book", None); let compiler = self.compiler; let target = self.target; - let absolute_path = builder.src.join(&relative_path); + let absolute_path = builder.src.join("src/doc/book"); let redirect_path = absolute_path.join("redirects"); - if !absolute_path.exists() - || !redirect_path.exists() - || dir_is_empty(&absolute_path) - || dir_is_empty(&redirect_path) - { - eprintln!("Please checkout submodule: {}", relative_path.display()); - crate::exit!(1); - } + // build book builder.ensure(RustbookSrc { target, @@ -240,6 +239,7 @@ impl Step for TheBook { src: absolute_path.clone(), parent: Some(self), languages: vec![], + rustdoc: None, }); // building older edition redirects @@ -252,6 +252,7 @@ impl Step for TheBook { // treat the other editions as not having a parent. parent: Option::::None, languages: vec![], + rustdoc: None, }); } @@ -932,8 +933,8 @@ macro_rules! tool_doc { let _ = source_type; // silence the "unused variable" warning let source_type = SourceType::Submodule; - let path = Path::new(submodule_helper!( $path, submodule $( = $submodule )? )); - builder.update_submodule(&path); + let path = submodule_helper!( $path, submodule $( = $submodule )? ); + builder.require_submodule(path, None); )? let stage = builder.top_stage; @@ -1172,12 +1173,6 @@ impl Step for RustcBook { /// in the "md-doc" directory in the build output directory. Then /// "rustbook" is used to convert it to HTML. fn run(self, builder: &Builder<'_>) { - // These submodules are required to be checked out to build rustbook - // because they have Cargo dependencies that are needed. - #[allow(clippy::single_element_loop)] // This will change soon. - for path in ["src/doc/book"] { - builder.update_submodule(Path::new(path)); - } let out_base = builder.md_doc_out(self.target).join("rustc"); t!(fs::create_dir_all(&out_base)); let out_listing = out_base.join("src/lints"); @@ -1228,6 +1223,50 @@ impl Step for RustcBook { src: out_base, parent: Some(self), languages: vec![], + rustdoc: None, + }); + } +} + +#[derive(Ord, PartialOrd, Debug, Clone, Hash, PartialEq, Eq)] +pub struct Reference { + pub compiler: Compiler, + pub target: TargetSelection, +} + +impl Step for Reference { + type Output = (); + const DEFAULT: bool = true; + + fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { + let builder = run.builder; + run.path("src/doc/reference").default_condition(builder.config.docs) + } + + fn make_run(run: RunConfig<'_>) { + run.builder.ensure(Reference { + compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.build), + target: run.target, + }); + } + + /// Builds the reference book. + fn run(self, builder: &Builder<'_>) { + builder.require_submodule("src/doc/reference", None); + + // This is needed for generating links to the standard library using + // the mdbook-spec plugin. + builder.ensure(compile::Std::new(self.compiler, builder.config.build)); + let rustdoc = builder.rustdoc(self.compiler); + + // Run rustbook/mdbook to generate the HTML pages. + builder.ensure(RustbookSrc { + target: self.target, + name: "reference".to_owned(), + src: builder.src.join("src/doc/reference"), + parent: Some(self), + languages: vec![], + rustdoc: Some(rustdoc), }); } } diff --git a/src/bootstrap/src/core/build_steps/format.rs b/src/bootstrap/src/core/build_steps/format.rs index d3ac2bae1e875..f254c058b129a 100644 --- a/src/bootstrap/src/core/build_steps/format.rs +++ b/src/bootstrap/src/core/build_steps/format.rs @@ -60,7 +60,7 @@ fn get_rustfmt_version(build: &Builder<'_>) -> Option<(String, PathBuf)> { }); cmd.arg("--version"); - let output = cmd.capture().allow_failure().run(build); + let output = cmd.allow_failure().run_capture(build); if output.is_failure() { return None; } @@ -160,25 +160,23 @@ pub fn format(build: &Builder<'_>, check: bool, all: bool, paths: &[PathBuf]) { } } let git_available = - helpers::git(None).capture().allow_failure().arg("--version").run(build).is_success(); + helpers::git(None).allow_failure().arg("--version").run_capture(build).is_success(); let mut adjective = None; if git_available { let in_working_tree = helpers::git(Some(&build.src)) - .capture() .allow_failure() .arg("rev-parse") .arg("--is-inside-work-tree") - .run(build) + .run_capture(build) .is_success(); if in_working_tree { let untracked_paths_output = helpers::git(Some(&build.src)) - .capture_stdout() .arg("status") .arg("--porcelain") .arg("-z") .arg("--untracked-files=normal") - .run(build) + .run_capture_stdout(build) .stdout(); let untracked_paths: Vec<_> = untracked_paths_output .split_terminator('\0') diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs index f234b08f5e2ca..92a7ffc3a9869 100644 --- a/src/bootstrap/src/core/build_steps/llvm.rs +++ b/src/bootstrap/src/core/build_steps/llvm.rs @@ -89,7 +89,7 @@ impl LdFlags { /// if not). pub fn prebuilt_llvm_config(builder: &Builder<'_>, target: TargetSelection) -> LlvmBuildStatus { // If we have llvm submodule initialized already, sync it. - builder.update_existing_submodule(&Path::new("src").join("llvm-project")); + builder.update_existing_submodule("src/llvm-project"); builder.config.maybe_download_ci_llvm(); @@ -110,7 +110,8 @@ pub fn prebuilt_llvm_config(builder: &Builder<'_>, target: TargetSelection) -> L } // Initialize the llvm submodule if not initialized already. - builder.update_submodule(&Path::new("src").join("llvm-project")); + // If submodules are disabled, this does nothing. + builder.update_submodule("src/llvm-project"); let root = "src/llvm-project/llvm"; let out_dir = builder.llvm_out(target); @@ -471,7 +472,7 @@ impl Step for Llvm { builder.ensure(Llvm { target: builder.config.build }); if !builder.config.dry_run() { let llvm_bindir = - command(&llvm_config).capture_stdout().arg("--bindir").run(builder).stdout(); + command(&llvm_config).arg("--bindir").run_capture_stdout(builder).stdout(); let host_bin = Path::new(llvm_bindir.trim()); cfg.define( "LLVM_TABLEGEN", @@ -522,7 +523,7 @@ impl Step for Llvm { // Helper to find the name of LLVM's shared library on darwin and linux. let find_llvm_lib_name = |extension| { let version = - command(&res.llvm_config).capture_stdout().arg("--version").run(builder).stdout(); + command(&res.llvm_config).arg("--version").run_capture_stdout(builder).stdout(); let major = version.split('.').next().unwrap(); match &llvm_version_suffix { @@ -578,7 +579,7 @@ fn check_llvm_version(builder: &Builder<'_>, llvm_config: &Path) { return; } - let version = command(llvm_config).capture_stdout().arg("--version").run(builder).stdout(); + let version = command(llvm_config).arg("--version").run_capture_stdout(builder).stdout(); let mut parts = version.split('.').take(2).filter_map(|s| s.parse::().ok()); if let (Some(major), Some(_minor)) = (parts.next(), parts.next()) { if major >= 17 { @@ -1197,7 +1198,10 @@ impl Step for CrtBeginEnd { /// Build crtbegin.o/crtend.o for musl target. fn run(self, builder: &Builder<'_>) -> Self::Output { - builder.update_submodule(Path::new("src/llvm-project")); + builder.require_submodule( + "src/llvm-project", + Some("The LLVM sources are required for the CRT from `compiler-rt`."), + ); let out_dir = builder.native_dir(self.target).join("crt"); @@ -1270,7 +1274,10 @@ impl Step for Libunwind { /// Build libunwind.a fn run(self, builder: &Builder<'_>) -> Self::Output { - builder.update_submodule(Path::new("src/llvm-project")); + builder.require_submodule( + "src/llvm-project", + Some("The LLVM sources are required for libunwind."), + ); if builder.config.dry_run() { return PathBuf::new(); diff --git a/src/bootstrap/src/core/build_steps/run.rs b/src/bootstrap/src/core/build_steps/run.rs index 3a2d3f675228d..b3ddb02801563 100644 --- a/src/bootstrap/src/core/build_steps/run.rs +++ b/src/bootstrap/src/core/build_steps/run.rs @@ -40,7 +40,7 @@ impl Step for BuildManifest { panic!("\n\nfailed to specify `dist.upload-addr` in `config.toml`\n\n") }); - let today = command("date").capture_stdout().arg("+%Y-%m-%d").run(builder).stdout(); + let today = command("date").arg("+%Y-%m-%d").run_capture_stdout(builder).stdout(); cmd.arg(sign); cmd.arg(distdir(builder)); diff --git a/src/bootstrap/src/core/build_steps/setup.rs b/src/bootstrap/src/core/build_steps/setup.rs index 226b3729c10ce..7da91b83895b7 100644 --- a/src/bootstrap/src/core/build_steps/setup.rs +++ b/src/bootstrap/src/core/build_steps/setup.rs @@ -275,7 +275,7 @@ impl Step for Link { } fn rustup_installed(builder: &Builder<'_>) -> bool { - command("rustup").capture_stdout().arg("--version").run(builder).is_success() + command("rustup").arg("--version").run_capture_stdout(builder).is_success() } fn stage_dir_exists(stage_path: &str) -> bool { @@ -313,10 +313,9 @@ fn attempt_toolchain_link(builder: &Builder<'_>, stage_path: &str) { fn toolchain_is_linked(builder: &Builder<'_>) -> bool { match command("rustup") - .capture_stdout() .allow_failure() .args(["toolchain", "list"]) - .run(builder) + .run_capture_stdout(builder) .stdout_if_ok() { Some(toolchain_list) => { @@ -341,9 +340,8 @@ fn toolchain_is_linked(builder: &Builder<'_>) -> bool { fn try_link_toolchain(builder: &Builder<'_>, stage_path: &str) -> bool { command("rustup") - .capture_stdout() .args(["toolchain", "link", "stage1", stage_path]) - .run(builder) + .run_capture_stdout(builder) .is_success() } @@ -481,9 +479,8 @@ impl Step for Hook { // install a git hook to automatically run tidy, if they want fn install_git_hook_maybe(builder: &Builder<'_>, config: &Config) -> io::Result<()> { let git = helpers::git(Some(&config.src)) - .capture() .args(["rev-parse", "--git-common-dir"]) - .run(builder) + .run_capture(builder) .stdout(); let git = PathBuf::from(git.trim()); let hooks_dir = git.join("hooks"); diff --git a/src/bootstrap/src/core/build_steps/suggest.rs b/src/bootstrap/src/core/build_steps/suggest.rs index 2d4409d27c65f..0f4765fc12120 100644 --- a/src/bootstrap/src/core/build_steps/suggest.rs +++ b/src/bootstrap/src/core/build_steps/suggest.rs @@ -14,10 +14,9 @@ pub fn suggest(builder: &Builder<'_>, run: bool) { let git_config = builder.config.git_config(); let suggestions = builder .tool_cmd(Tool::SuggestTests) - .capture_stdout() .env("SUGGEST_TESTS_GIT_REPOSITORY", git_config.git_repository) .env("SUGGEST_TESTS_NIGHTLY_BRANCH", git_config.nightly_branch) - .run(builder) + .run_capture_stdout(builder) .stdout(); let suggestions = suggestions diff --git a/src/bootstrap/src/core/build_steps/synthetic_targets.rs b/src/bootstrap/src/core/build_steps/synthetic_targets.rs index 021680302cde6..04297c01d10aa 100644 --- a/src/bootstrap/src/core/build_steps/synthetic_targets.rs +++ b/src/bootstrap/src/core/build_steps/synthetic_targets.rs @@ -64,7 +64,7 @@ fn create_synthetic_target( // we cannot use nightly features. So `RUSTC_BOOTSTRAP` is needed here. cmd.env("RUSTC_BOOTSTRAP", "1"); - let output = cmd.capture().run(builder).stdout(); + let output = cmd.run_capture(builder).stdout(); let mut spec: serde_json::Value = serde_json::from_slice(output.as_bytes()).unwrap(); let spec_map = spec.as_object_mut().unwrap(); diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index cc5931c68db1f..4942a4939af02 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -169,7 +169,7 @@ You can skip linkcheck with --skip src/tools/linkchecker" } fn check_if_tidy_is_installed(builder: &Builder<'_>) -> bool { - command("tidy").capture_stdout().allow_failure().arg("--version").run(builder).is_success() + command("tidy").allow_failure().arg("--version").run_capture_stdout(builder).is_success() } #[derive(Debug, Clone, PartialEq, Eq, Hash)] @@ -468,7 +468,7 @@ impl Miri { cargo.arg("--print-sysroot"); builder.verbose(|| println!("running: {cargo:?}")); - let stdout = cargo.capture_stdout().run(builder).stdout(); + let stdout = cargo.run_capture_stdout(builder).stdout(); // Output is "\n". let sysroot = stdout.trim_end(); builder.verbose(|| println!("`cargo miri setup --print-sysroot` said: {sysroot:?}")); @@ -749,7 +749,7 @@ impl Step for Clippy { let _guard = builder.msg_sysroot_tool(Kind::Test, compiler.stage, "clippy", host, host); // Clippy reports errors if it blessed the outputs - if cargo.allow_failure().run(builder).is_success() { + if cargo.allow_failure().run(builder) { // The tests succeeded; nothing to do. return; } @@ -904,12 +904,12 @@ fn get_browser_ui_test_version_inner( npm: &Path, global: bool, ) -> Option { - let mut command = command(npm).capture(); + let mut command = command(npm); command.arg("list").arg("--parseable").arg("--long").arg("--depth=0"); if global { command.arg("--global"); } - let lines = command.allow_failure().run(builder).stdout(); + let lines = command.allow_failure().run_capture(builder).stdout(); lines .lines() .find_map(|l| l.split(':').nth(1)?.strip_prefix("browser-ui-test@")) @@ -1846,19 +1846,17 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the let lldb_exe = builder.config.lldb.clone().unwrap_or_else(|| PathBuf::from("lldb")); let lldb_version = command(&lldb_exe) - .capture() .allow_failure() .arg("--version") - .run(builder) + .run_capture(builder) .stdout_if_ok() .and_then(|v| if v.trim().is_empty() { None } else { Some(v) }); if let Some(ref vers) = lldb_version { cmd.arg("--lldb-version").arg(vers); let lldb_python_dir = command(&lldb_exe) .allow_failure() - .capture_stdout() .arg("-P") - .run(builder) + .run_capture_stdout(builder) .stdout_if_ok() .map(|p| p.lines().next().expect("lldb Python dir not found").to_string()); if let Some(ref dir) = lldb_python_dir { @@ -1917,10 +1915,9 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the builder.ensure(llvm::Llvm { target: builder.config.build }); if !builder.config.dry_run() { let llvm_version = - builder.run(command(&llvm_config).capture_stdout().arg("--version")).stdout(); - let llvm_components = builder - .run(command(&llvm_config).capture_stdout().arg("--components")) - .stdout(); + command(&llvm_config).arg("--version").run_capture_stdout(builder).stdout(); + let llvm_components = + command(&llvm_config).arg("--components").run_capture_stdout(builder).stdout(); // Remove trailing newline from llvm-config output. cmd.arg("--llvm-version") .arg(llvm_version.trim()) @@ -1940,7 +1937,7 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the // platform-specific environment variable as a workaround. if !builder.config.dry_run() && suite.ends_with("fulldeps") { let llvm_libdir = - builder.run(command(&llvm_config).capture_stdout().arg("--libdir")).stdout(); + command(&llvm_config).arg("--libdir").run_capture_stdout(builder).stdout(); add_link_lib_path(vec![llvm_libdir.trim().into()], &mut cmd); } @@ -2212,7 +2209,7 @@ impl BookTest { compiler.host, ); let _time = helpers::timeit(builder); - let toolstate = if rustbook_cmd.delay_failure().run(builder).is_success() { + let toolstate = if rustbook_cmd.delay_failure().run(builder) { ToolState::TestPass } else { ToolState::TestFail @@ -2257,7 +2254,12 @@ impl BookTest { } macro_rules! test_book { - ($($name:ident, $path:expr, $book_name:expr, default=$default:expr;)+) => { + ($( + $name:ident, $path:expr, $book_name:expr, + default=$default:expr + $(,submodules = $submodules:expr)? + ; + )+) => { $( #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct $name { @@ -2280,6 +2282,11 @@ macro_rules! test_book { } fn run(self, builder: &Builder<'_>) { + $( + for submodule in $submodules { + builder.require_submodule(submodule, None); + } + )* builder.ensure(BookTest { compiler: self.compiler, path: PathBuf::from($path), @@ -2293,15 +2300,15 @@ macro_rules! test_book { } test_book!( - Nomicon, "src/doc/nomicon", "nomicon", default=false; - Reference, "src/doc/reference", "reference", default=false; + Nomicon, "src/doc/nomicon", "nomicon", default=false, submodules=["src/doc/nomicon"]; + Reference, "src/doc/reference", "reference", default=false, submodules=["src/doc/reference"]; RustdocBook, "src/doc/rustdoc", "rustdoc", default=true; RustcBook, "src/doc/rustc", "rustc", default=true; - RustByExample, "src/doc/rust-by-example", "rust-by-example", default=false; - EmbeddedBook, "src/doc/embedded-book", "embedded-book", default=false; - TheBook, "src/doc/book", "book", default=false; + RustByExample, "src/doc/rust-by-example", "rust-by-example", default=false, submodules=["src/doc/rust-by-example"]; + EmbeddedBook, "src/doc/embedded-book", "embedded-book", default=false, submodules=["src/doc/embedded-book"]; + TheBook, "src/doc/book", "book", default=false, submodules=["src/doc/book"]; UnstableBook, "src/doc/unstable-book", "unstable-book", default=true; - EditionGuide, "src/doc/edition-guide", "edition-guide", default=false; + EditionGuide, "src/doc/edition-guide", "edition-guide", default=false, submodules=["src/doc/edition-guide"]; ); #[derive(Debug, Clone, PartialEq, Eq, Hash)] @@ -2345,7 +2352,7 @@ impl Step for ErrorIndex { let guard = builder.msg(Kind::Test, compiler.stage, "error-index", compiler.host, compiler.host); let _time = helpers::timeit(builder); - tool.capture().run(builder); + tool.run_capture(builder); drop(guard); // The tests themselves need to link to std, so make sure it is // available. @@ -2376,9 +2383,10 @@ fn markdown_test(builder: &Builder<'_>, compiler: Compiler, markdown: &Path) -> cmd = cmd.delay_failure(); if !builder.config.verbose_tests { - cmd = cmd.capture(); + cmd.run_capture(builder).is_success() + } else { + cmd.run(builder) } - cmd.run(builder).is_success() } #[derive(Debug, Clone, PartialEq, Eq, Hash)] @@ -2398,17 +2406,14 @@ impl Step for RustcGuide { } fn run(self, builder: &Builder<'_>) { - let relative_path = Path::new("src").join("doc").join("rustc-dev-guide"); - builder.update_submodule(&relative_path); + let relative_path = "src/doc/rustc-dev-guide"; + builder.require_submodule(relative_path, None); let src = builder.src.join(relative_path); let mut rustbook_cmd = builder.tool_cmd(Tool::Rustbook).delay_failure(); rustbook_cmd.arg("linkcheck").arg(&src); - let toolstate = if rustbook_cmd.run(builder).is_success() { - ToolState::TestPass - } else { - ToolState::TestFail - }; + let toolstate = + if rustbook_cmd.run(builder) { ToolState::TestPass } else { ToolState::TestFail }; builder.save_toolstate("rustc-dev-guide", toolstate); } } @@ -2920,7 +2925,7 @@ impl Step for RemoteCopyLibs { let f = t!(f); let name = f.file_name().into_string().unwrap(); if helpers::is_dylib(&name) { - builder.run(command(&tool).arg("push").arg(f.path())); + command(&tool).arg("push").arg(f.path()).run(builder); } } } @@ -2951,21 +2956,21 @@ impl Step for Distcheck { builder.ensure(dist::PlainSourceTarball); builder.ensure(dist::Src); - let mut cmd = command("tar"); - cmd.arg("-xf") + command("tar") + .arg("-xf") .arg(builder.ensure(dist::PlainSourceTarball).tarball()) .arg("--strip-components=1") - .current_dir(&dir); - cmd.run(builder); - builder.run( - command("./configure") - .args(&builder.config.configure_args) - .arg("--enable-vendor") - .current_dir(&dir), - ); - builder.run( - command(helpers::make(&builder.config.build.triple)).arg("check").current_dir(&dir), - ); + .current_dir(&dir) + .run(builder); + command("./configure") + .args(&builder.config.configure_args) + .arg("--enable-vendor") + .current_dir(&dir) + .run(builder); + command(helpers::make(&builder.config.build.triple)) + .arg("check") + .current_dir(&dir) + .run(builder); // Now make sure that rust-src has all of libstd's dependencies builder.info("Distcheck rust-src"); @@ -2973,24 +2978,23 @@ impl Step for Distcheck { let _ = fs::remove_dir_all(&dir); t!(fs::create_dir_all(&dir)); - let mut cmd = command("tar"); - cmd.arg("-xf") + command("tar") + .arg("-xf") .arg(builder.ensure(dist::Src).tarball()) .arg("--strip-components=1") - .current_dir(&dir); - cmd.run(builder); + .current_dir(&dir) + .run(builder); let toml = dir.join("rust-src/lib/rustlib/src/rust/library/std/Cargo.toml"); - builder.run( - command(&builder.initial_cargo) - // Will read the libstd Cargo.toml - // which uses the unstable `public-dependency` feature. - .env("RUSTC_BOOTSTRAP", "1") - .arg("generate-lockfile") - .arg("--manifest-path") - .arg(&toml) - .current_dir(&dir), - ); + command(&builder.initial_cargo) + // Will read the libstd Cargo.toml + // which uses the unstable `public-dependency` feature. + .env("RUSTC_BOOTSTRAP", "1") + .arg("generate-lockfile") + .arg("--manifest-path") + .arg(&toml) + .current_dir(&dir) + .run(builder); } } @@ -3009,7 +3013,7 @@ impl Step for Bootstrap { let _guard = builder.msg(Kind::Test, 0, "bootstrap", host, host); // Some tests require cargo submodule to be present. - builder.build.update_submodule(Path::new("src/tools/cargo")); + builder.build.require_submodule("src/tools/cargo", None); let mut check_bootstrap = command(builder.python()); check_bootstrap diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs index 087df2f8a88e2..a059cc1518270 100644 --- a/src/bootstrap/src/core/build_steps/tool.rs +++ b/src/bootstrap/src/core/build_steps/tool.rs @@ -1,6 +1,6 @@ use std::env; use std::fs; -use std::path::{Path, PathBuf}; +use std::path::PathBuf; use crate::core::build_steps::compile; use crate::core::build_steps::toolstate::ToolState; @@ -241,6 +241,7 @@ macro_rules! bootstrap_tool { $(,is_external_tool = $external:expr)* $(,is_unstable_tool = $unstable:expr)* $(,allow_features = $allow_features:expr)? + $(,submodules = $submodules:expr)? ; )+) => { #[derive(PartialEq, Eq, Clone)] @@ -287,6 +288,11 @@ macro_rules! bootstrap_tool { } fn run(self, builder: &Builder<'_>) -> PathBuf { + $( + for submodule in $submodules { + builder.require_submodule(submodule, None); + } + )* builder.ensure(ToolBuild { compiler: self.compiler, target: self.target, @@ -314,7 +320,7 @@ macro_rules! bootstrap_tool { } bootstrap_tool!( - Rustbook, "src/tools/rustbook", "rustbook"; + Rustbook, "src/tools/rustbook", "rustbook", submodules = SUBMODULES_FOR_RUSTBOOK; UnstableBookGen, "src/tools/unstable-book-gen", "unstable-book-gen"; Tidy, "src/tools/tidy", "tidy"; Linkchecker, "src/tools/linkchecker", "linkchecker"; @@ -340,6 +346,10 @@ bootstrap_tool!( WasmComponentLd, "src/tools/wasm-component-ld", "wasm-component-ld", is_unstable_tool = true, allow_features = "min_specialization"; ); +/// These are the submodules that are required for rustbook to work due to +/// depending on mdbook plugins. +pub static SUBMODULES_FOR_RUSTBOOK: &[&str] = &["src/doc/book", "src/doc/reference"]; + #[derive(Debug, Clone, Hash, PartialEq, Eq)] pub struct OptimizedDist { pub compiler: Compiler, @@ -363,7 +373,7 @@ impl Step for OptimizedDist { fn run(self, builder: &Builder<'_>) -> PathBuf { // We need to ensure the rustc-perf submodule is initialized when building opt-dist since // the tool requires it to be in place to run. - builder.update_submodule(Path::new("src/tools/rustc-perf")); + builder.require_submodule("src/tools/rustc-perf", None); builder.ensure(ToolBuild { compiler: self.compiler, @@ -404,7 +414,7 @@ impl Step for RustcPerf { fn run(self, builder: &Builder<'_>) -> PathBuf { // We need to ensure the rustc-perf submodule is initialized. - builder.update_submodule(Path::new("src/tools/rustc-perf")); + builder.require_submodule("src/tools/rustc-perf", None); let tool = ToolBuild { compiler: self.compiler, @@ -589,8 +599,7 @@ impl Step for Rustdoc { .arg("--") .arg(librustdoc_src) .arg(rustdoc_src) - .run(builder) - .is_success(); + .run(builder); if !has_changes { let precompiled_rustdoc = builder @@ -705,7 +714,7 @@ impl Step for Cargo { } fn run(self, builder: &Builder<'_>) -> PathBuf { - builder.build.update_submodule(Path::new("src/tools/cargo")); + builder.build.require_submodule("src/tools/cargo", None); builder.ensure(ToolBuild { compiler: self.compiler, @@ -982,7 +991,7 @@ impl Step for LibcxxVersionTool { } } - let version_output = command(executable).capture_stdout().run(builder).stdout(); + let version_output = command(executable).run_capture_stdout(builder).stdout(); let version_str = version_output.split_once("version:").unwrap().1; let version = version_str.trim().parse::().unwrap(); @@ -1087,8 +1096,6 @@ macro_rules! tool_extended { // NOTE: tools need to be also added to `Builder::get_step_descriptions` in `builder.rs` // to make `./x.py build ` work. -// NOTE: Most submodule updates for tools are handled by bootstrap.py, since they're needed just to -// invoke Cargo to build bootstrap. See the comment there for more details. tool_extended!((self, builder), Cargofmt, "src/tools/rustfmt", "cargo-fmt", stable=true; CargoClippy, "src/tools/clippy", "cargo-clippy", stable=true; diff --git a/src/bootstrap/src/core/build_steps/toolstate.rs b/src/bootstrap/src/core/build_steps/toolstate.rs index 2ab0ce7454b17..912cd4b8676f6 100644 --- a/src/bootstrap/src/core/build_steps/toolstate.rs +++ b/src/bootstrap/src/core/build_steps/toolstate.rs @@ -102,12 +102,11 @@ fn print_error(tool: &str, submodule: &str) { fn check_changed_files(builder: &Builder<'_>, toolstates: &HashMap, ToolState>) { // Changed files let output = helpers::git(None) - .capture() .arg("diff") .arg("--name-status") .arg("HEAD") .arg("HEAD^") - .run(builder) + .run_capture(builder) .stdout(); for (tool, submodule) in STABLE_TOOLS.iter().chain(NIGHTLY_TOOLS.iter()) { @@ -391,7 +390,7 @@ fn commit_toolstate_change(builder: &Builder<'_>, current_toolstate: &ToolstateD .arg("-m") .arg(&message) .run(builder); - if !status.is_success() { + if !status { success = true; break; } @@ -403,7 +402,7 @@ fn commit_toolstate_change(builder: &Builder<'_>, current_toolstate: &ToolstateD .arg("master") .run(builder); // If we successfully push, exit. - if status.is_success() { + if status { success = true; break; } @@ -432,7 +431,7 @@ fn commit_toolstate_change(builder: &Builder<'_>, current_toolstate: &ToolstateD /// `publish_toolstate.py` script if the PR passes all tests and is merged to /// master. fn publish_test_results(builder: &Builder<'_>, current_toolstate: &ToolstateData) { - let commit = helpers::git(None).capture().arg("rev-parse").arg("HEAD").run(builder).stdout(); + let commit = helpers::git(None).arg("rev-parse").arg("HEAD").run_capture(builder).stdout(); let toolstate_serialized = t!(serde_json::to_string(¤t_toolstate)); diff --git a/src/bootstrap/src/core/build_steps/vendor.rs b/src/bootstrap/src/core/build_steps/vendor.rs index e6b3cb320cf16..8732b30e94000 100644 --- a/src/bootstrap/src/core/build_steps/vendor.rs +++ b/src/bootstrap/src/core/build_steps/vendor.rs @@ -1,6 +1,7 @@ +use crate::core::build_steps::tool::SUBMODULES_FOR_RUSTBOOK; use crate::core::builder::{Builder, RunConfig, ShouldRun, Step}; use crate::utils::exec::command; -use std::path::{Path, PathBuf}; +use std::path::PathBuf; #[derive(Debug, Clone, Hash, PartialEq, Eq)] pub(crate) struct Vendor { @@ -35,8 +36,8 @@ impl Step for Vendor { } // These submodules must be present for `x vendor` to work. - for path in ["src/tools/cargo", "src/doc/book"] { - builder.build.update_submodule(Path::new(path)); + for submodule in SUBMODULES_FOR_RUSTBOOK.iter().chain(["src/tools/cargo"].iter()) { + builder.build.require_submodule(submodule, None); } // Sync these paths by default. diff --git a/src/bootstrap/src/core/builder.rs b/src/bootstrap/src/core/builder.rs index 78fbea2e8107c..d21ddc5672bdf 100644 --- a/src/bootstrap/src/core/builder.rs +++ b/src/bootstrap/src/core/builder.rs @@ -1954,7 +1954,7 @@ impl<'a> Builder<'a> { if mode == Mode::ToolRustc || mode == Mode::Codegen { if let Some(llvm_config) = self.llvm_config(target) { let llvm_libdir = - command(llvm_config).capture_stdout().arg("--libdir").run(self).stdout(); + command(llvm_config).arg("--libdir").run_capture_stdout(self).stdout(); add_link_lib_path(vec![llvm_libdir.trim().into()], &mut cargo); } } diff --git a/src/bootstrap/src/core/builder/tests.rs b/src/bootstrap/src/core/builder/tests.rs index 97c9ece0036ea..ccabcad243f7b 100644 --- a/src/bootstrap/src/core/builder/tests.rs +++ b/src/bootstrap/src/core/builder/tests.rs @@ -13,15 +13,18 @@ fn configure_with_args(cmd: &[String], host: &[&str], target: &[&str]) -> Config config.save_toolstates = None; config.dry_run = DryRun::SelfCheck; - // Ignore most submodules, since we don't need them for a dry run. - // But make sure to check out the `doc` and `rust-analyzer` submodules, since some steps need them - // just to know which commands to run. + // Ignore most submodules, since we don't need them for a dry run, and the + // tests run much faster without them. + // + // The src/doc/book submodule is needed because TheBook step tries to + // access files even during a dry-run (may want to consider just skipping + // that in a dry run). let submodule_build = Build::new(Config { // don't include LLVM, so CI doesn't require ninja/cmake to be installed rust_codegen_backends: vec![], ..Config::parse(&["check".to_owned()]) }); - submodule_build.update_submodule(Path::new("src/doc/book")); + submodule_build.require_submodule("src/doc/book", None); config.submodules = Some(false); config.ninja_in_file = false; diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index e32288e2caf67..3435225af7bd3 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -2404,8 +2404,11 @@ impl Config { .unwrap_or_else(|| SplitDebuginfo::default_for_platform(target)) } - pub fn submodules(&self, rust_info: &GitInfo) -> bool { - self.submodules.unwrap_or(rust_info.is_managed_git_subrepository()) + /// Returns whether or not submodules should be managed by bootstrap. + pub fn submodules(&self) -> bool { + // If not specified in config, the default is to only manage + // submodules if we're currently inside a git repository. + self.submodules.unwrap_or(self.rust_info.is_managed_git_subrepository()) } pub fn codegen_backends(&self, target: TargetSelection) -> &[String] { diff --git a/src/bootstrap/src/core/metadata.rs b/src/bootstrap/src/core/metadata.rs index b18da844014be..9b4c85e6d34a4 100644 --- a/src/bootstrap/src/core/metadata.rs +++ b/src/bootstrap/src/core/metadata.rs @@ -81,7 +81,7 @@ fn workspace_members(build: &Build) -> Vec { .arg("--no-deps") .arg("--manifest-path") .arg(build.src.join(manifest_path)); - let metadata_output = cargo.capture_stdout().run_always().run(build).stdout(); + let metadata_output = cargo.run_always().run_capture_stdout(build).stdout(); let Output { packages, .. } = t!(serde_json::from_str(&metadata_output)); packages }; diff --git a/src/bootstrap/src/core/sanity.rs b/src/bootstrap/src/core/sanity.rs index 2be819d52ea1a..8aa0c43ad6e38 100644 --- a/src/bootstrap/src/core/sanity.rs +++ b/src/bootstrap/src/core/sanity.rs @@ -352,7 +352,7 @@ than building it. // There are three builds of cmake on windows: MSVC, MinGW, and // Cygwin. The Cygwin build does not have generators for Visual // Studio, so detect that here and error. - let out = command("cmake").capture_stdout().arg("--help").run(build).stdout(); + let out = command("cmake").arg("--help").run_capture_stdout(build).stdout(); if !out.contains("Visual Studio") { panic!( " diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs index 79bea50c626b2..43abf10c7e313 100644 --- a/src/bootstrap/src/lib.rs +++ b/src/bootstrap/src/lib.rs @@ -40,7 +40,7 @@ use crate::core::builder::{Builder, Kind}; use crate::core::config::{flags, LldMode}; use crate::core::config::{DryRun, Target}; use crate::core::config::{LlvmLibunwind, TargetSelection}; -use crate::utils::exec::{command, BehaviorOnFailure, BootstrapCommand, CommandOutput}; +use crate::utils::exec::{command, BehaviorOnFailure, BootstrapCommand, CommandOutput, OutputMode}; use crate::utils::helpers::{self, dir_is_empty, exe, libdir, mtime, output, symlink_dir}; mod core; @@ -441,7 +441,13 @@ impl Build { // Cargo.toml files. let rust_submodules = ["library/backtrace", "library/stdarch"]; for s in rust_submodules { - build.update_submodule(Path::new(s)); + build.require_submodule( + s, + Some( + "The submodule is required for the standard library \ + and the main Cargo workspace.", + ), + ); } // Now, update all existing submodules. build.update_existing_submodules(); @@ -470,12 +476,17 @@ impl Build { build } - // modified from `check_submodule` and `update_submodule` in bootstrap.py /// Given a path to the directory of a submodule, update it. /// /// `relative_path` should be relative to the root of the git repository, not an absolute path. - pub(crate) fn update_submodule(&self, relative_path: &Path) { - if !self.config.submodules(self.rust_info()) { + /// + /// This *does not* update the submodule if `config.toml` explicitly says + /// not to, or if we're not in a git repository (like a plain source + /// tarball). Typically [`Build::require_submodule`] should be + /// used instead to provide a nice error to the user if the submodule is + /// missing. + fn update_submodule(&self, relative_path: &str) { + if !self.config.submodules() { return; } @@ -496,21 +507,21 @@ impl Build { // Therefore, all commands below are marked with `run_always()`, so that they also run in // dry run mode. let submodule_git = || { - let mut cmd = helpers::git(Some(&absolute_path)).capture_stdout(); + let mut cmd = helpers::git(Some(&absolute_path)); cmd.run_always(); cmd }; // Determine commit checked out in submodule. - let checked_out_hash = submodule_git().args(["rev-parse", "HEAD"]).run(self).stdout(); + let checked_out_hash = + submodule_git().args(["rev-parse", "HEAD"]).run_capture_stdout(self).stdout(); let checked_out_hash = checked_out_hash.trim_end(); // Determine commit that the submodule *should* have. let recorded = helpers::git(Some(&self.src)) - .capture_stdout() .run_always() .args(["ls-tree", "HEAD"]) .arg(relative_path) - .run(self) + .run_capture_stdout(self) .stdout(); let actual_hash = recorded .split_whitespace() @@ -522,7 +533,7 @@ impl Build { return; } - println!("Updating submodule {}", relative_path.display()); + println!("Updating submodule {relative_path}"); helpers::git(Some(&self.src)) .run_always() .args(["submodule", "-q", "sync"]) @@ -534,11 +545,10 @@ impl Build { // Git is buggy and will try to fetch submodules from the tracking branch for *this* repository, // even though that has no relation to the upstream for the submodule. let current_branch = helpers::git(Some(&self.src)) - .capture_stdout() .allow_failure() .run_always() .args(["symbolic-ref", "--short", "HEAD"]) - .run(self) + .run_capture_stdout(self) .stdout_if_ok() .map(|s| s.trim().to_owned()); @@ -557,17 +567,14 @@ impl Build { git.arg(relative_path); git }; - if !update(true).run(self).is_success() { + if !update(true).run(self) { update(false).run(self); } // Save any local changes, but avoid running `git stash pop` if there are none (since it will exit with an error). // diff-index reports the modifications through the exit status - let has_local_modifications = submodule_git() - .allow_failure() - .args(["diff-index", "--quiet", "HEAD"]) - .run(self) - .is_failure(); + let has_local_modifications = + !submodule_git().allow_failure().args(["diff-index", "--quiet", "HEAD"]).run(self); if has_local_modifications { submodule_git().args(["stash", "push"]).run(self); } @@ -580,39 +587,81 @@ impl Build { } } + /// Updates a submodule, and exits with a failure if submodule management + /// is disabled and the submodule does not exist. + /// + /// The given submodule name should be its path relative to the root of + /// the main repository. + /// + /// The given `err_hint` will be shown to the user if the submodule is not + /// checked out and submodule management is disabled. + pub fn require_submodule(&self, submodule: &str, err_hint: Option<&str>) { + // When testing bootstrap itself, it is much faster to ignore + // submodules. Almost all Steps work fine without their submodules. + if cfg!(test) && !self.config.submodules() { + return; + } + self.update_submodule(submodule); + let absolute_path = self.config.src.join(submodule); + if dir_is_empty(&absolute_path) { + let maybe_enable = if !self.config.submodules() + && self.config.rust_info.is_managed_git_subrepository() + { + "\nConsider setting `build.submodules = true` or manually initializing the submodules." + } else { + "" + }; + let err_hint = err_hint.map_or_else(String::new, |e| format!("\n{e}")); + eprintln!( + "submodule {submodule} does not appear to be checked out, \ + but it is required for this step{maybe_enable}{err_hint}" + ); + exit!(1); + } + } + + /// Updates all submodules, and exits with an error if submodule + /// management is disabled and the submodule does not exist. + pub fn require_and_update_all_submodules(&self) { + for submodule in build_helper::util::parse_gitmodules(&self.src) { + self.require_submodule(submodule, None); + } + } + /// If any submodule has been initialized already, sync it unconditionally. /// This avoids contributors checking in a submodule change by accident. - pub fn update_existing_submodules(&self) { - // Avoid running git when there isn't a git checkout. - if !self.config.submodules(self.rust_info()) { + fn update_existing_submodules(&self) { + // Avoid running git when there isn't a git checkout, or the user has + // explicitly disabled submodules in `config.toml`. + if !self.config.submodules() { return; } let output = helpers::git(Some(&self.src)) - .capture() .args(["config", "--file"]) .arg(self.config.src.join(".gitmodules")) .args(["--get-regexp", "path"]) - .run(self) + .run_capture(self) .stdout(); for line in output.lines() { // Look for `submodule.$name.path = $path` // Sample output: `submodule.src/rust-installer.path src/tools/rust-installer` - let submodule = Path::new(line.split_once(' ').unwrap().1); + let submodule = line.split_once(' ').unwrap().1; + let path = Path::new(submodule); // Don't update the submodule unless it's already been cloned. - if GitInfo::new(false, submodule).is_managed_git_subrepository() { + if GitInfo::new(false, path).is_managed_git_subrepository() { self.update_submodule(submodule); } } } /// Updates the given submodule only if it's initialized already; nothing happens otherwise. - pub fn update_existing_submodule(&self, submodule: &Path) { + pub fn update_existing_submodule(&self, submodule: &str) { // Avoid running git when there isn't a git checkout. - if !self.config.submodules(self.rust_info()) { + if !self.config.submodules() { return; } - if GitInfo::new(false, submodule).is_managed_git_subrepository() { + if GitInfo::new(false, Path::new(submodule)).is_managed_git_subrepository() { self.update_submodule(submodule); } } @@ -870,14 +919,14 @@ impl Build { if let Some(s) = target_config.and_then(|c| c.llvm_filecheck.as_ref()) { s.to_path_buf() } else if let Some(s) = target_config.and_then(|c| c.llvm_config.as_ref()) { - let llvm_bindir = command(s).capture_stdout().arg("--bindir").run(self).stdout(); + let llvm_bindir = command(s).arg("--bindir").run_capture_stdout(self).stdout(); let filecheck = Path::new(llvm_bindir.trim()).join(exe("FileCheck", target)); if filecheck.exists() { filecheck } else { // On Fedora the system LLVM installs FileCheck in the // llvm subdirectory of the libdir. - let llvm_libdir = command(s).capture_stdout().arg("--libdir").run(self).stdout(); + let llvm_libdir = command(s).arg("--libdir").run_capture_stdout(self).stdout(); let lib_filecheck = Path::new(llvm_libdir.trim()).join("llvm").join(exe("FileCheck", target)); if lib_filecheck.exists() { @@ -944,7 +993,12 @@ impl Build { /// Execute a command and return its output. /// This method should be used for all command executions in bootstrap. #[track_caller] - fn run(&self, command: &mut BootstrapCommand) -> CommandOutput { + fn run( + &self, + command: &mut BootstrapCommand, + stdout: OutputMode, + stderr: OutputMode, + ) -> CommandOutput { command.mark_as_executed(); if self.config.dry_run() && !command.run_always { return CommandOutput::default(); @@ -957,19 +1011,20 @@ impl Build { println!("running: {command:?} (created at {created_at}, executed at {executed_at})") }); - let stdout = command.stdout.stdio(); - command.as_command_mut().stdout(stdout); - let stderr = command.stderr.stdio(); - command.as_command_mut().stderr(stderr); + let cmd = command.as_command_mut(); + cmd.stdout(stdout.stdio()); + cmd.stderr(stderr.stdio()); - let output = command.as_command_mut().output(); + let output = cmd.output(); use std::fmt::Write; let mut message = String::new(); let output: CommandOutput = match output { // Command has succeeded - Ok(output) if output.status.success() => output.into(), + Ok(output) if output.status.success() => { + CommandOutput::from_output(output, stdout, stderr) + } // Command has started, but then it failed Ok(output) => { writeln!( @@ -983,15 +1038,15 @@ Executed at: {executed_at}"#, ) .unwrap(); - let output: CommandOutput = output.into(); + let output: CommandOutput = CommandOutput::from_output(output, stdout, stderr); // If the output mode is OutputMode::Capture, we can now print the output. // If it is OutputMode::Print, then the output has already been printed to // stdout/stderr, and we thus don't have anything captured to print anyway. - if command.stdout.captures() { + if stdout.captures() { writeln!(message, "\nSTDOUT ----\n{}", output.stdout().trim()).unwrap(); } - if command.stderr.captures() { + if stderr.captures() { writeln!(message, "\nSTDERR ----\n{}", output.stderr().trim()).unwrap(); } output @@ -1004,7 +1059,7 @@ Executed at: {executed_at}"#, \nIt was not possible to execute the command: {e:?}" ) .unwrap(); - CommandOutput::did_not_start() + CommandOutput::did_not_start(stdout, stderr) } }; if !output.is_success() { @@ -1529,7 +1584,6 @@ Executed at: {executed_at}"#, // That's our beta number! // (Note that we use a `..` range, not the `...` symmetric difference.) helpers::git(Some(&self.src)) - .capture() .arg("rev-list") .arg("--count") .arg("--merges") @@ -1537,7 +1591,7 @@ Executed at: {executed_at}"#, "refs/remotes/origin/{}..HEAD", self.config.stage0_metadata.config.nightly_branch )) - .run(self) + .run_capture(self) .stdout() }); let n = count.trim().parse().unwrap(); @@ -1972,21 +2026,19 @@ pub fn generate_smart_stamp_hash( additional_input: &str, ) -> String { let diff = helpers::git(Some(dir)) - .capture_stdout() .allow_failure() .arg("diff") - .run(builder) + .run_capture_stdout(builder) .stdout_if_ok() .unwrap_or_default(); let status = helpers::git(Some(dir)) - .capture_stdout() .allow_failure() .arg("status") .arg("--porcelain") .arg("-z") .arg("--untracked-files=normal") - .run(builder) + .run_capture_stdout(builder) .stdout_if_ok() .unwrap_or_default(); diff --git a/src/bootstrap/src/utils/cc_detect.rs b/src/bootstrap/src/utils/cc_detect.rs index 20d79e490ec48..29e6b74aaceb8 100644 --- a/src/bootstrap/src/utils/cc_detect.rs +++ b/src/bootstrap/src/utils/cc_detect.rs @@ -182,15 +182,15 @@ fn default_compiler( return None; } - let cmd = BootstrapCommand::from(c.to_command()); - let output = cmd.capture_stdout().arg("--version").run(build).stdout(); + let mut cmd = BootstrapCommand::from(c.to_command()); + let output = cmd.arg("--version").run_capture_stdout(build).stdout(); let i = output.find(" 4.")?; match output[i + 3..].chars().next().unwrap() { '0'..='6' => {} _ => return None, } let alternative = format!("e{gnu_compiler}"); - if command(&alternative).capture().run(build).is_success() { + if command(&alternative).run_capture(build).is_success() { Some(PathBuf::from(alternative)) } else { None @@ -247,10 +247,8 @@ pub(crate) fn ndk_compiler(compiler: Language, triple: &str, ndk: &Path) -> Path triple.to_string() }; - // API 19 is the earliest API level supported by NDK r25b but AArch64 and x86_64 support - // begins at API level 21. - let api_level = - if triple.contains("aarch64") || triple.contains("x86_64") { "21" } else { "19" }; + // The earliest API supported by NDK r26d is 21. + let api_level = "21"; let compiler = format!("{}{}-{}", triple_translated, api_level, compiler.clang()); let host_tag = if cfg!(target_os = "macos") { // The NDK uses universal binaries, so this is correct even on ARM. @@ -258,7 +256,7 @@ pub(crate) fn ndk_compiler(compiler: Language, triple: &str, ndk: &Path) -> Path } else if cfg!(target_os = "windows") { "windows-x86_64" } else { - // NDK r25b only has official releases for macOS, Windows and Linux. + // NDK r26d only has official releases for macOS, Windows and Linux. // Try the Linux directory everywhere else, on the assumption that the OS has an // emulation layer that can cope (e.g. BSDs). "linux-x86_64" diff --git a/src/bootstrap/src/utils/change_tracker.rs b/src/bootstrap/src/utils/change_tracker.rs index 083418ed066b3..b8f70fdf6a805 100644 --- a/src/bootstrap/src/utils/change_tracker.rs +++ b/src/bootstrap/src/utils/change_tracker.rs @@ -210,4 +210,14 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[ severity: ChangeSeverity::Info, summary: "the `wasm-component-ld` tool is now built as part of `build.extended` and can be a member of `build.tools`", }, + ChangeInfo { + change_id: 120593, + severity: ChangeSeverity::Info, + summary: "Removed android-ndk r25b support in favor of android-ndk r26d.", + }, + ChangeInfo { + change_id: 125181, + severity: ChangeSeverity::Warning, + summary: "For tarball sources, default value for `rust.channel` will be taken from `src/ci/channel` file.", + }, ]; diff --git a/src/bootstrap/src/utils/exec.rs b/src/bootstrap/src/utils/exec.rs index a60c0084f3d7f..627ea050043e9 100644 --- a/src/bootstrap/src/utils/exec.rs +++ b/src/bootstrap/src/utils/exec.rs @@ -50,7 +50,7 @@ impl OutputMode { /// If you want to delay failures until the end of bootstrap, use [delay_failure]. /// /// By default, the command will print its stdout/stderr to stdout/stderr of bootstrap ([OutputMode::Print]). -/// If you want to handle the output programmatically, use [BootstrapCommand::capture]. +/// If you want to handle the output programmatically, use [BootstrapCommand::run_capture]. /// /// Bootstrap will print a debug log to stdout if the command fails and failure is not allowed. /// @@ -59,8 +59,6 @@ impl OutputMode { pub struct BootstrapCommand { command: Command, pub failure_behavior: BehaviorOnFailure, - pub stdout: OutputMode, - pub stderr: OutputMode, // Run the command even during dry run pub run_always: bool, // This field makes sure that each command is executed (or disarmed) before it is dropped, @@ -135,22 +133,23 @@ impl BootstrapCommand { self } - /// Capture all output of the command, do not print it. - #[must_use] - pub fn capture(self) -> Self { - Self { stdout: OutputMode::Capture, stderr: OutputMode::Capture, ..self } + /// Run the command, while printing stdout and stderr. + /// Returns true if the command has succeeded. + #[track_caller] + pub fn run(&mut self, builder: &Build) -> bool { + builder.run(self, OutputMode::Print, OutputMode::Print).is_success() } - /// Capture stdout of the command, do not print it. - #[must_use] - pub fn capture_stdout(self) -> Self { - Self { stdout: OutputMode::Capture, ..self } + /// Run the command, while capturing and returning all its output. + #[track_caller] + pub fn run_capture(&mut self, builder: &Build) -> CommandOutput { + builder.run(self, OutputMode::Capture, OutputMode::Capture) } - /// Run the command, returning its output. + /// Run the command, while capturing and returning stdout, and printing stderr. #[track_caller] - pub fn run(&mut self, builder: &Build) -> CommandOutput { - builder.run(self) + pub fn run_capture_stdout(&mut self, builder: &Build) -> CommandOutput { + builder.run(self, OutputMode::Capture, OutputMode::Print) } /// Provides access to the stdlib Command inside. @@ -189,11 +188,7 @@ impl BootstrapCommand { impl Debug for BootstrapCommand { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { write!(f, "{:?}", self.command)?; - write!( - f, - " (failure_mode={:?}, stdout_mode={:?}, stderr_mode={:?})", - self.failure_behavior, self.stdout, self.stderr - ) + write!(f, " (failure_mode={:?})", self.failure_behavior) } } @@ -205,8 +200,6 @@ impl From for BootstrapCommand { Self { command, failure_behavior: BehaviorOnFailure::Exit, - stdout: OutputMode::Print, - stderr: OutputMode::Print, run_always: false, drop_bomb: DropBomb::arm(program), } @@ -230,17 +223,41 @@ pub fn command>(program: S) -> BootstrapCommand { } /// Represents the output of an executed process. -#[allow(unused)] pub struct CommandOutput { status: CommandStatus, - stdout: Vec, - stderr: Vec, + stdout: Option>, + stderr: Option>, } impl CommandOutput { #[must_use] - pub fn did_not_start() -> Self { - Self { status: CommandStatus::DidNotStart, stdout: vec![], stderr: vec![] } + pub fn did_not_start(stdout: OutputMode, stderr: OutputMode) -> Self { + Self { + status: CommandStatus::DidNotStart, + stdout: match stdout { + OutputMode::Print => None, + OutputMode::Capture => Some(vec![]), + }, + stderr: match stderr { + OutputMode::Print => None, + OutputMode::Capture => Some(vec![]), + }, + } + } + + #[must_use] + pub fn from_output(output: Output, stdout: OutputMode, stderr: OutputMode) -> Self { + Self { + status: CommandStatus::Finished(output.status), + stdout: match stdout { + OutputMode::Print => None, + OutputMode::Capture => Some(output.stdout), + }, + stderr: match stderr { + OutputMode::Print => None, + OutputMode::Capture => Some(output.stderr), + }, + } } #[must_use] @@ -266,7 +283,10 @@ impl CommandOutput { #[must_use] pub fn stdout(&self) -> String { - String::from_utf8(self.stdout.clone()).expect("Cannot parse process stdout as UTF-8") + String::from_utf8( + self.stdout.clone().expect("Accessing stdout of a command that did not capture stdout"), + ) + .expect("Cannot parse process stdout as UTF-8") } #[must_use] @@ -276,7 +296,10 @@ impl CommandOutput { #[must_use] pub fn stderr(&self) -> String { - String::from_utf8(self.stderr.clone()).expect("Cannot parse process stderr as UTF-8") + String::from_utf8( + self.stderr.clone().expect("Accessing stderr of a command that did not capture stderr"), + ) + .expect("Cannot parse process stderr as UTF-8") } } @@ -284,18 +307,8 @@ impl Default for CommandOutput { fn default() -> Self { Self { status: CommandStatus::Finished(ExitStatus::default()), - stdout: vec![], - stderr: vec![], - } - } -} - -impl From for CommandOutput { - fn from(output: Output) -> Self { - Self { - status: CommandStatus::Finished(output.status), - stdout: output.stdout, - stderr: output.stderr, + stdout: Some(vec![]), + stderr: Some(vec![]), } } } diff --git a/src/bootstrap/src/utils/helpers.rs b/src/bootstrap/src/utils/helpers.rs index 690d7318f9420..51c14ff6282bc 100644 --- a/src/bootstrap/src/utils/helpers.rs +++ b/src/bootstrap/src/utils/helpers.rs @@ -347,7 +347,7 @@ pub fn get_clang_cl_resource_dir(builder: &Builder<'_>, clang_cl_path: &str) -> let mut builtins_locator = command(clang_cl_path); builtins_locator.args(["/clang:-print-libgcc-file-name", "/clang:--rtlib=compiler-rt"]); - let clang_rt_builtins = builtins_locator.capture_stdout().run(builder).stdout(); + let clang_rt_builtins = builtins_locator.run_capture_stdout(builder).stdout(); let clang_rt_builtins = Path::new(clang_rt_builtins.trim()); assert!( clang_rt_builtins.exists(), @@ -372,9 +372,9 @@ fn lld_flag_no_threads(builder: &Builder<'_>, lld_mode: LldMode, is_windows: boo let (windows_flag, other_flag) = LLD_NO_THREADS.get_or_init(|| { let newer_version = match lld_mode { LldMode::External => { - let mut cmd = command("lld").capture_stdout(); + let mut cmd = command("lld"); cmd.arg("-flavor").arg("ld").arg("--version"); - let out = cmd.run(builder).stdout(); + let out = cmd.run_capture_stdout(builder).stdout(); match (out.find(char::is_numeric), out.find('.')) { (Some(b), Some(e)) => out.as_str()[b..e].parse::().ok().unwrap_or(14) > 10, _ => true, @@ -534,7 +534,7 @@ pub fn get_closest_merge_base_commit( author: &str, target_paths: &[PathBuf], ) -> Result { - let mut git = git(source_dir).capture_stdout(); + let mut git = git(source_dir); let merge_base = get_git_merge_base(config, source_dir).unwrap_or_else(|_| "HEAD".into()); diff --git a/src/bootstrap/src/utils/tarball.rs b/src/bootstrap/src/utils/tarball.rs index 28a295e3e2a5a..cef67ae4c371a 100644 --- a/src/bootstrap/src/utils/tarball.rs +++ b/src/bootstrap/src/utils/tarball.rs @@ -370,11 +370,10 @@ impl<'a> Tarball<'a> { if self.builder.rust_info().is_managed_git_subrepository() { // %ct means committer date let timestamp = helpers::git(Some(&self.builder.src)) - .capture_stdout() .arg("log") .arg("-1") .arg("--format=%ct") - .run(self.builder) + .run_capture_stdout(self.builder) .stdout(); cmd.args(["--override-file-mtime", timestamp.trim()]); } diff --git a/src/ci/docker/host-x86_64/arm-android/Dockerfile b/src/ci/docker/host-x86_64/arm-android/Dockerfile index abca06fb9fb4c..222fa8a7355c8 100644 --- a/src/ci/docker/host-x86_64/arm-android/Dockerfile +++ b/src/ci/docker/host-x86_64/arm-android/Dockerfile @@ -6,7 +6,7 @@ RUN sh /scripts/android-base-apt-get.sh COPY scripts/android-ndk.sh /scripts/ RUN . /scripts/android-ndk.sh && \ - download_ndk android-ndk-r25b-linux.zip + download_ndk android-ndk-r26d-linux.zip RUN dpkg --add-architecture i386 && \ apt-get update && \ diff --git a/src/ci/docker/host-x86_64/arm-android/android-sdk.lock b/src/ci/docker/host-x86_64/arm-android/android-sdk.lock index a1be8a4346b6d..33b0c66ae095a 100644 --- a/src/ci/docker/host-x86_64/arm-android/android-sdk.lock +++ b/src/ci/docker/host-x86_64/arm-android/android-sdk.lock @@ -1,6 +1,6 @@ emulator emulator-linux-5264690.zip 48c1cda2bdf3095d9d9d5c010fbfb3d6d673e3ea patcher;v4 3534162-studio.sdk-patcher.zip 046699c5e2716ae11d77e0bad814f7f33fab261e -platform-tools platform-tools_r28.0.2-linux.zip 46a4c02a9b8e4e2121eddf6025da3c979bf02e28 -platforms;android-18 android-18_r03.zip e6b09b3505754cbbeb4a5622008b907262ee91cb -system-images;android-18;default;armeabi-v7a sys-img/android/armeabi-v7a-18_r05.zip 580b583720f7de671040d5917c8c9db0c7aa03fd +platform-tools platform-tools_r34.0.5-linux.zip 96097475cf7b279fdd8f218f5d043ffe94104ec3 +platforms;android-21 android-21_r02.zip 53536556059bb29ae82f414fd2e14bc335a4eb4c +system-images;android-21;default;armeabi-v7a sys-img/android/armeabi-v7a-21_r04.zip 8c606f81306564b65e41303d2603e4c42ded0d10 tools sdk-tools-linux-4333796.zip 8c7c28554a32318461802c1291d76fccfafde054 diff --git a/src/ci/docker/host-x86_64/dist-android/Dockerfile b/src/ci/docker/host-x86_64/dist-android/Dockerfile index 20b72b377cad2..54649e0d22b92 100644 --- a/src/ci/docker/host-x86_64/dist-android/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-android/Dockerfile @@ -6,7 +6,7 @@ RUN sh /scripts/android-base-apt-get.sh # ndk COPY scripts/android-ndk.sh /scripts/ RUN . /scripts/android-ndk.sh && \ - download_ndk android-ndk-r25b-linux.zip + download_ndk android-ndk-r26d-linux.zip # env ENV TARGETS=arm-linux-androideabi diff --git a/src/ci/docker/scripts/android-start-emulator.sh b/src/ci/docker/scripts/android-start-emulator.sh index 09f0d13759c79..5ffb72eddb118 100755 --- a/src/ci/docker/scripts/android-start-emulator.sh +++ b/src/ci/docker/scripts/android-start-emulator.sh @@ -10,7 +10,7 @@ export SHELL=/bin/bash # the emulator date is set to unix epoch (in armeabi-v7a-18 image). Using # classic engine the emulator starts with the current date and the tests run # fine. If another image is used, this need to be evaluated again. -nohup nohup emulator @armeabi-v7a-18 \ +nohup nohup emulator @armeabi-v7a-21 \ -engine classic -no-window -partition-size 2047 0<&- &>/dev/null & exec "$@" diff --git a/src/ci/github-actions/calculate-job-matrix.py b/src/ci/github-actions/calculate-job-matrix.py index d03bbda100807..7de6d5fcd5f75 100755 --- a/src/ci/github-actions/calculate-job-matrix.py +++ b/src/ci/github-actions/calculate-job-matrix.py @@ -97,9 +97,15 @@ def find_run_type(ctx: GitHubCtx) -> Optional[WorkflowRunType]: "refs/heads/automation/bors/try" ) + # Unrolled branch from a rollup for testing perf + # This should **not** allow custom try jobs + is_unrolled_perf_build = ctx.ref == "refs/heads/try-perf" + if try_build: - jobs = get_custom_jobs(ctx) - return TryRunType(custom_jobs=jobs) + custom_jobs = [] + if not is_unrolled_perf_build: + custom_jobs = get_custom_jobs(ctx) + return TryRunType(custom_jobs=custom_jobs) if ctx.ref == "refs/heads/auto": return AutoRunType() diff --git a/src/doc/reference b/src/doc/reference index e2f0bdc403186..2e191814f163e 160000 --- a/src/doc/reference +++ b/src/doc/reference @@ -1 +1 @@ -Subproject commit e2f0bdc4031866734661dcdb548184bde1450baf +Subproject commit 2e191814f163ee1e77e2d6094eee4dd78a289c5b diff --git a/src/doc/rustc/src/targets/custom.md b/src/doc/rustc/src/targets/custom.md index a67cb10fc75a8..a332d24c9f1fb 100644 --- a/src/doc/rustc/src/targets/custom.md +++ b/src/doc/rustc/src/targets/custom.md @@ -15,3 +15,16 @@ rustc +nightly -Z unstable-options --target=wasm32-unknown-unknown --print targe ``` To use a custom target, see the (unstable) [`build-std` feature](../../cargo/reference/unstable.html#build-std) of `cargo`. + +## Custom Target Lookup Path + +When `rustc` is given an option `--target=TARGET` (where `TARGET` is any string), it uses the following logic: +1. if `TARGET` is the name of a built-in target, use that +2. if `TARGET` is a path to a file, read that file as a json target +3. otherwise, search the colon-seperated list of directories found + in the `RUST_TARGET_PATH` environment variable from left to right + for a file named `TARGET.json`. + +These steps are tried in order, so if there are multple potentially valid +interpretations for a target, whichever is found first will take priority. +If none of these methods find a target, an error is thrown. diff --git a/src/doc/unstable-book/src/library-features/is-sorted.md b/src/doc/unstable-book/src/library-features/is-sorted.md deleted file mode 100644 index e3b7dc3b28eb2..0000000000000 --- a/src/doc/unstable-book/src/library-features/is-sorted.md +++ /dev/null @@ -1,11 +0,0 @@ -# `is_sorted` - -The tracking issue for this feature is: [#53485] - -[#53485]: https://github.com/rust-lang/rust/issues/53485 - ------------------------- - -Add the methods `is_sorted`, `is_sorted_by` and `is_sorted_by_key` to `[T]`; -add the methods `is_sorted`, `is_sorted_by` and `is_sorted_by_key` to -`Iterator`. diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 0024e246ef007..dbdc4a5ae7188 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -131,8 +131,8 @@ pub(crate) fn try_inline( Res::Def(DefKind::Const, did) => { record_extern_fqn(cx, did, ItemType::Constant); cx.with_param_env(did, |cx| { - let (generics, ty, ct) = build_const_item(cx, did); - clean::ConstantItem(generics, Box::new(ty), ct) + let ct = build_const_item(cx, did); + clean::ConstantItem(Box::new(ct)) }) } Res::Def(DefKind::Macro(kind), did) => { @@ -720,10 +720,7 @@ pub(crate) fn print_inlined_const(tcx: TyCtxt<'_>, did: DefId) -> String { } } -fn build_const_item( - cx: &mut DocContext<'_>, - def_id: DefId, -) -> (clean::Generics, clean::Type, clean::Constant) { +fn build_const_item(cx: &mut DocContext<'_>, def_id: DefId) -> clean::Constant { let mut generics = clean_ty_generics(cx, cx.tcx.generics_of(def_id), cx.tcx.explicit_predicates_of(def_id)); clean::simplify::move_bounds_to_generic_parameters(&mut generics); @@ -733,17 +730,17 @@ fn build_const_item( None, None, ); - (generics, ty, clean::Constant { kind: clean::ConstantKind::Extern { def_id } }) + clean::Constant { generics, type_: ty, kind: clean::ConstantKind::Extern { def_id } } } fn build_static(cx: &mut DocContext<'_>, did: DefId, mutable: bool) -> clean::Static { clean::Static { - type_: clean_middle_ty( + type_: Box::new(clean_middle_ty( ty::Binder::dummy(cx.tcx.type_of(did).instantiate_identity()), cx, Some(did), None, - ), + )), mutability: if mutable { Mutability::Mut } else { Mutability::Not }, expr: None, } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 2cd9b6fcd387e..aaefac32711f1 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -287,23 +287,21 @@ fn clean_lifetime<'tcx>(lifetime: &hir::Lifetime, cx: &mut DocContext<'tcx>) -> pub(crate) fn clean_const<'tcx>( constant: &hir::ConstArg<'tcx>, _cx: &mut DocContext<'tcx>, -) -> Constant { +) -> ConstantKind { match &constant.kind { hir::ConstArgKind::Path(qpath) => { - Constant { kind: ConstantKind::Path { path: qpath_to_string(&qpath).into() } } - } - hir::ConstArgKind::Anon(anon) => { - Constant { kind: ConstantKind::Anonymous { body: anon.body } } + ConstantKind::Path { path: qpath_to_string(&qpath).into() } } + hir::ConstArgKind::Anon(anon) => ConstantKind::Anonymous { body: anon.body }, } } pub(crate) fn clean_middle_const<'tcx>( constant: ty::Binder<'tcx, ty::Const<'tcx>>, _cx: &mut DocContext<'tcx>, -) -> Constant { +) -> ConstantKind { // FIXME: instead of storing the stringified expression, store `self` directly instead. - Constant { kind: ConstantKind::TyConst { expr: constant.skip_binder().to_string().into() } } + ConstantKind::TyConst { expr: constant.skip_binder().to_string().into() } } pub(crate) fn clean_middle_region<'tcx>(region: ty::Region<'tcx>) -> Option { @@ -1230,14 +1228,11 @@ fn clean_trait_item<'tcx>(trait_item: &hir::TraitItem<'tcx>, cx: &mut DocContext let local_did = trait_item.owner_id.to_def_id(); cx.with_param_env(local_did, |cx| { let inner = match trait_item.kind { - hir::TraitItemKind::Const(ty, Some(default)) => { - let generics = enter_impl_trait(cx, |cx| clean_generics(trait_item.generics, cx)); - AssocConstItem( - generics, - Box::new(clean_ty(ty, cx)), - ConstantKind::Local { def_id: local_did, body: default }, - ) - } + hir::TraitItemKind::Const(ty, Some(default)) => AssocConstItem(Box::new(Constant { + generics: enter_impl_trait(cx, |cx| clean_generics(trait_item.generics, cx)), + kind: ConstantKind::Local { def_id: local_did, body: default }, + type_: clean_ty(ty, cx), + })), hir::TraitItemKind::Const(ty, None) => { let generics = enter_impl_trait(cx, |cx| clean_generics(trait_item.generics, cx)); TyAssocConstItem(generics, Box::new(clean_ty(ty, cx))) @@ -1282,11 +1277,11 @@ pub(crate) fn clean_impl_item<'tcx>( let local_did = impl_.owner_id.to_def_id(); cx.with_param_env(local_did, |cx| { let inner = match impl_.kind { - hir::ImplItemKind::Const(ty, expr) => { - let generics = clean_generics(impl_.generics, cx); - let default = ConstantKind::Local { def_id: local_did, body: expr }; - AssocConstItem(generics, Box::new(clean_ty(ty, cx)), default) - } + hir::ImplItemKind::Const(ty, expr) => AssocConstItem(Box::new(Constant { + generics: clean_generics(impl_.generics, cx), + kind: ConstantKind::Local { def_id: local_did, body: expr }, + type_: clean_ty(ty, cx), + })), hir::ImplItemKind::Fn(ref sig, body) => { let m = clean_function(cx, sig, impl_.generics, FunctionArgs::Body(body)); let defaultness = cx.tcx.defaultness(impl_.owner_id); @@ -1320,12 +1315,12 @@ pub(crate) fn clean_middle_assoc_item<'tcx>( let tcx = cx.tcx; let kind = match assoc_item.kind { ty::AssocKind::Const => { - let ty = Box::new(clean_middle_ty( + let ty = clean_middle_ty( ty::Binder::dummy(tcx.type_of(assoc_item.def_id).instantiate_identity()), cx, Some(assoc_item.def_id), None, - )); + ); let mut generics = clean_ty_generics( cx, @@ -1339,9 +1334,13 @@ pub(crate) fn clean_middle_assoc_item<'tcx>( ty::TraitContainer => tcx.defaultness(assoc_item.def_id).has_value(), }; if provided { - AssocConstItem(generics, ty, ConstantKind::Extern { def_id: assoc_item.def_id }) + AssocConstItem(Box::new(Constant { + generics, + kind: ConstantKind::Extern { def_id: assoc_item.def_id }, + type_: ty, + })) } else { - TyAssocConstItem(generics, ty) + TyAssocConstItem(generics, Box::new(ty)) } } ty::AssocKind::Fn => { @@ -1397,7 +1396,7 @@ pub(crate) fn clean_middle_assoc_item<'tcx>( { true } - (GenericParamDefKind::Const { .. }, GenericArg::Const(c)) => match &c.kind { + (GenericParamDefKind::Const { .. }, GenericArg::Const(c)) => match &**c { ConstantKind::TyConst { expr } => **expr == *param.name.as_str(), _ => false, }, @@ -1858,7 +1857,7 @@ pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> T } TyKind::Path(_) => clean_qpath(ty, cx), TyKind::TraitObject(bounds, ref lifetime, _) => { - let bounds = bounds.iter().map(|bound| clean_poly_trait_ref(bound, cx)).collect(); + let bounds = bounds.iter().map(|(bound, _)| clean_poly_trait_ref(bound, cx)).collect(); let lifetime = if !lifetime.is_elided() { Some(clean_lifetime(*lifetime, cx)) } else { None }; DynTrait(bounds, lifetime) @@ -2744,14 +2743,16 @@ fn clean_maybe_renamed_item<'tcx>( let mut name = renamed.unwrap_or_else(|| cx.tcx.hir().name(item.hir_id())); cx.with_param_env(def_id, |cx| { let kind = match item.kind { - ItemKind::Static(ty, mutability, body_id) => { - StaticItem(Static { type_: clean_ty(ty, cx), mutability, expr: Some(body_id) }) - } - ItemKind::Const(ty, generics, body_id) => ConstantItem( - clean_generics(generics, cx), - Box::new(clean_ty(ty, cx)), - Constant { kind: ConstantKind::Local { body: body_id, def_id } }, - ), + ItemKind::Static(ty, mutability, body_id) => StaticItem(Static { + type_: Box::new(clean_ty(ty, cx)), + mutability, + expr: Some(body_id), + }), + ItemKind::Const(ty, generics, body_id) => ConstantItem(Box::new(Constant { + generics: clean_generics(generics, cx), + type_: clean_ty(ty, cx), + kind: ConstantKind::Local { body: body_id, def_id }, + })), ItemKind::OpaqueTy(ref ty) => OpaqueTyItem(OpaqueTy { bounds: ty.bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect(), generics: clean_generics(ty.generics, cx), @@ -3109,7 +3110,7 @@ fn clean_maybe_renamed_foreign_item<'tcx>( ForeignFunctionItem(Box::new(Function { decl, generics }), safety) } hir::ForeignItemKind::Static(ty, mutability, safety) => ForeignStaticItem( - Static { type_: clean_ty(ty, cx), mutability, expr: None }, + Static { type_: Box::new(clean_ty(ty, cx)), mutability, expr: None }, safety, ), hir::ForeignItemKind::Type => ForeignTypeItem, diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 3709953159686..92fe98130e859 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -852,9 +852,9 @@ pub(crate) enum ItemKind { PrimitiveItem(PrimitiveType), /// A required associated constant in a trait declaration. TyAssocConstItem(Generics, Box), - ConstantItem(Generics, Box, Constant), + ConstantItem(Box), /// An associated constant in a trait impl or a provided one in a trait declaration. - AssocConstItem(Generics, Box, ConstantKind), + AssocConstItem(Box), /// A required associated type in a trait declaration. /// /// The bounds may be non-empty if there is a `where` clause. @@ -888,7 +888,7 @@ impl ItemKind { | TypeAliasItem(_) | OpaqueTyItem(_) | StaticItem(_) - | ConstantItem(_, _, _) + | ConstantItem(_) | TraitAliasItem(_) | TyMethodItem(_) | MethodItem(_, _) @@ -922,7 +922,7 @@ impl ItemKind { | TypeAliasItem(_) | OpaqueTyItem(_) | StaticItem(_) - | ConstantItem(_, _, _) + | ConstantItem(_) | TraitAliasItem(_) | ForeignFunctionItem(_, _) | ForeignStaticItem(_, _) @@ -2050,7 +2050,7 @@ impl From for PrimitiveType { pub(crate) struct Struct { pub(crate) ctor_kind: Option, pub(crate) generics: Generics, - pub(crate) fields: Vec, + pub(crate) fields: ThinVec, } impl Struct { @@ -2076,7 +2076,7 @@ impl Union { /// only as a variant in an enum. #[derive(Clone, Debug)] pub(crate) struct VariantStruct { - pub(crate) fields: Vec, + pub(crate) fields: ThinVec, } impl VariantStruct { @@ -2110,7 +2110,7 @@ pub(crate) struct Variant { #[derive(Clone, Debug)] pub(crate) enum VariantKind { CLike, - Tuple(Vec), + Tuple(ThinVec), Struct(VariantStruct), } @@ -2246,7 +2246,7 @@ impl Path { pub(crate) enum GenericArg { Lifetime(Lifetime), Type(Type), - Const(Box), + Const(Box), Infer, } @@ -2359,20 +2359,22 @@ pub(crate) struct BareFunctionDecl { #[derive(Clone, Debug)] pub(crate) struct Static { - pub(crate) type_: Type, + pub(crate) type_: Box, pub(crate) mutability: Mutability, pub(crate) expr: Option, } #[derive(Clone, PartialEq, Eq, Hash, Debug)] pub(crate) struct Constant { + pub(crate) generics: Generics, pub(crate) kind: ConstantKind, + pub(crate) type_: Type, } #[derive(Clone, PartialEq, Eq, Hash, Debug)] pub(crate) enum Term { Type(Type), - Constant(Constant), + Constant(ConstantKind), } impl Term { @@ -2594,7 +2596,7 @@ mod size_asserts { static_assert_size!(GenericParamDef, 40); static_assert_size!(Generics, 16); static_assert_size!(Item, 56); - static_assert_size!(ItemKind, 56); + static_assert_size!(ItemKind, 48); static_assert_size!(PathSegment, 40); static_assert_size!(Type, 32); // tidy-alphabetical-end diff --git a/src/librustdoc/fold.rs b/src/librustdoc/fold.rs index 346e9a4e113a5..beb7686e29c56 100644 --- a/src/librustdoc/fold.rs +++ b/src/librustdoc/fold.rs @@ -79,7 +79,7 @@ pub(crate) trait DocFolder: Sized { | FunctionItem(_) | OpaqueTyItem(_) | StaticItem(_) - | ConstantItem(_, _, _) + | ConstantItem(..) | TraitAliasItem(_) | TyMethodItem(_) | MethodItem(_, _) diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 055781f7fed72..18ee04a2f4d5f 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -375,7 +375,7 @@ impl clean::Lifetime { } } -impl clean::Constant { +impl clean::ConstantKind { pub(crate) fn print(&self, tcx: TyCtxt<'_>) -> impl Display + '_ { let expr = self.expr(tcx); display_fn( diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 5b9ef67109cf2..47712264e972d 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -1090,22 +1090,26 @@ fn render_assoc_item( clean::MethodItem(m, _) => { assoc_method(w, item, &m.generics, &m.decl, link, parent, cx, render_mode) } - kind @ (clean::TyAssocConstItem(generics, ty) | clean::AssocConstItem(generics, ty, _)) => { - assoc_const( - w, - item, - generics, - ty, - match kind { - clean::TyAssocConstItem(..) => None, - clean::AssocConstItem(.., default) => Some(default), - _ => unreachable!(), - }, - link, - if parent == ItemType::Trait { 4 } else { 0 }, - cx, - ) - } + clean::TyAssocConstItem(generics, ty) => assoc_const( + w, + item, + generics, + ty, + None, + link, + if parent == ItemType::Trait { 4 } else { 0 }, + cx, + ), + clean::AssocConstItem(ci) => assoc_const( + w, + item, + &ci.generics, + &ci.type_, + Some(&ci.kind), + link, + if parent == ItemType::Trait { 4 } else { 0 }, + cx, + ), clean::TyAssocTypeItem(ref generics, ref bounds) => assoc_type( w, item, @@ -1690,8 +1694,7 @@ fn render_impl( w.write_str(""); } } - kind @ (clean::TyAssocConstItem(generics, ty) - | clean::AssocConstItem(generics, ty, _)) => { + clean::TyAssocConstItem(generics, ty) => { let source_id = format!("{item_type}.{name}"); let id = cx.derive_id(&source_id); write!(w, "

"); @@ -1706,11 +1709,29 @@ fn render_impl( item, generics, ty, - match kind { - clean::TyAssocConstItem(..) => None, - clean::AssocConstItem(.., default) => Some(default), - _ => unreachable!(), - }, + None, + link.anchor(if trait_.is_some() { &source_id } else { &id }), + 0, + cx, + ); + w.write_str("
"); + } + clean::AssocConstItem(ci) => { + let source_id = format!("{item_type}.{name}"); + let id = cx.derive_id(&source_id); + write!(w, "
"); + render_rightside(w, cx, item, render_mode); + if trait_.is_some() { + // Anchors are only used on trait impls. + write!(w, "§"); + } + w.write_str("

"); + assoc_const( + w, + item, + &ci.generics, + &ci.type_, + Some(&ci.kind), link.anchor(if trait_.is_some() { &source_id } else { &id }), 0, cx, diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index cf78a1d223c89..0cf62ccf6e7ff 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -267,7 +267,7 @@ pub(super) fn print_item(cx: &mut Context<'_>, item: &clean::Item, buf: &mut Buf clean::PrimitiveItem(_) => item_primitive(buf, cx, item), clean::StaticItem(ref i) => item_static(buf, cx, item, i, None), clean::ForeignStaticItem(ref i, safety) => item_static(buf, cx, item, i, Some(*safety)), - clean::ConstantItem(generics, ty, c) => item_constant(buf, cx, item, generics, ty, c), + clean::ConstantItem(ci) => item_constant(buf, cx, item, &ci.generics, &ci.type_, &ci.kind), clean::ForeignTypeItem => item_foreign_type(buf, cx, item), clean::KeywordItem => item_keyword(buf, cx, item), clean::OpaqueTyItem(ref e) => item_opaque_ty(buf, cx, item, e), @@ -1841,7 +1841,7 @@ fn item_constant( it: &clean::Item, generics: &clean::Generics, ty: &clean::Type, - c: &clean::Constant, + c: &clean::ConstantKind, ) { wrap_item(w, |w| { let tcx = cx.tcx(); @@ -1911,7 +1911,7 @@ fn item_fields( w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, - fields: &Vec, + fields: &[clean::Item], ctor_kind: Option, ) { let mut fields = fields diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index 41c506f33dc1a..e936e1ca07ecd 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -16,6 +16,24 @@ --src-sidebar-width: 300px; --desktop-sidebar-z-index: 100; --sidebar-elems-left-padding: 24px; + /* clipboard */ + --clipboard-image: url('data:image/svg+xml,\ +\ +\ +'); + --copy-path-height: 34px; + --copy-path-width: 33px; + /* Checkmark */ + --checkmark-image: url('data:image/svg+xml,\ +\ +'); + --button-left-margin: 4px; + --button-border-radius: 2px; } /* See FiraSans-LICENSE.txt for the Fira Sans license. */ @@ -723,6 +741,11 @@ ul.block, .block li { position: relative; margin-bottom: 10px; } + +.rustdoc .example-wrap > pre { + border-radius: 6px; +} + /* For the last child of a div, the margin will be taken care of by the margin-top of the next item. */ .rustdoc .example-wrap:last-child { @@ -1427,15 +1450,17 @@ documentation. */ top: 20px; } -a.test-arrow { +.example-wrap > a.test-arrow, .example-wrap .button-holder { visibility: hidden; position: absolute; - padding: 5px 10px 5px 10px; - border-radius: 5px; - font-size: 1.375rem; - top: 5px; - right: 5px; + top: 4px; + right: 4px; z-index: 1; +} +a.test-arrow { + padding: 5px 7px; + border-radius: var(--button-border-radius); + font-size: 1rem; color: var(--test-arrow-color); background-color: var(--test-arrow-background-color); } @@ -1443,9 +1468,37 @@ a.test-arrow:hover { color: var(--test-arrow-hover-color); background-color: var(--test-arrow-hover-background-color); } -.example-wrap:hover .test-arrow { +.example-wrap .button-holder { + display: flex; +} +.example-wrap:hover > .test-arrow { + padding: 2px 7px; +} +.example-wrap:hover > .test-arrow, .example-wrap:hover > .button-holder { visibility: visible; } +.example-wrap .button-holder .copy-button { + color: var(--copy-path-button-color); + background: var(--main-background-color); + height: var(--copy-path-height); + width: var(--copy-path-width); + margin-left: var(--button-left-margin); + padding: 2px 0 0 4px; + border: 0; + cursor: pointer; + border-radius: var(--button-border-radius); +} +.example-wrap .button-holder .copy-button::before { + filter: var(--copy-path-img-filter); + content: var(--clipboard-image); +} +.example-wrap .button-holder .copy-button:hover::before { + filter: var(--copy-path-img-hover-filter); +} +.example-wrap .button-holder .copy-button.clicked::before { + content: var(--checkmark-image); + padding-right: 5px; +} .code-attribute { font-weight: 300; @@ -1610,7 +1663,7 @@ a.tooltip:hover::after { } #settings-menu, #help-button { - margin-left: 4px; + margin-left: var(--button-left-margin); display: flex; } #sidebar-button { @@ -1641,7 +1694,7 @@ a.tooltip:hover::after { justify-content: center; background-color: var(--button-background-color); border: 1px solid var(--border-color); - border-radius: 2px; + border-radius: var(--button-border-radius); color: var(--settings-button-color); /* Rare exception to specifying font sizes in rem. Since this is acting as an icon, it's okay to specify their sizes in pixels. */ @@ -1693,8 +1746,8 @@ a.tooltip:hover::after { #copy-path { color: var(--copy-path-button-color); background: var(--main-background-color); - height: 34px; - width: 33px; + height: var(--copy-path-height); + width: var(--copy-path-width); margin-left: 10px; padding: 0; padding-left: 2px; @@ -1703,27 +1756,13 @@ a.tooltip:hover::after { } #copy-path::before { filter: var(--copy-path-img-filter); - /* clipboard */ - content: url('data:image/svg+xml,\ -\ -\ -'); - width: 19px; - height: 18px; + content: var(--clipboard-image); } #copy-path:hover::before { filter: var(--copy-path-img-hover-filter); } #copy-path.clicked::before { - /* Checkmark */ - content: url('data:image/svg+xml,\ - \ - '); + content: var(--checkmark-image); } @keyframes rotating { diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js index 9506bc9ed220b..40d65ae7910e2 100644 --- a/src/librustdoc/html/static/js/main.js +++ b/src/librustdoc/html/static/js/main.js @@ -1771,9 +1771,37 @@ href="https://doc.rust-lang.org/${channel}/rustdoc/read-documentation/search.htm }()); // This section handles the copy button that appears next to the path breadcrumbs +// and the copy buttons on the code examples. (function() { - let reset_button_timeout = null; + // Common functions to copy buttons. + function copyContentToClipboard(content) { + const el = document.createElement("textarea"); + el.value = content; + el.setAttribute("readonly", ""); + // To not make it appear on the screen. + el.style.position = "absolute"; + el.style.left = "-9999px"; + document.body.appendChild(el); + el.select(); + document.execCommand("copy"); + document.body.removeChild(el); + } + + function copyButtonAnimation(button) { + button.classList.add("clicked"); + + if (button.reset_button_timeout !== undefined) { + window.clearTimeout(button.reset_button_timeout); + } + + button.reset_button_timeout = window.setTimeout(() => { + button.reset_button_timeout = undefined; + button.classList.remove("clicked"); + }, 1000); + } + + // Copy button that appears next to the path breadcrumbs. const but = document.getElementById("copy-path"); if (!but) { return; @@ -1788,29 +1816,49 @@ href="https://doc.rust-lang.org/${channel}/rustdoc/read-documentation/search.htm } }); - const el = document.createElement("textarea"); - el.value = path.join("::"); - el.setAttribute("readonly", ""); - // To not make it appear on the screen. - el.style.position = "absolute"; - el.style.left = "-9999px"; - - document.body.appendChild(el); - el.select(); - document.execCommand("copy"); - document.body.removeChild(el); - - but.classList.add("clicked"); + copyContentToClipboard(path.join("::")); + copyButtonAnimation(but); + }; - if (reset_button_timeout !== null) { - window.clearTimeout(reset_button_timeout); + // Copy buttons on code examples. + function copyCode(codeElem) { + if (!codeElem) { + // Should never happen, but the world is a dark and dangerous place. + return; } + copyContentToClipboard(codeElem.textContent); + } - function reset_button() { - reset_button_timeout = null; - but.classList.remove("clicked"); + function addCopyButton(event) { + let elem = event.target; + while (!hasClass(elem, "example-wrap")) { + elem = elem.parentElement; + if (elem.tagName === "body" || hasClass(elem, "docblock")) { + return; + } + } + // Since the button will be added, no need to keep this listener around. + elem.removeEventListener("mouseover", addCopyButton); + + const parent = document.createElement("div"); + parent.className = "button-holder"; + const runButton = elem.querySelector(".test-arrow"); + if (runButton !== null) { + // If there is a run button, we move it into the same div. + parent.appendChild(runButton); } + elem.appendChild(parent); + const copyButton = document.createElement("button"); + copyButton.className = "copy-button"; + copyButton.title = "Copy code to clipboard"; + copyButton.addEventListener("click", () => { + copyCode(elem.querySelector("pre > code")); + copyButtonAnimation(copyButton); + }); + parent.appendChild(copyButton); + } - reset_button_timeout = window.setTimeout(reset_button, 1000); - }; + onEachLazy(document.querySelectorAll(".docblock .example-wrap"), elem => { + elem.addEventListener("mouseover", addCopyButton); + }); }()); diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js index 86af38f3ee75e..3eb27ea087c1d 100644 --- a/src/librustdoc/html/static/js/search.js +++ b/src/librustdoc/html/static/js/search.js @@ -2932,7 +2932,7 @@ ${item.displayPath}${name}\ } // Update document title to maintain a meaningful browser history - searchState.title = "Results for " + query.original + " - Rust"; + searchState.title = "\"" + query.original + "\" Search - Rust"; // Because searching is incremental by character, only the most // recent search query is added to the browser history. diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index 4ab0df3670859..a4731feb8de00 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -188,6 +188,16 @@ impl FromWithTcx for Constant { } } +impl FromWithTcx for Constant { + // FIXME(generic_const_items): Add support for generic const items. + fn from_tcx(constant: clean::ConstantKind, tcx: TyCtxt<'_>) -> Self { + let expr = constant.expr(tcx); + let value = constant.value(tcx); + let is_literal = constant.is_literal(tcx); + Constant { expr, value, is_literal } + } +} + impl FromWithTcx for TypeBinding { fn from_tcx(constraint: clean::AssocItemConstraint, tcx: TyCtxt<'_>) -> Self { TypeBinding { @@ -325,8 +335,8 @@ fn from_clean_item(item: clean::Item, tcx: TyCtxt<'_>) -> ItemEnum { TypeAliasItem(t) => ItemEnum::TypeAlias(t.into_tcx(tcx)), OpaqueTyItem(t) => ItemEnum::OpaqueTy(t.into_tcx(tcx)), // FIXME(generic_const_items): Add support for generic free consts - ConstantItem(_generics, t, c) => { - ItemEnum::Constant { type_: (*t).into_tcx(tcx), const_: c.into_tcx(tcx) } + ConstantItem(ci) => { + ItemEnum::Constant { type_: ci.type_.into_tcx(tcx), const_: ci.kind.into_tcx(tcx) } } MacroItem(m) => ItemEnum::Macro(m.source), ProcMacroItem(m) => ItemEnum::ProcMacro(m.into_tcx(tcx)), @@ -341,8 +351,8 @@ fn from_clean_item(item: clean::Item, tcx: TyCtxt<'_>) -> ItemEnum { ItemEnum::AssocConst { type_: (*ty).into_tcx(tcx), default: None } } // FIXME(generic_const_items): Add support for generic associated consts. - AssocConstItem(_generics, ty, default) => { - ItemEnum::AssocConst { type_: (*ty).into_tcx(tcx), default: Some(default.expr(tcx)) } + AssocConstItem(ci) => { + ItemEnum::AssocConst { type_: ci.type_.into_tcx(tcx), default: Some(ci.kind.expr(tcx)) } } TyAssocTypeItem(g, b) => ItemEnum::AssocType { generics: g.into_tcx(tcx), @@ -829,7 +839,7 @@ impl FromWithTcx for OpaqueTy { impl FromWithTcx for Static { fn from_tcx(stat: clean::Static, tcx: TyCtxt<'_>) -> Self { Static { - type_: stat.type_.into_tcx(tcx), + type_: (*stat.type_).into_tcx(tcx), mutable: stat.mutability == ast::Mutability::Mut, expr: stat .expr diff --git a/src/librustdoc/passes/check_doc_test_visibility.rs b/src/librustdoc/passes/check_doc_test_visibility.rs index 0437f5e5fd818..f97c417847359 100644 --- a/src/librustdoc/passes/check_doc_test_visibility.rs +++ b/src/librustdoc/passes/check_doc_test_visibility.rs @@ -62,7 +62,7 @@ pub(crate) fn should_have_doc_example(cx: &DocContext<'_>, item: &clean::Item) - | clean::AssocTypeItem(..) | clean::TypeAliasItem(_) | clean::StaticItem(_) - | clean::ConstantItem(_, _, _) + | clean::ConstantItem(..) | clean::ExternCrateItem { .. } | clean::ImportItem(_) | clean::PrimitiveItem(_) diff --git a/src/librustdoc/visit.rs b/src/librustdoc/visit.rs index b335dc5bd16b8..de836439be957 100644 --- a/src/librustdoc/visit.rs +++ b/src/librustdoc/visit.rs @@ -28,7 +28,7 @@ pub(crate) trait DocVisitor: Sized { | TypeAliasItem(_) | OpaqueTyItem(_) | StaticItem(_) - | ConstantItem(_, _, _) + | ConstantItem(..) | TraitAliasItem(_) | TyMethodItem(_) | MethodItem(_, _) diff --git a/src/tools/build-manifest/src/manifest.rs b/src/tools/build-manifest/src/manifest.rs index a9f19d8e5653f..6fa4f83e41543 100644 --- a/src/tools/build-manifest/src/manifest.rs +++ b/src/tools/build-manifest/src/manifest.rs @@ -88,7 +88,7 @@ impl Target { let gz = tarball_variant(builder, &base_path, "gz"); let xz = tarball_variant(builder, &base_path, "xz"); - if gz.is_none() { + if gz.is_none() && xz.is_none() { return Self::unavailable(); } diff --git a/src/tools/cargo b/src/tools/cargo index 5f6b9a92201d7..b5d44db1daf04 160000 --- a/src/tools/cargo +++ b/src/tools/cargo @@ -1 +1 @@ -Subproject commit 5f6b9a92201d78af75dc24f14662c3e2dacbbbe1 +Subproject commit b5d44db1daf0469b227a6211b987162a39a54730 diff --git a/src/tools/clippy/.cargo/config.toml b/src/tools/clippy/.cargo/config.toml index 48a63e4856815..7afdd068a9905 100644 --- a/src/tools/clippy/.cargo/config.toml +++ b/src/tools/clippy/.cargo/config.toml @@ -4,7 +4,7 @@ uibless = "test --test compile-test -- -- --bless" bless = "test -- -- --bless" dev = "run --package clippy_dev --bin clippy_dev --manifest-path clippy_dev/Cargo.toml --" lintcheck = "run --package lintcheck --bin lintcheck --manifest-path lintcheck/Cargo.toml -- " -collect-metadata = "test --test dogfood --features internal -- run_metadata_collection_lint --ignored" +collect-metadata = "test --test dogfood --features internal -- collect_metadata" [build] # -Zbinary-dep-depinfo allows us to track which rlib files to use for compiling UI tests diff --git a/src/tools/clippy/.github/workflows/lintcheck.yml b/src/tools/clippy/.github/workflows/lintcheck.yml index f016a77005920..6a5139b6dc0bb 100644 --- a/src/tools/clippy/.github/workflows/lintcheck.yml +++ b/src/tools/clippy/.github/workflows/lintcheck.yml @@ -53,18 +53,18 @@ jobs: id: cache-json uses: actions/cache@v4 with: - path: lintcheck-logs/lintcheck_crates_logs.json + path: lintcheck-logs/ci_crates_logs.json key: ${{ steps.key.outputs.key }} - name: Run lintcheck if: steps.cache-json.outputs.cache-hit != 'true' - run: ./target/debug/lintcheck --format json --warn-all + run: ./target/debug/lintcheck --format json --warn-all --crates-toml ./lintcheck/ci_crates.toml - name: Upload base JSON uses: actions/upload-artifact@v4 with: name: base - path: lintcheck-logs/lintcheck_crates_logs.json + path: lintcheck-logs/ci_crates_logs.json # Runs lintcheck on the PR and stores the results as an artifact head: @@ -86,13 +86,13 @@ jobs: run: cargo build --manifest-path=lintcheck/Cargo.toml - name: Run lintcheck - run: ./target/debug/lintcheck --format json --warn-all + run: ./target/debug/lintcheck --format json --warn-all --crates-toml ./lintcheck/ci_crates.toml - name: Upload head JSON uses: actions/upload-artifact@v4 with: name: head - path: lintcheck-logs/lintcheck_crates_logs.json + path: lintcheck-logs/ci_crates_logs.json # Retrieves the head and base JSON results and prints the diff to the GH actions step summary diff: @@ -115,4 +115,20 @@ jobs: uses: actions/download-artifact@v4 - name: Diff results - run: ./target/debug/lintcheck diff {base,head}/lintcheck_crates_logs.json >> $GITHUB_STEP_SUMMARY + # GH's summery has a maximum size of 1024k: + # https://docs.github.com/actions/using-workflows/workflow-commands-for-github-actions#adding-a-markdown-summary + # That's why we first log to file and then to the summary and logs + run: | + ./target/debug/lintcheck diff {base,head}/ci_crates_logs.json --truncate >> truncated_diff.md + head -c 1024000 truncated_diff.md >> $GITHUB_STEP_SUMMARY + cat truncated_diff.md + ./target/debug/lintcheck diff {base,head}/ci_crates_logs.json >> full_diff.md + + - name: Upload full diff + uses: actions/upload-artifact@v4 + with: + name: diff + if-no-files-found: ignore + path: | + full_diff.md + truncated_diff.md diff --git a/src/tools/clippy/CHANGELOG.md b/src/tools/clippy/CHANGELOG.md index 55281f3cbec0b..60c03b03d9be3 100644 --- a/src/tools/clippy/CHANGELOG.md +++ b/src/tools/clippy/CHANGELOG.md @@ -6,11 +6,53 @@ document. ## Unreleased / Beta / In Rust Nightly -[ca3b3937...master](https://github.com/rust-lang/rust-clippy/compare/ca3b3937...master) +[c9139bd5...master](https://github.com/rust-lang/rust-clippy/compare/c9139bd5...master) + +## Rust 1.80 + +Current stable, released 2024-07-25 + +[View all 68 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2024-04-18T22%3A50%3A22Z..2024-05-30T08%3A26%3A18Z+base%3Amaster) + +### New Lints + +* Added [`while_float`] to `nursery` + [#12765](https://github.com/rust-lang/rust-clippy/pull/12765) +* Added [`macro_metavars_in_unsafe`] to `suspicious` + [#12107](https://github.com/rust-lang/rust-clippy/pull/12107) +* Added [`renamed_function_params`] to `restriction` + [#11540](https://github.com/rust-lang/rust-clippy/pull/11540) +* Added [`doc_lazy_continuation`] to `style` + [#12770](https://github.com/rust-lang/rust-clippy/pull/12770) + +### Moves and Deprecations + +* Moved [`assigning_clones`] to `pedantic` (From `perf` now allow-by-default) + [#12779](https://github.com/rust-lang/rust-clippy/pull/12779) +* Moved [`single_char_pattern`] to `pedantic` (From `perf` now allow-by-default) + [#11852](https://github.com/rust-lang/rust-clippy/pull/11852) + +### Enhancements + +* [`panic`]: Added [`allow-panic-in-tests`] configuration to allow the lint in tests + [#12803](https://github.com/rust-lang/rust-clippy/pull/12803) +* [`missing_const_for_fn`]: Now respects the [`msrv`] configuration + [#12713](https://github.com/rust-lang/rust-clippy/pull/12713) +* [`missing_panics_doc`]: No longer lints on compile-time panics + [#12790](https://github.com/rust-lang/rust-clippy/pull/12790) +* [`collapsible_match`]: Now considers the [`msrv`] configuration for the suggestion + [#12745](https://github.com/rust-lang/rust-clippy/pull/12745) +* [`useless_vec`]: Added [`allow-useless-vec-in-tests`] configuration to allow the lint in tests + [#12725](https://github.com/rust-lang/rust-clippy/pull/12725) + +### Suggestion Fixes/Improvements + +* [`single_match`], [`single_match_else`]: Suggestions are now machine-applicable + [#12726](https://github.com/rust-lang/rust-clippy/pull/12726) ## Rust 1.79 -Current stable, released 2024-06-13 +Released 2024-06-13 [View all 102 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2024-03-08T11%3A13%3A58Z..2024-04-18T15%3A50%3A50Z+base%3Amaster) @@ -5712,6 +5754,7 @@ Released 2018-09-13 [`partialeq_to_none`]: https://rust-lang.github.io/rust-clippy/master/index.html#partialeq_to_none [`path_buf_push_overwrite`]: https://rust-lang.github.io/rust-clippy/master/index.html#path_buf_push_overwrite [`path_ends_with_ext`]: https://rust-lang.github.io/rust-clippy/master/index.html#path_ends_with_ext +[`pathbuf_init_then_push`]: https://rust-lang.github.io/rust-clippy/master/index.html#pathbuf_init_then_push [`pattern_type_mismatch`]: https://rust-lang.github.io/rust-clippy/master/index.html#pattern_type_mismatch [`permissions_set_readonly_false`]: https://rust-lang.github.io/rust-clippy/master/index.html#permissions_set_readonly_false [`positional_named_format_parameters`]: https://rust-lang.github.io/rust-clippy/master/index.html#positional_named_format_parameters diff --git a/src/tools/clippy/Cargo.toml b/src/tools/clippy/Cargo.toml index 4378849905514..bb4dc97e748e3 100644 --- a/src/tools/clippy/Cargo.toml +++ b/src/tools/clippy/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clippy" -version = "0.1.81" +version = "0.1.82" description = "A bunch of helpful lints to avoid common pitfalls in Rust" repository = "https://github.com/rust-lang/rust-clippy" readme = "README.md" @@ -30,11 +30,10 @@ color-print = "0.3.4" anstream = "0.6.0" [dev-dependencies] -ui_test = "0.23" +ui_test = "0.24" regex = "1.5.5" toml = "0.7.3" walkdir = "2.3" -# This is used by the `collect-metadata` alias. filetime = "0.2.9" itertools = "0.12" @@ -63,3 +62,7 @@ rustc_private = true [[test]] name = "compile-test" harness = false + +[[test]] +name = "dogfood" +harness = false diff --git a/src/tools/clippy/book/src/development/adding_lints.md b/src/tools/clippy/book/src/development/adding_lints.md index 48c00bcbf3413..a71d94daca74c 100644 --- a/src/tools/clippy/book/src/development/adding_lints.md +++ b/src/tools/clippy/book/src/development/adding_lints.md @@ -458,9 +458,8 @@ pub struct ManualStrip { } impl ManualStrip { - #[must_use] - pub fn new(msrv: Msrv) -> Self { - Self { msrv } + pub fn new(conf: &'static Conf) -> Self { + Self { msrv: conf.msrv.clone() } } } ``` @@ -689,7 +688,6 @@ for some users. Adding a configuration is done in the following steps: ]); // New manual definition struct - #[derive(Copy, Clone)] pub struct StructName {} impl_lint_pass!(StructName => [ @@ -700,7 +698,6 @@ for some users. Adding a configuration is done in the following steps: 2. Next add the configuration value and a corresponding creation method like this: ```rust - #[derive(Copy, Clone)] pub struct StructName { configuration_ident: Type, } @@ -708,9 +705,9 @@ for some users. Adding a configuration is done in the following steps: // ... impl StructName { - pub fn new(configuration_ident: Type) -> Self { + pub fn new(conf: &'static Conf) -> Self { Self { - configuration_ident, + configuration_ident: conf.configuration_ident, } } } @@ -726,8 +723,7 @@ for some users. Adding a configuration is done in the following steps: store.register_*_pass(|| box module::StructName); // New registration with configuration value - let configuration_ident = conf.configuration_ident.clone(); - store.register_*_pass(move || box module::StructName::new(configuration_ident)); + store.register_*_pass(move || box module::StructName::new(conf)); ``` Congratulations the work is almost done. The configuration value can now be diff --git a/src/tools/clippy/book/src/lint_configuration.md b/src/tools/clippy/book/src/lint_configuration.md index ad29339a84ad6..fb717a2c166d4 100644 --- a/src/tools/clippy/book/src/lint_configuration.md +++ b/src/tools/clippy/book/src/lint_configuration.md @@ -455,7 +455,7 @@ default configuration of Clippy. By default, any configuration will replace the * `doc-valid-idents = ["ClipPy"]` would replace the default list with `["ClipPy"]`. * `doc-valid-idents = ["ClipPy", ".."]` would append `ClipPy` to the default list. -**Default Value:** `["KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "DevOps", "DirectX", "ECMAScript", "GPLv2", "GPLv3", "GitHub", "GitLab", "IPv4", "IPv6", "ClojureScript", "CoffeeScript", "JavaScript", "PureScript", "TypeScript", "WebAssembly", "NaN", "NaNs", "OAuth", "GraphQL", "OCaml", "OpenDNS", "OpenGL", "OpenMP", "OpenSSH", "OpenSSL", "OpenStreetMap", "OpenTelemetry", "WebGL", "WebGL2", "WebGPU", "WebP", "OpenExr", "YCbCr", "sRGB", "TensorFlow", "TrueType", "iOS", "macOS", "FreeBSD", "TeX", "LaTeX", "BibTeX", "BibLaTeX", "MinGW", "CamelCase"]` +**Default Value:** `["TiB", "CoreGraphics", "CoffeeScript", "TeX", "Direct2D", "PiB", "DirectX", "NetBSD", "OAuth", "NaN", "OpenType", "WebGL2", "WebTransport", "JavaScript", "OpenSSL", "OpenSSH", "EiB", "PureScript", "OpenAL", "MiB", "WebAssembly", "MinGW", "CoreFoundation", "WebGPU", "ClojureScript", "CamelCase", "OpenDNS", "NaNs", "OpenMP", "GitLab", "KiB", "sRGB", "CoreText", "macOS", "TypeScript", "GiB", "OpenExr", "YCbCr", "OpenTelemetry", "OpenBSD", "FreeBSD", "GPLv2", "PostScript", "WebP", "LaTeX", "TensorFlow", "AccessKit", "TrueType", "OpenStreetMap", "OpenGL", "DevOps", "OCaml", "WebRTC", "WebGL", "BibLaTeX", "GitHub", "GraphQL", "iOS", "Direct3D", "BibTeX", "DirectWrite", "GPLv3", "IPv6", "WebSocket", "IPv4", "ECMAScript"]` --- **Affected lints:** @@ -679,6 +679,7 @@ The minimum rust version that the project supports. Defaults to the `rust-versio * [`cast_abs_to_unsigned`](https://rust-lang.github.io/rust-clippy/master/index.html#cast_abs_to_unsigned) * [`checked_conversions`](https://rust-lang.github.io/rust-clippy/master/index.html#checked_conversions) * [`cloned_instead_of_copied`](https://rust-lang.github.io/rust-clippy/master/index.html#cloned_instead_of_copied) +* [`collapsible_match`](https://rust-lang.github.io/rust-clippy/master/index.html#collapsible_match) * [`collapsible_str_replace`](https://rust-lang.github.io/rust-clippy/master/index.html#collapsible_str_replace) * [`deprecated_cfg_attr`](https://rust-lang.github.io/rust-clippy/master/index.html#deprecated_cfg_attr) * [`derivable_impls`](https://rust-lang.github.io/rust-clippy/master/index.html#derivable_impls) diff --git a/src/tools/clippy/clippy.toml b/src/tools/clippy/clippy.toml index 319b72e8c5d50..a7b0cc56ea127 100644 --- a/src/tools/clippy/clippy.toml +++ b/src/tools/clippy/clippy.toml @@ -8,7 +8,6 @@ reason = "this function does not add a link to our documentation, please use the path = "rustc_lint::context::LintContext::span_lint" reason = "this function does not add a link to our documentation, please use the `clippy_utils::diagnostics::span_lint*` functions instead" - [[disallowed-methods]] path = "rustc_middle::ty::context::TyCtxt::node_span_lint" reason = "this function does not add a link to our documentation, please use the `clippy_utils::diagnostics::span_lint_hir*` functions instead" diff --git a/src/tools/clippy/clippy_config/Cargo.toml b/src/tools/clippy/clippy_config/Cargo.toml index be0b048ac0c76..e1b2edc8a6ff9 100644 --- a/src/tools/clippy/clippy_config/Cargo.toml +++ b/src/tools/clippy/clippy_config/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clippy_config" -version = "0.1.81" +version = "0.1.82" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/src/tools/clippy/clippy_config/src/conf.rs b/src/tools/clippy/clippy_config/src/conf.rs index 7f53aad679330..63140a36875da 100644 --- a/src/tools/clippy/clippy_config/src/conf.rs +++ b/src/tools/clippy/clippy_config/src/conf.rs @@ -18,23 +18,26 @@ use std::{cmp, env, fmt, fs, io}; #[rustfmt::skip] const DEFAULT_DOC_VALID_IDENTS: &[&str] = &[ "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", + "AccessKit", + "CoreFoundation", "CoreGraphics", "CoreText", "DevOps", - "DirectX", + "Direct2D", "Direct3D", "DirectWrite", "DirectX", "ECMAScript", "GPLv2", "GPLv3", "GitHub", "GitLab", "IPv4", "IPv6", - "ClojureScript", "CoffeeScript", "JavaScript", "PureScript", "TypeScript", + "ClojureScript", "CoffeeScript", "JavaScript", "PostScript", "PureScript", "TypeScript", "WebAssembly", "NaN", "NaNs", "OAuth", "GraphQL", "OCaml", - "OpenDNS", "OpenGL", "OpenMP", "OpenSSH", "OpenSSL", "OpenStreetMap", "OpenTelemetry", - "WebGL", "WebGL2", "WebGPU", + "OpenAL", "OpenDNS", "OpenGL", "OpenMP", "OpenSSH", "OpenSSL", "OpenStreetMap", "OpenTelemetry", + "OpenType", + "WebGL", "WebGL2", "WebGPU", "WebRTC", "WebSocket", "WebTransport", "WebP", "OpenExr", "YCbCr", "sRGB", "TensorFlow", "TrueType", - "iOS", "macOS", "FreeBSD", + "iOS", "macOS", "FreeBSD", "NetBSD", "OpenBSD", "TeX", "LaTeX", "BibTeX", "BibLaTeX", "MinGW", "CamelCase", @@ -235,7 +238,7 @@ define_Conf! { /// /// A type, say `SomeType`, listed in this configuration has the same behavior of /// `["SomeType" , "*"], ["*", "SomeType"]` in `arithmetic_side_effects_allowed_binary`. - (arithmetic_side_effects_allowed: FxHashSet = <_>::default()), + (arithmetic_side_effects_allowed: Vec = <_>::default()), /// Lint: ARITHMETIC_SIDE_EFFECTS. /// /// Suppress checking of the passed type pair names in binary operations like addition or @@ -262,12 +265,12 @@ define_Conf! { /// ```toml /// arithmetic-side-effects-allowed-unary = ["SomeType", "AnotherType"] /// ``` - (arithmetic_side_effects_allowed_unary: FxHashSet = <_>::default()), + (arithmetic_side_effects_allowed_unary: Vec = <_>::default()), /// Lint: ENUM_VARIANT_NAMES, LARGE_TYPES_PASSED_BY_VALUE, TRIVIALLY_COPY_PASS_BY_REF, UNNECESSARY_WRAPS, UNUSED_SELF, UPPER_CASE_ACRONYMS, WRONG_SELF_CONVENTION, BOX_COLLECTION, REDUNDANT_ALLOCATION, RC_BUFFER, VEC_BOX, OPTION_OPTION, LINKEDLIST, RC_MUTEX, UNNECESSARY_BOX_RETURNS, SINGLE_CALL_FN, NEEDLESS_PASS_BY_REF_MUT. /// /// Suppress lints whenever the suggested change would cause breakage for other crates. (avoid_breaking_exported_api: bool = true), - /// Lint: MANUAL_SPLIT_ONCE, MANUAL_STR_REPEAT, CLONED_INSTEAD_OF_COPIED, REDUNDANT_FIELD_NAMES, OPTION_MAP_UNWRAP_OR, REDUNDANT_STATIC_LIFETIMES, FILTER_MAP_NEXT, CHECKED_CONVERSIONS, MANUAL_RANGE_CONTAINS, USE_SELF, MEM_REPLACE_WITH_DEFAULT, MANUAL_NON_EXHAUSTIVE, OPTION_AS_REF_DEREF, MAP_UNWRAP_OR, MATCH_LIKE_MATCHES_MACRO, MANUAL_STRIP, MISSING_CONST_FOR_FN, UNNESTED_OR_PATTERNS, FROM_OVER_INTO, PTR_AS_PTR, IF_THEN_SOME_ELSE_NONE, APPROX_CONSTANT, DEPRECATED_CFG_ATTR, INDEX_REFUTABLE_SLICE, MAP_CLONE, BORROW_AS_PTR, MANUAL_BITS, ERR_EXPECT, CAST_ABS_TO_UNSIGNED, UNINLINED_FORMAT_ARGS, MANUAL_CLAMP, MANUAL_LET_ELSE, UNCHECKED_DURATION_SUBTRACTION, COLLAPSIBLE_STR_REPLACE, SEEK_FROM_CURRENT, SEEK_REWIND, UNNECESSARY_LAZY_EVALUATIONS, TRANSMUTE_PTR_TO_REF, ALMOST_COMPLETE_RANGE, NEEDLESS_BORROW, DERIVABLE_IMPLS, MANUAL_IS_ASCII_CHECK, MANUAL_REM_EUCLID, MANUAL_RETAIN, TYPE_REPETITION_IN_BOUNDS, TUPLE_ARRAY_CONVERSIONS, MANUAL_TRY_FOLD, MANUAL_HASH_ONE, ITER_KV_MAP, MANUAL_C_STR_LITERALS, ASSIGNING_CLONES, LEGACY_NUMERIC_CONSTANTS, MANUAL_PATTERN_CHAR_COMPARISON, ALLOW_ATTRIBUTES, ALLOW_ATTRIBUTES_WITHOUT_REASON. + /// Lint: MANUAL_SPLIT_ONCE, MANUAL_STR_REPEAT, CLONED_INSTEAD_OF_COPIED, REDUNDANT_FIELD_NAMES, OPTION_MAP_UNWRAP_OR, REDUNDANT_STATIC_LIFETIMES, FILTER_MAP_NEXT, CHECKED_CONVERSIONS, MANUAL_RANGE_CONTAINS, USE_SELF, MEM_REPLACE_WITH_DEFAULT, MANUAL_NON_EXHAUSTIVE, OPTION_AS_REF_DEREF, MAP_UNWRAP_OR, MATCH_LIKE_MATCHES_MACRO, MANUAL_STRIP, MISSING_CONST_FOR_FN, UNNESTED_OR_PATTERNS, FROM_OVER_INTO, PTR_AS_PTR, IF_THEN_SOME_ELSE_NONE, APPROX_CONSTANT, DEPRECATED_CFG_ATTR, INDEX_REFUTABLE_SLICE, MAP_CLONE, BORROW_AS_PTR, MANUAL_BITS, ERR_EXPECT, CAST_ABS_TO_UNSIGNED, UNINLINED_FORMAT_ARGS, MANUAL_CLAMP, MANUAL_LET_ELSE, UNCHECKED_DURATION_SUBTRACTION, COLLAPSIBLE_STR_REPLACE, SEEK_FROM_CURRENT, SEEK_REWIND, UNNECESSARY_LAZY_EVALUATIONS, TRANSMUTE_PTR_TO_REF, ALMOST_COMPLETE_RANGE, NEEDLESS_BORROW, DERIVABLE_IMPLS, MANUAL_IS_ASCII_CHECK, MANUAL_REM_EUCLID, MANUAL_RETAIN, TYPE_REPETITION_IN_BOUNDS, TUPLE_ARRAY_CONVERSIONS, MANUAL_TRY_FOLD, MANUAL_HASH_ONE, ITER_KV_MAP, MANUAL_C_STR_LITERALS, ASSIGNING_CLONES, LEGACY_NUMERIC_CONSTANTS, MANUAL_PATTERN_CHAR_COMPARISON, ALLOW_ATTRIBUTES, ALLOW_ATTRIBUTES_WITHOUT_REASON, COLLAPSIBLE_MATCH. /// /// The minimum rust version that the project supports. Defaults to the `rust-version` field in `Cargo.toml` #[default_text = ""] @@ -311,7 +314,7 @@ define_Conf! { /// default configuration of Clippy. By default, any configuration will replace the default value. For example: /// * `doc-valid-idents = ["ClipPy"]` would replace the default list with `["ClipPy"]`. /// * `doc-valid-idents = ["ClipPy", ".."]` would append `ClipPy` to the default list. - (doc_valid_idents: Vec = DEFAULT_DOC_VALID_IDENTS.iter().map(ToString::to_string).collect()), + (doc_valid_idents: FxHashSet = DEFAULT_DOC_VALID_IDENTS.iter().map(ToString::to_string).collect()), /// Lint: TOO_MANY_ARGUMENTS. /// /// The maximum number of argument a function or method can have @@ -547,7 +550,7 @@ define_Conf! { /// Lint: PATH_ENDS_WITH_EXT. /// /// Additional dotfiles (files or directories starting with a dot) to allow - (allowed_dotfiles: FxHashSet = FxHashSet::default()), + (allowed_dotfiles: Vec = Vec::default()), /// Lint: MULTIPLE_CRATE_VERSIONS. /// /// A list of crate names to allow duplicates of @@ -700,7 +703,6 @@ pub fn lookup_conf_file() -> io::Result<(Option, Vec)> { fn deserialize(file: &SourceFile) -> TryConf { match toml::de::Deserializer::new(file.src.as_ref().unwrap()).deserialize_map(ConfVisitor(file)) { Ok(mut conf) => { - extend_vec_if_indicator_present(&mut conf.conf.doc_valid_idents, DEFAULT_DOC_VALID_IDENTS); extend_vec_if_indicator_present(&mut conf.conf.disallowed_names, DEFAULT_DISALLOWED_NAMES); extend_vec_if_indicator_present(&mut conf.conf.allowed_prefixes, DEFAULT_ALLOWED_PREFIXES); extend_vec_if_indicator_present( @@ -713,6 +715,11 @@ fn deserialize(file: &SourceFile) -> TryConf { .allowed_idents_below_min_chars .extend(DEFAULT_ALLOWED_IDENTS_BELOW_MIN_CHARS.iter().map(ToString::to_string)); } + if conf.conf.doc_valid_idents.contains("..") { + conf.conf + .doc_valid_idents + .extend(DEFAULT_DOC_VALID_IDENTS.iter().map(ToString::to_string)); + } conf }, diff --git a/src/tools/clippy/clippy_config/src/types.rs b/src/tools/clippy/clippy_config/src/types.rs index 435aa9244c522..d47e34bb5bce5 100644 --- a/src/tools/clippy/clippy_config/src/types.rs +++ b/src/tools/clippy/clippy_config/src/types.rs @@ -2,13 +2,13 @@ use serde::de::{self, Deserializer, Visitor}; use serde::{ser, Deserialize, Serialize}; use std::fmt; -#[derive(Clone, Debug, Deserialize)] +#[derive(Debug, Deserialize)] pub struct Rename { pub path: String, pub rename: String, } -#[derive(Clone, Debug, Deserialize)] +#[derive(Debug, Deserialize)] #[serde(untagged)] pub enum DisallowedPath { Simple(String), @@ -22,12 +22,10 @@ impl DisallowedPath { path } - pub fn reason(&self) -> Option { - match self { - Self::WithReason { - reason: Some(reason), .. - } => Some(format!("{reason} (from clippy.toml)")), - _ => None, + pub fn reason(&self) -> Option<&str> { + match &self { + Self::WithReason { reason, .. } => reason.as_deref(), + Self::Simple(_) => None, } } } diff --git a/src/tools/clippy/clippy_dev/src/new_lint.rs b/src/tools/clippy/clippy_dev/src/new_lint.rs index d762e30ef02e1..de91233d196c8 100644 --- a/src/tools/clippy/clippy_dev/src/new_lint.rs +++ b/src/tools/clippy/clippy_dev/src/new_lint.rs @@ -140,7 +140,7 @@ fn add_lint(lint: &LintData<'_>, enable_msrv: bool) -> io::Result<()> { let new_lint = if enable_msrv { format!( - "store.register_{lint_pass}_pass(move |{ctor_arg}| Box::new({module_name}::{camel_name}::new(msrv())));\n ", + "store.register_{lint_pass}_pass(move |{ctor_arg}| Box::new({module_name}::{camel_name}::new(conf)));\n ", lint_pass = lint.pass, ctor_arg = if lint.pass == "late" { "_" } else { "" }, module_name = lint.name, @@ -274,6 +274,7 @@ fn get_lint_file_contents(lint: &LintData<'_>, enable_msrv: bool) -> String { formatdoc!( r#" use clippy_config::msrvs::{{self, Msrv}}; + use clippy_config::Conf; {pass_import} use rustc_lint::{{{context_import}, {pass_type}, LintContext}}; use rustc_session::impl_lint_pass; @@ -301,9 +302,8 @@ fn get_lint_file_contents(lint: &LintData<'_>, enable_msrv: bool) -> String { }} impl {name_camel} {{ - #[must_use] - pub fn new(msrv: Msrv) -> Self {{ - Self {{ msrv }} + pub fn new(conf: &'static Conf) -> Self {{ + Self {{ msrv: conf.msrv.clone() }} }} }} diff --git a/src/tools/clippy/clippy_lints/Cargo.toml b/src/tools/clippy/clippy_lints/Cargo.toml index 5708ffba08fd5..eb04c006f89fd 100644 --- a/src/tools/clippy/clippy_lints/Cargo.toml +++ b/src/tools/clippy/clippy_lints/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clippy_lints" -version = "0.1.81" +version = "0.1.82" description = "A bunch of helpful lints to avoid common pitfalls in Rust" repository = "https://github.com/rust-lang/rust-clippy" readme = "README.md" diff --git a/src/tools/clippy/clippy_lints/src/absolute_paths.rs b/src/tools/clippy/clippy_lints/src/absolute_paths.rs index 461117cf965dc..c0a9d888e0b0b 100644 --- a/src/tools/clippy/clippy_lints/src/absolute_paths.rs +++ b/src/tools/clippy/clippy_lints/src/absolute_paths.rs @@ -1,3 +1,4 @@ +use clippy_config::Conf; use clippy_utils::diagnostics::span_lint; use clippy_utils::source::snippet_opt; use rustc_data_structures::fx::FxHashSet; @@ -47,7 +48,16 @@ impl_lint_pass!(AbsolutePaths => [ABSOLUTE_PATHS]); pub struct AbsolutePaths { pub absolute_paths_max_segments: u64, - pub absolute_paths_allowed_crates: FxHashSet, + pub absolute_paths_allowed_crates: &'static FxHashSet, +} + +impl AbsolutePaths { + pub fn new(conf: &'static Conf) -> Self { + Self { + absolute_paths_max_segments: conf.absolute_paths_max_segments, + absolute_paths_allowed_crates: &conf.absolute_paths_allowed_crates, + } + } } impl LateLintPass<'_> for AbsolutePaths { diff --git a/src/tools/clippy/clippy_lints/src/almost_complete_range.rs b/src/tools/clippy/clippy_lints/src/almost_complete_range.rs index 96e9c949b7500..451bae959874f 100644 --- a/src/tools/clippy/clippy_lints/src/almost_complete_range.rs +++ b/src/tools/clippy/clippy_lints/src/almost_complete_range.rs @@ -1,4 +1,5 @@ use clippy_config::msrvs::{self, Msrv}; +use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::{trim_span, walk_span_to_context}; use rustc_ast::ast::{Expr, ExprKind, LitKind, Pat, PatKind, RangeEnd, RangeLimits}; @@ -34,8 +35,10 @@ pub struct AlmostCompleteRange { msrv: Msrv, } impl AlmostCompleteRange { - pub fn new(msrv: Msrv) -> Self { - Self { msrv } + pub fn new(conf: &'static Conf) -> Self { + Self { + msrv: conf.msrv.clone(), + } } } impl EarlyLintPass for AlmostCompleteRange { diff --git a/src/tools/clippy/clippy_lints/src/approx_const.rs b/src/tools/clippy/clippy_lints/src/approx_const.rs index ec28fd4611184..e6d52bcef717c 100644 --- a/src/tools/clippy/clippy_lints/src/approx_const.rs +++ b/src/tools/clippy/clippy_lints/src/approx_const.rs @@ -1,4 +1,5 @@ use clippy_config::msrvs::{self, Msrv}; +use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_help; use rustc_ast::ast::{FloatTy, LitFloatType, LitKind}; use rustc_hir::{Expr, ExprKind}; @@ -67,9 +68,10 @@ pub struct ApproxConstant { } impl ApproxConstant { - #[must_use] - pub fn new(msrv: Msrv) -> Self { - Self { msrv } + pub fn new(conf: &'static Conf) -> Self { + Self { + msrv: conf.msrv.clone(), + } } fn check_lit(&self, cx: &LateContext<'_>, lit: &LitKind, e: &Expr<'_>) { diff --git a/src/tools/clippy/clippy_lints/src/arc_with_non_send_sync.rs b/src/tools/clippy/clippy_lints/src/arc_with_non_send_sync.rs index d57ab539fff42..4eafa330fafab 100644 --- a/src/tools/clippy/clippy_lints/src/arc_with_non_send_sync.rs +++ b/src/tools/clippy/clippy_lints/src/arc_with_non_send_sync.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::is_from_proc_macro; use clippy_utils::ty::{implements_trait, is_type_diagnostic_item}; -use clippy_utils::{is_from_proc_macro, last_path_segment}; -use rustc_hir::{Expr, ExprKind}; +use rustc_hir::{Expr, ExprKind, QPath}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_middle::ty::print::with_forced_trimmed_paths; @@ -42,12 +42,11 @@ declare_lint_pass!(ArcWithNonSendSync => [ARC_WITH_NON_SEND_SYNC]); impl<'tcx> LateLintPass<'tcx> for ArcWithNonSendSync { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { - if !expr.span.from_expansion() - && let ty = cx.typeck_results().expr_ty(expr) - && is_type_diagnostic_item(cx, ty, sym::Arc) - && let ExprKind::Call(func, [arg]) = expr.kind - && let ExprKind::Path(func_path) = func.kind - && last_path_segment(&func_path).ident.name == sym::new + if let ExprKind::Call(func, [arg]) = expr.kind + && let ExprKind::Path(QPath::TypeRelative(func_ty, func_name)) = func.kind + && func_name.ident.name == sym::new + && !expr.span.from_expansion() + && is_type_diagnostic_item(cx, cx.typeck_results().node_type(func_ty.hir_id), sym::Arc) && let arg_ty = cx.typeck_results().expr_ty(arg) // make sure that the type is not and does not contain any type parameters && arg_ty.walk().all(|arg| { diff --git a/src/tools/clippy/clippy_lints/src/assigning_clones.rs b/src/tools/clippy/clippy_lints/src/assigning_clones.rs index 0de0031ed24ff..03f777600f084 100644 --- a/src/tools/clippy/clippy_lints/src/assigning_clones.rs +++ b/src/tools/clippy/clippy_lints/src/assigning_clones.rs @@ -1,4 +1,5 @@ use clippy_config::msrvs::{self, Msrv}; +use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::mir::{enclosing_mir, PossibleBorrowerMap}; use clippy_utils::sugg::Sugg; @@ -57,9 +58,10 @@ pub struct AssigningClones { } impl AssigningClones { - #[must_use] - pub fn new(msrv: Msrv) -> Self { - Self { msrv } + pub fn new(conf: &'static Conf) -> Self { + Self { + msrv: conf.msrv.clone(), + } } } diff --git a/src/tools/clippy/clippy_lints/src/attrs/mod.rs b/src/tools/clippy/clippy_lints/src/attrs/mod.rs index 8ec60314cc9a0..8f430ae601a85 100644 --- a/src/tools/clippy/clippy_lints/src/attrs/mod.rs +++ b/src/tools/clippy/clippy_lints/src/attrs/mod.rs @@ -16,6 +16,7 @@ mod useless_attribute; mod utils; use clippy_config::msrvs::{self, Msrv}; +use clippy_config::Conf; use rustc_ast::{Attribute, MetaItemKind, NestedMetaItem}; use rustc_hir::{ImplItem, Item, ItemKind, TraitItem}; use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass}; @@ -499,7 +500,6 @@ declare_clippy_lint! { "duplicated attribute" } -#[derive(Clone)] pub struct Attributes { msrv: Msrv, } @@ -517,9 +517,10 @@ impl_lint_pass!(Attributes => [ ]); impl Attributes { - #[must_use] - pub fn new(msrv: Msrv) -> Self { - Self { msrv } + pub fn new(conf: &'static Conf) -> Self { + Self { + msrv: conf.msrv.clone(), + } } } @@ -589,7 +590,15 @@ impl<'tcx> LateLintPass<'tcx> for Attributes { } pub struct EarlyAttributes { - pub msrv: Msrv, + msrv: Msrv, +} + +impl EarlyAttributes { + pub fn new(conf: &'static Conf) -> Self { + Self { + msrv: conf.msrv.clone(), + } + } } impl_lint_pass!(EarlyAttributes => [ diff --git a/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs b/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs index d4a1e2780d083..d5f017b26509b 100644 --- a/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs +++ b/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs @@ -1,11 +1,11 @@ -use clippy_config::types::DisallowedPath; +use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::{match_def_path, paths}; -use rustc_data_structures::fx::FxHashMap; +use clippy_utils::{create_disallowed_map, match_def_path, paths}; use rustc_hir as hir; -use rustc_hir::def_id::DefId; +use rustc_hir::def_id::{DefId, DefIdMap}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::mir::CoroutineLayout; +use rustc_middle::ty::TyCtxt; use rustc_session::impl_lint_pass; use rustc_span::{sym, Span}; @@ -172,31 +172,19 @@ declare_clippy_lint! { impl_lint_pass!(AwaitHolding => [AWAIT_HOLDING_LOCK, AWAIT_HOLDING_REFCELL_REF, AWAIT_HOLDING_INVALID_TYPE]); -#[derive(Debug)] pub struct AwaitHolding { - conf_invalid_types: Vec, - def_ids: FxHashMap, + def_ids: DefIdMap<(&'static str, Option<&'static str>)>, } impl AwaitHolding { - pub(crate) fn new(conf_invalid_types: Vec) -> Self { + pub(crate) fn new(tcx: TyCtxt<'_>, conf: &'static Conf) -> Self { Self { - conf_invalid_types, - def_ids: FxHashMap::default(), + def_ids: create_disallowed_map(tcx, &conf.await_holding_invalid_types), } } } impl<'tcx> LateLintPass<'tcx> for AwaitHolding { - fn check_crate(&mut self, cx: &LateContext<'tcx>) { - for conf in &self.conf_invalid_types { - let segs: Vec<_> = conf.path().split("::").collect(); - for id in clippy_utils::def_path_def_ids(cx, &segs) { - self.def_ids.insert(id, conf.clone()); - } - } - } - fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) { if let hir::ExprKind::Closure(hir::Closure { kind: hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, _)), @@ -258,25 +246,22 @@ impl AwaitHolding { ); }, ); - } else if let Some(disallowed) = self.def_ids.get(&adt.did()) { - emit_invalid_type(cx, ty_cause.source_info.span, disallowed); + } else if let Some(&(path, reason)) = self.def_ids.get(&adt.did()) { + emit_invalid_type(cx, ty_cause.source_info.span, path, reason); } } } } } -fn emit_invalid_type(cx: &LateContext<'_>, span: Span, disallowed: &DisallowedPath) { +fn emit_invalid_type(cx: &LateContext<'_>, span: Span, path: &'static str, reason: Option<&'static str>) { span_lint_and_then( cx, AWAIT_HOLDING_INVALID_TYPE, span, - format!( - "`{}` may not be held across an await point per `clippy.toml`", - disallowed.path() - ), + format!("holding a disallowed type across an await point `{path}`"), |diag| { - if let Some(reason) = disallowed.reason() { + if let Some(reason) = reason { diag.note(reason); } }, diff --git a/src/tools/clippy/clippy_lints/src/borrow_deref_ref.rs b/src/tools/clippy/clippy_lints/src/borrow_deref_ref.rs index 0ca4a0e067d36..bd123a725a736 100644 --- a/src/tools/clippy/clippy_lints/src/borrow_deref_ref.rs +++ b/src/tools/clippy/clippy_lints/src/borrow_deref_ref.rs @@ -49,35 +49,31 @@ declare_lint_pass!(BorrowDerefRef => [BORROW_DEREF_REF]); impl<'tcx> LateLintPass<'tcx> for BorrowDerefRef { fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &rustc_hir::Expr<'tcx>) { - if !e.span.from_expansion() - && let ExprKind::AddrOf(_, Mutability::Not, addrof_target) = e.kind - && !addrof_target.span.from_expansion() + if let ExprKind::AddrOf(_, Mutability::Not, addrof_target) = e.kind && let ExprKind::Unary(UnOp::Deref, deref_target) = addrof_target.kind - && !deref_target.span.from_expansion() && !matches!(deref_target.kind, ExprKind::Unary(UnOp::Deref, ..)) + && !e.span.from_expansion() + && !deref_target.span.from_expansion() + && !addrof_target.span.from_expansion() && let ref_ty = cx.typeck_results().expr_ty(deref_target) && let ty::Ref(_, inner_ty, Mutability::Not) = ref_ty.kind() - { - if let Some(parent_expr) = get_parent_expr(cx, e) { - if matches!(parent_expr.kind, ExprKind::Unary(UnOp::Deref, ..)) - && !is_lint_allowed(cx, DEREF_ADDROF, parent_expr.hir_id) - { - return; + && get_parent_expr(cx, e).map_or(true, |parent| { + match parent.kind { + // `*&*foo` should lint `deref_addrof` instead. + ExprKind::Unary(UnOp::Deref, _) => is_lint_allowed(cx, DEREF_ADDROF, parent.hir_id), + // `&*foo` creates a distinct temporary from `foo` + ExprKind::AddrOf(_, Mutability::Mut, _) => !matches!( + deref_target.kind, + ExprKind::Path(..) + | ExprKind::Field(..) + | ExprKind::Index(..) + | ExprKind::Unary(UnOp::Deref, ..) + ), + _ => true, } - - // modification to `&mut &*x` is different from `&mut x` - if matches!( - deref_target.kind, - ExprKind::Path(..) | ExprKind::Field(..) | ExprKind::Index(..) | ExprKind::Unary(UnOp::Deref, ..) - ) && matches!(parent_expr.kind, ExprKind::AddrOf(_, Mutability::Mut, _)) - { - return; - } - } - if is_from_proc_macro(cx, e) { - return; - } - + }) + && !is_from_proc_macro(cx, e) + { span_lint_and_then( cx, BORROW_DEREF_REF, diff --git a/src/tools/clippy/clippy_lints/src/cargo/mod.rs b/src/tools/clippy/clippy_lints/src/cargo/mod.rs index 593bc6c81ee8e..312ad4c299007 100644 --- a/src/tools/clippy/clippy_lints/src/cargo/mod.rs +++ b/src/tools/clippy/clippy_lints/src/cargo/mod.rs @@ -5,6 +5,7 @@ mod multiple_crate_versions; mod wildcard_dependencies; use cargo_metadata::MetadataCommand; +use clippy_config::Conf; use clippy_utils::diagnostics::span_lint; use clippy_utils::is_lint_allowed; use rustc_data_structures::fx::FxHashSet; @@ -204,8 +205,8 @@ declare_clippy_lint! { } pub struct Cargo { - pub allowed_duplicate_crates: FxHashSet, - pub ignore_publish: bool, + allowed_duplicate_crates: &'static FxHashSet, + ignore_publish: bool, } impl_lint_pass!(Cargo => [ @@ -217,6 +218,15 @@ impl_lint_pass!(Cargo => [ LINT_GROUPS_PRIORITY, ]); +impl Cargo { + pub fn new(conf: &'static Conf) -> Self { + Self { + allowed_duplicate_crates: &conf.allowed_duplicate_crates, + ignore_publish: conf.cargo_ignore_publish, + } + } +} + impl LateLintPass<'_> for Cargo { fn check_crate(&mut self, cx: &LateContext<'_>) { static NO_DEPS_LINTS: &[&Lint] = &[ @@ -253,7 +263,7 @@ impl LateLintPass<'_> for Cargo { { match MetadataCommand::new().exec() { Ok(metadata) => { - multiple_crate_versions::check(cx, &metadata, &self.allowed_duplicate_crates); + multiple_crate_versions::check(cx, &metadata, self.allowed_duplicate_crates); }, Err(e) => { for lint in WITH_DEPS_LINTS { diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_lossless.rs b/src/tools/clippy/clippy_lints/src/casts/cast_lossless.rs index d52ad1c6f23f5..ff460a3fd8e39 100644 --- a/src/tools/clippy/clippy_lints/src/casts/cast_lossless.rs +++ b/src/tools/clippy/clippy_lints/src/casts/cast_lossless.rs @@ -1,19 +1,21 @@ use clippy_config::msrvs::{self, Msrv}; -use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::in_constant; -use clippy_utils::source::{snippet_opt, snippet_with_applicability}; +use clippy_utils::source::snippet_opt; +use clippy_utils::sugg::Sugg; use clippy_utils::ty::is_isize_or_usize; use rustc_errors::Applicability; -use rustc_hir::{Expr, ExprKind, QPath, TyKind}; +use rustc_hir::{Expr, QPath, TyKind}; use rustc_lint::LateContext; -use rustc_middle::ty::{self, FloatTy, Ty, UintTy}; +use rustc_middle::ty::{self, FloatTy, Ty}; +use rustc_span::hygiene; use super::{utils, CAST_LOSSLESS}; pub(super) fn check( cx: &LateContext<'_>, expr: &Expr<'_>, - cast_op: &Expr<'_>, + cast_from_expr: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>, cast_to_hir: &rustc_hir::Ty<'_>, @@ -23,64 +25,54 @@ pub(super) fn check( return; } - // The suggestion is to use a function call, so if the original expression - // has parens on the outside, they are no longer needed. - let mut app = Applicability::MachineApplicable; - let opt = snippet_opt(cx, cast_op.span.source_callsite()); - let sugg = opt.as_ref().map_or_else( - || { - app = Applicability::HasPlaceholders; - ".." - }, - |snip| { - if should_strip_parens(cast_op, snip) { - &snip[1..snip.len() - 1] - } else { - snip.as_str() - } - }, - ); - - // Display the type alias instead of the aliased type. Fixes #11285 - // - // FIXME: Once `lazy_type_alias` is stabilized(?) we should use `rustc_middle` types instead, - // this will allow us to display the right type with `cast_from` as well. - let cast_to_fmt = if let TyKind::Path(QPath::Resolved(None, path)) = cast_to_hir.kind - // It's a bit annoying but the turbofish is optional for types. A type in an `as` cast - // shouldn't have these if they're primitives, which are the only things we deal with. - // - // This could be removed for performance if this check is determined to have a pretty major - // effect. - && path.segments.iter().all(|segment| segment.args.is_none()) - { - snippet_with_applicability(cx, cast_to_hir.span, "..", &mut app) - } else { - cast_to.to_string().into() - }; - - let message = if cast_from.is_bool() { - format!("casting `{cast_from}` to `{cast_to_fmt}` is more cleanly stated with `{cast_to_fmt}::from(_)`") - } else { - format!("casting `{cast_from}` to `{cast_to_fmt}` may become silently lossy if you later change the type") - }; - - span_lint_and_sugg( + span_lint_and_then( cx, CAST_LOSSLESS, expr.span, - message, - "try", - format!("{cast_to_fmt}::from({sugg})"), - app, + format!("casts from `{cast_from}` to `{cast_to}` can be expressed infallibly using `From`"), + |diag| { + diag.help("an `as` cast can become silently lossy if the types change in the future"); + let mut applicability = Applicability::MachineApplicable; + let from_sugg = Sugg::hir_with_context(cx, cast_from_expr, expr.span.ctxt(), "", &mut applicability); + let Some(ty) = snippet_opt(cx, hygiene::walk_chain(cast_to_hir.span, expr.span.ctxt())) else { + return; + }; + match cast_to_hir.kind { + TyKind::Infer => { + diag.span_suggestion_verbose( + expr.span, + "use `Into::into` instead", + format!("{}.into()", from_sugg.maybe_par()), + applicability, + ); + }, + // Don't suggest `A<_>::B::From(x)` or `macro!()::from(x)` + kind if matches!(kind, TyKind::Path(QPath::Resolved(_, path)) if path.segments.iter().any(|s| s.args.is_some())) + || !cast_to_hir.span.eq_ctxt(expr.span) => + { + diag.span_suggestion_verbose( + expr.span, + format!("use `<{ty}>::from` instead"), + format!("<{ty}>::from({from_sugg})"), + applicability, + ); + }, + _ => { + diag.span_suggestion_verbose( + expr.span, + format!("use `{ty}::from` instead"), + format!("{ty}::from({from_sugg})"), + applicability, + ); + }, + } + }, ); } fn should_lint(cx: &LateContext<'_>, expr: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>, msrv: &Msrv) -> bool { // Do not suggest using From in consts/statics until it is valid to do so (see #2267). - // - // If destination is u128, do not lint because source type cannot be larger - // If source is bool, still lint due to the lint message differing (refers to style) - if in_constant(cx, expr.hir_id) || (!cast_from.is_bool() && matches!(cast_to.kind(), ty::Uint(UintTy::U128))) { + if in_constant(cx, expr.hir_id) { return false; } @@ -110,12 +102,3 @@ fn should_lint(cx: &LateContext<'_>, expr: &Expr<'_>, cast_from: Ty<'_>, cast_to }, } } - -fn should_strip_parens(cast_expr: &Expr<'_>, snip: &str) -> bool { - if let ExprKind::Binary(_, _, _) = cast_expr.kind { - if snip.starts_with('(') && snip.ends_with(')') { - return true; - } - } - false -} diff --git a/src/tools/clippy/clippy_lints/src/casts/mod.rs b/src/tools/clippy/clippy_lints/src/casts/mod.rs index 54f0c7c468719..c31716fbcee1d 100644 --- a/src/tools/clippy/clippy_lints/src/casts/mod.rs +++ b/src/tools/clippy/clippy_lints/src/casts/mod.rs @@ -24,6 +24,7 @@ mod utils; mod zero_ptr; use clippy_config::msrvs::{self, Msrv}; +use clippy_config::Conf; use clippy_utils::is_hir_ty_cfg_dependant; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; @@ -658,11 +659,11 @@ declare_clippy_lint! { /// /// ### Example /// ```rust,ignore - /// let _: (0.0_f32 / 0.0) as u64; + /// let _ = (0.0_f32 / 0.0) as u64; /// ``` /// Use instead: /// ```rust,ignore - /// let _: = 0_u64; + /// let _ = 0_u64; /// ``` #[clippy::version = "1.66.0"] pub CAST_NAN_TO_INT, @@ -722,9 +723,10 @@ pub struct Casts { } impl Casts { - #[must_use] - pub fn new(msrv: Msrv) -> Self { - Self { msrv } + pub fn new(conf: &'static Conf) -> Self { + Self { + msrv: conf.msrv.clone(), + } } } @@ -761,45 +763,45 @@ impl<'tcx> LateLintPass<'tcx> for Casts { return; } - if let ExprKind::Cast(cast_expr, cast_to_hir) = expr.kind { + if let ExprKind::Cast(cast_from_expr, cast_to_hir) = expr.kind { if is_hir_ty_cfg_dependant(cx, cast_to_hir) { return; } let (cast_from, cast_to) = ( - cx.typeck_results().expr_ty(cast_expr), + cx.typeck_results().expr_ty(cast_from_expr), cx.typeck_results().expr_ty(expr), ); - if !expr.span.from_expansion() && unnecessary_cast::check(cx, expr, cast_expr, cast_from, cast_to) { + if !expr.span.from_expansion() && unnecessary_cast::check(cx, expr, cast_from_expr, cast_from, cast_to) { return; } - cast_slice_from_raw_parts::check(cx, expr, cast_expr, cast_to, &self.msrv); - ptr_cast_constness::check(cx, expr, cast_expr, cast_from, cast_to, &self.msrv); - as_ptr_cast_mut::check(cx, expr, cast_expr, cast_to); - fn_to_numeric_cast_any::check(cx, expr, cast_expr, cast_from, cast_to); - fn_to_numeric_cast::check(cx, expr, cast_expr, cast_from, cast_to); - fn_to_numeric_cast_with_truncation::check(cx, expr, cast_expr, cast_from, cast_to); - zero_ptr::check(cx, expr, cast_expr, cast_to_hir); + cast_slice_from_raw_parts::check(cx, expr, cast_from_expr, cast_to, &self.msrv); + ptr_cast_constness::check(cx, expr, cast_from_expr, cast_from, cast_to, &self.msrv); + as_ptr_cast_mut::check(cx, expr, cast_from_expr, cast_to); + fn_to_numeric_cast_any::check(cx, expr, cast_from_expr, cast_from, cast_to); + fn_to_numeric_cast::check(cx, expr, cast_from_expr, cast_from, cast_to); + fn_to_numeric_cast_with_truncation::check(cx, expr, cast_from_expr, cast_from, cast_to); + zero_ptr::check(cx, expr, cast_from_expr, cast_to_hir); if cast_to.is_numeric() { - cast_possible_truncation::check(cx, expr, cast_expr, cast_from, cast_to, cast_to_hir.span); + cast_possible_truncation::check(cx, expr, cast_from_expr, cast_from, cast_to, cast_to_hir.span); if cast_from.is_numeric() { cast_possible_wrap::check(cx, expr, cast_from, cast_to); cast_precision_loss::check(cx, expr, cast_from, cast_to); - cast_sign_loss::check(cx, expr, cast_expr, cast_from, cast_to); - cast_abs_to_unsigned::check(cx, expr, cast_expr, cast_from, cast_to, &self.msrv); - cast_nan_to_int::check(cx, expr, cast_expr, cast_from, cast_to); + cast_sign_loss::check(cx, expr, cast_from_expr, cast_from, cast_to); + cast_abs_to_unsigned::check(cx, expr, cast_from_expr, cast_from, cast_to, &self.msrv); + cast_nan_to_int::check(cx, expr, cast_from_expr, cast_from, cast_to); } - cast_lossless::check(cx, expr, cast_expr, cast_from, cast_to, cast_to_hir, &self.msrv); - cast_enum_constructor::check(cx, expr, cast_expr, cast_from); + cast_lossless::check(cx, expr, cast_from_expr, cast_from, cast_to, cast_to_hir, &self.msrv); + cast_enum_constructor::check(cx, expr, cast_from_expr, cast_from); } as_underscore::check(cx, expr, cast_to_hir); if self.msrv.meets(msrvs::PTR_FROM_REF) { - ref_as_ptr::check(cx, expr, cast_expr, cast_to_hir); + ref_as_ptr::check(cx, expr, cast_from_expr, cast_to_hir); } else if self.msrv.meets(msrvs::BORROW_AS_PTR) { - borrow_as_ptr::check(cx, expr, cast_expr, cast_to_hir); + borrow_as_ptr::check(cx, expr, cast_from_expr, cast_to_hir); } } diff --git a/src/tools/clippy/clippy_lints/src/casts/ptr_cast_constness.rs b/src/tools/clippy/clippy_lints/src/casts/ptr_cast_constness.rs index 921693567fcd4..7513e18d408b1 100644 --- a/src/tools/clippy/clippy_lints/src/casts/ptr_cast_constness.rs +++ b/src/tools/clippy/clippy_lints/src/casts/ptr_cast_constness.rs @@ -4,7 +4,7 @@ use clippy_utils::sugg::Sugg; use rustc_errors::Applicability; use rustc_hir::{Expr, Mutability}; use rustc_lint::LateContext; -use rustc_middle::ty::{self, Ty}; +use rustc_middle::ty::{self, Ty, TypeVisitableExt}; use super::PTR_CAST_CONSTNESS; @@ -24,6 +24,7 @@ pub(super) fn check<'tcx>( (Mutability::Not, Mutability::Mut) | (Mutability::Mut, Mutability::Not) ) && from_ty == to_ty + && !from_ty.has_erased_regions() { let sugg = Sugg::hir(cx, cast_expr, "_"); let constness = match *to_mutbl { diff --git a/src/tools/clippy/clippy_lints/src/checked_conversions.rs b/src/tools/clippy/clippy_lints/src/checked_conversions.rs index 92810ea2aa0ff..0b1ab5411bf18 100644 --- a/src/tools/clippy/clippy_lints/src/checked_conversions.rs +++ b/src/tools/clippy/clippy_lints/src/checked_conversions.rs @@ -1,11 +1,12 @@ //! lint on manually implemented checked conversions that could be transformed into `try_from` use clippy_config::msrvs::{self, Msrv}; +use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; use clippy_utils::{in_constant, is_integer_literal, SpanlessEq}; use rustc_errors::Applicability; -use rustc_hir::{BinOp, BinOpKind, Expr, ExprKind, QPath, TyKind}; +use rustc_hir::{BinOpKind, Expr, ExprKind, QPath, TyKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_session::impl_lint_pass; @@ -40,9 +41,10 @@ pub struct CheckedConversions { } impl CheckedConversions { - #[must_use] - pub fn new(msrv: Msrv) -> Self { - Self { msrv } + pub fn new(conf: &'static Conf) -> Self { + Self { + msrv: conf.msrv.clone(), + } } } @@ -50,61 +52,54 @@ impl_lint_pass!(CheckedConversions => [CHECKED_CONVERSIONS]); impl<'tcx> LateLintPass<'tcx> for CheckedConversions { fn check_expr(&mut self, cx: &LateContext<'_>, item: &Expr<'_>) { - if !self.msrv.meets(msrvs::TRY_FROM) { - return; - } - - let result = if !in_constant(cx, item.hir_id) - && !in_external_macro(cx.sess(), item.span) - && let ExprKind::Binary(op, left, right) = &item.kind - { - match op.node { - BinOpKind::Ge | BinOpKind::Le => single_check(item), - BinOpKind::And => double_check(cx, left, right), - _ => None, + if let ExprKind::Binary(op, lhs, rhs) = item.kind + && let (lt1, gt1, op2) = match op.node { + BinOpKind::Le => (lhs, rhs, None), + BinOpKind::Ge => (rhs, lhs, None), + BinOpKind::And + if let ExprKind::Binary(op1, lhs1, rhs1) = lhs.kind + && let ExprKind::Binary(op2, lhs2, rhs2) = rhs.kind + && let Some((lt1, gt1)) = read_le_ge(op1.node, lhs1, rhs1) + && let Some((lt2, gt2)) = read_le_ge(op2.node, lhs2, rhs2) => + { + (lt1, gt1, Some((lt2, gt2))) + }, + _ => return, } - } else { - None - }; - - if let Some(cv) = result { - if let Some(to_type) = cv.to_type { - let mut applicability = Applicability::MachineApplicable; - let snippet = snippet_with_applicability(cx, cv.expr_to_cast.span, "_", &mut applicability); - span_lint_and_sugg( - cx, - CHECKED_CONVERSIONS, - item.span, - "checked cast can be simplified", - "try", - format!("{to_type}::try_from({snippet}).is_ok()"), - applicability, - ); + && !in_external_macro(cx.sess(), item.span) + && !in_constant(cx, item.hir_id) + && self.msrv.meets(msrvs::TRY_FROM) + && let Some(cv) = match op2 { + // todo: check for case signed -> larger unsigned == only x >= 0 + None => check_upper_bound(lt1, gt1).filter(|cv| cv.cvt == ConversionType::FromUnsigned), + Some((lt2, gt2)) => { + let upper_lower = |lt1, gt1, lt2, gt2| { + check_upper_bound(lt1, gt1) + .zip(check_lower_bound(lt2, gt2)) + .and_then(|(l, r)| l.combine(r, cx)) + }; + upper_lower(lt1, gt1, lt2, gt2).or_else(|| upper_lower(lt2, gt2, lt1, gt1)) + }, } + && let Some(to_type) = cv.to_type + { + let mut applicability = Applicability::MachineApplicable; + let snippet = snippet_with_applicability(cx, cv.expr_to_cast.span, "_", &mut applicability); + span_lint_and_sugg( + cx, + CHECKED_CONVERSIONS, + item.span, + "checked cast can be simplified", + "try", + format!("{to_type}::try_from({snippet}).is_ok()"), + applicability, + ); } } extract_msrv_attr!(LateContext); } -/// Searches for a single check from unsigned to _ is done -/// todo: check for case signed -> larger unsigned == only x >= 0 -fn single_check<'tcx>(expr: &'tcx Expr<'tcx>) -> Option> { - check_upper_bound(expr).filter(|cv| cv.cvt == ConversionType::FromUnsigned) -} - -/// Searches for a combination of upper & lower bound checks -fn double_check<'a>(cx: &LateContext<'_>, left: &'a Expr<'_>, right: &'a Expr<'_>) -> Option> { - let upper_lower = |l, r| { - let upper = check_upper_bound(l); - let lower = check_lower_bound(r); - - upper.zip(lower).and_then(|(l, r)| l.combine(r, cx)) - }; - - upper_lower(left, right).or_else(|| upper_lower(right, left)) -} - /// Contains the result of a tried conversion check #[derive(Clone, Debug)] struct Conversion<'a> { @@ -121,6 +116,19 @@ enum ConversionType { FromUnsigned, } +/// Attempts to read either `<=` or `>=` with a normalized operand order. +fn read_le_ge<'tcx>( + op: BinOpKind, + lhs: &'tcx Expr<'tcx>, + rhs: &'tcx Expr<'tcx>, +) -> Option<(&'tcx Expr<'tcx>, &'tcx Expr<'tcx>)> { + match op { + BinOpKind::Le => Some((lhs, rhs)), + BinOpKind::Ge => Some((rhs, lhs)), + _ => None, + } +} + impl<'a> Conversion<'a> { /// Combine multiple conversions if the are compatible pub fn combine(self, other: Self, cx: &LateContext<'_>) -> Option> { @@ -188,29 +196,17 @@ impl ConversionType { } /// Check for `expr <= (to_type::MAX as from_type)` -fn check_upper_bound<'tcx>(expr: &'tcx Expr<'tcx>) -> Option> { - if let ExprKind::Binary(ref op, left, right) = &expr.kind - && let Some((candidate, check)) = normalize_le_ge(op, left, right) - && let Some((from, to)) = get_types_from_cast(check, INTS, "max_value", "MAX") - { - Conversion::try_new(candidate, from, to) +fn check_upper_bound<'tcx>(lt: &'tcx Expr<'tcx>, gt: &'tcx Expr<'tcx>) -> Option> { + if let Some((from, to)) = get_types_from_cast(gt, INTS, "max_value", "MAX") { + Conversion::try_new(lt, from, to) } else { None } } /// Check for `expr >= 0|(to_type::MIN as from_type)` -fn check_lower_bound<'tcx>(expr: &'tcx Expr<'tcx>) -> Option> { - fn check_function<'a>(candidate: &'a Expr<'a>, check: &'a Expr<'a>) -> Option> { - (check_lower_bound_zero(candidate, check)).or_else(|| (check_lower_bound_min(candidate, check))) - } - - // First of we need a binary containing the expression & the cast - if let ExprKind::Binary(ref op, left, right) = &expr.kind { - normalize_le_ge(op, right, left).and_then(|(l, r)| check_function(l, r)) - } else { - None - } +fn check_lower_bound<'tcx>(lt: &'tcx Expr<'tcx>, gt: &'tcx Expr<'tcx>) -> Option> { + check_lower_bound_zero(gt, lt).or_else(|| check_lower_bound_min(gt, lt)) } /// Check for `expr >= 0` @@ -309,15 +305,6 @@ fn int_ty_to_sym<'tcx>(path: &QPath<'_>) -> Option<&'tcx str> { } } -/// Will return the expressions as if they were expr1 <= expr2 -fn normalize_le_ge<'a>(op: &BinOp, left: &'a Expr<'a>, right: &'a Expr<'a>) -> Option<(&'a Expr<'a>, &'a Expr<'a>)> { - match op.node { - BinOpKind::Le => Some((left, right)), - BinOpKind::Ge => Some((right, left)), - _ => None, - } -} - // Constants const UINTS: &[&str] = &["u8", "u16", "u32", "u64", "usize"]; const SINTS: &[&str] = &["i8", "i16", "i32", "i64", "isize"]; diff --git a/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs b/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs index 60815f4f2afbb..5fa0522e4e5f9 100644 --- a/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs +++ b/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs @@ -1,5 +1,6 @@ //! calculate cognitive complexity and warn about overly complex functions +use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::source::{IntoSpan, SpanRangeExt}; use clippy_utils::ty::is_type_diagnostic_item; @@ -39,10 +40,9 @@ pub struct CognitiveComplexity { } impl CognitiveComplexity { - #[must_use] - pub fn new(limit: u64) -> Self { + pub fn new(conf: &'static Conf) -> Self { Self { - limit: LimitStack::new(limit), + limit: LimitStack::new(conf.cognitive_complexity_threshold), } } } diff --git a/src/tools/clippy/clippy_lints/src/collapsible_if.rs b/src/tools/clippy/clippy_lints/src/collapsible_if.rs index 07b02c98df151..f311c052ad6ee 100644 --- a/src/tools/clippy/clippy_lints/src/collapsible_if.rs +++ b/src/tools/clippy/clippy_lints/src/collapsible_if.rs @@ -93,20 +93,14 @@ declare_lint_pass!(CollapsibleIf => [COLLAPSIBLE_IF, COLLAPSIBLE_ELSE_IF]); impl EarlyLintPass for CollapsibleIf { fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &ast::Expr) { - if !expr.span.from_expansion() { - check_if(cx, expr); - } - } -} - -fn check_if(cx: &EarlyContext<'_>, expr: &ast::Expr) { - if let ast::ExprKind::If(check, then, else_) = &expr.kind { - if let Some(else_) = else_ { - check_collapsible_maybe_if_let(cx, then.span, else_); - } else if let ast::ExprKind::Let(..) = check.kind { - // Prevent triggering on `if let a = b { if c { .. } }`. - } else { - check_collapsible_no_if_let(cx, expr, check, then); + if let ast::ExprKind::If(cond, then, else_) = &expr.kind + && !expr.span.from_expansion() + { + if let Some(else_) = else_ { + check_collapsible_maybe_if_let(cx, then.span, else_); + } else if !matches!(cond.kind, ast::ExprKind::Let(..)) { + check_collapsible_no_if_let(cx, expr, cond, then); + } } } } @@ -189,13 +183,10 @@ fn check_collapsible_no_if_let(cx: &EarlyContext<'_>, expr: &ast::Expr, check: & /// If the block contains only one expression, return it. fn expr_block(block: &ast::Block) -> Option<&ast::Expr> { - let mut it = block.stmts.iter(); - - if let (Some(stmt), None) = (it.next(), it.next()) { - match stmt.kind { - ast::StmtKind::Expr(ref expr) | ast::StmtKind::Semi(ref expr) => Some(expr), - _ => None, - } + if let [stmt] = &*block.stmts + && let ast::StmtKind::Expr(expr) | ast::StmtKind::Semi(expr) = &stmt.kind + { + Some(expr) } else { None } diff --git a/src/tools/clippy/clippy_lints/src/collection_is_never_read.rs b/src/tools/clippy/clippy_lints/src/collection_is_never_read.rs index 28d9f68d504cc..eebda3ff76fd9 100644 --- a/src/tools/clippy/clippy_lints/src/collection_is_never_read.rs +++ b/src/tools/clippy/clippy_lints/src/collection_is_never_read.rs @@ -59,9 +59,9 @@ static COLLECTIONS: [Symbol; 9] = [ impl<'tcx> LateLintPass<'tcx> for CollectionIsNeverRead { fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx LetStmt<'tcx>) { - // Look for local variables whose type is a container. Search surrounding bock for read access. - if match_acceptable_type(cx, local, &COLLECTIONS) - && let PatKind::Binding(_, local_id, _, _) = local.pat.kind + // Look for local variables whose type is a container. Search surrounding block for read access. + if let PatKind::Binding(_, local_id, _, _) = local.pat.kind + && match_acceptable_type(cx, local, &COLLECTIONS) && let Some(enclosing_block) = get_enclosing_block(cx, local.hir_id) && has_no_read_access(cx, local_id, enclosing_block) { diff --git a/src/tools/clippy/clippy_lints/src/copies.rs b/src/tools/clippy/clippy_lints/src/copies.rs index d896452be9209..86e0368c4e423 100644 --- a/src/tools/clippy/clippy_lints/src/copies.rs +++ b/src/tools/clippy/clippy_lints/src/copies.rs @@ -1,3 +1,4 @@ +use clippy_config::Conf; use clippy_utils::diagnostics::{span_lint_and_note, span_lint_and_then}; use clippy_utils::source::{first_line_of_span, indent_of, reindent_multiline, snippet, IntoSpan, SpanRangeExt}; use clippy_utils::ty::{needs_ordered_drop, InteriorMut}; @@ -11,6 +12,7 @@ use core::ops::ControlFlow; use rustc_errors::Applicability; use rustc_hir::{intravisit, BinOpKind, Block, Expr, ExprKind, HirId, HirIdSet, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty::TyCtxt; use rustc_session::impl_lint_pass; use rustc_span::hygiene::walk_chain; use rustc_span::source_map::SourceMap; @@ -159,15 +161,13 @@ declare_clippy_lint! { } pub struct CopyAndPaste<'tcx> { - ignore_interior_mutability: Vec, interior_mut: InteriorMut<'tcx>, } -impl CopyAndPaste<'_> { - pub fn new(ignore_interior_mutability: Vec) -> Self { +impl<'tcx> CopyAndPaste<'tcx> { + pub fn new(tcx: TyCtxt<'tcx>, conf: &'static Conf) -> Self { Self { - ignore_interior_mutability, - interior_mut: InteriorMut::default(), + interior_mut: InteriorMut::new(tcx, &conf.ignore_interior_mutability), } } } @@ -180,10 +180,6 @@ impl_lint_pass!(CopyAndPaste<'_> => [ ]); impl<'tcx> LateLintPass<'tcx> for CopyAndPaste<'tcx> { - fn check_crate(&mut self, cx: &LateContext<'tcx>) { - self.interior_mut = InteriorMut::new(cx, &self.ignore_interior_mutability); - } - fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { if !expr.span.from_expansion() && matches!(expr.kind, ExprKind::If(..)) && !is_else_clause(cx.tcx, expr) { let (conds, blocks) = if_sequence(expr); diff --git a/src/tools/clippy/clippy_lints/src/crate_in_macro_def.rs b/src/tools/clippy/clippy_lints/src/crate_in_macro_def.rs index adf6f7c473757..678bdbc0ffb8a 100644 --- a/src/tools/clippy/clippy_lints/src/crate_in_macro_def.rs +++ b/src/tools/clippy/clippy_lints/src/crate_in_macro_def.rs @@ -53,10 +53,9 @@ declare_lint_pass!(CrateInMacroDef => [CRATE_IN_MACRO_DEF]); impl EarlyLintPass for CrateInMacroDef { fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) { - if item.attrs.iter().any(is_macro_export) - && let ItemKind::MacroDef(macro_def) = &item.kind - && let tts = macro_def.body.tokens.clone() - && let Some(span) = contains_unhygienic_crate_reference(&tts) + if let ItemKind::MacroDef(macro_def) = &item.kind + && item.attrs.iter().any(is_macro_export) + && let Some(span) = contains_unhygienic_crate_reference(¯o_def.body.tokens) { span_lint_and_sugg( cx, diff --git a/src/tools/clippy/clippy_lints/src/dbg_macro.rs b/src/tools/clippy/clippy_lints/src/dbg_macro.rs index b0590b0a71cb2..788c6f3ada297 100644 --- a/src/tools/clippy/clippy_lints/src/dbg_macro.rs +++ b/src/tools/clippy/clippy_lints/src/dbg_macro.rs @@ -1,3 +1,4 @@ +use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::is_in_test; use clippy_utils::macros::{macro_backtrace, MacroCall}; @@ -33,7 +34,6 @@ declare_clippy_lint! { "`dbg!` macro is intended as a debugging tool" } -#[derive(Clone)] pub struct DbgMacro { allow_dbg_in_tests: bool, /// Tracks the `dbg!` macro callsites that are already checked. @@ -45,9 +45,9 @@ pub struct DbgMacro { impl_lint_pass!(DbgMacro => [DBG_MACRO]); impl DbgMacro { - pub fn new(allow_dbg_in_tests: bool) -> Self { + pub fn new(conf: &'static Conf) -> Self { DbgMacro { - allow_dbg_in_tests, + allow_dbg_in_tests: conf.allow_dbg_in_tests, checked_dbg_call_site: FxHashSet::default(), prev_ctxt: SyntaxContext::root(), } diff --git a/src/tools/clippy/clippy_lints/src/declared_lints.rs b/src/tools/clippy/clippy_lints/src/declared_lints.rs index eabc67601a2f1..69f9eb6842bcd 100644 --- a/src/tools/clippy/clippy_lints/src/declared_lints.rs +++ b/src/tools/clippy/clippy_lints/src/declared_lints.rs @@ -598,6 +598,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::partialeq_to_none::PARTIALEQ_TO_NONE_INFO, crate::pass_by_ref_or_value::LARGE_TYPES_PASSED_BY_VALUE_INFO, crate::pass_by_ref_or_value::TRIVIALLY_COPY_PASS_BY_REF_INFO, + crate::pathbuf_init_then_push::PATHBUF_INIT_THEN_PUSH_INFO, crate::pattern_type_mismatch::PATTERN_TYPE_MISMATCH_INFO, crate::permissions_set_readonly_false::PERMISSIONS_SET_READONLY_FALSE_INFO, crate::precedence::PRECEDENCE_INFO, diff --git a/src/tools/clippy/clippy_lints/src/derivable_impls.rs b/src/tools/clippy/clippy_lints/src/derivable_impls.rs index 0c9ad5e8d0015..f27f68e2cbc5f 100644 --- a/src/tools/clippy/clippy_lints/src/derivable_impls.rs +++ b/src/tools/clippy/clippy_lints/src/derivable_impls.rs @@ -1,4 +1,5 @@ use clippy_config::msrvs::{self, Msrv}; +use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::indent_of; use clippy_utils::{is_default_equivalent, peel_blocks}; @@ -60,9 +61,10 @@ pub struct DerivableImpls { } impl DerivableImpls { - #[must_use] - pub fn new(msrv: Msrv) -> Self { - DerivableImpls { msrv } + pub fn new(conf: &'static Conf) -> Self { + DerivableImpls { + msrv: conf.msrv.clone(), + } } } diff --git a/src/tools/clippy/clippy_lints/src/disallowed_macros.rs b/src/tools/clippy/clippy_lints/src/disallowed_macros.rs index 871f529da6c40..b51d343132b26 100644 --- a/src/tools/clippy/clippy_lints/src/disallowed_macros.rs +++ b/src/tools/clippy/clippy_lints/src/disallowed_macros.rs @@ -1,4 +1,5 @@ -use clippy_config::types::DisallowedPath; +use clippy_config::Conf; +use clippy_utils::create_disallowed_map; use clippy_utils::diagnostics::{span_lint_and_then, span_lint_hir_and_then}; use clippy_utils::macros::macro_backtrace; use rustc_ast::Attribute; @@ -9,6 +10,7 @@ use rustc_hir::{ Expr, ExprKind, ForeignItem, HirId, ImplItem, Item, ItemKind, OwnerId, Pat, Path, Stmt, TraitItem, Ty, }; use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty::TyCtxt; use rustc_session::impl_lint_pass; use rustc_span::{ExpnId, MacroKind, Span}; @@ -57,27 +59,24 @@ declare_clippy_lint! { } pub struct DisallowedMacros { - conf_disallowed: Vec, - disallowed: DefIdMap, + disallowed: DefIdMap<(&'static str, Option<&'static str>)>, seen: FxHashSet, - // Track the most recently seen node that can have a `derive` attribute. // Needed to use the correct lint level. derive_src: Option, } impl DisallowedMacros { - pub fn new(conf_disallowed: Vec) -> Self { + pub fn new(tcx: TyCtxt<'_>, conf: &'static Conf) -> Self { Self { - conf_disallowed, - disallowed: DefIdMap::default(), + disallowed: create_disallowed_map(tcx, &conf.disallowed_macros), seen: FxHashSet::default(), derive_src: None, } } fn check(&mut self, cx: &LateContext<'_>, span: Span, derive_src: Option) { - if self.conf_disallowed.is_empty() { + if self.disallowed.is_empty() { return; } @@ -86,11 +85,10 @@ impl DisallowedMacros { return; } - if let Some(&index) = self.disallowed.get(&mac.def_id) { - let conf = &self.conf_disallowed[index]; - let msg = format!("use of a disallowed macro `{}`", conf.path()); + if let Some(&(path, reason)) = self.disallowed.get(&mac.def_id) { + let msg = format!("use of a disallowed macro `{path}`"); let add_note = |diag: &mut Diag<'_, _>| { - if let Some(reason) = conf.reason() { + if let Some(reason) = reason { diag.note(reason); } }; @@ -116,15 +114,6 @@ impl DisallowedMacros { impl_lint_pass!(DisallowedMacros => [DISALLOWED_MACROS]); impl LateLintPass<'_> for DisallowedMacros { - fn check_crate(&mut self, cx: &LateContext<'_>) { - for (index, conf) in self.conf_disallowed.iter().enumerate() { - let segs: Vec<_> = conf.path().split("::").collect(); - for id in clippy_utils::def_path_def_ids(cx, &segs) { - self.disallowed.insert(id, index); - } - } - } - fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { self.check(cx, expr.span, None); // `$t + $t` can have the context of $t, check also the span of the binary operator diff --git a/src/tools/clippy/clippy_lints/src/disallowed_methods.rs b/src/tools/clippy/clippy_lints/src/disallowed_methods.rs index 38fe687f7ccfe..5a01d76a2a621 100644 --- a/src/tools/clippy/clippy_lints/src/disallowed_methods.rs +++ b/src/tools/clippy/clippy_lints/src/disallowed_methods.rs @@ -1,9 +1,11 @@ -use clippy_config::types::DisallowedPath; +use clippy_config::Conf; +use clippy_utils::create_disallowed_map; use clippy_utils::diagnostics::span_lint_and_then; use rustc_hir::def::{CtorKind, DefKind, Res}; use rustc_hir::def_id::DefIdMap; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty::TyCtxt; use rustc_session::impl_lint_pass; declare_clippy_lint! { @@ -55,17 +57,14 @@ declare_clippy_lint! { "use of a disallowed method call" } -#[derive(Clone, Debug)] pub struct DisallowedMethods { - conf_disallowed: Vec, - disallowed: DefIdMap, + disallowed: DefIdMap<(&'static str, Option<&'static str>)>, } impl DisallowedMethods { - pub fn new(conf_disallowed: Vec) -> Self { + pub fn new(tcx: TyCtxt<'_>, conf: &'static Conf) -> Self { Self { - conf_disallowed, - disallowed: DefIdMap::default(), + disallowed: create_disallowed_map(tcx, &conf.disallowed_methods), } } } @@ -73,15 +72,6 @@ impl DisallowedMethods { impl_lint_pass!(DisallowedMethods => [DISALLOWED_METHODS]); impl<'tcx> LateLintPass<'tcx> for DisallowedMethods { - fn check_crate(&mut self, cx: &LateContext<'_>) { - for (index, conf) in self.conf_disallowed.iter().enumerate() { - let segs: Vec<_> = conf.path().split("::").collect(); - for id in clippy_utils::def_path_def_ids(cx, &segs) { - self.disallowed.insert(id, index); - } - } - } - fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { let (id, span) = match &expr.kind { ExprKind::Path(path) @@ -95,14 +85,18 @@ impl<'tcx> LateLintPass<'tcx> for DisallowedMethods { }, _ => return, }; - if let Some(&index) = self.disallowed.get(&id) { - let conf = &self.conf_disallowed[index]; - let msg = format!("use of a disallowed method `{}`", conf.path()); - span_lint_and_then(cx, DISALLOWED_METHODS, span, msg, |diag| { - if let Some(reason) = conf.reason() { - diag.note(reason); - } - }); + if let Some(&(path, reason)) = self.disallowed.get(&id) { + span_lint_and_then( + cx, + DISALLOWED_METHODS, + span, + format!("use of a disallowed method `{path}`"), + |diag| { + if let Some(reason) = reason { + diag.note(reason); + } + }, + ); } } } diff --git a/src/tools/clippy/clippy_lints/src/disallowed_names.rs b/src/tools/clippy/clippy_lints/src/disallowed_names.rs index 58809604c373e..f55b0cf1c5034 100644 --- a/src/tools/clippy/clippy_lints/src/disallowed_names.rs +++ b/src/tools/clippy/clippy_lints/src/disallowed_names.rs @@ -1,9 +1,11 @@ +use clippy_config::Conf; use clippy_utils::diagnostics::span_lint; use clippy_utils::is_in_test; use rustc_data_structures::fx::FxHashSet; use rustc_hir::{Pat, PatKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::impl_lint_pass; +use rustc_span::Symbol; declare_clippy_lint! { /// ### What it does @@ -24,15 +26,14 @@ declare_clippy_lint! { "usage of a disallowed/placeholder name" } -#[derive(Clone, Debug)] pub struct DisallowedNames { - disallow: FxHashSet, + disallow: FxHashSet, } impl DisallowedNames { - pub fn new(disallowed_names: &[String]) -> Self { + pub fn new(conf: &'static Conf) -> Self { Self { - disallow: disallowed_names.iter().cloned().collect(), + disallow: conf.disallowed_names.iter().map(|x| Symbol::intern(x)).collect(), } } } @@ -42,7 +43,7 @@ impl_lint_pass!(DisallowedNames => [DISALLOWED_NAMES]); impl<'tcx> LateLintPass<'tcx> for DisallowedNames { fn check_pat(&mut self, cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>) { if let PatKind::Binding(.., ident, _) = pat.kind - && self.disallow.contains(&ident.name.to_string()) + && self.disallow.contains(&ident.name) && !is_in_test(cx.tcx, pat.hir_id) { span_lint( diff --git a/src/tools/clippy/clippy_lints/src/disallowed_script_idents.rs b/src/tools/clippy/clippy_lints/src/disallowed_script_idents.rs index 5ce11900adf8f..f79264e6b04a1 100644 --- a/src/tools/clippy/clippy_lints/src/disallowed_script_idents.rs +++ b/src/tools/clippy/clippy_lints/src/disallowed_script_idents.rs @@ -1,3 +1,4 @@ +use clippy_config::Conf; use clippy_utils::diagnostics::span_lint; use rustc_ast::ast; use rustc_data_structures::fx::FxHashSet; @@ -44,19 +45,20 @@ declare_clippy_lint! { "usage of non-allowed Unicode scripts" } -#[derive(Clone, Debug)] pub struct DisallowedScriptIdents { whitelist: FxHashSet