Rollup merge of #100941 - lyming2007:issue-100584, r=oli-obk

Point at the string inside literal and mention if we need string inte…

…rpolation

	modified:   compiler/rustc_passes/src/liveness.rs
This commit is contained in:
Dylan DPC 2022-08-30 16:56:10 +05:30 committed by GitHub
commit 467d2c1833
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 130 additions and 11 deletions

View File

@ -229,6 +229,19 @@ enum VarKind {
Upvar(HirId, Symbol),
}
struct CollectLitsVisitor<'tcx> {
lit_exprs: Vec<&'tcx hir::Expr<'tcx>>,
}
impl<'tcx> Visitor<'tcx> for CollectLitsVisitor<'tcx> {
fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
if let hir::ExprKind::Lit(_) = expr.kind {
self.lit_exprs.push(expr);
}
intravisit::walk_expr(self, expr);
}
}
struct IrMaps<'tcx> {
tcx: TyCtxt<'tcx>,
live_node_map: HirIdMap<LiveNode>,
@ -1333,7 +1346,7 @@ fn warn_about_unreachable(
impl<'a, 'tcx> Visitor<'tcx> for Liveness<'a, 'tcx> {
fn visit_local(&mut self, local: &'tcx hir::Local<'tcx>) {
self.check_unused_vars_in_pat(&local.pat, None, |spans, hir_id, ln, var| {
self.check_unused_vars_in_pat(&local.pat, None, None, |spans, hir_id, ln, var| {
if local.init.is_some() {
self.warn_about_dead_assign(spans, hir_id, ln, var);
}
@ -1348,7 +1361,7 @@ fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) {
}
fn visit_arm(&mut self, arm: &'tcx hir::Arm<'tcx>) {
self.check_unused_vars_in_pat(&arm.pat, None, |_, _, _, _| {});
self.check_unused_vars_in_pat(&arm.pat, None, None, |_, _, _, _| {});
intravisit::walk_arm(self, arm);
}
}
@ -1387,7 +1400,7 @@ fn check_expr<'tcx>(this: &mut Liveness<'_, 'tcx>, expr: &'tcx Expr<'tcx>) {
}
hir::ExprKind::Let(let_expr) => {
this.check_unused_vars_in_pat(let_expr.pat, None, |_, _, _, _| {});
this.check_unused_vars_in_pat(let_expr.pat, None, None, |_, _, _, _| {});
}
// no correctness conditions related to liveness
@ -1508,13 +1521,18 @@ fn warn_about_unused_upvars(&self, entry_ln: LiveNode) {
fn warn_about_unused_args(&self, body: &hir::Body<'_>, entry_ln: LiveNode) {
for p in body.params {
self.check_unused_vars_in_pat(&p.pat, Some(entry_ln), |spans, hir_id, ln, var| {
if !self.live_on_entry(ln, var) {
self.report_unused_assign(hir_id, spans, var, |name| {
format!("value passed to `{}` is never read", name)
});
}
});
self.check_unused_vars_in_pat(
&p.pat,
Some(entry_ln),
Some(body),
|spans, hir_id, ln, var| {
if !self.live_on_entry(ln, var) {
self.report_unused_assign(hir_id, spans, var, |name| {
format!("value passed to `{}` is never read", name)
});
}
},
);
}
}
@ -1522,6 +1540,7 @@ fn check_unused_vars_in_pat(
&self,
pat: &hir::Pat<'_>,
entry_ln: Option<LiveNode>,
opt_body: Option<&hir::Body<'_>>,
on_used_on_entry: impl Fn(Vec<Span>, HirId, LiveNode, Variable),
) {
// In an or-pattern, only consider the variable; any later patterns must have the same
@ -1549,7 +1568,7 @@ fn check_unused_vars_in_pat(
hir_ids_and_spans.into_iter().map(|(_, _, ident_span)| ident_span).collect();
on_used_on_entry(spans, id, ln, var);
} else {
self.report_unused(hir_ids_and_spans, ln, var, can_remove);
self.report_unused(hir_ids_and_spans, ln, var, can_remove, pat, opt_body);
}
}
}
@ -1561,6 +1580,8 @@ fn report_unused(
ln: LiveNode,
var: Variable,
can_remove: bool,
pat: &hir::Pat<'_>,
opt_body: Option<&hir::Body<'_>>,
) {
let first_hir_id = hir_ids_and_spans[0].0;
@ -1664,6 +1685,9 @@ fn report_unused(
.collect::<Vec<_>>(),
|lint| {
let mut err = lint.build(&format!("unused variable: `{}`", name));
if self.has_added_lit_match_name_span(&name, opt_body, &mut err) {
err.span_label(pat.span, "unused variable");
}
err.multipart_suggestion(
"if this is intentional, prefix it with an underscore",
non_shorthands,
@ -1677,6 +1701,42 @@ fn report_unused(
}
}
fn has_added_lit_match_name_span(
&self,
name: &str,
opt_body: Option<&hir::Body<'_>>,
err: &mut rustc_errors::DiagnosticBuilder<'_, ()>,
) -> bool {
let mut has_litstring = false;
let Some(opt_body) = opt_body else {return false;};
let mut visitor = CollectLitsVisitor { lit_exprs: vec![] };
intravisit::walk_body(&mut visitor, opt_body);
for lit_expr in visitor.lit_exprs {
let hir::ExprKind::Lit(litx) = &lit_expr.kind else { continue };
let rustc_ast::LitKind::Str(syb, _) = litx.node else{ continue; };
let name_str: &str = syb.as_str();
let mut name_pa = String::from("{");
name_pa.push_str(&name);
name_pa.push('}');
if name_str.contains(&name_pa) {
err.span_label(
lit_expr.span,
"you might have meant to use string interpolation in this string literal",
);
err.multipart_suggestion(
"string interpolation only works in `format!` invocations",
vec![
(lit_expr.span.shrink_to_lo(), "format!(".to_string()),
(lit_expr.span.shrink_to_hi(), ")".to_string()),
],
Applicability::MachineApplicable,
);
has_litstring = true;
}
}
has_litstring
}
fn warn_about_dead_assign(&self, spans: Vec<Span>, hir_id: HirId, ln: LiveNode, var: Variable) {
if !self.live_on_exit(ln, var) {
self.report_unused_assign(hir_id, spans, var, |name| {

View File

@ -0,0 +1,15 @@
#![deny(unused)]
fn foo(xyza: &str) {
//~^ ERROR unused variable: `xyza`
let _ = "{xyza}";
}
fn foo3(xyza: &str) {
//~^ ERROR unused variable: `xyza`
let _ = "aaa{xyza}bbb";
}
fn main() {
foo("x");
foo3("xx");
}

View File

@ -0,0 +1,44 @@
error: unused variable: `xyza`
--> $DIR/issue-100584.rs:2:8
|
LL | fn foo(xyza: &str) {
| ^^^^ unused variable
LL |
LL | let _ = "{xyza}";
| -------- you might have meant to use string interpolation in this string literal
|
note: the lint level is defined here
--> $DIR/issue-100584.rs:1:9
|
LL | #![deny(unused)]
| ^^^^^^
= note: `#[deny(unused_variables)]` implied by `#[deny(unused)]`
help: string interpolation only works in `format!` invocations
|
LL | let _ = format!("{xyza}");
| ++++++++ +
help: if this is intentional, prefix it with an underscore
|
LL | fn foo(_xyza: &str) {
| ~~~~~
error: unused variable: `xyza`
--> $DIR/issue-100584.rs:7:9
|
LL | fn foo3(xyza: &str) {
| ^^^^ unused variable
LL |
LL | let _ = "aaa{xyza}bbb";
| -------------- you might have meant to use string interpolation in this string literal
|
help: string interpolation only works in `format!` invocations
|
LL | let _ = format!("aaa{xyza}bbb");
| ++++++++ +
help: if this is intentional, prefix it with an underscore
|
LL | fn foo3(_xyza: &str) {
| ~~~~~
error: aborting due to 2 previous errors