Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
b6b897b
introduce future-compatibility warning for forbidden lint groups
nikomatsakis Jan 30, 2021
4d1efb7
OsStr eq_ignore_ascii_case takes arg by value
TyPR124 Feb 3, 2021
d3d0fb7
add #[inline] to all the public IpAddr functions
saethlin Feb 3, 2021
2c8bf1d
Stabilize the Wake trait
yoshuawuyts Jan 22, 2021
3719247
move test to be with the others
mark-i-m Feb 3, 2021
8988238
Revert stabilizing integer::BITS.
m-ou-se Feb 3, 2021
a616f82
Add lint for `panic!(123)` which is not accepted in Rust 2021.
m-ou-se Feb 1, 2021
34d5ac2
Make panic/assert calls in rustc compatible with Rust 2021.
m-ou-se Feb 1, 2021
e9ad5be
Allow/fix non_fmt_panic in tests.
m-ou-se Feb 1, 2021
753b0b0
Update panic!() documentation about non-string panics.
m-ou-se Feb 2, 2021
3f3eb89
Fix/allow non_fmt_panic in clippy tests.
m-ou-se Feb 2, 2021
0870c15
Suggest panic!("{}", ..) instead of panic!(..) clippy::expect_fun_call.
m-ou-se Feb 3, 2021
5c056ed
Rename Iterator::fold_first to reduce.
m-ou-se Dec 7, 2020
26af55f
Improve documentation of Iterator::{fold, reduce}.
m-ou-se Dec 7, 2020
24e0940
Stabilize feature(iterator_fold_self): Iterator::reduce
m-ou-se Dec 7, 2020
f42e961
Stabilize poison API of Once, rename poisoned()
Kixunil Feb 4, 2021
d20d097
Rollup merge of #74304 - yoshuawuyts:stabilize-wake, r=KodrAus
m-ou-se Feb 4, 2021
5b0acfd
Rollup merge of #79805 - m-ou-se:iterator-reduce, r=KodrAus
m-ou-se Feb 4, 2021
c5990dd
Rollup merge of #81556 - nikomatsakis:forbidden-lint-groups-lint, r=p…
m-ou-se Feb 4, 2021
87b269a
Rollup merge of #81645 - m-ou-se:panic-lint, r=estebank,flip1995
m-ou-se Feb 4, 2021
21e5827
Rollup merge of #81710 - TyPR124:patch-2, r=m-ou-se
m-ou-se Feb 4, 2021
e0ddc05
Rollup merge of #81711 - saethlin:ipaddr-inline, r=m-ou-se
m-ou-se Feb 4, 2021
83e0fe3
Rollup merge of #81725 - mark-i-m:mv-test, r=Mark-Simulacrum
m-ou-se Feb 4, 2021
113e27f
Rollup merge of #81727 - m-ou-se:unstabilize-bits, r=Mark-Simulacrum
m-ou-se Feb 4, 2021
6f014cd
Rollup merge of #81745 - Kixunil:stabilize_once_poison, r=m-ou-se
m-ou-se Feb 4, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Add lint for panic!(123) which is not accepted in Rust 2021.
This extends the `panic_fmt` lint to warn for all cases where the first
argument cannot be interpreted as a format string, as will happen in
Rust 2021.

It suggests to add `"{}", ` to format the message as a string. In the
case of `std::panic!()`, it also suggests the recently stabilized
`std::panic::panic_any()` function as an alternative.

It renames the lint to `non_fmt_panic` to match the lint naming
guidelines.
  • Loading branch information
m-ou-se committed Feb 3, 2021
commit a616f8267ed9b9c45cdef81346e98aae06a70990
6 changes: 3 additions & 3 deletions compiler/rustc_lint/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,8 @@ mod late;
mod levels;
mod methods;
mod non_ascii_idents;
mod non_fmt_panic;
mod nonstandard_style;
mod panic_fmt;
mod passes;
mod redundant_semicolon;
mod traits;
Expand All @@ -81,8 +81,8 @@ use builtin::*;
use internal::*;
use methods::*;
use non_ascii_idents::*;
use non_fmt_panic::NonPanicFmt;
use nonstandard_style::*;
use panic_fmt::PanicFmt;
use redundant_semicolon::*;
use traits::*;
use types::*;
Expand Down Expand Up @@ -169,7 +169,7 @@ macro_rules! late_lint_passes {
ClashingExternDeclarations: ClashingExternDeclarations::new(),
DropTraitConstraints: DropTraitConstraints,
TemporaryCStringAsPtr: TemporaryCStringAsPtr,
PanicFmt: PanicFmt,
NonPanicFmt: NonPanicFmt,
]
);
};
Expand Down
197 changes: 197 additions & 0 deletions compiler/rustc_lint/src/non_fmt_panic.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
use crate::{LateContext, LateLintPass, LintContext};
use rustc_ast as ast;
use rustc_errors::{pluralize, Applicability};
use rustc_hir as hir;
use rustc_middle::ty;
use rustc_parse_format::{ParseMode, Parser, Piece};
use rustc_span::{sym, symbol::kw, InnerSpan, Span, Symbol};

declare_lint! {
/// The `non_fmt_panic` lint detects `panic!(..)` invocations where the first
/// argument is not a formatting string.
///
/// ### Example
///
/// ```rust,no_run
/// panic!("{}");
/// panic!(123);
/// ```
///
/// {{produces}}
///
/// ### Explanation
///
/// In Rust 2018 and earlier, `panic!(x)` directly uses `x` as the message.
/// That means that `panic!("{}")` panics with the message `"{}"` instead
/// of using it as a formatting string, and `panic!(123)` will panic with
/// an `i32` as message.
///
/// Rust 2021 always interprets the first argument as format string.
NON_FMT_PANIC,
Warn,
"detect single-argument panic!() invocations in which the argument is not a format string",
report_in_external_macro
}

declare_lint_pass!(NonPanicFmt => [NON_FMT_PANIC]);

impl<'tcx> LateLintPass<'tcx> for NonPanicFmt {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) {
if let hir::ExprKind::Call(f, [arg]) = &expr.kind {
if let &ty::FnDef(def_id, _) = cx.typeck_results().expr_ty(f).kind() {
if Some(def_id) == cx.tcx.lang_items().begin_panic_fn()
|| Some(def_id) == cx.tcx.lang_items().panic_fn()
|| Some(def_id) == cx.tcx.lang_items().panic_str()
{
if let Some(id) = f.span.ctxt().outer_expn_data().macro_def_id {
if cx.tcx.is_diagnostic_item(sym::std_panic_2015_macro, id)
|| cx.tcx.is_diagnostic_item(sym::core_panic_2015_macro, id)
{
check_panic(cx, f, arg);
}
}
}
}
}
}
}

fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tcx hir::Expr<'tcx>) {
if let hir::ExprKind::Lit(lit) = &arg.kind {
if let ast::LitKind::Str(sym, _) = lit.node {
// The argument is a string literal.
check_panic_str(cx, f, arg, &sym.as_str());
return;
}
}

// The argument is *not* a string literal.

let (span, panic) = panic_call(cx, f);

cx.struct_span_lint(NON_FMT_PANIC, arg.span, |lint| {
let mut l = lint.build("panic message is not a string literal");
l.note("this is no longer accepted in Rust 2021");
if span.contains(arg.span) {
l.span_suggestion_verbose(
arg.span.shrink_to_lo(),
"add a \"{}\" format string to Display the message",
"\"{}\", ".into(),
Applicability::MaybeIncorrect,
);
if panic == sym::std_panic_macro {
l.span_suggestion_verbose(
span.until(arg.span),
"or use std::panic::panic_any instead",
"std::panic::panic_any(".into(),
Applicability::MachineApplicable,
);
}
}
l.emit();
});
}

fn check_panic_str<'tcx>(
cx: &LateContext<'tcx>,
f: &'tcx hir::Expr<'tcx>,
arg: &'tcx hir::Expr<'tcx>,
fmt: &str,
) {
if !fmt.contains(&['{', '}'][..]) {
// No brace, no problem.
return;
}

let fmt_span = arg.span.source_callsite();

let (snippet, style) = match cx.sess().parse_sess.source_map().span_to_snippet(fmt_span) {
Ok(snippet) => {
// Count the number of `#`s between the `r` and `"`.
let style = snippet.strip_prefix('r').and_then(|s| s.find('"'));
(Some(snippet), style)
}
Err(_) => (None, None),
};

let mut fmt_parser =
Parser::new(fmt.as_ref(), style, snippet.clone(), false, ParseMode::Format);
let n_arguments = (&mut fmt_parser).filter(|a| matches!(a, Piece::NextArgument(_))).count();

let (span, _) = panic_call(cx, f);

if n_arguments > 0 && fmt_parser.errors.is_empty() {
let arg_spans: Vec<_> = match &fmt_parser.arg_places[..] {
[] => vec![fmt_span],
v => v.iter().map(|span| fmt_span.from_inner(*span)).collect(),
};
cx.struct_span_lint(NON_FMT_PANIC, arg_spans, |lint| {
let mut l = lint.build(match n_arguments {
1 => "panic message contains an unused formatting placeholder",
_ => "panic message contains unused formatting placeholders",
});
l.note("this message is not used as a format string when given without arguments, but will be in Rust 2021");
if span.contains(arg.span) {
l.span_suggestion(
arg.span.shrink_to_hi(),
&format!("add the missing argument{}", pluralize!(n_arguments)),
", ...".into(),
Applicability::HasPlaceholders,
);
l.span_suggestion(
arg.span.shrink_to_lo(),
"or add a \"{}\" format string to use the message literally",
"\"{}\", ".into(),
Applicability::MachineApplicable,
);
}
l.emit();
});
} else {
let brace_spans: Option<Vec<_>> =
snippet.filter(|s| s.starts_with('"') || s.starts_with("r#")).map(|s| {
s.char_indices()
.filter(|&(_, c)| c == '{' || c == '}')
.map(|(i, _)| fmt_span.from_inner(InnerSpan { start: i, end: i + 1 }))
.collect()
});
let msg = match &brace_spans {
Some(v) if v.len() == 1 => "panic message contains a brace",
_ => "panic message contains braces",
};
cx.struct_span_lint(NON_FMT_PANIC, brace_spans.unwrap_or(vec![span]), |lint| {
let mut l = lint.build(msg);
l.note("this message is not used as a format string, but will be in Rust 2021");
if span.contains(arg.span) {
l.span_suggestion(
arg.span.shrink_to_lo(),
"add a \"{}\" format string to use the message literally",
"\"{}\", ".into(),
Applicability::MachineApplicable,
);
}
l.emit();
});
}
}

fn panic_call<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>) -> (Span, Symbol) {
let mut expn = f.span.ctxt().outer_expn_data();

let mut panic_macro = kw::Empty;

// Unwrap more levels of macro expansion, as panic_2015!()
// was likely expanded from panic!() and possibly from
// [debug_]assert!().
for &i in
&[sym::std_panic_macro, sym::core_panic_macro, sym::assert_macro, sym::debug_assert_macro]
{
let parent = expn.call_site.ctxt().outer_expn_data();
if parent.macro_def_id.map_or(false, |id| cx.tcx.is_diagnostic_item(i, id)) {
expn = parent;
panic_macro = i;
}
}

(expn.call_site, panic_macro)
}
155 changes: 0 additions & 155 deletions compiler/rustc_lint/src/panic_fmt.rs

This file was deleted.

2 changes: 1 addition & 1 deletion src/test/ui/fmt/format-args-capture.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ fn panic_with_single_argument_does_not_get_formatted() {
// RFC #2795 suggests that this may need to change so that captured arguments are formatted.
// For stability reasons this will need to part of an edition change.

#[allow(panic_fmt)]
#[allow(non_fmt_panic)]
let msg = std::panic::catch_unwind(|| {
panic!("{foo}");
}).unwrap_err();
Expand Down
Loading