From a439eb259da620fa95c67c0c6e89f196bcb61f08 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 7 Apr 2024 19:28:01 -0400 Subject: [PATCH 1/2] Don't use bytepos offsets when computing semicolon span for removal --- .../src/infer/error_reporting/suggest.rs | 11 ++++++-- .../typeck/remove-semi-but-confused-char.rs | 11 ++++++++ .../remove-semi-but-confused-char.stderr | 25 +++++++++++++++++++ 3 files changed, 45 insertions(+), 2 deletions(-) create mode 100644 tests/ui/typeck/remove-semi-but-confused-char.rs create mode 100644 tests/ui/typeck/remove-semi-but-confused-char.stderr diff --git a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs index 9a05fb1c30f8e..89c55602f220f 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs @@ -15,7 +15,7 @@ use rustc_middle::traits::{ }; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{self as ty, GenericArgKind, IsSuggestable, Ty, TypeVisitableExt}; -use rustc_span::{sym, BytePos, Span}; +use rustc_span::{sym, Span}; use crate::errors::{ ConsiderAddingAwait, FnConsiderCasting, FnItemsAreDistinct, FnUniqTypes, @@ -763,8 +763,15 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { let mac_call = rustc_span::source_map::original_sp(last_stmt.span, blk.span); self.tcx.sess.source_map().mac_call_stmt_semi_span(mac_call)? } else { - last_stmt.span.with_lo(last_stmt.span.hi() - BytePos(1)) + self.tcx + .sess + .source_map() + .span_extend_while(last_expr.span, |c| c.is_whitespace()) + .ok()? + .shrink_to_hi() + .with_hi(last_stmt.span.hi()) }; + Some((span, needs_box)) } diff --git a/tests/ui/typeck/remove-semi-but-confused-char.rs b/tests/ui/typeck/remove-semi-but-confused-char.rs new file mode 100644 index 0000000000000..ccc6f59344c05 --- /dev/null +++ b/tests/ui/typeck/remove-semi-but-confused-char.rs @@ -0,0 +1,11 @@ +// Ensures our "remove semicolon" suggestion isn't hardcoded with a character width, +// in case it was accidentally mixed up with a greek question mark. +// issue: rust-lang/rust#123607 + +pub fn square(num: i32) -> i32 { + //~^ ERROR mismatched types + num * num; + //~^ ERROR unknown start of token +} + +fn main() {} diff --git a/tests/ui/typeck/remove-semi-but-confused-char.stderr b/tests/ui/typeck/remove-semi-but-confused-char.stderr new file mode 100644 index 0000000000000..2d0b53a60ce40 --- /dev/null +++ b/tests/ui/typeck/remove-semi-but-confused-char.stderr @@ -0,0 +1,25 @@ +error: unknown start of token: \u{37e} + --> $DIR/remove-semi-but-confused-char.rs:7:14 + | +LL | num * num; + | ^ + | +help: Unicode character ';' (Greek Question Mark) looks like ';' (Semicolon), but it is not + | +LL | num * num; + | ~ + +error[E0308]: mismatched types + --> $DIR/remove-semi-but-confused-char.rs:5:28 + | +LL | pub fn square(num: i32) -> i32 { + | ------ ^^^ expected `i32`, found `()` + | | + | implicitly returns `()` as its body has no tail or `return` expression +LL | +LL | num * num; + | - help: remove this semicolon to return this value + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`. From 3253c021cbd3bca49393db6a2372764ec53f5920 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 7 Apr 2024 19:38:05 -0400 Subject: [PATCH 2/2] Add a helper for extending a span to include any trailing whitespace --- compiler/rustc_ast_passes/src/ast_validation.rs | 2 +- compiler/rustc_hir_typeck/src/expr.rs | 3 +-- .../src/infer/error_reporting/suggest.rs | 8 ++------ compiler/rustc_lint/src/context/diagnostics.rs | 5 +---- compiler/rustc_span/src/source_map.rs | 15 +++++++++------ .../src/traits/error_reporting/suggestions.rs | 8 ++------ src/tools/clippy/clippy_lints/src/lifetimes.rs | 3 +-- 7 files changed, 17 insertions(+), 27 deletions(-) diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 093a985495c9f..01addc8127e8a 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -346,7 +346,7 @@ impl<'a> AstValidator<'a> { in_impl: matches!(parent, TraitOrTraitImpl::TraitImpl { .. }), const_context_label: parent_constness, remove_const_sugg: ( - self.session.source_map().span_extend_while(span, |c| c == ' ').unwrap_or(span), + self.session.source_map().span_extend_while_whitespace(span), match parent_constness { Some(_) => rustc_errors::Applicability::MachineApplicable, None => rustc_errors::Applicability::MaybeIncorrect, diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index d3df3dd38853e..7a1a2c498aa7d 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -2023,8 +2023,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .tcx .sess .source_map() - .span_extend_while(range_start.span, |c| c.is_whitespace()) - .unwrap_or(range_start.span) + .span_extend_while_whitespace(range_start.span) .shrink_to_hi() .to(range_end.span); diff --git a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs index 89c55602f220f..7855031e705d7 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs @@ -766,8 +766,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { self.tcx .sess .source_map() - .span_extend_while(last_expr.span, |c| c.is_whitespace()) - .ok()? + .span_extend_while_whitespace(last_expr.span) .shrink_to_hi() .with_hi(last_stmt.span.hi()) }; @@ -874,10 +873,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { format!(" {ident} ") }; let left_span = sm.span_through_char(blk.span, '{').shrink_to_hi(); - ( - sm.span_extend_while(left_span, |c| c.is_whitespace()).unwrap_or(left_span), - sugg, - ) + (sm.span_extend_while_whitespace(left_span), sugg) }; Some(SuggestRemoveSemiOrReturnBinding::Add { sp: span, code: sugg, ident: *ident }) } diff --git a/compiler/rustc_lint/src/context/diagnostics.rs b/compiler/rustc_lint/src/context/diagnostics.rs index e2010ab3830ac..16e3b8c11c133 100644 --- a/compiler/rustc_lint/src/context/diagnostics.rs +++ b/compiler/rustc_lint/src/context/diagnostics.rs @@ -215,10 +215,7 @@ pub(super) fn builtin(sess: &Session, diagnostic: BuiltinLintDiag, diag: &mut Di if let Some(deletion_span) = deletion_span { let msg = "elide the single-use lifetime"; let (use_span, replace_lt) = if elide { - let use_span = sess - .source_map() - .span_extend_while(use_span, char::is_whitespace) - .unwrap_or(use_span); + let use_span = sess.source_map().span_extend_while_whitespace(use_span); (use_span, String::new()) } else { (use_span, "'_".to_owned()) diff --git a/compiler/rustc_span/src/source_map.rs b/compiler/rustc_span/src/source_map.rs index 770624d331d1e..f721a04d6b968 100644 --- a/compiler/rustc_span/src/source_map.rs +++ b/compiler/rustc_span/src/source_map.rs @@ -654,6 +654,12 @@ impl SourceMap { }) } + /// Extends the span to include any trailing whitespace, or returns the original + /// span if a `SpanSnippetError` was encountered. + pub fn span_extend_while_whitespace(&self, span: Span) -> Span { + self.span_extend_while(span, char::is_whitespace).unwrap_or(span) + } + /// Extends the given `Span` to previous character while the previous character matches the predicate pub fn span_extend_prev_while( &self, @@ -1034,12 +1040,9 @@ impl SourceMap { /// // ^^^^^^ input /// ``` pub fn mac_call_stmt_semi_span(&self, mac_call: Span) -> Option { - let span = self.span_extend_while(mac_call, char::is_whitespace).ok()?; - let span = span.shrink_to_hi().with_hi(BytePos(span.hi().0.checked_add(1)?)); - if self.span_to_snippet(span).as_deref() != Ok(";") { - return None; - } - Some(span) + let span = self.span_extend_while_whitespace(mac_call); + let span = self.next_point(span); + if self.span_to_snippet(span).as_deref() == Ok(";") { Some(span) } else { None } } } diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index af90372b97ce3..2067956d0f5f0 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -1592,8 +1592,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { .tcx .sess .source_map() - .span_extend_while(expr_span, char::is_whitespace) - .unwrap_or(expr_span) + .span_extend_while_whitespace(expr_span) .shrink_to_hi() .to(await_expr.span.shrink_to_hi()); err.span_suggestion( @@ -4851,10 +4850,7 @@ pub fn suggest_desugaring_async_fn_to_impl_future_in_trait<'tcx>( let hir::IsAsync::Async(async_span) = sig.header.asyncness else { return None; }; - let Ok(async_span) = tcx.sess.source_map().span_extend_while(async_span, |c| c.is_whitespace()) - else { - return None; - }; + let async_span = tcx.sess.source_map().span_extend_while_whitespace(async_span); let future = tcx.hir_node_by_def_id(opaque_def_id).expect_item().expect_opaque_ty(); let [hir::GenericBound::Trait(trait_ref, _)] = future.bounds else { diff --git a/src/tools/clippy/clippy_lints/src/lifetimes.rs b/src/tools/clippy/clippy_lints/src/lifetimes.rs index a60a40a2a4713..2bb63ec2b046b 100644 --- a/src/tools/clippy/clippy_lints/src/lifetimes.rs +++ b/src/tools/clippy/clippy_lints/src/lifetimes.rs @@ -294,8 +294,7 @@ fn elision_suggestions( let span = cx .sess() .source_map() - .span_extend_while(usage.ident.span, |ch| ch.is_ascii_whitespace()) - .unwrap_or(usage.ident.span); + .span_extend_while_whitespace(usage.ident.span); (span, String::new()) },