Rollup merge of #91607 - FabianWolff:issue-91560-const-span, r=jackh726
Make `span_extend_to_prev_str()` more robust Fixes #91560. The logic in `span_extend_to_prev_str()` is currently quite brittle and fails if there is extra whitespace or something else in between, and it also should return an `Option` but doesn't currently.
This commit is contained in:
commit
b7c48b4691
7 changed files with 123 additions and 46 deletions
|
@ -453,28 +453,28 @@ impl<'a> Resolver<'a> {
|
||||||
// edit:
|
// edit:
|
||||||
// only do this if the const and usage of the non-constant value are on the same line
|
// only do this if the const and usage of the non-constant value are on the same line
|
||||||
// the further the two are apart, the higher the chance of the suggestion being wrong
|
// the further the two are apart, the higher the chance of the suggestion being wrong
|
||||||
// also make sure that the pos for the suggestion is not 0 (ICE #90878)
|
|
||||||
|
|
||||||
let sp =
|
let sp = self
|
||||||
self.session.source_map().span_extend_to_prev_str(ident.span, current, true);
|
.session
|
||||||
|
.source_map()
|
||||||
|
.span_extend_to_prev_str(ident.span, current, true, false);
|
||||||
|
|
||||||
let pos_for_suggestion = sp.lo().0.saturating_sub(current.len() as u32);
|
match sp {
|
||||||
|
Some(sp) if !self.session.source_map().is_multiline(sp) => {
|
||||||
if sp.lo().0 == 0
|
let sp = sp.with_lo(BytePos(sp.lo().0 - (current.len() as u32)));
|
||||||
|| pos_for_suggestion == 0
|
err.span_suggestion(
|
||||||
|| self.session.source_map().is_multiline(sp)
|
sp,
|
||||||
{
|
&format!("consider using `{}` instead of `{}`", sugg, current),
|
||||||
err.span_label(ident.span, &format!("this would need to be a `{}`", sugg));
|
format!("{} {}", sugg, ident),
|
||||||
} else {
|
Applicability::MaybeIncorrect,
|
||||||
let sp = sp.with_lo(BytePos(pos_for_suggestion));
|
);
|
||||||
err.span_suggestion(
|
err.span_label(span, "non-constant value");
|
||||||
sp,
|
}
|
||||||
&format!("consider using `{}` instead of `{}`", sugg, current),
|
_ => {
|
||||||
format!("{} {}", sugg, ident),
|
err.span_label(ident.span, &format!("this would need to be a `{}`", sugg));
|
||||||
Applicability::MaybeIncorrect,
|
}
|
||||||
);
|
|
||||||
err.span_label(span, "non-constant value");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
err
|
err
|
||||||
}
|
}
|
||||||
ResolutionError::BindingShadowsSomethingUnacceptable {
|
ResolutionError::BindingShadowsSomethingUnacceptable {
|
||||||
|
|
|
@ -629,26 +629,41 @@ impl SourceMap {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Extends the given `Span` to just after the previous occurrence of `pat` when surrounded by
|
/// Extends the given `Span` to just after the previous occurrence of `pat` when surrounded by
|
||||||
/// whitespace. Returns the same span if no character could be found or if an error occurred
|
/// whitespace. Returns None if the pattern could not be found or if an error occurred while
|
||||||
/// while retrieving the code snippet.
|
/// retrieving the code snippet.
|
||||||
pub fn span_extend_to_prev_str(&self, sp: Span, pat: &str, accept_newlines: bool) -> Span {
|
pub fn span_extend_to_prev_str(
|
||||||
|
&self,
|
||||||
|
sp: Span,
|
||||||
|
pat: &str,
|
||||||
|
accept_newlines: bool,
|
||||||
|
include_whitespace: bool,
|
||||||
|
) -> Option<Span> {
|
||||||
// assure that the pattern is delimited, to avoid the following
|
// assure that the pattern is delimited, to avoid the following
|
||||||
// fn my_fn()
|
// fn my_fn()
|
||||||
// ^^^^ returned span without the check
|
// ^^^^ returned span without the check
|
||||||
// ---------- correct span
|
// ---------- correct span
|
||||||
|
let prev_source = self.span_to_prev_source(sp).ok()?;
|
||||||
for ws in &[" ", "\t", "\n"] {
|
for ws in &[" ", "\t", "\n"] {
|
||||||
let pat = pat.to_owned() + ws;
|
let pat = pat.to_owned() + ws;
|
||||||
if let Ok(prev_source) = self.span_to_prev_source(sp) {
|
if let Some(pat_pos) = prev_source.rfind(&pat) {
|
||||||
let prev_source = prev_source.rsplit(&pat).next().unwrap_or("").trim_start();
|
let just_after_pat_pos = pat_pos + pat.len() - 1;
|
||||||
if prev_source.is_empty() && sp.lo().0 != 0 {
|
let just_after_pat_plus_ws = if include_whitespace {
|
||||||
return sp.with_lo(BytePos(sp.lo().0 - 1));
|
just_after_pat_pos
|
||||||
} else if accept_newlines || !prev_source.contains('\n') {
|
+ prev_source[just_after_pat_pos..]
|
||||||
return sp.with_lo(BytePos(sp.lo().0 - prev_source.len() as u32));
|
.find(|c: char| !c.is_whitespace())
|
||||||
|
.unwrap_or(0)
|
||||||
|
} else {
|
||||||
|
just_after_pat_pos
|
||||||
|
};
|
||||||
|
let len = prev_source.len() - just_after_pat_plus_ws;
|
||||||
|
let prev_source = &prev_source[just_after_pat_plus_ws..];
|
||||||
|
if accept_newlines || !prev_source.trim_start().contains('\n') {
|
||||||
|
return Some(sp.with_lo(BytePos(sp.lo().0 - len as u32)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sp
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the source snippet as `String` after the given `Span`.
|
/// Returns the source snippet as `String` after the given `Span`.
|
||||||
|
@ -927,7 +942,7 @@ impl SourceMap {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn generate_fn_name_span(&self, span: Span) -> Option<Span> {
|
pub fn generate_fn_name_span(&self, span: Span) -> Option<Span> {
|
||||||
let prev_span = self.span_extend_to_prev_str(span, "fn", true);
|
let prev_span = self.span_extend_to_prev_str(span, "fn", true, true).unwrap_or(span);
|
||||||
if let Ok(snippet) = self.span_to_snippet(prev_span) {
|
if let Ok(snippet) = self.span_to_snippet(prev_span) {
|
||||||
debug!(
|
debug!(
|
||||||
"generate_fn_name_span: span={:?}, prev_span={:?}, snippet={:?}",
|
"generate_fn_name_span: span={:?}, prev_span={:?}, snippet={:?}",
|
||||||
|
@ -968,8 +983,7 @@ impl SourceMap {
|
||||||
pub fn generate_local_type_param_snippet(&self, span: Span) -> Option<(Span, String)> {
|
pub fn generate_local_type_param_snippet(&self, span: Span) -> Option<(Span, String)> {
|
||||||
// Try to extend the span to the previous "fn" keyword to retrieve the function
|
// Try to extend the span to the previous "fn" keyword to retrieve the function
|
||||||
// signature.
|
// signature.
|
||||||
let sugg_span = self.span_extend_to_prev_str(span, "fn", false);
|
if let Some(sugg_span) = self.span_extend_to_prev_str(span, "fn", false, true) {
|
||||||
if sugg_span != span {
|
|
||||||
if let Ok(snippet) = self.span_to_snippet(sugg_span) {
|
if let Ok(snippet) = self.span_to_snippet(sugg_span) {
|
||||||
// Consume the function name.
|
// Consume the function name.
|
||||||
let mut offset = snippet
|
let mut offset = snippet
|
||||||
|
|
|
@ -382,7 +382,7 @@ error[E0435]: attempt to use a non-constant value in a constant
|
||||||
--> $DIR/parse-error.rs:39:37
|
--> $DIR/parse-error.rs:39:37
|
||||||
|
|
|
|
||||||
LL | let mut foo = 0;
|
LL | let mut foo = 0;
|
||||||
| ---------- help: consider using `const` instead of `let`: `const foo`
|
| ----------- help: consider using `const` instead of `let`: `const foo`
|
||||||
...
|
...
|
||||||
LL | asm!("{}", options(), const foo);
|
LL | asm!("{}", options(), const foo);
|
||||||
| ^^^ non-constant value
|
| ^^^ non-constant value
|
||||||
|
@ -391,7 +391,7 @@ error[E0435]: attempt to use a non-constant value in a constant
|
||||||
--> $DIR/parse-error.rs:48:44
|
--> $DIR/parse-error.rs:48:44
|
||||||
|
|
|
|
||||||
LL | let mut foo = 0;
|
LL | let mut foo = 0;
|
||||||
| ---------- help: consider using `const` instead of `let`: `const foo`
|
| ----------- help: consider using `const` instead of `let`: `const foo`
|
||||||
...
|
...
|
||||||
LL | asm!("{}", clobber_abi("C"), const foo);
|
LL | asm!("{}", clobber_abi("C"), const foo);
|
||||||
| ^^^ non-constant value
|
| ^^^ non-constant value
|
||||||
|
@ -400,7 +400,7 @@ error[E0435]: attempt to use a non-constant value in a constant
|
||||||
--> $DIR/parse-error.rs:55:31
|
--> $DIR/parse-error.rs:55:31
|
||||||
|
|
|
|
||||||
LL | let mut foo = 0;
|
LL | let mut foo = 0;
|
||||||
| ---------- help: consider using `const` instead of `let`: `const foo`
|
| ----------- help: consider using `const` instead of `let`: `const foo`
|
||||||
...
|
...
|
||||||
LL | asm!("{a}", a = const foo, a = const bar);
|
LL | asm!("{a}", a = const foo, a = const bar);
|
||||||
| ^^^ non-constant value
|
| ^^^ non-constant value
|
||||||
|
@ -409,7 +409,7 @@ error[E0435]: attempt to use a non-constant value in a constant
|
||||||
--> $DIR/parse-error.rs:55:46
|
--> $DIR/parse-error.rs:55:46
|
||||||
|
|
|
|
||||||
LL | let mut bar = 0;
|
LL | let mut bar = 0;
|
||||||
| ---------- help: consider using `const` instead of `let`: `const bar`
|
| ----------- help: consider using `const` instead of `let`: `const bar`
|
||||||
...
|
...
|
||||||
LL | asm!("{a}", a = const foo, a = const bar);
|
LL | asm!("{a}", a = const foo, a = const bar);
|
||||||
| ^^^ non-constant value
|
| ^^^ non-constant value
|
||||||
|
@ -418,7 +418,7 @@ error[E0435]: attempt to use a non-constant value in a constant
|
||||||
--> $DIR/parse-error.rs:62:45
|
--> $DIR/parse-error.rs:62:45
|
||||||
|
|
|
|
||||||
LL | let mut bar = 0;
|
LL | let mut bar = 0;
|
||||||
| ---------- help: consider using `const` instead of `let`: `const bar`
|
| ----------- help: consider using `const` instead of `let`: `const bar`
|
||||||
...
|
...
|
||||||
LL | asm!("{a}", in("x0") foo, a = const bar);
|
LL | asm!("{a}", in("x0") foo, a = const bar);
|
||||||
| ^^^ non-constant value
|
| ^^^ non-constant value
|
||||||
|
@ -427,7 +427,7 @@ error[E0435]: attempt to use a non-constant value in a constant
|
||||||
--> $DIR/parse-error.rs:65:45
|
--> $DIR/parse-error.rs:65:45
|
||||||
|
|
|
|
||||||
LL | let mut bar = 0;
|
LL | let mut bar = 0;
|
||||||
| ---------- help: consider using `const` instead of `let`: `const bar`
|
| ----------- help: consider using `const` instead of `let`: `const bar`
|
||||||
...
|
...
|
||||||
LL | asm!("{a}", in("x0") foo, a = const bar);
|
LL | asm!("{a}", in("x0") foo, a = const bar);
|
||||||
| ^^^ non-constant value
|
| ^^^ non-constant value
|
||||||
|
@ -436,7 +436,7 @@ error[E0435]: attempt to use a non-constant value in a constant
|
||||||
--> $DIR/parse-error.rs:68:41
|
--> $DIR/parse-error.rs:68:41
|
||||||
|
|
|
|
||||||
LL | let mut bar = 0;
|
LL | let mut bar = 0;
|
||||||
| ---------- help: consider using `const` instead of `let`: `const bar`
|
| ----------- help: consider using `const` instead of `let`: `const bar`
|
||||||
...
|
...
|
||||||
LL | asm!("{1}", in("x0") foo, const bar);
|
LL | asm!("{1}", in("x0") foo, const bar);
|
||||||
| ^^^ non-constant value
|
| ^^^ non-constant value
|
||||||
|
|
|
@ -394,7 +394,7 @@ error[E0435]: attempt to use a non-constant value in a constant
|
||||||
--> $DIR/parse-error.rs:39:37
|
--> $DIR/parse-error.rs:39:37
|
||||||
|
|
|
|
||||||
LL | let mut foo = 0;
|
LL | let mut foo = 0;
|
||||||
| ---------- help: consider using `const` instead of `let`: `const foo`
|
| ----------- help: consider using `const` instead of `let`: `const foo`
|
||||||
...
|
...
|
||||||
LL | asm!("{}", options(), const foo);
|
LL | asm!("{}", options(), const foo);
|
||||||
| ^^^ non-constant value
|
| ^^^ non-constant value
|
||||||
|
@ -403,7 +403,7 @@ error[E0435]: attempt to use a non-constant value in a constant
|
||||||
--> $DIR/parse-error.rs:50:44
|
--> $DIR/parse-error.rs:50:44
|
||||||
|
|
|
|
||||||
LL | let mut foo = 0;
|
LL | let mut foo = 0;
|
||||||
| ---------- help: consider using `const` instead of `let`: `const foo`
|
| ----------- help: consider using `const` instead of `let`: `const foo`
|
||||||
...
|
...
|
||||||
LL | asm!("{}", clobber_abi("C"), const foo);
|
LL | asm!("{}", clobber_abi("C"), const foo);
|
||||||
| ^^^ non-constant value
|
| ^^^ non-constant value
|
||||||
|
@ -412,7 +412,7 @@ error[E0435]: attempt to use a non-constant value in a constant
|
||||||
--> $DIR/parse-error.rs:57:31
|
--> $DIR/parse-error.rs:57:31
|
||||||
|
|
|
|
||||||
LL | let mut foo = 0;
|
LL | let mut foo = 0;
|
||||||
| ---------- help: consider using `const` instead of `let`: `const foo`
|
| ----------- help: consider using `const` instead of `let`: `const foo`
|
||||||
...
|
...
|
||||||
LL | asm!("{a}", a = const foo, a = const bar);
|
LL | asm!("{a}", a = const foo, a = const bar);
|
||||||
| ^^^ non-constant value
|
| ^^^ non-constant value
|
||||||
|
@ -421,7 +421,7 @@ error[E0435]: attempt to use a non-constant value in a constant
|
||||||
--> $DIR/parse-error.rs:57:46
|
--> $DIR/parse-error.rs:57:46
|
||||||
|
|
|
|
||||||
LL | let mut bar = 0;
|
LL | let mut bar = 0;
|
||||||
| ---------- help: consider using `const` instead of `let`: `const bar`
|
| ----------- help: consider using `const` instead of `let`: `const bar`
|
||||||
...
|
...
|
||||||
LL | asm!("{a}", a = const foo, a = const bar);
|
LL | asm!("{a}", a = const foo, a = const bar);
|
||||||
| ^^^ non-constant value
|
| ^^^ non-constant value
|
||||||
|
@ -430,7 +430,7 @@ error[E0435]: attempt to use a non-constant value in a constant
|
||||||
--> $DIR/parse-error.rs:64:46
|
--> $DIR/parse-error.rs:64:46
|
||||||
|
|
|
|
||||||
LL | let mut bar = 0;
|
LL | let mut bar = 0;
|
||||||
| ---------- help: consider using `const` instead of `let`: `const bar`
|
| ----------- help: consider using `const` instead of `let`: `const bar`
|
||||||
...
|
...
|
||||||
LL | asm!("{a}", in("eax") foo, a = const bar);
|
LL | asm!("{a}", in("eax") foo, a = const bar);
|
||||||
| ^^^ non-constant value
|
| ^^^ non-constant value
|
||||||
|
@ -439,7 +439,7 @@ error[E0435]: attempt to use a non-constant value in a constant
|
||||||
--> $DIR/parse-error.rs:67:46
|
--> $DIR/parse-error.rs:67:46
|
||||||
|
|
|
|
||||||
LL | let mut bar = 0;
|
LL | let mut bar = 0;
|
||||||
| ---------- help: consider using `const` instead of `let`: `const bar`
|
| ----------- help: consider using `const` instead of `let`: `const bar`
|
||||||
...
|
...
|
||||||
LL | asm!("{a}", in("eax") foo, a = const bar);
|
LL | asm!("{a}", in("eax") foo, a = const bar);
|
||||||
| ^^^ non-constant value
|
| ^^^ non-constant value
|
||||||
|
@ -448,7 +448,7 @@ error[E0435]: attempt to use a non-constant value in a constant
|
||||||
--> $DIR/parse-error.rs:70:42
|
--> $DIR/parse-error.rs:70:42
|
||||||
|
|
|
|
||||||
LL | let mut bar = 0;
|
LL | let mut bar = 0;
|
||||||
| ---------- help: consider using `const` instead of `let`: `const bar`
|
| ----------- help: consider using `const` instead of `let`: `const bar`
|
||||||
...
|
...
|
||||||
LL | asm!("{1}", in("eax") foo, const bar);
|
LL | asm!("{1}", in("eax") foo, const bar);
|
||||||
| ^^^ non-constant value
|
| ^^^ non-constant value
|
||||||
|
|
21
src/test/ui/consts/issue-91560.fixed
Normal file
21
src/test/ui/consts/issue-91560.fixed
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
// Regression test for issue #91560.
|
||||||
|
|
||||||
|
// run-rustfix
|
||||||
|
|
||||||
|
#![allow(unused,non_upper_case_globals)]
|
||||||
|
|
||||||
|
fn foo() {
|
||||||
|
const length: usize = 2;
|
||||||
|
//~^ HELP: consider using `const`
|
||||||
|
let arr = [0; length];
|
||||||
|
//~^ ERROR: attempt to use a non-constant value in a constant [E0435]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bar() {
|
||||||
|
const length: usize = 2;
|
||||||
|
//~^ HELP: consider using `const`
|
||||||
|
let arr = [0; length];
|
||||||
|
//~^ ERROR: attempt to use a non-constant value in a constant [E0435]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
21
src/test/ui/consts/issue-91560.rs
Normal file
21
src/test/ui/consts/issue-91560.rs
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
// Regression test for issue #91560.
|
||||||
|
|
||||||
|
// run-rustfix
|
||||||
|
|
||||||
|
#![allow(unused,non_upper_case_globals)]
|
||||||
|
|
||||||
|
fn foo() {
|
||||||
|
let mut length: usize = 2;
|
||||||
|
//~^ HELP: consider using `const`
|
||||||
|
let arr = [0; length];
|
||||||
|
//~^ ERROR: attempt to use a non-constant value in a constant [E0435]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bar() {
|
||||||
|
let length: usize = 2;
|
||||||
|
//~^ HELP: consider using `const`
|
||||||
|
let arr = [0; length];
|
||||||
|
//~^ ERROR: attempt to use a non-constant value in a constant [E0435]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
21
src/test/ui/consts/issue-91560.stderr
Normal file
21
src/test/ui/consts/issue-91560.stderr
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
error[E0435]: attempt to use a non-constant value in a constant
|
||||||
|
--> $DIR/issue-91560.rs:10:19
|
||||||
|
|
|
||||||
|
LL | let mut length: usize = 2;
|
||||||
|
| -------------- help: consider using `const` instead of `let`: `const length`
|
||||||
|
LL |
|
||||||
|
LL | let arr = [0; length];
|
||||||
|
| ^^^^^^ non-constant value
|
||||||
|
|
||||||
|
error[E0435]: attempt to use a non-constant value in a constant
|
||||||
|
--> $DIR/issue-91560.rs:17:19
|
||||||
|
|
|
||||||
|
LL | let length: usize = 2;
|
||||||
|
| ------------ help: consider using `const` instead of `let`: `const length`
|
||||||
|
LL |
|
||||||
|
LL | let arr = [0; length];
|
||||||
|
| ^^^^^^ non-constant value
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0435`.
|
Loading…
Add table
Add a link
Reference in a new issue