From 92aa5f6b272bcdc020a34f8d90f9ef851b5b4504 Mon Sep 17 00:00:00 2001 From: John Millikin <john@john-millikin.com> Date: Mon, 9 Jan 2023 13:54:21 +0900 Subject: [PATCH 01/10] Disable `linux_ext` in wasm32 and fortanix rustdoc builds. The `std::os::unix` module is stubbed out when building docs for these target platforms. The introduction of Linux-specific extension traits caused `std::os::net` to depend on sub-modules of `std::os::unix`, which broke rustdoc for the `wasm32-unknown-unknown` target. Adding an additional `#[cfg]` guard solves that rustdoc failure by not declaring `linux_ext` on targets with a stubbed `std::os::unix`. --- library/std/src/os/net/mod.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/library/std/src/os/net/mod.rs b/library/std/src/os/net/mod.rs index 5ec267c41e97c..b7046dd7c598c 100644 --- a/library/std/src/os/net/mod.rs +++ b/library/std/src/os/net/mod.rs @@ -1,4 +1,13 @@ //! OS-specific networking functionality. +// See cfg macros in `library/std/src/os/mod.rs` for why these platforms must +// be special-cased during rustdoc generation. +#[cfg(not(all( + doc, + any( + all(target_arch = "wasm32", not(target_os = "wasi")), + all(target_vendor = "fortanix", target_env = "sgx") + ) +)))] #[cfg(any(target_os = "linux", target_os = "android", doc))] pub(super) mod linux_ext; From 8f70b5ccb7beda26ce7b012261110cd10890cb1f Mon Sep 17 00:00:00 2001 From: John Paul Adrian Glaubitz <glaubitz@physik.fu-berlin.de> Date: Sat, 21 Jan 2023 12:00:14 +0000 Subject: [PATCH 02/10] library/std/sys_common: Define MIN_ALIGN for m68k-unknown-linux-gnu --- library/std/src/sys/common/alloc.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/std/src/sys/common/alloc.rs b/library/std/src/sys/common/alloc.rs index 3edbe7280774d..403a5e627f1e7 100644 --- a/library/std/src/sys/common/alloc.rs +++ b/library/std/src/sys/common/alloc.rs @@ -7,6 +7,7 @@ use crate::ptr; #[cfg(any( target_arch = "x86", target_arch = "arm", + target_arch = "m68k", target_arch = "mips", target_arch = "powerpc", target_arch = "powerpc64", From e489971902c814e5adb7041d1bda230a1acb4fd7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= <tomasz.miasko@gmail.com> Date: Sun, 22 Jan 2023 00:00:00 +0000 Subject: [PATCH 03/10] Fix def-use dominance check A definition does not dominate a use in the same statement. For example in MIR generated for compound assignment x += a (when overflow checks are disabled). --- compiler/rustc_codegen_ssa/src/mir/analyze.rs | 33 ++++++++++++------- tests/ui/mir/mir_codegen_ssa.rs | 19 +++++++++++ 2 files changed, 41 insertions(+), 11 deletions(-) create mode 100644 tests/ui/mir/mir_codegen_ssa.rs diff --git a/compiler/rustc_codegen_ssa/src/mir/analyze.rs b/compiler/rustc_codegen_ssa/src/mir/analyze.rs index dd1ac2c74aed4..95aad10fdb0f9 100644 --- a/compiler/rustc_codegen_ssa/src/mir/analyze.rs +++ b/compiler/rustc_codegen_ssa/src/mir/analyze.rs @@ -36,7 +36,7 @@ pub fn non_ssa_locals<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( // Arguments get assigned to by means of the function being called for arg in mir.args_iter() { - analyzer.assign(arg, mir::START_BLOCK.start_location()); + analyzer.assign(arg, DefLocation::Argument); } // If there exists a local definition that dominates all uses of that local, @@ -64,7 +64,22 @@ enum LocalKind { /// A scalar or a scalar pair local that is neither defined nor used. Unused, /// A scalar or a scalar pair local with a single definition that dominates all uses. - SSA(mir::Location), + SSA(DefLocation), +} + +#[derive(Copy, Clone, PartialEq, Eq)] +enum DefLocation { + Argument, + Body(Location), +} + +impl DefLocation { + fn dominates(self, location: Location, dominators: &Dominators<mir::BasicBlock>) -> bool { + match self { + DefLocation::Argument => true, + DefLocation::Body(def) => def.successor_within_block().dominates(location, dominators), + } + } } struct LocalAnalyzer<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> { @@ -74,17 +89,13 @@ struct LocalAnalyzer<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> { } impl<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> LocalAnalyzer<'mir, 'a, 'tcx, Bx> { - fn assign(&mut self, local: mir::Local, location: Location) { + fn assign(&mut self, local: mir::Local, location: DefLocation) { let kind = &mut self.locals[local]; match *kind { LocalKind::ZST => {} LocalKind::Memory => {} - LocalKind::Unused => { - *kind = LocalKind::SSA(location); - } - LocalKind::SSA(_) => { - *kind = LocalKind::Memory; - } + LocalKind::Unused => *kind = LocalKind::SSA(location), + LocalKind::SSA(_) => *kind = LocalKind::Memory, } } @@ -166,7 +177,7 @@ impl<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> Visitor<'tcx> debug!("visit_assign(place={:?}, rvalue={:?})", place, rvalue); if let Some(local) = place.as_local() { - self.assign(local, location); + self.assign(local, DefLocation::Body(location)); if self.locals[local] != LocalKind::Memory { let decl_span = self.fx.mir.local_decls[local].source_info.span; if !self.fx.rvalue_creates_operand(rvalue, decl_span) { @@ -189,7 +200,7 @@ impl<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> Visitor<'tcx> match context { PlaceContext::MutatingUse(MutatingUseContext::Call) | PlaceContext::MutatingUse(MutatingUseContext::Yield) => { - self.assign(local, location); + self.assign(local, DefLocation::Body(location)); } PlaceContext::NonUse(_) | PlaceContext::MutatingUse(MutatingUseContext::Retag) => {} diff --git a/tests/ui/mir/mir_codegen_ssa.rs b/tests/ui/mir/mir_codegen_ssa.rs new file mode 100644 index 0000000000000..5e2f10cefe92b --- /dev/null +++ b/tests/ui/mir/mir_codegen_ssa.rs @@ -0,0 +1,19 @@ +// build-pass +// compile-flags: --crate-type=lib +#![feature(custom_mir, core_intrinsics)] +use std::intrinsics::mir::*; + +#[custom_mir(dialect = "runtime", phase = "optimized")] +pub fn f(a: u32) -> u32 { + mir!( + let x: u32; + { + // Previously code generation failed with ICE "use of .. before def ..." because the + // definition of x was incorrectly identified as dominating the use of x located in the + // same statement: + x = x + a; + RET = x; + Return() + } + ) +} From d4a816c8131af05dcf6c791ae8afbcce3272809b Mon Sep 17 00:00:00 2001 From: Lenko Donchev <lenko.donchev@gmail.com> Date: Fri, 27 Jan 2023 22:50:24 -0600 Subject: [PATCH 04/10] remove the usize field from CandidateSource::AliasBound --- compiler/rustc_trait_selection/src/solve/assembly.rs | 8 +++----- compiler/rustc_trait_selection/src/solve/project_goals.rs | 2 +- compiler/rustc_trait_selection/src/solve/trait_goals.rs | 2 +- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_trait_selection/src/solve/assembly.rs b/compiler/rustc_trait_selection/src/solve/assembly.rs index d23b550621e17..4d2a9eca6f9cb 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly.rs @@ -76,7 +76,7 @@ pub(super) enum CandidateSource { /// let _y = x.clone(); /// } /// ``` - AliasBound(usize), + AliasBound(), } pub(super) trait GoalKind<'tcx>: TypeFoldable<'tcx> + Copy + Eq { @@ -217,8 +217,6 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { // NOTE: Alternatively we could call `evaluate_goal` here and only have a `Normalized` candidate. // This doesn't work as long as we use `CandidateSource` in winnowing. let goal = goal.with(tcx, goal.predicate.with_self_ty(tcx, normalized_ty)); - // FIXME: This is broken if we care about the `usize` of `AliasBound` because the self type - // could be normalized to yet another projection with different item bounds. let normalized_candidates = self.assemble_and_evaluate_candidates(goal); for mut normalized_candidate in normalized_candidates { normalized_candidate.result = @@ -342,7 +340,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { ty::Alias(_, alias_ty) => alias_ty, }; - for (i, (assumption, _)) in self + for (_, (assumption, _)) in self .tcx() .bound_explicit_item_bounds(alias_ty.def_id) .subst_iter_copied(self.tcx(), alias_ty.substs) @@ -350,7 +348,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { { match G::consider_assumption(self, goal, assumption) { Ok(result) => { - candidates.push(Candidate { source: CandidateSource::AliasBound(i), result }) + candidates.push(Candidate { source: CandidateSource::AliasBound(), result }) } Err(NoSolution) => (), } diff --git a/compiler/rustc_trait_selection/src/solve/project_goals.rs b/compiler/rustc_trait_selection/src/solve/project_goals.rs index 30902c2bc4506..66f3395772b81 100644 --- a/compiler/rustc_trait_selection/src/solve/project_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/project_goals.rs @@ -171,7 +171,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { (CandidateSource::Impl(_), _) | (CandidateSource::ParamEnv(_), _) | (CandidateSource::BuiltinImpl, _) - | (CandidateSource::AliasBound(_), _) => unimplemented!(), + | (CandidateSource::AliasBound(), _) => unimplemented!(), } } } diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs index d74857dc4b480..4625e58652725 100644 --- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs @@ -320,7 +320,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { match (candidate.source, other.source) { (CandidateSource::Impl(_), _) | (CandidateSource::ParamEnv(_), _) - | (CandidateSource::AliasBound(_), _) + | (CandidateSource::AliasBound(), _) | (CandidateSource::BuiltinImpl, _) => unimplemented!(), } } From d3cf813b8d778fe80b59e5d1d09e1ad2d5ba4edb Mon Sep 17 00:00:00 2001 From: Lenko Donchev <lenko.donchev@gmail.com> Date: Sat, 28 Jan 2023 06:00:27 -0600 Subject: [PATCH 05/10] Use field-less variant for AliasBound. --- compiler/rustc_trait_selection/src/solve/assembly.rs | 7 +++---- compiler/rustc_trait_selection/src/solve/project_goals.rs | 2 +- compiler/rustc_trait_selection/src/solve/trait_goals.rs | 2 +- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_trait_selection/src/solve/assembly.rs b/compiler/rustc_trait_selection/src/solve/assembly.rs index 4d2a9eca6f9cb..5b1362b6fbd17 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly.rs @@ -76,7 +76,7 @@ pub(super) enum CandidateSource { /// let _y = x.clone(); /// } /// ``` - AliasBound(), + AliasBound, } pub(super) trait GoalKind<'tcx>: TypeFoldable<'tcx> + Copy + Eq { @@ -340,15 +340,14 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { ty::Alias(_, alias_ty) => alias_ty, }; - for (_, (assumption, _)) in self + for (assumption, _) in self .tcx() .bound_explicit_item_bounds(alias_ty.def_id) .subst_iter_copied(self.tcx(), alias_ty.substs) - .enumerate() { match G::consider_assumption(self, goal, assumption) { Ok(result) => { - candidates.push(Candidate { source: CandidateSource::AliasBound(), result }) + candidates.push(Candidate { source: CandidateSource::AliasBound, result }) } Err(NoSolution) => (), } diff --git a/compiler/rustc_trait_selection/src/solve/project_goals.rs b/compiler/rustc_trait_selection/src/solve/project_goals.rs index 66f3395772b81..f82eba030cbd4 100644 --- a/compiler/rustc_trait_selection/src/solve/project_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/project_goals.rs @@ -171,7 +171,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { (CandidateSource::Impl(_), _) | (CandidateSource::ParamEnv(_), _) | (CandidateSource::BuiltinImpl, _) - | (CandidateSource::AliasBound(), _) => unimplemented!(), + | (CandidateSource::AliasBound, _) => unimplemented!(), } } } diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs index 4625e58652725..e8ce1debf04bd 100644 --- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs @@ -320,7 +320,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { match (candidate.source, other.source) { (CandidateSource::Impl(_), _) | (CandidateSource::ParamEnv(_), _) - | (CandidateSource::AliasBound(), _) + | (CandidateSource::AliasBound, _) | (CandidateSource::BuiltinImpl, _) => unimplemented!(), } } From 5251769c9e1f6424a982c31fccf45e347c606171 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo <tshepang@gmail.com> Date: Sat, 28 Jan 2023 16:35:07 +0200 Subject: [PATCH 06/10] make more pleasant to read --- compiler/rustc_codegen_llvm/src/context.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index d9ccba07a346a..32cd3a4efa227 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -191,7 +191,7 @@ pub unsafe fn create_module<'ll>( // // FIXME(#34960) let cfg_llvm_root = option_env!("CFG_LLVM_ROOT").unwrap_or(""); - let custom_llvm_used = cfg_llvm_root.trim() != ""; + let custom_llvm_used = !cfg_llvm_root.trim().is_empty(); if !custom_llvm_used && target_data_layout != llvm_data_layout { bug!( From 832751fe1df232e36b283fa136b4e26475e55c00 Mon Sep 17 00:00:00 2001 From: Nilstrieb <48135649+Nilstrieb@users.noreply.github.com> Date: Sat, 28 Jan 2023 20:43:16 +0100 Subject: [PATCH 07/10] Also erase substs for new infcx in pin move error The code originally correctly erased the regions of the type it passed to the newly created infcx. But after the `fn_sig` query was made to return an `EarlyBinder<T>`, some substs that were around were substituted there without erasing their regions. They were then passed into the newly cerated infcx, which caused the ICE. --- .../rustc_borrowck/src/diagnostics/mod.rs | 4 ++++ ...-mut-reborrow-infer-var-issue-107419.fixed | 11 ++++++++++ ...pin-mut-reborrow-infer-var-issue-107419.rs | 11 ++++++++++ ...mut-reborrow-infer-var-issue-107419.stderr | 20 +++++++++++++++++++ 4 files changed, 46 insertions(+) create mode 100644 tests/ui/moves/pin-mut-reborrow-infer-var-issue-107419.fixed create mode 100644 tests/ui/moves/pin-mut-reborrow-infer-var-issue-107419.rs create mode 100644 tests/ui/moves/pin-mut-reborrow-infer-var-issue-107419.stderr diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs index 1011794d7b3b2..8c579bac7e8eb 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mod.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs @@ -1128,8 +1128,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { "{place_name} {partially_str}moved due to this method call{loop_message}", ), ); + let infcx = tcx.infer_ctxt().build(); + // Erase and shadow everything that could be passed to the new infcx. let ty = tcx.erase_regions(moved_place.ty(self.body, tcx).ty); + let method_substs = tcx.erase_regions(method_substs); + if let ty::Adt(def, substs) = ty.kind() && Some(def.did()) == tcx.lang_items().pin_type() && let ty::Ref(_, _, hir::Mutability::Mut) = substs.type_at(0).kind() diff --git a/tests/ui/moves/pin-mut-reborrow-infer-var-issue-107419.fixed b/tests/ui/moves/pin-mut-reborrow-infer-var-issue-107419.fixed new file mode 100644 index 0000000000000..0b9a3bae9619c --- /dev/null +++ b/tests/ui/moves/pin-mut-reborrow-infer-var-issue-107419.fixed @@ -0,0 +1,11 @@ +// run-rustfix +use std::pin::Pin; + +fn foo(_: &mut ()) {} + +fn main() { + let mut uwu = (); + let mut r = Pin::new(&mut uwu); + foo(r.as_mut().get_mut()); + foo(r.get_mut()); //~ ERROR use of moved value +} diff --git a/tests/ui/moves/pin-mut-reborrow-infer-var-issue-107419.rs b/tests/ui/moves/pin-mut-reborrow-infer-var-issue-107419.rs new file mode 100644 index 0000000000000..0e952b06ee118 --- /dev/null +++ b/tests/ui/moves/pin-mut-reborrow-infer-var-issue-107419.rs @@ -0,0 +1,11 @@ +// run-rustfix +use std::pin::Pin; + +fn foo(_: &mut ()) {} + +fn main() { + let mut uwu = (); + let mut r = Pin::new(&mut uwu); + foo(r.get_mut()); + foo(r.get_mut()); //~ ERROR use of moved value +} diff --git a/tests/ui/moves/pin-mut-reborrow-infer-var-issue-107419.stderr b/tests/ui/moves/pin-mut-reborrow-infer-var-issue-107419.stderr new file mode 100644 index 0000000000000..7e513b73c21b2 --- /dev/null +++ b/tests/ui/moves/pin-mut-reborrow-infer-var-issue-107419.stderr @@ -0,0 +1,20 @@ +error[E0382]: use of moved value: `r` + --> $DIR/pin-mut-reborrow-infer-var-issue-107419.rs:10:9 + | +LL | let mut r = Pin::new(&mut uwu); + | ----- move occurs because `r` has type `Pin<&mut ()>`, which does not implement the `Copy` trait +LL | foo(r.get_mut()); + | --------- `r` moved due to this method call +LL | foo(r.get_mut()); + | ^ value used here after move + | +note: `Pin::<&'a mut T>::get_mut` takes ownership of the receiver `self`, which moves `r` + --> $SRC_DIR/core/src/pin.rs:LL:COL +help: consider reborrowing the `Pin` instead of moving it + | +LL | foo(r.as_mut().get_mut()); + | +++++++++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0382`. From 65186e01285ba20e966e06f505f0e89e06694601 Mon Sep 17 00:00:00 2001 From: teapot4195 <huangalex409@gmail.com> Date: Sat, 28 Jan 2023 15:20:27 -0500 Subject: [PATCH 08/10] Gracefully exit when --keep-stage used on clean source tree --- src/bootstrap/lib.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index d44b96cfb991e..522b3b7e851ff 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -1431,6 +1431,13 @@ impl Build { return Vec::new(); } + if !stamp.exists() { + eprintln!( + "Warning: Unable to find the stamp file, did you try to keep a nonexistent build stage?" + ); + crate::detail_exit(1); + } + let mut paths = Vec::new(); let contents = t!(fs::read(stamp), &stamp); // This is the method we use for extracting paths from the stamp file passed to us. See From 4bfab39f9b466fa89f85c57a42c1e71a99c6aa4e Mon Sep 17 00:00:00 2001 From: clubby789 <jamie@hill-daniel.co.uk> Date: Sat, 28 Jan 2023 20:02:00 +0000 Subject: [PATCH 09/10] Check for missing space between fat arrow and range pattern --- compiler/rustc_parse/src/parser/expr.rs | 2 +- compiler/rustc_parse/src/parser/pat.rs | 44 +++++++++++++------ ...f-open-range-pats-inclusive-match-arrow.rs | 8 ++++ ...en-range-pats-inclusive-match-arrow.stderr | 19 ++++++++ 4 files changed, 59 insertions(+), 14 deletions(-) create mode 100644 tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-match-arrow.rs create mode 100644 tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-match-arrow.stderr diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 3225a309a319b..17d1e200b41aa 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -3168,7 +3168,7 @@ impl<'a> Parser<'a> { limits: RangeLimits, ) -> ExprKind { if end.is_none() && limits == RangeLimits::Closed { - self.inclusive_range_with_incorrect_end(self.prev_token.span); + self.inclusive_range_with_incorrect_end(); ExprKind::Err } else { ExprKind::Range(start, end, limits) diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index e5411538eea22..9cde00269205e 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -746,32 +746,38 @@ impl<'a> Parser<'a> { // Parsing e.g. `X..`. if let RangeEnd::Included(_) = re.node { // FIXME(Centril): Consider semantic errors instead in `ast_validation`. - self.inclusive_range_with_incorrect_end(re.span); + self.inclusive_range_with_incorrect_end(); } None }; Ok(PatKind::Range(Some(begin), end, re)) } - pub(super) fn inclusive_range_with_incorrect_end(&mut self, span: Span) { + pub(super) fn inclusive_range_with_incorrect_end(&mut self) { let tok = &self.token; - + let span = self.prev_token.span; // If the user typed "..==" instead of "..=", we want to give them // a specific error message telling them to use "..=". + // If they typed "..=>", suggest they use ".. =>". // Otherwise, we assume that they meant to type a half open exclusive // range and give them an error telling them to do that instead. - if matches!(tok.kind, token::Eq) && tok.span.lo() == span.hi() { - let span_with_eq = span.to(tok.span); + let no_space = tok.span.lo() == span.hi(); + match tok.kind { + token::Eq if no_space => { + let span_with_eq = span.to(tok.span); - // Ensure the user doesn't receive unhelpful unexpected token errors - self.bump(); - if self.is_pat_range_end_start(0) { - let _ = self.parse_pat_range_end().map_err(|e| e.cancel()); - } + // Ensure the user doesn't receive unhelpful unexpected token errors + self.bump(); + if self.is_pat_range_end_start(0) { + let _ = self.parse_pat_range_end().map_err(|e| e.cancel()); + } - self.error_inclusive_range_with_extra_equals(span_with_eq); - } else { - self.error_inclusive_range_with_no_end(span); + self.error_inclusive_range_with_extra_equals(span_with_eq); + } + token::Gt if no_space => { + self.error_inclusive_range_match_arrow(span); + } + _ => self.error_inclusive_range_with_no_end(span), } } @@ -782,6 +788,18 @@ impl<'a> Parser<'a> { .emit(); } + fn error_inclusive_range_match_arrow(&self, span: Span) { + let without_eq = span.with_hi(span.hi() - rustc_span::BytePos(1)); + self.struct_span_err(span, "unexpected `=>` after open range") + .span_suggestion_verbose( + without_eq.shrink_to_hi(), + "add a space between the pattern and `=>`", + " ", + Applicability::MachineApplicable, + ) + .emit(); + } + fn error_inclusive_range_with_no_end(&self, span: Span) { struct_span_err!(self.sess.span_diagnostic, span, E0586, "inclusive range with no end") .span_suggestion_short(span, "use `..` instead", "..", Applicability::MachineApplicable) diff --git a/tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-match-arrow.rs b/tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-match-arrow.rs new file mode 100644 index 0000000000000..7ba2b6d857cd0 --- /dev/null +++ b/tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-match-arrow.rs @@ -0,0 +1,8 @@ +fn main() { + let x = 42; + match x { + 0..=73 => {}, + 74..=> {}, //~ ERROR unexpected `=>` after open range + //~^ ERROR expected one of `=>`, `if`, or `|`, found `>` + } +} diff --git a/tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-match-arrow.stderr b/tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-match-arrow.stderr new file mode 100644 index 0000000000000..9ba6d15113cd6 --- /dev/null +++ b/tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-match-arrow.stderr @@ -0,0 +1,19 @@ +error: unexpected `=>` after open range + --> $DIR/half-open-range-pats-inclusive-match-arrow.rs:5:11 + | +LL | 74..=> {}, + | ^^^ + | +help: add a space between the pattern and `=>` + | +LL | 74.. => {}, + | + + +error: expected one of `=>`, `if`, or `|`, found `>` + --> $DIR/half-open-range-pats-inclusive-match-arrow.rs:5:14 + | +LL | 74..=> {}, + | ^ expected one of `=>`, `if`, or `|` + +error: aborting due to 2 previous errors + From c5688794e2c3bb94f93e37a4f77576ac0d86a14e Mon Sep 17 00:00:00 2001 From: clubby789 <jamie@hill-daniel.co.uk> Date: Sat, 28 Jan 2023 21:16:50 +0000 Subject: [PATCH 10/10] Migrate some range parsing diagnostics --- .../locales/en-US/parse.ftl | 11 +++++ compiler/rustc_parse/src/errors.rs | 42 +++++++++++++++++++ compiler/rustc_parse/src/parser/pat.rs | 27 ++++-------- 3 files changed, 61 insertions(+), 19 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/parse.ftl b/compiler/rustc_error_messages/locales/en-US/parse.ftl index a3e2002da781c..1728ef70cba0a 100644 --- a/compiler/rustc_error_messages/locales/en-US/parse.ftl +++ b/compiler/rustc_error_messages/locales/en-US/parse.ftl @@ -199,6 +199,17 @@ parse_match_arm_body_without_braces = `match` arm body without braces } with a body .suggestion_use_comma_not_semicolon = use a comma to end a `match` arm expression +parse_inclusive_range_extra_equals = unexpected `=` after inclusive range + .suggestion_remove_eq = use `..=` instead + .note = inclusive ranges end with a single equals sign (`..=`) + +parse_inclusive_range_match_arrow = unexpected `=>` after open range + .suggestion_add_space = add a space between the pattern and `=>` + +parse_inclusive_range_no_end = inclusive range with no end + .suggestion_open_range = use `..` instead + .note = inclusive ranges must be bounded at the end (`..=b` or `a..=b`) + parse_struct_literal_not_allowed_here = struct literals are not allowed here .suggestion = surround the struct literal with parentheses diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 40763da0bb547..054b41b478d60 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -649,6 +649,48 @@ pub(crate) struct MatchArmBodyWithoutBraces { pub sub: MatchArmBodyWithoutBracesSugg, } +#[derive(Diagnostic)] +#[diag(parse_inclusive_range_extra_equals)] +#[note] +pub(crate) struct InclusiveRangeExtraEquals { + #[primary_span] + #[suggestion( + suggestion_remove_eq, + style = "short", + code = "..=", + applicability = "maybe-incorrect" + )] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(parse_inclusive_range_match_arrow)] +pub(crate) struct InclusiveRangeMatchArrow { + #[primary_span] + pub span: Span, + #[suggestion( + suggestion_add_space, + style = "verbose", + code = " ", + applicability = "machine-applicable" + )] + pub after_pat: Span, +} + +#[derive(Diagnostic)] +#[diag(parse_inclusive_range_no_end, code = "E0586")] +#[note] +pub(crate) struct InclusiveRangeNoEnd { + #[primary_span] + #[suggestion( + suggestion_open_range, + code = "..", + applicability = "machine-applicable", + style = "short" + )] + pub span: Span, +} + #[derive(Subdiagnostic)] pub(crate) enum MatchArmBodyWithoutBracesSugg { #[multipart_suggestion(suggestion_add_braces, applicability = "machine-applicable")] diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index 9cde00269205e..912f7cc14f6cc 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -1,5 +1,7 @@ use super::{ForceCollect, Parser, PathStyle, TrailingToken}; -use crate::errors::RemoveLet; +use crate::errors::{ + InclusiveRangeExtraEquals, InclusiveRangeMatchArrow, InclusiveRangeNoEnd, RemoveLet, +}; use crate::{maybe_recover_from_interpolated_ty_qpath, maybe_whole}; use rustc_ast::mut_visit::{noop_visit_pat, MutVisitor}; use rustc_ast::ptr::P; @@ -9,7 +11,7 @@ use rustc_ast::{ PatField, PatKind, Path, QSelf, RangeEnd, RangeSyntax, }; use rustc_ast_pretty::pprust; -use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed, PResult}; +use rustc_errors::{Applicability, DiagnosticBuilder, ErrorGuaranteed, PResult}; use rustc_session::errors::ExprParenthesesNeeded; use rustc_span::source_map::{respan, Span, Spanned}; use rustc_span::symbol::{kw, sym, Ident}; @@ -782,29 +784,16 @@ impl<'a> Parser<'a> { } fn error_inclusive_range_with_extra_equals(&self, span: Span) { - self.struct_span_err(span, "unexpected `=` after inclusive range") - .span_suggestion_short(span, "use `..=` instead", "..=", Applicability::MaybeIncorrect) - .note("inclusive ranges end with a single equals sign (`..=`)") - .emit(); + self.sess.emit_err(InclusiveRangeExtraEquals { span }); } fn error_inclusive_range_match_arrow(&self, span: Span) { - let without_eq = span.with_hi(span.hi() - rustc_span::BytePos(1)); - self.struct_span_err(span, "unexpected `=>` after open range") - .span_suggestion_verbose( - without_eq.shrink_to_hi(), - "add a space between the pattern and `=>`", - " ", - Applicability::MachineApplicable, - ) - .emit(); + let after_pat = span.with_hi(span.hi() - rustc_span::BytePos(1)).shrink_to_hi(); + self.sess.emit_err(InclusiveRangeMatchArrow { span, after_pat }); } fn error_inclusive_range_with_no_end(&self, span: Span) { - struct_span_err!(self.sess.span_diagnostic, span, E0586, "inclusive range with no end") - .span_suggestion_short(span, "use `..` instead", "..", Applicability::MachineApplicable) - .note("inclusive ranges must be bounded at the end (`..=b` or `a..=b`)") - .emit(); + self.sess.emit_err(InclusiveRangeNoEnd { span }); } /// Parse a range-to pattern, `..X` or `..=X` where `X` remains to be parsed.