From ee034f4912f21291c523b4525d4ecafce8a92cfa Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 20 Jul 2024 22:28:13 +0200 Subject: [PATCH 1/9] Fix stab display in doc blocks --- src/librustdoc/html/static/css/rustdoc.css | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index 28ed94432c86e..caa9bd563b11e 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -831,6 +831,10 @@ pre, .rustdoc.src .example-wrap { background: var(--table-alt-row-background-color); } +.docblock .stab, .docblock-short .stab { + display: inline-block; +} + /* "where ..." clauses with block display are also smaller */ div.where { white-space: pre-wrap; From 3862095bd214a3ebdfb3fbaa4a13eac2ad8de331 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 20 Jul 2024 17:58:05 -0400 Subject: [PATCH 2/9] Just totally fully deny late-bound consts --- compiler/rustc_ast_passes/messages.ftl | 3 +++ compiler/rustc_ast_passes/src/errors.rs | 7 +++++++ compiler/rustc_ast_passes/src/feature_gate.rs | 16 ++++++++++++++++ .../src/collect/resolve_bound_vars.rs | 6 +----- compiler/rustc_resolve/src/late.rs | 6 +++++- tests/crashes/127009.rs | 11 ----------- tests/ui/closures/binder/const-bound.rs | 3 ++- tests/ui/closures/binder/const-bound.stderr | 8 +++++++- ...no-entry-found-for-key-ice-gce-nlb-113133.rs | 3 ++- ...ntry-found-for-key-ice-gce-nlb-113133.stderr | 8 +++++++- .../bad-suggestion-on-missing-assoc.rs | 3 ++- .../bad-suggestion-on-missing-assoc.stderr | 8 +++++++- .../binder-defaults-112547.rs | 5 +++-- .../binder-defaults-112547.stderr | 12 ++++++++++-- .../binder-defaults-119489.rs | 5 +++-- .../binder-defaults-119489.stderr | 8 +++++++- .../non_lifetime_binders/late-const-param-wf.rs | 11 +++++++++++ .../late-const-param-wf.stderr | 17 +++++++++++++++++ 18 files changed, 110 insertions(+), 30 deletions(-) delete mode 100644 tests/crashes/127009.rs create mode 100644 tests/ui/traits/non_lifetime_binders/late-const-param-wf.rs create mode 100644 tests/ui/traits/non_lifetime_binders/late-const-param-wf.stderr diff --git a/compiler/rustc_ast_passes/messages.ftl b/compiler/rustc_ast_passes/messages.ftl index 8f7dd77420709..ca0b7f2ac3a67 100644 --- a/compiler/rustc_ast_passes/messages.ftl +++ b/compiler/rustc_ast_passes/messages.ftl @@ -120,6 +120,9 @@ ast_passes_fn_without_body = ast_passes_forbidden_bound = bounds cannot be used in this context +ast_passes_forbidden_const_param = + late-bound const parameters cannot be used currently + ast_passes_forbidden_default = `default` is only allowed on items in trait impls .label = `default` because of this diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs index 783bca6b6958d..215ccd2ab4d9e 100644 --- a/compiler/rustc_ast_passes/src/errors.rs +++ b/compiler/rustc_ast_passes/src/errors.rs @@ -69,6 +69,13 @@ pub struct ForbiddenBound { pub spans: Vec, } +#[derive(Diagnostic)] +#[diag(ast_passes_forbidden_const_param)] +pub struct ForbiddenConstParam { + #[primary_span] + pub const_param_spans: Vec, +} + #[derive(Diagnostic)] #[diag(ast_passes_fn_param_too_many)] pub struct FnParamTooMany { diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 2178b65727d09..e91dfb2776662 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -162,6 +162,22 @@ impl<'a> PostExpansionVisitor<'a> { crate::fluent_generated::ast_passes_forbidden_non_lifetime_param ); + // FIXME(non_lifetime_binders): Const bound params are pretty broken. + // Let's keep users from using this feature accidentally. + if self.features.non_lifetime_binders { + let const_param_spans: Vec<_> = params + .iter() + .filter_map(|param| match param.kind { + ast::GenericParamKind::Const { .. } => Some(param.ident.span), + _ => None, + }) + .collect(); + + if !const_param_spans.is_empty() { + self.sess.dcx().emit_err(errors::ForbiddenConstParam { const_param_spans }); + } + } + for param in params { if !param.bounds.is_empty() { let spans: Vec<_> = param.bounds.iter().map(|b| b.span()).collect(); 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 7930f54038daf..349dc9ad00ed3 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -2094,11 +2094,7 @@ pub fn deny_non_region_late_bound( format!("late-bound {what} parameter not allowed on {where_}"), ); - let guar = if tcx.features().non_lifetime_binders && first { - diag.emit() - } else { - diag.delay_as_bug() - }; + let guar = diag.emit_unless(!tcx.features().non_lifetime_binders || !first); first = false; *arg = ResolvedArg::Error(guar); diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index dc7200465d97e..51414d785963d 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -2763,7 +2763,11 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { let res = match kind { RibKind::Item(..) | RibKind::AssocItem => Res::Def(def_kind, def_id.to_def_id()), RibKind::Normal => { - if self.r.tcx.features().non_lifetime_binders { + // FIXME(non_lifetime_binders): Stop special-casing + // const params to error out here. + if self.r.tcx.features().non_lifetime_binders + && matches!(param.kind, GenericParamKind::Type { .. }) + { Res::Def(def_kind, def_id.to_def_id()) } else { Res::Err diff --git a/tests/crashes/127009.rs b/tests/crashes/127009.rs deleted file mode 100644 index 74ca14393e4e9..0000000000000 --- a/tests/crashes/127009.rs +++ /dev/null @@ -1,11 +0,0 @@ -//@ known-bug: #127009 - -#![feature(non_lifetime_binders)] - -fn b() -where - for [(); C]: Copy, -{ -} - -fn main() {} diff --git a/tests/ui/closures/binder/const-bound.rs b/tests/ui/closures/binder/const-bound.rs index b1c79db137510..10d869fcc8512 100644 --- a/tests/ui/closures/binder/const-bound.rs +++ b/tests/ui/closures/binder/const-bound.rs @@ -3,5 +3,6 @@ fn main() { for || -> () {}; - //~^ ERROR late-bound const parameter not allowed on closures + //~^ ERROR late-bound const parameters cannot be used currently + //~| ERROR late-bound const parameter not allowed on closures } diff --git a/tests/ui/closures/binder/const-bound.stderr b/tests/ui/closures/binder/const-bound.stderr index 9c4fd95ed76ed..b805879f7fab5 100644 --- a/tests/ui/closures/binder/const-bound.stderr +++ b/tests/ui/closures/binder/const-bound.stderr @@ -1,3 +1,9 @@ +error: late-bound const parameters cannot be used currently + --> $DIR/const-bound.rs:5:15 + | +LL | for || -> () {}; + | ^ + warning: the feature `non_lifetime_binders` is incomplete and may not be safe to use and/or cause compiler crashes --> $DIR/const-bound.rs:1:37 | @@ -13,5 +19,5 @@ error: late-bound const parameter not allowed on closures LL | for || -> () {}; | ^^^^^^^^^^^^ -error: aborting due to 1 previous error; 1 warning emitted +error: aborting due to 2 previous errors; 1 warning emitted diff --git a/tests/ui/const-generics/generic_const_exprs/no-entry-found-for-key-ice-gce-nlb-113133.rs b/tests/ui/const-generics/generic_const_exprs/no-entry-found-for-key-ice-gce-nlb-113133.rs index 5673f1dd0738f..ffa9d960e048b 100644 --- a/tests/ui/const-generics/generic_const_exprs/no-entry-found-for-key-ice-gce-nlb-113133.rs +++ b/tests/ui/const-generics/generic_const_exprs/no-entry-found-for-key-ice-gce-nlb-113133.rs @@ -7,7 +7,8 @@ pub fn foo() where for ():, - //~^ ERROR defaults for generic parameters are not allowed in `for<...>` binders + //~^ ERROR late-bound const parameters cannot be used currently + //~| ERROR defaults for generic parameters are not allowed in `for<...>` binders {} fn main() {} diff --git a/tests/ui/const-generics/generic_const_exprs/no-entry-found-for-key-ice-gce-nlb-113133.stderr b/tests/ui/const-generics/generic_const_exprs/no-entry-found-for-key-ice-gce-nlb-113133.stderr index 5924a673da944..814022f26b90f 100644 --- a/tests/ui/const-generics/generic_const_exprs/no-entry-found-for-key-ice-gce-nlb-113133.stderr +++ b/tests/ui/const-generics/generic_const_exprs/no-entry-found-for-key-ice-gce-nlb-113133.stderr @@ -1,8 +1,14 @@ +error: late-bound const parameters cannot be used currently + --> $DIR/no-entry-found-for-key-ice-gce-nlb-113133.rs:9:15 + | +LL | for ():, + | ^ + error: defaults for generic parameters are not allowed in `for<...>` binders --> $DIR/no-entry-found-for-key-ice-gce-nlb-113133.rs:9:9 | LL | for ():, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 1 previous error +error: aborting due to 2 previous errors diff --git a/tests/ui/traits/non_lifetime_binders/bad-suggestion-on-missing-assoc.rs b/tests/ui/traits/non_lifetime_binders/bad-suggestion-on-missing-assoc.rs index fc64381b961d4..b61a21eab419c 100644 --- a/tests/ui/traits/non_lifetime_binders/bad-suggestion-on-missing-assoc.rs +++ b/tests/ui/traits/non_lifetime_binders/bad-suggestion-on-missing-assoc.rs @@ -18,7 +18,8 @@ trait TraitC {} fn foo() where for T: TraitA>, - //~^ ERROR defaults for generic parameters are not allowed in `for<...>` binders + //~^ ERROR late-bound const parameters cannot be used currently + //~| ERROR defaults for generic parameters are not allowed in `for<...>` binders //~| ERROR `impl Trait` is not allowed in bounds { } diff --git a/tests/ui/traits/non_lifetime_binders/bad-suggestion-on-missing-assoc.stderr b/tests/ui/traits/non_lifetime_binders/bad-suggestion-on-missing-assoc.stderr index a4a79413a9be6..e891df3f0c092 100644 --- a/tests/ui/traits/non_lifetime_binders/bad-suggestion-on-missing-assoc.stderr +++ b/tests/ui/traits/non_lifetime_binders/bad-suggestion-on-missing-assoc.stderr @@ -1,3 +1,9 @@ +error: late-bound const parameters cannot be used currently + --> $DIR/bad-suggestion-on-missing-assoc.rs:20:15 + | +LL | for T: TraitA>, + | ^ + warning: the feature `generic_const_exprs` is incomplete and may not be safe to use and/or cause compiler crashes --> $DIR/bad-suggestion-on-missing-assoc.rs:1:12 | @@ -29,6 +35,6 @@ LL | for T: TraitA` binders (||1usize)() }> V: IntoIterator -//~^^^ ERROR defaults for generic parameters are not allowed in `for<...>` binders -//~^^ ERROR cannot find type `V` in this scope +//~^ ERROR cannot find type `V` in this scope { } diff --git a/tests/ui/traits/non_lifetime_binders/binder-defaults-112547.stderr b/tests/ui/traits/non_lifetime_binders/binder-defaults-112547.stderr index edc55a3c8e68f..d9e77dec794a7 100644 --- a/tests/ui/traits/non_lifetime_binders/binder-defaults-112547.stderr +++ b/tests/ui/traits/non_lifetime_binders/binder-defaults-112547.stderr @@ -1,5 +1,5 @@ error[E0412]: cannot find type `V` in this scope - --> $DIR/binder-defaults-112547.rs:8:4 + --> $DIR/binder-defaults-112547.rs:10:4 | LL | }> V: IntoIterator | ^ not found in this scope @@ -9,6 +9,12 @@ help: you might be missing a type parameter LL | pub fn bar() | +++ +error: late-bound const parameters cannot be used currently + --> $DIR/binder-defaults-112547.rs:6:15 + | +LL | for $DIR/binder-defaults-112547.rs:1:12 | @@ -23,10 +29,12 @@ error: defaults for generic parameters are not allowed in `for<...>` binders | LL | for V: IntoIterator | |_^ -error: aborting due to 2 previous errors; 1 warning emitted +error: aborting due to 3 previous errors; 1 warning emitted For more information about this error, try `rustc --explain E0412`. diff --git a/tests/ui/traits/non_lifetime_binders/binder-defaults-119489.rs b/tests/ui/traits/non_lifetime_binders/binder-defaults-119489.rs index f33da416ad8ae..bdfe41ca11b04 100644 --- a/tests/ui/traits/non_lifetime_binders/binder-defaults-119489.rs +++ b/tests/ui/traits/non_lifetime_binders/binder-defaults-119489.rs @@ -5,8 +5,9 @@ fn fun() where for ():, -//~^ ERROR defaults for generic parameters are not allowed in `for<...>` binders -//~| ERROR defaults for generic parameters are not allowed in `for<...>` binders + //~^ ERROR late-bound const parameters cannot be used currently + //~| ERROR defaults for generic parameters are not allowed in `for<...>` binders + //~| ERROR defaults for generic parameters are not allowed in `for<...>` binders {} fn main() {} diff --git a/tests/ui/traits/non_lifetime_binders/binder-defaults-119489.stderr b/tests/ui/traits/non_lifetime_binders/binder-defaults-119489.stderr index 7fe82f1f097c4..947dd3a73bf12 100644 --- a/tests/ui/traits/non_lifetime_binders/binder-defaults-119489.stderr +++ b/tests/ui/traits/non_lifetime_binders/binder-defaults-119489.stderr @@ -1,3 +1,9 @@ +error: late-bound const parameters cannot be used currently + --> $DIR/binder-defaults-119489.rs:7:23 + | +LL | for ():, + | ^ + warning: the feature `non_lifetime_binders` is incomplete and may not be safe to use and/or cause compiler crashes --> $DIR/binder-defaults-119489.rs:1:12 | @@ -27,5 +33,5 @@ error: defaults for generic parameters are not allowed in `for<...>` binders LL | for ():, | ^^^^^^^^^^^^^^^^^^ -error: aborting due to 2 previous errors; 2 warnings emitted +error: aborting due to 3 previous errors; 2 warnings emitted diff --git a/tests/ui/traits/non_lifetime_binders/late-const-param-wf.rs b/tests/ui/traits/non_lifetime_binders/late-const-param-wf.rs new file mode 100644 index 0000000000000..2d44388f875f9 --- /dev/null +++ b/tests/ui/traits/non_lifetime_binders/late-const-param-wf.rs @@ -0,0 +1,11 @@ +#![feature(non_lifetime_binders)] +//~^ WARN the feature `non_lifetime_binders` is incomplete + +fn b() +where + for [(); C]: Copy, + //~^ ERROR late-bound const parameters cannot be used currently +{ +} + +fn main() {} diff --git a/tests/ui/traits/non_lifetime_binders/late-const-param-wf.stderr b/tests/ui/traits/non_lifetime_binders/late-const-param-wf.stderr new file mode 100644 index 0000000000000..136d533a03c40 --- /dev/null +++ b/tests/ui/traits/non_lifetime_binders/late-const-param-wf.stderr @@ -0,0 +1,17 @@ +error: late-bound const parameters cannot be used currently + --> $DIR/late-const-param-wf.rs:6:15 + | +LL | for [(); C]: Copy, + | ^ + +warning: the feature `non_lifetime_binders` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/late-const-param-wf.rs:1:12 + | +LL | #![feature(non_lifetime_binders)] + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #108185 for more information + = note: `#[warn(incomplete_features)]` on by default + +error: aborting due to 1 previous error; 1 warning emitted + From 95335444f7171c4582fd56f20ade6f84da84c984 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Kijewski?= Date: Sun, 21 Jul 2024 02:28:04 +0200 Subject: [PATCH 3/9] rustdoc: short descr. cause word-breaks in tables MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The `.item-table` class is used to display name+description lists, e.g. the exported functions, as a table. If the names are long and the descriptions are short, then the width of the table does not expand to the whole size, but only uses a fraction. This causes a some names to break inside a word. This change makes the table always use 100% of its parent width. The `.width-limiter` wrapper already ensures that the used width still does not become excessive. Signed-off-by: René Kijewski --- src/librustdoc/html/static/css/rustdoc.css | 1 + 1 file changed, 1 insertion(+) diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index 28ed94432c86e..867275cf4fbb6 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -953,6 +953,7 @@ table, display: table; padding: 0; margin: 0; + width: 100%; } .item-table > li { display: table-row; From e4d701b1d3f1cc04574c9b92abfa33e2a4c0e9c3 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 20 Jul 2024 22:28:27 +0200 Subject: [PATCH 4/9] Add regression test for stab display in doc blocks --- tests/rustdoc-gui/src/test_docs/lib.rs | 8 ++++---- tests/rustdoc-gui/stab-in-doc.goml | 9 +++++++++ 2 files changed, 13 insertions(+), 4 deletions(-) create mode 100644 tests/rustdoc-gui/stab-in-doc.goml diff --git a/tests/rustdoc-gui/src/test_docs/lib.rs b/tests/rustdoc-gui/src/test_docs/lib.rs index 7e34178e56f03..360ad3edefa1f 100644 --- a/tests/rustdoc-gui/src/test_docs/lib.rs +++ b/tests/rustdoc-gui/src/test_docs/lib.rs @@ -20,10 +20,10 @@ Also, stop using `bar` as it's deprecated Also, stop using `bar` as it's deprecated. Also, stop using `bar` as it's deprecated. -Finally, you can use `quz` only on Unix or x86-64 -. -Finally, you can use `quz` only on Unix or x86-64 -. +Finally, you can use `quz` only on Unix or x86-64 +. +Finally, you can use `quz` only on Unix or x86-64 +. */ use std::convert::AsRef; diff --git a/tests/rustdoc-gui/stab-in-doc.goml b/tests/rustdoc-gui/stab-in-doc.goml new file mode 100644 index 0000000000000..6a03a51fe9f27 --- /dev/null +++ b/tests/rustdoc-gui/stab-in-doc.goml @@ -0,0 +1,9 @@ +// This test ensure that `stab` elements if used in doc blocks are not breaking the text layout. +go-to: "file://" + |DOC_PATH| + "/test_docs/index.html" +// We make the window wide enough for the two stabs who are looking into to be on the same line. +set-window-size: (1100, 600) +compare-elements-position: ( + ".top-doc .docblock span[data-span='1']", + ".top-doc .docblock span[data-span='2']", + ["y"], +) From 84db684f49d9e1e4250fe24a90b5a5d2d4737df0 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sun, 21 Jul 2024 12:47:34 +0200 Subject: [PATCH 5/9] Update `source-code-page-code-scroll.goml` GUI test --- tests/rustdoc-gui/source-code-page-code-scroll.goml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/rustdoc-gui/source-code-page-code-scroll.goml b/tests/rustdoc-gui/source-code-page-code-scroll.goml index 35f338ea32834..31ab281d6ce09 100644 --- a/tests/rustdoc-gui/source-code-page-code-scroll.goml +++ b/tests/rustdoc-gui/source-code-page-code-scroll.goml @@ -2,7 +2,7 @@ go-to: "file://" + |DOC_PATH| + "/src/test_docs/lib.rs.html" set-window-size: (800, 1000) // "scrollWidth" should be superior than "clientWidth". -assert-property: ("body", {"scrollWidth": 1047, "clientWidth": 800}) +assert-property: ("body", {"scrollWidth": 1114, "clientWidth": 800}) // Both properties should be equal (ie, no scroll on the code block). -assert-property: (".example-wrap .rust", {"scrollWidth": 933, "clientWidth": 933}) +assert-property: (".example-wrap .rust", {"scrollWidth": 1000, "clientWidth": 1000}) From ae42efc522a5ed43631b95f1cce80520c7929e15 Mon Sep 17 00:00:00 2001 From: Nilstrieb <48135649+Nilstrieb@users.noreply.github.com> Date: Wed, 10 Jul 2024 19:42:54 +0200 Subject: [PATCH 6/9] Deal with invalid UTF-8 from `gai_strerror` When the system is using a non-UTF-8 locale, the value will indeed not be UTF-8. That sucks for everyone involved, but is no reason for panic. We can "handle" this gracefully by just using from lossy, replacing the invalid UTF-8 with the ? and keeping the accidentally valid UTF-8. Good luck when debugging, but at least it's not a crash. We already do this for `strerror_r`. --- library/std/src/sys/pal/unix/net.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/library/std/src/sys/pal/unix/net.rs b/library/std/src/sys/pal/unix/net.rs index b8dc1538a6378..bedb06043a7b4 100644 --- a/library/std/src/sys/pal/unix/net.rs +++ b/library/std/src/sys/pal/unix/net.rs @@ -4,7 +4,6 @@ use crate::io::{self, BorrowedBuf, BorrowedCursor, IoSlice, IoSliceMut}; use crate::mem; use crate::net::{Shutdown, SocketAddr}; use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, RawFd}; -use crate::str; use crate::sys::fd::FileDesc; use crate::sys::pal::unix::IsMinusOne; use crate::sys_common::net::{getsockopt, setsockopt, sockaddr_to_addr}; @@ -47,7 +46,9 @@ pub fn cvt_gai(err: c_int) -> io::Result<()> { #[cfg(not(target_os = "espidf"))] let detail = unsafe { - str::from_utf8(CStr::from_ptr(libc::gai_strerror(err)).to_bytes()).unwrap().to_owned() + // We can't always expect a UTF-8 environment. When we don't get that luxury, + // it's better to give a low-quality error message than none at all. + CStr::from_ptr(libc::gai_strerror(err)).to_string_lossy() }; #[cfg(target_os = "espidf")] From 710add58e2063616770ec8893e41b3179ad23d31 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sun, 21 Jul 2024 15:17:29 +0200 Subject: [PATCH 7/9] Tweak `collect_non_exhaustive_tys` --- .../src/thir/pattern/check_match.rs | 32 +++++++++---------- compiler/rustc_pattern_analysis/src/rustc.rs | 8 ++++- 2 files changed, 23 insertions(+), 17 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 70065b5a2c329..38f425581c100 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -16,8 +16,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, RustcPatCtxt as PatCtxt, Usefulness, UsefulnessReport, - WitnessPat, + Constructor, DeconstructedPat, MatchArm, RevealedTy, RustcPatCtxt as PatCtxt, Usefulness, + UsefulnessReport, WitnessPat, }; use rustc_session::lint::builtin::{ BINDINGS_WITH_VARIANT_NAME, IRREFUTABLE_LET_PATTERNS, UNREACHABLE_PATTERNS, @@ -998,26 +998,26 @@ fn report_non_exhaustive_match<'p, 'tcx>( err.note(format!("the matched value is of type `{}`", scrut_ty)); if !is_empty_match { - let mut non_exhaustive_tys = FxIndexSet::default(); + let mut special_tys = FxIndexSet::default(); // Look at the first witness. - collect_non_exhaustive_tys(cx, &witnesses[0], &mut non_exhaustive_tys); + collect_special_tys(cx, &witnesses[0], &mut special_tys); - for ty in non_exhaustive_tys { + for ty in special_tys { if ty.is_ptr_sized_integral() { - if ty == cx.tcx.types.usize { + if ty.inner() == cx.tcx.types.usize { err.note(format!( "`{ty}` does not have a fixed maximum value, so half-open ranges are necessary to match \ exhaustively", )); - } else if ty == cx.tcx.types.isize { + } else if ty.inner() == cx.tcx.types.isize { err.note(format!( "`{ty}` does not have fixed minimum and maximum values, so half-open ranges are necessary to match \ exhaustively", )); } - } else if ty == cx.tcx.types.str_ { + } else if ty.inner() == cx.tcx.types.str_ { err.note("`&str` cannot be matched exhaustively, so a wildcard `_` is necessary"); - } else if cx.is_foreign_non_exhaustive_enum(cx.reveal_opaque_ty(ty)) { + } else if cx.is_foreign_non_exhaustive_enum(ty) { err.note(format!("`{ty}` is marked as non-exhaustive, so a wildcard `_` is necessary to match exhaustively")); } } @@ -1168,22 +1168,22 @@ fn joined_uncovered_patterns<'p, 'tcx>( } } -fn collect_non_exhaustive_tys<'tcx>( +/// Collect types that require specific explanations when they show up in witnesses. +fn collect_special_tys<'tcx>( cx: &PatCtxt<'_, 'tcx>, pat: &WitnessPat<'_, 'tcx>, - non_exhaustive_tys: &mut FxIndexSet>, + special_tys: &mut FxIndexSet>, ) { - if matches!(pat.ctor(), Constructor::NonExhaustive) { - non_exhaustive_tys.insert(pat.ty().inner()); + if matches!(pat.ctor(), Constructor::NonExhaustive | Constructor::Never) { + special_tys.insert(*pat.ty()); } if let Constructor::IntRange(range) = pat.ctor() { if cx.is_range_beyond_boundaries(range, *pat.ty()) { // The range denotes the values before `isize::MIN` or the values after `usize::MAX`/`isize::MAX`. - non_exhaustive_tys.insert(pat.ty().inner()); + special_tys.insert(*pat.ty()); } } - pat.iter_fields() - .for_each(|field_pat| collect_non_exhaustive_tys(cx, field_pat, non_exhaustive_tys)) + pat.iter_fields().for_each(|field_pat| collect_special_tys(cx, field_pat, special_tys)) } fn report_adt_defined_here<'tcx>( diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs index d17ee8bff503e..6ef2d69273ee7 100644 --- a/compiler/rustc_pattern_analysis/src/rustc.rs +++ b/compiler/rustc_pattern_analysis/src/rustc.rs @@ -40,9 +40,15 @@ pub type WitnessPat<'p, 'tcx> = crate::pat::WitnessPat>; /// /// Use `.inner()` or deref to get to the `Ty<'tcx>`. #[repr(transparent)] -#[derive(Clone, Copy)] +#[derive(Clone, Copy, PartialEq, Eq, Hash)] pub struct RevealedTy<'tcx>(Ty<'tcx>); +impl<'tcx> fmt::Display for RevealedTy<'tcx> { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + self.0.fmt(fmt) + } +} + impl<'tcx> fmt::Debug for RevealedTy<'tcx> { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { self.0.fmt(fmt) From 8a49d83db730f3dfdd7f0c04df823549bf571b33 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sun, 21 Jul 2024 15:18:10 +0200 Subject: [PATCH 8/9] Explain why we require `_` for empty patterns --- compiler/rustc_mir_build/src/thir/pattern/check_match.rs | 4 ++++ .../pattern/usefulness/empty-types.min_exh_pats.stderr | 9 +++++++++ .../slice_of_empty.min_exhaustive_patterns.stderr | 1 + 3 files changed, 14 insertions(+) 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 38f425581c100..95799cec94b04 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -1019,6 +1019,10 @@ fn report_non_exhaustive_match<'p, 'tcx>( err.note("`&str` cannot be matched exhaustively, so a wildcard `_` is necessary"); } else if cx.is_foreign_non_exhaustive_enum(ty) { err.note(format!("`{ty}` is marked as non-exhaustive, so a wildcard `_` is necessary to match exhaustively")); + } else if cx.is_uninhabited(ty.inner()) && cx.tcx.features().min_exhaustive_patterns { + // The type is uninhabited yet there is a witness: we must be in the `MaybeInvalid` + // case. + err.note(format!("`{ty}` is uninhabited but is not being matched by value, so a wildcard `_` is required")); } } } diff --git a/tests/ui/pattern/usefulness/empty-types.min_exh_pats.stderr b/tests/ui/pattern/usefulness/empty-types.min_exh_pats.stderr index 6e50dfe6a263c..9b57c895eea32 100644 --- a/tests/ui/pattern/usefulness/empty-types.min_exh_pats.stderr +++ b/tests/ui/pattern/usefulness/empty-types.min_exh_pats.stderr @@ -204,6 +204,7 @@ note: `Option` defined here | = note: not covered = note: the matched value is of type `Option` + = note: `Void` is uninhabited but is not being matched by value, so a wildcard `_` is required help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | LL ~ None => {}, @@ -349,6 +350,7 @@ LL | match slice_never { | ^^^^^^^^^^^ pattern `&[_, ..]` not covered | = note: the matched value is of type `&[!]` + = note: `!` is uninhabited but is not being matched by value, so a wildcard `_` is required help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | LL ~ [] => {}, @@ -484,6 +486,7 @@ note: `Option` defined here | = note: not covered = note: the matched value is of type `&Option` + = note: `!` is uninhabited but is not being matched by value, so a wildcard `_` is required help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | LL ~ &None => {}, @@ -502,6 +505,7 @@ note: `Option` defined here | = note: not covered = note: the matched value is of type `Option` + = note: `!` is uninhabited but is not being matched by value, so a wildcard `_` is required help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | LL ~ None => {}, @@ -520,6 +524,7 @@ note: `Result` defined here | = note: not covered = note: the matched value is of type `Result` + = note: `!` is uninhabited but is not being matched by value, so a wildcard `_` is required help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | LL ~ Ok(_) => {}, @@ -538,6 +543,7 @@ note: `Result` defined here | = note: not covered = note: the matched value is of type `Result` + = note: `!` is uninhabited but is not being matched by value, so a wildcard `_` is required help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | LL ~ Ok(_a) => {}, @@ -589,6 +595,7 @@ LL | match ref_never { | ^^^^^^^^^ pattern `&_` not covered | = note: the matched value is of type `&!` + = note: `!` is uninhabited but is not being matched by value, so a wildcard `_` is required = note: references are always considered inhabited = note: match arms with guards don't count towards exhaustivity help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown @@ -609,6 +616,7 @@ note: `Result` defined here | = note: not covered = note: the matched value is of type `Result` + = note: `!` is uninhabited but is not being matched by value, so a wildcard `_` is required help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | LL ~ Err(_) => {}, @@ -627,6 +635,7 @@ note: `Option>` defined here | = note: not covered = note: the matched value is of type `Option>` + = note: `Result` is uninhabited but is not being matched by value, so a wildcard `_` is required help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | LL ~ None => {}, diff --git a/tests/ui/pattern/usefulness/slice_of_empty.min_exhaustive_patterns.stderr b/tests/ui/pattern/usefulness/slice_of_empty.min_exhaustive_patterns.stderr index a1239466c9c2c..f24ce154d149d 100644 --- a/tests/ui/pattern/usefulness/slice_of_empty.min_exhaustive_patterns.stderr +++ b/tests/ui/pattern/usefulness/slice_of_empty.min_exhaustive_patterns.stderr @@ -5,6 +5,7 @@ LL | match nevers { | ^^^^^^ pattern `&[_, ..]` not covered | = note: the matched value is of type `&[!]` + = note: `!` is uninhabited but is not being matched by value, so a wildcard `_` is required help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | LL ~ &[] => (), From 6a9110aa5ae9705ce62cb91f0d04f5100ecb3019 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 21 Jul 2024 13:45:51 -0400 Subject: [PATCH 9/9] Don't output test artifacts into working directory --- .gitignore | 1 - tests/ui/lto/debuginfo-lto-alloc.rs | 3 ++- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index f1ca6a79b5c5c..87d02563ed048 100644 --- a/.gitignore +++ b/.gitignore @@ -50,7 +50,6 @@ build/ /target /src/bootstrap/target /src/tools/x/target -/inc-fat/ # Created by default with `src/ci/docker/run.sh` /obj/ /rustc-ice* diff --git a/tests/ui/lto/debuginfo-lto-alloc.rs b/tests/ui/lto/debuginfo-lto-alloc.rs index 459103c354c1c..89043275329d1 100644 --- a/tests/ui/lto/debuginfo-lto-alloc.rs +++ b/tests/ui/lto/debuginfo-lto-alloc.rs @@ -9,7 +9,8 @@ // that compilation is successful. //@ check-pass -//@ compile-flags: --test -C debuginfo=2 -C lto=fat -C incremental=inc-fat +//@ compile-flags: --test -C debuginfo=2 -C lto=fat +//@ incremental extern crate alloc;