From 662024478deb04a8c71d779b66b4bedb0bf91dbe Mon Sep 17 00:00:00 2001 From: woppopo Date: Sun, 12 Dec 2021 04:19:23 +0900 Subject: [PATCH 01/11] Make some `Clone` impls `const` --- library/core/src/clone.rs | 21 +++++++++++++++------ library/core/src/convert/mod.rs | 3 ++- library/core/src/lib.rs | 1 + library/core/src/option.rs | 6 +++++- library/core/src/ptr/non_null.rs | 3 ++- library/core/src/ptr/unique.rs | 3 ++- library/core/src/result.rs | 7 ++++++- 7 files changed, 33 insertions(+), 11 deletions(-) diff --git a/library/core/src/clone.rs b/library/core/src/clone.rs index 6f9579043c37d..1912694412b98 100644 --- a/library/core/src/clone.rs +++ b/library/core/src/clone.rs @@ -127,7 +127,11 @@ pub trait Clone: Sized { /// allocations. #[inline] #[stable(feature = "rust1", since = "1.0.0")] - fn clone_from(&mut self, source: &Self) { + #[default_method_body_is_const] + fn clone_from(&mut self, source: &Self) + where + Self: ~const Drop, + { *self = source.clone() } } @@ -178,7 +182,8 @@ mod impls { ($($t:ty)*) => { $( #[stable(feature = "rust1", since = "1.0.0")] - impl Clone for $t { + #[rustc_const_unstable(feature = "const_clone", issue = "91805")] + impl const Clone for $t { #[inline] fn clone(&self) -> Self { *self @@ -196,7 +201,8 @@ mod impls { } #[unstable(feature = "never_type", issue = "35121")] - impl Clone for ! { + #[rustc_const_unstable(feature = "const_clone", issue = "91805")] + impl const Clone for ! { #[inline] fn clone(&self) -> Self { *self @@ -204,7 +210,8 @@ mod impls { } #[stable(feature = "rust1", since = "1.0.0")] - impl Clone for *const T { + #[rustc_const_unstable(feature = "const_clone", issue = "91805")] + impl const Clone for *const T { #[inline] fn clone(&self) -> Self { *self @@ -212,7 +219,8 @@ mod impls { } #[stable(feature = "rust1", since = "1.0.0")] - impl Clone for *mut T { + #[rustc_const_unstable(feature = "const_clone", issue = "91805")] + impl const Clone for *mut T { #[inline] fn clone(&self) -> Self { *self @@ -221,7 +229,8 @@ mod impls { /// Shared references can be cloned, but mutable references *cannot*! #[stable(feature = "rust1", since = "1.0.0")] - impl Clone for &T { + #[rustc_const_unstable(feature = "const_clone", issue = "91805")] + impl const Clone for &T { #[inline] #[rustc_diagnostic_item = "noop_method_clone"] fn clone(&self) -> Self { diff --git a/library/core/src/convert/mod.rs b/library/core/src/convert/mod.rs index 5aa53deee343d..a50b8904b593e 100644 --- a/library/core/src/convert/mod.rs +++ b/library/core/src/convert/mod.rs @@ -683,7 +683,8 @@ impl AsMut for str { pub enum Infallible {} #[stable(feature = "convert_infallible", since = "1.34.0")] -impl Clone for Infallible { +#[rustc_const_unstable(feature = "const_clone", issue = "91805")] +impl const Clone for Infallible { fn clone(&self) -> Infallible { match *self {} } diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 78383b54c5d1e..4ef4740799a0b 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -106,6 +106,7 @@ #![feature(const_caller_location)] #![feature(const_cell_into_inner)] #![feature(const_char_convert)] +#![feature(const_clone)] #![feature(const_discriminant)] #![feature(const_eval_select)] #![feature(const_float_bits_conv)] diff --git a/library/core/src/option.rs b/library/core/src/option.rs index 7b9c6e43960f7..941d7e0792628 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -1668,7 +1668,11 @@ const fn expect_failed(msg: &str) -> ! { ///////////////////////////////////////////////////////////////////////////// #[stable(feature = "rust1", since = "1.0.0")] -impl Clone for Option { +#[rustc_const_unstable(feature = "const_clone", issue = "91805")] +impl const Clone for Option +where + T: ~const Clone + ~const Drop, +{ #[inline] fn clone(&self) -> Self { match self { diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs index 58110b0680943..cb268abc8eecd 100644 --- a/library/core/src/ptr/non_null.rs +++ b/library/core/src/ptr/non_null.rs @@ -635,7 +635,8 @@ impl NonNull<[T]> { } #[stable(feature = "nonnull", since = "1.25.0")] -impl Clone for NonNull { +#[rustc_const_unstable(feature = "const_clone", issue = "91805")] +impl const Clone for NonNull { #[inline] fn clone(&self) -> Self { *self diff --git a/library/core/src/ptr/unique.rs b/library/core/src/ptr/unique.rs index d650a6f974b97..ee984b7b5a4f1 100644 --- a/library/core/src/ptr/unique.rs +++ b/library/core/src/ptr/unique.rs @@ -146,7 +146,8 @@ impl Unique { } #[unstable(feature = "ptr_internals", issue = "none")] -impl Clone for Unique { +#[rustc_const_unstable(feature = "const_clone", issue = "91805")] +impl const Clone for Unique { #[inline] fn clone(&self) -> Self { *self diff --git a/library/core/src/result.rs b/library/core/src/result.rs index e6b8c8ec3385a..d639c7188c15a 100644 --- a/library/core/src/result.rs +++ b/library/core/src/result.rs @@ -1665,7 +1665,12 @@ fn unwrap_failed(msg: &str, error: &dyn fmt::Debug) -> ! { ///////////////////////////////////////////////////////////////////////////// #[stable(feature = "rust1", since = "1.0.0")] -impl Clone for Result { +#[rustc_const_unstable(feature = "const_clone", issue = "91805")] +impl const Clone for Result +where + T: ~const Clone + ~const Drop, + E: ~const Clone + ~const Drop, +{ #[inline] fn clone(&self) -> Self { match self { From 9054fbb03ab2ebb048888f4963a364d800fba056 Mon Sep 17 00:00:00 2001 From: asquared31415 <34665709+asquared31415@users.noreply.github.com> Date: Mon, 3 Jan 2022 17:12:59 -0500 Subject: [PATCH 02/11] mirror mention of intent of From --- library/core/src/convert/mod.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/core/src/convert/mod.rs b/library/core/src/convert/mod.rs index 1c2e673d60493..b6211900b47f4 100644 --- a/library/core/src/convert/mod.rs +++ b/library/core/src/convert/mod.rs @@ -300,7 +300,8 @@ pub trait Into: Sized { /// that encapsulate multiple error types. See the "Examples" section and [the book][book] for more /// details. /// -/// **Note: This trait must not fail**. If the conversion can fail, use [`TryFrom`]. +/// **Note: This trait must not fail**. The `From` trait is intended for perfect conversions. +/// If the conversion can fail or is not perfect, use [`TryFrom`]. /// /// # Generic Implementations /// From b328688d23d56a7b95ddcd994c3967a193dd25ea Mon Sep 17 00:00:00 2001 From: Jon Gjengset Date: Mon, 7 Mar 2022 16:59:10 -0800 Subject: [PATCH 03/11] Statically compile libstdc++ everywhere if asked PR #93918 made it so that `-static-libstdc++` was only set in one place, and was only set during linking, but accidentally also made it so that it is no longer passed when building LLD or sanitizers, only when building LLVM itself. This moves the logic for setting `-static-libstdc++` in the linker flags back to `configure_cmake` so that it takes effect for all CMake invocations in `native.rs`. As a side-effect, this also causes libstdc++ to be statically compiled into sanitizers and LLD if `llvm-tools-enabled` is set but `llvm-static-stdcpp` is not, even though previously it was only linked statically if `llvm-static-stdcpp` was set explicitly. But that seems more like the expected behavior anyway. --- src/bootstrap/native.rs | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs index f00c5ce5aa6f0..0fe39defae85d 100644 --- a/src/bootstrap/native.rs +++ b/src/bootstrap/native.rs @@ -259,18 +259,6 @@ impl Step for Llvm { cfg.define("LLVM_LINK_LLVM_DYLIB", "ON"); } - // For distribution we want the LLVM tools to be *statically* linked to libstdc++. - // We also do this if the user explicitly requested static libstdc++. - if builder.config.llvm_tools_enabled || builder.config.llvm_static_stdcpp { - if !target.contains("msvc") && !target.contains("netbsd") { - if target.contains("apple") { - ldflags.push_all("-static-libstdc++"); - } else { - ldflags.push_all("-Wl,-Bsymbolic -static-libstdc++"); - } - } - } - if target.starts_with("riscv") && !target.contains("freebsd") { // RISC-V GCC erroneously requires linking against // `libatomic` when using 1-byte and 2-byte C++ @@ -576,6 +564,18 @@ fn configure_cmake( ldflags.push_all(&flags); } + // For distribution we want the LLVM tools to be *statically* linked to libstdc++. + // We also do this if the user explicitly requested static libstdc++. + if builder.config.llvm_tools_enabled || builder.config.llvm_static_stdcpp { + if !target.contains("msvc") && !target.contains("netbsd") { + if target.contains("apple") { + ldflags.push_all("-static-libstdc++"); + } else { + ldflags.push_all("-Wl,-Bsymbolic -static-libstdc++"); + } + } + } + cfg.define("CMAKE_SHARED_LINKER_FLAGS", &ldflags.shared); cfg.define("CMAKE_MODULE_LINKER_FLAGS", &ldflags.module); cfg.define("CMAKE_EXE_LINKER_FLAGS", &ldflags.exe); From 0d92752b8aac53e033541d04fc7d9677d8bca227 Mon Sep 17 00:00:00 2001 From: Esteban Kuber Date: Tue, 8 Mar 2022 05:54:38 +0000 Subject: [PATCH 04/11] Suggest `if let`/`let_else` for refutable pat in `let` --- .../src/thir/pattern/check_match.rs | 86 +++++++++++++++++-- .../ui/consts/const-match-check.eval1.stderr | 10 ++- .../ui/consts/const-match-check.eval2.stderr | 10 ++- .../consts/const-match-check.matchck.stderr | 40 ++++++--- src/test/ui/empty/empty-never-array.stderr | 6 +- src/test/ui/error-codes/E0005.stderr | 8 +- .../feature-gate-exhaustive-patterns.stderr | 8 +- ...een-expanded-earlier-non-exhaustive.stderr | 10 ++- .../ui/pattern/usefulness/issue-31561.stderr | 8 +- .../non-exhaustive-defined-here.stderr | 36 +++++--- .../refutable-pattern-errors.stderr | 8 +- ...recursive-types-are-not-uninhabited.stderr | 6 +- .../ui/uninhabited/uninhabited-irrefutable.rs | 6 +- .../uninhabited-irrefutable.stderr | 12 ++- .../uninhabited-matches-feature-gated.stderr | 6 +- 15 files changed, 204 insertions(+), 56 deletions(-) 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 b80d2e52ee709..dae313da8d993 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -7,7 +7,8 @@ use super::{PatCtxt, PatternError}; use rustc_arena::TypedArena; use rustc_ast::Mutability; use rustc_errors::{ - error_code, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, + error_code, pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, + ErrorGuaranteed, }; use rustc_hir as hir; use rustc_hir::def::*; @@ -20,7 +21,7 @@ use rustc_session::lint::builtin::{ }; use rustc_session::Session; use rustc_span::source_map::Spanned; -use rustc_span::{DesugaringKind, ExpnKind, MultiSpan, Span}; +use rustc_span::{BytePos, DesugaringKind, ExpnKind, MultiSpan, Span}; crate fn check_match(tcx: TyCtxt<'_>, def_id: DefId) { let body_id = match def_id.as_local() { @@ -241,6 +242,9 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> { } let joined_patterns = joined_uncovered_patterns(&cx, &witnesses); + + let mut bindings = vec![]; + let mut err = struct_span_err!( self.tcx.sess, pat.span, @@ -257,6 +261,16 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> { false } _ => { + pat.walk(&mut |pat: &hir::Pat<'_>| { + match pat.kind { + hir::PatKind::Binding(_, _, ident, _) => { + bindings.push(ident); + } + _ => {} + } + true + }); + err.span_label(pat.span, pattern_not_covered_label(&witnesses, &joined_patterns)); true } @@ -267,13 +281,71 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> { "`let` bindings require an \"irrefutable pattern\", like a `struct` or \ an `enum` with only one variant", ); - if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) { - err.span_suggestion( - span, - "you might want to use `if let` to ignore the variant that isn't matched", - format!("if {} {{ /* */ }}", &snippet[..snippet.len() - 1]), + if self.tcx.sess.source_map().span_to_snippet(span).is_ok() { + let semi_span = span.shrink_to_hi().with_lo(span.hi() - BytePos(1)); + let start_span = span.shrink_to_lo(); + let end_span = semi_span.shrink_to_lo(); + err.multipart_suggestion( + &format!( + "you might want to use `if let` to ignore the variant{} that {} matched", + pluralize!(witnesses.len()), + match witnesses.len() { + 1 => "isn't", + _ => "aren't", + }, + ), + vec![ + match &bindings[..] { + [] => (start_span, "if ".to_string()), + [binding] => (start_span, format!("let {} = if ", binding)), + bindings => ( + start_span, + format!( + "let ({}) = if ", + bindings + .iter() + .map(|ident| ident.to_string()) + .collect::>() + .join(", ") + ), + ), + }, + match &bindings[..] { + [] => (semi_span, " { todo!() }".to_string()), + [binding] => { + (end_span, format!(" {{ {} }} else {{ todo!() }}", binding)) + } + bindings => ( + end_span, + format!( + " {{ ({}) }} else {{ todo!() }}", + bindings + .iter() + .map(|ident| ident.to_string()) + .collect::>() + .join(", ") + ), + ), + }, + ], Applicability::HasPlaceholders, ); + if cx.tcx.sess.is_nightly_build() { + err.span_suggestion_verbose( + semi_span.shrink_to_lo(), + &format!( + "alternatively, on nightly, you might want to use \ + `#![feature(let_else)]` to handle the variant{} that {} matched", + pluralize!(witnesses.len()), + match witnesses.len() { + 1 => "isn't", + _ => "aren't", + }, + ), + " else { todo!() }".to_string(), + Applicability::HasPlaceholders, + ); + } } err.note( "for more information, visit \ diff --git a/src/test/ui/consts/const-match-check.eval1.stderr b/src/test/ui/consts/const-match-check.eval1.stderr index 4141cc4ab1a48..08ee800f138d2 100644 --- a/src/test/ui/consts/const-match-check.eval1.stderr +++ b/src/test/ui/consts/const-match-check.eval1.stderr @@ -7,10 +7,14 @@ LL | A = { let 0 = 0; 0 }, = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html = note: the matched value is of type `i32` -help: you might want to use `if let` to ignore the variant that isn't matched +help: you might want to use `if let` to ignore the variants that aren't matched | -LL | A = { if let 0 = 0 { /* */ } 0 }, - | ~~~~~~~~~~~~~~~~~~~~~~ +LL | A = { if let 0 = 0 { todo!() } 0 }, + | ++ ~~~~~~~~~~~ +help: alternatively, on nightly, you might want to use `#![feature(let_else)]` to handle the variants that aren't matched + | +LL | A = { let 0 = 0 else { todo!() }; 0 }, + | ++++++++++++++++ error: aborting due to previous error diff --git a/src/test/ui/consts/const-match-check.eval2.stderr b/src/test/ui/consts/const-match-check.eval2.stderr index af86ba0cc82f8..579cb7e780007 100644 --- a/src/test/ui/consts/const-match-check.eval2.stderr +++ b/src/test/ui/consts/const-match-check.eval2.stderr @@ -7,10 +7,14 @@ LL | let x: [i32; { let 0 = 0; 0 }] = []; = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html = note: the matched value is of type `i32` -help: you might want to use `if let` to ignore the variant that isn't matched +help: you might want to use `if let` to ignore the variants that aren't matched | -LL | let x: [i32; { if let 0 = 0 { /* */ } 0 }] = []; - | ~~~~~~~~~~~~~~~~~~~~~~ +LL | let x: [i32; { if let 0 = 0 { todo!() } 0 }] = []; + | ++ ~~~~~~~~~~~ +help: alternatively, on nightly, you might want to use `#![feature(let_else)]` to handle the variants that aren't matched + | +LL | let x: [i32; { let 0 = 0 else { todo!() }; 0 }] = []; + | ++++++++++++++++ error: aborting due to previous error diff --git a/src/test/ui/consts/const-match-check.matchck.stderr b/src/test/ui/consts/const-match-check.matchck.stderr index f71490eba6135..f89bbc0d42234 100644 --- a/src/test/ui/consts/const-match-check.matchck.stderr +++ b/src/test/ui/consts/const-match-check.matchck.stderr @@ -7,10 +7,14 @@ LL | const X: i32 = { let 0 = 0; 0 }; = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html = note: the matched value is of type `i32` -help: you might want to use `if let` to ignore the variant that isn't matched +help: you might want to use `if let` to ignore the variants that aren't matched | -LL | const X: i32 = { if let 0 = 0 { /* */ } 0 }; - | ~~~~~~~~~~~~~~~~~~~~~~ +LL | const X: i32 = { if let 0 = 0 { todo!() } 0 }; + | ++ ~~~~~~~~~~~ +help: alternatively, on nightly, you might want to use `#![feature(let_else)]` to handle the variants that aren't matched + | +LL | const X: i32 = { let 0 = 0 else { todo!() }; 0 }; + | ++++++++++++++++ error[E0005]: refutable pattern in local binding: `i32::MIN..=-1_i32` and `1_i32..=i32::MAX` not covered --> $DIR/const-match-check.rs:8:23 @@ -21,10 +25,14 @@ LL | static Y: i32 = { let 0 = 0; 0 }; = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html = note: the matched value is of type `i32` -help: you might want to use `if let` to ignore the variant that isn't matched +help: you might want to use `if let` to ignore the variants that aren't matched + | +LL | static Y: i32 = { if let 0 = 0 { todo!() } 0 }; + | ++ ~~~~~~~~~~~ +help: alternatively, on nightly, you might want to use `#![feature(let_else)]` to handle the variants that aren't matched | -LL | static Y: i32 = { if let 0 = 0 { /* */ } 0 }; - | ~~~~~~~~~~~~~~~~~~~~~~ +LL | static Y: i32 = { let 0 = 0 else { todo!() }; 0 }; + | ++++++++++++++++ error[E0005]: refutable pattern in local binding: `i32::MIN..=-1_i32` and `1_i32..=i32::MAX` not covered --> $DIR/const-match-check.rs:13:26 @@ -35,10 +43,14 @@ LL | const X: i32 = { let 0 = 0; 0 }; = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html = note: the matched value is of type `i32` -help: you might want to use `if let` to ignore the variant that isn't matched +help: you might want to use `if let` to ignore the variants that aren't matched | -LL | const X: i32 = { if let 0 = 0 { /* */ } 0 }; - | ~~~~~~~~~~~~~~~~~~~~~~ +LL | const X: i32 = { if let 0 = 0 { todo!() } 0 }; + | ++ ~~~~~~~~~~~ +help: alternatively, on nightly, you might want to use `#![feature(let_else)]` to handle the variants that aren't matched + | +LL | const X: i32 = { let 0 = 0 else { todo!() }; 0 }; + | ++++++++++++++++ error[E0005]: refutable pattern in local binding: `i32::MIN..=-1_i32` and `1_i32..=i32::MAX` not covered --> $DIR/const-match-check.rs:19:26 @@ -49,10 +61,14 @@ LL | const X: i32 = { let 0 = 0; 0 }; = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html = note: the matched value is of type `i32` -help: you might want to use `if let` to ignore the variant that isn't matched +help: you might want to use `if let` to ignore the variants that aren't matched + | +LL | const X: i32 = { if let 0 = 0 { todo!() } 0 }; + | ++ ~~~~~~~~~~~ +help: alternatively, on nightly, you might want to use `#![feature(let_else)]` to handle the variants that aren't matched | -LL | const X: i32 = { if let 0 = 0 { /* */ } 0 }; - | ~~~~~~~~~~~~~~~~~~~~~~ +LL | const X: i32 = { let 0 = 0 else { todo!() }; 0 }; + | ++++++++++++++++ error: aborting due to 4 previous errors diff --git a/src/test/ui/empty/empty-never-array.stderr b/src/test/ui/empty/empty-never-array.stderr index 8dd0f377533ce..909aa73a74a38 100644 --- a/src/test/ui/empty/empty-never-array.stderr +++ b/src/test/ui/empty/empty-never-array.stderr @@ -16,8 +16,12 @@ LL | T(T, [!; 0]), = note: the matched value is of type `Helper` help: you might want to use `if let` to ignore the variant that isn't matched | -LL | if let Helper::U(u) = Helper::T(t, []) { /* */ } +LL | let u = if let Helper::U(u) = Helper::T(t, []) { u } else { todo!() }; + | ++++++++++ ++++++++++++++++++++++ +help: alternatively, on nightly, you might want to use `#![feature(let_else)]` to handle the variant that isn't matched | +LL | let Helper::U(u) = Helper::T(t, []) else { todo!() }; + | ++++++++++++++++ error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0005.stderr b/src/test/ui/error-codes/E0005.stderr index 208c625a53e95..55b1112b5f8ec 100644 --- a/src/test/ui/error-codes/E0005.stderr +++ b/src/test/ui/error-codes/E0005.stderr @@ -22,8 +22,12 @@ LL | | } = note: the matched value is of type `Option` help: you might want to use `if let` to ignore the variant that isn't matched | -LL | if let Some(y) = x { /* */ } - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +LL | let y = if let Some(y) = x { y } else { todo!() }; + | ++++++++++ ++++++++++++++++++++++ +help: alternatively, on nightly, you might want to use `#![feature(let_else)]` to handle the variant that isn't matched + | +LL | let Some(y) = x else { todo!() }; + | ++++++++++++++++ error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-exhaustive-patterns.stderr b/src/test/ui/feature-gates/feature-gate-exhaustive-patterns.stderr index c2ffda6bb72d2..21180f31bbd26 100644 --- a/src/test/ui/feature-gates/feature-gate-exhaustive-patterns.stderr +++ b/src/test/ui/feature-gates/feature-gate-exhaustive-patterns.stderr @@ -21,8 +21,12 @@ LL | | } = note: the matched value is of type `Result` help: you might want to use `if let` to ignore the variant that isn't matched | -LL | if let Ok(_x) = foo() { /* */ } - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +LL | let _x = if let Ok(_x) = foo() { _x } else { todo!() }; + | +++++++++++ +++++++++++++++++++++++ +help: alternatively, on nightly, you might want to use `#![feature(let_else)]` to handle the variant that isn't matched + | +LL | let Ok(_x) = foo() else { todo!() }; + | ++++++++++++++++ error: aborting due to previous error diff --git a/src/test/ui/or-patterns/issue-69875-should-have-been-expanded-earlier-non-exhaustive.stderr b/src/test/ui/or-patterns/issue-69875-should-have-been-expanded-earlier-non-exhaustive.stderr index 37a35700b36d5..aa1aa4434c3fa 100644 --- a/src/test/ui/or-patterns/issue-69875-should-have-been-expanded-earlier-non-exhaustive.stderr +++ b/src/test/ui/or-patterns/issue-69875-should-have-been-expanded-earlier-non-exhaustive.stderr @@ -7,10 +7,14 @@ LL | let (0 | (1 | 2)) = 0; = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html = note: the matched value is of type `i32` -help: you might want to use `if let` to ignore the variant that isn't matched +help: you might want to use `if let` to ignore the variants that aren't matched | -LL | if let (0 | (1 | 2)) = 0 { /* */ } - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +LL | if let (0 | (1 | 2)) = 0 { todo!() } + | ++ ~~~~~~~~~~~ +help: alternatively, on nightly, you might want to use `#![feature(let_else)]` to handle the variants that aren't matched + | +LL | let (0 | (1 | 2)) = 0 else { todo!() }; + | ++++++++++++++++ error[E0004]: non-exhaustive patterns: `i32::MIN..=-1_i32` and `3_i32..=i32::MAX` not covered --> $DIR/issue-69875-should-have-been-expanded-earlier-non-exhaustive.rs:3:11 diff --git a/src/test/ui/pattern/usefulness/issue-31561.stderr b/src/test/ui/pattern/usefulness/issue-31561.stderr index dffcfc016072f..9da6b5eeead23 100644 --- a/src/test/ui/pattern/usefulness/issue-31561.stderr +++ b/src/test/ui/pattern/usefulness/issue-31561.stderr @@ -17,10 +17,14 @@ LL | Bar, LL | Baz | ^^^ not covered = note: the matched value is of type `Thing` -help: you might want to use `if let` to ignore the variant that isn't matched +help: you might want to use `if let` to ignore the variants that aren't matched | -LL | if let Thing::Foo(y) = Thing::Foo(1) { /* */ } +LL | let y = if let Thing::Foo(y) = Thing::Foo(1) { y } else { todo!() }; + | ++++++++++ ++++++++++++++++++++++ +help: alternatively, on nightly, you might want to use `#![feature(let_else)]` to handle the variants that aren't matched | +LL | let Thing::Foo(y) = Thing::Foo(1) else { todo!() }; + | ++++++++++++++++ error: aborting due to previous error diff --git a/src/test/ui/pattern/usefulness/non-exhaustive-defined-here.stderr b/src/test/ui/pattern/usefulness/non-exhaustive-defined-here.stderr index 8f5adccea806d..f7dc070f80248 100644 --- a/src/test/ui/pattern/usefulness/non-exhaustive-defined-here.stderr +++ b/src/test/ui/pattern/usefulness/non-exhaustive-defined-here.stderr @@ -42,10 +42,14 @@ LL | B, LL | C | ^ not covered = note: the matched value is of type `E` -help: you might want to use `if let` to ignore the variant that isn't matched +help: you might want to use `if let` to ignore the variants that aren't matched + | +LL | if let E::A = e { todo!() } + | ++ ~~~~~~~~~~~ +help: alternatively, on nightly, you might want to use `#![feature(let_else)]` to handle the variants that aren't matched | -LL | if let E::A = e { /* */ } - | ~~~~~~~~~~~~~~~~~~~~~~~~~ +LL | let E::A = e else { todo!() }; + | ++++++++++++++++ error[E0004]: non-exhaustive patterns: `&B` and `&C` not covered --> $DIR/non-exhaustive-defined-here.rs:52:11 @@ -91,10 +95,14 @@ LL | B, LL | C | ^ not covered = note: the matched value is of type `&E` -help: you might want to use `if let` to ignore the variant that isn't matched +help: you might want to use `if let` to ignore the variants that aren't matched | -LL | if let E::A = e { /* */ } - | ~~~~~~~~~~~~~~~~~~~~~~~~~ +LL | if let E::A = e { todo!() } + | ++ ~~~~~~~~~~~ +help: alternatively, on nightly, you might want to use `#![feature(let_else)]` to handle the variants that aren't matched + | +LL | let E::A = e else { todo!() }; + | ++++++++++++++++ error[E0004]: non-exhaustive patterns: `&&mut &B` and `&&mut &C` not covered --> $DIR/non-exhaustive-defined-here.rs:66:11 @@ -140,10 +148,14 @@ LL | B, LL | C | ^ not covered = note: the matched value is of type `&&mut &E` -help: you might want to use `if let` to ignore the variant that isn't matched +help: you might want to use `if let` to ignore the variants that aren't matched | -LL | if let E::A = e { /* */ } +LL | if let E::A = e { todo!() } + | ++ ~~~~~~~~~~~ +help: alternatively, on nightly, you might want to use `#![feature(let_else)]` to handle the variants that aren't matched | +LL | let E::A = e else { todo!() }; + | ++++++++++++++++ error[E0004]: non-exhaustive patterns: `None` not covered --> $DIR/non-exhaustive-defined-here.rs:92:11 @@ -185,8 +197,12 @@ LL | None, = note: the matched value is of type `Opt` help: you might want to use `if let` to ignore the variant that isn't matched | -LL | if let Opt::Some(ref _x) = e { /* */ } - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +LL | let _x = if let Opt::Some(ref _x) = e { _x } else { todo!() }; + | +++++++++++ +++++++++++++++++++++++ +help: alternatively, on nightly, you might want to use `#![feature(let_else)]` to handle the variant that isn't matched + | +LL | let Opt::Some(ref _x) = e else { todo!() }; + | ++++++++++++++++ error: aborting due to 8 previous errors diff --git a/src/test/ui/pattern/usefulness/refutable-pattern-errors.stderr b/src/test/ui/pattern/usefulness/refutable-pattern-errors.stderr index 74ec646e31cca..e3ffc092327ac 100644 --- a/src/test/ui/pattern/usefulness/refutable-pattern-errors.stderr +++ b/src/test/ui/pattern/usefulness/refutable-pattern-errors.stderr @@ -15,10 +15,14 @@ LL | let (1, (Some(1), 2..=3)) = (1, (None, 2)); = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html = note: the matched value is of type `(i32, (Option, i32))` -help: you might want to use `if let` to ignore the variant that isn't matched +help: you might want to use `if let` to ignore the variants that aren't matched | -LL | if let (1, (Some(1), 2..=3)) = (1, (None, 2)) { /* */ } +LL | if let (1, (Some(1), 2..=3)) = (1, (None, 2)) { todo!() } + | ++ ~~~~~~~~~~~ +help: alternatively, on nightly, you might want to use `#![feature(let_else)]` to handle the variants that aren't matched | +LL | let (1, (Some(1), 2..=3)) = (1, (None, 2)) else { todo!() }; + | ++++++++++++++++ error: aborting due to 2 previous errors diff --git a/src/test/ui/recursion/recursive-types-are-not-uninhabited.stderr b/src/test/ui/recursion/recursive-types-are-not-uninhabited.stderr index ded3cf3ad1d44..a9159562d9d51 100644 --- a/src/test/ui/recursion/recursive-types-are-not-uninhabited.stderr +++ b/src/test/ui/recursion/recursive-types-are-not-uninhabited.stderr @@ -21,8 +21,12 @@ LL | | } = note: the matched value is of type `Result` help: you might want to use `if let` to ignore the variant that isn't matched | -LL | if let Ok(x) = res { /* */ } +LL | let x = if let Ok(x) = res { x } else { todo!() }; + | ++++++++++ ++++++++++++++++++++++ +help: alternatively, on nightly, you might want to use `#![feature(let_else)]` to handle the variant that isn't matched | +LL | let Ok(x) = res else { todo!() }; + | ++++++++++++++++ error: aborting due to previous error diff --git a/src/test/ui/uninhabited/uninhabited-irrefutable.rs b/src/test/ui/uninhabited/uninhabited-irrefutable.rs index 48cd92719b49a..661b5486adc12 100644 --- a/src/test/ui/uninhabited/uninhabited-irrefutable.rs +++ b/src/test/ui/uninhabited/uninhabited-irrefutable.rs @@ -19,10 +19,10 @@ enum Foo { A(foo::SecretlyEmpty), B(foo::NotSoSecretlyEmpty), C(NotSoSecretlyEmpty), - D(u32), + D(u32, u32), } fn main() { - let x: Foo = Foo::D(123); - let Foo::D(_y) = x; //~ ERROR refutable pattern in local binding: `A(_)` not covered + let x: Foo = Foo::D(123, 456); + let Foo::D(_y, _z) = x; //~ ERROR refutable pattern in local binding: `A(_)` not covered } diff --git a/src/test/ui/uninhabited/uninhabited-irrefutable.stderr b/src/test/ui/uninhabited/uninhabited-irrefutable.stderr index ad19c34a40a11..c571e17a7b372 100644 --- a/src/test/ui/uninhabited/uninhabited-irrefutable.stderr +++ b/src/test/ui/uninhabited/uninhabited-irrefutable.stderr @@ -1,8 +1,8 @@ error[E0005]: refutable pattern in local binding: `A(_)` not covered --> $DIR/uninhabited-irrefutable.rs:27:9 | -LL | let Foo::D(_y) = x; - | ^^^^^^^^^^ pattern `A(_)` not covered +LL | let Foo::D(_y, _z) = x; + | ^^^^^^^^^^^^^^ pattern `A(_)` not covered | = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html @@ -16,8 +16,12 @@ LL | A(foo::SecretlyEmpty), = note: the matched value is of type `Foo` help: you might want to use `if let` to ignore the variant that isn't matched | -LL | if let Foo::D(_y) = x { /* */ } - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +LL | let (_y, _z) = if let Foo::D(_y, _z) = x { (_y, _z) } else { todo!() }; + | +++++++++++++++++ +++++++++++++++++++++++++++++ +help: alternatively, on nightly, you might want to use `#![feature(let_else)]` to handle the variant that isn't matched + | +LL | let Foo::D(_y, _z) = x else { todo!() }; + | ++++++++++++++++ error: aborting due to previous error diff --git a/src/test/ui/uninhabited/uninhabited-matches-feature-gated.stderr b/src/test/ui/uninhabited/uninhabited-matches-feature-gated.stderr index d90075d82f47b..74216d265d034 100644 --- a/src/test/ui/uninhabited/uninhabited-matches-feature-gated.stderr +++ b/src/test/ui/uninhabited/uninhabited-matches-feature-gated.stderr @@ -132,8 +132,12 @@ LL | | } = note: the matched value is of type `Result` help: you might want to use `if let` to ignore the variant that isn't matched | -LL | if let Ok(x) = x { /* */ } +LL | let x = if let Ok(x) = x { x } else { todo!() }; + | ++++++++++ ++++++++++++++++++++++ +help: alternatively, on nightly, you might want to use `#![feature(let_else)]` to handle the variant that isn't matched | +LL | let Ok(x) = x else { todo!() }; + | ++++++++++++++++ error: aborting due to 7 previous errors From c3a998e82a50b66e8f6f97170cd9117fadf03618 Mon Sep 17 00:00:00 2001 From: Esteban Kuber Date: Tue, 8 Mar 2022 17:20:05 +0000 Subject: [PATCH 05/11] Do not suggest `let_else` if no bindings would be introduced --- .../src/thir/pattern/check_match.rs | 2 +- .../ui/consts/const-match-check.eval1.stderr | 4 ---- .../ui/consts/const-match-check.eval2.stderr | 4 ---- .../ui/consts/const-match-check.matchck.stderr | 16 ---------------- ...e-been-expanded-earlier-non-exhaustive.stderr | 4 ---- .../non-exhaustive-defined-here.stderr | 12 ------------ .../usefulness/refutable-pattern-errors.stderr | 4 ---- 7 files changed, 1 insertion(+), 45 deletions(-) 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 dae313da8d993..c94da838680e0 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -330,7 +330,7 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> { ], Applicability::HasPlaceholders, ); - if cx.tcx.sess.is_nightly_build() { + if !bindings.is_empty() && cx.tcx.sess.is_nightly_build() { err.span_suggestion_verbose( semi_span.shrink_to_lo(), &format!( diff --git a/src/test/ui/consts/const-match-check.eval1.stderr b/src/test/ui/consts/const-match-check.eval1.stderr index 08ee800f138d2..6e61dbbd8eee3 100644 --- a/src/test/ui/consts/const-match-check.eval1.stderr +++ b/src/test/ui/consts/const-match-check.eval1.stderr @@ -11,10 +11,6 @@ help: you might want to use `if let` to ignore the variants that aren't matched | LL | A = { if let 0 = 0 { todo!() } 0 }, | ++ ~~~~~~~~~~~ -help: alternatively, on nightly, you might want to use `#![feature(let_else)]` to handle the variants that aren't matched - | -LL | A = { let 0 = 0 else { todo!() }; 0 }, - | ++++++++++++++++ error: aborting due to previous error diff --git a/src/test/ui/consts/const-match-check.eval2.stderr b/src/test/ui/consts/const-match-check.eval2.stderr index 579cb7e780007..1b3b6e06c3df6 100644 --- a/src/test/ui/consts/const-match-check.eval2.stderr +++ b/src/test/ui/consts/const-match-check.eval2.stderr @@ -11,10 +11,6 @@ help: you might want to use `if let` to ignore the variants that aren't matched | LL | let x: [i32; { if let 0 = 0 { todo!() } 0 }] = []; | ++ ~~~~~~~~~~~ -help: alternatively, on nightly, you might want to use `#![feature(let_else)]` to handle the variants that aren't matched - | -LL | let x: [i32; { let 0 = 0 else { todo!() }; 0 }] = []; - | ++++++++++++++++ error: aborting due to previous error diff --git a/src/test/ui/consts/const-match-check.matchck.stderr b/src/test/ui/consts/const-match-check.matchck.stderr index f89bbc0d42234..bc8edfa7af9f4 100644 --- a/src/test/ui/consts/const-match-check.matchck.stderr +++ b/src/test/ui/consts/const-match-check.matchck.stderr @@ -11,10 +11,6 @@ help: you might want to use `if let` to ignore the variants that aren't matched | LL | const X: i32 = { if let 0 = 0 { todo!() } 0 }; | ++ ~~~~~~~~~~~ -help: alternatively, on nightly, you might want to use `#![feature(let_else)]` to handle the variants that aren't matched - | -LL | const X: i32 = { let 0 = 0 else { todo!() }; 0 }; - | ++++++++++++++++ error[E0005]: refutable pattern in local binding: `i32::MIN..=-1_i32` and `1_i32..=i32::MAX` not covered --> $DIR/const-match-check.rs:8:23 @@ -29,10 +25,6 @@ help: you might want to use `if let` to ignore the variants that aren't matched | LL | static Y: i32 = { if let 0 = 0 { todo!() } 0 }; | ++ ~~~~~~~~~~~ -help: alternatively, on nightly, you might want to use `#![feature(let_else)]` to handle the variants that aren't matched - | -LL | static Y: i32 = { let 0 = 0 else { todo!() }; 0 }; - | ++++++++++++++++ error[E0005]: refutable pattern in local binding: `i32::MIN..=-1_i32` and `1_i32..=i32::MAX` not covered --> $DIR/const-match-check.rs:13:26 @@ -47,10 +39,6 @@ help: you might want to use `if let` to ignore the variants that aren't matched | LL | const X: i32 = { if let 0 = 0 { todo!() } 0 }; | ++ ~~~~~~~~~~~ -help: alternatively, on nightly, you might want to use `#![feature(let_else)]` to handle the variants that aren't matched - | -LL | const X: i32 = { let 0 = 0 else { todo!() }; 0 }; - | ++++++++++++++++ error[E0005]: refutable pattern in local binding: `i32::MIN..=-1_i32` and `1_i32..=i32::MAX` not covered --> $DIR/const-match-check.rs:19:26 @@ -65,10 +53,6 @@ help: you might want to use `if let` to ignore the variants that aren't matched | LL | const X: i32 = { if let 0 = 0 { todo!() } 0 }; | ++ ~~~~~~~~~~~ -help: alternatively, on nightly, you might want to use `#![feature(let_else)]` to handle the variants that aren't matched - | -LL | const X: i32 = { let 0 = 0 else { todo!() }; 0 }; - | ++++++++++++++++ error: aborting due to 4 previous errors diff --git a/src/test/ui/or-patterns/issue-69875-should-have-been-expanded-earlier-non-exhaustive.stderr b/src/test/ui/or-patterns/issue-69875-should-have-been-expanded-earlier-non-exhaustive.stderr index aa1aa4434c3fa..95b22ac059482 100644 --- a/src/test/ui/or-patterns/issue-69875-should-have-been-expanded-earlier-non-exhaustive.stderr +++ b/src/test/ui/or-patterns/issue-69875-should-have-been-expanded-earlier-non-exhaustive.stderr @@ -11,10 +11,6 @@ help: you might want to use `if let` to ignore the variants that aren't matched | LL | if let (0 | (1 | 2)) = 0 { todo!() } | ++ ~~~~~~~~~~~ -help: alternatively, on nightly, you might want to use `#![feature(let_else)]` to handle the variants that aren't matched - | -LL | let (0 | (1 | 2)) = 0 else { todo!() }; - | ++++++++++++++++ error[E0004]: non-exhaustive patterns: `i32::MIN..=-1_i32` and `3_i32..=i32::MAX` not covered --> $DIR/issue-69875-should-have-been-expanded-earlier-non-exhaustive.rs:3:11 diff --git a/src/test/ui/pattern/usefulness/non-exhaustive-defined-here.stderr b/src/test/ui/pattern/usefulness/non-exhaustive-defined-here.stderr index f7dc070f80248..0f06c31c468b1 100644 --- a/src/test/ui/pattern/usefulness/non-exhaustive-defined-here.stderr +++ b/src/test/ui/pattern/usefulness/non-exhaustive-defined-here.stderr @@ -46,10 +46,6 @@ help: you might want to use `if let` to ignore the variants that aren't matched | LL | if let E::A = e { todo!() } | ++ ~~~~~~~~~~~ -help: alternatively, on nightly, you might want to use `#![feature(let_else)]` to handle the variants that aren't matched - | -LL | let E::A = e else { todo!() }; - | ++++++++++++++++ error[E0004]: non-exhaustive patterns: `&B` and `&C` not covered --> $DIR/non-exhaustive-defined-here.rs:52:11 @@ -99,10 +95,6 @@ help: you might want to use `if let` to ignore the variants that aren't matched | LL | if let E::A = e { todo!() } | ++ ~~~~~~~~~~~ -help: alternatively, on nightly, you might want to use `#![feature(let_else)]` to handle the variants that aren't matched - | -LL | let E::A = e else { todo!() }; - | ++++++++++++++++ error[E0004]: non-exhaustive patterns: `&&mut &B` and `&&mut &C` not covered --> $DIR/non-exhaustive-defined-here.rs:66:11 @@ -152,10 +144,6 @@ help: you might want to use `if let` to ignore the variants that aren't matched | LL | if let E::A = e { todo!() } | ++ ~~~~~~~~~~~ -help: alternatively, on nightly, you might want to use `#![feature(let_else)]` to handle the variants that aren't matched - | -LL | let E::A = e else { todo!() }; - | ++++++++++++++++ error[E0004]: non-exhaustive patterns: `None` not covered --> $DIR/non-exhaustive-defined-here.rs:92:11 diff --git a/src/test/ui/pattern/usefulness/refutable-pattern-errors.stderr b/src/test/ui/pattern/usefulness/refutable-pattern-errors.stderr index e3ffc092327ac..d1dacc822e942 100644 --- a/src/test/ui/pattern/usefulness/refutable-pattern-errors.stderr +++ b/src/test/ui/pattern/usefulness/refutable-pattern-errors.stderr @@ -19,10 +19,6 @@ help: you might want to use `if let` to ignore the variants that aren't matched | LL | if let (1, (Some(1), 2..=3)) = (1, (None, 2)) { todo!() } | ++ ~~~~~~~~~~~ -help: alternatively, on nightly, you might want to use `#![feature(let_else)]` to handle the variants that aren't matched - | -LL | let (1, (Some(1), 2..=3)) = (1, (None, 2)) else { todo!() }; - | ++++++++++++++++ error: aborting due to 2 previous errors From a5216cf67d93de97091b41ecba85de2e08f39863 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 8 Mar 2022 17:40:24 +0100 Subject: [PATCH 06/11] Unify inherent impl blocks by wrapping them into a div --- src/librustdoc/html/markdown.rs | 1 + src/librustdoc/html/render/mod.rs | 16 ++++++++++------ src/librustdoc/html/static/js/main.js | 2 +- src/test/rustdoc/duplicate_impls/issue-33054.rs | 2 +- 4 files changed, 13 insertions(+), 8 deletions(-) diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 7061a9674e4fb..f2856690d257a 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -1460,6 +1460,7 @@ fn init_id_map() -> FxHashMap { map.insert("provided-methods".to_owned(), 1); map.insert("implementors".to_owned(), 1); map.insert("synthetic-implementors".to_owned(), 1); + map.insert("implementations-list".to_owned(), 1); map.insert("trait-implementations-list".to_owned(), 1); map.insert("synthetic-implementations-list".to_owned(), 1); map.insert("blanket-implementations-list".to_owned(), 1); diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 558dbb3b3965a..26f29a3524b00 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -1065,14 +1065,15 @@ fn render_assoc_items_inner( let (non_trait, traits): (Vec<_>, _) = v.iter().partition(|i| i.inner_impl().trait_.is_none()); if !non_trait.is_empty() { let mut tmp_buf = Buffer::empty_from(w); - let render_mode = match what { + let (render_mode, id) = match what { AssocItemRender::All => { tmp_buf.write_str( "

\ - Implementations\ -

", + Implementations\ + \ + ", ); - RenderMode::Normal + (RenderMode::Normal, "implementations-list".to_owned()) } AssocItemRender::DerefFor { trait_, type_, deref_mut_ } => { let id = @@ -1090,7 +1091,7 @@ fn render_assoc_items_inner( trait_ = trait_.print(cx), type_ = type_.print(cx), ); - RenderMode::ForDeref { mut_: deref_mut_ } + (RenderMode::ForDeref { mut_: deref_mut_ }, cx.derive_id(id)) } }; let mut impls_buf = Buffer::empty_from(w); @@ -1115,7 +1116,9 @@ fn render_assoc_items_inner( } if !impls_buf.is_empty() { w.push_buffer(tmp_buf); + write!(w, "
", id); w.push_buffer(impls_buf); + w.write_str("
"); } } @@ -1146,7 +1149,8 @@ fn render_assoc_items_inner( write!( w, "

\ - Trait Implementations\ + Trait Implementations\ + \

\
{}
", impls diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js index 8e1919f75d671..90592335d5ddf 100644 --- a/src/librustdoc/html/static/js/main.js +++ b/src/librustdoc/html/static/js/main.js @@ -741,7 +741,7 @@ function hideThemeButtonState() { } else { addClass(innerToggle, "will-expand"); onEachLazy(document.getElementsByClassName("rustdoc-toggle"), function(e) { - if (e.parentNode.id !== MAIN_ID || + if (e.parentNode.id !== "implementations-list" || (!hasClass(e, "implementors-toggle") && !hasClass(e, "type-contents-toggle"))) { diff --git a/src/test/rustdoc/duplicate_impls/issue-33054.rs b/src/test/rustdoc/duplicate_impls/issue-33054.rs index b018dd6cda58a..3f9a476d96e23 100644 --- a/src/test/rustdoc/duplicate_impls/issue-33054.rs +++ b/src/test/rustdoc/duplicate_impls/issue-33054.rs @@ -2,7 +2,7 @@ // @has - '//h3[@class="code-header in-band"]' 'impl Foo' // @has - '//h3[@class="code-header in-band"]' 'impl Bar for Foo' // @count - '//*[@id="trait-implementations-list"]//*[@class="impl has-srclink"]' 1 -// @count - '//*[@id="main-content"]/details/summary/*[@class="impl has-srclink"]' 1 +// @count - '//*[@id="main-content"]/div[@id="implementations-list"]/details/summary/*[@class="impl has-srclink"]' 1 // @has issue_33054/impls/bar/trait.Bar.html // @has - '//h3[@class="code-header in-band"]' 'impl Bar for Foo' // @count - '//*[@class="struct"]' 1 From fbd9c284d7f018db07da8aa6e03cffdf0ce1786b Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 8 Mar 2022 18:11:29 +0100 Subject: [PATCH 07/11] Update GUI tests for impl blocks path changes --- src/test/rustdoc-gui/docblock-table-overflow.goml | 8 ++++---- src/test/rustdoc-gui/hash-item-expansion.goml | 4 ++-- src/test/rustdoc-gui/impl-default-expansion.goml | 2 +- src/test/rustdoc-gui/toggle-docs-mobile.goml | 2 +- src/test/rustdoc-gui/toggle-docs.goml | 2 +- src/test/rustdoc/duplicate_impls/issue-33054.rs | 2 ++ 6 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/test/rustdoc-gui/docblock-table-overflow.goml b/src/test/rustdoc-gui/docblock-table-overflow.goml index a9af88189a67d..af76d2ea42760 100644 --- a/src/test/rustdoc-gui/docblock-table-overflow.goml +++ b/src/test/rustdoc-gui/docblock-table-overflow.goml @@ -12,10 +12,10 @@ assert-property: (".top-doc .docblock table", {"scrollWidth": "1573"}) // Logically, the ".docblock" and the "

" should have the same scroll width. compare-elements-property: ( - "#implementations + details .docblock", - "#implementations + details .docblock > p", + "#implementations-list > details .docblock", + "#implementations-list > details .docblock > p", ["scrollWidth"], ) -assert-property: ("#implementations + details .docblock", {"scrollWidth": "801"}) +assert-property: ("#implementations-list > details .docblock", {"scrollWidth": "801"}) // However, since there is overflow in the , its scroll width is bigger. -assert-property: ("#implementations + details .docblock table", {"scrollWidth": "1573"}) +assert-property: ("#implementations-list > details .docblock table", {"scrollWidth": "1573"}) diff --git a/src/test/rustdoc-gui/hash-item-expansion.goml b/src/test/rustdoc-gui/hash-item-expansion.goml index a680635ef8ae4..861f6928362c2 100644 --- a/src/test/rustdoc-gui/hash-item-expansion.goml +++ b/src/test/rustdoc-gui/hash-item-expansion.goml @@ -3,9 +3,9 @@ goto: file://|DOC_PATH|/test_docs/struct.Foo.html#method.borrow // In the blanket implementations list, "Borrow" is the second one, hence the ":nth(2)". assert-attribute: ("#blanket-implementations-list > details:nth-child(2)", {"open": ""}) // We first check that the impl block is open by default. -assert-attribute: ("#implementations + details", {"open": ""}) +assert-attribute: ("#implementations-list details", {"open": ""}) // To ensure that we will click on the currently hidden method. assert-text: (".sidebar-elems section .block li > a", "must_use") click: ".sidebar-elems section .block li > a" // We check that the impl block was opened as expected so that we can see the method. -assert-attribute: ("#implementations + details", {"open": ""}) +assert-attribute: ("#implementations-list > details", {"open": ""}) diff --git a/src/test/rustdoc-gui/impl-default-expansion.goml b/src/test/rustdoc-gui/impl-default-expansion.goml index 7c4496dc0cabc..6df2661e6c2bb 100644 --- a/src/test/rustdoc-gui/impl-default-expansion.goml +++ b/src/test/rustdoc-gui/impl-default-expansion.goml @@ -1,3 +1,3 @@ // This test ensures that the impl blocks are open by default. goto: file://|DOC_PATH|/test_docs/struct.Foo.html -assert-attribute: ("#main-content > details.implementors-toggle", {"open": ""}) +assert-attribute: ("#implementations-list details.implementors-toggle", {"open": ""}) diff --git a/src/test/rustdoc-gui/toggle-docs-mobile.goml b/src/test/rustdoc-gui/toggle-docs-mobile.goml index b502692300113..ee6bc3cf7675c 100644 --- a/src/test/rustdoc-gui/toggle-docs-mobile.goml +++ b/src/test/rustdoc-gui/toggle-docs-mobile.goml @@ -14,7 +14,7 @@ assert-attribute: (".top-doc", {"open": ""}) // Assert the position of the toggle on the top doc block. assert-position: (".top-doc summary::before", {"x": 4}) // Assert the position of the toggle on the impl block. -assert-position: ("#implementations + details > summary::before", {"x": 4}) +assert-position: ("#implementations-list > details > summary::before", {"x": 4}) // Assert the position of the toggle on a method. assert-position: ( "#trait-implementations-list .impl-items .method-toggle > summary::before", diff --git a/src/test/rustdoc-gui/toggle-docs.goml b/src/test/rustdoc-gui/toggle-docs.goml index 477105193d3ee..f98111484f315 100644 --- a/src/test/rustdoc-gui/toggle-docs.goml +++ b/src/test/rustdoc-gui/toggle-docs.goml @@ -24,7 +24,7 @@ wait-for: 50 assert-text: ("#toggle-all-docs", "[+]") // We check that all
are collapsed (except for the impl block ones). assert-attribute-false: ("details.rustdoc-toggle:not(.implementors-toggle)", {"open": ""}, ALL) -assert-attribute: ("details.rustdoc-toggle.implementors-toggle", {"open": ""}) +assert-attribute: ("#implementations-list > details.implementors-toggle", {"open": ""}) // We now check that the other impl blocks are collapsed. assert-attribute-false: ( "#blanket-implementations-list > details.rustdoc-toggle.implementors-toggle", diff --git a/src/test/rustdoc/duplicate_impls/issue-33054.rs b/src/test/rustdoc/duplicate_impls/issue-33054.rs index 3f9a476d96e23..84c9e4ac0cd84 100644 --- a/src/test/rustdoc/duplicate_impls/issue-33054.rs +++ b/src/test/rustdoc/duplicate_impls/issue-33054.rs @@ -1,3 +1,5 @@ +// ignore-tidy-linelength + // @has issue_33054/impls/struct.Foo.html // @has - '//h3[@class="code-header in-band"]' 'impl Foo' // @has - '//h3[@class="code-header in-band"]' 'impl Bar for Foo' From 4e067e80ebb60022d6446335b0721feed73483b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20BRANSTETT?= Date: Tue, 8 Mar 2022 23:11:37 +0100 Subject: [PATCH 08/11] Improve rustdoc book --- src/doc/rustdoc/book.toml | 4 ++ src/doc/rustdoc/src/SUMMARY.md | 15 +++--- src/doc/rustdoc/src/advanced-features.md | 22 ++++++++ src/doc/rustdoc/src/command-line-arguments.md | 30 ++--------- .../src/{passes.md => deprecated-features.md} | 4 +- src/doc/rustdoc/src/how-to-read-rustdoc.md | 4 +- src/doc/rustdoc/src/lints.md | 24 ++++----- src/doc/rustdoc/src/unstable-features.md | 51 +++++++++++++++++-- src/doc/rustdoc/src/website-features.md | 25 --------- .../documentation-tests.md | 2 +- .../linking-to-items-by-name.md | 2 +- .../the-doc-attribute.md | 4 +- .../what-to-include.md | 2 +- 13 files changed, 106 insertions(+), 83 deletions(-) rename src/doc/rustdoc/src/{passes.md => deprecated-features.md} (94%) delete mode 100644 src/doc/rustdoc/src/website-features.md rename src/doc/rustdoc/src/{ => write-documentation}/documentation-tests.md (99%) rename src/doc/rustdoc/src/{ => write-documentation}/linking-to-items-by-name.md (98%) rename src/doc/rustdoc/src/{ => write-documentation}/the-doc-attribute.md (98%) rename src/doc/rustdoc/src/{ => write-documentation}/what-to-include.md (99%) diff --git a/src/doc/rustdoc/book.toml b/src/doc/rustdoc/book.toml index 97e08416d7686..45405a11765cc 100644 --- a/src/doc/rustdoc/book.toml +++ b/src/doc/rustdoc/book.toml @@ -4,3 +4,7 @@ title = "The rustdoc book" [output.html] git-repository-url = "https://github.com/rust-lang/rust/tree/master/src/doc/rustdoc" + +[output.html.redirect] +"/the-doc-attribute.html" = "write-documentation/the-doc-attribute.html" +"/documentation-tests.html" = "write-documentation/documentation-tests.html" diff --git a/src/doc/rustdoc/src/SUMMARY.md b/src/doc/rustdoc/src/SUMMARY.md index eb18185945387..d627f5b0389f3 100644 --- a/src/doc/rustdoc/src/SUMMARY.md +++ b/src/doc/rustdoc/src/SUMMARY.md @@ -1,16 +1,15 @@ # The Rustdoc Book - [What is rustdoc?](what-is-rustdoc.md) +- [Command-line arguments](command-line-arguments.md) - [How to read rustdoc output](how-to-read-rustdoc.md) - [How to write documentation](how-to-write-documentation.md) -- [What to include (and exclude)](what-to-include.md) -- [Command-line arguments](command-line-arguments.md) -- [The `#[doc]` attribute](the-doc-attribute.md) -- [Documentation tests](documentation-tests.md) -- [Linking to items by name](linking-to-items-by-name.md) -- [Lints](lints.md) + - [What to include (and exclude)](write-documentation/what-to-include.md) + - [The `#[doc]` attribute](write-documentation/the-doc-attribute.md) + - [Linking to items by name](write-documentation/linking-to-items-by-name.md) + - [Documentation tests](write-documentation/documentation-tests.md) +- [Rustdoc-specific lints](lints.md) - [Advanced features](advanced-features.md) - [Unstable features](unstable-features.md) -- [Website features](website-features.md) -- [Passes](passes.md) +- [Deprecated features](deprecated-features.md) - [References](references.md) diff --git a/src/doc/rustdoc/src/advanced-features.md b/src/doc/rustdoc/src/advanced-features.md index 6147bd0a97a96..dbf0baec04c03 100644 --- a/src/doc/rustdoc/src/advanced-features.md +++ b/src/doc/rustdoc/src/advanced-features.md @@ -88,3 +88,25 @@ You can add multiple aliases at the same time by using a list: #[doc(alias("x", "big"))] pub struct BigX; ``` + +## Custom search engines + +If you find yourself often referencing online Rust docs you might enjoy using a custom search +engine. This allows you to use the navigation bar directly to search a `rustdoc` website. +Most browsers support this feature by letting you define a URL template containing `%s` +which will be substituted for the search term. As an example, for the standard library you could use +this template: + +```text +https://doc.rust-lang.org/stable/std/?search=%s +``` + +Note that this will take you to a results page listing all matches. If you want to navigate to the first +result right away (which is often the best match) use the following instead: + +```text +https://doc.rust-lang.org/stable/std/?search=%s&go_to_first=true +``` + +This URL adds the `go_to_first=true` query parameter which can be appended to any `rustdoc` search URL +to automatically go to the first result. diff --git a/src/doc/rustdoc/src/command-line-arguments.md b/src/doc/rustdoc/src/command-line-arguments.md index 3ce57f88938f7..2a2e51b2f6331 100644 --- a/src/doc/rustdoc/src/command-line-arguments.md +++ b/src/doc/rustdoc/src/command-line-arguments.md @@ -177,7 +177,7 @@ $ rustdoc src/lib.rs --test ``` This flag will run your code examples as tests. For more, see [the chapter -on documentation tests](documentation-tests.md). +on documentation tests](write-documentation/documentation-tests.md). See also `--test-args`. @@ -190,7 +190,7 @@ $ rustdoc src/lib.rs --test --test-args ignored ``` This flag will pass options to the test runner when running documentation tests. -For more, see [the chapter on documentation tests](documentation-tests.md). +For more, see [the chapter on documentation tests](write-documentation/documentation-tests.md). See also `--test`. @@ -336,7 +336,7 @@ $ rustdoc src/lib.rs --sysroot /path/to/sysroot Similar to `rustc --sysroot`, this lets you change the sysroot `rustdoc` uses when compiling your code. -### `--edition`: control the edition of docs and doctests +## `--edition`: control the edition of docs and doctests Using this flag looks like this: @@ -403,12 +403,12 @@ encoded as UTF-8. ## `--passes`: add more rustdoc passes This flag is **deprecated**. -For more details on passes, see [the chapter on them](passes.md). +For more details on passes, see [the chapter on them](deprecated-features.md#passes). ## `--no-defaults`: don't run default passes This flag is **deprecated**. -For more details on passes, see [the chapter on them](passes.md). +For more details on passes, see [the chapter on them](deprecated-features.md#passes). ## `-r`/`--input-format`: input format @@ -417,23 +417,3 @@ This flag is **deprecated** and **has no effect**. Rustdoc only supports Rust source code and Markdown input formats. If the file ends in `.md` or `.markdown`, `rustdoc` treats it as a Markdown file. Otherwise, it assumes that the input file is Rust. - -# Unstable command line arguments - -## `--nocapture` - -When this flag is used with `--test`, the output (stdout and stderr) of your tests won't be -captured by rustdoc. Instead, the output will be directed to your terminal, -as if you had run the test executable manually. This is especially useful -for debugging your tests! - -## `--check` - -When this flag is supplied, rustdoc will type check and lint your code, but will not generate any -documentation or run your doctests. - -Using this flag looks like: - -```bash -rustdoc -Z unstable-options --check src/lib.rs -``` diff --git a/src/doc/rustdoc/src/passes.md b/src/doc/rustdoc/src/deprecated-features.md similarity index 94% rename from src/doc/rustdoc/src/passes.md rename to src/doc/rustdoc/src/deprecated-features.md index c3c3fd3068ec4..2bc6e8fc8ae4d 100644 --- a/src/doc/rustdoc/src/passes.md +++ b/src/doc/rustdoc/src/deprecated-features.md @@ -1,4 +1,6 @@ -# Passes +# Deprecated features + +## Passes Rustdoc has a concept called "passes". These are transformations that `rustdoc` runs on your documentation before producing its final output. diff --git a/src/doc/rustdoc/src/how-to-read-rustdoc.md b/src/doc/rustdoc/src/how-to-read-rustdoc.md index 99724d859ee75..098bc1879b56f 100644 --- a/src/doc/rustdoc/src/how-to-read-rustdoc.md +++ b/src/doc/rustdoc/src/how-to-read-rustdoc.md @@ -26,7 +26,7 @@ At the top is some at-a-glance info and controls: - a button to collapse or expand the top-level documentation for that item (`[+]` or `[-]`), - a link to the source code (`[src]`), - if [configured](the-doc-attribute.html#html_no_source), + if [configured](write-documentation/the-doc-attribute.html#html_no_source), and present (the source may not be available if the documentation was created with `cargo doc --no-deps`), - and the version in which the item became stable, @@ -52,7 +52,7 @@ For example, when looking at documentation for the crate root, it shows all the crates documented in the documentation bundle, and quick links to the modules, structs, traits, functions, and macros available from the current crate. -At the top, it displays a [configurable logo](the-doc-attribute.html#html_logo_url) +At the top, it displays a [configurable logo](write-documentation/the-doc-attribute.html#html_logo_url) alongside the current crate's name and version, or the current item whose documentation is being displayed. diff --git a/src/doc/rustdoc/src/lints.md b/src/doc/rustdoc/src/lints.md index 1773c15464a94..bff01d7cb7c14 100644 --- a/src/doc/rustdoc/src/lints.md +++ b/src/doc/rustdoc/src/lints.md @@ -13,11 +13,11 @@ Note that, except for `missing_docs`, these lints are only available when runnin Here is the list of the lints provided by `rustdoc`: -## broken_intra_doc_links +## `broken_intra_doc_links` This lint **warns by default**. This lint detects when an [intra-doc link] fails to be resolved. For example: -[intra-doc link]: linking-to-items-by-name.md +[intra-doc link]: write-documentation/linking-to-items-by-name.md ```rust /// I want to link to [`Nonexistent`] but it doesn't exist! @@ -64,7 +64,7 @@ help: to link to the function, add parentheses ``` -## private_intra_doc_links +## `private_intra_doc_links` This lint **warns by default**. This lint detects when [intra-doc links] from public to private items. For example: @@ -104,9 +104,9 @@ warning: public documentation for `public` links to private item `private` = note: this link resolves only because you passed `--document-private-items`, but will break without ``` -[intra-doc links]: linking-to-items-by-name.html +[intra-doc links]: write-documentation/linking-to-items-by-name.md -## missing_docs +## `missing_docs` This lint is **allowed by default**. It detects items missing documentation. For example: @@ -130,7 +130,7 @@ warning: missing documentation for a function Note that unlike other rustdoc lints, this lint is also available from `rustc` directly. -## missing_crate_level_docs +## `missing_crate_level_docs` This lint is **allowed by default**. It detects if there is no documentation at the crate root. For example: @@ -154,7 +154,7 @@ warning in the future. This is intended as a means to introduce new users on get started, without providing overwhelming warnings like `missing_docs` might. -## missing_doc_code_examples +## `missing_doc_code_examples` This lint is **allowed by default** and is **nightly-only**. It detects when a documentation block is missing a code example. For example: @@ -190,7 +190,7 @@ To fix the lint, you need to add a code example into the documentation block: pub fn no_code_example() {} ``` -## private_doc_tests +## `private_doc_tests` This lint is **allowed by default**. It detects documentation tests when they are on a private item. For example: @@ -223,7 +223,7 @@ warning: Documentation test in private item | |___________^ ``` -## invalid_codeblock_attributes +## `invalid_codeblock_attributes` This lint **warns by default**. It detects code block attributes in documentation examples that have potentially mis-typed values. For example: @@ -259,7 +259,7 @@ warning: unknown attribute `should-panic`. Did you mean `should_panic`? In the example above, the correct form is `should_panic`. This helps detect typo mistakes for some common attributes. -## invalid_html_tags +## `invalid_html_tags` This lint is **allowed by default** and is **nightly-only**. It detects unclosed or invalid HTML tags. For example: @@ -298,7 +298,7 @@ warning: unclosed HTML tag `h1` warning: 2 warnings emitted ``` -## invalid_rust_codeblocks +## `invalid_rust_codeblocks` This lint **warns by default**. It detects Rust code blocks in documentation examples that are invalid (e.g. empty, not parsable as Rust). For example: @@ -342,7 +342,7 @@ warning: could not parse code block as Rust code = note: error from rustc: unterminated character literal ``` -## bare_urls +## `bare_urls` This lint is **warn-by-default**. It detects URLs which are not links. For example: diff --git a/src/doc/rustdoc/src/unstable-features.md b/src/doc/rustdoc/src/unstable-features.md index 141d5d2d2b2d0..537ab48bbfc12 100644 --- a/src/doc/rustdoc/src/unstable-features.md +++ b/src/doc/rustdoc/src/unstable-features.md @@ -22,7 +22,7 @@ As detailed in [the chapter on documentation tests][doctest-attributes], you can nightly, you can optionally add an error number to state that a doctest should emit a specific error number: -[doctest-attributes]: documentation-tests.html#attributes +[doctest-attributes]: write-documentation/documentation-tests.html#attributes ``````markdown ```compile_fail,E0044 @@ -45,6 +45,8 @@ and enabled with a `#![feature(...)]` attribute in your crate. ### `#[doc(cfg)]`: Recording what platforms or features are required for code to be present + * Tracking issue: [#43781](https://github.com/rust-lang/rust/issues/43781) + You can use `#[doc(cfg(...))]` to tell Rustdoc exactly which platform items appear on. This has two effects: @@ -86,6 +88,8 @@ Book][unstable-doc-cfg] and [its tracking issue][issue-doc-cfg]. ### `doc_auto_cfg`: Automatically generate `#[doc(cfg)]` + * Tracking issue: [#43781](https://github.com/rust-lang/rust/issues/43781) + `doc_auto_cfg` is an extension to the `#[doc(cfg)]` feature. With it, you don't need to add `#[doc(cfg(...)]` anymore unless you want to override the default behaviour. So if we take the previous source code: @@ -123,6 +127,8 @@ And `doc` won't show up anymore! ### Adding your trait to the "Notable traits" dialog + * Tracking issue: [#45040](https://github.com/rust-lang/rust/issues/45040) + Rustdoc keeps a list of a few traits that are believed to be "fundamental" to types that implement them. These traits are intended to be the primary interface for their implementers, and are often most of the API available to be documented @@ -146,6 +152,8 @@ and [its tracking issue][issue-notable_trait]. ### Exclude certain dependencies from documentation + * Tracking issue: [#44027](https://github.com/rust-lang/rust/issues/44027) + The standard library uses several dependencies which, in turn, use several types and traits from the standard library. In addition, there are several compiler-internal crates that are not considered to be part of the official standard library, and thus would be a distraction to include in @@ -164,8 +172,7 @@ Book][unstable-masked] and [its tracking issue][issue-masked]. [unstable-masked]: ../unstable-book/language-features/doc-masked.html [issue-masked]: https://github.com/rust-lang/rust/issues/44027 - -## Document primitives +### Document primitives This is for Rust compiler internal use only. @@ -174,7 +181,7 @@ attributes. The `#[doc(primitive)]` attribute is used by the standard library to to generate documentation for primitive types, and requires `#![feature(rustdoc_internals)]` to enable. -## Document keywords +### Document keywords This is for Rust compiler internal use only. @@ -199,6 +206,8 @@ the flag in question to Rustdoc on the command-line. To do this from Cargo, you ### `--markdown-before-content`: include rendered Markdown before the content + * Tracking issue: [#44027](https://github.com/rust-lang/rust/issues/44027) + Using this flag looks like this: ```bash @@ -241,7 +250,7 @@ attribute][doc-playground]. Please be aware that the official Rust Playground at https://play.rust-lang.org does not have every crate available, so if your examples require your crate, make sure the playground you provide has your crate available. -[doc-playground]: the-doc-attribute.html#html_playground_url +[doc-playground]: write-documentation/the-doc-attribute.html#html_playground_url If both `--playground-url` and `--markdown-playground-url` are present when rendering a standalone Markdown file, the URL given to `--markdown-playground-url` will take precedence. If both @@ -279,6 +288,8 @@ between compilations. ### `--resource-suffix`: modifying the name of CSS/JavaScript in crate docs + * Tracking issue: [#54765](https://github.com/rust-lang/rust/issues/54765) + Using this flag looks like this: ```bash @@ -331,6 +342,24 @@ Using `index-page` option enables `enable-index-page` option as well. This feature allows the generation of a default index-page which lists the generated crates. +### `--nocapture`: disable output capture for test + +When this flag is used with `--test`, the output (stdout and stderr) of your tests won't be +captured by rustdoc. Instead, the output will be directed to your terminal, +as if you had run the test executable manually. This is especially useful +for debugging your tests! + +### `--check`: only checks the documentation + +When this flag is supplied, rustdoc will type check and lint your code, but will not generate any +documentation or run your doctests. + +Using this flag looks like: + +```bash +rustdoc -Z unstable-options --check src/lib.rs +``` + ### `--static-root-path`: control how static files are loaded in HTML output Using this flag looks like this: @@ -348,6 +377,8 @@ renamed with `--resource-suffix` will load from the given path. ### `--persist-doctests`: persist doctest executables after running + * Tracking issue: [#56925](https://github.com/rust-lang/rust/issues/56925) + Using this flag looks like this: ```bash @@ -360,6 +391,8 @@ with this option, you can keep those binaries around for farther testing. ### `--show-coverage`: calculate the percentage of items with documentation + * Tracking issue: [#58154](https://github.com/rust-lang/rust/issues/58154) + Using this flag looks like this: ```bash @@ -438,6 +471,8 @@ information. ### `--enable-per-target-ignores`: allow `ignore-foo` style filters for doctests + * Tracking issue: [#64245](https://github.com/rust-lang/rust/issues/64245) + Using this flag looks like this: ```bash @@ -471,6 +506,8 @@ override `ignore`. ### `--runtool`, `--runtool-arg`: program to run tests with; args to pass to it + * Tracking issue: [#64245](https://github.com/rust-lang/rust/issues/64245) + Using these options looks like this: ```bash @@ -488,6 +525,8 @@ Another use case would be to run a test inside an emulator, or through a Virtual ### `--with-examples`: include examples of uses of items as documentation + * Tracking issue: [#88791](https://github.com/rust-lang/rust/issues/88791) + This option, combined with `--scrape-examples-target-crate` and `--scrape-examples-output-path`, is used to implement the functionality in [RFC #3123](https://github.com/rust-lang/rfcs/pull/3123). Uses of an item (currently @@ -515,6 +554,8 @@ add the `--scrape-tests` flag. ### `--check-cfg`: check configuration flags + * Tracking issue: [#82450](https://github.com/rust-lang/rust/issues/82450) + This flag accepts the same values as `rustc --check-cfg`, and uses it to check configuration flags. Using this flag looks like this: diff --git a/src/doc/rustdoc/src/website-features.md b/src/doc/rustdoc/src/website-features.md deleted file mode 100644 index 5fade4e84a992..0000000000000 --- a/src/doc/rustdoc/src/website-features.md +++ /dev/null @@ -1,25 +0,0 @@ -# Website features - -These features are about using the website generated by `rustdoc`. - -## Custom search engines - -If you find yourself often referencing online Rust docs you might enjoy using a custom search -engine. This allows you to use the navigation bar directly to search a `rustdoc` website. -Most browsers support this feature by letting you define a URL template containing `%s` -which will be substituted for the search term. As an example, for the standard library you could use -this template: - -```text -https://doc.rust-lang.org/stable/std/?search=%s -``` - -Note that this will take you to a results page listing all matches. If you want to navigate to the first -result right away (which is often the best match) use the following instead: - -```text -https://doc.rust-lang.org/stable/std/?search=%s&go_to_first=true -``` - -This URL adds the `go_to_first=true` query parameter which can be appended to any `rustdoc` search URL -to automatically go to the first result. diff --git a/src/doc/rustdoc/src/documentation-tests.md b/src/doc/rustdoc/src/write-documentation/documentation-tests.md similarity index 99% rename from src/doc/rustdoc/src/documentation-tests.md rename to src/doc/rustdoc/src/write-documentation/documentation-tests.md index 534fd19b52eb2..1cb5b049df404 100644 --- a/src/doc/rustdoc/src/documentation-tests.md +++ b/src/doc/rustdoc/src/write-documentation/documentation-tests.md @@ -269,7 +269,7 @@ By default, this will still hide `unused` warnings, since so many examples use p you can add `#![warn(unused)]` to the top of your example if you want to see unused variables or dead code warnings. You can also use [`#![doc(test(attr(warn(unused))))]`][test-attr] in the crate root to enable warnings globally. -[test-attr]: ./the-doc-attribute.md#testattr +[test-attr]: the-doc-attribute.md#testattr ## Documenting macros diff --git a/src/doc/rustdoc/src/linking-to-items-by-name.md b/src/doc/rustdoc/src/write-documentation/linking-to-items-by-name.md similarity index 98% rename from src/doc/rustdoc/src/linking-to-items-by-name.md rename to src/doc/rustdoc/src/write-documentation/linking-to-items-by-name.md index 6ca1d1153b494..36bc312b9c99a 100644 --- a/src/doc/rustdoc/src/linking-to-items-by-name.md +++ b/src/doc/rustdoc/src/write-documentation/linking-to-items-by-name.md @@ -35,7 +35,7 @@ link to `Option`. You can refer to anything in scope, and use paths, including `Self`, `self`, `super`, and `crate`. Associated items (functions, types, and constants) are supported, but [not for blanket trait implementations][#79682]. Rustdoc also supports linking to all primitives listed in -[the standard library documentation](../std/index.html#primitives). +[the standard library documentation](../../std/index.html#primitives). [#79682]: https://github.com/rust-lang/rust/pull/79682 diff --git a/src/doc/rustdoc/src/the-doc-attribute.md b/src/doc/rustdoc/src/write-documentation/the-doc-attribute.md similarity index 98% rename from src/doc/rustdoc/src/the-doc-attribute.md rename to src/doc/rustdoc/src/write-documentation/the-doc-attribute.md index c5cc84022e389..25ef8b5bb9141 100644 --- a/src/doc/rustdoc/src/the-doc-attribute.md +++ b/src/doc/rustdoc/src/write-documentation/the-doc-attribute.md @@ -38,7 +38,7 @@ but given that docs are rendered via Markdown, it will remove these newlines. Another use case is for including external files as documentation: ```rust,no_run -#[doc = include_str!("../README.md")] +#[doc = include_str!("../../README.md")] # fn f() {} ``` @@ -73,7 +73,7 @@ left hand side of the docs. #![doc(html_logo_url = "https://example.com/logo.jpg")] ``` -This will put `logo` into +This will put `logo` into your docs, where the string for the attribute goes into the `{}`. If you don't use this attribute, there will be no logo. diff --git a/src/doc/rustdoc/src/what-to-include.md b/src/doc/rustdoc/src/write-documentation/what-to-include.md similarity index 99% rename from src/doc/rustdoc/src/what-to-include.md rename to src/doc/rustdoc/src/write-documentation/what-to-include.md index 2a6b62ebfd552..35e6ccbc38807 100644 --- a/src/doc/rustdoc/src/what-to-include.md +++ b/src/doc/rustdoc/src/write-documentation/what-to-include.md @@ -122,4 +122,4 @@ Here is an example of a new theme, [Ayu]. [API Guidelines]: https://rust-lang.github.io/api-guidelines/documentation.html#rustdoc-does-not-show-unhelpful-implementation-details-c-hidden [Documentation tests]: documentation-tests.md [on this blog]: https://blog.guillaume-gomez.fr/articles/2016-09-16+Generating+doc+with+rustdoc+and+a+custom+theme -[rustdoc-lints]: lints.md +[rustdoc-lints]: ../lints.md From e346920907d1dec22d2dcc19b0dc483b9a94810b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20BRANSTETT?= Date: Wed, 9 Mar 2022 11:18:28 +0100 Subject: [PATCH 09/11] Also take in account mdbook redirect in linkchecker --- src/tools/linkchecker/main.rs | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/src/tools/linkchecker/main.rs b/src/tools/linkchecker/main.rs index 46daaf42883f0..c9b1649200d9c 100644 --- a/src/tools/linkchecker/main.rs +++ b/src/tools/linkchecker/main.rs @@ -489,16 +489,22 @@ fn is_exception(file: &Path, link: &str) -> bool { /// If the given HTML file contents is an HTML redirect, this returns the /// destination path given in the redirect. fn maybe_redirect(source: &str) -> Option { - const REDIRECT: &str = "

Redirecting to Redirecting to Redirecting to... (source: &str, attr: &str, mut f: F) { From e54d4ab189517efa1ef132b12443fc52de3faa8c Mon Sep 17 00:00:00 2001 From: JmPotato Date: Tue, 1 Mar 2022 13:23:30 +0800 Subject: [PATCH 10/11] Use MaybeUninit in VecDeque to remove the undefined behavior of slice Signed-off-by: JmPotato --- .../alloc/src/collections/vec_deque/iter.rs | 59 +++++++++++++------ .../alloc/src/collections/vec_deque/mod.rs | 56 ++++++++++++++---- 2 files changed, 86 insertions(+), 29 deletions(-) diff --git a/library/alloc/src/collections/vec_deque/iter.rs b/library/alloc/src/collections/vec_deque/iter.rs index edadd666edce6..253fa0b561e95 100644 --- a/library/alloc/src/collections/vec_deque/iter.rs +++ b/library/alloc/src/collections/vec_deque/iter.rs @@ -1,5 +1,6 @@ use core::fmt; use core::iter::{FusedIterator, TrustedLen, TrustedRandomAccess, TrustedRandomAccessNoCoerce}; +use core::mem::MaybeUninit; use core::ops::Try; use super::{count, wrap_index, RingSlices}; @@ -12,7 +13,7 @@ use super::{count, wrap_index, RingSlices}; /// [`iter`]: super::VecDeque::iter #[stable(feature = "rust1", since = "1.0.0")] pub struct Iter<'a, T: 'a> { - pub(crate) ring: &'a [T], + pub(crate) ring: &'a [MaybeUninit], pub(crate) tail: usize, pub(crate) head: usize, } @@ -44,7 +45,10 @@ impl<'a, T> Iterator for Iter<'a, T> { } let tail = self.tail; self.tail = wrap_index(self.tail.wrapping_add(1), self.ring.len()); - unsafe { Some(self.ring.get_unchecked(tail)) } + // Safety: + // - `self.tail` in a ring buffer is always a valid index. + // - `self.head` and `self.tail` equality is checked above. + unsafe { Some(self.ring.get_unchecked(tail).assume_init_ref()) } } #[inline] @@ -58,8 +62,13 @@ impl<'a, T> Iterator for Iter<'a, T> { F: FnMut(Acc, Self::Item) -> Acc, { let (front, back) = RingSlices::ring_slices(self.ring, self.head, self.tail); - accum = front.iter().fold(accum, &mut f); - back.iter().fold(accum, &mut f) + // Safety: + // - `self.head` and `self.tail` in a ring buffer are always valid indices. + // - `RingSlices::ring_slices` guarantees that the slices split according to `self.head` and `self.tail` are initialized. + unsafe { + accum = MaybeUninit::slice_assume_init_ref(front).iter().fold(accum, &mut f); + MaybeUninit::slice_assume_init_ref(back).iter().fold(accum, &mut f) + } } fn try_fold(&mut self, init: B, mut f: F) -> R @@ -70,17 +79,19 @@ impl<'a, T> Iterator for Iter<'a, T> { { let (mut iter, final_res); if self.tail <= self.head { - // single slice self.ring[self.tail..self.head] - iter = self.ring[self.tail..self.head].iter(); + // Safety: single slice self.ring[self.tail..self.head] is initialized. + iter = unsafe { MaybeUninit::slice_assume_init_ref(&self.ring[self.tail..self.head]) } + .iter(); final_res = iter.try_fold(init, &mut f); } else { - // two slices: self.ring[self.tail..], self.ring[..self.head] + // Safety: two slices: self.ring[self.tail..], self.ring[..self.head] both are initialized. let (front, back) = self.ring.split_at(self.tail); - let mut back_iter = back.iter(); + + let mut back_iter = unsafe { MaybeUninit::slice_assume_init_ref(back).iter() }; let res = back_iter.try_fold(init, &mut f); let len = self.ring.len(); self.tail = (self.ring.len() - back_iter.len()) & (len - 1); - iter = front[..self.head].iter(); + iter = unsafe { MaybeUninit::slice_assume_init_ref(&front[..self.head]).iter() }; final_res = iter.try_fold(res?, &mut f); } self.tail = self.head - iter.len(); @@ -109,7 +120,7 @@ impl<'a, T> Iterator for Iter<'a, T> { // that is in bounds. unsafe { let idx = wrap_index(self.tail.wrapping_add(idx), self.ring.len()); - self.ring.get_unchecked(idx) + self.ring.get_unchecked(idx).assume_init_ref() } } } @@ -122,7 +133,10 @@ impl<'a, T> DoubleEndedIterator for Iter<'a, T> { return None; } self.head = wrap_index(self.head.wrapping_sub(1), self.ring.len()); - unsafe { Some(self.ring.get_unchecked(self.head)) } + // Safety: + // - `self.head` in a ring buffer is always a valid index. + // - `self.head` and `self.tail` equality is checked above. + unsafe { Some(self.ring.get_unchecked(self.head).assume_init_ref()) } } fn rfold(self, mut accum: Acc, mut f: F) -> Acc @@ -130,8 +144,13 @@ impl<'a, T> DoubleEndedIterator for Iter<'a, T> { F: FnMut(Acc, Self::Item) -> Acc, { let (front, back) = RingSlices::ring_slices(self.ring, self.head, self.tail); - accum = back.iter().rfold(accum, &mut f); - front.iter().rfold(accum, &mut f) + // Safety: + // - `self.head` and `self.tail` in a ring buffer are always valid indices. + // - `RingSlices::ring_slices` guarantees that the slices split according to `self.head` and `self.tail` are initialized. + unsafe { + accum = MaybeUninit::slice_assume_init_ref(back).iter().rfold(accum, &mut f); + MaybeUninit::slice_assume_init_ref(front).iter().rfold(accum, &mut f) + } } fn try_rfold(&mut self, init: B, mut f: F) -> R @@ -142,16 +161,20 @@ impl<'a, T> DoubleEndedIterator for Iter<'a, T> { { let (mut iter, final_res); if self.tail <= self.head { - // single slice self.ring[self.tail..self.head] - iter = self.ring[self.tail..self.head].iter(); + // Safety: single slice self.ring[self.tail..self.head] is initialized. + iter = unsafe { + MaybeUninit::slice_assume_init_ref(&self.ring[self.tail..self.head]).iter() + }; final_res = iter.try_rfold(init, &mut f); } else { - // two slices: self.ring[self.tail..], self.ring[..self.head] + // Safety: two slices: self.ring[self.tail..], self.ring[..self.head] both are initialized. let (front, back) = self.ring.split_at(self.tail); - let mut front_iter = front[..self.head].iter(); + + let mut front_iter = + unsafe { MaybeUninit::slice_assume_init_ref(&front[..self.head]).iter() }; let res = front_iter.try_rfold(init, &mut f); self.head = front_iter.len(); - iter = back.iter(); + iter = unsafe { MaybeUninit::slice_assume_init_ref(back).iter() }; final_res = iter.try_rfold(res?, &mut f); } self.head = self.tail + iter.len(); diff --git a/library/alloc/src/collections/vec_deque/mod.rs b/library/alloc/src/collections/vec_deque/mod.rs index 7139a0fb94d76..f27cd684067f9 100644 --- a/library/alloc/src/collections/vec_deque/mod.rs +++ b/library/alloc/src/collections/vec_deque/mod.rs @@ -12,7 +12,7 @@ use core::fmt; use core::hash::{Hash, Hasher}; use core::iter::{repeat_with, FromIterator}; use core::marker::PhantomData; -use core::mem::{self, ManuallyDrop}; +use core::mem::{self, ManuallyDrop, MaybeUninit}; use core::ops::{Index, IndexMut, Range, RangeBounds}; use core::ptr::{self, NonNull}; use core::slice; @@ -181,16 +181,28 @@ impl VecDeque { } } - /// Turn ptr into a slice + /// Turn ptr into a slice, since the elements of the backing buffer may be uninitialized, + /// we will return a slice of [`MaybeUninit`]. + /// + /// See [`MaybeUninit::zeroed`][zeroed] for examples of correct and + /// incorrect usage of this method. + /// + /// [zeroed]: mem::MaybeUninit::zeroed #[inline] - unsafe fn buffer_as_slice(&self) -> &[T] { - unsafe { slice::from_raw_parts(self.ptr(), self.cap()) } + unsafe fn buffer_as_slice(&self) -> &[MaybeUninit] { + unsafe { slice::from_raw_parts(self.ptr() as *mut MaybeUninit, self.cap()) } } - /// Turn ptr into a mut slice + /// Turn ptr into a mut slice, since the elements of the backing buffer may be uninitialized, + /// we will return a slice of [`MaybeUninit`]. + /// + /// See [`MaybeUninit::zeroed`][zeroed] for examples of correct and + /// incorrect usage of this method. + /// + /// [zeroed]: mem::MaybeUninit::zeroed #[inline] - unsafe fn buffer_as_mut_slice(&mut self) -> &mut [T] { - unsafe { slice::from_raw_parts_mut(self.ptr(), self.cap()) } + unsafe fn buffer_as_mut_slice(&mut self) -> &mut [MaybeUninit] { + unsafe { slice::from_raw_parts_mut(self.ptr() as *mut MaybeUninit, self.cap()) } } /// Moves an element out of the buffer @@ -1055,9 +1067,13 @@ impl VecDeque { #[inline] #[stable(feature = "deque_extras_15", since = "1.5.0")] pub fn as_slices(&self) -> (&[T], &[T]) { + // Safety: + // - `self.head` and `self.tail` in a ring buffer are always valid indices. + // - `RingSlices::ring_slices` guarantees that the slices split according to `self.head` and `self.tail` are initialized. unsafe { let buf = self.buffer_as_slice(); - RingSlices::ring_slices(buf, self.head, self.tail) + let (front, back) = RingSlices::ring_slices(buf, self.head, self.tail); + (MaybeUninit::slice_assume_init_ref(front), MaybeUninit::slice_assume_init_ref(back)) } } @@ -1089,11 +1105,15 @@ impl VecDeque { #[inline] #[stable(feature = "deque_extras_15", since = "1.5.0")] pub fn as_mut_slices(&mut self) -> (&mut [T], &mut [T]) { + // Safety: + // - `self.head` and `self.tail` in a ring buffer are always valid indices. + // - `RingSlices::ring_slices` guarantees that the slices split according to `self.head` and `self.tail` are initialized. unsafe { let head = self.head; let tail = self.tail; let buf = self.buffer_as_mut_slice(); - RingSlices::ring_slices(buf, head, tail) + let (front, back) = RingSlices::ring_slices(buf, head, tail); + (MaybeUninit::slice_assume_init_mut(front), MaybeUninit::slice_assume_init_mut(back)) } } @@ -2327,7 +2347,14 @@ impl VecDeque { if self.is_contiguous() { let tail = self.tail; let head = self.head; - return unsafe { RingSlices::ring_slices(self.buffer_as_mut_slice(), head, tail).0 }; + // Safety: + // - `self.head` and `self.tail` in a ring buffer are always valid indices. + // - `RingSlices::ring_slices` guarantees that the slices split according to `self.head` and `self.tail` are initialized. + return unsafe { + MaybeUninit::slice_assume_init_mut( + RingSlices::ring_slices(self.buffer_as_mut_slice(), head, tail).0, + ) + }; } let buf = self.buf.ptr(); @@ -2413,7 +2440,14 @@ impl VecDeque { let tail = self.tail; let head = self.head; - unsafe { RingSlices::ring_slices(self.buffer_as_mut_slice(), head, tail).0 } + // Safety: + // - `self.head` and `self.tail` in a ring buffer are always valid indices. + // - `RingSlices::ring_slices` guarantees that the slices split according to `self.head` and `self.tail` are initialized. + unsafe { + MaybeUninit::slice_assume_init_mut( + RingSlices::ring_slices(self.buffer_as_mut_slice(), head, tail).0, + ) + } } /// Rotates the double-ended queue `mid` places to the left. From 4d56c1563c5ae75acbcb8c163296561a6e17e47a Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Wed, 9 Mar 2022 10:17:49 +0100 Subject: [PATCH 11/11] Add documentation about lifetimes to thread::scope. --- library/std/src/thread/scoped.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/library/std/src/thread/scoped.rs b/library/std/src/thread/scoped.rs index 4af58f1a38075..c4847b529a361 100644 --- a/library/std/src/thread/scoped.rs +++ b/library/std/src/thread/scoped.rs @@ -107,6 +107,24 @@ impl ScopeData { /// a.push(4); /// assert_eq!(x, a.len()); /// ``` +/// +/// # Lifetimes +/// +/// Scoped threads involve two lifetimes: `'scope` and `'env`. +/// +/// The `'scope` lifetime represents the lifetime of the scope itself. +/// That is: the time during which new scoped threads may be spawned, +/// and also the time during which they might still be running. +/// Once this lifetime ends, all scoped threads are joined. +/// This lifetime starts within the `scope` function, before `f` (the argument to `scope`) starts. +/// It ends after `f` returns and all scoped threads have been joined, but before `scope` returns. +/// +/// The `'env` lifetime represents the lifetime of whatever is borrowed by the scoped threads. +/// This lifetime must outlast the call to `scope`, and thus cannot be smaller than `'scope`. +/// It can be as small as the call to `scope`, meaning that anything that outlives this call, +/// such as local variables defined right before the scope, can be borrowed by the scoped threads. +/// +/// The `'env: 'scope` bound is part of the definition of the `Scope` type. #[track_caller] pub fn scope<'env, F, T>(f: F) -> T where